Compare commits

...

448 Commits

Author SHA1 Message Date
Kevin Hester
2b10a03178 Merge pull request #690 from geeksville/dev
oops - 1.1.47 had bad bug
2021-02-14 15:26:00 +08:00
Kevin Hester
80fb7e4ab8 Merge remote-tracking branch 'root/master' into dev 2021-02-14 15:15:28 +08:00
Kevin Hester
7c1ddd9447 1.1.48 2021-02-14 15:13:58 +08:00
Kevin Hester
c55074f7fe oops: we should crash if we >MAX_THREADS, also raise max threads 2021-02-14 15:06:49 +08:00
Kevin Hester
450e877cfb fix #661 - create $archivedir 2021-02-14 14:14:50 +08:00
Kevin Hester
c0fbfccf43 Merge pull request #689 from geeksville/dev
Dev
2021-02-14 13:48:39 +08:00
Kevin Hester
51ccc3aa9e 1.1.47 2021-02-14 12:28:27 +08:00
Kevin Hester
e35f137986 clean up nodeinfo broadcasts and move into plugin 2021-02-14 12:27:10 +08:00
Kevin Hester
71c35304d6 delay position plugin start until 60 secs after first boot 2021-02-14 12:26:51 +08:00
Kevin Hester
c1733a4ac6 Merge remote-tracking branch 'root/master' into dev 2021-02-14 12:07:11 +08:00
Kevin Hester
66a7e8eab9 oops - we were never sending 'fixed' gps positions to other nodes 2021-02-14 12:02:24 +08:00
Kevin Hester
a872231f8a clean up position broadcasts, send them even if we don't have gps lock 2021-02-14 11:57:48 +08:00
Kevin Hester
52ec4d511c oops - we weren't properly stripping timestamps from new style positions 2021-02-14 11:37:32 +08:00
Jm Casler
aa7fb86798 Merge pull request #687 from sachaw/master
Fix report formatting
2021-02-13 14:02:12 -08:00
Sacha Weatherstone
875eeb699c Fix report formatting 2021-02-13 19:51:31 +11:00
Jm Casler
b239b4dc57 Merge pull request #686 from mc-hamster/master
Finished and partial work
2021-02-12 19:07:13 -08:00
Jm
19db5ba421 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-12 18:53:08 -08:00
Jm
e225af28dc Disable plugins 2021-02-12 18:52:31 -08:00
Jm Casler
eecf89a9c0 Merge pull request #68 from meshtastic/master
from main to my fork
2021-02-12 18:49:39 -08:00
Jm
c9b1ee532d Update deviceonly.pb.h 2021-02-12 18:49:24 -08:00
Jm
8c27baae84 Update platformio.ini 2021-02-12 18:48:18 -08:00
Kevin Hester
8c225a3c65 disable lora while updating, show "Updating" on oled screen 2021-02-12 13:48:12 +08:00
Kevin Hester
7ff1f3a759 Merge pull request #684 from geeksville/dev
Dev
2021-02-12 10:04:48 +08:00
Kevin Hester
bbc8fc0269 fix build for nrf52 2021-02-12 09:56:42 +08:00
Kevin Hester
9d81511153 fix warning 2021-02-12 09:56:35 +08:00
Kevin Hester
16d63bd0ce 1.1.46 2021-02-12 09:42:04 +08:00
Kevin Hester
f2b7ff2b79 an optimization for #681 - make want_ack packets higher priority 2021-02-12 09:40:20 +08:00
Kevin Hester
bc8453283f Merge remote-tracking branch 'root/master' into dev 2021-02-12 09:10:48 +08:00
Kevin Hester
2ff5046dcd for #681, add MeshPacketQueue (a priority queue) to ensure acks get sent quickly 2021-02-12 09:08:49 +08:00
Kevin Hester
917090856f partial for #681: Never let stale nodeinfos/positions stay in xmit queue 2021-02-11 18:19:43 +08:00
Kevin Hester
b45d633a34 Merge pull request #680 from geeksville/dev
Dev
2021-02-10 16:33:02 +08:00
Kevin Hester
fdfe62edf0 updates to work with new protobuf names 2021-02-10 16:18:41 +08:00
Jm
b29bcbbd41 #682 Exposing the actual radio center frequency to /static/report 2021-02-09 21:59:00 -08:00
Kevin Hester
8e8170b667 Merge remote-tracking branch 'root/master' into dev 2021-02-08 18:03:35 +08:00
Kevin Hester
2fa38c7dc4 update protos 2021-02-08 17:57:45 +08:00
Jm
ca8a0ca8d2 update rangetest 2021-02-07 19:20:29 -08:00
Kevin Hester
58bb7169a0 use nodenum as the default nodeid 2021-02-08 10:15:02 +08:00
Jm
cb541d75a9 Update radio-settings.md with note of coverage. 2021-02-07 13:19:52 -08:00
Jm Casler
4ee01acb40 Change where the location information is taken from. 2021-02-07 09:31:29 -08:00
Jm
d678c48884 work on rangetestplugin and storeforwardplugin
done for the night.
2021-02-06 23:29:18 -08:00
Jm
9f9f02fc6f Reverting platform.ini back to the way it was. 2021-02-06 21:38:54 -08:00
Jm Casler
abf135abce Merge pull request #66 from meshtastic/master
mc-hamster/meshtastic-device <- meshtastic/meshtastic-device
2021-02-06 19:56:44 -08:00
Kevin Hester
f7beec4728 Merge pull request #678 from geeksville/dev
misc bugs
2021-02-07 11:00:09 +08:00
Kevin Hester
ccf3450864 make CI build steps more atomic for easier reporting 2021-02-07 10:49:14 +08:00
Kevin Hester
86553a4fc9 add libs needed for linux build on CI server 2021-02-07 10:44:31 +08:00
Kevin Hester
55349ea570 1.1.42 2021-02-07 10:27:04 +08:00
Kevin Hester
486b03e985 bug 677. Don't assert fail for missing interfaces, instead return
nak packet to clients.
2021-02-07 10:26:11 +08:00
Kevin Hester
ccb232b6ac make route errors a more general 'message delivery failure' reason
in support of https://github.com/meshtastic/Meshtastic-device/issues/677
2021-02-07 09:46:35 +08:00
Jm
22af1b551a Add note about antenna gain. 2021-02-06 10:06:20 -08:00
Jm
c696d226b2 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-06 10:04:13 -08:00
Jm
9035a06b4a Add link budget to radio-settings.md 2021-02-06 10:02:23 -08:00
Jm Casler
056940a4ad Documentation 2021-02-06 09:13:49 -08:00
Kevin Hester
e7af338c31 add trademark 2021-02-04 15:46:57 +08:00
Kevin Hester
9069e5b33e no longer need to set num jobs, because my computer is better 2021-02-04 11:51:12 +08:00
Jm
82db1f1db6 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-02-03 08:10:15 -08:00
Jm
f46059ec4c update to range test plugin 2021-02-03 08:10:13 -08:00
Jm
0c71de4e59 Update for rangetest plugin 2021-02-03 08:09:59 -08:00
Jm Casler
0fa654e53a update radio-settings.md 2021-02-03 07:01:35 -08:00
Jm Casler
45c17659cc radio-settings.md - add note about TCXO stability 2021-02-03 01:04:23 -08:00
Jm Casler
b901f8d9ae Update to radio-settings.md 2021-02-03 00:15:41 -08:00
Jm Casler
9c60a7966f Update radio-settings.md 2021-02-03 00:01:52 -08:00
Jm Casler
6d66a53f8d Another update to radio-settings.md 2021-02-02 23:59:34 -08:00
Jm Casler
324627482a Update radio-settings.md 2021-02-02 23:57:25 -08:00
Jm Casler
0c6c189028 Update to radio-settings.md 2021-02-02 23:01:05 -08:00
Jm Casler
8a68ae0d04 Update radio-settings.md 2021-02-02 22:47:16 -08:00
Jm Casler
5661e5dad6 Update radio-settings.md 2021-02-02 22:43:24 -08:00
Jm
e9affb50d2 #674 add support for lora32 v1.3 2021-02-02 17:34:50 -08:00
Jm Casler
c00173dbd2 partial work 2021-01-31 18:20:08 -08:00
Jm Casler
e8c6fccd63 #671 Range Test Plugin
Initial work for Range Test Plugin
2021-01-31 09:12:36 -08:00
Jm Casler
487b8c6e9e #668 Initial work for Store & Forward Plugin 2021-01-31 09:12:01 -08:00
Jm
b2481d1450 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-30 19:42:08 -08:00
Jm Casler
399fbc5d65 Merge pull request #665 from mc-hamster/master
#664 - Blink the LED when we enter disablePin() and #654 - ExternalNotificationPlugin
2021-01-30 17:28:28 -08:00
Jm Casler
48b38ed94b Update documentation 2021-01-30 17:21:54 -08:00
Jm Casler
c0444ef16f Merge pull request #64 from meshtastic/master
Update from meshtastic main
2021-01-30 17:20:56 -08:00
Kevin Hester
1719a8e764 Merge pull request #667 from geeksville/dev
kevins misc fixes
2021-01-31 09:18:05 +08:00
Jm
242bcc8353 Update documentation location to the main mesthastic repo 2021-01-30 09:52:21 -08:00
Jm Casler
092af0f9f9 Update to doc to add info on the bell character 2021-01-30 09:50:19 -08:00
Jm Casler
133a7ff166 Added more notes. 2021-01-30 09:46:26 -08:00
Jm Casler
5df08410e7 Create SerialPlugin.md 2021-01-30 09:39:40 -08:00
Jm
9f9787bc03 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-30 09:36:28 -08:00
Jm
7129a19f35 #654 Add reference to documentation 2021-01-30 09:36:17 -08:00
Jm Casler
f45ffc8773 Rename documentation 2021-01-30 09:32:44 -08:00
Jm Casler
3162f74945 Create External Notification documentation. 2021-01-30 09:32:04 -08:00
Jm
6cef3e41e7 Update comments and use radioConfig 2021-01-30 09:17:40 -08:00
Kevin Hester
c0e2ec8dec 1.1.34 2021-01-30 21:23:03 +08:00
Jm
aee81c8dcd #654 - Add comments on what the config does 2021-01-29 19:35:03 -08:00
Jm
9e736ab0d7 #654 Fix gpio initilization 2021-01-28 23:16:10 -08:00
Jm
85752b0fc7 #654 - Fixed problem with class namespaces. 2021-01-28 23:02:00 -08:00
Kevin Hester
c6f34c59b4 Update to logo by @thepoweroftwo 2021-01-29 13:26:08 +08:00
Kevin Hester
7f07725840 make improperly sized AES128/256 keys non fatal, instead pad with zeros
Fixes rebooting the board if someone specifies an invalid key
2021-01-29 10:15:48 +08:00
Kevin Hester
c81d090464 someone added storerequest app? 2021-01-29 10:14:46 +08:00
Jm Casler
c524732849 #654 - Non blocking call to toggle the output. 2021-01-27 21:35:07 -08:00
Jm Casler
5e303f8a1f #654 - Work in progress. Needs testing, non-blocking alert and integration with configuration 2021-01-27 21:20:18 -08:00
Jm
2246564279 #654 - Small changes. 2021-01-27 20:06:39 -08:00
Jm
eff0c1fe89 #654 - Partial work for the LED/Speaker.
Framework is done. Just need to blink a few things and update protobufs.
2021-01-27 19:18:16 -08:00
Jm Casler
ad322476d2 Merge branch 'master' into master 2021-01-27 18:56:48 -08:00
Jm
2561742683 #664 - Blink the LED when we enter disablePin() 2021-01-27 18:56:09 -08:00
Kevin Hester
fa9e31fe03 Merge pull request #663 from geeksville/eink
back in the saddle - reading github and slack next
2021-01-28 10:38:46 +08:00
Kevin Hester
3ac5b045c4 Merge remote-tracking branch 'root/master' into eink 2021-01-28 10:31:56 +08:00
Kevin Hester
6a593e01e1 notes on eink1.0 2021-01-28 10:30:24 +08:00
Kevin Hester
6f6dd2291e fix typo 2021-01-28 10:30:00 +08:00
Kevin Hester
2b4ddc07f5 Merge pull request #651 from android606/log-tx-failure
Set critical error and reboot when radio fails to generate Tx IRQ - fixes #138
2021-01-27 18:05:56 +08:00
Kevin Hester
63c650c33e Merge branch 'master' into log-tx-failure 2021-01-27 17:54:06 +08:00
Kevin Hester
dc29161f37 Merge pull request #659 from IZ1IVA/patch-4
Update radio-settings.md
2021-01-27 17:52:27 +08:00
Jm Casler
8a6fdafc79 Merge branch 'master' into patch-4 2021-01-26 22:29:41 -08:00
Jm Casler
ea40bd991c Merge pull request #660 from mc-hamster/master
Update version.properties to 1.1.33
2021-01-25 17:12:32 -08:00
Jm Casler
e19dd46f0f Merge branch 'master' into master 2021-01-25 17:05:52 -08:00
Jm
532b06c280 Update version.properties to 1.1.33 2021-01-25 17:01:47 -08:00
IZ1IVA
a8480d1eaf Update radio-settings.md
Added data-rates
2021-01-25 16:11:24 +01:00
Jm Casler
0cf7aaffff Merge pull request #658 from sachaw/master
Another missing header
2021-01-24 18:06:14 -08:00
Sacha Weatherstone
e2e1819ef1 Merge branch 'master' of https://github.com/sachaw/meshtastic-device 2021-01-24 10:49:23 +11:00
Sacha Weatherstone
31b89e2932 Another header required 2021-01-24 10:48:48 +11:00
Jm Casler
a021ff7eb8 Merge pull request #656 from sachaw/master
fix cors for API requsts & fix spiffs url
2021-01-22 23:36:27 -08:00
Jm Casler
bb5d0fac90 Merge branch 'master' into master 2021-01-22 23:26:53 -08:00
Jm Casler
df5ed64514 Merge pull request #655 from mc-hamster/master
Fix for #650 - build-all.sh will fail
2021-01-22 23:26:39 -08:00
Sacha Weatherstone
9db5f9ff67 fix cors for API requsts & fix spiffs url 2021-01-23 17:42:15 +11:00
Jm
ca83a78e13 Fix for #650 - build-all.sh will fail 2021-01-22 19:50:12 -08:00
Jm Casler
13eef9a309 Merge pull request #653 from mc-hamster/master
Update comments in SerialPlugin
2021-01-20 21:42:12 -08:00
Jm Casler
2a8ac2c0c6 Merge branch 'master' into master 2021-01-20 19:04:46 -08:00
Jm Casler
c97342db99 Merge pull request #63 from mc-hamster/serial
Update comments on SerialPlugin
2021-01-20 19:03:44 -08:00
Jm Casler
d7b2a0ed79 Merge pull request #62 from mc-hamster/master
update serial from master
2021-01-20 19:02:58 -08:00
Jm
af0a1b5db5 Update comments of SerialPlugin 2021-01-20 19:02:08 -08:00
Jm Casler
9cf030d587 Merge pull request #652 from mc-hamster/master
#649 More webserver refactoring
2021-01-19 21:52:56 -08:00
Jm
c04d70d5e5 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-19 21:38:30 -08:00
Jm
2a47819fd6 #649 More webserver refactoring 2021-01-19 21:38:17 -08:00
Jm Casler
4516c8f9b5 Merge pull request #61 from meshtastic/master
Merge pull request #648 from mc-hamster/master
2021-01-19 21:27:24 -08:00
Jm
e4fdf26dc7 #649 - First pass on the refactoring of the webserver 2021-01-19 21:26:23 -08:00
Andrew Mark
dd511588a2 Oops, let's only try to reboot ESP32 when there's an ESP32 2021-01-19 20:13:19 -08:00
Andrew Mark
79dad8ec8c Set critical error and reboot when radio fails to generate tx IRQ 2021-01-19 18:21:54 -08:00
Jm Casler
39d14fedc2 Merge pull request #648 from mc-hamster/master
#647 - Fix for admin mode being forced on boards without hardware pullup
2021-01-18 10:56:13 -08:00
Jm Casler
1da38fc748 Merge branch 'master' into master 2021-01-18 10:44:38 -08:00
Jm
b5f50efdcd #647 - Fix for admin mode being forced on boards without hardware pullup 2021-01-18 10:43:15 -08:00
Jm Casler
046e691d4e Merge pull request #645 from mc-hamster/master
#635 Added web_request_count and fixed printf of psram
2021-01-17 17:26:56 -08:00
Jm Casler
e72531b090 Merge pull request #60 from mc-hamster/master
Update Serial
2021-01-17 15:41:21 -08:00
Jm
81e320c9cf Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-17 15:40:27 -08:00
Jm
fa8cc74141 Update to Serial Plugin to make it easy to override the device configuration 2021-01-17 15:40:25 -08:00
Jm Casler
c7d9ff7cc0 Merge branch 'master' into master 2021-01-17 10:36:54 -08:00
Jm
8704a9d08f Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2021-01-17 10:30:40 -08:00
Jm
c0d27e2ce9 #635 Added web_request_count and fixed printf of psram 2021-01-17 10:30:34 -08:00
Jm Casler
84b9028ecb Merge pull request #642 from mc-hamster/master
#635 - Added memory usage statistics
2021-01-17 04:52:03 -08:00
Jm Casler
4fda7098c0 Merge branch 'master' into master 2021-01-17 04:44:42 -08:00
Jm
8e8264efb0 #635 - Added memory usage statistics 2021-01-17 00:29:29 -08:00
Jm Casler
54e780a6ca Merge pull request #641 from mc-hamster/master
Update generated protobuf; Update serial plugin; #615 - Configure charge current
2021-01-17 00:18:33 -08:00
Jm
125eb2b784 Fix for build fail on NRF 2021-01-17 00:11:26 -08:00
Jm Casler
6ea9cdc83b Merge pull request #59 from mc-hamster/master
Update serial plugin with new protobufs
2021-01-17 00:03:13 -08:00
Jm
c0711fde69 #615 Allow rate for tbeam battery charger to be configurable 2021-01-16 23:10:08 -08:00
Jm
20b8d2c4a5 Set the port to PortNum_SERIAL_APP 2021-01-16 22:41:33 -08:00
Jm
73ae151971 Added serialplugin_timeout to SerialPlugin 2021-01-16 22:39:28 -08:00
Jm Casler
f4806c9dd7 Merge branch 'serial' into master 2021-01-16 22:35:56 -08:00
Jm
79532210e8 SerialPlugin - Update comments with better instructions 2021-01-16 22:31:56 -08:00
Jm
d7f26493a5 Update to SerialPlugin to take advantage of the configs 2021-01-16 22:27:33 -08:00
Jm
b9d025dd58 Missed adding the proto file 2021-01-16 20:53:45 -08:00
Jm
f435086a5a Update generated protobufs 2021-01-16 20:50:58 -08:00
Jm
3dcdf372d7 add remote update 2021-01-16 20:12:31 -08:00
Jm
cd84f2867c Updated submodule proto 2021-01-16 20:00:37 -08:00
Jm
cafe00e463 Update of serialplugin 2021-01-16 19:40:47 -08:00
Kevin Hester
fd9ffbbb88 fix charging indication for dumb battery sensors 2021-01-16 13:05:33 +08:00
Kevin Hester
d1be7cf142 improve hardfault handler 2021-01-16 12:55:51 +08:00
Kevin Hester
d1f0be215b eink leds seem a bit busted 2021-01-16 11:42:06 +08:00
Kevin Hester
3a2c17998e turn off nrf52 ble while debugging 2021-01-16 11:41:50 +08:00
Kevin Hester
a0dd051511 turn off eink backlight 2021-01-16 11:41:28 +08:00
Kevin Hester
4faff3ec6f cope with bogus NMEA gps 2021-01-16 11:41:18 +08:00
Kevin Hester
f110225173 Update variant file and qspi flash programming settings for new ttgoeink
Note: bin/qspi-flash-test.sh contains a script you can use for basic
bench programming and testing of the serial spi flash over SWD
2021-01-16 10:34:46 +08:00
Kevin Hester
2684257e7e update protobufs 2021-01-16 09:59:43 +08:00
Kevin Hester
51fb1021df Merge remote-tracking branch 'root/master' into eink
# Conflicts:
#	platformio.ini
2021-01-16 09:59:08 +08:00
Kevin Hester
51d0d0d6c5 begin new ttgo eink board 2021-01-16 09:57:55 +08:00
Kevin Hester
047df76373 move rev 0.1 of the ttgo eink board to eink0.1 2021-01-16 09:55:06 +08:00
Jm
6da4e30215 Merge branch 'serial' of https://github.com/mc-hamster/Meshtastic-device into serial 2021-01-14 22:38:53 -08:00
Jm
dbf0569e29 Update comments for serial pins recommended by @ryguy 2021-01-14 22:36:51 -08:00
Jm Casler
18220b88b3 Merge pull request #58 from mc-hamster/master
update serial from master
2021-01-14 22:36:17 -08:00
Jm Casler
665da2fb00 Merge pull request #57 from meshtastic/master
Merge pull request #633 from mc-hamster/master
2021-01-14 22:34:01 -08:00
Jm Casler
57ffe6622d Merge pull request #56 from mc-hamster/master
update serial from master
2021-01-14 22:25:20 -08:00
Jm Casler
485fec9649 Merge pull request #633 from mc-hamster/master
Fix for #632 (move web server to osthread) and #611 (move airtime to osthread)
2021-01-14 22:06:18 -08:00
Jm
bd85736226 SerialPlugin - Exclude working on non esp32 platforms. 2021-01-14 21:59:26 -08:00
Jm
4ec8986934 Fixed switching to uint32 from 16 for airtime in json report 2021-01-14 21:45:41 -08:00
Jm Casler
b963216764 Merge pull request #55 from mc-hamster/serial
Update for SerialPlugin and Airtime
2021-01-14 21:43:28 -08:00
Jm Casler
813fd95bc8 Merge pull request #54 from geeksville/mc-master
fix @mc-hamster build to work on linux/nrf52
2021-01-14 21:33:27 -08:00
Kevin Hester
3598c91c29 fix @mc-hamster build to work on linux/nrf52 2021-01-15 13:30:40 +08:00
Jm
507cd1dd20 #639 - Move from counting seconds to milliseconds 2021-01-14 18:40:18 -08:00
Jm
e39506824d Added more comments 2021-01-14 18:08:23 -08:00
Jm
f68a31ab28 serialplugin - ability to configure ACK 2021-01-13 23:21:55 -08:00
Jm
b1181deb58 serialplugin - Added my todo list 2021-01-13 23:02:13 -08:00
Jm
89b32dd7ee Fix comments in serial plugin 2021-01-13 22:51:36 -08:00
Jm
c54e87f9a2 Update SerialPlugin.cpp
Added documentation.
2021-01-13 22:50:02 -08:00
Jm
eee7e1de57 Update to serial plugin 2021-01-13 22:39:11 -08:00
Jm
3c60df1565 Partial work on the SerialPlugin 2021-01-13 20:22:59 -08:00
Jm Casler
a827017bd2 Merge pull request #53 from crossan007/master
add power statistics for #635
2021-01-11 17:54:27 -08:00
Charles Crossan
95c502c658 fix typo 2021-01-11 20:30:02 -05:00
Charles Crossan
0f573901d5 didn't need power.h 2021-01-11 20:28:09 -05:00
Charles Crossan
fdc9bf5783 add power statistics for #635 2021-01-11 20:25:02 -05:00
Jm Casler
37e0f9a325 Merge pull request #52 from mc-hamster/osthread
maybe this will fix the linux build?
2021-01-09 19:32:40 -08:00
Jm
0c06d8db3c maybe this will fix the linux build? 2021-01-09 19:31:16 -08:00
Jm Casler
0be4bbb369 Merge pull request #51 from mc-hamster/osthread
Does this fix the linux build?
2021-01-09 19:17:45 -08:00
Jm
f02ab88393 Does this fix the linux build? 2021-01-09 19:15:10 -08:00
Jm Casler
c9d4de8808 Merge pull request #50 from mc-hamster/osthread
fixed in linux now?
2021-01-09 19:07:16 -08:00
Jm
adb912b665 fixed in linux now? 2021-01-09 19:06:34 -08:00
Jm Casler
3f5da1e03e Merge pull request #49 from mc-hamster/osthread
another linux fix?
2021-01-09 18:37:04 -08:00
Jm
0a40d920e3 Update BluetoothUtil.cpp
yet another linux fix?
2021-01-09 18:36:23 -08:00
Jm Casler
39311f1e40 Merge pull request #48 from mc-hamster/osthread
is linux fixed now?
2021-01-09 18:27:32 -08:00
Jm
9cd24a5646 is linux fixed now? 2021-01-09 18:27:03 -08:00
Jm Casler
1c0efde315 Merge pull request #47 from mc-hamster/osthread
is linux fixed now?
2021-01-09 18:09:57 -08:00
Jm
c82905bbdd is linux fixed now? 2021-01-09 18:09:16 -08:00
Jm Casler
275eace968 Merge pull request #46 from mc-hamster/osthread
more linux fixes
2021-01-09 17:52:09 -08:00
Jm
5688c8b81e more linux build fixes 2021-01-09 17:50:58 -08:00
Jm
8b2798abd5 Added a few commented out default_envs 2021-01-09 17:44:20 -08:00
Jm Casler
6d977923b6 Merge pull request #45 from mc-hamster/osthread
more fixes for linux build
2021-01-09 17:34:34 -08:00
Jm
52dacaed37 more fixes for linux build 2021-01-09 17:30:36 -08:00
Jm Casler
7a381eaea1 Merge pull request #44 from mc-hamster/osthread
Fix for breaking the linux build
2021-01-09 13:47:43 -08:00
Jm
69391e186b Fix for breaking the linux build 2021-01-09 13:47:10 -08:00
Jm Casler
06f8beaa17 Merge pull request #43 from mc-hamster/osthread
fix for building on NRF platform.
2021-01-08 23:00:36 -08:00
Jm
3798f4ca5b fix for building on NRF platform. 2021-01-08 22:59:37 -08:00
Jm Casler
4fd243a6e4 Merge pull request #42 from mc-hamster/osthread
Moving web server and airtime to osthread model. Moved web server to mesh/wifi
2021-01-08 22:29:45 -08:00
Jm
d458f673be Web server is now treaded and moved to mesh/wifi/* 2021-01-08 22:25:44 -08:00
Jm
cfcb00b943 that's enough for tonight. web server is in its own thread, needs to be further optimized but it works enough. next is to refactor. 2021-01-08 20:43:51 -08:00
Jm
977e47d109 partial work 2021-01-08 20:06:11 -08:00
Jm Casler
cfeb40f36d Merge pull request #41 from mc-hamster/master
Updated osthread branch from master
2021-01-08 19:57:19 -08:00
Jm Casler
4fcc3ac1de Merge pull request #40 from meshtastic/master
Updated my master from head
2021-01-08 19:54:57 -08:00
Kevin Hester
f4afa6931b Merge pull request #630 from geeksville/dev
Dev
2021-01-08 13:38:23 +08:00
Kevin Hester
71be71d63d add note about how to send messages thanks @rw-w for the question 2021-01-08 13:31:28 +08:00
Kevin Hester
de9f7e6c39 update protos 2021-01-08 13:21:14 +08:00
Kevin Hester
7c8db2b501 Merge remote-tracking branch 'root/master' into dev
# Conflicts:
#	docs/software/plugin-api.md
2021-01-08 13:20:28 +08:00
Kevin Hester
cd653f9434 Merge pull request #629 from ry-w/patch-1
Update plugin-api.md
2021-01-08 13:19:03 +08:00
Kevin Hester
74bc05936d Merge remote-tracking branch 'root/master' into dev 2021-01-08 13:16:27 +08:00
Kevin Hester
7aacfd66ef add assertIsSetup() and use it from OSThread constructor
fixes nasty bug @mc-hamster discovered with plugin order of operations
2021-01-08 13:15:49 +08:00
Kevin Hester
3636b87db0 formatting 2021-01-08 11:52:43 +08:00
ry-w
d6bd328576 Update plugin-api.md
Couple of clarifications, and fixes to minor errors.
2021-01-06 14:24:51 -08:00
Jm
0af5b225c4 intermediate 2021-01-05 23:32:33 -08:00
Jm
f7dcef39ce intermediate work 2021-01-05 23:21:14 -08:00
Kevin Hester
07042178d2 Merge pull request #627 from mc-hamster/master
Include instrusctions for real time backtrace decoding.
2021-01-06 14:55:46 +08:00
Kevin Hester
243878f2a0 Merge branch 'master' into master 2021-01-06 14:39:57 +08:00
Kevin Hester
d3f8a76cce Merge pull request #625 from geeksville/dev
fix #624 - update battery level and current time on mynodeinfo
2021-01-06 14:39:42 +08:00
Kevin Hester
20131a51a2 Merge branch 'master' into dev 2021-01-06 14:31:11 +08:00
Kevin Hester
1c9a369774 Merge branch 'master' into master 2021-01-06 13:26:30 +08:00
Kevin Hester
dcb426f58f Merge pull request #628 from IZ1IVA/patch-3
Update radio-settings.md
2021-01-06 13:23:53 +08:00
Jm Casler
35bcb5297a Merge pull request #38 from mc-hamster/master
update from master to osthread
2021-01-05 19:04:15 -08:00
Jm
84e3d7c276 Test fixes for Tobiases 2021-01-05 18:57:03 -08:00
IZ1IVA
9b03f0ac8e Update radio-settings.md
Fixed frequency table non showing
2021-01-05 12:13:18 +01:00
Jm Casler
eb402809e2 Merge branch 'master' into master 2021-01-04 22:16:07 -08:00
Jm
e9c9e40624 Include instrusctions for real time backtrace decoding. 2021-01-04 22:15:19 -08:00
Kevin Hester
01eed97b91 Merge branch 'master' into dev 2021-01-04 10:00:38 +08:00
Kevin Hester
94a47dba7d fix #624 - update battery level and current time on mynodeinfo 2021-01-04 09:59:53 +08:00
Kevin Hester
bce2c9347b Merge pull request #623 from geeksville/dev
Dev
2021-01-03 21:26:57 +08:00
Kevin Hester
da8b1d41c7 1.1.32 2021-01-03 20:57:59 +08:00
Kevin Hester
3ddae5faec fix build for esp32 2021-01-03 20:12:31 +08:00
Kevin Hester
34faea6100 fix #622 - we might not have a local position yet early in the boot 2021-01-03 20:11:26 +08:00
Kevin Hester
01848a9e5d moved wifi code 2021-01-03 20:11:03 +08:00
Kevin Hester
10db80541f Merge remote-tracking branch 'root/master' into dev 2021-01-03 10:12:08 +08:00
Kevin Hester
edd1268f5f portduino: begin adding wifi implementation 2021-01-03 10:11:20 +08:00
Jm Casler
11c16e8bbc Merge pull request #621 from mc-hamster/master
Remove text "This interface is experimental"
2021-01-02 10:39:20 -08:00
Jm Casler
7d411351c0 Merge pull request #37 from meshtastic/master
update from head
2021-01-02 10:20:56 -08:00
Jm
df21602c90 Remove text "This interface is experimental" 2021-01-02 10:18:35 -08:00
Kevin Hester
ce4ccf3cc4 no need for lora CS control on linux, the spi controller handles it 2021-01-02 19:40:24 +08:00
Kevin Hester
a7f93de3ad add a software based cross platform AES-CTR implementation 2021-01-02 18:20:51 +08:00
Kevin Hester
8e8257adf3 Merge pull request #619 from geeksville/dev
1.1.31
2021-01-02 16:51:08 +08:00
Kevin Hester
e627725dfc 1.1.31 2021-01-02 14:15:07 +08:00
Kevin Hester
b3ba557b8b cleanup portuino 2021-01-02 14:14:59 +08:00
Kevin Hester
bd03650140 Merge pull request #612 from wfang2002/master
Fix GPS turned on then off immediately every 2 minutes
2021-01-02 14:13:48 +08:00
Kevin Hester
42f51f33a8 Merge branch 'master' into master 2021-01-02 14:12:07 +08:00
Jm
8295b88d96 Checking in work so I don't lose it. Nothing's broke with the build. 2021-01-01 21:20:34 -08:00
Kevin Hester
70313b2660 Merge pull request #618 from geeksville/dev
portuino now kinda works for pinetab
2021-01-02 13:02:38 +08:00
Kevin Hester
745d3775b4 Merge branch 'master' into dev 2021-01-02 12:54:04 +08:00
Kevin Hester
aa176b6593 portuino now kinda works with the pinetab lora USB module.
still need to add an AEX256 impl for the linux port and optimize a bit
2021-01-02 12:38:18 +08:00
Kevin Hester
b0e3a7524f assign more portduino pins 2021-01-02 11:23:30 +08:00
Kevin Hester
5ceee50bb5 bug: we've always been setting gpio 0 as an input on rf95 based devices
found because portduino provides full visibility to all IO operations
to the hw simulator.
2021-01-02 11:23:18 +08:00
Kevin Hester
ebdad76fb2 portduino: gpios now kinda work on linux 2021-01-02 11:06:38 +08:00
Jm
925829dc58 Partial work to migrate to OSThread model 2021-01-01 12:31:46 -08:00
Jm Casler
e04ea853dc Merge pull request #616 from mc-hamster/master
Display AP connection usage only when in AP mode & Cleanup some compile time warnings that were driving me crazy
2020-12-31 21:26:32 -08:00
Jm Casler
9587729bb0 Merge branch 'master' into master 2020-12-31 20:55:32 -08:00
Jm
6ec368bf02 Commenting out upload ports 2020-12-31 20:50:11 -08:00
Jm
d71c7b512f Cleanup some compile time warnings that were driving me crazy. 2020-12-31 20:44:53 -08:00
Jm
349701ac14 Display AP connection usage only when in AP mode 2020-12-31 20:17:18 -08:00
Kevin Hester
d424fa5ea8 Merge pull request #605 from oztug/master
Genieblocks LoRa support
2020-12-31 14:19:30 +08:00
Kevin Hester
ca6293eefe Merge branch 'master' into master 2020-12-31 14:05:56 +08:00
Kevin Hester
d289e8a86f Merge remote-tracking branch 'root/master' into dev 2020-12-31 14:02:47 +08:00
Kevin Hester
96328526b7 Merge pull request #613 from wfang2002/#604_rtc
Shall upgrade RTC currentQuality if higher q available (fix #604)
2020-12-31 13:58:40 +08:00
Wei Fang
279c89dca3 Shall upgrade RTC currentQuality if higher q available 2020-12-30 21:46:43 -08:00
wfang2002
a7a52e08d1 Merge branch 'master' into master 2020-12-30 21:26:51 -08:00
Wei Fang
f6336855d0 Fix GPS turned on then off immediately every 2 minutes 2020-12-30 21:11:03 -08:00
Jm Casler
727d8a6456 Merge pull request #610 from mc-hamster/master
Fix for meshtastic#606 and meshtastic#597
2020-12-30 21:10:15 -08:00
Jm Casler
7b80b95381 Merge pull request #36 from mc-hamster/upload
Fix for meshtastic#606 and meshtastic#597
2020-12-30 18:19:52 -08:00
Jm
2867f8fd53 Fix for #606 and #597
Upload interface randomly crashes #606

watchdog timer exception while building https certificate #597
2020-12-30 18:10:35 -08:00
Kevin Hester
cdf416cb73 partial fix for #608 - when a new TCP API connection arrives, close old one completely 2020-12-31 10:02:18 +08:00
Jm
7716d62018 Remove old comment 2020-12-30 15:16:04 -08:00
Jm Casler
d5f76b16b9 write readLength to debug console 2020-12-30 14:52:39 -08:00
Jm Casler
552406b15f Merge pull request #34 from meshtastic/master
update from master
2020-12-30 13:59:58 -08:00
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
Kevin Hester
e32202e4f8 Merge pull request #570 from geeksville/dev
Dev
2020-12-17 11:09:19 +08:00
Kevin Hester
ca99b6b3b7 1.1.23 2020-12-17 10:59:05 +08:00
Kevin Hester
2eb2e9142f Merge remote-tracking branch 'root/master' into dev 2020-12-17 10:58:28 +08:00
Kevin Hester
15e1a3870c When new node joins mesh, all other nodes reply with their current state 2020-12-17 10:53:29 +08:00
Kevin Hester
5bdc7216b3 begin support for multiple simultanous channels 2020-12-17 10:32:19 +08:00
Kevin Hester
cc127f7dad Merge pull request #562 from geeksville/dev
Dev
2020-12-15 17:00:42 +08:00
Kevin Hester
be38a58a62 finish channel name cleanup 2020-12-15 16:13:16 +08:00
Kevin Hester
5930f8270d Merge remote-tracking branch 'root/master' into dev 2020-12-15 16:10:35 +08:00
Kevin Hester
c9f2318e78 Use simpler names for standard channels 2020-12-15 13:14:36 +08:00
Kevin Hester
5cdc2f5142 Make ChannelSettings SUPER short for common channels 2020-12-14 21:09:29 +08:00
Jm Casler
53d773b81f Merge pull request #565 from mc-hamster/master
Fixed bad copy/paste of http end points being used as default.
2020-12-13 17:00:43 -08:00
Jm Casler
85b2ba7ce9 Merge branch 'master' into master 2020-12-13 15:02:18 -08:00
Jm Casler
474e0e7158 Fixed bad copy/paste of http end points being used as default. 2020-12-13 14:59:56 -08:00
Jm Casler
99a8c80c44 Merge pull request #564 from mc-hamster/master
#563 Don't display the wifi password when we are a client.
2020-12-13 11:29:21 -08:00
Jm Casler
03a9d7da5e Merge branch 'master' into master 2020-12-13 11:05:40 -08:00
Jm Casler
6975848f45 #563 Don't display the wifi password when we are a client. 2020-12-13 11:01:01 -08:00
Kevin Hester
0cdc1fc959 make gpiowatch work correctly 2020-12-13 16:11:38 +08:00
Kevin Hester
e80c79edbe clean up debug msgs 2020-12-13 15:59:26 +08:00
Jm Casler
651d045afe Merge pull request #559 from mc-hamster/master
Endpoint to restart device, new sequence to force device into softAP, network scanner
2020-12-12 22:43:37 -08:00
Jm Casler
86952c5456 Fixed #541 - Work around to bug in espressif softap event handler 2020-12-12 22:37:07 -08:00
Jm Casler
46781357df remove hard coded network 2020-12-12 21:43:01 -08:00
Jm Casler
bb9abf2dca #560 Forgot to switch back to application/json 2020-12-12 21:42:32 -08:00
Jm Casler
5249608dce #561 Add escapes to strings 2020-12-12 21:35:21 -08:00
Kevin Hester
ee8f4de5ab make plugin reply handling simpler 2020-12-13 12:57:37 +08:00
Jm Casler
17297db2b1 #561 - Add a scan for SSID 2020-12-12 20:50:41 -08:00
Kevin Hester
ad8bcba5ef remove hack for the othernet ppr1 rev 1 board 2020-12-13 11:54:00 +08:00
Kevin Hester
138cebbf03 turn nrf52 ble back on 2020-12-13 11:53:32 +08:00
Jm Casler
9f9573d2eb #560 - Add note that we're in admin mode on network screen 2020-12-12 19:18:51 -08:00
Jm Casler
e10b82c118 #560 Partial changes 2020-12-12 19:09:58 -08:00
Jm Casler
d82aaaa806 #560 - Partial work for Charles. 2020-12-12 18:33:52 -08:00
Jm Casler
c0d94ae4ab Update main.cpp 2020-12-12 14:04:52 -08:00
Jm Casler
02ce12607c #560 - Force SoftAP if the user button is held down during startup.
#560 - Force SoftAP if the user button is held down during startup.
2020-12-12 13:54:14 -08:00
Jm Casler
bdeba54c50 Merge pull request #29 from meshtastic/master
Merge pull request #553 from mc-hamster/master
2020-12-12 12:38:49 -08:00
Jm Casler
26c9585c9d #557 - Switch from GET to POST 2020-12-12 12:38:17 -08:00
Jm Casler
696255c1f7 #557 - Endpoint to restart device over http(s) 2020-12-12 12:36:16 -08:00
Jm Casler
d857f8ba6d Merge pull request #553 from mc-hamster/master
Fix for #551 and #552
2020-12-12 11:56:29 -08:00
Jm Casler
5852caa61c Fix bug #551 - Turn the led off before shutting down.
Fix bug #551 - Turn the led off before shutting down.
2020-12-11 23:03:32 -08:00
Jm Casler
e82752c777 #552 - Updated the 404 handler for / to refer to instructions for how to fix the problem.
#552 - Updated the 404 handler for / to refer to instructions for how to fix the problem.
2020-12-11 22:54:48 -08:00
Jm Casler
3eae2c6286 Merge pull request #28 from meshtastic/master
update my repo from master
2020-12-11 22:42:31 -08:00
Kevin Hester
1e5d0b25ad Add doc note about threading and use OSThread to make GPIO watching work
Thanks to @mc-hamster for the idea
2020-12-11 18:29:32 +08:00
Kevin Hester
c8423400ea Merge pull request #548 from geeksville/dev
Dev
2020-12-11 10:11:48 +08:00
Kevin Hester
af88a34f75 update dev docs 2020-12-11 10:03:46 +08:00
Kevin Hester
b9f1ce70cb begin plugin-api tutorial 2020-12-11 09:11:53 +08:00
Kevin Hester
c361c1fab7 Update to nanopb 0.4.4 2020-12-11 08:31:41 +08:00
Kevin Hester
091e953ed4 todo updates 2020-12-10 14:34:50 +08:00
Kevin Hester
9ab02119f5 Merge branch 'udp' into dev 2020-12-10 14:05:13 +08:00
Kevin Hester
2d4849e0d0 remote try catch in new build tool - file was missing 2020-12-10 14:04:19 +08:00
Jm Casler
a70cda6fe4 Merge pull request #27 from meshtastic/master
updated by fork from master
2020-11-29 12:40:32 -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
152 changed files with 5948 additions and 1585 deletions

View File

@@ -22,5 +22,15 @@ jobs:
- name: Install extra python tools
run: |
pip install -U adafruit-nrfutil
- name: Build
run: platformio run -e tbeam -e heltec -e lora-relay-v1 -e linux
- name: Install libs needed for linux build
run: |
sudo apt install -y libpsocksxx-dev
- name: Build for tbeam
run: platformio run -e tbeam
- name: Build for heltec
run: platformio run -e heltec
- name: Build for lora-relay-v1
run: platformio run -e lora-relay-v1
- name: Build for linux
run: platformio run -e linux

2
.gitignore vendored
View File

@@ -17,5 +17,5 @@ Thumbs.db
.cproject
.idea/*
.vagrant
nanopb*
flash.uf2

3
.gitmodules vendored
View File

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

View File

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

@@ -21,7 +21,7 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins
mkdir -p $OUTDIR/bins $ARCHIVEDIR
rm -r $OUTDIR/bins/*
mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
@@ -49,7 +49,7 @@ function do_build() {
basename=universal/firmware-$BOARD-$VERSION
fi
pio run --jobs 4 --environment $BOARD # -v
pio run --environment $BOARD # -v
SRCELF=.pio/build/$BOARD/firmware.elf
cp $SRCELF $OUTDIR/elfs/$basename.elf

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

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

View File

@@ -3,19 +3,14 @@ Import("projenv")
import configparser
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
print(f"Preferences in {prefsLoc}")
try:
config = configparser.RawConfigParser()
config.read(prefsLoc)
version = dict(config.items('VERSION'))
verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"])
except:
print("Can't read preferences, using 0.0.0")
verStr = "0.0.0"
config = configparser.RawConfigParser()
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

@@ -1,6 +1,6 @@
set -e
source bin/version.sh
VERSION=`bin/buildinfo.py`
esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin

View File

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

View File

@@ -2,10 +2,13 @@
set -e
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1"
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.4 to be located in the"
echo "meshtastic-device root directory if the following step fails, you should download the correct"
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.1-linux-x86/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."

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

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

View File

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 532 B

View File

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 442 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

1
design Submodule

Submodule design added at 73ba05ceef

View File

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

View File

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

View File

@@ -2,19 +2,44 @@
You probably don't care about this section - skip to the next one.
eink:
* new battery level sensing
* measure current draw
* DONE: fix backlight
* USB is busted because of power enable mode?
* OHH BME280! THAT IS GREAT!
* make new screen work, ask for datasheet
* say I think you could ship this
* leds seem busted
* usb doesn't stay connected
* check GPS works
* check GPS fast locking
* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6
* send PR for bootloader
* fix nrf52 time/date
* send new master bin file
* send email about low power mode problems
* support new flash chip in appload, possibly use low power mode
* swbug! stuck busy tx occurred!
For app cleanup:
* use structured logging to kep logs in ram. Also send logs as packets to api clients
* 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
* DONE do fixed position bug https://github.com/meshtastic/Meshtastic-device/issues/536
* check build guide
* generate autodocs
* write devapi user guide
* DONE check build guide
* DONE write devapi user guide
* DONE update android code: https://developer.android.com/topic/libraries/view-binding/migration
* only do wantReplies once per packet type, if we change network settings force it again
* make gpio watch work, use thread and setup
* make hello world example service
* make python ping command
* make python gpio read a bit cleaner
* DONE test GPIO watch
* DONE set --set-chan-fast, --set-chan-default
* writeup docs on gpio
* DONE make python ping command
* DONE make hello world example service
* DONE have python tool check max packet size before sending to device
* DONE if request was sent reliably, send reply reliably
* DONE require a recent python api to talk to these new device loads
@@ -22,8 +47,8 @@ For app cleanup:
* DONE fix handleIncomingPosition
* DONE move want_replies handling into plugins
* DONE on android for received positions handle either old or new positions / user messages
* on android side send old or new positions as needed / user messages
* test python side handle new position/user messages
* DONE on android side send old or new positions as needed / user messages
* DONE test python side handle new position/user messages
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
* DONE fix position sending to use new plugin
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
@@ -31,9 +56,11 @@ 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
* 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
* 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

@@ -1,8 +1,11 @@
# Build instructions
This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode.
This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode. Workflows from building from the GUI or from the commandline are listed below.
If you encounter any problems, please post a question in [our forum](meshtastic.discourse.group). And when you learn a fix, update these instructions for the next person (i.e. edit this file and send in a [pull-request](https://opensource.com/article/19/7/create-pull-request-github) which we will eagerly merge).
## GUI
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
2. Install [Python](https://www.python.org/downloads/).
3. Install [Git](https://git-scm.com/downloads).
@@ -19,6 +22,7 @@ This project uses the simple PlatformIO build system. PlatformIO is an extension
Note - To get a clean build you may have to delete the auto-generated file `./.vscode/c_cpp_properties.json`, close and re-open Visual Studio and WAIT until the file is auto-generated before compiling again.
## Command Line
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it:
@@ -35,9 +39,20 @@ cd Meshtastic-device
## Decoding stack traces
### Option 1
If you get a crash, you can decode the addresses from the `Backtrace:` line:
1. Save the `Backtrace: 0x....` line to a file, e.g., `backtrace.txt`.
2. Run `bin/exception_decoder.py backtrace.txt` (this uses symbols from the
last `firmware.elf`, so you must be running the same binary that's still in
your `.pio/build` directory).
### Option 2
You can run the exception decoder to monitor the serial output and decode backtraces in real time.
1. From within PlatformIO, open a new terminal.
2. At the the terminal, enter:
`pio device monitor --port /dev/cu.SLAB_USBtoUART -f esp32_exception_decoder`
Replace the value of port with the location of your serial port.

View File

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

View File

@@ -1,4 +1,6 @@
# Device API
# Bluetooth/serial/TCP protocol API
(This document describes the protocol for external API clients using our devices. If you are interested in running your own code on the device itself, see the [on-device](plugin-api.md) documentation instead)
The Device API is design to have only a simple stream of ToRadio and FromRadio packets and all polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone.

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,81 @@
# Plugin-API
This is a tutorial on how to write small plugins which run on the device. Plugins are bits regular 'arduino' code that can send and receive packets to other nodes/apps/PCs using our mesh.
## Key concepts
All plugins should be subclasses of MeshPlugin. By inheriting from this class and creating an instance of your new plugin your plugin will be automatically registered to receive packets.
Messages are sent to particular port numbers (similar to UDP networking). Your new plugin should eventually pick its own port number (see below), but at first you can simply use PRIVATE_APP (which is the default).
Packets can be sent/received either as raw binary structures or as [Protobufs](https://developers.google.com/protocol-buffers).
### Class heirarchy
The relevant bits of the class heirarchy are as follows
* [MeshPlugin](/src/mesh/MeshPlugin.h) (in src/mesh/MeshPlugin.h) - you probably don't want to use this baseclass directly
* [SinglePortPlugin](/src/mesh/SinglePortPlugin.h) (in src/mesh/SinglePortPlugin.h) - for plugins that send/receive from a single port number (the normal case)
* [ProtobufPlugin](/src/mesh/ProtobufPlugin.h) (in src/mesh/ProtobufPlugin.h) - for plugins that send/receive a single particular Protobuf type. Inherit from this if you are using protocol buffers in your plugin.
You will typically want to inherit from either SinglePortPlugin (if you are just sending/receiving raw bytes) or ProtobufPlugin (if you are sending/receiving protobufs). You'll implement your own handleReceived/handleReceivedProtobuf - probably based on the example code.
If your plugin needs to perform any operations at startup you can override and implement the setup() method to run your code.
If you need to send a packet you can call service.sendToMesh with code like this (from the examples):
```
MeshPacket *p = allocReply();
p->to = dest;
service.sendToMesh(p);
```
## Example plugins
A number of [key services](/src/plugins) are implemented using the plugin API, these plugins are as follows:
* [TextMessagePlugin](/src/plugins/TextMessagePlugin.h) - receives text messages and displays them on the LCD screen/stores them in the local DB
* [NodeInfoPlugin](/src/plugins/NodeInfoPlugin.h) - receives/sends User information to other nodes so that usernames are available in the databases
* [RemoteHardwarePlugin](/src/plugins/RemoteHardwarePlugin.h) - a plugin that provides easy remote access to device hardware (for things like turning GPIOs on or off). Intended to be a more extensive example and provide a useful feature of its own. See [remote-hardware](remote-hardware.md) for details.
* [ReplyPlugin](/src/plugins/ReplyPlugin.h) - a simple plugin that just replies to any packet it receives (provides a 'ping' service).
## Getting started
The easiest way to get started is:
* [Build and install](build-instructions.md) the standard codebase from github.
* Copy [src/plugins/ReplyPlugin.*](/src/plugins/ReplyPlugin.cpp) into src/plugins/YourPlugin.*. Then change the port number from *PortNum_REPLY_APP* to *PortNum_PRIVATE_APP*.
* Edit plugins/Plugins.cpp:setupPlugins() to add a call to create an instance of your plugin (see comment at head of that function)
* Rebuild with your new messaging goodness and install on the device
* Use the [meshtastic commandline tool](https://github.com/meshtastic/Meshtastic-python) to send a packet to your board, for example "*meshtastic --dest 1234 --sendping*", where *1234* is another mesh node to send the ping to.
## Threading
It is very common that you would like your plugin to be invoked periodically.
We use a crude/basic cooperative threading system to allow this on any of our supported platforms. Simply inherit from OSThread and implement runOnce(). See the OSThread [documentation](/src/concurrency/OSThread.h) for more details. For an example consumer of this API see RemoteHardwarePlugin::runOnce.
## Sending messages
If you would like to proactively send messages (rather than just responding to them), just call service.sendToMesh(). For an example of this see [NodeInfoPlugin::sendOurNodeInfo(...)](/src/plugins/NodeInfoPlugin.cpp).
## Picking a port number
For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a unique 'portnum' for their application.
If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to [the master list](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/portnums.proto). PortNums should be assigned in the following range:
* **0-63** Core Meshtastic use; do not use for third party apps
* **64-127** Registered 3rd party apps. Send in a pull request that adds a new entry to portnums.proto to register your application
* **256-511** Use one of these portnums for your private applications that you don't want to register publically
* **1024-66559** Are reserved for use by IP tunneling (see *FIXME* for more information)
All other values are reserved.
## How to add custom protocol buffers
If you would like to use protocol buffers to define the structures you send over the mesh (recommended), here's how to do that.
* Create a new .proto file in the protos directory. You can use the existing [remote_hardware.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/remote_hardware.proto) file as an example.
* Run "bin/regen-protos.sh" to regenerate the C code for accessing the protocol buffers. If you don't have the required nanopb tool, follow the instructions printed by the script to get it.
* Done! You can now use your new protobuf just like any of the existing protobufs in meshtastic.

View File

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

View File

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

View File

@@ -0,0 +1,21 @@
# About
This is a work in progress and is not yet available.
The Store Request Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network.
Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12.
# Running notes
This will only work on nodes that are designated as a Router.
Initial Requirements:
* Must be installed on a router node.
* * This is an artificial limitation, but is in place to enforce best practices.
* * Router nodes are intended to be always online. If this plugin misses any messages, the reliability of the stored messages will be reduced
* Esp32 Processor based device with external PSRAM. (tbeam v1.0 and tbeamv1.1, maybe others)
Initial Features
*

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

@@ -1,9 +1,10 @@
This is a mini design doc for developing the meshtastic software.
* [Build instructions](build-instructions.md)
* [On device plugin API](plugin-api.md) - a tutorial on how to write small Plugins which run on the device and can message other nodes.
* [TODO](TODO.md) - read this if you are looking for things to do (or curious about currently missing features)
* Our [project board](https://github.com/orgs/meshtastic/projects/1) - shows what things we are currently working on and remaining work items for the current release.
* [Power Management](power.md)
* [Mesh algorithm](mesh-alg.md)
* [Device API](device-api.md) and porting guide for new clients (iOS, python, etc...)
* [External client API](device-api.md) and porting guide for new clients (iOS, python, etc...)
* TODO: how to port the device code to a new device.

View File

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

View File

@@ -11,7 +11,7 @@
*****************************************************************/
/* Enable support for dynamically allocated fields */
#define PB_ENABLE_MALLOC 1
/* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. */
@@ -55,7 +55,7 @@
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION nanopb-0.4.1
#define NANOPB_VERSION nanopb-0.4.4
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
@@ -276,17 +276,18 @@ typedef struct pb_field_iter_s pb_field_iter_t;
/* This structure is used in auto-generated constants
* to specify struct fields.
*/
PB_PACKED_STRUCT_START
typedef struct pb_msgdesc_s pb_msgdesc_t;
struct pb_msgdesc_s {
pb_size_t field_count;
const uint32_t *field_info;
const pb_msgdesc_t * const * submsg_info;
const pb_byte_t *default_value;
bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
} pb_packed;
PB_PACKED_STRUCT_END
pb_size_t field_count;
pb_size_t required_field_count;
pb_size_t largest_tag;
};
/* Iterator for message descriptor */
struct pb_field_iter_s {
@@ -469,137 +470,181 @@ struct pb_extension_s {
}; \
const pb_msgdesc_t structname ## _msg = \
{ \
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
structname ## _field_info, \
structname ## _submsg_info, \
msgname ## _DEFAULT, \
msgname ## _CALLBACK, \
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
}; \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
+ (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
* 0 + tag
/* X-macro for generating the entries in struct_field_info[] array. */
#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO(1, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO(2, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO(4, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO(8, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag)
#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_GEN_FIELD_INFO(width, structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname))
#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
/* X-macro for generating asserts that entries fit in struct_field_info[] array.
* The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
* but it is not easily reused because of how macro substitutions work. */
#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT(1, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT(2, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT(4, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT(8, structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype), structname, atype, htype, ltype, fieldname, tag)
PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_AUTO2(width, structname, atype, htype, ltype, fieldname, tag) \
PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag)
#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_GEN_FIELD_INFO_ASSERT(width, structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_ ## width(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(htype, structname, fieldname))
#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DATA_OFFSET_ ## htype(structname, fieldname)
#define PB_DATA_OFFSET_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DATA_OFFSET_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
#define PB_DATA_OFFSET_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DATA_OFFSET_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
#define PB_DATA_OFFSET_REPEATED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DATA_OFFSET_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SIZE_OFFSET_ ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SIZE_OFFSET_PTR_ ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SIZE_OFFSET_CB_ ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_REQUIRED(structname, fieldname) 0
#define PB_SIZE_OFFSET_SINGULAR(structname, fieldname) 0
#define PB_SIZE_OFFSET_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
#define PB_SIZE_OFFSET_ONEOF2(structname, fullname, unionname) PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname)
#define PB_SIZE_OFFSET_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
#define PB_SIZE_OFFSET_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
#define PB_SIZE_OFFSET_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
#define PB_SIZE_OFFSET_FIXARRAY(structname, fieldname) 0
#define PB_SIZE_OFFSET_PTR_REQUIRED(structname, fieldname) 0
#define PB_SIZE_OFFSET_PTR_SINGULAR(structname, fieldname) 0
#define PB_SIZE_OFFSET_PTR_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname)
#define PB_SIZE_OFFSET_PTR_OPTIONAL(structname, fieldname) 0
#define PB_SIZE_OFFSET_PTR_REPEATED(structname, fieldname) PB_SIZE_OFFSET_REPEATED(structname, fieldname)
#define PB_SIZE_OFFSET_PTR_FIXARRAY(structname, fieldname) 0
#define PB_SIZE_OFFSET_CB_REQUIRED(structname, fieldname) 0
#define PB_SIZE_OFFSET_CB_SINGULAR(structname, fieldname) 0
#define PB_SIZE_OFFSET_CB_ONEOF(structname, fieldname) PB_SIZE_OFFSET_ONEOF(structname, fieldname)
#define PB_SIZE_OFFSET_CB_OPTIONAL(structname, fieldname) 0
#define PB_SIZE_OFFSET_CB_REPEATED(structname, fieldname) 0
#define PB_SIZE_OFFSET_CB_FIXARRAY(structname, fieldname) 0
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_ARRAY_SIZE_ ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_ARRAY_SIZE_PTR_ ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
#define PB_ARRAY_SIZE_REQUIRED(structname, fieldname) 1
#define PB_ARRAY_SIZE_SINGULAR(structname, fieldname) 1
#define PB_ARRAY_SIZE_OPTIONAL(structname, fieldname) 1
#define PB_ARRAY_SIZE_ONEOF(structname, fieldname) 1
#define PB_ARRAY_SIZE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_ARRAY_SIZE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_ARRAY_SIZE_PTR_REQUIRED(structname, fieldname) 1
#define PB_ARRAY_SIZE_PTR_SINGULAR(structname, fieldname) 1
#define PB_ARRAY_SIZE_PTR_OPTIONAL(structname, fieldname) 1
#define PB_ARRAY_SIZE_PTR_ONEOF(structname, fieldname) 1
#define PB_ARRAY_SIZE_PTR_REPEATED(structname, fieldname) 1
#define PB_ARRAY_SIZE_PTR_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DATA_SIZE_ ## htype(structname, fieldname)
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DATA_SIZE_PTR_ ## htype(structname, fieldname)
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DATA_SIZE_CB_ ## htype(structname, fieldname)
#define PB_DATA_SIZE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DATA_SIZE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_PTR_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_PTR_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_PTR_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_PTR_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
#define PB_DATA_SIZE_PTR_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DATA_SIZE_PTR_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
#define PB_DATA_SIZE_CB_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_CB_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_CB_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_CB_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DATA_SIZE_CB_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_CB_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
@@ -607,37 +652,37 @@ struct pb_extension_s {
#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
PB_SUBMSG_INFO_ ## htype(ltype, structname, fieldname)
PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname)
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SUBMSG_INFO_ ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_BOOL(t)
#define PB_SUBMSG_INFO_BYTES(t)
#define PB_SUBMSG_INFO_DOUBLE(t)
#define PB_SUBMSG_INFO_ENUM(t)
#define PB_SUBMSG_INFO_UENUM(t)
#define PB_SUBMSG_INFO_FIXED32(t)
#define PB_SUBMSG_INFO_FIXED64(t)
#define PB_SUBMSG_INFO_FLOAT(t)
#define PB_SUBMSG_INFO_INT32(t)
#define PB_SUBMSG_INFO_INT64(t)
#define PB_SUBMSG_INFO_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SUBMSG_INFO_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SUBMSG_INFO_SFIXED32(t)
#define PB_SUBMSG_INFO_SFIXED64(t)
#define PB_SUBMSG_INFO_SINT32(t)
#define PB_SUBMSG_INFO_SINT64(t)
#define PB_SUBMSG_INFO_STRING(t)
#define PB_SUBMSG_INFO_UINT32(t)
#define PB_SUBMSG_INFO_UINT64(t)
#define PB_SUBMSG_INFO_EXTENSION(t)
#define PB_SUBMSG_INFO_FIXED_LENGTH_BYTES(t)
#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SI_PB_LTYPE_BOOL(t)
#define PB_SI_PB_LTYPE_BYTES(t)
#define PB_SI_PB_LTYPE_DOUBLE(t)
#define PB_SI_PB_LTYPE_ENUM(t)
#define PB_SI_PB_LTYPE_UENUM(t)
#define PB_SI_PB_LTYPE_FIXED32(t)
#define PB_SI_PB_LTYPE_FIXED64(t)
#define PB_SI_PB_LTYPE_FLOAT(t)
#define PB_SI_PB_LTYPE_INT32(t)
#define PB_SI_PB_LTYPE_INT64(t)
#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_SFIXED32(t)
#define PB_SI_PB_LTYPE_SFIXED64(t)
#define PB_SI_PB_LTYPE_SINT32(t)
#define PB_SI_PB_LTYPE_SINT64(t)
#define PB_SI_PB_LTYPE_STRING(t)
#define PB_SI_PB_LTYPE_UINT32(t)
#define PB_SI_PB_LTYPE_UINT64(t)
#define PB_SI_PB_LTYPE_EXTENSION(t)
#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg),
/* The field descriptors use a variable width format, with width of either
@@ -726,37 +771,37 @@ struct pb_extension_s {
* The generator will give explicit size argument when it knows that a message
* structure grows beyond 1-word format limits.
*/
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FIELDINFO_WIDTH_ ## atype(htype, ltype)
#define PB_FIELDINFO_WIDTH_STATIC(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype)
#define PB_FIELDINFO_WIDTH_POINTER(htype, ltype) PB_FIELDINFO_WIDTH_ ## htype(ltype)
#define PB_FIELDINFO_WIDTH_CALLBACK(htype, ltype) 2
#define PB_FIELDINFO_WIDTH_REQUIRED(ltype) PB_FIELDINFO_WIDTH_ ## ltype
#define PB_FIELDINFO_WIDTH_SINGULAR(ltype) PB_FIELDINFO_WIDTH_ ## ltype
#define PB_FIELDINFO_WIDTH_OPTIONAL(ltype) PB_FIELDINFO_WIDTH_ ## ltype
#define PB_FIELDINFO_WIDTH_ONEOF(ltype) PB_FIELDINFO_WIDTH_ ## ltype
#define PB_FIELDINFO_WIDTH_REPEATED(ltype) 2
#define PB_FIELDINFO_WIDTH_FIXARRAY(ltype) 2
#define PB_FIELDINFO_WIDTH_BOOL 1
#define PB_FIELDINFO_WIDTH_BYTES 2
#define PB_FIELDINFO_WIDTH_DOUBLE 1
#define PB_FIELDINFO_WIDTH_ENUM 1
#define PB_FIELDINFO_WIDTH_UENUM 1
#define PB_FIELDINFO_WIDTH_FIXED32 1
#define PB_FIELDINFO_WIDTH_FIXED64 1
#define PB_FIELDINFO_WIDTH_FLOAT 1
#define PB_FIELDINFO_WIDTH_INT32 1
#define PB_FIELDINFO_WIDTH_INT64 1
#define PB_FIELDINFO_WIDTH_MESSAGE 2
#define PB_FIELDINFO_WIDTH_MSG_W_CB 2
#define PB_FIELDINFO_WIDTH_SFIXED32 1
#define PB_FIELDINFO_WIDTH_SFIXED64 1
#define PB_FIELDINFO_WIDTH_SINT32 1
#define PB_FIELDINFO_WIDTH_SINT64 1
#define PB_FIELDINFO_WIDTH_STRING 2
#define PB_FIELDINFO_WIDTH_UINT32 1
#define PB_FIELDINFO_WIDTH_UINT64 1
#define PB_FIELDINFO_WIDTH_EXTENSION 1
#define PB_FIELDINFO_WIDTH_FIXED_LENGTH_BYTES 2
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
#define PB_FI_WIDTH_PB_LTYPE_BOOL 1
#define PB_FI_WIDTH_PB_LTYPE_BYTES 2
#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1
#define PB_FI_WIDTH_PB_LTYPE_ENUM 1
#define PB_FI_WIDTH_PB_LTYPE_UENUM 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1
#define PB_FI_WIDTH_PB_LTYPE_INT32 1
#define PB_FI_WIDTH_PB_LTYPE_INT64 1
#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2
#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2
#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_SINT32 1
#define PB_FI_WIDTH_PB_LTYPE_SINT64 1
#define PB_FI_WIDTH_PB_LTYPE_STRING 2
#define PB_FI_WIDTH_PB_LTYPE_UINT32 1
#define PB_FI_WIDTH_PB_LTYPE_UINT64 1
#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
/* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL

View File

@@ -32,6 +32,10 @@ bool pb_field_iter_next(pb_field_iter_t *iter);
* Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
* There can be only one extension range field per message. */
bool pb_field_iter_find_extension(pb_field_iter_t *iter);
#ifdef PB_VALIDATE_UTF8
/* Validate UTF-8 text string */
bool pb_validate_utf8(const char *s);

View File

@@ -113,6 +113,9 @@ bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_s
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
#else
/* Allocation is not supported, so release is no-op */
#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct);
#endif
@@ -121,11 +124,14 @@ void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
**************************************/
/* Create an input stream for reading from a memory buffer.
*
* msglen should be the actual length of the message, not the full size of
* allocated buffer.
*
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
/* Function to read from a pb_istream_t. You can use this if you need to
* read some custom header data, or to read data in field callbacks.

View File

@@ -132,7 +132,7 @@ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
* structure. Call this from the callback before writing out field contents. */
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
/* Encode field header by manually specifing wire type. You need to use this
/* Encode field header by manually specifying wire type. You need to use this
* if you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);

View File

@@ -9,89 +9,102 @@ static bool load_descriptor_values(pb_field_iter_t *iter)
{
uint32_t word0;
uint32_t data_offset;
uint_least8_t format;
int_least8_t size_offset;
if (iter->index >= iter->descriptor->field_count)
return false;
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
format = word0 & 3;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
if (format == 0)
switch(word0 & 3)
{
/* 1-word format */
iter->array_size = 1;
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
}
else if (format == 1)
{
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
case 0: {
/* 1-word format */
iter->array_size = 1;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
break;
}
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
}
else if (format == 2)
{
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
case 1: {
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
}
else
{
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
break;
}
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(iter->tag | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
case 2: {
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
default: {
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
}
iter->pField = (char*)iter->message + data_offset;
if (size_offset)
{
iter->pSize = (char*)iter->pField - size_offset;
}
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
{
/* Fixed count array */
iter->pSize = &iter->array_size;
}
else
if (!iter->message)
{
/* Avoid doing arithmetic on null pointers, it is undefined */
iter->pField = NULL;
iter->pSize = NULL;
}
if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
{
iter->pData = *(void**)iter->pField;
}
else
{
iter->pData = iter->pField;
iter->pField = (char*)iter->message + data_offset;
if (size_offset)
{
iter->pSize = (char*)iter->pField - size_offset;
}
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
{
/* Fixed count array */
iter->pSize = &iter->array_size;
}
else
{
iter->pSize = NULL;
}
if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
{
iter->pData = *(void**)iter->pField;
}
else
{
iter->pData = iter->pField;
}
}
if (PB_LTYPE_IS_SUBMSG(iter->type))
@@ -130,17 +143,13 @@ static void advance_iterator(pb_field_iter_t *iter)
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
/* Add to fields.
* The cast to pb_size_t is needed to avoid -Wconversion warning.
* Because the data is is constants from generator, there is no danger of overflow.
*/
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
if (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)
{
iter->required_field_index++;
}
if (PB_LTYPE_IS_SUBMSG(prev_type))
{
iter->submessage_index++;
}
iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
}
}
@@ -189,11 +198,23 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
{
return true; /* Nothing to do, correct field already. */
}
else if (tag > iter->descriptor->largest_tag)
{
return false;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
if (tag < iter->tag)
{
/* Fields are in tag number order, so we know that tag is between
* 0 and our start position. Setting index to end forces
* advance_iterator() call below to restart from beginning. */
iter->index = iter->descriptor->field_count;
}
do
{
/* Advance iterator but don't load values yet */
@@ -222,6 +243,37 @@ bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
}
}
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
{
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
{
return true;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for field type */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
{
return load_descriptor_values(iter);
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator

View File

@@ -24,19 +24,17 @@
static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof);
static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field);
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);
static bool checkreturn find_extension_field(pb_field_iter_t *iter);
static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension);
static bool pb_field_set_to_default(pb_field_iter_t *field);
static bool pb_message_set_to_defaults(pb_field_iter_t *iter);
static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field);
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field);
@@ -59,6 +57,8 @@ static void pb_release_single_field(pb_field_iter_t *field);
#define pb_uint64_t uint64_t
#endif
#define PB_WT_PACKED ((pb_wire_type_t)0xFF)
typedef struct {
uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32];
} pb_fields_seen_t;
@@ -139,7 +139,7 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf)
return true;
}
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen)
{
pb_istream_t stream;
/* Cast away the const from buf without a compiler error. We are
@@ -156,7 +156,7 @@ pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
#endif
state.c_state = buf;
stream.state = state.state;
stream.bytes_left = bufsize;
stream.bytes_left = msglen;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
@@ -205,8 +205,10 @@ static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *d
{
/* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension))
bool valid_extension = ((byte & 0x7F) == 0x00 ||
((result >> 31) != 0 && byte == sign_extension));
if (bitpos >= 64 || !valid_extension)
{
PB_RETURN_ERROR(stream, "varint overflow");
}
@@ -388,61 +390,70 @@ bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *s
* Decode a single field *
*************************/
static bool checkreturn check_wire_type(pb_wire_type_t wire_type, pb_field_iter_t *field)
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
{
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
return wire_type == PB_WT_VARINT;
if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
case PB_LTYPE_FIXED32:
return wire_type == PB_WT_32BIT;
case PB_LTYPE_FIXED64:
return wire_type == PB_WT_64BIT;
case PB_LTYPE_BYTES:
case PB_LTYPE_STRING:
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
case PB_LTYPE_FIXED_LENGTH_BYTES:
return wire_type == PB_WT_STRING;
default:
return false;
}
}
static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_field_iter_t *field)
{
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_BOOL:
return pb_dec_bool(stream, field);
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_varint(stream, field);
case PB_LTYPE_FIXED32:
if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_decode_fixed32(stream, field->pData);
case PB_LTYPE_FIXED64:
return pb_dec_fixed(stream, field);
if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED)
PB_RETURN_ERROR(stream, "wrong wire type");
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float))
{
return pb_decode_double_as_float(stream, (float*)field->pData);
}
#endif
#ifdef PB_WITHOUT_64BIT
PB_RETURN_ERROR(stream, "invalid data_size");
#else
return pb_decode_fixed64(stream, field->pData);
#endif
case PB_LTYPE_BYTES:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_bytes(stream, field);
case PB_LTYPE_STRING:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_string(stream, field);
case PB_LTYPE_SUBMESSAGE:
case PB_LTYPE_SUBMSG_W_CB:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_submessage(stream, field);
case PB_LTYPE_FIXED_LENGTH_BYTES:
if (wire_type != PB_WT_STRING)
PB_RETURN_ERROR(stream, "wrong wire type");
return pb_dec_fixed_length_bytes(stream, field);
default:
@@ -455,18 +466,12 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
case PB_HTYPE_OPTIONAL:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (field->pSize != NULL)
*(bool*)field->pSize = true;
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
@@ -483,7 +488,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
while (substream.bytes_left > 0 && *size < field->array_size)
{
if (!decode_basic_field(&substream, field))
if (!decode_basic_field(&substream, PB_WT_PACKED, field))
{
status = false;
break;
@@ -505,18 +510,15 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
pb_size_t *size = (pb_size_t*)field->pSize;
field->pData = (char*)field->pField + field->data_size * (*size);
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if ((*size)++ >= field->array_size)
PB_RETURN_ERROR(stream, "array overflow");
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
}
case PB_HTYPE_ONEOF:
*(pb_size_t*)field->pSize = field->tag;
if (PB_LTYPE_IS_SUBMSG(field->type))
if (PB_LTYPE_IS_SUBMSG(field->type) &&
*(pb_size_t*)field->pSize != field->tag)
{
/* We memset to zero so that any callbacks are set to NULL.
* This is because the callbacks might otherwise have values
@@ -526,12 +528,14 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
* that can set the fields before submessage is decoded.
* pb_dec_submessage() will set any default values. */
memset(field->pData, 0, (size_t)field->data_size);
/* Set default values for the submessage fields. */
if (!pb_field_set_to_default(field))
PB_RETURN_ERROR(stream, "failed to set defaults");
}
*(pb_size_t*)field->pSize = field->tag;
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
default:
PB_RETURN_ERROR(stream, "invalid field type");
@@ -599,14 +603,8 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *field)
else if (PB_LTYPE_IS_SUBMSG(field->type))
{
/* We memset to zero so that any callbacks are set to NULL.
* Then set any default values. */
pb_field_iter_t submsg_iter;
* Default values will be set by pb_dec_submessage(). */
memset(pItem, 0, field->data_size);
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, pItem))
{
(void)pb_message_set_to_defaults(&submsg_iter);
}
}
}
#endif
@@ -623,9 +621,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
case PB_HTYPE_REQUIRED:
case PB_HTYPE_OPTIONAL:
case PB_HTYPE_ONEOF:
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL)
{
/* Duplicate field, have to release the old allocation first. */
@@ -643,7 +638,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
{
/* pb_dec_string and pb_dec_bytes handle allocation themselves */
field->pData = field->pField;
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
}
else
{
@@ -652,7 +647,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
field->pData = *(void**)field->pField;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
}
case PB_HTYPE_REPEATED:
@@ -700,7 +695,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
/* Decode the array entry */
field->pData = *(char**)field->pField + field->data_size * (*size);
initialize_pointer_field(field->pData, field);
if (!decode_basic_field(&substream, field))
if (!decode_basic_field(&substream, PB_WT_PACKED, field))
{
status = false;
break;
@@ -721,16 +716,13 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_
if (*size == PB_SIZE_MAX)
PB_RETURN_ERROR(stream, "too many array entries");
if (!check_wire_type(wire_type, field))
PB_RETURN_ERROR(stream, "wrong wire type");
if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1)))
return false;
field->pData = *(char**)field->pField + field->data_size * (*size);
(*size)++;
initialize_pointer_field(field->pData, field);
return decode_basic_field(stream, field);
return decode_basic_field(stream, wire_type, field);
}
default:
@@ -821,7 +813,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream,
if (!pb_field_iter_begin_extension(&iter, extension))
PB_RETURN_ERROR(stream, "invalid extension");
if (iter.tag != tag)
if (iter.tag != tag || !iter.message)
return true;
extension->found = true;
@@ -831,9 +823,8 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream,
/* Try to decode an unknown field as an extension field. Tries each extension
* decoder in turn, until one of them handles the field or loop ends. */
static bool checkreturn decode_extension(pb_istream_t *stream,
uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter)
uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension)
{
pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
size_t pos = stream->bytes_left;
while (extension != NULL && pos == stream->bytes_left)
@@ -853,22 +844,6 @@ static bool checkreturn decode_extension(pb_istream_t *stream,
return true;
}
/* Step through the iterator until an extension field is found or until all
* entries have been checked. There can be only one extension field per
* message. Returns false if no extension field is found. */
static bool checkreturn find_extension_field(pb_field_iter_t *iter)
{
pb_size_t start = iter->index;
do {
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
return true;
(void)pb_field_iter_next(iter);
} while (iter->index != start);
return false;
}
/* Initialize message fields to default values, recursively */
static bool pb_field_set_to_default(pb_field_iter_t *field)
{
@@ -910,9 +885,14 @@ static bool pb_field_set_to_default(pb_field_iter_t *field)
if (init_data)
{
if (PB_LTYPE_IS_SUBMSG(field->type))
if (PB_LTYPE_IS_SUBMSG(field->type) &&
(field->submsg_desc->default_value != NULL ||
field->submsg_desc->field_callback != NULL ||
field->submsg_desc->submsg_info[0] != NULL))
{
/* Initialize submessage to defaults */
/* Initialize submessage to defaults.
* Only needed if it has default values
* or callback/submessage fields. */
pb_field_iter_t submsg_iter;
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
{
@@ -989,6 +969,7 @@ static bool pb_message_set_to_defaults(pb_field_iter_t *iter)
static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
{
uint32_t extension_range_start = 0;
pb_extension_t *extensions = NULL;
/* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
* count field. This can only handle _one_ repeated fixed count field that
@@ -1040,25 +1021,31 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t
if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
{
/* No match found, check if it matches an extension. */
if (extension_range_start == 0)
{
if (pb_field_iter_find_extension(&iter))
{
extensions = *(pb_extension_t* const *)iter.pData;
extension_range_start = iter.tag;
}
if (!extensions)
{
extension_range_start = (uint32_t)-1;
}
}
if (tag >= extension_range_start)
{
if (!find_extension_field(&iter))
extension_range_start = (uint32_t)-1;
else
extension_range_start = iter.tag;
size_t pos = stream->bytes_left;
if (tag >= extension_range_start)
if (!decode_extension(stream, tag, wire_type, extensions))
return false;
if (pos != stream->bytes_left)
{
size_t pos = stream->bytes_left;
if (!decode_extension(stream, tag, wire_type, &iter))
return false;
if (pos != stream->bytes_left)
{
/* The field was handled */
continue;
}
/* The field was handled */
continue;
}
}
@@ -1112,27 +1099,15 @@ static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t
/* Check that all required fields were present. */
{
/* First figure out the number of required fields by
* seeking to the end of the field array. Usually we
* are already close to end after decoding.
*/
pb_size_t req_field_count;
pb_type_t last_type;
pb_size_t i;
do {
req_field_count = iter.required_field_index;
last_type = iter.type;
} while (pb_field_iter_next(&iter));
/* Fixup if last field was also required. */
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.tag != 0)
req_field_count++;
if (req_field_count > PB_MAX_REQUIRED_FIELDS)
req_field_count = PB_MAX_REQUIRED_FIELDS;
pb_size_t req_field_count = iter.descriptor->required_field_count;
if (req_field_count > 0)
{
pb_size_t i;
if (req_field_count > PB_MAX_REQUIRED_FIELDS)
req_field_count = PB_MAX_REQUIRED_FIELDS;
/* Check the whole words */
for (i = 0; i < (req_field_count >> 5); i++)
{
@@ -1277,7 +1252,7 @@ static void pb_release_single_field(pb_field_iter_t *field)
if (field->pData)
{
while (count--)
for (; count > 0; count--)
{
pb_release(field->submsg_desc, field->pData);
field->pData = (char*)field->pData + field->data_size;
@@ -1294,7 +1269,7 @@ static void pb_release_single_field(pb_field_iter_t *field)
/* Release entries in repeated string or bytes array */
void **pItem = *(void***)field->pField;
pb_size_t count = *(pb_size_t*)field->pSize;
while (count--)
for (; count > 0; count--)
{
pb_free(*pItem);
*pItem++ = NULL;
@@ -1454,7 +1429,7 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_
/* See issue 97: Google's C++ protobuf allows negative varint values to
* be cast as int32_t, instead of the int64_t that should be used when
* encoding. Previous nanopb versions had a bug in encoding. In order to
* encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to
* not break decoding of such messages, we cast <=32 bit fields to
* int32_t first to get the sign correct.
*/
@@ -1483,31 +1458,6 @@ static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_
}
}
static bool checkreturn pb_dec_fixed(pb_istream_t *stream, const pb_field_iter_t *field)
{
#ifdef PB_CONVERT_DOUBLE_FLOAT
if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
return pb_decode_double_as_float(stream, (float*)field->pData);
}
#endif
if (field->data_size == sizeof(uint32_t))
{
return pb_decode_fixed32(stream, field->pData);
}
#ifndef PB_WITHOUT_64BIT
else if (field->data_size == sizeof(uint64_t))
{
return pb_decode_fixed64(stream, field->pData);
}
#endif
else
{
PB_RETURN_ERROR(stream, "invalid data_size");
}
}
static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
{
uint32_t size;
@@ -1601,6 +1551,7 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_
static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field)
{
bool status = true;
bool submsg_consumed = false;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
@@ -1609,19 +1560,6 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i
if (field->submsg_desc == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
/* New array entries need to be initialized, while required and optional
* submessages have already been initialized in the top-level pb_decode. */
if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED ||
PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
{
pb_field_iter_t submsg_iter;
if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
{
if (!pb_message_set_to_defaults(&submsg_iter))
PB_RETURN_ERROR(stream, "failed to set defaults");
}
}
/* Submessages can have a separate message-level callback that is called
* before decoding the message. Typically it is used to set callback fields
* inside oneofs. */
@@ -1632,13 +1570,28 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_i
if (callback->funcs.decode)
{
status = callback->funcs.decode(&substream, field, &callback->arg);
if (substream.bytes_left == 0)
{
submsg_consumed = true;
}
}
}
/* Now decode the submessage contents */
if (status)
if (status && !submsg_consumed)
{
status = pb_decode_inner(&substream, field->submsg_desc, field->pData, 0);
unsigned int flags = 0;
/* Static required/optional fields are already initialized by top-level
* pb_decode(), no need to initialize them again. */
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_HTYPE(field->type) != PB_HTYPE_REPEATED)
{
flags = PB_DECODE_NOINIT;
}
status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags);
}
if (!pb_close_string_substream(stream, &substream))
@@ -1692,37 +1645,41 @@ bool pb_decode_double_as_float(pb_istream_t *stream, float *dest)
{
/* Special value */
exponent = 128;
}
else if (exponent > 127)
{
/* Too large, convert to infinity */
exponent = 128;
mantissa = 0;
}
else if (exponent < -150)
{
/* Too small, convert to zero */
exponent = -127;
mantissa = 0;
}
else if (exponent < -126)
{
/* Denormalized */
mantissa |= 0x1000000;
mantissa >>= (-126 - exponent);
exponent = -127;
}
/* Round off mantissa */
mantissa = (mantissa + 1) >> 1;
/* Check if mantissa went over 2.0 */
if (mantissa & 0x800000)
{
exponent += 1;
mantissa &= 0x7FFFFF;
mantissa >>= 1;
}
else
{
if (exponent > 127)
{
/* Too large, convert to infinity */
exponent = 128;
mantissa = 0;
}
else if (exponent < -150)
{
/* Too small, convert to zero */
exponent = -127;
mantissa = 0;
}
else if (exponent < -126)
{
/* Denormalized */
mantissa |= 0x1000000;
mantissa >>= (-126 - exponent);
exponent = -127;
}
/* Round off mantissa */
mantissa = (mantissa + 1) >> 1;
/* Check if mantissa went over 2.0 */
if (mantissa & 0x800000)
{
exponent += 1;
mantissa &= 0x7FFFFF;
mantissa >>= 1;
}
}
/* Combine fields */
out.i = mantissa;

View File

@@ -82,8 +82,11 @@ bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t cou
{
if (count > 0 && stream->callback != NULL)
{
if (stream->bytes_written + count > stream->max_size)
if (stream->bytes_written + count < stream->bytes_written ||
stream->bytes_written + count > stream->max_size)
{
PB_RETURN_ERROR(stream, "stream full");
}
#ifdef PB_BUFFER_ONLY
if (!buf_write(stream, buf, count))
@@ -262,9 +265,33 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie
* submessage fields. */
return safe_read_bool(field->pSize) == false;
}
else if (field->descriptor->default_value)
{
/* Proto3 messages do not have default values, but proto2 messages
* can contain optional fields without has_fields (generator option 'proto3').
* In this case they must always be encoded, to make sure that the
* non-zero default value is overwritten.
*/
return false;
}
/* Rest is proto3 singular fields */
if (PB_LTYPE(type) == PB_LTYPE_BYTES)
if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
{
/* Simple integer / float fields */
pb_size_t i;
const char *p = (const char*)field->pData;
for (i = 0; i < field->data_size; i++)
{
if (p[i] != 0)
{
return false;
}
}
return true;
}
else if (PB_LTYPE(type) == PB_LTYPE_BYTES)
{
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData;
return bytes->size == 0;
@@ -302,27 +329,29 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie
return true;
}
}
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
{
/* Catch-all branch that does byte-per-byte comparison for zero value.
*
* This is for all pointer fields, and for static PB_LTYPE_VARINT,
* UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
* callback fields. These all have integer or pointer value which
* can be compared with 0.
*/
pb_size_t i;
const char *p = (const char*)field->pData;
for (i = 0; i < field->data_size; i++)
{
if (p[i] != 0)
{
return false;
}
}
return true;
return field->pData == NULL;
}
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
{
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
{
const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
return extension == NULL;
}
else if (field->descriptor->field_callback == pb_default_field_callback)
{
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
return pCallback->funcs.encode == NULL;
}
else
{
return field->descriptor->field_callback == NULL;
}
}
return false; /* Not typically reached, safe default for weird special cases. */
}
/* Encode a field with static or pointer allocation, i.e. one whose data
@@ -823,7 +852,7 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t
}
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
{
PB_RETURN_ERROR(stream, "bytes size exceeded");
}

View File

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

View File

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

View File

@@ -9,8 +9,13 @@
; 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 = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec
;default_envs = tlora-v1
;default_envs = tlora-v2
;default_envs = lora-relay-v1 # nrf board
;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
[common]
; common is not currently used
@@ -65,12 +70,12 @@ 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
SPI
https://github.com/geeksville/ArduinoThread.git#333ffd09b596977c217ba25da4258f588b462ac6
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
; Common settings for conventional (non Portduino) Ardino targets
[arduino_base]
@@ -103,7 +108,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
@@ -180,10 +185,10 @@ build_type = debug ; I'm debugging with ICE a lot now
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
@@ -247,7 +252,7 @@ src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
lib_deps =
${arduino_base.lib_deps}
; Prototype eink/nrf52840/sx1262 device
; First prototype eink/nrf52840/sx1262 device
[env:eink]
extends = nrf52_base
board = eink
@@ -261,6 +266,20 @@ lib_deps =
https://github.com/geeksville/EPD_Libraries.git
TFT_eSPI
; First prototype eink/nrf52840/sx1262 device
[env:eink0.1]
extends = nrf52_base
board = eink0.1
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
lib_deps =
${arduino_base.lib_deps}
https://github.com/geeksville/EPD_Libraries.git
TFT_eSPI
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
[env:lora-relay-v1]
extends = nrf52_base
@@ -310,7 +329,17 @@ lib_deps =
; The Portduino based sim environment on top of linux
[env:linux]
platform = https://github.com/geeksville/platform-portduino.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/>
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/>
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: ebd18145ca...0cadaed395

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

@@ -1,4 +1,5 @@
#include "power.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "main.h"
#include "sleep.h"
@@ -83,7 +84,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
virtual bool isVBUSPlug() { return getBattVoltage() > 1000 * chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
@@ -268,7 +269,42 @@ 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
if (radioConfig.preferences.charge_current == ChargeCurrent_MAUnset) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA100) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_100MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA190) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_190MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA280) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_280MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA360) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_360MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA450) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA550) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_550MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA630) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_630MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA700) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_700MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA780) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_780MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA880) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_880MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA960) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_960MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1000) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1000MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1080) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1080MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1160) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1160MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1240) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1240MA);
} else if (radioConfig.preferences.charge_current == ChargeCurrent_MA1320) {
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA);
}
#if 0
// 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 other nodes 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

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

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

107
src/airtime.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "airtime.h"
#include <Arduino.h>
#define periodsToLog 48
AirTime *airTime;
uint32_t secondsPerPeriod = 3600;
uint32_t lastMillis = 0;
uint32_t secSinceBoot = 0;
// AirTime at;
// Don't read out of this directly. Use the helper functions.
struct airtimeStruct {
uint32_t periodTX[periodsToLog]; // AirTime transmitted
uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets)
uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise.
uint8_t lastPeriodIndex;
} airtimes;
void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms;
} else if (reportType == RX_LOG) {
DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) {
DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms;
} else {
DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
}
}
uint8_t currentPeriodIndex()
{
return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
}
void airtimeRotatePeriod()
{
if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());
for (int i = periodsToLog - 2; i >= 0; --i) {
airtimes.periodTX[i + 1] = airtimes.periodTX[i];
airtimes.periodRX[i + 1] = airtimes.periodRX[i];
airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
}
airtimes.periodTX[0] = 0;
airtimes.periodRX[0] = 0;
airtimes.periodRX_ALL[0] = 0;
airtimes.lastPeriodIndex = currentPeriodIndex();
}
}
uint32_t *airtimeReport(reportTypes reportType)
{
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;
}
AirTime::AirTime() : concurrency::OSThread("AirTime") {}
int32_t AirTime::runOnce()
{
//DEBUG_MSG("AirTime::runOnce()\n");
airtimeRotatePeriod();
secSinceBoot++;
/*
This actually doesn't need to be run once per second but we currently use it for the
secSinceBoot counter.
If we have a better counter of how long the device has been online (and not millis())
then we can change this to something less frequent. Maybe once ever 5 seconds?
*/
return (1000 * 1);
}

54
src/airtime.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include "concurrency/OSThread.h"
#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 airtimeRotatePeriod();
uint8_t currentPeriodIndex();
uint8_t getPeriodsToLog();
uint32_t getSecondsSinceBoot();
uint32_t *airtimeReport(reportTypes reportType);
uint32_t getSecondsPerPeriod();
class AirTime : private concurrency::OSThread
{
public:
AirTime();
void logAirtime(reportTypes reportType, uint32_t airtime_ms);
protected:
virtual int32_t runOnce();
};
extern AirTime *airTime;

View File

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

View File

@@ -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;
@@ -26,10 +28,14 @@ void OSThread::setup()
OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller)
: Thread(NULL, period), controller(_controller)
{
assertIsSetup();
ThreadName = _name;
if (controller)
controller->add(this);
if (controller) {
bool added = controller->add(this);
assert(added);
}
}
OSThread::~OSThread()
@@ -68,12 +74,47 @@ bool OSThread::shouldRun(unsigned long time)
void OSThread::run()
{
currentThread = this;
auto newDelay = runOnce();
runned();
if (newDelay >= 0)
setInterval(newDelay);
currentThread = NULL;
}
/**
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
*
* it is super important to never allocate those object statically. instead, you should explicitly
* new them at a point where you are guaranteed that other objects that this instance
* depends on have already been created.
*
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
* this makes it guaranteed that the global mainController is fully constructed first.
*/
bool hasBeenSetup;
void assertIsSetup()
{
/**
* Dear developer comrade - If this assert fails() that means you need to fix the following:
*
* This flag is set **only** when setup() starts, to provide a way for us to check for sloppy static constructor calls.
* Call assertIsSetup() to force a crash if someone tries to create an instance too early.
*
* it is super important to never allocate those object statically. instead, you should explicitly
* new them at a point where you are guaranteed that other objects that this instance
* depends on have already been created.
*
* in particular, for OSThread that means "all instances must be declared via new() in setup() or later" -
* this makes it guaranteed that the global mainController is fully constructed first.
*/
assert(hasBeenSetup);
}
} // namespace concurrency

View File

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

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
@@ -307,6 +309,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V1_3)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tlora-v1-3"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 36
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2_1_16)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tlora-v2-1-1.6"
@@ -336,6 +365,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 +421,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 +429,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 +486,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

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

View File

@@ -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

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

View File

@@ -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

@@ -4,7 +4,6 @@
#include "EInkDisplay.h"
#include "SPILock.h"
#include "epd1in54.h" // Screen specific library
#include "graphics/configs.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Graphics library and Sprite class
@@ -123,7 +122,8 @@ bool EInkDisplay::connect()
#endif
#ifdef PIN_EINK_EN
digitalWrite(PIN_EINK_EN, HIGH);
// backlight power, HIGH is backlight on, LOW is off
digitalWrite(PIN_EINK_EN, LOW);
pinMode(PIN_EINK_EN, OUTPUT);
#endif

View File

@@ -26,21 +26,33 @@ 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"
#include "meshwifi/meshwifi.h"
#include "plugins/TextMessagePlugin.h"
#include "target_specific.h"
#include "utils.h"
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#endif
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 +164,36 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, 48 + y, buf);
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Updating");
display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait...");
//display->setFont(FONT_LARGE);
//display->drawString(64 + x, 26 + y, btPIN);
}
/// Draw the last text message we received
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
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)
{
@@ -173,7 +215,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[96];
assert(mp.decoded.which_payload == SubPacket_data_tag);
assert(mp.decoded.which_payloadVariant == SubPacket_data_tag);
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf);
@@ -290,7 +332,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 +585,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
@@ -721,7 +763,7 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
textMessageObserver.observe(&textMessagePlugin);
textMessageObserver.observe(textMessagePlugin);
}
void Screen::forceDisplay()
@@ -770,6 +812,9 @@ int32_t Screen::runOnce()
case Cmd::START_BLUETOOTH_PIN_SCREEN:
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
break;
case Cmd::START_FIRMWARE_UPDATE_SCREEN:
handleStartFirmwareUpdateScreen();
break;
case Cmd::STOP_BLUETOOTH_PIN_SCREEN:
case Cmd::STOP_BOOT_SCREEN:
setFrames();
@@ -849,7 +894,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;
@@ -866,10 +915,12 @@ void Screen::setFrames()
// call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
#ifndef NO_ESP32
if (isWifiAvailable()) {
// call a method on debugInfoScreen object (for more details)
normalFrames[numframes++] = &Screen::drawDebugInfoWiFiTrampoline;
}
#endif
ui.setFrames(normalFrames, numframes);
ui.enableAllIndicators();
@@ -894,9 +945,40 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
setFastFramerate();
}
void Screen::handleStartFirmwareUpdateScreen()
{
DEBUG_MSG("showing firmware screen\n");
showingNormalScreen = false;
static FrameCallback btFrames[] = {drawFrameFirmware};
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
}
void Screen::blink()
{
setFastFramerate();
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;
@@ -984,7 +1066,9 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
if (radioConfig.preferences.wifi_ap_mode) {
if (isSoftAPForced()) {
display->drawString(x, y, String("WiFi: Software AP (Admin)"));
} else if (radioConfig.preferences.wifi_ap_mode) {
display->drawString(x, y, String("WiFi: Software AP"));
} else if (WiFi.status() != WL_CONNECTED) {
display->drawString(x, y, String("WiFi: Not Connected"));
@@ -1007,13 +1091,17 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
- WL_NO_SHIELD: assigned when no WiFi shield is present;
*/
if (WiFi.status() == WL_CONNECTED) {
if (radioConfig.preferences.wifi_ap_mode) {
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()));
}
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
} else if (WiFi.status() == WL_CONNECTION_LOST) {
@@ -1088,10 +1176,23 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
}
}
if ((millis() / 10000) % 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
if (isSoftAPForced()) {
if ((millis() / 10000) % 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: meshtasticAdmin");
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: 12345678");
}
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw));
if (radioConfig.preferences.wifi_ap_mode) {
if ((millis() / 10000) % 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw));
}
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
}
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local");
@@ -1185,8 +1286,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
if (showingNormalScreen &&
nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens
}
nodeDB.updateGUI = false;

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}); }
@@ -126,6 +128,14 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
void startFirmwareUpdateScreen()
{
ScreenCmd cmd;
cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN;
enqueueCmd(cmd);
}
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -231,6 +241,7 @@ class Screen : public concurrency::OSThread
void handleOnPress();
void handleStartBluetoothPinScreen(uint32_t pin);
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();

