Compare commits

...

170 Commits

Author SHA1 Message Date
Jm Casler
ea40bd991c Merge pull request #660 from mc-hamster/master
Update version.properties to 1.1.33
2021-01-25 17:12:32 -08:00
Jm Casler
e19dd46f0f Merge branch 'master' into master 2021-01-25 17:05:52 -08:00
Jm
532b06c280 Update version.properties to 1.1.33 2021-01-25 17:01:47 -08:00
Jm Casler
0cf7aaffff Merge pull request #658 from sachaw/master
Another missing header
2021-01-24 18:06:14 -08:00
Sacha Weatherstone
e2e1819ef1 Merge branch 'master' of https://github.com/sachaw/meshtastic-device 2021-01-24 10:49:23 +11:00
Sacha Weatherstone
31b89e2932 Another header required 2021-01-24 10:48:48 +11:00
Jm Casler
a021ff7eb8 Merge pull request #656 from sachaw/master
fix cors for API requsts & fix spiffs url
2021-01-22 23:36:27 -08:00
Jm Casler
bb5d0fac90 Merge branch 'master' into master 2021-01-22 23:26:53 -08:00
Jm Casler
df5ed64514 Merge pull request #655 from mc-hamster/master
Fix for #650 - build-all.sh will fail
2021-01-22 23:26:39 -08:00
Sacha Weatherstone
9db5f9ff67 fix cors for API requsts & fix spiffs url 2021-01-23 17:42:15 +11:00
Jm
ca83a78e13 Fix for #650 - build-all.sh will fail 2021-01-22 19:50:12 -08:00
Jm Casler
13eef9a309 Merge pull request #653 from mc-hamster/master
Update comments in SerialPlugin
2021-01-20 21:42:12 -08:00
Jm Casler
2a8ac2c0c6 Merge branch 'master' into master 2021-01-20 19:04:46 -08:00
Jm Casler
c97342db99 Merge pull request #63 from mc-hamster/serial
Update comments on SerialPlugin
2021-01-20 19:03:44 -08:00
Jm Casler
d7b2a0ed79 Merge pull request #62 from mc-hamster/master
update serial from master
2021-01-20 19:02:58 -08:00
Jm
af0a1b5db5 Update comments of SerialPlugin 2021-01-20 19:02:08 -08:00
Jm Casler
9cf030d587 Merge pull request #652 from mc-hamster/master
#649 More webserver refactoring
2021-01-19 21:52:56 -08:00
Jm
c04d70d5e5 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-19 21:38:30 -08:00
Jm
2a47819fd6 #649 More webserver refactoring 2021-01-19 21:38:17 -08:00
Jm Casler
4516c8f9b5 Merge pull request #61 from meshtastic/master
Merge pull request #648 from mc-hamster/master
2021-01-19 21:27:24 -08:00
Jm
e4fdf26dc7 #649 - First pass on the refactoring of the webserver 2021-01-19 21:26:23 -08:00
Jm Casler
39d14fedc2 Merge pull request #648 from mc-hamster/master
#647 - Fix for admin mode being forced on boards without hardware pullup
2021-01-18 10:56:13 -08:00
Jm Casler
1da38fc748 Merge branch 'master' into master 2021-01-18 10:44:38 -08:00
Jm
b5f50efdcd #647 - Fix for admin mode being forced on boards without hardware pullup 2021-01-18 10:43:15 -08:00
Jm Casler
046e691d4e Merge pull request #645 from mc-hamster/master
#635 Added web_request_count and fixed printf of psram
2021-01-17 17:26:56 -08:00
Jm Casler
e72531b090 Merge pull request #60 from mc-hamster/master
Update Serial
2021-01-17 15:41:21 -08:00
Jm
81e320c9cf Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-17 15:40:27 -08:00
Jm
fa8cc74141 Update to Serial Plugin to make it easy to override the device configuration 2021-01-17 15:40:25 -08:00
Jm Casler
c7d9ff7cc0 Merge branch 'master' into master 2021-01-17 10:36:54 -08:00
Jm
8704a9d08f Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-17 10:30:40 -08:00
Jm
c0d27e2ce9 #635 Added web_request_count and fixed printf of psram 2021-01-17 10:30:34 -08:00
Jm Casler
84b9028ecb Merge pull request #642 from mc-hamster/master
#635 - Added memory usage statistics
2021-01-17 04:52:03 -08:00
Jm Casler
4fda7098c0 Merge branch 'master' into master 2021-01-17 04:44:42 -08:00
Jm
8e8264efb0 #635 - Added memory usage statistics 2021-01-17 00:29:29 -08:00
Jm Casler
54e780a6ca Merge pull request #641 from mc-hamster/master
Update generated protobuf; Update serial plugin; #615 - Configure charge current
2021-01-17 00:18:33 -08:00
Jm
125eb2b784 Fix for build fail on NRF 2021-01-17 00:11:26 -08:00
Jm Casler
6ea9cdc83b Merge pull request #59 from mc-hamster/master
Update serial plugin with new protobufs
2021-01-17 00:03:13 -08:00
Jm
c0711fde69 #615 Allow rate for tbeam battery charger to be configurable 2021-01-16 23:10:08 -08:00
Jm
20b8d2c4a5 Set the port to PortNum_SERIAL_APP 2021-01-16 22:41:33 -08:00
Jm
73ae151971 Added serialplugin_timeout to SerialPlugin 2021-01-16 22:39:28 -08:00
Jm Casler
f4806c9dd7 Merge branch 'serial' into master 2021-01-16 22:35:56 -08:00
Jm
79532210e8 SerialPlugin - Update comments with better instructions 2021-01-16 22:31:56 -08:00
Jm
d7f26493a5 Update to SerialPlugin to take advantage of the configs 2021-01-16 22:27:33 -08:00
Jm
b9d025dd58 Missed adding the proto file 2021-01-16 20:53:45 -08:00
Jm
f435086a5a Update generated protobufs 2021-01-16 20:50:58 -08:00
Jm
3dcdf372d7 add remote update 2021-01-16 20:12:31 -08:00
Jm
cd84f2867c Updated submodule proto 2021-01-16 20:00:37 -08:00
Jm
cafe00e463 Update of serialplugin 2021-01-16 19:40:47 -08:00
Jm
6da4e30215 Merge branch 'serial' of https://github.com/mc-hamster/Meshtastic-device into serial 2021-01-14 22:38:53 -08:00
Jm
dbf0569e29 Update comments for serial pins recommended by @ryguy 2021-01-14 22:36:51 -08:00
Jm Casler
18220b88b3 Merge pull request #58 from mc-hamster/master
update serial from master
2021-01-14 22:36:17 -08:00
Jm Casler
665da2fb00 Merge pull request #57 from meshtastic/master
Merge pull request #633 from mc-hamster/master
2021-01-14 22:34:01 -08:00
Jm Casler
57ffe6622d Merge pull request #56 from mc-hamster/master
update serial from master
2021-01-14 22:25:20 -08:00
Jm Casler
485fec9649 Merge pull request #633 from mc-hamster/master
Fix for #632 (move web server to osthread) and #611 (move airtime to osthread)
2021-01-14 22:06:18 -08:00
Jm
bd85736226 SerialPlugin - Exclude working on non esp32 platforms. 2021-01-14 21:59:26 -08:00
Jm
4ec8986934 Fixed switching to uint32 from 16 for airtime in json report 2021-01-14 21:45:41 -08:00
Jm Casler
b963216764 Merge pull request #55 from mc-hamster/serial
Update for SerialPlugin and Airtime
2021-01-14 21:43:28 -08:00
Jm Casler
813fd95bc8 Merge pull request #54 from geeksville/mc-master
fix @mc-hamster build to work on linux/nrf52
2021-01-14 21:33:27 -08:00
Kevin Hester
3598c91c29 fix @mc-hamster build to work on linux/nrf52 2021-01-15 13:30:40 +08:00
Jm
507cd1dd20 #639 - Move from counting seconds to milliseconds 2021-01-14 18:40:18 -08:00
Jm
e39506824d Added more comments 2021-01-14 18:08:23 -08:00
Jm
f68a31ab28 serialplugin - ability to configure ACK 2021-01-13 23:21:55 -08:00
Jm
b1181deb58 serialplugin - Added my todo list 2021-01-13 23:02:13 -08:00
Jm
89b32dd7ee Fix comments in serial plugin 2021-01-13 22:51:36 -08:00
Jm
c54e87f9a2 Update SerialPlugin.cpp
Added documentation.
2021-01-13 22:50:02 -08:00
Jm
eee7e1de57 Update to serial plugin 2021-01-13 22:39:11 -08:00
Jm
3c60df1565 Partial work on the SerialPlugin 2021-01-13 20:22:59 -08:00
Jm Casler
a827017bd2 Merge pull request #53 from crossan007/master
add power statistics for #635
2021-01-11 17:54:27 -08:00
Charles Crossan
95c502c658 fix typo 2021-01-11 20:30:02 -05:00
Charles Crossan
0f573901d5 didn't need power.h 2021-01-11 20:28:09 -05:00
Charles Crossan
fdc9bf5783 add power statistics for #635 2021-01-11 20:25:02 -05:00
Jm Casler
37e0f9a325 Merge pull request #52 from mc-hamster/osthread
maybe this will fix the linux build?
2021-01-09 19:32:40 -08:00
Jm
0c06d8db3c maybe this will fix the linux build? 2021-01-09 19:31:16 -08:00
Jm Casler
0be4bbb369 Merge pull request #51 from mc-hamster/osthread
Does this fix the linux build?
2021-01-09 19:17:45 -08:00
Jm
f02ab88393 Does this fix the linux build? 2021-01-09 19:15:10 -08:00
Jm Casler
c9d4de8808 Merge pull request #50 from mc-hamster/osthread
fixed in linux now?
2021-01-09 19:07:16 -08:00
Jm
adb912b665 fixed in linux now? 2021-01-09 19:06:34 -08:00
Jm Casler
3f5da1e03e Merge pull request #49 from mc-hamster/osthread
another linux fix?
2021-01-09 18:37:04 -08:00
Jm
0a40d920e3 Update BluetoothUtil.cpp
yet another linux fix?
2021-01-09 18:36:23 -08:00
Jm Casler
39311f1e40 Merge pull request #48 from mc-hamster/osthread
is linux fixed now?
2021-01-09 18:27:32 -08:00
Jm
9cd24a5646 is linux fixed now? 2021-01-09 18:27:03 -08:00
Jm Casler
1c0efde315 Merge pull request #47 from mc-hamster/osthread
is linux fixed now?
2021-01-09 18:09:57 -08:00
Jm
c82905bbdd is linux fixed now? 2021-01-09 18:09:16 -08:00
Jm Casler
275eace968 Merge pull request #46 from mc-hamster/osthread
more linux fixes
2021-01-09 17:52:09 -08:00
Jm
5688c8b81e more linux build fixes 2021-01-09 17:50:58 -08:00
Jm
8b2798abd5 Added a few commented out default_envs 2021-01-09 17:44:20 -08:00
Jm Casler
6d977923b6 Merge pull request #45 from mc-hamster/osthread
more fixes for linux build
2021-01-09 17:34:34 -08:00
Jm
52dacaed37 more fixes for linux build 2021-01-09 17:30:36 -08:00
Jm Casler
7a381eaea1 Merge pull request #44 from mc-hamster/osthread
Fix for breaking the linux build
2021-01-09 13:47:43 -08:00
Jm
69391e186b Fix for breaking the linux build 2021-01-09 13:47:10 -08:00
Jm Casler
06f8beaa17 Merge pull request #43 from mc-hamster/osthread
fix for building on NRF platform.
2021-01-08 23:00:36 -08:00
Jm
3798f4ca5b fix for building on NRF platform. 2021-01-08 22:59:37 -08:00
Jm Casler
4fd243a6e4 Merge pull request #42 from mc-hamster/osthread
Moving web server and airtime to osthread model. Moved web server to mesh/wifi
2021-01-08 22:29:45 -08:00
Jm
d458f673be Web server is now treaded and moved to mesh/wifi/* 2021-01-08 22:25:44 -08:00
Jm
cfcb00b943 that's enough for tonight. web server is in its own thread, needs to be further optimized but it works enough. next is to refactor. 2021-01-08 20:43:51 -08:00
Jm
977e47d109 partial work 2021-01-08 20:06:11 -08:00
Jm Casler
cfeb40f36d Merge pull request #41 from mc-hamster/master
Updated osthread branch from master
2021-01-08 19:57:19 -08:00
Jm Casler
4fcc3ac1de Merge pull request #40 from meshtastic/master
Updated my master from head
2021-01-08 19:54:57 -08:00
Kevin Hester
f4afa6931b Merge pull request #630 from geeksville/dev
Dev
2021-01-08 13:38:23 +08:00
Kevin Hester
71be71d63d add note about how to send messages thanks @rw-w for the question 2021-01-08 13:31:28 +08:00
Kevin Hester
de9f7e6c39 update protos 2021-01-08 13:21:14 +08:00
Kevin Hester
7c8db2b501 Merge remote-tracking branch 'root/master' into dev
# Conflicts:
#	docs/software/plugin-api.md
2021-01-08 13:20:28 +08:00
Kevin Hester
cd653f9434 Merge pull request #629 from ry-w/patch-1
Update plugin-api.md
2021-01-08 13:19:03 +08:00
Kevin Hester
74bc05936d Merge remote-tracking branch 'root/master' into dev 2021-01-08 13:16:27 +08:00
Kevin Hester
7aacfd66ef add assertIsSetup() and use it from OSThread constructor
fixes nasty bug @mc-hamster discovered with plugin order of operations
2021-01-08 13:15:49 +08:00
Kevin Hester
3636b87db0 formatting 2021-01-08 11:52:43 +08:00
ry-w
d6bd328576 Update plugin-api.md
Couple of clarifications, and fixes to minor errors.
2021-01-06 14:24:51 -08:00
Jm
0af5b225c4 intermediate 2021-01-05 23:32:33 -08:00
Jm
f7dcef39ce intermediate work 2021-01-05 23:21:14 -08:00
Kevin Hester
07042178d2 Merge pull request #627 from mc-hamster/master
Include instrusctions for real time backtrace decoding.
2021-01-06 14:55:46 +08:00
Kevin Hester
243878f2a0 Merge branch 'master' into master 2021-01-06 14:39:57 +08:00
Kevin Hester
d3f8a76cce Merge pull request #625 from geeksville/dev
fix #624 - update battery level and current time on mynodeinfo
2021-01-06 14:39:42 +08:00
Kevin Hester
20131a51a2 Merge branch 'master' into dev 2021-01-06 14:31:11 +08:00
Kevin Hester
1c9a369774 Merge branch 'master' into master 2021-01-06 13:26:30 +08:00
Kevin Hester
dcb426f58f Merge pull request #628 from IZ1IVA/patch-3
Update radio-settings.md
2021-01-06 13:23:53 +08:00
Jm Casler
35bcb5297a Merge pull request #38 from mc-hamster/master
update from master to osthread
2021-01-05 19:04:15 -08:00
Jm
84e3d7c276 Test fixes for Tobiases 2021-01-05 18:57:03 -08:00
IZ1IVA
9b03f0ac8e Update radio-settings.md
Fixed frequency table non showing
2021-01-05 12:13:18 +01:00
Jm Casler
eb402809e2 Merge branch 'master' into master 2021-01-04 22:16:07 -08:00
Jm
e9c9e40624 Include instrusctions for real time backtrace decoding. 2021-01-04 22:15:19 -08:00
Kevin Hester
01eed97b91 Merge branch 'master' into dev 2021-01-04 10:00:38 +08:00
Kevin Hester
94a47dba7d fix #624 - update battery level and current time on mynodeinfo 2021-01-04 09:59:53 +08:00
Kevin Hester
bce2c9347b Merge pull request #623 from geeksville/dev
Dev
2021-01-03 21:26:57 +08:00
Kevin Hester
da8b1d41c7 1.1.32 2021-01-03 20:57:59 +08:00
Kevin Hester
3ddae5faec fix build for esp32 2021-01-03 20:12:31 +08:00
Kevin Hester
34faea6100 fix #622 - we might not have a local position yet early in the boot 2021-01-03 20:11:26 +08:00
Kevin Hester
01848a9e5d moved wifi code 2021-01-03 20:11:03 +08:00
Kevin Hester
10db80541f Merge remote-tracking branch 'root/master' into dev 2021-01-03 10:12:08 +08:00
Kevin Hester
edd1268f5f portduino: begin adding wifi implementation 2021-01-03 10:11:20 +08:00
Jm Casler
11c16e8bbc Merge pull request #621 from mc-hamster/master
Remove text "This interface is experimental"
2021-01-02 10:39:20 -08:00
Jm Casler
7d411351c0 Merge pull request #37 from meshtastic/master
update from head
2021-01-02 10:20:56 -08:00
Jm
df21602c90 Remove text "This interface is experimental" 2021-01-02 10:18:35 -08:00
Kevin Hester
ce4ccf3cc4 no need for lora CS control on linux, the spi controller handles it 2021-01-02 19:40:24 +08:00
Kevin Hester
a7f93de3ad add a software based cross platform AES-CTR implementation 2021-01-02 18:20:51 +08:00
Kevin Hester
8e8257adf3 Merge pull request #619 from geeksville/dev
1.1.31
2021-01-02 16:51:08 +08:00
Kevin Hester
e627725dfc 1.1.31 2021-01-02 14:15:07 +08:00
Kevin Hester
b3ba557b8b cleanup portuino 2021-01-02 14:14:59 +08:00
Kevin Hester
bd03650140 Merge pull request #612 from wfang2002/master
Fix GPS turned on then off immediately every 2 minutes
2021-01-02 14:13:48 +08:00
Kevin Hester
42f51f33a8 Merge branch 'master' into master 2021-01-02 14:12:07 +08:00
Jm
8295b88d96 Checking in work so I don't lose it. Nothing's broke with the build. 2021-01-01 21:20:34 -08:00
Kevin Hester
70313b2660 Merge pull request #618 from geeksville/dev
portuino now kinda works for pinetab
2021-01-02 13:02:38 +08:00
Kevin Hester
745d3775b4 Merge branch 'master' into dev 2021-01-02 12:54:04 +08:00
Kevin Hester
aa176b6593 portuino now kinda works with the pinetab lora USB module.
still need to add an AEX256 impl for the linux port and optimize a bit
2021-01-02 12:38:18 +08:00
Kevin Hester
b0e3a7524f assign more portduino pins 2021-01-02 11:23:30 +08:00
Kevin Hester
5ceee50bb5 bug: we've always been setting gpio 0 as an input on rf95 based devices
found because portduino provides full visibility to all IO operations
to the hw simulator.
2021-01-02 11:23:18 +08:00
Kevin Hester
ebdad76fb2 portduino: gpios now kinda work on linux 2021-01-02 11:06:38 +08:00
Jm
925829dc58 Partial work to migrate to OSThread model 2021-01-01 12:31:46 -08:00
Jm Casler
e04ea853dc Merge pull request #616 from mc-hamster/master
Display AP connection usage only when in AP mode & Cleanup some compile time warnings that were driving me crazy
2020-12-31 21:26:32 -08:00
Jm Casler
9587729bb0 Merge branch 'master' into master 2020-12-31 20:55:32 -08:00
Jm
6ec368bf02 Commenting out upload ports 2020-12-31 20:50:11 -08:00
Jm
d71c7b512f Cleanup some compile time warnings that were driving me crazy. 2020-12-31 20:44:53 -08:00
Jm
349701ac14 Display AP connection usage only when in AP mode 2020-12-31 20:17:18 -08:00
Kevin Hester
d424fa5ea8 Merge pull request #605 from oztug/master
Genieblocks LoRa support
2020-12-31 14:19:30 +08:00
Kevin Hester
ca6293eefe Merge branch 'master' into master 2020-12-31 14:05:56 +08:00
Kevin Hester
d289e8a86f Merge remote-tracking branch 'root/master' into dev 2020-12-31 14:02:47 +08:00
Kevin Hester
96328526b7 Merge pull request #613 from wfang2002/#604_rtc
Shall upgrade RTC currentQuality if higher q available (fix #604)
2020-12-31 13:58:40 +08:00
Wei Fang
279c89dca3 Shall upgrade RTC currentQuality if higher q available 2020-12-30 21:46:43 -08:00
wfang2002
a7a52e08d1 Merge branch 'master' into master 2020-12-30 21:26:51 -08:00
Wei Fang
f6336855d0 Fix GPS turned on then off immediately every 2 minutes 2020-12-30 21:11:03 -08:00
Jm Casler
727d8a6456 Merge pull request #610 from mc-hamster/master
Fix for meshtastic#606 and meshtastic#597
2020-12-30 21:10:15 -08:00
Jm Casler
7b80b95381 Merge pull request #36 from mc-hamster/upload
Fix for meshtastic#606 and meshtastic#597
2020-12-30 18:19:52 -08:00
Jm
2867f8fd53 Fix for #606 and #597
Upload interface randomly crashes #606

watchdog timer exception while building https certificate #597
2020-12-30 18:10:35 -08:00
Kevin Hester
cdf416cb73 partial fix for #608 - when a new TCP API connection arrives, close old one completely 2020-12-31 10:02:18 +08:00
Jm
7716d62018 Remove old comment 2020-12-30 15:16:04 -08:00
Jm Casler
d5f76b16b9 write readLength to debug console 2020-12-30 14:52:39 -08:00
Jm Casler
552406b15f Merge pull request #34 from meshtastic/master
update from master
2020-12-30 13:59:58 -08:00
oztug
9a3d558f61 Revert "Update proto"
This reverts commit 85ddf3be1b.
2020-12-30 01:27:20 +03:00
oztug
85ddf3be1b Update proto 2020-12-30 01:26:12 +03:00
oztug
3ca42b8f51 Merge remote-tracking branch 'upstream/master' 2020-12-30 01:24:13 +03:00
oztug
5595fb38c1 Genieblocks Lora support 2020-12-29 18:08:11 +03:00
61 changed files with 1616 additions and 726 deletions

View File

@@ -14,7 +14,7 @@ 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 # 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" BOARDS_NRF52="lora-relay-v1"
NUM_JOBS=2 NUM_JOBS=2 || true
OUTDIR=release/latest OUTDIR=release/latest

View File

@@ -2,7 +2,7 @@
We use the same channel maps as LoRaWAN (though this is not LoRaWAN). We use the same channel maps as LoRaWAN (though this is not LoRaWAN).
![freq table](images/LoRa-Frequency-Bands.jpg) ![freq table](/images/LoRa-Frequency-Bands.jpg)
See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.html) for more information. See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.html) for more information.

View File

@@ -39,9 +39,20 @@ cd Meshtastic-device
## Decoding stack traces ## Decoding stack traces
### Option 1
If you get a crash, you can decode the addresses from the `Backtrace:` line: If you get a crash, you can decode the addresses from the `Backtrace:` line:
1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`. 1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`.
2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the 2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the
last `firmware.elf`, so you must be running the same binary that's still in last `firmware.elf`, so you must be running the same binary that's still in
your `.pio/build` directory). your `.pio/build` directory).
### Option 2
You can run the exception decoder to monitor the serial output and decode backtraces in real time.
1. From within PlatformIO, open a new terminal.
2. At the the terminal, enter:
`pio device monitor --port /dev/cu.SLAB_USBtoUART -f esp32_exception_decoder`
Replace the value of port with the location of your serial port.

View File

@@ -15,10 +15,10 @@ Packets can be sent/received either as raw binary structures or as [Protobufs](h
The relevant bits of the class heirarchy are as follows The relevant bits of the class heirarchy are as follows
* [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly * [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly
* [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that receive from a single port number (the normal case) * [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that send/receive from a single port number (the normal case)
* [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that are sending/receiving a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin. * [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that send/receive a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin.
You will typically want to inherit from either SinglePortPlugin (if you are just sending raw bytes) or ProtobufPlugin (if you are sending protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code. You will typically want to inherit from either SinglePortPlugin (if you are just sending/receiving raw bytes) or ProtobufPlugin (if you are sending/receiving protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code.
If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code. If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code.
@@ -45,25 +45,30 @@ A number of [key services](/src/plugins) are implemented using the plugin API, t
The easiest way to get started is: The easiest way to get started is:
* [Build and install](build-instructions.md) the standard codebase from github. * [Build and install](build-instructions.md) the standard codebase from github.
* Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from REPLY_APP to PRIVATE_APP. * Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from *PortNum_REPLY_APP* to *PortNum_PRIVATE_APP*.
* Edit plugins/Plugins.cpp:setupPlugins() to add a call to create an instance of your plugin (see comment at head of that function)
* Rebuild with your new messaging goodness and install on the device * Rebuild with your new messaging goodness and install on the device
* Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board "meshtastic --dest 1234 --ping" * Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board, for example "*meshtastic --dest 1234 --sendping*", where *1234* is another mesh node to send the ping to.
## Threading ## Threading
It is very common that you would like your plugin to be invoked periodically. It is very common that you would like your plugin to be invoked periodically.
We use a crude/basic cooperative threading system to allow this on any of our supported platforms. Simply inherit from OSThread and implement runOnce(). See the OSThread [documentation](/src/concurrency/OSThread.h) for more details. For an example consumer of this API see RemoteHardwarePlugin::runOnce. We use a crude/basic cooperative threading system to allow this on any of our supported platforms. Simply inherit from OSThread and implement runOnce(). See the OSThread [documentation](/src/concurrency/OSThread.h) for more details. For an example consumer of this API see RemoteHardwarePlugin::runOnce.
## Sending messages
If you would like to proactively send messages (rather than just responding to them), just call service.sendToMesh(). For an example of this see [NodeInfoPlugin::sendOurNodeInfo(...)](/src/plugins/NodeInfoPlugin.cpp).
## Picking a port number ## Picking a port number
For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application. For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application.
If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range: If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range:
* 0-63 Core Meshtastic use, do not use for third party apps * **0-63** Core Meshtastic use; do not use for third party apps
* 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application * **64-127** Registered 3rd party apps. Send in a pull request that adds a new entry to portnums.proto to register your application
* 256-511 Use one of these portnums for your private applications that you don't want to register publically * **256-511** Use one of these portnums for your private applications that you don't want to register publically
* 1024-66559 Are reserved for use by IP tunneling (see FIXME for more information) * **1024-66559** Are reserved for use by IP tunneling (see *FIXME* for more information)
All other values are reserved. All other values are reserved.
@@ -73,4 +78,4 @@ If you would like to use protocol buffers to define the structures you send over
* Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example. * Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example.
* Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it. * Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it.
* Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic. * Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic.

View File

@@ -9,8 +9,13 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
default_envs = tbeam # 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 = tbeam
;default_envs = heltec # 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 = 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
[common] [common]
; common is not currently used ; common is not currently used
@@ -65,7 +70,7 @@ lib_deps =
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206 https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it Wire ; explicitly needed here because the AXP202 library forgets to add it
@@ -180,10 +185,10 @@ build_type = debug ; I'm debugging with ICE a lot now
build_flags = build_flags =
${arduino_base.build_flags} -Wno-unused-variable ${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52 -Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3 -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3 ;-DCFG_DEBUG=3
src_filter = src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/> ${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/>
lib_ignore = lib_ignore =
BluetoothOTA BluetoothOTA
monitor_port = /dev/ttyACM1 monitor_port = /dev/ttyACM1
@@ -310,7 +315,17 @@ lib_deps =
; The Portduino based sim environment on top of linux ; The Portduino based sim environment on top of linux
[env:linux] [env:linux]
platform = https://github.com/geeksville/platform-portduino.git platform = https://github.com/geeksville/platform-portduino.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/> src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/>
build_flags = ${arduino_base.build_flags} -O0 build_flags = ${arduino_base.build_flags} -O0
framework = arduino framework = arduino
board = linux_x86_64 board = linux_x86_64
lib_deps =
${arduino_base.lib_deps}
rweather/Crypto
; The GenieBlocks LORA prototype board
[env:genieblocks_lora]
extends = esp32_base
board = genieblocks_lora
build_flags =
${esp32_base.build_flags} -D GENIEBLOCKS

2
proto

Submodule proto updated: dfe7bc1217...855da8701e

View File

@@ -1,4 +1,5 @@
#include "power.h" #include "power.h"
#include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "main.h" #include "main.h"
#include "sleep.h" #include "sleep.h"
@@ -268,9 +269,42 @@ bool Power::axp192Init()
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE"); DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE"); DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
//axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); // There's no HW limit on the tbeam. Setting to 450mz to be a good neighbor on the usb bus. axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
}
#if 0 #if 0
// Not connected // Not connected

View File

@@ -11,7 +11,7 @@ namespace meshtastic
*/ */
enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 }; enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 };
/// Describes the state of the GPS system. /// Describes the state of the Power system.
class PowerStatus : public Status class PowerStatus : public Status
{ {

View File

@@ -3,33 +3,35 @@
#define periodsToLog 48 #define periodsToLog 48
// A reminder that there are 3600 seconds in an hour so I don't have AirTime *airTime;
// to keep googling it.
// This can be changed to a smaller number to speed up testing.
//
uint32_t secondsPerPeriod = 3600; uint32_t secondsPerPeriod = 3600;
uint32_t lastMillis = 0; uint32_t lastMillis = 0;
uint32_t secSinceBoot = 0; uint32_t secSinceBoot = 0;
// AirTime at;
// Don't read out of this directly. Use the helper functions. // Don't read out of this directly. Use the helper functions.
struct airtimeStruct { struct airtimeStruct {
uint16_t periodTX[periodsToLog]; uint32_t periodTX[periodsToLog]; // AirTime transmitted
uint16_t periodRX[periodsToLog]; uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets)
uint16_t periodRX_ALL[periodsToLog]; uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise.
uint8_t lastPeriodIndex; uint8_t lastPeriodIndex;
} airtimes; } airtimes;
void logAirtime(reportTypes reportType, uint32_t airtime_ms) void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{ {
if (reportType == TX_LOG) { if (reportType == TX_LOG) {
airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000); DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms;
} else if (reportType == RX_LOG) { } else if (reportType == RX_LOG) {
airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000); DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) { } else if (reportType == RX_ALL_LOG) {
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000); DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms;
} else { } else {
// Unknown report type DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
} }
} }
@@ -38,29 +40,27 @@ uint8_t currentPeriodIndex()
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog); return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
} }
void airtimeCalculator() void airtimeRotatePeriod()
{ {
if (millis() - lastMillis > 1000) {
lastMillis = millis();
secSinceBoot++;
if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
for (int i = periodsToLog - 2; i >= 0; --i) {
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
}
airtimes.periodTX[0] = 0;
airtimes.periodRX[0] = 0;
airtimes.periodRX_ALL[0] = 0;
airtimes.lastPeriodIndex = currentPeriodIndex(); if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
for (int i = periodsToLog - 2; i >= 0; --i) {
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
} }
airtimes.periodTX[0] = 0;
airtimes.periodRX[0] = 0;
airtimes.periodRX_ALL[0] = 0;
airtimes.lastPeriodIndex = currentPeriodIndex();
} }
} }
uint16_t *airtimeReport(reportTypes reportType) uint32_t *airtimeReport(reportTypes reportType)
{ {
// currentHourIndexReset();
if (reportType == TX_LOG) { if (reportType == TX_LOG) {
return airtimes.periodTX; return airtimes.periodTX;
@@ -86,3 +86,22 @@ uint32_t getSecondsSinceBoot()
{ {
return secSinceBoot; return secSinceBoot;
} }
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
int32_t AirTime::runOnce()
{
//DEBUG_MSG("AirTime::runOnce()\n");
airtimeRotatePeriod();
secSinceBoot++;
/*
This actually doesn't need to be run once per second but we currently use it for the
secSinceBoot counter.
If we have a better counter of how long the device has been online (and not millis())
then we can change this to something less frequent. Maybe once ever 5 seconds?
*/
return (1000 * 1);
}

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "concurrency/OSThread.h"
#include "configuration.h" #include "configuration.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
@@ -18,7 +19,7 @@
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel. TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
other lora radios. other lora radios.
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel. RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
*/ */
@@ -26,13 +27,28 @@ enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
void logAirtime(reportTypes reportType, uint32_t airtime_ms); void logAirtime(reportTypes reportType, uint32_t airtime_ms);
void airtimeCalculator(); void airtimeRotatePeriod();
uint8_t currentPeriodIndex(); uint8_t currentPeriodIndex();
uint8_t getPeriodsToLog(); uint8_t getPeriodsToLog();
uint32_t getSecondsSinceBoot(); uint32_t getSecondsSinceBoot();
uint16_t *airtimeReport(reportTypes reportType); uint32_t *airtimeReport(reportTypes reportType);
uint32_t getSecondsPerPeriod(); uint32_t getSecondsPerPeriod();
class AirTime : private concurrency::OSThread
{
public:
AirTime();
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
protected:
virtual int32_t runOnce();
};
extern AirTime *airTime;

View File

@@ -28,6 +28,8 @@ void OSThread::setup()
OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller) OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller)
: Thread(NULL, period), controller(_controller) : Thread(NULL, period), controller(_controller)
{ {
assertIsSetup();
ThreadName = _name; ThreadName = _name;
if (controller) if (controller)
@@ -81,4 +83,36 @@ void OSThread::run()
currentThread = NULL; currentThread = NULL;
} }
/**
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
*
* it is super important to never allocate those object statically. instead, you should explicitly
* new them at a point where you are guaranteed that other objects that this instance
* depends on have already been created.
*
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
* this makes it guaranteed that the global mainController is fully constructed first.
*/
bool hasBeenSetup;
void assertIsSetup()
{
/**
* Dear developer comrade - If this assert fails() that means you need to fix the following:
*
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
*
* it is super important to never allocate those object statically. instead, you should explicitly
* new them at a point where you are guaranteed that other objects that this instance
* depends on have already been created.
*
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
* this makes it guaranteed that the global mainController is fully constructed first.
*/
assert(hasBeenSetup);
}
} // namespace concurrency } // namespace concurrency

View File

@@ -17,14 +17,14 @@ extern InterruptableDelay mainDelay;
/** /**
* @brief Base threading * @brief Base threading
* *
* This is a pseudo threading layer that is super easy to port, well suited to our slow network and very ram & power efficient. * This is a pseudo threading layer that is super easy to port, well suited to our slow network and very ram & power efficient.
* *
* TODO FIXME @geeksville * TODO FIXME @geeksville
* *
* move more things into OSThreads * move more things into OSThreads
* remove lock/lockguard * remove lock/lockguard
* *
* move typedQueue into concurrency * move typedQueue into concurrency
* remove freertos from typedqueue * remove freertos from typedqueue
*/ */
@@ -42,7 +42,6 @@ class OSThread : public Thread
static bool showWaiting; static bool showWaiting;
public: public:
/// For debug printing only (might be null) /// For debug printing only (might be null)
static const OSThread *currentThread; static const OSThread *currentThread;
@@ -71,4 +70,19 @@ class OSThread : public Thread
virtual void run(); virtual void run();
}; };
/**
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
*
* it is super important to never allocate those object statically. instead, you should explicitly
* new them at a point where you are guaranteed that other objects that this instance
* depends on have already been created.
*
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
* this makes it guaranteed that the global mainController is fully constructed first.
*/
extern bool hasBeenSetup;
void assertIsSetup();
} // namespace concurrency } // namespace concurrency

