Compare commits

...

292 Commits

Author SHA1 Message Date
Kevin Hester
96c4286e7d Merge pull request #733 from geeksville/dev1.2
1.2.6
2021-03-07 10:00:00 +08:00
Kevin Hester
f320ecbde8 1.2.6 2021-03-07 09:51:51 +08:00
Kevin Hester
d014ae0bff fix ls_sleeps communication to device clients 2021-03-07 09:51:17 +08:00
Kevin Hester
12a7934ca1 add RU 2021-03-07 09:34:35 +08:00
Kevin Hester
64bc791e48 fix docs 2021-03-07 09:34:29 +08:00
Kevin Hester
1f33506962 Add RU region 2021-03-06 21:10:36 +08:00
Kevin Hester
ba9a94d026 fix is_low_power detection 2021-03-06 18:00:20 +08:00
Kevin Hester
6f13966d19 fix missing acks for broadcasts 2021-03-06 17:48:35 +08:00
Kevin Hester
96cfad4e57 less logspam 2021-03-06 14:52:26 +08:00
Kevin Hester
a26ebb1b69 Merge pull request #732 from geeksville/dev1.2
Dev1.2 - fix lora message rx
2021-03-06 14:31:59 +08:00
Kevin Hester
7a764efc10 1.2.5 2021-03-06 14:30:53 +08:00
Kevin Hester
49b1f4c5af oops - fix failed text message rx 2021-03-06 14:21:20 +08:00
Kevin Hester
fbe56531d2 Merge remote-tracking branch 'root/master' into dev1.2 2021-03-06 11:20:08 +08:00
Kevin Hester
aa6b29a4b5 fix from address on naks 2021-03-06 11:19:52 +08:00
Kevin Hester
c88b9732eb REALLY IMPORTANT: fix bug with retransmissions not happening 2021-03-06 11:13:33 +08:00
Kevin Hester
2c29e8b179 make nodeinfo & position plugins optional 2021-03-06 10:36:30 +08:00
Kevin Hester
d2d6b8e12f fix log formatting 2021-03-06 10:27:48 +08:00
Kevin Hester
badfaa8545 make error message clearer for packets that are too big 2021-03-06 10:27:31 +08:00
Kevin Hester
c5b67d821d Merge pull request #730 from geeksville/dev1.2
1.2.4
2021-03-05 13:46:18 +08:00
Kevin Hester
63bf7a29f3 Merge branch 'master' into dev1.2 2021-03-05 13:46:10 +08:00
Kevin Hester
845dd1f9e3 1.2.4 2021-03-05 12:39:39 +08:00
Kevin Hester
c9c44a934d don't generate acks for locally sourced msgs 2021-03-05 12:39:31 +08:00
Kevin Hester
2f6981a27f Merge pull request #729 from geeksville/dev1.2
important fixes for 1.2
2021-03-05 12:07:27 +08:00
Kevin Hester
8739469db3 oops typo 2021-03-05 11:49:37 +08:00
Kevin Hester
0c0c0babba combine acks works 2021-03-05 11:44:45 +08:00
Kevin Hester
950b32232f don't send messages the phone sent us back towards the phone 2021-03-05 10:19:27 +08:00
Kevin Hester
2f6034b067 update todos 2021-03-04 22:10:09 +08:00
Kevin Hester
159f7622e4 Merge pull request #724 from crossan007/improvements_to_env_plugin
Improvements to Environmental Measurement Plugin
2021-03-04 22:00:25 +08:00
Kevin Hester
2cc2fa906a Merge branch 'master' into improvements_to_env_plugin 2021-03-04 20:06:27 +08:00
Kevin Hester
249390a75e Merge pull request #727 from geeksville/dev1.2
Dev1.2
2021-03-04 11:41:44 +08:00
Kevin Hester
189cf7ea5e Merge remote-tracking branch 'root/master' into dev1.2 2021-03-04 11:32:34 +08:00
Kevin Hester
56fe211466 1.2.1 2021-03-04 11:29:55 +08:00
Kevin Hester
955d03acb1 fix symbol conflict with new nrf52 libs 2021-03-04 11:28:50 +08:00
Charles Crossan
1b71a0f436 refactor ENV to single multi-inheritance class with cleaner user preferences
Fix merge issues

don't log when drawing blank frames

remove useless logging

re-comment stuff

fix comment

unused var
2021-03-03 20:30:20 -05:00
Charles Crossan
2af9e1431e Improvements to EnvironmentalMeasurementPlugin
Instead of holding onto only the last measurement, hold onto a copy of the last MeshPacket containing a measurement

This will make it easier to display the last time received

make DHT sensor reads more reliable

user preference for Farenheit vs Celsius
2021-03-03 08:23:03 -05:00
Kevin Hester
076251e6a8 todo cleanup 2021-03-03 11:49:09 +08:00
Kevin Hester
fdb3cee3f2 Merge pull request #725 from geeksville/dev1.2
release to devs
2021-03-03 11:47:17 +08:00
Kevin Hester
92e05bc438 release to devs 2021-03-03 11:46:09 +08:00
Kevin Hester
69de2a047f Merge pull request #706 from geeksville/dev1.2
merging 1.2 soon!
2021-03-03 11:23:40 +08:00
Kevin Hester
05c458225f Merge remote-tracking branch 'root/master' into dev1.2 2021-03-02 15:46:16 +08:00
Kevin Hester
866125f2ab fix release script for universal builds 2021-03-02 15:37:56 +08:00
Kevin Hester
d0263e4fa3 Merge branch 'dev' into dev1.2 2021-03-02 15:16:28 +08:00
Kevin Hester
e884ace0ab show build name 2021-03-02 15:16:22 +08:00
Kevin Hester
2ac4106004 add play store link 2021-03-02 12:53:23 +08:00
Kevin Hester
59a63e4aea Merge pull request #721 from geeksville/dev
add (editable) android warning landing page
2021-03-02 12:47:19 +08:00
Kevin Hester
fbdf1f19f0 add (editable) android warning landing page 2021-03-02 12:46:19 +08:00
Kevin Hester
082101f99f wire compat 2021-03-02 12:44:48 +08:00
Kevin Hester
f6761d637f proto update 2021-03-02 11:46:00 +08:00
Kevin Hester
ef612d0b58 Merge remote-tracking branch 'root/master' into dev1.2
# Conflicts:
#	src/plugins/Plugins.cpp
#	version.properties
2021-03-01 10:26:16 +08:00
Kevin Hester
43673c0598 Merge pull request #719 from geeksville/dev
1.1.50
2021-03-01 09:21:42 +08:00
Kevin Hester
9b45749bf0 1.1.50 2021-03-01 08:33:01 +08:00
Jm Casler
f22243a209 Merge pull request #716 from apt105/master
Add files via upload
2021-02-28 12:30:18 -08:00
Kevin Hester
a51c08bfb1 todo updated 2021-02-27 14:42:07 +08:00
Kevin Hester
fb47c3a03d move channel and settings protos 2021-02-27 13:17:18 +08:00
Adrian
3b8f5ea099 Add files via upload 2021-02-27 02:01:51 +00:00
Kevin Hester
63e0b53054 1 index channel index 2021-02-27 09:17:58 +08:00
Kevin Hester
989f52494d clean up ack packets 2021-02-26 20:36:22 +08:00
Kevin Hester
0307e4161e get settings message works 2021-02-26 20:10:41 +08:00
Kevin Hester
c7c8b34adf impl get channels/get radio remote api 2021-02-26 15:34:00 +08:00
Jm Casler
1faf6c99db Merge pull request #712 from mc-hamster/master
Update how airtime report gathers data, update stable storeandforward build code
2021-02-25 08:25:42 -08:00
Jm
5f041ea7e9 Update Plugins.cpp 2021-02-25 08:14:07 -08:00
Jm Casler
14271be816 Rename src/plugins/StoreForwardPlugin.h to src/plugins/esp32/StoreForwardPlugin.h 2021-02-25 08:12:57 -08:00
Jm Casler
30d600040b Rename src/plugins/StoreForwardPlugin.cpp to src/plugins/esp32/StoreForwardPlugin.cpp 2021-02-25 08:12:30 -08:00
Jm Casler
10dd2337fc Merge branch 'master' into master 2021-02-25 08:04:41 -08:00
Kevin Hester
5ae4edf8fd move admin out of core proto 2021-02-25 20:36:37 +08:00
Kevin Hester
d3df6d3749 Merge pull request #711 from geeksville/dev
fixes for 1.1.49
2021-02-25 20:04:05 +08:00
Kevin Hester
8ba43e1745 merge latest from master 2021-02-25 20:02:32 +08:00
Kevin Hester
cedd87001d Merge branch 'dev' into dev1.2 2021-02-25 19:49:50 +08:00
Kevin Hester
afc901ddbe fix build. platformio isn't smart enough to git pull latest without
specifying a tag/commit/etc (I haven't tried specifying a branch?)

Without specifying the hash, the build breaks for anyone who already had
a repo (the CI build doesn't see this because it always pulls from scratch)

cc @crossan007 & @mc-hamster
2021-02-25 19:49:34 +08:00
Kevin Hester
e4eb7ab589 Merge branch 'dev' into dev1.2
# Conflicts:
#	proto
#	src/mesh/generated/deviceonly.pb.h
#	src/mesh/generated/mesh.pb.h
#	src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp
2021-02-25 19:44:08 +08:00
Kevin Hester
b052928af2 Merge remote-tracking branch 'root/master' into dev 2021-02-25 19:33:06 +08:00
Kevin Hester
a3b1c4608e Merge pull request #713 from Eninspace/patch-2
Update README.md
2021-02-25 18:28:05 +08:00
Niko
204c42234c Update README.md
Added line break
2021-02-25 13:12:47 +03:00
Jm Casler
0fe046b92d Merge pull request #72 from meshtastic/master
Update from head
2021-02-24 20:27:58 -08:00
Jm
fd6842cb5b Partial Work, stable build. 2021-02-24 20:27:21 -08:00
Jm Casler
4f40128bbe Merge pull request #705 from crossan007/AddEnvironmentMessage
Changes to Environmental Measurement App
2021-02-24 20:26:44 -08:00
Jm Casler
3d4580c03e Merge branch 'master' into AddEnvironmentMessage 2021-02-24 20:20:23 -08:00
Kevin Hester
66638655a5 Merge branch 'dev' into dev1.2
# Conflicts:
#	src/mesh/NodeDB.cpp
2021-02-25 08:56:36 +08:00
Kevin Hester
2d214df76f Merge remote-tracking branch 'root/master' into dev 2021-02-25 08:52:26 +08:00
Kevin Hester
8f1cd33d14 Merge pull request #709 from Eninspace/patch-1
Update README.md
2021-02-25 08:51:47 +08:00
Kevin Hester
b2c47a7dea fix #710. nodes disappearing from map. thanks @DylanHoen for noticing! 2021-02-25 08:50:46 +08:00
Niko
5f3f62ed46 Update README.md
Added Russian community group link
2021-02-24 13:45:21 +03:00
Charles Crossan
bfdad7d4d5 Merge branch 'master' into AddEnvironmentMessage 2021-02-23 20:23:13 -05:00
Kevin Hester
577336d2df oh well - github actions defeated me 2021-02-23 17:16:12 +08:00
Kevin Hester
245638a1d4 get more parallism in CI build 2021-02-23 17:07:38 +08:00
Kevin Hester
ada05a1374 fix linux 2021-02-23 16:56:28 +08:00
Kevin Hester
4b07f9e160 todo update 2021-02-23 14:45:02 +08:00
Kevin Hester
f8d8dc25c0 properly route messages to phone again 2021-02-23 14:35:34 +08:00
Jm
256ba8fa1b partial work, untested 2021-02-22 20:07:19 -08:00
Kevin Hester
aa8b86c6b2 multichannel send/rx kinda works 2021-02-23 11:43:30 +08:00
Kevin Hester
ae6b7e7259 multichannel code is done! (only basic testing completed though) 2021-02-23 10:45:03 +08:00
Kevin Hester
2761c85564 clean up the crypto api 2021-02-23 10:10:35 +08:00
Charles Crossan
ec41c11e58 initialize the last measurement values to something obviously "unread" 2021-02-22 21:00:41 -05:00
Charles Crossan
3a91da5e52 remove UI render comment log spam 2021-02-22 21:00:05 -05:00
Charles Crossan
690b843678 add missing newline 2021-02-22 20:52:10 -05:00
Charles Crossan
3f1ada29ac support independently enabling/disabling the on-device screen and actual measurement 2021-02-22 20:47:35 -05:00
Charles Crossan
0c9df6ccbd disable the app by default 2021-02-22 20:33:42 -05:00
Charles Crossan
b62b01fe7c consume the additional details from OLEDDisplayUiState to handle transitions to/from plugin screens better
It's still a bit janky, but should work

https://github.com/meshtastic/esp8266-oled-ssd1306/pull/2
2021-02-22 20:18:36 -05:00
Charles Crossan
efaf669479 update Environmental Measurement plugin to use radio config prefs 2021-02-22 19:50:51 -05:00
Kevin Hester
94cd96cfde begin multichannel hash impl 2021-02-22 12:57:26 +08:00
Kevin Hester
923ecc9d8a fix printf warnings 2021-02-22 12:57:03 +08:00
Jm Casler
d5cb7ebf3b check in partial work. 2021-02-21 20:15:31 -08:00
Kevin Hester
d6c2e9063a 1.2 channel cleanup 2021-02-22 11:16:38 +08:00
Kevin Hester
3088fe3f91 Stay up-to-date wrt master (cc @mc-hamster)
# Conflicts:
#	src/plugins/Plugins.cpp
#	src/plugins/RangeTestPlugin.cpp
#	src/plugins/StoreForwardPlugin.cpp
2021-02-22 10:39:46 +08:00
Kevin Hester
d4781280b7 update protos 2021-02-22 10:29:27 +08:00
Kevin Hester
008187caa4 1.2 wip - psk work 2021-02-22 10:26:11 +08:00
Charles Crossan
6dffaae72e fix typo 2021-02-21 16:49:35 -05:00
Charles Crossan
ae76ce4024 Implement interface for plugins to have custom UI Frames 2021-02-21 16:46:46 -05:00
Charles Crossan
087945d7cb udpate protobufs 2021-02-21 12:05:23 -05:00
Charles Crossan
fc72d16bcb Disable the plugin by default 2021-02-21 11:48:32 -05:00
Charles Crossan
5817afd4ac fix port number for ENVIRONMENTAL_MEASUREMENT_APP 2021-02-21 11:42:03 -05:00
Charles Crossan
765a6fcc62 Display received measurements in logs and on screen 2021-02-21 11:39:45 -05:00
Charles Crossan
0b20c46b79 standardize log line beginnings 2021-02-21 11:39:20 -05:00
Jm Casler
c6864417c6 Merge pull request #646 from crossan007/AddEnvironmentMessage
Add Environmental Measurement Plugin
2021-02-21 08:31:13 -08:00
Charles Crossan
27f74382aa Fix CI build for non-esp32 devices 2021-02-21 11:09:58 -05:00
Charles Crossan
77961e8e93 Un-derp testing details 2021-02-21 11:00:58 -05:00
Charles Crossan
3c564796e0 2021-02-21 10:55:33 -05:00
Jm
a4e5c7224f Add sawNodeReport to storeforwardplugin 2021-02-20 23:53:53 -08:00
Jm
7ffe601743 Changes to how airtime noise is gathered. 2021-02-20 23:53:17 -08:00
Kevin Hester
c6091338ab admin ops 2021-02-21 14:03:44 +08:00
Kevin Hester
99467cd874 1.2 WIP at least doesn't crash 2021-02-21 12:59:47 +08:00
Kevin Hester
587102f6bc fix android lint warning 2021-02-21 11:36:34 +08:00
Jm Casler
f41d79d586 Merge pull request #703 from mc-hamster/master
#701, #697 - Bug fix and update to debug output.
2021-02-20 00:53:07 -08:00
Jm Casler
fc5030ff7b Merge branch 'master' into master 2021-02-20 00:46:03 -08:00
Jm
ca40cb4be3 Update RangeTestPlugin.cpp 2021-02-20 00:43:56 -08:00
Jm
e4141df0e9 #697 GPIO 12 is an odd pin. 2021-02-20 00:34:25 -08:00
Jm
c690f81574 #697 Disable internal pullup on this board. 2021-02-19 18:19:14 -08:00
Jm
47b942ca00 #697 - Fixed button selection for tlora v2 1.6 2021-02-19 17:46:15 -08:00
Jm
621313d63c #701 - Add system up time to debug output 2021-02-19 16:58:52 -08:00
Jm Casler
d361935c09 Merge pull request #699 from crossan007/fix-exception-decoder
Fix exception decoder output
2021-02-19 16:46:46 -08:00
Charles Crossan
a2bea87332 Fix exception decoder output 2021-02-19 19:24:18 -05:00
Jm
13b8c140b4 Update StoreForwardPlugin.md 2021-02-18 21:47:16 -08:00
Kevin Hester
69a11e7375 WIP phone api changes for dev1.2 2021-02-17 19:04:41 +08:00
Kevin Hester
60a01567d9 remove region specific builds 2021-02-17 19:01:20 +08:00
Kevin Hester
f064e56dc9 fix esp32 build for dev1.2 2021-02-17 16:17:46 +08:00
Kevin Hester
42ae27973e WIP 1.2 move routing into plugin 2021-02-17 13:06:23 +08:00
Jm Casler
f6e2695a4d Merge pull request #695 from mc-hamster/master
Range test plugin done-enough
2021-02-16 18:54:42 -08:00
Jm
e840465ef3 fix for failed builds on nrf and linux 2021-02-16 18:46:16 -08:00
Jm Casler
f24e8e5f5c Rename src/plugins/RangeTestPlugin.h to src/plugins/esp32/RangeTestPlugin.h 2021-02-16 18:36:58 -08:00
Jm Casler
6376ab51f1 Moving to plugins/esp32 2021-02-16 18:36:30 -08:00
Jm Casler
bd29d78a29 Update StoreForwardPlugin.md 2021-02-16 18:24:37 -08:00
Jm Casler
b35cd76854 Update StoreForwardPlugin.md 2021-02-16 18:19:24 -08:00
Kevin Hester
205282c4bc show hwvendor at boot 2021-02-17 10:08:33 +08:00
Jm
a4fd74b58e Update Plugins.cpp 2021-02-16 18:07:02 -08:00
Jm Casler
25072f0637 Merge branch 'master' into master 2021-02-16 17:44:17 -08:00
Jm
937955b36d Updating range test and storeforward. 2021-02-16 17:42:46 -08:00
Jm
2e8867eda6 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-16 17:42:25 -08:00
Jm Casler
bd399a134b Merge pull request #693 from geoffreyheller/tlora-v2116-tx-pin-fix
Fix for non-working tx pin
2021-02-16 12:31:09 -08:00
Kevin Hester
45caf394f0 WIP multichannel support 2021-02-16 15:41:52 +08:00
Jm Casler
d67e2187d0 Update RangeTestPlugin.md 2021-02-15 21:17:06 -08:00
geoffreyheller
c8584d576a Fix for non-working tx pin 2021-02-15 19:33:35 -08:00
Jm Casler
418a12e75f Merge pull request #692 from crossan007/add_set_channel
add handleSetChannel
2021-02-15 18:49:29 -08:00
Charles Crossan
05d237ee84 add handleSetChannel 2021-02-15 21:02:30 -05:00
Jm
9a044f31a3 Tweak to the startup condition of the range test plugin. 2021-02-15 09:11:28 -08:00
Jm
8320754b98 Added recommended settings as a sender 2021-02-14 21:45:26 -08:00
Jm
703ce2e292 Keep device from sleeping while transmitting in range test plugin. 2021-02-14 21:34:47 -08:00
Jm
c9353ebee3 Update RangeTestPlugin.md 2021-02-14 21:24:41 -08:00
Jm Casler
9601868e0f Merge pull request #71 from mc-hamster/RangeTestPlugin
Merge pull request #69 from mc-hamster/master
2021-02-14 20:18:41 -08:00
Jm
fea2228b16 Update RangeTestPlugin.md 2021-02-14 20:17:16 -08:00
Jm
7d4ce483c5 Update RangeTestPlugin.md 2021-02-14 20:16:29 -08:00
Jm
e6605e5ac8 Store Forward can see All(?) rx packets! 2021-02-14 20:13:52 -08:00
Jm Casler
2472d6fd1b Merge pull request #70 from meshtastic/master
pull from main
2021-02-14 18:40:38 -08:00
Jm
3311146aba Turning storeforward back on for @geeksville 2021-02-14 16:19:06 -08:00
Jm Casler
793528b057 Merge pull request #69 from mc-hamster/master
#671 Range test plugin
2021-02-14 16:18:36 -08:00
Jm
b8adaf6fbe #671 Range test plugin 2021-02-14 16:17:40 -08:00
Jm
24329a26de Framework for storeforward 2021-02-14 14:01:08 -08:00
Jm
f1a65f9d0e Update to store and forward. Don't merge this to main! 2021-02-14 13:31:11 -08:00
Jm
ae46b3df32 Update StoreForwardPlugin.md 2021-02-14 11:10:56 -08:00
Jm
d5c1e3c6e0 Update StoreForwardPlugin.md 2021-02-14 11:00:11 -08:00
Jm
a95f612452 Update StoreForwardPlugin.md 2021-02-14 10:56:08 -08:00
Jm Casler
3201d1c3bc #668 Partial work for store & forward 2021-02-14 08:44:49 -08:00
Kevin Hester
2b10a03178 Merge pull request #690 from geeksville/dev
oops - 1.1.47 had bad bug
2021-02-14 15:26:00 +08:00
Kevin Hester
80fb7e4ab8 Merge remote-tracking branch 'root/master' into dev 2021-02-14 15:15:28 +08:00
Kevin Hester
7c1ddd9447 1.1.48 2021-02-14 15:13:58 +08:00
Kevin Hester
c55074f7fe oops: we should crash if we >MAX_THREADS, also raise max threads 2021-02-14 15:06:49 +08:00
Jm Casler
36643cf5f5 #671 range test plugin documentation
#671 range test plugin documentation
2021-02-13 22:40:04 -08:00
Jm Casler
92a62d93ef #671 Rangetest - This just needs to be tested. 2021-02-13 22:21:01 -08:00
Kevin Hester
450e877cfb fix #661 - create $archivedir 2021-02-14 14:14:50 +08:00
Kevin Hester
c0fbfccf43 Merge pull request #689 from geeksville/dev
Dev
2021-02-14 13:48:39 +08:00
Kevin Hester
51ccc3aa9e 1.1.47 2021-02-14 12:28:27 +08:00
Kevin Hester
e35f137986 clean up nodeinfo broadcasts and move into plugin 2021-02-14 12:27:10 +08:00
Kevin Hester
71c35304d6 delay position plugin start until 60 secs after first boot 2021-02-14 12:26:51 +08:00
Kevin Hester
c1733a4ac6 Merge remote-tracking branch 'root/master' into dev 2021-02-14 12:07:11 +08:00
Kevin Hester
66a7e8eab9 oops - we were never sending 'fixed' gps positions to other nodes 2021-02-14 12:02:24 +08:00
Kevin Hester
a872231f8a clean up position broadcasts, send them even if we don't have gps lock 2021-02-14 11:57:48 +08:00
Kevin Hester
52ec4d511c oops - we weren't properly stripping timestamps from new style positions 2021-02-14 11:37:32 +08:00
Jm Casler
aa7fb86798 Merge pull request #687 from sachaw/master
Fix report formatting
2021-02-13 14:02:12 -08:00
Sacha Weatherstone
875eeb699c Fix report formatting 2021-02-13 19:51:31 +11:00
Jm Casler
b239b4dc57 Merge pull request #686 from mc-hamster/master
Finished and partial work
2021-02-12 19:07:13 -08:00
Jm
19db5ba421 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-12 18:53:08 -08:00
Jm
e225af28dc Disable plugins 2021-02-12 18:52:31 -08:00
Jm Casler
eecf89a9c0 Merge pull request #68 from meshtastic/master
from main to my fork
2021-02-12 18:49:39 -08:00
Jm
c9b1ee532d Update deviceonly.pb.h 2021-02-12 18:49:24 -08:00
Jm
8c27baae84 Update platformio.ini 2021-02-12 18:48:18 -08:00
Kevin Hester
8c225a3c65 disable lora while updating, show "Updating" on oled screen 2021-02-12 13:48:12 +08:00
Kevin Hester
7ff1f3a759 Merge pull request #684 from geeksville/dev
Dev
2021-02-12 10:04:48 +08:00
Kevin Hester
bbc8fc0269 fix build for nrf52 2021-02-12 09:56:42 +08:00
Kevin Hester
9d81511153 fix warning 2021-02-12 09:56:35 +08:00
Kevin Hester
16d63bd0ce 1.1.46 2021-02-12 09:42:04 +08:00
Kevin Hester
f2b7ff2b79 an optimization for #681 - make want_ack packets higher priority 2021-02-12 09:40:20 +08:00
Kevin Hester
bc8453283f Merge remote-tracking branch 'root/master' into dev 2021-02-12 09:10:48 +08:00
Kevin Hester
2ff5046dcd for #681, add MeshPacketQueue (a priority queue) to ensure acks get sent quickly 2021-02-12 09:08:49 +08:00
Kevin Hester
917090856f partial for #681: Never let stale nodeinfos/positions stay in xmit queue 2021-02-11 18:19:43 +08:00
Kevin Hester
b45d633a34 Merge pull request #680 from geeksville/dev
Dev
2021-02-10 16:33:02 +08:00
Kevin Hester
fdfe62edf0 updates to work with new protobuf names 2021-02-10 16:18:41 +08:00
Jm
b29bcbbd41 #682 Exposing the actual radio center frequency to /static/report 2021-02-09 21:59:00 -08:00
Kevin Hester
8e8170b667 Merge remote-tracking branch 'root/master' into dev 2021-02-08 18:03:35 +08:00
Kevin Hester
2fa38c7dc4 update protos 2021-02-08 17:57:45 +08:00
Jm
ca8a0ca8d2 update rangetest 2021-02-07 19:20:29 -08:00
Kevin Hester
58bb7169a0 use nodenum as the default nodeid 2021-02-08 10:15:02 +08:00
Jm
cb541d75a9 Update radio-settings.md with note of coverage. 2021-02-07 13:19:52 -08:00
Jm Casler
4ee01acb40 Change where the location information is taken from. 2021-02-07 09:31:29 -08:00
Jm
d678c48884 work on rangetestplugin and storeforwardplugin
done for the night.
2021-02-06 23:29:18 -08:00
Jm
9f9f02fc6f Reverting platform.ini back to the way it was. 2021-02-06 21:38:54 -08:00
Jm Casler
abf135abce Merge pull request #66 from meshtastic/master
mc-hamster/meshtastic-device <- meshtastic/meshtastic-device
2021-02-06 19:56:44 -08:00
Kevin Hester
f7beec4728 Merge pull request #678 from geeksville/dev
misc bugs
2021-02-07 11:00:09 +08:00
Kevin Hester
ccf3450864 make CI build steps more atomic for easier reporting 2021-02-07 10:49:14 +08:00
Kevin Hester
86553a4fc9 add libs needed for linux build on CI server 2021-02-07 10:44:31 +08:00
Kevin Hester
55349ea570 1.1.42 2021-02-07 10:27:04 +08:00
Kevin Hester
486b03e985 bug 677. Don't assert fail for missing interfaces, instead return
nak packet to clients.
2021-02-07 10:26:11 +08:00
Kevin Hester
ccb232b6ac make route errors a more general 'message delivery failure' reason
in support of https://github.com/meshtastic/Meshtastic-device/issues/677
2021-02-07 09:46:35 +08:00
Jm
22af1b551a Add note about antenna gain. 2021-02-06 10:06:20 -08:00
Jm
c696d226b2 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-06 10:04:13 -08:00
Jm
9035a06b4a Add link budget to radio-settings.md 2021-02-06 10:02:23 -08:00
Jm Casler
056940a4ad Documentation 2021-02-06 09:13:49 -08:00
Kevin Hester
e7af338c31 add trademark 2021-02-04 15:46:57 +08:00
Kevin Hester
9069e5b33e no longer need to set num jobs, because my computer is better 2021-02-04 11:51:12 +08:00
Jm
82db1f1db6 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-03 08:10:15 -08:00
Jm
f46059ec4c update to range test plugin 2021-02-03 08:10:13 -08:00
Jm
0c71de4e59 Update for rangetest plugin 2021-02-03 08:09:59 -08:00
Jm Casler
0fa654e53a update radio-settings.md 2021-02-03 07:01:35 -08:00
Jm Casler
45c17659cc radio-settings.md - add note about TCXO stability 2021-02-03 01:04:23 -08:00
Jm Casler
b901f8d9ae Update to radio-settings.md 2021-02-03 00:15:41 -08:00
Jm Casler
9c60a7966f Update radio-settings.md 2021-02-03 00:01:52 -08:00
Jm Casler
6d66a53f8d Another update to radio-settings.md 2021-02-02 23:59:34 -08:00
Jm Casler
324627482a Update radio-settings.md 2021-02-02 23:57:25 -08:00
Jm Casler
0c6c189028 Update to radio-settings.md 2021-02-02 23:01:05 -08:00
Jm Casler
8a68ae0d04 Update radio-settings.md 2021-02-02 22:47:16 -08:00
Jm Casler
5661e5dad6 Update radio-settings.md 2021-02-02 22:43:24 -08:00
Jm
e9affb50d2 #674 add support for lora32 v1.3 2021-02-02 17:34:50 -08:00
Jm Casler
c00173dbd2 partial work 2021-01-31 18:20:08 -08:00
Jm Casler
e8c6fccd63 #671 Range Test Plugin
Initial work for Range Test Plugin
2021-01-31 09:12:36 -08:00
Jm Casler
487b8c6e9e #668 Initial work for Store & Forward Plugin 2021-01-31 09:12:01 -08:00
Jm
b2481d1450 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-30 19:42:08 -08:00
Jm Casler
399fbc5d65 Merge pull request #665 from mc-hamster/master
#664 - Blink the LED when we enter disablePin() and #654 - ExternalNotificationPlugin
2021-01-30 17:28:28 -08:00
Jm Casler
48b38ed94b Update documentation 2021-01-30 17:21:54 -08:00
Jm Casler
c0444ef16f Merge pull request #64 from meshtastic/master
Update from meshtastic main
2021-01-30 17:20:56 -08:00
Kevin Hester
1719a8e764 Merge pull request #667 from geeksville/dev
kevins misc fixes
2021-01-31 09:18:05 +08:00
Jm
242bcc8353 Update documentation location to the main mesthastic repo 2021-01-30 09:52:21 -08:00
Jm Casler
092af0f9f9 Update to doc to add info on the bell character 2021-01-30 09:50:19 -08:00
Jm Casler
133a7ff166 Added more notes. 2021-01-30 09:46:26 -08:00
Jm Casler
5df08410e7 Create SerialPlugin.md 2021-01-30 09:39:40 -08:00
Jm
9f9787bc03 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-30 09:36:28 -08:00
Jm
7129a19f35 #654 Add reference to documentation 2021-01-30 09:36:17 -08:00
Jm Casler
f45ffc8773 Rename documentation 2021-01-30 09:32:44 -08:00
Jm Casler
3162f74945 Create External Notification documentation. 2021-01-30 09:32:04 -08:00
Jm
6cef3e41e7 Update comments and use radioConfig 2021-01-30 09:17:40 -08:00
Kevin Hester
c0e2ec8dec 1.1.34 2021-01-30 21:23:03 +08:00
Jm
aee81c8dcd #654 - Add comments on what the config does 2021-01-29 19:35:03 -08:00
Jm
9e736ab0d7 #654 Fix gpio initilization 2021-01-28 23:16:10 -08:00
Jm
85752b0fc7 #654 - Fixed problem with class namespaces. 2021-01-28 23:02:00 -08:00
Kevin Hester
c6f34c59b4 Update to logo by @thepoweroftwo 2021-01-29 13:26:08 +08:00
Kevin Hester
7f07725840 make improperly sized AES128/256 keys non fatal, instead pad with zeros
Fixes rebooting the board if someone specifies an invalid key
2021-01-29 10:15:48 +08:00
Kevin Hester
c81d090464 someone added storerequest app? 2021-01-29 10:14:46 +08:00
Jm Casler
c524732849 #654 - Non blocking call to toggle the output. 2021-01-27 21:35:07 -08:00
Jm Casler
5e303f8a1f #654 - Work in progress. Needs testing, non-blocking alert and integration with configuration 2021-01-27 21:20:18 -08:00
Jm
2246564279 #654 - Small changes. 2021-01-27 20:06:39 -08:00
Jm
eff0c1fe89 #654 - Partial work for the LED/Speaker.
Framework is done. Just need to blink a few things and update protobufs.
2021-01-27 19:18:16 -08:00
Jm Casler
ad322476d2 Merge branch 'master' into master 2021-01-27 18:56:48 -08:00
Jm
2561742683 #664 - Blink the LED when we enter disablePin() 2021-01-27 18:56:09 -08:00
Kevin Hester
fa9e31fe03 Merge pull request #663 from geeksville/eink
back in the saddle - reading github and slack next
2021-01-28 10:38:46 +08:00
Kevin Hester
3ac5b045c4 Merge remote-tracking branch 'root/master' into eink 2021-01-28 10:31:56 +08:00
Kevin Hester
6a593e01e1 notes on eink1.0 2021-01-28 10:30:24 +08:00
Kevin Hester
6f6dd2291e fix typo 2021-01-28 10:30:00 +08:00
Kevin Hester
2b4ddc07f5 Merge pull request #651 from android606/log-tx-failure
Set critical error and reboot when radio fails to generate Tx IRQ - fixes #138
2021-01-27 18:05:56 +08:00
Kevin Hester
63c650c33e Merge branch 'master' into log-tx-failure 2021-01-27 17:54:06 +08:00
Kevin Hester
dc29161f37 Merge pull request #659 from IZ1IVA/patch-4
Update radio-settings.md
2021-01-27 17:52:27 +08:00
Jm Casler
8a6fdafc79 Merge branch 'master' into patch-4 2021-01-26 22:29:41 -08:00
IZ1IVA
a8480d1eaf Update radio-settings.md
Added data-rates
2021-01-25 16:11:24 +01:00
Andrew Mark
dd511588a2 Oops, let's only try to reboot ESP32 when there's an ESP32 2021-01-19 20:13:19 -08:00
Andrew Mark
79dad8ec8c Set critical error and reboot when radio fails to generate tx IRQ 2021-01-19 18:21:54 -08:00
Kevin Hester
fd9ffbbb88 fix charging indication for dumb battery sensors 2021-01-16 13:05:33 +08:00
Kevin Hester
d1be7cf142 improve hardfault handler 2021-01-16 12:55:51 +08:00
Kevin Hester
d1f0be215b eink leds seem a bit busted 2021-01-16 11:42:06 +08:00
Kevin Hester
3a2c17998e turn off nrf52 ble while debugging 2021-01-16 11:41:50 +08:00
Kevin Hester
a0dd051511 turn off eink backlight 2021-01-16 11:41:28 +08:00
Kevin Hester
4faff3ec6f cope with bogus NMEA gps 2021-01-16 11:41:18 +08:00
Kevin Hester
f110225173 Update variant file and qspi flash programming settings for new ttgoeink
Note: bin/qspi-flash-test.sh contains a script you can use for basic
bench programming and testing of the serial spi flash over SWD
2021-01-16 10:34:46 +08:00
Kevin Hester
2684257e7e update protobufs 2021-01-16 09:59:43 +08:00
Kevin Hester
51fb1021df Merge remote-tracking branch 'root/master' into eink
# Conflicts:
#	platformio.ini
2021-01-16 09:59:08 +08:00
Kevin Hester
51d0d0d6c5 begin new ttgo eink board 2021-01-16 09:57:55 +08:00
Kevin Hester
047df76373 move rev 0.1 of the ttgo eink board to eink0.1 2021-01-16 09:55:06 +08:00
123 changed files with 5026 additions and 1300 deletions

View File

@@ -4,8 +4,7 @@ on:
- pull_request
jobs:
main:
name: Main
setup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
@@ -22,5 +21,14 @@ jobs:
- name: Install extra python tools
run: |
pip install -U adafruit-nrfutil
- name: Build
run: platformio run -e tbeam -e heltec -e lora-relay-v1 -e linux
- name: Install libs needed for linux build
run: |
sudo apt install -y libpsocksxx-dev
- name: Build for tbeam
run: platformio run -e tbeam
- name: Build for heltec
run: platformio run -e heltec
- name: Build for lora-relay-v1
run: platformio run -e lora-relay-v1
- name: Build for linux
run: platformio run -e linux

3
.gitmodules vendored
View File

@@ -4,3 +4,6 @@
[submodule "sdk-nrfxlib"]
path = sdk-nrfxlib
url = https://github.com/nrfconnect/sdk-nrfxlib.git
[submodule "design"]
path = design
url = https://github.com/meshtastic/meshtastic-design.git

10
.vscode/settings.json vendored
View File

@@ -68,5 +68,13 @@
"protobufs",
"wifi"
],
"C_Cpp.dimInactiveRegions": true
"C_Cpp.dimInactiveRegions": true,
"protoc": {
"compile_on_save": false,
"compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto",
"options": [
"--java_out=/tmp",
"-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto"
]
}
}

