Compare commits

...

157 Commits

Author SHA1 Message Date
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
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 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
Kevin Hester
abb52e5446 Merge pull request #607 from geeksville/dev
1.1.30
2020-12-30 18:31:20 +08:00
Kevin Hester
de37a0c31e 1.1.30 2020-12-30 18:21:32 +08:00
Kevin Hester
6e31ba30c7 move generated protobuf c code to own directory 2020-12-30 12:34:22 +08:00
Kevin Hester
8fe1c518d9 Merge branch 'mqtt' into dev
# Conflicts:
#	proto
2020-12-30 12:25:00 +08:00
Kevin Hester
b6006fe3d5 use default serial port for the current platform 2020-12-30 12:19:08 +08:00
Kevin Hester
3e8173c4bd Merge pull request #600 from geeksville/dev
Dev
2020-12-30 10:20:05 +08:00
Kevin Hester
d8a15d6324 Merge branch 'master' into dev 2020-12-30 10:08:01 +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
Jm Casler
b75c7ad179 Merge pull request #596 from mc-hamster/master
#588 - Calculate air time. TX and RX logging is done. #601 - tbeam draws too much power from usb
2020-12-29 14:08:24 -08:00
Jm Casler
44f89c969d Merge branch 'master' into master 2020-12-29 13:31:31 -08:00
oztug
5595fb38c1 Genieblocks Lora support 2020-12-29 18:08:11 +03:00
Jm Casler
c0e0e095c9 Merge pull request #602 from Noki/master
case with large gps antenna option
2020-12-28 10:02:27 -08:00
Jm Casler
6c1c0640f2 Merge branch 'master' into master 2020-12-28 09:54:31 -08:00
Tobias Schwarz
698102371f case with large gps antenna option 2020-12-28 11:20:43 +01:00
Jm
997ed283bf #601 - tbeam draws too much power from USB port 2020-12-28 01:12:42 -08:00
Kevin Hester
9128f7d4b3 turn on battery pin for lora_v2 per @msws 2020-12-28 15:00:34 +08:00
Kevin Hester
93d0257be7 Merge remote-tracking branch 'root/master' into dev 2020-12-28 14:59:09 +08:00
Kevin Hester
adc71e7ed2 mqtt doc progress 2020-12-28 14:42:24 +08:00
Kevin Hester
516e18ca80 mqtt doc updates 2020-12-28 13:57:59 +08:00
Kevin Hester
4777e53c23 more mqtt design work 2020-12-28 13:36:11 +08:00
Kevin Hester
d6912cfd8e mqtt design progress 2020-12-28 13:22:10 +08:00
Jm
621306e610 Add IP address and rssi to /json/report 2020-12-27 15:03:32 -08:00
Jm Casler
0e507e1923 Merge branch 'master' into master 2020-12-27 12:39:36 -08:00
Jm
15a0b3694d Update to #588 - Change "hour" to "period" 2020-12-27 10:50:52 -08:00
Jm Casler
6e4cf22cf0 Accidently checked in my platform.ini 2020-12-27 09:49:23 -08:00
Jm Casler
58859848a3 Add RX and RX_ALL analytics for #588 2020-12-27 09:29:48 -08:00
Kevin Hester
55f61826bf Merge pull request #599 from geeksville/mqtt
fix bug for scriptblock
2020-12-27 17:05:33 +08:00
Kevin Hester
f80d357b77 Merge remote-tracking branch 'root/master' into mqtt 2020-12-27 16:59:23 +08:00
Kevin Hester
c972197643 fix #598 don't corrupt the heap when a TCP connection drops 2020-12-27 16:58:32 +08:00
Kevin Hester
c06b7b2b48 add misc mqtt ideas 2020-12-27 16:06:30 +08:00
Jm
3c69beef94 Update to the airtime calculator. I didn't 0 out the RX log. 2020-12-26 23:37:04 -08:00
Jm Casler
e55c5e10bc Merge branch 'master' into master 2020-12-26 22:43:56 -08:00
Jm
e321528a6d #588 - Calculate TX air time 2020-12-26 22:39:43 -08:00
Kevin Hester
ee897bce6c Merge pull request #595 from geeksville/mqtt
draft pull request to visualize MQTT changes vs master
2020-12-27 13:28:55 +08:00
Kevin Hester
186a52172c fix #577 don't make invalid radio settings reboot the board
instead raise a critical fault (note though: this is still not ideal
because the radio will be in an undefined state until valid settings
are used)
2020-12-27 13:09:20 +08:00
Kevin Hester
21570fc24f fix #540 use gps to fix rtc clock drift every 12 hrs 2020-12-27 12:54:44 +08:00
Kevin Hester
2edc6b363d fix #587 thanks @cronyx 2020-12-27 12:53:23 +08:00
Kevin Hester
0c74303e9d move criticalerror defs into .proto for cross platform support 2020-12-27 11:22:08 +08:00
Kevin Hester
244e597a9f Merge remote-tracking branch 'root/master' into dev 2020-12-26 14:01:46 +08:00
Kevin Hester
15833e1e53 Merge remote-tracking branch 'root/master' into mqtt 2020-12-26 13:59:26 +08:00
Kevin Hester
73d64d378a Merge branch 'dev' into mqtt 2020-12-26 13:58:58 +08:00
Kevin Hester
8d04410f45 improve error descriptions 2020-12-26 13:55:59 +08:00
Kevin Hester
36d28d2da6 Merge pull request #594 from geeksville/dev
Dev
2020-12-26 13:53:48 +08:00
Kevin Hester
4a653ab054 fix nrf52 build 2020-12-26 13:47:02 +08:00
Kevin Hester
651bd71454 show critical faults on the screen 2020-12-26 13:36:21 +08:00
Kevin Hester
1e9ebbc476 Merge remote-tracking branch 'root/master' into dev 2020-12-26 12:53:39 +08:00
Kevin Hester
27c16ba185 add ppr1 notes 2020-12-26 12:53:20 +08:00
Kevin Hester
51a8c7118a Merge pull request #593 from Noki/master
More cases and info about GPS and LoRa antennas
2020-12-26 12:17:08 +08:00
Kevin Hester
808c4ff5ca Merge branch 'master' into master 2020-12-26 10:35:07 +08:00
Jm Casler
ded2b86e55 Calculate TX air time duty cycles #588 -- UNTESTED 2020-12-25 16:10:38 -08:00
Tobias Schwarz
9efcdc7c67 More cases and info about GPS and LoRa antennas 2020-12-25 20:58:31 +01:00
Jm Casler
34e6dbec81 Merge pull request #33 from meshtastic/master
updated my repo
2020-12-25 09:44:27 -08:00
Kevin Hester
62b655ccea Merge pull request #592 from geeksville/dev
Dev
2020-12-25 15:51:14 +08:00
Kevin Hester
3c2aac87f7 better fix for screen messages in log 2020-12-25 15:39:42 +08:00
Kevin Hester
3aba097096 Merge branch 'dev' of https://github.com/geeksville/Meshtastic-esp32 into dev 2020-12-25 15:32:21 +08:00
Kevin Hester
f45451ca74 missing line term 2020-12-25 15:31:17 +08:00
Kevin Hester
c35fec9f20 Merge branch 'master' into dev 2020-12-25 15:23:54 +08:00
Kevin Hester
88fa24ce79 Merge branch 'dev' of https://github.com/geeksville/Meshtastic-esp32 into dev 2020-12-25 15:19:25 +08:00
Kevin Hester
59577b9d79 add real formatted debug logging with timestamps 2020-12-25 15:17:56 +08:00
Kevin Hester
c349ad62e7 we set randomSeed at boot so I think probably not good to do again
cool @mc-hamster?
2020-12-25 14:53:33 +08:00
Jm
d5b57840d9 checking in a little of the airtime so i can switch to the laptop. 2020-12-24 22:12:59 -08:00
Kevin Hester
f8a3d143cb Merge pull request #591 from geeksville/dev
Dev
2020-12-25 14:04:50 +08:00
Kevin Hester
c717dfc33d Merge branch 'master' into dev 2020-12-25 11:38:27 +08:00
Jm Casler
22d9096c3d Merge pull request #590 from mc-hamster/master
#554 Keep radio turned on if we're contacted over http(s)
2020-12-24 19:30:30 -08:00
Jm Casler
8080bc608b Merge pull request #32 from meshtastic/master
Update from upstream.
2020-12-24 19:20:36 -08:00
Kevin Hester
c4b9d60afa Merge remote-tracking branch 'root/master' into dev 2020-12-25 11:16:55 +08:00
Kevin Hester
dda5568e2c update arduino lib & esp bins to fix #584 2020-12-25 11:14:00 +08:00
Kevin Hester
2d8e00e2a0 Merge pull request #589 from geeksville/dev
Dev
2020-12-25 10:23:47 +08:00
Kevin Hester
901ff6bb1e bug #587 try to work with old (2.x?) versions of python 2020-12-25 10:16:49 +08:00
Kevin Hester
7312c56d6c Merge remote-tracking branch 'root/master' into dev
# Conflicts:
#	src/PowerFSM.cpp
2020-12-25 10:16:12 +08:00
Kevin Hester
031c58e21c remove logspam that was busting serial api 2020-12-23 17:12:48 +08:00
Jm
35b1cfcc42 #554 Keep radio turned on if we're contacted over http(s) while on battery power. 2020-12-22 23:15:09 -08:00
Jm Casler
e545778154 Merge pull request #583 from mc-hamster/master
Quiet a compile time warning I introduced
2020-12-22 22:49:05 -08:00
Jm Casler
6fd2bc5f83 Merge branch 'master' into master 2020-12-22 22:39:05 -08:00
Jm
9a587b2743 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-12-22 22:37:49 -08:00
Jm
bacc1b1dad #581 - Quiet a compile time warning I introduced. 2020-12-22 22:37:34 -08:00
Jm Casler
575b69c541 Merge pull request #582 from mc-hamster/master
#407 - Fix for wifi does not come back up after power down
2020-12-22 22:36:09 -08:00
Jm Casler
73092b4b40 Merge branch 'master' into master 2020-12-22 22:28:22 -08:00
Jm
877dc824a9 #407 - Fix for wifi does not come back up after power down 2020-12-22 22:26:08 -08:00
Kevin Hester
89c76dca11 Merge pull request #579 from mc-hamster/master
Fix for #535 -- Heltec board stays asleep ...
2020-12-23 10:05:07 +08:00
Kevin Hester
2253ea1b41 Merge branch 'master' into master 2020-12-23 09:58:36 +08:00
Jm Casler
b732a13d6c Merge pull request #580 from crossan007/master
add HTTP/Delete method handler for SPIFFS
2020-12-22 15:46:18 -08:00
Charles Crossan
8e0c224813 remove extra whitespace 2020-12-22 17:47:24 -05:00
Charles Crossan
5a96dc0083 move json delete endpoint 2020-12-22 17:44:40 -05:00
Jm Casler
181db06b0c Merge branch 'master' into master 2020-12-21 19:59:40 -08:00
Charles Crossan
47ccfb6106 add HTTP/Delete method handler for SPIFFS 2020-12-21 21:10:53 -05:00
Jm Casler
5f97740ab7 Fix for #535 -- Heltec board stays asleep ... 2020-12-21 17:42:00 -08:00
Jm Casler
90d6878bbb Merge pull request #578 from crossan007/master
add mime types for ico and svg
2020-12-21 16:25:54 -08:00
Charles Crossan
5c70f36aa5 add mime types for ico and svg 2020-12-21 17:42:55 -05:00
Tobias Schwarz
09cc0a85db Merge pull request #1 from meshtastic/master
merge from original repository
2020-12-21 19:56:45 +01:00
Jm Casler
a47fcdacb5 Merge pull request #575 from mc-hamster/master
Fix for #574 - add /json/blink endpoint
2020-12-20 20:24:15 -08:00
Jm Casler
ef0891ae5d Fix for #576 - The browser was seeing the other files on the filesystem. 2020-12-20 20:09:17 -08:00
Kevin Hester
a8d7700295 move more of is_router out of python and into the device code 2020-12-21 11:38:03 +08:00
Kevin Hester
412916ba7c fix printf format for 64 bits 2020-12-21 11:13:30 +08:00
Kevin Hester
616290edcc speed up build for my slow laptop 2020-12-21 11:13:16 +08:00
Jm Casler
9ed19892e2 Merge branch 'master' into master 2020-12-20 18:59:23 -08:00
Jm Casler
88cf60ad9d Merge pull request #31 from crossan007/adjust-blink-timings
adjust LED timings; switch to HTTP/POST; add SCREEN blink support
2020-12-20 18:49:45 -08:00
Charles Crossan
7f59e76c72 fix formatting 2020-12-20 21:47:46 -05:00
Charles Crossan
dcb9125b32 remove unused parser 2020-12-20 21:47:23 -05:00
Charles Crossan
2743b9d310 use POST URL parameters; fix response status 2020-12-20 21:44:51 -05:00
Charles Crossan
2f779bfd37 improve blink; LED or SCREEN as POST Parameter 2020-12-20 18:24:48 -05:00
Charles Crossan
db2193b526 implement screen blink 2020-12-20 17:45:45 -05:00
Charles Crossan
7205e9a5b4 adjust LED timings; switch to HTTP/POST 2020-12-20 14:50:13 -05:00
Jm Casler
1ca83509dd Blink the LED for one second on get of /json/blink 2020-12-20 11:32:49 -08:00
Jm Casler
7135a12300 Merge pull request #573 from mc-hamster/master
New feature #571 - Report contents of spiffs in a json data structure.
2020-12-19 12:25:15 -08:00
Jm Casler
fae9ea8b3b Update for #571 (i forgot to set the mime type) 2020-12-19 12:18:08 -08:00
Jm Casler
b96ee7be72 New feature #571 - Report contents of spiffs in a json data structure. 2020-12-19 12:09:48 -08:00
Jm Casler
9e449bebf9 Merge pull request #30 from meshtastic/master
update my repo
2020-12-19 09:22:26 -08:00
geeksville
8bdbbfbe16 add notes about tuple 2020-09-21 12:44:30 -07:00
geeksville
0ba4925f75 add @mc-hamster comment 2020-09-21 11:54:54 -07:00
geeksville
26d50fda9a Update mqtt doc 2020-09-20 18:08:10 -07:00
geeksville
bc22ab7b87 riot.im 2020-09-20 13:07:53 -07:00
geeksville
d5e3e63d6d begin mqtt planning 2020-09-20 13:04:29 -07:00
68 changed files with 1500 additions and 263 deletions