View File

@@ -338,6 +338,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LORA_DIO1 35 // Not really used #define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used #define LORA_DIO2 34 // Not really used
#elif defined(GENIEBLOCKS)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "genieblocks"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 5
#define GPS_TX_PIN 18
#define GPS_RESET_N 10
#define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY.
#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 2
#define LED_PIN 12 // If defined we will blink this LED
//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen --> Long press start!)
//#define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs input only pins. These pins dont have internal pull-ups or pull-down resistors.
#define USE_RF95
#define LORA_DIO0 38 // a No connect on the SX1262 module
#define LORA_RESET 9
#define RF95_SCK 22
#define RF95_MISO 19
#define RF95_MOSI 13
#define RF95_NSS 21
#endif #endif
#ifdef ARDUINO_NRF52840_PCA10056 #ifdef ARDUINO_NRF52840_PCA10056
@@ -365,7 +394,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define USE_RF95 #define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module #define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23 #define LORA_RESET RADIOLIB_NC
#define LORA_DIO1 33 // Not really used #define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used #define LORA_DIO2 32 // Not really used
@@ -373,7 +402,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RF95_SCK 5 #define RF95_SCK 5
#define RF95_MISO 19 #define RF95_MISO 19
#define RF95_MOSI 27 #define RF95_MOSI 27
#define RF95_NSS 18 #define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
#endif #endif