View File

@@ -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

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

View File

@@ -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"
@@ -18,8 +19,7 @@
#include "concurrency/Periodic.h"
#include "graphics/Screen.h"
#include "main.h"
#include "meshwifi/meshhttp.h"
#include "meshwifi/meshwifi.h"
#include "plugins/Plugins.h"
#include "sleep.h"
#include "target_specific.h"
#include <OneButton.h>
@@ -27,6 +27,8 @@
// #include <driver/rtc_io.h>
#ifndef NO_ESP32
#include "mesh/http/WebServer.h"
#include "mesh/http/WiFiAPClient.h"
#include "nimble/BluetoothUtil.h"
#endif
@@ -92,6 +94,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
@@ -236,11 +239,12 @@ class ButtonThread : public OSThread
if (millis() - longPressTime > 10 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
setLed(false);
power->shutdown();
}
#endif
} else {
//DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
// DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
@@ -272,6 +276,8 @@ RadioInterface *rIf = NULL;
void setup()
{
concurrency::hasBeenSetup = true;
#ifdef SEGGER_STDOUT_CH
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
@@ -297,6 +303,25 @@ void setup()
digitalWrite(RESET_OLED, 1);
#endif
#ifdef BUTTON_PIN
#ifndef NO_ESP32
// If BUTTON_PIN is held down during the startup process,
// force the device to go into a SoftAP mode.
bool forceSoftAP = 0;
pinMode(BUTTON_PIN, INPUT);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif
// BUTTON_PIN is pulled high by a 12k resistor.
if (!digitalRead(BUTTON_PIN)) {
forceSoftAP = 1;
DEBUG_MSG("Setting forceSoftAP = 1\n");
}
#endif
#endif
OSThread::setup();
ledPeriodic = new Periodic("Blink", ledBlinker);
@@ -345,6 +370,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);
@@ -366,6 +395,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
@@ -403,8 +445,17 @@ void setup()
service.init();
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
// Now that the mesh service is created, create any plugins
setupPlugins();
// 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)
screen->setup();
#else
@@ -439,6 +490,8 @@ void setup()
DEBUG_MSG("Warning: Failed to find RF95 radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Radio init succeeded, using RF95 radio\n");
}
}
#endif
@@ -450,6 +503,8 @@ void setup()
DEBUG_MSG("Warning: Failed to find SX1262 radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Radio init succeeded, using SX1262 radio\n");
}
}
#endif
@@ -461,15 +516,25 @@ void setup()
DEBUG_MSG("Warning: Failed to find simulated radio\n");
delete rIf;
rIf = NULL;
} else {
DEBUG_MSG("Using SIMULATED radio!\n");
}
}
#endif
#ifndef NO_ESP32
// Initialize Wifi
initWifi();
initWifi(forceSoftAP);
// Start web server thread.
webServerThread = new WebServerThread();
#endif
// Start airtime logger thread.
airTime = new AirTime();
if (!rIf)
recordCriticalError(ErrNoRadio);
recordCriticalError(CriticalErrorCode_NoRadio);
else
router->addInterface(rIf);
@@ -528,7 +593,7 @@ void loop()
#endif
// TODO: This should go into a thread handled by FreeRTOS.
handleWebResponse();
// handleWebResponse();
service.loop();

