Compare commits

...

504 Commits
0.9.1 ... 1.1.8

Author SHA1 Message Date
Kevin Hester
21751da5a2 Merge pull request #512 from geeksville/dev
Dev
2020-11-07 04:19:36 -08:00
Kevin Hester
c2e8ac7173 1.1.8 2020-11-07 19:20:38 +08:00
Kevin Hester
2fd5ce00ce fix build for esp32 targets 2020-11-07 15:09:05 +08:00
Kevin Hester
952c216bf7 Merge remote-tracking branch 'root/master' into dev 2020-11-07 14:08:22 +08:00
Kevin Hester
ff4b03b8c1 Fix #509 was causing failure on non GPS equipped boards 2020-11-07 09:15:28 +08:00
Kevin Hester
c5903a790b update for portduino 2020-10-31 15:50:39 +08:00
Kevin Hester
bbc36f7b6f switch to my new SD 7.2.0 S113 based bootloader 2020-10-31 12:22:20 +08:00
Kevin Hester
d7368d5a51 begin deep sleep support for nrf52 2020-10-30 17:05:32 +08:00
Kevin Hester
47bbde3c60 fix #505 allow forced standby mode to not assert fail 2020-10-29 16:13:44 +08:00
Kevin Hester
04942a3570 fix #505 - device can reboot due to race condition in sending 2020-10-29 15:27:05 +08:00
Kevin Hester
62a8c968e8 Merge pull request #504 from geeksville/dev
Dev
2020-10-28 23:14:52 -07:00
Kevin Hester
b9a1cae72d 1.1.7 2020-10-29 13:27:52 +08:00
Kevin Hester
6b442784f3 Merge remote-tracking branch 'root/master' into dev 2020-10-29 13:26:49 +08:00
Kevin Hester
cfcb62bd18 Make region changes take effect immedately 2020-10-29 13:26:36 +08:00
Kevin Hester
f698883c02 add pinetab docs 2020-10-29 13:26:14 +08:00
Kevin Hester
4a5cef886e Merge pull request #450 from BeardyWalrus/master
Fix for #357 - Bluetooth pairing pin disable on devices with no display
2020-10-28 18:44:58 -07:00
Kevin Hester
f6ec129288 Merge branch 'master' into master 2020-10-28 18:38:27 -07:00
Kevin Hester
17763034a0 Merge pull request #503 from geeksville/ppr1
Ppr1
2020-10-27 22:26:18 -07:00
Kevin Hester
4ad562b9f4 The new 7.2.0 soft device works on nrf52833 2020-10-28 13:01:50 +08:00
Kevin Hester
6b838002d4 switch back to tbeam for merge to master 2020-10-28 09:51:30 +08:00
Kevin Hester
5e0d53a1e3 ppr1 todo updates 2020-10-28 09:48:28 +08:00
Kevin Hester
7597d5b3fd PPR1 - GPS serial now works 2020-10-25 17:07:54 +08:00
Kevin Hester
1a8891c33d ppr1: add crude version of charge controller driver 2020-10-24 18:40:47 +08:00
Kevin Hester
f0eeaf01d4 ppr1 lcd is 'good enough' for now 2020-10-24 09:49:14 +08:00
Kevin Hester
d4e95e95a6 fix long-press handling on alternate button 2020-10-24 08:44:54 +08:00
Kevin Hester
0767c8be03 PPR1 fix screen mirroring on LCD 2020-10-24 08:16:15 +08:00
Kevin Hester
18bbf3523e remove unused display code 2020-10-23 22:18:22 +08:00
Kevin Hester
b081a6da56 ppr1 st7567 lcd kinda works now 2020-10-23 18:00:43 +08:00
Kevin Hester
a102e49fdb PPR1 WIP - hacky code to make LCD talk on I2C. Works! 2020-10-23 17:10:48 +08:00
Kevin Hester
c078c08c3e Merge branch 'dev' into ppr1 2020-10-23 16:53:38 +08:00
Kevin Hester
4dd50df810 Merge pull request #498 from geeksville/dev
1.1.6
2020-10-21 04:28:55 -07:00
Kevin Hester
14c4022c18 1.1.6 (and screen layout tweaks) 2020-10-21 19:18:03 +08:00
Kevin Hester
a5d7bacdbf Show current region on the boot screen 2020-10-21 17:27:13 +08:00
Kevin Hester
0b3c25f6d9 use correct code for "talking to phone" fixes OTA update while a router 2020-10-21 16:50:09 +08:00
Kevin Hester
ad7a474a52 update buildscript to generate universal/regionless roms 2020-10-21 12:48:04 +08:00
Kevin Hester
430186ec53 Merge remote-tracking branch 'root/master' into dev 2020-10-21 10:44:56 +08:00
Jm Casler
227c6fc27e Merge pull request #494 from meshtastic/dev-https
Added the x-protobuf-schema, initial integration of javascript library, tuning of the CPU throttle timer.
2020-10-18 22:03:46 -07:00
Jm Casler
a37844d7e5 Merge pull request #493 from mc-hamster/master
update case of meshhttpStatic.h
2020-10-18 21:55:25 -07:00
Jm Casler
ff20b29c3c update case of meshhttpStatic.h 2020-10-18 21:44:55 -07:00
Jm Casler
64c29c4a35 Merge pull request #490 from mc-hamster/master
Update filename, cpu clock timer, add more debug info on the web server startup
2020-10-18 21:41:34 -07:00
Jm Casler
d4df3f8a7e mDNS server http://meshtastic.local 2020-10-18 21:39:02 -07:00
Jm Casler
a16c3af30a Clarified debug message regardding the Web Server startup status. 2020-10-18 18:44:08 -07:00
Jm Casler
3061860dab Update sleep timer for the CPU clock 2020-10-18 18:30:19 -07:00
Jm Casler
2450d98b59 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-18 18:08:03 -07:00
Jm Casler
a371592ad9 Added instructions for David 2020-10-18 18:07:44 -07:00
Jm Casler
f7aaf48ae9 Merge pull request #20 from meshtastic/dev-https
Update my branch from dev-https
2020-10-18 18:04:49 -07:00
Jm Casler
1fb604ebc8 Merge pull request #488 from mc-hamster/master
Update dev-https from my fork.
2020-10-18 16:44:01 -07:00
Jm Casler
df2733a3b5 readded nodeScriptScriptsJS. it got lost in the transition to the new webserver 2020-10-17 20:28:19 -07:00
Kevin Hester
8fd3cb1aac add crude charging detection for 'dumb' voltage based battery sensors 2020-10-18 09:44:29 +08:00
Kevin Hester
485c476f17 cleaner battery debug messages 2020-10-18 09:32:12 +08:00
Jm Casler
7dd4ce32d2 Moved style.css into meshhttpStatic.h
Also created /data to store static files before they go into meshhttpStatic.h
2020-10-17 17:33:29 -07:00
Jm Casler
7f12af73d4 Updated to be host and protocol agnostic 2020-10-17 12:00:21 -07:00
Jm Casler
63113d57b3 Initial integration of meshtastic.js and sample code 2020-10-17 11:30:59 -07:00
Jm Casler
32850ff39d Merge pull request #487 from mc-hamster/master
Some cleanup and implement the X-Protobuf-Schema header
2020-10-16 23:40:48 -07:00
Jm Casler
2901f773a4 Some cleanup and implement the X-Protobuf-Schema header 2020-10-16 23:33:50 -07:00
Kevin Hester
a7c54e4ad7 Merge remote-tracking branch 'root/master' into dev 2020-10-17 13:41:51 +08:00
Kevin Hester
e1f0e11cb8 ppr1 WIP DO NOT MERGE - will break other clients 2020-10-17 13:15:12 +08:00
Kevin Hester
c73ee98739 Merge branch 'master' into ppr1 2020-10-17 11:00:28 +08:00
Jm Casler
c2a1141dfa Merge pull request #485 from mc-hamster/master
update class case of HttpAPI
2020-10-16 19:40:32 -07:00
Jm Casler
5b4472ab56 fix case of HttpAPI class 2020-10-16 19:38:59 -07:00
Jm Casler
3262f732d8 Merge pull request #19 from meshtastic/master
update my branch from master
2020-10-16 19:31:59 -07:00
Jm Casler
cff21ca130 Merge pull request #484 from meshtastic/dev-https
Functional protobuf/rest interface.
2020-10-16 19:28:40 -07:00
Jm Casler
81ce04d3da Merge branch 'master' into dev-https 2020-10-16 19:21:06 -07:00
Jm Casler
f4d2b10840 Merge pull request #483 from mc-hamster/master
Update for interface with the JS client.
2020-10-16 19:18:31 -07:00
Jm Casler
2370cb8aac Merge pull request #482 from meshtastic/dev-https
Merge from dev-https to master.
2020-10-16 19:10:04 -07:00
Kevin Hester
59ec87f5b0 oops tbeam was inheriting from arduino, it should inherit from esp32 2020-10-17 09:58:34 +08:00
Jm Casler
0d9481b6ea add allow-headers 2020-10-16 18:00:28 -07:00
Jm Casler
8f0105ccd9 don't send content-type when options is set 2020-10-16 17:46:22 -07:00
Kevin Hester
05ca3c3d56 Update to work with my font size change 2020-10-17 08:44:04 +08:00
Jm Casler
ba549d8fcd Return OPTIONS when requested for toradio 2020-10-16 17:41:08 -07:00
Jm Casler
b9df2c00fa fromradio all option
requesting fromradio will return one protobuf
4:56
requesting fromradio?all=true will give you all of them.
2020-10-16 17:07:35 -07:00
Kevin Hester
d9dcb33576 Merge branch 'master' into dev-https 2020-10-16 17:05:06 -07:00
Jm Casler
f698231be7 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-16 16:36:55 -07:00
Jm Casler
8414f4a6a3 Added access-control-allow headers 2020-10-16 16:36:52 -07:00
Kevin Hester
8505020be5 Merge branch 'dev' into ppr1 2020-10-16 17:03:30 +08:00
Kevin Hester
f3b93d55fb oops fix for esp32 2020-10-16 17:03:04 +08:00
Kevin Hester
9e0731a956 Merge branch 'dev' into ppr1 2020-10-16 17:01:42 +08:00
Kevin Hester
2b373048c6 fix battery voltage sensing on NRF52 boards 2020-10-16 17:00:27 +08:00
Kevin Hester
22f23bb07d Merge branch 'dev' into ppr1
# Conflicts:
#	src/gps/NMEAGPS.cpp
2020-10-16 15:59:55 +08:00
Kevin Hester
b32e3f1269 Merge pull request #479 from geeksville/dev
minor eink things
2020-10-15 23:44:15 -07:00
Kevin Hester
68ddb712f5 properly keep nrf52s from sleeping 2020-10-16 14:00:56 +08:00
Kevin Hester
2fb5cd8c1c work with more NMEA gps sentences 2020-10-16 14:00:17 +08:00
Kevin Hester
79aea8231f make screen positions less hardwired wrt font size 2020-10-16 11:22:07 +08:00
Kevin Hester
b0837c10c6 eink display improvements 2020-10-16 10:53:55 +08:00
Jm Casler
cd811951b1 Merge pull request #481 from mc-hamster/master
Update from mchamster to dev-https
2020-10-15 19:53:03 -07:00
Jm Casler
df2976dad0 Merge pull request #18 from meshtastic/dev-https
From Dev https to mc-hamster master
2020-10-15 19:40:49 -07:00
Jm Casler
4ccbe6ff71 Merge pull request #480 from meshtastic/master
Updating dev-https from master
2020-10-15 19:40:01 -07:00
Jm Casler
038ddb887f Be a little smarter with setting the CPU frequency
in the event we have HTTPS and HTTP requests within close periods, let the speed set by the HTTPS request take presidence.
2020-10-15 19:28:20 -07:00
Kevin Hester
9134faaed1 turn off segger debug in ttgo eink build 2020-10-15 16:11:40 +08:00
Kevin Hester
649a120fe0 make eink screen look nicer 2020-10-15 15:56:38 +08:00
Kevin Hester
4db0c4a563 Make screen code resolution agnostic. Look better on big TFT/eink screens 2020-10-15 15:12:27 +08:00
Kevin Hester
5f2f3c94b9 PPR1 and allow boards to set lower or higher sx1262 power limits 2020-10-15 13:47:10 +08:00
Jm Casler
3b2f5fa5e3 fromRadio now returns all the vailable protobufs. a request to http sets the cpu clock to 160mhz, https to 240mhz then will clock it back down after 2 minutes. 2020-10-14 20:24:19 -07:00
Jm Casler
97adb598b6 toRadio is functional 2020-10-14 16:17:12 -07:00
Kevin Hester
152ebf0dff Merge branch 'dev' into ppr1 2020-10-14 10:24:39 +08:00
Kevin Hester
5b1511c930 ppr1 make jlink scripts 2020-10-14 10:21:55 +08:00
Kevin Hester
7ef2cc8623 Merge pull request #478 from geeksville/dev
1.1.5
2020-10-13 18:11:15 -07:00
Kevin Hester
b41a32c6b6 1.1.5 2020-10-14 09:04:20 +08:00
Kevin Hester
1ebd7b0c3e make lightsleep default time 5 minutes, with 1 minute in for BLE syncing 2020-10-14 08:53:12 +08:00
Kevin Hester
5457541244 fix #477: sleep behavior was broken in app due to device bug since 1.1.1
+        // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
+        // So even if we internally use 0 to represent 'use default' we still need to send the value we are
+        // using to the app (so that even old phone apps work with new device loads).
2020-10-14 08:45:29 +08:00
Kevin Hester
ca77d48b20 corvus2 gps still doesn't work WIP 2020-10-13 14:43:28 +08:00
Kevin Hester
965c2bda8d corvus2 board builds 2020-10-13 13:59:06 +08:00
Jm Casler
02e3438d5e Added a favicon.ico 2020-10-11 22:13:14 -07:00
Jm Casler
02b1ece6ac Update meshhttp.cpp 2020-10-11 21:30:14 -07:00
Jm Casler
9fdef366f7 Merge pull request #473 from mc-hamster/master
update dev-https from my fork
2020-10-11 21:20:50 -07:00
Jm Casler
284816229e Merge pull request #17 from meshtastic/master
update my fork from head
2020-10-11 21:19:39 -07:00
Jm Casler
10008d4eef fix merge conflict 2020-10-11 21:19:22 -07:00
Jm Casler
58cfd1317c Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-11 20:38:13 -07:00
Jm Casler
3d3f7869d4 Increase CPU frequency on HTTPS requests. Clock back down after a period of time. 2020-10-11 20:38:09 -07:00
Kevin Hester
ef325289eb fix a doc error 2020-10-12 11:09:53 +08:00
Kevin Hester
40c63c0615 Merge pull request #472 from geeksville/dev
1.1.4
2020-10-11 18:39:02 -07:00
Kevin Hester
a9de8b9bb3 oops - only read axp on boards that have it 2020-10-12 09:33:15 +08:00
Kevin Hester
66a7f896c8 1.1.4 2020-10-12 09:27:48 +08:00
Kevin Hester
45a36f5571 fix POWER state entry/exit based on loss of USB power (tx @mc-hamster) 2020-10-12 09:27:07 +08:00
Jm Casler
876d32c9ee Merge pull request #16 from geeksville/mc-master
fix build for linux (by moving esp32 specific lib to esp32 tree)
2020-10-11 18:17:20 -07:00
Kevin Hester
b9ce75b09c fix build for linux (by moving esp32 specific lib to esp32 tree) 2020-10-12 09:03:04 +08:00
Kevin Hester
62493efc40 Merge pull request #471 from geeksville/coroutine
fix my breakage
2020-10-11 17:42:26 -07:00
Kevin Hester
2848b76cc9 Merge branch 'master' into coroutine 2020-10-11 17:28:52 -07:00
Kevin Hester
ef8bea478d Merge branch 'coroutine' of https://github.com/geeksville/Meshtastic-esp32 into coroutine 2020-10-12 08:25:33 +08:00
Kevin Hester
a8e4bbbe65 fix my breaking of button press behavior 2020-10-12 08:25:17 +08:00
Kevin Hester
9a414d9c77 fix my breakage of screen waking 2020-10-12 08:13:32 +08:00
Jm Casler
48e6a60a07 Merge pull request #470 from mc-hamster/master
Merge pull request #15 from meshtastic/master
2020-10-10 22:30:34 -07:00
Jm Casler
ca48079545 Merge pull request #15 from meshtastic/master
updated my branch from head
2020-10-10 22:29:09 -07:00
Jm Casler
76b4be3b87 Merge pull request #469 from mc-hamster/master
Switched to esp32_https_server from the Espressif (Issue #452) and Enable RX LNA (#466)
2020-10-10 22:28:08 -07:00
Jm Casler
d39cc3d57b Checking if ESP32 for the frequency display 2020-10-10 22:06:56 -07:00
Jm Casler
b17a8d7a6a Removed powerExit -- it wasn't working 2020-10-10 21:54:27 -07:00
Kevin Hester
3d21794039 Merge pull request #465 from geeksville/coroutine
Lightweight thread refactoring
2020-10-10 18:32:15 -07:00
Kevin Hester
beac614e65 Merge branch 'master' into coroutine 2020-10-10 18:19:40 -07:00
Kevin Hester
87f2673fc4 Merge pull request #463 from geeksville/dev
fix #462 publish immediately on any GPS state change
2020-10-10 18:19:22 -07:00
Kevin Hester
999b292717 fixes for the posix port 2020-10-11 09:18:47 +08:00
Jm Casler
c16acb904e Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-10 17:59:46 -07:00
Jm Casler
5b777219be Enable the RX LNA #466
Enabling the RX LNA
2020-10-10 17:59:32 -07:00
Jm Casler
32ea11d2af Merge pull request #14 from meshtastic/master
Update from head
2020-10-10 17:23:13 -07:00
Kevin Hester
8330c3270e 1.1.3 2020-10-11 08:15:52 +08:00
Kevin Hester
0c8e0efed2 new threading finished- saves about 10mA for the high activity states 2020-10-11 08:12:53 +08:00
Kevin Hester
c44d8a0433 Merge remote-tracking branch 'root/master' into coroutine 2020-10-10 18:12:37 +08:00
Kevin Hester
49b4ed2a89 coroutine: kinda works now 2020-10-10 18:03:45 +08:00
Jm Casler
db8faa9faf added powerExit 2020-10-09 23:07:37 -07:00
Kevin Hester
4b9ea4f808 Merge branch 'dev' into coroutine 2020-10-10 09:22:23 +08:00
Kevin Hester
c3beca3e23 Merge branch 'master' into dev 2020-10-09 18:21:16 -07:00
Kevin Hester
95cb6b06e4 fix #462 publish immediately on any GPS state change
(don't wait until end of aquisition window)
2020-10-10 09:20:38 +08:00
Kevin Hester
c46a884558 concurrency wip 2020-10-10 08:28:00 +08:00
Kevin Hester
2044427e97 coroutines: wip compiles but does not link 2020-10-09 14:16:51 +08:00
Kevin Hester
514ebdf013 Merge pull request #460 from geeksville/dev
Dev
2020-10-08 19:09:12 -07:00
Kevin Hester
10f64590a9 Merge branch 'dev' into coroutine 2020-10-09 10:03:27 +08:00
Kevin Hester
4a70ba1f7a fix nodeinfo stored times (I think) for @lgoix 2020-10-09 10:01:13 +08:00
Kevin Hester
dd6a402ea0 coroutine: wip 2020-10-09 09:10:44 +08:00
Kevin Hester
bed7d8a619 threads: begin change to cooperative threading 2020-10-08 13:32:34 +08:00
Jm Casler
6d178ebc91 Added esp32_https_server to the meshtastic project 2020-10-07 22:18:46 -07:00
Jm Casler
f75a256631 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-07 22:02:59 -07:00
Jm Casler
4f659b7563 Initial check in of HTTPS server for #452
This switches from the espressif web server to esp32_https_server. Both HTTPS and HTTP have been migrated. On board SSL key generation.
2020-10-07 22:02:53 -07:00
Kevin Hester
1b6e8e36d3 Merge remote-tracking branch 'root/master' 2020-10-08 11:14:28 +08:00
Kevin Hester
7a4b8cde11 keep rf95 max power at 20 dBm so users don't smoke their boards 2020-10-08 10:51:31 +08:00
Kevin Hester
113859e791 increase sx1272 max power
+#define MAX_POWER 27
 // if we use 20 we are limited to 1% duty cycle or hw might overheat.  For continuous operation set a limit of 17
+// In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20.  So BIG WARNING
+// if you set power to something higher than 17 or 20 you might fry your board.
2020-10-08 09:57:59 +08:00
Kevin Hester
a6b82ccfd9 Merge pull request #457 from geeksville/master
fixes based on alpha tester report
2020-10-07 16:55:41 -07:00
Kevin Hester
e8b8ec69f1 1.1.2 2020-10-08 07:48:14 +08:00
Kevin Hester
023f1c24fb RTC: add notion of 'quality' for different time sources
Allow use of mesh based time until a GPS time arrives
2020-10-08 07:46:20 +08:00
Kevin Hester
f00d07baa3 RTC: pull rtc code into own file for cleanup 2020-10-08 07:28:57 +08:00
Kevin Hester
62c228b986 gps: don't stop lock attempts just because the main cpu is sleeping 2020-10-08 06:23:53 +08:00
Kevin Hester
1a3cc40c7e sx1262 better to check for header because preamble might never result in irq 2020-10-08 06:23:05 +08:00
Kevin Hester
bdcd5c3981 allow reporting # sats before we ahve a fix 2020-10-08 06:22:25 +08:00
Kevin Hester
fc82e872d6 don't require gps to have lock before we'll trust GPS time 2020-10-08 05:23:52 +08:00
Jm Casler
dffcea1f4d Merge pull request #13 from meshtastic/master
Update my fork from head with 1.1 changes
2020-10-07 08:32:54 -07:00
Kevin Hester
b47c54b5b6 keep lora radio totally unpowered when in deep-sleep 2020-10-07 17:52:44 +08:00
Kevin Hester
c0c83ad389 If we are not supposed to share locations make sure phone doesn't either 2020-10-07 17:46:25 +08:00
Kevin Hester
23aecbdc38 Merge pull request #456 from geeksville/power
major cleanup of GPS code and changes to keep GPS asleep
2020-10-06 23:26:39 -07:00
Kevin Hester
eca7242a1f fix NRF52 build 2020-10-07 14:00:59 +08:00
Kevin Hester
ef899425b8 1.1.1 2020-10-07 13:46:39 +08:00
Kevin Hester
269f90c510 Force GPS power to zero when in deep sleep 2020-10-07 13:44:17 +08:00
Kevin Hester
7a5832ab8a SX1262: fix serious bug with detecting if we have a rx packet in progress
Could cause hangs on the way into sleep (and enormous power consumption).
Instead of checking for rx packet length (which only changes at completion)
check if we've received preamble bits but haven't yet received a completed
packet interrupt.

notes:


wait to sleep loop problem
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
Can not send yet, busyRx
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0

vs normal run
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
radio wait to sleep, txEmpty=0
Starting low level send (id=0x53fe1dd0 Fr0xe5 To0xff, WantAck0, HopLim3 encrypted)
Completed sending (id=0x53fe1dd0 Fr0xe5 To0xff, WantAck0, HopLim3 encrypted)
2020-10-07 13:43:51 +08:00
Kevin Hester
044cc26340 #376 use power off command instead of killing gps power per manual 9.5 2020-10-07 11:44:30 +08:00
Kevin Hester
4ccd03623f bug #376: disable the "wake on serial" feature, because it causes
bogus wakes on TBEAMS because the USB->SERIAL chip pulls the RX input
to ground.  This feature is no longer needed because in !isRouter
nodes we force the node to never sleep anyways when on USB power.

    // this doesn't work on TBEAMs when the USB is depowered (causes bogus interrupts)
    // So we disable this "wake on serial" feature - because now when a TBEAM (only) has power connected it
    // never tries to go to sleep if the user is using the API
    // gpio_wakeup_enable((gpio_num_t)SERIAL0_RX_GPIO, GPIO_INTR_LOW_LEVEL);
2020-10-06 14:24:08 +08:00
Kevin Hester
7854a22fbf bug #376 - stop using pmu IRQ - we don't need it and it causes LS wakes 2020-10-06 12:45:19 +08:00
Kevin Hester
943d5cb08d bug #376 we were not staying in light sleep as long as intended 2020-10-06 11:48:53 +08:00
Kevin Hester
7480eb1826 Change to use zeros for timeout values that are 'default' 2020-10-06 09:43:00 +08:00
Kevin Hester
c32c97c389 TBEAM 1.1 has an extra controllable LED - blink that also 2020-10-06 08:20:06 +08:00
BeardyWalrus
b4b1b24c84 always need double press, even if you dont have a screen 2020-10-05 20:13:04 -04:00
Kevin Hester
ef146fc0b5 bug #376 - wip time only mode now works 2020-10-06 06:27:46 +08:00
Kevin Hester
f6861a8fe2 bug #376 wip - we now minimize comms to gps to save power 2020-10-06 06:07:30 +08:00
Kevin Hester
736642455f bug #376 wip - we now respect the new gps_operating_mode pref. 2020-10-06 05:34:56 +08:00
Kevin Hester
3c1c11e439 bug #376 wip - we now kill gps power when it is supposed to be asleep 2020-10-05 15:29:26 +08:00
Kevin Hester
b072eec4ac wip for #376 2020-10-05 14:43:44 +08:00
Kevin Hester
ff9b49ddaa add lora32 schematic
Signed-off-by: Kevin Hester <kevinh@geeksville.com>
2020-10-05 11:03:30 +08:00
Kevin Hester
b8863c8a07 Merge remote-tracking branch 'root/master' into power 2020-10-05 10:56:50 +08:00
BeardyWalrus
4d7cd0a09d conditional on needing ESP32 bluetooth header loaded 2020-10-03 17:23:36 -04:00
BeardyWalrus
fed8e80ae4 Merge branch 'master' into master 2020-10-03 17:04:47 -04:00
BeardyWalrus
b38bcffafb Merge branch 'master' of https://github.com/BeardyWalrus/Meshtastic-device 2020-10-03 17:02:19 -04:00
BeardyWalrus
530432411e revised fix for #357
Now supports default password for devices with no display, and override with double press of user button
2020-10-03 17:02:17 -04:00
Jm Casler
71cdbb1a73 Merge pull request #454 from mc-hamster/master
Update readme to link to the US aliexpress listing
2020-10-01 20:39:38 -07:00
Jm Casler
200aa27cc0 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-10-01 20:08:01 -07:00
Jm Casler
f7752e4f9d Merge pull request #12 from meshtastic/master
Update my repo from head
2020-10-01 20:07:07 -07:00
Jm Casler
7f0e8a8d6b Update readme to link to the US aliexpress listing for T-Beam V1.1 w/ NEO-M8N /w SX1262 2020-10-01 20:04:12 -07:00
BeardyWalrus
f30c84012f Merge branch 'master' into master 2020-10-01 22:24:30 -04:00
Jm Casler
1f6877606f Merge pull request #453 from ikstream/update_readme
Fix update/install instructions
2020-10-01 17:32:55 -07:00
geeksville
1907873831 gps wip for #376 2020-10-01 10:04:04 -07:00
geeksville
bacc6caf04 wip gps power fixes #376 2020-10-01 09:17:43 -07:00
geeksville
56d4250197 Merge remote-tracking branch 'root/master' into power 2020-10-01 07:51:24 -07:00
geeksville
d66cede7fc Merge branch 'eink' into power 2020-10-01 07:51:01 -07:00
Stefan Venz
f7ffd196e3 Fix update/install instructions 2020-10-01 11:22:41 +02:00
geeksville
3a638090a2 update protos for #376 2020-09-30 07:47:16 -07:00
geeksville
4342ae74fb Merge remote-tracking branch 'root/master' 2020-09-30 07:24:38 -07:00
BeardyWalrus
5150d15997 Merge branch 'master' into master 2020-09-29 19:57:01 -04:00
BeardyWalrus
7d6dbcfa3f Update BluetoothUtil.cpp
fix for #357
use presence of ssd1306 display to set display functionality for bluetooth security.
2020-09-29 19:51:39 -04:00
Kevin Hester
5a7962896d Merge pull request #449 from geeksville/eink
pulling in some common GPS fixes, so I can use them on ESP32
2020-09-29 14:21:00 -07:00
Kevin Hester
cfb9a600e4 Merge branch 'master' into eink 2020-09-29 14:14:10 -07:00
geeksville
7f3217d69e update image build script 2020-09-29 14:12:26 -07:00
Jm Casler
d94be0f534 Merge pull request #448 from mc-hamster/master
Add frequency information to debug output (#447) and cleanup of screen.cpp and meshwifi.cpp
2020-09-29 01:09:55 -07:00
Jm Casler
17a3e6e975 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-09-29 00:59:31 -07:00
Jm Casler
423cbc2c6d Added frequency information to debug output (#447) and cleanup of screen.cpp and meshwifi.cpp 2020-09-29 00:59:26 -07:00
geeksville
124a82888d add power testing notes for eink 2020-09-28 17:38:36 -07:00
geeksville
fec7a6bf17 add air530 gps sleep support 2020-09-28 17:04:19 -07:00
geeksville
bc50b39a3b put eink screen to sleep to save power 2020-09-28 16:08:52 -07:00
geeksville
158e3edbe7 eink generate full image 2020-09-28 15:21:54 -07:00
geeksville
116fe6d109 eink bootloader finished 2020-09-28 15:18:32 -07:00
geeksville
6a4ef7e1d1 eink board serial flash seems to work 2020-09-28 14:10:33 -07:00
geeksville
a0fd83428f eink use RESET button as regular button instead 2020-09-28 13:10:27 -07:00
geeksville
e5d4fbb164 fix pins per email eink 2020-09-28 13:03:54 -07:00
BeardyWalrus
26bafb4082 Merge pull request #3 from meshtastic/master
Update from upstream
2020-09-27 19:23:26 -04:00
Jm Casler
154dd3990c Merge pull request #11 from meshtastic/master
Merge pull request #446 from mc-hamster/master
2020-09-27 09:34:27 -07:00
Jm Casler
78fe41710b Merge pull request #446 from mc-hamster/master
Give more details of why wifi is disconnected & Set device hostname with hardwire ID #445
2020-09-27 01:04:01 -07:00
Jm Casler
1f38404e60 Merge branch 'master' into master 2020-09-27 00:58:12 -07:00
Jm Casler
848760e5bf Set device hostname with hardwire ID #445 2020-09-27 00:55:41 -07:00
Jm Casler
5ebac0cd54 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-09-26 23:38:22 -07:00
Jm Casler
9b4079317b Give more details of why wifi is disconnected 2020-09-26 23:37:58 -07:00
Jm Casler
0f64332f93 Merge pull request #444 from mc-hamster/master
Display gps altitude on display #443
2020-09-26 18:50:00 -07:00
Jm Casler
fd62edbcab Merge branch 'master' into master 2020-09-26 18:44:53 -07:00
Kevin Hester
46abb9ae3f Merge pull request #441 from geeksville/eink
add preiminary support for TTGO eink board
2020-09-26 18:39:35 -07:00
Jm Casler
b5361ef89f Display gps altitude on display #443 2020-09-26 18:37:51 -07:00
geeksville
bf808f57fe add air530 manuals 2020-09-26 18:25:10 -07:00
geeksville
648589ed16 translate important parts of the Air530 datasheet to english 2020-09-26 18:16:32 -07:00
geeksville
28ec0e310d make bat voltage sensing work on eink 2020-09-26 18:13:16 -07:00
geeksville
956d9e96f2 Merge branch 'eink' of https://github.com/geeksville/Meshtastic-esp32 into eink 2020-09-26 13:49:54 -07:00
geeksville
266ba03bb7 route debug output back to the CDC-ACM device instead of JLINK 2020-09-26 13:49:22 -07:00
Kevin Hester
04c54840f4 Merge branch 'master' into eink 2020-09-26 12:58:13 -07:00
geeksville
db33200468 remove more stale eink code 2020-09-26 12:51:05 -07:00
geeksville
d7fbcf89bf cleanup todo eink now ready to merge 2020-09-26 12:36:11 -07:00
geeksville
a8b1bc735a remove debugging code eink gps now works 2020-09-26 12:12:50 -07:00
geeksville
ba8c640d6e eink leds kinda work now 2020-09-26 10:53:02 -07:00
geeksville
d88d2780f4 eink display now kinda works 2020-09-26 09:40:48 -07:00
geeksville
b0bbf95b03 LORA now works on the eink board (new schematic from ttgo) 2020-09-26 07:25:32 -07:00
geeksville
7ca150bf07 personal notes about threading 2020-09-26 06:50:54 -07:00
Jm Casler
9c7aa02db8 Merge pull request #440 from mc-hamster/master
Merging from my fork into master for some cleanup, more code comments, reduce compile warnings and move the "Mode" text up a line.
2020-09-26 00:20:27 -07:00
Jm Casler
6f444ed4b5 Accidently left #include "nimble/BluetoothUtil.h" in screen 2020-09-26 00:03:23 -07:00
Jm Casler
28119bf1bf Fix for #439 and some cleanup 2020-09-26 00:01:02 -07:00
Jm Casler
7fdb5b594d Merge pull request #10 from meshtastic/master
update my fork from head
2020-09-25 16:40:01 -07:00
Kevin Hester
6013fceb10 Merge pull request #438 from geeksville/master
fix TCP API server and get ready to end "region specific" firmware builds
2020-09-25 16:27:29 -07:00
geeksville
2996c7c8e2 Make tcp API now work. Sample usage and caveats below:
Sample usage:

First configure device to use @mc-hamster's new wifi stuff:
meshtastic --set wifi_ssid mylanname --set wifi_password mylanpassword

Then reboot the device (so wifi starts up).

(assuming device was assigned addr 192.168.81.45)
meshtastic --info --host 192.168.81.45
(See the usual device info you previously had to get over USB)

Caveats:

* Currently we are limiting to one active TCP connection open at once, if
you open a new session the old one is closed automatically
* There are no access controls/authentication needed to open a TCP
connection to the device
* Currently main.cpp is kinda dumb about how we should schedule work and
we rely on too many helper loop() functions.  Very soon in my queue
(related to all the other cleanup) is to add a basic notion of coroutines,
so that we can get away from freertos threads and this old school arduino
loop function.  Once that cleanup happens we can the a) have much lower
battery consumption (always) and b) super fast response for all operations.
2020-09-25 16:18:30 -07:00
geeksville
d1c3078698 shrink guard for channel settings lock 2020-09-25 12:52:26 -07:00
geeksville
3e5f81bf2a move region into userpreferences, to end region specific firmwares 2020-09-25 12:52:08 -07:00
geeksville
772d045166 more eink notes 2020-09-25 10:41:27 -07:00
geeksville
1a064a4666 Merge remote-tracking branch 'root/master' 2020-09-25 09:19:58 -07:00
Kevin Hester
e81c89dcae Merge pull request #436 from meshtastic/dev-wifi
Initial Merge of WiFi Soft AP, WiFi Client, HTTP Server, DNS Server, Captive Portal and Apple Captive Network Assistant (CNA)
2020-09-25 09:18:44 -07:00
geeksville
1f36139e99 remove Signal 2020-09-25 09:14:44 -07:00
geeksville
6f77244af3 eink wip notes 2020-09-25 09:14:00 -07:00
Jm Casler
05351ce3e4 Merge branch 'master' into dev-wifi 2020-09-24 17:21:16 -07:00
geeksville
a79aff4778 WIP - I think some pins are wrong, waiting for new schematic 2020-09-24 16:36:07 -07:00
geeksville
86d6f88787 Merge remote-tracking branch 'root/master' into eink 2020-09-24 15:13:08 -07:00
geeksville
5fbeaee0b0 eink kinda builds 2020-09-24 14:36:43 -07:00
Jm Casler
fed4dfd410 Merge pull request #435 from mc-hamster/master
Update dev-wifi from my fork
2020-09-24 11:15:47 -07:00
Jm Casler
0d3b8bdb22 Note not to file bugs 2020-09-24 11:07:30 -07:00
Kevin Hester
3c4f56f3bf Merge pull request #434 from geeksville/dev-wifi
Add stubs so that portduino can build with wifi. cc @mc-hamster
2020-09-24 10:51:39 -07:00
geeksville
d3c00584a2 oops - the NRF52 build rules are suppose to inherit from arduino_base. 2020-09-24 10:36:37 -07:00
Jm Casler
ce7fa65595 David's latest changes to the HTML UI 2020-09-23 19:04:12 -07:00
geeksville
9c0a0ad220 Add stubs so that portduino can build with wifi. cc @mc-hamster 2020-09-23 17:22:17 -07:00
Kevin Hester
22d0ef36b8 Merge pull request #431 from KenVanHoeylandt/patch-1
Fix for broken link to device API docs
2020-09-23 17:12:52 -07:00
Ken Van Hoeylandt
829c5f493c Fix for broken link to device API docs
bluetooth-api.md -> device-api.md
2020-09-23 20:16:21 +02:00
Jm Casler
2d8eb8e205 Merge pull request #9 from meshtastic/dev-wifi
from dev-wifi to my fork
2020-09-22 22:09:06 -07:00
Jm Casler
52a3927585 Merge branch 'master' into dev-wifi 2020-09-22 22:00:55 -07:00
Jm Casler
b39f6c96bd Merge remote-tracking branch 'origin/dev-wifi' 2020-09-22 22:00:07 -07:00
Jm Casler
a96c2e0eac Merge pull request #428 from mc-hamster/master
Initial check-in of David's UI
2020-09-22 21:10:48 -07:00
Jm Casler
10b24c0269 Initial check-in of David's UI 2020-09-22 21:01:31 -07:00
Jm Casler
4140883684 Merge pull request #426 from comgram/kr
Add Korean Frequency
2020-09-22 05:46:18 -07:00
geeksville
3352fae64c fix #371 allow button while using API. also don't let tbeams sleep if they have USB power 2020-09-21 12:41:39 -07:00
comgram
55cb0c52ee Add Korean Frequency 2020-09-21 16:10:20 +09:00
Jm Casler
626d82614c Merge pull request #425 from mc-hamster/master
Fix for - dev-wifi: Detailed error reporting of reason why WiFi didn't connect #424
2020-09-19 22:05:57 -07:00
Jm Casler
d890068acb dev-wifi: Detailed error reporting of reason why WiFi didn't connect #424 2020-09-19 21:58:21 -07:00
Jm Casler
468ad39a94 Merge pull request #7 from meshtastic/dev-wifi
Bringing in the API changes
2020-09-19 17:27:29 -07:00
Jm Casler
5cbe06c2b0 Merge pull request #419 from geeksville/dev-wifi
Add API server on port 4403 (kinda a WIP, seems to work but I haven't
2020-09-19 17:25:24 -07:00
Jm Casler
3412ecfe7b Merge pull request #6 from meshtastic/dev-wifi
Pulling from meshtastic dev-wifi to my work area
2020-09-19 17:21:56 -07:00
Jm Casler
adb16a334c Merge pull request #423 from mc-hamster/master
Add more detail on the connection status on the screen #422
2020-09-19 17:20:35 -07:00
Jm Casler
377f0bda5d Add more detail on the connection status on the screen #422 2020-09-19 17:15:03 -07:00
Jm Casler
51ab853658 Merge pull request #421 from mc-hamster/master
Fix for Bug #420 : Wifi in station mode sometimes enters loops of repeatedly joining
2020-09-19 16:46:05 -07:00
Jm Casler
464a42258f Fix for "Wifi in station mode sometimes enters loops of repeatedly joining... #420"
Fix for Wifi in station mode sometimes enters loops of repeatedly joining... #420
2020-09-19 16:38:59 -07:00
geeksville
9e9c50e6d8 Add API server on port 4403 (kinda a WIP, seems to work but I haven't
finished the python client code)
2020-09-19 12:54:49 -07:00
Jm Casler
945f726b65 Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-09-19 12:50:46 -07:00
Jm Casler
7c44daf8f4 pushing my chances to personal branch so i can get the changes from the laptop 2020-09-19 12:50:43 -07:00
Jm Casler
c57a9a8613 Update from my laptop 2020-09-19 11:24:55 -07:00
geeksville
3c0429deee Add new factory_reset preferences option clients can set 2020-09-19 11:19:42 -07:00
Kevin Hester
5d8f541e70 Merge pull request #418 from geeksville/master
1.1.0
2020-09-19 10:33:48 -07:00
geeksville
bd126b866c 1.1.0 2020-09-19 10:32:57 -07:00
Kevin Hester
036a1991b8 Merge pull request #403 from r51n/anz
Add Australia/New Zealand channels and build target
2020-09-19 07:48:17 -07:00
Jm Casler
6e3b22c624 Stub for a handler of the root (/) of the web server with a html table and form for chat 2020-09-18 20:42:35 -07:00
Jm Casler
82fbedbf41 Auto formatting of meshwifi.cpp 2020-09-18 18:51:42 -07:00
Jm Casler
0929b86d62 Merge pull request #411 from mc-hamster/master
Moved handleDNSResponse from main into handleWebResponse and used the auto format
2020-09-18 18:36:40 -07:00
Jm Casler
65fc1cf4a6 Moved handleDNSResponse into handleWebResponse and used the autoformatter 2020-09-18 18:29:16 -07:00
Jm Casler
6f753799fd Merge pull request #410 from mc-hamster/master
Completed Software AP and basic Captive Portal
2020-09-18 18:20:27 -07:00
Jm Casler
4d72afebe6 Soft AP and basic captive portal done. 2020-09-18 18:16:58 -07:00
Jm Casler
b1643e6036 Merge pull request #5 from meshtastic/dev-wifi
Dev wifi
2020-09-18 18:06:13 -07:00
Jm Casler
362d8cb831 Merge branch 'master' into dev-wifi 2020-09-18 18:02:56 -07:00
Jm Casler
b203c95dd1 changes for soft ap + captive portal 2020-09-18 15:33:03 -07:00
Kevin Hester
8d4672964c Merge pull request #409 from geeksville/dev-wifi
Make wifi optional and exclude from nrf52 builds
2020-09-18 13:38:00 -07:00
geeksville
6e5e5822aa Make wifi optional and exclude from nrf52 builds 2020-09-18 10:48:39 -07:00
Kevin Hester
5fb0bf2575 Merge branch 'master' into anz 2020-09-18 10:19:43 -07:00
Kevin Hester
9af2045dc1 Merge pull request #404 from geeksville/master
Merge portduino/sim beginnings into mainline
2020-09-18 10:18:33 -07:00
Kevin Hester
9624cc3798 Merge pull request #405 from mc-hamster/master
Initial Check-in of wifi changes into dev-wifi
2020-09-18 10:18:12 -07:00
geeksville
3541228c1f update to my latest radiolib 2020-09-17 11:41:34 -07:00
geeksville
cc95361fdc Merge remote-tracking branch 'root/master' 2020-09-17 11:24:42 -07:00
geeksville
9b1d1ad0a5 add linux/portduino to the CI test build
Signed-off-by: geeksville <kevinh@geeksville.com>
2020-09-17 11:23:46 -07:00
geeksville
7e467f1466 Merge branch 'portduino' 2020-09-17 11:20:50 -07:00
geeksville
d3e28e3e2c Merge branch 'dev' 2020-09-17 11:20:41 -07:00
r51n
1a1a0fbfbe add ANZ to build list 2020-09-17 12:04:38 +00:00
r51n
91305c2c84 add AU/NZ channel definitions 2020-09-17 12:02:38 +00:00
Jm Casler
48dd6d388d Merge branch 'master' of https://github.com/mc-hamster/Meshtastic-device 2020-09-16 23:16:19 -07:00
Jm Casler
64710a6a04 renamed reconnectWiFi to initWifi 2020-09-16 23:16:11 -07:00
Jm Casler
c83ff03d66 Merge pull request #4 from meshtastic/master
Updating form head
2020-09-16 22:51:19 -07:00
Jm Casler
73b47a78aa Clean up and added comments about the esp32 sdk bug 2020-09-16 22:31:07 -07:00
Jm Casler
493b25f23e Final checkin of WiFi and basic HTTP server 2020-09-16 20:15:00 -07:00
Kevin Hester
004f1f625b Merge pull request #398 from geeksville/master
misc atomic bug fixes - see commits
2020-09-16 10:10:00 -07:00
geeksville
fc20f658e6 Fix #362 by @a-f-G-U-C - I was mispelling NMEA ;-) 2020-09-16 09:22:03 -07:00
geeksville
8e988cc926 fix #397 from @a-f-G-U-C - bogus GPS positions during locking could be reported
btw - from my read of the NMEA, the lowest value that means 'has a valid
position' is 1 not 2.  But I only know this because you pointed me at
it ;-)

Thanks!
2020-09-16 09:18:44 -07:00
geeksville
8c240b59f6 fix #393. immediately save node db to disk if user changes name 2020-09-16 09:08:35 -07:00
geeksville
f847e30a3c Merge remote-tracking branch 'root/master' 2020-09-16 09:04:27 -07:00
geeksville
7050ae4ba1 Merge branch 'master' into portduino 2020-09-15 21:14:42 -07:00
geeksville
3e64d8439d Merge branch 'master' into dev 2020-09-15 21:13:24 -07:00
geeksville
435c955acd make hash prototype a bit stricter 2020-09-15 21:05:57 -07:00
Jm Casler
c656a95a84 Merge pull request #3 from meshtastic/master
Update from meshtastic main
2020-09-15 20:34:30 -07:00
Jm Casler
27ad8472c1 remove ssid info from configuration.h 2020-09-15 20:24:58 -07:00
Jm Casler
3fcd4a61aa commenting out the strcpy to manually set the wifi info. 2020-09-15 20:24:03 -07:00
geeksville
c6d93d1a28 fix #346 limit tx power in japan 2020-09-15 18:54:50 -07:00
Kevin Hester
b0c82dcb5b Merge pull request #394 from geeksville/master
misc bug fixes
2020-09-15 18:19:58 -07:00
geeksville
7d4058f49d let users set 20 dBm if they wish 2020-09-15 18:00:21 -07:00
geeksville
31fc8fafec make default power level radio chipset specific 2020-09-15 17:55:33 -07:00
geeksville
313cee9a3f update webpage 2020-09-15 17:54:55 -07:00
Jm Casler
066d9d48a4 New method to deinit the wifi stack. 2020-09-14 20:27:49 -07:00
geeksville
16de4a0d2e Merge remote-tracking branch 'root/master' 2020-09-14 09:25:31 -07:00
geeksville
621fcb598e Declare 1.0 2020-09-14 09:25:14 -07:00
Jm Casler
b2a6a4000b Merge pull request #2 from meshtastic/master
Updating from head
2020-09-14 00:05:21 -07:00
Jm Casler
f5c939fb10 Fix to turn WiFi back on after the bluetooth radio is reenabled. 2020-09-13 22:22:49 -07:00
Jm Casler
e508306395 Refactoring to break out HTTP from WiFi 2020-09-13 16:58:36 -07:00
Kevin Hester
cc6b500029 Merge pull request #388 from geeksville/master
1.0.0
2020-09-13 12:11:32 -07:00
geeksville
887b1b5dcd Merge remote-tracking branch 'root/master' 2020-09-13 11:58:31 -07:00
geeksville
62e333b235 1.0.0 2020-09-13 11:53:31 -07:00
Jm Casler
d859700497 Merge branch 'master' into master 2020-09-12 21:55:01 -07:00
Jm Casler
f129b458ad Initial Checkin for WiFi and HTTP Server Framework 2020-09-12 21:43:41 -07:00
Kevin Hester
bf68ad7cf5 Merge pull request #382 from geeksville/master
0.9.7
2020-09-12 10:31:19 -07:00
geeksville
6d9bdbb628 0.9.7 2020-09-12 10:21:44 -07:00
Kevin Hester
6782c2d3d1 Merge pull request #380 from mc-hamster/master
Fix for screen crashing after GPS lock.
2020-09-12 10:20:13 -07:00
Jm Casler
b6f71ca1db Update screen.cpp for for crash when gps gets lock
Update screen.cpp for for crash when gps gets a lock
2020-09-11 22:17:45 -07:00
geeksville
92df77f228 Merge remote-tracking branch 'root/master' into dev 2020-09-11 18:15:13 -07:00
Jm Casler
caeea41867 Merge pull request #1 from meshtastic/master
Merge from original repo
2020-09-11 17:59:02 -07:00
Kevin Hester
bc17dd1a0f Merge pull request #378 from geeksville/master
0.9.6
2020-09-11 13:41:09 -07:00
geeksville
2a3175470b merge remote-tracking branch 'root/master' 2020-09-11 13:31:28 -07:00
geeksville
8ca6bbfb78 0.9.6 2020-09-11 13:30:44 -07:00
Kevin Hester
9777762052 Merge pull request #368 from geeksville/master
misc bug fixes
2020-09-11 11:42:51 -07:00
geeksville
da01f0ab7f Merge remote-tracking branch 'mine/master' 2020-09-10 10:11:53 -07:00
geeksville
1cd81208c0 Merge remote-tracking branch 'root/master' 2020-09-10 10:11:15 -07:00
Kevin Hester
2394075d94 Merge branch 'master' into master 2020-09-10 10:11:04 -07:00
geeksville
de7b9877f9 remove auto-inserted whitespace that might confuse platformio 2020-09-10 09:51:53 -07:00
geeksville
ee27c15c2c likely fix for bug #373. fix #339. great gps fixes from @a-f-G-U-C
fixes described in bug #376
2020-09-10 09:25:10 -07:00
geeksville
076f8bd77b fix #370 by pulling in my bugfix to ESP32-Nimble 2020-09-09 14:15:43 -07:00
Kevin Hester
288363b3a6 Merge pull request #369 from gkelly/fix-no-button
Fix compilation without a BUTTON_PIN definition
2020-09-08 12:49:24 -07:00
Garret Kelly
48256d6e9e Fix compilation without a BUTTON_PIN definition 2020-09-08 15:22:49 -04:00
geeksville
c007302564 fix #363 gps altitude - based on tip by @a-f-G-U-C 2020-09-08 10:28:53 -07:00
geeksville
0a9f7147f3 probably fix #341 enable internal pullup on lora-v2 button 2020-09-08 10:25:37 -07:00
geeksville
46ba36511a Merge branch 'portduino' into dev
# Conflicts:
#	platformio.ini
2020-09-07 16:31:17 -07:00
Kevin Hester
170f0693c6 Merge pull request #366 from mc-hamster/master
New screen to fix issue #352
2020-09-07 15:31:16 -07:00
Kevin Hester
d900509fbc Merge branch 'master' into master 2020-09-07 15:26:35 -07:00
Kevin Hester
8018c27dcd Merge pull request #367 from geeksville/master
test fixing CI build
2020-09-07 15:26:24 -07:00
geeksville
8df5ac9d3f pull in my fixed nrf52 platform 2020-09-07 15:22:00 -07:00
geeksville
c3196f47ef Merge remote-tracking branch 'root/master' 2020-09-07 15:13:09 -07:00
geeksville
81a49d4e3c Merge branch 'post1' 2020-09-07 15:12:14 -07:00
Kevin Hester
4f32c36db8 Merge branch 'master' into master 2020-09-07 15:04:01 -07:00
Kevin Hester
5db0bb3368 Merge pull request #361 from drewsed/add-new-cases-to-both-README
Added a new 3D printable case to \README.md and updated \docs\README.md fixes #360
2020-09-07 15:02:55 -07:00
geeksville
f3d38d84c9 fix nrf52 build 2020-09-07 13:03:37 -07:00
geeksville
f8bb6bbcb4 try to bang on SPI from simulator 2020-09-06 16:32:13 -07:00
geeksville
e0d5b9dce1 use simradio on portduino 2020-09-06 16:09:07 -07:00
geeksville
94e4b30125 add crude sim getmacaddr 2020-09-06 16:07:32 -07:00
geeksville
2a067e7f6b make gps optional. Portduino almost works in sim! 2020-09-06 14:45:43 -07:00
geeksville
97ab07e05c WIP 2020-09-06 10:09:40 -07:00
geeksville
b8d39845cf portduino now links! 2020-09-06 09:24:08 -07:00
Jm Casler
cbea36a151 Merge branch 'master' into master 2020-09-05 22:53:03 -07:00
Jm Casler
49dea6d6bd Update Screen.cpp
Added commnets for concepts for future TODO work.
2020-09-05 22:36:57 -07:00
Jm Casler
7d4c6c7086 Update Screen.cpp
- Changed "No Satellite Lock" to "No GPS Lock"
- Fixed bug when there's no battery. Now shows "USB"
- Tested on tlora-v1
2020-09-05 14:41:00 -07:00
geeksville
fefd3d78f3 Portduino WIP now compiles but does not link 2020-09-05 12:34:48 -07:00
Jm Casler
f41a77c46d Initial add of status screen
Initial add of the status screen.

TODO:
- Get status of the BT Radio
- Display something on line 3
2020-09-05 09:30:18 -07:00
geeksville
6a475d8288 WIP 2020-09-04 17:23:17 -07:00
geeksville
c629b94333 portduino WIP 2020-09-04 15:03:22 -07:00
drewsed
5423f4e06c Added a new 3D printable case to \README.md and updated \docs\README.md 2020-09-04 10:41:22 +02:00
Kevin Hester
88f8bbe21e Merge pull request #358 from Dafeman/master
Update build instructions
2020-09-02 14:36:13 -07:00
Dafeman
eda4862f0d Update build-instructions.md 2020-09-03 08:34:52 +12:00
Dafeman
7ca752cd32 Merge pull request #5 from meshtastic/master
Merge latest
2020-09-03 08:14:37 +12:00
Kevin Hester
c5ffebc498 Merge pull request #355 from geeksville/master
stop using post1 for now (it was a dumb idea)
2020-09-01 16:33:17 -07:00
geeksville
baa12aa5b3 Merge branch 'master' into post1 2020-09-01 08:54:39 -07:00
geeksville
ccf3522ada Merge remote-tracking branch 'root/master' 2020-09-01 08:53:31 -07:00
geeksville
d14cf5aa94 Merge remote-tracking branch 'root/post1' 2020-09-01 08:53:26 -07:00
geeksville
810429b54f Merge branch 'master' into post1 2020-08-31 09:10:24 -07:00
Kevin Hester
915427c964 Merge pull request #350 from geeksville/master
misc bugfix
2020-08-30 14:43:48 -07:00
geeksville
347484baaf 0.9.5 2020-08-30 14:38:23 -07:00
geeksville
bb6913a56a Merge remote-tracking branch 'root/master' 2020-08-30 13:48:16 -07:00
geeksville
6cdaf8c600 fix #349 channel suffix letter didn't match between device and phone 2020-08-30 12:38:15 -07:00
geeksville
c370eb4a88 allow restarting failed upgrades (fixes an android autobug report) 2020-08-30 12:21:05 -07:00
geeksville
8dc4492ba3 add taiwan frequencies 2020-08-30 12:20:43 -07:00
geeksville
901cc536ef less logspam 2020-08-29 15:17:32 -07:00
Kevin Hester
41c2732e4f Merge pull request #347 from geeksville/post1
Post1
2020-08-29 13:13:40 -07:00
Kevin Hester
2d12a363db Merge pull request #348 from geeksville/master
finish (ish) corvus board
2020-08-29 13:13:25 -07:00
geeksville
28455f0056 Merge branch 'master' into post1 2020-08-29 12:47:27 -07:00
geeksville
5125126aec Merge branch 'corvus' 2020-08-29 12:47:01 -07:00
geeksville
f1ca1ee3c0 okay basic support for @bigcorvus board is done 2020-08-29 12:46:42 -07:00
geeksville
dffb6c2f06 If display is on on the @BigCorvus board and we xmit the board browns out? 2020-08-28 17:38:23 -07:00
geeksville
7f214ffbb0 TFT kinda correct now - but slow because of bit banging 2020-08-28 15:33:33 -07:00
geeksville
e049eac38a TFT display kinda draws stuff (badly) 2020-08-28 15:06:52 -07:00
geeksville
338445d175 basic init of the Corvus TFT display works 2020-08-28 14:24:22 -07:00
Kevin Hester
8eb492d356 Merge pull request #345 from geeksville/post1
update from master
2020-08-27 14:56:28 -07:00
Kevin Hester
a5341d766e Merge pull request #344 from geeksville/master
lora32 again
2020-08-27 14:56:18 -07:00
geeksville
c78142b235 Merge remote-tracking branch 'root/post1' into post1 2020-08-27 14:50:54 -07:00
geeksville
9ebaa2b962 Merge remote-tracking branch 'root/master' 2020-08-27 14:49:52 -07:00
geeksville
79498580b1 If LORA32 battery voltage is super low, assume no battery installed 2020-08-27 14:46:59 -07:00
Kevin Hester
41901aed97 Merge pull request #342 from geeksville/master
ttgo lora32 fixes
2020-08-26 14:06:25 -07:00
geeksville
2729a513ab Merge remote-tracking branch 'root/master' 2020-08-26 14:00:43 -07:00
geeksville
af046e7dbd bug #322 - ttgo lora32 deep sleep
oh - I think I found the problem (probably)!  we were isolating gpio12 (which isn't used on other boards) to save power during sleep.  gpio12 is the button for this board. @thomslik would you mind pulling this commit and seeing if it works better?
2020-08-26 14:00:10 -07:00
Kevin Hester
0caf534b65 Merge pull request #338 from geeksville/master
fix heltec battery display
2020-08-25 13:06:32 -07:00
geeksville
f650222e94 Merge remote-tracking branch 'root/master' 2020-08-25 13:01:19 -07:00
geeksville
5c40378805 fix #336 don't send battery status on nodes without batteries 2020-08-25 13:00:55 -07:00
geeksville
780b7e3628 don't show battery status on boards that can't sense that #336 2020-08-25 12:48:47 -07:00
geeksville
83ae3c7714 doc rename 2020-08-25 12:48:19 -07:00
Kevin Hester
25ebb9adb8 Merge pull request #337 from geeksville/master
fix screen redrawing
2020-08-25 12:14:07 -07:00
geeksville
7f6a0e7ddc Merge remote-tracking branch 'root/master' 2020-08-25 12:08:38 -07:00
geeksville
f62e6793c5 Fix #333 screens were redrawing when they should not
thanks @drewsed for the clear report - made it easy to repro/fix
due to refactoring/cleanup a couple of weeks back
2020-08-25 12:08:18 -07:00
geeksville
babd57ecde add hw docs 2020-08-25 12:06:55 -07:00
geeksville
de196810a2 add debugging for SNR values on SX1262 2020-08-25 12:06:36 -07:00
Kevin Hester
82fe55471d Merge pull request #331 from geeksville/master
hotfix
2020-08-22 09:15:51 -07:00
Kevin Hester
83726086a9 Merge pull request #329 from geeksville/post1
Post1
2020-08-22 09:13:55 -07:00
geeksville
60d90c4533 Merge remote-tracking branch 'root/master' 2020-08-22 09:10:33 -07:00
geeksville
9145945efa 0.9.3 2020-08-22 09:10:08 -07:00
geeksville
7b09fbe049 fix #327 side effect noticed by @smarti2019 2020-08-22 09:06:54 -07:00
geeksville
a90bab5455 this seems bad - this value was not inited if it wasn't in bss 2020-08-21 10:56:54 -07:00
Kevin Hester
3d9cc8a056 Merge pull request #328 from geeksville/master
for 0.9.2
2020-08-21 10:52:14 -07:00
geeksville
ff885ef215 Merge remote-tracking branch 'root/post1' 2020-08-21 10:50:49 -07:00
Kevin Hester
eb4286b560 Merge pull request #325 from geeksville/ttgo1262
Add support for SX1262 based TBEAMs, see below for more details.
2020-08-21 10:49:02 -07:00
geeksville
9c90de0f6f 0.9.2 2020-08-21 10:25:34 -07:00
geeksville
d7a1cef046 fix #327 always factory reset the GPS once 2020-08-21 10:14:03 -07:00
geeksville
6a359e2124 don't keep uf2 files in source control 2020-08-21 09:37:41 -07:00
geeksville
ca75dcd64d Add support for SX1262 based TBEAMs, see below for more details.
We probe dynamically for the SX1262 or RF95 based radios on TBEAM1.0
boards now.  If either is present it will be used.
2020-08-20 15:42:36 -07:00
Kevin Hester
aba05ba5ce Merge pull request #324 from geeksville/master
merge from dev
2020-08-17 17:20:16 -07:00
Kevin Hester
99882a675b Merge pull request #323 from geeksville/post1
Post1
2020-08-17 15:28:26 -07:00
geeksville
9c9347df23 don't reference tft libs on devices that don't have it 2020-08-17 14:06:31 -07:00
geeksville
b66856c53f default back to tbeam 2020-08-17 14:01:53 -07:00
geeksville
285069703c add missing button 2020-08-17 14:01:03 -07:00
geeksville
d91ab5480f begin support for TFT displays 2020-08-17 13:47:05 -07:00
geeksville
e3b74ece74 use the lora-relay board for CI builds 2020-08-17 12:38:53 -07:00
geeksville
66557241f3 Generate UF2 files for NRF52 release builds 2020-08-17 12:29:45 -07:00
geeksville
3c09c3e520 show NRF52840 debug output via the USB CDC-ACM device 2020-08-17 11:50:50 -07:00
geeksville
781077e799 Turn on buck converter for @BigCorvus board, now radio works 2020-08-17 11:42:19 -07:00
geeksville
22946b5e51 @BigCorvus board now kinda boots
###RTT Client: -----------------------------------------------
###RTT Client: Connecting to J-Link RTT Server via localhost:19021 ...
###RTT Client: Connected.

SEGGER J-Link V6.70c - Real time terminal output
SEGGER J-Link ARM V9.6, SN=69663845
Process: JLinkGDBServerCLExe
Emitting reboot packet for serial shell
I2C device found at address 0x55
done
Meshtastic swver=unset, hwver=unset
Reset reason: 0x0
FIXME, call randomSeed
ERROR: No UBLOX GPS found
Hoping that NEMA might work
RadioConfig reset!
Initial packet id 1481765933, numPacketId 4294967295
No saved preferences found
NODENUM=0xB18C3A4E, dbsize=1
Starting meshradio init...
Set radio: name=Default, config=3, ch=6, power=17
SX1262 init result 0
sending owner !df5db18c3a4e/Unknown 3a4e/?4E
Update DB node 0xB18C3A4E, rx_time=0
old user !df5db18c3a4e/Unknown 3a4e/?4E
updating changed=0 user !df5db18c3a4e/Unknown 3a4e/?4E
Adding packet record (id=0x5851F430 Fr0x4E To0xFF, WantAck0, HopLim3 Payload:User)
enqueuing for send (id=0x5851F430 Fr0x4E To0xFF, WantAck0, HopLim3 encrypted)
txGood=0,rxGood=0,rxBad=0
Starting low level send (id=0x5851F430 Fr0x4E To0xFF, WantAck0, HopLim3 encrypted)
assert failed src/mesh/SX1262Interface.cpp: 102, virtual void SX1262Interface::setStandby(), test=err == ERR_NONE
2020-08-17 11:29:00 -07:00
geeksville
c0307cbcb0 a cleaner way to add variants - no longer need symlinks in adafruit proj 2020-08-17 10:23:21 -07:00
geeksville
6b568ab2fb add powerhold for @bigcorvus board 2020-08-16 14:50:04 -07:00
geeksville
67bad9a689 Add SX1262 to @BigCorvus board 2020-08-16 14:20:05 -07:00
geeksville
559a790286 Add @BigCorvus board support to build 2020-08-16 14:08:31 -07:00
geeksville
08e5bd728b lorarelay wip 2020-08-16 14:07:01 -07:00
geeksville
0cfeeba2e2 add variant files by @BigCorvus 2020-08-16 13:25:24 -07:00
geeksville
5007624ba5 Merge remote-tracking branch 'root/post1' into post1 2020-08-16 13:21:54 -07:00
Kevin Hester
bba4677915 Merge pull request #318 from geeksville/master
fix 279
2020-08-13 20:08:13 -07:00
geeksville
ac969cdb26 Merge remote-tracking branch 'root/master' 2020-08-13 19:56:41 -07:00
geeksville
1c3eff0ee5 turn on fix #279 for tbeam0.7 and ttgo lora32-1.6 battery levels 2020-08-13 19:55:57 -07:00
Kevin Hester
cba9546a4d Merge pull request #316 from geeksville/master
for bug #279
2020-08-13 11:30:25 -07:00
geeksville
ceae60cf13 Merge remote-tracking branch 'root/master' 2020-08-13 11:25:11 -07:00
geeksville
3de1607cea bug #279 change battery voltage to millivolts 2020-08-13 11:23:27 -07:00
Kevin Hester
029b2f3139 Merge pull request #313 from geeksville/post1
Post1
2020-08-12 21:35:42 -07:00
Kevin Hester
ab6c97bfef Merge pull request #315 from geeksville/master
misc bug fixes
2020-08-12 21:35:31 -07:00
Kevin Hester
a61b15e861 Merge branch 'post1' into post1 2020-08-12 17:24:58 -07:00
geeksville
8c7aa07c70 Only do AXP debugging on ESP32 targets 2020-08-12 17:10:59 -07:00
geeksville
6a402b13fa Add battery sensing (mostly) for TBEAM0.7
However, disabled until someone with suitable hardware can test and report
back.

@slavino and @tschundler would you be willing to try it with your boards?

You'll need to uncomment the following line in configuration.h

// #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
2020-08-12 17:03:36 -07:00
geeksville
c30b570e16 Merge remote-tracking branch 'root/master' 2020-08-12 15:53:23 -07:00
geeksville
9b25818a50 fix #249: report battery levels even if no GPS lock
@professr I noticed you added a "newStatus" observable to the GPS class.
Do you remember why you didn't remove the old GPS status (which seemed
to be dumber).  Is it just because you didn't want to risk breaking
MeshService?  (I assume) In this change I removed the old Observable
and all seems well (just using newStatus everywhere).
2020-08-12 15:51:57 -07:00
Kevin Hester
5311e44660 Merge pull request #314 from geeksville/master
my bug queue
2020-08-12 11:11:01 -07:00
geeksville
55dafcbecb fix #269 see below
/**
 * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs.
 * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they
their nodes
 * aren't talking to each other.
 *
 * This string is of the form "#name-XY".
 *
 * Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together.
 * Y is not yet used but should eventually indicate 'speed/range' of the link
 *
 * This function will also need to be implemented in GUI apps that talk to the radio.
 *
 * https://github.com/meshtastic/Meshtastic-device/issues/269
 */
const char *getChannelName();
2020-08-12 11:04:03 -07:00
geeksville
178958c165 allow advanced users to specify channel numbers if they wish 2020-08-12 10:46:44 -07:00
geeksville
d7cf7e2eb4 Allow advanced users to set arbitrary spreadfactor/codingrate/bandwidth 2020-08-12 10:42:25 -07:00
geeksville
fce8c16d52 Merge remote-tracking branch 'mine/post1' into post1 2020-08-11 19:21:07 -07:00
geeksville
b690868bb1 Merge branch 'master' into post1 2020-08-11 19:20:46 -07:00
geeksville
dec88a368b First attempt at better protocol docs. Bug #308
@cyclomies thank you for the prodding and help.  I'm happy to add more
detail, can you insert a few questions inline?  Then I'll answer and
hopefully that will be enough to be useful for others.
2020-08-11 17:34:49 -07:00
Kevin Hester
17394d8c1c Merge pull request #307 from geeksville/post1
Add accidentally lost support for the PPR nrf52 board - so Corvus can use it as a reference
2020-08-10 09:20:53 -07:00
Kevin Hester
a7da7cd32e Merge branch 'post1' into post1 2020-08-10 09:15:49 -07:00
Kevin Hester
f37dc9c776 Merge pull request #310 from Dafeman/PlatformIO-build-guide-update
PlatformIO build guide update
2020-08-10 09:12:11 -07:00
Kevin Hester
d6658dbb2e Merge branch 'master' into PlatformIO-build-guide-update 2020-08-10 08:56:15 -07:00
Dafeman
05531b2684 Update build-instructions.md 2020-08-09 14:07:42 +12:00
Dafeman
8b1fb39ce1 Update build-instructions.md 2020-08-06 22:06:38 +12:00
Dafeman
da46d4ca0e Update build-instructions.md 2020-08-06 19:44:42 +12:00
geeksville
047141eb34 make TXEN/RXEN immediately low once changed to be outputs 2020-08-03 11:29:26 -07:00
geeksville
cb1053850d Oops - I mismerged at somepoint, restore correct PPR variant.h defs 2020-08-03 11:05:24 -07:00
Kevin Hester
7652331e8c Merge pull request #306 from geeksville/master
less logspam
2020-08-02 13:38:23 -07:00
geeksville
12bf3795ea less logspam when debugging the serial API 2020-08-02 12:55:22 -07:00
Ellie Hussey
7f45184d90 Fixed message text wrapping, compass rose position, and added device ID on status page (#300) 2020-08-01 10:50:06 -07:00
geeksville
829763af2c remove stale comment 2020-07-30 09:35:07 -07:00
geeksville
75806ee666 clarify build instructions 2020-07-29 10:25:20 -07:00
Kevin Hester
91ec29db03 Merge pull request #301 from ColPanic/flash_improvements
Adding port/help flags and error checking
2020-07-27 11:33:06 -07:00
Todd Allen
d191b12801 Adding port/help flags and error checking 2020-07-27 09:14:04 -04:00
Kevin Hester
e0d6456618 Merge pull request #299 from jasonfish/add-new-case-to-readme
Adding new case URL to Readme
2020-07-26 09:15:38 -07:00
Jason Fish
70eda2ee06 Adding new case URL to Readme 2020-07-26 08:39:37 -07:00
geeksville
7c4eb3eddd add amazon appstore link 2020-07-24 15:08:10 -07:00
Dafeman
91b4cadb1b Merge pull request #4 from meshtastic/master
Update
2020-06-16 14:41:27 +12:00
BeardyWalrus
0b1a78c028 Merge pull request #2 from meshtastic/master
Pull to live
2020-06-14 16:06:06 -04:00
BeardyWalrus
b8e1b28958 Merge pull request #1 from meshtastic/master
Resync with Upstream
2020-05-21 20:36:06 -04:00
Dafeman
a23f327461 Merge pull request #3 from Dafeman/README-GUI-update
Update GUI Install
2020-05-19 13:50:30 +12:00
165 changed files with 49182 additions and 1957 deletions

View File

@@ -23,4 +23,4 @@ jobs:
run: |
pip install -U adafruit-nrfutil
- name: Build
run: platformio run -e tbeam -e heltec -e nrf52840dk -e rak815
run: platformio run -e tbeam -e heltec -e lora-relay-v1 -e linux

2
.gitignore vendored
View File

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

View File

@@ -48,13 +48,17 @@
"optional": "cpp",
"string_view": "cpp",
"cassert": "cpp",
"iterator": "cpp"
"iterator": "cpp",
"shared_mutex": "cpp"
},
"cSpell.words": [
"Blox",
"EINK",
"HFSR",
"Meshtastic",
"NEMAGPS",
"NMEAGPS",
"RDEF",
"Ublox",
"bkpt",
"cfsr",

View File

@@ -25,11 +25,16 @@ We currently support three models of radios.
- TTGO T-Beam (usually the recommended choice)
- [T-Beam V1.1 w/ NEO-6M - special Meshtastic version](https://www.aliexpress.com/item/4001178678568.html) (Includes built-in OLED display and they have **preinstalled** the meshtastic software)
- [T-Beam V1.1 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
- [T-Beam V1.1 w/ NEO-M8N /w SX1262](https://www.aliexpress.com/item/4001287221970.html) (slightly better GPS + LoRa)
- board labels "TTGO T22_V1.1 20191212"
- [T-Beam V0.7 w/ NEO-6M](https://www.aliexpress.com/item/4000574335430.html) (will work but **you must use the tbeam0.7 firmware ** - but the T-Beam V1.0 or later are better!)
- board labels "TTGO T22_V07 20180711"
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
- [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:3830711)
- [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297)
- Laser-cut cases
- [T-Beam V1](https://www.thingiverse.com/thing:4552771)
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
- version 2.1
@@ -98,10 +103,10 @@ Hard resetting via RTS pin...
```
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`.
6. Install the correct firmware for your board with `device-install.sh -f firmware-_board_-_country_.bin`.
- Example: `./device-install.sh -f firmware-HELTEC-US-0.0.3.bin`.
7. To update run `device-update.sh -f firmware-_board_-_country_.bin`
- Example: `./device-update.sh -f 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_-_version_.bin`. This will be faster, also all of your current preferences will be preserved.

View File

@@ -4,12 +4,15 @@ set -e
source bin/version.sh
COUNTRIES="US EU433 EU865 CN JP"
COUNTRIES="US EU433 EU865 CN JP ANZ KR"
#COUNTRIES=US
#COUNTRIES=CN
BOARDS="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
#BOARDS=tbeam
BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
# BOARDS_ESP32=tbeam
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
BOARDS_NRF52="lora-relay-v1"
OUTDIR=release/latest
@@ -18,25 +21,61 @@ ARCHIVEDIR=release/archive
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/bins $OUTDIR/elfs
rm -f $OUTDIR/bins/*
mkdir -p $OUTDIR/bins
rm -r $OUTDIR/bins/*
mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal
# 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
function do_build() {
BOARD=$1
COUNTRY=$2
isNrf=$3
echo "Building $COUNTRY for $BOARD with $PLATFORMIO_BUILD_FLAGS"
rm -f .pio/build/$BOARD/firmware.*
# 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
# Are we building a universal/regionless rom?
if [ "x$COUNTRY" != "x" ]
then
export HW_VERSION="1.0-$COUNTRY"
export COUNTRY
basename=firmware-$BOARD-$COUNTRY-$VERSION
else
export HW_VERSION="1.0"
unset COUNTRY
basename=universal/firmware-$BOARD-$VERSION
fi
pio run --jobs 4 --environment $BOARD # -v
SRCELF=.pio/build/$BOARD/firmware.elf
cp $SRCELF $OUTDIR/elfs/$basename.elf
if [ "$isNrf" = "false" ]
then
echo "Copying ESP32 bin file"
SRCBIN=.pio/build/$BOARD/firmware.bin
cp $SRCBIN $OUTDIR/bins/$basename.bin
else
echo "Generating NRF52 uf2 file"
SRCHEX=.pio/build/$BOARD/firmware.hex
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/bins/$basename.uf2 -f 0xADA52840
fi
}
function do_boards() {
declare boards=$1
declare isNrf=$2
for board in $boards; do
for country in $COUNTRIES; do
do_build $board $country "$isNrf"
done
# Build universal
do_build $board "" "$isNrf"
done
}
# Make sure our submodules are current
@@ -45,14 +84,16 @@ 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 BOARD in $BOARDS; do
do_build $BOARD
done
done
do_boards "$BOARDS_ESP32" "false"
do_boards "$BOARDS_NRF52" "true"
# keep the bins in archive also
cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR
echo Updating android bins $OUTDIR/forandroid
rm -rf $OUTDIR/forandroid
mkdir -p $OUTDIR/forandroid
cp -a $OUTDIR/bins/universal/*.bin $OUTDIR/forandroid/
cat >$OUTDIR/curfirmwareversion.xml <<XML
<?xml version="1.0" encoding="utf-8"?>
@@ -66,6 +107,7 @@ Generated by bin/buildall.sh -->
</resources>
XML
echo Generating $ARCHIVEDIR/firmware-$VERSION.zip
rm -f $ARCHIVEDIR/firmware-$VERSION.zip
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh

View File

@@ -1,11 +1,45 @@
#!/bin/bash
#!/bin/sh
set -e
# Usage info
show_help() {
cat << EOF
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] [-f FILENAME]
Flash image file to device, but first erasing and writing system information"
FILENAME=$1
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-f FILENAME The .bin file to flash. Custom to your device type and region.
EOF
}
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
while getopts ":h:p:f:" opt; do
case "${opt}" in
h)
show_help
exit 0
;;
p) export ESPTOOL_PORT=${OPTARG}
;;
f) FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
show_help >&2
exit 1
;;
esac
done
shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then
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}
else
echo "Invalid file: ${FILENAME}"
show_help
fi
exit 0

View File

@@ -1,8 +1,43 @@
#!/bin/bash
#!/bin/sh
set -e
# Usage info
show_help() {
cat << EOF
Usage: ${0##*/} [-h] [-p ESPTOOL_PORT] -f FILENAME
Flash image file to device, leave existing system intact."
FILENAME=$1
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-f FILENAME The .bin file to flash. Custom to your device type and region.
EOF
}
echo "Trying to update $FILENAME"
esptool.py --baud 921600 write_flash 0x10000 $FILENAME
while getopts ":h:p:f:" opt; do
case "${opt}" in
h)
show_help
exit 0
;;
p) export ESPTOOL_PORT=${OPTARG}
;;
f) FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
show_help >&2
exit 1
;;
esac
done
shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then
echo "Trying to flash update ${FILENAME}."
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
else
echo "Invalid file: ${FILENAME}"
show_help
fi
exit 0

35
bin/install-bootloader.sh Executable file
View File

@@ -0,0 +1,35 @@
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e
# dependencies
# apt install srecord
BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
BOARD=othernet_ppr1
BOOTVER=0.3.2
BOOTNUM=128
BOOTSHA=gc01b9ea
SDCODE=s113
SDVER=7.2.0
PROJ=ppr1
# FIXME for nRF52840 use 0xff000, for nRF52833 use 0x7f000
BOOTSET=0x7f000
nrfjprog --eraseall -f nrf52
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
# first 4 bytes should be 0x01 to indicate valid app image
# second 4 bytes should be 0x00 to indicate no CRC required for image
echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin
srec_cat /tmp/bootconf.bin -binary -offset $BOOTSET -output /tmp/bootconf.hex -intel
echo Generating merged hex file from .pio/build/$PROJ/firmware.hex
mergehex -o ${BOARD}_full.hex -m $BOOTDIR/_build/build-$BOARD/${BOARD}_bootloader-$BOOTVER-$BOOTNUM-$BOOTSHA-dirty_${SDCODE}_$SDVER.hex .pio/build/$PROJ/firmware.hex /tmp/bootconf.hex
echo Telling bootloader app region is valid and telling CPU to run
nrfjprog --program ${BOARD}_full.hex -f nrf52 --reset
# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less

22
bin/install-eink.sh Executable file
View File

@@ -0,0 +1,22 @@
# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board
set -e
BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader
nrfjprog --eraseall -f nrf52
# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid
# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000
# first 4 bytes should be 0x01 to indicate valid app image
# second 4 bytes should be 0x00 to indicate no CRC required for image
echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin
srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel
echo Generating merged hex file
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-125-gf38f8f4-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
echo Telling bootloader app region is valid and telling CPU to run
nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset
# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less

View File

@@ -1,3 +1,3 @@
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52832_XXAA

3
bin/nrf52833-gdbserver.sh Executable file
View File

@@ -0,0 +1,3 @@
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52833_XXAA

View File

@@ -1,3 +1,3 @@
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52832_XXAA
JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA

6
bin/qspi-flash-test.sh Executable file
View File

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

314
bin/uf2conv.py Executable file
View File

@@ -0,0 +1,314 @@
#!/usr/bin/env python3
import sys
import struct
import subprocess
import re
import os
import os.path
import argparse
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
UF2_MAGIC_END = 0x0AB16F30 # Ditto
families = {
'SAMD21': 0x68ed2b88,
'SAML21': 0x1851780a,
'SAMD51': 0x55114460,
'NRF52': 0x1b57745f,
'STM32F0': 0x647824b6,
'STM32F1': 0x5ee21072,
'STM32F2': 0x5d1a0a2e,
'STM32F3': 0x6b846188,
'STM32F4': 0x57755a57,
'STM32F7': 0x53b80f00,
'STM32G0': 0x300f5633,
'STM32G4': 0x4c71240a,
'STM32H7': 0x6db66082,
'STM32L0': 0x202e3a91,
'STM32L1': 0x1e1f432d,
'STM32L4': 0x00ff6919,
'STM32L5': 0x04240bdf,
'STM32WB': 0x70d16653,
'STM32WL': 0x21460ff0,
'ATMEGA32': 0x16573617,
'MIMXRT10XX': 0x4FB2D5BD
}
INFO_FILE = "/INFO_UF2.TXT"
appstartaddr = 0x2000
familyid = 0x0
def is_uf2(buf):
w = struct.unpack("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def is_hex(buf):
try:
w = buf[0:30].decode("utf-8")
except UnicodeDecodeError:
return False
if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf):
return True
return False
def convert_from_uf2(buf):
global appstartaddr
numblocks = len(buf) // 512
curraddr = None
outp = b""
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
continue
datalen = hd[4]
if datalen > 476:
assert False, "Invalid UF2 data size at " + ptr
newaddr = hd[3]
if curraddr == None:
appstartaddr = newaddr
curraddr = newaddr
padding = newaddr - curraddr
if padding < 0:
assert False, "Block out of order at " + ptr
if padding > 10*1024*1024:
assert False, "More than 10M of padding needed at " + ptr
if padding % 4 != 0:
assert False, "Non-word padding size at " + ptr
while padding > 0:
padding -= 4
outp += b"\x00\x00\x00\x00"
outp += block[32 : 32 + datalen]
curraddr = newaddr + datalen
return outp
def convert_to_carray(file_content):
outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {"
for i in range(len(file_content)):
if i % 16 == 0:
outp += "\n"
outp += "0x%02x, " % ord(file_content[i])
outp += "\n};\n"
return outp
def convert_to_uf2(file_content):
global familyid
datapadding = b""
while len(datapadding) < 512 - 256 - 32 - 4:
datapadding += b"\x00\x00\x00\x00"
numblocks = (len(file_content) + 255) // 256
outp = b""
for blockno in range(numblocks):
ptr = 256 * blockno
chunk = file_content[ptr:ptr + 256]
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack(b"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
while len(chunk) < 256:
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp += block
return outp
class Block:
def __init__(self, addr):
self.addr = addr
self.bytes = bytearray(256)
def encode(self, blockno, numblocks):
global familyid
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, self.addr, 256, blockno, numblocks, familyid)
hd += self.bytes[0:256]
while len(hd) < 512 - 4:
hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END)
return hd
def convert_from_hex_to_uf2(buf):
global appstartaddr
appstartaddr = None
upper = 0
currblock = None
blocks = []
for line in buf.split('\n'):
if line[0] != ":":
continue
i = 1
rec = []
while i < len(line) - 1:
rec.append(int(line[i:i+2], 16))
i += 2
tp = rec[3]
if tp == 4:
upper = ((rec[4] << 8) | rec[5]) << 16
elif tp == 2:
upper = ((rec[4] << 8) | rec[5]) << 4
assert (upper & 0xffff) == 0
elif tp == 1:
break
elif tp == 0:
addr = upper | (rec[1] << 8) | rec[2]
if appstartaddr == None:
appstartaddr = addr
i = 4
while i < len(rec) - 1:
if not currblock or currblock.addr & ~0xff != addr & ~0xff:
currblock = Block(addr & ~0xff)
blocks.append(currblock)
currblock.bytes[addr & 0xff] = rec[i]
addr += 1
i += 1
numblocks = len(blocks)
resfile = b""
for i in range(0, numblocks):
resfile += blocks[i].encode(i, numblocks)
return resfile
def to_str(b):
return b.decode("utf-8")
def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk",
"get", "DeviceID,", "VolumeName,",
"FileSystem,", "DriveType"])
for line in to_str(r).split('\n'):
words = re.split('\s+', line)
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
drives.append(words[0])
else:
rootpath = "/media"
if sys.platform == "darwin":
rootpath = "/Volumes"
elif sys.platform == "linux":
tmp = rootpath + "/" + os.environ["USER"]
if os.path.isdir(tmp):
rootpath = tmp
for d in os.listdir(rootpath):
drives.append(os.path.join(rootpath, d))
def has_info(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False
return list(filter(has_info, drives))
def board_id(path):
with open(path + INFO_FILE, mode='r') as file:
file_content = file.read()
return re.search("Board-ID: ([^\r\n]*)", file_content).group(1)
def list_drives():
for d in get_drives():
print(d, board_id(d))
def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print("Wrote %d bytes to %s" % (len(buf), name))
def main():
global appstartaddr, familyid
def error(msg):
print(msg)
sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
help='input file (HEX, BIN or UF2)')
parser.add_argument('-b' , '--base', dest='base', type=str,
default="0x2000",
help='set base address of application for BIN format (default: 0x2000)')
parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str,
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
parser.add_argument('-d' , '--device', dest="device_path",
help='select a device path to flash')
parser.add_argument('-l' , '--list', action='store_true',
help='list connected devices')
parser.add_argument('-c' , '--convert', action='store_true',
help='do not flash, just convert')
parser.add_argument('-D' , '--deploy', action='store_true',
help='just flash, do not convert')
parser.add_argument('-f' , '--family', dest='family', type=str,
default="0x0",
help='specify familyID - number or name (default: 0x0)')
parser.add_argument('-C' , '--carray', action='store_true',
help='convert binary file to a C array, not UF2')
args = parser.parse_args()
appstartaddr = int(args.base, 0)
if args.family.upper() in families:
familyid = families[args.family.upper()]
else:
try:
familyid = int(args.family, 0)
except ValueError:
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
if args.list:
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if args.deploy:
outbuf = inpbuf
elif from_uf2:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
elif is_hex(inpbuf):
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
elif args.carray:
outbuf = convert_to_carray(inpbuf)
ext = "h"
else:
outbuf = convert_to_uf2(inpbuf)
print("Converting to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert or ext != "uf2":
drives = []
if args.output == None:
args.output = "flash." + ext
else:
drives = get_drives()
if args.output:
write_file(args.output, outbuf)
else:
if len(drives) == 0:
error("No drive to deploy.")
for d in drives:
print("Flashing %s (%s)" % (d, board_id(d)))
write_file(d + "/NEW.UF2", outbuf)
if __name__ == "__main__":
main()

4
bin/upload-to-bootloader.sh Executable file
View File

@@ -0,0 +1,4 @@
echo "Converting to uf2 for NRF52 Adafruit bootloader"
bin/uf2conv.py .pio/build/lora-relay-v2/firmware.hex -f 0xADA52840
# cp flash.uf2 /media/kevinh/FTH*BOOT/

View File

@@ -1,3 +1,3 @@
export VERSION=0.9.1
export VERSION=1.1.8

2
bin/view-map.sh Executable file
View File

@@ -0,0 +1,2 @@
echo using amap tool to display memory map
amap .pio/build/output.map

61
boards/eink.json Normal file
View File

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

46
boards/lora-relay-v1.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_LORA_RELAY_V1 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4404"]],
"usb_product": "LORA_RELAY",
"mcu": "nrf52840",
"variant": "lora_relay_v1",
"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 Lora Relay V1 (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": ["jlink", "nrfjprog", "stlink"]
},
"url": "https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay",
"vendor": "BigCorvus"
}