View File

@@ -49,7 +49,8 @@ void esp32Setup()
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any // Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now. // false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now.
#define APP_WATCHDOG_SECS 45 // #define APP_WATCHDOG_SECS 45
#define APP_WATCHDOG_SECS 90
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true); res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
assert(res == ESP_OK); assert(res == ESP_OK);

View File

@@ -239,6 +239,7 @@ int32_t GPS::runOnce()
} }
// We've been awake too long - force sleep // We've been awake too long - force sleep
now = millis();
auto wakeTime = getWakeTime(); auto wakeTime = getWakeTime();
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;

View File

@@ -36,6 +36,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
bool shouldSet; bool shouldSet;
if (q > currentQuality) { if (q > currentQuality) {
currentQuality = q;
shouldSet = true; shouldSet = true;
DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q); DEBUG_MSG("Upgrading time to RTC %ld secs (quality %d)\n", tv->tv_sec, q);
} else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) { } else if(q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000L)) {

View File

@@ -4,7 +4,6 @@
#include "EInkDisplay.h" #include "EInkDisplay.h"
#include "SPILock.h" #include "SPILock.h"
#include "epd1in54.h" // Screen specific library #include "epd1in54.h" // Screen specific library
#include "graphics/configs.h"
#include <SPI.h> #include <SPI.h>
#include <TFT_eSPI.h> // Graphics library and Sprite class #include <TFT_eSPI.h> // Graphics library and Sprite class

View File

@@ -27,14 +27,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "NodeDB.h" #include "NodeDB.h"
#include "Screen.h" #include "Screen.h"
#include "configuration.h" #include "configuration.h"
#include "fonts.h"
#include "graphics/images.h" #include "graphics/images.h"
#include "main.h" #include "main.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "plugins/TextMessagePlugin.h" #include "plugins/TextMessagePlugin.h"
#include "target_specific.h" #include "target_specific.h"
#include "utils.h" #include "utils.h"
#include "fonts.h"
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#endif
using namespace meshtastic; /** @todo remove */ using namespace meshtastic; /** @todo remove */
@@ -42,7 +45,7 @@ namespace graphics
{ {
// This means the *visible* area (sh1106 can address 132, but shows 128 for example) // This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define IDLE_FRAMERATE 1 // in fps #define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44 #define COMPASS_DIAM 44
// DEBUG // DEBUG
@@ -177,7 +180,6 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group"); display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
} }
/// Draw the last text message we received /// Draw the last text message we received
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
@@ -316,7 +318,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
display->drawFastImage(x + 24, y, 8, 8, imgSatellite); display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
// Draw the number of satellites // Draw the number of satellites
sprintf(satsString, "%lu", gps->getNumSatellites()); sprintf(satsString, "%u", gps->getNumSatellites());
display->drawString(x + 34, y - 2, satsString); display->drawString(x + 34, y - 2, satsString);
} }
} }
@@ -569,11 +571,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
uint32_t agoSecs = sinceLastSeen(node); uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20]; static char lastStr[20];
if (agoSecs < 120) // last 2 mins? if (agoSecs < 120) // last 2 mins?
snprintf(lastStr, sizeof(lastStr), "%lu seconds ago", agoSecs); snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
else if (agoSecs < 120 * 60) // last 2 hrs else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60); snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
else else
snprintf(lastStr, sizeof(lastStr), "%lu hours ago", agoSecs / 60 / 60); snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
static char distStr[20]; static char distStr[20];
strcpy(distStr, "? km"); // might not have location data strcpy(distStr, "? km"); // might not have location data
@@ -747,7 +749,7 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus); powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus); gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus);
textMessageObserver.observe(&textMessagePlugin); textMessageObserver.observe(textMessagePlugin);
} }
void Screen::forceDisplay() void Screen::forceDisplay()
@@ -896,10 +898,12 @@ void Screen::setFrames()
// call a method on debugInfoScreen object (for more details) // call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
#ifndef NO_ESP32
if (isWifiAvailable()) { if (isWifiAvailable()) {
// call a method on debugInfoScreen object (for more details) // call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline; normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
} }
#endif
ui.setFrames(normalFrames, numframes); ui.setFrames(normalFrames, numframes);
ui.enableAllIndicators(); ui.enableAllIndicators();
@@ -924,20 +928,21 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
setFastFramerate(); setFastFramerate();
} }
void Screen::blink() { void Screen::blink()
{
setFastFramerate(); setFastFramerate();
uint8_t count = 10; uint8_t count = 10;
dispdev.setBrightness(254); dispdev.setBrightness(254);
while(count>0) { while (count > 0) {
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
dispdev.display(); dispdev.display();
delay(50); delay(50);
dispdev.clear(); dispdev.clear();
dispdev.display(); dispdev.display();
delay(50); delay(50);
count = count -1; count = count - 1;
} }
dispdev.setBrightness(brightness); dispdev.setBrightness(brightness);
} }
void Screen::handlePrint(const char *text) void Screen::handlePrint(const char *text)
@@ -1060,11 +1065,13 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) { if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) {
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) { if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
// Number of connections to the AP. Default mmax for the esp32 is 4
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"),
y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)");
} else { } else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str())); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
} }
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"),
y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)");
} else if (WiFi.status() == WL_NO_SSID_AVAIL) { } else if (WiFi.status() == WL_NO_SSID_AVAIL) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found"); display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");