View File

@@ -30,11 +30,14 @@ We currently support three models of radios.
- [T-Beam V0.7 w/ NEO-6M](https://www.aliexpress.com/item/4000574335430.html) (will work but **you must use the tbeam0.7 firmware ** - but the T-Beam V1.0 or later are better!)
- board labels "TTGO T22_V07 20180711"
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
- [T-Beam V0](https://www.thingiverse.com/thing:3773717) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:3830711)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4677388) (Mounting option for larger GPS antenna but LoRa antenna enclosed)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4589651)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4619981) (GPS and LoRa antenna misaligned if GPS placed as pictured)
- Laser-cut cases
- [T-Beam V1](https://www.thingiverse.com/thing:4552771)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4552771)
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
- version 2.1
@@ -43,7 +46,10 @@ We currently support three models of radios.
- [TTGO LORA32 v1](https://www.thingiverse.com/thing:3385109)
- [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/) - No GPS
- [Official Heltec case](https://www.aliexpress.com/item/4001050707951.html)
- [3D Printable case](https://www.thingiverse.com/thing:3125854)
Note: The GPS and LoRa stock antennas should be placed in a way, that the GPS antenna faces the sky and the LoRa antenna radiates 360 degrees horizontally. For better GPS reception you might want to [upgrade the GPS antenna](https://meshtastic.discourse.group/t/the-importance-of-gps-antennas-and-request-to-3d-case-documentation-people/1505) and to properly align the antennas you might want to upgrade to a LoRa antenna that can be adjusted to radiate into the right directions.
**Make sure to get the frequency for your country**

View File

@@ -14,6 +14,8 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="lora-relay-v1"
NUM_JOBS=2
OUTDIR=release/latest
# We keep all old builds (and their map files in the archive dir)
@@ -49,7 +51,7 @@ function do_build() {
basename=universal/firmware-$BOARD-$VERSION
fi
pio run --jobs 4 --environment $BOARD # -v
pio run --jobs $NUM_JOBS --environment $BOARD # -v
SRCELF=.pio/build/$BOARD/firmware.elf
cp $SRCELF $OUTDIR/elfs/$basename.elf

View File

@@ -8,9 +8,9 @@ config.read(prefsLoc)
version = dict(config.items('VERSION'))
verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"])
print(f"Using meshtastic platform-custom.py, firmare version {verStr}")
print("Using meshtastic platform-custom.py, firmare version " + verStr)
# General options that are passed to the C and C++ compilers
projenv.Append(CCFLAGS=[
f"-DAPP_VERSION={verStr}"
"-DAPP_VERSION=" + verStr
])

View File

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

View File

@@ -4,6 +4,9 @@ You probably don't care about this section - skip to the next one.
For app cleanup:
* use structured logging to kep logs in ram. Also send logs as packets to api clients
* DONE writeup nice python options docs (common cases, link to protobuf docs)
* have android app link to user manual
* DONE only do wantReplies once per packet type, if we change network settings force it again
* update positions and nodeinfos based on packets we just merely witness on the mesh. via isPromsciousPort bool, remove sniffing
* DONE make device build always have a valid version
@@ -32,11 +35,10 @@ For app cleanup:
* DONE move user info into regular data packets (use new app framework)
* DONE test that positions, text messages and user info still work
* DONE test that position, text messages and user info work properly with new android app and old device code
* do UDP tunnel
* fix the RTC drift bug
* DONE do UDP tunnel
* DONE fix the RTC drift bug
* move python ping functionality into device, reply with rxsnr info
* use channels for gpio security https://github.com/meshtastic/Meshtastic-device/issues/104
* generate autodocs
* MeshPackets for sending should be reference counted so that API clients would have the option of checking sent status (would allow removing the nasty 30 sec timer in gpio watch sending)
For high speed/lots of devices/short range tasks:

View File

@@ -10,7 +10,7 @@ you'll automatically get our fixed libraries.
IDF release/v3.3 46b12a560
IDF release/v3.3 367c3c09c
https://docs.espressif.com/projects/esp-idf/en/release-v3.3/get-started/linux-setup.html
kevinh@kevin-server:~/development/meshtastic/esp32-arduino-lib-builder\$ python /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/esp-idf/components/esptool*py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/build/bootloader/bootloader.bin
kevinh@kevin-server:~/development/meshtastic/esp32-arduino-lib-builder\$ python /home/kevinh/development/meshtastic/
cp -a out/tools/sdk/* components/arduino/tools/sdk
cp -ar components/arduino/* ~/.platformio/packages/framework-arduinoespressif32
@@ -21,3 +21,9 @@ you'll automatically get our fixed libraries.
cp -ar out/tools/sdk/* ~/.platformio/packages/framework-arduinoespressif32/tools/sdk
```
How to flash new bootloader
```
esp32-arduino-lib-builder/esp-idf/components/esptool*py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/build/bootloader/bootloader.bin
```

192
docs/software/mqtt.md Normal file
View File

@@ -0,0 +1,192 @@
# Table of Contents
- [Table of Contents](#table-of-contents)
- [Abstract](#abstract)
- [Short term goals](#short-term-goals)
- [Long term goals](#long-term-goals)
- [Multiple Channel support / Security](#multiple-channel-support--security)
- [On device API](#on-device-api)
- [MQTT transport](#mqtt-transport)
- [Topics](#topics)
- [Service Envelope](#service-envelope)
- [NODEID](#nodeid)
- [USERID](#userid)
- [CHANNELID](#channelid)
- [Gateway nodes](#gateway-nodes)
- [Optional web services](#optional-web-services)
- [Public MQTT broker service](#public-mqtt-broker-service)
- [Riot.im messaging bridge](#riotim-messaging-bridge)
- [Deprecated concepts](#deprecated-concepts)
- [MESHID (deprecated)](#meshid-deprecated)
- [DESTCLASS (deprecated)](#destclass-deprecated)
- [DESTID (deprecated)](#destid-deprecated)
- [Rejected idea: RAW UDP](#rejected-idea-raw-udp)
- [Development plan](#development-plan)
- [Work items](#work-items)
- [Enhancements in following releases](#enhancements-in-following-releases)
## Abstract
This is a mini-doc/RFC sketching out a development plan to satisfy a number of 1.1 goals.
- [MQTT](https://opensource.com/article/18/6/mqtt) internet accessible API. Issue #[369](https://github.com/meshtastic/Meshtastic-device/issues/169)
- An open API to easily run custom mini-apps on the devices
- A text messaging bridge when a node in the mesh can gateway to the internet. Issue #[353](https://github.com/meshtastic/Meshtastic-device/issues/353) and this nicely documented [android issue](https://github.com/meshtastic/Meshtastic-Android/issues/2).
- An easy way to let desktop app developers remotely control GPIOs. Issue #[182](https://github.com/meshtastic/Meshtastic-device/issues/182)
- Remote attribute access (to change settings of distant nodes). Issue #182
## Short term goals
- We want a clean API for novice developers to write mini "apps" that run **on the device** with the existing messaging/location "apps".
- We want the ability to have a gateway web service, so that if any node in the mesh can connect to the internet (via its connected phone app or directly) then that node will provide bidirectional messaging between nodes and the internet.
- We want an easy way for novice developers to remotely read and control GPIOs (because this is an often requested use case), without those developers having to write any device code.
- We want a way to gateway text messaging between our current private meshes and the broader internet (when that mesh is able to connect to the internet)
- We want a way to remotely set any device/channel parameter on a node. This is particularly important for administering physically inaccessible router nodes. Ideally this mechanism would also be used for administering the local node (so one common mechanism for both cases).
- This work should be independent of our current (semi-custom) LoRa transport, so that in the future we can swap out that transport if we wish (to QMesh or Reticulum?)
- Our networks are (usually) very slow and low bandwidth, so the messaging must be very airtime efficient.
## Long term goals
- Store and forward messaging should be supported, so apps can send messages that might be delivered to their destination in **hours** or **days** if a node/mesh was partitioned.
## Multiple Channel support / Security
Mini-apps API can bind to particular channels. They will only see messages sent on that channel.
During the 1.0 timeframe only one channel was supported per node. Starting in the 1.1 tree we will do things like "remote admin operations / channel settings etc..." are on the "Control" channel and only especially trusted users should have the keys to access that channel.
FIXME - explain this more, talk about how useful for users and security domains.
- add channels as security
## On device API
For information on the related on-device API see [here](device-api.md).
## MQTT transport
Any gateway-device will contact the MQTT broker.
### Topics
The "mesh/crypt/CHANNELID/NODEID/PORTID" [topic](https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices/) will be used for messages sent from/to a mesh.
Gateway nodes will foward any MeshPacket from a local mesh channel with uplink_enabled. The packet (encapsulated in a ServiceEnvelope) will remain encrypted with the key for the specified channel.
For any channels in the local node with downlink_enabled, the gateway node will forward packets from MQTT to the local mesh. It will do this by subscribing to mesh/crypt/CHANNELID/# and forwarding relevant packets.
If the channelid 'well known'/public it could be decrypted by a web service (if the web service was provided with the associated channel key), in which case it will be decrypted by a web service and appear at "mesh/clear/CHANNELID/NODEID/PORTID". Note: This is not in the initial deliverable.
FIXME, discuss how text message global mirroring could scale (or not)
FIXME, possibly don't global mirror text messages - instead rely on matrix/riot?
FIXME, discuss possible attacks by griefers and how they can be prvented
#### Service Envelope
The payload published on mesh/... will always be wrapped in a [ServiceEnvelope protobuf](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/docs/docs.md#.ServiceEnvelope).
ServiceEnvelope will include the message, and full information about arrival time, who forwarded it, source channel, source mesh id, etc...
#### NODEID
The unique ID for a node. A hex string that starts with a ! symbol.
#### USERID
A user ID string. This string is either a user ID if known or a nodeid to simply deliver the message to whoever the local user is of a particular device (i.e. person who might see the screen). FIXME, see what riot.im uses and perhaps use that convention? Or use the signal +phone number convention? Or the email addr?
#### CHANNELID
FIXME, figure out how channelids work
### Gateway nodes
Any meshtastic node that has a direct connection to the internet (either via a helper app or installed wifi/4G/satellite hardware) can function as a "Gateway node".
Gateway nodes (via code running in the phone) will contain two tables to whitelist particular traffic to either be delivered toward the internet, or down toward the mesh. Users that are developing custom apps will be able to customize these filters/subscriptions.
Since multiple gateway nodes might be connected to a single mesh, it is possible that duplicate messages will be published on any particular topic. Therefore subscribers to these topics should
deduplicate if needed by using the packet ID of each message.
### Optional web services
#### Public MQTT broker service
An existing public [MQTT broker](https://mosquitto.org/) will be the default for this service, but clients can use any MQTT broker they choose.
FIXME - figure out how to avoid impersonation (because we are initially using a public mqtt server with no special security options). FIXME, include some ideas on this in the ServiceEnvelope documentation.
#### Riot.im messaging bridge
@Geeksville will run a riot.im bridge that talks to the public MQTT broker and sends/receives into the riot.im network.
There is apparently [already](https://github.com/derEisele/tuple) a riot.im [bridge](https://matrix.org/bridges/) for MQTT. That will possibly need to be customized a bit. But by doing this, we should be able to let random riot.im users send/receive messages to/from any meshtastic device. (FIXME ponder security). See this [issue](https://github.com/meshtastic/Meshtastic-Android/issues/2#issuecomment-645660990) with discussion with the dev.
### Deprecated concepts
You can ignore these for now...
#### MESHID (deprecated)
Earlier drafts of this document included the concept of a MESHID. That concept has been removed for now, but might be useful in the future. The old idea is listed below:
A unique ID for this mesh. There will be some sort of key exchange process so that the mesh ID can not be impersonated by other meshes.
#### DESTCLASS (deprecated)
Earlier drafts of this document included the concept of a DESTCLASS. That concept has been removed for now, but might be useful in the future. The old idea is listed below:
The type of DESTID this message should be delivered to. A short one letter sequence:
| Symbol | Description |
| ------ | ------------------------------------------------------------- |
| R | riot.im |
| L | local mesh node ID or ^all |
| A | an application specific message, ID will be an APP ID |
| S | SMS gateway, DESTID is a phone number to reach via Twilio.com |
| E | Emergency message, see bug #fixme for more context |
#### DESTID (deprecated)
Earlier drafts of this document included the concept of a DESTCLASS. That concept has been removed for now, but might be useful in the future. The old idea is listed below:
Can be...
- an internet username: kevinh@geeksville.com
- ^ALL for anyone
- An app ID (to allow apps out in the web to receive arbitrary binary data from nodes or simply other apps using meshtastic as a transport). They would connect to the MQTT broker and subscribe to their topic
## Rejected idea: RAW UDP
A number of commenters have requested/proposed using UDP for the transport. We've considered this option and decided to use MQTT instead for the following reasons:
- Most UDP uses cases would need to have a server anyways so that nodes can reach each other from anywhere (i.e. if most gateways will be behind some form of NAT which would need to be tunnelled)
- Raw UDP is dropped **very** agressively by many cellular providers. MQTT from the gateway to a broker can be done over a TCP connection for this reason.
- MQTT provides a nice/documented/standard security model to build upon
- MQTT is fairly wire efficient with multiple broker implementations/providers and numerous client libraries for any language. The actual implementation of MQTT is quite simple.
## Development plan
Given the previous problem/goals statement, here's the initial thoughts on the work items required. As this idea becomes a bit more fully baked we should add details
on how this will be implemented and guesses at approximate work items.
### Work items
- Change nodeIDs to be base64 instead of eight hex digits.
- DONE Refactor the position features into a position "mini-app". Use only the new public on-device API to implement this app.
- DONE Refactor the on device texting features into a messaging "mini-app". (Similar to the position mini-app)
- Add new multi channel concept
- Send new channels to python client
- Let python client add channels
- Add portion of channelid to the raw lora packet header
- Confirm that we can now forward encrypted packets without decrypting at each node
- Use a channel named "remotehw" to secure the GPIO service. If that channel is not found, don't even start the service. Document this as the standard method for securing services.
- Add first cut of the "gateway node" code (i.e. MQTT broker client) to the python API (very little code needed for this component)
- Confirm that texting works to/from the internet
- Confirm that positions are optionally sent to the internet
- Add the first cut of the "gateway node" code to the android app (very little code needed for this component)
### Enhancements in following releases
The initial gateway will be added to the python tool. But the gateway implementation is designed to be fairly trivial/dumb. After the initial release the actual gateway code can be ported to also run inside of the android app. In fact, we could have ESP32 based nodes include a built-in "gateway node" implementation.
Store and forward could be added so that nodes on the mesh could deliver messages (i.e. text messages) on an "as possible" basis. This would allow things like "hiker sends a message to friend - mesh can not currently reach friend - eventually (days later) mesh can somehow reach friend, message gets delivered"

View File

@@ -0,0 +1,23 @@
# Remote Hardware Service
FIXME - the following are a collection of notes moved from elsewhere. We need to refactor these notes into actual documentation on the remote-hardware/gpio service.
### 1.7.2. New 'no-code-IOT' mini-app
Add a new 'remote GPIO/serial port/SPI/I2C access' mini-app. This new standard app would use the MQTT messaging layer to let users (developers that don't need to write device code) do basic (potentially dangerous) operations remotely.
#### 1.7.2.1. Supported operations in the initial release
Initially supported features for no-code-IOT.
- Set any GPIO
- Read any GPIO
#### 1.7.2.2. Supported operations eventually
General ideas for no-code IOT.
- Subscribe for notification of GPIO input status change (i.e. when pin goes low, send my app a message)
- Write/read N bytes over I2C/SPI bus Y (as one atomic I2C/SPI transaction)
- Send N bytes out serial port Z
- Subscribe for notification for when regex X matches the bytes that were received on serial port Z

View File

@@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[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 = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = 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
[common]
@@ -65,7 +65,7 @@ lib_deps =
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/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/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
@@ -103,7 +103,7 @@ lib_deps =
# board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore = segger_rtt
platform_packages =
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#2814f110aa618429bdd9a0a2d6a93c55f29f87a6
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#352c8ea7cb73f10433ed139f34251979c470ad56
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
@@ -183,7 +183,7 @@ build_flags =
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/> -<mesh/wifi/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
@@ -314,3 +314,13 @@ src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/>
build_flags = ${arduino_base.build_flags} -O0
framework = arduino
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: 75078afe43...dfe7bc1217

View File

@@ -16,6 +16,10 @@ template <class T> class Observer
public:
virtual ~Observer();
/// Stop watching our current obserable
void unobserve();
/// Start watching a specified observable
void observe(Observable<T> *o);
private:
@@ -82,6 +86,11 @@ template <class T> class Observable
};
template <class T> Observer<T>::~Observer()
{
unobserve();
}
template <class T> void Observer<T>::unobserve()
{
if (observed)
observed->removeObserver(this);

View File

@@ -268,7 +268,9 @@ bool Power::axp192Init()
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "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
//axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
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.
#if 0
// Not connected

View File

@@ -144,12 +144,12 @@ static void onEnter()
uint32_t now = millis();
if (now - lastPingMs > 30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
if (now - lastPingMs >
30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
if (displayedNodeNum)
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now;
}
}
static void screenPress()
@@ -171,11 +171,18 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = radioConfig.preferences.is_router;
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
// We assume routers might be powered all the time, but from a low current (solar) source
bool isLowPower = radioConfig.preferences.is_low_power;
bool hasPower = !isLowPower && powerStatus && powerStatus->getHasUSB();
bool isRouter = radioConfig.preferences.is_router;
bool isLowPower = radioConfig.preferences.is_low_power || isRouter;
/* To determine if we're externally powered, assumptions
1) If we're powered up and there's no battery, we must be getting power externally.
2) If we detect USB power from the power management chip, we must be getting power externally.
*/
bool hasPower = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB());
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");

View File

@@ -1,6 +1,9 @@
#include "RedirectablePrint.h"
#include "configuration.h"
#include <assert.h>
#include <sys/time.h>
#include <time.h>
#include "concurrency/OSThread.h"
/**
* A printer that doesn't go anywhere
@@ -15,10 +18,82 @@ void RedirectablePrint::setDestination(Print *_dest)
size_t RedirectablePrint::write(uint8_t c)
{
// Always send the characters to our segger JTAG debugger
#ifdef SEGGER_STDOUT_CH
SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c);
#endif
dest->write(c);
return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero)
}
size_t RedirectablePrint::vprintf(const char *format, va_list arg)
{
va_list copy;
va_copy(copy, arg);
int len = vsnprintf(printBuf, printBufLen, format, copy);
va_end(copy);
if (len < 0) {
va_end(arg);
return 0;
};
if (len >= printBufLen) {
delete[] printBuf;
printBufLen *= 2;
printBuf = new char[printBufLen];
len = vsnprintf(printBuf, printBufLen, format, arg);
}
len = Print::write(printBuf, len);
return len;
}
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600
#define SEC_PER_MIN 60
size_t RedirectablePrint::logDebug(const char *format, ...)
{
va_list arg;
va_start(arg, format);
// Cope with 0 len format strings, but look for new line terminator
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
size_t r = 0;
// If we are the first message on a report, include the header
if (!isContinuationMessage) {
struct timeval tv;
if (!gettimeofday(&tv, NULL)) {
long hms = tv.tv_sec % SEC_PER_DAY;
//hms += tz.tz_dsttime * SEC_PER_HOUR;
//hms -= tz.tz_minuteswest * SEC_PER_MIN;
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
// Tear apart hms into h:m:s
int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
r += printf("%02d:%02d:%02d ", hour, min, sec);
} else
r += printf("??:??:?? ");
auto thread = concurrency::OSThread::currentThread;
if(thread) {
print("[");
print(thread->ThreadName);
print("] ");
}
}
r += vprintf(format, arg);
va_end(arg);
isContinuationMessage = !hasNewline;
return r;
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <Print.h>
#include <stdarg.h>
/**
* A Printable that can be switched to squirt its bytes to a different sink.
@@ -11,6 +12,13 @@ class RedirectablePrint : public Print
{
Print *dest;
/// We dynamically grow this scratch buffer if necessary
char *printBuf = new char[64];
size_t printBufLen = 64;
/// Used to allow multiple logDebug messages to appear on a single log line
bool isContinuationMessage = false;
public:
RedirectablePrint(Print *_dest) : dest(_dest) {}
@@ -20,6 +28,21 @@ class RedirectablePrint : public Print
void setDestination(Print *dest);
virtual size_t write(uint8_t c);
/**
* Debug logging print message
*
* If the provide format string ends with a newline we assume it is the final print of a single
* log message. Otherwise we assume more prints will come before the log message ends. This
* allows you to call logDebug a few times to build up a single log message line if you wish.
*
* FIXME, eventually add log levels (INFO, WARN, ERROR) and subsystems. Move into
* a different class.
*/
size_t logDebug(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
/** like printf but va_list based */
size_t vprintf(const char *format, va_list arg);
};
class NoopPrint : public Print

88
src/airtime.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "airtime.h"
#include <Arduino.h>
#define periodsToLog 48
// A reminder that there are 3600 seconds in an hour so I don't have
// to keep googling it.
// This can be changed to a smaller number to speed up testing.
//
uint32_t secondsPerPeriod = 3600;
uint32_t lastMillis = 0;
uint32_t secSinceBoot = 0;
// Don't read out of this directly. Use the helper functions.
struct airtimeStruct {
uint16_t periodTX[periodsToLog];
uint16_t periodRX[periodsToLog];
uint16_t periodRX_ALL[periodsToLog];
uint8_t lastPeriodIndex;
} airtimes;
void logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000);
} else if (reportType == RX_LOG) {
airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000);
} else if (reportType == RX_ALL_LOG) {
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000);
} else {
// Unknown report type
}
}
uint8_t currentPeriodIndex()
{
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
}
void airtimeCalculator()
{
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();
}
}
}
uint16_t *airtimeReport(reportTypes reportType)
{
// currentHourIndexReset();
if (reportType == TX_LOG) {
return airtimes.periodTX;
} else if (reportType == RX_LOG) {
return airtimes.periodRX;
} else if (reportType == RX_ALL_LOG) {
return airtimes.periodRX_ALL;
}
return 0;
}
uint8_t getPeriodsToLog()
{
return periodsToLog;
}
uint32_t getSecondsPerPeriod()
{
return secondsPerPeriod;
}
uint32_t getSecondsSinceBoot()
{
return secSinceBoot;
}