46
boards/lora-relay-v2.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_LORA_RELAY_V2 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4406"]],
"usb_product": "LORA_RELAY",
"mcu": "nrf52840",
"variant": "lora_relay_v2",
"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 Lora Relay V1 (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": ["jlink", "nrfjprog", "stlink"]
},
"url": "https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay",
"vendor": "BigCorvus"
}

View File

@@ -1,7 +1,7 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
"ldscript": "nrf52840_s113_v7.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
@@ -16,9 +16,9 @@
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_flags": "-DS113",
"sd_name": "s113",
"sd_version": "7.2.0",
"sd_fwid": "0x00B6"
},
"bootloader": {

46
boards/ppr1.json Normal file
View File

@@ -0,0 +1,46 @@
{
"build": {
"arduino": {
"ldscript": "nrf52833_s113_v7.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52833_PPR -DNRF52833_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4406"]],
"usb_product": "PPR",
"mcu": "nrf52833",
"variant": "ppr",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS113",
"sd_name": "s113",
"sd_version": "7.2.0",
"sd_fwid": "0x00b6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52833_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52833.svd"
},
"frameworks": ["arduino"],
"name": "Meshtastic PPR1 (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"
}

277
data/style.css Normal file
View File

@@ -0,0 +1,277 @@
/* latin-ext */
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(./Google.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
*, *:before, *:after {
box-sizing: border-box;
}
body {
background: #C5DDEB;
font: 14px/20px "Lato", Arial, sans-serif;
padding: 40px 0;
color: white;
}
.grid {
display: grid;
grid-template-columns:
1fr 4fr;
grid-template-areas:
"header header"
"sidebar content";
margin: 0 auto;
width: 750px;
background: #444753;
border-radius: 5px;
}
.top {grid-area: header;}
.side {grid-area: sidebar;}
.main {grid-area: content;}
.top {
border-bottom: 2px solid white;
}
.top-text {
font-weight: bold;
font-size: 24px;
text-align: center;
padding: 20px;
}
.side {
width: 260px;
float: left;
}
.side .side-header {
padding: 20px;
border-bottom: 2px solid white;
}
.side .side-header .side-text {
padding-left: 10px;
margin-top: 6px;
font-size: 16px;
text-align: left;
font-weight: bold;
}
.channel-list ul {
padding: 20px;
height: 570px;
list-style-type: none;
}
.channel-list ul li {
padding-bottom: 20px;
}
.channel-list .channel-name {
font-size: 20px;
margin-top: 8px;
padding-left: 8px;
}
.channel-list .message-count {
padding-left: 16px;
color: #92959E;
}
.icon {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
}
.icon-map-marker {
width: 0.5714285714285714em;
}
.icon-circle {
width: 0.8571428571428571em;
}
.content {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
/* width: 490px; */
float: left;
background: #F2F5F8;
/* border-top-right-radius: 5px;
border-bottom-right-radius: 5px; */
color: #434651;
}
.content .content-header {
flex-grow: 0;
padding: 20px;
border-bottom: 2px solid white;
}
.content .content-header .content-from {
padding-left: 10px;
margin-top: 6px;
font-size: 20px;
text-align: center;
font-size: 16px;
}
.content .content-header .content-from .content-from-highlight {
font-weight: bold;
}
.content .content-header .content-num-messages {
color: #92959E;
}
.content .content-history {
flex-grow: 1;
padding: 20px 20px 20px;
border-bottom: 2px solid white;
overflow-y: scroll;
height: 375px;
}
.content .content-history ul {
list-style-type: none;
padding-inline-start: 10px;
}
.content .content-history .message-data {
margin-bottom: 10px;
}
.content .content-history .message-data-time {
color: #a8aab1;
padding-left: 6px;
}
.content .content-history .message {
color: white;
padding: 8px 10px;
line-height: 20px;
font-size: 14px;
border-radius: 7px;
margin-bottom: 30px;
width: 90%;
position: relative;
}
.content .content-history .message:after {
bottom: 100%;
left: 7%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-bottom-color: #86BB71;
border-width: 10px;
margin-left: -10px;
}
.content .content-history .my-message {
background: #86BB71;
}
.content .content-history .other-message {
background: #94C2ED;
}
.content .content-history .other-message:after {
border-bottom-color: #94C2ED;
left: 93%;
}
.content .content-message {
flex-grow: 0;
padding: 10px;
}
.content .content-message textarea {
width: 100%;
border: none;
padding: 10px 10px;
font: 14px/22px "Lato", Arial, sans-serif;
margin-bottom: 10px;
border-radius: 5px;
resize: none;
}
.content .content-message button {
float: right;
color: #94C2ED;
font-size: 16px;
text-transform: uppercase;
border: none;
cursor: pointer;
font-weight: bold;
background: #F2F5F8;
}
.content .content-message button:hover {
color: #75b1e8;
}
/* Tooltip container */
.tooltip {
color: #86BB71;
position: relative;
display: inline-block;
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #444753;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text - see examples below! */
position: absolute;
z-index: 1;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
}
.online, .offline, .me {
margin-right: 3px;
font-size: 10px;
}
.online {
color: #86BB71;
}
.offline {
color: #E38968;
}
.me {
color: #94C2ED;
}
.align-left {
text-align: left;
}
.align-right {
text-align: right;
}
.float-right {
float: right;
}
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}

