Compare commits

...

432 Commits
0.1.0 ... 0.6.4

Author SHA1 Message Date
Kevin Hester
1897d4703c Merge pull request #142 from geeksville/reliable
Reliable messages now also work for broadcasts
2020-05-21 17:55:31 -07:00
geeksville
a25cead7d7 Merge remote-tracking branch 'root/master' into reliable 2020-05-21 17:51:50 -07:00
geeksville
3d919b21f6 0.6.4 2020-05-21 17:51:35 -07:00
geeksville
d2de04d5b2 Fix #59 no need for broadcasts when showing new node pane 2020-05-21 17:21:44 -07:00
Kevin Hester
a753c942b9 Merge pull request #141 from geeksville/reliable
Reliable
2020-05-21 16:46:01 -07:00
geeksville
9dd88281af reliable broadcast now works 2020-05-21 16:34:16 -07:00
geeksville
e75561016b retransmissions work again 2020-05-21 15:55:57 -07:00
geeksville
e2cbccb133 add want_ack support for broadcast packets 2020-05-21 12:47:41 -07:00
geeksville
0271df0657 add beginnings of full DSR routing 2020-05-21 12:47:08 -07:00
Kevin Hester
e05e324a7c Merge pull request #136 from geeksville/reliable
WIP for reliable unicast and BLE software update
2020-05-19 16:09:06 -07:00
geeksville
71041e8674 reliable unicast 1 hop works! 2020-05-19 15:51:07 -07:00
geeksville
c65b518432 less logspam 2020-05-19 14:54:58 -07:00
geeksville
6ba960ce47 one hop reliable ready for testing 2020-05-19 14:54:47 -07:00
geeksville
8bf4919576 wip reliable unicast (1 hop) 2020-05-19 11:56:17 -07:00
geeksville
cca4867987 want_ack flag added 2020-05-19 10:27:28 -07:00
geeksville
7aa47cf93b Merge remote-tracking branch 'root/master' into reliable 2020-05-19 10:20:34 -07:00
Kevin Hester
3089de79ee thanks @dafeman for documentation updates!
README GUI update
2020-05-19 07:31:43 -07:00
Dafeman
6b020149f3 Update GUI Install 2020-05-19 13:50:07 +12:00
Dafeman
34fae52e98 Merge pull request #2 from meshtastic/master
Update
2020-05-19 13:30:21 +12:00
geeksville
976bdad067 sniffReceived now allows router to inspect packets not destined for this node 2020-05-18 17:57:58 -07:00
geeksville
26d3ef529e Use the hop_limit field of MeshPacket to limit max delivery depth in
the mesh.
2020-05-18 17:35:23 -07:00
geeksville
53c3d9baa2 doc updates 2020-05-18 17:02:51 -07:00
Kevin Hester
2a6858fa34 Update CNAME 2020-05-18 08:10:51 -07:00
Kevin Hester
5440cbec6a Update CNAME 2020-05-18 08:08:57 -07:00
geeksville
19f5a5ef79 oops - use correct battery shutoff voltage 2020-05-17 05:12:16 -07:00
geeksville
ef831a0b4d Fix leaving display on in deep sleep.
We shutoff screen immediately, rather than waiting for our loop call()
2020-05-17 05:11:32 -07:00
geeksville
efc239533c Fix #133 - force deep sleep if battery reaches 10% 2020-05-17 05:10:51 -07:00
geeksville
ef1463a6a9 have tbeam charge at max rate (450mA) 2020-05-17 04:44:48 -07:00
geeksville
95e952b896 todo update 2020-05-16 16:09:06 -07:00
geeksville
db72faca5e Merge remote-tracking branch 'root/master' 2020-05-15 11:25:47 -07:00
geeksville
6961853ed7 ble software update fixes 2020-05-15 10:16:10 -07:00
geeksville
5ec5248fe4 complete ble ota move 2020-05-14 14:22:11 -07:00
geeksville
14fdd33972 move bluetooth OTA back into main tree for now 2020-05-14 14:20:05 -07:00
geeksville
140e29840a fix rare gurumeditation if we are unlucky and some ISR code is in serial flash 2020-05-14 12:46:29 -07:00
Kevin Hester
d1d318fad5 Merge pull request #135 from mehuman/supported-hardware
Supported hardware README updates
2020-05-13 08:22:23 -07:00
Mark Huson
dfb6c0bb20 Merge branch 'master' into supported-hardware 2020-05-12 19:15:47 -07:00
Mark Huson
7339abbab5 Update README.md 2020-05-12 19:14:12 -07:00
Mark Huson
27db0e27e8 Update supported hardware 2020-05-12 19:11:16 -07:00
geeksville
a0b43b9a95 Send "unset" for hwver and swver if they were unset 2020-05-12 17:57:51 -07:00
geeksville
b6a202d68e runs again with new protobufs 2020-05-12 13:35:22 -07:00
Dafeman
125035d546 Merge pull request #1 from meshtastic/master
Update
2020-05-12 22:49:54 +12:00
geeksville
9f05ad2927 remove random delay hack from broadcast, since we now do that for all transmits 2020-05-11 16:19:44 -07:00
geeksville
86ae69d360 refactor so I can track and ignore recent packets of any type 2020-05-11 16:14:53 -07:00
geeksville
c12fb69ca2 update protos 2020-05-10 14:17:05 -07:00
geeksville
8b911aba7f Cleanup build for NRF52 targets 2020-05-10 12:33:17 -07:00
geeksville
2fa595523f minor fixups to get nrf52 building again 2020-05-09 21:02:56 -07:00
geeksville
190a3c2d6b filename typo 2020-05-09 20:27:08 -07:00
Kevin Hester
1bf9d052fc Merge pull request #132 from geeksville/crypto
Crypto
2020-05-09 19:14:01 -07:00
Kevin Hester
e7b99b0d78 Merge branch 'master' into crypto 2020-05-09 19:12:00 -07:00
geeksville
96313ee1c4 remove stale link 2020-05-09 19:11:06 -07:00
geeksville
3e356e5866 Crypto works! 2020-05-09 19:08:04 -07:00
geeksville
1cc24de787 stub encryptor seems nicely backwards compatible with old devices and apps 2020-05-09 17:51:20 -07:00
geeksville
e6875d559c Remove MeshRadio wrapper class - we don't need it anymore. 2020-05-09 16:32:26 -07:00
geeksville
b73dd5b23b misc todo 2020-05-09 16:15:16 -07:00
geeksville
28d21ecdcc begin work on crypto 2020-05-09 16:15:01 -07:00
Kevin Hester
42298abfad Merge pull request #131 from Dafeman/master
Pad Bluetooth passkey to 6 digits
2020-05-09 10:13:29 -07:00
Dafeman
c4a1fe0f36 Pad Bluetooth passkey to 6 digits 2020-05-09 23:09:36 +12:00
Mark Huson
0396f8f968 Merge pull request #1 from meshtastic/master
Merge upstream
2020-05-08 08:50:58 -07:00
Kevin Hester
f1b840dede Merge pull request #128 from mehuman/device-update
Device update
2020-05-07 14:42:42 -07:00
Mark Huson
4da5d79e88 add device-update to zip 2020-05-06 19:45:02 -07:00
Mark Huson
fc0c9bcfe3 add update script and README changes 2020-05-06 19:43:17 -07:00
Kevin Hester
32d0368f59 Merge pull request #127 from geeksville/nema-124
0.6.3 - fix the problem of BLE message receiption being busted in 0.6.2
2020-05-05 18:49:44 -07:00
geeksville
8bfe9fa8fc 0.6.3 - fix the problem of BLE message receiption being busted in 0.6.2 2020-05-05 18:40:17 -07:00
Kevin Hester
f10ad07f97 Merge pull request #125 from geeksville/nema-124
support ublox 8m gpses (I think)
2020-05-04 20:18:33 -07:00
geeksville
95df7dd8dc 0.6.2 2020-05-04 20:04:44 -07:00
geeksville
dcd1f7478a fix 124 - we now fallback to nema if we can't talk ublox protocol to
the GPS.  Though we are super power inefficient about it so TODO/FIXME
someday to decrease our power draw.
2020-05-04 20:02:43 -07:00
geeksville
c2be6c4068 WIP on #124 2020-05-04 17:39:57 -07:00
geeksville
101eef5495 oops lat/lon need to be signed ;-) 2020-05-04 11:21:24 -07:00
geeksville
933d5424da abstract out the UBlox GPS driver 2020-05-04 11:15:05 -07:00
geeksville
ecf528f9b6 move gps before refactoring 2020-05-04 10:23:47 -07:00
geeksville
9b309fe0a0 Use int based lat/long from now on in the device code
for https://github.com/meshtastic/Meshtastic-device/issues/124
2020-05-04 08:09:08 -07:00
Kevin Hester
29fd8dc7a5 Merge pull request #123 from geeksville/screen
fix missing carriage returns.  thanks to @gregwalters in #119
2020-05-02 20:24:03 -07:00
geeksville
624b95782d fix missing carriage returns. thanks to @gregwalters in #119 2020-05-02 20:21:42 -07:00
Kevin Hester
4fa25042c8 Merge pull request #122 from geeksville/dropped
changes to fix #121
2020-05-02 20:17:14 -07:00
Kevin Hester
9f9cb030ad Merge branch 'master' into dropped 2020-05-02 20:14:48 -07:00
geeksville
1d9290afc0 now that the rfinterfaces are smarter, no need to do backoff in
the flood router.  the interfaces will handle it.
2020-05-02 19:53:58 -07:00
geeksville
ad2f639195 don't leak messages if they are handled locally 2020-05-02 19:53:13 -07:00
geeksville
07b4eea037 fix log msg 2020-05-02 19:52:54 -07:00
geeksville
79c61cf0e0 limit max power on rf95 to 17 (rather than 20, because 20 can...
burn up parts if you exceed 1% duty cycle)
2020-05-02 19:52:37 -07:00
geeksville
80268ea56a send() is supposed to always free buffers, even if it returns an error 2020-05-02 19:51:55 -07:00
geeksville
bb9f595b8b Fix #11 2020-05-02 19:51:25 -07:00
geeksville
2ad314f150 we now always listen before transmit - even if we have just completed a packet 2020-05-02 08:29:51 -07:00
Kevin Hester
916e62398d Merge pull request #120 from geeksville/master
fix busted build on heltec style devices (0.6.1)
2020-05-01 17:01:52 -07:00
geeksville
4735b3ff5b 0.6.1 hotfix build for busted heltec style devices 2020-05-01 16:35:32 -07:00
geeksville
cfd6483ea5 oops - platform IO can have stale target specific builds without this 2020-05-01 16:34:16 -07:00
geeksville
4f7a25f562 remove unneeded include 2020-05-01 16:33:40 -07:00
geeksville
4176d79ee9 fix warnings 2020-05-01 16:33:26 -07:00
Kevin Hester
fad496378c Merge pull request #118 from geeksville/master
misc fri workqueue
2020-05-01 12:37:28 -07:00
geeksville
e084699704 SNR is now a float, fix the screen display 2020-05-01 12:31:36 -07:00
geeksville
50213d8323 move packet handling into its own thread 2020-05-01 12:11:04 -07:00
geeksville
763276a2c8 Merge branch 'radiolib' 2020-05-01 09:04:19 -07:00
geeksville
71fcdba017 cleanup directory structure 2020-05-01 09:04:00 -07:00
Kevin Hester
08227e79d0 Merge pull request #117 from geeksville/radiolib
Change to use Radiolib as the basis for our networking, and add RX1262 support
2020-05-01 08:55:17 -07:00
geeksville
5a4fab2506 start msg sequence numbers with a random number each boot 2020-05-01 08:51:53 -07:00
geeksville
31eb2f5337 very important: don't allow immediate sends if we have pending ISRs 2020-05-01 08:32:16 -07:00
geeksville
82c1752d85 less logspam 2020-05-01 08:31:52 -07:00
geeksville
49a13bbfd3 increase gps config timeout, could take up to 2.5 secs 2020-05-01 08:31:31 -07:00
geeksville
0096f54ae9 better debug output 2020-04-30 22:53:21 -07:00
geeksville
5af122b39d update todo list 2020-04-30 21:49:55 -07:00
geeksville
4e106f4098 remove radiohead 2020-04-30 21:42:11 -07:00
geeksville
1f1d683f4f add back the old code that checked if the radio was actvively receiving 2020-04-30 21:29:51 -07:00
geeksville
a8f64c3cc8 make a custom version fo rf95 class, so we can can deal with
chips that have bad version codes.
2020-04-30 21:11:03 -07:00
geeksville
968a2d7fbc store SNR in received packets 2020-04-30 19:58:10 -07:00
geeksville
1fab9c5aac temp hack to get new rf95 driver working 2020-04-30 19:31:17 -07:00
geeksville
22bca31ce3 properly set the RF95 iface 2020-04-30 18:05:06 -07:00
geeksville
48c045a253 move SPI init into main 2020-04-30 17:56:30 -07:00
geeksville
e9ca7792eb new RF95 driver is written 2020-04-30 17:43:29 -07:00
geeksville
b1a55b4576 old RF95 API works again 2020-04-30 16:47:56 -07:00
geeksville
dd7452ad96 old RF95 code builds again 2020-04-30 16:36:59 -07:00
geeksville
d7d8188093 implement most of sleep handling for the new radio stack 2020-04-30 15:50:07 -07:00
geeksville
62a893c760 SX1262 approximately works top-to-bottom, but need to add sleep modes 2020-04-30 15:43:41 -07:00
geeksville
a2ba9d3c44 new receive code works a little better 2020-04-30 13:50:40 -07:00
geeksville
22720e9f63 ex1262 receiving kinda works 2020-04-30 12:37:58 -07:00
geeksville
11b79a942d add todos 2020-04-30 10:54:53 -07:00
geeksville
3c3e722181 new sending kinda works 2020-04-30 10:00:40 -07:00
geeksville
fce31560c6 the mountain of changes needed to kinda make tx work compiles. 2020-04-30 09:44:16 -07:00
geeksville
074ac33b8a make a gdb "restart" command that allows restarting without rebuilding 2020-04-29 20:23:59 -07:00
geeksville
2982e197e0 radio settings now work on real sx1262 hw 2020-04-29 19:04:59 -07:00
geeksville
f69ddf168b we now hopefully apply the same radio settings as we did for the RF95 2020-04-29 18:46:32 -07:00
geeksville
8d985cfd37 cleanup so eventually rf95 can share common msg code with sx1262 2020-04-29 16:28:11 -07:00
geeksville
4693302d82 crummy sx1262 fake init kinda works 2020-04-29 16:06:23 -07:00
geeksville
814c126e67 ugly WIP on switching to RadioLib, still need to set freq etc... 2020-04-29 14:54:03 -07:00
geeksville
a7d153abcb CUSTOM GPIOs the SX1262MB2CAS shield when installed on the NRF52840-DK development board 2020-04-29 12:57:34 -07:00
geeksville
1b265eb48d switch from sx126x-arduino to radiolab 2020-04-29 10:50:50 -07:00
geeksville
94e80d3b44 mention python API 2020-04-28 20:51:02 -07:00
geeksville
f1ec95f49b update project name 2020-04-28 20:47:20 -07:00
Kevin Hester
7ee2643e9a Merge pull request #114 from geeksville/master
Add python API to webpage
2020-04-28 17:48:00 -07:00
geeksville
2ab34357d5 emit FromRadio.rebooted to serial test harness can detect reboots 2020-04-28 17:43:16 -07:00
geeksville
b53392ab73 Merge remote-tracking branch 'root/master' 2020-04-28 17:07:42 -07:00
geeksville
803d2dfefb add note about python API 2020-04-28 17:06:00 -07:00
Kevin Hester
6a54bbcf2a Merge pull request #113 from geeksville/master
Make new (optional) serial protobuf API work
2020-04-28 15:46:56 -07:00
geeksville
02dfe7564f 0.6.0 release 2020-04-28 15:39:05 -07:00
geeksville
b704911603 minor protobuf update 2020-04-28 11:20:00 -07:00
geeksville
0193c281ef change webpage to say android app is in general availability 2020-04-28 08:42:09 -07:00
geeksville
59086fd477 fixes after testing stream protocol with python client 2020-04-27 18:52:57 -07:00
geeksville
88a704c4d3 for now, allow debug out to be interleaved with protobufs 2020-04-27 09:46:06 -07:00
geeksville
9f49f90acd ignore vscode/launch.json 2020-04-27 09:42:31 -07:00
Kevin Hester
93f69d5a94 Merge pull request #112 from geeksville/serialproto
Serial/USB API for stress testing and other API clients
2020-04-27 09:40:10 -07:00
geeksville
cceecf5f8e New serial protobuf transport approximately works and is backward
compatiable with the text debug output.
2020-04-27 09:36:39 -07:00
geeksville
e5d2d24e2c move nanopb includes to correct directory 2020-04-27 09:27:36 -07:00
geeksville
eb40013ddc Create RedirectablePrint and NoopPrint for serial debug redirection 2020-04-27 09:01:25 -07:00
geeksville
dda946d933 Stream API coded but not tested 2020-04-27 08:45:39 -07:00
geeksville
178e800969 add beginnings of StreamAPI 2020-04-27 08:10:17 -07:00
geeksville
dec4870649 begin cleaning up mesh library layer so that it could be split someday 2020-04-27 07:54:19 -07:00
Kevin Hester
97f5a7c5fe Merge pull request #111 from geeksville/nrf52
Changes to support the NRF52
2020-04-27 07:47:29 -07:00
geeksville
7ff42b89a6 CI autobuilder can't yet build nrf52 targets 2020-04-27 07:44:57 -07:00
Kevin Hester
44de3bd179 Merge branch 'master' into nrf52 2020-04-27 07:41:23 -07:00
geeksville
15cb599cd1 move nrf52 stuff to correct directory name 2020-04-27 07:39:50 -07:00
geeksville
038b7c9c91 update todos 2020-04-27 07:29:36 -07:00
Kevin Hester
724e39bc92 Merge pull request #109 from geeksville/master
my saturday recreational work queue
2020-04-27 07:26:30 -07:00
geeksville
def86131f0 Merge branch 'master' into nrf52
# Conflicts:
#	src/main.cpp
2020-04-26 18:34:41 -07:00
geeksville
8f1c1a9049 move debug msg 2020-04-25 11:46:46 -07:00
geeksville
3f3a1a11df when flooding, randomly delay sent packets to decrease chances of...
stomping on other senders that we can't even hear.
2020-04-25 11:43:28 -07:00
geeksville
64f6c0f5c0 clean up PeriodicTask so I can eventually use it with a scheduler 2020-04-25 10:59:40 -07:00
geeksville
7cd60d859e possibly use radiohub for the new radio 2020-04-24 21:59:05 -07:00
geeksville
db11d9280c add nrf52 DFU app helper 2020-04-24 21:08:16 -07:00
geeksville
ca03110932 Update ESP32 build to work with latest NRF52 changes 2020-04-24 14:55:51 -07:00
geeksville
b8b503cb0a Add starting point of PPR variants definition 2020-04-24 12:40:22 -07:00
geeksville
bb885a5110 add a variant based on the nrf52840-dk but with a RC clock.
Because I was dumb and accidentally ran some code that configured gpio 0
as an output and that was enough to smoke the xtal that was preinstalled
between P0.0 and P0.1.
2020-04-24 12:30:06 -07:00
geeksville
bebaa838c4 no need for LightSleep state on NRF52 CPUs 2020-04-24 11:21:10 -07:00
geeksville
7fa9d09d9f placeholder guess at PMU code until I have HW 2020-04-24 09:33:45 -07:00
geeksville
7bc299573f move esp32 specific code into esp32 land 2020-04-24 08:52:49 -07:00
geeksville
e0a1855429 Add PMU driver 2020-04-24 08:38:00 -07:00
geeksville
5e75beff3f don't block but queue log messages for the ICE (and eventual crash reports) 2020-04-24 08:06:29 -07:00
geeksville
4f7e85c1a4 cleanup serial instanciation on boards where we might not use it 2020-04-24 08:05:56 -07:00
geeksville
5ad30caf67 todo updates 2020-04-24 08:05:33 -07:00
geeksville
8f26ae240a Add UC1701 and SX126X drivers (not yet using them though) 2020-04-24 08:05:25 -07:00
geeksville
d445cbe083 fix device name 2020-04-23 21:22:58 -07:00
geeksville
12599849db update todo list 2020-04-23 19:05:03 -07:00
geeksville
3c9c01189d old RF95 driver probably works on NRF52 now 2020-04-23 18:47:27 -07:00
geeksville
4f3a9d8646 example BLE code approximately works 2020-04-23 18:11:32 -07:00
geeksville
0c7c3f17e5 fix nrf52 macaddr byte order 2020-04-23 18:06:46 -07:00
geeksville
5b0451f25c add NRF52 BLE example code 2020-04-23 18:02:28 -07:00
geeksville
8f3b33c84c use a real macaddr on the nrf52 2020-04-23 16:55:25 -07:00
geeksville
2fdb75efdf make GPS 'work' on nrf52 2020-04-23 16:20:07 -07:00
geeksville
fbd12e1929 oled screen probably works now on nrf52 2020-04-23 13:56:15 -07:00
geeksville
ffe95f62ab no need to pass in scl & sda into screen constructor 2020-04-23 13:53:51 -07:00
geeksville
3e4ccef992 fix warnings 2020-04-23 13:53:29 -07:00
geeksville
309e7be00c use segger console on nrf52 2020-04-23 13:52:46 -07:00
geeksville
f0f6c4950b on NRF52 use the Segger debug console for debug logging 2020-04-23 13:27:16 -07:00
geeksville
16998ebd8d fix compiler warnings 2020-04-23 13:26:53 -07:00
geeksville
b77c068881 create MeshRadio even on NRF52 (though it is currently using a Sim interface) 2020-04-23 12:50:54 -07:00
geeksville
e94227cddd cope with missing interfaces in send 2020-04-23 12:48:00 -07:00
geeksville
fe3cbeed3a misc NRF52 fixes 2020-04-23 12:47:41 -07:00
Kevin Hester
2061706c11 Merge pull request #105 from geeksville/newapi
The new bluetooth API
2020-04-23 11:44:56 -07:00
geeksville
a0b6d57591 Fix #69 - new BLE API is in and tested from android 2020-04-23 11:41:30 -07:00
geeksville
3673f95fe5 woot! using new BLE api approximately works for reading 2020-04-23 11:02:14 -07:00
geeksville
c67b53b969 remove owner from ToRadio 2020-04-23 10:30:14 -07:00
geeksville
562b227c73 new API now seems fully implemented - now on to testing. #69 2020-04-22 16:11:54 -07:00
geeksville
169d85d0fa handle the new set_owner and set_radio messages 2020-04-22 15:13:05 -07:00
geeksville
bd77d47215 change serial baud rate to 921600 2020-04-22 14:58:35 -07:00
geeksville
e40524baf0 begin moving comms glue from the old crufty BLE code to the new cleaner PhoneAPI class 2020-04-22 14:55:36 -07:00
geeksville
31f735ae1f minor status update 2020-04-20 19:30:41 -07:00
geeksville
9232dfcccf WIP - add new baseclass for all api endpoints (serial, bluetooth, udp)
https://github.com/meshtastic/Meshtastic-esp32/issues/69
2020-04-20 18:03:13 -07:00
Kevin Hester
fab616a15e Merge pull request #101 from geeksville/master
0.4.3 Fix #92: omg - for the last couple of weeks the official builds…
2020-04-19 08:39:51 -07:00
geeksville
2419ebb04e 0.4.3 Fix #92: omg - for the last couple of weeks the official builds were
all using US frequencies.  This build fixes this (and makes the build
system cleaner in general).

If you are building your own builds in the IDE you'll need to start
setting an environment variable called COUNTRY to your two letter
country code (or leave unset to get US frequencies).  See new comment
in platformio.ini.
2020-04-19 08:33:59 -07:00
Kevin Hester
88c576798b Merge pull request #100 from geeksville/removeradiohead
Removeradiohead
2020-04-18 18:42:25 -07:00
geeksville
db766f18ed Fix #99: move spi ISR operations into helper thread. SPI from ISR is bad! 2020-04-18 14:56:09 -07:00
geeksville
f9a805e3d4 Merge remote-tracking branch 'root/master' into removeradiohead 2020-04-18 09:22:38 -07:00
geeksville
e5f9a752d8 fix comments and cleanup ISR code 2020-04-18 09:22:26 -07:00
geeksville
20b41836e2 clarify log msg 2020-04-18 09:22:08 -07:00
Kevin Hester
c55df4d1cc Merge pull request #98 from geeksville/removeradiohead
Removeradiohead
2020-04-18 08:58:12 -07:00
Kevin Hester
908b1020c0 Merge branch 'master' into removeradiohead 2020-04-18 08:51:00 -07:00
geeksville
78470ed3f5 fix #97, we need the RF95 IRQ to be level triggered, or we have slim chance of missing events 2020-04-18 08:48:03 -07:00
geeksville
4ce7df295e don't poll for completion so quickly - the log messages scare people 2020-04-18 08:39:05 -07:00
Kevin Hester
598abb0d23 Merge pull request #96 from geeksville/removeradiohead
Removeradiohead
2020-04-17 18:55:23 -07:00
geeksville
184eac6281 0.4.2 2020-04-17 18:51:46 -07:00
geeksville
176532f55f autoformat per formatting rules 2020-04-17 18:50:07 -07:00
geeksville
8eb3045451 Fix #85, we were stalling sometimes on send while in ISR which is NEVER legal 2020-04-17 18:49:54 -07:00
geeksville
2fe145aed9 debugging goo 2020-04-17 18:48:37 -07:00
Kevin Hester
ab61e64056 Merge pull request #94 from geeksville/removeradiohead
LOTS of changes:
2020-04-17 14:37:03 -07:00
geeksville
5b17417e0c debugging GPIO wake on heltec- seems fine. 2020-04-17 14:30:42 -07:00
geeksville
04a83fd6b7 properly detach observers at destruction 2020-04-17 13:24:38 -07:00
geeksville
7730bd762a be less chatty about sleep 2020-04-17 13:18:33 -07:00
geeksville
62286fff52 0.4.1 release 2020-04-17 13:05:16 -07:00
geeksville
25cca0628d more debug output 2020-04-17 12:46:57 -07:00
geeksville
65406eaa08 mesh flooding seems to work pretty well! 2020-04-17 12:41:01 -07:00
geeksville
ea24394110 add first cut of mesh naive flooding 2020-04-17 11:52:20 -07:00
geeksville
6afeb3e456 ok - new router seems to approximately work 2020-04-17 10:38:44 -07:00
geeksville
f108c576a7 massive WIP updates to create a clean Router abstraction for mesh 2020-04-17 09:48:54 -07:00
geeksville
6eb74415ab protobuf changes as part of getting ready for mesh again 2020-04-16 17:32:36 -07:00
geeksville
0d14b69a24 remove disasterradio experiment 2020-04-16 17:30:46 -07:00
geeksville
d4eb47e837 doc updates 2020-04-16 17:30:33 -07:00
geeksville
86716c4397 remove tbeam0.7 until someone who has the hardware can debug it 2020-04-16 09:05:53 -07:00
geeksville
7bbcf101c1 Merge remote-tracking branch 'root/master' into removeradiohead 2020-04-15 18:52:04 -07:00
Kevin Hester
8e495e417c Merge pull request #91 from geeksville/master
add production android fingerprints
2020-04-15 18:41:17 -07:00
Kevin Hester
a6e0d6d751 Merge branch 'master' into master 2020-04-15 18:33:22 -07:00
geeksville
cff255a397 add production android fingerprints 2020-04-15 18:20:45 -07:00
Kevin Hester
3336e821ad Merge pull request #90 from geeksville/master
fighting github pages
2020-04-15 18:05:28 -07:00
geeksville
d75d603218 Merge remote-tracking branch 'root/master' 2020-04-15 18:02:28 -07:00
geeksville
bf5be49186 It helps if I use the right filename when I'm remote debugging githubpages 2020-04-15 18:01:43 -07:00
geeksville
39ff26aa45 Merge branch 'master' into removeradiohead 2020-04-15 18:00:24 -07:00
Kevin Hester
02b5efed96 Merge pull request #89 from geeksville/master
add .well_known so that hopefully I can prove I own this domain to an…
2020-04-15 17:50:19 -07:00
geeksville
0a07c5692c add .well_known so that hopefully I can prove I own this domain to android 2020-04-15 17:46:34 -07:00
geeksville
2464784f00 todo updates 2020-04-15 14:51:17 -07:00
Kevin Hester
a8f5ff1fbd Merge pull request #87 from geeksville/cleanupblue
Refactoring to cleanup the relationship between bluetooth and everything else
2020-04-15 14:19:38 -07:00
geeksville
0a6af936ed Get build (kinda, not really) running on a NRF52
Lots of NO_ESP32 to remove later...
2020-04-14 20:22:27 -07:00
geeksville
0b62083e35 wip - plan 2020-04-14 16:45:26 -07:00
geeksville
5ca149fac9 move radiointerface into lib 2020-04-14 14:36:26 -07:00
geeksville
80c69c28cd move pool/queue management into the rf95 lib 2020-04-14 13:20:36 -07:00
geeksville
5904d66111 Move Custom95 in with the rest of the RH code, to be ready to refactor 2020-04-14 12:38:42 -07:00
geeksville
fd17193d5e Strip out all the parts of Radiohead (most of it) that we don't need 2020-04-14 12:31:29 -07:00
geeksville
5c379c4a98 missing newline 2020-04-14 11:44:35 -07:00
geeksville
9c5d626e7d Merge remote-tracking branch 'mine/cleanupblue' into cleanupblue 2020-04-14 11:41:16 -07:00
geeksville
4757b6807e lots of changes:
* preflightSleep, notifySleep, notifyDeepSleep now allow arbitrary
drivers/devices/software to register for sleep notification.
* Use the proceeding to clean up MeshRadio - now the mesh radio is more
like an independent driver that doesn't care so much about other systems
* clean up MeshService so that it can work with zero MeshRadios added.
This is a prelude to supporting boards with multiple interfaces (wifi,
extra LORA radios etc) and allows development/testing in sim with a bare
ESP32 board
* Remove remaining ESP32 dependencies from the bare simulation target
this allows running on anything that implements the arduino API
2020-04-14 11:40:49 -07:00
geeksville
ac7f3cd603 fix bin paths 2020-04-12 10:54:27 -07:00
Kevin Hester
04ad8bb533 Merge branch 'master' into cleanupblue 2020-04-10 21:11:46 -07:00
Kevin Hester
5924690ce3 Merge pull request #86 from BeardyWalrus/master
pinouts are swapped for TTGO-Lora32 V1 and V2 boards.
2020-04-10 21:11:30 -07:00
Kevin Hester
3ac3baf1c1 Merge branch 'master' into master 2020-04-10 21:09:12 -07:00
Kevin Hester
aa88e2bb1f Merge pull request #83 from geeksville/master
misc minor fix queue
2020-04-10 21:08:37 -07:00
geeksville
640cb3bf7f allow observers to return an error code to abort further processing
Will allow me to use observers to generalize the various hooks
that need to run to preflight sleep entry.
2020-04-10 12:40:44 -07:00
geeksville
6ad451eb5f move bluetooth code into something that is architecture specific...
because the ESP32 implementation will be different from NRF52
to make this possible I needed to decouple knowlege about bluetooth from
our mesh service.  Instead mesh service now uses the Obserable pattern
to let any interested consumer get notified of important mesh changes
(currently that is only bluetooth, but really we should do the same
thing for decoupling the GUI 'app' from the mesh service)

@girtsf would you mind reviewing my Observer changes? I haven't written
C++ code in a long time ;-)
2020-04-10 12:18:48 -07:00
geeksville
93a06906cb begin splitting up source files, so we can have a tree of sources...
unique to each architecture.  For now, we have "esp32" and "bare"

esp32 is the old esp stuff