View File

@@ -4,7 +4,7 @@ This is the device side code for the [meshtastic.org](https://www.meshtastic.org
![Continuous Integration](https://github.com/meshtastic/Meshtastic-esp32/workflows/Continuous%20Integration/badge.svg)
Meshtastic is a project that lets you use
Meshtastic® is a project that lets you use
inexpensive GPS mesh radios as an extensible, super long battery life mesh GPS communicator. These radios are great for hiking, skiing, paragliding -
essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other
members and any text messages sent to your group chat.

View File

@@ -4,7 +4,9 @@ set -e
VERSION=`bin/buildinfo.py`
COUNTRIES="US EU433 EU865 CN JP ANZ KR"
# We now only do regionless builds
COUNTRIES=""
#COUNTRIES="US EU433 EU865 CN JP ANZ KR"
#COUNTRIES=US
#COUNTRIES=CN
@@ -14,8 +16,6 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="lora-relay-v1"
NUM_JOBS=2 || true
OUTDIR=release/latest
# We keep all old builds (and their map files in the archive dir)
@@ -23,7 +23,7 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins
mkdir -p $OUTDIR/bins $ARCHIVEDIR
rm -r $OUTDIR/bins/*
mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
@@ -51,7 +51,7 @@ function do_build() {
basename=universal/firmware-$BOARD-$VERSION
fi
pio run --jobs $NUM_JOBS --environment $BOARD # -v
pio run --environment $BOARD # -v
SRCELF=.pio/build/$BOARD/firmware.elf
cp $SRCELF $OUTDIR/elfs/$basename.elf
@@ -94,7 +94,7 @@ pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
# keep the bins in archive also
cp $OUTDIR/bins/firmware* $OUTDIR/bins/universal/spiffs* $OUTDIR/elfs/firmware* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/universal/spiffs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
echo Updating android bins $OUTDIR/forandroid
rm -rf $OUTDIR/forandroid
@@ -109,12 +109,12 @@ release. It is used by the android app for forcing software updates. Do not ed
Generated by bin/buildall.sh -->
<resources>
<string name="cur_firmware_version">$VERSION</string>
<string name="cur_firmware_version" translatable="false">$VERSION</string>
</resources>
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/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh
echo BUILT ALL

View File

@@ -241,7 +241,7 @@ def print_addr(name, value, resolver):
def print_stack_full(lines, resolver):
print("stack:")
for line in lines:
print(line.offset + ":")
print(str(line.offset) + ":")
for content in line.content:
print(" " + resolver.resolve_stack_addr(content))

19
bin/gen-images.sh Executable file
View File

@@ -0,0 +1,19 @@
set -e
# regen the design bins first
cd design
bin/generate-pngs.sh
cd ..
# assumes 50 wide, 28 high
convert design/logo/png/Mesh_Logo_Black_Small.png -background white -alpha Background src/graphics/img/icon.xbm
inkscape --batch-process -o images/compass.png -w 48 -h 48 images/location_searching-24px.svg
convert compass.png -background white -alpha Background src/graphics/img/compass.xbm
inkscape --batch-process -o images/face.png -w 13 -h 13 images/face-24px.svg
inkscape --batch-process -o images/pin.png -w 13 -h 13 images/room-24px.svg
convert pin.png -background white -alpha Background src/graphics/img/pin.xbm

View File

@@ -2,5 +2,7 @@
set -e
VERSION=`bin/buildinfo.py`
FILENAME=release/latest/bins/universal/firmware-tbeam-$VERSION.bin
esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin
echo Installing $FILENAME
esptool.py --baud 921600 write_flash 0x10000 $FILENAME

View File

@@ -1,6 +1,6 @@
# You probably don't need this - it is a basic test of the serial flash on the TTGO eink board
nrfjprog -qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall
nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall
nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --memwr 0x12000000 --val 0xdeadbeef --verify
nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --readqspi spi.hex
objdump -s spi.hex | less

61
boards/eink0.1.json Normal file
View File

@@ -0,0 +1,61 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x4405"
]
],
"usb_product": "TTGO_eink",
"mcu": "nrf52840",
"variant": "eink0.1",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": [
"jlink"
],
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "TTGO eink (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": [
"jlink",
"nrfjprog",
"stlink"
]
},
"url": "FIXME",
"vendor": "TTGO"
}

View File

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 532 B

View File

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 442 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

1
design Submodule

Submodule design added at 73ba05ceef

View File

@@ -1,13 +1,13 @@
# What is Meshtastic?
Meshtastic is a project that lets you use
Meshtastic® is a project that lets you use
inexpensive (\$30 ish) GPS radios as an extensible, long battery life, secure, mesh GPS communicator. These radios are great for hiking, skiing, paragliding - essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other members and any text messages sent to your group chat.
The radios automatically create a mesh to forward packets as needed, so everyone in the group can receive messages from even the furthest member. The radios will optionally work with your phone, but no phone is required.
Note: Questions after reading this? See our new [forum](https://meshtastic.discourse.group/).
### Uses
## Uses
- Outdoor sports where cellular coverage is limited. (Hiking, Skiing, Boating, Paragliding, Gliders etc..)
- Applications where closed source GPS communicators just won't cut it (it is easy to add features for glider pilots etc...)
@@ -17,7 +17,7 @@ Note: Questions after reading this? See our new [forum](https://meshtastic.disco
[![Youtube video demo](desk-video-screenshot.png)](https://www.youtube.com/watch?v=WlNbMbVZlHI "Meshtastic early demo")
### Features
## Features
Not all of these features are fully implemented yet - see **important** disclaimers below. But they should be in by the time we decide to call this project beta (three months?)
@@ -41,7 +41,8 @@ For an detailed walk-through aimed at beginners, we recommend [meshtastic.letsta
### Related Groups
Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).
Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).<br/>
Telegram group for **Russian**-based users [t.me/meshtastic_russia](https://t.me/meshtastic_russia) (Russian language, unofficial).
# Updates

View File

@@ -28,3 +28,78 @@ The maximum output power for North America is +30 dBm ERP.
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are separated by 2.16 MHz with respect to the adjacent channels.
Channel zero starts at 903.08 MHz center frequency.
## Data-rates
### About
Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices.
Considerations:
* Spreading Factor - How much we "spread" our data over time.
* * Each step up in Spreading Factor dobules the airtime to transmit.
* * Each step up in Spreading Factor adds about 2.5db extra link budget.
* Bandwidth - How big of a slice of the spectrum we use.
* * Each doubling of the bandwidth is almost 3db less link budget.
* * Bandwidths less than 31 may be unstable unless you have a high quality Crystal Ossilator.
* Coding Rate - How much redundency we encode to resist noise.
* * Increasing coding rate increases reliability while decrasing data-rate.
* * 4/5 - 1.25x overhead
* * 4/6 - 1.5x overhead
* * 4/7 - 1.75x overhead
* * 4/8 - 2x overhead
### Pre-Defined
We have four predefined channels. These are the most common settings and have been proven to work well:
| Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget |
|:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------|:------------|
| Short range (but fast) | Short Fast | 21.875 kbps | 7 / 128 | 4/5 | 125 | 134dB |
| Medium range (but fast) | Medium | 5.469 kbps | 7 / 128 | 4/5 | 500 | 140dB |
| Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | 153dB |
| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | 154dB |
The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices.
### Custom Settings
You may want to select other channels for your usage. The other settings can be set by using the Python API.
> meshtastic --setchan spread_factor 10 --setchan coding_rate 8 --setchan bandwidth 125
After applying the settings, you will need to restart the device. After your device is restarted, it will generate a new crypto key and you will need to share the newly generated QR Code or URL to all your other devices.
Some example settings:
| Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget | Note |
|:---------------------|:-------------|:------------|:----------|:------------|:-----|
| 37.50 kbps | 6 / 64 | 4/5 | 500 | 129dB | Fastest possible speed |
| 3.125 kbps | 8 / 256 | 4/5 | 125 | 143dB | |
| 1.953 kbps | 8 / 256 | 4/8 | 125 | 143dB | |
| 1.343 kbps | 11 / 2048 | 4/8 | 500 | 145dB | |
| 1.099 kbps | 9 / 512 | 4/8 | 125 | 146dB | |
| 0.814 kbps | 10 / 1024 | 4/6 | 125 | 149dB | |
| 0.610 kbps | 10 / 1024 | 4/8 | 125 | 149dB | |
| 0.488 kbps | 11 / 2048 | 4/6 | 125 | 152dB | |
| 0.336 kbps | 11 / 2048 | 4/8 | 125 | 152dB | |
| 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", low resliance to noise |
| 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", high resliance to noise |
The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices.
These channel settings may have not been tested. Use at your own discression. Share on https://meshtastic.discourse.group with your successes or failure.
## Cryptography
The preshared key used by the devices can be modified.
* 0 = No crypto
* 1 = Default channel key
* 2 - 10 = The default channel key, except with 1 through 9 added to the last byte
Use of cryptography can also be modified. To disable cryptography (maybe useful if you have HAM radio license):
> meshtastic --setchan psk 0

View File

@@ -2,6 +2,106 @@
You probably don't care about this section - skip to the next one.
## 1.2 cleanup & multichannel support:
* DONE call RouterPlugin 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
* DONE fix setchannel in phoneapi.cpp
* 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 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 use get-channels from python
* DONE use get channels & get settings from android
* DONE use set-channel from python
* DONE make settings changes from python work
* DONE pthon should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
* DONE add check for old devices with new API library
* DONE release python api
* DONE release protobufs
* DONE release to developers
* 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 don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* fix 1.1.50 android debug panel display
* DONE test android channel setting
* DONE release to users
* DONE warn in android app about unset regions
* DONE use set-channel from android
* DONE add gui in android app for setting region
* make python tests more exhaustive
* pick default random admin key
* exclude admin channels from URL?
* make a way to share just secondary channels via URL
* use single byte 'well known' channel names for the four default channel names (longslow etc), and for admin, gpio, etc...
* use presence of gpio channel to enable gpio ops, same for serial etc...
* restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
* add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
* stress test multi channel
* investigate @mc-hamster report of heap corruption
* DONE use set-user from android
* use portuino TCP connection to debug with python API
* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered)
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
* DONE warn in python api if we are too new to talk to the device code
* DONE make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning.
* DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well"
* DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions)
* DONE change syncword (now ox2b)
* 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
* confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
* confirm we are still multi hop routing flood broadcasts
* 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
* add support for full DSR unicast delivery
* 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)
* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it?
* only send battery updates a max of once a minute
* add python channel selection for sending
* DONE record recevied channel in meshpacket
* test remote settings operations (confirm it works 3 hops away)
* DONE make a primaryChannel global and properly maintain it when the phone sends setChannel
* DONE move setCrypto call into packet send and packet decode code
* implement 'small location diffs' change
* move battery level out of position?
* DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads
eink:
* new battery level sensing
* measure current draw
* DONE: fix backlight
* USB is busted because of power enable mode?
* OHH BME280! THAT IS GREAT!
* make new screen work, ask for datasheet
* say I think you could ship this
* leds seem busted
* usb doesn't stay connected
* check GPS works
* check GPS fast locking
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
* send PR for bootloader
* fix nrf52 time/date
* send new master bin file
* send email about low power mode problems
* support new flash chip in appload, possibly use low power mode
* swbug! stuck busy tx occurred!
For app cleanup:
* use structured logging to kep logs in ram. Also send logs as packets to api clients

View File

@@ -0,0 +1,13 @@
# Your android application needs updating
Hi.
If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but in this special circumstance it is not. Sorry.
Probably, what this means is that you installed the **alpha test** version of the firmware from github. We really love people helping with development by running the alpha test binaries. But if you aren't ready to sign up for that right now, please go back to [github](https://github.com/meshtastic/Meshtastic-device/releases) and install the latest **not alpha** 1.1.x firmware.
If you **do** intend to run the alpha test please [opt-in](https://play.google.com/apps/testing/com.geeksville.mesh) to receive the alpha test version of the android application.
If you are willing to be an alpha tester, please keep an eye on our forum where we post frequent release notes. We also will actively help you with any bugs you might encounter (along our shared journey of new feature goodness).
If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help.

View File

@@ -13,7 +13,7 @@ the project developers are not cryptography experts. Therefore we ask two things
Based on comments from reviewers (see below), here's some tips for usage of these radios. So you can know the level of protection offered:
* It is pretty likely that the AES256 security is implemented 'correctly' and an observer will not be able to decode your messages.
* Warning: If an attacker is able to get one of the radios in their position, they could either a) extract the channel key from that device or b) use that radio to listen to new communications.
* Warning: If an attacker is able to get one of the radios in their posession, they could either a) extract the channel key from that device or b) use that radio to listen to new communications.
* Warning: If an attacker is able to get the "Channel QR code/URL" that you share with others - that attacker could then be able to read any messages sent on the channel (either tomorrow or in the past - if they kept a raw copy of those broadcast packets)
Possible future areas of work (if there is enough interest - post in our [forum](https://meshtastic.discourse.group) if you want this):
@@ -48,4 +48,4 @@ I'm assuming that meshtastic is being used to hike in places where someone capab
* I think the bigger encryption question is "what does the encryption need to do"? As it stands, an attacker who has yet to capture any of the devices cannot reasonably capture text or location data. An attacker who captures any device in the channel/mesh can read everything going to that device, everything stored on that device, and any other communication within the channel that they captured in encrypted form. If that capability basically matches your expectations, it is suitable for whatever adventures this was intended for, then, based on information publicly available or widely disclosed, the encryption is good. If those properties are distressing (like, device history is deliberately limited and you don't want a device captured today to endanger the information sent over the channel yesterday) we could talk about ways to achieve that (most likely synchronizing time and replacing the key with its own SHA256 every X hours, and ensuring the old key is not retained unnecessarily).
* Two other things to keep in mind are that AES-CTR does not itself provide authenticity (e.g. an attacker can flip bits in replaying data and scramble the resulting plaintext), and that the current scheme gives some hints about transmission in the size. So, if you worry about an adversary deliberately messing-up messages or knowing the length of a text message, it looks like those might be possible.
I'm guessing that the network behaves somewhat like a store-and-forward network - or, at least, that the goal is to avoid establishing a two-way connection to transmit data. I'm afraid I haven't worked with mesh networks much, but remember studying them briefly in school about ten years ago.
I'm guessing that the network behaves somewhat like a store-and-forward network - or, at least, that the goal is to avoid establishing a two-way connection to transmit data. I'm afraid I haven't worked with mesh networks much, but remember studying them briefly in school about ten years ago.

View File

@@ -0,0 +1,89 @@
# About
The ExternalNotification Plugin will allow you to connect a speaker, LED or other device to notify you when a message has been received from the mesh network.
# Configuration
These are the settings that can be configured.
ext_notification_plugin_enabled
Is the plugin enabled?
0 = Disabled (Default)
1 = Enabled
ext_notification_plugin_active
Is your external circuit triggered when our GPIO is low or high?
0 = Active Low (Default)
1 = Active High
ext_notification_plugin_alert_message
Do you want to be notified on an incoming message?
0 = Disabled (Default)
1 = Alert when a text message comes
ext_notification_plugin_alert_bell
Do you want to be notified on an incoming bell?
0 = Disabled (Default)
1 = Alert when the bell character is received
ext_notification_plugin_output
What GPIO is your external circuit attached?
GPIO of the output. (Default = 13)
ext_notification_plugin_output_ms
How long do you want us to trigger your external circuit?
Amount of time in ms for the alert. Default is 1000.
# Usage Notes
For basic usage, start with:
ext_notification_plugin_enabled = 1
ext_notification_plugin_alert_message = 1
Depending on how your external cirtcuit configured is configured, you may need to set the active state to true.
ext_notification_plugin_active = 1
## Alert Types
We support being alerted on two events:
1) Incoming Text Message
2) Incoming Text Message that contains the ascii bell character. At present, only the Python API can send an ascii bell character, but more support may be added in the future.
### Bell Character
The bell character is ASCII 0x07. Include 0x07 anywhere in the text message and with ext_notification_plugin_alert_bell enabled, we will issue an external notification.
# External Hardware
Be mindful of the max current sink and source of the esp32 GPIO. The easiest devices to interface with would be either an LED or Active Buzzer.
Ideas for external hardware:
* LED
* Active Buzzer
* Flame thrower
* Strobe Light
* Siren
# Known Problems
* This won't directly support an passive (normal) speaker as it does not generate any audio wave forms.
* This currently only supports the esp32. Other targets may be possible, I just don't have to test with.
* This plugin only monitors text messages. We won't trigger on any other packet types.
# Need more help?
Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this.
https://meshtastic.discourse.group

View File

@@ -0,0 +1,93 @@
# About
The RangeTest Plugin will help you perform range and coverage tests.
# Configuration
These are the settings that can be configured.
range_test_plugin_enabled
Is the plugin enabled?
0 = Disabled (Default)
1 = Enabled
range_test_plugin_save
If enabled, we will save a log of all received messages to /static/rangetest.csv which you can access from the webserver. We will abort
writing if there is less than 50k of space on the filesystem to prevent filling up the storage.
0 = Disabled (Default)
1 = Enabled
range_test_plugin_sender
Number of seconds to wait between sending packets. Using the long_slow channel configuration, it's best not to go more frequent than once every 60 seconds. You can be more agressive with faster settings. 0 is default which disables sending messages.
# Usage Notes
For basic usage, you will need two devices both with a GPS. A device with a paired phone with GPS may work, I have not tried it.
The first thing to do is to turn on the plugin. With the plugin turned on, the other settings will be available:
range_test_plugin_enabled = 1
If you want to send a message every 60 seconds:
range_test_plugin_sender = 60
To save a log of the messages:
range_test_plugin_save = 1
Recommended settings for a sender at different radio settings:
Long Slow ... range_test_plugin_sender = 60
Long Alt ... range_test_plugin_sender = 30
Medium ... range_test_plugin_sender = 15
Short Fast ... range_test_plugin_sender = 15
## Other things to keep in mind
Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel.
Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results.
# Known Problems
* If turned on, using mesh network will become unwieldly because messages are sent over the same channel as the other messages. See TODO below.
# TODO
* Right now range test messages go over the TEXT_MESSAGE_APP port. We need a toggle to switch to optionally send over RANGE_TEST_APP.
# FAQ
Q: Where is rangetest.csv saved?
A: Turn on the WiFi on your device as either a WiFi client or a WiFi AP. Once you can connect to your device, go to /static and you will see rangetest.csv.
Q: Do I need to have WiFi turned on for the file to be saved?
A: Nope, it'll just work.
Q: Do I need a phone for this plugin?
A: There's no need for a phone.
Q: Can I use this as a message logger?
A: While it's not the intended purpose, sure, why not. Do it!
Q: What will happen if I run out of space on my device?
A: We have a protection in place to keep you from completly filling up your device. This will make sure that other device critical functions will continue to work. We will reserve at least 50k of free space.
Q: What do I do with the rangetest.csv file when I'm done?
A: Go to /static and delete the file.
Q: Can I use this as a sender while on battery power?
A: Yes, but your battery will run down quicker than normal. While sending, we tell the device not to go into low-power mode since it needs to keep to a fairly strict timer.
Q: Why is this operating on incoming messages instead of the existing location discovery protocol?
A: This plugin is still young and currently supports monitoring just one port at a time. I decided to use the existing message port because that is easy to test with. A future version will listen to multiple ports to be more promiscuous.
# Need more help?
Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this.
https://meshtastic.discourse.group

View File

@@ -0,0 +1,40 @@
# About
A simple interface to send messages over the mesh network by sending strings
over a serial port.
Default is to use RX GPIO 16 and TX GPIO 17.
# Basic Usage:
1) Enable the plugin by setting serialplugin_enabled to 1.
2) Set the pins (serialplugin_rxd / serialplugin_rxd) for your preferred RX and TX GPIO pins.
On tbeam, recommend to use:
RXD 35
TXD 15
3) Set serialplugin_timeout to the amount of time to wait before we consider
your packet as "done".
4) (Optional) In SerialPlugin.h set the port to PortNum_TEXT_MESSAGE_APP if you want to
send messages to/from the general text message channel.
5) Connect to your device over the serial interface at 38400 8N1.
6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network.
7) (Optional) Set serialplugin_echo to 1 and any message you send out will be echoed back
to your device.
# TODO (in this order):
* Define a verbose RX mode to report on mesh and packet infomration.
- This won't happen any time soon.
# Known Problems
* Until the plugin is initilized by the startup sequence, the TX pin is in a floating
state. Device connected to that pin may see this as "noise".
* Will not work on NRF and the Linux device targets.
# Need help?
Need help with this plugin? Post your question on the Meshtastic Discourse:
https://meshtastic.discourse.group

View File

@@ -0,0 +1,105 @@
# About
This is a work in progress and is not yet available.
The Store Forward Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network.
Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12 (Long range but Slow).
# Requirements
Initial Requirements:
* Must be installed on a router node.
* * This is an artificial limitation, but is in place to enforce best practices.
* * Router nodes are intended to be always online. If this plugin misses any messages, the reliability of the stored messages will be reduced
* Esp32 Processor based device with external PSRAM. (tbeam v1.0 and tbeamv1.1, maybe others)
# Implementation timeline
Not necessarily in this order:
UC 1) MVP - automagically forward packets to a client that may have missed packets.
UC 2) Client Interface (Web, Android, Python or iOS when that happens) to optionally request packets be resent. This is to support the case where Router has not detected that the client was away. This is because the router will only know you're away if you've been gone for a period of time but will have no way of knowing if you were offline for a short number of minutes. This will cover the case where you have ducked into a cave or you're swapping out your battery.
UC 3) router sends a periodic “heartbeat” to let the clients know theyre part of the main mesh
UC 4) support for a mesh to have multiple routers that have the store & forward functionality (for redundancy)
UC 5) Support for "long term" delayed messages and "short term" delayed messages. Handle the cases slightly different to improve user expierence. A short term delayed message would be a message that was resent becaue a node was not heard from for <5 minutes. A long term delayed message is a message that has not been delivered in >5 minutes.
UC 6) Eventually we could add a "want_store_and_forward" bit to MeshPacket and that could be nicer than whitelists in this plugin. Initially we'd only set that bit in text messages (and any other plugin messages that can cope with this). This change would be backward wire compatible so can add easily later.
UC 7) Currently the way we allocate messages in the device code is super inefficient. It always allocates the worst case message size. Really we should dynamically allocate just the # of bytes we need. This would allow many more MeshPackets to be kept in RAM.
UC 8) We'll want a "delayed" bit in MeshPacket. This will indicate that the message was not received in real time.
# Things to consider
Not all these cases will be initially implemented. It's just a running stream of thoughts to be considered.
## Main Mesh Network with Router
The store and forward plugin is intended to be enabled on a router that designates your "main" mesh network.
## Store and Forward on Multiple Routers
If multiple routers with the plugin are enabled, they should be able to share their stored database amongst each other. This enable resilliancy from one router going offline.
## Fragmented networks - No router
In this case, the mesh network has been fragmented by two client devices leaving the main network.
If two Meshtastic devices walk away from the main mesh, they will be able to message each other but not message the main network. When they return to the main network, they will receive the messages they have missed from the main mesh network.
## Fragmented network - With routers
In this case, we have two routers separate by a great distance, each serving multiple devices. One of the routers have gone offline. This has now created two physically seaprated mesh networks using the same channel configuration.
Q: How do we rejoin both fragmented networks? Do we care about messages that were unrouted between fagments?
## Identifing Delayed Messages
When a message is replayed for a node, identify the packet as "Delayed". This will indicate that the message was not received in real time.
# Router Data Structures
Structure of received messages:
receivedMessages
Port_No
packetID
to
from
rxTimeMsec
data
Structure of nodes and last time we heard from them. This is a record of any packet type.
receivedRecord
From
rxTimeMillis
# General Operation for UC1 - automagically forward packets to a client that may have missed packets
On every handled packet
* Record the sender from and the time we heard from that sender into senderRecord.
On every handled packet
* If the packet is a message, save the messsage into receivedMessages
On every handled packet, if we have not heard from that sender in a period of time greater than timeAway, let's assume that they have been away from the network.
* In this case, we will resend them all the messages they have missed since they were gone
## Expected problems this implementation
* If the client has been away for less than 5 minutes and has received the previously sent message, the client will gracefully ignore it. This is thanks to PacketHistory::wasSeenRecently in PacketHistory.cpp.
* * If the client has been away for more than 5 minutes and we resend packets that they have already received, it's possible they will see duplicate messages. This should be unlikely but is still possible.
# Designed limitations
The Store and Forward plugin will subscribe to specific packet types and channels and only save those. This will both reduce the amount of data we will need to store and reduce the overhead on the network. Eg: There's no need to replay ACK packets nor is there's no need to replay old location packets.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,11 +0,0 @@
# using height of 50 to have 14 pixels beneath icon for text
inkscape -z -e icon.png -w 50 -h 50 icon-24px.svg
convert icon.png -background white -alpha Background ../src/icon.xbm
inkscape -z -e compass.png -w 48 -h 48 location_searching-24px.svg
convert compass.png -background white -alpha Background ../src/compass.xbm
inkscape -z -e face.png -w 13 -h 13 face-24px.svg
inkscape -z -e pin.png -w 13 -h 13 room-24px.svg
convert pin.png -background white -alpha Background ../src/pin.xbm

BIN
images/platformio-erase.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -8,10 +8,10 @@
MemSize = 0x200000
; Define the desired ReadMode. Valid options are FASTREAD, READ2O, READ2IO, READ4O and READ4IO
ReadMode = READ2IO
ReadMode = READ4IO
; Define the desired WriteMode. Valid options are PP, PP2O, PP4O and PP4IO
WriteMode = PP
WriteMode = PP4IO
; Define the desired AddressMode. Valid options are BIT24 and BIT32
AddressMode = BIT24
@@ -38,12 +38,10 @@ DIO0Pin = 12
DIO0Port = 1
DIO1Pin = 13
DIO1Port = 1
;These two pins are not connected, but we must name something
DIO2Pin = 3
DIO2Port = 1
DIO2Pin = 7
DIO2Port = 0
DIO3Pin = 5
DIO3Port = 1
DIO3Port = 0
; Define the Index of the Write In Progress (WIP) bit in the status register. Valid options are in the range of 0 to 7.
WIPIndex = 0
@@ -57,13 +55,8 @@ PPSize = PAGE256
; Numbers can be given in decimal, hex (starting with either 0x or 0X) and binary (starting with either 0b or 0B) formats.
; The custom instructions will be executed in the order found.
; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling the Quad Operation and the High Performance
; mode for the MX25R6435F memory present in the nRF52840 DK.
;InitializationCustomInstruction = 0x06
;InitializationCustomInstruction = 0x01, [0x40, 0, 0x2]
; For MX25R1635F on TTGO board, only two data lines are connected
; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) disabling Quad Operation and the High Performance
; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling Quad Operation and the High Performance
; mode. For normal operation you might want low power mode instead.
InitializationCustomInstruction = 0x06
InitializationCustomInstruction = 0x01, [0x00, 0, 0x2]
InitializationCustomInstruction = 0x01, [0x40, 0, 0x2]

View File

@@ -0,0 +1,69 @@
; nrfjprog.exe configuration file.
; Note: QSPI flash is mapped into memory at address 0x12000000
[DEFAULT_CONFIGURATION]
; Define the capacity of the flash memory device in bytes. Set to 0 if no external memory device is present in your board.
; MX25R1635F is 16Mbit/2Mbyte
MemSize = 0x200000
; Define the desired ReadMode. Valid options are FASTREAD, READ2O, READ2IO, READ4O and READ4IO
ReadMode = READ2IO
; Define the desired WriteMode. Valid options are PP, PP2O, PP4O and PP4IO
WriteMode = PP
; Define the desired AddressMode. Valid options are BIT24 and BIT32
AddressMode = BIT24
; Define the desired Frequency. Valid options are M2, M4, M8, M16 and M32
Frequency = M16
; Define the desired SPI mode. Valid options are MODE0 and MODE3
SpiMode = MODE0
; Define the desired SckDelay. Valid options are in the range 0 to 255
SckDelay = 0x80
; Define the desired IO level for DIO2 and DIO3 during a custom instruction. Valid options are LEVEL_HIGH and LEVEL_LOW
CustomInstructionIO2Level = LEVEL_LOW
CustomInstructionIO3Level = LEVEL_HIGH
; Define the assigned pins for the QSPI peripheral. Valid options are those existing in your device
CSNPin = 15
CSNPort = 1
SCKPin = 14
SCKPort = 1
DIO0Pin = 12
DIO0Port = 1
DIO1Pin = 13
DIO1Port = 1
;These two pins are not connected, but we must name something
DIO2Pin = 3
DIO2Port = 1
DIO3Pin = 5
DIO3Port = 1
; Define the Index of the Write In Progress (WIP) bit in the status register. Valid options are in the range of 0 to 7.
WIPIndex = 0
; Define page size for commands. Valid sizes are PAGE256 and PAGE512.
PPSize = PAGE256
; Custom instructions to send to the external memory after initialization. Format is instruction code plus data to send in between optional brakets.
; These instructions will be executed each time the qspi peripheral is initiated by nrfjprog.
; To improve execution speed on consecutive interations with QSPI, you can run nrfjprog once with custom initialization, and then comment out the lines below.
; Numbers can be given in decimal, hex (starting with either 0x or 0X) and binary (starting with either 0b or 0B) formats.
; The custom instructions will be executed in the order found.
; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling the Quad Operation and the High Performance
; mode for the MX25R6435F memory present in the nRF52840 DK.
;InitializationCustomInstruction = 0x06
;InitializationCustomInstruction = 0x01, [0x40, 0, 0x2]
; For MX25R1635F on TTGO board, only two data lines are connected
; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) disabling Quad Operation and the High Performance
; mode. For normal operation you might want low power mode instead.
InitializationCustomInstruction = 0x06
InitializationCustomInstruction = 0x01, [0x00, 0, 0x2]

View File

@@ -9,13 +9,14 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
;default_envs = tbeam
default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec
;default_envs = tlora-v1
;default_envs = tlora-v2
;default_envs = lora-relay-v1 # nrf board
default_envs = linux # 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 = eink
;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
[common]
; common is not currently used
@@ -33,7 +34,9 @@ extra_scripts = bin/platformio-custom.py
; note: we add src to our include search path so that lmic_project_config can override
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map
build_flags = -Wno-missing-field-initializers
-Wno-format
-Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map
-DHW_VERSION_${sysenv.COUNTRY}
-DHW_VERSION=${sysenv.HW_VERSION}
-DUSE_THREAD_NAMES
@@ -65,7 +68,7 @@ debug_tool = jlink
; monitor adapter_khz 10000
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306
https://github.com/geeksville/OneButton.git ; 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#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
@@ -75,7 +78,7 @@ lib_deps =
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
https://github.com/geeksville/ArduinoThread.git#333ffd09b596977c217ba25da4258f588b462ac6
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
; Common settings for conventional (non Portduino) Ardino targets
[arduino_base]
@@ -104,6 +107,8 @@ build_flags =
lib_deps =
${arduino_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
adafruit/DHT sensor library@^1.4.1
adafruit/Adafruit Unified Sensor@^1.1.4
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore = segger_rtt
@@ -188,7 +193,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/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
@@ -252,7 +257,7 @@ src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
lib_deps =
${arduino_base.lib_deps}
; Prototype eink/nrf52840/sx1262 device
; First prototype eink/nrf52840/sx1262 device
[env:eink]
extends = nrf52_base
board = eink
@@ -266,6 +271,20 @@ lib_deps =
https://github.com/geeksville/EPD_Libraries.git
TFT_eSPI
; First prototype eink/nrf52840/sx1262 device
[env:eink0.1]
extends = nrf52_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 =
${arduino_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 = nrf52_base
@@ -315,7 +334,7 @@ lib_deps =
; The Portduino based sim environment on top of linux
[env:linux]
platform = https://github.com/geeksville/platform-portduino.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/>
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
build_flags = ${arduino_base.build_flags} -O0
framework = arduino
board = linux_x86_64
@@ -328,4 +347,4 @@ lib_deps =
extends = esp32_base
board = genieblocks_lora
build_flags =
${esp32_base.build_flags} -D GENIEBLOCKS
${esp32_base.build_flags} -D GENIEBLOCKS

2
proto

Submodule proto updated: 855da8701e...7c025b9a4d

View File

@@ -84,7 +84,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
/// 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() { return getBattVoltage() > 1000 * chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?

View File

@@ -178,10 +178,11 @@ void PowerFSM_setup()
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
/* To determine if we're externally powered, assumptions
1) If we're powered up and there's no battery, we must be getting power externally.
2) If we detect USB power from the power management chip, we must be getting power externally.
1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise)
2) If we detect USB power from the power management chip, we must be getting power externally.
*/
bool hasPower = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB());
bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB());
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");