View File

@@ -72,7 +72,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
addRoute(p->from, p->from, 0); // We are adjacent with zero hops
}
switch (p->decoded.which_payload) {
switch (p->decoded.which_payloadVariant) {
case SubPacket_route_request_tag:
// Handle route discovery packets (will be a broadcast message)
// FIXME - always start request with the senders nodenum
@@ -105,7 +105,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
// packets until ack arrives)
// FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own...
break;
case SubPacket_route_error_tag:
case SubPacket_error_reason_tag:
removeRoute(p->decoded.dest);
// FIXME: if any pending packets were waiting on this route, delete them
@@ -131,7 +131,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
assert(p->decoded.source); // I think this is guaranteed by now
// FIXME - what if the current packet _is_ a route error packet?
sendRouteError(p, RouteError_NO_ROUTE);
sendRouteError(p, ErrorReason_NO_ROUTE);
}
// FIXME, stop local processing of this packet
@@ -139,13 +139,13 @@ void DSRRouter::sniffReceived(const MeshPacket *p)
// handle naks - convert them to route error packets
// All naks are generated locally, because we failed resending the packet too many times
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
if (nakId) {
auto pending = findPendingPacket(p->to, nakId);
if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore
removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node
sendRouteError(p, RouteError_GOT_NAK);
sendRouteError(p, ErrorReason_GOT_NAK);
}
}
}
@@ -170,7 +170,7 @@ bool DSRRouter::weAreInRoute(const RouteDiscovery &route)
**/
void DSRRouter::updateRoutes(const RouteDiscovery &route, bool isRequest)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented updateRoutes\n");
}
/**
@@ -178,7 +178,7 @@ void DSRRouter::updateRoutes(const RouteDiscovery &route, bool isRequest)
*/
void DSRRouter::sendRouteReply(const RouteDiscovery &route, NodeNum toAppend)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented sendRoute\n");
}
/**
@@ -188,7 +188,7 @@ void DSRRouter::sendRouteReply(const RouteDiscovery &route, NodeNum toAppend)
*/
NodeNum DSRRouter::getNextHop(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented getNextHop\n");
return 0;
}
@@ -198,7 +198,7 @@ NodeNum DSRRouter::getNextHop(NodeNum dest)
*/
void DSRRouter::resendRouteRequest(const MeshPacket *p)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented resendRoute\n");
}
/**
@@ -208,7 +208,7 @@ void DSRRouter::resendRouteRequest(const MeshPacket *p)
*/
void DSRRouter::addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented addRoute\n");
}
/**
@@ -216,7 +216,7 @@ void DSRRouter::addRoute(NodeNum dest, NodeNum forwarder, uint8_t numHops)
*/
void DSRRouter::removeRoute(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented removeRoute\n");
}
/**
@@ -224,15 +224,15 @@ void DSRRouter::removeRoute(NodeNum dest)
*/
void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented sendNextHop\n");
}
/**
* Send a route error packet towards whoever originally sent this message
*/
void DSRRouter::sendRouteError(const MeshPacket *p, RouteError err)
void DSRRouter::sendRouteError(const MeshPacket *p, ErrorReason err)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented sendRouteError\n");
}
/** make a copy of p, start discovery, but only if we don't
@@ -241,5 +241,5 @@ void DSRRouter::sendRouteError(const MeshPacket *p, RouteError err)
*/
void DSRRouter::startDiscovery(NodeNum dest)
{
DEBUG_MSG("FIXME not implemented");
DEBUG_MSG("FIXME not implemented startDiscovery\n");
}