bare is an target suitable for emulation that doesn't require any
particular hardware to run (no bluetooth, no i2c devices, no spi devices)
2020-04-10 12:15:35 -07:00
BeardyWalrus
3754950a0e pinouts are swapped for TTGO-Lora32 V1 and V2 boards.
discovered by eriktheV-king in discourse
2020-04-09 20:44:15 -04:00
geeksville
06a17885eb need need to link against the axp202 library on devices that don't have it 2020-04-07 21:27:08 -07:00
geeksville
33624b7753 todo update 2020-04-07 21:26:50 -07:00
Kevin Hester
2d6b9320a5 Merge pull request #82 from android606/screen-timeout-increase
Increase screen timeout to 5 minutes
2020-04-07 21:11:09 -07:00
Andrew
6b35454570 Merge pull request #1 from android606/meshtastic-esp32#80
Fix Meshtastic#80: Increase screen timeout to 5 minutes
2020-04-06 22:57:24 -07:00
Andrew
753a57230d Fix Meshtastic#80: Increase screen timeout to 5 minutes 2020-04-06 22:53:10 -07:00
Kevin Hester
9c3e63e6b5 Merge pull request #81 from Dafeman/patch-1
Update README.md
2020-04-06 20:28:43 -07:00
Kevin Hester
4d4d7b38cc Merge branch 'master' into patch-1 2020-04-06 20:26:17 -07:00
Kevin Hester
23f148f8ce Merge pull request #79 from geeksville/master
kevin's misc bugfix queue ;-)
2020-04-06 20:26:04 -07:00
Dafeman
d150549754 Update README.md
Added GUI install instructions and minor other formatting changes.
2020-04-07 14:37:00 +12:00
geeksville
441c4c7b3c Merge remote-tracking branch 'root/master' 2020-04-06 09:40:01 -07:00
geeksville
c22df18e28 fix collision avoidance for transmit - substantially improves lora tx success 2020-04-06 09:39:44 -07:00
Kevin Hester
e32b41938a Merge pull request #78 from geeksville/master
Fix #77: bluetooth is supposed to be on in DARK state
2020-04-05 14:41:52 -07:00
geeksville
ef395a1596 0.2.3 2020-04-05 14:39:42 -07:00
geeksville
af35f3006c force other devs to update for
fix https://github.com/meshtastic/Meshtastic-esp32/issues/76
2020-04-05 14:13:04 -07:00
geeksville
13ac686c96 minor doc cleanups 2020-04-05 13:58:38 -07:00
geeksville
05a0266fc4 Fix #77: bluetooth is supposed to be on in DARK state 2020-04-05 13:09:46 -07:00
Kevin Hester
3acbf31198 Merge pull request #75 from geeksville/master
fix bugs I noticed while testing a virgin tbeam
2020-04-04 20:55:06 -07:00
geeksville
2e82bf3ca1 Merge remote-tracking branch 'root/master' 2020-04-04 20:51:31 -07:00
geeksville
63e1a3f47e always set time from GPS if we can 2020-04-04 19:16:30 -07:00
geeksville
07a8972aea NEO-6M gps with empty backup batteries give super invalid times 2020-04-04 18:47:41 -07:00
geeksville
d1cb45aa5d string typo 2020-04-04 18:46:19 -07:00
Kevin Hester
1b3610d0fa Merge pull request #74 from geeksville/master
begin cleanup on radio abstraction - so we can support different radio chips and libraries
2020-04-02 08:10:12 -07:00
geeksville
2fcdc2c09f Merge remote-tracking branch 'root/master' 2020-04-01 11:51:15 -07:00
geeksville
da74803ffb begin cleanup on radio abstraction, details below:
* to allow changing to new mesh transport
* to allow a different chipset for the radio
* to allow testing on hardware with a SimRadio
* new "bare" build env for a devboard with virtually no hardware
* make buttons optional
2020-03-31 21:56:35 -07:00
Kevin Hester
890511615f Merge pull request #72 from geeksville/master
kevin's monday bug queue ;-)
2020-03-31 10:40:13 -07:00
geeksville
17de6f9532 fix #73: allow hw-model to be longer (16 bytes including terminator) 2020-03-30 19:58:06 -07:00
Kevin Hester
2a15195c32 Merge branch 'master' into master 2020-03-30 18:52:29 -07:00
geeksville
1b050a6c3d stop distributing the (enormous) elf files in the zip file 2020-03-30 18:51:15 -07:00
geeksville
1da62e5ba1 oops - we were previously not marking these protobuf structs as valid 2020-03-30 17:02:41 -07:00
geeksville
feb6f2e59e extra debug output for radio config, and bump up bax handles for BLE 2020-03-30 17:02:09 -07:00
geeksville
7dabad1b70 don't let phones send down fatally invalid RadioConfig records
and if a phone did in the past, fixup the garbage we saved in flash
2020-03-30 16:10:11 -07:00
geeksville
a73f466473 Add GPL statement 2020-03-30 13:46:46 -07:00
geeksville
1fd92cf8eb fix build for Windows based on tip from @moinars 2020-03-29 12:33:14 -07:00
Kevin Hester
dd671ceca6 Merge pull request #71 from geeksville/master
add OS-X instructions from @android606
2020-03-29 11:50:13 -07:00
geeksville
8a76931b37 add OS-X instructions from @android606 2020-03-29 11:40:18 -07:00
Kevin Hester
b071eecce1 Merge pull request #70 from geeksville/fix68
Fix68
2020-03-29 11:16:15 -07:00
geeksville
81734f75c8 fix review comments (don't let commands queue up if we are missing a display) 2020-03-29 11:13:53 -07:00
geeksville
11d57e721a fix #68 (@girtsf, pls review - ps: no worries ;-) )
// We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
2020-03-29 11:00:25 -07:00
geeksville
9b0e329bb9 update credits 2020-03-28 20:33:21 -07:00
Kevin Hester
450fb7bc35 Merge pull request #67 from geeksville/master
kevin's minor work items saturday queue
2020-03-28 20:22:36 -07:00
geeksville
c1f8c8cca4 0.2.0 2020-03-28 20:10:37 -07:00
geeksville
ea250d9cd3 add initial guess at TBEAM 0.7 hardware support 2020-03-28 15:31:22 -07:00
geeksville
be468a2183 add reasonable guesses for TTGO LORA V1 and V2 boards - thanks @sensorsiot
for the pinouts
2020-03-28 14:45:33 -07:00
Kevin Hester
a47d6c4d68 Merge pull request #65 from geeksville/master
kevin's friday minor bugfix queue
2020-03-28 13:26:30 -07:00
geeksville
5386a5b224 update build instructions 2020-03-28 13:17:07 -07:00
geeksville
a350b3795b remove unused file 2020-03-28 13:16:54 -07:00
geeksville
cf2aa37635 clean up configuration.h and add support for ttgo-lora-v1 boards 2020-03-27 16:55:19 -07:00
geeksville
d1387be015 Merge remote-tracking branch 'root/master'
# Conflicts:
#	src/main.cpp
#	src/screen.cpp
2020-03-27 14:18:07 -07:00
Kevin Hester
f8857ad45b Merge pull request #63 from girtsf/debug-screen-b49
fix #49: make debug screen show real data
2020-03-27 14:11:56 -07:00
geeksville
d831beab3d moving build selection into platformio.ini rather than nasty #defines. thanks to @sensorslot
for the pointer to https://github.com/arendst/Tasmota - where I just borrowed heavily ;-)
2020-03-27 14:03:58 -07:00
geeksville
5c4ae6c042 now that axp192 interrups work, no need to poll over i2c. #48 2020-03-27 14:03:58 -07:00
geeksville
a0c97825e8 always use gps.isConnected to check for GPS, it is the only thing
guaranteed to be fresh and accurate
2020-03-27 12:32:18 -07:00
geeksville
cc3bac7ea0 Fix AXP192 handling by @spattinson. yay! fix #48
Also - now that he fixed that, we can leave PMU interrupts on across sleep

Hopefully the following line will properly credit him in the magic github
universe...

Co-authored-by: spattinson <spattinson@users.noreply.github.com>
2020-03-27 12:29:51 -07:00
geeksville
ce21859ada toto updates 2020-03-27 12:08:05 -07:00
Girts Folkmanis
54cd082bfe fix #49: make debug screen show real data
* Break out debug screen to a separate class and make it thread-safe.
* Break out power state to a separate class.
* Show battery voltage, charging & USB status on debug screen.
* Show GPS lock / no lock
* Fix an off-by-one that I introduced earlier in `drawRows`.
2020-03-26 22:17:47 -07:00
Kevin Hester
4c35d1f207 Merge pull request #58 from geeksville/master
kevins bug fixes for weds
2020-03-25 16:24:56 -07:00
geeksville
4d54df4c9b 0.1.10 2020-03-25 16:21:41 -07:00
geeksville
aa9aca2b88 Merge remote-tracking branch 'root/master' 2020-03-25 13:38:26 -07:00
geeksville
a579bbcb50 heltec style devices were not automatically setting their time from the mesh
due to a bug in the init of has_gps.  Now that we probe for gps we should
default has_gps to false until we hear from it
2020-03-25 13:36:54 -07:00
geeksville
12e67d3b30 add some debug output 2020-03-25 13:35:49 -07:00
geeksville
50d724780a make user presses ask other nodes for their latest status
see related bug
https://github.com/meshtastic/Meshtastic-esp32/issues/59
2020-03-25 13:09:12 -07:00
geeksville
45babab8c4 generalize the serial console script 2020-03-25 12:35:35 -07:00
geeksville
3443e60718 never loop waiting on hardware without some sort of timeout ;-)
related to https://github.com/meshtastic/Meshtastic-esp32/issues/53
2020-03-25 12:25:46 -07:00
geeksville
65128a04c9 my new watchdog related to the the send tx bug was not quite complete
https://github.com/meshtastic/Meshtastic-esp32/issues/53
2020-03-25 11:45:18 -07:00
geeksville
7210c1ae5e emphasize the forum link
and ... alas, do a one time autoformat from the IDE.
2020-03-25 08:13:07 -07:00
Kevin Hester
9075501917 Merge pull request #56 from geeksville/master
misc changes as kevin bangs through the post illness bug-queue
2020-03-24 15:30:04 -07:00
geeksville
a3b70e7538 0.1.9 2020-03-24 15:23:50 -07:00
geeksville
b4b8abe6ec omg I was not setting the correct flag to tell phone we had gps 2020-03-24 15:20:24 -07:00
geeksville
d647be73df oops nasty bug probably responsible for ble mutex seeming bugs #33
Was calling the wrong superclass method and therfore not properly
populating radio
2020-03-24 15:16:32 -07:00
geeksville
42d7966858 add instructions on how to reinstall 2020-03-24 15:13:28 -07:00
geeksville
f4d368e1f4 fix #27 - add a device-install.sh script to the release 2020-03-24 14:48:52 -07:00
geeksville
3a756b0e08 keep the elf files in the zip package, useful with @girtsf tool 2020-03-24 13:58:17 -07:00
geeksville
34ead2d68e add support for reporting device errors up through the phone to analytics
related to https://github.com/meshtastic/Meshtastic-esp32/issues/53
2020-03-24 13:33:24 -07:00
geeksville
3f1161b68b bug #53 - report the error on console and fixup (will add analytics in
a separate call)
2020-03-24 13:04:28 -07:00
Kevin Hester
f108e24bc1 Merge pull request #51 from girtsf/fix-upside-down-screen
screen.cpp: flip the display 180
2020-03-24 11:09:06 -07:00
Kevin Hester
1f83f7d9df Merge branch 'master' into fix-upside-down-screen 2020-03-24 10:55:56 -07:00
Kevin Hester
756c7ca7b3 Merge pull request #55 from girtsf/fix-ble
fix #52: bluetooth not pairing
2020-03-24 10:55:00 -07:00
Kevin Hester
79f7bf77c9 Merge branch 'master' into fix-ble 2020-03-24 10:52:10 -07:00
Girts Folkmanis
dee3e530de fix #52: bluetooth not pairing
Silly type error on my part - PIN was always truncated to lower 8 bits.
😬

Tested: Pairing now works from both nRF Connect and phone.
2020-03-22 19:18:49 -07:00
Girts Folkmanis
3e44c2c3e1 screen.cpp: flip the display 180 2020-03-19 20:15:51 -07:00
Kevin Hester
3886665041 Merge pull request #47 from geeksville/master
update todo list
2020-03-18 20:37:46 -07:00
geeksville
c9b269c3c0 Merge remote-tracking branch 'root/master' 2020-03-18 19:36:37 -07:00
geeksville
eb51c92d08 update todo list 2020-03-18 19:28:55 -07:00
Kevin Hester
992b525588 Merge pull request #46 from geeksville/master
a quick window to sneak in and fix formatting
2020-03-18 19:19:18 -07:00
geeksville
25288d8ed6 Merge remote-tracking branch 'root/master' 2020-03-18 19:16:56 -07:00
geeksville
32ac5ac9ae reformat everything
using @girtsf clang-format prefs settings.  This should allow us to turn
on auto format in our editors without causing spurious file changes.
2020-03-18 19:15:51 -07:00
Kevin Hester
ef5cdefca6 Merge pull request #44 from geeksville/master
various minor commits based on bugs I see while testing app
2020-03-18 18:55:57 -07:00
geeksville
f6f9dfa463 0.1.8 2020-03-18 18:53:55 -07:00
geeksville
2161ce21df the firmware version xml file should not be checked in, it is used directly
by the android build and derived from version.sh
2020-03-18 18:53:42 -07:00
geeksville
534691f0c2 Merge remote-tracking branch 'root/master'
# Conflicts:
#	src/main.cpp
#	src/screen.cpp
#	src/screen.h
2020-03-18 18:44:12 -07:00
Kevin Hester
6bc8e1b10a Merge pull request #45 from girtsf/screen-cpp-refactor
Screen cleanups and refactoring
2020-03-18 18:35:51 -07:00
geeksville
c8b95f7691 oops - I broke compass display with my gps changes and didn't notice till
testing with two gps equipped devices.  fixed.
2020-03-18 18:34:22 -07:00
Girts Folkmanis
daf8594b99 Screen cleanups and refactoring
Work towards separating out how Screen interacts with other stuff.
* `Screen` should now be thread-safe. All commands to it are put in a
  queue and handled in `doTask` from the `loop()` task.
* Break dependency from `BluetoothUtil` to `Screen` by changing the
  pairing request into a callback.