38
src/airtime.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include "configuration.h"
#include <Arduino.h>
#include <functional>
/*
TX_LOG - Time on air this device has transmitted
RX_LOG - Time on air used by valid and routable mesh packets, does not include
TX air time
RX_ALL_LOG - Time of all received lora packets. This includes packets that are not
for meshtastic devices. Does not include TX air time.
Example analytics:
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
other lora radios.
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
*/
enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
void airtimeCalculator();
uint8_t currentPeriodIndex();
uint8_t getPeriodsToLog();
uint32_t getSecondsSinceBoot();
uint16_t *airtimeReport(reportTypes reportType);
uint32_t getSecondsPerPeriod();

View File

@@ -14,6 +14,8 @@ bool OSThread::showRun = false;
/// Show debugging info for threads we decide not to run;
bool OSThread::showWaiting = false;
const OSThread *OSThread::currentThread;
ThreadController mainController, timerController;
InterruptableDelay mainDelay;
@@ -68,12 +70,15 @@ bool OSThread::shouldRun(unsigned long time)
void OSThread::run()
{
currentThread = this;
auto newDelay = runOnce();
runned();
if (newDelay >= 0)
setInterval(newDelay);
currentThread = NULL;
}
} // namespace concurrency

View File

@@ -42,6 +42,10 @@ class OSThread : public Thread
static bool showWaiting;
public:
/// For debug printing only (might be null)
static const OSThread *currentThread;
OSThread(const char *name, uint32_t period = 0, ThreadController *controller = &mainController);
virtual ~OSThread();