BIN
data/style.css.gz Normal file

Binary file not shown.

View File

@@ -43,7 +43,8 @@ For an detailed walk-through aimed at beginners, we recommend [meshtastic.letsta
Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum.
- 06/24/2020 - 0.7.x Now with over 1000 android users, over 600 people using the radios and translated into 13 languages. Fairly stable and we are working through bugs to get to 1.0.
- 09/14/2020 - 1.0.0 Now with over 1700 android users, over 2000 nodes and translated into 15 languages. This project will always be a "beta" experiment, but now quite usable. We are currently selecting 1.1 features in our discussion forum.
- 06/24/2020 - 0.7.x Now with over 1000 android users, over 600 people using the radios and translated into 22 languages. Fairly stable and we are working through bugs to get to 1.0.
- 06/04/2020 - 0.6.7 Beta releases of both the application and the device code are released. Features are fairly solid now with a sizable number of users.
- 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.
- 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.
@@ -66,6 +67,8 @@ The link above will return older more stable releases. We would prefer if you jo
If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android).
The app is also distributed for Amazon Fire devices via the Amazon appstore: [![Amazon appstore link](https://raw.githubusercontent.com/meshtastic/Meshtastic-device/master/images/amazon-fire-button.png)](https://www.amazon.com/Geeksville-Industries-Meshtastic/dp/B08CY9394Q)
## Supported hardware
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4001178678568.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). Also, the version of the T-Beam we link to is shipped with Meshtastic **preinstalled** by TTGO, so you don't have to install it yourself.
@@ -74,11 +77,15 @@ Make sure to buy the frequency range which is legal for your country. For the US
Instructions for installing prebuilt firmware can be found [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md).
For a nice printable cases:
For a nice looking cases:
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).
- 3D printable cases
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 (SMA) 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. TTGO T_Beam V1 (IPEX) see this [design](https://www.thingiverse.com/thing:4587297) by [drewsed](https://www.thingiverse.com/drewsed)
4. Heltec Lora32 see this [design](https://www.thingiverse.com/thing:3125854) by [ornotermes](https://www.thingiverse.com/ornotermes).
- Laser-cut cases
1. TTGO T_Beam V1 (SMA) see this [design](https://www.thingiverse.com/thing:4552771) by [jefish](https://www.thingiverse.com/jefish)
# IMPORTANT DISCLAIMERS AND FAQ

View File

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

Binary file not shown.

BIN
docs/hardware/T-SX1262.pdf Normal file

Binary file not shown.

Binary file not shown.

35
docs/hardware/corvus.md Normal file
View File

@@ -0,0 +1,35 @@
# Notes on @BigCorvus boards
## Board version 1.1
variant name lora_relay_v1
### Remaining TODOs
- power hold for the ST7735
- look at example sketch
- turn on xmit boost
## Recommendations for future boards
@BigCorvus your board is **really** nice. Here's some ideas for the future:
- make the SWDIO header more standard (the small ARM 2x5 micro footprint?) or at least througholes so it is easy to solder a header
## How to program bootloader
Download from here: https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases
```
nrfjprog -f nrf52 --eraseall
Erasing user available code and UICR flash areas.
Applying system reset.
nrfjprog -f nrf52 --program feather_nrf52840_express_bootloader-0.3.2_s140_6.1.1.hex
Parsing hex file.
Reading flash area to program to guarantee it is erased.
Checking that the area to write is not protected.
Programming device.
```
Then reboot the board, if all went well it now shows up as a mountable filesystem on your USB bus.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,12 @@
You probably don't care about this section - skip to the next one.
For high speed/lots of devices/short range tasks:
- When guessing numhops for sending: if I've heard from many local (0 hop neighbors) decrease hopcount by 2 rather than 1.
This should nicely help 'router' nodes do the right thing when long range, or if there are many local nodes for short range.
- fix timeouts/delays to be based on packet length at current radio settings
Nimble tasks:
- readerror.txt stress test bug

View File

@@ -1,15 +1,36 @@
# 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.
This project uses the simple PlatformIO build system. PlatformIO is an extension to Microsoft VSCode.
1. Purchase a suitable radio (see above)
## GUI
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
2. Install [Python](https://www.python.org/downloads/).
3. Install [Git](https://git-scm.com/downloads).
4. Reboot your computer.
5. Install [PlatformIO](https://platformio.org/platformio-ide).
6. Click the PlatformIO icon on the side bar. ![platformio icon](https://user-images.githubusercontent.com/47490997/89482668-77c7ea00-d7ee-11ea-8785-5faf8ff99800.png)
7. Under `Quick Access, Miscellaneous, Clone Git Project` enter the URL of the Meshtastic repo found [here](https://github.com/meshtastic/Meshtastic-device). ![image](https://user-images.githubusercontent.com/47490997/89483047-4c91ca80-d7ef-11ea-91f4-1d53d4e8acd9.png)
8. Select a file location to save the repo.
9. Once loaded, open the `platformio.ini` file.
10. At the line `default_envs` you can change it to the board type you are building for ie. `tlora-v2, tlora-v1, tlora-v2-1-1.6, tbeam, heltec, tbeam0.7` (boards are listed further down in the file).
11. The hardware can be configured for different countries by adding a definition to the `configuration.h` file. `#define HW_VERSION_US` or `HW_VERSION_EU433, HW_VERSION_EU865, HW_VERSION_CN, HW_VERSION_JP`. Other country settings can be found in `MeshRadio.h`. The default is `HW_VERSION_US`.
12. Click the PlatformIO icon on the side bar. Under `Project Tasks` you can now build or upload.
Note - To get a clean build you may have to delete the auto-generated file `./.vscode/c_cpp_properties.json`, close and re-open Visual Studio and WAIT until the file is auto-generated before compiling again.
## Command Line
1. Purchase a suitable [radio](https://github.com/meshtastic/Meshtastic-device/wiki/Hardware-Information).
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it
3. Download this git repo and cd into it:
```
git clone https://github.com/meshtastic/Meshtastic-device.git
cd Meshtastic-device
```
4. Run `git submodule update --init --recursive` to pull in dependencies this project needs.
5. If you are outside the USA, run "export COUNTRY=EU865" (or whatever) to set the correct frequency range for your country. Options are provided for `EU433`, `EU865`, `CN`, `JP` and `US` (default). Pull-requests eagerly accepted for other countries.
6. Plug the radio into your USB port
7. 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. 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 `tlora-v2, tlora-v1, tlora-v2-1-1.6, tbeam, heltec, tbeam0.7`).
8. 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

View File

@@ -42,7 +42,6 @@ Expected sequence for initial download:
- Read a RadioConfig from "radio" - used to get the channel and radio settings
- Read 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 a series of NodeInfo packets to build the phone's copy of the current NodeDB for the mesh
- Read a endConfig packet that indicates that the entire state you need has been sent.
- Read a series of MeshPackets until it returns empty to get any messages that arrived for this node while the phone was away

View File

@@ -0,0 +1,17 @@
You probably don't care about this ugly file of personal notes ;-)
for taiwan region:
bin/run.sh --set region 8
time only mode
./bin/run.sh --set gps_operation 3
ublox parsing failure
record power measurements and update spreadsheet
have loop methods return allowable sleep time (from their perspective)
increase main cpu sleep time
warn people about crummy gps antennas - add to faq

View File

@@ -1,5 +1,75 @@
# Mesh broadcast algorithm
## Current algorithm
The routing protocol for Meshtastic is really quite simple (and suboptimal). It is heavily influenced by the mesh routing algorithm used in [Radiohead](https://www.airspayce.com/mikem/arduino/RadioHead/) (which was used in very early versions of this project). It has four conceptual layers.
### A note about protocol buffers
Because we want our devices to work across various vendors and implementations, we use [Protocol Buffers](https://github.com/meshtastic/Meshtastic-protobufs) pervasively. For information on how the protocol buffers are used wrt API clients see [sw-design](sw-design.md), for purposes of this document you mostly only
need to consider the MeshPacket and Subpacket message types.
### Layer 1: Non reliable zero hop messaging
This layer is conventional non-reliable lora packet transmission. The transmitted packet has the following representation on the ether:
- A 32 bit LORA preamble (to allow receiving radios to synchronize clocks and start framing). We use a longer than minimum (8 bit) preamble to maximize the amount of time the LORA receivers can stay asleep, which dramatically lowers power consumption.
After the preamble the 16 byte packet header is transmitted. This header is described directly by the PacketHeader class in the C++ source code. But indirectly it matches the first portion of the "MeshPacket" protobuf definition. But notably: this portion of the packet is sent directly as the following 16 bytes (rather than using the protobuf encoding). We do this to both save airtime and to allow receiving radio hardware the option of filtering packets before even waking the main CPU.
- to (4 bytes): the unique NodeId of the destination (or 0xffffffff for NodeNum_BROADCAST)
- from (4 bytes): the unique NodeId of the sender)
- id (4 bytes): the unique (wrt the sending node only) packet ID number for this packet. We use a large (32 bit) packet ID to ensure there is enough unique state to protect any encrypted payload from attack.
- flags (4 bytes): Only a few bits are are currently used - 3 bits for for the "HopLimit" (see below) and 1 bit for "WantAck"
After the packet header the actual packet is placed onto the the wire. These bytes are merely the encrypted packed protobuf encoding of the SubPacket protobuf. A full description of our encryption is available in [crypto](crypto.md). It is worth noting that only this SubPacket is encrypted, headers are not. Which leaves open the option of eventually allowing nodes to route packets without knowing the keys used to encrypt.
NodeIds are constructed from the bottom four bytes of the macaddr of the bluetooth address. Because the OUI is assigned by the IEEE and we currently only support a few CPU manufacturers, the upper byte is defacto guaranteed unique for each vendor. The bottom 3 bytes are guaranteed unique by that vendor.
To prevent collisions all transmitters will listen before attempting to send. If they hear some other node transmitting, they will reattempt transmission in x milliseconds. This retransmission delay is random between FIXME and FIXME (these two numbers are currently hardwired, but really should be scaled based on expected packet transmission time at current channel settings).
### Layer 2: Reliable zero hop messaging
This layer adds reliable messaging between the node and its immediate neighbors (only).
The default messaging provided by layer-1 is extended by setting the "want-ack" flag in the MeshPacket protobuf. If want-ack is set the following documentation from mesh.proto applies:
"""This packet is being sent as a reliable message, we would prefer it to arrive
at the destination. We would like to receive a ack packet in response.
Broadcasts messages treat this flag specially: Since acks for broadcasts would
rapidly flood the channel, the normal ack behavior is suppressed. Instead,
the original sender listens to see if at least one node is rebroadcasting this
packet (because naive flooding algorithm). If it hears that the odds (given
typical LoRa topologies) the odds are very high that every node should
eventually receive the message. So FloodingRouter.cpp generates an implicit
ack which is delivered to the original sender. If after some time we don't
hear anyone rebroadcast our packet, we will timeout and retransmit, using the
regular resend logic."""
If a transmitting node does not receive an ACK (or a NAK) packet within FIXME milliseconds, it will use layer-1 to attempt a retransmission of the sent packet. A reliable packet (at this 'zero hop' level) will be resent a maximum of three times. If no ack or nak has been received by then the local node will internally generate a nak (either for local consumption or use by higher layers of the protocol).
### Layer 3: (Naive) flooding for multi-hop messaging
Given our use-case for the initial release, most of our protocol is built around [flooding](<https://en.wikipedia.org/wiki/Flooding_(computer_networking)>). The implementation is currently 'naive' - i.e. it doesn't try to optimize flooding other than abandoning retransmission once we've seen a nearby receiver has acked the packet. Therefore, for each source packet up to N retransmissions might occur (if there are N nodes in the mesh).
Each node in the mesh, if it sees a packet on the ether with HopLimit set to a value other than zero, it will decrement that HopLimit and attempt retransmission on behalf of the original sending node.
### Layer 4: DSR for multi-hop unicast messaging
This layer is not yet fully implemented (and not yet used). But eventually (if we stay with our own transport rather than switching to QMesh or Reticulum)
we will use conventional DSR for unicast messaging. Currently (even when not requiring 'broadcasts') we send any multi-hop unicasts as 'broadcasts' so that we can
leverage our (functional) flooding implementation. This is suboptimal but it is a very rare use-case, because the odds are high that most nodes (given our small networks and 'hiking' use case) are within a very small number of hops. When any node witnesses an ack for a packet, it will realize that it can abandon its own
broadcast attempt for that packet.
## Misc notes on remaining tasks
This section is currently poorly formatted, it is mostly a mere set of todo lists and notes for @geeksville during his initial development. After release 1.0 ideas for future optimization include:
- Make flood-routing less naive (because we have GPS and radio signal strength as heuristics to avoid redundant retransmissions)
- If nodes have been user marked as 'routers', preferentially do flooding via those nodes
- Fully implement DSR to improve unicast efficiency (or switch to QMesh/Reticulum as these projects mature)
great source of papers and class notes: http://www.cs.jhu.edu/~cs647/
flood routing improvements
@@ -146,23 +216,3 @@ look into the literature for this idea specifically.
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.

View File

@@ -5,8 +5,30 @@
## RAK815
TODO:
### PPR1 TODO
* V_BK for the GPS should probably be supplied from something always on
* use S113 soft device 7.2.0
* properly test charge controller config and read battery/charge status
* fix bluetooth
* fix LCD max contrast (currently too high, needs to be about 40?)
* save brightness settings in flash
* make ST7567Wire driver less ugly, move OLED stuff into a common class treee
* add LCD power save mode for lcd per page 31 of datasheet
* add LCD power off sequence per datasheet to lcd driver
* leave LCD screen on most of the time (because it needs little power)
### general nrf52 TODO:
- turn off transitions on eink screens
- change update interval on eink from 1/sec frames to one frame every 5 mins
- enter SDS state at correct time (to protect battery or loss of phone contact)
- show screen on eink when we enter SDS state (with app info and say sleeping)
- require button press to pair
- shrink soft device RAM usage
- get nrf52832 working again (currently OOM)
- i2c gps comms not quite right
- ble: AdafruitBluefruit::begin - adafruit_ble_task was assigned an invalid stack pointer. out of memory?
- measure power draw
@@ -194,7 +216,7 @@ Nice ideas worth considering someday...
- 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
- add a NMEA 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

View File

@@ -2,18 +2,25 @@
These are **preliminary** notes on support for Meshtastic in the Pinetab.
A RF95 is connected via a CS341 USB-SPI chip.
A RF95 is connected via a CH341 USB-SPI chip.
Pin assignments:
CS0 from RF95 goes to CS0 on CS341
DIO0 from RF95 goes to INT on CS341
RST from RF95 goes to RST on CS341
CS0 from RF95 goes to CS0 on CH341
DIO0 from RF95 goes to INT on CH341
RST from RF95 goes to RST on CH341
This linux driver claims to provide USB-SPI support: https://github.com/gschorcht/spi-ch341-usb
Notes here on using that driver: https://www.linuxquestions.org/questions/linux-hardware-18/ch341-usb-to-spi-adaptor-driver-doesn%27t-work-4175622736/
Or if **absolutely** necessary could bitbang: https://www.cnx-software.com/2018/02/16/wch-ch341-usb-to-serial-chip-gets-linux-driver-to-control-gpios-over-usb/
## Portduino tasks
* How to access spi devices via ioctl (spidev): https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md#:~:text=Troubleshooting-,Overview,bus)%2C%20UARTs%2C%20etc.
* access gpio via libgpiod?
* Use dkms to distribute driver?
* echo 100 > /sys/module/spi_ch341_usb/parameters/poll_period
## Task list
* Port meshtastic to build (under platformio) for a poxix target. spec: no screen, no gpios, sim network interface, posix threads, posix semaphores & queues, IO to the console only

View File

@@ -32,14 +32,18 @@ From lower to higher power consumption.
onEntry: setBluetoothOn(true)
onExit:
- full on (ON) - Everything is on
onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen.setOn(false)
- serial API usage (SERIAL) - Screen is on, device doesn't sleep, bluetooth off
onEntry: setBluetooth off, screen on
onExit:
- full on (ON) - Everything is on, can eventually timeout and lower to a lower power state
onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen->setOn(false)
- has power (POWER) - Screen is on, device doesn't sleep, bluetooth on, will stay in this state as long as we have power
onEntry: setBluetooth off, screen on
onExit:
## Behavior
### events that increase CPU activity
@@ -56,9 +60,11 @@ From lower to higher power consumption.
- 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)
- while in LS/NB/DARK: if SERIAL_CONNECTED, go to serial
- while in any state: if we have AC power, go to POWER
### events that decrease cpu activity
- While in POWER: if lose AC go to ON
- While in SERIAL: if SERIAL_DISCONNECTED, go to NB
- 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

View File

@@ -5,5 +5,5 @@ This is a mini design doc for developing the meshtastic software.
* 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...)
* [Device API](device-api.md) and porting guide for new clients (iOS, python, etc...)
* TODO: how to port the device code to a new device.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

69
nrf52/ttgo_eink_qpsi.ini Normal file
View File

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

View File

@@ -9,7 +9,8 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam ; Note: the github actions CI test build can't yet build NRF52 targets
default_envs = tbeam # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
;default_envs = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
[common]
; common is not currently used
@@ -23,24 +24,21 @@ default_envs = tbeam ; Note: the github actions CI test build can't yet build NR
[env]
framework = arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
; note: we add src to our include search path so that lmic_project_config can override
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Os -Wl,-Map,.pio/build/output.map
-DAXP_DEBUG_PORT=Serial
build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map
-DHW_VERSION_${sysenv.COUNTRY}
-DAPP_VERSION=${sysenv.APP_VERSION}
-DHW_VERSION=${sysenv.HW_VERSION}
-DUSE_THREAD_NAMES
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
;upload_port = /dev/cu.SLAB_USBtoUART
;monitor_port = /dev/cu.SLAB_USBtoUART
; the default is esptool
; upload_protocol = esp-prog
@@ -61,30 +59,53 @@ debug_tool = jlink
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
SPI
1260 ; OneButton library for non-blocking button debounce
https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
Wire ; explicitly needed here because the AXP202 library forgets to add it
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c
https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
https://github.com/geeksville/ArduinoThread.git#333ffd09b596977c217ba25da4258f588b462ac6
; Common settings for conventional (non Portduino) Ardino targets
[arduino_base]
framework = arduino
lib_deps =
${env.lib_deps}
build_flags = ${env.build_flags} -Os
src_filter = ${env.src_filter} -<portduino/>
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
platform = espressif32
src_filter =
${env.src_filter} -<nrf52/>
${arduino_base.src_filter} -<nrf52/>
upload_speed = 921600
debug_init_break = tbreak setup
build_flags =
${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11
${arduino_base.build_flags} -Wall -Wextra -Isrc/esp32 -Isrc/esp32-mfix-esp32-psram-cache-issue -lnimble -std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-DAXP_DEBUG_PORT=Serial
lib_deps =
${arduino_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore = segger_rtt
platform_packages =
framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#1adba3f11ca8406ac0a704d151697b572058b53d
framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#2814f110aa618429bdd9a0a2d6a93c55f29f87a6
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
; 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
@@ -93,13 +114,12 @@ platform_packages =
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; The 1.0 release of the TBEAM board
; 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
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
@@ -142,25 +162,26 @@ build_flags =
platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x
board = cubecell_board_plus
; FIXME, bug in cubecell arduino - they are supposed to set ARDUINO
build_flags = ${env.build_flags} -DARDUINO=100 -Isrc/cubecell
build_flags = ${arduino_base.build_flags} -DARDUINO=100 -Isrc/cubecell
src_filter =
${env.src_filter} -<esp32/> -<nrf52/>
${arduino_base.src_filter} -<esp32/> -<nrf52/>
; Common settings for NRF52 based targets
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
; platform = nordicnrf52
platform = https://github.com/meshtastic/platform-nordicnrf52.git#62d185fe61b6c84c554046106529b4fd8f155e2c
platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63
extends = arduino_base
debug_tool = jlink
build_type = debug ; I'm debugging with ICE a lot now
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
build_flags =
${env.build_flags} -Wno-unused-variable
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
;-DCFG_DEBUG=3
src_filter =
${env.src_filter} -<esp32/> -<nimble/>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<meshwifi/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
@@ -186,6 +207,9 @@ board = nrf52840_dk
[env:nrf52840dk-geeksville]
extends = nrf52_base
board = nrf52840_dk_modified
# add our variants files to the include and src paths
build_flags = ${nrf52_base.build_flags} -Ivariants/pca10056-rc-clock
src_filter = ${nrf52_base.src_filter} +<../variants/pca10056-rc-clock>
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:feather_nrf52832]
@@ -209,9 +233,82 @@ monitor_speed = 115200
extends = nrf52_base
board = ppr
lib_deps =
${env.lib_deps}
${arduino_base.lib_deps}
UC1701
; The PPR board
[env:ppr1]
extends = nrf52_base
board = ppr1
build_flags = ${nrf52_base.build_flags} -Ivariants/ppr1
src_filter = ${nrf52_base.src_filter} +<../variants/ppr1>
lib_deps =
${arduino_base.lib_deps}
; Prototype eink/nrf52840/sx1262 device
[env:eink]
extends = nrf52_base
board = eink
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/eink
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
src_filter = ${nrf52_base.src_filter} +<../variants/eink>
lib_deps =
${arduino_base.lib_deps}
https://github.com/geeksville/EPD_Libraries.git
TFT_eSPI
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
[env:lora-relay-v1]
extends = nrf52_base
board = lora-relay-v1
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v1
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v1>
lib_deps =
${arduino_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The https://github.com/BigCorvus/LoRa-BLE-Relay-v2 board by @BigCorvus
[env:lora-relay-v2]
extends = nrf52_base
board = lora-relay-v2
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/lora_relay_v2
-DUSER_SETUP_LOADED
-DTFT_WIDTH=80
-DTFT_HEIGHT=160
-DST7735_GREENTAB160x80
-DST7735_DRIVER
-DTFT_CS=ST7735_CS
-DTFT_DC=ST7735_RS
-DTFT_RST=ST7735_RESET
-DSPI_FREQUENCY=27000000
-DTFT_WR=ST7735_SDA
-DTFT_SCLK=ST7735_SCK
src_filter = ${nrf52_base.src_filter} +<../variants/lora_relay_v2>
lib_deps =
${arduino_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
; The Portduino based sim environment on top of linux
[env:linux]
platform = https://github.com/geeksville/platform-portduino.git
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<meshwifi/>
build_flags = ${arduino_base.build_flags} -O0
framework = arduino
board = linux_x86_64

2
proto

Submodule proto updated: 0523977d1f...a0b8d88896

3
release/.gitignore vendored
View File

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

View File

@@ -1,126 +1,98 @@
#pragma once
#include <Arduino.h>
#include "Status.h"
#include "configuration.h"
#include <Arduino.h>
namespace meshtastic {
namespace meshtastic
{
/// Describes the state of the GPS system.
class GPSStatus : public Status
/// Describes the state of the GPS system.
class GPSStatus : public Status
{
private:
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver =
CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
public:
GPSStatus() { statusType = STATUS_TYPE_GPS; }
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
uint32_t heading, uint32_t numSatellites)
: Status()
{
this->hasLock = hasLock;
this->isConnected = isConnected;
this->latitude = latitude;
this->longitude = longitude;
this->altitude = altitude;
this->dop = dop;
this->heading = heading;
this->numSatellites = numSatellites;
}
GPSStatus(const GPSStatus &);
GPSStatus &operator=(const GPSStatus &);
private:
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver = CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
void observe(Observable<const GPSStatus *> *source) { statusObserver.observe(source); }
bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
bool getHasLock() const { return hasLock; }
public:
bool getIsConnected() const { return isConnected; }
GPSStatus() {
statusType = STATUS_TYPE_GPS;
}
GPSStatus( bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop, uint32_t heading, uint32_t numSatellites ) : Status()
int32_t getLatitude() const { return latitude; }
int32_t getLongitude() const { return longitude; }
int32_t getAltitude() const { return altitude; }
uint32_t getDOP() const { return dop; }
uint32_t getHeading() const { return heading; }
uint32_t getNumSatellites() const { return numSatellites; }
bool matches(const GPSStatus *newStatus) const
{
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->latitude != latitude ||
newStatus->longitude != longitude || newStatus->altitude != altitude || newStatus->dop != dop ||
newStatus->heading != heading || newStatus->numSatellites != numSatellites);
}
int updateStatus(const GPSStatus *newStatus)
{
// Only update the status if values have actually changed
bool isDirty;
{
this->hasLock = hasLock;
this->isConnected = isConnected;
this->latitude = latitude;
this->longitude = longitude;
this->altitude = altitude;
this->dop = dop;
this->heading = heading;
this->numSatellites = numSatellites;
isDirty = matches(newStatus);
initialized = true;
hasLock = newStatus->hasLock;
isConnected = newStatus->isConnected;
latitude = newStatus->latitude;
longitude = newStatus->longitude;
altitude = newStatus->altitude;
dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
}
GPSStatus(const GPSStatus &);
GPSStatus &operator=(const GPSStatus &);
void observe(Observable<const GPSStatus *> *source)
{
statusObserver.observe(source);
if (isDirty) {
if (hasLock)
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7,
altitude, dop * 1e-2, heading * 1e-5, numSatellites);
else
DEBUG_MSG("No GPS lock\n");
onNewStatus.notifyObservers(this);
}
return 0;
}
};
bool getHasLock() const
{
return hasLock;
}
bool getIsConnected() const
{
return isConnected;
}
int32_t getLatitude() const
{
return latitude;
}
int32_t getLongitude() const
{
return longitude;
}
int32_t getAltitude() const
{
return altitude;
}
uint32_t getDOP() const
{
return dop;
}
uint32_t getHeading() const
{
return heading;
}
uint32_t getNumSatellites() const
{
return numSatellites;
}
bool matches(const GPSStatus *newStatus) const
{
return (
newStatus->hasLock != hasLock ||
newStatus->isConnected != isConnected ||
newStatus->latitude != latitude ||
newStatus->longitude != longitude ||
newStatus->altitude != altitude ||
newStatus->dop != dop ||
newStatus->heading != heading ||
newStatus->numSatellites != numSatellites
);
}
int updateStatus(const GPSStatus *newStatus) {
// Only update the status if values have actually changed
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
hasLock = newStatus->hasLock;
isConnected = newStatus->isConnected;
latitude = newStatus->latitude;
longitude = newStatus->longitude;
altitude = newStatus->altitude;
dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
}
if(isDirty) {
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5, numSatellites);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
}
} // namespace meshtastic
extern meshtastic::GPSStatus *gpsStatus;

View File

@@ -1,27 +1,137 @@
#include "power.h"
#include "PowerFSM.h"
#include "main.h"
#include "utils.h"
#include "sleep.h"
#ifdef TBEAM_V10
#include "utils.h"
// FIXME. nasty hack cleanup how we load axp192
#undef AXP192_SLAVE_ADDRESS
#include "axp20x.h"
#ifdef TBEAM_V10
AXP20X_Class axp;
#endif
bool pmu_irq = false;
Power *power;
bool Power::setup()
using namespace meshtastic;
#if defined(NRF52_SERIES)
/*
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
*
* External Reference is VDD/4, with an adjustable gain of 1, 2 or 4, meaning
* VDD/4, VDD/2 or VDD for the ADC levels.
*
* Default settings are internal reference with 1/6 gain (GND..3.6V ADC range)
*/
#define AREF_VOLTAGE 3.6
#else
#define AREF_VOLTAGE 3.3
#endif
/**
* If this board has a battery level sensor, set this to a valid implementation
*/
static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level sensor
/**
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
*/
class AnalogBatteryLevel : public HasBatteryLevel
{
/**
* Battery state of charge, from 0 to 100 or -1 for unknown
*
* FIXME - use a lipo lookup table, the current % full is super wrong
*/
virtual int getBattPercentage()
{
float v = getBattVoltage() / 1000;
axp192Init();
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
setPeriod(1);
if (v < noBatVolt)
return -1; // If voltage is super low assume no battery installed
return axp192_found;
if (v > chargingVolt)
return 0; // While charging we can't report % full on the battery
return 100 * (v - emptyVolt) / (fullVolt - emptyVolt);
}
/**
* The raw voltage of the batteryin millivolts or NAN if unknown
*/
virtual float getBattVoltage()
{
// Tested ttgo eink nrf52 board and the reported value is perfect
// DEBUG_MSG("raw val %u", raw);
return
#ifdef BATTERY_PIN
1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN);
#else
NAN;
#endif
}
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() { return getBattPercentage() != -1; }
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
/// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'?
virtual bool isChargeing() { return isBatteryConnect() && isVBUSPlug(); }
private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
const float fullVolt = 4.2, emptyVolt = 3.27, chargingVolt = 4.3, noBatVolt = 2.1;
} analogLevel;
Power::Power() : OSThread("Power") {}
bool Power::analogInit()
{
#ifdef BATTERY_PIN
DEBUG_MSG("Using analog input for battery level\n");
// disable any internal pullups
pinMode(BATTERY_PIN, INPUT);
#ifndef NO_ESP32
// ESP32 needs special analog stuff
adcAttachPin(BATTERY_PIN);
#endif
#ifdef NRF52_SERIES
analogReference(AR_INTERNAL); // 3.6V
#endif
// adcStart(BATTERY_PIN);
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
batteryLevel = &analogLevel;
return true;
#else
return false;
#endif
}
bool Power::setup()
{
bool found = axp192Init();
if (!found) {
found = analogInit();
}
enabled = found;
return found;
}
/// Reads power status to powerStatus singleton.
@@ -29,42 +139,86 @@ bool Power::setup()
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
void Power::readPowerStatus()
{
bool hasBattery = axp.isBatteryConnect();
int batteryVoltageMv = 0;
uint8_t batteryChargePercent = 0;
if (hasBattery) {
batteryVoltageMv = axp.getBattVoltage();
// If the AXP192 returns a valid battery percentage, use it
if (axp.getBattPercentage() >= 0) {
batteryChargePercent = axp.getBattPercentage();
} else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in power.h
batteryChargePercent = clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100);
if (batteryLevel) {
bool hasBattery = batteryLevel->isBatteryConnect();
int batteryVoltageMv = 0;
int8_t batteryChargePercent = 0;
if (hasBattery) {
batteryVoltageMv = batteryLevel->getBattVoltage();
// If the AXP192 returns a valid battery percentage, use it
if (batteryLevel->getBattPercentage() >= 0) {
batteryChargePercent = batteryLevel->getBattPercentage();
} else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in
// power.h
batteryChargePercent =
clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)),
0, 100);
}
}
// Notify any status instances that are observing us
const PowerStatus powerStatus =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus.getHasUSB(),
powerStatus.getIsCharging(), powerStatus.getBatteryVoltageMv(), powerStatus.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
} else {
// No power sensing on this board - tell everyone else we have no idea what is happening
const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1);
newStatus.notifyObservers(&powerStatus);
}
// Notify any status instances that are observing us
const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(hasBattery, axp.isVBUSPlug(), axp.isChargeing(), batteryVoltageMv, batteryChargePercent);
newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() &&
axp.getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
}
void Power::doTask()
int32_t Power::runOnce()
{
readPowerStatus();
// Only read once every 20 seconds once the power status for the app has been initialized
if(statusHandler && statusHandler->isInitialized())
setPeriod(1000 * 20);
}
#endif // TBEAM_V10
#ifdef AXP192_SLAVE_ADDRESS
#ifdef TBEAM_V10
// WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll
// the IRQ status by reading the registers over I2C
axp.readIRQ();
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
/*
Other things we could check if we cared...
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n");
}
if (axp.isBattRemoveIRQ()) {
DEBUG_MSG("Battery removed\n");
}
if (axp.isPEKShortPressIRQ()) {
DEBUG_MSG("PEK short button press\n");
}
*/
axp.clearIRQ();
#endif
// Only read once every 20 seconds once the power status for the app has been initialized
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
}
/**
* Init the power manager chip
*
@@ -74,10 +228,13 @@ void Power::doTask()
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*/
void Power::axp192Init()
bool Power::axp192Init()
{
#ifdef TBEAM_V10
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
batteryLevel = &axp;
DEBUG_MSG("AXP192 Begin PASS\n");
// axp.setChgLEDMode(LED_BLINK_4HZ);
@@ -90,7 +247,7 @@ void Power::axp192Init()
DEBUG_MSG("----------------------------------------\n");
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power
// axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power - now turned on in setGpsPower
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
@@ -122,9 +279,11 @@ void Power::axp192Init()
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
axp.enableIRQ(AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | AXP202_CHARGING_FINISHED_IRQ | AXP202_CHARGING_IRQ |
AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
1);
// we do not look for AXP202_CHARGING_FINISHED_IRQ & AXP202_CHARGING_IRQ because it occurs repeatedly while there is
// no battery also it could cause inadvertent waking from light sleep just because the battery filled
// we don't look for AXP202_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
// we don't look at AXP202_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
axp.enableIRQ(AXP202_BATT_CONNECT_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ, 1);
axp.clearIRQ();
#endif
@@ -135,45 +294,9 @@ void Power::axp192Init()
} else {
DEBUG_MSG("AXP192 not found\n");
}
}
return axp192_found;
#else
return false;
#endif
void Power::loop()
{
#ifdef PMU_IRQ
if (pmu_irq) {
pmu_irq = false;
axp.readIRQ();
DEBUG_MSG("pmu irq!\n");
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
}
if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n");
}
if (axp.isBattRemoveIRQ()) {
DEBUG_MSG("Battery removed\n");
}
if (axp.isPEKShortPressIRQ()) {
DEBUG_MSG("PEK short button press\n");
}
readPowerStatus();
axp.clearIRQ();
}
#endif // T_BEAM_V10
}