View File

@@ -78,9 +78,9 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
r += printf("%02d:%02d:%02d ", hour, min, sec);
r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
} else
r += printf("??:??:?? ");
r += printf("??:??:?? %u ", millis() / 1000);
auto thread = concurrency::OSThread::currentThread;
if(thread) {

View File

@@ -9,6 +9,7 @@ enum class Cmd {
SET_OFF,
ON_PRESS,
START_BLUETOOTH_PIN_SCREEN,
START_FIRMWARE_UPDATE_SCREEN,
STOP_BLUETOOTH_PIN_SCREEN,
STOP_BOOT_SCREEN,
PRINT,

View File

@@ -32,8 +32,10 @@ OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_contro
ThreadName = _name;
if (controller)
controller->add(this);
if (controller) {
bool added = controller->add(this);
assert(added);
}
}
OSThread::~OSThread()

View File

@@ -309,6 +309,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 "tlora-v1-3"
#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 "tlora-v2-1-1.6"
@@ -316,7 +343,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 39
#define GPS_TX_PIN 13
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -327,9 +354,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
#define BUTTON_NEED_PULLUP
#define USE_RF95
@@ -348,15 +374,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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_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 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

View File

@@ -7,6 +7,8 @@
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include "NodeDB.h"
#include "../graphics/Screen.h"
#include "../main.h"
#include <CRC32.h>
#include <Update.h>
@@ -47,8 +49,9 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
// void stopMeshBluetoothService();
// stopMeshBluetoothService();
screen->startFirmwareUpdateScreen();
if (RadioLibInterface::instance)
RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
// writing flash - shut the radio off during updates
}
}

View File

@@ -18,9 +18,6 @@ class ESP32CryptoEngine : public CryptoEngine
mbedtls_aes_context aes;
/// How many bytes in our key
uint8_t keySize = 0;
public:
ESP32CryptoEngine() { mbedtls_aes_init(&aes); }
@@ -35,12 +32,12 @@ 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(size_t numBytes, uint8_t *bytes)
virtual void setKey(const CryptoKey &k)
{
keySize = numBytes;
DEBUG_MSG("Installing AES%d key!\n", numBytes * 8);
if (numBytes != 0) {
auto res = mbedtls_aes_setkey_enc(&aes, bytes, numBytes * 8);
CryptoEngine::setKey(k);
if (key.length != 0) {
auto res = mbedtls_aes_setkey_enc(&aes, key.bytes, key.length * 8);
assert(!res);
}
}
@@ -52,12 +49,12 @@ class ESP32CryptoEngine : public CryptoEngine
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
if (keySize != 0) {
if (key.length > 0) {
uint8_t stream_block[16];
static uint8_t scratch[MAX_BLOCKSIZE];
size_t nc_off = 0;
// DEBUG_MSG("ESP32 encrypt!\n");
// DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetNum, numBytes);
initNonce(fromNode, packetNum);
assert(numBytes <= MAX_BLOCKSIZE);
memcpy(scratch, bytes, numBytes);

View File

@@ -47,6 +47,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t);
return true;
@@ -87,11 +89,17 @@ bool NMEAGPS::lookForLocation()
auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
foundLocation = true;
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
dop * 1e-2, heading * 1e-5);
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
if(longitude == 0)
DEBUG_MSG("Ignoring bogus NMEA position\n");
else {
foundLocation = true;
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
dop * 1e-2, heading * 1e-5);
}
}
return foundLocation;

View File

@@ -122,7 +122,8 @@ bool EInkDisplay::connect()
#endif
#ifdef PIN_EINK_EN
digitalWrite(PIN_EINK_EN, HIGH);
// backlight power, HIGH is backlight on, LOW is off
digitalWrite(PIN_EINK_EN, LOW);
pinMode(PIN_EINK_EN, OUTPUT);
#endif

View File

@@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/TextMessagePlugin.h"
#include "mesh/Channels.h"
#include "target_specific.h"
#include "utils.h"
@@ -64,6 +65,10 @@ 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;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourId[5];
@@ -144,6 +149,30 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int
drawIconScreen("Sleeping...", display, state, x, y);
}
static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
uint8_t plugin_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,
// the passed-state doesn't quite reflect the "current"
// screen, so we have to detect it.
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;
}
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);
}
//DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame);
MeshPlugin &pi = *pluginFrames.at(plugin_frame);
pi.drawFrame(display,state,x,y);
}
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -164,6 +193,20 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, 48 + y, buf);
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Updating");
display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
//display->setFont(FONT_LARGE);
//display->drawString(64 + x, 26 + y, btPIN);
}
/// Draw the last text message we received
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -186,7 +229,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
displayedNodeNum = 0; // Not currently showing a node pane
MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(mp.from);
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
// mp.decoded.variant.data.decoded.bytes);
@@ -201,8 +244,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[96];
assert(mp.decoded.which_payload == SubPacket_data_tag);
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
}
@@ -776,9 +818,6 @@ int32_t Screen::runOnce()
showingBootScreen = false;
}
// Update the screen last, after we've figured out what to show.
debug_info()->setChannelNameStatus(getChannelName());
// Process incoming commands.
for (;;) {
ScreenCmd cmd;
@@ -798,6 +837,9 @@ int32_t Screen::runOnce()
case Cmd::START_BLUETOOTH_PIN_SCREEN:
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
break;
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
handleStartFirmwareUpdateScreen();
break;
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
case Cmd::STOP_BOOT_SCREEN:
setFrames();
@@ -870,6 +912,11 @@ 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();
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)
size_t numnodes = nodeStatus->getNumTotal();
if (numnodes > 0)
@@ -877,6 +924,18 @@ void Screen::setFrames()
size_t numframes = 0;
// put all of the plugin 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
// 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;
}
DEBUG_MSG("Added plugins. numframes: %d\n", numframes);
// If we have a critical fault, show it first
if (myNodeInfo.error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
@@ -905,6 +964,8 @@ void Screen::setFrames()
}
#endif
DEBUG_MSG("Finished building frames. numframes: %d\n", numframes);
ui.setFrames(normalFrames, numframes);
ui.enableAllIndicators();
@@ -928,6 +989,18 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
setFastFramerate();
}
void Screen::handleStartFirmwareUpdateScreen()
{
DEBUG_MSG("showing firmware screen\n");
showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameFirmware};
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
}
void Screen::blink()
{
setFastFramerate();
@@ -993,7 +1066,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
char channelStr[20];
{
concurrency::LockGuard guard(&lock);
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
auto chName = channels.getPrimaryName();
snprintf(channelStr, sizeof(channelStr), "%s", chName);
}
// Display power status
@@ -1200,8 +1274,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x, y, String("USB"));
}
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)), y,
"Mode " + String(channelSettings.modem_config));
auto mode = "Mode " + String(channels.getPrimary().modem_config);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
// Line 2
uint32_t currentMillis = millis();

View File

@@ -39,13 +39,6 @@ class DebugInfo
DebugInfo(const DebugInfo &) = delete;
DebugInfo &operator=(const DebugInfo &) = delete;
/// Sets the name of the channel.
void setChannelNameStatus(const char *name)
{
concurrency::LockGuard guard(&lock);
channelName = name;
}
private:
friend Screen;
@@ -56,8 +49,6 @@ class DebugInfo
void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
std::string channelName;
/// Protects all of internal state.
concurrency::Lock lock;
};
@@ -128,6 +119,14 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
void startFirmwareUpdateScreen()
{
ScreenCmd cmd;
cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN;
enqueueCmd(cmd);
}
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -233,6 +232,7 @@ class Screen : public concurrency::OSThread
void handleOnPress();
void handleStartBluetoothPinScreen(uint32_t pin);
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();

View File