View File

@@ -289,6 +289,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
@@ -336,6 +338,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(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
#ifdef ARDUINO_NRF52840_PCA10056
@@ -363,7 +394,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define USE_RF95
#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_DIO2 32 // Not really used
@@ -371,7 +402,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS 18
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
#endif
@@ -428,7 +459,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.printf(__VA_ARGS__)
#define DEBUG_MSG(...) DEBUG_PORT.logDebug(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif

View File

@@ -2,8 +2,7 @@
#include <Arduino.h>
/// Error codes for critical error
enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait, ErrNoRadio, ErrUnspecified, UBloxInitFailed };
#include "mesh/generated/mesh.pb.h" // For CriticalErrorCode
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address = 0);
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0);

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
// 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);
assert(res == ESP_OK);

View File

@@ -158,7 +158,7 @@ uint32_t GPS::getWakeTime() const
return t; // already maxint
if (t == 0)
t = 15 * 60; // Allow up to 5 mins for each attempt (probably will be much less if we can find sats)
t = radioConfig.preferences.is_router ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much less if we can find sats) or less if a router
t *= 1000; // msecs
@@ -179,8 +179,8 @@ uint32_t GPS::getSleepTime() const
if (t == UINT32_MAX)
return t; // already maxint
if (t == 0)
t = 2 * 60; // 2 mins
if (t == 0) // default - unset in preferences
t = radioConfig.preferences.is_router ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers
t *= 1000;
@@ -239,6 +239,7 @@ int32_t GPS::runOnce()
}
// We've been awake too long - force sleep
now = millis();
auto wakeTime = getWakeTime();
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;

View File

@@ -31,9 +31,24 @@ void readFromRTC()
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
{
static uint32_t lastSetMsec = 0;
uint32_t now = millis();
bool shouldSet;
if (q > currentQuality) {
currentQuality = q;
DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec);
shouldSet = true;
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)) {
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
shouldSet = true;
DEBUG_MSG("Reapplying GPS time to correct clock drift %ld secs\n", tv->tv_sec);
}
else
shouldSet = false;
if (shouldSet) {
lastSetMsec = now;
#ifndef NO_ESP32
settimeofday(tv, NULL);
#else

View File

@@ -43,7 +43,7 @@ bool UBloxGPS::setupGPS()
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
if (!setUBXMode())
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
recordCriticalError(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
return true;
} else {

View File

@@ -26,8 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "MeshService.h"
#include "NodeDB.h"
#include "Screen.h"
#include "configs.h"
#include "configuration.h"
#include "fonts.h"
#include "graphics/images.h"
#include "main.h"
#include "mesh-pb-constants.h"
@@ -41,6 +41,15 @@ using namespace meshtastic; /** @todo remove */
namespace graphics
{
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44
// DEBUG
#define NUM_EXTRA_FRAMES 3 // text message and debug frame
// if defined a pixel will blink to show redraws
// #define SHOW_REDRAWS
// A text message frame + debug frame + all the node infos
static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
static uint32_t targetFramerate = IDLE_FRAMERATE;
@@ -152,6 +161,22 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, 48 + y, buf);
}
/// Draw the last text message we received
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
char tempBuf[24];
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", myNodeInfo.error_code);
display->drawString(0 + x, 0 + y, tempBuf);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please post on\nmeshtastic.discourse.group");
}
/// Draw the last text message we received
static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -290,7 +315,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
// Draw the number of satellites
sprintf(satsString, "%lu", gps->getNumSatellites());
sprintf(satsString, "%u", gps->getNumSatellites());
display->drawString(x + 34, y - 2, satsString);
}
}
@@ -543,11 +568,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20];
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
snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60);
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
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];
strcpy(distStr, "? km"); // might not have location data
@@ -849,7 +874,11 @@ void Screen::setFrames()
size_t numframes = 0;
// If we have a text message - show it first
// If we have a critical fault, show it first
if (myNodeInfo.error_code)
normalFrames[numframes++] = drawCriticalFaultFrame;
// If we have a text message - show it next
if (devicestate.has_rx_text_message)
normalFrames[numframes++] = drawTextMessageFrame;
@@ -894,9 +923,28 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
setFastFramerate();
}
void Screen::blink()
{
setFastFramerate();
uint8_t count = 10;
dispdev.setBrightness(254);
while (count > 0) {
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
dispdev.display();
delay(50);
dispdev.clear();
dispdev.display();
delay(50);
count = count - 1;
}
dispdev.setBrightness(brightness);
}
void Screen::handlePrint(const char *text)
{
DEBUG_MSG("Screen: %s", text);
// the string passed into us probably has a newline, but that would confuse the logging system
// so strip it
DEBUG_MSG("Screen: %.*s\n", strlen(text) - 1, text);
if (!useDisplay || !showingNormalScreen)
return;
@@ -1012,11 +1060,13 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) {
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
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 {
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) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");

View File

@@ -107,6 +107,8 @@ class Screen : public concurrency::OSThread
*/
void doDeepSleep();
void blink();
/// Handles a button press.
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }

View File

@@ -3,7 +3,6 @@
#ifdef ST7735_CS
#include "SPILock.h"
#include "TFTDisplay.h"
#include "graphics/configs.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip

View File

@@ -1,12 +0,0 @@
#pragma once
#include "fonts.h"
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44
// DEBUG
#define NUM_EXTRA_FRAMES 2 // text message and debug frame
// if defined a pixel will blink to show redraws
// #define SHOW_REDRAWS

View File

@@ -5,6 +5,7 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "UBloxGPS.h"
#include "airtime.h"
#include "configuration.h"
#include "error.h"
#include "power.h"
@@ -92,6 +93,7 @@ void scanI2Cdevice(void)
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
DEBUG_MSG("No I2C devices found\n");
else
@@ -362,6 +364,10 @@ void setup()
nrf52Setup();
#endif
// We do this as early as possible because this loads preferences from flash
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
nodeDB.init();
// Currently only the tbeam has a PMU
power = new Power();
power->setStatusHandler(powerStatus);
@@ -383,6 +389,19 @@ void setup()
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
UBloxGPS *ublox = NULL;
#ifdef GPS_TX_PIN
@@ -420,6 +439,12 @@ void setup()
service.init();
// Do this after service.init (because that clears error_code)
#ifdef AXP192_SLAVE_ADDRESS
if(!axp192_found)
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
#endif
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(HAS_EINK)
@@ -486,7 +511,7 @@ void setup()
initWifi(forceSoftAP);
if (!rIf)
recordCriticalError(ErrNoRadio);
recordCriticalError(CriticalErrorCode_NoRadio);
else
router->addInterface(rIf);
@@ -558,4 +583,7 @@ void loop()
// We want to sleep as long as possible here - because it saves power
mainDelay.delay(delayMsec);
// if (didWake) DEBUG_MSG("wake!\n");
// Handles cleanup for the airtime calculator.
airtimeCalculator();
}

View File