View File

@@ -4,25 +4,15 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
#include "main.h"
#include "graphics/Screen.h"
#include "main.h"
#include "sleep.h"
#include "target_specific.h"
#include "timing.h"
static void sdsEnter()
{
/*
// Don't deepsleep if we have USB power or if the user as pressed a button recently
// !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME
if (timing::millis() - lastPressMs > radioConfig.preferences.mesh_sds_timeout_secs)
{
doDeepSleep(radioConfig.preferences.sds_secs);
}
*/
doDeepSleep(radioConfig.preferences.sds_secs * 1000LL);
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(getPref_sds_secs() * 1000LL);
}
#include "error.h"
@@ -31,8 +21,8 @@ static uint32_t secsSlept;
static void lsEnter()
{
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
screen.setOn(false);
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", getPref_ls_secs());
screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time
DEBUG_MSG("lsEnter end\n");
@@ -40,13 +30,13 @@ static void lsEnter()
static void lsIdle()
{
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
// DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
#ifndef NO_ESP32
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
// Do we have more sleeping to do?
if (secsSlept < radioConfig.preferences.ls_secs) {
if (secsSlept < getPref_ls_secs()) {
// Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30;
@@ -55,7 +45,8 @@ static void lsIdle()
setLed(false); // Never leave led on while in light sleep
wakeCause = doLightSleep(sleepTime * 1000LL);
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
switch (wakeCause) {
case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
setLed(true); // briefly turn on led
@@ -63,12 +54,15 @@ static void lsIdle()
secsSlept += sleepTime;
// DEBUG_MSG("sleeping, flash led!\n");
}
if (wakeCause == ESP_SLEEP_WAKEUP_UART) {
break;
case ESP_SLEEP_WAKEUP_UART:
// Not currently used (because uart triggers in hw have problems)
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
} else {
// We woke for some other reason (button press, uart, device interrupt)
break;
default:
// We woke for some other reason (button press, device interrupt)
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
DEBUG_MSG("wakeCause %d\n", wakeCause);
@@ -82,8 +76,10 @@ static void lsIdle()
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
// we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
}
break;
}
} else {
// Someone says we can't sleep now, so just save some power by sleeping the CPU for 100ms or so
@@ -101,12 +97,12 @@ static void lsIdle()
static void lsExit()
{
// setGPSPower(true); // restore GPS power
gps->startLock();
gps->forceWake(true);
}
static void nbEnter()
{
screen.setOn(false);
screen->setOn(false);
setBluetoothEnable(false);
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
@@ -115,36 +111,50 @@ static void nbEnter()
static void darkEnter()
{
setBluetoothEnable(true);
screen.setOn(false);
screen->setOn(false);
}
static void serialEnter()
{
setBluetoothEnable(false);
screen.setOn(true);
screen->setOn(true);
screen->print("Using API...\n");
}
static void powerEnter()
{
screen->setOn(true);
setBluetoothEnable(true);
screen->print("Powered...\n");
}
static void powerExit()
{
screen->setOn(true);
setBluetoothEnable(true);
screen->print("Unpowered...\n");
}
static void onEnter()
{
screen.setOn(true);
screen->setOn(true);
setBluetoothEnable(true);
static uint32_t lastPingMs;
uint32_t now = timing::millis();
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 screenPress()
{
screen.onPress();
screen->onPress();
}
static void bootEnter() {}
@@ -156,16 +166,25 @@ State stateDARK(darkEnter, NULL, NULL, "DARK");
State stateSERIAL(serialEnter, NULL, NULL, "SERIAL");
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
State stateON(onEnter, NULL, NULL, "ON");
State statePOWER(powerEnter, NULL, powerExit, "POWER");
Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout");
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
// We assume routers might be powered all the time, but from a low current (solar) source
bool isLowPower = radioConfig.preferences.is_low_power;
bool hasPower = !isLowPower && powerStatus && powerStatus->getHasUSB();
bool isRouter = radioConfig.preferences.is_router;
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
// wake timer expired or a packet arrived
// if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "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 powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
// Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB or dark and
// then it 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");
@@ -173,7 +192,10 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateLS, &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(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
@@ -186,42 +208,61 @@ void PowerFSM_setup()
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(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
// if we are a router we don't turn the screen on for these things
if (!isRouter) {
// show the latest node when we get a new node db update
powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
// Show the received text message
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
}
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
if (!isLowPower) {
powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
}
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect");
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
powerFSM.add_timed_transition(&stateON, &stateDARK, radioConfig.preferences.screen_on_secs * 1000, NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout");
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
#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");
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL,
"Bluetooth timeout");
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
#else
lowPowerState = &stateDARK;
#endif
powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL,
"mesh timeout");
auto meshSds = getPref_mesh_sds_timeout_secs();
if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, meshSds * 1000, NULL, "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
// powerFSM.add_timed_transition(lowPowerState, &stateSDS, getPref_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

View File

@@ -13,10 +13,13 @@
#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_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep
#define EVENT_SERIAL_CONNECTED 11
#define EVENT_SERIAL_DISCONNECTED 12
#define EVENT_POWER_CONNECTED 13
#define EVENT_POWER_DISCONNECTED 14
extern Fsm powerFSM;
extern State statePOWER, stateSERIAL;
void PowerFSM_setup();

View File

@@ -1,103 +1,94 @@
#pragma once
#include <Arduino.h>
#include "Status.h"
#include "configuration.h"
#include <Arduino.h>
namespace meshtastic {
namespace meshtastic
{
/// Describes the state of the GPS system.
class PowerStatus : public Status
/**
* A boolean where we have a third state of Unknown
*/
enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 };
/// Describes the state of the GPS system.
class PowerStatus : public Status
{
private:
CallbackObserver<PowerStatus, const PowerStatus *> statusObserver =
CallbackObserver<PowerStatus, const PowerStatus *>(this, &PowerStatus::updateStatus);
/// Whether we have a battery connected
OptionalBool hasBattery = OptUnknown;
/// Battery voltage in mV, valid if haveBattery is true
int batteryVoltageMv = 0;
/// Battery charge percentage, either read directly or estimated
int8_t batteryChargePercent = 0;
/// Whether USB is connected
OptionalBool hasUSB = OptUnknown;
/// Whether we are charging the battery
OptionalBool isCharging = OptUnknown;
public:
PowerStatus() { statusType = STATUS_TYPE_POWER; }
PowerStatus(OptionalBool hasBattery, OptionalBool hasUSB, OptionalBool isCharging, int batteryVoltageMv = -1,
int8_t batteryChargePercent = 0)
: Status()
{
this->hasBattery = hasBattery;
this->hasUSB = hasUSB;
this->isCharging = isCharging;
this->batteryVoltageMv = batteryVoltageMv;
this->batteryChargePercent = batteryChargePercent;
}
PowerStatus(const PowerStatus &);
PowerStatus &operator=(const PowerStatus &);
private:
CallbackObserver<PowerStatus, const PowerStatus *> statusObserver = CallbackObserver<PowerStatus, const PowerStatus *>(this, &PowerStatus::updateStatus);
void observe(Observable<const PowerStatus *> *source) { statusObserver.observe(source); }
/// Whether we have a battery connected
bool hasBattery;
/// Battery voltage in mV, valid if haveBattery is true
int batteryVoltageMv;
/// Battery charge percentage, either read directly or estimated
uint8_t batteryChargePercent;
/// Whether USB is connected
bool hasUSB;
/// Whether we are charging the battery
bool isCharging;
bool getHasBattery() const { return hasBattery == OptTrue; }
public:
bool getHasUSB() const { return hasUSB == OptTrue; }
PowerStatus() {
statusType = STATUS_TYPE_POWER;
}
PowerStatus( bool hasBattery, bool hasUSB, bool isCharging, int batteryVoltageMv, uint8_t batteryChargePercent ) : Status()
/// Can we even know if this board has USB power or not
bool knowsUSB() const { return hasUSB != OptUnknown; }
bool getIsCharging() const { return isCharging == OptTrue; }
int getBatteryVoltageMv() const { return batteryVoltageMv; }
/**
* Note: 0% battery means 'unknown/this board doesn't have a battery installed'
*/
uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 0; }
bool matches(const PowerStatus *newStatus) const
{
return (newStatus->getHasBattery() != hasBattery || newStatus->getHasUSB() != hasUSB ||
newStatus->getBatteryVoltageMv() != batteryVoltageMv);
}
int updateStatus(const PowerStatus *newStatus)
{
// Only update the status if values have actually changed
bool isDirty;
{
this->hasBattery = hasBattery;
this->hasUSB = hasUSB;
this->isCharging = isCharging;
this->batteryVoltageMv = batteryVoltageMv;
this->batteryChargePercent = batteryChargePercent;
isDirty = matches(newStatus);
initialized = true;
hasBattery = newStatus->hasBattery;
batteryVoltageMv = newStatus->getBatteryVoltageMv();
batteryChargePercent = newStatus->getBatteryChargePercent();
hasUSB = newStatus->hasUSB;
isCharging = newStatus->isCharging;
}
PowerStatus(const PowerStatus &);
PowerStatus &operator=(const PowerStatus &);
void observe(Observable<const PowerStatus *> *source)
{
statusObserver.observe(source);
if (isDirty) {
// DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
bool getHasBattery() const
{
return hasBattery;
}
bool getHasUSB() const
{
return hasUSB;
}
bool getIsCharging() const
{
return isCharging;
}
int getBatteryVoltageMv() const
{
return batteryVoltageMv;
}
uint8_t getBatteryChargePercent() const
{
return batteryChargePercent;
}
bool matches(const PowerStatus *newStatus) const
{
return (
newStatus->getHasBattery() != hasBattery ||
newStatus->getHasUSB() != hasUSB ||
newStatus->getBatteryVoltageMv() != batteryVoltageMv
);
}
int updateStatus(const PowerStatus *newStatus) {
// Only update the status if values have actually changed
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
hasBattery = newStatus->getHasBattery();
batteryVoltageMv = newStatus->getBatteryVoltageMv();
batteryChargePercent = newStatus->getBatteryChargePercent();
hasUSB = newStatus->getHasUSB();
isCharging = newStatus->getIsCharging();
}
if(isDirty) {
DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
}
} // namespace meshtastic
extern meshtastic::PowerStatus *powerStatus;

11
src/SPILock.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "SPILock.h"
#include <Arduino.h>
#include <assert.h>
concurrency::Lock *spiLock;
void initSPI()
{
assert(!spiLock);
spiLock = new concurrency::Lock();
}

12
src/SPILock.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "../concurrency/LockGuard.h"
/**
* Used to provide mutual exclusion for access to the SPI bus. Usage:
* concurrency::LockGuard g(spiLock);
*/
extern concurrency::Lock *spiLock;
/** Setup SPI access and create the spiLock lock. */
void initSPI();

View File

@@ -40,6 +40,8 @@ void SerialConsole::onConnectionChanged(bool connected)
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
} else {
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
// received a packet in a while
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
}
}

View File

@@ -20,7 +20,7 @@ namespace meshtastic
CallbackObserver<Status, const Status *> statusObserver = CallbackObserver<Status, const Status *>(this, &Status::updateStatus);
bool initialized = false;
// Workaround for no typeid support
int statusType;
int statusType = 0;
public:
// Allows us to generate observable events

View File

@@ -0,0 +1,39 @@
#include "concurrency/BinarySemaphoreFreeRTOS.h"
#include "configuration.h"
#ifdef HAS_FREE_RTOS
namespace concurrency
{
BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS()
{
semaphore = xSemaphoreCreateBinary();
}
BinarySemaphoreFreeRTOS::~BinarySemaphoreFreeRTOS()
{
vSemaphoreDelete(semaphore);
}
/**
* Returns false if we were interrupted
*/
bool BinarySemaphoreFreeRTOS::take(uint32_t msec)
{
return xSemaphoreTake(semaphore, pdMS_TO_TICKS(msec));
}
void BinarySemaphoreFreeRTOS::give()
{
xSemaphoreGive(semaphore);
}
IRAM_ATTR void BinarySemaphoreFreeRTOS::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken)
{
xSemaphoreGiveFromISR(semaphore, pxHigherPriorityTaskWoken);
}
} // namespace concurrency
#endif

View File

@@ -0,0 +1,31 @@
#pragma once
#include "configuration.h"
#include "../freertosinc.h"
namespace concurrency
{
#ifdef HAS_FREE_RTOS
class BinarySemaphoreFreeRTOS
{
SemaphoreHandle_t semaphore;
public:
BinarySemaphoreFreeRTOS();
~BinarySemaphoreFreeRTOS();
/**
* Returns false if we timed out
*/
bool take(uint32_t msec);
void give();
void giveFromISR(BaseType_t *pxHigherPriorityTaskWoken);
};
#endif
}

View File

@@ -0,0 +1,36 @@
#include "concurrency/BinarySemaphorePosix.h"
#include "configuration.h"
#ifndef HAS_FREE_RTOS
namespace concurrency
{
BinarySemaphorePosix::BinarySemaphorePosix()
{
}
BinarySemaphorePosix::~BinarySemaphorePosix()
{
}
/**
* Returns false if we timed out
*/
bool BinarySemaphorePosix::take(uint32_t msec)
{
delay(msec); // FIXME
return false;
}
void BinarySemaphorePosix::give()
{
}
IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken)
{
}
} // namespace concurrency
#endif

View File

@@ -0,0 +1,31 @@
#pragma once
#include "configuration.h"
#include "../freertosinc.h"
namespace concurrency
{
#ifndef HAS_FREE_RTOS
class BinarySemaphorePosix
{
// SemaphoreHandle_t semaphore;
public:
BinarySemaphorePosix();
~BinarySemaphorePosix();
/**
* Returns false if we timed out
*/
bool take(uint32_t msec);
void give();
void giveFromISR(BaseType_t *pxHigherPriorityTaskWoken);
};
#endif
}

View File

@@ -0,0 +1,35 @@
#include "concurrency/InterruptableDelay.h"
#include "configuration.h"
namespace concurrency
{
InterruptableDelay::InterruptableDelay() {}
InterruptableDelay::~InterruptableDelay() {}
/**
* Returns false if we were interrupted
*/
bool InterruptableDelay::delay(uint32_t msec)
{
// DEBUG_MSG("delay %u ", msec);
// sem take will return false if we timed out (i.e. were not interrupted)
bool r = semaphore.take(msec);
// DEBUG_MSG("interrupt=%d\n", r);
return !r;
}
void InterruptableDelay::interrupt()
{
semaphore.give();
}
IRAM_ATTR void InterruptableDelay::interruptFromISR(BaseType_t *pxHigherPriorityTaskWoken)
{
semaphore.giveFromISR(pxHigherPriorityTaskWoken);
}
} // namespace concurrency

View File

@@ -0,0 +1,42 @@
#pragma once
#include "../freertosinc.h"
#ifdef HAS_FREE_RTOS
#include "concurrency/BinarySemaphoreFreeRTOS.h"
#define BinarySemaphore BinarySemaphoreFreeRTOS
#else
#include "concurrency/BinarySemaphorePosix.h"
#define BinarySemaphore BinarySemaphorePosix
#endif
namespace concurrency
{
/**
* An object that provides delay(msec) like functionality, but can be interrupted by calling interrupt().
*
* Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event.
*
* This is implmented for FreeRTOS but should be easy to port to other operating systems.
*/
class InterruptableDelay
{
BinarySemaphore semaphore;
public:
InterruptableDelay();
~InterruptableDelay();
/**
* Returns false if we were interrupted
*/
bool delay(uint32_t msec);
void interrupt();
void interruptFromISR(BaseType_t *pxHigherPriorityTaskWoken);
};
} // namespace concurrency

View File

@@ -1,8 +1,10 @@
#include "Lock.h"
#include <cassert>
namespace concurrency {
namespace concurrency
{
#ifdef HAS_FREE_RTOS
Lock::Lock()
{
handle = xSemaphoreCreateBinary();
@@ -19,5 +21,12 @@ void Lock::unlock()
{
assert(xSemaphoreGive(handle));
}
#else
Lock::Lock() {}
void Lock::lock() {}
void Lock::unlock() {}
#endif
} // namespace concurrency

View File

@@ -2,7 +2,8 @@
#include "../freertosinc.h"
namespace concurrency {
namespace concurrency
{
/**
* @brief Simple wrapper around FreeRTOS API for implementing a mutex lock
@@ -26,8 +27,9 @@ class Lock
void unlock();
private:
#ifdef HAS_FREE_RTOS
SemaphoreHandle_t handle;
#endif
};
} // namespace concurrency

View File

@@ -1,19 +1,85 @@
#include "NotifiedWorkerThread.h"
#include "configuration.h"
#include <assert.h>
namespace concurrency {
namespace concurrency
{
static bool debugNotification;
/**
* Notify this thread so it can run
*/
void NotifiedWorkerThread::notify(uint32_t v, eNotifyAction action)
bool NotifiedWorkerThread::notify(uint32_t v, bool overwrite)
{
xTaskNotify(taskHandle, v, action);
bool r = notifyCommon(v, overwrite);
if (r)
mainDelay.interrupt();
return r;
}
void NotifiedWorkerThread::block()
/**
* Notify this thread so it can run
*/
IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
{
xTaskNotifyWait(0, // don't clear notification on entry
clearOnRead, &notification, portMAX_DELAY); // Wait forever
if (overwrite || notification == 0) {
enabled = true;
setInterval(0); // Run ASAP
notification = v;
if (debugNotification)
DEBUG_MSG("setting notification %d\n", v);
return true;
} else {
if (debugNotification)
DEBUG_MSG("dropping notification %d\n", v);
return false;
}
}
} // namespace concurrency
/**
* Notify from an ISR
*
* This must be inline or IRAM_ATTR on ESP32
*/
IRAM_ATTR bool NotifiedWorkerThread::notifyFromISR(BaseType_t *highPriWoken, uint32_t v, bool overwrite)
{
bool r = notifyCommon(v, overwrite);
if (r)
mainDelay.interruptFromISR(highPriWoken);
return r;
}
/**
* Schedule a notification to fire in delay msecs
*/
bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrite)
{
bool didIt = notify(v, overwrite);
if (didIt) { // If we didn't already have something queued, override the delay to be larger
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
if (debugNotification)
DEBUG_MSG("delaying notification %u\n", delay);
}
return didIt;
}
int32_t NotifiedWorkerThread::runOnce()
{
auto n = notification;
enabled = false; // Only run once per notification
notification = 0; // clear notification
if (n) {
onNotify(n);
}
return RUN_SAME;
}
} // namespace concurrency

View File

@@ -1,47 +1,50 @@
#pragma once
#include "WorkerThread.h"
#include "OSThread.h"
namespace concurrency {
namespace concurrency
{
/**
* @brief A worker thread that waits on a freertos notification
*/
class NotifiedWorkerThread : public WorkerThread
class NotifiedWorkerThread : public OSThread
{
/**
* The notification that was most recently used to wake the thread. Read from runOnce()
*/
uint32_t notification = 0;
public:
NotifiedWorkerThread(const char *name) : OSThread(name) {}
/**
* Notify this thread so it can run
*/
void notify(uint32_t v = 0, eNotifyAction action = eNoAction);
bool notify(uint32_t v, bool overwrite);
/**
* 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);
}
bool notifyFromISR(BaseType_t *highPriWoken, uint32_t v, bool overwrite);
/**
* Schedule a notification to fire in delay msecs
*/
bool notifyLater(uint32_t delay, uint32_t v, bool overwrite);
protected:
/**
* The notification that was most recently used to wake the thread. Read from loop()
*/
uint32_t notification = 0;
virtual void onNotify(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;
virtual int32_t runOnce();
private:
/**
* A method that should block execution - either waiting ona queue/mutex or a "task notification"
* Notify this thread so it can run
*/
virtual void block();
bool notifyCommon(uint32_t v, bool overwrite);
};
} // namespace concurrency

View File

@@ -0,0 +1,79 @@
#include "OSThread.h"
#include "configuration.h"
#include <assert.h>
namespace concurrency
{
/// Show debugging info for disabled threads
bool OSThread::showDisabled;
/// Show debugging info for threads when we run them
bool OSThread::showRun = false;
/// Show debugging info for threads we decide not to run;
bool OSThread::showWaiting = false;
ThreadController mainController, timerController;
InterruptableDelay mainDelay;
void OSThread::setup()
{
mainController.ThreadName = "mainController";
timerController.ThreadName = "timerController";
}
OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_controller)
: Thread(NULL, period), controller(_controller)
{
ThreadName = _name;
if (controller)
controller->add(this);
}
OSThread::~OSThread()
{
if (controller)
controller->remove(this);
}
/**
* Wait a specified number msecs starting from the current time (rather than the last time we were run)
*/
void OSThread::setIntervalFromNow(unsigned long _interval)
{
// Save interval
interval = _interval;
// Cache the next run based on the last_run
_cached_next_run = millis() + interval;
}
bool OSThread::shouldRun(unsigned long time)
{
bool r = Thread::shouldRun(time);
if (showRun && r)
DEBUG_MSG("Thread %s: run\n", ThreadName.c_str());
if (showWaiting && enabled && !r)
DEBUG_MSG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
if (showDisabled && !enabled)
DEBUG_MSG("Thread %s: disabled\n", ThreadName.c_str());
return r;
}
void OSThread::run()
{
auto newDelay = runOnce();
runned();
if (newDelay >= 0)
setInterval(newDelay);
}
} // namespace concurrency

View File

@@ -0,0 +1,70 @@
#pragma once
#include <cstdlib>
#include <stdint.h>
#include "Thread.h"
#include "ThreadController.h"
#include "concurrency/InterruptableDelay.h"
namespace concurrency
{
extern ThreadController mainController, timerController;
extern InterruptableDelay mainDelay;
#define RUN_SAME -1
/**
* @brief Base threading
*
* This is a pseudo threading layer that is super easy to port, well suited to our slow network and very ram & power efficient.
*
* TODO FIXME @geeksville
*
* move more things into OSThreads
* remove lock/lockguard
*
* move typedQueue into concurrency
* remove freertos from typedqueue
*/
class OSThread : public Thread
{
ThreadController *controller;
/// Show debugging info for disabled threads
static bool showDisabled;
/// Show debugging info for threads when we run them
static bool showRun;
/// Show debugging info for threads we decide not to run;
static bool showWaiting;
public:
OSThread(const char *name, uint32_t period = 0, ThreadController *controller = &mainController);
virtual ~OSThread();
virtual bool shouldRun(unsigned long time);
static void setup();
/**
* Wait a specified number msecs starting from the current time (rather than the last time we were run)
*/
void setIntervalFromNow(unsigned long _interval);
protected:
/**
* The method that will be called each time our thread gets a chance to run
*
* Returns desired period for next invocation (or RUN_SAME for no change)
*/
virtual int32_t runOnce() = 0;
// Do not override this
virtual void run();
};
} // namespace concurrency

View File

@@ -1,26 +1,24 @@
#pragma once
#include "PeriodicTask.h"
#include "concurrency/OSThread.h"
namespace concurrency {
namespace concurrency
{
/**
* @brief Periodically invoke a callback. This just provides C-style callback conventions
* @brief Periodically invoke a callback. This just provides C-style callback conventions
* rather than a virtual function - FIXME, remove?
*/
class Periodic : public PeriodicTask
class Periodic : public OSThread
{
uint32_t (*callback)();
int32_t (*callback)();
public:
// 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(const char *name, int32_t (*_callback)()) : OSThread(name), callback(_callback) {}
protected:
void doTask() {
uint32_t p = callback();
setPeriod(p);
}
int32_t runOnce() { return callback(); }
};
} // namespace concurrency

View File

@@ -1,35 +0,0 @@
#include "PeriodicScheduler.h"
#include "PeriodicTask.h"
#include "LockGuard.h"
#include "../timing.h"
namespace concurrency {
/// call this from loop
void PeriodicScheduler::loop()
{
LockGuard lg(&lock);
uint32_t now = timing::millis();
for (auto t : tasks) {
if (t->period && (now - t->lastMsec) >= t->period) {
t->doTask();
t->lastMsec = now;
}
}
}
void PeriodicScheduler::schedule(PeriodicTask *t)
{
LockGuard lg(&lock);
tasks.insert(t);
}
void PeriodicScheduler::unschedule(PeriodicTask *t)
{
LockGuard lg(&lock);
tasks.erase(t);
}
} // namespace concurrency

View File

@@ -1,40 +0,0 @@
#pragma once
#include "Lock.h"
#include <cstdint>
#include <unordered_set>
namespace concurrency {
class PeriodicTask;
/**
* @brief 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.
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;
} // namespace concurrency

View File

@@ -1,16 +0,0 @@
#include "PeriodicTask.h"
#include "Periodic.h"
#include "LockGuard.h"
namespace concurrency {
PeriodicScheduler periodicScheduler;
PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) {}
void PeriodicTask::setup()
{
periodicScheduler.schedule(this);
}
} // namespace concurrency

View File

@@ -1,56 +0,0 @@
#pragma once
#include "PeriodicScheduler.h"
#include "timing.h"
namespace concurrency {
/**
* @brief A base class for tasks that want their doTask() method invoked periodically
*
* @todo 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
* something like this or triggered off of an irq.
*/
class PeriodicTask
{
friend class PeriodicScheduler;
uint32_t lastMsec = 0;
uint32_t period = 1; // call soon after creation
public:
virtual ~PeriodicTask() { periodicScheduler.unschedule(this); }
/**
* Constructor (will schedule with the global PeriodicScheduler)
*/
PeriodicTask(uint32_t initialPeriod = 1);
/**
* MUST be be called once at startup (but after threading is running - i.e. not from a constructor)
*/
void setup();
/**
* 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)
{
lastMsec = timing::millis(); // reset starting from now
period = p;
}
uint32_t getPeriod() const { return period; }
/**
* Syntatic sugar for suspending tasks
*/
void disable() { setPeriod(0); }
protected:
virtual void doTask() = 0;
};
} // namespace concurrency

View File

@@ -1,46 +0,0 @@
#include "Thread.h"
#include "timing.h"
#include <assert.h>
#ifdef ARDUINO_ARCH_ESP32
#include "esp_task_wdt.h"
#endif
namespace concurrency
{
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 Thread::serviceWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
esp_task_wdt_reset();
#endif
}
void Thread::startWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
auto r = esp_task_wdt_add(taskHandle);
assert(r == ESP_OK);
#endif
}
void Thread::stopWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
auto r = esp_task_wdt_delete(taskHandle);
assert(r == ESP_OK);
#endif
}
} // namespace concurrency

View File

@@ -1,47 +0,0 @@
#pragma once
#include "freertosinc.h"
namespace concurrency {
/**
* @brief Base threading
*/
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); }
uint32_t getStackHighwaterMark() { return uxTaskGetStackHighWaterMark(taskHandle); }
protected:
/**
* The method that will be called when start is called.
*/
virtual void doRun() = 0;
/**
* All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic.
*
* this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog()
*/
void serviceWatchdog();
void startWatchdog();
void stopWatchdog();
private:
static void callRun(void *_this);
};
} // namespace concurrency

View File

@@ -1,32 +0,0 @@
#include "WorkerThread.h"
#include "timing.h"
namespace concurrency {
void WorkerThread::doRun()
{
startWatchdog();
while (!wantExit) {
stopWatchdog();
block();
startWatchdog();
// no need - startWatchdog is guaranteed to give us one full watchdog interval
// serviceWatchdog(); // Let our loop worker have one full watchdog interval (at least) to run
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
if (timing::millis() - lastPrint > 10 * 1000L) {
lastPrint = timing::millis();
meshtastic::printThreadInfo("net");
}
#endif
loop();
}
stopWatchdog();
}
} // namespace concurrency

View File

@@ -1,29 +0,0 @@
#pragma once
#include "Thread.h"
namespace concurrency {
/**
* @brief This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting
* old-school arduino loop() code. Use as a mixin base class for the classes you want to convert.
*
* @link 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();
};
} // namespace concurrency

View File

@@ -55,24 +55,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
#define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
#ifdef NRF52_SERIES // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
// board specific
#ifdef PORTDUINO
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
#elif defined(NRF52_SERIES) // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
// board specific
//
// Standard definitions for NRF52 targets
//
// Nop definition for these attributes - not used on NRF52
#define EXT_RAM_ATTR
#define IRAM_ATTR
#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
// If the variant filed defines as standard button
@@ -80,6 +77,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN PIN_BUTTON1
#endif
#ifdef PIN_BUTTON2
#define BUTTON_PIN_ALT PIN_BUTTON2
#endif
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#elif defined(CubeCell_BoardPlus)
@@ -89,9 +90,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
// FIXME, not yet ready for NRF52
#define RTC_DATA_ATTR
#define LED_PIN -1 // FIXME totally bogus
#define BUTTON_PIN -1
@@ -101,6 +99,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Standard definitions for ESP32 targets
//
#define HAS_WIFI
#define GPS_SERIAL_NUM 1
#define GPS_RX_PIN 34
#ifdef USE_JTAG
@@ -123,11 +123,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
//
// Standard definitions for !ESP32 targets
//
#ifdef NO_ESP32
// Nop definition for these attributes - not used on NRF52
#define EXT_RAM_ATTR
#define IRAM_ATTR
#define RTC_DATA_ATTR
#endif
// -----------------------------------------------------------------------------
// OLED
// -----------------------------------------------------------------------------
#define SSD1306_ADDRESS 0x3C
#define ST7567_ADDRESS 0x3F
// The SH1106 controller is almost, but not quite, the same as SSD1306
// Define this if you know you have that controller or your "SSD1306" misbehaves.
@@ -135,10 +147,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// 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
#define SCREEN_FLIP_VERTICALLY
// DEBUG LED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
// Define if screen should be mirrored left to right
// #define SCREEN_MIRROR
// -----------------------------------------------------------------------------
// GPS
@@ -158,16 +170,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
#ifndef USE_JTAG
#define RF95_RESET 14
#define LED_INVERTED 1
#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262
#define USE_RF95
#define USE_SX1262
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // SX1262 IRQ
#define LORA_DIO2 32 // SX1262 BUSY
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
#ifdef USE_SX1262
#define SX1262_CS RF95_NSS // FIXME - we really should define LORA_CS instead
#define SX1262_DIO1 LORA_DIO1
#define SX1262_BUSY LORA_DIO2
#define SX1262_RESET LORA_RESET
#define SX1262_E22 // Not really an E22 but TTGO seems to be trying to clone that
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
// code)
#endif
#define RF95_IRQ 26
#define RF95_DIO1 33 // Note: not really used on this board
#define RF95_DIO2 32 // Note: not really used on this board
// Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
// and waking from light sleep
// #define PMU_IRQ 35
#define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07)
@@ -180,13 +209,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define I2C_SCL 22
#define BUTTON_PIN 39
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#ifndef USE_JTAG
#define RF95_RESET 23
#endif
#define RF95_IRQ 26
#define RF95_DIO1 33 // Note: not really used on this board
#define RF95_DIO2 32 // Note: not really used on this board
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
@@ -216,12 +245,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#ifndef USE_JTAG
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#define LORA_RESET 14
#endif
#define RF95_IRQ 26
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tlora-v1"
@@ -238,11 +269,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ 26 // IRQ line for the LORA radio
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
@@ -263,11 +296,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 BUTTON_NEED_PULLUP
#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
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#elif defined(TLORA_V2_1_16)
// This string must exactly match the case used in release file names or the android updater won't work
@@ -278,6 +313,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_RX_PIN 36
#define GPS_TX_PIN 39
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
@@ -288,11 +325,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN \
12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define BUTTON_NEED_PULLUP
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 14
#define LORA_DIO1 35 // Not really used
#define LORA_DIO2 34 // Not really used
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ 26 // IRQ line for the LORA radio
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#endif
#ifdef ARDUINO_NRF52840_PCA10056
@@ -312,6 +352,36 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board
#elif PORTDUINO
#define HW_VENDOR "portduino"
#define USE_SIM_RADIO
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
#define LORA_DIO1 33 // Not really used
#define LORA_DIO2 32 // Not really used
// Fake SPI device selections
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS 18
#endif
// DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on)
#endif
#ifdef USE_RF95
#define RF95_RESET LORA_RESET
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
#define RF95_DIO1 LORA_DIO1 // Note: not really used for RF95
#define RF95_DIO2 LORA_DIO2 // Note: not really used for RF95
#endif
// -----------------------------------------------------------------------------
@@ -337,8 +407,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
// nrf52 gets its settings via variant files
#ifndef PIN_SERIAL_RX
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
// use SEGGER for debug output
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
@@ -363,3 +434,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define GPS_POWER_CTRL_CH 3
#define LORA_POWER_CTRL_CH 2
// Default Bluetooth PIN
#define defaultBLEPin 123456

View File

@@ -1,7 +1,6 @@
#include <Arduino.h>
#include "../concurrency/LockGuard.h"
#include "../timing.h"
#include "BluetoothSoftwareUpdate.h"
#include "PowerFSM.h"
#include "RadioLibInterface.h"
@@ -31,6 +30,8 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
updateActualSize = 0;
crc.reset();
if (Update.isRunning())
Update.abort();
bool canBegin = Update.begin(updateExpectedSize);
DEBUG_MSG("Setting update size %u, result %d\n", updateExpectedSize, canBegin);
if (!canBegin) {
@@ -71,7 +72,7 @@ int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
crc.update(data, len);
Update.write(data, len);
updateActualSize += len;
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG); // Not exactly correct, but we want to force the device to not sleep now
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
return 0;
}
@@ -100,7 +101,7 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
} else {
if (Update.end()) {
DEBUG_MSG("OTA done, rebooting in 5 seconds!\n");
rebootAtMsec = timing::millis() + 5000;
rebootAtMsec = millis() + 5000;
} else {
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
}
@@ -126,7 +127,7 @@ int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl
void bluetoothRebootCheck()
{
if (rebootAtMsec && timing::millis() > rebootAtMsec) {
if (rebootAtMsec && millis() > rebootAtMsec) {
DEBUG_MSG("Rebooting for update\n");
ESP.restart();
}

View File

@@ -33,25 +33,36 @@ void WiFiServerAPI::loop()
if (client.connected()) {
StreamAPI::loop();
} else {
DEBUG_MSG("Client dropped connection, closing UDP server\n");
DEBUG_MSG("Client dropped connection, closing TCP server\n");
delete this;
}
}
#define MESHTASTIC_PORTNUM 4403
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM) {}
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::OSThread("ApiServer") {}
void WiFiServerPort::init()
{
DEBUG_MSG("Listening on TCP port %d\n", MESHTASTIC_PORTNUM);
DEBUG_MSG("API server sistening on TCP port %d\n", MESHTASTIC_PORTNUM);
begin();
}
void WiFiServerPort::loop()
int32_t WiFiServerPort::runOnce()
{
auto client = available();
if (client) {
new WiFiServerAPI(client);
// Close any previous connection (see FIXME in header file)
if (openAPI)
delete openAPI;
openAPI = new WiFiServerAPI(client);
}
if (openAPI) {
// Allow idle processing so the API can read from its incoming stream
openAPI->loop();
return 0; // run fast while our API server is running
} else
return 100; // only check occasionally for incoming connections
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "StreamAPI.h"
#include "concurrency/OSThread.h"
#include <WiFi.h>
/**
@@ -27,12 +28,19 @@ class WiFiServerAPI : public StreamAPI
/**
* Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed
*/
class WiFiServerPort : public WiFiServer
class WiFiServerPort : public WiFiServer, private concurrency::OSThread
{
/** The currently open port
*
* FIXME: We currently only allow one open TCP connection at a time, because we depend on the loop() call in this class to
* delegate to the worker. Once coroutines are implemented we can relax this restriction.
*/
WiFiServerAPI *openAPI = NULL;
public:
WiFiServerPort();
void init();
void loop();
int32_t runOnce();
};

View File

@@ -9,6 +9,7 @@
#include "utils.h"
#include <nvs.h>
#include <nvs_flash.h>
#include <driver/rtc_io.h>
void getMacAddr(uint8_t *dmac)
{
@@ -86,4 +87,58 @@ void esp32Loop()
// for debug printing
// radio.radioIf.canSleep();
}
void cpuDeepSleep(uint64_t msecToWake)
{
/*
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
If an external circuit drives this pin in deep sleep mode, current consumption may
increase due to current flowing through these pullups and pulldowns.
To isolate a pin, preventing extra current draw, call rtc_gpio_isolate() function.
For example, on ESP32-WROVER module, GPIO12 is pulled up externally.
GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep,
some current will flow through these external and internal resistors, increasing deep
sleep current above the minimal possible value.
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
*/
static const uint8_t rtcGpios[] = {/* 0, */ 2,
/* 4, */
#ifndef USE_JTAG
13,
/* 14, */ /* 15, */
#endif
/* 25, */ 26, /* 27, */
32, 33, 34, 35,
36, 37
/* 38, 39 */};
for (int i = 0; i < sizeof(rtcGpios); i++)
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
// to detect wake and in normal operation the external part drives them hard.
// We want RTC peripherals to stay on
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#ifdef BUTTON_PIN
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
uint64_t gpioMask = (1ULL << BUTTON_PIN);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif
// Not needed because both of the current boards have external pullups
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of
// just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
#endif
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
esp_deep_sleep_start(); // TBD mA sleep current (battery)
}

View File

@@ -3,22 +3,32 @@
// The FreeRTOS includes are in a different directory on ESP32 and I can't figure out how to make that work with platformio gcc
// options so this is my quick hack to make things work
#ifdef ARDUINO_ARCH_ESP32
#if defined(ARDUINO_ARCH_ESP32)
#define HAS_FREE_RTOS
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#else
// not yet supported on cubecell
#ifndef CubeCell_BoardPlus
#endif
#if defined(ARDUINO_NRF52_ADAFRUIT)
#define HAS_FREE_RTOS
#include <FreeRTOS.h>
#include <queue.h>
#include <semphr.h>
#include <task.h>
#endif
#ifdef HAS_FREE_RTOS
// Include real FreeRTOS defs above
#else
// Include placeholder fake FreeRTOS defs
#include <Arduino.h>
typedef uint32_t TickType_t;
@@ -26,5 +36,12 @@ typedef uint32_t BaseType_t;
#define portMAX_DELAY UINT32_MAX
#define tskIDLE_PRIORITY 0
#define configMAX_PRIORITIES 10 // Highest priority level
// Don't do anything on non free rtos platforms when done with the ISR
#define portYIELD_FROM_ISR(x)
enum eNotifyAction { eNoAction, eSetValueWithoutOverwrite, eSetValueWithOverwrite };
#endif
#endif

83
src/gps/Air530GPS.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include "Air530GPS.h"
#include <assert.h>
/*
Helpful translations from the Air530 GPS datasheet
Sat acquision mode
捕获电流值@3.3v 42.6 mA
sat tracking mode
跟踪电流值@3.3v 36.7 mA
Low power mode
低功耗模式@3.3V 0.85 mA
(发送指令:$PGKC051,0)
Super low power mode
超低功耗模式@3.3V 31 uA
(发送指令:$PGKC105,4)
To exit sleep use WAKE pin
Commands to enter sleep
6、Command: 105
进入周期性低功耗模式
Arguments:
Arg1: “0”,正常运行模式 (normal mode)
“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up)
“2”,周期低功耗模式 (periodic low power mode)
“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume)
“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port)
“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume)
(Arg 2 & 3 only valid if Arg1 is "1" or "2")
Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
ON time in msecs
Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
Sleep time in msecs
Example:
$PGKC105,8*3F<CR><LF>
This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a
new location. When we wake again in a minute we send a character to wake up.
*/
void Air530GPS::sendCommand(const char *cmd) {
uint8_t sum = 0;
// Skip the $
assert(cmd[0] == '$');
const char *p = cmd + 1;
while(*p)
sum ^= *p++;
assert(_serial_gps);
_serial_gps->write(cmd);
_serial_gps->printf("*%02x\r\n", sum);
// DEBUG_MSG("xsum %02x\n", sum);
}
void Air530GPS::sleep() {
NMEAGPS::sleep();
#ifdef PIN_GPS_WAKE
sendCommand("$PGKC105,4");
#endif
}
/// wake the GPS into normal operation mode
void Air530GPS::wake()
{
#if 1
NMEAGPS::wake();
#else
// For power testing - keep GPS sleeping forever
sleep();
#endif
}

22
src/gps/Air530GPS.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "NMEAGPS.h"
/**
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class Air530GPS : public NMEAGPS
{
protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
/// wake the GPS into normal operation mode
virtual void wake();
private:
/// Send a NMEA cmd with checksum
void sendCommand(const char *str);
};

View File

@@ -1,15 +1,16 @@
#include "GPS.h"
#include "NodeDB.h"
#include "RTC.h"
#include "configuration.h"
#include "timing.h"
#include "sleep.h"
#include <assert.h>
#include <time.h>
// If we have a serial GPS port it will not be null
#ifdef GPS_RX_PIN
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
HardwareSerial *GPS::_serial_gps = &_serial_gps_real;
#elif defined(NRF52840_XXAA)
#elif defined(NRF52840_XXAA) || defined(NRF52833_XXAA)
// Assume NRF52840
HardwareSerial *GPS::_serial_gps = &Serial1;
#else
@@ -22,67 +23,279 @@ uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
uint8_t GPS::i2cAddress = 0;
#endif
bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep
GPS *gps;
// stuff that really should be in in the instance instead...
static uint32_t
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
/// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once.
static bool didSerialInit;
void readFromRTC()
bool GPS::setupGPS()
{
struct timeval tv; /* btw settimeofday() is helpfull here too*/
if (!gettimeofday(&tv, NULL)) {
uint32_t now = timing::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 perhapsSetRTC(const struct timeval *tv)
{
if (!timeSetFromGPS) {
timeSetFromGPS = true;
DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec);
#ifndef NO_ESP32
settimeofday(tv, NULL);
if (_serial_gps && !didSerialInit) {
didSerialInit = true;
#ifdef GPS_RX_PIN
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#else
DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n");
_serial_gps->begin(GPS_BAUDRATE);
#endif
readFromRTC();
#ifndef NO_ESP32
_serial_gps->setRxBufferSize(2048); // the default is 256
#endif
}
return true;
}
bool GPS::setup()
{
// Master power for the GPS
#ifdef PIN_GPS_EN
digitalWrite(PIN_GPS_EN, PIN_GPS_EN);
pinMode(PIN_GPS_EN, OUTPUT);
#endif
#ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
pinMode(PIN_GPS_RESET, OUTPUT);
delay(10);
digitalWrite(PIN_GPS_RESET, 0);
#endif
setAwake(true); // Wake GPS power before doing any init
bool ok = setupGPS();
if (ok) {
notifySleepObserver.observe(&notifySleep);
notifyDeepSleepObserver.observe(&notifyDeepSleep);
}
return ok;
}
// Allow defining the polarity of the WAKE output. default is active high
#ifndef GPS_WAKE_ACTIVE
#define GPS_WAKE_ACTIVE 1
#endif
void GPS::wake()
{
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE);
pinMode(PIN_GPS_WAKE, OUTPUT);
#endif
}
void GPS::sleep() {
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE ? 0 : 1);
pinMode(PIN_GPS_WAKE, OUTPUT);
#endif
}
/// Record that we have a GPS
void GPS::setConnected()
{
if (!hasGPS) {
hasGPS = true;
shouldPublish = true;
}
}
void perhapsSetRTC(struct tm &t)
void GPS::setNumSatellites(uint8_t 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).
*/
time_t res = mktime(&t);
struct timeval tv;
tv.tv_sec = res;
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300)
DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
else
perhapsSetRTC(&tv);
if (n != numSatellites) {
numSatellites = n;
shouldPublish = true;
}
}
uint32_t getTime()
/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
* calls sleep/wake
*/
void GPS::setAwake(bool on)
{
return ((timing::millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
if (!wakeAllowed && on) {
DEBUG_MSG("Inhibiting because !wakeAllowed\n");
on = false;
}
if (isAwake != on) {
DEBUG_MSG("WANT GPS=%d\n", on);
if (on) {
lastWakeStartMsec = millis();
wake();
} else {
lastSleepStartMsec = millis();
sleep();
}
isAwake = on;
}
}
uint32_t getValidTime()
GpsOperation GPS::getGpsOp() const
{
return timeSetFromGPS ? getTime() : 0;
auto op = radioConfig.preferences.gps_operation;
if (op == GpsOperation_GpsOpUnset)
op = (radioConfig.preferences.location_share == LocationSharing_LocDisabled) ? GpsOperation_GpsOpTimeOnly
: GpsOperation_GpsOpMobile;
return op;
}
/** Get how long we should stay looking for each aquisition in msecs
*/
uint32_t GPS::getWakeTime() const
{
uint32_t t = radioConfig.preferences.gps_attempt_time;
if (t == UINT32_MAX)
return t; // already maxint
if (t == 0)
t = 15 * 60; // Allow up to 5 mins for each attempt (probably will be much less if we can find sats)
t *= 1000; // msecs
return t;
}
/** Get how long we should sleep between aqusition attempts in msecs
*/
uint32_t GPS::getSleepTime() const
{
uint32_t t = radioConfig.preferences.gps_update_interval;
auto op = getGpsOp();
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
if ((gotTime && op == GpsOperation_GpsOpTimeOnly) || (op == GpsOperation_GpsOpDisabled))
t = UINT32_MAX; // Sleep forever now
if (t == UINT32_MAX)
return t; // already maxint
if (t == 0)
t = 2 * 60; // 2 mins
t *= 1000;
return t;
}
void GPS::publishUpdate()
{
if (shouldPublish) {
shouldPublish = false;
DEBUG_MSG("publishing GPS lock=%d\n", hasLock());
// Notify any status instances that are observing us
const meshtastic::GPSStatus status =
meshtastic::GPSStatus(hasLock(), isConnected(), latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
}
}
int32_t GPS::runOnce()
{
if (whileIdle()) {
// if we have received valid NMEA claim we are connected
setConnected();
}
// If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis();
auto sleepTime = getSleepTime();
if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) {
// We now want to be awake - so wake up the GPS
setAwake(true);
}
// While we are awake
if (isAwake) {
// DEBUG_MSG("looking for location\n");
if ((now - lastWhileActiveMsec) > 5000) {
lastWhileActiveMsec = now;
whileActive();
}
// If we've already set time from the GPS, no need to ask the GPS
bool gotTime = (getRTCQuality() >= RTCQualityGPS);
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
gotTime = true;
shouldPublish = true;
}
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
hasValidLocation = true;
shouldPublish = true;
}
// We've been awake too long - force sleep
auto wakeTime = getWakeTime();
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
// Once we get a location we no longer desperately want an update
// or if we got a time and we are in GpsOpTimeOnly mode
// DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) {
if (tooLong) {
// we didn't get a location during this ack window, therefore declare loss of lock
hasValidLocation = false;
}
setAwake(false);
shouldPublish = true; // publish our update for this just finished acquisition window
}
}
// If state has changed do a publish
publishUpdate();
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
return isAwake ? 100 : 5000;
}
void GPS::forceWake(bool on)
{
if (on) {
DEBUG_MSG("Allowing GPS lock\n");
// lastSleepStartMsec = 0; // Force an update ASAP
wakeAllowed = true;
} else {
wakeAllowed = false;
// Note: if the gps was already awake, we DO NOT shut it down, because we want to allow it to complete its lock
// attempt even if we are in light sleep. Once the attempt succeeds (or times out) we'll then shut it down.
// setAwake(false);
}
}
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
int GPS::prepareSleep(void *unused)
{
DEBUG_MSG("GPS prepare sleep!\n");
forceWake(false);
return 0;
}
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
int GPS::prepareDeepSleep(void *unused)
{
DEBUG_MSG("GPS deep sleep!\n");
// For deep sleep we also want abandon any lock attempts (because we want minimum power)
setAwake(false);
return 0;
}