View File

@@ -19,8 +19,7 @@
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "meshwifi/meshhttp.h" #include "plugins/Plugins.h"
#include "meshwifi/meshwifi.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include <OneButton.h> #include <OneButton.h>
@@ -28,6 +27,8 @@
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#ifndef NO_ESP32 #ifndef NO_ESP32
#include "mesh/http/WebServer.h"
#include "mesh/http/WiFiAPClient.h"
#include "nimble/BluetoothUtil.h" #include "nimble/BluetoothUtil.h"
#endif #endif
@@ -275,6 +276,8 @@ RadioInterface *rIf = NULL;
void setup() void setup()
{ {
concurrency::hasBeenSetup = true;
#ifdef SEGGER_STDOUT_CH #ifdef SEGGER_STDOUT_CH
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM); SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif #endif
@@ -300,17 +303,20 @@ void setup()
digitalWrite(RESET_OLED, 1); digitalWrite(RESET_OLED, 1);
#endif #endif
#ifdef BUTTON_PIN
#ifndef NO_ESP32
// If BUTTON_PIN is held down during the startup process, // If BUTTON_PIN is held down during the startup process,
// force the device to go into a SoftAP mode. // force the device to go into a SoftAP mode.
bool forceSoftAP = 0; bool forceSoftAP = 0;
#ifdef BUTTON_PIN
#ifndef NO_ESP32
pinMode(BUTTON_PIN, INPUT); pinMode(BUTTON_PIN, INPUT);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif
// BUTTON_PIN is pulled high by a 12k resistor. // BUTTON_PIN is pulled high by a 12k resistor.
if (!digitalRead(BUTTON_PIN)) { if (!digitalRead(BUTTON_PIN)) {
forceSoftAP = 1; forceSoftAP = 1;
DEBUG_MSG("-------------------- Setting forceSoftAP = 1\n"); DEBUG_MSG("Setting forceSoftAP = 1\n");
} }
#endif #endif
@@ -389,6 +395,19 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
#ifdef GENIEBLOCKS
// gps setup
pinMode(GPS_RESET_N, OUTPUT);
pinMode(GPS_EXTINT, OUTPUT);
digitalWrite(GPS_RESET_N, HIGH);
digitalWrite(GPS_EXTINT, LOW);
// battery setup
// If we want to read battery level, we need to set BATTERY_EN_PIN pin to low.
// ToDo: For low power consumption after read battery level, set that pin to high.
pinMode(BATTERY_EN_PIN, OUTPUT);
digitalWrite(BATTERY_EN_PIN, LOW);
#endif
// If we don't have bidirectional comms, we can't even try talking to UBLOX // If we don't have bidirectional comms, we can't even try talking to UBLOX
UBloxGPS *ublox = NULL; UBloxGPS *ublox = NULL;
#ifdef GPS_TX_PIN #ifdef GPS_TX_PIN
@@ -426,14 +445,17 @@ void setup()
service.init(); service.init();
// Now that the mesh service is created, create any plugins
setupPlugins();
// Do this after service.init (because that clears error_code) // Do this after service.init (because that clears error_code)
#ifdef AXP192_SLAVE_ADDRESS #ifdef AXP192_SLAVE_ADDRESS
if(!axp192_found) if (!axp192_found)
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
#endif #endif
// Don't call screen setup until after nodedb is setup (because we need // Don't call screen setup until after nodedb is setup (because we need
// the current region name) // the current region name)
#if defined(ST7735_CS) || defined(HAS_EINK) #if defined(ST7735_CS) || defined(HAS_EINK)
screen->setup(); screen->setup();
#else #else
@@ -494,9 +516,17 @@ void setup()
} }
#endif #endif
#ifndef NO_ESP32
// Initialize Wifi // Initialize Wifi
initWifi(forceSoftAP); initWifi(forceSoftAP);
// Start web server thread.
webServerThread = new WebServerThread();
#endif
// Start airtime logger thread.
airTime = new AirTime();
if (!rIf) if (!rIf)
recordCriticalError(CriticalErrorCode_NoRadio); recordCriticalError(CriticalErrorCode_NoRadio);
else else
@@ -557,7 +587,7 @@ void loop()
#endif #endif
// TODO: This should go into a thread handled by FreeRTOS. // TODO: This should go into a thread handled by FreeRTOS.
handleWebResponse(); // handleWebResponse();
service.loop(); service.loop();
@@ -570,7 +600,4 @@ void loop()
// We want to sleep as long as possible here - because it saves power // We want to sleep as long as possible here - because it saves power
mainDelay.delay(delayMsec); mainDelay.delay(delayMsec);
// if (didWake) DEBUG_MSG("wake!\n"); // if (didWake) DEBUG_MSG("wake!\n");
// Handles cleanup for the airtime calculator.
airtimeCalculator();
} }