* All accesses to screen now happen through the class.
* Fix `drawRows` so that the text scrolls along with frame animations.
* Remove example code that wasn't used.
2020-03-18 18:11:35 -07:00
Girts Folkmanis
5b54fd6359 screen.cpp: reformat with clang-format 2020-03-18 17:16:19 -07:00
geeksville
53765298e1 add a real BOOT state, to avoid glitch from redrawing bootscreen twice
also its the right thing to do ;-)
2020-03-18 15:00:17 -07:00
geeksville
0d94458c4e bump preferences # 2020-03-18 14:59:30 -07:00
geeksville
5e55695862 fix build warning 2020-03-18 14:51:54 -07:00
Kevin Hester
c9e2e6c386 Merge pull request #43 from geeksville/one-wire-gps
fixes to make one-wire gpses work and cope with tbeams with crummy rx buffers
2020-03-18 14:02:46 -07:00
geeksville
dbbb62f63e fix press to properly force any node we are watching to send us a new
position report
2020-03-18 13:51:32 -07:00
geeksville
79ce7d929c send dynamic probed GPS status to the phone 2020-03-18 13:29:22 -07:00
geeksville
33437b5246 oops - I accidentally shadowed a variable I didn't want to shadow ;-) 2020-03-18 09:37:38 -07:00
geeksville
f4bacb9d87 some tbeams have occasional crap sitting in their gps rx buffer at boot? 2020-03-18 09:29:20 -07:00
geeksville
0ac218b06d allow gpses which only have the RX pin connected to also work.
(and because I'm lazy, let the autoreformat rule work on this file)
2020-03-18 09:21:28 -07:00
Kevin Hester
2ce1b4bb2c Merge pull request #42 from geeksville/master
release 0.1.7
2020-03-17 20:02:01 -07:00
geeksville
f002bee4f4 release 0.1.7 2020-03-17 19:50:26 -07:00
Kevin Hester
9c69326ed9 Merge pull request #39 from geeksville/bug17
Bug17
2020-03-17 19:42:44 -07:00
Kevin Hester
7a617d5378 Merge branch 'master' into bug17 2020-03-17 19:40:25 -07:00
Kevin Hester
90edae1ce0 Merge pull request #41 from geeksville/new-oled
fix #40 force an extra redraw for the bootscreen,
2020-03-17 19:39:32 -07:00
geeksville
2134b4db9b fix #40 force an extra redraw for the bootscreen,
some clones drop the first draw cmd
2020-03-17 16:36:48 -07:00
geeksville
7b1ffb5c09 #17 WIP add tool to capture the system portion of flash
based on initial encouraging feedback from @illperipherals

if more people report success, we'll need to change the install instructions
to:

esptool.py --port COM10 --baud 921600 erase_flash
esptool.py --port COM10 --baud 921600 write_flash 0x1000 system-info.bin
esptool.py --port COM10 --baud 921600 write_flash 0x10000 firmware-HELTEC-US-0.1.6.bin
2020-03-17 11:17:58 -07:00
geeksville
535f07d927 add a tbeam program script 2020-03-17 11:16:22 -07:00
Kevin Hester
bfad136137 Merge pull request #31 from geeksville/master
@girtsf can you review these changes and blessmotize if they seem good?
2020-03-16 09:37:31 -07:00
geeksville
36bee8fa53 Merge remote-tracking branch 'root/master' 2020-03-16 09:30:24 -07:00
Kevin Hester
99cb0b3855 Merge pull request #37 from girtsf/fix-build-2
fix build: add missing include to screen.cpp
2020-03-16 09:30:14 -07:00
Girts Folkmanis
41c95eaff7 fix build: add missing include to screen.cpp 2020-03-16 09:26:40 -07:00
geeksville
ca8a25f585 Merge remote-tracking branch 'root/master' 2020-03-16 09:03:21 -07:00
Kevin Hester
51a8700391 Merge pull request #35 from girtsf/underp-lock-paths
underp include paths in lock.h
2020-03-16 09:02:54 -07:00
Kevin Hester
f099a31a29 Merge pull request #34 from girtsf/patch-1
run CI on pull requests as well
2020-03-16 09:01:28 -07:00
Kevin Hester
52dbc4e15d Merge pull request #36 from girtsf/various-cleanups
Various cleanups
2020-03-16 09:00:42 -07:00
Girts Folkmanis
8cabb3ea3d add .clang-format file
Tried to infer the style from existing files.
2020-03-15 19:29:55 -07:00
Girts Folkmanis
7a4a1af332 TypedQueue: make functions return bools instead of BaseType_t
Minor cleanup to hide away some FreeRTOS bits.

Note: I believe src/CustomRF95.cpp:62 had a bug where it had the
condition inverted.
2020-03-15 19:29:04 -07:00
Girts Folkmanis
90ecdf229e add locks to PeriodicTask 2020-03-15 19:29:00 -07:00
geeksville
24ac907780 auto generate channel numbers from name
NOTE: All radios on a channel will need to be updated to this release
before they can talk together again.
2020-03-15 17:51:57 -07:00
geeksville
5037fb830e fix build (and autoformat in visual studio code) 2020-03-15 17:50:48 -07:00
Girts Folkmanis
79f1346359 underp include paths in lock.h
Had the casing wrong, but could get away with it on a mac.
2020-03-15 17:43:42 -07:00
Girts
35dada683a run CI on pull requests as well 2020-03-15 17:42:48 -07:00
geeksville
30a431788d we now do bidirectional comms to GPS at startup, so we can always trust isConnected 2020-03-15 16:57:21 -07:00
geeksville
d0b8adab75 In my work for #11 I accidentially created a serious bug on Heltec...
devices.  It caused bogus i2c transactions when device would go to sleep.
Fixed now, also, I now treat GPS usage uniformly between TBEAM and HELTEC
we always probe for and use the GPS if we find it.

Which means for the extra nerds
(someone requested this, I'm sorry - I don't remember who) you can now
optionally attach an external GPS to HELTECs if you want.  The pins are:

 #define GPS_RX_PIN 34
 #define GPS_TX_PIN 12

(@girtsf, sorry about including formatting changes in this PR, apparently
I had my IDE set to not autoreformat until just now
2020-03-15 16:57:21 -07:00
geeksville
74f7b7b622 print extra info the next time this error occurs 2020-03-15 16:57:21 -07:00
geeksville
9ec8562ce7 fix old geeksville link (though github provides redirects) 2020-03-15 16:57:21 -07:00
Kevin Hester
0cbcb7a9bd Merge pull request #32 from girtsf/add-lock-etc
add a Lock, LockGuard and printThreadInfo
2020-03-15 16:55:48 -07:00
Girts Folkmanis
2874b22d6c add a Lock, LockGuard and printThreadInfo
* `Lock`: trivial wrapper for FreeRTOS binary semaphores
* `LockGuard`: RAII wrapper for using `Lock`
* `printThreadInfo`: helper for showing which core/FreeRTOS task we are
  running under
2020-03-15 16:52:19 -07:00
Kevin Hester
3c9be48445 Merge pull request #30 from girtsf/fix-build
fix the build: remove includes for TinyGPS that's not longer used or …
2020-03-15 14:30:04 -07:00
Girts Folkmanis
b5201f928b fix the build: remove includes for TinyGPS that's not longer used or in deps 2020-03-15 13:27:00 -07:00
Kevin Hester
2591859df5 Merge pull request #29 from girtsf/exception-decoder
check in script to decode backtraces
2020-03-15 12:38:44 -07:00
Girts Folkmanis
c411db111b check in script to decode backtraces 2020-03-15 12:29:15 -07:00
geeksville
0d62a2be85 release 0.1.6 2020-03-14 18:48:15 -07:00
geeksville
9c971d3686 Finally - new sexy ultra low power/low latency GPS code is in for TBEAM 2020-03-14 18:45:24 -07:00
geeksville
3c1357b732 ublox is better but still not perfect 2020-03-14 16:31:12 -07:00
geeksville
acd5e5d29d use power save mode on gps 2020-03-14 13:33:53 -07:00
geeksville
64109b25f2 Switch to native ublox api for GPS position and time 2020-03-14 12:46:24 -07:00
geeksville
e93bc76ac9 Merge branch 'master' into gps-sleep-mode 2020-03-13 22:45:40 -07:00
geeksville
1107c6d23d Fix serious bug: button presses were not waking from light-sleep on TBEAM
Root cause seems to be the axp192 interrupt, which on some boards fires
during sleep.  I'm not sure why, but we don't need this yet, so leaving
masked during sleep.
2020-03-13 22:42:43 -07:00
geeksville
9b2155402d todo update 2020-03-13 22:41:12 -07:00
geeksville
35cf8a4859 power debugging 2020-03-13 22:38:58 -07:00
geeksville
76f21dfd6e wip 2020-03-13 22:34:44 -07:00
geeksville
b101dc2c88 wip 2020-03-13 20:48:37 -07:00
geeksville
9bbd658b9d begin testing native ublox api 2020-03-13 20:30:48 -07:00
geeksville
4999da0824 Merge branch 'dev' into gps-sleep-mode
# Conflicts:
#	docs/software/TODO.md
#	platformio.ini
2020-03-13 18:48:38 -07:00
geeksville
a783341df1 begin adding temporary support for both NEMA and UBLOX gpses 2020-03-13 18:44:14 -07:00
geeksville
04258755e7 change from gitter to discourse. 2020-03-13 15:06:51 -07:00
geeksville
ea711ece1f new firmware released 2020-03-13 15:03:47 -07:00
geeksville
e93187b630 0.1.5 add support for EU 433MHz radios thanks to @astro-arphid 2020-03-12 09:34:10 -07:00
geeksville
eca3cda8b9 fix typos 2020-03-12 09:31:31 -07:00
Kevin Hester
2874adfd69 Merge pull request #21 from astro-arphid/master
#13 - add support for 433MHz Heltec boards (thanks to @astro-arphid)
2020-03-12 09:29:54 -07:00
astro-arphid
91227b25df #13 - add support for 433MHz Heltec boards 2020-03-12 06:05:11 +00:00
geeksville
4dfac03402 add note about 3d printed cases 2020-03-11 10:59:02 -07:00
geeksville
9bc895eb57 fix formatting 2020-03-11 10:55:58 -07:00
geeksville
474026d7fe add a faq 2020-03-11 10:51:38 -07:00
geeksville
9995d2a7ab oops copypasta error fix #19. Thanks @iveskins! 2020-03-10 19:33:16 -07:00
geeksville
3028ac3f24 add note about dash7 2020-03-10 19:32:45 -07:00
geeksville
8605950eef add credits list 2020-03-10 11:43:45 -07:00
Kevin Hester
0f856dea7b Merge pull request #18 from claesg/master
Updated README for 3D cases for T-Beam.
2020-03-10 11:39:17 -07:00
claes
2a2bc5b1d6 Updated README for 3D cases for T-Beam.
T-Beam V1 has moved the antenna connector a bit to the right compared
to the V0. This makes the case not fit.
Added 2 more links for T-Beam cases.
2020-03-10 09:31:32 +01:00
geeksville
f87cb00940 show reason for last reset 2020-03-08 14:05:12 -07:00
geeksville
a4ebf83b69 minor doc update 2020-03-08 14:03:36 -07:00
geeksville
5dbacbddba version 0.1.13 Fix #15 found by @claesg. Thanks for the detailed report! 2020-03-08 11:07:27 -07:00
geeksville
011864a2d3 Fix #15 Force all devices to update preferences 2020-03-08 11:02:58 -07:00
geeksville
8646d8aeba mesh alg replacement update 2020-03-08 11:02:15 -07:00
geeksville
87782cdf8f progress on re readdition of the mesh router 2020-03-06 19:52:34 -08:00
geeksville
10289ed11a todo updates 2020-03-06 19:47:57 -08:00
geeksville
5def6a66e6 cleanup dev docs a bit more 2020-03-05 19:00:00 -08:00
geeksville
2d3bb4bb75 fix table formatting 2020-03-05 18:45:48 -08:00
geeksville
ffe8bf2be6 Refactor to make some real design docs 2020-03-05 18:39:24 -08:00
geeksville
ab73033e51 Fix #10. Add note about board types. 2020-03-05 13:18:36 -08:00
geeksville
c66e24aa4d most users are not using the phone app now, don't enter SDS state because of no phone comms 2020-03-04 18:59:10 -08:00
geeksville
635e189007 GPS sleep mode WIP - alas this thread will have to be back burner for a
while because my TX wire on my ONLY T-BEAM broke while I was soldering
a jtag connector - so I can only RX from the GPS.

My other 5 boards are still delayed due to corona virus.

So I'll work on other features for now
2020-02-22 20:05:38 -08:00
geeksville
6eba792537 WIP - changing to a ublox aware GPS lib so I can put it in sleep 2020-02-22 19:08:16 -08:00
176 changed files with 14572 additions and 3996 deletions

6
.clang-format Normal file
View File

@@ -0,0 +1,6 @@
Language: Cpp
IndentWidth: 4
ColumnLimit: 130
PointerAlignment: Right
BreakBeforeBraces: Linux
AllowShortFunctionsOnASingleLine: Inline

View File

@@ -1,5 +1,7 @@
name: Continuous Integration name: Continuous Integration
on: push on:
- push
- pull_request
jobs: jobs:
main: main:

1
.gitignore vendored
View File

@@ -6,6 +6,5 @@ main/credentials.h
.vscode/* .vscode/*
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
*.code-workspace *.code-workspace

32
.vscode/launch.json vendored
View File

@@ -1,32 +0,0 @@
// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY
// PIO Unified Debugger
//
// Documentation: https://docs.platformio.org/page/plus/debugging.html
// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html
{
"version": "0.2.0",
"configurations": [
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/esp32/firmware.elf",
"toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"preLaunchTask": {
"type": "PlatformIO",
"task": "Pre-Debug"
},
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "/home/kevinh/development/meshtastic/meshtastic-esp32/.pio/build/esp32/firmware.elf",
"toolchainBinDir": "/home/kevinh/.platformio/packages/toolchain-xtensa32/bin",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

13
.vscode/settings.json vendored
View File

@@ -42,10 +42,19 @@
"typeinfo": "cpp", "typeinfo": "cpp",
"string": "cpp", "string": "cpp",
"*.xbm": "cpp", "*.xbm": "cpp",
"list": "cpp" "list": "cpp",
"atomic": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"string_view": "cpp",
"cassert": "cpp"
}, },
"cSpell.words": [ "cSpell.words": [
"Blox",
"Meshtastic", "Meshtastic",
"descs" "NEMAGPS",
"Ublox",
"descs",
"protobufs"
] ]
} }

179
README.md
View File

@@ -1,39 +1,73 @@
# Meshtastic-esp32 # Meshtastic-device
This is the device side code for the [meshtastic.org](https://www.meshtastic.org) project.
This is the device side code for the [meshtastic.org](https://www.meshtastic.org) project.
![Continuous Integration](https://github.com/meshtastic/Meshtastic-esp32/workflows/Continuous%20Integration/badge.svg) ![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 - 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 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. 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 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. will optionally work with your phone, but no phone is required.
Typical time between recharging the radios should be about eight days. Typical time between recharging the radios should be about eight days.
This project is currently early-alpha, but if you have questions please join our chat [![Join the chat at https://gitter.im/Meshtastic/community](https://badges.gitter.im/Meshtastic/community.svg)](https://gitter.im/Meshtastic/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). This project is currently early-alpha, but if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the chat. This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the chat.
## Supported hardware ## Supported hardware
We currently support three models of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html), [TTGO LORA32](https://www.banggood.com/LILYGO-TTGO-LORA32-868Mhz-SX1276-ESP32-Oled-Display-bluetooth-WIFI-Lora-Development-Module-Board-p-1248652.html?cur_warehouse=UK) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most users should buy the T-Beam and a 18650 battery (total cost less than $35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen
is optional, but highly recommended.
See (meshtastic.org) for 3D printable cases. We currently support three models of radios.
- TTGO T-Beam
- [T-Beam V1.0 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (Recommended)
- [T-Beam V1.0 w/ NEO-6M](https://www.aliexpress.com/item/33050391850.html)
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
## Installing the firmware - [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
Prebuilt binaries for the supported radios is available in our [releases](https://github.com/meshtastic/Meshtastic-esp32/releases). Your initial installation has to happen over USB from your Mac, Windows or Linux PC. Once our software is installed, all future software updates happen over bluetooth from your phone.
The instructions currently require a few commmand lines, but it should be pretty straightforward. Please post comments on our group chat if you have problems or successes. Steps to install: - [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/) - No GPS
- [3D Printable case](https://www.thingiverse.com/thing:3125854)
**Make sure to get the frequency for your country**
- US/JP/AU/NZ - 915MHz
- CN - 470MHz
- EU - 870MHz
Getting a version that includes a screen is optional, but highly recommended.
## Firmware Installation
Prebuilt binaries for the supported radios are available in our [releases](https://github.com/meshtastic/Meshtastic-esp32/releases). Your initial installation has to happen over USB from your Mac, Windows or Linux PC. Once our software is installed, all future software updates happen over bluetooth from your phone.
Please post comments on our [group chat](https://meshtastic.discourse.group/) if you have problems or successes.
### Installing from a GUI - Windows and Mac
1. Download and unzip the latest Meshtastic firmware [release](https://github.com/meshtastic/Meshtastic-esp32/releases).
2. Download [ESPHome Flasher](https://github.com/esphome/esphome-flasher/releases) (either x86-32bit Windows or x64-64 bit Windows).
3. Connect your radio to your USB port and open ESPHome Flasher.
4. If your board is not showing under Serial Port then you likely need to install the drivers for the CP210X serial chip. In Windows you can check by searching “Device Manager” and ensuring the device is shown under “Ports”.
5. If there is an error, download the drivers [here](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers), then unzip and run the Installer application.
6. In ESPHome Flasher, refresh the serial ports and select your board.
7. Browse to the previously downloaded firmware and select the correct firmware based on the board type, country and frequency.
8. Select Flash ESP.
9. Once complete, “Done! Flashing is complete!” will be shown.
10. Debug messages sent from the Meshtastic device can be viewed with a terminal program such as [PuTTY](https://www.putty.org/) (Windows only). Within PuTTY, click “Serial”, enter the “Serial line” com port (can be found at step 4), enter “Speed” as 921600, then click “Open”.
### Installing from a commandline
These instructions currently require a few commmand lines, but it should be pretty straightforward.
1. Install "pip". Pip is the python package manager we use to get the esptool installer app. Instructions [here](https://www.makeuseof.com/tag/install-pip-for-python/). If you are using OS-X, see these [special instructions](docs/software/install-OSX.md).
2. Run "pip install --upgrade esptool" to get esptool installed on your machine.
3. Connect your radio to your USB port.
4. Confirm that your device is talking to your PC by running "esptool.py chip_id". The Heltec build also works on the TTGO LORA32 radio. You should see something like:
1. Purchase a radio (see above) with the correct frequencies for your country (915MHz for US or JP, 470MHz for CN, 870MHz for EU).
2. Install "pip". Pip is the python package manager we use to get the esptool installer app. Instructions [here](https://www.makeuseof.com/tag/install-pip-for-python/).
3. Run "pip install --upgrade esptool" to get esptool installed on your machine
4. Connect your radio to your USB port
5. Confirm that your device is talking to your PC by running "esptool.py chip_id". The Heltec build also works on the TTGO LORA32 radio. You should see something like:
``` ```
mydir$ esptool.py chip_id mydir$ esptool.py chip_id
esptool.py v2.6 esptool.py v2.6
@@ -51,53 +85,112 @@ Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: 24:6f:28:b5:36:71 MAC: 24:6f:28:b5:36:71
Hard resetting via RTS pin... Hard resetting via RTS pin...
``` ```
6. Install the correct firmware for your board with "esptool.py write_flash 0x10000 firmware-_board_-_country_.bin". For instance "esptool.py write_flash 0x10000 release/firmware-HELTEC-US-0.0.3.bin". You should see something like this:
5. cd into the directory where the release zip file was expanded.
6. Install the correct firmware for your board with `device-install.sh firmware-_board_-_country_.bin`.
- Example: `./device-install.sh firmware-HELTEC-US-0.0.3.bin`.
7. To update run `device-update.sh firmware-_board_-_country_.bin`
- Example: `./device-update.sh firmware-HELTEC-US-0.0.3.bin`.
Note: If you have previously installed meshtastic, you don't need to run this full script instead just run "esptool.py --baud 921600 write*flash 0x10000 firmware-\_board*-_country_.bin". This will be faster, also all of your current preferences will be preserved.
You should see something like this:
``` ```
~/development/meshtastic/meshtastic-esp32$ esptool.py write_flash 0x10000 release/firmware-HELTEC-US-0.0.3.bin kevinh@kevin-server:~/development/meshtastic/meshtastic-esp32/release/latest$ ./device-install.sh firmware-TBEAM-US-0.1.8.bin
Trying to flash firmware-TBEAM-US-0.1.8.bin, but first erasing and writing system information
esptool.py v2.6 esptool.py v2.6
Found 2 serial ports Found 2 serial ports
Serial port /dev/ttyUSB0 Serial port /dev/ttyUSB0
Connecting...... Connecting........____
Detecting chip type... ESP32 Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1) Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b5:36:71 MAC: 24:6f:28:b2:01:6c
Uploading stub... Uploading stub...
Running stub... Running stub...
Stub running... Stub running...
Changing baud rate to 921600
Changed.
Erasing flash (this may take a while)...
Chip erase completed successfully in 6.1s
Hard resetting via RTS pin...
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting.......
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b2:01:6c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size... Configuring flash size...
Auto-detected Flash size: 8MB Auto-detected Flash size: 4MB
Compressed 1184800 bytes to 652635... Flash params set to 0x0220
Wrote 1184800 bytes (652635 compressed) at 0x00010000 in 57.6 seconds (effective 164.5 kbit/s)... Compressed 61440 bytes to 11950...
Wrote 61440 bytes (11950 compressed) at 0x00001000 in 0.2 seconds (effective 3092.4 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
esptool.py v2.6
Found 2 serial ports
Serial port /dev/ttyUSB0
Connecting.....
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:b2:01:6c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1223568 bytes to 678412...
Wrote 1223568 bytes (678412 compressed) at 0x00010000 in 10.7 seconds (effective 912.0 kbit/s)...
Hash of data verified. Hash of data verified.
Leaving... Leaving...
Hard resetting via RTS pin... Hard resetting via RTS pin...
``` ```
7. The board will boot and show the Meshtastic logo. 7. The board will boot and show the Meshtastic logo.
8. Please post a comment on our chat so we know if these instructions worked for you ;-). If you find bugs/have-questions post there also - we will be rapidly iterating over the next few weeks. 8. Please post a comment on our chat so we know if these instructions worked for you ;-). If you find bugs/have-questions post there also - we will be rapidly iterating over the next few weeks.
## Meshtastic Android app # Meshtastic Android app
The source code for the (optional) Meshtastic Android app is [here](https://github.com/meshtastic/Meshtastic-Android).
Alpha test builds are current available by opting into our alpha test group. See (www.meshtastic.org) for instructions. The source code for the (optional) Meshtastic Android app is [here](https://github.com/meshtastic/Meshtastic-Android).
After our rate of change slows a bit, we will make beta builds available here (without needing to join the alphatest group): Alpha test builds available by opting into our alpha test group. See (www.meshtastic.org) for instructions.
If you don't want to live on the 'bleeding edge' you can opt-in to the beta-test or use the released version:
[![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub%26utm_medium%3Desp32-readme%26utm_campaign%3Dmeshtastic-esp32%2520readme%26anid%3Dadmob&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1) [![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub%26utm_medium%3Desp32-readme%26utm_campaign%3Dmeshtastic-esp32%2520readme%26anid%3Dadmob&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
# Python API
We offer a [python API](https://github.com/meshtastic/Meshtastic-python) that makes it easy to use these devices to provide mesh networking for your custom projects.
# Development # Development
The following sections are probably only interesting if you want to join us in developing the software.
## Power measurements We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and [join us in our discussion forum](https://meshtastic.discourse.group/).
Since one of the main goals of this project is long battery life, it is important to consider that in our software/protocol design. Based on initial measurements it seems that the current code should run about three days between charging, and with a bit more software work (see the [TODO list](TODO.md)) a battery life of eight days should be quite doable. Our current power measurements/model is in [this spreadsheet](https://docs.google.com/spreadsheets/d/1ft1bS3iXqFKU8SApU8ZLTq9r7QQEGESYnVgdtvdT67k/edit?usp=sharing).
## Build instructions # Credits
This project uses the simple PlatformIO build system. You can use the IDE, but for brevity
in these instructions I describe use of their command line tool.
1. Purchase a suitable radio (see above) This project is run by volunteers. Past contributors include:
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it - @astro-arphid: Added support for 433MHz radios in europe.
4. Plug the radio into your USB port - @claesg: Various documentation fixes and 3D print enclosures
4. Type "pio run -t upload" (This command will fetch dependencies, build the project and install it on the board via USB) - @girtsf: Lots of improvements
5. Platform IO also installs a very nice VisualStudio Code based IDE, see their [tutorial](https://docs.platformio.org/en/latest/tutorials/espressif32/arduino_debugging_unit_testing.html) if you'd like to use it - @spattinson: Fixed interrupt handling for the AXP192 part
# IMPORTANT DISCLAIMERS AND FAQ
For a listing of currently missing features and a FAQ click [here](docs/faq.md).
Copyright 2019 Geeksville Industries, LLC. GPL V3 Licensed.

192
TODO.md
View File

@@ -1,192 +0,0 @@
# High priority
Items to complete soon (next couple of alpha releases).
* lower wait_bluetooth_secs to 30 seconds once we have the GPS power on (but GPS in sleep mode) across light sleep. For the time
being I have it set at 2 minutes to ensure enough time for a GPS lock from scratch.
* use gps sleep mode instead of killing its power (to allow fast position when we wake)
* enable fast lock and low power inside the gps chip
* remeasure wake time power draws now that we run CPU down at 80MHz
# AXP192 tasks
* "AXP192 interrupt is not firing, remove this temporary polling of battery state"
* make debug info screen show real data (including battery level & charging) - close corresponding github issue
# Medium priority
Items to complete before the first beta release.
* Make a FAQ
* good source of battery/signal/gps icons https://materialdesignicons.com/
* investigate changing routing to https://github.com/sudomesh/LoRaLayer2 ?
* check fcc rules on duty cycle. we might not need to freq hop. https://www.sunfiretesting.com/LoRa-FCC-Certification-Guide/
* use fuse bits to store the board type and region. So one load can be used on all boards
* research and implement better mesh algorithm
* the BLE stack is leaking about 200 bytes each time we go to light sleep
* rx signal measurements -3 marginal, -9 bad, 10 great, -10 means almost unusable. So scale this into % signal strength. preferably as a graph, with an X indicating loss of comms.
* assign every "channel" a random shared 8 bit sync word (per 4.2.13.6 of datasheet) - use that word to filter packets before even checking CRC. This will ensure our CPU will only wake for packets on our "channel"
* Note: we do not do address filtering at the chip level, because we might need to route for the mesh
* add basic crypto - https://github.com/chegewara/esp32-mbedtls-aes-test/blob/master/main/main.c https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation - use ECB at first (though it is shit) because it doesn't require us to send 16 bytes of IV with each packet. Then OFB per example
* add frequency hopping, dependent on the gps time, make the switch moment far from the time anyone is going to be transmitting
* share channel settings over Signal (or qr code) by embedding an an URL which is handled by the MeshUtil app.
* publish update articles on the web
# Pre-beta priority
During the beta timeframe the following improvements 'would be nice' (and yeah - I guess some of these items count as features, but it is a hobby project ;-) )
* If the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs
for it (because it will redownload the nodedb when it comes back)
* Figure out why the RF95 ISR is never seeing RH_RF95_VALID_HEADER, so it is not protecting our rx packets from getting stomped on by sends
* fix the frequency error reading in the RF95 RX code (can't do floating point math in an ISR ;-)
* See CustomRF95::send and fix the problem of dropping partially received packets if we want to start sending
* make sure main cpu is not woken for packets with bad crc or not addressed to this node - do that in the radio hw
* triple check fcc compliance
* pick channel center frequency based on channel name? "dolphin" would hash to 900Mhz, "cat" to 905MHz etc? allows us to hide the concept of channel # from hte user.
* scan to find channels with low background noise? (Use CAD mode of the RF95 to automatically find low noise channels)
* make a no bluetooth configured yet screen - include this screen in the loop if the user hasn't yet paired
* if radio params change fundamentally, discard the nodedb
* reneable the bluetooth battery level service on the T-BEAM, because we can read battery level there
# Spinoff project ideas
* an open source version of https://www.burnair.ch/skynet/
* a paragliding app like http://airwhere.co.uk/
* a version with a solar cell for power, just mounted high to permanently provide routing for nodes in a valley. Someone just pointed me at disaster.radio
* How do avalanche beacons work? Could this do that as well? possibly by using beacon mode feature of the RF95?
* provide generalized (but slow) internet message forwarding servie if one of our nodes has internet connectivity
# Low priority
Items after the first final candidate release.
* use variable length arduino Strings in protobufs (instead of current fixed buffers)
* use BLEDevice::setPower to lower our BLE transmit power - extra range doesn't help us, it costs amps and it increases snoopability
* make an install script to let novices install software on their boards
* use std::map<NodeInfo*, std::string> in node db
* make a HAM build: yep - that's a great idea. I'll add it to the TODO. should be pretty painless - just a new frequency list, a bool to say 'never do encryption' and use hte callsign as that node's unique id. -from Girts
* don't forward redundant pings or ping responses to the phone, it just wastes phone battery
* use https://platformio.org/lib/show/1260/OneButton if necessary
* don't send location packets if we haven't moved
* scrub default radio config settings for bandwidth/range/speed
* answer to pings (because some other user is looking at our nodeinfo) with our latest location (not a stale location)
* show radio and gps signal strength as an image
* only BLE advertise for a short time after the screen is on and button pressed - to save power and prevent people for sniffing for our BT app.
* make mesh aware network timing state machine (sync wake windows to gps time)
* split out the software update utility so other projects can use it. Have the appload specify the URL for downloads.
* read the PMU battery fault indicators and blink/led/warn user on screen
* the AXP debug output says it is trying to charge at 700mA, but the max I've seen is 180mA, so AXP registers probably need to be set to tell them the circuit can only provide 300mAish max. So that the low charge rate kicks in faster and we don't wear out batteries.
* increase the max charging rate a bit for 18650s, currently it limits to 180mA (at 4V). Work backwards from the 500mA USB limit (at 5V) and let the AXP charge at that rate.
* discard very old nodedb records (> 1wk)
* using the genpartitions based table doesn't work on TTGO so for now I stay with my old memory map
* We let anyone BLE scan for us (FIXME, perhaps only allow that until we are paired with a phone and configured)
* use two different buildenv flags for ttgo vs lora32. https://docs.platformio.org/en/latest/ide/vscode.html#key-bindings
* sim gps data for testing nodes that don't have hardware
* do debug serial logging to android over bluetooth
* break out my bluetooth OTA software as a seperate library so others can use it
* Heltec LoRa32 has 8MB flash, use a bigger partition table if needed - TTGO is 4MB but has PSRAM
* add a watchdog timer
* handle millis() rollover in GPS.getTime - otherwise we will break after 50 days
* report esp32 device code bugs back to the mothership via android
# Done
* change the partition table to take advantage of the 4MB flash on the wroom: http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
* wrap in nice MeshRadio class
* add mesh send & rx
* make message send from android go to service, then to mesh radio
* make message receive from radio go through to android
* test loopback tx/rx path code without using radio
* notify phone when rx packets arrive, currently the phone polls at startup only
* figure out if we can use PA_BOOST - yes, it seems to be on both boards
* implement new ble characteristics
* have MeshService keep a node DB by sniffing user messages
* have a state machine return the correct FromRadio packet to the phone, it isn't always going to be a MeshPacket. Do a notify on fromnum to force the radio to read our state machine generated packets
* send my_node_num when phone sends WantsNodes
* have meshservice periodically send location data on mesh (if device has a GPS)
* implement getCurrentTime() - set based off gps but then updated locally
* make default owner record have valid usernames
* message loop between node 0x28 and 0x7c
* check in my radiolib fixes
* figure out what is busted with rx
* send our owner info at boot, reply if we see anyone send theirs
* add manager layers
* confirm second device receives that gps message and updates device db
* send correct hw vendor in the bluetooth info - needed so the android app can update different radio models
* correctly map nodeids to nodenums, currently we just do a proof of concept by always doing a broadcast
* add interrupt detach/sleep mode config to lora radio so we can enable deepsleep without panicing
* make jtag work on second board
* implement regen owner and radio prefs
* use a better font
* make nice screens (boot, about to sleep, debug info (gps signal, #people), latest text, person info - one frame per person on network)
* turn framerate from ui->state.frameState to 1 fps (or less) unless in transition
* switch to my gui layout manager
* make basic gui. different screens: debug, one page for each user in the user db, last received text message
* make button press cycle between screens
* save our node db on entry to sleep
* fix the logo
* sent/received packets (especially if a node was just reset) have variant of zero sometimes - I think there is a bug (race-condtion?) in the radio send/rx path.
* DONE dynamic nodenum assignment tasks
* make jtag debugger id stable: https://askubuntu.com/questions/49910/how-to-distinguish-between-identical-usb-to-serial-adapters
* reported altitude is crap
* good tips on which bands might be more free https://github.com/TheThingsNetwork/ttn/issues/119
* finish power measurements (GPS on during sleep vs LCD on during sleep vs LORA on during sleep) and est battery life
* make screen sleep behavior work
* make screen advance only when a new node update arrives, a new text arrives or the user presses a button, turn off screen after a while
* after reboot, channel number is getting reset to zero! fix!
* send user and location events much less often
* send location (or if not available user) when the user wakes the device from display sleep (both for testing and to improve user experience)
* make real implementation of getNumOnlineNodes
* very occasionally send our position and user packet based on the schedule in the radio info (if for nothing else so that other nodes update last_seen)
* show real text info on the text screen
* apply radio settings from android land
* cope with nodes that have 0xff or 0x00 as the last byte of their mac
* allow setting full radio params from android
* add receive timestamps to messages, inserted by esp32 when message is received but then shown on the phone
* update build to generate both board types
* have node info screen show real info (including distance and heading)
* blink the power led less often
* have radiohead ISR send messages to RX queue directly, to allow that thread to block until we have something to send
* move lora rx/tx to own thread and block on IO
* keep our pseudo time moving forward even if we enter deep sleep (use esp32 rtc)
* for non GPS equipped devices, set time from phone
* GUI on oled hangs for a few seconds occasionally, but comes back
* update local GPS position (but do not broadcast) at whatever rate the GPS is giving it
* don't send our times to other nodes
* don't trust times from other nodes
* draw compass rose based off local walking track
* add requestResponse optional bool - use for location broadcasts when sending tests
* post sample video to signal forum
* support non US frequencies
* send pr https://github.com/ThingPulse/esp8266-oled-ssd1306 to tell them about this project
* document rules for sleep wrt lora/bluetooth/screen/gps. also: if I have text messages (only) for the phone, then give a few seconds in the hopes BLE can get it across before we have to go back to sleep.
* wake from light sleep as needed for our next scheduled periodic task (needed for gps position broadcasts etc)
* turn bluetooth off based on our sleep policy
* blink LED while in LS sleep mode
* scrolling between screens based on press is busted
* Use Neo-M8M API to put it in sleep mode (on hold until my new boards arrive)
* update the prebuilt bins for different regulatory regions
* don't enter NB state if we've recently talked to the phone (to prevent breaking syncing or bluetooth sw update)
* have sw update prevent BLE sleep
* manually delete characteristics/descs
* leave lora receiver always on
* protobufs are sometimes corrupted after sleep!
* stay awake while charging
* check gps battery voltage
* if a position report includes ground truth time and we don't have time yet, set our clock from that. It is better than nothing.
* retest BLE software update for both board types
* report on wikifactory
* send note to the guy who designed the cases
* turn light sleep on aggressively (while lora is on but BLE off)
* Use the Periodic class for both position and user periodic broadcasts
* don't treat north as up, instead adjust shown bearings for our guess at the users heading (i.e. subtract one from the other)
* sendToMesh can currently block for a long time, instead have it just queue a packet for a radio freertos thread
* don't even power on bluetooth until we have some data to send to the android phone. Most of the time we should be sleeping in a lowpower "listening for lora" only mode. Once we have some packets for the phone, then power on bluetooth
until the phone pulls those packets. Ever so often power on bluetooth just so we can see if the phone wants to send some packets. Possibly might need ULP processor to help with this wake process.
* do hibernation mode to get power draw down to 2.5uA https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/
* fix GPS.zeroOffset calculation it is wrong
* (needs testing) fixed the following during a plane flight:
Have state machine properly enter deep sleep based on loss of mesh and phone comms.
Default to enter deep sleep if no LORA received for two hours (indicates user has probably left the mesh).
* (fixed I think) text messages are not showing on local screen if screen was on

View File

@@ -4,11 +4,13 @@ set -e
source bin/version.sh source bin/version.sh
COUNTRIES="US EU CN JP" COUNTRIES="US EU433 EU865 CN JP"
# COUNTRIES=US #COUNTRIES=US
#COUNTRIES=CN
BOARDS="ttgo-lora32-v2 ttgo-lora32-v1 tbeam heltec"
#BOARDS=tbeam
SRCMAP=.pio/build/esp32/output.map
SRCBIN=.pio/build/esp32/firmware.bin
OUTDIR=release/latest OUTDIR=release/latest
# We keep all old builds (and their map files in the archive dir) # We keep all old builds (and their map files in the archive dir)
@@ -16,27 +18,41 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware* rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins $OUTDIR/elfs
rm -f $OUTDIR/bins/*
# build the named environment and copy the bins to the release directory
function do_build {
ENV_NAME=$1
echo "Building for $ENV_NAME with $PLATFORMIO_BUILD_FLAGS"
SRCBIN=.pio/build/$ENV_NAME/firmware.bin
SRCELF=.pio/build/$ENV_NAME/firmware.elf
rm -f $SRCBIN
# The shell vars the build tool expects to find
export HW_VERSION="1.0-$COUNTRY"
export APP_VERSION=$VERSION
export COUNTRY
pio run --jobs 4 --environment $ENV_NAME # -v
cp $SRCBIN $OUTDIR/bins/firmware-$ENV_NAME-$COUNTRY-$VERSION.bin
cp $SRCELF $OUTDIR/elfs/firmware-$ENV_NAME-$COUNTRY-$VERSION.elf
}
# Make sure our submodules are current
git submodule update
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio lib update
for COUNTRY in $COUNTRIES; do for COUNTRY in $COUNTRIES; do
for BOARD in $BOARDS; do
HWVERSTR="1.0-$COUNTRY" do_build $BOARD
COMMONOPTS="-DAPP_VERSION=$VERSION -DHW_VERSION_$COUNTRY -DHW_VERSION=$HWVERSTR -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -Wl,-Map,.pio/build/esp32/output.map -DAXP_DEBUG_PORT=Serial" done
export PLATFORMIO_BUILD_FLAGS="-DT_BEAM_V10 $COMMONOPTS"
echo "Building with $PLATFORMIO_BUILD_FLAGS"
rm -f $SRCBIN $SRCMAP
pio run # -v
cp $SRCBIN $OUTDIR/firmware-TBEAM-$COUNTRY-$VERSION.bin
#cp $SRCMAP $ARCHIVEDIR/firmware-TBEAM-$COUNTRY-$VERSION.map
export PLATFORMIO_BUILD_FLAGS="-DHELTEC_LORA32 $COMMONOPTS"
rm -f $SRCBIN $SRCMAP
pio run # -v
cp $SRCBIN $OUTDIR/firmware-HELTEC-$COUNTRY-$VERSION.bin
#cp $SRCMAP $ARCHIVEDIR/firmware-HELTEC-$COUNTRY-$VERSION.map
done done
# keep the bins in archive also # keep the bins in archive also
cp $OUTDIR/firmware* $ARCHIVEDIR cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $ARCHIVEDIR
cat >$OUTDIR/curfirmwareversion.xml <<XML cat >$OUTDIR/curfirmwareversion.xml <<XML
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
@@ -51,6 +67,6 @@ Generated by bin/buildall.sh -->
XML XML
rm -f $ARCHIVEDIR/firmware-$VERSION.zip rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/firmware-*-$VERSION.bin zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh
echo BUILT ALL echo BUILT ALL

11
bin/device-install.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -e
FILENAME=$1
echo "Trying to flash $FILENAME, but first erasing and writing system information"
esptool.py --baud 921600 erase_flash
esptool.py --baud 921600 write_flash 0x1000 system-info.bin
esptool.py --baud 921600 write_flash 0x10000 $FILENAME

8
bin/device-update.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
set -e
FILENAME=$1
echo "Trying to update $FILENAME"
esptool.py --baud 921600 writeflash 0x10000 $FILENAME

329
bin/exception_decoder.py Executable file
View File

@@ -0,0 +1,329 @@
#!/usr/bin/env python3
"""ESP Exception Decoder
github: https://github.com/janLo/EspArduinoExceptionDecoder
license: GPL v3
author: Jan Losinski
Meshtastic notes:
* original version is at: https://github.com/janLo/EspArduinoExceptionDecoder
* version that's checked into meshtastic repo is based on: https://github.com/me21/EspArduinoExceptionDecoder
which adds in ESP32 Backtrace decoding.
* this also updates the defaults to use ESP32, instead of ESP8266 and defaults to the built firmware.bin
To use, copy the "Backtrace: 0x...." line to a file, e.g., backtrace.txt, then run:
$ bin/exception_decoder.py backtrace.txt
"""
import argparse
import re
import subprocess
from collections import namedtuple
import sys
import os
EXCEPTIONS = [
"Illegal instruction",
"SYSCALL instruction",
"InstructionFetchError: Processor internal physical address or data error during instruction fetch",
"LoadStoreError: Processor internal physical address or data error during load or store",
"Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register",
"Alloca: MOVSP instruction, if caller's registers are not in the register file",
"IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero",
"reserved",
"Privileged: Attempt to execute a privileged operation when CRING ? 0",
"LoadStoreAlignmentCause: Load or store to an unaligned address",
"reserved",
"reserved",
"InstrPIFDataError: PIF data error during instruction fetch",
"LoadStorePIFDataError: Synchronous PIF data error during LoadStore access",
"InstrPIFAddrError: PIF address error during instruction fetch",
"LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access",
"InstTLBMiss: Error during Instruction TLB refill",
"InstTLBMultiHit: Multiple instruction TLB entries matched",
"InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level less than CRING",
"reserved",
"InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch",
"reserved",
"reserved",
"reserved",
"LoadStoreTLBMiss: Error during TLB refill for a load or store",
"LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store",
"LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING",
"reserved",
"LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads",
"StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores"
]
PLATFORMS = {
"ESP8266": "lx106",
"ESP32": "esp32"
}
BACKTRACE_REGEX = re.compile(r"(?:\s+(0x40[0-2](?:\d|[a-f]|[A-F]){5}):0x(?:\d|[a-f]|[A-F]){8})\b")
EXCEPTION_REGEX = re.compile("^Exception \\((?P<exc>[0-9]*)\\):$")
COUNTER_REGEX = re.compile('^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) '
'excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$')
CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$")
POINTER_REGEX = re.compile('^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$')
STACK_BEGIN = '>>>stack>>>'
STACK_END = '<<<stack<<<'
STACK_REGEX = re.compile(
'^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$')
StackLine = namedtuple("StackLine", ["offset", "content"])
class ExceptionDataParser(object):
def __init__(self):
self.exception = None
self.epc1 = None
self.epc2 = None
self.epc3 = None
self.excvaddr = None
self.depc = None
self.ctx = None
self.sp = None
self.end = None
self.offset = None
self.stack = []
def _parse_backtrace(self, line):
if line.startswith('Backtrace:'):
self.stack = [StackLine(offset=0, content=(addr,)) for addr in BACKTRACE_REGEX.findall(line)]
return None
return self._parse_backtrace
def _parse_exception(self, line):
match = EXCEPTION_REGEX.match(line)
if match is not None:
self.exception = int(match.group('exc'))
return self._parse_counters
return self._parse_exception
def _parse_counters(self, line):
match = COUNTER_REGEX.match(line)
if match is not None:
self.epc1 = match.group("epc1")
self.epc2 = match.group("epc2")
self.epc3 = match.group("epc3")
self.excvaddr = match.group("excvaddr")
self.depc = match.group("depc")
return self._parse_ctx
return self._parse_counters
def _parse_ctx(self, line):
match = CTX_REGEX.match(line)
if match is not None:
self.ctx = match.group("ctx")
return self._parse_pointers
return self._parse_ctx
def _parse_pointers(self, line):
match = POINTER_REGEX.match(line)
if match is not None:
self.sp = match.group("sp")
self.end = match.group("end")
self.offset = match.group("offset")
return self._parse_stack_begin
return self._parse_pointers
def _parse_stack_begin(self, line):
if line == STACK_BEGIN:
return self._parse_stack_line
return self._parse_stack_begin
def _parse_stack_line(self, line):
if line != STACK_END:
match = STACK_REGEX.match(line)
if match is not None:
self.stack.append(StackLine(offset=match.group("off"),
content=(match.group("c1"), match.group("c2"), match.group("c3"),
match.group("c4"))))
return self._parse_stack_line
return None
def parse_file(self, file, platform, stack_only=False):
if platform == 'ESP32':
func = self._parse_backtrace
else:
func = self._parse_exception
if stack_only:
func = self._parse_stack_begin
for line in file:
func = func(line.strip())
if func is None:
break
if func is not None:
print("ERROR: Parser not complete!")
sys.exit(1)
class AddressResolver(object):
def __init__(self, tool_path, elf_path):
self._tool = tool_path
self._elf = elf_path
self._address_map = {}
def _lookup(self, addresses):
cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None]
if sys.version_info[0] < 3:
output = subprocess.check_output(cmd)
else:
output = subprocess.check_output(cmd, encoding="utf-8")
line_regex = re.compile("^(?P<addr>[0-9a-fx]+): (?P<result>.+)$")
last = None
for line in output.splitlines():
line = line.strip()
match = line_regex.match(line)
if match is None:
if last is not None and line.startswith('(inlined by)'):
line = line [12:].strip()
self._address_map[last] += ("\n \-> inlined by: " + line)
continue
if match.group("result") == '?? ??:0':
continue
self._address_map[match.group("addr")] = match.group("result")
last = match.group("addr")
def fill(self, parser):
addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset]
for line in parser.stack:
addresses.extend(line.content)
self._lookup(addresses)
def _sanitize_addr(self, addr):
if addr.startswith("0x"):
addr = addr[2:]
fill = "0" * (8 - len(addr))
return "0x" + fill + addr
def resolve_addr(self, addr):
out = self._sanitize_addr(addr)
if out in self._address_map:
out += ": " + self._address_map[out]
return out
def resolve_stack_addr(self, addr, full=True):
addr = self._sanitize_addr(addr)
if addr in self._address_map:
return addr + ": " + self._address_map[addr]
if full:
return "[DATA (0x" + addr + ")]"
return None
def print_addr(name, value, resolver):
print("{}:{} {}".format(name, " " * (8 - len(name)), resolver.resolve_addr(value)))
def print_stack_full(lines, resolver):
print("stack:")
for line in lines:
print(line.offset + ":")
for content in line.content:
print(" " + resolver.resolve_stack_addr(content))
def print_stack(lines, resolver):
print("stack:")
for line in lines:
for content in line.content:
out = resolver.resolve_stack_addr(content, full=False)
if out is None:
continue
print(out)
def print_result(parser, resolver, platform, full=True, stack_only=False):
if platform == 'ESP8266' and not stack_only:
print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception]))
print("")
print_addr("epc1", parser.epc1, resolver)
print_addr("epc2", parser.epc2, resolver)
print_addr("epc3", parser.epc3, resolver)
print_addr("excvaddr", parser.excvaddr, resolver)
print_addr("depc", parser.depc, resolver)
print("")
print("ctx: " + parser.ctx)
print("")
print_addr("sp", parser.sp, resolver)
print_addr("end", parser.end, resolver)
print_addr("offset", parser.offset, resolver)
print("")
if full:
print_stack_full(parser.stack, resolver)
else:
print_stack(parser.stack, resolver)
def parse_args():
parser = argparse.ArgumentParser(description="decode ESP Stacktraces.")
parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(),
default="ESP32")
parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain",
default="~/.platformio/packages/toolchain-xtensa32/")
parser.add_argument("-e", "--elf", help="path to elf file",
default=".pio/build/esp32/firmware.elf")
parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true")
parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true")
parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-")
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
if args.file == "-":
file = sys.stdin
else:
if not os.path.exists(args.file):
print("ERROR: file " + args.file + " not found")
sys.exit(1)
file = open(args.file, "r")
addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)),
"bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line")
if os.name == 'nt':
addr2line += '.exe'
if not os.path.exists(addr2line):
print("ERROR: addr2line not found (" + addr2line + ")")
elf_file = os.path.abspath(os.path.expanduser(args.elf))
if not os.path.exists(elf_file):
print("ERROR: elf file not found (" + elf_file + ")")
parser = ExceptionDataParser()
resolver = AddressResolver(addr2line, elf_file)
parser.parse_file(file, args.platform, args.stack_only)
resolver.fill(parser)
print_result(parser, resolver, args.platform, args.full, args.stack_only)

1
bin/nrf52-console.sh Executable file
View File

@@ -0,0 +1 @@
JLinkRTTViewer

View File

@@ -3,4 +3,4 @@ set -e
source bin/version.sh source bin/version.sh
esptool.py --baud 921600 write_flash 0x10000 release/latest/firmware-HELTEC-US-$VERSION.bin esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-heltec-US-$VERSION.bin

6
bin/program-release-tbeam.sh Executable file
View File

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

1
bin/read-system-info.sh Executable file
View File

@@ -0,0 +1 @@
esptool.py --baud 921600 read_flash 0x1000 0xf000 system-info.img

View File

@@ -3,4 +3,4 @@
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.1"
# the nanopb tool seems to require that the .options file be in the current directory! # the nanopb tool seems to require that the .options file be in the current directory!
cd proto cd proto
../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src -I=../proto mesh.proto ../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto mesh.proto

1
bin/run-1-monitor.sh Executable file
View File

@@ -0,0 +1 @@
pio run --upload-port /dev/ttyUSB1 -t upload -t monitor

View File

@@ -1 +0,0 @@
pio device monitor -b 115200

1
bin/start-terminal0.sh Executable file
View File

@@ -0,0 +1 @@
pio device monitor -b 921600

1
bin/start-terminal1.sh Executable file
View File

@@ -0,0 +1 @@
pio device monitor -p /dev/ttyUSB1 -b 921600

View File

@@ -1,3 +1,3 @@
export VERSION=0.1.0 export VERSION=0.6.4

View File

@@ -0,0 +1,46 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4404"]],
"usb_product": "SimPPR",
"mcu": "nrf52840",
"variant": "pca10056-rc-clock",
"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": "A modified NRF52840-DK devboard (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": ["jlink", "nrfjprog", "stlink"]
},
"url": "https://meshtastic.org/",
"vendor": "Nordic Semi"
}

46
boards/ppr.json Normal file
View File

@@ -0,0 +1,46 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PPR -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4403"]],
"usb_product": "PPR",
"mcu": "nrf52840",
"variant": "ppr",
"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": "Meshtastic PPR (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": ["jlink", "nrfjprog", "stlink"]
},
"url": "https://meshtastic.org/",
"vendor": "Othernet"
}

View File

@@ -4,6 +4,6 @@
"namespace": "android_app", "namespace": "android_app",
"package_name": "com.geeksville.mesh", "package_name": "com.geeksville.mesh",
"sha256_cert_fingerprints": "sha256_cert_fingerprints":
["D0:05:E7:8B:D2:1B:FA:94:56:1D:6B:90:EB:53:07:1A:74:4F:D9:C2:6F:13:87:6A:D9:17:4F:C2:59:48:02:9D"] ["D0:05:E7:8B:D2:1B:FA:94:56:1D:6B:90:EB:53:07:1A:74:4F:D9:C2:6F:13:87:6A:D9:17:4F:C2:59:48:02:9D", "42:17:52:DC:57:40:38:B5:6B:86:61:1C:2F:47:DB:2B:0F:A2:EA:59:E1:18:9C:AA:90:8D:37:D6:CD:40:0E:BB", "A9:3B:45:65:68:C1:75:DB:08:00:A0:9F:06:77:7F:89:2D:81:24:32:AD:B8:A3:DF:73:BC:3E:7F:06:C8:0C:6D"]
} }
}] }]

View File

@@ -1,82 +1,78 @@
# What is Meshtastic? # 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, super long battery life mesh GPS communicator. These radios are great for hiking, skiing, paragliding - 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.
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 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.
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..) - 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...) - Applications where closed source GPS communicators just won't cut it (it is easy to add features for glider pilots etc...)
* Secure long-range communication within groups without depending on cellular providers - Secure long-range communication within groups without depending on cellular providers
* Finding your lost kids ;-) - Finding your lost kids ;-)
- Through our [python API](https://pypi.org/project/meshtastic/) use these inexpensive radios to easily add mesh networking to your own projects.
[![Youtube video demo](desk-video-screenshot.png)](https://www.youtube.com/watch?v=WlNbMbVZlHI "Meshtastic early demo") [![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?)
* Very long battery life (should be about eight days with the beta software) 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?)
* Built in GPS and [LoRa](https://en.wikipedia.org/wiki/LoRa) radio, but we manage the radio automatically for you
* Long range - a few miles per node but each node will forward packets as needed
* Shows direction and distance to all members of your channel
* Directed or broadcast text messages for channel members
* Open and extensible codebase supporting multiple hardware vendors - no lock in to one vendor
* Communication API for bluetooth devices (such as our Android app) to use the mesh. So if you have some application that needs long range low power networking, this might work for you.
* Eventually (within a couple of months) we should have a modified version of Signal that works with this project.
* Very easy sharing of private secured channels. Just share a special link or QR code with friends and they can join your encrypted mesh
This project is currently in early alpha - if you have questions please join our chat [![Join the chat at https://gitter.im/Meshtastic/community](https://badges.gitter.im/Meshtastic/community.svg)](https://gitter.im/Meshtastic/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [chat](https://gitter.im/Meshtastic/community). - Very long battery life (should be about eight days with the beta software)
- Built in GPS and [LoRa](https://en.wikipedia.org/wiki/LoRa) radio, but we manage the radio automatically for you
- Long range - a few miles per node but each node will forward packets as needed
- Shows direction and distance to all members of your channel
- Directed or broadcast text messages for channel members
- Open and extensible codebase supporting multiple hardware vendors - no lock in to one vendor
- Communication API for bluetooth devices (such as our Android app) to use the mesh. So if you have some application that needs long range low power networking, this might work for you.
- Eventually (within a couple of months) we should have a modified version of Signal that works with this project.
- Very easy sharing of private secured channels. Just share a special link or QR code with friends and they can join your encrypted mesh
This project is currently in early alpha - if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [forum](https://meshtastic.discourse.group/).
# Updates # Updates
Note: Updates are happening almost daily, only major updates are listed below. For more details see our chat, github releases or the Android alpha tester emails. Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum.
* 03/03/2020 - 0.0.9 of the Android app and device code is released. Still an alpha but fairly functional. - 04/28/2020 - 0.6.0 [Python API](https://pypi.org/project/meshtastic/) released. Makes it easy to use meshtastic devices as "zero config / just works" mesh transport adapters for other projects.
* 02/25/2020 - 0.0.4 of the Android app is released. This is a very early alpha, see below to join the alpha-testers group. - 04/20/2020 - 0.4.3 Pretty solid now both for the android app and the device code. Many people have donated translations and code. Probably going to call it a beta soon.
* 02/23/2020 - 0.0.4 release. Still very bleeding edge but much closer to the final power management, a charged T-BEAM should run for many days with this load. If you'd like to try it, we'd love your feedback. Click [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md) for instructions. - 03/03/2020 - 0.0.9 of the Android app and device code is released. Still an alpha but fairly functional.
* 02/20/2020 - Our first alpha release (0.0.3) of the radio software is ready brave early people. - 02/25/2020 - 0.0.4 of the Android app is released. This is a very early alpha, see below to join the alpha-testers group.
- 02/23/2020 - 0.0.4 release. Still very bleeding edge but much closer to the final power management, a charged T-BEAM should run for many days with this load. If you'd like to try it, we'd love your feedback. Click [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md) for instructions.
- 02/20/2020 - Our first alpha release (0.0.3) of the radio software is ready brave early people.
## Meshtastic Android app ## Meshtastic Android app
Once out of alpha the companion Android application will be released here:
Our Android application is available here:
[![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dhomepage%26anid%3Dadmob) [![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dhomepage%26anid%3Dadmob)
But if you want the bleeding edge app now, we'd love to have your help testing. Three steps to opt-in to the alpha- test: The link above will return older more stable releases. We would prefer if you join our alpha-test group, because the application is rapidly improving. Three steps to opt-in to the alpha- test:
1. Join [this Google group](https://groups.google.com/forum/#!forum/meshtastic-alpha-testers) with the account you use in Google Play. 1. Join [this Google group](https://groups.google.com/forum/#!forum/meshtastic-alpha-testers) with the account you use in Google Play.
2. Go to this [URL](https://play.google.com/apps/testing/com.geeksville.mesh) to opt-in to the alpha test. 2. Go to this [URL](https://play.google.com/apps/testing/com.geeksville.mesh) to opt-in to the alpha test.
3. If you encounter any problems or have questions, post in our gitter chat and we'll help. 3. If you encounter any problems or have questions, post in our [forum](https://meshtastic.discourse.group/) and we'll help.
If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android). If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android).
## Supported hardware ## Supported hardware
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than $35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen is optional, but highly recommended. We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than \$35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen is optional, but highly recommended.
Instructions for installing prebuilt firmware can be found [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md). Instructions for installing prebuilt firmware can be found [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md).
For a nice TTGO 3D printable case see this [design](https://www.thingiverse.com/thing:3773717) by [bsiege](https://www.thingiverse.com/bsiege). For a nice printable cases:
For a nice Heltec 3D printable case see this [design](https://www.thingiverse.com/thing:3125854) by [ornotermes](https://www.thingiverse.com/ornotermes).
# Disclaimers 1. TTGO T-Beam V0 see this [design](https://www.thingiverse.com/thing:3773717) by [bsiege](https://www.thingiverse.com/bsiege).
2. TTGO T_Beam V1 see this [design](https://www.thingiverse.com/thing:3830711) by [rwanrooy](https://www.thingiverse.com/rwanrooy) or this [remix](https://www.thingiverse.com/thing:3949330) by [8ung](https://www.thingiverse.com/8ung)
3. Heltec Lora32 see this [design](https://www.thingiverse.com/thing:3125854) by [ornotermes](https://www.thingiverse.com/ornotermes).
This project is still pretty young but moving at a pretty good pace. Not all features are fully implemented in the current alpha builds. # IMPORTANT DISCLAIMERS AND FAQ
Most of these problems should be solved by the beta release:
* We don't make these devices and they haven't been tested by UL or the FCC. If you use them you are experimenting and we can't promise they won't burn your house down ;-) For a listing of currently missing features and a FAQ click [here](faq.md).
* Encryption is turned off for now
* A number of (straightforward) software work items have to be completed before battery life matches our measurements, currently battery life is about three days. Join us on chat if you want the spreadsheet of power measurements/calculations.
* The current Android GUI is pretty ugly still
* The Android API needs to be documented better
* The Bluetooth API needs to be documented better
* The mesh protocol is turned off for now, currently we only send packets one hop distant
* No one has written an iOS app yet ;-)
For more details see the [device software TODO](https://github.com/meshtastic/Meshtastic-esp32/blob/master/TODO.md) or the [Android app TODO](https://github.com/meshtastic/Meshtastic-Android/blob/master/TODO.md).

View File

@@ -3,3 +3,6 @@ theme: jekyll-theme-cayman
title: Meshtastic title: Meshtastic
description: An opensource hiking, pilot, skiing, Signal-App-extending GPS mesh communicator description: An opensource hiking, pilot, skiing, Signal-App-extending GPS mesh communicator
google_analytics: G-DRZ5H5EXHV google_analytics: G-DRZ5H5EXHV
include: [".well-known"]

34
docs/faq.md Normal file
View File

@@ -0,0 +1,34 @@
# Disclaimers
This project is still pretty young but moving at a pretty good pace. Not all features are fully implemented in the current alpha builds.
Most of these problems should be solved by the beta release (within three months):
- We don't make these devices and they haven't been tested by UL or the FCC. If you use them you are experimenting and we can't promise they won't burn your house down ;-)
- The encryption [implementation](software/crypto.md) has not been reviewed by an expert. (Are you an expert? Please help us)
- A number of (straightforward) software work items have to be completed before battery life matches our measurements, currently battery life is about three days. Join us on chat if you want the spreadsheet of power measurements/calculations.
- The Android API needs to be documented better
- No one has written an iOS app yet. But some good souls [are talking about it](https://github.com/meshtastic/Meshtastic-esp32/issues/14) ;-)
For more details see the [device software TODO](https://github.com/meshtastic/Meshtastic-esp32/blob/master/docs/software/TODO.md) or the [Android app TODO](https://github.com/meshtastic/Meshtastic-Android/blob/master/TODO.md).
# FAQ
If you have a question missing from this faq, please [ask in our discussion forum](https://meshtastic.discourse.group/). And if you are feeling extra generous send in a pull-request for this faq.md with whatever we answered ;-).
## Q: Which of the various supported radios should I buy?
Basically you just need the radio + (optional but recommended) battery. The TBEAM is usually better because it has gps and huge battery socket. The Heltec is basically the same hardware but without the GPS (the phone provides position data to the radio in that case, so the behavior is similar - but it does burn some battery in the phone). Also the battery for the Heltec can be smaller.
In addition to Aliexpress, (banggood.com) usually has stock and faster shipping, or Amazon. If buying a TBEAM, make sure to buy a version that includes the OLED screen - this project doesn't absolutely require the screen, but we use it if is installed.
@claesg has added links to various 3D printable cases, you can see them at (www.meshtastic.org).
## Q: Do you have plans to commercialize this project
Nope. though if some other person/group wanted to use this software and a more customized device we think that would be awesome (as long as they obey the GPL license).
## Q: Does this project use patented algorithms?
(Kindly borrowed from the geeks at [ffmpeg](http://ffmpeg.org/legal.html))
We do not know, we are not lawyers so we are not qualified to answer this. Also we have never read patents to implement any part of this, so even if we were qualified we could not answer it as we do not know what is patented. Furthermore the sheer number of software patents makes it impossible to read them all so no one (lawyer or not) could answer such a question with a definite no. We are merely geeks experimenting on a fun and free project.

View File

@@ -10,6 +10,13 @@ See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.ht
The maximum power allowed is +14dBM. The maximum power allowed is +14dBM.
### 433 MHz
There are eight channels defined with a 0.2 MHz gap between them.
Channel zero starts at 433.175 MHz
### 870 MHz
There are eight channels defined with a 0.3 MHz gap between them. There are eight channels defined with a 0.3 MHz gap between them.
Channel zero starts at 865.20 MHz Channel zero starts at 865.20 MHz

205
docs/software/TODO.md Normal file
View File

@@ -0,0 +1,205 @@
# High priority
Items to complete soon (next couple of alpha releases).
- lower wait_bluetooth_secs to 30 seconds once we have the GPS power on (but GPS in sleep mode) across light sleep. For the time
being I have it set at 2 minutes to ensure enough time for a GPS lock from scratch.
# Medium priority
Items to complete before the first beta release.
- Use 32 bits for message IDs
- Use fixed32 for node IDs
- Remove the "want node" node number arbitration process
- Don't store position packets in the to phone fifo if we are disconnected. The phone will get that info for 'free' when it
fetches the fresh nodedb.
- Use the RFM95 sequencer to stay in idle mode most of the time, then automatically go to receive mode and automatically go from transmit to receive mode. See 4.2.8.2 of manual.
- possibly switch to https://github.com/SlashDevin/NeoGPS for gps comms
- good source of battery/signal/gps icons https://materialdesignicons.com/
- research and implement better mesh algorithm - investigate changing routing to https://github.com/sudomesh/LoRaLayer2 ?
- check fcc rules on duty cycle. we might not need to freq hop. https://www.sunfiretesting.com/LoRa-FCC-Certification-Guide/
- use fuse bits to store the board type and region. So one load can be used on all boards
- the BLE stack is leaking about 200 bytes each time we go to light sleep
- rx signal measurements -3 marginal, -9 bad, 10 great, -10 means almost unusable. So scale this into % signal strength. preferably as a graph, with an X indicating loss of comms.
- assign every "channel" a random shared 8 bit sync word (per 4.2.13.6 of datasheet) - use that word to filter packets before even checking CRC. This will ensure our CPU will only wake for packets on our "channel"
- Note: we do not do address filtering at the chip level, because we might need to route for the mesh
is in cleartext (so that nodes will route for other radios that are cryptoed with a key we don't know)
- add frequency hopping, dependent on the gps time, make the switch moment far from the time anyone is going to be transmitting
- share channel settings over Signal (or qr code) by embedding an an URL which is handled by the MeshUtil app.
- publish update articles on the web
# Pre-beta priority
During the beta timeframe the following improvements 'would be nice' (and yeah - I guess some of these items count as features, but it is a hobby project ;-) )
- If the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs
for it (because it will redownload the nodedb when it comes back)
- Figure out why the RF95 ISR is never seeing RH_RF95_VALID_HEADER, so it is not protecting our rx packets from getting stomped on by sends
- fix the frequency error reading in the RF95 RX code (can't do floating point math in an ISR ;-)
- See CustomRF95::send and fix the problem of dropping partially received packets if we want to start sending
- make sure main cpu is not woken for packets with bad crc or not addressed to this node - do that in the radio hw
- triple check fcc compliance
- pick channel center frequency based on channel name? "dolphin" would hash to 900Mhz, "cat" to 905MHz etc? allows us to hide the concept of channel # from hte user.
- scan to find channels with low background noise? (Use CAD mode of the RF95 to automatically find low noise channels)
- make a no bluetooth configured yet screen - include this screen in the loop if the user hasn't yet paired
- if radio params change fundamentally, discard the nodedb
- reneable the bluetooth battery level service on the T-BEAM, because we can read battery level there
# Spinoff project ideas
- an open source version of https://www.burnair.ch/skynet/
- a paragliding app like http://airwhere.co.uk/
- a version with a solar cell for power, just mounted high to permanently provide routing for nodes in a valley. Someone just pointed me at disaster.radio
- How do avalanche beacons work? Could this do that as well? possibly by using beacon mode feature of the RF95?
- provide generalized (but slow) internet message forwarding servie if one of our nodes has internet connectivity
# Low priority
Items after the first final candidate release.
- use variable length arduino Strings in protobufs (instead of current fixed buffers)
- use BLEDevice::setPower to lower our BLE transmit power - extra range doesn't help us, it costs amps and it increases snoopability
- make an install script to let novices install software on their boards
- use std::map<NodeInfo\*, std::string> in node db
- make a HAM build: yep - that's a great idea. I'll add it to the TODO. should be pretty painless - just a new frequency list, a bool to say 'never do encryption' and use hte callsign as that node's unique id. -from Girts
- don't forward redundant pings or ping responses to the phone, it just wastes phone battery
- use https://platformio.org/lib/show/1260/OneButton if necessary
- don't send location packets if we haven't moved
- scrub default radio config settings for bandwidth/range/speed
- answer to pings (because some other user is looking at our nodeinfo) with our latest location (not a stale location)
- show radio and gps signal strength as an image
- only BLE advertise for a short time after the screen is on and button pressed - to save power and prevent people for sniffing for our BT app.
- make mesh aware network timing state machine (sync wake windows to gps time)
- split out the software update utility so other projects can use it. Have the appload specify the URL for downloads.
- read the PMU battery fault indicators and blink/led/warn user on screen
- the AXP debug output says it is trying to charge at 700mA, but the max I've seen is 180mA, so AXP registers probably need to be set to tell them the circuit can only provide 300mAish max. So that the low charge rate kicks in faster and we don't wear out batteries.
- increase the max charging rate a bit for 18650s, currently it limits to 180mA (at 4V). Work backwards from the 500mA USB limit (at 5V) and let the AXP charge at that rate.
- discard very old nodedb records (> 1wk)
- using the genpartitions based table doesn't work on TTGO so for now I stay with my old memory map
- We let anyone BLE scan for us (FIXME, perhaps only allow that until we are paired with a phone and configured)
- use two different buildenv flags for ttgo vs lora32. https://docs.platformio.org/en/latest/ide/vscode.html#key-bindings
- sim gps data for testing nodes that don't have hardware
- do debug serial logging to android over bluetooth
- break out my bluetooth OTA software as a seperate library so others can use it
- Heltec LoRa32 has 8MB flash, use a bigger partition table if needed - TTGO is 4MB but has PSRAM
- add a watchdog timer
- handle millis() rollover in GPS.getTime - otherwise we will break after 50 days
- report esp32 device code bugs back to the mothership via android
# Done
- change the partition table to take advantage of the 4MB flash on the wroom: http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
- wrap in nice MeshRadio class
- add mesh send & rx
- make message send from android go to service, then to mesh radio
- make message receive from radio go through to android
- test loopback tx/rx path code without using radio
- notify phone when rx packets arrive, currently the phone polls at startup only
- figure out if we can use PA_BOOST - yes, it seems to be on both boards
- implement new ble characteristics
- have MeshService keep a node DB by sniffing user messages
- have a state machine return the correct FromRadio packet to the phone, it isn't always going to be a MeshPacket. Do a notify on fromnum to force the radio to read our state machine generated packets
- send my_node_num when phone sends WantsNodes
- have meshservice periodically send location data on mesh (if device has a GPS)
- implement getCurrentTime() - set based off gps but then updated locally
- make default owner record have valid usernames
- message loop between node 0x28 and 0x7c
- check in my radiolib fixes
- figure out what is busted with rx
- send our owner info at boot, reply if we see anyone send theirs
- add manager layers
- confirm second device receives that gps message and updates device db
- send correct hw vendor in the bluetooth info - needed so the android app can update different radio models
- correctly map nodeids to nodenums, currently we just do a proof of concept by always doing a broadcast
- add interrupt detach/sleep mode config to lora radio so we can enable deepsleep without panicing
- make jtag work on second board
- implement regen owner and radio prefs
- use a better font
- make nice screens (boot, about to sleep, debug info (gps signal, #people), latest text, person info - one frame per person on network)
- turn framerate from ui->state.frameState to 1 fps (or less) unless in transition
- switch to my gui layout manager
- make basic gui. different screens: debug, one page for each user in the user db, last received text message
- make button press cycle between screens
- save our node db on entry to sleep
- fix the logo
- sent/received packets (especially if a node was just reset) have variant of zero sometimes - I think there is a bug (race-condtion?) in the radio send/rx path.
- DONE dynamic nodenum assignment tasks
- make jtag debugger id stable: https://askubuntu.com/questions/49910/how-to-distinguish-between-identical-usb-to-serial-adapters
- reported altitude is crap
- good tips on which bands might be more free https://github.com/TheThingsNetwork/ttn/issues/119
- finish power measurements (GPS on during sleep vs LCD on during sleep vs LORA on during sleep) and est battery life
- make screen sleep behavior work
- make screen advance only when a new node update arrives, a new text arrives or the user presses a button, turn off screen after a while
- after reboot, channel number is getting reset to zero! fix!
- send user and location events much less often
- send location (or if not available user) when the user wakes the device from display sleep (both for testing and to improve user experience)
- make real implementation of getNumOnlineNodes
- very occasionally send our position and user packet based on the schedule in the radio info (if for nothing else so that other nodes update last_seen)
- show real text info on the text screen
- apply radio settings from android land
- cope with nodes that have 0xff or 0x00 as the last byte of their mac
- allow setting full radio params from android
- add receive timestamps to messages, inserted by esp32 when message is received but then shown on the phone
- update build to generate both board types
- have node info screen show real info (including distance and heading)
- blink the power led less often
- have radiohead ISR send messages to RX queue directly, to allow that thread to block until we have something to send
- move lora rx/tx to own thread and block on IO
- keep our pseudo time moving forward even if we enter deep sleep (use esp32 rtc)
- for non GPS equipped devices, set time from phone
- GUI on oled hangs for a few seconds occasionally, but comes back
- update local GPS position (but do not broadcast) at whatever rate the GPS is giving it
- don't send our times to other nodes
- don't trust times from other nodes
- draw compass rose based off local walking track
- add requestResponse optional bool - use for location broadcasts when sending tests
- post sample video to signal forum
- support non US frequencies
- send pr https://github.com/ThingPulse/esp8266-oled-ssd1306 to tell them about this project
- document rules for sleep wrt lora/bluetooth/screen/gps. also: if I have text messages (only) for the phone, then give a few seconds in the hopes BLE can get it across before we have to go back to sleep.
- wake from light sleep as needed for our next scheduled periodic task (needed for gps position broadcasts etc)
- turn bluetooth off based on our sleep policy
- blink LED while in LS sleep mode
- scrolling between screens based on press is busted
- Use Neo-M8M API to put it in sleep mode (on hold until my new boards arrive)
- update the prebuilt bins for different regulatory regions
- don't enter NB state if we've recently talked to the phone (to prevent breaking syncing or bluetooth sw update)
- have sw update prevent BLE sleep
- manually delete characteristics/descs
- leave lora receiver always on
- protobufs are sometimes corrupted after sleep!
- stay awake while charging
- check gps battery voltage
- if a position report includes ground truth time and we don't have time yet, set our clock from that. It is better than nothing.
- retest BLE software update for both board types
- report on wikifactory
- send note to the guy who designed the cases
- turn light sleep on aggressively (while lora is on but BLE off)
- Use the Periodic class for both position and user periodic broadcasts
- don't treat north as up, instead adjust shown bearings for our guess at the users heading (i.e. subtract one from the other)
- sendToMesh can currently block for a long time, instead have it just queue a packet for a radio freertos thread
- don't even power on bluetooth until we have some data to send to the android phone. Most of the time we should be sleeping in a lowpower "listening for lora" only mode. Once we have some packets for the phone, then power on bluetooth
until the phone pulls those packets. Ever so often power on bluetooth just so we can see if the phone wants to send some packets. Possibly might need ULP processor to help with this wake process.
- do hibernation mode to get power draw down to 2.5uA https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/
- fix GPS.zeroOffset calculation it is wrong
- (needs testing) fixed the following during a plane flight:
Have state machine properly enter deep sleep based on loss of mesh and phone comms.
Default to enter deep sleep if no LORA received for two hours (indicates user has probably left the mesh).
- (fixed I think) text messages are not showing on local screen if screen was on
- add links to todos
- link to the kanban page
- add a getting started page
- finish mesh alg reeval
- ublox gps parsing seems a little buggy (we shouldn't be sending out read solution commands, the device is already broadcasting them)
- turn on gps https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino
- switch gps to 38400 baud https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/examples/Example11_ResetModule/Example2_FactoryDefaultsviaSerial/Example2_FactoryDefaultsviaSerial.ino
- Use Neo-M8M API to put it in sleep mode
- use gps sleep mode instead of killing its power (to allow fast position when we wake)
- enable fast lock and low power inside the gps chip
- Make a FAQ
- add a SF12 transmit option for _super_ long range
- figure out why this fixme is needed: "FIXME, disable wake due to PMU because it seems to fire all the time?"
- "AXP192 interrupt is not firing, remove this temporary polling of battery state"
- make debug info screen show real data (including battery level & charging) - close corresponding github issue
- remeasure wake time power draws now that we run CPU down at 80MHz

View File

@@ -0,0 +1,98 @@
# Bluetooth API
The Bluetooth API is design to have only a few characteristics and most 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.
## A note on MTU sizes
This device will work with any MTU size, but it is highly recommended that you call your phone's "setMTU function to increase MTU to 512 bytes" as soon as you connect to a service. This will dramatically improve performance when reading/writing packets.
## MeshBluetoothService
This is the main bluetooth service for the device and provides the API your app should use to get information about the mesh, send packets or provision the radio.
For a reference implementation of a client that uses this service see [RadioInterfaceService](https://github.com/meshtastic/Meshtastic-Android/blob/master/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt). Typical flow when
a phone connects to the device should be the following:
- SetMTU size to 512
- Read a RadioConfig from "radio" - used to get the channel and radio settings
- Read (and write if incorrect) a User from "user" - to get the username for this node
- Read a MyNodeInfo from "mynode" to get information about this local device
- Write an empty record to "nodeinfo" to restart the nodeinfo reading state machine
- Read from "nodeinfo" until it returns empty to build the phone's copy of the current NodeDB for the mesh
- Read from "fromradio" until it returns empty to get any messages that arrived for this node while the phone was away
- Subscribe to notify on "fromnum" to get notified whenever the device has a new received packet
- Read that new packet from "fromradio"
- Whenever the phone has a packet to send write to "toradio"
For definitions (and documentation) on FromRadio, ToRadio, MyNodeInfo, NodeInfo and User protocol buffers see [mesh.proto](https://github.com/meshtastic/Meshtastic-protobufs/blob/master/mesh.proto)
UUID for the service: 6ba1b218-15a8-461f-9fa8-5dcae273eafd
Each characteristic is listed as follows:
UUID
Properties
Description (including human readable name)
8ba2bcc2-ee02-4a55-a531-c525c5e454d5
read
fromradio - contains a newly received FromRadio packet destined towards the phone (up to MAXPACKET bytes per packet).
After reading the esp32 will put the next packet in this mailbox. If the FIFO is empty it will put an empty packet in this
mailbox.
f75c76d2-129e-4dad-a1dd-7866124401e7
write
toradio - write ToRadio protobufs to this characteristic to send them (up to MAXPACKET len)
ed9da18c-a800-4f66-a670-aa7547e34453
read,notify,write
fromnum - the current packet # in the message waiting inside fromradio, if the phone sees this notify it should read messages
until it catches up with this number.
The phone can write to this register to go backwards up to FIXME packets, to handle the rare case of a fromradio packet was dropped after the esp32 callback was called, but before it arrives at the phone. If the phone writes to this register the esp32 will discard older packets and put the next packet >= fromnum in fromradio.
When the esp32 advances fromnum, it will delay doing the notify by 100ms, in the hopes that the notify will never actally need to be sent if the phone is already pulling from fromradio.
Note: that if the phone ever sees this number decrease, it means the esp32 has rebooted.
Re: queue management
Not all messages are kept in the fromradio queue (filtered based on SubPacket):
- only the most recent Position and User messages for a particular node are kept
- all Data SubPackets are kept
- No WantNodeNum / DenyNodeNum messages are kept
A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging)
## Protobuf API
On connect, you should send a want_config_id protobuf to the device. This will cause the device to send its node DB and radio config via the fromradio endpoint. After sending the full DB, the radio will send a want_config_id to indicate it is done sending the configuration.
## Other bluetooth services
This document focuses on the core mesh service, but it is worth noting that the following other Bluetooth services are also
provided by the device.
### BluetoothSoftwareUpdate
The software update service. For a sample function that performs a software update using this API see [startUpdate](https://github.com/meshtastic/Meshtastic-Android/blob/master/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt).
SoftwareUpdateService UUID cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30
Characteristics
| UUID | properties | description |
| ------------------------------------ | ----------- | ----------------------------------------------------------------------------------------------------------------- |
| e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e | write,read | total image size, 32 bit, write this first, then read read back to see if it was acceptable (0 mean not accepted) |
| e272ebac-d463-4b98-bc84-5cc1a39ee517 | write | data, variable sized, recommended 512 bytes, write one for each block of file |
| 4826129c-c22a-43a3-b066-ce8f0d5bacc6 | write | crc32, write last - writing this will complete the OTA operation, now you can read result |
| 5e134862-7411-4424-ac4a-210937432c77 | read,notify | result code, readable but will notify when the OTA operation completes |
| GATT_UUID_SW_VERSION_STR/0x2a28 | read | We also implement these standard GATT entries because SW update probably needs them: |
| GATT_UUID_MANU_NAME/0x2a29 | read | |
| GATT_UUID_HW_VERSION_STR/0x2a27 | read | |
### DeviceInformationService
Implements the standard BLE contract for this service (has software version, hardware model, serial number, etc...)
### BatteryLevelService
Implements the standard BLE contract service, provides battery level in a way that most client devices should automatically understand (i.e. it should show in the bluetooth devices screen automatically)

View File

@@ -0,0 +1,21 @@
# Build instructions
This project uses the simple PlatformIO build system. You can use the IDE, but for brevity
in these instructions I describe use of their command line tool.
1. Purchase a suitable radio (see above)
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it
4. If you are outside the USA, edit [platformio.ini](/platformio.ini) to set the correct frequency range for your country. The line you need to change starts with "hw_version" and instructions are provided above that line. Options are provided for EU433, EU835, CN, JP and US. Pull-requests eagerly accepted for other countries.
5. Plug the radio into your USB port
6. Type "pio run --environment XXX -t upload" (This command will fetch dependencies, build the project and install it on the board via USB). For XXX, use the board type you have (either tbeam, heltec, ttgo-lora32-v1, ttgo-lora32-v2).
7. Platform IO also installs a very nice VisualStudio Code based IDE, see their [tutorial](https://docs.platformio.org/en/latest/tutorials/espressif32/arduino_debugging_unit_testing.html) if you'd like to use it.
## Decoding stack traces
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).

40
docs/software/crypto.md Normal file
View File

@@ -0,0 +1,40 @@
# Encryption in Meshtastic
Cryptography is tricky, so we've tried to 'simply' apply standard crypto solutions to our implementation. However,
the project developers are not cryptography experts. Therefore we ask two things:
- If you are a cryptography expert, please review these notes and our questions below. Can you help us by reviewing our
notes below and offering advice? We will happily give as much or as little credit as you wish ;-).
- Consider our existing solution 'alpha' and probably fairly secure against a not particularly aggressive adversary. But until
it is reviewed by someone smarter than us, assume it might have flaws.
## Notes on implementation
- We do all crypto at the SubPacket (payload) level only, so that all meshtastic nodes will route for others - even those channels which are encrypted with a different key.
- Mostly based on reading [Wikipedia](<https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)>) and using the modes the ESP32 provides support for in hardware.
- We use AES256-CTR as a stream cypher (with zero padding on the last BLOCK) because it is well supported with hardware acceleration.
Parameters for our CTR implementation:
- Our AES key is 128 or 256 bits, shared as part of the 'Channel' specification.
- Each SubPacket will be sent as a series of 16 byte BLOCKS.
- The node number concatenated with the packet number is used as the NONCE. This counter will be stored in flash in the device and should essentially never repeat. If the user makes a new 'Channel' (i.e. picking a new random 256 bit key), the packet number will start at zero. The packet number is sent
in cleartext with each packet. The node number can be derived from the "from" field of each packet.
- Each BLOCK for a packet has an incrementing COUNTER. COUNTER starts at zero for the first block of each packet.
- The IV for each block is constructed by concatenating the NONCE as the upper 96 bits of the IV and the COUNTER as the bottom 32 bits. Note: since our packets are small counter will really never be higher than 32 (five bits).
```
You can encrypt separate messages by dividing the nonce_counter buffer in two areas: the first one used for a per-message nonce, handled by yourself, and the second one updated by this function internally.
For example, you might reserve the first 12 bytes for the per-message nonce, and the last 4 bytes for internal use. In that case, before calling this function on a new message you need to set the first 12 bytes of nonce_counter to your chosen nonce value, the last 4 to 0, and nc_off to 0 (which will cause stream_block to be ignored). That way, you can encrypt at most 2**96 messages of up to 2**32 blocks each with the same key.
The per-message nonce (or information sufficient to reconstruct it) needs to be communicated with the ciphertext and must be unique. The recommended way to ensure uniqueness is to use a message counter. An alternative is to generate random nonces, but this limits the number of messages that can be securely encrypted: for example, with 96-bit random nonces, you should not encrypt more than 2**32 messages with the same key.
Note that for both stategies, sizes are measured in blocks and that an AES block is 16 bytes.
```
## Remaining todo
- Make the packet numbers 32 bit
- Confirm the packet #s are stored in flash across deep sleep (and otherwise in in RAM)
- Have the app change the crypto key when the user generates a new channel
- Implement for NRF52 [NRF52](https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.0.0/lib_crypto_aes.html#sub_aes_ctr)

View File

@@ -0,0 +1,27 @@
(Here's some quick tips on installing the device code from OS-X, thanks to @android606)
First time using LoRa for anything, just checking it out.
I bought a T-Beam on eBay, followed the instructions to install the firmware here:
[https://github.com/meshtastic/Meshtastic-esp32](https://github.com/meshtastic/Meshtastic-esp32)
I'm using a Mac for this, so that might account for differences in the steps to get it working. I just swapped out my SSD last month, I'm using a pretty fresh install of OS X 10.15.3/Catalina.
I got it working fairly smoothly, but there were two hang-ups I thought I'd mention:
1. I am about 0% familiar with Python, so there were some issues getting esptool.py working. Basically, this OS X comes with Python 2.7 and no pip. Pip installed okay, so I used it to install esptool. Esptool appeared to install correctly, but I couldn't get it to work to save my life. Simply typing "esptool.py" doesn't work, and I just don't know enough python to figure out why. For some reason, it installs but isn't in the \$PATH anywhere, and I don't know where it went. Python 2.7 kept giving me warning messages about being old and unsupported, so I figured that might be a hint that I should upgrade.
I ended up doing this:
- brew install pyenv (to install pyenv)
- pyenv install 3.7.7 (to install and select python 3.7.7)
- pyenv global 3.7.7 (to select the new version of python)
- brew install pip (to install pip3)
- pip3 install --upgrade esptool (note I specifically had to use "pip3", not "pip")
...then I was able to execute esptool.py
2. esptool.py didn't work though, because the virtual com port wasn't showing up as a device. I had to install a driver from Silicon Labs, which I got here:
[driver for the CP210X USB to UART bridge from Silicon Labs](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)
After I installed that, esptool.py was completely happy and the firmware loaded right up.

162
docs/software/mesh-alg.md Normal file
View File

@@ -0,0 +1,162 @@
# Mesh broadcast algorithm
great source of papers and class notes: http://www.cs.jhu.edu/~cs647/
flood routing improvements
- DONE if we don't see anyone rebroadcast our want_ack=true broadcasts, retry as needed.
reliable messaging tasks (stage one for DSR):
- DONE generalize naive flooding
- DONE add a max hops parameter, use it for broadcast as well (0 means adjacent only, 1 is one forward etc...). Store as three bits in the header.
- DONE add a 'snoopReceived' hook for all messages that pass through our node.
- DONE use the same 'recentmessages' array used for broadcast msgs to detect duplicate retransmitted messages.
- DONE in the router receive path?, send an ack packet if want_ack was set and we are the final destination. FIXME, for now don't handle multihop or merging of data replies with these acks.
- DONE keep a list of packets waiting for acks
- DONE for each message keep a count of # retries (max of three). Local to the node, only for the most immediate hop, ignorant of multihop routing.
- DONE delay some random time for each retry (large enough to allow for acks to come in)
- DONE once an ack comes in, remove the packet from the retry list and deliver the ack to the original sender
- DONE after three retries, deliver a no-ack packet to the original sender (i.e. the phone app or mesh router service)
- DONE test one hop ack/nak with the python framework
- Do stress test with acks
dsr tasks
- Don't use broadcasts for the network pings (close open github issue)
- add ignoreSenders to radioconfig to allow testing different mesh topologies by refusing to see certain senders
- test multihop delivery with the python framework
optimizations / low priority:
- low priority: think more careful about reliable retransmit intervals
- make ReliableRouter.pending threadsafe
- bump up PacketPool size for all the new ack/nak/routing packets
- handle 51 day rollover in doRetransmissions
- use a priority queue for the messages waiting to send. Send acks first, then routing messages, then data messages, then broadcasts?
when we send a packet
- do "hop by hop" routing
- when sending, if destnodeinfo.next_hop is zero (and no message is already waiting for an arp for that node), startRouteDiscovery() for that node. Queue the message in the 'waiting for arp queue' so we can send it later when then the arp completes.
- otherwise, use next_hop and start sending a message (with ack request) towards that node (starting with next_hop).
when we receive any packet
- sniff and update tables (especially useful to find adjacent nodes). Update user, network and position info.
- if we need to route() that packet, resend it to the next_hop based on our nodedb.
- if it is broadcast or destined for our node, deliver locally
- handle routereply/routeerror/routediscovery messages as described below
- then free it
routeDiscovery
- if we've already passed through us (or is from us), then it ignore it
- use the nodes already mentioned in the request to update our routing table
- if they were looking for us, send back a routereply
- NOT DOING FOR NOW -if max_hops is zero and they weren't looking for us, drop (FIXME, send back error - I think not though?)
- if we receive a discovery packet, and we don't have next_hop set in our nodedb, we use it to populate next_hop (if needed) towards the requester (after decrementing max_hops)
- if we receive a discovery packet, and we have a next_hop in our nodedb for that destination we send a (reliable) we send a route reply towards the requester
when sending any reliable packet
- if timeout doing retries, send a routeError (nak) message back towards the original requester. all nodes eavesdrop on that packet and update their route caches.
when we receive a routereply packet
- update next_hop on the node, if the new reply needs fewer hops than the existing one (we prefer shorter paths). fixme, someday use a better heuristic
when we receive a routeError packet
- delete the route for that failed recipient, restartRouteDiscovery()
- if we receive routeerror in response to a discovery,
- fixme, eventually keep caches of possible other routes.
TODO:
- optimize our generalized flooding with heuristics, possibly have particular nodes self mark as 'router' nodes.
- DONE reread the radiohead mesh implementation - hop to hop acknowledgement seems VERY expensive but otherwise it seems like DSR
- DONE read about mesh routing solutions (DSR and AODV)
- DONE read about general mesh flooding solutions (naive, MPR, geo assisted)
- DONE reread the disaster radio protocol docs - seems based on Babel (which is AODVish)
- REJECTED - seems dying - possibly dash7? https://www.slideshare.net/MaartenWeyn1/dash7-alliance-protocol-technical-presentation https://github.com/MOSAIC-LoPoW/dash7-ap-open-source-stack - does the opensource stack implement multihop routing? flooding? their discussion mailing list looks dead-dead
- update duty cycle spreadsheet for our typical usecase
a description of DSR: https://tools.ietf.org/html/rfc4728 good slides here: https://www.slideshare.net/ashrafmath/dynamic-source-routing
good description of batman protocol: https://www.open-mesh.org/projects/open-mesh/wiki/BATMANConcept
interesting paper on lora mesh: https://portal.research.lu.se/portal/files/45735775/paper.pdf
It seems like DSR might be the algorithm used by RadioheadMesh. DSR is described in https://tools.ietf.org/html/rfc4728
https://en.wikipedia.org/wiki/Dynamic_Source_Routing
broadcast solution:
Use naive flooding at first (FIXME - do some math for a 20 node, 3 hop mesh. A single flood will require a max of 20 messages sent)
Then move to MPR later (http://www.olsr.org/docs/report_html/node28.html). Use altitude and location as heursitics in selecting the MPR set
compare to db sync algorithm?
what about never flooding gps broadcasts. instead only have them go one hop in the common case, but if any node X is looking at the position of Y on their gui, then send a unicast to Y asking for position update. Y replies.
If Y were to die, at least the neighbor nodes of Y would have their last known position of Y.
## approach 1
- send all broadcasts with a TTL
- periodically(?) do a survey to find the max TTL that is needed to fully cover the current network.
- to do a study first send a broadcast (maybe our current initial user announcement?) with TTL set to one (so therefore no one will rebroadcast our request)
- survey replies are sent unicast back to us (and intervening nodes will need to keep the route table that they have built up based on past packets)
- count the number of replies to this TTL 1 attempt. That is the number of nodes we can reach without any rebroadcasts
- repeat the study with a TTL of 2 and then 3. stop once the # of replies stops going up.
- it is important for any node to do listen before talk to prevent stomping on other rebroadcasters...
- For these little networks I bet a max TTL would never be higher than 3?
## approach 2
- send a TTL1 broadcast, the replies let us build a list of the nodes (stored as a bitvector?) that we can see (and their rssis)
- we then broadcast out that bitvector (also TTL1) asking "can any of ya'll (even indirectly) see anyone else?"
- if a node can see someone I missed (and they are the best person to see that node), they reply (unidirectionally) with the missing nodes and their rssis (other nodes might sniff (and update their db) based on this reply but they don't have to)
- given that the max number of nodes in this mesh will be like 20 (for normal cases), I bet globally updating this db of "nodenums and who has the best rssi for packets from that node" would be useful
- once the global DB is shared, when a node wants to broadcast, it just sends out its broadcast . the first level receivers then make a decision "am I the best to rebroadcast to someone who likely missed this packet?" if so, rebroadcast
## approach 3
- when a node X wants to know other nodes positions, it broadcasts its position with want_replies=true. Then each of the nodes that received that request broadcast their replies (possibly by using special timeslots?)
- all nodes constantly update their local db based on replies they witnessed.
- after 10s (or whatever) if node Y notices that it didn't hear a reply from node Z (that Y has heard from recently ) to that initial request, that means Z never heard the request from X. Node Y will reply to X on Z's behalf.
- could this work for more than one hop? Is more than one hop needed? Could it work for sending messages (i.e. for a msg sent to Z with want-reply set).
## approach 4
look into the literature for this idea specifically.
- don't view it as a mesh protocol as much as a "distributed db unification problem". When nodes talk to nearby nodes they work together
to update their nodedbs. Each nodedb would have a last change date and any new changes that only one node has would get passed to the
other node. This would nicely allow distant nodes to propogate their position to all other nodes (eventually).
- handle group messages the same way, there would be a table of messages and time of creation.
- when a node has a new position or message to send out, it does a broadcast. All the adjacent nodes update their db instantly (this handles 90% of messages I'll bet).
- Occasionally a node might broadcast saying "anyone have anything newer than time X?" If someone does, they send the diffs since that date.
- essentially everything in this variant becomes broadcasts of "request db updates for >time X - for _all_ or for a particular nodenum" and nodes sending (either due to request or because they changed state) "here's a set of db updates". Every node is constantly trying to
build the most recent version of reality, and if some nodes are too far, then nodes closer in will eventually forward their changes to the distributed db.
- construct non ambigious rules for who broadcasts to request db updates. ideally the algorithm should nicely realize node X can see most other nodes, so they should just listen to all those nodes and minimize the # of broadcasts. the distributed picture of nodes rssi could be useful here?
- possibly view the BLE protocol to the radio the same way - just a process of reconverging the node/msgdb database.
# Old notes
FIXME, merge into the above:
good description of batman protocol: https://www.open-mesh.org/projects/open-mesh/wiki/BATMANConcept
interesting paper on lora mesh: https://portal.research.lu.se/portal/files/45735775/paper.pdf
It seems like DSR might be the algorithm used by RadioheadMesh. DSR is described in https://tools.ietf.org/html/rfc4728
https://en.wikipedia.org/wiki/Dynamic_Source_Routing
broadcast solution:
Use naive flooding at first (FIXME - do some math for a 20 node, 3 hop mesh. A single flood will require a max of 20 messages sent)
Then move to MPR later (http://www.olsr.org/docs/report_html/node28.html). Use altitude and location as heursitics in selecting the MPR set
compare to db sync algorithm?
what about never flooding gps broadcasts. instead only have them go one hop in the common case, but if any node X is looking at the position of Y on their gui, then send a unicast to Y asking for position update. Y replies.
If Y were to die, at least the neighbor nodes of Y would have their last known position of Y.

171
docs/software/nrf52-TODO.md Normal file
View File

@@ -0,0 +1,171 @@
# NRF52 TODO
## Misc work items
## Initial work items
Minimum items needed to make sure hardware is good.
- test my hackedup bootloader on the real hardware
- add a hard fault handler
- Use the PMU driver on real hardware
- Use new radio driver on real hardware
- Use UC1701 LCD driver on real hardware. Still need to create at startup and probe on SPI
- test the LEDs
- test the buttons
## Secondary work items
Needed to be fully functional at least at the same level of the ESP32 boards. At this point users would probably want them.
- stop polling for GPS characters, instead stay blocked on read in a thread
- increase preamble length? - will break other clients? so all devices must update
- enable BLE DFU somehow
- set appversion/hwversion
- report appversion/hwversion in BLE
- use new LCD driver from screen.cpp. Still need to hook it to a subclass of (poorly named) OLEDDisplay, and override display() to stream bytes out to the screen.
- get full BLE api working
- we need to enable the external xtal for the sx1262 (on dio3)
- figure out which regulator mode the sx1262 is operating in
- turn on security for BLE, make pairing work
- make power management/sleep work properly
- make a settimeofday implementation
- make a file system implementation (preferably one that can see the files the bootloader also sees) - use https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/lib_fds_usage.html?cp=7_5_0_3_55_3
- make ble endpoints not require "start config", just have them start in config mode
- measure power management and confirm battery life
- use new PMU to provide battery voltage/% full to app (both bluetooth and screen)
- do initial power measurements
## Items to be 'feature complete'
- use SX126x::startReceiveDutyCycleAuto to save power by sleeping and briefly waking to check for preamble bits. Change xmit rules to have more preamble bits.
- turn back on in-radio destaddr checking for RF95
- figure out what the correct current limit should be for the sx1262, currently we just use the default 100
- put sx1262 in sleepmode when processor gets shutdown (or rebooted), ideally even for critical faults (to keep power draw low). repurpose deepsleep state for this.
- good power management tips: https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/optimizing-power-on-nrf52-designs
- call PMU set_ADC_CONV(0) during sleep, to stop reading PMU adcs and decrease current draw
- do final power measurements
- backport the common PMU API between AXP192 and PmuBQ25703A
- use the new buttons in the UX
- currently using soft device SD140, is that ideal?
- turn on the watchdog timer, require servicing from key application threads
- install a hardfault handler for null ptrs (if one isn't already installed)
- nrf52setup should call randomSeed(tbd)
## Things to do 'someday'
Nice ideas worth considering someday...
- Use flego to me an iOS/linux app? https://felgo.com/doc/qt/qtbluetooth-index/ or
- Use flutter to make an iOS/linux app? https://github.com/Polidea/FlutterBleLib
- make a Mfg Controller and device under test classes as examples of custom app code for third party devs. Make a post about this. Use a custom payload type code. Have device under test send a broadcast with max hopcount of 0 for the 'mfgcontroller' payload type. mfg controller will read SNR and reply. DOT will declare failure/success and switch to the regular app screen.
- Hook Segger RTT to the nordic logging framework. https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/debugging-with-real-time-terminal
- Use nordic logging for DEBUG_MSG
- use the Jumper simulator to run meshes of simulated hardware: https://docs.jumper.io/docs/install.html
- make/find a multithread safe debug logging class (include remote logging and timestamps and levels). make each log event atomic.
- turn on freertos stack size checking
- Currently we use Nordic's vendor ID, which is apparently okay: https://devzone.nordicsemi.com/f/nordic-q-a/44014/using-nordic-vid-and-pid-for-nrf52840 and I just picked a PID of 0x4403
- Use NRF logger module (includes flash logging etc...) instead of DEBUG_MSG
- Use "LED softblink" library on NRF52 to do nice pretty "breathing" LEDs. Don't whack LED from main thread anymore.
- decrease BLE xmit power "At 0dBm with the DC/DC on, the nRF52832 transmitter draws 5.3mA. Increasing the TX power to +4dBm adds only 2.2mA. Decreasing it to -40 dBm saves only 2.6mA."
- in addition to the main CPU watchdog, use the PMU watchdog as a really big emergency hammer
- turn on 'shipping mode' in the PMU when device is 'off' - to cut battery draw to essentially zero
- make Lorro_BQ25703A read/write operations atomic, current version could let other threads sneak in (once we start using threads)
- make the segger logbuffer larger, move it to RAM that is preserved across reboots and support reading it out at runtime (to allow full log messages to be included in crash reports). Share this code with ESP32 (use gcc noinit attribute)
- convert hardfaults/panics/asserts/wd exceptions into fault codes sent to phone
- stop enumerating all i2c devices at boot, it wastes power & time
- consider using "SYSTEMOFF" deep sleep mode, without RAM retension. Only useful for 'truly off - wake only by button press' only saves 1.5uA vs SYSTEMON. (SYSTEMON only costs 1.5uA). Possibly put PMU into shipping mode?
- change the BLE protocol to be more symmetric. Have the phone _also_ host a GATT service which receives writes to
'fromradio'. This would allow removing the 'fromnum' mailbox/notify scheme of the current approach and decrease the number of packet handoffs when a packet is received.
- Using the preceeding, make a generalized 'nrf52/esp32 ble to internet' bridge service. To let nrf52 apps do MQTT/UDP/HTTP POST/HTTP GET operations to web services.
- lower advertise interval to save power, lower ble transmit power to save power
## Old unorganized notes
## Notes on PCA10059 Dongle
- docs: https://infocenter.nordicsemi.com/pdf/nRF52840_Dongle_User_Guide_v1.0.pdf
- Currently using Nordic PCA10059 Dongle hardware
- https://community.platformio.org/t/same-bootloader-same-softdevice-different-board-different-pins/11411/9
## Done
- DONE add "DFU trigger library" to application load
- DONE: using this: Possibly use this bootloader? https://github.com/adafruit/Adafruit_nRF52_Bootloader
- DONE select and install a bootloader (adafruit)
- DONE get old radio driver working on NRF52
- DONE basic test of BLE
- DONE get a debug 'serial' console working via the ICE passthrough feature
- DONE switch to RadioLab? test it with current radio. https://github.com/jgromes/RadioLib
- DONE change rx95 to radiolib
- DONE track rxbad, rxgood, txgood
- DONE neg 7 error code from receive
- DONE remove unused sx1262 lib from github
- at boot we are starting our message IDs at 1, rather we should start them at a random number. also, seed random based on timer. this could be the cause of our first message not seen bug.
- add a NEMA based GPS driver to test GPS
- DONE use "variants" to get all gpio bindings
- DONE plug in correct variants for the real board
- turn on DFU assistance in the appload using the nordic DFU helper lib call
- make a new boarddef with a variant.h file. Fix pins in that file. In particular (at least):
#define PIN_SPI_MISO (46)
#define PIN_SPI_MOSI (45)
#define PIN_SPI_SCK (47)
#define PIN_WIRE_SDA (26)
#define PIN_WIRE_SCL (27)
- customize the bootloader to use proper button bindings
- remove the MeshRadio wrapper - we don't need it anymore, just do everything in RadioInterface subclasses.
```
/*
per
https://docs.platformio.org/en/latest/tutorials/nordicnrf52/arduino_debugging_unit_testing.html
ardunino github is here https://github.com/sandeepmistry/arduino-nRF5
devboard hw docs here:
https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_buttons_leds.html?cp=4_0_4_7_6
https://docs.platformio.org/en/latest/boards/nordicnrf52/nrf52840_dk_adafruit.html
must install adafruit bootloader first!
https://learn.adafruit.com/circuitpython-on-the-nrf52/nrf52840-bootloader
see link above and turn off jlink filesystem if we see unreliable serial comms
over USBCDC
adafruit bootloader install commands (from their readme)
kevinh@kevin-server:~/.platformio/packages/framework-arduinoadafruitnrf52/bootloader$
nrfjprog -e -f nrf52 Erasing user available code and UICR flash areas. Applying
system reset.
kevinh@kevin-server:~/.platformio/packages/framework-arduinoadafruitnrf52/bootloader$
nrfjprog --program pca10056/pca10056_bootloader-0.3.2_s140_6.1.1.hex -f nrf52
Parsing hex file.
Reading flash area to program to guarantee it is erased.
Checking that the area to write is not protected.
Programming device.
kevinh@kevin-server:~/.platformio/packages/framework-arduinoadafruitnrf52/bootloader$
nrfjprog --reset -f nrf52 Applying system reset. Run.
install jlink tools from here:
https://www.segger.com/downloads/jlink#J-LinkSoftwareAndDocumentationPack
install nrf tools from here:
https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Command-Line-Tools/Download#infotabs
examples of turning off the loop call to save power:
https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/advertising-beacon
example of a more complex BLE service:
https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/custom-hrm
*/
// See g_ADigitalPinMap to see how arduino maps to the real gpio#s - and all in
// P0
#define LED1 14
#define LED2 13
/*
good led ble demo:
https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/nrf_blinky/nrf_blinky.ino
*/
```

86
docs/software/power.md Normal file
View File

@@ -0,0 +1,86 @@
# Power Management State Machine
i.e. sleep behavior
## Power measurements
Since one of the main goals of this project is long battery life, it is important to consider that in our software/protocol design. Based on initial measurements it seems that the current code should run about three days between charging, and with a bit more software work (see the [TODO list](TODO.md)) a battery life of eight days should be quite doable. Our current power measurements/model is in [this spreadsheet](https://docs.google.com/spreadsheets/d/1ft1bS3iXqFKU8SApU8ZLTq9r7QQEGESYnVgdtvdT67k/edit?usp=sharing).
## States
From lower to higher power consumption.
- Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press. We enter this mode only after no radio comms for a few hours, used to put the device into what is effectively "off" mode.
onEntry: setBluetoothOn(false), call doDeepSleep
onExit: (standard bootup code, starts in DARK)
- deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
(Not currently used)
- light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
off during light sleep, but there is a TODO item to fix this.
NOTE: On NRF52 platforms (because CPU current draw is so low), light-sleep state is never used.
onEntry: setBluetoothOn(false), setGPSPower(false), doLightSleep()
onIdle: (if we wake because our led blink timer has expired) blink the led then go back to sleep until we sleep for ls_secs
onExit: setGPSPower(true), start trying to get gps lock: gps.startLock(), once lock arrives service.sendPosition(BROADCAST)
- No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off.
onEntry: setBluetoothOn(false)
onExit:
- running dark (DARK) - Everything is on except screen
onEntry: setBluetoothOn(true)
onExit:
- full on (ON) - Everything is on
onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen.setOn(false)
## Behavior
### events that increase CPU activity
- At cold boot: The initial state (after setup() has run) is DARK
- While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
- While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
- While in LS: Every send*owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we \_also* broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
- While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
- While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)
- While in LS: while we receive packets on the radio (EVENT_RECEIVED_PACKET) we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds)
- While in NB: If we do have packets the phone (EVENT_PACKETS_FOR_PHONE) would want we transition to DARK mode for wait_bluetooth secs.
- While in DARK/ON: If we receive EVENT_BLUETOOTH_PAIR we transition to ON and start our screen_on_secs timeout
- While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown)
- While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts)
### events that decrease cpu activity
- While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess
- While in ON: If it has been more than screen_on_secs since a press, lower to DARK
- While in DARK: If time since last contact by our phone exceeds phone_timeout_secs (15 minutes), we transition down into NB mode
- While in DARK or NB: If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, min_wake_secs) we will lower down to LS state
- While in LS: If either phone_sds_timeout_secs (default 2 hr) or mesh_sds_timeout_secs (default 2 hr) are exceeded we will lower into SDS mode for sds_secs (default 1 yr) (or a button press). (Note: phone_sds_timeout_secs is currently disabled for now, because most users
are using without a phone)
- Any time we enter LS mode: We stay in that until an interrupt, button press or other state transition. Every ls_secs (default 1 hr) and let the arduino loop() run one iteration (FIXME, not sure if we need this at all), and then immediately reenter lightsleep mode on the CPU.
TODO: Eventually these scheduled intervals should be synchronized to the GPS clock, so that we can consider leaving the lora receiver off to save even more power.
TODO: In NB mode we should put cpu into light sleep any time we really aren't that busy (without declaring LS state) - i.e. we should leave GPS on etc...
# Low power consumption tasks
General ideas to hit the power draws our spreadsheet predicts. Do the easy ones before beta, the last 15% can be done after 1.0.
- don't even power on the gps until someone else wants our position, just stay in lora deep sleep until press or rxpacket (except for once an hour updates)
- (possibly bad idea - better to have lora radio always listen - check spreadsheet) have every node wake at the same tick and do their position syncs then go back to deep sleep
- lower BT announce interval to save battery
- change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet) - I think this is already the case
- have mesh service run in a thread that stays blocked until a packet arrives from the RF95
- platformio sdkconfig CONFIG_PM and turn on modem sleep mode
- keep cpu 100% in deepsleep until irq from radio wakes it. Then stay awake for 30 secs to attempt delivery to phone.
- use https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/ association sleep pattern to save power - but see https://github.com/espressif/esp-idf/issues/2070 and https://esp32.com/viewtopic.php?f=13&t=12182 it seems with BLE on the 'easy' draw people are getting is 80mA
- stop using loop() instead use a job queue and let cpu sleep
- measure power consumption and calculate battery life assuming no deep sleep
- do lowest sleep level possible where BT still works during normal sleeping, make sure cpu stays in that mode unless lora rx packet happens, bt rx packet happens or button press happens
- optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature
- see section 7.3 of https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf and have hope radio wake only when a valid packet is received. Possibly even wake the ESP32 from deep sleep via GPIO.
- never enter deep sleep while connected to USB power (but still go to other low power modes)
- when main cpu is idle (in loop), turn cpu clock rate down and/or activate special sleep modes. We want almost everything shutdown until it gets an interrupt.

View File

@@ -0,0 +1,9 @@
This is a mini design doc for developing the meshtastic software.
* [Build instructions](build-instructions.md)
* [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)
* [Bluetooth API](bluetooth-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,126 +0,0 @@
This is a mini design doc for various core behaviors...
# Rules for sleep
## States
From lower to higher power consumption.
* Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press. We enter this mode only after no radio comms for a few hours, used to put the device into what is effectively "off" mode.
onEntry: setBluetoothOn(false), call doDeepSleep
onExit: (standard bootup code, starts in DARK)
* deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
(Not currently used)
* light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
off during light sleep, but there is a TODO item to fix this.
onEntry: setBluetoothOn(false), setGPSPower(false), doLightSleep()
onIdle: (if we wake because our led blink timer has expired) blink the led then go back to sleep until we sleep for ls_secs
onExit: setGPSPower(true), start trying to get gps lock: gps.startLock(), once lock arrives service.sendPosition(BROADCAST)
* No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off.
onEntry: setBluetoothOn(false)
onExit:
* running dark (DARK) - Everything is on except screen
onEntry: setBluetoothOn(true)
onExit:
* full on (ON) - Everything is on
onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen.setOn(false)
## Behavior
### events that increase CPU activity
* At cold boot: The initial state (after setup() has run) is DARK
* While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
* While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
* While in LS: Every send_owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we _also_ broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
* While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
* While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)
* While in LS: while we receive packets on the radio (EVENT_RECEIVED_PACKET) we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds)
* While in NB: If we do have packets the phone (EVENT_PACKETS_FOR_PHONE) would want we transition to DARK mode for wait_bluetooth secs.
* While in DARK/ON: If we receive EVENT_BLUETOOTH_PAIR we transition to ON and start our screen_on_secs timeout
* While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown)
* While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts)
### events that decrease cpu activity
* While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess
* While in ON: If it has been more than screen_on_secs since a press, lower to DARK
* While in DARK: If time since last contact by our phone exceeds phone_timeout_secs (15 minutes), we transition down into NB mode
* While in DARK or NB: If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, min_wake_secs) we will lower down to LS state
* While in LS: If either phone_sds_timeout_secs (default 2 hr) or mesh_sds_timeout_secs (default 2 hr) are exceeded we will lower into SDS mode for sds_secs (default 1 yr) (or a button press).
* Any time we enter LS mode: We stay in that until an interrupt, button press or other state transition. Every ls_secs (default 1 hr) and let the arduino loop() run one iteration (FIXME, not sure if we need this at all), and then immediately reenter lightsleep mode on the CPU.
TODO: Eventually these scheduled intervals should be synchronized to the GPS clock, so that we can consider leaving the lora receiver off to save even more power.
TODO: In NB mode we should put cpu into light sleep any time we really aren't that busy (without declaring LS state) - i.e. we should leave GPS on etc...
# Low power consumption tasks
General ideas to hit the power draws our spreadsheet predicts. Do the easy ones before beta, the last 15% can be done after 1.0.
* don't even power on the gps until someone else wants our position, just stay in lora deep sleep until press or rxpacket (except for once an hour updates)
* (possibly bad idea - better to have lora radio always listen - check spreadsheet) have every node wake at the same tick and do their position syncs then go back to deep sleep
* lower BT announce interval to save battery
* change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet) - I think this is already the case
* have mesh service run in a thread that stays blocked until a packet arrives from the RF95
* platformio sdkconfig CONFIG_PM and turn on modem sleep mode
* keep cpu 100% in deepsleep until irq from radio wakes it. Then stay awake for 30 secs to attempt delivery to phone.
* use https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/ association sleep pattern to save power - but see https://github.com/espressif/esp-idf/issues/2070 and https://esp32.com/viewtopic.php?f=13&t=12182 it seems with BLE on the 'easy' draw people are getting is 80mA
* stop using loop() instead use a job queue and let cpu sleep
* measure power consumption and calculate battery life assuming no deep sleep
* do lowest sleep level possible where BT still works during normal sleeping, make sure cpu stays in that mode unless lora rx packet happens, bt rx packet happens or button press happens
* optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature
* see section 7.3 of https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf and have hope radio wake only when a valid packet is received. Possibly even wake the ESP32 from deep sleep via GPIO.
* never enter deep sleep while connected to USB power (but still go to other low power modes)
* when main cpu is idle (in loop), turn cpu clock rate down and/or activate special sleep modes. We want almost everything shutdown until it gets an interrupt.
# Mesh broadcast algoritm
FIXME - instead look for standard solutions. this approach seems really suboptimal, because too many nodes will try to rebroast. If
all else fails could always use the stock radiohead solution - though super inefficent.
## approach 1
* send all broadcasts with a TTL
* periodically(?) do a survey to find the max TTL that is needed to fully cover the current network.
* to do a study first send a broadcast (maybe our current initial user announcement?) with TTL set to one (so therefore no one will rebroadcast our request)
* survey replies are sent unicast back to us (and intervening nodes will need to keep the route table that they have built up based on past packets)
* count the number of replies to this TTL 1 attempt. That is the number of nodes we can reach without any rebroadcasts
* repeat the study with a TTL of 2 and then 3. stop once the # of replies stops going up.
* it is important for any node to do listen before talk to prevent stomping on other rebroadcasters...
* For these little networks I bet a max TTL would never be higher than 3?
## approach 2
* send a TTL1 broadcast, the replies let us build a list of the nodes (stored as a bitvector?) that we can see (and their rssis)
* we then broadcast out that bitvector (also TTL1) asking "can any of ya'll (even indirectly) see anyone else?"
* if a node can see someone I missed (and they are the best person to see that node), they reply (unidirectionally) with the missing nodes and their rssis (other nodes might sniff (and update their db) based on this reply but they don't have to)
* given that the max number of nodes in this mesh will be like 20 (for normal cases), I bet globally updating this db of "nodenums and who has the best rssi for packets from that node" would be useful
* once the global DB is shared, when a node wants to broadcast, it just sends out its broadcast . the first level receivers then make a decision "am I the best to rebroadcast to someone who likely missed this packet?" if so, rebroadcast
## approach 3
* when a node X wants to know other nodes positions, it broadcasts its position with want_replies=true. Then each of the nodes that received that request broadcast their replies (possibly by using special timeslots?)
* all nodes constantly update their local db based on replies they witnessed.
* after 10s (or whatever) if node Y notices that it didn't hear a reply from node Z (that Y has heard from recently ) to that initial request, that means Z never heard the request from X. Node Y will reply to X on Z's behalf.
* could this work for more than one hop? Is more than one hop needed? Could it work for sending messages (i.e. for a msg sent to Z with want-reply set).
## approach 4
look into the literature for this idea specifically.
* don't view it as a mesh protocol as much as a "distributed db unification problem". When nodes talk to nearby nodes they work together
to update their nodedbs. Each nodedb would have a last change date and any new changes that only one node has would get passed to the
other node. This would nicely allow distant nodes to propogate their position to all other nodes (eventually).
* handle group messages the same way, there would be a table of messages and time of creation.
* when a node has a new position or message to send out, it does a broadcast. All the adjacent nodes update their db instantly (this handles 90% of messages I'll bet).
* Occasionally a node might broadcast saying "anyone have anything newer than time X?" If someone does, they send the diffs since that date.
* essentially everything in this variant becomes broadcasts of "request db updates for >time X - for _all_ or for a particular nodenum" and nodes sending (either due to request or because they changed state) "here's a set of db updates". Every node is constantly trying to
build the most recent version of reality, and if some nodes are too far, then nodes closer in will eventually forward their changes to the distributed db.
* construct non ambigious rules for who broadcasts to request db updates. ideally the algorithm should nicely realize node X can see most other nodes, so they should just listen to all those nodes and minimize the # of broadcasts. the distributed picture of nodes rssi could be useful here?
* possibly view the BLE protocol to the radio the same way - just a process of reconverging the node/msgdb database.

6
gdbinit Normal file
View File

@@ -0,0 +1,6 @@
# the jlink debugger seems to want a pause after reset before we tell it to start running
define restart
monitor reset
shell sleep 1
cont
end

BIN
images/system-info.bin Normal file

Binary file not shown.

View File

@@ -1,304 +0,0 @@
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h"
#include <esp_gatt_defs.h>
#include <BLE2902.h>
#include <Arduino.h>
#include <Update.h>
#include "configuration.h"
#include "screen.h"
SimpleAllocator btPool;
/**
* Create standard device info service
**/
BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion = "")
{
BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC));
BLECharacteristic *swC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR), BLECharacteristic::PROPERTY_READ);
/*
* Mandatory characteristic for device info service?
BLECharacteristic *m_pnpCharacteristic = m_deviceInfoService->createCharacteristic(ESP_GATT_UUID_PNP_ID, BLECharacteristic::PROPERTY_READ);
uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version;
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
*/
swC->setValue(swVersion);
deviceInfoService->addCharacteristic(addBLECharacteristic(swC));
mfC->setValue(hwVendor);
deviceInfoService->addCharacteristic(addBLECharacteristic(mfC));
if (!hwVersion.empty())
{
BLECharacteristic *hwvC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
hwvC->setValue(hwVersion);
deviceInfoService->addCharacteristic(addBLECharacteristic(hwvC));
}
//SerialNumberCharacteristic.setValue("FIXME");
//deviceInfoService->addCharacteristic(&SerialNumberCharacteristic);
// m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ);
// m_manufacturerCharacteristic->setValue(name);
/* add these later?
ESP_GATT_UUID_SYSTEM_ID
*/
// caller must call service->start();
return deviceInfoService;
}
bool _BLEClientConnected = false;
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer)
{
_BLEClientConnected = true;
};
void onDisconnect(BLEServer *pServer)
{
_BLEClientConnected = false;
}
};
#define MAX_DESCRIPTORS 32
#define MAX_CHARACTERISTICS 32
static BLECharacteristic *chars[MAX_CHARACTERISTICS];
static size_t numChars;
static BLEDescriptor *descs[MAX_DESCRIPTORS];
static size_t numDescs;
/// Add a characteristic that we will delete when we restart
BLECharacteristic *addBLECharacteristic(BLECharacteristic *c)
{
assert(numChars < MAX_CHARACTERISTICS);
chars[numChars++] = c;
return c;
}
/// Add a characteristic that we will delete when we restart
BLEDescriptor *addBLEDescriptor(BLEDescriptor *c)
{
assert(numDescs < MAX_DESCRIPTORS);
descs[numDescs++] = c;
return c;
}
// Help routine to add a description to any BLECharacteristic and add it to the service
// We default to require an encrypted BOND for all these these characterstics
void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description)
{
c->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
BLEDescriptor *desc = new BLEDescriptor(BLEUUID((uint16_t)ESP_GATT_UUID_CHAR_DESCRIPTION), strlen(description) + 1);
assert(desc);
desc->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
desc->setValue(description);
c->addDescriptor(desc);
service->addCharacteristic(c);
addBLECharacteristic(c);
addBLEDescriptor(desc);
}
static BLECharacteristic *batteryLevelC;
/**
* Create a battery level service
*/
BLEService *createBatteryService(BLEServer *server)
{
// Create the BLE Service
BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F));
batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100");
batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
// I don't think we need to advertise this
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery->start();
return pBattery;
}
/**
* Update the battery level we are currently telling clients.
* level should be a pct between 0 and 100
*/
void updateBatteryLevel(uint8_t level)
{
// Pretend to update battery levels - fixme do elsewhere
if (batteryLevelC)
{
batteryLevelC->setValue(&level, 1);
batteryLevelC->notify();
}
}
void dumpCharacteristic(BLECharacteristic *c)
{
std::string value = c->getValue();
if (value.length() > 0)
{
DEBUG_MSG("New value: ");
for (int i = 0; i < value.length(); i++)
DEBUG_MSG("%c", value[i]);
DEBUG_MSG("\n");
}
}
/** converting endianness pull out a 32 bit value */
uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue)
{
std::string value = c->getValue();
uint32_t r = defaultValue;
if (value.length() == 4)
r = value[0] | (value[1] << 8UL) | (value[2] << 16UL) | (value[3] << 24UL);
return r;
}
class MySecurity : public BLESecurityCallbacks
{
bool onConfirmPIN(uint32_t pin)
{
Serial.printf("onConfirmPIN %u\n", pin);
return false;
}
uint32_t onPassKeyRequest()
{
Serial.println("onPassKeyRequest");
return 123511; // not used
}
void onPassKeyNotify(uint32_t pass_key)
{
Serial.printf("onPassKeyNotify %u\n", pass_key);
screen_start_bluetooth(pass_key);
}
bool onSecurityRequest()
{
Serial.println("onSecurityRequest");
return true;
}
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl)
{
if (cmpl.success)
{
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
Serial.printf(" onAuthenticationComplete -> success size: %d\n", length);
}
else
{
Serial.printf("onAuthenticationComplete -> fail %d\n", cmpl.fail_reason);
}
// Remove our custom screen
screen.setFrames();
}
};
BLEServer *pServer;
BLEService *pDevInfo, *pUpdate;
void deinitBLE()
{
assert(pServer);
pServer->getAdvertising()->stop();
destroyUpdateService();
pUpdate->stop();
pDevInfo->stop();
pUpdate->stop(); // we delete them below
// First shutdown bluetooth
BLEDevice::deinit(false);
// do not delete this - it is dynamically allocated, but only once - statically in BLEDevice
// delete pServer->getAdvertising();
delete pUpdate;
delete pDevInfo;
delete pServer;
batteryLevelC = NULL; // Don't let anyone generate bogus notifies
for (int i = 0; i < numChars; i++)
delete chars[i];
numChars = 0;
for (int i = 0; i < numDescs; i++)
delete descs[i];
numDescs = 0;
btPool.reset();
}
BLEServer *initBLE(std::string deviceName, std::string hwVendor, std::string swVersion, std::string hwVersion)
{
BLEDevice::init(deviceName);
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
/*
* Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation
*/
static MySecurity mySecurity;
BLEDevice::setSecurityCallbacks(&mySecurity);
// Create the BLE Server
pServer = BLEDevice::createServer();
static MyServerCallbacks myCallbacks;
pServer->setCallbacks(&myCallbacks);
pDevInfo = createDeviceInfomationService(pServer, hwVendor, swVersion, hwVersion);
// We now let users create the battery service only if they really want (not all devices have a battery)
// BLEService *pBattery = createBatteryService(pServer);
pUpdate = createUpdateService(pServer, hwVendor, swVersion, hwVersion); // We need to advertise this so our android ble scan operation can see it
// It seems only one service can be advertised - so for now don't advertise our updater
// pServer->getAdvertising()->addServiceUUID(pUpdate->getUUID());
// start all our services (do this after creating all of them)
pDevInfo->start();
pUpdate->start();
// FIXME turn on this restriction only after the device is paired with a phone
// advert->setScanFilter(false, true); // We let anyone scan for us (FIXME, perhaps only allow that until we are paired with a phone and configured) but only let whitelist phones connect
static BLESecurity security; // static to avoid allocs
BLESecurity *pSecurity = &security;
pSecurity->setCapability(ESP_IO_CAP_OUT);
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
return pServer;
}
// Called from loop
void loopBLE()
{
bluetoothRebootCheck();
}

View File

@@ -0,0 +1,34 @@
Important - Read carefully:
SEGGER RTT - Real Time Transfer for embedded targets
All rights reserved.
SEGGER strongly recommends to not make any changes
to or modify the source code of this software in order to stay
compatible with the RTT protocol and J-Link.
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
condition is met:
o Redistributions of source code must retain the above copyright
notice, this condition and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
(c) 2014 - 2016 SEGGER Microcontroller GmbH
www.segger.com

20
lib/segger_rtt/README.txt Normal file
View File

@@ -0,0 +1,20 @@
README.txt for the SEGGER RTT Implementation Pack.
Included files:
===============
Root Directory
- Examples
- Main_RTT_InputEchoApp.c - Sample application which echoes input on Channel 0.
- Main_RTT_MenuApp.c - Sample application to demonstrate RTT bi-directional functionality.
- Main_RTT_PrintfTest.c - Sample application to test RTT small printf implementation.
- Main_RTT_SpeedTestApp.c - Sample application for measuring RTT performance. embOS needed.
- RTT
- SEGGER_RTT.c - The RTT implementation.
- SEGGER_RTT.h - Header for RTT implementation.
- SEGGER_RTT_Conf.h - Pre-processor configuration for the RTT implementation.
- SEGGER_RTT_Printf.c - Simple implementation of printf to write formatted strings via RTT.
- Syscalls
- RTT_Syscalls_GCC.c - Low-level syscalls to retarget printf() to RTT with GCC / Newlib.
- RTT_Syscalls_IAR.c - Low-level syscalls to retarget printf() to RTT with IAR compiler.
- RTT_Syscalls_KEIL.c - Low-level syscalls to retarget printf() to RTT with KEIL/uVision compiler.
- RTT_Syscalls_SES.c - Low-level syscalls to retarget printf() to RTT with SEGGER Embedded Studio.

View File

@@ -0,0 +1,121 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_GCC.c
Purpose : Low-level functions for using printf() via RTT in GCC.
To use RTT for printf output, include this file in your
application.
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#if (defined __GNUC__) && !(defined __SES_ARM) && !(defined __CROSSWORKS_ARM)
#include "SEGGER_RTT.h"
#include <reent.h> // required for _write_r
/*********************************************************************
*
* Types
*
**********************************************************************
*/
//
// If necessary define the _reent struct
// to match the one passed by the used standard library.
//
struct _reent;
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
int _write(int file, char *ptr, int len);
// _ssize_t _write_r(struct _reent *r, int file, const void *ptr, int len);
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* _write()
*
* Function description
* Low-level write function.
* libc subroutines will use this system routine for output to all files,
* including stdout.
* Write data via RTT.
*/
int _write(int file, char *ptr, int len)
{
(void)file; /* Not used, avoid warning */
SEGGER_RTT_Write(0, ptr, len);
return len;
}
/*********************************************************************
*
* _write_r()
*
* Function description
* Low-level reentrant write function.
* libc subroutines will use this system routine for output to all files,
* including stdout.
* Write data via RTT.
*/
_ssize_t _write_r(struct _reent *r, int file, const void *ptr, int len)
{
(void)file; /* Not used, avoid warning */
(void)r; /* Not used, avoid warning */
SEGGER_RTT_Write(0, ptr, len);
return len;
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,115 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_IAR.c
Purpose : Low-level functions for using printf() via RTT in IAR.
To use RTT for printf output, include this file in your
application and set the Library Configuration to Normal.
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#ifdef __IAR_SYSTEMS_ICC__
//
// Since IAR EWARM V8 and EWRX V4, yfuns.h is considered as deprecated and LowLevelIOInterface.h
// shall be used instead. To not break any compatibility with older compiler versions, we have a
// version check in here.
//
#if ((defined __ICCARM__) && (__VER__ >= 8000000)) || ((defined __ICCRX__) && (__VER__ >= 400))
#include <LowLevelIOInterface.h>
#else
#include <yfuns.h>
#endif
#include "SEGGER_RTT.h"
#pragma module_name = "?__write"
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
size_t __write(int handle, const unsigned char * buffer, size_t size);
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* __write()
*
* Function description
* Low-level write function.
* Standard library subroutines will use this system routine
* for output to all files, including stdout.
* Write data via RTT.
*/
size_t __write(int handle, const unsigned char * buffer, size_t size) {
(void) handle; /* Not used, avoid warning */
SEGGER_RTT_Write(0, (const char*)buffer, size);
return size;
}
/*********************************************************************
*
* __write_buffered()
*
* Function description
* Low-level write function.
* Standard library subroutines will use this system routine
* for output to all files, including stdout.
* Write data via RTT.
*/
size_t __write_buffered(int handle, const unsigned char * buffer, size_t size) {
(void) handle; /* Not used, avoid warning */
SEGGER_RTT_Write(0, (const char*)buffer, size);
return size;
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,386 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : RTT_Syscalls_KEIL.c
Purpose : Retargeting module for KEIL MDK-CM3.
Low-level functions for using printf() via RTT
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#ifdef __CC_ARM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rt_sys.h>
#include <rt_misc.h>
#include "SEGGER_RTT.h"
/*********************************************************************
*
* #pragmas
*
**********************************************************************
*/
#pragma import(__use_no_semihosting)
#ifdef _MICROLIB
#pragma import(__use_full_stdio)
#endif
/*********************************************************************
*
* Defines non-configurable
*
**********************************************************************
*/
/* Standard IO device handles - arbitrary, but any real file system handles must be
less than 0x8000. */
#define STDIN 0x8001 // Standard Input Stream
#define STDOUT 0x8002 // Standard Output Stream
#define STDERR 0x8003 // Standard Error Stream
/*********************************************************************
*
* Public const
*
**********************************************************************
*/
#if __ARMCC_VERSION < 5000000
//const char __stdin_name[] = "STDIN";
const char __stdout_name[] = "STDOUT";
const char __stderr_name[] = "STDERR";
#endif
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* _ttywrch
*
* Function description:
* Outputs a character to the console
*
* Parameters:
* c - character to output
*
*/
void _ttywrch(int c) {
fputc(c, stdout); // stdout
fflush(stdout);
}
/*********************************************************************
*
* _sys_open
*
* Function description:
* Opens the device/file in order to do read/write operations
*
* Parameters:
* sName - sName of the device/file to open
* OpenMode - This parameter is currently ignored
*
* Return value:
* != 0 - Handle to the object to open, otherwise
* == 0 -"device" is not handled by this module
*
*/
FILEHANDLE _sys_open(const char * sName, int OpenMode) {
(void)OpenMode;
// Register standard Input Output devices.
if (strcmp(sName, __stdout_name) == 0) {
return (STDOUT);
} else if (strcmp(sName, __stderr_name) == 0) {
return (STDERR);
} else
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_close
*
* Function description:
* Closes the handle to the open device/file
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* 0 - device/file closed
*
*/
int _sys_close(FILEHANDLE hFile) {
(void)hFile;
return 0; // Not implemented
}
/*********************************************************************
*
* _sys_write
*
* Function description:
* Writes the data to an open handle.
* Currently this function only outputs data to the console
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* pBuffer - Pointer to the data that shall be written
* NumBytes - Number of bytes to write
* Mode - The Mode that shall be used
*
* Return value:
* Number of bytes *not* written to the file/device
*
*/
int _sys_write(FILEHANDLE hFile, const unsigned char * pBuffer, unsigned NumBytes, int Mode) {
int r = 0;
(void)Mode;
if (hFile == STDOUT) {
SEGGER_RTT_Write(0, (const char*)pBuffer, NumBytes);
return 0;
}
return r;
}
/*********************************************************************
*
* _sys_read
*
* Function description:
* Reads data from an open handle.
* Currently this modules does nothing.
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* pBuffer - Pointer to buffer to store the read data
* NumBytes - Number of bytes to read
* Mode - The Mode that shall be used
*
* Return value:
* Number of bytes read from the file/device
*
*/
int _sys_read(FILEHANDLE hFile, unsigned char * pBuffer, unsigned NumBytes, int Mode) {
(void)hFile;
(void)pBuffer;
(void)NumBytes;
(void)Mode;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_istty
*
* Function description:
* This function shall return whether the opened file
* is a console device or not.
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* 1 - Device is a console
* 0 - Device is not a console
*
*/
int _sys_istty(FILEHANDLE hFile) {
if (hFile > 0x8000) {
return (1);
}
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_seek
*
* Function description:
* Seeks via the file to a specific position
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* Pos -
*
* Return value:
* int -
*
*/
int _sys_seek(FILEHANDLE hFile, long Pos) {
(void)hFile;
(void)Pos;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_ensure
*
* Function description:
*
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* int -
*
*/
int _sys_ensure(FILEHANDLE hFile) {
(void)hFile;
return (-1); // Not implemented
}
/*********************************************************************
*
* _sys_flen
*
* Function description:
* Returns the length of the opened file handle
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* Length of the file
*
*/
long _sys_flen(FILEHANDLE hFile) {
(void)hFile;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_tmpnam
*
* Function description:
* This function converts the file number fileno for a temporary
* file to a unique filename, for example, tmp0001.
*
* Parameters:
* pBuffer - Pointer to a buffer to store the name
* FileNum - file number to convert
* MaxLen - Size of the buffer
*
* Return value:
* 1 - Error
* 0 - Success
*
*/
int _sys_tmpnam(char * pBuffer, int FileNum, unsigned MaxLen) {
(void)pBuffer;
(void)FileNum;
(void)MaxLen;
return (1); // Not implemented
}
/*********************************************************************
*
* _sys_command_string
*
* Function description:
* This function shall execute a system command.
*
* Parameters:
* cmd - Pointer to the command string
* len - Length of the string
*
* Return value:
* == NULL - Command was not successfully executed
* == sCmd - Command was passed successfully
*
*/
char * _sys_command_string(char * cmd, int len) {
(void)len;
return cmd; // Not implemented
}
/*********************************************************************
*
* _sys_exit
*
* Function description:
* This function is called when the application returns from main
*
* Parameters:
* ReturnCode - Return code from the main function
*
*
*/
void _sys_exit(int ReturnCode) {
(void)ReturnCode;
while (1); // Not implemented
}
#if __ARMCC_VERSION >= 5000000
/*********************************************************************
*
* stdout_putchar
*
* Function description:
* Put a character to the stdout
*
* Parameters:
* ch - Character to output
*
*
*/
int stdout_putchar(int ch) {
(void)ch;
return ch; // Not implemented
}
#endif
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,247 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_SES.c
Purpose : Reimplementation of printf, puts and __getchar using RTT
in SEGGER Embedded Studio.
To use RTT for printf output, include this file in your
application.
Revision: $Rev: 18539 $
----------------------------------------------------------------------
*/
#if (defined __SES_ARM) || (defined __SES_RISCV) || (defined __CROSSWORKS_ARM)
#include "SEGGER_RTT.h"
#include <stdarg.h>
#include <stdio.h>
#include "limits.h"
#include "__libc.h"
#include "__vfprintf.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
//
// Select string formatting implementation.
//
// RTT printf formatting
// - Configurable stack usage. (SEGGER_RTT_PRINTF_BUFFER_SIZE in SEGGER_RTT_Conf.h)
// - No maximum string length.
// - Limited conversion specifiers and flags. (See SEGGER_RTT_printf.c)
// Standard library printf formatting
// - Configurable formatting capabilities.
// - Full conversion specifier and flag support.
// - Maximum string length has to be known or (slightly) slower character-wise output.
//
// #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 // Use standard library formatting
// #define PRINTF_USE_SEGGER_RTT_FORMATTING 1 // Use RTT formatting
//
#ifndef PRINTF_USE_SEGGER_RTT_FORMATTING
#define PRINTF_USE_SEGGER_RTT_FORMATTING 0
#endif
//
// If using standard library formatting,
// select maximum output string buffer size or character-wise output.
//
// #define PRINTF_BUFFER_SIZE 0 // Use character-wise output
// #define PRINTF_BUFFER_SIZE 128 // Default maximum string length
//
#ifndef PRINTF_BUFFER_SIZE
#define PRINTF_BUFFER_SIZE 128
#endif
#if PRINTF_USE_SEGGER_RTT_FORMATTING // Use SEGGER RTT formatting implementation
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string using RTT and SEGGER RTT formatting.
*/
int printf(const char *fmt,...) {
int n;
va_list args;
va_start (args, fmt);
n = SEGGER_RTT_vprintf(0, fmt, &args);
va_end(args);
return n;
}
#elif PRINTF_BUFFER_SIZE == 0 // Use standard library formatting with character-wise output
/*********************************************************************
*
* Static functions
*
**********************************************************************
*/
static int _putchar(int x, __printf_tag_ptr ctx) {
(void)ctx;
SEGGER_RTT_Write(0, (char *)&x, 1);
return x;
}
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string character-wise, using RTT and standard
* library formatting.
*/
int printf(const char *fmt, ...) {
int n;
va_list args;
__printf_t iod;
va_start(args, fmt);
iod.string = 0;
iod.maxchars = INT_MAX;
iod.output_fn = _putchar;
SEGGER_RTT_LOCK();
n = __vfprintf(&iod, fmt, args);
SEGGER_RTT_UNLOCK();
va_end(args);
return n;
}
#else // Use standard library formatting with static buffer
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string using RTT and standard library formatting.
*/
int printf(const char *fmt,...) {
int n;
char aBuffer[PRINTF_BUFFER_SIZE];
va_list args;
va_start (args, fmt);
n = vsnprintf(aBuffer, sizeof(aBuffer), fmt, args);
if (n > (int)sizeof(aBuffer)) {
SEGGER_RTT_Write(0, aBuffer, sizeof(aBuffer));
} else if (n > 0) {
SEGGER_RTT_Write(0, aBuffer, n);
}
va_end(args);
return n;
}
#endif
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* puts()
*
* Function description
* print a string using RTT.
*/
int puts(const char *s) {
return SEGGER_RTT_WriteString(0, s);
}
/*********************************************************************
*
* __putchar()
*
* Function description
* Write one character via RTT.
*/
int __putchar(int x, __printf_tag_ptr ctx) {
(void)ctx;
SEGGER_RTT_Write(0, (char *)&x, 1);
return x;
}
/*********************************************************************
*
* __getchar()
*
* Function description
* Wait for and get a character via RTT.
*/
int __getchar() {
return SEGGER_RTT_WaitKey();
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,43 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
--------- END-OF-HEADER --------------------------------------------
File : Main_RTT_MenuApp.c
Purpose : Sample application to demonstrate RTT bi-directional functionality
*/
#define MAIN_C
#include <stdio.h>
#include "SEGGER_RTT.h"
volatile int _Cnt;
volatile int _Delay;
static char r;
/*********************************************************************
*
* main
*/
void main(void) {
SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\r\n");
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
do {
r = SEGGER_RTT_WaitKey();
SEGGER_RTT_Write(0, &r, 1);
r++;
} while (1);
}
/*************************** End of file ****************************/

View File

@@ -0,0 +1,70 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
--------- END-OF-HEADER --------------------------------------------
File : Main_RTT_MenuApp.c
Purpose : Sample application to demonstrate RTT bi-directional functionality
*/
#define MAIN_C
#include <stdio.h>
#include "SEGGER_RTT.h"
volatile int _Cnt;
volatile int _Delay;
/*********************************************************************
*
* main
*/
void main(void) {
int r;
int CancelOp;
do {
_Cnt = 0;
SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\r\n");
SEGGER_RTT_WriteString(0, "Press <1> to continue in blocking mode (Application waits if necessary, no data lost)\r\n");
SEGGER_RTT_WriteString(0, "Press <2> to continue in non-blocking mode (Application does not wait, data lost if fifo full)\r\n");
do {
r = SEGGER_RTT_WaitKey();
} while ((r != '1') && (r != '2'));
if (r == '1') {
SEGGER_RTT_WriteString(0, "\r\nSelected <1>. Configuring RTT and starting...\r\n");
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
} else {
SEGGER_RTT_WriteString(0, "\r\nSelected <2>. Configuring RTT and starting...\r\n");
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
}
CancelOp = 0;
do {
//for (_Delay = 0; _Delay < 10000; _Delay++);
SEGGER_RTT_printf(0, "Count: %d. Press <Space> to get back to menu.\r\n", _Cnt++);
r = SEGGER_RTT_HasKey();
if (r) {
CancelOp = (SEGGER_RTT_GetKey() == ' ') ? 1 : 0;
}
//
// Check if user selected to cancel the current operation
//
if (CancelOp) {
SEGGER_RTT_WriteString(0, "Operation cancelled, going back to menu...\r\n");
break;
}
} while (1);
SEGGER_RTT_GetKey();
SEGGER_RTT_WriteString(0, "\r\n");
} while (1);
}
/*************************** End of file ****************************/

View File

@@ -0,0 +1,118 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
--------- END-OF-HEADER --------------------------------------------
File : Main_RTT_MenuApp.c
Purpose : Sample application to demonstrate RTT bi-directional functionality
*/
#define MAIN_C
#include <stdio.h>
#include "SEGGER_RTT.h"
volatile int _Cnt;
/*********************************************************************
*
* main
*/
void main(void) {
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
SEGGER_RTT_WriteString(0, "SEGGER Real-Time-Terminal Sample\r\n\r\n");
SEGGER_RTT_WriteString(0, "###### Testing SEGGER_printf() ######\r\n");
SEGGER_RTT_printf(0, "printf Test: %%c, 'S' : %c.\r\n", 'S');
SEGGER_RTT_printf(0, "printf Test: %%5c, 'E' : %5c.\r\n", 'E');
SEGGER_RTT_printf(0, "printf Test: %%-5c, 'G' : %-5c.\r\n", 'G');
SEGGER_RTT_printf(0, "printf Test: %%5.3c, 'G' : %-5c.\r\n", 'G');
SEGGER_RTT_printf(0, "printf Test: %%.3c, 'E' : %-5c.\r\n", 'E');
SEGGER_RTT_printf(0, "printf Test: %%c, 'R' : %c.\r\n", 'R');
SEGGER_RTT_printf(0, "printf Test: %%s, \"RTT\" : %s.\r\n", "RTT");
SEGGER_RTT_printf(0, "printf Test: %%s, \"RTT\\r\\nRocks.\" : %s.\r\n", "RTT\r\nRocks.");
SEGGER_RTT_printf(0, "printf Test: %%u, 12345 : %u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%+u, 12345 : %+u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%.3u, 12345 : %.3u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%.6u, 12345 : %.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%6.3u, 12345 : %6.3u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%8.6u, 12345 : %8.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%08u, 12345 : %08u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%08.6u, 12345 : %08.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%0u, 12345 : %0u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-.6u, 12345 : %-.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-6.3u, 12345 : %-6.3u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-8.6u, 12345 : %-8.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-08u, 12345 : %-08u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-08.6u, 12345 : %-08.6u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%-0u, 12345 : %-0u.\r\n", 12345);
SEGGER_RTT_printf(0, "printf Test: %%u, -12345 : %u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%+u, -12345 : %+u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%.3u, -12345 : %.3u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%.6u, -12345 : %.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%6.3u, -12345 : %6.3u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%8.6u, -12345 : %8.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%08u, -12345 : %08u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%08.6u, -12345 : %08.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%0u, -12345 : %0u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-.6u, -12345 : %-.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-6.3u, -12345 : %-6.3u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-8.6u, -12345 : %-8.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-08u, -12345 : %-08u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-08.6u, -12345 : %-08.6u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-0u, -12345 : %-0u.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%d, -12345 : %d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%+d, -12345 : %+d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%.3d, -12345 : %.3d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%.6d, -12345 : %.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%6.3d, -12345 : %6.3d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%8.6d, -12345 : %8.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%08d, -12345 : %08d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%08.6d, -12345 : %08.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%0d, -12345 : %0d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-.6d, -12345 : %-.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-6.3d, -12345 : %-6.3d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-8.6d, -12345 : %-8.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-08d, -12345 : %-08d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-08.6d, -12345 : %-08.6d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%-0d, -12345 : %-0d.\r\n", -12345);
SEGGER_RTT_printf(0, "printf Test: %%x, 0x1234ABC : %x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%+x, 0x1234ABC : %+x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%.3x, 0x1234ABC : %.3x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%.6x, 0x1234ABC : %.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%6.3x, 0x1234ABC : %6.3x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%8.6x, 0x1234ABC : %8.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%08x, 0x1234ABC : %08x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%08.6x, 0x1234ABC : %08.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%0x, 0x1234ABC : %0x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-.6x, 0x1234ABC : %-.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-6.3x, 0x1234ABC : %-6.3x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-8.6x, 0x1234ABC : %-8.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-08x, 0x1234ABC : %-08x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-08.6x, 0x1234ABC : %-08.6x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%-0x, 0x1234ABC : %-0x.\r\n", 0x1234ABC);
SEGGER_RTT_printf(0, "printf Test: %%p, &_Cnt : %p.\r\n", &_Cnt);
SEGGER_RTT_WriteString(0, "###### SEGGER_printf() Tests done. ######\r\n");
do {
_Cnt++;
} while (1);
}
/*************************** End of file ****************************/

View File

@@ -0,0 +1,69 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1995 - 2018 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
--------- END-OF-HEADER --------------------------------------------
File : Main_RTT_SpeedTestApp.c
Purpose : Sample program for measuring RTT performance.
*/
#include "RTOS.h"
#include "BSP.h"
#include "SEGGER_RTT.h"
#include <stdio.h>
OS_STACKPTR int StackHP[128], StackLP[128]; /* Task stacks */
OS_TASK TCBHP, TCBLP; /* Task-control-blocks */
static void HPTask(void) {
while (1) {
//
// Measure time needed for RTT output
// Perform dummy write with 0 characters, so we know the overhead of toggling LEDs and RTT in general
//
// Set BP here. Then start sampling on scope
BSP_ClrLED(0);
SEGGER_RTT_Write(0, 0, 0);
BSP_SetLED(0);
BSP_ClrLED(0);
SEGGER_RTT_Write(0, "01234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n", 82);
BSP_SetLED(0);
// Set BP here. Then stop sampling on scope
OS_Delay(200);
}
}
static void LPTask(void) {
while (1) {
BSP_ToggleLED(1);
OS_Delay (500);
}
}
/*********************************************************************
*
* main
*
*********************************************************************/
int main(void) {
OS_IncDI(); /* Initially disable interrupts */
OS_InitKern(); /* Initialize OS */
OS_InitHW(); /* Initialize Hardware for OS */
BSP_Init(); /* Initialize LED ports */
BSP_SetLED(0);
/* You need to create at least one task before calling OS_Start() */
OS_CREATETASK(&TCBHP, "HP Task", HPTask, 100, StackHP);
OS_CREATETASK(&TCBLP, "LP Task", LPTask, 50, StackLP);
OS_Start(); /* Start multitasking */
return 0;
}

View File

@@ -0,0 +1,321 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT.h
Purpose : Implementation of SEGGER real-time transfer which allows
real-time communication on targets which support debugger
memory accesses while the CPU is running.
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#ifndef SEGGER_RTT_H
#define SEGGER_RTT_H
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, defaults
*
**********************************************************************
*/
#ifndef RTT_USE_ASM
#if (defined __SES_ARM) // SEGGER Embedded Studio
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __CROSSWORKS_ARM) // Rowley Crossworks
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __GNUC__) // GCC
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __clang__) // Clang compiler
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __IASMARM__) // IAR assembler
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ICCARM__) // IAR compiler
#define _CC_HAS_RTT_ASM_SUPPORT 1
#else
#define _CC_HAS_RTT_ASM_SUPPORT 0
#endif
#if (defined __ARM_ARCH_7M__) // Cortex-M3/4
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_7EM__) // Cortex-M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM7M__) // IAR Cortex-M3/4
#if (__CORE__ == __ARM7M__)
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#elif (defined __ARM7EM__) // IAR Cortex-M7
#if (__CORE__ == __ARM7EM__)
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
//
// If IDE and core support the ASM version, enable ASM version by default
//
#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT)
#define RTT_USE_ASM (1)
#else
#define RTT_USE_ASM (0)
#endif
#endif
#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file
#include <stdlib.h>
#include <stdarg.h>
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* Types
*
**********************************************************************
*/
//
// Description for a circular buffer (also called "ring buffer")
// which is used as up-buffer (T->H)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
unsigned WrOff; // Position of next item to be written by either target.
volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
unsigned Flags; // Contains configuration flags
} SEGGER_RTT_BUFFER_UP;
//
// Description for a circular buffer (also called "ring buffer")
// which is used as down-buffer (H->T)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
unsigned RdOff; // Position of next item to be read by target (down-buffer).
unsigned Flags; // Contains configuration flags
} SEGGER_RTT_BUFFER_DOWN;
//
// RTT control block which describes the number of buffers available
// as well as the configuration for each buffer
//
//
typedef struct {
char acID[16]; // Initialized to "SEGGER RTT"
int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
} SEGGER_RTT_CB;
/*********************************************************************
*
* Global data
*
**********************************************************************
*/
extern SEGGER_RTT_CB _SEGGER_RTT;
/*********************************************************************
*
* RTT API functions
*
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_GetKey (void);
unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
int SEGGER_RTT_HasKey (void);
unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex);
void SEGGER_RTT_Init (void);
unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_WaitKey (void);
unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex);
unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex);
//
// Function macro for performance optimization
//
#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff)
#if RTT_USE_ASM
#define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock
#endif
/*********************************************************************
*
* RTT transfer functions to send RTT data via other channels.
*
**********************************************************************
*/
unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
#define SEGGER_RTT_HASDATA_UP(n) (_SEGGER_RTT.aUp[n].WrOff - _SEGGER_RTT.aUp[n].RdOff)
/*********************************************************************
*
* RTT "Terminal" API functions
*
**********************************************************************
*/
int SEGGER_RTT_SetTerminal (unsigned char TerminalId);
int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s);
/*********************************************************************
*
* RTT printf functions (require SEGGER_RTT_printf.c)
*
**********************************************************************
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
#ifdef __cplusplus
}
#endif
#endif // ifndef(SEGGER_RTT_ASM)
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
//
// Operating modes. Define behavior if buffer is full (not enough space for entire message)
//
#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)
#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.
#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.
#define SEGGER_RTT_MODE_MASK (3)
//
// Control sequences, based on ANSI.
// Can be used to control color, and clear the screen
//
#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
#define RTT_CTRL_BG_RED "\x1B[24;41m"
#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,384 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Conf.h
Purpose : Implementation of SEGGER real-time transfer (RTT) which
allows real-time communication on targets which support
debugger memory accesses while the CPU is running.
Revision: $Rev: 18601 $
*/
#ifndef SEGGER_RTT_CONF_H
#define SEGGER_RTT_CONF_H
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h>
#endif
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3)
#endif
#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3)
#endif
#ifndef BUFFER_SIZE_UP
#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
#endif
#ifndef BUFFER_SIZE_DOWN
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
#endif
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
#endif
#ifndef SEGGER_RTT_MODE_DEFAULT
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
#endif
/*********************************************************************
*
* RTT memcpy configuration
*
* memcpy() is good for large amounts of data,
* but the overhead is big for small amounts, which are usually stored via RTT.
* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.
*
* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.
* This is may be required with memory access restrictions,
* such as on Cortex-A devices with MMU.
*/
#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP
#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
#endif
//
// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets
//
//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))
// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes))
//#endif
//
// Target is not allowed to perform other RTT operations while string still has not been stored completely.
// Otherwise we would probably end up with a mixed string in the buffer.
// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
//
// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
// (Higher priority = lower priority number)
// Default value for embOS: 128u
// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
// or define SEGGER_RTT_LOCK() to completely disable interrupts.
//
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
#endif
/*********************************************************************
*
* RTT lock configuration for SEGGER Embedded Studio,
* Rowley CrossStudio and GCC
*/
#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32))
#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs %0, primask \n\t" \
"movs r1, $1 \n\t" \
"msr primask, r1 \n\t" \
: "=r" (LockState) \
: \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
: \
: "r" (LockState) \
: \
); \
}
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs %0, basepri \n\t" \
"mov r1, %1 \n\t" \
"msr basepri, r1 \n\t" \
: "=r" (LockState) \
: "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
: \
: "r" (LockState) \
: \
); \
}
#elif defined(__ARM_ARCH_7A__)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs r1, CPSR \n\t" \
"mov %0, r1 \n\t" \
"orr r1, r1, #0xC0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: "=r" (LockState) \
: \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
"mrs r1, CPSR \n\t" \
"bic r1, r1, #0xC0 \n\t" \
"and r0, r0, #0xC0 \n\t" \
"orr r1, r1, r0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: \
: "r" (LockState) \
: "r0", "r1" \
); \
}
#elif defined(__riscv) || defined(__riscv_xlen)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("csrr %0, mstatus \n\t" \
"csrci mstatus, 8 \n\t" \
"andi %0, %0, 8 \n\t" \
: "=r" (LockState) \
: \
: \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \
"or %0, %0, a1 \n\t" \
"csrs mstatus, %0 \n\t" \
: \
: "r" (LockState) \
: "a1" \
); \
}
#else
#define SEGGER_RTT_LOCK()
#define SEGGER_RTT_UNLOCK()
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR EWARM
*/
#ifdef __ICCARM__
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \
(defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
}
#elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \
(defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_BASEPRI(); \
__set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RX
*/
#ifdef __ICCRX__
#define SEGGER_RTT_LOCK() { \
unsigned long LockState; \
LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RL78
*/
#ifdef __ICCRL78__
#define SEGGER_RTT_LOCK() { \
__istate_t LockState; \
LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for KEIL ARM
*/
#ifdef __CC_ARM
#if (defined __TARGET_ARCH_6S_M)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
register unsigned char PRIMASK __asm( "primask"); \
LockState = PRIMASK; \
PRIMASK = 1u; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \
__schedule_barrier(); \
}
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
register unsigned char BASEPRI __asm( "basepri"); \
LockState = BASEPRI; \
BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \
__schedule_barrier(); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for TI ARM
*/
#ifdef __TI_ARM__
#if defined (__TI_ARM_V6M0__)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
}
#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() _set_interrupt_priority(LockState); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for CCRX
*/
#ifdef __RX
#define SEGGER_RTT_LOCK() { \
unsigned long LockState; \
LockState = get_psw() & 0x010000; \
clrpsw_i();
#define SEGGER_RTT_UNLOCK() set_psw(get_psw() | LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for embOS Simulation on Windows
* (Can also be used for generic RTT locking with embOS)
*/
#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS)
void OS_SIM_EnterCriticalSection(void);
void OS_SIM_LeaveCriticalSection(void);
#define SEGGER_RTT_LOCK() { \
OS_SIM_EnterCriticalSection();
#define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \
}
#endif
/*********************************************************************
*
* RTT lock configuration fallback
*/
#ifndef SEGGER_RTT_LOCK
#define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts)
#endif
#ifndef SEGGER_RTT_UNLOCK
#define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
#endif
#endif
/*************************** End of file ****************************/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : SEGGER_RTT_ASM_ARMv7M.S
Purpose : Assembler implementation of RTT functions for ARMv7M
Additional information:
This module is written to be assembler-independent and works with
GCC and clang (Embedded Studio) and IAR.
*/
#define SEGGER_RTT_ASM // Used to control processed input from header file
#include "SEGGER_RTT.h"
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
#define _CCIAR 0
#define _CCCLANG 1
#if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__)
#define _CC_TYPE _CCCLANG
#define _PUB_SYM .global
#define _EXT_SYM .extern
#define _END .end
#define _WEAK .weak
#define _THUMB_FUNC .thumb_func
#define _THUMB_CODE .code 16
#define _WORD .word
#define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax"
#define _ALIGN(Exp) .align Exp
#define _PLACE_LITS .ltorg
#define _DATA_SECT_START
#define _C_STARTUP _start
#define _STACK_END __stack_end__
#define _RAMFUNC
//
// .text => Link to flash
// .fast => Link to RAM
// OtherSect => Usually link to RAM
// Alignment is 2^x
//
#elif defined (__IASMARM__)
#define _CC_TYPE _CCIAR
#define _PUB_SYM PUBLIC
#define _EXT_SYM EXTERN
#define _END END
#define _WEAK _WEAK
#define _THUMB_FUNC
#define _THUMB_CODE THUMB
#define _WORD DCD
#define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp)
#define _ALIGN(Exp) alignrom Exp
#define _PLACE_LITS
#define _DATA_SECT_START DATA
#define _C_STARTUP __iar_program_start
#define _STACK_END sfe(CSTACK)
#define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR
//
// .text => Link to flash
// .textrw => Link to RAM
// OtherSect => Usually link to RAM
// NOROOT => Allows linker to throw away the function, if not referenced
// Alignment is 2^x
//
#endif
#if (_CC_TYPE == _CCIAR)
NAME SEGGER_RTT_ASM_ARMv7M
#else
.syntax unified
#endif
#if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
#define SHT_PROGBITS 0x1
/*********************************************************************
*
* Public / external symbols
*
**********************************************************************
*/
_EXT_SYM __aeabi_memcpy
_EXT_SYM __aeabi_memcpy4
_EXT_SYM _SEGGER_RTT
_PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock
/*********************************************************************
*
* SEGGER_RTT_WriteSkipNoLock
*
* Function description
* Stores a specified number of characters in SEGGER RTT
* control block which is then read by the host.
* SEGGER_RTT_WriteSkipNoLock does not lock the application and
* skips all data, if the data does not fit into the buffer.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
* MUST be > 0!!!
* This is done for performance reasons, so no initial check has do be done.
*
* Return value
* 1: Data has been copied
* 0: No space, data has not been copied
*
* Notes
* (1) If there is not enough space in the "Up"-buffer, all data is dropped.
* (2) For performance reasons this function does not call Init()
* and may only be called after RTT has been initialized.
* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
*/
_SECTION(.text, CODE, 2)
_ALIGN(2)
_THUMB_FUNC
SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) {
//
// Cases:
// 1) RdOff <= WrOff => Space until wrap-around is sufficient
// 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks)
// 3) RdOff < WrOff => No space in buf
// 4) RdOff > WrOff => Space is sufficient
// 5) RdOff > WrOff => No space in buf
//
// 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough
//
// Register usage:
// R0 Temporary needed as RdOff, <Tmp> register later on
// R1 pData
// R2 <NumBytes>
// R3 <Tmp> register. Hold free for subroutine calls
// R4 <Rem>
// R5 pRing->pBuffer
// R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN)
// R7 WrOff
//
PUSH {R4-R7}
ADD R3,R0,R0, LSL #+1
LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex];
ADD R0,R0,R3, LSL #+3
ADD R6,R0,#+24
LDR R0,[R6, #+16] // RdOff = pRing->RdOff;
LDR R7,[R6, #+12] // WrOff = pRing->WrOff;
LDR R5,[R6, #+4] // pRing->pBuffer
CMP R7,R0
BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3)
//
// Handling for case 1, later on identical to case 4
//
LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0)
SUBS R4,R3,R7 // <Rem> (Used in case we jump into case 2 afterwards)
SUBS R3,R4,#+1 // <Avail>
CMP R3,R2
BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)?
_Case4:
ADDS R5,R7,R5 // pBuffer += WrOff
ADDS R0,R2,R7 // v = WrOff + NumBytes
//
// 2x unrolling for the copy loop that is used most of the time
// This is a special optimization for small SystemView packets and makes them even faster
//
_ALIGN(2)
_LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes);
LDRB R3,[R1], #+1
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BEQ _CSDone
LDRB R3,[R1], #+1
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BNE _LoopCopyStraight
_CSDone:
STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes;
MOVS R0,#+1
POP {R4-R7}
BX LR // Return 1
_CheckCase2:
ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around
CMP R0,R2
BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit)
//
// Handling for case 2
//
ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value
SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer)
_LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk
LDRB R3,[R1], #+1
STRB R3,[R0], #+1 // *pDest++ = *pSrc++
SUBS R4,R4,#+1
BNE _LoopCopyBeforeWrapAround
//
// Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used
// But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element
// In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks
// Therefore, check if 2nd memcpy is necessary at all
//
ADDS R4,R2,#+0 // Save <NumBytes> (needed as counter in loop but must be written to <WrOff> after the loop). Also use this inst to update the flags to skip 2nd loop if possible
BEQ.N _No2ChunkNeeded // if (NumBytes) {
_LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes);
LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BNE _LoopCopyAfterWrapAround
_No2ChunkNeeded:
STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer
MOVS R0,#+1
POP {R4-R7}
BX LR // Return 1
_CheckCase4:
SUBS R0,R0,R7
SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u;
CMP R0,R2
BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit)
_Case3:
MOVS R0,#+0
POP {R4-R7}
BX LR // Return 0
_PLACE_LITS
#endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
_END
/*************************** End of file ****************************/

View File

@@ -0,0 +1,500 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* www.segger.com Support: support@segger.com *
* *
**********************************************************************
* *
* SEGGER RTT * Real Time Transfer for embedded targets *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* SEGGER strongly recommends to not make any changes *
* to or modify the source code of this software in order to stay *
* compatible with the RTT protocol and J-Link. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_printf.c
Purpose : Replacement for printf to write formatted data via RTT
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
#endif
#include <stdlib.h>
#include <stdarg.h>
#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
#define FORMAT_FLAG_PAD_ZERO (1u << 1)
#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
#define FORMAT_FLAG_ALTERNATE (1u << 3)
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
char* pBuffer;
unsigned BufferSize;
unsigned Cnt;
int ReturnValue;
unsigned RTTBufferIndex;
} SEGGER_RTT_PRINTF_DESC;
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _StoreChar
*/
static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
unsigned Cnt;
Cnt = p->Cnt;
if ((Cnt + 1u) <= p->BufferSize) {
*(p->pBuffer + Cnt) = c;
p->Cnt = Cnt + 1u;
p->ReturnValue++;
}
//
// Write part of string, when the buffer is full
//
if (p->Cnt == p->BufferSize) {
if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
p->ReturnValue = -1;
} else {
p->Cnt = 0u;
}
}
}
/*********************************************************************
*
* _PrintUnsigned
*/
static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
unsigned Div;
unsigned Digit;
unsigned Number;
unsigned Width;
char c;
Number = v;
Digit = 1u;
//
// Get actual field width
//
Width = 1u;
while (Number >= Base) {
Number = (Number / Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
//
// Print leading chars if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
if (FieldWidth != 0u) {
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
c = '0';
} else {
c = ' ';
}
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, c);
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Compute Digit.
// Loop until Digit has the value of the highest digit required.
// Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
//
while (1) {
if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
NumDigits--;
} else {
Div = v / Digit;
if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done
break;
}
}
Digit *= Base;
}
//
// Output digits
//
do {
Div = v / Digit;
v -= Div * Digit;
_StoreChar(pBufferDesc, _aV2C[Div]);
if (pBufferDesc->ReturnValue < 0) {
break;
}
Digit /= Base;
} while (Digit);
//
// Print trailing spaces if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
}
}
/*********************************************************************
*
* _PrintInt
*/
static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
unsigned Width;
int Number;
Number = (v < 0) ? -v : v;
//
// Get actual field width
//
Width = 1u;
while (Number >= (int)Base) {
Number = (Number / (int)Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
FieldWidth--;
}
//
// Print leading spaces if necessary
//
if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
//
// Print sign if necessary
//
if (pBufferDesc->ReturnValue >= 0) {
if (v < 0) {
v = -v;
_StoreChar(pBufferDesc, '-');
} else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
_StoreChar(pBufferDesc, '+');
} else {
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print leading zeros if necessary
//
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, '0');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print number without sign
//
_PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
}
}
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* SEGGER_RTT_vprintf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string
* pParamList Pointer to the list of arguments for the format string
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*/
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
char c;
SEGGER_RTT_PRINTF_DESC BufferDesc;
int v;
unsigned NumDigits;
unsigned FormatFlags;
unsigned FieldWidth;
char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
BufferDesc.pBuffer = acBuffer;
BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
BufferDesc.Cnt = 0u;
BufferDesc.RTTBufferIndex = BufferIndex;
BufferDesc.ReturnValue = 0;
do {
c = *sFormat;
sFormat++;
if (c == 0u) {
break;
}
if (c == '%') {
//
// Filter out flags
//
FormatFlags = 0u;
v = 1;
do {
c = *sFormat;
switch (c) {
case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
default: v = 0; break;
}
} while (v);
//
// filter out field with
//
FieldWidth = 0u;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
} while (1);
//
// Filter out precision (number of digits to display)
//
NumDigits = 0u;
c = *sFormat;
if (c == '.') {
sFormat++;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
NumDigits = NumDigits * 10u + ((unsigned)c - '0');
} while (1);
}
//
// Filter out length modifier
//
c = *sFormat;
do {
if ((c == 'l') || (c == 'h')) {
sFormat++;
c = *sFormat;
} else {
break;
}
} while (1);
//
// Handle specifiers
//
switch (c) {
case 'c': {
char c0;
v = va_arg(*pParamList, int);
c0 = (char)v;
_StoreChar(&BufferDesc, c0);
break;
}
case 'd':
v = va_arg(*pParamList, int);
_PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
break;
case 'u':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
break;
case 's':
{
const char * s = va_arg(*pParamList, const char *);
do {
c = *s;
s++;
if (c == '\0') {
break;
}
_StoreChar(&BufferDesc, c);
} while (BufferDesc.ReturnValue >= 0);
}
break;
case 'p':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
break;
case '%':
_StoreChar(&BufferDesc, '%');
break;
default:
break;
}
sFormat++;
} else {
_StoreChar(&BufferDesc, c);
}
} while (BufferDesc.ReturnValue >= 0);
if (BufferDesc.ReturnValue > 0) {
//
// Write remaining data, if any
//
if (BufferDesc.Cnt != 0u) {
SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
}
BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
}
return BufferDesc.ReturnValue;
}
/*********************************************************************
*
* SEGGER_RTT_printf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string, followed by the arguments for conversion
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*
* Notes
* (1) Conversion specifications have following syntax:
* %[flags][FieldWidth][.Precision]ConversionSpecifier
* (2) Supported flags:
* -: Left justify within the field width
* +: Always print sign extension for signed conversions
* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
* Supported conversion specifiers:
* c: Print the argument as one char
* d: Print the argument as a signed integer
* u: Print the argument as an unsigned integer
* x: Print the argument as an hexadecimal integer
* s: Print the string pointed to by the argument
* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
int r;
va_list ParamList;
va_start(ParamList, sFormat);
r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
va_end(ParamList);
return r;
}
/*************************** End of file ****************************/

View File

@@ -9,11 +9,20 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
default_envs = tbeam ; Note: the github actions CI test build can't yet build NRF52 targets
[env:esp32] [common]
; common is not currently used
; REQUIRED environment variables - if not set the specified default will be sued
; The following environment variables must be set in the shell if you'd like to override them.
; They are used in this ini file as systenv.VARNAME, so in your shell do export "VARNAME=fish"
; HW_VERSION (default US)
; APP_VERSION (default emptystring)
; HW_VERSION (default emptystring)
[env]
platform = espressif32 platform = espressif32
board = ttgo-t-beam
; board = heltec_wifi_lora_32_V2
framework = arduino framework = arduino
; customize the partition table ; customize the partition table
@@ -22,24 +31,28 @@ board_build.partitions = partition-table.csv
; note: we add src to our include search path so that lmic_project_config can override ; note: we add src to our include search path so that lmic_project_config can override
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc ; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
build_flags = -Wall -Wextra -Wno-missing-field-initializers -Isrc -Os -Wl,-Map,.pio/build/esp32/output.map -DAXP_DEBUG_PORT=Serial build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Os -Wl,-Map,.pio/build/output.map
-DAXP_DEBUG_PORT=Serial
-DHW_VERSION_${sysenv.COUNTRY}
-DAPP_VERSION=${sysenv.APP_VERSION}
-DHW_VERSION=${sysenv.HW_VERSION}
; not needed included in ttgo-t-beam board file ; not needed included in ttgo-t-beam board file
; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram ; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
; -DBOARD_HAS_PSRAM ; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue ; -mfix-esp32-psram-cache-issue
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG ; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
upload_speed = 921600 ; leave this commented out to avoid breaking Windows
upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
; the default is esptool ; the default is esptool
; upload_protocol = esp-prog ; upload_protocol = esp-prog
monitor_port = /dev/ttyUSB0 ; monitor_speed = 115200
monitor_speed = 115200 monitor_speed = 921600
# debug_tool = esp-prog # debug_tool = esp-prog
# debug_port = /dev/ttyACM0 # debug_port = /dev/ttyACM0
@@ -53,24 +66,98 @@ debug_tool = jlink
;debug_init_cmds = ;debug_init_cmds =
; monitor adapter_khz 10000 ; monitor adapter_khz 10000
debug_init_break = tbreak setup
; Note: some libraries are specified by #ID where there are conflicting library
; names.
lib_deps = lib_deps =
https://github.com/meshtastic/RadioHead.git
1655 ; TinyGPSPlus
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
AXP202X_Library
SPI SPI
1260 ; OneButton ; 1260 ; OneButton - not used yet
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
Wire ; explicitly needed here because the AXP202 library forgets to add it Wire ; explicitly needed here because the AXP202 library forgets to add it
https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
https://github.com/meshtastic/RadioLib.git
https://github.com/meshtastic/TinyGPSPlus.git
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
src_filter =
${env.src_filter} -<nrf52/>
upload_speed = 921600
debug_init_break = tbreak setup
build_flags =
${env.build_flags} -Wall -Wextra -Isrc/esp32
lib_ignore = segger_rtt
;[env:tbeam] ; The 1.0 release of the TBEAM board
[env:tbeam]
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${env.lib_deps}
https://github.com/meshtastic/AXP202X_Library.git
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
; The original TBEAM board without the AXP power chip and a few other changes
; Note: I've heard reports this didn't work. Disabled until someone with a 0.7 can test and debug.
;[env:tbeam0.7]
;extends = esp32_base
;board = ttgo-t-beam ;board = ttgo-t-beam
;build_flags =
; ${esp32_base.build_flags} -D TBEAM_V07
;[env:heltec] [env:heltec]
;build_type = debug ; to make it possible to step through our jtag debugger ;build_type = debug ; to make it possible to step through our jtag debugger
;board = heltec_wifi_lora_32_V2 extends = esp32_base
board = heltec_wifi_lora_32_V2
[env:ttgo-lora32-v1]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TTGO_LORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:ttgo-lora32-v2]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TTGO_LORA_V2
; Common settings for NRF52 based targets
[nrf52_base]
platform = nordicnrf52
framework = arduino
debug_tool = jlink
build_type = debug ; I'm debugging with ICE a lot now
build_flags =
${env.build_flags} -Wno-unused-variable -Isrc/nrf52
src_filter =
${env.src_filter} -<esp32/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
debug_extra_cmds =
source gdbinit
; Set initial breakpoint (defaults to main)
debug_init_break =
;debug_init_break = tbreak loop
;debug_init_break = tbreak Reset_Handler
; The NRF52840-dk development board
[env:nrf52dk]
extends = nrf52_base
board = nrf52840_dk_modified
; The PPR board
[env:ppr]
extends = nrf52_base
board = ppr
lib_deps =
${env.lib_deps}
UC1701
https://github.com/meshtastic/BQ25703A.git

2
proto

Submodule proto updated: f309ee8f9e...bfae47bdc0

1
release/.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.elf
*.bin *.bin
*.map *.map
*.zip *.zip

1
release/latest/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
curfirmwareversion.xml

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This file is kept in source control because it reflects the last stable
release. It is used by the android app for forcing software updates. Do not edit.
Generated by bin/buildall.sh -->
<resources>
<string name="cur_firmware_version">0.0.9</string>
</resources>

View File

@@ -1,187 +0,0 @@
#include "CustomRF95.h"
#include <pb_encode.h>
#include <pb_decode.h>
#include "configuration.h"
#include "assert.h"
#include "NodeDB.h"
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
#define MAX_RHPACKETLEN 251
static uint8_t radiobuf[MAX_RHPACKETLEN];
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: RH_RF95(NSS_GPIO, DIO0_GPIO),
pool(_pool),
rxDest(_rxDest),
txQueue(MAX_TX_QUEUE),
sendingPacket(NULL)
{
}
bool CustomRF95::canSleep()
{
// We allow initializing mode, because sometimes while testing we don't ever call init() to turn on the hardware
return (_mode == RHModeInitialising || _mode == RHModeIdle || _mode == RHModeRx) && !_isReceiving && txQueue.isEmpty();
}
bool CustomRF95::sleep()
{
// we no longer care about interrupts from this device
prepareDeepSleep();
// FIXME - leave the device state in rx mode instead
return RH_RF95::sleep();
}
bool CustomRF95::init()
{
bool ok = RH_RF95::init();
return ok;
}
/// 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 because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode CustomRF95::send(MeshPacket *p)
{
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
// we almost certainly guarantee no one outside will like the packet we are sending.
if (_mode == RHModeIdle || (_mode == RHModeRx && !_isReceiving))
{
// if the radio is idle, we can send right away
DEBUG_MSG("immedate send on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", txGood(), rxGood(), rxBad());
startSend(p);
return ERRNO_OK;
}
else
{
DEBUG_MSG("enquing packet for send from=0x%x, to=0x%x\n", p->from, p->to);
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
if (res != ERRNO_OK) // we weren't able to queue it, so we must drop it to prevent leaks
pool.release(p);
return res;
}
}
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
void CustomRF95::handleInterrupt()
{
RH_RF95::handleInterrupt();
BaseType_t higherPriWoken = false;
if (_mode == RHModeIdle) // We are now done sending or receiving
{
if (sendingPacket) // Were we sending?
{
// We are done sending that packet, release it
pool.releaseFromISR(sendingPacket, &higherPriWoken);
sendingPacket = NULL;
// DEBUG_MSG("Done with send\n");
}
// If we just finished receiving a packet, forward it into a queue
if (_rxBufValid)
{
// We received a packet
// Skip the 4 headers that are at the beginning of the rxBuf
size_t payloadLen = _bufLen - RH_RF95_HEADER_LEN;
uint8_t *payload = _buf + RH_RF95_HEADER_LEN;
// FIXME - throws exception if called in ISR context: frequencyError() - probably the floating point math
int32_t freqerr = -1, snr = lastSNR();
//DEBUG_MSG("Received packet from mesh src=0x%x,dest=0x%x,id=%d,len=%d rxGood=%d,rxBad=%d,freqErr=%d,snr=%d\n",
// srcaddr, destaddr, id, rxlen, rf95.rxGood(), rf95.rxBad(), freqerr, snr);
MeshPacket *mp = pool.allocZeroed();
SubPacket *p = &mp->payload;
mp->from = _rxHeaderFrom;
mp->to = _rxHeaderTo;
//_rxHeaderId = _buf[2];
//_rxHeaderFlags = _buf[3];
// If we already have an entry in the DB for this nodenum, goahead and hide the snr/freqerr info there.
// Note: we can't create it at this point, because it might be a bogus User node allocation. But odds are we will
// already have a record we can hide this debugging info in.
NodeInfo *info = nodeDB.getNode(mp->from);
if (info)
{
info->snr = snr;
info->frequency_error = freqerr;
}
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p))
{
pool.releaseFromISR(mp, &higherPriWoken);
}
else
{
// parsing was successful, queue for our recipient
mp->has_payload = true;
int res = rxDest.enqueueFromISR(mp, &higherPriWoken); // NOWAIT - fixme, if queue is full, delete older messages
assert(res == pdTRUE);
}
clearRxBuf(); // This message accepted and cleared
}
higherPriWoken |= handleIdleISR();
}
// If we call this _IT WILL NOT RETURN_
if (higherPriWoken)
portYIELD_FROM_ISR();
}
/** The ISR doesn't have any good work to do, give a new assignment.
*
* Return true if a higher pri task has woken
*/
bool CustomRF95::handleIdleISR()
{
BaseType_t higherPriWoken = false;
// First send any outgoing packets we have ready
MeshPacket *txp = txQueue.dequeuePtrFromISR(0);
if (txp)
startSend(txp);
else
{
// Nothing to send, let's switch back to receive mode
setModeRx();
}
return higherPriWoken;
}
/// This routine might be called either from user space or ISR
void CustomRF95::startSend(MeshPacket *txp)
{
assert(!sendingPacket);
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
assert(txp->has_payload);
size_t numbytes = pb_encode_to_bytes(radiobuf, sizeof(radiobuf), SubPacket_fields, &txp->payload);
sendingPacket = txp;
setHeaderTo(txp->to);
setHeaderFrom(nodeDB.getNodeNum()); // We must do this before each send, because we might have just changed our nodenum
// setHeaderId(0);
assert(numbytes <= 251); // Make sure we don't overflow the tiny max packet size
// uint32_t start = millis(); // FIXME, store this in the class
int res = RH_RF95::send(radiobuf, numbytes);
assert(res);
}

View File

@@ -1,58 +0,0 @@
#pragma once
#include <RH_RF95.h>
#include <RHMesh.h>
#include "MemoryPool.h"
#include "mesh.pb.h"
#include "PointerQueue.h"
#include "MeshTypes.h"
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
/**
* A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!)
*/
class CustomRF95 : public RH_RF95
{
friend class MeshRadio; // for debugging we let that class touch pool
MemoryPool<MeshPacket> &pool;
PointerQueue<MeshPacket> &rxDest;
PointerQueue<MeshPacket> txQueue;
MeshPacket *sendingPacket; // The packet we are currently sending
public:
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
*/
CustomRF95(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
/**
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
*
* This method must be used before putting the CPU into deep or light sleep.
*/
bool canSleep();
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool 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 because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode send(MeshPacket *p);
bool init();
protected:
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
virtual void handleInterrupt();
private:
/// Send a new packet - this low level call can be called from either ISR or userspace
void startSend(MeshPacket *txp);
/// Return true if a higher pri task has woken
bool handleIdleISR();
};

View File

@@ -1,157 +0,0 @@
#include "GPS.h"
#include "time.h"
#include <sys/time.h>
#include "configuration.h"
// stuff that really should be in in the instance instead...
HardwareSerial _serial_gps(GPS_SERIAL_NUM);
uint32_t timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock (even across sleeps)
GPS gps;
bool hasValidLocation; // default to false, until we complete our first read
bool wantNewLocation = true;
GPS::GPS() : PeriodicTask()
{
}
void GPS::setup()
{
readFromRTC();
#ifdef GPS_RX_PIN
_serial_gps.begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#endif
}
void GPS::readFromRTC()
{
struct timeval tv; /* btw settimeofday() is helpfull here too*/
if (!gettimeofday(&tv, NULL))
{
uint32_t now = millis();
DEBUG_MSG("Read RTC time as %ld (cur millis %u) valid=%d\n", tv.tv_sec, now, timeSetFromGPS);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
}
}
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
void GPS::perhapsSetRTC(const struct timeval *tv)
{
if (!timeSetFromGPS)
{
timeSetFromGPS = true;
DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec);
settimeofday(tv, NULL);
readFromRTC();
}
}
#include <time.h>
// for the time being we need to rapidly read from the serial port to prevent overruns
void GPS::loop()
{
PeriodicTask::loop();
}
uint32_t GPS::getTime()
{
return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
}
uint32_t GPS::getValidTime()
{
return timeSetFromGPS ? getTime() : 0;
}
/// Returns true if we think the board can enter deep or light sleep now (we might be trying to get a GPS lock)
bool GPS::canSleep()
{
return !wantNewLocation;
}
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
void GPS::prepareSleep()
{
// discard all rx serial bytes so we don't try to parse them when we come back
while (_serial_gps.available())
{
_serial_gps.read();
}
// make the parser bail on whatever it was parsing
encode('\n');
}
void GPS::doTask()
{
#ifdef GPS_RX_PIN
// Consume all characters that have arrived
while (_serial_gps.available())
{
encode(_serial_gps.read());
// DEBUG_MSG("Got GPS response\n");
}
if (!timeSetFromGPS && time.isValid() && date.isValid())
{
struct timeval tv;
DEBUG_MSG("Got time from GPS\n");
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = time.second();
t.tm_min = time.minute();
t.tm_hour = time.hour();
t.tm_mday = date.day();
t.tm_mon = date.month() - 1;
t.tm_year = date.year() - 1900;
t.tm_isdst = false;
time_t res = mktime(&t);
tv.tv_sec = res;
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
perhapsSetRTC(&tv);
}
#endif
if (location.isValid() && location.isUpdated())
{ // we only notify if position has changed
// DEBUG_MSG("new gps pos\n");
hasValidLocation = true;
wantNewLocation = false;
notifyObservers();
}
else // we didn't get a location update, go back to sleep and hope the characters show up
wantNewLocation = true;
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 100ms until we have something over the serial
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 100);
}
void GPS::startLock()
{
DEBUG_MSG("Looking for GPS lock\n");
wantNewLocation = true;
setPeriod(1);
}
String GPS::getTimeStr()
{
static char t[12]; // used to sprintf for Serial output
snprintf(t, sizeof(t), "%02d:%02d:%02d", time.hour(), time.minute(), time.second());
return t;
}

View File

@@ -1,48 +0,0 @@
#pragma once
#include <TinyGPS++.h>
#include "PeriodicTask.h"
#include "Observer.h"
#include "sys/time.h"
/**
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class GPS : public PeriodicTask, public Observable, public TinyGPSPlus
{
public:
GPS();
/// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero
uint32_t getTime();
/// Return time since 1970 in secs. If we don't have a GPS lock return zero
uint32_t getValidTime();
String getTimeStr();
void setup();
virtual void loop();
virtual void doTask();
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
void perhapsSetRTC(const struct timeval *tv);
/// Returns true if we think the board can enter deep or light sleep now (we might be trying to get a GPS lock)
bool canSleep();
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
void prepareSleep();
/// Restart our lock attempt - try to get and broadcast a GPS reading ASAP
void startLock();
private:
void readFromRTC();
};
extern GPS gps;

View File

@@ -1,346 +0,0 @@
#include "BluetoothUtil.h"
#include "MeshBluetoothService.h"
#include <esp_gatt_defs.h>
#include <BLE2902.h>
#include <Arduino.h>
#include <assert.h>
#include "mesh.pb.h"
#include "MeshService.h"
#include "mesh-pb-constants.h"
#include "NodeDB.h"
#include "configuration.h"
#include "PowerFSM.h"
#include "CallbackCharacteristic.h"
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in proccess at once
static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
class ProtobufCharacteristic : public CallbackCharacteristic
{
const pb_msgdesc_t *fields;
void *my_struct;
public:
ProtobufCharacteristic(const char *uuid, uint32_t btprops, const pb_msgdesc_t *_fields, void *_my_struct)
: CallbackCharacteristic(uuid, btprops),
fields(_fields),
my_struct(_my_struct)
{
setCallbacks(this);
}
void onRead(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onRead(c);
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), fields, my_struct);
DEBUG_MSG("pbread from %s returns %d bytes\n", c->getUUID().toString().c_str(), numbytes);
c->setValue(trBytes, numbytes);
}
void onWrite(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onWrite(c);
writeToDest(c, my_struct);
}
protected:
/// like onWrite, but we provide an different destination to write to, for use by subclasses that
/// want to optionally ignore parts of writes.
/// returns true for success
bool writeToDest(BLECharacteristic *c, void *dest)
{
// dumpCharacteristic(pCharacteristic);
std::string src = c->getValue();
DEBUG_MSG("pbwrite to %s of %d bytes\n", c->getUUID().toString().c_str(), src.length());
return pb_decode_from_bytes((const uint8_t *)src.c_str(), src.length(), fields, dest);
}
};
class NodeInfoCharacteristic : public BLECharacteristic, public BLEKeepAliveCallbacks
{
public:
NodeInfoCharacteristic()
: BLECharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
{
setCallbacks(this);
}
void onRead(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onRead(c);
const NodeInfo *info = nodeDB.readNextInfo();
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);
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), NodeInfo_fields, info);
c->setValue(trBytes, numbytes);
}
else
{
c->setValue(trBytes, 0); // Send an empty response
DEBUG_MSG("Done sending nodeinfos\n");
}
}
void onWrite(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onWrite(c);
DEBUG_MSG("Reset nodeinfo read pointer\n");
nodeDB.resetReadPointer();
}
};
// wrap our protobuf version with something that forces the service to reload the config
class RadioCharacteristic : public ProtobufCharacteristic
{
public:
RadioCharacteristic()
: ProtobufCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, RadioConfig_fields, &radioConfig)
{
}
void onWrite(BLECharacteristic *c)
{
ProtobufCharacteristic::onWrite(c);
service.reloadConfig();
}
};
// wrap our protobuf version with something that forces the service to reload the owner
class OwnerCharacteristic : public ProtobufCharacteristic
{
public:
OwnerCharacteristic()
: ProtobufCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, User_fields, &owner)
{
}
void onWrite(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onWrite(c); // NOTE: We do not call the standard ProtobufCharacteristic superclass, because we want custom write behavior
static User o; // if the phone doesn't set ID we are careful to keep ours, we also always keep our macaddr
if (writeToDest(c, &o))
{
int changed = 0;
if (*o.long_name)
{
changed |= strcmp(owner.long_name, o.long_name);
strcpy(owner.long_name, o.long_name);
}
if (*o.short_name)
{
changed |= strcmp(owner.short_name, o.short_name);
strcpy(owner.short_name, o.short_name);
}
if (*o.id)
{
changed |= strcmp(owner.id, o.id);
strcpy(owner.id, o.id);
}
if (changed) // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner();
}
}
};
class ToRadioCharacteristic : public CallbackCharacteristic
{
public:
ToRadioCharacteristic()
: CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE)
{
}
void onWrite(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onWrite(c);
DEBUG_MSG("Got on write\n");
service.handleToRadio(c->getValue());
}
};
class FromRadioCharacteristic : public CallbackCharacteristic
{
public:
FromRadioCharacteristic()
: CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ)
{
}
void onRead(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onRead(c);
MeshPacket *mp = service.getForPhone();
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty
if (!mp)
{
DEBUG_MSG("toPhone queue is empty\n");
c->setValue((uint8_t *)"", 0);
}
else
{
static FromRadio fRadio;
// Encapsulate as a FromRadio packet
memset(&fRadio, 0, sizeof(fRadio));
fRadio.which_variant = FromRadio_packet_tag;
fRadio.variant.packet = *mp;
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), FromRadio_fields, &fRadio);
DEBUG_MSG("delivering toPhone packet to phone %d bytes\n", numbytes);
c->setValue(trBytes, numbytes);
service.releaseToPool(mp); // we just copied the bytes, so don't need this buffer anymore
}
}
};
class FromNumCharacteristic : public CallbackCharacteristic
{
public:
FromNumCharacteristic()
: CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453",
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY)
{
}
void onRead(BLECharacteristic *c)
{
BLEKeepAliveCallbacks::onRead(c);
DEBUG_MSG("FIXME implement fromnum read\n");
}
};
FromNumCharacteristic *meshFromNumCharacteristic;
/**
* Tell any bluetooth clients that the number of rx packets has changed
*/
void bluetoothNotifyFromNum(uint32_t newValue)
{
if (meshFromNumCharacteristic)
{
// if bt not running ignore
meshFromNumCharacteristic->setValue(newValue);
meshFromNumCharacteristic->notify();
}
}
BLEService *meshService;
/*
MeshBluetoothService UUID 6ba1b218-15a8-461f-9fa8-5dcae273eafd
FIXME - notify vs indication for fromradio output. Using notify for now, not sure if that is best
FIXME - in the esp32 mesh managment code, occasionally mirror the current net db to flash, so that if we reboot we still have a good guess of users who are out there.
FIXME - make sure this protocol is guaranteed robust and won't drop packets
"According to the BLE specification the notification length can be max ATT_MTU - 3. The 3 bytes subtracted is the 3-byte header(OP-code (operation, 1 byte) and the attribute handle (2 bytes)).
In BLE 4.1 the ATT_MTU is 23 bytes (20 bytes for payload), but in BLE 4.2 the ATT_MTU can be negotiated up to 247 bytes."
MAXPACKET is 256? look into what the lora lib uses. FIXME
Characteristics:
UUID
properties
description
8ba2bcc2-ee02-4a55-a531-c525c5e454d5
read
fromradio - contains a newly received packet destined towards the phone (up to MAXPACKET bytes? per packet).
After reading the esp32 will put the next packet in this mailbox. If the FIFO is empty it will put an empty packet in this
mailbox.
f75c76d2-129e-4dad-a1dd-7866124401e7
write
toradio - write ToRadio protobufs to this charstic to send them (up to MAXPACKET len)
ed9da18c-a800-4f66-a670-aa7547e34453
read|notify|write
fromnum - the current packet # in the message waiting inside fromradio, if the phone sees this notify it should read messages
until it catches up with this number.
The phone can write to this register to go backwards up to FIXME packets, to handle the rare case of a fromradio packet was dropped after the esp32
callback was called, but before it arrives at the phone. If the phone writes to this register the esp32 will discard older packets and put the next packet >= fromnum in fromradio.
When the esp32 advances fromnum, it will delay doing the notify by 100ms, in the hopes that the notify will never actally need to be sent if the phone is already pulling from fromradio.
Note: that if the phone ever sees this number decrease, it means the esp32 has rebooted.
meshMyNodeCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ)
mynode - read this to access a MyNodeInfo protobuf
meshNodeInfoCharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ),
nodeinfo - read this to get a series of node infos (ending with a null empty record), write to this to restart the read statemachine that returns all the node infos
meshRadioCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ),
radio - read/write this to access a RadioConfig protobuf
meshOwnerCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
owner - read/write this to access a User protobuf
Re: queue management
Not all messages are kept in the fromradio queue (filtered based on SubPacket):
* only the most recent Position and User messages for a particular node are kept
* all Data SubPackets are kept
* No WantNodeNum / DenyNodeNum messages are kept
A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging)
*/
BLEService *createMeshBluetoothService(BLEServer *server)
{
// Create the BLE Service, we need more than the default of 15 handles
BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 25, 0);
assert(!meshFromNumCharacteristic);
meshFromNumCharacteristic = new FromNumCharacteristic;
addWithDesc(service, meshFromNumCharacteristic, "fromRadio");
addWithDesc(service, new ToRadioCharacteristic, "toRadio");
addWithDesc(service, new FromRadioCharacteristic, "fromNum");
addWithDesc(service, new ProtobufCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ, MyNodeInfo_fields, &myNodeInfo), "myNode");
addWithDesc(service, new RadioCharacteristic, "radio");
addWithDesc(service, new OwnerCharacteristic, "owner");
addWithDesc(service, new NodeInfoCharacteristic, "nodeinfo");
meshFromNumCharacteristic->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
service->start();
// We only add to advertisting once, because the ESP32 arduino code is dumb and that object never dies
static bool firstTime = true;
if (firstTime)
{
firstTime = false;
server->getAdvertising()->addServiceUUID(service->getUUID());
}
DEBUG_MSG("*** Mesh service:\n");
service->dump();
meshService = service;
return service;
}
void stopMeshBluetoothService()
{
assert(meshService);
meshService->stop();
}
void destroyMeshBluetoothService()
{
assert(meshService);
delete meshService;
meshFromNumCharacteristic = NULL;
}

View File

@@ -1,132 +0,0 @@
#include <SPI.h>
#include "RH_RF95.h"
#include <RHMesh.h>
#include <assert.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "MeshRadio.h"
#include "configuration.h"
#include "NodeDB.h"
#define DEFAULT_CHANNEL_NUM 3 // we randomly pick one
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
/**
* ## LoRaWAN for North America
LoRaWAN defines 64, 125 kHz channels from 902.3 to 914.9 MHz increments.
The maximum output power for North America is +30 dBM.
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.
*/
/// Sometimes while debugging it is useful to set this false, to disable rf95 accesses
bool useHardware = true;
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
: rf95(_pool, _rxDest),
manager(rf95)
{
myNodeInfo.num_channels = NUM_CHANNELS;
//radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
//channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth so incompatible radios can talk together
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
channelSettings.tx_power = 23;
channelSettings.channel_num = DEFAULT_CHANNEL_NUM;
memcpy(&channelSettings.psk, &defaultpsk, sizeof(channelSettings.psk));
strcpy(channelSettings.name, "Default");
// Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
}
bool MeshRadio::init()
{
if (!useHardware)
return true;
DEBUG_MSG("Starting meshradio init...\n");
#ifdef RESET_GPIO
pinMode(RESET_GPIO, OUTPUT); // Deassert reset
digitalWrite(RESET_GPIO, HIGH);
// pulse reset
digitalWrite(RESET_GPIO, LOW);
delay(10);
digitalWrite(RESET_GPIO, HIGH);
delay(10);
#endif
manager.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor time.
if (!manager.init())
{
DEBUG_MSG("LoRa radio init failed\n");
DEBUG_MSG("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info\n");
return false;
}
// not needed - defaults on
// rf95.setPayloadCRC(true);
reloadConfig();
return true;
}
void MeshRadio::reloadConfig()
{
rf95.setModeIdle(); // Need to be idle before doing init
// Set up default configuration
// No Sync Words in LORA mode.
rf95.setModemConfig((RH_RF95::ModemConfigChoice)channelSettings.modem_config); // Radio default
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
// rf95.setPreambleLength(8); // Default is 8
assert(channelSettings.channel_num < NUM_CHANNELS); // If the phone tries to tell us to use an illegal channel then panic
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
float center_freq = CH0 + CH_SPACING * channelSettings.channel_num;
if (!rf95.setFrequency(center_freq))
{
DEBUG_MSG("setFrequency failed\n");
assert(0); // fixme panic
}
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
// FIXME - can we do this? It seems to be in the Heltec board.
rf95.setTxPower(channelSettings.tx_power, false);
DEBUG_MSG("Set radio: name=%s. config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config, channelSettings.channel_num, channelSettings.tx_power);
// Done with init tell radio to start receiving
rf95.setModeRx();
}
ErrorCode MeshRadio::send(MeshPacket *p)
{
if (useHardware)
return rf95.send(p);
else
{
rf95.pool.release(p);
return ERRNO_OK;
}
}
void MeshRadio::loop()
{
// Currently does nothing, since we do it all in ISRs now
}

View File

@@ -1,93 +0,0 @@
#pragma once
#include "CustomRF95.h"
#include <RHMesh.h>
#include "MemoryPool.h"
#include "mesh.pb.h"
#include "PointerQueue.h"
#include "MeshTypes.h"
#include "configuration.h"
// US channel settings
#define CH0_US 903.08f // MHz
#define CH_SPACING_US 2.16f // MHz
#define NUM_CHANNELS_US 13
// EU channel settings
#define CH0_EU 865.2f // MHz
#define CH_SPACING_EU 0.3f // MHz
#define NUM_CHANNELS_EU 10
// CN channel settings
#define CH0_CN 470.0f // MHz
#define CH_SPACING_CN 2.0f // MHz FIXME, this is just a guess for 470-510
#define NUM_CHANNELS_CN 20
// CN channel settings
#define CH0_JP 920.0f // MHz
#define CH_SPACING_JP 0.5f // MHz FIXME, this is just a guess for 920-925
#define NUM_CHANNELS_JP 10
// FIXME add defs for other regions and use them here
#ifdef HW_VERSION_US
#define CH0 CH0_US
#define CH_SPACING CH_SPACING_US
#define NUM_CHANNELS NUM_CHANNELS_US
#elif defined(HW_VERSION_EU)
#define CH0 CH0_EU
#define CH_SPACING CH_SPACING_EU
#define NUM_CHANNELS NUM_CHANNELS_EU
#elif defined(HW_VERSION_CN)
#define CH0 CH0_CN
#define CH_SPACING CH_SPACING_CN
#define NUM_CHANNELS NUM_CHANNELS_CN
#elif defined(HW_VERSION_JP)
#define CH0 CH0_JP
#define CH_SPACING CH_SPACING_JP
#define NUM_CHANNELS NUM_CHANNELS_JP
#else
#error "HW_VERSION not set"
#endif
/**
* A raw low level interface to our mesh. Only understands nodenums and bytes (not protobufs or node ids)
*/
class MeshRadio {
public:
CustomRF95 rf95; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing
/** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
*/
MeshRadio(MemoryPool<MeshPacket> &pool, PointerQueue<MeshPacket> &rxDest);
bool init();
/// 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 because it is called from
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode send(MeshPacket *p);
/// Do loop callback operations (we currently FIXME poll the receive mailbox here)
/// for received packets it will call the rx handler
void loop();
/// The radioConfig object just changed, call this to force the hw to change to the new settings
void reloadConfig();
private:
// RHDatagram manager;
// RHReliableDatagram manager; // don't use mesh yet
RHMesh manager;
// MeshRXHandler rxHandler;
/// low level send, might block for mutiple seconds
ErrorCode sendTo(NodeNum dest, const uint8_t *buf, size_t len);
/// enqueue a received packet in rxDest
void handleReceive(MeshPacket *p);
};

View File

@@ -1,358 +0,0 @@
#include <Arduino.h>
#include <assert.h>
#include "mesh-pb-constants.h"
#include "MeshService.h"
#include "MeshBluetoothService.h"
#include "NodeDB.h"
#include "GPS.h"
#include "screen.h"
#include "Periodic.h"
#include "PowerFSM.h"
/*
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were alloced with new).
After a packet ptr is removed from the queue and processed it should be deleted. (eventually we should move sent packets into a 'sentToPhone' queue
of packets we can delete just as soon as we are sure the phone has acked those packets - when the phone writes to FromNum)
mesh - an instance of Mesh class. Which manages the interface to the mesh radio library, reception of packets from other nodes, arbitrating to select
a node number and keeping the current nodedb.
*/
/* Broadcast when a newly powered mesh node wants to find a node num it can use
The algoritm is as follows:
* when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so the new node can build its node db)
* If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that indicates a collision has occurred and the following steps should happen:
If the receiving node (that was already in the mesh)'s macaddr is LOWER than the new User who just tried to sign in: it gets to keep its nodenum. We send a broadcast message
of OUR User (we use a broadcast so that the other node can receive our message, considering we have the same id - it also serves to let observers correct their nodedb) - this case is rare so it should be okay.
If any node receives a User where the macaddr is GTE than their local macaddr, they have been vetoed and should pick a new random nodenum (filtering against whatever it knows about the nodedb) and
rebroadcast their User.
FIXME in the initial proof of concept we just skip the entire want/deny flow and just hand pick node numbers at first.
*/
MeshService service;
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
#define MAX_PACKETS (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + MAX_TX_QUEUE + 2) // max number of packets which can be in flight (either queued from reception or queued for sending)
#define MAX_RX_FROMRADIO 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
MeshService::MeshService()
: packetPool(MAX_PACKETS),
toPhoneQueue(MAX_RX_TOPHONE),
fromRadioQueue(MAX_RX_FROMRADIO),
fromNum(0),
radio(packetPool, fromRadioQueue)
{
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
}
void MeshService::init()
{
nodeDB.init();
if (!radio.init())
DEBUG_MSG("radio init failed\n");
gps.addObserver(this);
// No need to call this here, our periodic task will fire quite soon
// sendOwnerPeriod();
}
void MeshService::sendOurOwner(NodeNum dest)
{
MeshPacket *p = allocForSending();
p->to = dest;
p->payload.which_variant = SubPacket_user_tag;
User &u = p->payload.variant.user;
u = owner;
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
sendToMesh(p);
}
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
MeshPacket *MeshService::handleFromRadioUser(MeshPacket *mp)
{
bool wasBroadcast = mp->to == NODENUM_BROADCAST;
bool isCollision = mp->from == myNodeInfo.my_node_num;
// we win if we have a lower macaddr
bool weWin = memcmp(&owner.macaddr, &mp->payload.variant.user.macaddr, sizeof(owner.macaddr)) < 0;
if (isCollision)
{
if (weWin)
{
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
packetPool.release(mp); // discard it
mp = NULL;
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
}
else
{
// we lost, we need to try for a new nodenum!
DEBUG_MSG("NOTE! Received a nodenum collision we lost, so picking a new nodenum\n");
nodeDB.updateFrom(*mp); // update the DB early - before trying to repick (so we don't select the same node number again)
nodeDB.pickNewNodeNum();
sendOurOwner(); // broadcast our new attempt at a node number
}
}
else if (wasBroadcast)
{
// If we haven't yet abandoned the packet and it was a broadcast, reply (just to them) with our User record so they can build their DB
// Someone just sent us a User, reply with our Owner
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
sendOurOwner(mp->from);
String lcd = String("Joined: ") + mp->payload.variant.user.long_name + "\n";
screen_print(lcd.c_str());
}
return mp;
}
void MeshService::handleIncomingPosition(MeshPacket *mp)
{
if (mp->has_payload && mp->payload.which_variant == SubPacket_position_tag)
{
DEBUG_MSG("handled incoming position time=%u\n", mp->payload.variant.position.time);
if (mp->payload.variant.position.time)
{
struct timeval tv;
uint32_t secs = mp->payload.variant.position.time;
tv.tv_sec = secs;
tv.tv_usec = 0;
gps.perhapsSetRTC(&tv);
}
}
}
void MeshService::handleFromRadio(MeshPacket *mp)
{
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
mp->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone
// If it is a position packet, perhaps set our clock (if we don't have a GPS of our own, otherwise wait for that to work)
if (!myNodeInfo.has_gps)
handleIncomingPosition(mp);
if (mp->has_payload && mp->payload.which_variant == SubPacket_user_tag)
{
mp = handleFromRadioUser(mp);
}
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
if (mp)
{
DEBUG_MSG("Forwarding to phone, from=0x%x, rx_time=%u\n", mp->from, mp->rx_time);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++;
if (toPhoneQueue.numFree() == 0)
{
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
assert(toPhoneQueue.enqueue(mp, 0) == pdTRUE); // FIXME, instead of failing for full queue, delete the oldest mssages
if (mp->payload.want_response)
sendNetworkPing(mp->from);
}
else
DEBUG_MSG("Dropping vetoed User message\n");
}
void MeshService::handleFromRadio()
{
MeshPacket *mp;
uint32_t oldFromNum = fromNum;
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL)
{
handleFromRadio(mp);
}
if (oldFromNum != fromNum) // We don't want to generate extra notifies for multiple new packets
bluetoothNotifyFromNum(fromNum);
}
uint32_t sendOwnerCb()
{
service.sendOurOwner();
return radioConfig.preferences.send_owner_interval * radioConfig.preferences.position_broadcast_secs * 1000;
}
Periodic sendOwnerPeriod(sendOwnerCb);
/// Do idle processing (mostly processing messages which have been queued from the radio)
void MeshService::loop()
{
radio.loop(); // FIXME, possibly move radio interaction to own thread
handleFromRadio();
// occasionally send our owner info
sendOwnerPeriod.loop();
}
/// The radioConfig object just changed, call this to force the hw to change to the new settings
void MeshService::reloadConfig()
{
// If we can successfully set this radio to these settings, save them to disk
radio.reloadConfig();
nodeDB.saveToDisk();
}
/// Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
void MeshService::handleToRadio(std::string s)
{
static ToRadio r; // this is a static scratch object, any data must be copied elsewhere before returning
if (pb_decode_from_bytes((const uint8_t *)s.c_str(), s.length(), ToRadio_fields, &r))
{
switch (r.which_variant)
{
case ToRadio_packet_tag:
{
// If our phone is sending a position, see if we can use it to set our RTC
handleIncomingPosition(&r.variant.packet); // If it is a position packet, perhaps set our clock
r.variant.packet.rx_time = gps.getValidTime(); // Record the time the packet arrived from the phone (so we update our nodedb for the local node)
// Send the packet into the mesh
sendToMesh(packetPool.allocCopy(r.variant.packet));
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
if (loopback)
{
MeshPacket *mp = packetPool.allocCopy(r.variant.packet);
handleFromRadio(mp);
bluetoothNotifyFromNum(fromNum); // tell the phone a new packet arrived
}
break;
}
default:
DEBUG_MSG("Error: unexpected ToRadio variant\n");
break;
}
}
}
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: for now, we allow a device with a local GPS to include the time, so that gpsless devices can get time.
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag)
{
if (!myNodeInfo.has_gps)
p->payload.variant.position.time = 0;
else
DEBUG_MSG("Providing time to mesh %u\n", p->payload.variant.position.time);
}
// If the phone sent a packet just to us, don't send it out into the network
if (p->to == nodeDB.getNodeNum())
DEBUG_MSG("Dropping locally processed message\n");
else
{
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
if (radio.send(p) != ERRNO_OK)
DEBUG_MSG("Dropped packet because send queue was full!\n");
}
}
MeshPacket *MeshService::allocForSending()
{
MeshPacket *p = packetPool.allocZeroed();
p->has_payload = true;
p->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST;
p->rx_time = gps.getValidTime(); // Just in case we process the packet locally - make sure it has a valid timestamp
return p;
}
void MeshService::sendNetworkPing(NodeNum dest)
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
if (node->has_position)
sendOurPosition(dest);
else
sendOurOwner(dest);
}
void MeshService::sendOurPosition(NodeNum dest)
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocForSending();
p->to = dest;
p->payload.which_variant = SubPacket_position_tag;
p->payload.variant.position = node->position;
p->payload.variant.position.time = gps.getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid.
sendToMesh(p);
}
void MeshService::onGPSChanged()
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocForSending();
p->payload.which_variant = SubPacket_position_tag;
Position &pos = p->payload.variant.position;
if (gps.altitude.isValid())
pos.altitude = gps.altitude.meters();
pos.latitude = gps.location.lat();
pos.longitude = gps.location.lng();
pos.time = gps.getValidTime();
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();
if (lastGpsSend == 0 || now - lastGpsSend > radioConfig.preferences.position_broadcast_secs * 1000)
{
lastGpsSend = now;
DEBUG_MSG("Sending position to mesh\n");
sendToMesh(p);
}
else
{
// We don't need to send this packet to anyone else, but it still serves as a nice uniform way to update our local state
nodeDB.updateFrom(*p);
releaseToPool(p);
}
}
void MeshService::onNotify(Observable *o)
{
DEBUG_MSG("got gps notify\n");
onGPSChanged();
}

View File

@@ -1,13 +0,0 @@
#pragma once
// low level types
#include <Arduino.h>
typedef uint8_t NodeNum;
#define NODENUM_BROADCAST 255
#define ERRNO_OK 0
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
typedef int ErrorCode;

49
src/OSTimer.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "OSTimer.h"
#include "configuration.h"
#ifdef NO_ESP32
/**
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
*
* NOTE! xTimerPend... seems to ignore the time passed in on ESP32 - I haven't checked on NRF52
*
* @return true if successful, false if the timer fifo is too full.
*/
bool scheduleOSCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
{
return xTimerPendFunctionCall(callback, param1, param2, pdMS_TO_TICKS(delayMsec));
}
#else
// Super skanky quick hack to use hardware timers of the ESP32
static hw_timer_t *timer;
static PendableFunction tCallback;
static void *tParam1;
static uint32_t tParam2;
static void IRAM_ATTR onTimer()
{
(*tCallback)(tParam1, tParam2);
}
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec)
{
if (!timer) {
timer = timerBegin(0, 80, true); // one usec per tick (main clock is 80MhZ on ESP32)
assert(timer);
timerAttachInterrupt(timer, &onTimer, true);
}
tCallback = callback;
tParam1 = param1;
tParam2 = param2;
timerAlarmWrite(timer, delayMsec * 1000L, false); // Do not reload, we want it to be a single shot timer
timerRestart(timer);
timerAlarmEnable(timer);
return true;
}
#endif

18
src/OSTimer.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <Arduino.h>
typedef void (*PendableFunction)(void *pvParameter1, uint32_t ulParameter2);
/**
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
*
* NOTE! ESP32 implementation is busted - always waits 0 ticks
*
* @return true if successful, false if the timer fifo is too full.
*/
bool scheduleOSCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec);
/// Uses a hardware timer, but calls the handler in _interrupt_ context
bool scheduleHWCallback(PendableFunction callback, void *param1, uint32_t param2, uint32_t delayMsec);

View File

@@ -1,13 +1,2 @@
#include "Observer.h" #include "Observer.h"
Observer::~Observer()
{
if (observed)
observed->removeObserver(this);
observed = NULL;
}
void Observer::observe(Observable *o)
{
o->addObserver(this);
}

View File

@@ -1,49 +1,98 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <assert.h>
#include <list> #include <list>
class Observable; template <class T> class Observable;
class Observer /**
* An observer which can be mixed in as a baseclass. Implement onNotify as a method in your class.
*/
template <class T> class Observer
{ {
Observable *observed; Observable<T> *observed = NULL;
public:
Observer() : observed(NULL) {}
public:
virtual ~Observer(); virtual ~Observer();
void observe(Observable *o); void observe(Observable<T> *o);
private: private:
friend class Observable; friend class Observable<T>;
virtual void onNotify(Observable *o) = 0; protected:
/**
* returns 0 if other observers should continue to be called
* returns !0 if the observe calls should be aborted and this result code returned for notifyObservers
**/
virtual int onNotify(T arg) = 0;
}; };
class Observable /**
* An observer that calls an arbitrary method
*/
template <class Callback, class T> class CallbackObserver : public Observer<T>
{ {
std::list<Observer *> observers; typedef int (Callback::*ObserverCallback)(T arg);
public: Callback *objPtr;
void notifyObservers() ObserverCallback method;
{
for (std::list<Observer *>::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator)
{
(*iterator)->onNotify(this);
}
}
void addObserver(Observer *o) public:
{ CallbackObserver(Callback *_objPtr, ObserverCallback _method) : objPtr(_objPtr), method(_method) {}
observers.push_back(o);
}
void removeObserver(Observer *o) protected:
{ virtual int onNotify(T arg) { return (objPtr->*method)(arg); }
observers.remove(o);
}
}; };
/**
* An observable class that will notify observers anytime notifyObservers is called. Argument type T can be any type, but for
* performance reasons a pointer or word sized object is recommended.
*/
template <class T> class Observable
{
std::list<Observer<T> *> observers;
public:
/**
* Tell all observers about a change, observers can process arg as they wish
*
* returns !0 if an observer chose to abort processing by returning this code
*/
int notifyObservers(T arg)
{
for (typename std::list<Observer<T> *>::const_iterator iterator = observers.begin(); iterator != observers.end();
++iterator) {
int result = (*iterator)->onNotify(arg);
if (result != 0)
return result;
}
return 0;
}
private:
friend class Observer<T>;
// Not called directly, instead call observer.observe
void addObserver(Observer<T> *o) { observers.push_back(o); }
void removeObserver(Observer<T> *o) { observers.remove(o); }
};
template <class T> Observer<T>::~Observer()
{
if (observed)
observed->removeObserver(this);
observed = NULL;
}
template <class T> void Observer<T>::observe(Observable<T> *o)
{
// We can only watch one thing at a time
assert(!observed);
observed = o;
o->addObserver(this);
}

View File

@@ -1,22 +1,21 @@
#pragma once #pragma once
#include <Arduino.h>
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include <Arduino.h>
/** /**
* Periodically invoke a callback. * Periodically invoke a callback.
* *
* This just provides C style callback conventions rather than a virtual function - FIXME, remove? * This just provides C style callback conventions rather than a virtual function - FIXME, remove?
*/ */
class Periodic : public PeriodicTask class Periodic : public PeriodicTask
{ {
uint32_t (*callback)(); uint32_t (*callback)();
public: public:
// callback returns the period for the next callback invocation (or 0 if we should no longer be called) // callback returns the period for the next callback invocation (or 0 if we should no longer be called)
Periodic(uint32_t (*_callback)()) : callback(_callback) {} Periodic(uint32_t (*_callback)()) : callback(_callback) {}
protected: protected:
void doTask();
void doTask();
}; };

View File

@@ -1,23 +1,43 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "Periodic.h" #include "Periodic.h"
PeriodicScheduler periodicScheduler;
PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) {}
void PeriodicTask::setup()
{ {
periodicScheduler.schedule(this);
} }
/// call this from loop /// call this from loop
void PeriodicTask::loop() void PeriodicScheduler::loop()
{ {
meshtastic::LockGuard lg(&lock);
uint32_t now = millis(); uint32_t now = millis();
if (period && (now - lastMsec) >= period) for (auto t : tasks) {
{ if (t->period && (now - t->lastMsec) >= t->period) {
lastMsec = now;
doTask(); t->doTask();
t->lastMsec = now;
}
} }
} }
void PeriodicScheduler::schedule(PeriodicTask *t)
{
meshtastic::LockGuard lg(&lock);
tasks.insert(t);
}
void PeriodicScheduler::unschedule(PeriodicTask *t)
{
meshtastic::LockGuard lg(&lock);
tasks.erase(t);
}
void Periodic::doTask() void Periodic::doTask()
{ {
uint32_t p = callback(); uint32_t p = callback();
setPeriod(p); setPeriod(p);
} }

View File

@@ -1,33 +1,78 @@
#pragma once #pragma once
#include <Arduino.h> #include "lock.h"
#include "configuration.h" #include <cstdint>
#include <unordered_set>
class PeriodicTask;
/**
* Runs all PeriodicTasks in the system.
*
* Currently called from main loop() but eventually should be its own thread blocked on a freertos timer.
*/
class PeriodicScheduler
{
friend class PeriodicTask;
/**
* This really should be some form of heap, and when the period gets changed on a task it should get
* rescheduled in that heap. Currently it is just a dumb array and everytime we run loop() we check
* _every_ tasks. If it was a heap we'd only have to check the first task.
*/
std::unordered_set<PeriodicTask *> tasks;
// Protects the above variables.
meshtastic::Lock lock;
public:
/// Run any next tasks which are due for execution
void loop();
private:
void schedule(PeriodicTask *t);
void unschedule(PeriodicTask *t);
};
extern PeriodicScheduler periodicScheduler;
/** /**
* A base class for tasks that want their doTask() method invoked periodically * A base class for tasks that want their doTask() method invoked periodically
* *
* FIXME: currently just syntatic sugar for polling in loop (you must call .loop), but eventually * FIXME: currently just syntatic sugar for polling in loop (you must call .loop), but eventually
* generalize with the freertos scheduler so we can save lots of power by having everything either in * generalize with the freertos scheduler so we can save lots of power by having everything either in
* something like this or triggered off of an irq. * something like this or triggered off of an irq.
*/ */
class PeriodicTask class PeriodicTask
{ {
friend class PeriodicScheduler;
uint32_t lastMsec = 0; uint32_t lastMsec = 0;
uint32_t period = 1; // call soon after creation uint32_t period = 1; // call soon after creation
public: public:
uint32_t periodMsec; virtual ~PeriodicTask() { periodicScheduler.unschedule(this); }
virtual ~PeriodicTask() {}
/**
* Constructor (will schedule with the global PeriodicScheduler)
*/
PeriodicTask(uint32_t initialPeriod = 1); PeriodicTask(uint32_t initialPeriod = 1);
/// call this from loop /** MUST be be called once at startup (but after threading is running - i.e. not from a constructor)
virtual void loop(); */
void setup();
/// Set a new period in msecs (can be called from doTask or elsewhere and the scheduler will cope) /**
* Set a new period in msecs (can be called from doTask or elsewhere and the scheduler will cope)
* While zero this task is disabled and will not run
*/
void setPeriod(uint32_t p) { period = p; } void setPeriod(uint32_t p) { period = p; }
protected: /**
* Syntatic sugar for suspending tasks
*/
void disable() { setPeriod(0); }
protected:
virtual void doTask() = 0; virtual void doTask() = 0;
}; };

View File

@@ -1,12 +1,13 @@
#include "sleep.h" #include "PowerFSM.h"
#include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h" #include "configuration.h"
#include "screen.h"
#include "PowerFSM.h"
#include "GPS.h"
#include "main.h" #include "main.h"
#include "screen.h"
#include "sleep.h"
#include "target_specific.h"
static void sdsEnter() static void sdsEnter()
{ {
@@ -23,27 +24,26 @@ static void sdsEnter()
doDeepSleep(radioConfig.preferences.sds_secs * 1000LL); doDeepSleep(radioConfig.preferences.sds_secs * 1000LL);
} }
#include "error.h"
static void lsEnter() static void lsEnter()
{ {
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
screen.setOn(false); screen.setOn(false);
while (!service.radio.rf95.canSleep())
delay(10); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
gps.prepareSleep(); // abandon in-process parsing DEBUG_MSG("lsEnter end\n");
if (!isUSBPowered) // FIXME - temp hack until we can put gps in sleep mode, if we have AC when we go to sleep then leave GPS on
setGPSPower(false); // kill GPS power
} }
static void lsIdle() static void lsIdle()
{ {
DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
#ifndef NO_ESP32
uint32_t secsSlept = 0; uint32_t secsSlept = 0;
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED; esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
bool reached_ls_secs = false; bool reached_ls_secs = false;
while (!reached_ls_secs) while (!reached_ls_secs) {
{
// Briefly come out of sleep long enough to blink the led once every few seconds // Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 5; uint32_t sleepTime = 5;
@@ -62,22 +62,32 @@ static void lsIdle()
} }
setLed(false); setLed(false);
if (reached_ls_secs) if (reached_ls_secs) {
{
// stay in LS mode but let loop check whatever it wants // stay in LS mode but let loop check whatever it wants
DEBUG_MSG("reached ls_secs, servicing loop()\n"); DEBUG_MSG("reached ls_secs, servicing loop()\n");
} else {
DEBUG_MSG("wakeCause %d\n", wakeCause);
#ifdef BUTTON_PIN
bool pressed = !digitalRead(BUTTON_PIN);
#else
bool pressed = false;
#endif
if (pressed) // If we woke because of press, instead generate a PRESS event.
{
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
powerFSM.trigger(EVENT_WAKE_TIMER);
}
} }
else #endif
{
// Regardless of why we woke just transition to NB (and that state will handle stuff like IRQs etc)
powerFSM.trigger(EVENT_WAKE_TIMER);
}
} }
static void lsExit() static void lsExit()
{ {
setGPSPower(true); // restore GPS power // setGPSPower(true); // restore GPS power
gps.startLock(); gps->startLock();
} }
static void nbEnter() static void nbEnter()
@@ -90,6 +100,7 @@ static void nbEnter()
static void darkEnter() static void darkEnter()
{ {
setBluetoothEnable(true);
screen.setOn(false); screen.setOn(false);
} }
@@ -97,42 +108,59 @@ static void onEnter()
{ {
screen.setOn(true); screen.setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
static uint32_t lastPingMs;
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 (displayedNodeNum)
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now;
}
} }
static void wakeForPing() {}
static void wakeForPing()
{
}
static void screenPress() static void screenPress()
{ {
screen.onPress(); screen.onPress();
} }
static void bootEnter() {}
State stateSDS(sdsEnter, NULL, NULL, "SDS"); State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS"); State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB"); State stateNB(nbEnter, NULL, NULL, "NB");
State stateDARK(darkEnter, NULL, NULL, "DARK"); State stateDARK(darkEnter, NULL, NULL, "DARK");
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
State stateON(onEnter, NULL, NULL, "ON"); State stateON(onEnter, NULL, NULL, "ON");
Fsm powerFSM(&stateDARK); Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BOOT, NULL, "Boot"); powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout");
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer"); powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then it handles things // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then it
// powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet"); // handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake"); powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then it handles things // Handle press events
// powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
// Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateLS, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateNB, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing"); powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
@@ -153,12 +181,19 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout"); powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout");
#ifndef NRF52_SERIES
// We never enter light-sleep state on NRF52 (because the CPU uses so little power normally)
powerFSM.add_timed_transition(&stateNB, &stateLS, radioConfig.preferences.min_wake_secs * 1000, NULL, "Min wake timeout"); powerFSM.add_timed_transition(&stateNB, &stateLS, radioConfig.preferences.min_wake_secs * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL, "Bluetooth timeout"); powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL,
"Bluetooth timeout");
#endif
powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL, "mesh timeout"); powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL,
powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.phone_sds_timeout_sec * 1000, NULL, "phone timeout"); "mesh timeout");
// removing for now, because some users don't even have phones
// powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.phone_sds_timeout_sec * 1000, NULL, "phone
// timeout");
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
} }

View File

@@ -1,4 +1,4 @@
#pragma once #pragma once
#include <Fsm.h> #include <Fsm.h>
@@ -9,10 +9,11 @@
#define EVENT_RECEIVED_PACKET 3 #define EVENT_RECEIVED_PACKET 3
#define EVENT_PACKET_FOR_PHONE 4 #define EVENT_PACKET_FOR_PHONE 4
#define EVENT_RECEIVED_TEXT_MSG 5 #define EVENT_RECEIVED_TEXT_MSG 5
#define EVENT_BOOT 6 // #define EVENT_BOOT 6 // now done with a timed transition
#define EVENT_BLUETOOTH_PAIR 7 #define EVENT_BLUETOOTH_PAIR 7
#define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen #define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen
#define EVENT_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth #define EVENT_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
extern Fsm powerFSM; extern Fsm powerFSM;

13
src/RedirectablePrint.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "RedirectablePrint.h"
#include <assert.h>
/**
* A printer that doesn't go anywhere
*/
NoopPrint noopPrint;
void RedirectablePrint::setDestination(Print *_dest)
{
assert(_dest);
dest = _dest;
}

34
src/RedirectablePrint.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include <Print.h>
/**
* A Printable that can be switched to squirt its bytes to a different sink.
* This class is mostly useful to allow debug printing to be redirected away from Serial
* to some other transport if we switch Serial usage (on the fly) to some other purpose.
*/
class RedirectablePrint : public Print
{
Print *dest;
public:
RedirectablePrint(Print *_dest) : dest(_dest) {}
/**
* Set a new destination
*/
void setDestination(Print *dest);
virtual size_t write(uint8_t c) { return dest->write(c); }
};
class NoopPrint : public Print
{
public:
virtual size_t write(uint8_t c) { return 1; }
};
/**
* A printer that doesn't go anywhere
*/
extern NoopPrint noopPrint;

37
src/SerialConsole.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "SerialConsole.h"
#include "configuration.h"
#include <Arduino.h>
#define Port Serial
SerialConsole console;
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
{
canWrite = false; // We don't send packets to our port until it has talked to us first
// setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks
}
/// Do late init that can't happen at constructor time
void SerialConsole::init()
{
Port.begin(SERIAL_BAUD);
StreamAPI::init();
emitRebooted();
}
/**
* we override this to notice when we've received a protobuf over the serial
* stream. Then we shunt off debug serial output.
*/
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
{
// Note: for the time being we could _allow_ debug printing to keep going out the console
// I _think_ this is okay because we currently only print debug msgs from loop() and we are only
// dispatching serial protobuf msgs from loop() as well. When things are more threaded in the future this
// will need to change.
// setDestination(&noopPrint);
canWrite = true;
StreamAPI::handleToRadio(buf, len);
}

31
src/SerialConsole.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include "RedirectablePrint.h"
#include "StreamAPI.h"
/**
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
class SerialConsole : public StreamAPI, public RedirectablePrint
{
public:
SerialConsole();
/// Do late init that can't happen at constructor time
virtual void init();
/**
* we override this to notice when we've received a protobuf over the serial stream. Then we shunt off
* debug serial output.
*/
virtual void handleToRadio(const uint8_t *buf, size_t len);
virtual size_t write(uint8_t c)
{
if (c == '\n') // prefix any newlines with carriage return
RedirectablePrint::write('\r');
return RedirectablePrint::write(c);
}
};
extern SerialConsole console;

View File

@@ -1,58 +0,0 @@
#pragma once
#include <Arduino.h>
#include <assert.h>
/**
* A wrapper for freertos queues. Note: each element object must be quite small, so T should be only
* pointer types or ints
*/
template <class T>
class TypedQueue
{
QueueHandle_t h;
public:
TypedQueue(int maxElements)
{
h = xQueueCreate(maxElements, sizeof(T));
assert(h);
}
~TypedQueue()
{
vQueueDelete(h);
}
int numFree()
{
return uxQueueSpacesAvailable(h);
}
bool isEmpty()
{
return uxQueueMessagesWaiting(h) == 0;
}
// pdTRUE for success else failure
BaseType_t enqueue(T x, TickType_t maxWait = portMAX_DELAY)
{
return xQueueSendToBack(h, &x, maxWait);
}
BaseType_t enqueueFromISR(T x, BaseType_t *higherPriWoken)
{
return xQueueSendToBackFromISR(h, &x, higherPriWoken);
}
// pdTRUE for success else failure
BaseType_t dequeue(T *p, TickType_t maxWait = portMAX_DELAY)
{
return xQueueReceive(h, p, maxWait);
}
BaseType_t dequeueFromISR(T *p, BaseType_t *higherPriWoken)
{
return xQueueReceiveFromISR(h, p, higherPriWoken);
}
};

37
src/WorkerThread.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "WorkerThread.h"
#include <assert.h>
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
{
auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle);
assert(r == pdPASS);
}
void Thread::callRun(void *_this)
{
((Thread *)_this)->doRun();
}
void WorkerThread::doRun()
{
while (!wantExit) {
block();
loop();
}
}
/**
* Notify this thread so it can run
*/
void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action)
{
xTaskNotify(taskHandle, v, action);
}
void NotifiedWorkerThread::block()
{
xTaskNotifyWait(0, // don't clear notification on entry
clearOnRead, &notification, portMAX_DELAY); // Wait forever
}

89
src/WorkerThread.h Normal file
View File

@@ -0,0 +1,89 @@
#include <Arduino.h>
class Thread
{
protected:
TaskHandle_t taskHandle = NULL;
/**
* set this to true to ask thread to cleanly exit asap
*/
volatile bool wantExit = false;
public:
void start(const char *name, size_t stackSize = 1024, uint32_t priority = tskIDLE_PRIORITY);
virtual ~Thread() { vTaskDelete(taskHandle); }
protected:
/**
* The method that will be called when start is called.
*/
virtual void doRun() = 0;
private:
static void callRun(void *_this);
};
/**
* This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting onlyschool arduino loop() code.
*
* Use as a mixin base class for the classes you want to convert.
*
* https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
*/
class WorkerThread : public Thread
{
protected:
/**
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
*/
virtual void block() = 0;
virtual void loop() = 0;
/**
* The method that will be called when start is called.
*/
virtual void doRun();
};
/**
* A worker thread that waits on a freertos notification
*/
class NotifiedWorkerThread : public WorkerThread
{
public:
/**
* Notify this thread so it can run
*/
void notify(uint32_t v = 0, eNotifyAction action = eNoAction);
/**
* Notify from an ISR
*
* This must be inline or IRAM_ATTR on ESP32
*/
inline void notifyFromISR(BaseType_t *highPriWoken, uint32_t v = 0, eNotifyAction action = eNoAction)
{
xTaskNotifyFromISR(taskHandle, v, action, highPriWoken);
}
protected:
/**
* The notification that was most recently used to wake the thread. Read from loop()
*/
uint32_t notification = 0;
/**
* What notification bits should be cleared just after we read and return them in notification?
*
* Defaults to clear all of them.
*/
uint32_t clearOnRead = UINT32_MAX;
/**
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
*/
virtual void block();
};

View File

@@ -31,67 +31,61 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// If app version is not specified we assume we are not being invoked by the build script // If app version is not specified we assume we are not being invoked by the build script
#ifndef APP_VERSION #ifndef APP_VERSION
#define APP_VERSION 0.0.0 // this def normally comes from build-all.sh #error APP_VERSION, HW_VERSION, and HW_VERSION_countryname must be set by the build environment
#define HW_VERSION 1.0 - US // normally comes from build-all.sh and contains the region code //#define APP_VERSION 0.0.0 // this def normally comes from build-all.sh
//#define HW_VERSION 1.0 - US // normally comes from build-all.sh and contains the region code
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Configuration // Configuration
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Select which board is being used. If the outside build environment has sent a choice, just use that
#if !defined(T_BEAM_V10) && !defined(HELTEC_LORA32)
// #define T_BEAM_V10 // AKA Rev1 (second board released)
#define HELTEC_LORA32
#define HW_VERSION_US // We encode the hardware freq range in the hw version string, so sw update can eventually install the correct build
#endif
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled) // If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
// we don't support jtag on the ttgo - access to gpio 12 is a PITA // we don't support jtag on the ttgo - access to gpio 12 is a PITA
#ifdef HELTEC_LORA32 #ifdef ARDUINO_HELTEC_WIFI_LORA_32_V2
//#define USE_JTAG //#define USE_JTAG
#endif #endif
#define DEBUG_PORT Serial // Serial debug port
#define SERIAL_BAUD 115200 // Serial debug baud rate
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found #define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
/// Convert a preprocessor name into a quoted string
#define xstr(s) str(s) #define xstr(s) str(s)
#define str(s) #s #define str(s) #s
// ----------------------------------------------------------------------------- /// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
// DEBUG #define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
// -----------------------------------------------------------------------------
#ifdef DEBUG_PORT #ifdef NRF52840_XXAA // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
#define DEBUG_MSG(...) DEBUG_PORT.printf(__VA_ARGS__) // board specific
//
// Standard definitions for NRF52 targets
//
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
// We bind to the GPS using variant.h instead for this platform (Serial1)
// FIXME, not yet ready for NRF52
#define RTC_DATA_ATTR
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
#define BUTTON_PIN PIN_BUTTON1
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#else #else
#define DEBUG_MSG(...)
#endif
// ----------------------------------------------------------------------------- //
// OLED // Standard definitions for ESP32 targets
// ----------------------------------------------------------------------------- //
#define SSD1306_ADDRESS 0x3C
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------
#define GPS_SERIAL_NUM 1 #define GPS_SERIAL_NUM 1
#define GPS_BAUDRATE 9600
#if defined(T_BEAM_V10)
#define GPS_RX_PIN 34 #define GPS_RX_PIN 34
#ifdef USE_JTAG #ifdef USE_JTAG
#define GPS_TX_PIN -1 #define GPS_TX_PIN -1
#else #else
#define GPS_TX_PIN 12 #define GPS_TX_PIN 12
#endif #endif
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// LoRa SPI // LoRa SPI
@@ -102,11 +96,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MOSI_GPIO 27 #define MOSI_GPIO 27
#define NSS_GPIO 18 #define NSS_GPIO 18
#if defined(T_BEAM_V10) #endif
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "TBEAM"
#define BICOLOR_DISPLAY // we have yellow at the top 16 lines // -----------------------------------------------------------------------------
// OLED
// -----------------------------------------------------------------------------
#define SSD1306_ADDRESS 0x3C
// Flip the screen upside down by default as it makes more sense on T-BEAM
// devices. Comment this out to not rotate screen 180 degrees.
#define FLIP_SCREEN_VERTICALLY
// DEBUG LED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------
#define GPS_BAUDRATE 9600
#if defined(TBEAM_V10)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tbeam"
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21 #define I2C_SDA 21
#define I2C_SCL 22 #define I2C_SCL 22
@@ -116,40 +131,148 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef USE_JTAG #ifndef USE_JTAG
#define RESET_GPIO 14 #define RESET_GPIO 14
#endif #endif
#define DIO0_GPIO 26 #define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board #define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board #define DIO2_GPIO 32 // Note: not really used on this board
// Leave undefined to disable our PMU IRQ handler // Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35 #define PMU_IRQ 35
#elif defined(HELTEC_LORA32) #define AXP192_SLAVE_ADDRESS 0x34
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "HELTEC"
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag #elif defined(TBEAM_V07)
#define I2C_SDA 4 // This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tbeam0.7"
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 39
#ifndef USE_JTAG
#define RESET_GPIO 23
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 12
#define GPS_TX_PIN 15
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "heltec"
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15 #define I2C_SCL 15
#endif #endif
#define RESET_OLED 16 #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 VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 #define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN 0 #define BUTTON_PIN 0 // If defined, this will be used for user button presses
#ifndef USE_JTAG #ifndef USE_JTAG
#define RESET_GPIO 14 #define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v1"
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v2"
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#endif
#ifdef ARDUINO_NRF52840_PCA10056
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "nrf52dk"
// This board uses 0 to be mean LED on
#undef LED_INVERTED
#define LED_INVERTED 1
// Uncomment to confirm if we can build the RF95 driver for NRF52
#if 0
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#endif
#elif defined(ARDUINO_NRF52840_PPR)
#define HW_VENDOR "ppr"
#endif
// -----------------------------------------------------------------------------
// DEBUG
// -----------------------------------------------------------------------------
#define SERIAL_BAUD 921600 // Serial debug baud rate
#ifdef NO_ESP32
#define USE_SEGGER
#endif
#ifdef USE_SEGGER
#include "SEGGER_RTT.h"
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#include "SerialConsole.h"
#define DEBUG_PORT console // Serial debug port
#ifdef DEBUG_PORT
#define DEBUG_MSG(...) DEBUG_PORT.printf(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif #endif
#define DIO0_GPIO 26
#define DIO1_GPIO 35
#define DIO2_GPIO 34
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// AXP192 (Rev1-specific options) // AXP192 (Rev1-specific options)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// #define AXP192_SLAVE_ADDRESS 0x34 // Now defined in axp20x.h
#define GPS_POWER_CTRL_CH 3 #define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2 #define LORA_POWER_CTRL_CH 2

20
src/debug.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include "debug.h"
#include <cstdint>
#include "freertosinc.h"
#include "configuration.h"
namespace meshtastic
{
void printThreadInfo(const char *extra)
{
#ifndef NO_ESP32
uint32_t taskHandle = reinterpret_cast<uint32_t>(xTaskGetCurrentTaskHandle());
DEBUG_MSG("printThreadInfo(%s) task: %" PRIx32 " core id: %u min free stack: %u\n", extra, taskHandle, xPortGetCoreID(),
uxTaskGetStackHighWaterMark(nullptr));
#endif
}
} // namespace meshtastic

10
src/debug.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
namespace meshtastic
{
/// Dumps out which core we are running on, and min level of remaining stack
/// seen.
void printThreadInfo(const char *extra);
} // namespace meshtastic

9
src/error.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <Arduino.h>
/// Error codes for critical error
enum CriticalErrorCode { NoError, ErrTxWatchdog, ErrSleepEnterWait, ErrNoRadio, ErrUnspecified };
/// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code, uint32_t address = 0);

View File

@@ -1,21 +1,30 @@
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h" #include "BluetoothSoftwareUpdate.h"
#include "configuration.h" #include "BluetoothUtil.h"
#include <esp_gatt_defs.h>
#include <BLE2902.h>
#include <Arduino.h>
#include <Update.h>
#include <CRC32.h>
#include "CallbackCharacteristic.h" #include "CallbackCharacteristic.h"
#include "RadioLibInterface.h"
#include "configuration.h"
#include "lock.h"
#include <Arduino.h>
#include <BLE2902.h>
#include <CRC32.h>
#include <Update.h>
#include <esp_gatt_defs.h>
using namespace meshtastic;
CRC32 crc; CRC32 crc;
uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes) uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
uint32_t updateExpectedSize, updateActualSize;
Lock *updateLock;
class TotalSizeCharacteristic : public CallbackCharacteristic class TotalSizeCharacteristic : public CallbackCharacteristic
{ {
public: public:
TotalSizeCharacteristic() TotalSizeCharacteristic()
: CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ) : CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e",
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
{ {
} }
@@ -23,43 +32,54 @@ public:
{ {
BLEKeepAliveCallbacks::onWrite(c); BLEKeepAliveCallbacks::onWrite(c);
LockGuard g(updateLock);
// Check if there is enough to OTA Update // Check if there is enough to OTA Update
uint32_t len = getValue32(c, 0); uint32_t len = getValue32(c, 0);
updateExpectedSize = len;
updateActualSize = 0;
crc.reset(); crc.reset();
bool canBegin = Update.begin(len); bool canBegin = Update.begin(len);
DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin); DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin);
if (!canBegin) if (!canBegin) {
// Indicate failure by forcing the size to 0 // Indicate failure by forcing the size to 0
c->setValue(0UL); uint32_t zero = 0;
else { c->setValue(zero);
} else {
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only // This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
// talk to one service during the sw update. // talk to one service during the sw update.
//DEBUG_MSG("FIXME, crufty shutdown of mesh bluetooth for sw update."); // DEBUG_MSG("FIXME, crufty shutdown of mesh bluetooth for sw update.");
//void stopMeshBluetoothService(); // void stopMeshBluetoothService();
//stopMeshBluetoothService(); // stopMeshBluetoothService();
if (RadioLibInterface::instance)
RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are
// writing flash - shut the radio off during updates
} }
} }
}; };
#define MAX_BLOCKSIZE 512
class DataCharacteristic : public CallbackCharacteristic class DataCharacteristic : public CallbackCharacteristic
{ {
public: public:
DataCharacteristic() DataCharacteristic() : CallbackCharacteristic("e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE) {}
: CallbackCharacteristic(
"e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE)
{
}
void onWrite(BLECharacteristic *c) void onWrite(BLECharacteristic *c)
{ {
BLEKeepAliveCallbacks::onWrite(c); BLEKeepAliveCallbacks::onWrite(c);
LockGuard g(updateLock);
std::string value = c->getValue(); std::string value = c->getValue();
uint32_t len = value.length(); uint32_t len = value.length();
uint8_t *data = c->getData(); assert(len <= MAX_BLOCKSIZE);
static uint8_t
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
memcpy(data, c->getData(), len);
// DEBUG_MSG("Writing %u\n", len); // DEBUG_MSG("Writing %u\n", len);
crc.update(data, len); crc.update(data, len);
Update.write(data, len); Update.write(data, len);
updateActualSize += len;
} }
}; };
@@ -67,49 +87,46 @@ static BLECharacteristic *resultC;
class CRC32Characteristic : public CallbackCharacteristic class CRC32Characteristic : public CallbackCharacteristic
{ {
public: public:
CRC32Characteristic() CRC32Characteristic() : CallbackCharacteristic("4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE) {}
: CallbackCharacteristic(
"4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE)
{
}
void onWrite(BLECharacteristic *c) void onWrite(BLECharacteristic *c)
{ {
BLEKeepAliveCallbacks::onWrite(c); BLEKeepAliveCallbacks::onWrite(c);
LockGuard g(updateLock);
uint32_t expectedCRC = getValue32(c, 0); uint32_t expectedCRC = getValue32(c, 0);
uint32_t actualCRC = crc.finalize();
DEBUG_MSG("expected CRC %u\n", expectedCRC); DEBUG_MSG("expected CRC %u\n", expectedCRC);
uint8_t result = 0xff; uint8_t result = 0xff;
// Check the CRC before asking the update to happen. if (updateActualSize != updateExpectedSize) {
if (crc.finalize() != expectedCRC) DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
result = 0xe1; // FIXME, use real error codes
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
{ {
DEBUG_MSG("Invalid CRC!\n"); DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
result = 0xe0; // FIXME, use real error codes result = 0xe0; // FIXME, use real error codes
} } else {
else if (Update.end()) {
{
if (Update.end())
{
DEBUG_MSG("OTA done, rebooting in 5 seconds!\n"); DEBUG_MSG("OTA done, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000; rebootAtMsec = millis() + 5000;
} } else {
else
{
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError()); DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
} }
result = Update.getError(); result = Update.getError();
} }
if (RadioLibInterface::instance)
RadioLibInterface::instance->startReceive(); // Resume radio
assert(resultC); assert(resultC);
resultC->setValue(&result, 1); resultC->setValue(&result, 1);
resultC->notify(); resultC->notify();
} }
}; };
void bluetoothRebootCheck() void bluetoothRebootCheck()
{ {
if (rebootAtMsec && millis() > rebootAtMsec) if (rebootAtMsec && millis() > rebootAtMsec)
@@ -117,30 +134,20 @@ void bluetoothRebootCheck()
} }
/* /*
SoftwareUpdateService UUID cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30 See bluetooth-api.md
Characteristics
UUID properties description
e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e write|read total image size, 32 bit, write this first, then read read back to see if it was acceptable (0 mean not accepted)
e272ebac-d463-4b98-bc84-5cc1a39ee517 write data, variable sized, recommended 512 bytes, write one for each block of file
4826129c-c22a-43a3-b066-ce8f0d5bacc6 write crc32, write last - writing this will complete the OTA operation, now you can read result
5e134862-7411-4424-ac4a-210937432c77 read|notify result code, readable but will notify when the OTA operation completes
We also implement the following standard GATT entries because SW update probably needs them:
ESP_GATT_UUID_SW_VERSION_STR/0x2a28
ESP_GATT_UUID_MANU_NAME/0x2a29
ESP_GATT_UUID_HW_VERSION_STR/0x2a27
*/ */
BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion) BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion)
{ {
if (!updateLock)
updateLock = new Lock();
// Create the BLE Service // Create the BLE Service
BLEService *service = server->createService(BLEUUID("cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"), 25, 0); BLEService *service = server->createService(BLEUUID("cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"), 25, 0);
assert(!resultC); assert(!resultC);
resultC = new BLECharacteristic("5e134862-7411-4424-ac4a-210937432c77", BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); resultC = new BLECharacteristic("5e134862-7411-4424-ac4a-210937432c77",
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(service, new TotalSizeCharacteristic, "total image size"); addWithDesc(service, new TotalSizeCharacteristic, "total image size");
addWithDesc(service, new DataCharacteristic, "data"); addWithDesc(service, new DataCharacteristic, "data");
@@ -149,7 +156,8 @@ BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::st
resultC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification resultC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
BLECharacteristic *swC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ); BLECharacteristic *swC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
swC->setValue(swVersion); swC->setValue(swVersion);
service->addCharacteristic(addBLECharacteristic(swC)); service->addCharacteristic(addBLECharacteristic(swC));
@@ -157,7 +165,8 @@ BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::st
mfC->setValue(hwVendor); mfC->setValue(hwVendor);
service->addCharacteristic(addBLECharacteristic(mfC)); service->addCharacteristic(addBLECharacteristic(mfC));
BLECharacteristic *hwvC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ); BLECharacteristic *hwvC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
hwvC->setValue(hwVersion); hwvC->setValue(hwVersion);
service->addCharacteristic(addBLECharacteristic(hwvC)); service->addCharacteristic(addBLECharacteristic(hwvC));

View File

@@ -1,8 +1,11 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
BLEService *createUpdateService(BLEServer* server, std::string hwVendor, std::string swVersion, std::string hwVersion); BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion);
void destroyUpdateService(); void destroyUpdateService();
void bluetoothRebootCheck(); void bluetoothRebootCheck();

306
src/esp32/BluetoothUtil.cpp Normal file
View File

@@ -0,0 +1,306 @@
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h"
#include "configuration.h"
#include <Arduino.h>
#include <BLE2902.h>
#include <Update.h>
#include <esp_gatt_defs.h>
SimpleAllocator btPool;
/**
* Create standard device info service
**/
BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendor, std::string swVersion,
std::string hwVersion = "")
{
BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC));
BLECharacteristic *swC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR),
// BLECharacteristic::PROPERTY_READ);
/*
* Mandatory characteristic for device info service?
BLECharacteristic *m_pnpCharacteristic = m_deviceInfoService->createCharacteristic(ESP_GATT_UUID_PNP_ID,
BLECharacteristic::PROPERTY_READ);
uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version;
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >>
8), (uint8_t) version }; m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
*/
swC->setValue(swVersion);
deviceInfoService->addCharacteristic(addBLECharacteristic(swC));
mfC->setValue(hwVendor);
deviceInfoService->addCharacteristic(addBLECharacteristic(mfC));
if (!hwVersion.empty()) {
BLECharacteristic *hwvC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
hwvC->setValue(hwVersion);
deviceInfoService->addCharacteristic(addBLECharacteristic(hwvC));
}
// SerialNumberCharacteristic.setValue("FIXME");
// deviceInfoService->addCharacteristic(&SerialNumberCharacteristic);
// m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29,
// BLECharacteristic::PROPERTY_READ); m_manufacturerCharacteristic->setValue(name);
/* add these later?
ESP_GATT_UUID_SYSTEM_ID
*/
// caller must call service->start();
return deviceInfoService;
}
bool _BLEClientConnected = false;
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer) { _BLEClientConnected = true; };
void onDisconnect(BLEServer *pServer) { _BLEClientConnected = false; }
};
#define MAX_DESCRIPTORS 32
#define MAX_CHARACTERISTICS 32
static BLECharacteristic *chars[MAX_CHARACTERISTICS];
static size_t numChars;
static BLEDescriptor *descs[MAX_DESCRIPTORS];
static size_t numDescs;
/// Add a characteristic that we will delete when we restart
BLECharacteristic *addBLECharacteristic(BLECharacteristic *c)
{
assert(numChars < MAX_CHARACTERISTICS);
chars[numChars++] = c;
return c;
}
/// Add a characteristic that we will delete when we restart
BLEDescriptor *addBLEDescriptor(BLEDescriptor *c)
{
assert(numDescs < MAX_DESCRIPTORS);
descs[numDescs++] = c;
return c;
}
// Help routine to add a description to any BLECharacteristic and add it to the service
// We default to require an encrypted BOND for all these these characterstics
void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description)
{
c->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
BLEDescriptor *desc = new BLEDescriptor(BLEUUID((uint16_t)ESP_GATT_UUID_CHAR_DESCRIPTION), strlen(description) + 1);
assert(desc);
desc->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
desc->setValue(description);
c->addDescriptor(desc);
service->addCharacteristic(c);
addBLECharacteristic(c);
addBLEDescriptor(desc);
}
static BLECharacteristic *batteryLevelC;
/**
* Create a battery level service
*/
BLEService *createBatteryService(BLEServer *server)
{
// Create the BLE Service
BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F));
batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL),
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100");
batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
// I don't think we need to advertise this
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery->start();
return pBattery;
}
/**
* Update the battery level we are currently telling clients.
* level should be a pct between 0 and 100
*/
void updateBatteryLevel(uint8_t level)
{
// Pretend to update battery levels - fixme do elsewhere
if (batteryLevelC) {
batteryLevelC->setValue(&level, 1);
batteryLevelC->notify();
}
}
void dumpCharacteristic(BLECharacteristic *c)
{
std::string value = c->getValue();
if (value.length() > 0) {
DEBUG_MSG("New value: ");
for (int i = 0; i < value.length(); i++)
DEBUG_MSG("%c", value[i]);
DEBUG_MSG("\n");
}
}
/** converting endianness pull out a 32 bit value */
uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue)
{
std::string value = c->getValue();
uint32_t r = defaultValue;
if (value.length() == 4)
r = value[0] | (value[1] << 8UL) | (value[2] << 16UL) | (value[3] << 24UL);
return r;
}
class MySecurity : public BLESecurityCallbacks
{
protected:
bool onConfirmPIN(uint32_t pin)
{
Serial.printf("onConfirmPIN %u\n", pin);
return false;
}
uint32_t onPassKeyRequest()
{
Serial.println("onPassKeyRequest");
return 123511; // not used
}
void onPassKeyNotify(uint32_t pass_key)
{
Serial.printf("onPassKeyNotify %06u\n", pass_key);
startCb(pass_key);
}
bool onSecurityRequest()
{
Serial.println("onSecurityRequest");
return true;
}
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl)
{
if (cmpl.success) {
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
Serial.printf(" authenticated and connected to phone\n");
} else {
Serial.printf("phone authenticate failed %d\n", cmpl.fail_reason);
}
// Remove our custom PIN request screen.
stopCb();
}
public:
StartBluetoothPinScreenCallback startCb;
StopBluetoothPinScreenCallback stopCb;
};
BLEServer *pServer;
BLEService *pDevInfo, *pUpdate;
void deinitBLE()
{
assert(pServer);
pServer->getAdvertising()->stop();
destroyUpdateService();
pUpdate->stop();
pDevInfo->stop();
pUpdate->stop(); // we delete them below
// First shutdown bluetooth
BLEDevice::deinit(false);
// do not delete this - it is dynamically allocated, but only once - statically in BLEDevice
// delete pServer->getAdvertising();
delete pUpdate;
delete pDevInfo;
delete pServer;
batteryLevelC = NULL; // Don't let anyone generate bogus notifies
for (int i = 0; i < numChars; i++)
delete chars[i];
numChars = 0;
for (int i = 0; i < numDescs; i++)
delete descs[i];
numDescs = 0;
btPool.reset();
}
BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen,
std::string deviceName, std::string hwVendor, std::string swVersion, std::string hwVersion)
{
BLEDevice::init(deviceName);
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
/*
* Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation
*/
static MySecurity mySecurity;
mySecurity.startCb = startBtPinScreen;
mySecurity.stopCb = stopBtPinScreen;
BLEDevice::setSecurityCallbacks(&mySecurity);
// Create the BLE Server
pServer = BLEDevice::createServer();
static MyServerCallbacks myCallbacks;
pServer->setCallbacks(&myCallbacks);
pDevInfo = createDeviceInfomationService(pServer, hwVendor, swVersion, hwVersion);
// We now let users create the battery service only if they really want (not all devices have a battery)
// BLEService *pBattery = createBatteryService(pServer);
pUpdate = createUpdateService(pServer, hwVendor, swVersion,
hwVersion); // We need to advertise this so our android ble scan operation can see it
// It seems only one service can be advertised - so for now don't advertise our updater
// pServer->getAdvertising()->addServiceUUID(pUpdate->getUUID());
// start all our services (do this after creating all of them)
pDevInfo->start();
pUpdate->start();
// FIXME turn on this restriction only after the device is paired with a phone
// advert->setScanFilter(false, true); // We let anyone scan for us (FIXME, perhaps only allow that until we are paired with a
// phone and configured) but only let whitelist phones connect
static BLESecurity security; // static to avoid allocs
BLESecurity *pSecurity = &security;
pSecurity->setCapability(ESP_IO_CAP_OUT);
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
return pServer;
}
// Called from loop
void loopBLE()
{
bluetoothRebootCheck();
}

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <functional>
#include <Arduino.h> #include <Arduino.h>
#include <BLEDevice.h> #include <BLEDevice.h>
#include <BLEServer.h> #include <BLEServer.h>
@@ -17,8 +19,14 @@ void dumpCharacteristic(BLECharacteristic *c);
/** converting endianness pull out a 32 bit value */ /** converting endianness pull out a 32 bit value */
uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue); uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue);
// TODO(girts): create a class for the bluetooth utils helpers?
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
using StopBluetoothPinScreenCallback = std::function<void(void)>;
void loopBLE(); void loopBLE();
BLEServer *initBLE(std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = ""); BLEServer *initBLE(
StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen,
std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = "");
void deinitBLE(); void deinitBLE();
/// Add a characteristic that we will delete when we restart /// Add a characteristic that we will delete when we restart

View File

@@ -0,0 +1,83 @@
#include "CryptoEngine.h"
#include "configuration.h"
#include "crypto/includes.h"
#include "crypto/common.h"
// #include "esp_system.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "mbedtls/aes.h"
#define MAX_BLOCKSIZE 256
class ESP32CryptoEngine : public CryptoEngine
{
mbedtls_aes_context aes;
/// How many bytes in our key
uint8_t keySize = 0;
public:
ESP32CryptoEngine() { mbedtls_aes_init(&aes); }
~ESP32CryptoEngine() { mbedtls_aes_free(&aes); }
/**
* Set the key used for encrypt, decrypt.
*
* As a special case: If all bytes are zero, we assume _no encryption_ and send all data in cleartext.
*
* @param numBytes must be 16 (AES128), 32 (AES256) or 0 (no crypt)
* @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the
* provided pointer)
*/
virtual void setKey(size_t numBytes, uint8_t *bytes)
{
keySize = numBytes;
DEBUG_MSG("Installing AES%d key!\n", numBytes * 8);
if (numBytes != 0) {
auto res = mbedtls_aes_setkey_enc(&aes, bytes, numBytes * 8);
assert(!res);
}
}
/**
* Encrypt a packet
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
if (keySize != 0) {
uint8_t stream_block[16];
static uint8_t scratch[MAX_BLOCKSIZE];
size_t nc_off = 0;
// DEBUG_MSG("ESP32 encrypt!\n");
initNonce(fromNode, packetNum);
assert(numBytes <= MAX_BLOCKSIZE);
memcpy(scratch, bytes, numBytes);
memset(scratch + numBytes, 0,
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
auto res = mbedtls_aes_crypt_ctr(&aes, numBytes, &nc_off, nonce, stream_block, scratch, bytes);
assert(!res);
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
// DEBUG_MSG("ESP32 decrypt!\n");
// For CTR, the implementation is the same
encrypt(fromNode, packetNum, numBytes, bytes);
}
private:
};
CryptoEngine *crypto = new ESP32CryptoEngine();

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