View File

@@ -1,35 +1,37 @@
#pragma once
#include "../concurrency/PeriodicTask.h"
#include "GPSStatus.h"
#include "Observer.h"
#include "sys/time.h"
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
void perhapsSetRTC(const struct timeval *tv);
void perhapsSetRTC(struct tm &t);
#include "concurrency/OSThread.h"
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
/// 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();
void readFromRTC();
/**
* 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 Observable<void *>
class GPS : private concurrency::OSThread
{
protected:
private:
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
bool hasValidLocation = false; // default to false, until we complete our first read
bool isAwake = false; // true if we want a location right now
bool wakeAllowed = true; // false if gps must be forced to sleep regardless of what time it is
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to
uint8_t numSatellites = 0;
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
public:
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
@@ -42,29 +44,105 @@ class GPS : public Observable<void *>
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
uint32_t numSatellites = 0;
bool isConnected = false; // Do we have a GPS we are talking to
GPS() : concurrency::OSThread("GPS") {}
virtual ~GPS() {}
virtual ~GPS() {} // FIXME, we really should unregister our sleep observer
/** We will notify this observable anytime GPS state has changed meaningfully */
Observable<const meshtastic::GPSStatus *> newStatus;
/**
* Returns true if we succeeded
*/
virtual bool setup() { return true; }
/// A loop callback for subclasses that need it. FIXME, instead just block on serial reads
virtual void loop() {}
virtual bool setup();
/// Returns ture if we have acquired GPS lock.
bool hasLock() const { return hasValidLocation; }
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
/**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state */
virtual void startLock() {}
* called after the CPU wakes from light-sleep state
*
* Or set to false, to disallow any sort of waking
* */
void forceWake(bool on);
protected:
/// Do gps chipset specific init, return true for success
virtual bool setupGPS();
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
/// wake the GPS into normal operation mode
virtual void wake();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle() = 0;
/** Idle processing while GPS is looking for lock, called once per secondish */
virtual void whileActive() {}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime() = 0;
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation() = 0;
/// Record that we have a GPS
void setConnected();
void setNumSatellites(uint8_t n);
private:
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareDeepSleep(void *unused);
/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
* calls sleep/wake
*/
void setAwake(bool on);
/** Get how long we should stay looking for each aquisition
*/
uint32_t getWakeTime() const;
/** Get how long we should sleep between aqusition attempts
*/
uint32_t getSleepTime() const;
GpsOperation getGpsOp() const;
/**
* Tell users we have new GPS readings
*/
void publishUpdate();
virtual int32_t runOnce();
};
extern GPS *gps;