@@ -4,7 +4,6 @@
#include "MeshTypes.h"
#include "PointerQueue.h"
#include "configuration.h"
#include "mesh.pb.h"
// Map from old region names to new region enums
struct RegionInfo {

View File

@@ -77,7 +77,8 @@ void MeshService::init()
sendOwnerPeriod = new concurrency::Periodic("SendOwner", sendOwnerCb);
sendOwnerPeriod->setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
nodeDB.init();
// moved much earlier in boot (called from setup())
// nodeDB.init();
if (gps)
gpsObserver.observe(&gps->newStatus);

View File

@@ -10,7 +10,6 @@
#include "MeshTypes.h"
#include "Observer.h"
#include "PointerQueue.h"
#include "mesh.pb.h"
/**
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.

View File

@@ -3,7 +3,7 @@
// low level types
#include "MemoryPool.h"
#include "mesh.pb.h"
#include "mesh/mesh-pb-constants.h"
#include <Arduino.h>
typedef uint32_t NodeNum;

View File

@@ -271,6 +271,9 @@ void NodeDB::init()
myNodeInfo.node_num_bits = sizeof(NodeNum) * 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_address = 0;
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20

View File

@@ -147,23 +147,53 @@ their nodes
*/
const char *getChannelName();
/*
If is_router is set, we use a number of different default values
# FIXME - after tuning, move these params into the on-device defaults based on is_router and is_low_power
# prefs.position_broadcast_secs = FIXME possibly broadcast only once an hr
prefs.wait_bluetooth_secs = 1 # Don't stay in bluetooth mode
prefs.mesh_sds_timeout_secs = never
prefs.phone_sds_timeout_sec = never
# try to stay in light sleep one full day, then briefly wake and sleep again
prefs.ls_secs = oneday
prefs.send_owner_interval = 2 # Send an owner packet every other network ping
prefs.position_broadcast_secs = 12 hours # send either position or owner every 12hrs
# get a new GPS position once per day
prefs.gps_update_interval = oneday
prefs.is_low_power = True
# allow up to five minutes for each new GPS lock attempt
prefs.gps_attempt_time = 300
*/
// Our delay functions check for this for times that should never expire
#define DELAY_FOREVER 0xffffffff
#define IF_ROUTER(routerVal, normalVal) (radioConfig.preferences.is_router ? (routerVal) : (normalVal))
#define PREF_GET(name, defaultVal) \
inline uint32_t getPref_##name() { return radioConfig.preferences.name ? radioConfig.preferences.name : (defaultVal); }
PREF_GET(send_owner_interval, 4)
PREF_GET(position_broadcast_secs, 15 * 60)
PREF_GET(send_owner_interval, IF_ROUTER(2, 4))
PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60))
// Each time we wake into the DARK state allow 1 minute to send and receive BLE packets to the phone
PREF_GET(wait_bluetooth_secs, 60)
PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60))
PREF_GET(screen_on_secs, 60)
PREF_GET(mesh_sds_timeout_secs, 2 * 60 * 60)
PREF_GET(phone_sds_timeout_sec, 2 * 60 * 60)
PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(phone_sds_timeout_sec, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60))
PREF_GET(sds_secs, 365 * 24 * 60 * 60)
// We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between
// latency for the user sending messages and power savings because of not having to run (expensive) ESP32 bluetooth
PREF_GET(ls_secs, 5 * 60)
PREF_GET(ls_secs, IF_ROUTER(24 * 60 * 60, 5 * 60))
PREF_GET(phone_timeout_secs, 15 * 60)
PREF_GET(min_wake_secs, 10)

View File