@@ -1,33 +1,20 @@
#define icon_width 50
#define icon_height 50
#define icon_height 28
static char icon_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF,
0xFF, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFE, 0x0F, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00,
0xFF, 0x03, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xFC, 0x07, 0x00, 0xC0, 0x3F,
0xE0, 0x1F, 0xF0, 0x0F, 0x00, 0xC0, 0x1F, 0xFC, 0xFF, 0xE0, 0x0F, 0x00,
0xE0, 0x0F, 0xFF, 0xFF, 0xC3, 0x1F, 0x00, 0xF0, 0x87, 0xFF, 0xFF, 0x87,
0x3F, 0x00, 0xF0, 0xC3, 0xFF, 0xFF, 0x0F, 0x3F, 0x00, 0xF8, 0xE3, 0x7F,
0xF8, 0x1F, 0x7F, 0x00, 0xF8, 0xF1, 0x0F, 0xC0, 0x3F, 0x7E, 0x00, 0xF8,
0xF1, 0x07, 0x80, 0x3F, 0x7E, 0x00, 0xFC, 0xF8, 0x03, 0x00, 0x7F, 0xFC,
0x00, 0xFC, 0xF8, 0x81, 0x07, 0x7E, 0xFC, 0x00, 0x7C, 0xF8, 0xE0, 0x1F,
0x7C, 0xF8, 0x00, 0x7C, 0xFC, 0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0xFC,
0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00,
0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x03, 0x00,
0x00, 0x00, 0x80, 0x7F, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00,
0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, };
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x03,
0x00, 0x00, 0x00, 0x80, 0x07, 0xC0, 0x07, 0x00, 0x00, 0x00, 0xC0, 0x1F,
0xC0, 0x0F, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00,
0xE0, 0x0F, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0, 0x3F, 0x00,
0x00, 0x00, 0xF8, 0x03, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC,
0x7F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0xFE, 0x00, 0x00, 0x00, 0xFE,
0x00, 0xFE, 0xFC, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFC, 0x01, 0x00,
0x00, 0x7F, 0x00, 0x3F, 0xF8, 0x03, 0x00, 0x80, 0x3F, 0x80, 0x3F, 0xF0,
0x07, 0x00, 0x80, 0x3F, 0xC0, 0x1F, 0xF0, 0x07, 0x00, 0xC0, 0x1F, 0xC0,
0x0F, 0xE0, 0x0F, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0xE0,
0x0F, 0xF0, 0x07, 0x80, 0x1F, 0x00, 0xF0, 0x07, 0xF8, 0x03, 0x80, 0x3F,
0x00, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x7F, 0x00, 0xFC, 0x03, 0xFC, 0x01,
0x00, 0x7E, 0x00, 0xFC, 0x01, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00,
0xFE, 0x00, 0x00, 0xFC, 0x01, 0x7E, 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x01,
0x7E, 0x00, 0x3E, 0x00, 0x00, 0xF8, 0x01, 0x38, 0x00, 0x3C, 0x00, 0x00,
0x70, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, };

View File

@@ -305,12 +305,15 @@ void setup()
#ifdef BUTTON_PIN
#ifndef NO_ESP32
// If BUTTON_PIN is held down during the startup process,
// force the device to go into a SoftAP mode.
bool forceSoftAP = 0;
// If the button is connected to GPIO 12, don't enable the ability to use
// meshtasticAdmin on the device.
pinMode(BUTTON_PIN, INPUT);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
delay(10);
#endif
// BUTTON_PIN is pulled high by a 12k resistor.
@@ -356,7 +359,7 @@ void setup()
#endif
// Hello
DEBUG_MSG("Meshtastic swver=%s, hwver=%s\n", optstr(APP_VERSION), optstr(HW_VERSION));
DEBUG_MSG("Meshtastic hwvendor=%s, swver=%s, hwver=%s\n", HW_VENDOR, optstr(APP_VERSION), optstr(HW_VERSION));
#ifndef NO_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
@@ -490,6 +493,8 @@ void setup()
DEBUG_MSG("Warning: Failed to find RF95 radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Radio init succeeded, using RF95 radio\n");
}
}
#endif
@@ -501,6 +506,8 @@ void setup()
DEBUG_MSG("Warning: Failed to find SX1262 radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Radio init succeeded, using SX1262 radio\n");
}
}
#endif
@@ -512,6 +519,8 @@ void setup()
DEBUG_MSG("Warning: Failed to find simulated radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Using SIMULATED radio!\n");
}
}
#endif

297
src/mesh/Channels.cpp Normal file
View File

@@ -0,0 +1,297 @@
#include "Channels.h"
#include "CryptoEngine.h"
#include "NodeDB.h"
#include <assert.h>
/// 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};
Channels channels;
uint8_t xorHash(const uint8_t *p, size_t len)
{
uint8_t code = 0;
for (int i = 0; i < len; i++)
code ^= p[i];
return code;
}
/** Given a channel number, return the (0 to 255) hash for that channel.
* The hash is just an xor of the channel name followed by the channel PSK being used for encryption
* If no suitable channel could be found, return -1
*/
int16_t Channels::generateHash(ChannelIndex channelNum)
{
auto k = getKey(channelNum);
if (k.length < 0)
return -1; // invalid
else {
const char *name = getName(channelNum);
uint8_t h = xorHash((const uint8_t *) name, strlen(name));
h ^= xorHash(k.bytes, k.length);
return h;
}
}
/**
* Validate a channel, fixing any errors as needed
*/
Channel &Channels::fixupChannel(ChannelIndex chIndex)
{
Channel &ch = getByIndex(chIndex);
ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later)
if (!ch.has_settings) {
// No settings! Must disable and skip
ch.role = Channel_Role_DISABLED;
memset(&ch.settings, 0, sizeof(ch.settings));
ch.has_settings = true;
} else {
ChannelSettings &channelSettings = ch.settings;
// Convert the old string "Default" to our new short representation
if (strcmp(channelSettings.name, "Default") == 0)
*channelSettings.name = '\0';
/* Convert any old usage of the defaultpsk into our new short representation.
if (channelSettings.psk.size == sizeof(defaultpsk) &&
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
*channelSettings.psk.bytes = 1;
channelSettings.psk.size = 1;
} */
}
hashes[chIndex] = generateHash(chIndex);
return ch;
}
/**
* Write a default channel to the specified channel index
*/
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.tx_power = 0; // default
uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1;
strcpy(channelSettings.name, "");
ch.has_settings = true;
ch.role = Channel_Role_PRIMARY;
}
CryptoKey Channels::getKey(ChannelIndex chIndex)
{
Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings;
assert(ch.has_settings);
CryptoKey k;
memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros
if (ch.role == Channel_Role_DISABLED) {
k.length = -1; // invalid
} else {
memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size);
k.length = channelSettings.psk.size;
if (k.length == 0) {
if (ch.role == Channel_Role_SECONDARY) {
DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
k = getKey(primaryIndex);
} else
DEBUG_MSG("Warning: User disabled encryption\n");
} else if (k.length == 1) {
// Convert the short single byte variants of psk into variant that can be used more generally
uint8_t pskIndex = k.bytes[0];
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
if (pskIndex == 0)
k.length = 0; // Turn off encryption
else {
memcpy(k.bytes, defaultpsk, sizeof(defaultpsk));
k.length = sizeof(defaultpsk);
// Bump up the last byte of PSK as needed
uint8_t *last = k.bytes + sizeof(defaultpsk) - 1;
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
}
} else if (k.length < 16) {
// Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the
// key with zeros
DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n");
k.length = 16;
} else if (k.length < 32 && k.length != 16) {
// Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the
// key with zeros
DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n");
k.length = 32;
}
}
return k;
}
/** Given a channel index, change to use the crypto key specified by that index
*/
int16_t Channels::setCrypto(ChannelIndex chIndex)
{
CryptoKey k = getKey(chIndex);
if (k.length < 0)
return -1;
else {
// Tell our crypto engine about the psk
crypto->setKey(k);
return getHash(chIndex);
}
}
void Channels::initDefaults()
{
devicestate.channels_count = MAX_NUM_CHANNELS;
for (int i = 0; i < devicestate.channels_count; i++)
fixupChannel(i);
initDefaultChannel(0);
}
void Channels::onConfigChanged()
{
// Make sure the phone hasn't mucked anything up
for (int i = 0; i < devicestate.channels_count; i++) {
Channel &ch = fixupChannel(i);
if (ch.role == Channel_Role_PRIMARY)
primaryIndex = i;
}
}
Channel &Channels::getByIndex(ChannelIndex chIndex)
{
assert(chIndex < devicestate.channels_count);
Channel *ch = devicestate.channels + chIndex;
return *ch;
}
void Channels::setChannel(const Channel &c)
{
Channel &old = getByIndex(c.index);
// if this is the new primary, demote any existing roles
if (c.role == Channel_Role_PRIMARY)
for (int i = 0; i < getNumChannels(); i++)
if (devicestate.channels[i].role == Channel_Role_PRIMARY)
devicestate.channels[i].role = Channel_Role_SECONDARY;
old = c; // slam in the new settings/role
}
const char *Channels::getName(size_t chIndex)
{
// Convert the short "" representation for Default into a usable string
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
// the app fucked up and forgot to set channelSettings.name
if (channelSettings.bandwidth != 0)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
channelName = "Medium";
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongAlt";
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow";
break;
default:
channelName = "Invalid";
break;
}
}
return channelName;
}
/**
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
their nodes
* aren't talking to each other.
*
* This string is of the form "#name-X".
*
* Where X is either:
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
*
* This function will also need to be implemented in GUI apps that talk to the radio.
*
* https://github.com/meshtastic/Meshtastic-device/issues/269
*/
const char *Channels::getPrimaryName()
{
static char buf[32];
char suffix;
// auto channelSettings = getPrimary();
// if (channelSettings.psk.size != 1) {
// We have a standard PSK, so generate a letter based hash.
uint8_t code = getHash(primaryIndex);
suffix = 'A' + (code % 26);
/* } else {
suffix = '0' + channelSettings.psk.bytes[0];
} */
snprintf(buf, sizeof(buf), "#%s-%c", getName(primaryIndex), suffix);
return buf;
}
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before decoding inbound packets
*
* @return false if the channel hash or channel is invalid
*/
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
{
if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
// DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash);
return false;
}
else {
DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
setCrypto(chIndex);
return true;
}
}
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before encoding outbound packets
*
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
*/
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex)
{
return setCrypto(channelIndex);
}

127
src/mesh/Channels.h Normal file
View File

@@ -0,0 +1,127 @@
#pragma once
#include "CryptoEngine.h"
#include "NodeDB.h"
#include "mesh-pb-constants.h"
#include <Arduino.h>
/** A channel number (index into the channel table)
*/
typedef uint8_t ChannelIndex;
/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex)
* Used as a hint to limit which PSKs are considered for packet decoding.
*/
typedef uint8_t ChannelHash;
/** The container/on device API for working with channels */
class Channels
{
/// The index of the primary channel
ChannelIndex primaryIndex = 0;
/** The channel index that was requested for sending/receving. Note: if this channel is a secondary
channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled
no sending or receiving will be allowed */
ChannelIndex activeChannelIndex = 0;
/// the precomputed hashes for each of our channels, or -1 for invalid
int16_t hashes[MAX_NUM_CHANNELS];
public:
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
/** Return the Channel for a specified index */
Channel &getByIndex(ChannelIndex chIndex);
/** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted
* to be primary, force all other channels to be secondary.
*/
void setChannel(const Channel &c);
const char *getName(size_t chIndex);
/** The index of the primary channel */
ChannelIndex getPrimaryIndex() const { return primaryIndex; }
ChannelIndex getNumChannels() { return devicestate.channels_count; }
/**
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different
PSKs.
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why
they their nodes
* aren't talking to each other.
*
* This string is of the form "#name-X".
*
* Where X is either:
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
* OR (for the standard minimially secure PSKs) a number from 0 to 9.
*
* This function will also need to be implemented in GUI apps that talk to the radio.
*
* https://github.com/meshtastic/Meshtastic-device/issues/269
*/
const char *getPrimaryName();
/// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config.
void initDefaults();
/// called when the user has just changed our radio config and we might need to change channel keys
void onConfigChanged();
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before decoding inbound packets
*
* @return false if the channel hash or channel is invalid
*/
bool decryptForHash(ChannelIndex chIndex, ChannelHash channelHash);
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before encoding outbound packets
*
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
*/
int16_t setActiveByIndex(ChannelIndex channelIndex);
private:
/** Given a channel index, change to use the crypto key specified by that index
*
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
*/
int16_t setCrypto(ChannelIndex chIndex);
/** Return the channel index for the specified channel hash, or -1 for not found */
int8_t getIndexByHash(ChannelHash channelHash);
/** Given a channel number, return the (0 to 255) hash for that channel
* If no suitable channel could be found, return -1
*
* called by fixupChannel when a new channel is set
*/
int16_t generateHash(ChannelIndex channelNum);
int16_t getHash(ChannelIndex i) { return hashes[i]; }
/**
* Validate a channel, fixing any errors as needed
*/
Channel &fixupChannel(ChannelIndex chIndex);
/**
* Write a default channel to the specified channel index
*/
void initDefaultChannel(ChannelIndex chIndex);
/**
* Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's
* PSK)
*/
CryptoKey getKey(ChannelIndex chIndex);
};
/// Singleton channel table
extern Channels channels;

View File

@@ -1,9 +1,14 @@
#include "CryptoEngine.h"
#include "configuration.h"
void CryptoEngine::setKey(size_t numBytes, uint8_t *bytes)
void CryptoEngine::setKey(const CryptoKey &k)
{
DEBUG_MSG("WARNING: Using stub crypto - all crypto is sent in plaintext!\n");
DEBUG_MSG("Installing AES%d key!\n", k.length * 8);
/* for(uint8_t i = 0; i < k.length; i++)
DEBUG_MSG("%02x ", k.bytes[i]);
DEBUG_MSG("\n"); */
key = k;
}
/**

View File

@@ -2,6 +2,13 @@
#include <Arduino.h>
struct CryptoKey {
uint8_t bytes[32];
/// # of bytes, or -1 to mean "invalid key - do not use"
int8_t length;
};
/**
* see docs/software/crypto.md for details.
*
@@ -15,6 +22,8 @@ class CryptoEngine
/** Our per packet nonce */
uint8_t nonce[16];
CryptoKey key;
public:
virtual ~CryptoEngine() {}
@@ -27,7 +36,7 @@ class 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(size_t numBytes, uint8_t *bytes);
virtual void setKey(const CryptoKey &k);
/**
* Encrypt a packet

View File

@@ -62,57 +62,59 @@ ErrorCode DSRRouter::send(MeshPacket *p)
return ReliableRouter::send(p);
}
void DSRRouter::sniffReceived(const MeshPacket *p)
void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
// Learn 0 hop routes by just hearing any adjacent nodes
// But treat broadcasts carefully, because when flood broadcasts go out they keep the same original "from". So we want to
// ignore rebroadcasts.
// this will also add records for any ACKs we receive for our messages
if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) {
addRoute(p->from, p->from, 0); // We are adjacent with zero hops
addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops
}
switch (p->decoded.which_payload) {
case SubPacket_route_request_tag:
// Handle route discovery packets (will be a broadcast message)
// FIXME - always start request with the senders nodenum
if (weAreInRoute(p->decoded.route_request)) {
DEBUG_MSG("Ignoring a route request that contains us\n");
} else {
updateRoutes(p->decoded.route_request,
true); // Update our routing tables based on the route that came in so far on this request
if (p->decoded.dest == getNodeNum()) {
// They were looking for us, send back a route reply (the sender address will be first in the list)
sendRouteReply(p->decoded.route_request);
if (c)
switch (c->which_variant) {
case Routing_route_request_tag:
// Handle route discovery packets (will be a broadcast message)
// FIXME - always start request with the senders nodenum
if (weAreInRoute(c->route_request)) {
DEBUG_MSG("Ignoring a route request that contains us\n");
} else {
// They were looking for someone else, forward it along (as a zero hop broadcast)
NodeNum nextHop = getNextHop(p->decoded.dest);
if (nextHop) {
// in our route cache, reply to the requester (the sender address will be first in the list)
sendRouteReply(p->decoded.route_request, nextHop);
updateRoutes(c->route_request,
true); // Update our routing tables based on the route that came in so far on this request
if (p->decoded.dest == getNodeNum()) {
// They were looking for us, send back a route reply (the sender address will be first in the list)
sendRouteReply(c->route_request);
} else {
// Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route)
resendRouteRequest(p);
// They were looking for someone else, forward it along (as a zero hop broadcast)
NodeNum nextHop = getNextHop(p->decoded.dest);
if (nextHop) {
// in our route cache, reply to the requester (the sender address will be first in the list)
sendRouteReply(c->route_request, nextHop);
} else {
// Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route)
resendRouteRequest(p);
}
}
}
break;
case Routing_route_reply_tag:
updateRoutes(c->route_reply, false);
// FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular
// pending packets until ack arrives)
// FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our
// own...
break;
case Routing_error_reason_tag:
removeRoute(p->decoded.dest);
// FIXME: if any pending packets were waiting on this route, delete them
break;
default:
break;
}
break;
case SubPacket_route_reply_tag:
updateRoutes(p->decoded.route_reply, false);
// FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular pending
// packets until ack arrives)
// FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own...
break;
case SubPacket_route_error_tag:
removeRoute(p->decoded.dest);
// FIXME: if any pending packets were waiting on this route, delete them
break;
default:
break;
}
// We simply ignore ACKs - because ReliableRouter will delete the pending packet for us
@@ -131,26 +133,29 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
assert(p->decoded.source); // I think this is guaranteed by now
// FIXME - what if the current packet _is_ a route error packet?
sendRouteError(p, RouteError_NO_ROUTE);
sendRouteError(p, Routing_Error_NO_ROUTE);
}
// FIXME, stop local processing of this packet
}
// handle naks - convert them to route error packets
// All naks are generated locally, because we failed resending the packet too many times
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
if (nakId) {
auto pending = findPendingPacket(p->to, nakId);
if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore
removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node
if (c) {
// handle naks - convert them to route error packets
// All naks are generated locally, because we failed resending the packet too many times
PacketId nakId = c->error_reason ? p->decoded.request_id : 0;
if (nakId) {
auto pending = findPendingPacket(p->to, nakId);
if (pending &&
pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore
removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node
sendRouteError(p, RouteError_GOT_NAK);
sendRouteError(p, Routing_Error_GOT_NAK);
}
}
}
}
return ReliableRouter::sniffReceived(p);
ReliableRouter::sniffReceived(p, c);
}
/**
@@ -230,7 +235,7 @@ void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p)
/**
* Send a route error packet towards whoever originally sent this message
*/
void DSRRouter::sendRouteError(const MeshPacket *p, RouteError err)
void DSRRouter::sendRouteError(const MeshPacket *p, Routing_Error err)
{
DEBUG_MSG("FIXME not implemented sendRouteError\n");
}

View File

@@ -8,7 +8,7 @@ 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);
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
/**
* Send a packet on a suitable interface. This routine will
@@ -70,7 +70,7 @@ class DSRRouter : public ReliableRouter
/**
* Send a route error packet towards whoever originally sent this message
*/
void sendRouteError(const MeshPacket *p, RouteError err);
void sendRouteError(const MeshPacket *p, Routing_Error err);
/** make a copy of p, start discovery, but only if we don't
* already a discovery in progress for that node number. Caller has already scheduled this message for retransmission

View File

@@ -27,11 +27,11 @@ bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
return Router::shouldFilterReceived(p);
}
void FloodingRouter::sniffReceived(const MeshPacket *p)
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) {
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
@@ -48,5 +48,5 @@ void FloodingRouter::sniffReceived(const MeshPacket *p)
}
// handle the packet as normal
Router::sniffReceived(p);
Router::sniffReceived(p, c);
}

View File

@@ -55,5 +55,5 @@ class FloodingRouter : public Router, protected PacketHistory
/**
* Look for broadcasts we need to rebroadcast
*/
virtual void sniffReceived(const MeshPacket *p);
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
};

View File

@@ -0,0 +1,91 @@
#include "MeshPacketQueue.h"
#include <algorithm>
/// @return the priority of the specified packet
inline uint32_t getPriority(MeshPacket *p)
{
auto pri = p->priority;
return pri;
}
/// @return "true" if "p1" is ordered before "p2"
bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2)
{
assert(p1 && p2);
auto p1p = getPriority(p1), p2p = getPriority(p2);
// If priorities differ, use that
// for equal priorities, order by id (older packets have higher priority - this will briefly be wrong when IDs roll over but
// no big deal)
return (p1p != p2p) ? (p1p < p2p) // prefer bigger priorities
: (p1->id >= p2->id); // prefer smaller packet ids
}
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}
/** Some clients might not properly set priority, therefore we fix it here.
*/
void fixPriority(MeshPacket *p)
{
// We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that
// and fix it
if (p->priority == MeshPacket_Priority_UNSET) {
// if acks give high priority
// if a reliable message give a bit higher default priority
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK :
(p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT);
}
}
/** enqueue a packet, return false if full */
bool MeshPacketQueue::enqueue(MeshPacket *p)
{
fixPriority(p);
// fixme if there is something lower priority in the queue that can be deleted to make space, delete that instead
if (size() >= maxLen)
return false;
else {
push(p);
return true;
}
}
MeshPacket *MeshPacketQueue::dequeue()
{
if (empty())
return NULL;
else {
auto p = top();
pop(); // remove the first item
return p;
}
}
// this is kinda yucky, but I'm not sure if all arduino c++ compilers support closuers. And we only have one
// thread that can run at a time - so safe
static NodeNum findFrom;
static PacketId findId;
static bool isMyPacket(MeshPacket *p)
{
return p->id == findId && getFrom(p) == findFrom;
}
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
{
findFrom = from;
findId = id;
auto it = std::find_if(this->c.begin(), this->c.end(), isMyPacket);
if (it != this->c.end()) {
auto p = *it;
this->c.erase(it);
std::make_heap(this->c.begin(), this->c.end(), this->comp);
return p;
} else {
return NULL;
}
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "MeshTypes.h"
#include <assert.h>
#include <queue>
// this is an strucure which implements the
// operator overloading
struct CompareMeshPacket {
bool operator()(MeshPacket *p1, MeshPacket *p2);
};
/**
* A priority queue of packets.
*
*/
class MeshPacketQueue : public std::priority_queue<MeshPacket *, std::vector<MeshPacket *>, CompareMeshPacket>
{
size_t maxLen;
public:
MeshPacketQueue(size_t _maxLen);
/** enqueue a packet, return false if full */
bool enqueue(MeshPacket *p);
// bool isEmpty();
MeshPacket *dequeue();
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */
MeshPacket *remove(NodeNum from, PacketId id);
};

View File

@@ -1,23 +1,28 @@
#include "MeshPlugin.h"
#include "NodeDB.h"
#include "MeshService.h"
#include "NodeDB.h"
#include <assert.h>
std::vector<MeshPlugin *> *MeshPlugin::plugins;
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
* the RoutingPlugin to avoid sending redundant acks
*/
MeshPacket *MeshPlugin::currentReply;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
if(!plugins)
if (!plugins)
plugins = new std::vector<MeshPlugin *>();
plugins->push_back(this);
}
void MeshPlugin::setup() {
}
void MeshPlugin::setup() {}
MeshPlugin::~MeshPlugin()
{
@@ -28,51 +33,100 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
{
// DEBUG_MSG("In call plugins\n");
bool pluginFound = false;
assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point?
currentReply = NULL; // No reply yet
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB.getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
pi.currentRequest = &mp;
if (pi.wantPortnum(mp.decoded.data.portnum)) {
// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
if (wantsPacket) {
pluginFound = true;
bool handled = pi.handleReceived(mp);
// Possibly send replies
if (mp.decoded.want_response)
pi.sendResponse(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 considered
DEBUG_MSG("Plugin %s handled=%d\n", pi.name, handled);
if (handled)
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because
// currently when the phone sends things, it sends things using the local node ID as the from address. A better
// solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like 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);
} else {
DEBUG_MSG("Plugin %s considered\n", pi.name);
}
if (handled) {
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
break;
}
}
pi.currentRequest = NULL;
}
if(!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.data.portnum);
if(currentReply) {
DEBUG_MSG("Sending response\n");
service.sendToMesh(currentReply);
currentReply = NULL;
}
if (!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
}
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
* is optional
*/
void MeshPlugin::sendResponse(const MeshPacket &req) {
void MeshPlugin::sendResponse(const MeshPacket &req)
{
auto r = allocReply();
if(r) {
DEBUG_MSG("Sending response\n");
if (r) {
setReplyTo(r, req);
service.sendToMesh(r);
}
else {
DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
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");
}
}
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
/** 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) {
p->to = to.from;
p->want_ack = to.want_ack;
}
*/
void setReplyTo(MeshPacket *p, const MeshPacket &to)
{
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
p->to = getFrom(&to);
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false;
if(p->priority == MeshPacket_Priority_UNSET)
p->priority = MeshPacket_Priority_RELIABLE;
p->decoded.request_id = to.id;
}
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
{
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);
}
}
return pluginsWithUIFrames;
}

View File

@@ -2,6 +2,8 @@
#include "mesh/MeshTypes.h"
#include <vector>
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
/** A baseclass for any mesh "plugin".
*
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
@@ -14,7 +16,7 @@
*/
class MeshPlugin
{
static std::vector<MeshPlugin *> *plugins;
static std::vector<MeshPlugin *> *plugins;
public:
/** Constructor
@@ -28,9 +30,19 @@ class MeshPlugin
*/
static void callPlugins(const MeshPacket &mp);
static std::vector<MeshPlugin *> GetMeshPluginsWithUIFrames();
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
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 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.
*/
bool isPromiscuous = false;
/**
* If this plugin is currently handling a request currentRequest will be preset
* to the packet with the request. This is mostly useful for reply handlers.
@@ -49,7 +61,7 @@ class MeshPlugin
/**
* @return true if you want to receive the specified portnum
*/
virtual bool wantPortnum(PortNum p) = 0;
virtual bool wantPacket(const MeshPacket *p) = 0;
/** Called to handle a particular incoming message
@@ -61,8 +73,22 @@ class MeshPlugin
* so that subclasses can (optionally) send a response back to the original sender. */
virtual MeshPacket *allocReply() { return NULL; }
/***
* @return true if you want to be alloced a UI screen frame
*/
virtual bool wantUIFrame() { return false; }
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
*/
static MeshPacket *currentReply;
friend class ReliableRouter;
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
* to generate the reply message, and if !NULL that message will be delivered to whoever sent req

View File

@@ -13,8 +13,8 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/PositionPlugin.h"
#include "plugins/NodeInfoPlugin.h"
#include "plugins/PositionPlugin.h"
#include "power.h"
/*
@@ -51,23 +51,6 @@ MeshService service;
#include "Router.h"
static int32_t sendOwnerCb()
{
static uint32_t currentGeneration;
// If we changed channels, ask everyone else for their latest info
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
assert(nodeInfoPlugin);
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
}
static concurrency::Periodic *sendOwnerPeriod;
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
{
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
@@ -75,18 +58,13 @@ MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
void MeshService::init()
{
sendOwnerPeriod = new concurrency::Periodic("SendOwner", sendOwnerCb);
sendOwnerPeriod->setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
// moved much earlier in boot (called from setup())
// nodeDB.init();
if (gps)
gpsObserver.observe(&gps->newStatus);
packetReceivedObserver.observe(&router->notifyPacketReceived);
}
int MeshService::handleFromRadio(const MeshPacket *mp)
{
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
@@ -136,7 +114,8 @@ bool MeshService::reloadConfig()
void MeshService::reloadOwner()
{
assert(nodeInfoPlugin);
nodeInfoPlugin->sendOurNodeInfo();
if(nodeInfoPlugin)
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -147,8 +126,12 @@ void MeshService::reloadOwner()
*/
void MeshService::handleToRadio(MeshPacket &p)
{
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
p.from = nodeDB.getNodeNum();
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
p.from = 0;
} else {
// p.from = nodeDB.getNodeNum();
}
if (p.id == 0)
p.id = generatePacketId(); // If the phone didn't supply one, then pick one
@@ -169,22 +152,16 @@ void MeshService::handleToRadio(MeshPacket &p)
}
}
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool MeshService::cancelSending(PacketId id)
{
return router->cancelSending(nodeDB.getNodeNum(), id);
}
void MeshService::sendToMesh(MeshPacket *p)
{
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
// devices can get time.
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag &&
p->decoded.position.time) {
if (getRTCQuality() < RTCQualityGPS) {
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
p->decoded.position.time = 0;
} else
DEBUG_MSG("Providing time to mesh %u\n", p->decoded.position.time);
}
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
router->sendLocal(p);
}
@@ -194,29 +171,36 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
assert(positionPlugin && nodeInfoPlugin);
if (node->has_position)
positionPlugin->sendOurPosition(dest, wantReplies);
else
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
if (node->has_position) {
if(positionPlugin) {
DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
}
}
else {
if(nodeInfoPlugin) {
DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
}
}
NodeInfo *MeshService::refreshMyNodeInfo() {
NodeInfo *MeshService::refreshMyNodeInfo()
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
// We might not have a position yet for our local node, in that case, at least try to send the time
if(!node->has_position) {
if (!node->has_position) {
memset(&node->position, 0, sizeof(node->position));
node->has_position = true;
}
Position &position = node->position;
// Update our local node info with our position (even if we don't decide to update anyone else)
position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
position.time =
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
position.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(position.battery_level);
@@ -235,11 +219,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
pos.altitude = gps->altitude;
pos.latitude_i = gps->latitude;
pos.longitude_i = gps->longitude;
}
else {
} else {
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
if(!radioConfig.preferences.fixed_position) {
if (radioConfig.preferences.fixed_position) {
DEBUG_MSG("WARNING: Using fixed position\n");
} else {
// throw away old position
@@ -249,27 +232,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
}
}
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.time, pos.latitude_i, pos.battery_level);
// Update our current position in the local DB
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
lastGpsSend = now;
static uint32_t currentGeneration;
// If we changed channels, ask everyone else for their latest info
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
assert(positionPlugin);
positionPlugin->sendOurPosition(NODENUM_BROADCAST, requestReplies);
}
return 0;
}