View File

@@ -1,79 +0,0 @@
#include "NEMAGPS.h"
#include "configuration.h"
#include "timing.h"
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
int32_t r = d.deg * degMult + d.billionths / 100;
if (d.negative)
r *= -1;
return r;
}
void NEMAGPS::loop()
{
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// Serial.write(c);
reader.encode(c);
}
uint32_t now = timing::millis();
if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume
// serial chars at whatever rate)
lastUpdateMsec = now;
auto ti = reader.time;
auto d = reader.date;
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
/* 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 = ti.second();
t.tm_min = ti.minute();
t.tm_hour = ti.hour();
t.tm_mday = d.day();
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
perhapsSetRTC(t);
isConnected = true; // we seem to have a real GPS (but not necessarily a lock)
}
if (reader.location.isUpdated()) {
if (reader.altitude.isValid())
altitude = reader.altitude.meters();
if (reader.location.isValid()) {
auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isValid()) {
dop = reader.hdop.value();
}
if (reader.course.isValid()) {
heading = reader.course.value() * 1e3; //Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.satellites.isValid()) {
numSatellites = reader.satellites.value();
}
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5);
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
if (hasValidLocation)
notifyObservers(NULL);
}
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
}
}

View File

@@ -1,21 +0,0 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "../concurrency/PeriodicTask.h"
#include "TinyGPS++.h"
/**
* A gps class thatreads from a NEMA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class NEMAGPS : public GPS
{
TinyGPSPlus reader;
uint32_t lastUpdateMsec = 0;
public:
virtual void loop();
};

112
src/gps/NMEAGPS.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include "NMEAGPS.h"
#include "RTC.h"
#include "configuration.h"
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
int32_t r = d.deg * degMult + d.billionths / 100;
if (d.negative)
r *= -1;
return r;
}
bool NMEAGPS::setupGPS()
{
GPS::setupGPS();
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
pinMode(PIN_GPS_PPS, INPUT);
#endif
return true;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForTime()
{
auto ti = reader.time;
auto d = reader.date;
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
/* 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 = ti.second();
t.tm_min = ti.minute();
t.tm_hour = ti.hour();
t.tm_mday = d.day();
t.tm_mon = d.month() - 1;
t.tm_year = d.year() - 1900;
t.tm_isdst = false;
perhapsSetRTC(RTCQualityGPS, t);
return true;
} else
return false;
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool NMEAGPS::lookForLocation()
{
bool foundLocation = false;
// uint8_t fixtype = reader.fixQuality();
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
if (reader.satellites.isUpdated()) {
setNumSatellites(reader.satellites.value());
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if (reader.hdop.isUpdated()) {
dop = reader.hdop.value();
}
if (reader.course.isUpdated()) {
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.altitude.isUpdated())
altitude = reader.altitude.meters();
if (reader.location.isUpdated()) {
auto loc = reader.location.value();
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
foundLocation = true;
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
dop * 1e-2, heading * 1e-5);
}
return foundLocation;
}
bool NMEAGPS::whileIdle()
{
bool isValid = false;
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// DEBUG_MSG("%c", c);
isValid |= reader.encode(c);
}
return isValid;
}

41
src/gps/NMEAGPS.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include "GPS.h"
#include "Observer.h"
#include "TinyGPS++.h"
/**
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class NMEAGPS : public GPS
{
TinyGPSPlus reader;
public:
virtual bool setupGPS();
protected:
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
};

77
src/gps/RTC.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "RTC.h"
#include "configuration.h"
#include <sys/time.h>
#include <time.h>
static RTCQuality currentQuality = RTCQualityNone;
RTCQuality getRTCQuality()
{
return currentQuality;
}
// stuff that really should be in in the instance instead...
static uint32_t
timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
void 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) quality=%d\n", tv.tv_sec, now, currentQuality);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
}
}
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
{
if (q > currentQuality) {
currentQuality = q;
DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec);
#ifndef NO_ESP32
settimeofday(tv, NULL);
#else
DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n");
#endif
readFromRTC();
return true;
} else {
return false;
}
}
bool perhapsSetRTC(RTCQuality q, struct tm &t)
{
/* 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).
*/
time_t res = mktime(&t);
struct timeval tv;
tv.tv_sec = res;
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300) {
// DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
return false;
} else {
return perhapsSetRTC(q, &tv);
}
}
uint32_t getTime()
{
return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
}
uint32_t getValidTime(RTCQuality minQuality)
{
return (currentQuality >= minQuality) ? getTime() : 0;
}