View File

@@ -70,7 +70,7 @@ class DSRRouter : public ReliableRouter
/**
* Send a route error packet towards whoever originally sent this message
*/
void sendRouteError(const MeshPacket *p, RouteError err);
void sendRouteError(const MeshPacket *p, ErrorReason err);
/** make a copy of p, start discovery, but only if we don't
* already a discovery in progress for that node number. Caller has already scheduled this message for retransmission

View File

@@ -20,8 +20,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
DEBUG_MSG("Ignoring incoming msg, because we've already seen it: fr=0x%x,to=0x%x,id=%d,hop_limit=%d\n", p->from, p->to,
p->id, p->hop_limit);
printPacket("Ignoring incoming msg, because we've already seen it", p);
return true;
}
@@ -38,8 +37,7 @@ void FloodingRouter::sniffReceived(const MeshPacket *p)
tosend->hop_limit--; // bump down the hop count
DEBUG_MSG("Rebroadcasting received floodmsg to neighbors, fr=0x%x,to=0x%x,id=%d,hop_limit=%d\n", p->from, p->to,
p->id, tosend->hop_limit);
printPacket("Rebroadcasting received floodmsg to neighbors", p);
// Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend);

View File

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

View File

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

View File

@@ -5,6 +5,8 @@
std::vector<MeshPlugin *> *MeshPlugin::plugins;
const MeshPacket *MeshPlugin::currentRequest;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
@@ -25,23 +27,30 @@ MeshPlugin::~MeshPlugin()
void MeshPlugin::callPlugins(const MeshPacket &mp)
{
// DEBUG_MSG("In call plugins\n");
bool pluginFound = false;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
pi.currentRequest = &mp;
if (pi.wantPortnum(mp.decoded.data.portnum)) {
pluginFound = true;
bool handled = pi.handleReceived(mp);
// Possibly send replies (unless we are handling a locally generated message)
if (mp.decoded.want_response && mp.from != nodeDB.getNodeNum())
// Possibly send replies
if (mp.decoded.want_response)
pi.sendResponse(mp);
DEBUG_MSG("Plugin %s handled=%d\n", pi.name, handled);
if (handled)
break;
}
else {
DEBUG_MSG("Plugin %s not interested\n", pi.name);
}
pi.currentRequest = NULL;
}
if(!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.data.portnum);
}
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked

View File

@@ -31,6 +31,15 @@ class MeshPlugin
protected:
const char *name;
/**
* If this plugin is currently handling a request currentRequest will be preset
* to the packet with the request. This is mostly useful for reply handlers.
*
* Note: this can be static because we are guaranteed to be processing only one
* plugin at a time.
*/
static const MeshPacket *currentRequest;
/**
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
* been initialized

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

@@ -51,14 +51,7 @@ MeshService service;
#include "Router.h"
static int32_t sendOwnerCb()
{
nodeInfoPlugin.sendOurNodeInfo();
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
}
static concurrency::Periodic *sendOwnerPeriod;
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
{
@@ -67,9 +60,8 @@ MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
void MeshService::init()
{
sendOwnerPeriod = new concurrency::Periodic("SendOwner", sendOwnerCb);
nodeDB.init();
// moved much earlier in boot (called from setup())
// nodeDB.init();
if (gps)
gpsObserver.observe(&gps->newStatus);
@@ -125,7 +117,8 @@ bool MeshService::reloadConfig()
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void MeshService::reloadOwner()
{
nodeInfoPlugin.sendOurNodeInfo();
assert(nodeInfoPlugin);
nodeInfoPlugin->sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -158,22 +151,15 @@ void MeshService::handleToRadio(MeshPacket &p)
}
}
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool MeshService::cancelSending(PacketId id) {
return router->cancelSending(nodeDB.getNodeNum(), id);
}
void MeshService::sendToMesh(MeshPacket *p)
{
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
// devices can get time.
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag &&
p->decoded.position.time) {
if (getRTCQuality() < RTCQualityGPS) {
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
p->decoded.position.time = 0;
} else
DEBUG_MSG("Providing time to mesh %u\n", p->decoded.position.time);
}
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
router->sendLocal(p);
}
@@ -184,17 +170,40 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
assert(node);
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
assert(positionPlugin && nodeInfoPlugin);
if (node->has_position)
positionPlugin.sendOurPosition(dest, wantReplies);
positionPlugin->sendOurPosition(dest, wantReplies);
else
nodeInfoPlugin.sendOurNodeInfo(dest, wantReplies);
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
NodeInfo *MeshService::refreshMyNodeInfo() {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
// We might not have a position yet for our local node, in that case, at least try to send the time
if(!node->has_position) {
memset(&node->position, 0, sizeof(node->position));
node->has_position = true;
}
Position &position = node->position;
// Update our local node info with our position (even if we don't decide to update anyone else)
position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
position.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(position.battery_level);
return node;
}
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
{
// Update our local node info with our position (even if we don't decide to update anyone else)
Position pos = Position_init_default;
NodeInfo *node = refreshMyNodeInfo();
Position pos = node->position;
if (gps->hasLock()) {
if (gps->altitude != 0)
@@ -206,33 +215,19 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
if(radioConfig.preferences.fixed_position) {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
pos = node->position;
DEBUG_MSG("WARNING: Using fixed position\n");
} else {
// throw away old position
pos.latitude_i = 0;
pos.longitude_i = 0;
pos.altitude = 0;
}
}
pos.time = getValidTime(RTCQualityGPS);
// Include our current battery voltage in our position announcement
pos.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(pos.battery_level);
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.time, pos.latitude_i, pos.battery_level);
// Update our current position in the local DB
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
lastGpsSend = now;
DEBUG_MSG("Sending position to mesh (not requesting replies)\n");
positionPlugin.sendOurPosition();
}
return 0;
}

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.
@@ -80,6 +79,12 @@ class MeshService
/// cache
void sendToMesh(MeshPacket *p);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id);
/// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo();
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh

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;
@@ -13,6 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number
#define ERRNO_OK 0
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
#define ERRNO_DISABLED 34 // the itnerface is disabled
/**
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.

View File

@@ -5,7 +5,9 @@
#include "FS.h"
#include "CryptoEngine.h"
#include "FSCommon.h"
#include "GPS.h"
#include "main.h"
#include "MeshRadio.h"
#include "NodeDB.h"
#include "PacketHistory.h"
@@ -15,11 +17,13 @@
#include "configuration.h"
#include "error.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "FSCommon.h"
#include <pb_decode.h>
#include <pb_encode.h>
#ifndef NO_ESP32
#include "mesh/http/WiFiAPClient.h"
#endif
NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now)
@@ -28,6 +32,11 @@ MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig &radioConfig = devicestate.radio;
ChannelSettings &channelSettings = radioConfig.channel_settings;
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel.
*/
uint32_t radioGeneration;
/*
DeviceState versions used to be defined in the .proto file but really only this function cares. So changed to a
#define here.
@@ -36,8 +45,6 @@ DeviceState versions used to be defined in the .proto file but really only this
#define DEVICESTATE_CUR_VER 11
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
// FIXME - move this somewhere else
extern void getMacAddr(uint8_t *dmac);
@@ -57,16 +64,24 @@ static uint8_t ourMacAddr[6];
*/
NodeNum displayedNodeNum;
/// A usable (but bigger) version of the channel name in the channelSettings object
const char *channelName;
/// A usable psk - which has been constructed based on the (possibly short psk) in channelSettings
static uint8_t activePSK[32];
static uint8_t activePSKSize;
/**
* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
their nodes
* aren't talking to each other.
*
* This string is of the form "#name-XY".
* This string is of the form "#name-X".
*
* Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together.
* Y is not yet used but should eventually indicate 'speed/range' of the link
* Where X is either:
* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together,
* OR (for the standard minimially secure PSKs) a number from 0 to 9.
*
* This function will also need to be implemented in GUI apps that talk to the radio.
*
@@ -76,11 +91,19 @@ const char *getChannelName()
{
static char buf[32];
uint8_t code = 0;
for (int i = 0; i < channelSettings.psk.size; i++)
code ^= channelSettings.psk.bytes[i];
char suffix;
if (channelSettings.psk.size != 1) {
// We have a standard PSK, so generate a letter based hash.
uint8_t code = 0;
for (int i = 0; i < activePSKSize; i++)
code ^= activePSK[i];
snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, 'A' + (code % 26));
suffix = 'A' + (code % 26);
} else {
suffix = '0' + channelSettings.psk.bytes[0];
}
snprintf(buf, sizeof(buf), "#%s-%c", channelName, suffix);
return buf;
}
@@ -90,6 +113,8 @@ bool NodeDB::resetRadioConfig()
{
bool didFactoryReset = false;
radioGeneration++;
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
@@ -110,13 +135,84 @@ bool NodeDB::resetRadioConfig()
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 0; // default
memcpy(&channelSettings.psk.bytes, defaultpsk, sizeof(channelSettings.psk));
channelSettings.psk.size = sizeof(defaultpsk);
strcpy(channelSettings.name, "Default");
uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1;
strcpy(channelSettings.name, "");
}
// Convert the old string "Default" to our new short representation
if (strcmp(channelSettings.name, "Default") == 0)
*channelSettings.name = '\0';
// Convert the short "" representation for Default into a usable string
channelName = channelSettings.name;
if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case
// the app fucked up and forgot to set channelSettings.name
if (channelSettings.bandwidth != 0)
channelName = "Unset";
else
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128:
channelName = "Medium";
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128:
channelName = "ShortFast";
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512:
channelName = "LongAlt";
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
channelName = "LongSlow";
break;
default:
channelName = "Invalid";
break;
}
}
// Convert any old usage of the defaultpsk into our new short representation.
if (channelSettings.psk.size == sizeof(defaultpsk) &&
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
*channelSettings.psk.bytes = 1;
channelSettings.psk.size = 1;
}
memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros
memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size);
activePSKSize = channelSettings.psk.size;
if(activePSKSize == 0)
DEBUG_MSG("Warning: User disabled encryption\n");
else if (activePSKSize == 1) {
// Convert the short single byte variants of psk into variant that can be used more generally
uint8_t pskIndex = activePSK[0];
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
if (pskIndex == 0)
activePSKSize = 0; // Turn off encryption
else {
memcpy(activePSK, defaultpsk, sizeof(defaultpsk));
activePSKSize = sizeof(defaultpsk);
// Bump up the last byte of PSK as needed
uint8_t *last = activePSK + sizeof(defaultpsk) - 1;
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
}
} else if(activePSKSize < 16) {
// Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key
// with zeros
DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n");
activePSKSize = 16;
} else if(activePSKSize < 32 && activePSKSize != 16) {
// Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key
// with zeros
DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n");
activePSKSize = 32;
}
// Tell our crypto engine about the psk
crypto->setKey(channelSettings.psk.size, channelSettings.psk.bytes);
crypto->setKey(activePSKSize, activePSK);
// temp hack for quicker testing
// devicestate.no_save = true;
@@ -169,16 +265,15 @@ void NodeDB::installDefaultDeviceState()
// Init our blank owner info to reasonable defaults
getMacAddr(ourMacAddr);
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4],
ourMacAddr[5]);
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Set default owner name
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid
// owner.short_name now
pickNewNodeNum(); // based on macaddr now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff));
sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
// Restore region if possible
if (oldRegionCode != RegionCode_Unset)
radioConfig.preferences.region = oldRegionCode;
@@ -199,9 +294,13 @@ 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
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
pickNewNodeNum();
@@ -426,7 +525,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p)
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp)
{
if (mp.which_payload == MeshPacket_decoded_tag) {
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
const SubPacket &p = mp.decoded;
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
@@ -439,7 +538,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
switch (p.which_payload) {
switch (p.which_payloadVariant) {
case SubPacket_position_tag: {
// handle a legacy position packet
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from);
@@ -498,8 +597,14 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address)
{
DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address);
// Print error to screen and serial port
String lcd = String("Critical error ") + code + "!\n";
screen->print(lcd.c_str());
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
// Record error to DB
myNodeInfo.error_code = code;
myNodeInfo.error_address = address;
myNodeInfo.error_count++;
}

View File

@@ -13,6 +13,7 @@ extern MyNodeInfo &myNodeInfo;
extern RadioConfig &radioConfig;
extern ChannelSettings &channelSettings;
extern User &owner;
extern const char *channelName;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
uint32_t sinceLastSeen(const NodeInfo *n);
@@ -146,23 +147,58 @@ 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)
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel.
*/
extern uint32_t radioGeneration;