View File

@@ -60,7 +60,8 @@ static int32_t sendOwnerCb()
currentGeneration = radioGeneration; currentGeneration = radioGeneration;
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
nodeInfoPlugin.sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) assert(nodeInfoPlugin);
nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000; return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
} }
@@ -134,7 +135,8 @@ bool MeshService::reloadConfig()
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh /// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void MeshService::reloadOwner() void MeshService::reloadOwner()
{ {
nodeInfoPlugin.sendOurNodeInfo(); assert(nodeInfoPlugin);
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk(); nodeDB.saveToDisk();
} }
@@ -193,17 +195,40 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node); assert(node);
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies); 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) if (node->has_position)
positionPlugin.sendOurPosition(dest, wantReplies); positionPlugin->sendOurPosition(dest, wantReplies);
else else
nodeInfoPlugin.sendOurNodeInfo(dest, wantReplies); nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
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) {
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.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(position.battery_level);
return node;
} }
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
{ {
// Update our local node info with our position (even if we don't decide to update anyone else) // Update our local node info with our position (even if we don't decide to update anyone else)
NodeInfo *node = refreshMyNodeInfo();
Position pos = Position_init_default; Position pos = node->position;
if (gps->hasLock()) { if (gps->hasLock()) {
if (gps->altitude != 0) if (gps->altitude != 0)
@@ -214,21 +239,16 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
else { else {
// The GPS has lost lock, if we are fixed position we should just keep using // The GPS has lost lock, if we are fixed position we should just keep using
// the old position // the old position
if(radioConfig.preferences.fixed_position) { if(!radioConfig.preferences.fixed_position) {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
pos = node->position;
DEBUG_MSG("WARNING: Using fixed position\n"); DEBUG_MSG("WARNING: Using fixed position\n");
} else {
// throw away old position
pos.latitude_i = 0;
pos.longitude_i = 0;
pos.altitude = 0;
} }
} }
pos.time = getValidTime(RTCQualityGPS);
// Include our current battery voltage in our position announcement
pos.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(pos.battery_level);
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.latitude_i, pos.time, pos.battery_level);
// Update our current position in the local DB // Update our current position in the local DB
@@ -247,7 +267,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
currentGeneration = radioGeneration; currentGeneration = radioGeneration;
DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies); DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies);
positionPlugin.sendOurPosition(NODENUM_BROADCAST, requestReplies); assert(positionPlugin);
positionPlugin->sendOurPosition(NODENUM_BROADCAST, requestReplies);
} }
return 0; return 0;

View File

@@ -79,6 +79,9 @@ class MeshService
/// cache /// cache
void sendToMesh(MeshPacket *p); void sendToMesh(MeshPacket *p);
/// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo();
private: private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh /// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh

View File

@@ -5,6 +5,7 @@
#include "FS.h" #include "FS.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "FSCommon.h"
#include "GPS.h" #include "GPS.h"
#include "MeshRadio.h" #include "MeshRadio.h"
#include "NodeDB.h" #include "NodeDB.h"
@@ -15,11 +16,13 @@
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "FSCommon.h"
#include <pb_decode.h> #include <pb_decode.h>
#include <pb_encode.h> #include <pb_encode.h>
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#endif
NodeDB nodeDB; NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now) // we have plenty of ram so statically alloc this tempbuf (for now)
@@ -28,7 +31,7 @@ MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig &radioConfig = devicestate.radio; RadioConfig &radioConfig = devicestate.radio;
ChannelSettings &channelSettings = radioConfig.channel_settings; ChannelSettings &channelSettings = radioConfig.channel_settings;
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel. * might have changed is incremented. Allows others to detect they might now be on a new channel.
*/ */
uint32_t radioGeneration; uint32_t radioGeneration;
@@ -41,8 +44,6 @@ DeviceState versions used to be defined in the .proto file but really only this
#define DEVICESTATE_CUR_VER 11 #define DEVICESTATE_CUR_VER 11
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER #define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
// FIXME - move this somewhere else // FIXME - move this somewhere else
extern void getMacAddr(uint8_t *dmac); extern void getMacAddr(uint8_t *dmac);
@@ -90,7 +91,7 @@ const char *getChannelName()
static char buf[32]; static char buf[32];
char suffix; char suffix;
if(channelSettings.psk.size != 1) { if (channelSettings.psk.size != 1) {
// We have a standard PSK, so generate a letter based hash. // We have a standard PSK, so generate a letter based hash.
uint8_t code = 0; uint8_t code = 0;
for (int i = 0; i < activePSKSize; i++) for (int i = 0; i < activePSKSize; i++)
@@ -140,32 +141,40 @@ bool NodeDB::resetRadioConfig()
} }
// Convert the old string "Default" to our new short representation // Convert the old string "Default" to our new short representation
if(strcmp(channelSettings.name, "Default") == 0) if (strcmp(channelSettings.name, "Default") == 0)
*channelSettings.name = '\0'; *channelSettings.name = '\0';
// Convert the short "" representation for Default into a usable string // Convert the short "" representation for Default into a usable string
channelName = channelSettings.name; channelName = channelSettings.name;
if(!*channelName) { // emptystring if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case // Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
// the app fucked up and forgot to set channelSettings.name // the app fucked up and forgot to set channelSettings.name
channelName = "Unset";
if(channelSettings.bandwidth == 0) switch(channelSettings.modem_config) { if (channelSettings.bandwidth != 0)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
channelName = "Medium"; break; channelName = "Medium";
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
channelName = "ShortFast"; break; channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongAlt"; break; channelName = "LongAlt";
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096: case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow"; break; channelName = "LongSlow";
break;
default: default:
channelName = "Invalid"; break; channelName = "Invalid";
} break;
}
} }
// Convert any old usage of the defaultpsk into our new short representation. // Convert any old usage of the defaultpsk into our new short representation.
if(channelSettings.psk.size == sizeof(defaultpsk) && if (channelSettings.psk.size == sizeof(defaultpsk) &&
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) { memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
*channelSettings.psk.bytes = 1; *channelSettings.psk.bytes = 1;
channelSettings.psk.size = 1; channelSettings.psk.size = 1;
} }
@@ -173,10 +182,10 @@ bool NodeDB::resetRadioConfig()
// Convert the short single byte variants of psk into variant that can be used more generally // Convert the short single byte variants of psk into variant that can be used more generally
memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size);
activePSKSize = channelSettings.psk.size; activePSKSize = channelSettings.psk.size;
if(activePSKSize == 1) { if (activePSKSize == 1) {
uint8_t pskIndex = activePSK[0]; uint8_t pskIndex = activePSK[0];
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
if(pskIndex == 0) if (pskIndex == 0)
activePSKSize = 0; // Turn off encryption activePSKSize = 0; // Turn off encryption
else { else {
memcpy(activePSK, defaultpsk, sizeof(defaultpsk)); memcpy(activePSK, defaultpsk, sizeof(defaultpsk));
@@ -271,12 +280,13 @@ void NodeDB::init()
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8; myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8; myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
myNodeInfo.error_code = CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash) myNodeInfo.error_code =
CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash)
myNodeInfo.error_address = 0; myNodeInfo.error_address = 0;
// likewise - we always want the app requirements to come from the running appload // likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't // Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts) // keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
pickNewNodeNum(); pickNewNodeNum();

View File

@@ -21,11 +21,17 @@ void PhoneAPI::init()
observe(&service.fromNumChanged); observe(&service.fromNumChanged);
} }
PhoneAPI::~PhoneAPI() {
close();
}
void PhoneAPI::close() { void PhoneAPI::close() {
unobserve(); unobserve();
state = STATE_SEND_NOTHING; state = STATE_SEND_NOTHING;
bool oldConnected = isConnected;
isConnected = false; isConnected = false;
onConnectionChanged(isConnected); if(oldConnected != isConnected)
onConnectionChanged(isConnected);
} }
void PhoneAPI::checkConnectionTimeout() void PhoneAPI::checkConnectionTimeout()
@@ -128,6 +134,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.which_variant = FromRadio_my_info_tag; fromRadioScratch.which_variant = FromRadio_my_info_tag;
fromRadioScratch.variant.my_info = myNodeInfo; fromRadioScratch.variant.my_info = myNodeInfo;
state = STATE_SEND_RADIO; state = STATE_SEND_RADIO;
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break; break;
case STATE_SEND_RADIO: case STATE_SEND_RADIO:

View File