View File

@@ -19,8 +19,6 @@ class MeshService
{
CallbackObserver<MeshService, const meshtastic::GPSStatus *> gpsObserver =
CallbackObserver<MeshService, const meshtastic::GPSStatus *>(this, &MeshService::onGPSChanged);
CallbackObserver<MeshService, const MeshPacket *> packetReceivedObserver =
CallbackObserver<MeshService, const MeshPacket *>(this, &MeshService::handleFromRadio);
/// received packets waiting for the phone to process them
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
@@ -79,6 +77,9 @@ class MeshService
/// cache
void sendToMesh(MeshPacket *p);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id);
/// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo();
@@ -88,9 +89,10 @@ class MeshService
/// returns 0 to allow futher processing
int onGPSChanged(const meshtastic::GPSStatus *arg);
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
/// 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;
};
extern MeshService service;

View File

@@ -13,6 +13,9 @@ typedef uint32_t PacketId; // A packet sequence number
#define ERRNO_OK 0
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
#define ERRNO_DISABLED 34 // the itnerface is disabled
#define ERRNO_TOO_LARGE 35
#define ERRNO_NO_CHANNEL 36
/**
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
@@ -29,4 +32,10 @@ typedef uint32_t PacketId; // A packet sequence number
typedef int ErrorCode;
/// Alloc and free packets to our global, ISR safe pool
extern Allocator<MeshPacket> &packetPool;
extern Allocator<MeshPacket> &packetPool;
/**
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node.
* If from is zero this function returns our node number instead
*/
NodeNum getFrom(const MeshPacket *p);

View File

@@ -4,6 +4,7 @@
#include "FS.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "FSCommon.h"
#include "GPS.h"
@@ -15,6 +16,7 @@
#include "Router.h"
#include "configuration.h"
#include "error.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include <pb_decode.h>
#include <pb_encode.h>
@@ -29,7 +31,6 @@ NodeDB nodeDB;
EXT_RAM_ATTR DeviceState devicestate;
MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig &radioConfig = devicestate.radio;
ChannelSettings &channelSettings = radioConfig.channel_settings;
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel.
@@ -63,141 +64,35 @@ static uint8_t ourMacAddr[6];
*/
NodeNum displayedNodeNum;
/// A usable (but bigger) version of the channel name in the channelSettings object
const char *channelName;
/// A usable psk - which has been constructed based on the (possibly short psk) in channelSettings
static uint8_t activePSK[32];
static uint8_t activePSKSize;
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
/**
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
their nodes
* aren't talking to each other.
*
* This string is of the form "#name-X".
*
* Where X is either:
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
* OR (for the standard minimially secure PSKs) a number from 0 to 9.
*
* This function will also need to be implemented in GUI apps that talk to the radio.
*
* https://github.com/meshtastic/Meshtastic-device/issues/269
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node.
* If from is zero this function returns our node number instead
*/
const char *getChannelName()
{
static char buf[32];
char suffix;
if (channelSettings.psk.size != 1) {
// We have a standard PSK, so generate a letter based hash.
uint8_t code = 0;
for (int i = 0; i < activePSKSize; i++)
code ^= activePSK[i];
suffix = 'A' + (code % 26);
} else {
suffix = '0' + channelSettings.psk.bytes[0];
}
snprintf(buf, sizeof(buf), "#%s-%c", channelName, suffix);
return buf;
NodeNum getFrom(const MeshPacket *p) {
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
}
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
bool NodeDB::resetRadioConfig()
{
bool didFactoryReset = false;
radioGeneration++;
/// 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};
if (radioConfig.preferences.factory_reset) {
DEBUG_MSG("Performing factory reset!\n");
installDefaultDeviceState();
didFactoryReset = true;
} else if (!channelSettings.psk.size) {
DEBUG_MSG("Setting default preferences!\n");
} else if (devicestate.channels_count == 0) {
DEBUG_MSG("Setting default channel and radio preferences!\n");
channels.initDefaults();
radioConfig.has_channel_settings = true;
radioConfig.has_preferences = true;
// 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.tx_power = 0; // default
uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1;
strcpy(channelSettings.name, "");
}
// Convert the old string "Default" to our new short representation
if (strcmp(channelSettings.name, "Default") == 0)
*channelSettings.name = '\0';
// Convert the short "" representation for Default into a usable string
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
// the app fucked up and forgot to set channelSettings.name
if (channelSettings.bandwidth != 0)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
channelName = "Medium";
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongAlt";
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow";
break;
default:
channelName = "Invalid";
break;
}
}
// Convert any old usage of the defaultpsk into our new short representation.
if (channelSettings.psk.size == sizeof(defaultpsk) &&
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
*channelSettings.psk.bytes = 1;
channelSettings.psk.size = 1;
}
// Convert the short single byte variants of psk into variant that can be used more generally
memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size);
activePSKSize = channelSettings.psk.size;
if (activePSKSize == 1) {
uint8_t pskIndex = activePSK[0];
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
if (pskIndex == 0)
activePSKSize = 0; // Turn off encryption
else {
memcpy(activePSK, defaultpsk, sizeof(defaultpsk));
activePSKSize = sizeof(defaultpsk);
// Bump up the last byte of PSK as needed
uint8_t *last = activePSK + sizeof(defaultpsk) - 1;
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
}
}
// Tell our crypto engine about the psk
crypto->setKey(activePSKSize, activePSK);
channels.onConfigChanged();
// temp hack for quicker testing
// devicestate.no_save = true;
@@ -236,7 +131,6 @@ void NodeDB::installDefaultDeviceState()
devicestate.has_my_node = true;
devicestate.has_radio = true;
devicestate.has_owner = true;
devicestate.radio.has_channel_settings = true;
devicestate.radio.has_preferences = true;
devicestate.node_db_count = 0;
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
@@ -250,20 +144,19 @@ void NodeDB::installDefaultDeviceState()
// Init our blank owner info to reasonable defaults
getMacAddr(ourMacAddr);
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4],
ourMacAddr[5]);
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Set default owner name
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid
// owner.short_name now
pickNewNodeNum(); // based on macaddr now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff));
sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Restore region if possible
if (oldRegionCode != RegionCode_Unset)
radioConfig.preferences.region = oldRegionCode;
if (oldRegion.length())
if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date
strcpy(myNodeInfo.region, oldRegion.c_str());
}
@@ -275,17 +168,14 @@ void NodeDB::init()
loadFromDisk();
// saveToDisk();
// We set node_num and packet_id _after_ loading from disk, because we always want to use the values this
// rom was compiled for, not what happens to be in the save file.
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand
myNodeInfo.error_code =
CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash)
myNodeInfo.error_address = 0;
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
myNodeInfo.min_app_version = 20200; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
@@ -475,7 +365,17 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
info->position = p;
// Be careful to only update fields that have been set by the sender
// A lot of position reports don't have time populated. In that case, be careful to not blow away the time we
// recorded based on the packet rxTime
if (!info->position.time && p.time)
info->position.time = p.time;
if(p.battery_level)
info->position.battery_level = p.battery_level;
if (p.latitude_i || p.longitude_i) {
info->position.latitude_i = p.latitude_i;
info->position.longitude_i = p.longitude_i;
}
info->has_position = true;
updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed
@@ -511,11 +411,10 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp)
{
if (mp.which_payload == MeshPacket_decoded_tag) {
const SubPacket &p = mp.decoded;
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
NodeInfo *info = getOrCreateNode(mp.from);
NodeInfo *info = getOrCreateNode(getFrom(&mp));
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
info->has_position = true; // at least the time is valid
@@ -523,31 +422,6 @@ void NodeDB::updateFrom(const MeshPacket &mp)
}
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
switch (p.which_payload) {
case SubPacket_position_tag: {
// handle a legacy position packet
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from);
updatePosition(mp.from, p.position);
break;
}
case SubPacket_data_tag: {
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum())
MeshPlugin::callPlugins(mp);
break;
}
case SubPacket_user_tag: {
DEBUG_MSG("WARNING: Processing a (deprecated) user packet from %d\n", mp.from);
updateUser(mp.from, p.user);
break;
}
default: {
notifyObservers(); // If the node counts have changed, notify observers
}
}
}
}
@@ -583,7 +457,12 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address)
{
DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address);
// Print error to screen and serial port
String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str());
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
// Record error to DB
myNodeInfo.error_code = code;
myNodeInfo.error_address = address;
myNodeInfo.error_count++;

View File

@@ -11,9 +11,7 @@
extern DeviceState devicestate;
extern MyNodeInfo &myNodeInfo;
extern RadioConfig &radioConfig;
extern ChannelSettings &channelSettings;
extern User &owner;
extern const char *channelName;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
uint32_t sinceLastSeen(const NodeInfo *n);
@@ -130,23 +128,6 @@ extern NodeNum displayedNodeNum;
extern NodeDB nodeDB;
/**
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
their nodes
* aren't talking to each other.
*
* This string is of the form "#name-XY".
*
* Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together.
* Y is not yet used but should eventually indicate 'speed/range' of the link
*
* This function will also need to be implemented in GUI apps that talk to the radio.
*
* https://github.com/meshtastic/Meshtastic-device/issues/269
*/
const char *getChannelName();
/*
If is_router is set, we use a number of different default values
@@ -173,7 +154,7 @@ const char *getChannelName();
*/
// Our delay functions check for this for times that should never expire
#define DELAY_FOREVER 0xffffffff
#define NODE_DELAY_FOREVER 0xffffffff
#define IF_ROUTER(routerVal, normalVal) (radioConfig.preferences.is_router ? (routerVal) : (normalVal))
@@ -187,8 +168,8 @@ PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60))
PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60))
PREF_GET(screen_on_secs, 60)
PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(phone_sds_timeout_sec, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(phone_sds_timeout_sec, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(sds_secs, 365 * 24 * 60 * 60)
// We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between
@@ -202,3 +183,4 @@ PREF_GET(min_wake_secs, 10)
* might have changed is incremented. Allows others to detect they might now be on a new channel.
*/
extern uint32_t radioGeneration;

View File

@@ -26,7 +26,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
// DEBUG_MSG("Deleting old broadcast record %d\n", i);
recentPackets.erase(recentPackets.begin() + i); // delete old record
} else {
if (r.id == p->id && r.sender == p->from) {
if (r.id == p->id && r.sender == getFrom(p)) {
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
// Update the time on this record to now
@@ -43,7 +43,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
if (withUpdate) {
PacketRecord r;
r.id = p->id;
r.sender = p->from;
r.sender = getFrom(p);
r.rxTimeMsec = now;
recentPackets.push_back(r);
printPacket("Adding packet record", p);

View File

@@ -4,6 +4,7 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "Channels.h"
#include <assert.h>
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
@@ -58,16 +59,17 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
}
// return (lastContactMsec != 0) &&
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_variant) {
switch (toRadioScratch.which_payloadVariant) {
case ToRadio_packet_tag: {
MeshPacket &p = toRadioScratch.variant.packet;
MeshPacket &p = toRadioScratch.packet;
printPacket("PACKET FROM PHONE", &p);
service.handleToRadio(p);
break;
}
case ToRadio_want_config_id_tag:
config_nonce = toRadioScratch.variant.want_config_id;
config_nonce = toRadioScratch.want_config_id;
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
state = STATE_SEND_MY_INFO;
@@ -77,16 +79,6 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
// this will break once we have multiple instances of PhoneAPI running independently
break;
case ToRadio_set_owner_tag:
DEBUG_MSG("Client is setting owner\n");
handleSetOwner(toRadioScratch.variant.set_owner);
break;
case ToRadio_set_radio_tag:
DEBUG_MSG("Client is setting radio\n");
handleSetRadio(toRadioScratch.variant.set_radio);
break;
default:
DEBUG_MSG("Error: unexpected ToRadio variant\n");
break;
@@ -131,26 +123,13 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
? true
: (gps && gps->isConnected()); // Update with latest GPS connect info
fromRadioScratch.which_variant = FromRadio_my_info_tag;
fromRadioScratch.variant.my_info = myNodeInfo;
state = STATE_SEND_RADIO;
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_NODEINFO;
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break;
case STATE_SEND_RADIO:
fromRadioScratch.which_variant = FromRadio_radio_tag;
fromRadioScratch.variant.radio = radioConfig;
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
fromRadioScratch.variant.radio.preferences.ls_secs = getPref_ls_secs();
state = STATE_SEND_NODEINFO;
break;
case STATE_SEND_NODEINFO: {
const NodeInfo *info = nodeInfoForPhone;
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
@@ -158,8 +137,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
if (info) {
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
info->user.long_name);
fromRadioScratch.which_variant = FromRadio_node_info_tag;
fromRadioScratch.variant.node_info = *info;
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
fromRadioScratch.node_info = *info;
// Stay in current state until done sending nodeinfos
} else {
DEBUG_MSG("Done sending nodeinfos\n");
@@ -171,8 +150,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
case STATE_SEND_COMPLETE_ID:
fromRadioScratch.which_variant = FromRadio_config_complete_id_tag;
fromRadioScratch.variant.config_complete_id = config_nonce;
fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag;
fromRadioScratch.config_complete_id = config_nonce;
config_nonce = 0;
state = STATE_SEND_PACKETS;
break;
@@ -185,8 +164,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
printPacket("phone downloaded packet", packetForPhone);
// Encapsulate as a FromRadio packet
fromRadioScratch.which_variant = FromRadio_packet_tag;
fromRadioScratch.variant.packet = *packetForPhone;
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
fromRadioScratch.packet = *packetForPhone;
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
packetForPhone = NULL;
@@ -198,11 +177,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
// Do we have a message from the mesh?
if (fromRadioScratch.which_variant != 0) {
if (fromRadioScratch.which_payloadVariant != 0) {
// Encapsulate as a FromRadio packet
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_variant);
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
DEBUG_MSG(", %d bytes\n", numbytes);
// DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes);
return numbytes;
}
@@ -227,9 +205,6 @@ bool PhoneAPI::available()
nodeInfoForPhone = nodeDB.readNextInfo();
return true; // Always say we have something, because we might need to advance our state machine
case STATE_SEND_RADIO:
return true;
case STATE_SEND_COMPLETE_ID:
return true;
@@ -250,41 +225,6 @@ bool PhoneAPI::available()
return false;
}
//
// The following routines are only public for now - until the rev1 bluetooth API is removed
//
void PhoneAPI::handleSetOwner(const User &o)
{
int changed = 0;
if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name);
strcpy(owner.long_name, o.long_name);
}
if (*o.short_name) {
changed |= strcmp(owner.short_name, o.short_name);
strcpy(owner.short_name, o.short_name);
}
if (*o.id) {
changed |= strcmp(owner.id, o.id);
strcpy(owner.id, o.id);
}
if (changed) // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner();
}
void PhoneAPI::handleSetRadio(const RadioConfig &r)
{
radioConfig = r;
bool didReset = service.reloadConfig();
if (didReset) {
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
}
}
/**
* Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool
*/

View File

@@ -23,7 +23,7 @@ class PhoneAPI
STATE_LEGACY, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_RADIO,
// 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
STATE_SEND_COMPLETE_ID,
@@ -83,13 +83,6 @@ class PhoneAPI
*/
bool available();
//
// The following routines are only public for now - until the rev1 bluetooth API is removed
//
void handleSetOwner(const User &o);
void handleSetRadio(const RadioConfig &r);
protected:
/// Are we currently connected to a client?
bool isConnected = false;

View File

@@ -8,7 +8,7 @@
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
* and avoid a bunch of boilerplate code.
*/
template <class T> class ProtobufPlugin : private SinglePortPlugin
template <class T> class ProtobufPlugin : protected SinglePortPlugin
{
const pb_msgdesc_t *fields;
@@ -25,8 +25,11 @@ template <class T> class ProtobufPlugin : private SinglePortPlugin
/**
* Handle a received message, the data field in the message is already decoded and is provided
*
* In general decoded will always be !NULL. But in some special applications (where you have handling packets
* for multiple port numbers, decoding will ONLY be attempted for packets where the portnum matches our expected ourPortNum.
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T &decoded) = 0;
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T *decoded) = 0;
/**
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.
@@ -38,8 +41,8 @@ template <class T> class ProtobufPlugin : private SinglePortPlugin
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocDataPacket();
p->decoded.data.payload.size =
pb_encode_to_bytes(p->decoded.data.payload.bytes, sizeof(p->decoded.data.payload.bytes), fields, &payload);
p->decoded.payload.size =
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), fields, &payload);
// DEBUG_MSG("did encode\n");
return p;
}
@@ -54,13 +57,19 @@ template <class T> class ProtobufPlugin : private SinglePortPlugin
// 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.
auto &p = mp.decoded.data;
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
auto &p = mp.decoded;
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum, p.payload.size);
T scratch;
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
return handleReceivedProtobuf(mp, scratch);
T *decoded = NULL;
if(mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
decoded = &scratch;
else
DEBUG_MSG("Error decoding protobuf plugin!\n");
}
return false; // Let others look at this message also if they want
return handleReceivedProtobuf(mp, decoded);
}
};

View File

@@ -1,10 +1,12 @@
#include "configuration.h"
#include "RadioInterface.h"
#include "Channels.h"
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "assert.h"
#include "configuration.h"
#include "Router.h"
#include "sleep.h"
#include <assert.h>
#include <pb_decode.h>
@@ -23,9 +25,27 @@ const RegionInfo regions[] = {
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
};
/* 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()
@@ -36,7 +56,7 @@ void initRegion()
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
myNodeInfo.num_bands = myRegion->numChannels; // Tell our android app how many channels we have
}
/**
@@ -83,7 +103,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
{
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
return getPacketTime(pl);
@@ -117,27 +137,13 @@ uint32_t RadioInterface::getTxDelayMsec()
void printPacket(const char *prefix, const MeshPacket *p)
{
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
p->hop_limit);
if (p->which_payload == MeshPacket_decoded_tag) {
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
p->want_ack, p->hop_limit, p->channel);
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
auto &s = p->decoded;
switch (s.which_payload) {
case SubPacket_data_tag:
DEBUG_MSG(" Portnum=%d", s.data.portnum);
break;
case SubPacket_position_tag:
DEBUG_MSG(" Payload:Position");
break;
case SubPacket_user_tag:
DEBUG_MSG(" Payload:User");
break;
case 0:
DEBUG_MSG(" Payload:None");
break;
default:
DEBUG_MSG(" Payload:%d", s.which_payload);
break;
}
DEBUG_MSG(" Portnum=%d", s.portnum);
if (s.want_response)
DEBUG_MSG(" WANTRESP");
@@ -147,10 +153,11 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (s.dest != 0)
DEBUG_MSG(" dest=%08x", s.dest);
if (s.which_ack == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ack.success_id);
else if (s.which_ack == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ack.fail_id);
/* now inside Data and therefore kinda opaque
if (s.which_ackVariant == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
else if (s.which_ackVariant == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); */
} else {
DEBUG_MSG(" encrypted");
}
@@ -161,12 +168,15 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (p->rx_snr != 0.0) {
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
}
if (p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority);
DEBUG_MSG(")\n");
}
RadioInterface::RadioInterface()
{
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
// Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
@@ -209,6 +219,38 @@ unsigned long hash(const char *str)
return hash;
}
/**
* Save our frequency for later reuse.
*/
void RadioInterface::saveFreq(float freq)
{
savedFreq = freq;
}
/**
* Save our channel for later reuse.
*/
void RadioInterface::saveChannelNum(uint32_t channel_num)
{
savedChannelNum = channel_num;
}
/**
* Save our frequency for later reuse.
*/
float RadioInterface::getFreq()
{
return savedFreq;
}
/**
* Save our channel for later reuse.
*/
uint32_t RadioInterface::getChannelNum()
{
return savedChannelNum;
}
/**
* Pull our channel settings etc... from protobufs to the dumb interface settings
*/
@@ -217,6 +259,7 @@ void RadioInterface::applyModemConfig()
// Set up default configuration
// No Sync Words in LORA mode
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
@@ -261,18 +304,20 @@ void RadioInterface::applyModemConfig()
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
int channel_num =
(channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels;
const char *channelName = channels.getName(channels.getPrimaryIndex());
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels;
freq = myRegion->freq + myRegion->spacing * channel_num;
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num,
power);
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, 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 channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", freq);
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
saveChannelNum(channel_num);
saveFreq(freq);
}
/**
@@ -305,6 +350,10 @@ void RadioInterface::deliverToReceiver(MeshPacket *p)
{
assert(rxDest);
assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
if (router)
router->setReceivedMessage();
}
/***
@@ -315,7 +364,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
assert(!sendingPacket);
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
lastTxStart = millis();
@@ -324,6 +373,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
h->from = p->from;
h->to = p->to;
h->id = p->id;
h->channel = p->channel;
assert(p->hop_limit <= HOP_MAX);
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);

View File

@@ -29,6 +29,9 @@ typedef struct {
* The bottom three bits of flags are use to store hop_limit when sent over the wire.
**/
uint8_t flags;
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
uint8_t channel;
} PacketHeader;
/**
@@ -54,6 +57,8 @@ class RadioInterface
uint32_t shortPacketMsec;
protected:
bool disabled = false;
float bw = 125;
uint8_t sf = 9;
uint8_t cr = 7;
@@ -98,6 +103,9 @@ class RadioInterface
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() { return true; }
/// Disable this interface (while disabled, no packets can be sent or received)
void disable() { disabled = true; sleep(); }
/**
* Send a packet (possibly by enquing in a private fifo). This routine will
* later free() the packet to pool. This routine is not allowed to stall.
@@ -105,6 +113,9 @@ class RadioInterface
*/
virtual ErrorCode send(MeshPacket *p) = 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) { return false; }
// methods from radiohead
/// Initialise the Driver transport hardware and software.
@@ -133,9 +144,22 @@ class RadioInterface
uint32_t getPacketTime(MeshPacket *p);
uint32_t getPacketTime(uint32_t totalPacketLen);
/**
* Get the channel we saved.
*/
uint32_t getChannelNum();
/**
* Get the frequency we saved.
*/
float getFreq();
protected:
int8_t power = 17; // Set by applyModemConfig()
float savedFreq;
uint32_t savedChannelNum;
/***
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
* PacketHeader & payload).
@@ -157,6 +181,16 @@ class RadioInterface
*/
virtual void applyModemConfig();
/**
* Save the frequency we selected for later reuse.
*/
virtual void saveFreq(float savedFreq);
/**
* Save the chanel we selected for later reuse.
*/
virtual void saveChannelNum(uint32_t savedChannelNum);
private:
/// Return 0 if sleep is okay
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }

View File

@@ -2,6 +2,7 @@
#include "MeshTypes.h"
#include "NodeDB.h"
#include "SPILock.h"
#include "error.h"
#include "mesh-pb-constants.h"
#include <configuration.h>
#include <pb_decode.h>
@@ -70,6 +71,16 @@ bool RadioLibInterface::canSendImmediately()
if (busyTx || busyRx) {
if (busyTx)
DEBUG_MSG("Can not send yet, busyTx\n");
// If we've been trying to send the same packet more than one minute and we haven't gotten a
// TX IRQ from the radio, the radio is probably broken.
if (busyTx && (millis() - lastTxStart > 60000)) {
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
recordCriticalError(CriticalErrorCode_TransmitFailed);
#ifndef NO_ESP32
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
ESP.restart();
#endif
}
if (busyRx)
DEBUG_MSG("Can not send yet, busyRx\n");
return false;
@@ -82,13 +93,18 @@ bool RadioLibInterface::canSendImmediately()
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode RadioLibInterface::send(MeshPacket *p)
{
if (disabled) {
packetPool.release(p);
return ERRNO_DISABLED;
}
// Sometimes when testing it is useful to be able to never turn on the xmitter
#ifndef LORA_DISABLE_SENDING
printPacket("enqueuing for send", p);
uint32_t xmitMsec = getPacketTime(p);
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
packetPool.release(p);
@@ -98,7 +114,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
// Count the packet toward our TX airtime utilization.
// We only count it if it can be added to the TX queue.
airTime->logAirtime(TX_LOG, xmitMsec);
//airTime.logAirtime(TX_LOG, xmitMsec);
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
@@ -107,19 +122,31 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
return res;
#else
packetPool.release(p);
return ERRNO_UNKNOWN;
return ERRNO_DISABLED;
#endif
}
bool RadioLibInterface::canSleep()
{
bool res = txQueue.isEmpty();
bool res = txQueue.empty();
if (!res) // only print debug messages if we are vetoing sleep
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
return res;
}
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
{
auto p = txQueue.remove(from, id);
if (p)
packetPool.release(p); // free the packet we just removed
bool result = (p != NULL);
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
return result;
}
/** radio helper thread callback.
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
@@ -153,12 +180,12 @@ void RadioLibInterface::onNotify(uint32_t notification)
// If we are not currently in receive mode, then restart the timer and try again later (this can happen if the main thread
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
if (!txQueue.isEmpty()) {
if (!txQueue.empty()) {
if (!canSendImmediately()) {
startTransmitTimer(); // try again in a little while
} else {
// Send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeuePtr(0);
MeshPacket *txp = txQueue.dequeue();
assert(txp);
startSend(txp);
}
@@ -174,7 +201,7 @@ void RadioLibInterface::onNotify(uint32_t notification)
void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.isEmpty()) {
if (!txQueue.empty()) {
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
@@ -217,13 +244,14 @@ void RadioLibInterface::handleReceiveInterrupt()
size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length);
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
//airTime.logAirtime(RX_ALL_LOG, xmitMsec);
int state = iface->readData(radiobuf, length);
if (state != ERR_NONE) {
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
// Skip the 4 headers that are at the beginning of the rxBuf
int32_t payloadLen = length - sizeof(PacketHeader);
@@ -233,6 +261,7 @@ void RadioLibInterface::handleReceiveInterrupt()
if (payloadLen < 0) {
DEBUG_MSG("ignoring received packet too short\n");
rxBad++;
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
} else {
const PacketHeader *h = (PacketHeader *)radiobuf;
@@ -246,22 +275,22 @@ void RadioLibInterface::handleReceiveInterrupt()
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
addReceiveMetadata(mp);
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes));
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
printPacket("Lora RX", mp);
xmitMsec = getPacketTime(mp);
//xmitMsec = getPacketTime(mp);
airTime->logAirtime(RX_LOG, xmitMsec);
//airTime.logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
}
@@ -272,15 +301,20 @@ void RadioLibInterface::handleReceiveInterrupt()
void RadioLibInterface::startSend(MeshPacket *txp)
{
printPacket("Starting low level send", txp);
setStandby(); // Cancel any already in process receives
if (disabled) {
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
packetPool.release(txp);
} else {
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);
assert(res == ERR_NONE);
int res = iface->startTransmit(radiobuf, numbytes);
assert(res == ERR_NONE);
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
enableInterrupt(isrTxLevel0);
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
enableInterrupt(isrTxLevel0);
}
}

View File

@@ -2,6 +2,7 @@
#include "../concurrency/OSThread.h"
#include "RadioInterface.h"
#include "MeshPacketQueue.h"
#ifdef CubeCell_BoardPlus
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
@@ -74,15 +75,18 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
protected:
/**
* FIXME, use a meshtastic sync word, but hashed with the Channel name. Currently picking the same default
* the RF95 used (0x14). Note: do not use 0x34 - that is reserved for lorawan
* We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old loads 0x14)
* Note: do not use 0x34 - that is reserved for lorawan
*
* We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with this code
* for a long time.
*/
uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE;
const uint8_t syncWord = 0x2b;
float currentLimit = 100; // FIXME
@@ -136,6 +140,9 @@ 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);
private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
* the transmit

View File

@@ -1,4 +1,5 @@
#include "ReliableRouter.h"
#include "MeshPlugin.h"
#include "MeshTypes.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
@@ -26,15 +27,18 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
{
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
printPacket("Rx someone rebroadcasting for us", p);
// We are seeing someone rebroadcast one of our broadcast attempts.
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
// the original sending process.
if (stopRetransmission(p->from, p->id)) {
DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n");
sendAckNak(true, p->from, p->id);
if (stopRetransmission(getFrom(p), p->id)) {
DEBUG_MSG("generating implicit ack\n");
// NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be
// marked as wantAck
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
}
}
@@ -53,56 +57,39 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
*
* Otherwise, let superclass handle it.
*/
void ReliableRouter::sniffReceived(const MeshPacket *p)
void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
NodeNum ourNode = getNodeNum();
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
// - not DSR routing)
if (p->want_ack) {
sendAckNak(true, p->from, p->id);
if (MeshPlugin::currentReply)
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack");
else
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
}
// If the payload is valid, look for ack/nak
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
PacketId ackId = ((c && c->error_reason == Routing_Error_NONE) || !c) ? p->decoded.request_id : 0;
PacketId ackId = p->decoded.which_ack == SubPacket_success_id_tag ? p->decoded.ack.success_id : 0;
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
// A nak is a routing packt that has an error code
PacketId nakId = (c && c->error_reason != Routing_Error_NONE) ? p->decoded.request_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) {
if (ackId) {
DEBUG_MSG("Received a ack=%d, stopping retransmissions\n", ackId);
DEBUG_MSG("Received a ack for 0x%x, stopping retransmissions\n", ackId);
stopRetransmission(p->to, ackId);
} else {
DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId);
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
stopRetransmission(p->to, nakId);
}
}
}
// handle the packet as normal
FloodingRouter::sniffReceived(p);
}
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void ReliableRouter::sendAckNak(bool isAck, NodeNum to, PacketId idFrom)
{
auto p = allocForSending();
p->hop_limit = 0; // Assume just immediate neighbors for now
p->to = to;
DEBUG_MSG("Sending an ack=0x%x,to=0x%x,idFrom=0x%x,id=0x%x\n", isAck, to, idFrom, p->id);
if (isAck) {
p->decoded.ack.success_id = idFrom;
p->decoded.which_ack = SubPacket_success_id_tag;
} else {
p->decoded.ack.fail_id = idFrom;
p->decoded.which_ack = SubPacket_fail_id_tag;
}
sendLocal(p); // we sometimes send directly to the local node
FloodingRouter::sniffReceived(p, c);
}
#define NUM_RETRANSMISSIONS 3
@@ -150,8 +137,9 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
auto id = GlobalPacketId(p);
auto rec = PendingPacket(p);
stopRetransmission(getFrom(p), p->id);
setNextTx(&rec);
stopRetransmission(p->from, p->id);
pending[id] = rec;
return &pending[id];
@@ -171,18 +159,21 @@ int32_t ReliableRouter::doRetransmissions()
++nextIt; // we use this odd pattern because we might be deleting it...
auto &p = it->second;
bool stillValid = true; // assume we'll keep this record around
// FIXME, handle 51 day rolloever here!!!
if (p.nextTxMsec <= now) {
if (p.numRetransmissions == 0) {
DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to,
DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to,
p.packet->id);
sendAckNak(false, p.packet->from, p.packet->id);
sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
// allows the DSR version to still be able to look at the PendingPacket
stopRetransmission(it->first);
stillValid = false; // just deleted it
} else {
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=%d, tries left=%d\n", p.packet->from, p.packet->to,
p.packet->id, p.numRetransmissions);
DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
p.packet->to, p.packet->id, p.numRetransmissions);
// Note: we call the superclass version because we don't want to have our version of send() add a new
// retransmission record
@@ -192,8 +183,10 @@ int32_t ReliableRouter::doRetransmissions()
--p.numRetransmissions;
setNextTx(&p);
}
} else {
// Not yet time
}
if (stillValid) {
// Update our desired sleep delay
int32_t t = p.nextTxMsec - now;
d = min(t, d);
@@ -201,4 +194,14 @@ int32_t ReliableRouter::doRetransmissions()
}
return d;
}
void ReliableRouter::setNextTx(PendingPacket *pending)
{
assert(iface);
auto d = iface->getRetransmissionMsec(pending->packet);
pending->nextTxMsec = millis() + d;
DEBUG_MSG("Setting next retransmission in %u msecs: ", d);
printPacket("", pending->packet);
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
}

View File

@@ -15,7 +15,7 @@ struct GlobalPacketId {
GlobalPacketId(const MeshPacket *p)
{
node = p->from;
node = getFrom(p);
id = p->id;
}
@@ -90,7 +90,7 @@ class ReliableRouter : public FloodingRouter
/**
* Look for acks/naks or someone retransmitting us
*/
virtual void sniffReceived(const MeshPacket *p);
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
/**
* Try to find the pending packet record for this ID (or NULL if not found)
@@ -109,10 +109,6 @@ class ReliableRouter : public FloodingRouter
PendingPacket *startRetransmission(MeshPacket *p);
private:
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(bool isAck, NodeNum to, PacketId idFrom);
/**
* Stop any retransmissions we are doing of the specified node/packet ID pair
@@ -129,7 +125,5 @@ class ReliableRouter : public FloodingRouter
*/
int32_t doRetransmissions();
void setNextTx(PendingPacket *pending) {
assert(iface);
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
void setNextTx(PendingPacket *pending);
};

View File

@@ -1,9 +1,11 @@
#include "Router.h"
#include "Channels.h"
#include "CryptoEngine.h"
#include "NodeDB.h"
#include "RTC.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
#include <NodeDB.h>
#include "plugins/RoutingPlugin.h"
/**
* Router todo
@@ -80,7 +82,6 @@ PacketId generatePacketId()
i++;
PacketId id = (i % numPacketId) + 1; // return number between 1 and numPacketId (ie - never zero)
myNodeInfo.current_packet_id = id; // Kinda crufty - we keep updating this so the phone can see a current value
return id;
}
@@ -88,7 +89,7 @@ MeshPacket *Router::allocForSending()
{
MeshPacket *p = packetPool.allocZeroed();
p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST;
p->hop_limit = HOP_RELIABLE;
@@ -99,22 +100,54 @@ MeshPacket *Router::allocForSending()
return p;
}
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
{
routingPlugin->sendAckNak(err, to, idFrom);
}
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
{
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id);
packetPool.release(p);
}
void Router::setReceivedMessage() {
setInterval(0); // Run ASAP, so we can figure out our correct sleep time
}
ErrorCode Router::sendLocal(MeshPacket *p)
{
// No need to deliver externally if the destination is the local node
if (p->to == nodeDB.getNodeNum()) {
printPacket("Enqueuing local", p);
fromRadioQueue.enqueue(p);
setReceivedMessage();
return ERRNO_OK;
}
} else if (!iface) {
// We must be sending to remote nodes also, fail if no interface found
abortSendAndNak(Routing_Error_NO_INTERFACE, p);
// If we are sending a broadcast, we also treat it as if we just received it ourself
// this allows local apps (and PCs) to see broadcasts sourced locally
if (p->to == NODENUM_BROADCAST) {
handleReceived(p);
}
return ERRNO_NO_INTERFACES;
} else {
// If we are sending a broadcast, we also treat it as if we just received it ourself
// this allows local apps (and PCs) to see broadcasts sourced locally
if (p->to == NODENUM_BROADCAST) {
handleReceived(p);
}
return send(p);
return send(p);
}
}
void printBytes(const char *label, const uint8_t *p, size_t numbytes) {
DEBUG_MSG("%s: ", label);
for(size_t i = 0; i < numbytes; i++)
DEBUG_MSG("%02x ", p[i]);
DEBUG_MSG("\n");
}
/**
@@ -126,49 +159,70 @@ ErrorCode Router::send(MeshPacket *p)
{
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
assert(
!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
// assert
// Never set the want_ack flag on broadcast packets sent over the air.
if (p->to == NODENUM_BROADCAST)
p->want_ack = false;
// Up until this point we might have been using 0 for the from address (if it started with the phone), but when we send over
// the lora we need to make sure we have replaced it with our local address
p->from = getFrom(p);
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
assert(p->which_payload == MeshPacket_encrypted_tag ||
p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
p->which_payloadVariant == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
// First convert from protobufs to raw bytes
if (p->which_payload == MeshPacket_decoded_tag) {
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded);
// printPacket("pre encrypt", p); // portnum valid here
assert(numbytes <= MAX_RHPACKETLEN);
crypto->encrypt(p->from, p->id, numbytes, bytes);
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
if (numbytes > MAX_RHPACKETLEN) {
abortSendAndNak(Routing_Error_TOO_LARGE, p);
return ERRNO_TOO_LARGE;
}
//printBytes("plaintext", bytes, numbytes);
auto hash = channels.setActiveByIndex(p->channel);
if (hash < 0) {
// No suitable channel could be found for sending
abortSendAndNak(Routing_Error_NO_CHANNEL, p);
return ERRNO_NO_CHANNEL;
}
// Now that we are encrypting the packet channel should be the hash (no longer the index)
p->channel = hash;
crypto->encrypt(getFrom(p), p->id, numbytes, bytes);
// Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes);
p->encrypted.size = numbytes;
p->which_payload = MeshPacket_encrypted_tag;
p->which_payloadVariant = MeshPacket_encrypted_tag;
}
if (iface) {
// DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
return iface->send(p);
} else {
DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
packetPool.release(p);
return ERRNO_NO_INTERFACES;
}
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
return iface->send(p);
}
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool Router::cancelSending(NodeNum from, PacketId id)
{
return iface ? iface->cancelSending(from, id) : false;
}
/**
* 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)
*/
void Router::sniffReceived(const MeshPacket *p)
void Router::sniffReceived(const MeshPacket *p, const Routing *c)
{
DEBUG_MSG("FIXME-update-db Sniffing packet\n");
// FIXME, update nodedb here for any packet that passes through us
@@ -176,28 +230,44 @@ void Router::sniffReceived(const MeshPacket *p)
bool Router::perhapsDecode(MeshPacket *p)
{
if (p->which_payload == MeshPacket_decoded_tag)
if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return
assert(p->which_payload == MeshPacket_encrypted_tag);
assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without
// being able to decrypt their data.
// Try to decrypt the packet if we can
static uint8_t bytes[MAX_RHPACKETLEN];
memcpy(bytes, p->encrypted.bytes,
p->encrypted.size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
crypto->decrypt(p->from, p->id, p->encrypted.size, bytes);
// Try to find a channel that works with this hash
for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) {
// Try to use this hash/channel pair
if (channels.decryptForHash(chIndex, p->channel)) {
// Try to decrypt the packet if we can
static uint8_t bytes[MAX_RHPACKETLEN];
size_t rawSize = p->encrypted.size;
assert(rawSize <= sizeof(bytes));
memcpy(bytes, p->encrypted.bytes,
rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf
crypto->decrypt(p->from, p->id, rawSize, bytes);
// Take those raw bytes and convert them back into a well structured protobuf we can understand
if (!pb_decode_from_bytes(bytes, p->encrypted.size, SubPacket_fields, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet!\n");
return false;
} else {
// parsing was successful
p->which_payload = MeshPacket_decoded_tag;
return true;
//printBytes("plaintext", bytes, p->encrypted.size);
// Take those raw bytes and convert them back into a well structured protobuf we can understand
memset(&p->decoded, 0, sizeof(p->decoded));
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
} else if(p->decoded.portnum == PortNum_UNKNOWN_APP) {
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
}
else {
// parsing was successful
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
p->channel = chIndex; // change to store the index instead of the hash
printPacket("decoded message", p);
return true;
}
}
}
DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", p->channel);
return false;
}
NodeNum Router::getNodeNum()
@@ -215,22 +285,21 @@ void Router::handleReceived(MeshPacket *p)
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
// Take those raw bytes and convert them back into a well structured protobuf we can understand
if (perhapsDecode(p)) {
bool decoded = perhapsDecode(p);
if (decoded) {
// parsing was successful, queue for our recipient
printPacket("handleReceived", p);
sniffReceived(p);
if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) {
printPacket("Delivering rx packet", p);
notifyPacketReceived.notifyObservers(p);
}
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
// sniffReceived(p);
MeshPlugin::callPlugins(*p);
}
}
void Router::perhapsHandleReceived(MeshPacket *p)
{
assert(radioConfig.has_preferences);
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from);
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p));
if (ignore)
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);

View File

@@ -21,10 +21,6 @@ class Router : protected concurrency::OSThread
RadioInterface *iface = NULL;
public:
/// Local services that want to see _every_ packet this node receives can observe this.
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting
/// freed)
Observable<const MeshPacket *> notifyPacketReceived;
/**
* Constructor
@@ -48,20 +44,33 @@ class Router : protected concurrency::OSThread
virtual int32_t runOnce();
/**
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
* This is the primary method used for sending packets, because it handles both the remote and local cases.
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
ErrorCode sendLocal(MeshPacket *p);
/// Allocate and return a meshpacket which defaults as send to broadcast from the current node.
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool cancelSending(NodeNum from, PacketId id);
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
* The returned packet is guaranteed to have a unique packet ID already assigned
*/
MeshPacket *allocForSending();
/**
* @return our local nodenum */
NodeNum getNodeNum();
/** Wake up the router thread ASAP, because we just queued a message for it.
* FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue'
*/
void setReceivedMessage();
protected:
friend class RoutingPlugin;
/**
* Send a packet on a suitable interface. This routine will
* later free() the packet to pool. This routine is not allowed to stall.
@@ -73,6 +82,8 @@ 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
*
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
@@ -83,7 +94,7 @@ class Router : protected concurrency::OSThread
* 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);
virtual void sniffReceived(const MeshPacket *p, const Routing *c);
/**
* Remove any encryption and decode the protobufs inside this packet (if necessary).
@@ -92,6 +103,11 @@ class Router : protected concurrency::OSThread
*/
bool perhapsDecode(MeshPacket *p);
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom);
private:
/**
* Called from loop()
@@ -112,6 +128,9 @@ class Router : protected concurrency::OSThread
* Note: this method will free the provided packet.
*/
void handleReceived(MeshPacket *p);
/** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */
void abortSendAndNak(Routing_Error err, MeshPacket *p);
};
extern Router *router;

View File

@@ -21,7 +21,7 @@ class SinglePortPlugin : public MeshPlugin
/**
* @return true if you want to receive the specified portnum
*/
virtual bool wantPortnum(PortNum p) { return p == ourPortNum; }
virtual bool wantPacket(const MeshPacket *p) { return p->decoded.portnum == ourPortNum; }
/**
* Return a mesh packet which has been preinited as a data packet with a particular port number.
@@ -32,8 +32,7 @@ class SinglePortPlugin : public MeshPlugin
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending();
p->decoded.which_payload = SubPacket_data_tag;
p->decoded.data.portnum = ourPortNum;
p->decoded.portnum = ourPortNum;
return p;
}

View File

@@ -84,8 +84,8 @@ void StreamAPI::emitRebooted()
{
// In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
fromRadioScratch.which_variant = FromRadio_rebooted_tag;
fromRadioScratch.variant.rebooted = true;
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
fromRadioScratch.rebooted = true;
DEBUG_MSG("Emitting reboot packet for serial shell\n");
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));

View File

@@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "admin.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(AdminMessage, AdminMessage, 2)

View File

@@ -0,0 +1,76 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_ADMIN_PB_H_INCLUDED
#define PB_ADMIN_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#include "radioconfig.pb.h"
#include "channel.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _AdminMessage {
pb_size_t which_variant;
union {
RadioConfig set_radio;
User set_owner;
Channel set_channel;
bool get_radio_request;
RadioConfig get_radio_response;
uint32_t get_channel_request;
Channel get_channel_response;
};
} AdminMessage;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define AdminMessage_init_default {0, {RadioConfig_init_default}}
#define AdminMessage_init_zero {0, {RadioConfig_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define AdminMessage_set_radio_tag 1
#define AdminMessage_set_owner_tag 2
#define AdminMessage_set_channel_tag 3
#define AdminMessage_get_radio_request_tag 4
#define AdminMessage_get_radio_response_tag 5
#define AdminMessage_get_channel_request_tag 6
#define AdminMessage_get_channel_response_tag 7
/* Struct field encoding specification for nanopb */
#define AdminMessage_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \
X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \
X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7)
#define AdminMessage_CALLBACK NULL
#define AdminMessage_DEFAULT NULL
#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig
#define AdminMessage_variant_set_owner_MSGTYPE User
#define AdminMessage_variant_set_channel_MSGTYPE Channel
#define AdminMessage_variant_get_radio_response_MSGTYPE RadioConfig
#define AdminMessage_variant_get_channel_response_MSGTYPE Channel
extern const pb_msgdesc_t AdminMessage_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 351
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -9,4 +9,7 @@
PB_BIND(ServiceEnvelope, ServiceEnvelope, 2)
PB_BIND(ChannelSet, ChannelSet, AUTO)

View File

@@ -5,12 +5,17 @@
#define PB_APPONLY_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#include "channel.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _ChannelSet {
pb_callback_t settings;
} ChannelSet;
typedef struct _ServiceEnvelope {
bool has_packet;
MeshPacket packet;
@@ -25,9 +30,12 @@ extern "C" {
/* Initializer values for message structs */
#define ServiceEnvelope_init_default {false, MeshPacket_init_default, {{NULL}, NULL}, {{NULL}, NULL}}
#define ChannelSet_init_default {{{NULL}, NULL}}
#define ServiceEnvelope_init_zero {false, MeshPacket_init_zero, {{NULL}, NULL}, {{NULL}, NULL}}
#define ChannelSet_init_zero {{{NULL}, NULL}}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSet_settings_tag 1
#define ServiceEnvelope_packet_tag 1
#define ServiceEnvelope_channel_id_tag 2
#define ServiceEnvelope_gateway_id_tag 3
@@ -41,13 +49,22 @@ X(a, CALLBACK, SINGULAR, STRING, gateway_id, 3)
#define ServiceEnvelope_DEFAULT NULL
#define ServiceEnvelope_packet_MSGTYPE MeshPacket
#define ChannelSet_FIELDLIST(X, a) \
X(a, CALLBACK, REPEATED, MESSAGE, settings, 1)
#define ChannelSet_CALLBACK pb_default_field_callback
#define ChannelSet_DEFAULT NULL
#define ChannelSet_settings_MSGTYPE ChannelSettings
extern const pb_msgdesc_t ServiceEnvelope_msg;
extern const pb_msgdesc_t ChannelSet_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define ServiceEnvelope_fields &ServiceEnvelope_msg
#define ChannelSet_fields &ChannelSet_msg
/* Maximum encoded size of messages (where known) */
/* ServiceEnvelope_size depends on runtime parameters */
/* ChannelSet_size depends on runtime parameters */
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -0,0 +1,17 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "channel.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(ChannelSettings, ChannelSettings, AUTO)
PB_BIND(Channel, Channel, AUTO)

View File

@@ -0,0 +1,125 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_CHANNEL_PB_H_INCLUDED
#define PB_CHANNEL_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
ChannelSettings_ModemConfig_Bw31_25Cr48Sf512 = 2,
ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3
} ChannelSettings_ModemConfig;
typedef enum _Channel_Role {
Channel_Role_DISABLED = 0,
Channel_Role_PRIMARY = 1,
Channel_Role_SECONDARY = 2
} Channel_Role;
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t;
typedef struct _ChannelSettings {
int8_t tx_power;
ChannelSettings_ModemConfig modem_config;
ChannelSettings_psk_t psk;
char name[12];
uint16_t bandwidth;
uint32_t spread_factor;
uint8_t coding_rate;
uint8_t channel_num;
uint32_t id;
bool uplink_enabled;
bool downlink_enabled;
} ChannelSettings;
typedef struct _Channel {
uint8_t index;
bool has_settings;
ChannelSettings settings;
Channel_Role role;
} Channel;
/* Helper constants for enums */
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
#define _Channel_Role_MIN Channel_Role_DISABLED
#define _Channel_Role_MAX Channel_Role_SECONDARY
#define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSettings_tx_power_tag 1
#define ChannelSettings_modem_config_tag 3
#define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5
#define ChannelSettings_bandwidth_tag 6
#define ChannelSettings_spread_factor_tag 7
#define ChannelSettings_coding_rate_tag 8
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_id_tag 10
#define ChannelSettings_uplink_enabled_tag 16
#define ChannelSettings_downlink_enabled_tag 17
#define Channel_index_tag 1
#define Channel_settings_tag 2
#define Channel_role_tag 3
/* Struct field encoding specification for nanopb */
#define ChannelSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \
X(a, STATIC, SINGULAR, BYTES, psk, 4) \
X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \
X(a, STATIC, SINGULAR, FIXED32, id, 10) \
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17)
#define ChannelSettings_CALLBACK NULL
#define ChannelSettings_DEFAULT NULL
#define Channel_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, index, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \
X(a, STATIC, SINGULAR, UENUM, role, 3)
#define Channel_CALLBACK NULL
#define Channel_DEFAULT NULL
#define Channel_settings_MSGTYPE ChannelSettings
extern const pb_msgdesc_t ChannelSettings_msg;
extern const pb_msgdesc_t Channel_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define ChannelSettings_fields &ChannelSettings_msg
#define Channel_fields &Channel_msg
/* Maximum encoded size of messages (where known) */
#define ChannelSettings_size 87
#define Channel_size 94
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -5,6 +5,8 @@
#define PB_DEVICEONLY_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#include "radioconfig.pb.h"
#include "channel.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -27,8 +29,8 @@ typedef struct _DeviceState {
uint32_t version;
bool no_save;
bool did_gps_reset;
pb_size_t secondary_channels_count;
ChannelSettings secondary_channels[7];
pb_size_t channels_count;
Channel channels[8];
} DeviceState;
@@ -37,8 +39,8 @@ extern "C" {
#endif
/* Initializer values for message structs */
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define DeviceState_radio_tag 1
@@ -50,7 +52,7 @@ extern "C" {
#define DeviceState_version_tag 8
#define DeviceState_no_save_tag 9
#define DeviceState_did_gps_reset_tag 11
#define DeviceState_secondary_channels_tag 12
#define DeviceState_channels_tag 13
/* Struct field encoding specification for nanopb */
#define DeviceState_FIELDLIST(X, a) \
@@ -63,7 +65,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8) \
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12)
X(a, STATIC, REPEATED, MESSAGE, channels, 13)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_radio_MSGTYPE RadioConfig
@@ -72,7 +74,7 @@ X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12)
#define DeviceState_node_db_MSGTYPE NodeInfo
#define DeviceState_receive_queue_MSGTYPE MeshPacket
#define DeviceState_rx_text_message_MSGTYPE MeshPacket
#define DeviceState_secondary_channels_MSGTYPE ChannelSettings
#define DeviceState_channels_MSGTYPE Channel
extern const pb_msgdesc_t DeviceState_msg;
@@ -80,7 +82,7 @@ extern const pb_msgdesc_t DeviceState_msg;
#define DeviceState_fields &DeviceState_msg
/* Maximum encoded size of messages (where known) */
#define DeviceState_size 6206
#define DeviceState_size 6169
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "environmental_measurement.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(EnvironmentalMeasurement, EnvironmentalMeasurement, AUTO)