@@ -7,22 +7,33 @@
#include <assert.h>
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
#error FromRadio is too big
#error FromRadio is too big
#endif
#if ToRadio_size > MAX_TO_FROM_RADIO_SIZE
#error ToRadio is too big
#error ToRadio is too big
#endif
PhoneAPI::PhoneAPI()
{
}
PhoneAPI::PhoneAPI() {}
void PhoneAPI::init()
{
observe(&service.fromNumChanged);
}
PhoneAPI::~PhoneAPI() {
close();
}
void PhoneAPI::close() {
unobserve();
state = STATE_SEND_NOTHING;
bool oldConnected = isConnected;
isConnected = false;
if(oldConnected != isConnected)
onConnectionChanged(isConnected);
}
void PhoneAPI::checkConnectionTimeout()
{
if (isConnected) {
@@ -100,9 +111,9 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
size_t PhoneAPI::getFromRadio(uint8_t *buf)
{
if (!available()) {
DEBUG_MSG("getFromRadio, !available\n");
// DEBUG_MSG("getFromRadio, !available\n");
return 0;
}
}
DEBUG_MSG("getFromRadio, state=%d\n", state);
@@ -170,7 +181,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
if (packetForPhone) {
printPacket("phone downloaded packet", packetForPhone);
// Encapsulate as a FromRadio packet
fromRadioScratch.which_variant = FromRadio_packet_tag;
fromRadioScratch.variant.packet = *packetForPhone;
@@ -226,7 +237,7 @@ bool PhoneAPI::available()
if (!packetForPhone)
packetForPhone = service.getForPhone();
bool hasPacket = !!packetForPhone;
DEBUG_MSG("available hasPacket=%d\n", hasPacket);
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
return hasPacket;
}

View File

@@ -2,7 +2,6 @@
#include "Observer.h"
#include "mesh-pb-constants.h"
#include "mesh.pb.h"
#include <string>
// Make sure that we never let our packets grow too large for one BLE packet
@@ -21,7 +20,7 @@ class PhoneAPI
: public Observer<uint32_t> // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
{
enum State {
STATE_LEGACY, // Temporary default state - until Android apps are all updated, uses the old BLE API
STATE_LEGACY, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API
STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_RADIO,
@@ -31,7 +30,7 @@ class PhoneAPI
STATE_SEND_PACKETS // send packets or debug strings
};
State state = STATE_LEGACY;
State state = STATE_SEND_NOTHING;
/**
* Each packet sent to the phone has an incrementing count
@@ -53,14 +52,19 @@ class PhoneAPI
/** the last msec we heard from the client on the other side of this link */
uint32_t lastContactMsec = 0;
bool isConnected = false;
public:
PhoneAPI();
/// Destructor - calls close()
virtual ~PhoneAPI();
/// Do late init that can't happen at constructor time
virtual void init();
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
virtual void close();
/**
* Handle a ToRadio protobuf
*/
@@ -87,6 +91,9 @@ class PhoneAPI
void handleSetRadio(const RadioConfig &r);
protected:
/// Are we currently connected to a client?
bool isConnected = false;
/// Our fromradio packet while it is being assembled
FromRadio fromRadioScratch;

View File

@@ -1,6 +1,7 @@
#include "RF95Interface.h"
#include "MeshRadio.h" // kinda yucky, but we need to know which region we are in
#include "RadioLibRF95.h"
#include "error.h"
#include <configuration.h>
#define MAX_POWER 20
@@ -11,7 +12,7 @@
#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)
: RadioLibInterface(cs, irq, rst, 0, spi)
: RadioLibInterface(cs, irq, rst, RADIOLIB_NC, spi)
{
// FIXME - we assume devices never get destroyed
}
@@ -85,6 +86,8 @@ void INTERRUPT_ATTR RF95Interface::disableInterrupt()
lora->clearDio0Action();
}
bool RF95Interface::reconfigure()
{
applyModemConfig();
@@ -94,13 +97,13 @@ bool RF95Interface::reconfigure()
// configure publicly accessible settings
int err = lora->setSpreadingFactor(sf);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
err = lora->setBandwidth(bw);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
err = lora->setCodingRate(cr);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
err = lora->setSyncWord(syncWord);
assert(err == ERR_NONE);
@@ -112,12 +115,12 @@ bool RF95Interface::reconfigure()
assert(err == ERR_NONE);
err = lora->setFrequency(freq);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
if (power > MAX_POWER) // This chip has lower power limits than some
power = MAX_POWER;
err = lora->setOutputPower(power);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
startReceive(); // restart receiving

View File

@@ -14,6 +14,9 @@ class RF95Interface : public RadioLibInterface
public:
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.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.

View File

@@ -5,7 +5,7 @@
#include "MeshTypes.h"
#include "Observer.h"
#include "PointerQueue.h"
#include "mesh.pb.h"
#include "airtime.h"
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
@@ -36,7 +36,7 @@ typedef struct {
*
* This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations)
*/
class RadioInterface
class RadioInterface
{
friend class MeshRadio; // for debugging we let that class touch pool
PointerQueue<MeshPacket> *rxDest = NULL;

View File

@@ -58,7 +58,6 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0()
*/
RadioLibInterface *RadioLibInterface::instance;
/** Could we send right now (i.e. either not actively receving or transmitting)? */
bool RadioLibInterface::canSendImmediately()
{
@@ -96,6 +95,10 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
return res;
}
// Count the packet toward our TX airtime utilization.
// We only count it if it can be added to the TX queue.
logAirtime(TX_LOG, xmitMsec);
// We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent
// in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio
startTransmitTimer(true);
@@ -205,12 +208,16 @@ void RadioLibInterface::completeSending()
void RadioLibInterface::handleReceiveInterrupt()
{
uint32_t xmitMsec;
assert(isReceiving);
isReceiving = false;
// read the number of actually received bytes
size_t length = iface->getPacketLength();
xmitMsec = getPacketTime(length);
logAirtime(RX_ALL_LOG, xmitMsec);
int state = iface->readData(radiobuf, length);
if (state != ERR_NONE) {
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
@@ -250,11 +257,14 @@ void RadioLibInterface::handleReceiveInterrupt()
printPacket("Lora RX", mp);
xmitMsec = getPacketTime(mp);
logAirtime(RX_LOG, xmitMsec);
deliverToReceiver(mp);
}
}
}
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket *txp)
{

View File

@@ -6,7 +6,6 @@
#include "PointerQueue.h"
#include "RadioInterface.h"
#include "concurrency/OSThread.h"
#include "mesh.pb.h"
/**
* A mesh aware router that supports multiple interfaces.

View File

@@ -1,4 +1,5 @@
#include "SX1262Interface.h"
#include "error.h"
#include <configuration.h>
// Particular boards might define a different max power based on what their hardware can do
@@ -78,13 +79,13 @@ bool SX1262Interface::reconfigure()
// configure publicly accessible settings
int err = lora.setSpreadingFactor(sf);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
err = lora.setBandwidth(bw);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
err = lora.setCodingRate(cr);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
err = lora.setRxGain(true);
@@ -100,7 +101,7 @@ bool SX1262Interface::reconfigure()
assert(err == ERR_NONE);
err = lora.setFrequency(freq);
assert(err == ERR_NONE);
if(err != ERR_NONE) recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
if (power > 22) // This chip has lower power limits than some
power = 22;

View File

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

View File

@@ -0,0 +1,56 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_APPONLY_PB_H_INCLUDED
#define PB_APPONLY_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _ServiceEnvelope {
bool has_packet;
MeshPacket packet;
pb_callback_t channel_id;
pb_callback_t gateway_id;
} ServiceEnvelope;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define ServiceEnvelope_init_default {false, MeshPacket_init_default, {{NULL}, NULL}, {{NULL}, NULL}}
#define ServiceEnvelope_init_zero {false, MeshPacket_init_zero, {{NULL}, NULL}, {{NULL}, NULL}}
/* Field tags (for use in manual encoding/decoding) */
#define ServiceEnvelope_packet_tag 1
#define ServiceEnvelope_channel_id_tag 2
#define ServiceEnvelope_gateway_id_tag 3
/* Struct field encoding specification for nanopb */
#define ServiceEnvelope_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, packet, 1) \
X(a, CALLBACK, SINGULAR, STRING, channel_id, 2) \
X(a, CALLBACK, SINGULAR, STRING, gateway_id, 3)
#define ServiceEnvelope_CALLBACK pb_default_field_callback
#define ServiceEnvelope_DEFAULT NULL
#define ServiceEnvelope_packet_MSGTYPE MeshPacket
extern const pb_msgdesc_t ServiceEnvelope_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define ServiceEnvelope_fields &ServiceEnvelope_msg
/* Maximum encoded size of messages (where known) */
/* ServiceEnvelope_size depends on runtime parameters */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

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

View File

@@ -0,0 +1,89 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_DEVICEONLY_PB_H_INCLUDED
#define PB_DEVICEONLY_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _DeviceState {
bool has_radio;
RadioConfig radio;
bool has_my_node;
MyNodeInfo my_node;
bool has_owner;
User owner;
pb_size_t node_db_count;
NodeInfo node_db[32];
pb_size_t receive_queue_count;
MeshPacket receive_queue[1];
bool has_rx_text_message;
MeshPacket rx_text_message;
uint32_t version;
bool no_save;
bool did_gps_reset;
pb_size_t secondary_channels_count;
ChannelSettings secondary_channels[7];
} DeviceState;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define DeviceState_radio_tag 1
#define DeviceState_my_node_tag 2
#define DeviceState_owner_tag 3
#define DeviceState_node_db_tag 4
#define DeviceState_receive_queue_tag 5
#define DeviceState_rx_text_message_tag 7
#define DeviceState_version_tag 8
#define DeviceState_no_save_tag 9
#define DeviceState_did_gps_reset_tag 11
#define DeviceState_secondary_channels_tag 12
/* Struct field encoding specification for nanopb */
#define DeviceState_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, radio, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8) \
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_radio_MSGTYPE RadioConfig
#define DeviceState_my_node_MSGTYPE MyNodeInfo
#define DeviceState_owner_MSGTYPE User
#define DeviceState_node_db_MSGTYPE NodeInfo
#define DeviceState_receive_queue_MSGTYPE MeshPacket
#define DeviceState_rx_text_message_MSGTYPE MeshPacket
#define DeviceState_secondary_channels_MSGTYPE ChannelSettings
extern const pb_msgdesc_t DeviceState_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define DeviceState_fields &DeviceState_msg
/* Maximum encoded size of messages (where known) */
#define DeviceState_size 6176
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -39,10 +39,7 @@ PB_BIND(NodeInfo, NodeInfo, AUTO)
PB_BIND(MyNodeInfo, MyNodeInfo, AUTO)
PB_BIND(DeviceState, DeviceState, 2)
PB_BIND(DebugString, DebugString, 2)
PB_BIND(LogRecord, LogRecord, AUTO)
PB_BIND(FromRadio, FromRadio, 2)
@@ -58,3 +55,5 @@ PB_BIND(ToRadio, ToRadio, 2)

View File

@@ -48,6 +48,17 @@ typedef enum _LocationSharing {
LocationSharing_LocDisabled = 2
} LocationSharing;
typedef enum _CriticalErrorCode {
CriticalErrorCode_None = 0,
CriticalErrorCode_TxWatchdog = 1,
CriticalErrorCode_SleepEnterWait = 2,
CriticalErrorCode_NoRadio = 3,
CriticalErrorCode_Unspecified = 4,
CriticalErrorCode_UBloxInitFailed = 5,
CriticalErrorCode_NoAXP192 = 6,
CriticalErrorCode_InvalidRadioSetting = 7
} CriticalErrorCode;
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
@@ -55,6 +66,16 @@ typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3
} ChannelSettings_ModemConfig;
typedef enum _LogRecord_Level {
LogRecord_Level_UNSET = 0,
LogRecord_Level_CRITICAL = 50,
LogRecord_Level_ERROR = 40,
LogRecord_Level_WARNING = 30,
LogRecord_Level_INFO = 20,
LogRecord_Level_DEBUG = 10,
LogRecord_Level_TRACE = 5
} LogRecord_Level;
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t;
typedef struct _ChannelSettings {
@@ -66,6 +87,9 @@ typedef struct _ChannelSettings {
uint32_t spread_factor;
uint32_t coding_rate;
uint32_t channel_num;
uint32_t id;
bool uplink_enabled;
bool downlink_enabled;
} ChannelSettings;
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
@@ -74,9 +98,12 @@ typedef struct _Data {
Data_payload_t payload;
} Data;
typedef struct _DebugString {
char message[256];
} DebugString;
typedef struct _LogRecord {
char message[64];
uint32_t time;
char source[8];
LogRecord_Level level;
} LogRecord;
typedef struct _MyNodeInfo {
uint32_t my_node_num;
@@ -85,7 +112,7 @@ typedef struct _MyNodeInfo {
char region[12];
char hw_model[16];
char firmware_version[12];
uint32_t error_code;
CriticalErrorCode error_code;
uint32_t error_address;
uint32_t error_count;
uint32_t packet_id_bits;
@@ -106,7 +133,6 @@ typedef struct _Position {
typedef struct _RadioConfig_UserPreferences {
uint32_t position_broadcast_secs;
uint32_t send_owner_interval;
uint32_t num_missed_to_fail;
uint32_t wait_bluetooth_secs;
uint32_t screen_on_secs;
uint32_t phone_timeout_secs;
@@ -199,26 +225,6 @@ typedef struct _MeshPacket {
bool want_ack;
} MeshPacket;
typedef struct _DeviceState {
bool has_radio;
RadioConfig radio;
bool has_my_node;
MyNodeInfo my_node;
bool has_owner;
User owner;
pb_size_t node_db_count;
NodeInfo node_db[32];
pb_size_t receive_queue_count;
MeshPacket receive_queue[1];
bool has_rx_text_message;
MeshPacket rx_text_message;
uint32_t version;
bool no_save;
bool did_gps_reset;
pb_size_t secondary_channels_count;
ChannelSettings secondary_channels[4];
} DeviceState;
typedef struct _FromRadio {
uint32_t num;
pb_size_t which_variant;
@@ -227,10 +233,10 @@ typedef struct _FromRadio {
MyNodeInfo my_info;
NodeInfo node_info;
RadioConfig radio;
DebugString debug_string;
LogRecord log_record;
uint32_t config_complete_id;
bool rebooted;
ChannelSettings secondary_channel;
ChannelSettings channel;
} variant;
} FromRadio;
@@ -241,6 +247,7 @@ typedef struct _ToRadio {
uint32_t want_config_id;
RadioConfig set_radio;
User set_owner;
ChannelSettings set_channel;
} variant;
} ToRadio;
@@ -266,10 +273,18 @@ typedef struct _ToRadio {
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
#define _CriticalErrorCode_MIN CriticalErrorCode_None
#define _CriticalErrorCode_MAX CriticalErrorCode_InvalidRadioSetting
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_InvalidRadioSetting+1))
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
#define _LogRecord_Level_MIN LogRecord_Level_UNSET
#define _LogRecord_Level_MAX LogRecord_Level_CRITICAL
#define _LogRecord_Level_ARRAYSIZE ((LogRecord_Level)(LogRecord_Level_CRITICAL+1))
#ifdef __cplusplus
extern "C" {
@@ -282,13 +297,12 @@ extern "C" {
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 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, _LocationSharing_MIN, _GpsOperation_MIN, 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 MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}}
#define DebugString_init_default {""}
#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 FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define Position_init_zero {0, 0, 0, 0, 0}
@@ -297,13 +311,12 @@ extern "C" {
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 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, _LocationSharing_MIN, _GpsOperation_MIN, 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 MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}}
#define DebugString_init_zero {""}
#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 FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
@@ -316,9 +329,15 @@ extern "C" {
#define ChannelSettings_spread_factor_tag 7
#define ChannelSettings_coding_rate_tag 8
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_id_tag 10
#define ChannelSettings_uplink_enabled_tag 16
#define ChannelSettings_downlink_enabled_tag 17
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define DebugString_message_tag 1
#define LogRecord_message_tag 1
#define LogRecord_time_tag 2
#define LogRecord_source_tag 3
#define LogRecord_level_tag 4
#define MyNodeInfo_my_node_num_tag 1
#define MyNodeInfo_has_gps_tag 2
#define MyNodeInfo_num_channels_tag 3
@@ -340,7 +359,6 @@ extern "C" {
#define Position_time_tag 9
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
#define RadioConfig_UserPreferences_send_owner_interval_tag 2
#define RadioConfig_UserPreferences_num_missed_to_fail_tag 3
#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4
#define RadioConfig_UserPreferences_screen_on_secs_tag 5
#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6
@@ -397,29 +415,20 @@ extern "C" {
#define MeshPacket_rx_time_tag 9
#define MeshPacket_hop_limit_tag 10
#define MeshPacket_want_ack_tag 11
#define DeviceState_radio_tag 1
#define DeviceState_my_node_tag 2
#define DeviceState_owner_tag 3
#define DeviceState_node_db_tag 4
#define DeviceState_receive_queue_tag 5
#define DeviceState_rx_text_message_tag 7
#define DeviceState_version_tag 8
#define DeviceState_no_save_tag 9
#define DeviceState_did_gps_reset_tag 11
#define DeviceState_secondary_channels_tag 12
#define FromRadio_num_tag 1
#define FromRadio_packet_tag 2
#define FromRadio_my_info_tag 3
#define FromRadio_node_info_tag 4
#define FromRadio_radio_tag 6
#define FromRadio_debug_string_tag 7
#define FromRadio_log_record_tag 7
#define FromRadio_config_complete_id_tag 8
#define FromRadio_rebooted_tag 9
#define FromRadio_secondary_channel_tag 10
#define FromRadio_channel_tag 10
#define ToRadio_packet_tag 1
#define ToRadio_want_config_id_tag 100
#define ToRadio_set_radio_tag 101
#define ToRadio_set_owner_tag 102
#define ToRadio_set_channel_tag 103
/* Struct field encoding specification for nanopb */
#define Position_FIELDLIST(X, a) \
@@ -494,7 +503,10 @@ X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 9)
X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \
X(a, STATIC, SINGULAR, FIXED32, id, 10) \
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17)
#define ChannelSettings_CALLBACK NULL
#define ChannelSettings_DEFAULT NULL
@@ -509,7 +521,6 @@ X(a, STATIC, OPTIONAL, MESSAGE, channel_settings, 2)
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \
X(a, STATIC, SINGULAR, UINT32, num_missed_to_fail, 3) \
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \
X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \
@@ -553,7 +564,7 @@ X(a, STATIC, SINGULAR, INT32, num_channels, 3) \
X(a, STATIC, SINGULAR, STRING, region, 4) \
X(a, STATIC, SINGULAR, STRING, hw_model, 5) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \
X(a, STATIC, SINGULAR, UINT32, error_code, 7) \
X(a, STATIC, SINGULAR, UENUM, error_code, 7) \
X(a, STATIC, SINGULAR, UINT32, error_address, 8) \
X(a, STATIC, SINGULAR, UINT32, error_count, 9) \
X(a, STATIC, SINGULAR, UINT32, packet_id_bits, 10) \
@@ -564,31 +575,13 @@ X(a, STATIC, SINGULAR, UINT32, min_app_version, 14)
#define MyNodeInfo_CALLBACK NULL
#define MyNodeInfo_DEFAULT NULL
#define DeviceState_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, radio, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8) \
X(a, STATIC, SINGULAR, BOOL, no_save, 9) \
X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \
X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_radio_MSGTYPE RadioConfig
#define DeviceState_my_node_MSGTYPE MyNodeInfo
#define DeviceState_owner_MSGTYPE User
#define DeviceState_node_db_MSGTYPE NodeInfo
#define DeviceState_receive_queue_MSGTYPE MeshPacket
#define DeviceState_rx_text_message_MSGTYPE MeshPacket
#define DeviceState_secondary_channels_MSGTYPE ChannelSettings
#define DebugString_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, message, 1)
#define DebugString_CALLBACK NULL
#define DebugString_DEFAULT NULL
#define LogRecord_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, message, 1) \
X(a, STATIC, SINGULAR, FIXED32, time, 2) \
X(a, STATIC, SINGULAR, STRING, source, 3) \
X(a, STATIC, SINGULAR, UENUM, level, 4)
#define LogRecord_CALLBACK NULL
#define LogRecord_DEFAULT NULL
#define FromRadio_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, num, 1) \
@@ -596,29 +589,31 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \
X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \
X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \
X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \
X(a, STATIC, ONEOF, MESSAGE, (variant,debug_string,variant.debug_string), 7) \
X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \
X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \
X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \
X(a, STATIC, ONEOF, MESSAGE, (variant,secondary_channel,variant.secondary_channel), 10)
X(a, STATIC, ONEOF, MESSAGE, (variant,channel,variant.channel), 10)
#define FromRadio_CALLBACK NULL
#define FromRadio_DEFAULT NULL
#define FromRadio_variant_packet_MSGTYPE MeshPacket
#define FromRadio_variant_my_info_MSGTYPE MyNodeInfo
#define FromRadio_variant_node_info_MSGTYPE NodeInfo
#define FromRadio_variant_radio_MSGTYPE RadioConfig
#define FromRadio_variant_debug_string_MSGTYPE DebugString
#define FromRadio_variant_secondary_channel_MSGTYPE ChannelSettings
#define FromRadio_variant_log_record_MSGTYPE LogRecord
#define FromRadio_variant_channel_MSGTYPE ChannelSettings
#define ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 1) \
X(a, STATIC, ONEOF, UINT32, (variant,want_config_id,variant.want_config_id), 100) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,variant.set_radio), 101) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102)
X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102) \
X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,variant.set_channel), 103)
#define ToRadio_CALLBACK NULL
#define ToRadio_DEFAULT NULL
#define ToRadio_variant_packet_MSGTYPE MeshPacket
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
#define ToRadio_variant_set_owner_MSGTYPE User
#define ToRadio_variant_set_channel_MSGTYPE ChannelSettings
extern const pb_msgdesc_t Position_msg;
extern const pb_msgdesc_t Data_msg;
@@ -631,8 +626,7 @@ extern const pb_msgdesc_t RadioConfig_msg;
extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
extern const pb_msgdesc_t NodeInfo_msg;
extern const pb_msgdesc_t MyNodeInfo_msg;
extern const pb_msgdesc_t DeviceState_msg;
extern const pb_msgdesc_t DebugString_msg;
extern const pb_msgdesc_t LogRecord_msg;
extern const pb_msgdesc_t FromRadio_msg;
extern const pb_msgdesc_t ToRadio_msg;
@@ -648,8 +642,7 @@ extern const pb_msgdesc_t ToRadio_msg;
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
#define NodeInfo_fields &NodeInfo_msg
#define MyNodeInfo_fields &MyNodeInfo_msg
#define DeviceState_fields &DeviceState_msg
#define DebugString_fields &DebugString_msg
#define LogRecord_fields &LogRecord_msg
#define FromRadio_fields &FromRadio_msg
#define ToRadio_fields &ToRadio_msg
@@ -660,13 +653,12 @@ extern const pb_msgdesc_t ToRadio_msg;
#define RouteDiscovery_size 88
#define SubPacket_size 275
#define MeshPacket_size 320
#define ChannelSettings_size 84
#define RadioConfig_size 314
#define RadioConfig_UserPreferences_size 225
#define ChannelSettings_size 95
#define RadioConfig_size 319
#define RadioConfig_UserPreferences_size 219
#define NodeInfo_size 132
#define MyNodeInfo_size 110
#define DeviceState_size 5824
#define DebugString_size 258
#define MyNodeInfo_size 106
#define LogRecord_size 81
#define FromRadio_size 329
#define ToRadio_size 323