@@ -55,12 +55,15 @@ class PhoneAPI
public: public:
PhoneAPI(); PhoneAPI();
/// Destructor - calls close()
virtual ~PhoneAPI();
/// Do late init that can't happen at constructor time /// Do late init that can't happen at constructor time
virtual void init(); virtual void init();
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING // Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer // Unregisters our observer. A closed connection **can** be reopened by calling init again.
void close(); virtual void close();
/** /**
* Handle a ToRadio protobuf * Handle a ToRadio protobuf

View File

@@ -12,7 +12,7 @@
#define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level #define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level
RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi) RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi)
: RadioLibInterface(cs, irq, rst, 0, spi) : RadioLibInterface(cs, irq, rst, RADIOLIB_NC, spi)
{ {
// FIXME - we assume devices never get destroyed // FIXME - we assume devices never get destroyed
} }

View File

@@ -14,6 +14,9 @@ class RF95Interface : public RadioLibInterface
public: public:
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi); RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
/// Some boards (Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
bool isIRQPending() { return lora->getPendingIRQ(); }
/// Initialise the Driver transport hardware and software. /// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init(). /// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded. /// \return true if initialisation succeeded.

View File

@@ -97,7 +97,8 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
// Count the packet toward our TX airtime utilization. // Count the packet toward our TX airtime utilization.
// We only count it if it can be added to the TX queue. // We only count it if it can be added to the TX queue.
logAirtime(TX_LOG, xmitMsec); 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 // 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 // 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
@@ -216,7 +217,8 @@ void RadioLibInterface::handleReceiveInterrupt()
size_t length = iface->getPacketLength(); size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length); xmitMsec = getPacketTime(length);
logAirtime(RX_ALL_LOG, xmitMsec); airTime->logAirtime(RX_ALL_LOG, xmitMsec);
//airTime.logAirtime(RX_ALL_LOG, xmitMsec);
int state = iface->readData(radiobuf, length); int state = iface->readData(radiobuf, length);
if (state != ERR_NONE) { if (state != ERR_NONE) {
@@ -258,7 +260,8 @@ void RadioLibInterface::handleReceiveInterrupt()
printPacket("Lora RX", mp); printPacket("Lora RX", mp);
xmitMsec = getPacketTime(mp); xmitMsec = getPacketTime(mp);
logAirtime(RX_LOG, xmitMsec); airTime->logAirtime(RX_LOG, xmitMsec);
//airTime.logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp); deliverToReceiver(mp);
} }

View File

@@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg;
#define DeviceState_fields &DeviceState_msg #define DeviceState_fields &DeviceState_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define DeviceState_size 6176 #define DeviceState_size 6206
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -57,3 +57,4 @@ PB_BIND(ToRadio, ToRadio, 2)

View File

@@ -35,6 +35,26 @@ typedef enum _RegionCode {
RegionCode_TW = 8 RegionCode_TW = 8
} RegionCode; } 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 { typedef enum _GpsOperation {
GpsOperation_GpsOpUnset = 0, GpsOperation_GpsOpUnset = 0,
GpsOperation_GpsOpMobile = 2, GpsOperation_GpsOpMobile = 2,
@@ -145,6 +165,7 @@ typedef struct _RadioConfig_UserPreferences {
char wifi_password[64]; char wifi_password[64];
bool wifi_ap_mode; bool wifi_ap_mode;
RegionCode region; RegionCode region;
ChargeCurrent charge_current;
LocationSharing location_share; LocationSharing location_share;
GpsOperation gps_operation; GpsOperation gps_operation;
uint32_t gps_update_interval; uint32_t gps_update_interval;
@@ -156,6 +177,11 @@ typedef struct _RadioConfig_UserPreferences {
bool debug_log_enabled; bool debug_log_enabled;
pb_size_t ignore_incoming_count; pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3]; 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; } RadioConfig_UserPreferences;
typedef struct _RouteDiscovery { typedef struct _RouteDiscovery {
@@ -265,6 +291,10 @@ typedef struct _ToRadio {
#define _RegionCode_MAX RegionCode_TW #define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1)) #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_MIN GpsOperation_GpsOpUnset
#define _GpsOperation_MAX GpsOperation_GpsOpDisabled #define _GpsOperation_MAX GpsOperation_GpsOpDisabled
#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1)) #define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
@@ -299,7 +329,7 @@ extern "C" {
#define MeshPacket_init_default {0, 0, 0, {SubPacket_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 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_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, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #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 NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #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, 0, 0}
#define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN}
@@ -313,7 +343,7 @@ extern "C" {
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_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 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_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, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}} #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 NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #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, 0, 0}
#define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN}
@@ -371,6 +401,7 @@ extern "C" {
#define RadioConfig_UserPreferences_wifi_password_tag 13 #define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14 #define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_region_tag 15 #define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_charge_current_tag 16
#define RadioConfig_UserPreferences_location_share_tag 32 #define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33 #define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34 #define RadioConfig_UserPreferences_gps_update_interval_tag 34
@@ -381,6 +412,11 @@ extern "C" {
#define RadioConfig_UserPreferences_factory_reset_tag 100 #define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101 #define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103 #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 RouteDiscovery_route_tag 2
#define User_id_tag 1 #define User_id_tag 1
#define User_long_name_tag 2 #define User_long_name_tag 2
@@ -533,6 +569,7 @@ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \ X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \ X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \ 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, location_share, 32) \
X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \ X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \ X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
@@ -542,7 +579,12 @@ X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \ X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \ X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \ X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) 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_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL #define RadioConfig_UserPreferences_DEFAULT NULL
@@ -654,13 +696,13 @@ extern const pb_msgdesc_t ToRadio_msg;
#define SubPacket_size 275 #define SubPacket_size 275
#define MeshPacket_size 320 #define MeshPacket_size 320
#define ChannelSettings_size 95 #define ChannelSettings_size 95
#define RadioConfig_size 319 #define RadioConfig_size 349
#define RadioConfig_UserPreferences_size 219 #define RadioConfig_UserPreferences_size 249
#define NodeInfo_size 132 #define NodeInfo_size 132
#define MyNodeInfo_size 106 #define MyNodeInfo_size 106
#define LogRecord_size 81 #define LogRecord_size 81
#define FromRadio_size 329 #define FromRadio_size 358
#define ToRadio_size 323 #define ToRadio_size 353
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -18,13 +18,15 @@ typedef enum _PortNum {
PortNum_NODEINFO_APP = 4, PortNum_NODEINFO_APP = 4,
PortNum_REPLY_APP = 32, PortNum_REPLY_APP = 32,
PortNum_IP_TUNNEL_APP = 33, PortNum_IP_TUNNEL_APP = 33,
PortNum_PRIVATE_APP = 256 PortNum_SERIAL_APP = 64,
PortNum_PRIVATE_APP = 256,
PortNum_ATAK_FORWARDER = 257
} PortNum; } PortNum;
/* Helper constants for enums */ /* Helper constants for enums */
#define _PortNum_MIN PortNum_UNKNOWN_APP #define _PortNum_MIN PortNum_UNKNOWN_APP
#define _PortNum_MAX PortNum_PRIVATE_APP #define _PortNum_MAX PortNum_ATAK_FORWARDER
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1)) #define _PortNum_ARRAYSIZE ((PortNum)(PortNum_ATAK_FORWARDER+1))
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -0,0 +1,46 @@
#pragma once
void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer);
// Declare some handler functions for the various URLs on the server
void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res);
void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res);
void handleStyleCSS(HTTPRequest *req, HTTPResponse *res);
void handleHotspot(HTTPRequest *req, HTTPResponse *res);
void handleRoot(HTTPRequest *req, HTTPResponse *res);
void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res);
void handleStaticPost(HTTPRequest *req, HTTPResponse *res);
void handleStatic(HTTPRequest *req, HTTPResponse *res);
void handleRestart(HTTPRequest *req, HTTPResponse *res);
void handle404(HTTPRequest *req, HTTPResponse *res);
void handleFormUpload(HTTPRequest *req, HTTPResponse *res);
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res);
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res);
void handleReport(HTTPRequest *req, HTTPResponse *res);
void handleFavicon(HTTPRequest *req, HTTPResponse *res);
void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
void middlewareSession(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
uint32_t getTimeSpeedUp();
void setTimeSpeedUp();
// Interface to the PhoneAPI to access the protobufs with messages
class HttpAPI : public PhoneAPI
{
public:
// Nothing here yet
private:
// Nothing here yet
protected:
// Nothing here yet
};

View File

@@ -0,0 +1,14 @@
#include "mesh/http/ContentHelper.h"
//#include <Arduino.h>
//#include "main.h"
void replaceAll(std::string &str, const std::string &from, const std::string &to)
{
if (from.empty())
return;
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}

View File

@@ -0,0 +1,8 @@
#include <Arduino.h>
#include <functional>
#define BoolToString(x) ((x) ? "true" : "false")
void replaceAll(std::string &str, const std::string &from, const std::string &to);

View File

@@ -2,14 +2,7 @@
#include <functional> #include <functional>
/* /*
Steps: This file contains static content.
- Compress the .js file to .js.gz
- Convert to hex:
http://tomeko.net/online_tools/file_to_hex.php?lang=en
- Paste into the array
- Note the filesize of your .gz file and write the file
size into the length int.
*/ */
// Length of the binary data // Length of the binary data

231
src/mesh/http/WebServer.cpp Normal file
View File

@@ -0,0 +1,231 @@
#include "mesh/http/WebServer.h"
#include "NodeDB.h"
#include "mesh/http/WiFiAPClient.h"
#include <HTTPBodyParser.hpp>
#include <HTTPMultipartBodyParser.hpp>
#include <HTTPURLEncodedBodyParser.hpp>
#include <WebServer.h>
#include <WiFi.h>
#ifndef NO_ESP32
#include "esp_task_wdt.h"
#endif
// Persistant Data Storage
#include <Preferences.h>
Preferences prefs;
/*
Including the esp32_https_server library will trigger a compile time error. I've
tracked it down to a reoccurrance of this bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824
The work around is described here:
https://forums.xilinx.com/t5/Embedded-Development-Tools/Error-with-Standard-Libaries-in-Zynq/td-p/450032
Long story short is we need "#undef str" before including the esp32_https_server.
- Jm Casler (jm@casler.org) Oct 2020
*/
#undef str
// Includes for the https server
// https://github.com/fhessel/esp32_https_server
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>
#include <HTTPSServer.hpp>
#include <HTTPServer.hpp>
#include <SSLCert.hpp>
// The HTTPS Server comes in a separate namespace. For easier use, include it here.
using namespace httpsserver;
#include "mesh/http/ContentHandler.h"
SSLCert *cert;
HTTPSServer *secureServer;
HTTPServer *insecureServer;
bool isWebServerReady = 0;
bool isCertReady = 0;
void handleWebResponse()
{
if (isWifiAvailable() == 0) {
return;
}
if (isWebServerReady) {
// We're going to handle the DNS responder here so it
// will be ignored by the NRF boards.
handleDNSResponse();
secureServer->loop();
insecureServer->loop();
}
/*
Slow down the CPU if we have not received a request within the last few
seconds.
*/
if (millis() - getTimeSpeedUp() >= (25 * 1000)) {
setCpuFrequencyMhz(80);
setTimeSpeedUp();
}
}
void taskCreateCert(void *parameter)
{
prefs.begin("MeshtasticHTTPS", false);
// Delete the saved certs
if (0) {
DEBUG_MSG("Deleting any saved SSL keys ...\n");
// prefs.clear();
prefs.remove("PK");
prefs.remove("cert");
}
size_t pkLen = prefs.getBytesLength("PK");
size_t certLen = prefs.getBytesLength("cert");
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
if (pkLen && certLen) {
DEBUG_MSG("Existing SSL Certificate found!\n");
} else {
DEBUG_MSG("Creating the certificate. This may take a while. Please wait...\n");
yield();
cert = new SSLCert();
yield();
int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=meshtastic.local,O=Meshtastic,C=US",
"20190101000000", "20300101000000");
yield();
if (createCertResult != 0) {
DEBUG_MSG("Creating the certificate failed\n");
// Serial.printf("Creating the certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details",
// createCertResult);
// while (true)
// delay(500);
} else {
DEBUG_MSG("Creating the certificate was successful\n");
DEBUG_MSG("Created Private Key: %d Bytes\n", cert->getPKLength());
// for (int i = 0; i < cert->getPKLength(); i++)
// Serial.print(cert->getPKData()[i], HEX);
// Serial.println();
DEBUG_MSG("Created Certificate: %d Bytes\n", cert->getCertLength());
// for (int i = 0; i < cert->getCertLength(); i++)
// Serial.print(cert->getCertData()[i], HEX);
// Serial.println();
prefs.putBytes("PK", (uint8_t *)cert->getPKData(), cert->getPKLength());
prefs.putBytes("cert", (uint8_t *)cert->getCertData(), cert->getCertLength());
}
}
isCertReady = 1;
vTaskDelete(NULL);
}
void createSSLCert()
{
if (isWifiAvailable() == 0) {
return;
}
// Create a new process just to handle creating the cert.
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
// jm@casler.org (Oct 2020)
xTaskCreate(taskCreateCert, /* Task function. */
"createCert", /* String with name of task. */
16384, /* Stack size in bytes. */
NULL, /* Parameter passed as input of the task */
16, /* Priority of the task. */
NULL); /* Task handle. */
DEBUG_MSG("Waiting for SSL Cert to be generated.\n");
while (!isCertReady) {
DEBUG_MSG(".");
delay(1000);
yield();
esp_task_wdt_reset();
}
DEBUG_MSG("SSL Cert Ready!\n");
}
WebServerThread *webServerThread;
WebServerThread::WebServerThread() : concurrency::OSThread("WebServerThread") {}
int32_t WebServerThread::runOnce()
{
// DEBUG_MSG("WebServerThread::runOnce()\n");
handleWebResponse();
// Loop every 5ms.
return (5);
}
void initWebServer()
{
DEBUG_MSG("Initializing Web Server ...\n");
prefs.begin("MeshtasticHTTPS", false);
size_t pkLen = prefs.getBytesLength("PK");
size_t certLen = prefs.getBytesLength("cert");
DEBUG_MSG("Checking if we have a previously saved SSL Certificate.\n");
if (pkLen && certLen) {
uint8_t *pkBuffer = new uint8_t[pkLen];
prefs.getBytes("PK", pkBuffer, pkLen);
uint8_t *certBuffer = new uint8_t[certLen];
prefs.getBytes("cert", certBuffer, certLen);
cert = new SSLCert(certBuffer, certLen, pkBuffer, pkLen);
DEBUG_MSG("Retrieved Private Key: %d Bytes\n", cert->getPKLength());
// DEBUG_MSG("Retrieved Private Key: " + String(cert->getPKLength()) + " Bytes");
// for (int i = 0; i < cert->getPKLength(); i++)
// Serial.print(cert->getPKData()[i], HEX);
// Serial.println();
DEBUG_MSG("Retrieved Certificate: %d Bytes\n", cert->getCertLength());
// for (int i = 0; i < cert->getCertLength(); i++)
// Serial.print(cert->getCertData()[i], HEX);
// Serial.println();
} else {
DEBUG_MSG("Web Server started without SSL keys! How did this happen?\n");
}
// We can now use the new certificate to setup our server as usual.
secureServer = new HTTPSServer(cert);
insecureServer = new HTTPServer();
registerHandlers(insecureServer, secureServer);
DEBUG_MSG("Starting Web Servers...\n");
secureServer->start();
insecureServer->start();
if (secureServer->isRunning() && insecureServer->isRunning()) {
DEBUG_MSG("HTTP and HTTPS Web Servers Ready! :-) \n");
isWebServerReady = 1;
} else {
DEBUG_MSG("HTTP and HTTPS Web Servers Failed! ;-( \n");
}
}