View File

@@ -0,0 +1,53 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
#define PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _EnvironmentalMeasurement {
float temperature;
float relative_humidity;
float barometric_pressure;
} EnvironmentalMeasurement;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define EnvironmentalMeasurement_init_default {0, 0, 0}
#define EnvironmentalMeasurement_init_zero {0, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define EnvironmentalMeasurement_temperature_tag 1
#define EnvironmentalMeasurement_relative_humidity_tag 2
#define EnvironmentalMeasurement_barometric_pressure_tag 3
/* Struct field encoding specification for nanopb */
#define EnvironmentalMeasurement_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, FLOAT, temperature, 1) \
X(a, STATIC, SINGULAR, FLOAT, relative_humidity, 2) \
X(a, STATIC, SINGULAR, FLOAT, barometric_pressure, 3)
#define EnvironmentalMeasurement_CALLBACK NULL
#define EnvironmentalMeasurement_DEFAULT NULL
extern const pb_msgdesc_t EnvironmentalMeasurement_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define EnvironmentalMeasurement_fields &EnvironmentalMeasurement_msg
/* Maximum encoded size of messages (where known) */
#define EnvironmentalMeasurement_size 15
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -9,30 +9,21 @@
PB_BIND(Position, Position, AUTO)
PB_BIND(Data, Data, AUTO)
PB_BIND(User, User, AUTO)
PB_BIND(RouteDiscovery, RouteDiscovery, AUTO)
PB_BIND(SubPacket, SubPacket, 2)
PB_BIND(Routing, Routing, AUTO)
PB_BIND(Data, Data, 2)
PB_BIND(MeshPacket, MeshPacket, 2)
PB_BIND(ChannelSettings, ChannelSettings, AUTO)
PB_BIND(RadioConfig, RadioConfig, 2)
PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
PB_BIND(NodeInfo, NodeInfo, AUTO)
@@ -54,7 +45,3 @@ PB_BIND(ToRadio, ToRadio, 2)

View File

@@ -11,63 +11,11 @@
#endif
/* Enum definitions */
typedef enum _RouteError {
RouteError_NONE = 0,
RouteError_NO_ROUTE = 1,
RouteError_GOT_NAK = 2,
RouteError_TIMEOUT = 3
} RouteError;
typedef enum _Constants {
Constants_Unused = 0,
Constants_DATA_PAYLOAD_LEN = 240
} Constants;
typedef enum _RegionCode {
RegionCode_Unset = 0,
RegionCode_US = 1,
RegionCode_EU433 = 2,
RegionCode_EU865 = 3,
RegionCode_CN = 4,
RegionCode_JP = 5,
RegionCode_ANZ = 6,
RegionCode_KR = 7,
RegionCode_TW = 8
} RegionCode;
typedef enum _ChargeCurrent {
ChargeCurrent_MAUnset = 0,
ChargeCurrent_MA100 = 1,
ChargeCurrent_MA190 = 2,
ChargeCurrent_MA280 = 3,
ChargeCurrent_MA360 = 4,
ChargeCurrent_MA450 = 5,
ChargeCurrent_MA550 = 6,
ChargeCurrent_MA630 = 7,
ChargeCurrent_MA700 = 8,
ChargeCurrent_MA780 = 9,
ChargeCurrent_MA880 = 10,
ChargeCurrent_MA960 = 11,
ChargeCurrent_MA1000 = 12,
ChargeCurrent_MA1080 = 13,
ChargeCurrent_MA1160 = 14,
ChargeCurrent_MA1240 = 15,
ChargeCurrent_MA1320 = 16
} ChargeCurrent;
typedef enum _GpsOperation {
GpsOperation_GpsOpUnset = 0,
GpsOperation_GpsOpMobile = 2,
GpsOperation_GpsOpTimeOnly = 3,
GpsOperation_GpsOpDisabled = 4
} GpsOperation;
typedef enum _LocationSharing {
LocationSharing_LocUnset = 0,
LocationSharing_LocEnabled = 1,
LocationSharing_LocDisabled = 2
} LocationSharing;
typedef enum _CriticalErrorCode {
CriticalErrorCode_None = 0,
CriticalErrorCode_TxWatchdog = 1,
@@ -76,15 +24,30 @@ typedef enum _CriticalErrorCode {
CriticalErrorCode_Unspecified = 4,
CriticalErrorCode_UBloxInitFailed = 5,
CriticalErrorCode_NoAXP192 = 6,
CriticalErrorCode_InvalidRadioSetting = 7
CriticalErrorCode_InvalidRadioSetting = 7,
CriticalErrorCode_TransmitFailed = 8
} CriticalErrorCode;
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
ChannelSettings_ModemConfig_Bw31_25Cr48Sf512 = 2,
ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3
} ChannelSettings_ModemConfig;
typedef enum _Routing_Error {
Routing_Error_NONE = 0,
Routing_Error_NO_ROUTE = 1,
Routing_Error_GOT_NAK = 2,
Routing_Error_TIMEOUT = 3,
Routing_Error_NO_INTERFACE = 4,
Routing_Error_MAX_RETRANSMIT = 5,
Routing_Error_NO_CHANNEL = 6,
Routing_Error_TOO_LARGE = 7
} Routing_Error;
typedef enum _MeshPacket_Priority {
MeshPacket_Priority_UNSET = 0,
MeshPacket_Priority_MIN = 1,
MeshPacket_Priority_BACKGROUND = 10,
MeshPacket_Priority_DEFAULT = 64,
MeshPacket_Priority_RELIABLE = 70,
MeshPacket_Priority_ACK = 120,
MeshPacket_Priority_MAX = 127
} MeshPacket_Priority;
typedef enum _LogRecord_Level {
LogRecord_Level_UNSET = 0,
@@ -97,25 +60,14 @@ typedef enum _LogRecord_Level {
} LogRecord_Level;
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t;
typedef struct _ChannelSettings {
int32_t tx_power;
ChannelSettings_ModemConfig modem_config;
ChannelSettings_psk_t psk;
char name[12];
uint32_t bandwidth;
uint32_t spread_factor;
uint32_t coding_rate;
uint32_t channel_num;
uint32_t id;
bool uplink_enabled;
bool downlink_enabled;
} ChannelSettings;
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
typedef PB_BYTES_ARRAY_T(237) Data_payload_t;
typedef struct _Data {
PortNum portnum;
Data_payload_t payload;
bool want_response;
uint32_t dest;
uint32_t source;
uint32_t request_id;
} Data;
typedef struct _LogRecord {
@@ -128,65 +80,29 @@ typedef struct _LogRecord {
typedef struct _MyNodeInfo {
uint32_t my_node_num;
bool has_gps;
int32_t num_channels;
uint32_t num_bands;
char region[12];
char hw_model[16];
char firmware_version[12];
CriticalErrorCode error_code;
uint32_t error_address;
uint32_t error_count;
uint32_t packet_id_bits;
uint32_t current_packet_id;
uint32_t node_num_bits;
uint32_t message_timeout_msec;
uint32_t min_app_version;
uint32_t max_channels;
} MyNodeInfo;
typedef struct _Position {
int32_t altitude;
int32_t battery_level;
int32_t latitude_i;
int32_t longitude_i;
int32_t altitude;
int32_t battery_level;
uint32_t time;
} Position;
typedef struct _RadioConfig_UserPreferences {
uint32_t position_broadcast_secs;
uint32_t send_owner_interval;
uint32_t wait_bluetooth_secs;
uint32_t screen_on_secs;
uint32_t phone_timeout_secs;
uint32_t phone_sds_timeout_sec;
uint32_t mesh_sds_timeout_secs;
uint32_t sds_secs;
uint32_t ls_secs;
uint32_t min_wake_secs;
char wifi_ssid[33];
char wifi_password[64];
bool wifi_ap_mode;
RegionCode region;
ChargeCurrent charge_current;
LocationSharing location_share;
GpsOperation gps_operation;
uint32_t gps_update_interval;
uint32_t gps_attempt_time;
bool is_router;
bool is_low_power;
bool fixed_position;
bool factory_reset;
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
bool serialplugin_enabled;
bool serialplugin_echo;
uint32_t serialplugin_rxd;
uint32_t serialplugin_txd;
uint32_t serialplugin_timeout;
} RadioConfig_UserPreferences;
typedef struct _RouteDiscovery {
pb_size_t route_count;
int32_t route[8];
uint32_t route[8];
} RouteDiscovery;
typedef struct _User {
@@ -196,6 +112,24 @@ typedef struct _User {
pb_byte_t macaddr[6];
} User;
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
typedef struct _MeshPacket {
uint32_t from;
uint32_t to;
uint8_t channel;
pb_size_t which_payloadVariant;
union {
Data decoded;
MeshPacket_encrypted_t encrypted;
};
uint32_t id;
uint32_t rx_time;
float rx_snr;
uint8_t hop_limit;
bool want_ack;
MeshPacket_Priority priority;
} MeshPacket;
typedef struct _NodeInfo {
uint32_t num;
bool has_user;
@@ -206,110 +140,53 @@ typedef struct _NodeInfo {
float snr;
} NodeInfo;
typedef struct _RadioConfig {
bool has_preferences;
RadioConfig_UserPreferences preferences;
bool has_channel_settings;
ChannelSettings channel_settings;
} RadioConfig;
typedef struct _SubPacket {
pb_size_t which_payload;
typedef struct _Routing {
pb_size_t which_variant;
union {
Position position;
Data data;
User user;
RouteDiscovery route_request;
RouteDiscovery route_reply;
RouteError route_error;
Routing_Error error_reason;
};
uint32_t original_id;
bool want_response;
uint32_t dest;
pb_size_t which_ack;
union {
uint32_t success_id;
uint32_t fail_id;
} ack;
uint32_t source;
} SubPacket;
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
typedef struct _MeshPacket {
uint32_t from;
uint32_t to;
pb_size_t which_payload;
union {
SubPacket decoded;
MeshPacket_encrypted_t encrypted;
};
uint32_t channel_index;
uint32_t id;
float rx_snr;
uint32_t rx_time;
uint32_t hop_limit;
bool want_ack;
} MeshPacket;
} Routing;
typedef struct _FromRadio {
uint32_t num;
pb_size_t which_variant;
pb_size_t which_payloadVariant;
union {
MeshPacket packet;
MyNodeInfo my_info;
NodeInfo node_info;
RadioConfig radio;
LogRecord log_record;
uint32_t config_complete_id;
bool rebooted;
ChannelSettings channel;
} variant;
MeshPacket packet;
};
} FromRadio;
typedef struct _ToRadio {
pb_size_t which_variant;
pb_size_t which_payloadVariant;
union {
MeshPacket packet;
uint32_t want_config_id;
RadioConfig set_radio;
User set_owner;
ChannelSettings set_channel;
} variant;
};
} ToRadio;
/* Helper constants for enums */
#define _RouteError_MIN RouteError_NONE
#define _RouteError_MAX RouteError_TIMEOUT
#define _RouteError_ARRAYSIZE ((RouteError)(RouteError_TIMEOUT+1))
#define _Constants_MIN Constants_Unused
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1))
#define _GpsOperation_MIN GpsOperation_GpsOpUnset
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
#define _LocationSharing_MIN LocationSharing_LocUnset
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
#define _CriticalErrorCode_MIN CriticalErrorCode_None
#define _CriticalErrorCode_MAX CriticalErrorCode_InvalidRadioSetting
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_InvalidRadioSetting+1))
#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1))
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
#define _Routing_Error_MIN Routing_Error_NONE
#define _Routing_Error_MAX Routing_Error_TOO_LARGE
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1))
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
#define _MeshPacket_Priority_ARRAYSIZE ((MeshPacket_Priority)(MeshPacket_Priority_MAX+1))
#define _LogRecord_Level_MIN LogRecord_Level_UNSET
#define _LogRecord_Level_MAX LogRecord_Level_CRITICAL
@@ -322,166 +199,100 @@ extern "C" {
/* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, 0}
#define Data_init_default {_PortNum_MIN, {0, {0}}}
#define User_init_default {"", "", "", {0}}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0}
#define Routing_init_default {0, {RouteDiscovery_init_default}}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define Position_init_zero {0, 0, 0, 0, 0}
#define Data_init_zero {_PortNum_MIN, {0, {0}}}
#define User_init_zero {"", "", "", {0}}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0}
#define Routing_init_zero {0, {RouteDiscovery_init_zero}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0}
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0}
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSettings_tx_power_tag 1
#define ChannelSettings_modem_config_tag 3
#define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5
#define ChannelSettings_bandwidth_tag 6
#define ChannelSettings_spread_factor_tag 7
#define ChannelSettings_coding_rate_tag 8
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_id_tag 10
#define ChannelSettings_uplink_enabled_tag 16
#define ChannelSettings_downlink_enabled_tag 17
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define Data_want_response_tag 3
#define Data_dest_tag 4
#define Data_source_tag 5
#define Data_request_id_tag 6
#define LogRecord_message_tag 1
#define LogRecord_time_tag 2
#define LogRecord_source_tag 3
#define LogRecord_level_tag 4
#define MyNodeInfo_my_node_num_tag 1
#define MyNodeInfo_has_gps_tag 2
#define MyNodeInfo_num_channels_tag 3
#define MyNodeInfo_num_bands_tag 3
#define MyNodeInfo_region_tag 4
#define MyNodeInfo_hw_model_tag 5
#define MyNodeInfo_firmware_version_tag 6
#define MyNodeInfo_error_code_tag 7
#define MyNodeInfo_error_address_tag 8
#define MyNodeInfo_error_count_tag 9
#define MyNodeInfo_packet_id_bits_tag 10
#define MyNodeInfo_current_packet_id_tag 11
#define MyNodeInfo_node_num_bits_tag 12
#define MyNodeInfo_message_timeout_msec_tag 13
#define MyNodeInfo_min_app_version_tag 14
#define MyNodeInfo_max_channels_tag 15
#define Position_latitude_i_tag 1
#define Position_longitude_i_tag 2
#define Position_altitude_tag 3
#define Position_battery_level_tag 4
#define Position_latitude_i_tag 7
#define Position_longitude_i_tag 8
#define Position_time_tag 9
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
#define RadioConfig_UserPreferences_send_owner_interval_tag 2
#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4
#define RadioConfig_UserPreferences_screen_on_secs_tag 5
#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6
#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7
#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8
#define RadioConfig_UserPreferences_sds_secs_tag 9
#define RadioConfig_UserPreferences_ls_secs_tag 10
#define RadioConfig_UserPreferences_min_wake_secs_tag 11
#define RadioConfig_UserPreferences_wifi_ssid_tag 12
#define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_charge_current_tag 16
#define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
#define RadioConfig_UserPreferences_gps_attempt_time_tag 36
#define RadioConfig_UserPreferences_is_router_tag 37
#define RadioConfig_UserPreferences_is_low_power_tag 38
#define RadioConfig_UserPreferences_fixed_position_tag 39
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120
#define RadioConfig_UserPreferences_serialplugin_echo_tag 121
#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122
#define RadioConfig_UserPreferences_serialplugin_txd_tag 123
#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124
#define RouteDiscovery_route_tag 2
#define User_id_tag 1
#define User_long_name_tag 2
#define User_short_name_tag 3
#define User_macaddr_tag 4
#define MeshPacket_from_tag 1
#define MeshPacket_to_tag 2
#define MeshPacket_channel_tag 3
#define MeshPacket_decoded_tag 4
#define MeshPacket_encrypted_tag 5
#define MeshPacket_id_tag 6
#define MeshPacket_rx_time_tag 7
#define MeshPacket_rx_snr_tag 8
#define MeshPacket_hop_limit_tag 10
#define MeshPacket_want_ack_tag 11
#define MeshPacket_priority_tag 12
#define NodeInfo_num_tag 1
#define NodeInfo_user_tag 2
#define NodeInfo_position_tag 3
#define NodeInfo_next_hop_tag 5
#define NodeInfo_snr_tag 7
#define RadioConfig_preferences_tag 1
#define RadioConfig_channel_settings_tag 2
#define SubPacket_position_tag 1
#define SubPacket_data_tag 3
#define SubPacket_user_tag 4
#define SubPacket_route_request_tag 6
#define SubPacket_route_reply_tag 7
#define SubPacket_route_error_tag 13
#define SubPacket_original_id_tag 2
#define SubPacket_want_response_tag 5
#define SubPacket_dest_tag 9
#define SubPacket_success_id_tag 10
#define SubPacket_fail_id_tag 11
#define SubPacket_source_tag 12
#define MeshPacket_from_tag 1
#define MeshPacket_to_tag 2
#define MeshPacket_decoded_tag 3
#define MeshPacket_encrypted_tag 8
#define MeshPacket_channel_index_tag 4
#define MeshPacket_id_tag 6
#define MeshPacket_rx_snr_tag 7
#define MeshPacket_rx_time_tag 9
#define MeshPacket_hop_limit_tag 10
#define MeshPacket_want_ack_tag 11
#define Routing_route_request_tag 1
#define Routing_route_reply_tag 2
#define Routing_error_reason_tag 3
#define FromRadio_num_tag 1
#define FromRadio_packet_tag 2
#define FromRadio_my_info_tag 3
#define FromRadio_node_info_tag 4
#define FromRadio_radio_tag 6
#define FromRadio_log_record_tag 7
#define FromRadio_config_complete_id_tag 8
#define FromRadio_rebooted_tag 9
#define FromRadio_channel_tag 10
#define ToRadio_packet_tag 1
#define FromRadio_packet_tag 11
#define ToRadio_packet_tag 2
#define ToRadio_want_config_id_tag 100
#define ToRadio_set_radio_tag 101
#define ToRadio_set_owner_tag 102
#define ToRadio_set_channel_tag 103
/* Struct field encoding specification for nanopb */
#define Position_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \
X(a, STATIC, SINGULAR, INT32, altitude, 3) \
X(a, STATIC, SINGULAR, INT32, battery_level, 4) \
X(a, STATIC, SINGULAR, SINT32, latitude_i, 7) \
X(a, STATIC, SINGULAR, SINT32, longitude_i, 8) \
X(a, STATIC, SINGULAR, FIXED32, time, 9)
#define Position_CALLBACK NULL
#define Position_DEFAULT NULL
#define Data_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
X(a, STATIC, SINGULAR, BYTES, payload, 2)
#define Data_CALLBACK NULL
#define Data_DEFAULT NULL
#define User_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, id, 1) \
X(a, STATIC, SINGULAR, STRING, long_name, 2) \
@@ -491,102 +302,44 @@ X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4)
#define User_DEFAULT NULL
#define RouteDiscovery_FIELDLIST(X, a) \
X(a, STATIC, REPEATED, INT32, route, 2)
X(a, STATIC, REPEATED, FIXED32, route, 2)
#define RouteDiscovery_CALLBACK NULL
#define RouteDiscovery_DEFAULT NULL
#define SubPacket_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload,position,position), 1) \
X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \
X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \
X(a, STATIC, ONEOF, UENUM, (payload,route_error,route_error), 13) \
X(a, STATIC, SINGULAR, UINT32, original_id, 2) \
X(a, STATIC, SINGULAR, BOOL, want_response, 5) \
X(a, STATIC, SINGULAR, UINT32, dest, 9) \
X(a, STATIC, ONEOF, UINT32, (ack,success_id,ack.success_id), 10) \
X(a, STATIC, ONEOF, UINT32, (ack,fail_id,ack.fail_id), 11) \
X(a, STATIC, SINGULAR, UINT32, source, 12)
#define SubPacket_CALLBACK NULL
#define SubPacket_DEFAULT NULL
#define SubPacket_payload_position_MSGTYPE Position
#define SubPacket_payload_data_MSGTYPE Data
#define SubPacket_payload_user_MSGTYPE User
#define SubPacket_payload_route_request_MSGTYPE RouteDiscovery
#define SubPacket_payload_route_reply_MSGTYPE RouteDiscovery
#define Routing_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,route_request,route_request), 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,route_reply,route_reply), 2) \
X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3)
#define Routing_CALLBACK NULL
#define Routing_DEFAULT NULL
#define Routing_variant_route_request_MSGTYPE RouteDiscovery
#define Routing_variant_route_reply_MSGTYPE RouteDiscovery
#define Data_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
X(a, STATIC, SINGULAR, BYTES, payload, 2) \
X(a, STATIC, SINGULAR, BOOL, want_response, 3) \
X(a, STATIC, SINGULAR, FIXED32, dest, 4) \
X(a, STATIC, SINGULAR, FIXED32, source, 5) \
X(a, STATIC, SINGULAR, FIXED32, request_id, 6)
#define Data_CALLBACK NULL
#define Data_DEFAULT NULL
#define MeshPacket_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, from, 1) \
X(a, STATIC, SINGULAR, UINT32, to, 2) \
X(a, STATIC, ONEOF, MESSAGE, (payload,decoded,decoded), 3) \
X(a, STATIC, ONEOF, BYTES, (payload,encrypted,encrypted), 8) \
X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \
X(a, STATIC, SINGULAR, UINT32, id, 6) \
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \
X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \
X(a, STATIC, SINGULAR, FIXED32, from, 1) \
X(a, STATIC, SINGULAR, FIXED32, to, 2) \
X(a, STATIC, SINGULAR, UINT32, channel, 3) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 4) \
X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 5) \
X(a, STATIC, SINGULAR, FIXED32, id, 6) \
X(a, STATIC, SINGULAR, FIXED32, rx_time, 7) \
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \
X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \
X(a, STATIC, SINGULAR, BOOL, want_ack, 11)
X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \
X(a, STATIC, SINGULAR, UENUM, priority, 12)
#define MeshPacket_CALLBACK NULL
#define MeshPacket_DEFAULT NULL
#define MeshPacket_payload_decoded_MSGTYPE SubPacket
#define ChannelSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \
X(a, STATIC, SINGULAR, BYTES, psk, 4) \
X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \
X(a, STATIC, SINGULAR, FIXED32, id, 10) \
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17)
#define ChannelSettings_CALLBACK NULL
#define ChannelSettings_DEFAULT NULL
#define RadioConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, channel_settings, 2)
#define RadioConfig_CALLBACK NULL
#define RadioConfig_DEFAULT NULL
#define RadioConfig_preferences_MSGTYPE RadioConfig_UserPreferences
#define RadioConfig_channel_settings_MSGTYPE ChannelSettings
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \
X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \
X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \
X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \
X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \
X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \
X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
#define MeshPacket_payloadVariant_decoded_MSGTYPE Data
#define NodeInfo_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, num, 1) \
@@ -602,18 +355,16 @@ X(a, STATIC, SINGULAR, FLOAT, snr, 7)
#define MyNodeInfo_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \
X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \
X(a, STATIC, SINGULAR, INT32, num_channels, 3) \
X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \
X(a, STATIC, SINGULAR, STRING, region, 4) \
X(a, STATIC, SINGULAR, STRING, hw_model, 5) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
X(a, STATIC, SINGULAR, UINT32, error_count, 9) \
X(a, STATIC, SINGULAR, UINT32, packet_id_bits, 10) \
X(a, STATIC, SINGULAR, UINT32, current_packet_id, 11) \
X(a, STATIC, SINGULAR, UINT32, node_num_bits, 12) \
X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 13) \
X(a, STATIC, SINGULAR, UINT32, min_app_version, 14)
X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \
X(a, STATIC, SINGULAR, UINT32, max_channels, 15)
#define MyNodeInfo_CALLBACK NULL
#define MyNodeInfo_DEFAULT NULL
@@ -627,45 +378,32 @@ X(a, STATIC, SINGULAR, UENUM, level, 4)
#define FromRadio_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, num, 1) \
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \
X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \
X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \
X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \
X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \
X(a, STATIC, ONEOF, MESSAGE, (variant,channel,variant.channel), 10)
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \
X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \
X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11)
#define FromRadio_CALLBACK NULL
#define FromRadio_DEFAULT NULL
#define FromRadio_variant_packet_MSGTYPE MeshPacket
#define FromRadio_variant_my_info_MSGTYPE MyNodeInfo
#define FromRadio_variant_node_info_MSGTYPE NodeInfo
#define FromRadio_variant_radio_MSGTYPE RadioConfig
#define FromRadio_variant_log_record_MSGTYPE LogRecord
#define FromRadio_variant_channel_MSGTYPE ChannelSettings
#define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo
#define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo
#define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord
#define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket
#define ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 1) \
X(a, STATIC, ONEOF, UINT32, (variant,want_config_id,variant.want_config_id), 100) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,variant.set_radio), 101) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,variant.set_channel), 103)
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \
X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100)
#define ToRadio_CALLBACK NULL
#define ToRadio_DEFAULT NULL
#define ToRadio_variant_packet_MSGTYPE MeshPacket
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
#define ToRadio_variant_set_owner_MSGTYPE User
#define ToRadio_variant_set_channel_MSGTYPE ChannelSettings
#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket
extern const pb_msgdesc_t Position_msg;
extern const pb_msgdesc_t Data_msg;
extern const pb_msgdesc_t User_msg;
extern const pb_msgdesc_t RouteDiscovery_msg;
extern const pb_msgdesc_t SubPacket_msg;
extern const pb_msgdesc_t Routing_msg;
extern const pb_msgdesc_t Data_msg;
extern const pb_msgdesc_t MeshPacket_msg;
extern const pb_msgdesc_t ChannelSettings_msg;
extern const pb_msgdesc_t RadioConfig_msg;
extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
extern const pb_msgdesc_t NodeInfo_msg;
extern const pb_msgdesc_t MyNodeInfo_msg;
extern const pb_msgdesc_t LogRecord_msg;
@@ -674,14 +412,11 @@ extern const pb_msgdesc_t ToRadio_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Position_fields &Position_msg
#define Data_fields &Data_msg
#define User_fields &User_msg
#define RouteDiscovery_fields &RouteDiscovery_msg
#define SubPacket_fields &SubPacket_msg
#define Routing_fields &Routing_msg
#define Data_fields &Data_msg
#define MeshPacket_fields &MeshPacket_msg
#define ChannelSettings_fields &ChannelSettings_msg
#define RadioConfig_fields &RadioConfig_msg
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
#define NodeInfo_fields &NodeInfo_msg
#define MyNodeInfo_fields &MyNodeInfo_msg
#define LogRecord_fields &LogRecord_msg
@@ -689,20 +424,17 @@ extern const pb_msgdesc_t ToRadio_msg;
#define ToRadio_fields &ToRadio_msg
/* Maximum encoded size of messages (where known) */
#define Position_size 39
#define Data_size 246
#define Position_size 37
#define User_size 72
#define RouteDiscovery_size 88
#define SubPacket_size 275
#define MeshPacket_size 320
#define ChannelSettings_size 95
#define RadioConfig_size 349
#define RadioConfig_UserPreferences_size 249
#define NodeInfo_size 132
#define MyNodeInfo_size 106
#define RouteDiscovery_size 40
#define Routing_size 42
#define Data_size 260
#define MeshPacket_size 298
#define NodeInfo_size 130
#define MyNodeInfo_size 89
#define LogRecord_size 81
#define FromRadio_size 358
#define ToRadio_size 353
#define FromRadio_size 307
#define ToRadio_size 301
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -16,17 +16,23 @@ typedef enum _PortNum {
PortNum_REMOTE_HARDWARE_APP = 2,
PortNum_POSITION_APP = 3,
PortNum_NODEINFO_APP = 4,
PortNum_ROUTING_APP = 5,
PortNum_ADMIN_APP = 6,
PortNum_REPLY_APP = 32,
PortNum_IP_TUNNEL_APP = 33,
PortNum_SERIAL_APP = 64,
PortNum_STORE_FORWARD_APP = 65,
PortNum_RANGE_TEST_APP = 66,
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
PortNum_PRIVATE_APP = 256,
PortNum_ATAK_FORWARDER = 257
PortNum_ATAK_FORWARDER = 257,
PortNum_MAX = 511
} PortNum;
/* Helper constants for enums */
#define _PortNum_MIN PortNum_UNKNOWN_APP
#define _PortNum_MAX PortNum_ATAK_FORWARDER
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_ATAK_FORWARDER+1))
#define _PortNum_MAX PortNum_MAX
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_MAX+1))
#ifdef __cplusplus