View File

@@ -6,17 +6,34 @@
#include "RadioInterface.h"
#include <assert.h>
PhoneAPI::PhoneAPI()
{
assert(FromRadio_size <= MAX_TO_FROM_RADIO_SIZE);
assert(ToRadio_size <= MAX_TO_FROM_RADIO_SIZE);
}
#if FromRadio_size > MAX_TO_FROM_RADIO_SIZE
#error FromRadio is too big
#endif
#if ToRadio_size > MAX_TO_FROM_RADIO_SIZE
#error ToRadio is too big
#endif
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) {
@@ -42,15 +59,15 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
// return (lastContactMsec != 0) &&
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_variant) {
switch (toRadioScratch.which_payloadVariant) {
case ToRadio_packet_tag: {
MeshPacket &p = toRadioScratch.variant.packet;
MeshPacket &p = toRadioScratch.packet;
printPacket("PACKET FROM PHONE", &p);
service.handleToRadio(p);
break;
}
case ToRadio_want_config_id_tag:
config_nonce = toRadioScratch.variant.want_config_id;
config_nonce = toRadioScratch.want_config_id;
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
state = STATE_SEND_MY_INFO;
@@ -62,12 +79,12 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
case ToRadio_set_owner_tag:
DEBUG_MSG("Client is setting owner\n");
handleSetOwner(toRadioScratch.variant.set_owner);
handleSetOwner(toRadioScratch.set_owner);
break;
case ToRadio_set_radio_tag:
DEBUG_MSG("Client is setting radio\n");
handleSetRadio(toRadioScratch.variant.set_radio);
handleSetRadio(toRadioScratch.set_radio);
break;
default:
@@ -95,11 +112,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
{
if (!available()) {
// DEBUG_MSG("getFromRadio, !available\n");
return false;
} else {
DEBUG_MSG("getFromRadio, state=%d\n", state);
return 0;
}
DEBUG_MSG("getFromRadio, state=%d\n", state);
// In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
@@ -114,20 +131,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled)
? true
: (gps && gps->isConnected()); // Update with latest GPS connect info
fromRadioScratch.which_variant = FromRadio_my_info_tag;
fromRadioScratch.variant.my_info = myNodeInfo;
fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag;
fromRadioScratch.my_info = myNodeInfo;
state = STATE_SEND_RADIO;
service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon.
break;
case STATE_SEND_RADIO:
fromRadioScratch.which_variant = FromRadio_radio_tag;
fromRadioScratch.which_payloadVariant = FromRadio_radio_tag;
fromRadioScratch.variant.radio = radioConfig;
fromRadioScratch.radio = radioConfig;
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
fromRadioScratch.variant.radio.preferences.ls_secs = getPref_ls_secs();
fromRadioScratch.radio.preferences.ls_secs = getPref_ls_secs();
state = STATE_SEND_NODEINFO;
break;
@@ -139,8 +158,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
if (info) {
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
info->user.long_name);
fromRadioScratch.which_variant = FromRadio_node_info_tag;
fromRadioScratch.variant.node_info = *info;
fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag;
fromRadioScratch.node_info = *info;
// Stay in current state until done sending nodeinfos
} else {
DEBUG_MSG("Done sending nodeinfos\n");
@@ -152,8 +171,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
case STATE_SEND_COMPLETE_ID:
fromRadioScratch.which_variant = FromRadio_config_complete_id_tag;
fromRadioScratch.variant.config_complete_id = config_nonce;
fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag;
fromRadioScratch.config_complete_id = config_nonce;
config_nonce = 0;
state = STATE_SEND_PACKETS;
break;
@@ -162,9 +181,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_PACKETS:
// Do we have a message from the mesh?
if (packetForPhone) {
printPacket("phone downloaded packet", packetForPhone);
// Encapsulate as a FromRadio packet
fromRadioScratch.which_variant = FromRadio_packet_tag;
fromRadioScratch.variant.packet = *packetForPhone;
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
fromRadioScratch.packet = *packetForPhone;
service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore
packetForPhone = NULL;
@@ -176,9 +198,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
}
// Do we have a message from the mesh?
if (fromRadioScratch.which_variant != 0) {
if (fromRadioScratch.which_payloadVariant != 0) {
// Encapsulate as a FromRadio packet
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_variant);
DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant);
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
DEBUG_MSG(", %d bytes\n", numbytes);
return numbytes;
@@ -212,11 +234,14 @@ bool PhoneAPI::available()
return true;
case STATE_LEGACY: // Treat as the same as send packets
case STATE_SEND_PACKETS:
case STATE_SEND_PACKETS: {
// Try to pull a new packet from the service (if we haven't already)
if (!packetForPhone)
packetForPhone = service.getForPhone();
return !!packetForPhone;
bool hasPacket = !!packetForPhone;
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
return hasPacket;
}
default:
assert(0); // unexpected state - FIXME, make an error code and reboot

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

@@ -55,11 +55,11 @@ template <class T> class ProtobufPlugin : private SinglePortPlugin
// it would be better to update even if the message was destined to others.
auto &p = mp.decoded.data;
DEBUG_MSG("Received %s from=0x%0x, id=%d, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
T scratch;
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
handleReceivedProtobuf(mp, scratch);
return handleReceivedProtobuf(mp, scratch);
return false; // Let others look at this message also if they want
}

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

@@ -83,7 +83,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl)
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
{
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
return getPacketTime(pl);
@@ -119,11 +119,11 @@ void printPacket(const char *prefix, const MeshPacket *p)
{
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
p->hop_limit);
if (p->which_payload == MeshPacket_decoded_tag) {
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
auto &s = p->decoded;
switch (s.which_payload) {
switch (s.which_payloadVariant) {
case SubPacket_data_tag:
DEBUG_MSG(" Payload:Data");
DEBUG_MSG(" Portnum=%d", s.data.portnum);
break;
case SubPacket_position_tag:
DEBUG_MSG(" Payload:Position");
@@ -135,7 +135,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
DEBUG_MSG(" Payload:None");
break;
default:
DEBUG_MSG(" Payload:%d", s.which_payload);
DEBUG_MSG(" Payload:%d", s.which_payloadVariant);
break;
}
if (s.want_response)
@@ -147,10 +147,10 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (s.dest != 0)
DEBUG_MSG(" dest=%08x", s.dest);
if (s.which_ack == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ack.success_id);
else if (s.which_ack == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ack.fail_id);
if (s.which_ackVariant == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
else if (s.which_ackVariant == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id);
} else {
DEBUG_MSG(" encrypted");
}
@@ -161,6 +161,9 @@ void printPacket(const char *prefix, const MeshPacket *p)
if (p->rx_snr != 0.0) {
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
}
if(p->priority != 0)
DEBUG_MSG(" priority=%d", p->priority);
DEBUG_MSG(")\n");
}
@@ -209,6 +212,38 @@ unsigned long hash(const char *str)
return hash;
}
/**
* Save our frequency for later reuse.
*/
void RadioInterface::saveFreq(float freq)
{
savedFreq = freq;
}
/**
* Save our channel for later reuse.
*/
void RadioInterface::saveChannelNum(uint32_t channel_num)
{
savedChannelNum = channel_num;
}
/**
* Save our frequency for later reuse.
*/
float RadioInterface::getFreq()
{
return savedFreq;
}
/**
* Save our channel for later reuse.
*/
uint32_t RadioInterface::getChannelNum()
{
return savedChannelNum;
}
/**
* Pull our channel settings etc... from protobufs to the dumb interface settings
*/
@@ -261,18 +296,19 @@ void RadioInterface::applyModemConfig()
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
int channel_num =
(channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelSettings.name)) % myRegion->numChannels;
int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels;
freq = myRegion->freq + myRegion->spacing * channel_num;
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
power);
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", freq);
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
saveChannelNum(channel_num);
saveFreq(freq);
}
/**
@@ -315,7 +351,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
assert(!sendingPacket);
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
lastTxStart = millis();

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;
@@ -54,6 +54,8 @@ class RadioInterface
uint32_t shortPacketMsec;
protected:
bool disabled = false;
float bw = 125;
uint8_t sf = 9;
uint8_t cr = 7;
@@ -98,6 +100,9 @@ class RadioInterface
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() { return true; }
/// Disable this interface (while disabled, no packets can be sent or received)
void disable() { disabled = true; sleep(); }
/**
* Send a packet (possibly by enquing in a private fifo). This routine will
* later free() the packet to pool. This routine is not allowed to stall.
@@ -105,6 +110,9 @@ class RadioInterface
*/
virtual ErrorCode send(MeshPacket *p) = 0;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id) { return false; }
// methods from radiohead
/// Initialise the Driver transport hardware and software.
@@ -133,9 +141,22 @@ class RadioInterface
uint32_t getPacketTime(MeshPacket *p);
uint32_t getPacketTime(uint32_t totalPacketLen);
/**
* Get the channel we saved.
*/
uint32_t getChannelNum();
/**
* Get the frequency we saved.
*/
float getFreq();
protected:
int8_t power = 17; // Set by applyModemConfig()
float savedFreq;
uint32_t savedChannelNum;
/***
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
* PacketHeader & payload).
@@ -157,6 +178,16 @@ class RadioInterface
*/
virtual void applyModemConfig();
/**
* Save the frequency we selected for later reuse.
*/
virtual void saveFreq(float savedFreq);
/**
* Save the chanel we selected for later reuse.
*/
virtual void saveChannelNum(uint32_t savedChannelNum);
private:
/// Return 0 if sleep is okay
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }

View File

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

View File

@@ -2,6 +2,7 @@
#include "../concurrency/OSThread.h"
#include "RadioInterface.h"
#include "MeshPacketQueue.h"
#ifdef CubeCell_BoardPlus
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
@@ -74,7 +75,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
protected:
@@ -136,6 +137,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
*/
virtual bool isActivelyReceiving() = 0;
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
virtual bool cancelSending(NodeNum from, PacketId id);
private:
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
* the transmit

View File

@@ -34,7 +34,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
// the original sending process.
if (stopRetransmission(p->from, p->id)) {
DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n");
sendAckNak(true, p->from, p->id);
sendAckNak(ErrorReason_NONE, p->from, p->id);
}
}
@@ -60,13 +60,13 @@ void ReliableRouter::sniffReceived(const MeshPacket *p)
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
// - not DSR routing)
if (p->want_ack) {
sendAckNak(true, p->from, p->id);
sendAckNak(ErrorReason_NONE, p->from, p->id);
}
// If the payload is valid, look for ack/nak
PacketId ackId = p->decoded.which_ack == SubPacket_success_id_tag ? p->decoded.ack.success_id : 0;
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
PacketId ackId = p->decoded.which_ackVariant == SubPacket_success_id_tag ? p->decoded.ackVariant.success_id : 0;
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) {
@@ -84,27 +84,6 @@ void ReliableRouter::sniffReceived(const MeshPacket *p)
FloodingRouter::sniffReceived(p);
}
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void ReliableRouter::sendAckNak(bool isAck, NodeNum to, PacketId idFrom)
{
auto p = allocForSending();
p->hop_limit = 0; // Assume just immediate neighbors for now
p->to = to;
DEBUG_MSG("Sending an ack=0x%x,to=0x%x,idFrom=%d,id=%d\n", isAck, to, idFrom, p->id);
if (isAck) {
p->decoded.ack.success_id = idFrom;
p->decoded.which_ack = SubPacket_success_id_tag;
} else {
p->decoded.ack.fail_id = idFrom;
p->decoded.which_ack = SubPacket_fail_id_tag;
}
sendLocal(p); // we sometimes send directly to the local node
}
#define NUM_RETRANSMISSIONS 3
PendingPacket::PendingPacket(MeshPacket *p)
@@ -176,7 +155,7 @@ int32_t ReliableRouter::doRetransmissions()
if (p.numRetransmissions == 0) {
DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to,
p.packet->id);
sendAckNak(false, p.packet->from, p.packet->id);
sendAckNak(ErrorReason_MAX_RETRANSMIT, p.packet->from, p.packet->id);
// Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which
// allows the DSR version to still be able to look at the PendingPacket
stopRetransmission(it->first);