26
src/mesh/http/WebServer.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include "PhoneAPI.h"
#include "concurrency/OSThread.h"
#include <Arduino.h>
#include <functional>
void initWebServer();
void createSSLCert();
void handleWebResponse();
class WebServerThread : private concurrency::OSThread
{
public:
WebServerThread();
protected:
virtual int32_t runOnce();
};
extern WebServerThread *webServerThread;

View File

@@ -1,9 +1,9 @@
#include "meshwifi.h" #include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "WiFiServerAPI.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "meshwifi/meshhttp.h" #include "mesh/http/WebServer.h"
#include "mesh/wifi/WiFiServerAPI.h"
#include "target_specific.h" #include "target_specific.h"
#include <DNSServer.h> #include <DNSServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>

View File

@@ -5,7 +5,7 @@
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client) WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
{ {
DEBUG_MSG("Incoming connection from %s\n", client.remoteIP().toString().c_str()); DEBUG_MSG("Incoming wifi connection\n");
} }
WiFiServerAPI::~WiFiServerAPI() WiFiServerAPI::~WiFiServerAPI()
@@ -28,18 +28,19 @@ void WiFiServerAPI::onConnectionChanged(bool connected)
} }
} }
void WiFiServerAPI::loop() /// override close to also shutdown the TCP link
void WiFiServerAPI::close() {
client.stop(); // drop tcp connection
StreamAPI::close();
}
bool WiFiServerAPI::loop()
{ {
if (client.connected()) { if (client.connected()) {
StreamAPI::loop(); StreamAPI::loop();
} else if(isConnected) { return true;
// If our API link was up, shut it down } else {
return false;
DEBUG_MSG("Client dropped connection, closing API client\n");
// Note: we can't call delete here because this object includes other state
// besides the stream API. Instead kill it later when we start a new instance
// delete this;
close();
} }
} }
@@ -58,15 +59,25 @@ int32_t WiFiServerPort::runOnce()
auto client = available(); auto client = available();
if (client) { if (client) {
// Close any previous connection (see FIXME in header file) // Close any previous connection (see FIXME in header file)
if (openAPI) if (openAPI) {
DEBUG_MSG("Force closing previous TCP connection\n");
delete openAPI; delete openAPI;
}
openAPI = new WiFiServerAPI(client); openAPI = new WiFiServerAPI(client);
} }
if (openAPI) { if (openAPI) {
// Allow idle processing so the API can read from its incoming stream // Allow idle processing so the API can read from its incoming stream
openAPI->loop(); if(!openAPI->loop()) {
// If our API link was up, shut it down
DEBUG_MSG("Client dropped connection, closing API client\n");
// Note: we can't call delete here because this object includes other state
// besides the stream API. Instead kill it later when we start a new instance
delete openAPI;
openAPI = NULL;
}
return 0; // run fast while our API server is running return 0; // run fast while our API server is running
} else } else
return 100; // only check occasionally for incoming connections return 100; // only check occasionally for incoming connections

View File

@@ -18,7 +18,11 @@ class WiFiServerAPI : public StreamAPI
virtual ~WiFiServerAPI(); virtual ~WiFiServerAPI();
virtual void loop(); // Check for dropped client connections /// @return true if we want to keep running, or false if we are ready to be destroyed
virtual bool loop(); // Check for dropped client connections
/// override close to also shutdown the TCP link
virtual void close();
protected: protected:
/// Hookable to find out when connection changes /// Hookable to find out when connection changes

View File

@@ -1,38 +0,0 @@
#pragma once
#include "PhoneAPI.h"
#include <Arduino.h>
#include <functional>
void initWebServer();
void createSSLCert();
void handleNotFound();
void handleWebResponse();
void handleJSONChatHistory();
void notifyWebUI();
void handleHotspot();
void handleStyleCSS();
void handleRoot();
void handleScriptsScriptJS();
void handleJSONChatHistoryDummy();
void replaceAll(std::string& str, const std::string& from, const std::string& to);
class HttpAPI : public PhoneAPI
{
public:
// Nothing here yet
private:
// Nothing here yet
protected:
// Nothing here yet
};

View File

@@ -7,13 +7,16 @@
#include "esp_bt.h" #include "esp_bt.h"
#include "host/util/util.h" #include "host/util/util.h"
#include "main.h" #include "main.h"
#include "meshwifi/meshwifi.h"
#include "nimble/NimbleDefs.h" #include "nimble/NimbleDefs.h"
#include "services/gap/ble_svc_gap.h" #include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h" #include "services/gatt/ble_svc_gatt.h"
#include <Arduino.h> #include <Arduino.h>
#include <WiFi.h> #include <WiFi.h>
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#endif
static bool pinShowing; static bool pinShowing;
static uint32_t doublepressed; static uint32_t doublepressed;
@@ -545,7 +548,9 @@ void setBluetoothEnable(bool on)
if (firstTime) { if (firstTime) {
firstTime = 0; firstTime = 0;
} else { } else {
initWifi(0); #ifndef NO_ESP32
initWifi(0);
#endif
} }
} else { } else {
@@ -557,7 +562,9 @@ void setBluetoothEnable(bool on)
*/ */
// shutdown wifi // shutdown wifi
#ifndef NO_ESP32
deinitWifi(); deinitWifi();
#endif
// We have to totally teardown our bluetooth objects to prevent leaks // We have to totally teardown our bluetooth objects to prevent leaks
deinitBLE(); deinitBLE();

View File

@@ -1,5 +1,9 @@
#include "meshwifi/meshhttp.h" //#include "mesh/wifi/WebServer.h"
#include "meshwifi/meshwifi.h" #include "configuration.h"
#ifndef NO_ESP32
//#include "mesh/wifi/WiFiAPClient.h"
void initWifi(bool forceSoftAP) {} void initWifi(bool forceSoftAP) {}
@@ -10,7 +14,4 @@ bool isWifiAvailable()
return false; return false;
} }
void handleWebResponse() {} #endif
/// Perform idle loop processing required by the wifi layer
void loopWifi() {}

View File

@@ -6,7 +6,7 @@
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
NodeInfoPlugin nodeInfoPlugin; NodeInfoPlugin *nodeInfoPlugin;
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p) bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
{ {

View File

@@ -29,4 +29,4 @@ class NodeInfoPlugin : public ProtobufPlugin<User>
virtual MeshPacket *allocReply(); virtual MeshPacket *allocReply();
}; };
extern NodeInfoPlugin nodeInfoPlugin; extern NodeInfoPlugin *nodeInfoPlugin;

29
src/plugins/Plugins.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include "plugins/NodeInfoPlugin.h"
#include "plugins/PositionPlugin.h"
#include "plugins/RemoteHardwarePlugin.h"
#include "plugins/ReplyPlugin.h"
#include "plugins/SerialPlugin.h"
#include "plugins/TextMessagePlugin.h"
/**
* Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else)
*/
void setupPlugins()
{
nodeInfoPlugin = new NodeInfoPlugin();
positionPlugin = new PositionPlugin();
textMessagePlugin = new TextMessagePlugin();
// Note: if the rest of meshtastic doesn't need to explicitly use your plugin, you do not need to assign the instance
// to a global variable.
new RemoteHardwarePlugin();
new ReplyPlugin();
#ifndef NO_ESP32
// Only run on an esp32 based device.
new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org
#endif
}

6
src/plugins/Plugins.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
/**
* Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else)
*/
void setupPlugins();

View File