View File

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

View File

@@ -0,0 +1,286 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_RADIOCONFIG_PB_H_INCLUDED
#define PB_RADIOCONFIG_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _RegionCode {
RegionCode_Unset = 0,
RegionCode_US = 1,
RegionCode_EU433 = 2,
RegionCode_EU865 = 3,
RegionCode_CN = 4,
RegionCode_JP = 5,
RegionCode_ANZ = 6,
RegionCode_KR = 7,
RegionCode_TW = 8,
RegionCode_RU = 9
} RegionCode;
typedef enum _ChargeCurrent {
ChargeCurrent_MAUnset = 0,
ChargeCurrent_MA100 = 1,
ChargeCurrent_MA190 = 2,
ChargeCurrent_MA280 = 3,
ChargeCurrent_MA360 = 4,
ChargeCurrent_MA450 = 5,
ChargeCurrent_MA550 = 6,
ChargeCurrent_MA630 = 7,
ChargeCurrent_MA700 = 8,
ChargeCurrent_MA780 = 9,
ChargeCurrent_MA880 = 10,
ChargeCurrent_MA960 = 11,
ChargeCurrent_MA1000 = 12,
ChargeCurrent_MA1080 = 13,
ChargeCurrent_MA1160 = 14,
ChargeCurrent_MA1240 = 15,
ChargeCurrent_MA1320 = 16
} ChargeCurrent;
typedef enum _GpsOperation {
GpsOperation_GpsOpUnset = 0,
GpsOperation_GpsOpStationary = 1,
GpsOperation_GpsOpMobile = 2,
GpsOperation_GpsOpTimeOnly = 3,
GpsOperation_GpsOpDisabled = 4
} GpsOperation;
typedef enum _LocationSharing {
LocationSharing_LocUnset = 0,
LocationSharing_LocEnabled = 1,
LocationSharing_LocDisabled = 2
} LocationSharing;
typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType {
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0
} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType;
/* Struct definitions */
typedef struct _RadioConfig_UserPreferences {
uint32_t position_broadcast_secs;
uint32_t send_owner_interval;
uint32_t wait_bluetooth_secs;
uint32_t screen_on_secs;
uint32_t phone_timeout_secs;
uint32_t phone_sds_timeout_sec;
uint32_t mesh_sds_timeout_secs;
uint32_t sds_secs;
uint32_t ls_secs;
uint32_t min_wake_secs;
char wifi_ssid[33];
char wifi_password[64];
bool wifi_ap_mode;
RegionCode region;
ChargeCurrent charge_current;
LocationSharing location_share;
GpsOperation gps_operation;
uint32_t gps_update_interval;
uint32_t gps_attempt_time;
bool is_router;
bool is_low_power;
bool fixed_position;
bool factory_reset;
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
bool serialplugin_enabled;
bool serialplugin_echo;
uint32_t serialplugin_rxd;
uint32_t serialplugin_txd;
uint32_t serialplugin_timeout;
uint32_t serialplugin_mode;
bool ext_notification_plugin_enabled;
uint32_t ext_notification_plugin_output_ms;
uint32_t ext_notification_plugin_output;
bool ext_notification_plugin_active;
bool ext_notification_plugin_alert_message;
bool ext_notification_plugin_alert_bell;
bool range_test_plugin_enabled;
uint32_t range_test_plugin_sender;
bool range_test_plugin_save;
bool store_forward_plugin_enabled;
uint32_t store_forward_plugin_records;
bool environmental_measurement_plugin_measurement_enabled;
bool environmental_measurement_plugin_screen_enabled;
uint32_t environmental_measurement_plugin_read_error_count_threshold;
uint32_t environmental_measurement_plugin_update_interval;
uint32_t environmental_measurement_plugin_recovery_interval;
bool environmental_measurement_plugin_display_farenheit;
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
uint32_t environmental_measurement_plugin_sensor_pin;
} RadioConfig_UserPreferences;
typedef struct _RadioConfig {
bool has_preferences;
RadioConfig_UserPreferences preferences;
} RadioConfig;
/* Helper constants for enums */
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_RU
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1))
#define _ChargeCurrent_MIN ChargeCurrent_MAUnset
#define _ChargeCurrent_MAX ChargeCurrent_MA1320
#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1))
#define _GpsOperation_MIN GpsOperation_GpsOpUnset
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
#define _LocationSharing_MIN LocationSharing_LocUnset
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
#define RadioConfig_UserPreferences_send_owner_interval_tag 2
#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4
#define RadioConfig_UserPreferences_screen_on_secs_tag 5
#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6
#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7
#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8
#define RadioConfig_UserPreferences_sds_secs_tag 9
#define RadioConfig_UserPreferences_ls_secs_tag 10
#define RadioConfig_UserPreferences_min_wake_secs_tag 11
#define RadioConfig_UserPreferences_wifi_ssid_tag 12
#define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_charge_current_tag 16
#define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
#define RadioConfig_UserPreferences_gps_attempt_time_tag 36
#define RadioConfig_UserPreferences_is_router_tag 37
#define RadioConfig_UserPreferences_is_low_power_tag 38
#define RadioConfig_UserPreferences_fixed_position_tag 39
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120
#define RadioConfig_UserPreferences_serialplugin_echo_tag 121
#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122
#define RadioConfig_UserPreferences_serialplugin_txd_tag 123
#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124
#define RadioConfig_UserPreferences_serialplugin_mode_tag 125
#define RadioConfig_UserPreferences_ext_notification_plugin_enabled_tag 126
#define RadioConfig_UserPreferences_ext_notification_plugin_output_ms_tag 127
#define RadioConfig_UserPreferences_ext_notification_plugin_output_tag 128
#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130
#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131
#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132
#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133
#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134
#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136
#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137
#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140
#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143
#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144
#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
#define RadioConfig_preferences_tag 1
/* Struct field encoding specification for nanopb */
#define RadioConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1)
#define RadioConfig_CALLBACK NULL
#define RadioConfig_DEFAULT NULL
#define RadioConfig_preferences_MSGTYPE RadioConfig_UserPreferences
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \
X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \
X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \
X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \
X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \
X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \
X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \
X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \
X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) \
X(a, STATIC, SINGULAR, UINT32, serialplugin_mode, 125) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_enabled, 126) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \
X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \
X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \
X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \
X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \
X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \
X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
extern const pb_msgdesc_t RadioConfig_msg;
extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define RadioConfig_fields &RadioConfig_msg
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
/* Maximum encoded size of messages (where known) */
#define RadioConfig_size 348
#define RadioConfig_UserPreferences_size 345
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -11,6 +11,7 @@
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <SPIFFS.h>
#include "RadioLibInterface.h"
#ifndef NO_ESP32
#include "esp_task_wdt.h"
@@ -928,10 +929,17 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery()));
res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB()));
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
res->println("},");
res->println("\"radio\": {");
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
res->println("}");
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
}

View File

@@ -18,8 +18,8 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
if (!pb_encode(&stream, fields, src_struct)) {
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
assert(0); // FIXME - panic
DEBUG_MSG("Panic: can't encode protobuf %s, did you make a field too large?\n", PB_GET_ERROR(&stream));
assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options
} else {
return stream.bytes_written;
}

View File

@@ -2,6 +2,7 @@
#include "mesh/generated/mesh.pb.h"
#include "mesh/generated/deviceonly.pb.h"
#include "mesh/generated/admin.pb.h"
// this file defines constants which come from mesh.options
@@ -16,6 +17,9 @@
/// max number of nodes allowed in the mesh
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
/// Max number of channels allowed
#define MAX_NUM_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0]))
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
/// returns the encoded packet size
size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct);

View File

@@ -10,6 +10,7 @@
#include "nimble/NimbleDefs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "sleep.h"
#include <Arduino.h>
#include <WiFi.h>
@@ -226,16 +227,14 @@ static int gap_event(struct ble_gap_event *event, void *arg)
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
pkey.action = event->passkey.params.action;
DEBUG_MSG("dp: %d now:%d\n",doublepressed, now);
if (doublepressed > 0 && (doublepressed + (30*1000)) > now)
{
DEBUG_MSG("dp: %d now:%d\n", doublepressed, now);
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > now) {
DEBUG_MSG("User has overridden passkey or no display available\n");
pkey.passkey = defaultBLEPin;
}
else {
pkey.passkey = defaultBLEPin;
} else {
DEBUG_MSG("Using random passkey\n");
pkey.passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
}
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", pkey.passkey);
@@ -395,7 +394,6 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
}
}
/**
* A helper function that implements simple read and write handling for a uint32_t
*
@@ -449,8 +447,7 @@ int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt)
if (len < vlen) {
DEBUG_MSG("Error: wrongsized write\n");
return BLE_ATT_ERR_UNLIKELY;
}
else {
} else {
DEBUG_MSG("BLE writing bytes\n");
}
} else {
@@ -465,7 +462,21 @@ void disablePin()
{
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
// keep track of when it was pressed, so we know it was within X seconds
doublepressed = millis();
// Flash the LED
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
doublepressed = millis();
}
// This routine is called multiple times, once each time we come back from sleep
@@ -549,7 +560,7 @@ void setBluetoothEnable(bool on)
firstTime = 0;
} else {
#ifndef NO_ESP32
initWifi(0);
initWifi(0);
#endif
}
} else {

View File

@@ -6,30 +6,13 @@
class NRF52CryptoEngine : public CryptoEngine
{
/// How many bytes in our key
uint8_t keySize = 0;
const uint8_t *keyBytes;
public:
NRF52CryptoEngine() {}
~NRF52CryptoEngine() {}
/**
* Set the key used for encrypt, decrypt.
*
* As a special case: If all bytes are zero, we assume _no encryption_ and send all data in cleartext.
*
* @param numBytes must be 16 (AES128), 32 (AES256) or 0 (no crypt)
* @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(size_t numBytes, uint8_t *bytes)
{
keySize = numBytes;
keyBytes = bytes;
}
/**
* Encrypt a packet
*
@@ -39,11 +22,11 @@ class NRF52CryptoEngine : public CryptoEngine
{
// DEBUG_MSG("NRF52 encrypt!\n");
if (keySize != 0) {
if (key.length > 0) {
ocrypto_aes_ctr_ctx ctx;
initNonce(fromNode, packetNum);
ocrypto_aes_ctr_init(&ctx, keyBytes, keySize, nonce);
ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce);
ocrypto_aes_ctr_encrypt(&ctx, bytes, bytes, numBytes);
}
@@ -53,11 +36,11 @@ class NRF52CryptoEngine : public CryptoEngine
{
// DEBUG_MSG("NRF52 decrypt!\n");
if (keySize != 0) {
if (key.length > 0) {
ocrypto_aes_ctr_ctx ctx;
initNonce(fromNode, packetNum);
ocrypto_aes_ctr_init(&ctx, keyBytes, keySize, nonce);
ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce);
ocrypto_aes_ctr_decrypt(&ctx, bytes, bytes, numBytes);
}

View File

@@ -16,8 +16,14 @@ static void printUsageErrorMsg(uint32_t cfsr)
cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb
if ((cfsr & (1 << 9)) != 0)
FAULT_MSG("Divide by zero\n");
if ((cfsr & (1 << 8)) != 0)
else if ((cfsr & (1 << 8)) != 0)
FAULT_MSG("Unaligned\n");
else if ((cfsr & (1 << 1)) != 0)
FAULT_MSG("Invalid state\n");
else if ((cfsr & (1 << 0)) != 0)
FAULT_MSG("Invalid instruction\n");
else
FAULT_MSG("FIXME add to printUsageErrorMsg!\n");
}
static void printBusErrorMsg(uint32_t cfsr)
@@ -71,8 +77,9 @@ extern "C" void HardFault_Impl(uint32_t stack[])
FAULT_MSG("Done with fault report - Waiting to reboot\n");
asm volatile("bkpt #01"); // Enter the debugger if one is connected
while (1)
;
// Don't spin, so that the debugger will let the user step to next instruction
// while (1) ;
}
extern "C" void HardFault_Handler(void)

View File

@@ -51,7 +51,7 @@ void getMacAddr(uint8_t *dmac)
NRF52Bluetooth *nrf52Bluetooth;
static bool bleOn = false;
static const bool enableBle = true; // Set to false for easier debugging
static const bool enableBle = false; // Set to false for easier debugging
void setBluetoothEnable(bool on)
{

125
src/plugins/AdminPlugin.cpp Normal file
View File

@@ -0,0 +1,125 @@
#include "AdminPlugin.h"
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "Router.h"
#include "configuration.h"
#include "main.h"
AdminPlugin *adminPlugin;
void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) {
if (req.decoded.want_response) {
// We create the reply here
AdminMessage r = AdminMessage_init_default;
r.get_channel_response = channels.getByIndex(channelIndex);
r.which_variant = AdminMessage_get_channel_response_tag;
reply = allocDataProtobuf(r);
}
}
void AdminPlugin::handleGetRadio(const MeshPacket &req)
{
if (req.decoded.want_response) {
// We create the reply here
AdminMessage r = AdminMessage_init_default;
r.get_radio_response = devicestate.radio;
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
r.which_variant = AdminMessage_get_radio_response_tag;
reply = allocDataProtobuf(r);
}
}
bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *r)
{
assert(r);
switch (r->which_variant) {
case AdminMessage_set_owner_tag:
DEBUG_MSG("Client is setting owner\n");
handleSetOwner(r->set_owner);
break;
case AdminMessage_set_radio_tag:
DEBUG_MSG("Client is setting radio\n");
handleSetRadio(r->set_radio);
break;
case AdminMessage_set_channel_tag:
DEBUG_MSG("Client is setting channel\n");
handleSetChannel(r->set_channel);
break;
case AdminMessage_get_channel_request_tag:
DEBUG_MSG("Client is getting channel %d\n", r->get_channel_request - 1);
handleGetChannel(mp, r->get_channel_request - 1);
break;
case AdminMessage_get_radio_request_tag:
DEBUG_MSG("Client is getting radio\n");
handleGetRadio(mp);
break;
default:
break;
}
return false; // Let others look at this message also if they want
}
void AdminPlugin::handleSetOwner(const User &o)
{
int changed = 0;
if (*o.long_name) {
changed |= strcmp(owner.long_name, o.long_name);
strcpy(owner.long_name, o.long_name);
}
if (*o.short_name) {
changed |= strcmp(owner.short_name, o.short_name);
strcpy(owner.short_name, o.short_name);
}
if (*o.id) {
changed |= strcmp(owner.id, o.id);
strcpy(owner.id, o.id);
}
if (changed) // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner();
}
void AdminPlugin::handleSetChannel(const Channel &cc)
{
channels.setChannel(cc);
bool didReset = service.reloadConfig();
/* FIXME - do we need this still?
if (didReset) {
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
} */
}
void AdminPlugin::handleSetRadio(const RadioConfig &r)
{
radioConfig = r;
bool didReset = service.reloadConfig();
/* FIXME - do we need this still? if (didReset) {
state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client
} */
}
MeshPacket *AdminPlugin::allocReply()
{
auto r = reply;
reply = NULL; // Only use each reply once
return r;
}
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
{
// FIXME, restrict to the admin channel for rx
}

37
src/plugins/AdminPlugin.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include "ProtobufPlugin.h"
/**
* Routing plugin for router control messages
*/
class AdminPlugin : public ProtobufPlugin<AdminMessage>
{
MeshPacket *reply = NULL;
public:
/** Constructor
* name is for debugging output
*/
AdminPlugin();
protected:
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *p);
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */
virtual MeshPacket *allocReply();
private:
void handleSetOwner(const User &o);
void handleSetChannel(const Channel &cc);
void handleSetRadio(const RadioConfig &r);
void handleGetChannel(const MeshPacket &req, uint32_t channelIndex);
void handleGetRadio(const MeshPacket &req);
};
extern AdminPlugin *adminPlugin;

View File

@@ -0,0 +1,176 @@
#include "ExternalNotificationPlugin.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
#include "configuration.h"
#include <Arduino.h>
//#include <assert.h>
/*
Documentation:
https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md
This plugin supports:
https://github.com/meshtastic/Meshtastic-device/issues/654
Quick reference:
radioConfig.preferences.ext_notification_plugin_enabled
0 = Disabled (Default)
1 = Enabled
radioConfig.preferences.ext_notification_plugin_active
0 = Active Low (Default)
1 = Active High
radioConfig.preferences.ext_notification_plugin_alert_message
0 = Disabled (Default)
1 = Alert when a text message comes
radioConfig.preferences.ext_notification_plugin_alert_bell
0 = Disabled (Default)
1 = Alert when the bell character is received
radioConfig.preferences.ext_notification_plugin_output
GPIO of the output. (Default = 13)
radioConfig.preferences.ext_notification_plugin_output_ms
Amount of time in ms for the alert. Default is 1000.
*/
// Default configurations
#define EXT_NOTIFICATION_PLUGIN_OUTPUT 13
#define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 1000
#define ASCII_BELL 0x07
ExternalNotificationPlugin *externalNotificationPlugin;
ExternalNotificationPluginRadio *externalNotificationPluginRadio;
ExternalNotificationPlugin::ExternalNotificationPlugin() : concurrency::OSThread("ExternalNotificationPlugin") {}
bool externalCurrentState = 0;
uint32_t externalTurnedOn = 0;
int32_t ExternalNotificationPlugin::runOnce()
{
#ifndef NO_ESP32
/*
Uncomment the preferences below if you want to use the plugin
without having to configure it from the PythonAPI or WebUI.
*/
// radioConfig.preferences.ext_notification_plugin_enabled = 1;
// radioConfig.preferences.ext_notification_plugin_alert_message = 1;
// radioConfig.preferences.ext_notification_plugin_active = 1;
// radioConfig.preferences.ext_notification_plugin_alert_bell = 1;
// radioConfig.preferences.ext_notification_plugin_output_ms = 1000;
// radioConfig.preferences.ext_notification_plugin_output = 13;
if (radioConfig.preferences.ext_notification_plugin_enabled) {
if (firstTime) {
DEBUG_MSG("Initializing External Notification Plugin\n");
// Set the direction of a pin
pinMode((radioConfig.preferences.ext_notification_plugin_output
? radioConfig.preferences.ext_notification_plugin_output
: EXT_NOTIFICATION_PLUGIN_OUTPUT),
OUTPUT);
// Turn off the pin
setExternalOff();
externalNotificationPluginRadio = new ExternalNotificationPluginRadio();
firstTime = 0;
} else {
if (externalCurrentState) {
// If the output is turned on, turn it back off after the given period of time.
if (externalTurnedOn + (radioConfig.preferences.ext_notification_plugin_output_ms
? radioConfig.preferences.ext_notification_plugin_output_ms
: EXT_NOTIFICATION_PLUGIN_OUTPUT_MS) <
millis()) {
DEBUG_MSG("Turning off external notification\n");
setExternalOff();
}
}
}
return (25);
} else {
DEBUG_MSG("External Notification Plugin Disabled\n");
return (INT32_MAX);
}
#endif
}
void ExternalNotificationPlugin::setExternalOn()
{
externalCurrentState = 1;
externalTurnedOn = millis();
digitalWrite((radioConfig.preferences.ext_notification_plugin_output ? radioConfig.preferences.ext_notification_plugin_output
: EXT_NOTIFICATION_PLUGIN_OUTPUT),
(radioConfig.preferences.ext_notification_plugin_active ? true : false));
}
void ExternalNotificationPlugin::setExternalOff()
{
externalCurrentState = 0;
digitalWrite((radioConfig.preferences.ext_notification_plugin_output ? radioConfig.preferences.ext_notification_plugin_output
: EXT_NOTIFICATION_PLUGIN_OUTPUT),
(radioConfig.preferences.ext_notification_plugin_active ? false : true));
}
// --------
bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp)
{
#ifndef NO_ESP32
if (radioConfig.preferences.ext_notification_plugin_enabled) {
auto &p = mp.decoded;
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
// Need to know if and how this could be a problem.
if (radioConfig.preferences.ext_notification_plugin_alert_bell) {
DEBUG_MSG("externalNotificationPlugin - Notification Bell\n");
for (int i = 0; i < p.payload.size; i++) {
if (p.payload.bytes[i] == ASCII_BELL) {
externalNotificationPlugin->setExternalOn();
}
}
}
if (radioConfig.preferences.ext_notification_plugin_alert_message) {
DEBUG_MSG("externalNotificationPlugin - Notification Plugin\n");
externalNotificationPlugin->setExternalOn();
}
}
} else {
DEBUG_MSG("External Notification Plugin Disabled\n");
}
#endif
return true; // Let others look at this message also if they want
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include "SinglePortPlugin.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include <Arduino.h>
#include <functional>
class ExternalNotificationPlugin : private concurrency::OSThread
{
bool firstTime = 1;
public:
ExternalNotificationPlugin();
void setExternalOn();
void setExternalOff();
void getExternal();
protected:
virtual int32_t runOnce();
};
extern ExternalNotificationPlugin *externalNotificationPlugin;
/*
* Radio interface for ExternalNotificationPlugin
*
*/
class ExternalNotificationPluginRadio : public SinglePortPlugin
{
public:
ExternalNotificationPluginRadio() : SinglePortPlugin("ExternalNotificationPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
protected:
//virtual MeshPacket *allocReply();
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceived(const MeshPacket &mp);
};
extern ExternalNotificationPluginRadio *externalNotificationPluginRadio;

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