View File

@@ -17,14 +17,14 @@ typedef enum _PortNum {
PortNum_POSITION_APP = 3,
PortNum_NODEINFO_APP = 4,
PortNum_REPLY_APP = 32,
PortNum_PRIVATE_APP = 256,
PortNum_IP_TUNNEL_APP = 1024
PortNum_IP_TUNNEL_APP = 33,
PortNum_PRIVATE_APP = 256
} PortNum;
/* Helper constants for enums */
#define _PortNum_MIN PortNum_UNKNOWN_APP
#define _PortNum_MAX PortNum_IP_TUNNEL_APP
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_IP_TUNNEL_APP+1))
#define _PortNum_MAX PortNum_PRIVATE_APP
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1))
#ifdef __cplusplus

View File

@@ -1,6 +1,7 @@
#pragma once
#include "mesh.pb.h"
#include "mesh/generated/mesh.pb.h"
#include "mesh/generated/deviceonly.pb.h"
// this file defines constants which come from mesh.options

View File

@@ -5,7 +5,7 @@
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()
@@ -28,13 +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()) {
StreamAPI::loop();
return true;
} else {
DEBUG_MSG("Client dropped connection, closing TCP server\n");
delete this;
return false;
}
}
@@ -53,15 +59,25 @@ int32_t WiFiServerPort::runOnce()
auto client = available();
if (client) {
// Close any previous connection (see FIXME in header file)
if (openAPI)
if (openAPI) {
DEBUG_MSG("Force closing previous TCP connection\n");
delete openAPI;
}
openAPI = new WiFiServerAPI(client);
}
if (openAPI) {
// 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
} else
return 100; // only check occasionally for incoming connections

View File

@@ -18,7 +18,11 @@ class WiFiServerAPI : public StreamAPI
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:
/// Hookable to find out when connection changes

View File

@@ -1,6 +1,9 @@
#include "meshwifi/meshhttp.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "airtime.h"
#include "configuration.h"
#include "esp_task_wdt.h"
#include "main.h"
#include "meshhttpStatic.h"
#include "meshwifi/meshwifi.h"
@@ -60,6 +63,10 @@ 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 middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<void()> next);
@@ -76,7 +83,8 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}
{".js", "text/javascript"}, {".png", "image/png"},
{".jpg", "image/jpg"}, {".gz", "application/gzip"},
{".gif", "image/gif"}, {".json", "application/json"},
{".css", "text/css"}, {"", ""}};
{".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"},
{".svg", "image/svg+xml"}, {"", ""}};
void handleWebResponse()
{
@@ -125,11 +133,12 @@ void taskCreateCert(void *parameter)
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();
// disableCore1WDT();
yield();
int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=meshtastic.local,O=Meshtastic,C=US",
"20190101000000", "20300101000000");
// enableCore1WDT();
yield();
if (createCertResult != 0) {
DEBUG_MSG("Creating the certificate failed\n");
@@ -182,6 +191,7 @@ void createSSLCert()
DEBUG_MSG(".");
delay(1000);
yield();
esp_task_wdt_reset();
}
DEBUG_MSG("SSL Cert Ready!\n");
}
@@ -241,6 +251,10 @@ void initWebServer()
ResourceNode *node404 = new ResourceNode("", "GET", &handle404);
ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks);
ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED);
ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport);
ResourceNode *nodeJsonSpiffsBrowseStatic = new ResourceNode("/json/spiffs/browse/static/", "GET", &handleSpiffsBrowseStatic);
ResourceNode *nodeJsonDelete = new ResourceNode("/json/spiffs/delete/static", "DELETE", &handleSpiffsDeleteStatic);
// Secure nodes
secureServer->registerNode(nodeAPIv1ToRadioOptions);
@@ -255,6 +269,10 @@ void initWebServer()
secureServer->registerNode(nodeRestart);
secureServer->registerNode(nodeFormUpload);
secureServer->registerNode(nodeJsonScanNetworks);
secureServer->registerNode(nodeJsonBlinkLED);
secureServer->registerNode(nodeJsonSpiffsBrowseStatic);
secureServer->registerNode(nodeJsonDelete);
secureServer->registerNode(nodeJsonReport);
secureServer->setDefaultNode(node404);
secureServer->addMiddleware(&middlewareSpeedUp240);
@@ -272,6 +290,10 @@ void initWebServer()
insecureServer->registerNode(nodeRestart);
insecureServer->registerNode(nodeFormUpload);
insecureServer->registerNode(nodeJsonScanNetworks);
insecureServer->registerNode(nodeJsonBlinkLED);
insecureServer->registerNode(nodeJsonSpiffsBrowseStatic);
insecureServer->registerNode(nodeJsonDelete);
insecureServer->registerNode(nodeJsonReport);
insecureServer->setDefaultNode(node404);
insecureServer->addMiddleware(&middlewareSpeedUp160);
@@ -292,6 +314,10 @@ void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function<voi
// We want to print the response status, so we need to call next() first.
next();
// Phone (or other device) has contacted us over WiFi. Keep the radio turned on.
// TODO: This should go into its own middleware layer separate from the speedup.
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
setCpuFrequencyMhz(240);
timeSpeedUp = millis();
}
@@ -301,6 +327,10 @@ void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<voi
// We want to print the response status, so we need to call next() first.
next();
// Phone (or other device) has contacted us over WiFi. Keep the radio turned on.
// TODO: This should go into its own middleware layer separate from the speedup.
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
// If the frequency is 240mhz, we have recently gotten a HTTPS request.
// In that case, leave the frequency where it is and just update the
// countdown timer (timeSpeedUp).
@@ -313,7 +343,7 @@ void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function<voi
void handleStaticPost(HTTPRequest *req, HTTPResponse *res)
{
// Assume POST request. Contains submitted data.
res->println("<html><head><title>File Edited</title><meta http-equiv=\"refresh\" content=\"3;url=/static\" "
res->println("<html><head><title>File Edited</title><meta http-equiv=\"refresh\" content=\"1;url=/static\" "
"/><head><body><h1>File Edited</h1>");
// The form is submitted with the x-www-form-urlencoded content type, so we need the
@@ -379,6 +409,84 @@ void handleStaticPost(HTTPRequest *req, HTTPResponse *res)
res->println("</body></html>");
}
void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
{
// jm
res->setHeader("Content-Type", "application/json");
// res->setHeader("Content-Type", "text/html");
File root = SPIFFS.open("/");
if (root.isDirectory()) {
res->println("{");
res->println("\"data\": {");
File file = root.openNextFile();
res->print("\"files\": [");
bool firstFile = 1;
while (file) {
String filePath = String(file.name());
if (filePath.indexOf("/static") == 0) {
if (firstFile) {
firstFile = 0;
} else {
res->println(",");
}
res->println("{");
if (String(file.name()).substring(1).endsWith(".gz")) {
String modifiedFile = String(file.name()).substring(1);
modifiedFile.remove((modifiedFile.length() - 3), 3);
res->print("\"nameModified\": \"" + modifiedFile + "\",");
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
} else {
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
}
res->print("\"size\": " + String(file.size()));
res->print("}");
}
file = root.openNextFile();
}
res->print("],");
res->print("\"filesystem\" : {");
res->print("\"total\" : " + String(SPIFFS.totalBytes()) + ",");
res->print("\"used\" : " + String(SPIFFS.usedBytes()) + ",");
res->print("\"free\" : " + String(SPIFFS.totalBytes() - SPIFFS.usedBytes()));
res->println("}");
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
}
}
void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
{
ResourceParameters *params = req->getParams();
std::string paramValDelete;
res->setHeader("Content-Type", "application/json");
if (params->getQueryParameter("delete", paramValDelete)) {
std::string pathDelete = "/" + paramValDelete;
if (SPIFFS.remove(pathDelete.c_str())) {
Serial.println(pathDelete.c_str());
res->println("{");
res->println("\"status\": \"ok\"");
res->println("}");
return;
} else {
Serial.println(pathDelete.c_str());
res->println("{");
res->println("\"status\": \"Error\"");
res->println("}");
return;
}
}
}
void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res)
{
// Get access to the parameters
@@ -393,15 +501,15 @@ void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res)
std::string pathDelete = "/" + paramValDelete;
if (SPIFFS.remove(pathDelete.c_str())) {
Serial.println(pathDelete.c_str());
res->println("<html><head><meta http-equiv=\"refresh\" content=\"3;url=/static\" /><title>File "
res->println("<html><head><meta http-equiv=\"refresh\" content=\"1;url=/static\" /><title>File "
"deleted!</title></head><body><h1>File deleted!</h1>");
res->println("<meta http-equiv=\"refresh\" content=\"2;url=/static\" />\n");
res->println("<meta http-equiv=\"refresh\" 1;url=/static\" />\n");
res->println("</body></html>");
return;
} else {
Serial.println(pathDelete.c_str());
res->println("<html><head><meta http-equiv=\"refresh\" content=\"3;url=/static\" /><title>Error deleteing "
res->println("<html><head><meta http-equiv=\"refresh\" content=\"1;url=/static\" /><title>Error deleteing "
"file!</title></head><body><h1>Error deleteing file!</h1>");
res->println("Error deleteing file!<br>");
@@ -451,9 +559,7 @@ void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res)
}
res->println("<h2>Upload new file</h2>");
res->println("<p><b>*** This interface is experimental ***</b></p>");
res->println("<p>This form allows you to upload files. Keep your filenames very short and files small. Big filenames and big "
"files are a known problem.</p>");
res->println("<p>This form allows you to upload files. Keep your filenames small and files under 200k.</p>");
res->println("<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">");
res->println("file: <input type=\"file\" name=\"file\"><br>");
res->println("<input type=\"submit\" value=\"Upload\">");
@@ -594,6 +700,9 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
{
// The upload process is very CPU intensive. Let's speed things up a bit.
setCpuFrequencyMhz(240);
// First, we need to check the encoding of the form that we have received.
// The browser will set the Content-Type request header, so we can use it for that purpose.
// Then we select the body parser based on the encoding.
@@ -620,7 +729,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
return;
}
res->println("<html><head><meta http-equiv=\"refresh\" content=\"3;url=/static\" /><title>File "
res->println("<html><head><meta http-equiv=\"refresh\" content=\"1;url=/static\" /><title>File "
"Upload</title></head><body><h1>File Upload</h1>");
// We iterate over the fields. Any field with a filename is uploaded.
@@ -680,20 +789,31 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
// With endOfField you can check whether the end of field has been reached or if there's
// still data pending. With multipart bodies, you cannot know the field size in advance.
while (!parser->endOfField()) {
esp_task_wdt_reset();
byte buf[512];
size_t readLength = parser->read(buf, 512);
file.write(buf, readLength);
fileLength += readLength;
// DEBUG_MSG("\n\nreadLength - %i\n", readLength);
// Abort the transfer if there is less than 50k space left on the filesystem.
if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 51200) {
file.close();
res->println("<p>Write aborted! File is won't fit!</p>");
res->println("<p>Write aborted! Reserving 50k on filesystem.</p>");
// enableLoopWDT();
delete parser;
return;
}
//if (readLength) {
file.write(buf, readLength);
fileLength += readLength;
DEBUG_MSG("File Length %i\n", fileLength);
//}
}
// enableLoopWDT();
file.close();
res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str());
}
@@ -742,10 +862,8 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res)
// We want to deliver a simple HTML page, so we send a corresponding content type:
res->setHeader("Content-Type", "text/html");
// The response implements the Print interface, so you can use it just like
// you would write to Serial etc.
res->println("<!DOCTYPE html>");
res->println("<meta http-equiv=\"refresh\" content=\"0;url=http://meshtastic.org/\" />\n");
// res->println("<!DOCTYPE html>");
res->println("<meta http-equiv=\"refresh\" content=\"0;url=/\" />\n");
}
void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
@@ -848,8 +966,6 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "text/html");
randomSeed(millis());
res->setHeader("Set-Cookie",
"mt_session=" + httpsserver::intToString(random(1, 9999999)) + "; Expires=Wed, 20 Apr 2049 4:20:00 PST");
@@ -870,7 +986,7 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res)
res->printf("<p></p>\n");
res->printf("<p>You have gotten this error because the filesystem for the web server has not been loaded.</p>\n");
res->printf("<p>Please review the 'Common Problems' section of the <a "
"href=https://github.com/meshtastic/Meshtastic-device/issues/552>web interface</a> documentation.</p>\n");
"href=https://github.com/meshtastic/Meshtastic-device/wiki/How-to-use-the-Meshtastic-Web-Interface-over-WiFi>web interface</a> documentation.</p>\n");
return;
}
@@ -911,6 +1027,128 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
ESP.restart();
}
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");
ResourceParameters *params = req->getParams();
std::string blink_target;
if (!params->getQueryParameter("blink_target", blink_target)) {
// if no blink_target was supplied in the URL parameters of the
// POST request, then assume we should blink the LED
blink_target = "LED";
}
if (blink_target == "LED") {
uint8_t count = 10;
while (count > 0) {
setLed(true);
delay(50);
setLed(false);
delay(50);
count = count - 1;
}
} else {
screen->blink();
}
res->println("{");
res->println("\"status\": \"ok\"");
res->println("}");
}
void handleReport(HTTPRequest *req, HTTPResponse *res)
{
ResourceParameters *params = req->getParams();
std::string content;
if (!params->getQueryParameter("content", content)) {
content = "json";
}
if (content == "json") {
res->setHeader("Content-Type", "application/json");
} else {
res->setHeader("Content-Type", "text/html");
res->println("<pre>");
}
res->println("{");
res->println("\"data\": {");
res->println("\"airtime\": {");
uint16_t *logArray;
res->print("\"tx_log\": [");
logArray = airtimeReport(TX_LOG);
for (int i = 0; i < getPeriodsToLog(); i++) {
uint16_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != getPeriodsToLog() - 1) {
res->print(", ");
}
}
res->println("],");
res->print("\"rx_log\": [");
logArray = airtimeReport(RX_LOG);
for (int i = 0; i < getPeriodsToLog(); i++) {
uint16_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != getPeriodsToLog() - 1) {
res->print(", ");
}
}
res->println("],");
res->print("\"rx_all_log\": [");
logArray = airtimeReport(RX_ALL_LOG);
for (int i = 0; i < getPeriodsToLog(); i++) {
uint16_t tmp;
tmp = *(logArray + i);
res->printf("%d", tmp);
if (i != getPeriodsToLog() - 1) {
res->print(", ");
}
}
res->println("],");
res->printf("\"seconds_since_boot\": %u,\n", getSecondsSinceBoot());
res->printf("\"seconds_per_period\": %u,\n", getSecondsPerPeriod());
res->printf("\"periods_to_log\": %u\n", getPeriodsToLog());
res->println("},");
res->println("\"wifi\": {");
res->println("\"rssi\": " + String(WiFi.RSSI()) + ",");
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
res->println("\"ip\": \"" + String(WiFi.softAPIP().toString().c_str()) + "\"");
} else {
res->println("\"ip\": \"" + String(WiFi.localIP().toString().c_str()) + "\"");
}
res->println("},");
res->println("\"test\": 123");
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
}
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");
@@ -929,17 +1167,16 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
for (int i = 0; i < n; ++i) {
char ssidArray[50];
String ssidString = String(WiFi.SSID(i));
//String ssidString = String(WiFi.SSID(i)).toCharArray(ssidArray, WiFi.SSID(i).length());
// String ssidString = String(WiFi.SSID(i)).toCharArray(ssidArray, WiFi.SSID(i).length());
ssidString.replace("\"", "\\\"");
ssidString.toCharArray(ssidArray, 50);
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
//res->println("{\"ssid\": \"%s\",\"rssi\": -75}, ", String(WiFi.SSID(i).c_str() );
res->printf("{\"ssid\": \"%s\",\"rssi\": %d}", ssidArray, WiFi.RSSI(i) ) ;
//WiFi.RSSI(i)
if (i != n-1) {
// res->println("{\"ssid\": \"%s\",\"rssi\": -75}, ", String(WiFi.SSID(i).c_str() );
res->printf("{\"ssid\": \"%s\",\"rssi\": %d}", ssidArray, WiFi.RSSI(i));
// WiFi.RSSI(i)
if (i != n - 1) {
res->printf(",");
}
}
@@ -953,7 +1190,6 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
res->println("},");
res->println("\"status\": \"ok\"");
res->println("}");
}
void handleFavicon(HTTPRequest *req, HTTPResponse *res)