@@ -5,7 +5,7 @@
#include "Router.h" #include "Router.h"
#include "configuration.h" #include "configuration.h"
PositionPlugin positionPlugin; PositionPlugin *positionPlugin;
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p) bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p)
{ {
@@ -29,15 +29,10 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position
MeshPacket *PositionPlugin::allocReply() MeshPacket *PositionPlugin::allocReply()
{ {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position
assert(node);
assert(node->has_position); assert(node->has_position);
// Update our local node info with our position (even if we don't decide to update anyone else) return allocDataProtobuf(node->position);
auto position = node->position;
position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
return allocDataProtobuf(position);
} }
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)

View File

@@ -30,4 +30,4 @@ class PositionPlugin : public ProtobufPlugin<Position>
virtual MeshPacket *allocReply(); virtual MeshPacket *allocReply();
}; };
extern PositionPlugin positionPlugin; extern PositionPlugin *positionPlugin;

View File

@@ -6,8 +6,6 @@
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
RemoteHardwarePlugin remoteHardwarePlugin;
#define NUM_GPIOS 64 #define NUM_GPIOS 64
// Because (FIXME) we currently don't tell API clients status on sent messages // Because (FIXME) we currently don't tell API clients status on sent messages

View File

@@ -5,9 +5,6 @@
#include <assert.h> #include <assert.h>
// Create an a static instance of our plugin - this registers with the plugin system
ReplyPlugin replyPlugin;
MeshPacket *ReplyPlugin::allocReply() MeshPacket *ReplyPlugin::allocReply()
{ {
assert(currentRequest); // should always be !NULL assert(currentRequest); // should always be !NULL

View File

@@ -0,0 +1,194 @@
#include "SerialPlugin.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
#include "configuration.h"
#include <Arduino.h>
#include <assert.h>
/*
SerialPlugin
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.
Need help with this plugin? Post your question on the Meshtastic Discourse:
https://meshtastic.discourse.group
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.
*/
#define RXD2 16
#define TXD2 17
#define SERIALPLUGIN_RX_BUFFER 128
#define SERIALPLUGIN_STRING_MAX Constants_DATA_PAYLOAD_LEN
#define SERIALPLUGIN_TIMEOUT 250
#define SERIALPLUGIN_BAUD 38400
#define SERIALPLUGIN_ACK 1
SerialPlugin *serialPlugin;
SerialPluginRadio *serialPluginRadio;
SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {}
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
int32_t SerialPlugin::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.serialplugin_enabled = 1;
// radioConfig.preferences.serialplugin_rxd = 35;
// radioConfig.preferences.serialplugin_txd = 15;
// radioConfig.preferences.serialplugin_timeout = 1000;
// radioConfig.preferences.serialplugin_echo = 1;
if (radioConfig.preferences.serialplugin_enabled) {
if (firstTime) {
// Interface with the serial peripheral from in here.
DEBUG_MSG("Initializing serial peripheral interface\n");
if (radioConfig.preferences.serialplugin_rxd && radioConfig.preferences.serialplugin_txd) {
Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, radioConfig.preferences.serialplugin_rxd,
radioConfig.preferences.serialplugin_txd);
} else {
Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, RXD2, TXD2);
}
if (radioConfig.preferences.serialplugin_timeout) {
Serial2.setTimeout(
radioConfig.preferences.serialplugin_timeout); // Number of MS to wait to set the timeout for the string.
} else {
Serial2.setTimeout(SERIALPLUGIN_TIMEOUT); // Number of MS to wait to set the timeout for the string.
}
Serial2.setRxBufferSize(SERIALPLUGIN_RX_BUFFER);
serialPluginRadio = new SerialPluginRadio();
firstTime = 0;
} else {
String serialString;
while (Serial2.available()) {
serialString = Serial2.readString();
serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
serialPluginRadio->sendPayload();
DEBUG_MSG("Received: %s\n", serialStringChar);
}
}
return (10);
} else {
DEBUG_MSG("Serial Plugin Disabled\n");
return (INT32_MAX);
}
#endif
}
MeshPacket *SerialPluginRadio::allocReply()
{
auto reply = allocDataPacket(); // Allocate a packet for sending
return reply;
}
void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies)
{
MeshPacket *p = allocReply();
p->to = dest;
p->decoded.want_response = wantReplies;
p->want_ack = SERIALPLUGIN_ACK;
p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size);
service.sendToMesh(p);
}
bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
{
#ifndef NO_ESP32
if (radioConfig.preferences.serialplugin_enabled) {
auto &p = mp.decoded.data;
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
if (mp.from == nodeDB.getNodeNum()) {
/*
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX
* of the serial interface.
*/
if (radioConfig.preferences.serialplugin_echo) {
// For some reason, we get the packet back twice when we send out of the radio.
// TODO: need to find out why.
if (lastRxID != mp.id) {
lastRxID = mp.id;
// DEBUG_MSG("* * Message came this device\n");
// Serial2.println("* * Message came this device");
Serial2.printf("%s", p.payload.bytes);
}
}
} else {
// DEBUG_MSG("* * Message came from the mesh\n");
// Serial2.println("* * Message came from the mesh");
Serial2.printf("%s", p.payload.bytes);
}
} else {
DEBUG_MSG("Serial Plugin Disabled\n");
}
#endif
return true; // Let others look at this message also if they want
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "SinglePortPlugin.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include <Arduino.h>
#include <functional>
class SerialPlugin : private concurrency::OSThread
{
bool firstTime = 1;
public:
SerialPlugin();
protected:
virtual int32_t runOnce();
};
extern SerialPlugin *serialPlugin;
/*
* Radio interface for SerialPlugin
*
*/
class SerialPluginRadio : public SinglePortPlugin
{
uint32_t lastRxID;
public:
/*
TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here
from the main code.
*/
// SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {}
SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {}
/**
* Send our payload into the mesh
*/
void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
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 SerialPluginRadio *serialPluginRadio;

View File

@@ -3,7 +3,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
TextMessagePlugin textMessagePlugin; TextMessagePlugin *textMessagePlugin;
bool TextMessagePlugin::handleReceived(const MeshPacket &mp) bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
{ {
@@ -18,11 +18,5 @@ bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
notifyObservers(&mp); notifyObservers(&mp);
// This is going into the wifidev feature branch
// Only update the WebUI if WiFi is enabled
//#if WiFi_MODE != 0
// notifyWebUI();
//#endif
return false; // Let others look at this message also if they want return false; // Let others look at this message also if they want
} }

View File

@@ -22,4 +22,4 @@ class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshP
virtual bool handleReceived(const MeshPacket &mp); virtual bool handleReceived(const MeshPacket &mp);
}; };
extern TextMessagePlugin textMessagePlugin; extern TextMessagePlugin *textMessagePlugin;

View File

@@ -0,0 +1,82 @@
#include "AES.h"
#include "CTR.h"
#include "CryptoEngine.h"
#include "configuration.h"
/** A platform independent AES engine implemented using Tiny-AES
*/
class CrossPlatformCryptoEngine : public CryptoEngine
{
CTRCommon *ctr = NULL;
/// How many bytes in our key
uint8_t keySize = 0;
public:
CrossPlatformCryptoEngine() {}
~CrossPlatformCryptoEngine() {}
/**
* 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;
DEBUG_MSG("Installing AES%d key!\n", numBytes * 8);
if (ctr) {
delete ctr;
ctr = NULL;
}
if (numBytes != 0) {
if (numBytes == 16)
ctr = new CTR<AES128>();
else
ctr = new CTR<AES256>();
ctr->setKey(bytes, numBytes);
}
}
/**
* Encrypt a packet
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
if (keySize != 0) {
uint8_t stream_block[16];
static uint8_t scratch[MAX_BLOCKSIZE];
size_t nc_off = 0;
// DEBUG_MSG("ESP32 encrypt!\n");
initNonce(fromNode, packetNum);
assert(numBytes <= MAX_BLOCKSIZE);
memcpy(scratch, bytes, numBytes);
memset(scratch + numBytes, 0,
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
ctr->setIV(nonce, sizeof(nonce));
ctr->setCounterSize(4);
ctr->encrypt(bytes, scratch, numBytes);
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
// For CTR, the implementation is the same
encrypt(fromNode, packetNum, numBytes, bytes);
}
private:
};
CryptoEngine *crypto = new CrossPlatformCryptoEngine();

View File

@@ -1,8 +1,12 @@
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "target_specific.h" #include "target_specific.h"
#include <Utility.h> #include "PortduinoGPIO.h"
#include "mesh/RF95Interface.h"
#include "sleep.h" #include "sleep.h"
#include <Utility.h>
#include <assert.h>
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class // FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
uint32_t hwId; // fixme move into portduino uint32_t hwId; // fixme move into portduino
@@ -31,7 +35,60 @@ void cpuDeepSleep(uint64_t msecs) {
notImplemented("cpuDeepSleep"); notImplemented("cpuDeepSleep");
} }
// FIXME - implement real crypto for linux void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
CryptoEngine *crypto = new CryptoEngine();
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); /** Dear pinetab hardware geeks!
*
* The current pinetab lora module has a slight bug. The ch341 part only provides ISR assertions on edges.
* This makes sense because USB interrupts happen through fast/repeated special irq urbs that are constantly
* chattering on the USB bus.
*
* But this isn't sufficient for level triggered ISR sources like the sx127x radios. The common way that seems to
* be addressed by cs341 users is to **always** connect the INT# (pin 26 on the ch341f) signal to one of the GPIO signals
* on the part. I'd recommend connecting that LORA_DIO0/INT# line to pin 19 (data 4) on the pinetab board. This would
* provide an efficent mechanism so that the (kernel) code in the cs341 driver that I've slightly hacked up to see the
* current state of LORA_DIO0. Without that access, I can't know if the interrupt is still pending - which would create
* race conditions in packet handling.
*
* My workaround is to poll the status register internally to the sx127x. Which is expensive because it involves a number of
* i2c transactions and many trips back and forth between kernel and my userspace app. I think shipping the current version
* of the pinetab lora device would be fine because I can poll slowly (because lora is slow). But if you ever have cause to
* rev this board. I highly encourage this small change.
*
* Btw - your little "USB lora dongle" is really neat. I encourage you to sell it, because even non pinetab customers could
* use it to easily add lora to rasberry pi, desktop pcs etc...
*
* Porduino helper class to do this i2c based polling:
*/
class R595PolledIrqPin : public GPIOPin {
public:
R595PolledIrqPin() : GPIOPin(LORA_DIO0, "LORA_DIO0") {}
/// Read the low level hardware for this pin
virtual PinStatus readPinHardware()
{
if(isrPinStatus < 0)
return LOW; // No interrupt handler attached, don't bother polling i2c right now
else {
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
assert(rIf);
RF95Interface *rIf95 = static_cast<RF95Interface *>(rIf);
bool p = rIf95->isIRQPending();
// log(SysGPIO, LogDebug, "R595PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p);
return p ? HIGH : LOW;
}
}
};
/** apps run under portduino can optionally define a portduinoSetup() to
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
* before running 'arduino' code.
*/
void portduinoSetup() {
printf("Setting up Meshtastic on Porduino...\n");
gpioBind(new R595PolledIrqPin());
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
}

View File

@@ -1,4 +1,4 @@
[VERSION] [VERSION]
major = 1 major = 1
minor = 1 minor = 1
build = 30 build = 33