30
src/gps/RTC.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include "configuration.h"
#include "sys/time.h"
#include <Arduino.h>
enum RTCQuality {
/// We haven't had our RTC set yet
RTCQualityNone = 0,
/// Some other node gave us a time we can use
RTCQualityFromNet = 1,
/// Our time is based on our own GPS
RTCQualityGPS = 2
};
RTCQuality getRTCQuality();
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv);
bool perhapsSetRTC(RTCQuality q, struct tm &t);
/// Return time since 1970 in secs. While quality is RTCQualityNone we will be returning time based at zero
uint32_t getTime();
/// Return time since 1970 in secs. If quality is RTCQualityNone return zero
uint32_t getValidTime(RTCQuality minQuality);
void readFromRTC();

View File

@@ -1,137 +1,143 @@
#include "UBloxGPS.h"
#include "RTC.h"
#include "error.h"
#include "sleep.h"
#include <assert.h>
UBloxGPS::UBloxGPS() : concurrency::PeriodicTask()
{
notifySleepObserver.observe(&notifySleep);
}
UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
{
isConnected = false;
bool c = false;
if (_serial_gps)
isConnected = ublox.begin(*_serial_gps);
c = ublox.begin(*_serial_gps);
if (!isConnected && i2cAddress) {
if (!c && i2cAddress) {
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
// supports the newer API
neo6M = true;
isConnected = ublox.begin(Wire, i2cAddress);
c = ublox.begin(Wire, i2cAddress);
}
return isConnected;
if (c)
setConnected();
return c;
}
bool UBloxGPS::setup()
bool UBloxGPS::setupGPS()
{
if (_serial_gps) {
#ifdef GPS_RX_PIN
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#else
_serial_gps->begin(GPS_BAUDRATE);
#endif
// _serial_gps.setRxBufferSize(1024); // the default is 256
}
#ifdef GPS_POWER_EN
pinMode(GPS_POWER_EN, OUTPUT);
digitalWrite(GPS_POWER_EN, 1);
delay(200); // Give time for the GPS to startup after we gave power
#endif
GPS::setupGPS();
// uncomment to see debug info
// ublox.enableDebugging(Serial);
// try a second time, the ublox lib serial parsing is buggy?
if (!tryConnect())
tryConnect();
// see https://github.com/meshtastic/Meshtastic-device/issues/376
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
if (isConnected) {
if (isConnected()) {
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
bool factoryReset = false;
bool ok;
if (factoryReset) {
// It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have
// GPS_TX connected)
ublox.factoryReset();
delay(3000);
tryConnect();
DEBUG_MSG("Factory reset success=%d\n", isConnected);
ok = ublox.saveConfiguration(3000);
assert(ok);
return false;
} else {
if (_serial_gps) {
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
assert(ok);
}
if (i2cAddress) {
ok = ublox.setI2COutput(COM_TYPE_UBX, 500);
assert(ok);
}
ok = ublox.setNavigationFrequency(1, 500); // Produce 4x/sec to keep the amount of time we stall in getPVT low
assert(ok);
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
// assert(ok);
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
// assert(ok);
ok = ublox.powerSaveMode(true, 2000); // use power save mode, the default timeout (1100ms seems a bit too tight)
assert(ok);
}
ok = ublox.saveConfiguration(3000);
if (!ok)
if (!setUBXMode())
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
return true;
} else {
return false;
}
}
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
int UBloxGPS::prepareSleep(void *unused)
bool UBloxGPS::setUBXMode()
{
if (isConnected)
ublox.powerOff();
if (_serial_gps) {
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
return false;
}
if (i2cAddress) {
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
return false;
}
return 0;
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
return false;
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
// assert(ok);
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
// assert(ok);
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
// TTGO antennas
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
// return false;
if (!ublox.saveConfiguration(3000))
return false;
return true;
}
void UBloxGPS::doTask()
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool UBloxGPS::factoryReset()
{
uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix
bool ok = false;
assert(isConnected);
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
// GPS_TX connected)
ublox.factoryReset();
delay(5000);
tryConnect(); // sets isConnected
// Consume all characters that have arrived
// try a second time, the ublox lib serial parsing is buggy?
for (int i = 0; (i < 3) && !tryConnect(); i++)
delay(500);
// if using i2c or serial look too see if any chars are ready
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
if (isConnected())
ok = setUBXMode();
// If we don't have a fix (a quick check), don't try waiting for a solution)
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
// turn off for now
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
fixtype = ublox.getFixType(maxWait);
DEBUG_MSG("GPS fix type %d\n", fixtype);
return ok;
}
// DEBUG_MSG("sec %d\n", ublox.getSecond());
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
/** Idle processing while GPS is looking for lock */
void UBloxGPS::whileActive()
{
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
// any fix that has time
// Ask for a new position fix - hopefully it will have results ready by next time
// the order here is important, because we only check for has latitude when reading
ublox.getSIV(maxWait());
ublox.getPDOP(maxWait());
ublox.getP(maxWait());
if (ublox.getT(maxWait)) {
// Update fixtype
if (ublox.moduleQueried.fixType) {
fixType = ublox.getFixType(0);
// DEBUG_MSG("GPS fix type %d, numSats %d\n", fixType, numSatellites);
}
}
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForTime()
{
if (ublox.moduleQueried.gpsSecond) {
/* 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).
*/
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 = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
@@ -140,45 +146,72 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(t);
perhapsSetRTC(RTCQualityGPS, t);
return true;
}
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
heading = ublox.getHeading(0);
numSatellites = ublox.getSIV(0);
return false;
}
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
hasValidLocation =
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
bool UBloxGPS::lookForLocation()
{
bool foundLocation = false;
if (ublox.moduleQueried.SIV)
setNumSatellites(ublox.getSIV(0));
if (ublox.moduleQueried.pDOP)
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
// we only notify if position has changed due to a new fix
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
{
if (hasValidLocation) {
wantNewLocation = false;
notifyObservers(NULL);
// ublox.powerOff();
if ((fixType >= 3 && fixType <= 4)) {
if (ublox.moduleQueried.latitude) // rd fixes only
{
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
// don't read it here - it will generate an ignored getPVT command on the 6ms
// heading = ublox.getHeading(0);
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
foundLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000);
}
} else // we didn't get a location update, go back to sleep and hope the characters show up
wantNewLocation = true;
}
// Notify any status instances that are observing us
const meshtastic::GPSStatus status =
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over
// the serial
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
return foundLocation;
}
void UBloxGPS::startLock()
bool UBloxGPS::whileIdle()
{
DEBUG_MSG("Looking for GPS lock\n");
wantNewLocation = true;
setPeriod(1);
// if using i2c or serial look too see if any chars are ready
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
}
/// If possible force the GPS into sleep/low power mode
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
void UBloxGPS::sleep()
{
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
ublox.powerOff();
// setGPSPower(false);
}
void UBloxGPS::wake()
{
fixType = 0; // assume we hace no fix yet
setGPSPower(true);
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
// Give time for the GPS to boot
// delay(200);
}

View File

@@ -2,7 +2,6 @@
#include "GPS.h"
#include "Observer.h"
#include "../concurrency/PeriodicTask.h"
#include "SparkFun_Ublox_Arduino_Library.h"
/**
@@ -10,35 +9,63 @@
*
* When new data is available it will notify observers.
*/
class UBloxGPS : public GPS, public concurrency::PeriodicTask
class UBloxGPS : public GPS
{
SFE_UBLOX_GPS ublox;
bool wantNewLocation = true;
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
uint8_t fixType = 0;
public:
UBloxGPS();
/**
* Reset our GPS back to factory settings
*
* @return true for success
*/
bool factoryReset();
protected:
/**
* Returns true if we succeeded
*/
virtual bool setup();
virtual bool setupGPS();
virtual void doTask();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
* Return true if we received a valid message from the GPS
*/
virtual bool whileIdle();
/** Idle processing while GPS is looking for lock */
virtual void whileActive();
/**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state */
virtual void startLock();
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
virtual bool lookForTime();
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
virtual bool lookForLocation();
/// If possible force the GPS into sleep/low power mode
virtual void sleep();
virtual void wake();
private:
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
/// Switch to our desired operating mode and save the settings to flash
/// returns true for success
bool setUBXMode();
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
};

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