View File

@@ -109,10 +109,6 @@ class ReliableRouter : public FloodingRouter
PendingPacket *startRetransmission(MeshPacket *p);
private:
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(bool isAck, NodeNum to, PacketId idFrom);
/**
* Stop any retransmissions we are doing of the specified node/packet ID pair

View File

@@ -88,24 +88,70 @@ MeshPacket *Router::allocForSending()
{
MeshPacket *p = packetPool.allocZeroed();
p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST;
p->hop_limit = HOP_RELIABLE;
p->id = generatePacketId();
p->rx_time = getValidTime(RTCQualityFromNet); // Just in case we process the packet locally - make sure it has a valid timestamp
p->rx_time =
getValidTime(RTCQualityFromNet); // Just in case we process the packet locally - make sure it has a valid timestamp
return p;
}
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom)
{
auto p = allocForSending();
p->hop_limit = 0; // Assume just immediate neighbors for now
p->to = to;
DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
if (!err) {
p->decoded.ackVariant.success_id = idFrom;
p->decoded.which_ackVariant = SubPacket_success_id_tag;
} else {
p->decoded.ackVariant.fail_id = idFrom;
p->decoded.which_ackVariant = SubPacket_fail_id_tag;
// Also send back the error reason
p->decoded.which_payloadVariant = SubPacket_error_reason_tag;
p->decoded.error_reason = err;
}
p->priority = MeshPacket_Priority_ACK;
sendLocal(p); // we sometimes send directly to the local node
}
ErrorCode Router::sendLocal(MeshPacket *p)
{
// No need to deliver externally if the destination is the local node
if (p->to == nodeDB.getNodeNum()) {
DEBUG_MSG("Enqueuing internal message for the receive queue\n");
printPacket("Enqueuing local", p);
fromRadioQueue.enqueue(p);
return ERRNO_OK;
} else
} else if (!iface) {
// We must be sending to remote nodes also, fail if no interface found
// ERROR! no radio found, report failure back to the client and drop the packet
DEBUG_MSG("Error: No interface, returning NAK and dropping packet.\n");
sendAckNak(ErrorReason_NO_INTERFACE, p->from, p->id);
packetPool.release(p);
return ERRNO_NO_INTERFACES;
} else {
// If we are sending a broadcast, we also treat it as if we just received it ourself
// this allows local apps (and PCs) to see broadcasts sourced locally
if (p->to == NODENUM_BROADCAST) {
handleReceived(p);
}
return send(p);
}
}
/**
@@ -117,7 +163,7 @@ ErrorCode Router::send(MeshPacket *p)
{
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0;
PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
assert(
!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert
@@ -127,11 +173,11 @@ ErrorCode Router::send(MeshPacket *p)
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
assert(p->which_payload == MeshPacket_encrypted_tag ||
p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
p->which_payloadVariant == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now
// First convert from protobufs to raw bytes
if (p->which_payload == MeshPacket_decoded_tag) {
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded);
@@ -142,19 +188,27 @@ ErrorCode Router::send(MeshPacket *p)
// Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes);
p->encrypted.size = numbytes;
p->which_payload = MeshPacket_encrypted_tag;
p->which_payloadVariant = MeshPacket_encrypted_tag;
}
if (iface) {
// DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
return iface->send(p);
} else {
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
// if (iface) {
// DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
return iface->send(p);
/* } else {
DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
packetPool.release(p);
return ERRNO_NO_INTERFACES;
}
} */
}
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool Router::cancelSending(NodeNum from, PacketId id) {
return iface ? iface->cancelSending(from, id) : false;
}
/**
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
@@ -167,10 +221,10 @@ void Router::sniffReceived(const MeshPacket *p)
bool Router::perhapsDecode(MeshPacket *p)
{
if (p->which_payload == MeshPacket_decoded_tag)
if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return
assert(p->which_payload == MeshPacket_encrypted_tag);
assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
// FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without
// being able to decrypt their data.
@@ -186,7 +240,7 @@ bool Router::perhapsDecode(MeshPacket *p)
return false;
} else {
// parsing was successful
p->which_payload = MeshPacket_decoded_tag;
p->which_payloadVariant = MeshPacket_decoded_tag;
return true;
}
}

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.
@@ -49,13 +48,19 @@ class Router : protected concurrency::OSThread
virtual int32_t runOnce();
/**
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue
* Works like send, but if we are sending to the local node, we directly put the message in the receive queue.
* This is the primary method used for sending packets, because it handles both the remote and local cases.
*
* NOTE: This method will free the provided packet (even if we return an error code)
*/
ErrorCode sendLocal(MeshPacket *p);
/// Allocate and return a meshpacket which defaults as send to broadcast from the current node.
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool cancelSending(NodeNum from, PacketId id);
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
* The returned packet is guaranteed to have a unique packet ID already assigned
*/
MeshPacket *allocForSending();
/**
@@ -93,6 +98,11 @@ class Router : protected concurrency::OSThread
*/
bool perhapsDecode(MeshPacket *p);
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
void sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom);
private:
/**
* Called from loop()

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

@@ -32,7 +32,7 @@ class SinglePortPlugin : public MeshPlugin
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending();
p->decoded.which_payload = SubPacket_data_tag;
p->decoded.which_payloadVariant = SubPacket_data_tag;
p->decoded.data.portnum = ourPortNum;
return p;

View File

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

View File

@@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "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)

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