View File

@@ -1,6 +1,6 @@
#include "meshwifi.h"
#include "NodeDB.h"
#include "WiFiServerAPI.h"
#include "mesh/wifi/WiFiServerAPI.h"
#include "configuration.h"
#include "main.h"
#include "meshwifi/meshhttp.h"
@@ -40,12 +40,14 @@ bool isWifiAvailable()
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
// strcpy(radioConfig.preferences.wifi_ssid, "");
// strcpy(radioConfig.preferences.wifi_password, "");
// strcpy(radioConfig.preferences.wifi_ssid, "meshtastic");
// strcpy(radioConfig.preferences.wifi_password, "meshtastic!");
// strcpy(radioConfig.preferences.wifi_ssid, "meshtasticAdmin");
// strcpy(radioConfig.preferences.wifi_password, "12345678");
// radioConfig.preferences.wifi_ap_mode = true;
// radioConfig.preferences.wifi_ap_mode = false;
if (*wifiName && *wifiPsw) {
return 1;
@@ -221,9 +223,16 @@ static void WiFiEvent(WiFiEvent_t event)
DEBUG_MSG("Obtained IP address: \n");
Serial.println(WiFi.localIP());
// Start web server
initWebServer();
initApiServer();
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
initWebServer();
initApiServer();
APStartupComplete = true;
} else {
DEBUG_MSG("... Not starting network services (They're already running)\n");
}
break;
case SYSTEM_EVENT_STA_LOST_IP:
@@ -253,7 +262,7 @@ static void WiFiEvent(WiFiEvent_t event)
APStartupComplete = true;
} else {
DEBUG_MSG("... Not starting network services\n");
DEBUG_MSG("... Not starting network services (They're already running)\n");
}
break;

View File

@@ -18,10 +18,10 @@ bool BQ25713::setup()
if (!writeReg(0x00, 0x0F0A))
return false; // Config Charge Option 0
if (!writeReg(0x02, 0x0224))
if (!writeReg(0x02, 0x0224)) // 512mA, FIXME, this seems to be setting a number of bits marked as reserved, why?
return false; // Config Charge Current
if (!writeReg(0x04, 0x1070))
if (!writeReg(0x04, 0x1070)) // about 4.29V
return false; // Config Charge Voltage
if (!writeReg(0x06, 0x099C))
@@ -32,7 +32,7 @@ bool BQ25713::setup()
// if(!writeReg(0x0A,0x0100)) return false;//Config Input Voltage
if (!writeReg(0x0C, 0x1800))
if (!writeReg(0x0C, 0x1800)) // 4.2Vish FIXME, we could lower this?
return false; // Config Minimum System Voltage
if (!writeReg(0x0E, 0x4900))

View File

@@ -31,10 +31,16 @@ MeshPacket *PositionPlugin::allocReply()
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
// 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)
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);

View File

@@ -89,7 +89,7 @@ bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const H
lastWatchMsec = 0; // Force a new publish soon
previousWatch = ~watchGpios; // generate a 'previous' value which is guaranteed to not match (to force an initial publish)
enabled = true; // Let our thread run at least once
DEBUG_MSG("Now watching GPIOs 0x%x\n", watchGpios);
DEBUG_MSG("Now watching GPIOs 0x%llx\n", watchGpios);
break;
}
@@ -114,7 +114,7 @@ int32_t RemoteHardwarePlugin::runOnce() {
if(curVal != previousWatch) {
previousWatch = curVal;
DEBUG_MSG("Broadcasting GPIOS 0x%x changed!\n", curVal);
DEBUG_MSG("Broadcasting GPIOS 0x%llx changed!\n", curVal);
// Something changed! Tell the world with a broadcast message
HardwareMessage reply = HardwareMessage_init_default;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "ProtobufPlugin.h"
#include "remote_hardware.pb.h"
#include "mesh/generated/remote_hardware.pb.h"
#include "concurrency/OSThread.h"
/**

View File

@@ -18,11 +18,5 @@ bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
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
}

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 "target_specific.h"
#include <Utility.h>
#include "PortduinoGPIO.h"
#include "mesh/RF95Interface.h"
#include "sleep.h"
#include <Utility.h>
#include <assert.h>
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
uint32_t hwId; // fixme move into portduino
@@ -31,7 +35,60 @@ void cpuDeepSleep(uint64_t msecs) {
notImplemented("cpuDeepSleep");
}
// FIXME - implement real crypto for linux
CryptoEngine *crypto = new CryptoEngine();
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
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

@@ -127,7 +127,7 @@ static void waitEnterSleep()
delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
recordCriticalError(ErrSleepEnterWait);
recordCriticalError(CriticalErrorCode_SleepEnterWait);
assert(0); // FIXME - for now we just restart, need to fix bug #167
break;
}

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 1
build = 23
build = 32