Compare commits

...

232 Commits

Author SHA1 Message Date
Kevin Hester
16f897d27c Merge pull request #547 from geeksville/udp
1.1.20
2020-12-10 13:32:59 +08:00
Kevin Hester
4cbf0a0730 oops - forgot to check in the new version file, broke CI 2020-12-10 13:19:00 +08:00
Kevin Hester
99c8df8e7d try to fix CI again 2020-12-10 13:17:43 +08:00
Kevin Hester
8e2e4f7e6a Merge remote-tracking branch 'root/master' into udp 2020-12-10 12:46:51 +08:00
Kevin Hester
45d72bd51b fix CI build - make projectdir relative 2020-12-10 12:44:35 +08:00
Jm Casler
781ed3eafd Merge pull request #544 from IZ1IVA/patch-1
Update radio-settings.md
2020-12-09 20:39:18 -08:00
Jm Casler
c66a0a37d8 Merge branch 'master' into patch-1 2020-12-09 20:25:17 -08:00
Jm Casler
92f2007207 Merge pull request #545 from IZ1IVA/patch-2
Update radio-settings.md
2020-12-09 20:24:32 -08:00
Kevin Hester
1f7b537d2d Merge remote-tracking branch 'root/master' into udp 2020-12-10 11:46:03 +08:00
Kevin Hester
cabeacfa94 1.1.21 2020-12-10 11:45:22 +08:00
Kevin Hester
df8b3ebbc7 always pull min_app_version from appload 2020-12-10 11:32:51 +08:00
Kevin Hester
b1c30f0650 Use a custom platformio py file to always set build version 2020-12-10 11:28:15 +08:00
IZ1IVA
194028f9fc Update radio-settings.md
- added ERP reference to LoRaWAN for NA
2020-12-09 11:16:31 +01:00
IZ1IVA
f49c8f4c43 Update radio-settings.md
- corrected dBM into dBm
- specified ERP reference
- added link to ERP in-depth article
2020-12-09 11:04:07 +01:00
Kevin Hester
b3b4c2c1c3 Merge pull request #543 from geeksville/udp
big set of changes from my weeks away
2020-12-08 22:46:26 -08:00
Kevin Hester
a0076eb394 better position debug output 2020-12-09 13:42:36 +08:00
Kevin Hester
a6a4fec4b9 Merge remote-tracking branch 'root/master' into udp 2020-12-09 12:15:32 +08:00
Kevin Hester
2d4657c8d4 Merge pull request #542 from IZ1IVA/patch-1
Update README.md
2020-12-08 20:14:43 -08:00
Kevin Hester
32b8e4f20a fix #536 allow fixed positions
meshtastic --setlat 32.7767 --setlon -96.7970 --setalt 1337
2020-12-09 12:05:15 +08:00
Kevin Hester
3753fef298 add debug_log_enabled 2020-12-09 11:56:41 +08:00
Kevin Hester
a4bb1937c1 Merge remote-tracking branch 'root/master' into udp 2020-12-09 11:21:59 +08:00
Kevin Hester
4bd22dd5db ignore our own msgs for gpio ctrl 2020-12-08 08:16:58 +08:00
Kevin Hester
79a24c200e use autogened protobuf init code 2020-12-07 10:27:31 +08:00
Kevin Hester
90060e84c0 WIP on GPIO example 2020-12-07 10:18:11 +08:00
Kevin Hester
8f5a1f19d3 add remote gpio control as an example plugin
https://github.com/meshtastic/Meshtastic-device/issues/182
2020-12-06 18:33:42 +08:00
Kevin Hester
3e0dc44210 move want_replies into new plugin system 2020-12-05 11:15:06 +08:00
Kevin Hester
91b99bd584 require apps to be 1.1.20 or later 2020-12-05 10:27:04 +08:00
Kevin Hester
b6e21bcbcd add SinglePortPlugin to simpilify api 2020-12-05 10:14:15 +08:00
Kevin Hester
ae7d3ee5ed move nodeinfo messages into new plugin system 2020-12-05 10:00:46 +08:00
Kevin Hester
f1179bd3ea positions now sent using the new API 2020-12-05 08:46:19 +08:00
Kevin Hester
9b24cc6dd6 update protobufs 2020-12-04 18:54:00 +08:00
IZ1IVA
20c5b98b2d Update README.md
Added "Related Groups" section
Added Meshtastic Italian Telegram group link
2020-12-03 12:27:44 +01:00
Kevin Hester
d3cb9bdd4a WIP moving positions to new system 2020-12-03 16:48:44 +08:00
Kevin Hester
7737123d0f begin moving position stuff into plugin 2020-11-28 18:10:31 +08:00
Kevin Hester
5138aff4b2 fix static initializer bug with mesh plugins 2020-11-28 13:25:03 +08:00
Kevin Hester
0b0d293a66 Move text message handling into the new plugin system 2020-11-28 12:10:19 +08:00
Kevin Hester
ddab4a0235 remove support for 8bit nodenums 2020-11-28 09:56:21 +08:00
Jm Casler
50615540ce Merge pull request #538 from meshtastic/dev-https
Merging in dev-https to master
2020-11-27 17:21:56 -08:00
Kevin Hester
f5e42b2533 update protos 2020-11-28 09:17:20 +08:00
Kevin Hester
9e9913101f Merge pull request #527 from geeksville/spiffs-bug496
Spiffs bug496
2020-11-27 17:11:34 -08:00
Kevin Hester
b1289b632a Merge remote-tracking branch 'root/master' into dev 2020-11-28 09:00:21 +08:00
Kevin Hester
c427c8abf9 oops - fix my crummy merge 2020-11-28 08:55:56 +08:00
Jm Casler
9170dc7738 Merge pull request #534 from mc-hamster/master
Fix for #533 - We will deinit wifi even if it were never initialized.
2020-11-27 16:19:03 -08:00
Kevin Hester
cc36e3a9a6 Merge branch 'dev-https' into spiffs-bug496 2020-11-27 16:15:14 -08:00
Jm Casler
7d4c77abfd Fix for #533 - deinitWifi() will de initialize the radio even if it was never initialized 2020-11-27 14:49:44 -08:00
Jm Casler
1ba91ec27f Merge pull request #26 from meshtastic/master
update my repo from master
2020-11-25 21:36:56 -08:00
Jm Casler
575c5b2193 Merge pull request #532 from meshtastic/mc-hamster-patch-2
wait_bluetooth_secs to 60 seconds.
2020-11-22 19:38:39 -08:00
Jm Casler
3473a1e323 wait_bluetooth_secs to 60 seconds. 2020-11-22 19:32:48 -08:00
Jm Casler
11a00e2977 Merge pull request #531 from mc-hamster/master
Add support for the power button #528
2020-11-22 19:19:35 -08:00
Jm Casler
817c99e09c trying to fix it again 2020-11-22 19:12:11 -08:00
Jm Casler
9801a62d2d Fix for CI on other boards. 2020-11-22 19:01:48 -08:00
Jm Casler
2bd40b7053 Add support for the power button #528 2020-11-22 18:50:14 -08:00
Jm Casler
dccc15946b Merge pull request #530 from mc-hamster/master
Removing stuff I accidently checked in for the duplexer
2020-11-22 16:50:45 -08:00
Jm Casler
3ab9d2a50e Removing stuff I accidently checked in for the duplexer 2020-11-22 16:24:22 -08:00
Jm Casler
776a978ea0 Merge pull request #529 from mc-hamster/master
Accidentally checked in my rf deduplixer
2020-11-22 15:44:19 -08:00
Jm Casler
f60922af34 Accidently checked in my rf deduplexer 2020-11-22 15:42:36 -08:00
Kevin Hester
cb34fd5eb9 Merge remote-tracking branch 'root/master' into dev 2020-11-20 08:59:54 +08:00
Kevin Hester
19d81347f2 1.1.9 (release for @mc-hamster only in android app alpha) 2020-11-20 07:42:02 +08:00
Kevin Hester
d7d13d637c clean up filesystem goo, add spiffs to install scripts, fix #496
@mc-hamster seems to work pretty good for me, so I'll send a PR to you
for the dev-http branch.

I'll push out an android alpha build later today (once the build is
complete).  Once this new device load is out in the field _future_
device builds will support updating spiffs from android. (i.e. device
loads older than 1.1.9 must be updated to 1.1.9 or later before spiffs
support is implemented on the device side - so some users might need to
update twice before the new spiffs contents will appear on their device)
2020-11-19 09:25:02 +08:00
Kevin Hester
df75cefeeb fix #525 - turn off (buggy) TinyGPS custom candidates support 2020-11-18 10:54:25 +08:00
Jm Casler
66f9dbec45 Merge pull request #524 from meshtastic/mc-hamster-patch-1
Lora Design Guide
2020-11-17 13:16:49 -08:00
Jm Casler
4679dd7c4d Lora Design Guide
Airtime calculation is in section 4.
2020-11-17 11:14:57 -08:00
Jm Casler
a02979d564 Merge branch 'externalAmp' into master 2020-11-16 19:54:06 -08:00
Kevin Hester
f2698bbf91 bug #496 - allow update clients to program SPIFFS region
also have build system properly build spiffs release builds
2020-11-16 08:56:32 +08:00
Kevin Hester
d045139945 return ble errors for invalid values 2020-11-16 07:57:32 +08:00
Kevin Hester
2c9c5991a0 add a script for testing release builds 2020-11-15 08:24:34 +08:00
Jm Casler
1b365fa0aa Merge pull request #24 from meshtastic/dev-https
Dev https
2020-11-13 21:40:00 -08:00
Jm Casler
71d1d4d8fa Merge pull request #521 from meshtastic/master
Update dev-https from master
2020-11-13 21:35:20 -08:00
Jm Casler
64df994a32 Merge pull request #520 from crossan007/dev-https
Only issue ContentType header once; correctly.
2020-11-13 20:13:31 -08:00
Charles Crossan
49a19e26d5 Only issue ContentType header once; correctly. 2020-11-13 22:07:52 -05:00
Kevin Hester
ef37f955c3 Merge remote-tracking branch 'root/master' into dev 2020-11-14 10:22:10 +08:00
Kevin Hester
ac50b9544b Merge pull request #519 from geeksville/bug513
Bug513
2020-11-14 10:21:44 +08:00
Kevin Hester
ccc1600bc9 remove stale fixme 2020-11-14 10:19:55 +08:00
Kevin Hester
7c220f8a39 Merge branch 'master' into bug513 2020-11-14 10:14:22 +08:00
Kevin Hester
1839f8f7ca fix #513 scale retransmission times based on true packet time on wire 2020-11-14 10:07:25 +08:00
Kevin Hester
48c461c50c Merge pull request #515 from geeksville/eink
nrf52 deep sleep support
2020-11-13 11:08:17 +08:00
Kevin Hester
f346b4f0f2 Merge branch 'eink' into bug513 2020-11-13 09:41:23 +08:00
Kevin Hester
5aab4f5c95 Merge branch 'master' into eink 2020-11-13 09:36:18 +08:00
Kevin Hester
d407db5ee1 add more deep sleep support for nrf52 boards 2020-11-13 09:33:59 +08:00
Kevin Hester
93afc71e2e Show "sleeping" on eink while in deep sleep 2020-11-13 07:49:01 +08:00
Kevin Hester
67e657f10f always print debug output to both serial and segger debug port
cc @mc-hamster, this  makes USE_SEGGER optional on nrf52 targets
2020-11-13 07:48:25 +08:00
Kevin Hester
619a48085a pinetab docs 2020-11-12 18:31:35 +08:00
Kevin Hester
68937d52fe bug #503 wip 2020-11-12 17:49:04 +08:00
Jm Casler
e33657eb75 Toggle GPIO2 to HIGH when transmitting a packet out the LORA radio. 2020-11-09 19:47:31 -08:00
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
Jm Casler
825001f313 Merge pull request #23 from mc-hamster/master
update
2020-11-06 23:12:50 -08:00
Jm Casler
576526576a Merge pull request #511 from mc-hamster/master
Web text editor #510
2020-11-06 23:11:09 -08:00
Kevin Hester
2fd5ce00ce fix build for esp32 targets 2020-11-07 15:09:05 +08:00
Jm Casler
4204c494ae fix poorly merged file 2020-11-06 22:41:26 -08:00
Jm Casler
84beae1001 Merge branch 'dev-https' into master 2020-11-06 22:29:03 -08:00
Jm Casler
951b4293c4 Set web cookie and web text editor. 2020-11-06 22:21:20 -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
Jm Casler
2f9ef463d8 Merge pull request #507 from meshtastic/master
update dev-https from master
2020-10-30 21:04:16 -07:00
Jm Casler
bea00569fd Merge pull request #22 from meshtastic/master
update my fork from master
2020-10-30 21:03:40 -07: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
Jm Casler
b1dae3608e Merge pull request #502 from mc-hamster/master
Update to basic.js and add mime types.
2020-10-26 18:18:16 -07:00
Jm Casler
44aafd5b9c Update to basic.js and add mime types. 2020-10-26 18:17:33 -07: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
Jm Casler
91756d1fec Merge pull request #501 from mc-hamster/master
Fixed typo. Updated js library. Update root file handler.
2020-10-22 18:46:26 -07:00
Jm Casler
5981831bc0 Fixed typo. Updated js library. Update root file handler.
Typo fixed. I placed the latest javascript library files into the static folder. Updated the root file handler to be able to serve both compressed and uncompressed files.
2020-10-22 18:43:54 -07:00
Jm Casler
00eed206cb Update typo, import from js library 2020-10-22 18:26:43 -07:00
Jm Casler
130d55aaaa Merge pull request #500 from mc-hamster/master
Updated dev-https from my fork.
2020-10-21 21:29:34 -07:00
Jm Casler
13ef48094d Merge pull request #21 from meshtastic/dev-https
Dev https to my fork
2020-10-21 21:20:55 -07:00
Jm Casler
529fd5a830 Merge pull request #499 from meshtastic/master
Update dev-https from master
2020-10-21 21:20:07 -07:00
Jm Casler
baa3d1dae4 Support for the SPIFFS 2020-10-21 20:57:44 -07: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
e9279919ae Remove uncompressed style.css. Combine SSID/PWD on same line and toggle between the two every 10 seconds. 2020-10-19 16:58:11 -07: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
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
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
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
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
Jm Casler
db8faa9faf added powerExit 2020-10-09 23:07:37 -07: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
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
BeardyWalrus
b4b1b24c84 always need double press, even if you dont have a screen 2020-10-05 20:13:04 -04: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
BeardyWalrus
f30c84012f Merge branch 'master' into master 2020-10-01 22:24:30 -04: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
BeardyWalrus
26bafb4082 Merge pull request #3 from meshtastic/master
Update from upstream
2020-09-27 19:23:26 -04: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
122 changed files with 4956 additions and 1551 deletions

View File

@@ -49,7 +49,8 @@
"string_view": "cpp",
"cassert": "cpp",
"iterator": "cpp",
"shared_mutex": "cpp"
"shared_mutex": "cpp",
"iostream": "cpp"
},
"cSpell.words": [
"Blox",

View File

@@ -2,18 +2,17 @@
set -e
source bin/version.sh
VERSION=`bin/buildinfo.py`
COUNTRIES="US EU433 EU865 CN JP ANZ KR"
#COUNTRIES=US
#COUNTRIES=CN
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"
BOARDS="$BOARDS_ESP32 $BOARDS_NRF52"
#BOARDS=tbeam
OUTDIR=release/latest
@@ -22,22 +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 {
echo "Building for $BOARD with $PLATFORMIO_BUILD_FLAGS"
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
# 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/firmware-$BOARD-$COUNTRY-$VERSION.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
@@ -46,26 +84,20 @@ 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
do_boards "$BOARDS_ESP32" "false"
do_boards "$BOARDS_NRF52" "true"
echo "Copying ESP32 bin files"
for BOARD in $BOARDS_ESP32; do
SRCBIN=.pio/build/$BOARD/firmware.bin
cp $SRCBIN $OUTDIR/bins/firmware-$BOARD-$COUNTRY-$VERSION.bin
done
echo "Generating NRF52 uf2 files"
for BOARD in $BOARDS_NRF52; do
SRCHEX=.pio/build/$BOARD/firmware.hex
bin/uf2conv.py $SRCHEX -c -o $OUTDIR/bins/firmware-$BOARD-$COUNTRY-$VERSION.uf2 -f 0xADA52840
done
done
echo "Building SPIFFS for ESP32 targets"
pio run --environment tbeam -t buildfs
cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin
# keep the bins in archive also
cp $OUTDIR/bins/firmware* $OUTDIR/elfs/firmware* $ARCHIVEDIR
cp $OUTDIR/bins/firmware* $OUTDIR/bins/universal/spiffs* $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"?>
@@ -79,7 +111,8 @@ 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
zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh
echo BUILT ALL

11
bin/buildinfo.py Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python3
import configparser
config = configparser.RawConfigParser()
config.read('version.properties')
version = dict(config.items('VERSION'))
verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"])
print(f"{verStr}")

View File

@@ -1,5 +1,7 @@
#!/bin/sh
set -e
# Usage info
show_help() {
cat << EOF
@@ -36,6 +38,7 @@ 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 0x00390000 spiffs-*.bin
esptool.py --baud 921600 write_flash 0x10000 ${FILENAME}
else
echo "Invalid file: ${FILENAME}"

View File

@@ -2,7 +2,20 @@
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
@@ -11,12 +24,12 @@ nrfjprog --eraseall -f nrf52
# 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
srec_cat /tmp/bootconf.bin -binary -offset $BOOTSET -output /tmp/bootconf.hex -intel
echo Generating merged hex file
mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-124-g69bd8eb-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex
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 ttgo_eink_full.hex -f nrf52 --reset
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

21
bin/platformio-custom.py Normal file
View File

@@ -0,0 +1,21 @@
Import("projenv")
import configparser
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
print(f"Preferences in {prefsLoc}")
try:
config = configparser.RawConfigParser()
config.read(prefsLoc)
version = dict(config.items('VERSION'))
verStr = "{}.{}.{}".format(version["major"], version["minor"], version["build"])
except:
print("Can't read preferences, using 0.0.0")
verStr = "0.0.0"
print(f"Using meshtastic platform-custom.py, firmare version {verStr}")
# General options that are passed to the C and C++ compilers
projenv.Append(CCFLAGS=[
f"-DAPP_VERSION={verStr}"
])

View File

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

View File

@@ -1,6 +1,12 @@
#!/bin/bash
set -e
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1"
# the nanopb tool seems to require that the .options file be in the current directory!
cd proto
../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto mesh.proto
../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto *.proto
echo "Regenerating protobuf documentation - if you see an error message"
echo "you can ignore it unless doing a new protobuf release to github."
bin/regen-docs.sh

View File

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

View File

@@ -1,3 +0,0 @@
export VERSION=1.1.5

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

View File

@@ -5,7 +5,7 @@
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_LORA_RELAY_V1 -DNRF52840_XXAA",
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[

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"
}

43
data/static/basic.js Normal file
View File

@@ -0,0 +1,43 @@
var meshtasticClient;
var connectionOne;
// Important: the connect action must be called from a user interaction (e.g. button press), otherwise the browsers won't allow the connect
function connect() {
// Create new connection
var httpconn = new meshtasticjs.IHTTPConnection();
// Set connection params
let sslActive;
if (window.location.protocol === 'https:') {
sslActive = true;
} else {
sslActive = false;
}
let deviceIp = window.location.hostname; // Your devices IP here
// Add event listeners that get called when a new packet is received / state of device changes
httpconn.addEventListener('fromRadio', function (packet) { console.log(packet) });
// Connect to the device async, then send a text message
httpconn.connect(deviceIp, sslActive)
.then(result => {
alert('device has been configured')
// This gets called when the connection has been established
// -> send a message over the mesh network. If no recipient node is provided, it gets sent as a broadcast
return httpconn.sendText('meshtastic is awesome');
})
.then(result => {
// This gets called when the message has been sucessfully sent
console.log('Message sent!');
})
.catch(error => { console.log(error); });
}

18
data/static/index.html Normal file
View File

@@ -0,0 +1,18 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title></title>
<script src="/static/meshtastic.js"></script>
<script src="/static/basic.js"></script>
</head>
<body>
<button id="connect_button" onclick="connect()">Connect to Meshtastic device</button>
</body>
</html>

Binary file not shown.

View File

@@ -39,6 +39,10 @@ This software is 100% open source and developed by a group of hobbyist experimen
For an detailed walk-through aimed at beginners, we recommend [meshtastic.letstalkthis.com](https://meshtastic.letstalkthis.com/).
### Related Groups
Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).
# Updates
Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum.

Binary file not shown.

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

View File

@@ -8,7 +8,7 @@ See [this site](https://www.rfwireless-world.com/Tutorials/LoRa-channels-list.ht
## LoRaWAN Europe Frequency Band
The maximum power allowed is +14dBM.
The maximum power allowed is +14dBm ERP (Effective Radiated Power, see [this site](https://en.wikipedia.org/wiki/Effective_radiated_power) for more information).
### 433 MHz
@@ -24,7 +24,7 @@ Channel zero starts at 865.20 MHz
LoRaWAN defines 64, 125 kHz channels from 902.3 to 914.9 MHz increments.
The maximum output power for North America is +30 dBM.
The maximum output power for North America is +30 dBm ERP.
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are separated by 2.16 MHz with respect to the adjacent channels.
Channel zero starts at 903.08 MHz center frequency.
Channel zero starts at 903.08 MHz center frequency.

View File

@@ -2,31 +2,90 @@
You probably don't care about this section - skip to the next one.
Threading tasks:
For app cleanup:
- Use https://github.com/ivanseidel/ArduinoThread? rather than full coroutines
- clean up main loop()
- check that we are mostly asleep, show which thread is causing us to wake
-
- use tickless idle on nrf52, and sleep X msec or until an interrupt occurs or the cooperative scheduling changes. https://devzone.nordicsemi.com/f/nordic-q-a/12363/nrf52-freertos-power-consumption-tickless-idle
- BAD IDEA: use vTaskDelay and https://www.freertos.org/xTaskAbortDelay.html if scheduling changes. (define INCLUDE_xTaskAbortDelay on ESP32 and NRF52 - seems impossible to find?)
- GOOD IDEA: use xSemaphoreTake to take a semaphore using a timeout. Expect semaphore to not be set, but set it to indicate scheduling has changed.
* DONE make device build always have a valid version
* DONE do fixed position bug https://github.com/meshtastic/Meshtastic-device/issues/536
* check build guide
* generate autodocs
* write devapi user guide
* DONE update android code: https://developer.android.com/topic/libraries/view-binding/migration
* only do wantReplies once per packet type, if we change network settings force it again
* make gpio watch work, use thread and setup
* make hello world example service
* make python ping command
* make python gpio read a bit cleaner
* DONE have python tool check max packet size before sending to device
* DONE if request was sent reliably, send reply reliably
* DONE require a recent python api to talk to these new device loads
* DONE require a recent android app to talk to these new device loads
* DONE fix handleIncomingPosition
* DONE move want_replies handling into plugins
* DONE on android for received positions handle either old or new positions / user messages
* on android side send old or new positions as needed / user messages
* test python side handle new position/user messages
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
* DONE fix position sending to use new plugin
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
* DONE move positions into regular data packets (use new app framework)
* DONE move user info into regular data packets (use new app framework)
* DONE test that positions, text messages and user info still work
* DONE test that position, text messages and user info work properly with new android app and old device code
* fix the RTC drift bug
* move python ping functionality into device, reply with rxsnr info
* use channels for gpio security https://github.com/meshtastic/Meshtastic-device/issues/104
Nimble tasks:
For high speed/lots of devices/short range tasks:
- readerror.txt stress test bug
- started RPA long test, jul 22 6pm
- implement nimble software update api
- update to latest bins, test OTA again (measure times) and then checkin bins
- do alpha release
- 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
* update protocol description per cyclomies email thread
* update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2
* update faq on recommended android version and phones
* add help link inside the app, reference a page on the wiki
* turn on amazon reviews support
* add a tablet layout (with map next to messages) in the android app
# Old docs to merge
MESH RADIO PROTOCOL
Old TODO notes on the mesh radio protocol, merge into real docs someday...
for each named group we have a pre-shared key known by all group members and
wrapped around the device. you can only be in one group at a time (FIXME?!) To
join the group we read a qr code with the preshared key and ParamsCodeEnum. that
gets sent via bluetooth to the device. ParamsCodeEnum maps to a set of various
radio params (regulatory region, center freq, SF, bandwidth, bitrate, power
etc...) so all members of the mesh can have their radios set the same way.
once in that group, we can talk between 254 node numbers.
to get our node number (and announce our presence in the channel) we pick a
random node number and broadcast as that node with WANT-NODENUM(my globally
unique name). If anyone on the channel has seen someone _else_ using that name
within the last 24 hrs(?) they reply with DENY-NODENUM. Note: we might receive
multiple denies. Note: this allows others to speak up for some other node that
might be saving battery right now. Any time we hear from another node (for any
message type), we add that node number to the unpickable list. To dramatically
decrease the odds a node number we request is already used by someone. If no one
denies within TBD seconds, we assume that we have that node number. As long as
we keep talking to folks at least once every 24 hrs, others should remember we
have it.
Once we have a node number we can broadcast POSITION-UPDATE(my globally unique
name, lat, lon, alt, amt battery remaining). All receivers will use this to a)
update the mapping of who is at what node nums, b) the time of last rx, c)
position. If we haven't heard from that node in a while we reply to that node
(only) with our current POSITION_UPDATE state - so that node (presumably just
rejoined the network) can build a map of all participants.
We will periodically broadcast POSITION-UPDATE as needed based on distance moved
or a periodic minimum heartbeat.
If user wants to send a text they can SEND_TEXT(dest user, short text message).
Dest user is a node number, or 0xff for broadcast.
# Medium priority
Items to complete before 1.0.

View File

@@ -111,6 +111,7 @@ Characteristics
| e272ebac-d463-4b98-bc84-5cc1a39ee517 | write | data, variable sized, recommended 512 bytes, write one for each block of file |
| 4826129c-c22a-43a3-b066-ce8f0d5bacc6 | write | crc32, write last - writing this will complete the OTA operation, now you can read result |
| 5e134862-7411-4424-ac4a-210937432c77 | read,notify | result code, readable but will notify when the OTA operation completes |
| 5e134862-7411-4424-ac4a-210937432c67 | write | sets the region for programming, currently only 0 (app) or 100 (spiffs) are defined, if not set app is assumed |
| GATT_UUID_SW_VERSION_STR/0x2a28 | read | We also implement these standard GATT entries because SW update probably needs them: |
| GATT_UUID_MANU_NAME/0x2a29 | read | |
| GATT_UUID_HW_VERSION_STR/0x2a27 | read | |

View File

@@ -5,7 +5,27 @@
## 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)

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

@@ -50,7 +50,7 @@ From lower to higher power consumption.
- At cold boot: The initial state (after setup() has run) is DARK
- While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
- While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
- While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 60 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
- While in LS: Every send*owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we \_also* broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
- While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
- While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)

View File

@@ -19,24 +19,25 @@ default_envs = tbeam # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you
; The following environment variables must be set in the shell if you'd like to override them.
; They are used in this ini file as systenv.VARNAME, so in your shell do export "VARNAME=fish"
; COUNTRY (default US), i.e. "export COUNTRY=EU865"
; APP_VERSION (default emptystring)
; HW_VERSION (default emptystring)
[env]
; note: APP_VERSION now comes from bin/version.json
extra_scripts = bin/platformio-custom.py
; 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 -Wl,-Map,.pio/build/output.map
-DHW_VERSION_${sysenv.COUNTRY}
-DAPP_VERSION=${sysenv.APP_VERSION}
-DHW_VERSION=${sysenv.HW_VERSION}
-DUSE_THREAD_NAMES
-DTINYGPSPLUS_OPTION_NO_CUSTOM_FIELDS
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
; geeksville: I think setting this should not be required - it breaks linux
;upload_port = /dev/cu.SLAB_USBtoUART
;monitor_port = /dev/cu.SLAB_USBtoUART
@@ -65,7 +66,7 @@ lib_deps =
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/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
@@ -95,6 +96,9 @@ build_flags =
${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
@@ -117,7 +121,7 @@ board_build.partitions = partition-table.csv
extends = esp32_base
board = ttgo-t-beam
lib_deps =
${arduino_base.lib_deps}
${esp32_base.lib_deps}
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
@@ -234,6 +238,15 @@ 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
@@ -269,7 +282,30 @@ lib_deps =
${arduino_base.lib_deps}
SparkFun BQ27441 LiPo Fuel Gauge Arduino Library
TFT_eSPI
# Adafruit ST7735 and ST7789 Library
; 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]

2
proto

Submodule proto updated: a0b8d88896...ebd18145ca

21
src/FSCommon.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include "FSCommon.h"
void fsInit()
{
#ifdef FS
if (!FSBegin())
{
DEBUG_MSG("ERROR filesystem mount Failed\n");
assert(0); // FIXME - report failure to phone
}
DEBUG_MSG("Filesystem files:\n");
File dir = FS.open("/");
File f = dir.openNextFile();
while (f) {
DEBUG_MSG(" %s\n", f.name());
f.close();
f = dir.openNextFile();
}
#endif
}

29
src/FSCommon.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include "configuration.h"
// Cross platform filesystem API
#ifdef PORTDUINO
// Portduino version
#include "PortduinoFS.h"
#define FS PortduinoFS
#define FSBegin() true
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#elif !defined(NO_ESP32)
// ESP32 version
#include "SPIFFS.h"
#define FS SPIFFS
#define FSBegin() FS.begin(true)
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#else
// NRF52 version
#include "InternalFileSystem.h"
#define FS InternalFS
#define FSBegin() FS.begin()
using namespace Adafruit_LittleFS_Namespace;
#endif
void fsInit();

View File

@@ -18,6 +18,21 @@ Power *power;
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
*/
@@ -37,10 +52,13 @@ class AnalogBatteryLevel : public HasBatteryLevel
{
float v = getBattVoltage() / 1000;
if (v < 2.1)
if (v < noBatVolt)
return -1; // If voltage is super low assume no battery installed
return 100 * (v - 3.27) / (4.2 - 3.27);
if (v > chargingVolt)
return 0; // While charging we can't report % full on the battery
return 100 * (v - emptyVolt) / (fullVolt - emptyVolt);
}
/**
@@ -48,9 +66,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
*/
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 * analogRead(BATTERY_PIN) * 2.0 * (3.3 / 1024.0);
1000.0 * 2.0 * (AREF_VOLTAGE / 1024.0) * analogRead(BATTERY_PIN);
#else
NAN;
#endif
@@ -59,7 +79,20 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
virtual bool isBatteryConnect() { return getBattVoltage() != -1; }
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") {}
@@ -68,10 +101,18 @@ 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;
@@ -93,6 +134,14 @@ bool Power::setup()
return found;
}
void Power::shutdown()
{
#ifdef TBEAM_V10
DEBUG_MSG("Shutting down\n");
axp.shutdown();
#endif
}
/// Reads power status to powerStatus singleton.
//
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
@@ -121,7 +170,8 @@ void Power::readPowerStatus()
const PowerStatus powerStatus =
PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse,
batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent);
DEBUG_MSG("Read power stat %d\n", powerStatus.getHasUSB());
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

View File

@@ -149,6 +149,7 @@ static void onEnter()
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now;
}
}
static void screenPress()
@@ -244,20 +245,24 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_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, getPref_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, &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
auto meshSds = getPref_mesh_sds_timeout_secs();
if (meshSds != UINT32_MAX)
powerFSM.add_timed_transition(&stateLS, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
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, getPref_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

@@ -82,7 +82,7 @@ class PowerStatus : public Status
isCharging = newStatus->isCharging;
}
if (isDirty) {
DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
// DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this);
}
return 0;

View File

@@ -1,4 +1,5 @@
#include "RedirectablePrint.h"
#include "configuration.h"
#include <assert.h>
/**
@@ -10,4 +11,14 @@ void RedirectablePrint::setDestination(Print *_dest)
{
assert(_dest);
dest = _dest;
}
size_t RedirectablePrint::write(uint8_t c)
{
#ifdef SEGGER_STDOUT_CH
SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c);
#endif
dest->write(c);
return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero)
}

View File

@@ -19,7 +19,7 @@ class RedirectablePrint : public Print
*/
void setDestination(Print *dest);
virtual size_t write(uint8_t c) { return dest->write(c); }
virtual size_t write(uint8_t c);
};
class NoopPrint : public Print

View File

@@ -1,6 +1,7 @@
#include "SerialConsole.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "NodeDB.h"
#include <Arduino.h>
#define Port Serial
@@ -28,7 +29,8 @@ void SerialConsole::init()
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
{
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
setDestination(&noopPrint);
if(!radioConfig.preferences.debug_log_enabled)
setDestination(&noopPrint);
canWrite = true;
StreamAPI::handleToRadio(buf, len);

View File

@@ -31,9 +31,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// If app version is not specified we assume we are not being invoked by the build script
#ifndef APP_VERSION
#error APP_VERSION, HW_VERSION, and HW_VERSION_countryname must be set by the build environment
//#define APP_VERSION 0.0.0 // this def normally comes from build-all.sh
//#define HW_VERSION 1.0 - US // normally comes from build-all.sh and contains the region code
#error APP_VERSION must be set by the build environment
#endif
// If app version is not specified we assume we are not being invoked by the build script
#ifndef HW_VERSION
#error HW_VERSION, and HW_VERSION_countryname must be set by the build environment
#endif
// -----------------------------------------------------------------------------
@@ -139,6 +142,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
#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.
@@ -146,7 +150,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
// Define if screen should be mirrored left to right
// #define SCREEN_MIRROR
// -----------------------------------------------------------------------------
// GPS
@@ -400,8 +407,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// The channel we send stdout data to
#define SEGGER_STDOUT_CH 0
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
// 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
@@ -430,3 +440,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

@@ -6,6 +6,7 @@
#include "RadioLibInterface.h"
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include "NodeDB.h"
#include <CRC32.h>
#include <Update.h>
@@ -16,6 +17,8 @@ static CRC32 crc;
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
static uint32_t updateExpectedSize, updateActualSize;
static uint8_t update_result;
static uint8_t update_region;
static concurrency::Lock *updateLock;
@@ -32,8 +35,8 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
crc.reset();
if (Update.isRunning())
Update.abort();
bool canBegin = Update.begin(updateExpectedSize);
DEBUG_MSG("Setting update size %u, result %d\n", updateExpectedSize, canBegin);
bool canBegin = Update.begin(updateExpectedSize, update_region);
DEBUG_MSG("Setting region %d update size %u, result %d\n", update_region, updateExpectedSize, canBegin);
if (!canBegin) {
// Indicate failure by forcing the size to 0 (client will read it back)
updateExpectedSize = 0;
@@ -72,13 +75,11 @@ 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;
}
static uint8_t update_result;
/// Handle writes to crc32
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
@@ -100,8 +101,14 @@ int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble
result = 0xe0; // FIXME, use real error codes
} else {
if (Update.end()) {
DEBUG_MSG("OTA done, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000;
if (update_region == U_SPIFFS) {
DEBUG_MSG("SPIFFS updated!\n");
nodeDB.saveToDisk(); // Since we just wiped spiffs, we need to save our current state
}
else {
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000;
}
} else {
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
}
@@ -125,6 +132,11 @@ int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct bl
return chr_readwrite8(&update_result, sizeof(update_result), ctxt);
}
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
}
void bluetoothRebootCheck()
{
if (rebootAtMsec && millis() > rebootAtMsec) {

View File

@@ -14,10 +14,11 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
extern const struct ble_gatt_svc_def gatt_update_svcs[];
extern const ble_uuid128_t update_result_uuid;
extern const ble_uuid128_t update_result_uuid, update_region_uuid;
extern int16_t updateResultHandle;

View File

@@ -23,6 +23,10 @@ const ble_uuid128_t update_crc32_uuid =
const ble_uuid128_t update_result_uuid =
BLE_UUID128_INIT(0x77, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
// "5e134862-7411-4424-ac4a-210937432c67" write
const ble_uuid128_t update_region_uuid =
BLE_UUID128_INIT(0x67, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
const struct ble_gatt_svc_def gatt_update_svcs[] = {
{
/*** Service: Security test. */
@@ -47,9 +51,14 @@ const struct ble_gatt_svc_def gatt_update_svcs[] = {
},
{
.uuid = &update_result_uuid.u,
.access_cb = update_size_callback,
.access_cb = update_result_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
},
{
.uuid = &update_region_uuid.u,
.access_cb = update_region_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
0, /* No more characteristics in this service. */
}},

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

@@ -65,9 +65,8 @@ void Air530GPS::sendCommand(const char *cmd) {
}
void Air530GPS::sleep() {
NMEAGPS::sleep();
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, 0);
pinMode(PIN_GPS_WAKE, OUTPUT);
sendCommand("$PGKC105,4");
#endif
}
@@ -76,10 +75,7 @@ void Air530GPS::sleep() {
void Air530GPS::wake()
{
#if 1
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, 1);
pinMode(PIN_GPS_WAKE, OUTPUT);
#endif
NMEAGPS::wake();
#else
// For power testing - keep GPS sleeping forever
sleep();

View File

@@ -10,7 +10,7 @@
#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
@@ -25,17 +25,75 @@ uint8_t GPS::i2cAddress = 0;
GPS *gps;
/// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once.
static bool didSerialInit;
bool GPS::setupGPS()
{
if (_serial_gps && !didSerialInit) {
didSerialInit = true;
#ifdef GPS_RX_PIN
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#else
_serial_gps->begin(GPS_BAUDRATE);
#endif
#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)
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()
{
@@ -225,7 +283,19 @@ void GPS::forceWake(bool on)
/// 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

@@ -30,6 +30,7 @@ class GPS : private concurrency::OSThread
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 */
@@ -72,13 +73,13 @@ class GPS : private concurrency::OSThread
protected:
/// Do gps chipset specific init, return true for success
virtual bool setupGPS() = 0;
virtual bool setupGPS();
/// If possible force the GPS into sleep/low power mode
virtual void sleep() {}
virtual void sleep();
/// wake the GPS into normal operation mode
virtual void wake() {}
virtual void wake();
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
*
@@ -115,6 +116,10 @@ class GPS : private concurrency::OSThread
/// 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
*

View File

@@ -1,6 +1,6 @@
#include "NMEAGPS.h"
#include "configuration.h"
#include "RTC.h"
#include "configuration.h"
static int32_t toDegInt(RawDegrees d)
{
@@ -13,6 +13,8 @@ static int32_t toDegInt(RawDegrees d)
bool NMEAGPS::setupGPS()
{
GPS::setupGPS();
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
@@ -32,7 +34,7 @@ bool NMEAGPS::lookForTime()
{
auto ti = reader.time;
auto d = reader.date;
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
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).
@@ -65,27 +67,27 @@ bool NMEAGPS::lookForLocation()
// 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()) {
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);
foundLocation = true;
}
// 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()) {
setNumSatellites(reader.satellites.value());
}
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,

View File

@@ -29,16 +29,7 @@ bool UBloxGPS::tryConnect()
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
#ifndef NO_ESP32
_serial_gps->setRxBufferSize(2048); // the default is 256
#endif
}
GPS::setupGPS();
// uncomment to see debug info
// ublox.enableDebugging(Serial);

View File

@@ -46,15 +46,18 @@ void updateDisplay(uint8_t *blackFrame = framePtr)
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will
// work ie GEOMETRY_RAWMODE
setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
}
// FIXME quick hack to limit drawing to a very slow rate
uint32_t lastDrawMsec;
// Write the buffer to the display memory
void EInkDisplay::display(void)
/**
* Force a display update if we haven't drawn within the specified msecLimit
*/
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
{
// No need to grab this lock because we are on our own SPI bus
// concurrency::LockGuard g(spiLock);
@@ -62,16 +65,16 @@ void EInkDisplay::display(void)
uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec;
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) {
if (framePtr && (sinceLast > msecLimit || lastDrawMsec == 0)) {
lastDrawMsec = now;
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH];
auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7));
frame.drawPixel(x, y, isset ? INK : PAPER);
}
@@ -83,11 +86,25 @@ void EInkDisplay::display(void)
updateDisplay(); // Send image to display and refresh
DEBUG_MSG("done\n");
// Put screen to sleep to save power
// Put screen to sleep to save power
ePaper.Sleep();
return true;
} else {
// DEBUG_MSG("Skipping eink display\n");
return false;
}
}
// Write the buffer to the display memory
void EInkDisplay::display(void)
{
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
// bootscreen (that we want to look nice)
if (lastDrawMsec)
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
}
// Send a command to the display (low level function)
void EInkDisplay::sendCommand(uint8_t com)
{

View File

@@ -14,15 +14,26 @@
*/
class EInkDisplay : public OLEDDisplay
{
/// How often should we update the display
/// thereafter we do once per 5 minutes
uint32_t slowUpdateMsec = 5 * 60 * 1000;
public:
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
EInkDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory
// Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void);
/**
* Force a display update if we haven't drawn within the specified msecLimit
*
* @return true if we did draw the screen
*/
bool forceDisplay(uint32_t msecLimit = 1000);
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; }
@@ -33,3 +44,5 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display
virtual bool connect();
};

View File

@@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "plugins/TextMessagePlugin.h"
#include "target_specific.h"
#include "utils.h"
@@ -58,39 +59,92 @@ static char ourId[5];
static bool heartbeat = false;
#endif
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
static uint16_t displayWidth, displayHeight;
#define SCREEN_WIDTH displayWidth
#define SCREEN_HEIGHT displayHeight
#ifdef HAS_EINK
// The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16
#define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24
#else
#define FONT_SMALL ArialMT_Plain_10
#define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24
#endif
#define fontHeight(font) ((font)[1] + 1) // height is position 1
#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL)
#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM)
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
#ifndef SCREEN_TRANSITION_MSECS
#define SCREEN_TRANSITION_MSECS 300
#endif
/**
* Draw the icon with extra info printed around the corners
*/
static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
// Please note that everything that should be transitioned
// needs to be drawn relative to x and y
display->drawXbm(x + 32, y, icon_width, icon_height, (const uint8_t *)icon_bits);
display->setFont(ArialMT_Plain_16);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, SCREEN_HEIGHT - FONT_HEIGHT_16, "meshtastic.org");
display->setFont(ArialMT_Plain_10);
const char *region = xstr(HW_VERSION);
if (*region && region[3] == '-') // Skip past 1.0- in the 1.0-EU865 string
region += 4;
// draw centered icon left to right and centered above the one line of app text
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
icon_width, icon_height, (const uint8_t *)icon_bits);
display->setFont(FONT_MEDIUM);
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *title = "meshtastic.org";
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
// Draw region in upper left
if (upperMsg)
display->drawString(x + 0, y + 0, upperMsg);
// Draw version in upper right
char buf[16];
snprintf(buf, sizeof(buf), "%s",
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(SCREEN_WIDTH - 20, 0, buf);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
// FIXME - draw serial # somewhere?
}
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawIconScreen(region, display, state, x, y);
}
/// Used on eink displays while in deep sleep
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
drawIconScreen("Sleeping...", display, state, x, y);
}
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
display->setFont(FONT_MEDIUM);
display->drawString(64 + x, y, "Bluetooth");
display->setFont(ArialMT_Plain_10);
display->drawString(64 + x, FONT_HEIGHT + y + 2, "Enter this code");
display->setFont(FONT_SMALL);
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
display->setFont(ArialMT_Plain_24);
display->setFont(FONT_LARGE);
display->drawString(64 + x, 26 + y, btPIN);
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
char buf[30];
const char *name = "Name: ";
strcpy(buf, name);
@@ -112,10 +166,10 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// with the third parameter you can define the width after which words will
// be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_16);
display->setFont(FONT_MEDIUM);
String sender = (node && node->has_user) ? node->user.short_name : "???";
display->drawString(0 + x, 0 + y, sender);
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
// the max length of this buffer is much longer than we can possibly print
static char tempBuf[96];
@@ -135,8 +189,8 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
int xo = x, yo = y;
while (*f) {
display->drawString(xo, yo, *f);
yo += FONT_HEIGHT;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT) {
yo += FONT_HEIGHT_SMALL;
if (yo > SCREEN_HEIGHT - FONT_HEIGHT_SMALL) {
xo += SCREEN_WIDTH / 2;
yo = 0;
}
@@ -162,14 +216,14 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
// Wrap to next row, if needed.
if (++col >= COLUMNS) {
xo = x;
yo += FONT_HEIGHT;
yo += FONT_HEIGHT_SMALL;
col = 0;
}
f++;
}
if (col != 0) {
// Include last incomplete line in our total.
yo += FONT_HEIGHT;
yo += FONT_HEIGHT_SMALL;
}
return yo;
@@ -236,7 +290,7 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
// Draw the number of satellites
sprintf(satsString, "%d", gps->getNumSatellites());
sprintf(satsString, "%lu", gps->getNumSatellites());
display->drawString(x + 34, y - 2, satsString);
}
}
@@ -476,7 +530,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -489,11 +543,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20];
if (agoSecs < 120) // last 2 mins?
snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs);
snprintf(lastStr, sizeof(lastStr), "%lu seconds ago", agoSecs);
else if (agoSecs < 120 * 60) // last 2 hrs
snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60);
snprintf(lastStr, sizeof(lastStr), "%lu minutes ago", agoSecs / 60);
else
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
snprintf(lastStr, sizeof(lastStr), "%lu hours ago", agoSecs / 60 / 60);
static char distStr[20];
strcpy(distStr, "? km"); // might not have location data
@@ -531,7 +585,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// direction to node is unknown so display question mark
// Debug info for gps lock errors
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?");
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
// Must be after distStr is populated
@@ -561,10 +615,26 @@ void _screen_header()
}
#endif
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) {
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev)
{
cmdQueue.setReader(this);
}
/**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
*/
void Screen::doDeepSleep()
{
#ifdef HAS_EINK
static FrameCallback sleepFrames[] = {drawSleepScreen};
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
ui.setFrames(sleepFrames, sleepFrameCount);
ui.update();
#endif
setOn(false);
}
void Screen::handleSetOn(bool on)
{
if (!useDisplay)
@@ -592,11 +662,17 @@ void Screen::setup()
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
useDisplay = true;
dispdev.resetOrientation();
// I think this is not needed - redundant with ui.init
// dispdev.resetOrientation();
// Initialising the UI will init the display too.
ui.init();
ui.setTimePerTransition(300); // msecs
displayWidth = dispdev.width();
displayHeight = dispdev.height();
ui.setTimePerTransition(SCREEN_TRANSITION_MSECS);
ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar.
ui.setIndicatorDirection(LEFT_RIGHT);
@@ -622,7 +698,9 @@ void Screen::setup()
// Set up a log buffer with 3 lines, 32 chars each.
dispdev.setLogBuffer(3, 32);
#ifdef FLIP_SCREEN_VERTICALLY
#ifdef SCREEN_MIRROR
dispdev.mirrorScreen();
#elif defined(SCREEN_FLIP_VERTICALLY)
dispdev.flipScreenVertically();
#endif
@@ -643,6 +721,15 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
textMessageObserver.observe(&textMessagePlugin);
}
void Screen::forceDisplay()
{
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef HAS_EINK
dispdev.forceDisplay();
#endif
}
int32_t Screen::runOnce()
@@ -655,7 +742,8 @@ int32_t Screen::runOnce()
// Show boot screen for first 3 seconds, then switch to normal operation.
static bool showingBootScreen = true;
if (showingBootScreen && (millis() > 3000)) {
if (showingBootScreen && (millis() > 5000)) {
DEBUG_MSG("Done with boot screen...\n");
stopBootScreen();
showingBootScreen = false;
}
@@ -701,6 +789,10 @@ int32_t Screen::runOnce()
return 0;
}
// this must be before the frameState == FIXED check, because we always
// want to draw at least one FIXED frame before doing forceDisplay
ui.update();
// Switch to a low framerate (to save CPU) when we are not in transition
// but we should only call setTargetFPS when framestate changes, because
// otherwise that breaks animations.
@@ -709,6 +801,7 @@ int32_t Screen::runOnce()
DEBUG_MSG("Setting idle framerate\n");
targetFramerate = IDLE_FRAMERATE;
ui.setTargetFPS(targetFramerate);
forceDisplay();
}
// While showing the bootscreen or Bluetooth pair screen all of our
@@ -717,8 +810,6 @@ int32_t Screen::runOnce()
// standard screen loop handling here
}
ui.update();
// DEBUG_MSG("want fps %d, fixed=%d\n", targetFramerate,
// ui.getUiState()->frameState); If we are scrolling we need to be called
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
@@ -785,6 +876,8 @@ void Screen::setFrames()
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed)
setFastFramerate(); // Draw ASAP
}
void Screen::handleStartBluetoothPinScreen(uint32_t pin)
@@ -794,16 +887,17 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
static FrameCallback btFrames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
snprintf(btPIN, sizeof(btPIN), "%06lu", pin);
ui.disableAllIndicators();
ui.setFrames(btFrames, 1);
setFastFramerate();
}
void Screen::handlePrint(const char *text)
{
DEBUG_MSG("Screen: %s", text);
if (!useDisplay)
if (!useDisplay || !showingNormalScreen)
return;
dispdev.print(text);
@@ -814,22 +908,31 @@ void Screen::handleOnPress()
// If screen was off, just wake it, otherwise advance to next frame
// If we are in a transition, the press must have bounced, drop it.
if (ui.getUiState()->frameState == FIXED) {
setInterval(0); // redraw ASAP
ui.nextFrame();
DEBUG_MSG("Setting fast framerate\n");
// We are about to start a transition so speed up fps
targetFramerate = TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
setFastFramerate();
}
}
#ifndef SCREEN_TRANSITION_FRAMERATE
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
#endif
void Screen::setFastFramerate()
{
DEBUG_MSG("Setting fast framerate\n");
// We are about to start a transition so speed up fps
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP
}
void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -851,13 +954,13 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
// Draw the channel name
display->drawString(x, y + FONT_HEIGHT, channelStr);
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT, 8, 8, imgInfo);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT, ourId);
display->drawFastImage(x + SCREEN_WIDTH - (10) - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
// Draw any log messages
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2));
display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2));
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
@@ -876,7 +979,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -907,86 +1010,90 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
if (WiFi.status() == WL_CONNECTED) {
if (radioConfig.preferences.wifi_ap_mode) {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str()));
} else {
display->drawString(x, y + FONT_HEIGHT * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
}
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
display->drawString(x, y + FONT_HEIGHT * 1, "SSID Not Found");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
} else if (WiFi.status() == WL_CONNECTION_LOST) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Lost");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Lost");
} else if (WiFi.status() == WL_CONNECT_FAILED) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
//} else if (WiFi.status() == WL_DISCONNECTED) {
// display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected");
// display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disconnected");
} else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT * 1, "Idle ... Reconnecting");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
} else {
// Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
if (getWifiDisconnectReason() == 2) {
display->drawString(x, y + FONT_HEIGHT * 1, "Authentication Invalid");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid");
} else if (getWifiDisconnectReason() == 3) {
display->drawString(x, y + FONT_HEIGHT * 1, "De-authenticated");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "De-authenticated");
} else if (getWifiDisconnectReason() == 4) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated Expired");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated Expired");
} else if (getWifiDisconnectReason() == 5) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP - Too Many Clients");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP - Too Many Clients");
} else if (getWifiDisconnectReason() == 6) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_AUTHED");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_AUTHED");
} else if (getWifiDisconnectReason() == 7) {
display->drawString(x, y + FONT_HEIGHT * 1, "NOT_ASSOCED");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_ASSOCED");
} else if (getWifiDisconnectReason() == 8) {
display->drawString(x, y + FONT_HEIGHT * 1, "Disassociated");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated");
} else if (getWifiDisconnectReason() == 9) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_NOT_AUTHED");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_NOT_AUTHED");
} else if (getWifiDisconnectReason() == 10) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_PWRCAP_BAD");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_PWRCAP_BAD");
} else if (getWifiDisconnectReason() == 11) {
display->drawString(x, y + FONT_HEIGHT * 1, "DISASSOC_SUPCHAN_BAD");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_SUPCHAN_BAD");
} else if (getWifiDisconnectReason() == 13) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_INVALID");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_INVALID");
} else if (getWifiDisconnectReason() == 14) {
display->drawString(x, y + FONT_HEIGHT * 1, "MIC_FAILURE");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "MIC_FAILURE");
} else if (getWifiDisconnectReason() == 15) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Handshake Timeout");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Handshake Timeout");
} else if (getWifiDisconnectReason() == 16) {
display->drawString(x, y + FONT_HEIGHT * 1, "GROUP_KEY_UPDATE_TIMEOUT");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "GROUP_KEY_UPDATE_TIMEOUT");
} else if (getWifiDisconnectReason() == 17) {
display->drawString(x, y + FONT_HEIGHT * 1, "IE_IN_4WAY_DIFFERS");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_IN_4WAY_DIFFERS");
} else if (getWifiDisconnectReason() == 18) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Group Cipher");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Group Cipher");
} else if (getWifiDisconnectReason() == 19) {
display->drawString(x, y + FONT_HEIGHT * 1, "Invalid Pairwise Cipher");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Pairwise Cipher");
} else if (getWifiDisconnectReason() == 20) {
display->drawString(x, y + FONT_HEIGHT * 1, "AKMP_INVALID");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AKMP_INVALID");
} else if (getWifiDisconnectReason() == 21) {
display->drawString(x, y + FONT_HEIGHT * 1, "UNSUPP_RSN_IE_VERSION");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "UNSUPP_RSN_IE_VERSION");
} else if (getWifiDisconnectReason() == 22) {
display->drawString(x, y + FONT_HEIGHT * 1, "INVALID_RSN_IE_CAP");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "INVALID_RSN_IE_CAP");
} else if (getWifiDisconnectReason() == 23) {
display->drawString(x, y + FONT_HEIGHT * 1, "802_1X_AUTH_FAILED");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "802_1X_AUTH_FAILED");
} else if (getWifiDisconnectReason() == 24) {
display->drawString(x, y + FONT_HEIGHT * 1, "CIPHER_SUITE_REJECTED");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "CIPHER_SUITE_REJECTED");
} else if (getWifiDisconnectReason() == 200) {
display->drawString(x, y + FONT_HEIGHT * 1, "BEACON_TIMEOUT");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "BEACON_TIMEOUT");
} else if (getWifiDisconnectReason() == 201) {
display->drawString(x, y + FONT_HEIGHT * 1, "AP Not Found");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Not Found");
} else if (getWifiDisconnectReason() == 202) {
display->drawString(x, y + FONT_HEIGHT * 1, "AUTH_FAIL");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AUTH_FAIL");
} else if (getWifiDisconnectReason() == 203) {
display->drawString(x, y + FONT_HEIGHT * 1, "ASSOC_FAIL");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_FAIL");
} else if (getWifiDisconnectReason() == 204) {
display->drawString(x, y + FONT_HEIGHT * 1, "HANDSHAKE_TIMEOUT");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "HANDSHAKE_TIMEOUT");
} else if (getWifiDisconnectReason() == 205) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
} else {
display->drawString(x, y + FONT_HEIGHT * 1, "Unknown Status");
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unknown Status");
}
}
display->drawString(x, y + FONT_HEIGHT * 2, "SSID: " + String(wifiName));
display->drawString(x, y + FONT_HEIGHT * 3, "PWD: " + String(wifiPsw));
if ((millis() / 10000) % 2) {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
} else {
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw));
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local");
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
@@ -1001,7 +1108,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
{
displayedNodeNum = 0; // Not currently showing a node pane
display->setFont(ArialMT_Plain_10);
display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -1035,15 +1142,21 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
minutes %= 60;
hours %= 24;
display->drawString(x, y + FONT_HEIGHT * 1,
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
#ifndef NO_ESP32
// Show CPU Frequency.
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("CPU " + String(getCpuFrequencyMhz()) + "MHz"),
y + FONT_HEIGHT_SMALL * 1, "CPU " + String(getCpuFrequencyMhz()) + "MHz");
#endif
// Line 3
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus);
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
// Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT * 3, gpsStatus);
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
@@ -1072,16 +1185,24 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens
prevFrame = -1; // Force a GUI update
setInterval(0); // Update the screen right away
if (showingNormalScreen &&
nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens
}
nodeDB.updateGUI = false;
nodeDB.updateTextMessage = false;
break;
}
return 0;
}
int Screen::handleTextMessage(const MeshPacket *arg)
{
if (showingNormalScreen) {
setFrames(); // Regen the list of screens (will show new text message)
}
return 0;
}
} // namespace graphics

View File

@@ -6,6 +6,8 @@
#ifdef USE_SH1106
#include <SH1106Wire.h>
#elif defined(USE_ST7567)
#include <ST7567Wire.h>
#else
#include <SSD1306Wire.h>
#endif
@@ -19,6 +21,11 @@
#include "power.h"
#include <string>
// 0 to 255, though particular variants might define different defaults
#ifndef BRIGHTNESS_DEFAULT
#define BRIGHTNESS_DEFAULT 150
#endif
namespace graphics
{
@@ -70,6 +77,8 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const MeshPacket *> textMessageObserver =
CallbackObserver<Screen, const MeshPacket *>(this, &Screen::handleTextMessage);
public:
Screen(uint8_t address, int sda = -1, int scl = -1);
@@ -92,12 +101,18 @@ class Screen : public concurrency::OSThread
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
}
/**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
*/
void doDeepSleep();
/// Handles a button press.
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
// Implementation to Adjust Brightness
void adjustBrightness();
uint8_t brightness = 150;
uint8_t brightness = BRIGHTNESS_DEFAULT;
/// Starts showing the Bluetooth PIN screen.
//
@@ -179,6 +194,10 @@ class Screen : public concurrency::OSThread
DebugInfo *debug_info() { return &debugInfo; }
int handleStatusUpdate(const meshtastic::Status *arg);
int handleTextMessage(const MeshPacket *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
protected:
/// Updates the UI.
@@ -216,6 +235,9 @@ class Screen : public concurrency::OSThread
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();
/// Try to start drawing ASAP
void setFastFramerate();
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
@@ -244,6 +266,8 @@ class Screen : public concurrency::OSThread
EInkDisplay dispdev;
#elif defined(USE_SH1106)
SH1106Wire dispdev;
#elif defined(USE_ST7567)
ST7567Wire dispdev;
#else
SSD1306Wire dispdev;
#endif

View File

@@ -11,8 +11,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
{
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will
// work ie GEOMETRY_RAWMODE
setGeometry(GEOMETRY_RAWMODE, 160, 80);
}
// Write the buffer to the display memory
@@ -22,11 +21,11 @@ void TFTDisplay::display(void)
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
for (uint8_t y = 0; y < displayHeight; y++) {
for (uint8_t x = 0; x < displayWidth; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH];
auto b = buffer[x + (y / 8) * displayWidth];
auto isset = b & (1 << (y & 7));
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
}

View File

@@ -2,12 +2,7 @@
#include "fonts.h"
#define FONT_HEIGHT 14 // actually 13 for "Arial 10" but want a little extra space
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
// This means the *visible* area (sh1106 can address 132, but shows 128 for example)
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define TRANSITION_FRAMERATE 30 // fps
#define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44

View File

@@ -11,6 +11,7 @@
// #include "rom/rtc.h"
#include "DSRRouter.h"
// #include "debug.h"
#include "FSCommon.h"
#include "RTC.h"
#include "SPILock.h"
#include "concurrency/OSThread.h"
@@ -50,7 +51,9 @@ meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus();
// Global Node status
meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus();
bool ssd1306_found;
/// The I2C address of our display (if found)
uint8_t screen_found;
bool axp192_found;
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
@@ -72,9 +75,13 @@ void scanI2Cdevice(void)
nDevices++;
if (addr == SSD1306_ADDRESS) {
ssd1306_found = true;
screen_found = addr;
DEBUG_MSG("ssd1306 display found\n");
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
DEBUG_MSG("st7567 display found\n");
}
#ifdef AXP192_SLAVE_ADDRESS
if (addr == AXP192_SLAVE_ADDRESS) {
axp192_found = true;
@@ -161,19 +168,35 @@ class ButtonThread : public OSThread
#endif
public:
static uint32_t longPressTime;
// callback returns the period for the next callback invocation (or 0 if we should no longer be called)
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
#endif
userButtonAlt.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
userButtonAlt.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN_ALT, FALLING);
#endif
}
@@ -190,9 +213,10 @@ class ButtonThread : public OSThread
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
canSleep &= userButton.isIdle();
canSleep &= userButtonAlt.isIdle();
#endif
// if(!canSleep) DEBUG_MSG("Supressing sleep!\n");
// if (!canSleep) DEBUG_MSG("Supressing sleep!\n");
// else DEBUG_MSG("sleep ok\n");
return 5;
}
@@ -203,16 +227,55 @@ class ButtonThread : public OSThread
// DEBUG_MSG("press!\n");
powerFSM.trigger(EVENT_PRESS);
}
static void userButtonPressedLong() { screen->adjustBrightness(); }
static void userButtonPressedLong()
{
// DEBUG_MSG("Long press!\n");
screen->adjustBrightness();
// If user button is held down for 10 seconds, shutdown the device.
if (millis() - longPressTime > 10 * 1000) {
#ifdef TBEAM_V10
if (axp192_found == true) {
power->shutdown();
}
#endif
} else {
//DEBUG_MSG("Long press %u\n", (millis() - longPressTime));
}
}
static void userButtonDoublePressed()
{
#ifndef NO_ESP32
disablePin();
#endif
}
static void userButtonPressedLongStart()
{
DEBUG_MSG("Long press start!\n");
longPressTime = millis();
}
static void userButtonPressedLongStop()
{
DEBUG_MSG("Long press stop!\n");
longPressTime = 0;
}
};
static Periodic *ledPeriodic;
static OSThread *powerFSMthread, *buttonThread;
uint32_t ButtonThread::longPressTime = 0;
RadioInterface *rIf = NULL;
void setup()
{
#ifdef SEGGER_STDOUT_CH
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
#ifdef USE_SEGGER
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
@@ -238,6 +301,8 @@ void setup()
ledPeriodic = new Periodic("Blink", ledBlinker);
fsInit();
router = new DSRRouter();
#ifdef I2C_SDA
@@ -245,13 +310,21 @@ void setup()
#else
Wire.begin();
#endif
// i2c still busted on new board
#ifndef ARDUINO_NRF52840_PPR
scanI2Cdevice();
#ifdef PIN_LCD_RESET
// FIXME - move this someplace better, LCD is at address 0x3F
pinMode(PIN_LCD_RESET, OUTPUT);
digitalWrite(PIN_LCD_RESET, 0);
delay(1);
digitalWrite(PIN_LCD_RESET, 1);
delay(1);
#endif
scanI2Cdevice();
// Buttons & LED
buttonThread = new ButtonThread();
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, 1 ^ LED_INVERTED); // turn on for now
@@ -263,7 +336,7 @@ void setup()
#ifndef NO_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER)
ssd1306_found = false; // forget we even have the hardware
screen_found = 0; // forget we even have the hardware
esp32Setup();
#endif
@@ -289,55 +362,58 @@ void setup()
#endif
// Initialize the screen first so we can show the logo while we start up everything else.
screen = new graphics::Screen(SSD1306_ADDRESS);
#if defined(ST7735_CS) || defined(HAS_EINK)
screen->setup();
#else
if (ssd1306_found)
screen->setup();
#endif
screen->print("Started...\n");
screen = new graphics::Screen(screen_found);
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
// If we know we have a L80 GPS, don't try UBLOX
#ifndef L80_RESET
// If we don't have bidirectional comms, we can't even try talking to UBLOX
UBloxGPS *ublox = NULL;
#ifdef GPS_TX_PIN
// Init GPS - first try ublox
auto ublox = new UBloxGPS();
ublox = new UBloxGPS();
gps = ublox;
if (!gps->setup()) {
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
delete ublox;
gps = ublox = NULL;
}
#endif
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
// dumb NMEA access only work for serial GPSes)
DEBUG_MSG("Hoping that NMEA might work\n");
if (!gps && GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NMEA at 9600 baud.
// dumb NMEA access only work for serial GPSes)
DEBUG_MSG("Hoping that NMEA might work\n");
#ifdef HAS_AIR530_GPS
gps = new Air530GPS();
gps = new Air530GPS();
#else
gps = new NMEAGPS();
gps = new NMEAGPS();
#endif
gps->setup();
}
gps->setup();
}
#else
gps = new NMEAGPS();
gps->setup();
#endif
if (gps)
gpsStatus->observe(&gps->newStatus);
else
DEBUG_MSG("Warning: No GPS found - running without GPS\n");
nodeStatus->observe(&nodeDB.newStatus);
service.init();
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(HAS_EINK)
screen->setup();
#else
if (screen_found)
screen->setup();
#endif
screen->print("Started...\n");
// We have now loaded our saved preferences from flash
// ONCE we will factory reset the GPS for bug #327

View File

@@ -6,7 +6,6 @@
#include "graphics/Screen.h"
extern bool axp192_found;
extern bool ssd1306_found;
extern bool isCharging;
extern bool isUSBPowered;

69
src/mesh/MeshPlugin.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include "MeshPlugin.h"
#include "NodeDB.h"
#include "MeshService.h"
#include <assert.h>
std::vector<MeshPlugin *> *MeshPlugin::plugins;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
if(!plugins)
plugins = new std::vector<MeshPlugin *>();
plugins->push_back(this);
}
void MeshPlugin::setup() {
}
MeshPlugin::~MeshPlugin()
{
assert(0); // FIXME - remove from list of plugins once someone needs this feature
}
void MeshPlugin::callPlugins(const MeshPacket &mp)
{
// DEBUG_MSG("In call plugins\n");
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
if (pi.wantPortnum(mp.decoded.data.portnum)) {
bool handled = pi.handleReceived(mp);
// Possibly send replies (unless we are handling a locally generated message)
if (mp.decoded.want_response && mp.from != nodeDB.getNodeNum())
pi.sendResponse(mp);
DEBUG_MSG("Plugin %s handled=%d\n", pi.name, handled);
if (handled)
break;
}
else {
DEBUG_MSG("Plugin %s not interested\n", pi.name);
}
}
}
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
* is optional
*/
void MeshPlugin::sendResponse(const MeshPacket &req) {
auto r = allocReply();
if(r) {
DEBUG_MSG("Sending response\n");
setReplyTo(r, req);
service.sendToMesh(r);
}
else {
DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
}
}
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/
void setReplyTo(MeshPacket *p, const MeshPacket &to) {
p->to = to.from;
p->want_ack = to.want_ack;
}

67
src/mesh/MeshPlugin.h Normal file
View File

@@ -0,0 +1,67 @@
#pragma once
#include "mesh/MeshTypes.h"
#include <vector>
/** A baseclass for any mesh "plugin".
*
* A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
*
* A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
* and handle.
*
* Interally we use plugins to implement the core meshtastic text messaging and gps position sharing features. You
* can use these classes as examples for how to write your own custom plugin. See here: (FIXME)
*/
class MeshPlugin
{
static std::vector<MeshPlugin *> *plugins;
public:
/** Constructor
* name is for debugging output
*/
MeshPlugin(const char *_name);
virtual ~MeshPlugin();
/** For use only by MeshService
*/
static void callPlugins(const MeshPacket &mp);
protected:
const char *name;
/**
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
* been initialized
*/
virtual void setup();
/**
* @return true if you want to receive the specified portnum
*/
virtual bool wantPortnum(PortNum p) = 0;
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceived(const MeshPacket &mp) { return false; }
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */
virtual MeshPacket *allocReply() { return NULL; }
private:
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
* to generate the reply message, and if !NULL that message will be delivered to whoever sent req
*/
void sendResponse(const MeshPacket &req);
};
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/
void setReplyTo(MeshPacket *p, const MeshPacket &to);

View File

@@ -16,4 +16,7 @@ struct RegionInfo {
const char *name; // EU433 etc
};
extern const RegionInfo regions[];
extern const RegionInfo regions[];
extern const RegionInfo *myRegion;
extern void initRegion();

View File

@@ -13,6 +13,8 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/PositionPlugin.h"
#include "plugins/NodeInfoPlugin.h"
#include "power.h"
/*
@@ -51,7 +53,7 @@ MeshService service;
static int32_t sendOwnerCb()
{
service.sendOurOwner();
nodeInfoPlugin.sendOurNodeInfo();
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
}
@@ -74,113 +76,25 @@ void MeshService::init()
packetReceivedObserver.observe(&router->notifyPacketReceived);
}
void MeshService::sendOurOwner(NodeNum dest, bool wantReplies)
{
MeshPacket *p = router->allocForSending();
p->to = dest;
p->decoded.want_response = wantReplies;
p->decoded.which_payload = SubPacket_user_tag;
User &u = p->decoded.user;
u = owner;
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
sendToMesh(p);
}
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp)
{
bool wasBroadcast = mp->to == NODENUM_BROADCAST;
// Disable this collision testing if we use 32 bit nodenums
bool isCollision = (sizeof(NodeNum) == 1) && (mp->from == myNodeInfo.my_node_num);
if (isCollision) {
// we win if we have a lower macaddr
bool weWin = memcmp(&owner.macaddr, &mp->decoded.user.macaddr, sizeof(owner.macaddr)) < 0;
if (weWin) {
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
mp = NULL;
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
} else {
// we lost, we need to try for a new nodenum!
DEBUG_MSG("NOTE! Received a nodenum collision we lost, so picking a new nodenum\n");
nodeDB.updateFrom(
*mp); // update the DB early - before trying to repick (so we don't select the same node number again)
nodeDB.pickNewNodeNum();
sendOurOwner(); // broadcast our new attempt at a node number
}
} else if (wasBroadcast) {
// If we haven't yet abandoned the packet and it was a broadcast, reply (just to them) with our User record so they can
// build their DB
// Someone just sent us a User, reply with our Owner
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
sendOurOwner(mp->from);
String lcd = String("Joined: ") + mp->decoded.user.long_name + "\n";
screen->print(lcd.c_str());
}
return mp;
}
void MeshService::handleIncomingPosition(const MeshPacket *mp)
{
if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_position_tag) {
DEBUG_MSG("handled incoming position time=%u\n", mp->decoded.position.time);
if (mp->decoded.position.time) {
struct timeval tv;
uint32_t secs = mp->decoded.position.time;
tv.tv_sec = secs;
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityFromNet, &tv);
}
} else {
DEBUG_MSG("Ignoring incoming packet - not a position\n");
}
}
int MeshService::handleFromRadio(const MeshPacket *mp)
{
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
// If it is a position packet, perhaps set our clock - this must be before nodeDB.updateFrom
handleIncomingPosition(mp);
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_user_tag) {
mp = handleFromRadioUser(mp);
fromNum++;
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
if (mp) {
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++;
if (toPhoneQueue.numFree() == 0) {
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d)
releaseToPool(d);
}
MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
if (mp->decoded.want_response)
sendNetworkPing(mp->from);
} else {
DEBUG_MSG("Not delivering vetoed User message\n");
}
MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
return 0;
}
@@ -198,7 +112,10 @@ void MeshService::loop()
bool MeshService::reloadConfig()
{
// If we can successfully set this radio to these settings, save them to disk
// This will also update the region as needed
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
configChanged.notifyObservers(NULL);
nodeDB.saveToDisk();
@@ -208,7 +125,7 @@ bool MeshService::reloadConfig()
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
void MeshService::reloadOwner()
{
sendOurOwner();
nodeInfoPlugin.sendOurNodeInfo();
nodeDB.saveToDisk();
}
@@ -219,8 +136,6 @@ void MeshService::reloadOwner()
*/
void MeshService::handleToRadio(MeshPacket &p)
{
handleIncomingPosition(&p); // If it is a position packet, perhaps set our clock
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
p.from = nodeDB.getNodeNum();
@@ -250,7 +165,8 @@ void MeshService::sendToMesh(MeshPacket *p)
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
// devices can get time.
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag) {
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag &&
p->decoded.position.time) {
if (getRTCQuality() < RTCQualityGPS) {
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
p->decoded.position.time = 0;
@@ -269,36 +185,16 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
if (node->has_position)
sendOurPosition(dest, wantReplies);
positionPlugin.sendOurPosition(dest, wantReplies);
else
sendOurOwner(dest, wantReplies);
}
void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending();
p->to = dest;
p->decoded.which_payload = SubPacket_position_tag;
p->decoded.position = node->position;
p->decoded.want_response = wantReplies;
p->decoded.position.time =
getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
sendToMesh(p);
nodeInfoPlugin.sendOurNodeInfo(dest, wantReplies);
}
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending();
p->decoded.which_payload = SubPacket_position_tag;
Position &pos = p->decoded.position;
Position pos = Position_init_default;
if (gps->hasLock()) {
if (gps->altitude != 0)
@@ -306,6 +202,17 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
pos.latitude_i = gps->latitude;
pos.longitude_i = gps->longitude;
}
else {
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
if(radioConfig.preferences.fixed_position) {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
assert(node->has_position);
pos = node->position;
DEBUG_MSG("WARNING: Using fixed position\n");
}
}
pos.time = getValidTime(RTCQualityGPS);
@@ -313,21 +220,18 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
pos.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(pos.battery_level);
// DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
// Update our current position in the local DB
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
lastGpsSend = now;
DEBUG_MSG("Sending position to mesh\n");
sendToMesh(p);
} else {
// We don't need to send this packet to anyone else, but it still serves as a nice uniform way to update our local state
nodeDB.updateFrom(*p);
releaseToPool(p);
DEBUG_MSG("Sending position to mesh (not requesting replies)\n");
positionPlugin.sendOurPosition();
}
return 0;

View File

@@ -75,18 +75,13 @@ class MeshService
/// sends our owner
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
/// Send our owner info to a particular node
void sendOurOwner(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
private:
/// Broadcasts our last known position
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
/// cache
void sendToMesh(MeshPacket *p);
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
int onGPSChanged(const meshtastic::GPSStatus *arg);
@@ -94,12 +89,6 @@ class MeshService
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
/// to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p);
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
const MeshPacket *handleFromRadioUser(const MeshPacket *mp);
/// look at inbound packets and if they contain a position with time, possibly set our clock
void handleIncomingPosition(const MeshPacket *mp);
};
extern MeshService service;

View File

@@ -9,7 +9,7 @@
typedef uint32_t NodeNum;
typedef uint32_t PacketId; // A packet sequence number
#define NODENUM_BROADCAST (sizeof(NodeNum) == 4 ? UINT32_MAX : UINT8_MAX)
#define NODENUM_BROADCAST UINT32_MAX
#define ERRNO_OK 0
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER

View File

@@ -16,6 +16,7 @@
#include "error.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
#include "FSCommon.h"
#include <pb_decode.h>
#include <pb_encode.h>
@@ -35,27 +36,7 @@ DeviceState versions used to be defined in the .proto file but really only this
#define DEVICESTATE_CUR_VER 11
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
#ifdef PORTDUINO
// Portduino version
#include "PortduinoFS.h"
#define FS PortduinoFS
#define FSBegin() true
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#elif !defined(NO_ESP32)
// ESP32 version
#include "SPIFFS.h"
#define FS SPIFFS
#define FSBegin() FS.begin(true)
#define FILE_O_WRITE "w"
#define FILE_O_READ "r"
#else
// NRF52 version
#include "InternalFileSystem.h"
#define FS InternalFS
#define FSBegin() FS.begin()
using namespace Adafruit_LittleFS_Namespace;
#endif
// FIXME - move this somewhere else
extern void getMacAddr(uint8_t *dmac);
@@ -143,12 +124,20 @@ bool NodeDB::resetRadioConfig()
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
radioConfig.preferences.screen_on_secs = 30;
radioConfig.preferences.wait_bluetooth_secs = 30;
radioConfig.preferences.screen_on_secs = 10;
radioConfig.preferences.wait_bluetooth_secs = 10;
radioConfig.preferences.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60;
radioConfig.preferences.region = RegionCode_TW;
// Enter super deep sleep soon and stay there not very long
// radioConfig.preferences.mesh_sds_timeout_secs = 10;
// radioConfig.preferences.sds_secs = 60;
}
// Update the global myRegion
initRegion();
return didFactoryReset;
}
@@ -176,7 +165,6 @@ void NodeDB::installDefaultDeviceState()
// default to no GPS, until one has been found by probing
myNodeInfo.has_gps = false;
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
myNodeInfo.min_app_version = 172;
generatePacketId(); // FIXME - ugly way to init current_packet_id;
// Init our blank owner info to reasonable defaults
@@ -202,12 +190,6 @@ void NodeDB::init()
{
installDefaultDeviceState();
if (!FSBegin()) // FIXME - do this in main?
{
DEBUG_MSG("ERROR filesystem mount Failed\n");
assert(0); // FIXME - report failure to phone
}
// saveToDisk();
loadFromDisk();
// saveToDisk();
@@ -217,6 +199,9 @@ void NodeDB::init()
myNodeInfo.node_num_bits = sizeof(NodeNum) * 8;
myNodeInfo.packet_id_bits = sizeof(PacketId) * 8;
// likewise - we always want the app requirements to come from the running appload
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
pickNewNodeNum();
@@ -265,8 +250,7 @@ void NodeDB::pickNewNodeNum()
// If we don't have a nodenum at app - pick an initial nodenum based on the macaddr
if (r == 0)
r = sizeof(NodeNum) == 1 ? ourMacAddr[5]
: ((ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]);
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
r = NUM_RESERVED; // don't pick a reserved node number
@@ -396,6 +380,48 @@ size_t NodeDB::getNumOnlineNodes()
return numseen;
}
#include "MeshPlugin.h"
/** Update position info for this node based on received position data
*/
void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
{
NodeInfo *info = getOrCreateNode(nodeId);
DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
info->position = p;
info->has_position = true;
updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed
}
/** Update user info for this node based on received user data
*/
void NodeDB::updateUser(uint32_t nodeId, const User &p)
{
NodeInfo *info = getOrCreateNode(nodeId);
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
bool changed = memcmp(&info->user, &p,
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
info->user = p;
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
info->has_user = true;
if (changed) {
updateGUIforNode = info;
powerFSM.trigger(EVENT_NODEDB_UPDATED);
notifyObservers(true); // Force an update whether or not our node counts have changed
// Not really needed - we will save anyways when we go to sleep
// We just changed something important about the user, store our DB
// saveToDisk();
}
}
/// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp)
@@ -415,58 +441,21 @@ void NodeDB::updateFrom(const MeshPacket &mp)
switch (p.which_payload) {
case SubPacket_position_tag: {
// we always trust our local timestamps more
info->position = p.position;
if (mp.rx_time)
info->position.time = mp.rx_time;
info->has_position = true;
updateGUIforNode = info;
notifyObservers(true); // Force an update whether or not our node counts have changed
// handle a legacy position packet
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from);
updatePosition(mp.from, p.position);
break;
}
case SubPacket_data_tag: {
// Keep a copy of the most recent text message.
if (p.data.typ == Data_Type_CLEAR_TEXT) {
DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.data.payload.size,
p.data.payload.bytes);
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) {
// We only store/display messages destined for us.
devicestate.rx_text_message = mp;
devicestate.has_rx_text_message = true;
updateTextMessage = true;
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
notifyObservers(true); // Force an update whether or not our node counts have changed
// This is going into the wifidev feature branch
// Only update the WebUI if WiFi is enabled
//#if WiFi_MODE != 0
// notifyWebUI();
//#endif
}
}
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum())
MeshPlugin::callPlugins(mp);
break;
}
case SubPacket_user_tag: {
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
bool changed = memcmp(&info->user, &p.user,
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
info->user = p.user;
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
info->has_user = true;
if (changed) {
updateGUIforNode = info;
powerFSM.trigger(EVENT_NODEDB_UPDATED);
notifyObservers(true); // Force an update whether or not our node counts have changed
// Not really needed - we will save anyways when we go to sleep
// We just changed something important about the user, store our DB
// saveToDisk();
}
DEBUG_MSG("WARNING: Processing a (deprecated) user packet from %d\n", mp.from);
updateUser(mp.from, p.user);
break;
}

View File

@@ -33,7 +33,6 @@ class NodeDB
public:
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled
NodeInfo *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
bool updateTextMessage = false; // if true, the GUI should show a new text message
Observable<const meshtastic::NodeStatus *> newStatus;
/// don't do mesh based algoritm for node id assignment (initially)
@@ -58,6 +57,14 @@ class NodeDB
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void updateFrom(const MeshPacket &p);
/** Update position info for this node based on received position data
*/
void updatePosition(uint32_t nodeId, const Position &p);
/** Update user info for this node based on received user data
*/
void updateUser(uint32_t nodeId, const User &p);
/// @return our node number
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }

View File

@@ -0,0 +1,3 @@
#include "ProtobufPlugin.h"

66
src/mesh/ProtobufPlugin.h Normal file
View File

@@ -0,0 +1,66 @@
#pragma once
#include "SinglePortPlugin.h"
/**
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
* payload. Using one particular app ID.
*
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
* and avoid a bunch of boilerplate code.
*/
template <class T> class ProtobufPlugin : private SinglePortPlugin
{
const pb_msgdesc_t *fields;
public:
/** Constructor
* name is for debugging output
*/
ProtobufPlugin(const char *_name, PortNum _ourPortNum, const pb_msgdesc_t *_fields)
: SinglePortPlugin(_name, _ourPortNum), fields(_fields)
{
}
protected:
/**
* Handle a received message, the data field in the message is already decoded and is provided
*/
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T &decoded) = 0;
/**
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.
* You can then send this packet (after customizing any of the payload fields you might need) with
* service.sendToMesh()
*/
MeshPacket *allocDataProtobuf(const T &payload)
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocDataPacket();
p->decoded.data.payload.size =
pb_encode_to_bytes(p->decoded.data.payload.bytes, sizeof(p->decoded.data.payload.bytes), fields, &payload);
// DEBUG_MSG("did encode\n");
return p;
}
private:
/** Called to handle a particular incoming message
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual bool handleReceived(const MeshPacket &mp)
{
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
// it would be better to update even if the message was destined to others.
auto &p = mp.decoded.data;
DEBUG_MSG("Received %s from=0x%0x, id=%d, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
T scratch;
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
handleReceivedProtobuf(mp, scratch);
return false; // Let others look at this message also if they want
}
};

View File

@@ -26,7 +26,18 @@ const RegionInfo regions[] = {
RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last
};
static const RegionInfo *myRegion;
const RegionInfo *myRegion;
void initRegion()
{
const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
}
/**
* ## LoRaWAN for North America
@@ -42,6 +53,68 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
// 1kb was too small
#define RADIO_STACK_SIZE 4096
/**
* Calculate airtime per
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
* section 4
*
* @return num msecs for the packet
*/
uint32_t RadioInterface::getPacketTime(uint32_t pl)
{
float bandwidthHz = bw * 1000.0f;
bool headDisable = false; // we currently always use the header
float tSym = (1 << sf) / bandwidthHz;
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
float tPreamble = (preambleLength + 4.25f) * tSym;
float numPayloadSym =
8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
float tPayload = numPayloadSym * tSym;
float tPacket = tPreamble + tPayload;
uint32_t msecs = tPacket * 1000;
DEBUG_MSG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
pl, msecs);
return msecs;
}
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
{
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
return getPacketTime(pl);
}
/** The delay to use for retransmitting dropped packets */
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
{
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
}
/** The delay to use when we want to send something but the ether is busy */
uint32_t RadioInterface::getTxDelayMsec()
{
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
* has had enough time to switch their radio back into receive mode.
*/
const uint32_t MIN_TX_WAIT_MSEC = 100;
/**
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
* to guarantee this.
*/
// const uint32_t MAX_TX_WAIT_MSEC = 2000; // stress test would still fail occasionally with 1000
return random(MIN_TX_WAIT_MSEC, shortPacketMsec);
}
void printPacket(const char *prefix, const MeshPacket *p)
{
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
@@ -91,20 +164,10 @@ void printPacket(const char *prefix, const MeshPacket *p)
DEBUG_MSG(")\n");
}
RadioInterface::RadioInterface()
RadioInterface::RadioInterface()
{
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
if (!myRegion) {
const RegionInfo *r = regions;
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
;
myRegion = r;
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have
}
// Can't print strings this early - serial not setup yet
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
}
@@ -120,10 +183,16 @@ bool RadioInterface::init()
// we now expect interfaces to operate in promiscous mode
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
// time.
return true;
}
int RadioInterface::notifyDeepSleepCb(void *unused)
{
sleep();
return 0;
}
/** hash a string into an integer
*
* djb2 by Dan Bernstein.
@@ -148,8 +217,47 @@ void RadioInterface::applyModemConfig()
// Set up default configuration
// No Sync Words in LORA mode
if (channelSettings.spread_factor == 0) {
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
///< range
bw = 125;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
///< range
bw = 500;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
///< range
bw = 31.25;
cr = 8;
sf = 9;
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
bw = 125;
cr = 8;
sf = 12;
break;
default:
assert(0); // Unknown enum
}
} else {
sf = channelSettings.spread_factor;
cr = channelSettings.coding_rate;
bw = channelSettings.bandwidth;
if (bw == 31) // This parameter is not an integer
bw = 31.25;
}
power = channelSettings.tx_power;
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
assert(myRegion); // Should have been found in init
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
@@ -164,6 +272,7 @@ void RadioInterface::applyModemConfig()
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
DEBUG_MSG("Radio frequency: %f\n", freq);
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
}
/**

View File

@@ -48,9 +48,18 @@ class RadioInterface
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::preflightSleepCb);
CallbackObserver<RadioInterface, void *> notifyDeepSleepObserver =
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepDb);
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepCb);
/// Number of msecs we expect our shortest actual packet to be over the wire (used in retry timeout calcs)
uint32_t shortPacketMsec;
protected:
float bw = 125;
uint8_t sf = 9;
uint8_t cr = 7;
uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
uint32_t lastTxStart = 0L;
@@ -108,6 +117,22 @@ class RadioInterface
/// \return true if initialisation succeeded.
virtual bool reconfigure() = 0;
/** The delay to use for retransmitting dropped packets */
uint32_t getRetransmissionMsec(const MeshPacket *p);
/** The delay to use when we want to send something but the ether is busy */
uint32_t getTxDelayMsec();
/**
* Calculate airtime per
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
* section 4
*
* @return num msecs for the packet
*/
uint32_t getPacketTime(MeshPacket *p);
uint32_t getPacketTime(uint32_t totalPacketLen);
protected:
int8_t power = 17; // Set by applyModemConfig()
@@ -136,11 +161,7 @@ class RadioInterface
/// Return 0 if sleep is okay
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
int notifyDeepSleepDb(void *unused = NULL)
{
sleep();
return 0;
}
int notifyDeepSleepCb(void *unused = NULL);
int reloadConfig(void *unused)
{

View File

@@ -58,50 +58,6 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0()
*/
RadioLibInterface *RadioLibInterface::instance;
/**
* Convert our modemConfig enum into wf, sf, etc...
*/
void RadioLibInterface::applyModemConfig()
{
RadioInterface::applyModemConfig();
if (channelSettings.spread_factor == 0) {
switch (channelSettings.modem_config) {
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
///< range
bw = 125;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
///< range
bw = 500;
cr = 5;
sf = 7;
break;
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
///< range
bw = 31.25;
cr = 8;
sf = 9;
break;
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
bw = 125;
cr = 8;
sf = 12;
break;
default:
assert(0); // Unknown enum
}
} else {
sf = channelSettings.spread_factor;
cr = channelSettings.coding_rate;
bw = channelSettings.bandwidth;
if (bw == 31) // This parameter is not an integer
bw = 31.25;
}
}
/** Could we send right now (i.e. either not actively receving or transmitting)? */
bool RadioLibInterface::canSendImmediately()
@@ -130,6 +86,8 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
// Sometimes when testing it is useful to be able to never turn on the xmitter
#ifndef LORA_DISABLE_SENDING
printPacket("enqueuing for send", p);
uint32_t xmitMsec = getPacketTime(p);
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
@@ -158,19 +116,6 @@ bool RadioLibInterface::canSleep()
return res;
}
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
* has had enough time to switch their radio back into receive mode.
*/
#define MIN_TX_WAIT_MSEC 100
/**
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
* to guarantee this.
*/
#define MAX_TX_WAIT_MSEC 2000 // stress test would still fail occasionally with 1000
/** radio helper thread callback.
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
@@ -226,8 +171,7 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
{
// If we have work to do and the timer wasn't already scheduled, schedule it now
if (!txQueue.isEmpty()) {
uint32_t delay =
!withDelay ? 1 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
// DEBUG_MSG("xmit timer %d\n", delay);
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
}
@@ -236,20 +180,25 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
void RadioLibInterface::handleTransmitInterrupt()
{
// DEBUG_MSG("handling lora TX interrupt\n");
assert(sendingPacket); // Were we sending? - FIXME, this was null coming out of light sleep due to RF95 ISR!
completeSending();
// This can be null if we forced the device to enter standby mode. In that case
// ignore the transmit interrupt
if (sendingPacket)
completeSending();
}
void RadioLibInterface::completeSending()
{
if (sendingPacket) {
// We are careful to clear sending packet before calling printPacket because
// that can take a long time
auto p = sendingPacket;
sendingPacket = NULL;
if (p) {
txGood++;
printPacket("Completed sending", sendingPacket);
printPacket("Completed sending", p);
// We are done sending that packet, release it
packetPool.release(sendingPacket);
sendingPacket = NULL;
packetPool.release(p);
// DEBUG_MSG("Done with send\n");
}
}
@@ -295,7 +244,7 @@ void RadioLibInterface::handleReceiveInterrupt()
addReceiveMetadata(mp);
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
assert(payloadLen <= sizeof(mp->encrypted.bytes));
assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes));
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
@@ -305,7 +254,7 @@ void RadioLibInterface::handleReceiveInterrupt()
}
}
}
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket *txp)
{

View File

@@ -77,9 +77,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
protected:
float bw = 125;
uint8_t sf = 9;
uint8_t cr = 7;
/**
* FIXME, use a meshtastic sync word, but hashed with the Channel name. Currently picking the same default
@@ -88,7 +85,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE;
float currentLimit = 100; // FIXME
uint16_t preambleLength = 32; // 8 is default, but FIXME use longer to increase the amount of sleep time when receiving
LockingModule module; // The HW interface to the radio
@@ -165,13 +161,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
virtual void configHardwareForSend() {}
/**
* Convert our modemConfig enum into wf, sf, etc...
*
* These paramaters will be pull from the channelSettings global
*/
virtual void applyModemConfig();
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
virtual bool canSendImmediately();

View File

@@ -111,7 +111,6 @@ PendingPacket::PendingPacket(MeshPacket *p)
{
packet = p;
numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send
setNextTx();
}
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
@@ -151,6 +150,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
auto id = GlobalPacketId(p);
auto rec = PendingPacket(p);
setNextTx(&rec);
stopRetransmission(p->from, p->id);
pending[id] = rec;
@@ -190,10 +190,9 @@ int32_t ReliableRouter::doRetransmissions()
// Queue again
--p.numRetransmissions;
p.setNextTx();
setNextTx(&p);
}
}
else {
} else {
// Not yet time
int32_t t = p.nextTxMsec - now;

View File

@@ -46,8 +46,6 @@ struct PendingPacket {
PendingPacket() {}
PendingPacket(MeshPacket *p);
void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); }
};
class GlobalPacketIdHashFunction
@@ -130,4 +128,8 @@ class ReliableRouter : public FloodingRouter
* @return the number of msecs until our next retransmission or MAXINT if none scheduled
*/
int32_t doRetransmissions();
void setNextTx(PendingPacket *pending) {
assert(iface);
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
};

View File

@@ -14,12 +14,13 @@
class Router : protected concurrency::OSThread
{
private:
RadioInterface *iface;
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
/// forwarded to the phone.
PointerQueue<MeshPacket> fromRadioQueue;
protected:
RadioInterface *iface = NULL;
public:
/// Local services that want to see _every_ packet this node receives can observe this.
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting

View File

@@ -1,6 +1,11 @@
#include "SX1262Interface.h"
#include <configuration.h>
// Particular boards might define a different max power based on what their hardware can do
#ifndef SX1262_MAX_POWER
#define SX1262_MAX_POWER 22
#endif
SX1262Interface::SX1262Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
SPIClass &spi)
: RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
@@ -39,10 +44,10 @@ bool SX1262Interface::init()
applyModemConfig();
if (power == 0)
power = 22;
power = SX1262_MAX_POWER;
if (power > 22) // This chip has lower power limits than some
power = 22;
if (power > SX1262_MAX_POWER) // This chip has lower power limits than some
power = SX1262_MAX_POWER;
limitPower();
@@ -82,8 +87,8 @@ bool SX1262Interface::reconfigure()
assert(err == ERR_NONE);
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
// err = lora.setRxGain(true);
// assert(err == ERR_NONE);
err = lora.setRxGain(true);
assert(err == ERR_NONE);
err = lora.setSyncWord(syncWord);
assert(err == ERR_NONE);
@@ -196,9 +201,21 @@ bool SX1262Interface::isActivelyReceiving()
bool SX1262Interface::sleep()
{
// put chipset into sleep mode
disableInterrupt();
lora.sleep();
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
DEBUG_MSG("sx1262 entering sleep mode (FIXME, don't keep config)\n");
setStandby(); // Stop any pending operations
// turn off TCXO if it was powered
// FIXME - this isn't correct
// lora.setTCXO(0);
// put chipset into sleep mode (we've already disabled interrupts by now)
bool keepConfig = true;
lora.sleep(keepConfig); // Note: we do not keep the config, full reinit will be needed
#ifdef SX1262_POWER_EN
digitalWrite(SX1262_POWER_EN, LOW);
#endif
return true;
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "MeshPlugin.h"
#include "Router.h"
/**
* Most plugins are only interested in sending/receving one particular portnum. This baseclass simplifies that common
* case.
*/
class SinglePortPlugin : public MeshPlugin
{
protected:
PortNum ourPortNum;
public:
/** Constructor
* name is for debugging output
*/
SinglePortPlugin(const char *_name, PortNum _ourPortNum) : MeshPlugin(_name), ourPortNum(_ourPortNum) {}
protected:
/**
* @return true if you want to receive the specified portnum
*/
virtual bool wantPortnum(PortNum p) { return p == ourPortNum; }
/**
* Return a mesh packet which has been preinited as a data packet with a particular port number.
* You can then send this packet (after customizing any of the payload fields you might need) with
* service.sendToMesh()
*/
MeshPacket *allocDataPacket()
{
// Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = router->allocForSending();
p->decoded.which_payload = SubPacket_data_tag;
p->decoded.data.portnum = ourPortNum;
return p;
}
};

View File

@@ -51,10 +51,6 @@ PB_BIND(FromRadio, FromRadio, 2)
PB_BIND(ToRadio, ToRadio, 2)
PB_BIND(ManufacturingData, ManufacturingData, AUTO)

View File

@@ -4,6 +4,7 @@
#ifndef PB_MESH_PB_H_INCLUDED
#define PB_MESH_PB_H_INCLUDED
#include <pb.h>
#include "portnums.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -22,7 +23,8 @@ typedef enum _RouteError {
} RouteError;
typedef enum _Constants {
Constants_Unused = 0
Constants_Unused = 0,
Constants_DATA_PAYLOAD_LEN = 240
} Constants;
typedef enum _RegionCode {
@@ -50,12 +52,6 @@ typedef enum _LocationSharing {
LocationSharing_LocDisabled = 2
} LocationSharing;
typedef enum _Data_Type {
Data_Type_OPAQUE = 0,
Data_Type_CLEAR_TEXT = 1,
Data_Type_CLEAR_READACK = 2
} Data_Type;
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
@@ -78,7 +74,7 @@ typedef struct _ChannelSettings {
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
typedef struct _Data {
Data_Type typ;
PortNum portnum;
Data_payload_t payload;
} Data;
@@ -86,13 +82,6 @@ typedef struct _DebugString {
char message[256];
} DebugString;
typedef struct _ManufacturingData {
uint32_t fradioFreq;
pb_callback_t hw_model;
pb_callback_t hw_version;
int32_t selftest_result;
} ManufacturingData;
typedef struct _MyNodeInfo {
uint32_t my_node_num;
bool has_gps;
@@ -140,7 +129,9 @@ typedef struct _RadioConfig_UserPreferences {
uint32_t gps_attempt_time;
bool is_router;
bool is_low_power;
bool fixed_position;
bool factory_reset;
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
} RadioConfig_UserPreferences;
@@ -260,8 +251,8 @@ typedef struct _ToRadio {
#define _RouteError_ARRAYSIZE ((RouteError)(RouteError_TIMEOUT+1))
#define _Constants_MIN Constants_Unused
#define _Constants_MAX Constants_Unused
#define _Constants_ARRAYSIZE ((Constants)(Constants_Unused+1))
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
#define _RegionCode_MIN RegionCode_Unset
#define _RegionCode_MAX RegionCode_TW
@@ -275,10 +266,6 @@ typedef struct _ToRadio {
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
#define _Data_Type_MIN Data_Type_OPAQUE
#define _Data_Type_MAX Data_Type_CLEAR_READACK
#define _Data_Type_ARRAYSIZE ((Data_Type)(Data_Type_CLEAR_READACK+1))
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
@@ -286,37 +273,35 @@ typedef struct _ToRadio {
/* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, 0}
#define Data_init_default {_Data_Type_MIN, {0, {0}}}
#define Data_init_default {_PortNum_MIN, {0, {0}}}
#define User_init_default {"", "", "", {0}}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
#define DebugString_init_default {""}
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define ManufacturingData_init_default {0, {{NULL}, NULL}, {{NULL}, NULL}, 0}
#define Position_init_zero {0, 0, 0, 0, 0}
#define Data_init_zero {_Data_Type_MIN, {0, {0}}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}}
#define User_init_zero {"", "", "", {0}}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
#define DebugString_init_zero {""}
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
#define ManufacturingData_init_zero {0, {{NULL}, NULL}, {{NULL}, NULL}, 0}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSettings_tx_power_tag 1
@@ -327,13 +312,9 @@ typedef struct _ToRadio {
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5
#define Data_typ_tag 1
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define DebugString_message_tag 1
#define ManufacturingData_fradioFreq_tag 1
#define ManufacturingData_hw_model_tag 2
#define ManufacturingData_hw_version_tag 3
#define ManufacturingData_selftest_result_tag 4
#define MyNodeInfo_my_node_num_tag 1
#define MyNodeInfo_has_gps_tag 2
#define MyNodeInfo_num_channels_tag 3
@@ -370,7 +351,9 @@ typedef struct _ToRadio {
#define RadioConfig_UserPreferences_region_tag 15
#define RadioConfig_UserPreferences_is_router_tag 37
#define RadioConfig_UserPreferences_is_low_power_tag 38
#define RadioConfig_UserPreferences_fixed_position_tag 39
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_location_share_tag 32
#define RadioConfig_UserPreferences_gps_operation_tag 33
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
@@ -442,7 +425,7 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9)
#define Position_DEFAULT NULL
#define Data_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, typ, 1) \
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
X(a, STATIC, SINGULAR, BYTES, payload, 2)
#define Data_CALLBACK NULL
#define Data_DEFAULT NULL
@@ -537,7 +520,9 @@ X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
@@ -623,14 +608,6 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102)
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
#define ToRadio_variant_set_owner_MSGTYPE User
#define ManufacturingData_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, fradioFreq, 1) \
X(a, CALLBACK, SINGULAR, STRING, hw_model, 2) \
X(a, CALLBACK, SINGULAR, STRING, hw_version, 3) \
X(a, STATIC, SINGULAR, SINT32, selftest_result, 4)
#define ManufacturingData_CALLBACK pb_default_field_callback
#define ManufacturingData_DEFAULT NULL
extern const pb_msgdesc_t Position_msg;
extern const pb_msgdesc_t Data_msg;
extern const pb_msgdesc_t User_msg;
@@ -646,7 +623,6 @@ extern const pb_msgdesc_t DeviceState_msg;
extern const pb_msgdesc_t DebugString_msg;
extern const pb_msgdesc_t FromRadio_msg;
extern const pb_msgdesc_t ToRadio_msg;
extern const pb_msgdesc_t ManufacturingData_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Position_fields &Position_msg
@@ -664,25 +640,23 @@ extern const pb_msgdesc_t ManufacturingData_msg;
#define DebugString_fields &DebugString_msg
#define FromRadio_fields &FromRadio_msg
#define ToRadio_fields &ToRadio_msg
#define ManufacturingData_fields &ManufacturingData_msg
/* Maximum encoded size of messages (where known) */
#define Position_size 39
#define Data_size 245
#define Data_size 246
#define User_size 72
#define RouteDiscovery_size 88
#define SubPacket_size 274
#define MeshPacket_size 313
#define SubPacket_size 275
#define MeshPacket_size 314
#define ChannelSettings_size 84
#define RadioConfig_size 308
#define RadioConfig_UserPreferences_size 219
#define RadioConfig_size 314
#define RadioConfig_UserPreferences_size 225
#define NodeInfo_size 132
#define MyNodeInfo_size 110
#define DeviceState_size 5460
#define DeviceState_size 5468
#define DebugString_size 258
#define FromRadio_size 322
#define ToRadio_size 316
/* ManufacturingData_size depends on runtime parameters */
#define FromRadio_size 323
#define ToRadio_size 318
#ifdef __cplusplus
} /* extern "C" */

10
src/mesh/portnums.pb.c Normal file
View File

@@ -0,0 +1,10 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.1 */
#include "portnums.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif

37
src/mesh/portnums.pb.h Normal file
View File

@@ -0,0 +1,37 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.1 */
#ifndef PB_PORTNUMS_PB_H_INCLUDED
#define PB_PORTNUMS_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _PortNum {
PortNum_UNKNOWN_APP = 0,
PortNum_TEXT_MESSAGE_APP = 1,
PortNum_REMOTE_HARDWARE_APP = 2,
PortNum_POSITION_APP = 3,
PortNum_NODEINFO_APP = 4,
PortNum_PRIVATE_APP = 256,
PortNum_IP_TUNNEL_APP = 1024
} PortNum;
/* Helper constants for enums */
#define _PortNum_MIN PortNum_UNKNOWN_APP
#define _PortNum_MAX PortNum_IP_TUNNEL_APP
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_IP_TUNNEL_APP+1))
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

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

View File

@@ -0,0 +1,69 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.1 */
#ifndef PB_REMOTE_HARDWARE_PB_H_INCLUDED
#define PB_REMOTE_HARDWARE_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _HardwareMessage_Type {
HardwareMessage_Type_UNSET = 0,
HardwareMessage_Type_WRITE_GPIOS = 1,
HardwareMessage_Type_WATCH_GPIOS = 2,
HardwareMessage_Type_GPIOS_CHANGED = 3,
HardwareMessage_Type_READ_GPIOS = 4,
HardwareMessage_Type_READ_GPIOS_REPLY = 5
} HardwareMessage_Type;
/* Struct definitions */
typedef struct _HardwareMessage {
HardwareMessage_Type typ;
uint64_t gpio_mask;
uint64_t gpio_value;
} HardwareMessage;
/* Helper constants for enums */
#define _HardwareMessage_Type_MIN HardwareMessage_Type_UNSET
#define _HardwareMessage_Type_MAX HardwareMessage_Type_READ_GPIOS_REPLY
#define _HardwareMessage_Type_ARRAYSIZE ((HardwareMessage_Type)(HardwareMessage_Type_READ_GPIOS_REPLY+1))
/* Initializer values for message structs */
#define HardwareMessage_init_default {_HardwareMessage_Type_MIN, 0, 0}
#define HardwareMessage_init_zero {_HardwareMessage_Type_MIN, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define HardwareMessage_typ_tag 1
#define HardwareMessage_gpio_mask_tag 2
#define HardwareMessage_gpio_value_tag 3
/* Struct field encoding specification for nanopb */
#define HardwareMessage_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, typ, 1) \
X(a, STATIC, SINGULAR, UINT64, gpio_mask, 2) \
X(a, STATIC, SINGULAR, UINT64, gpio_value, 3)
#define HardwareMessage_CALLBACK NULL
#define HardwareMessage_DEFAULT NULL
extern const pb_msgdesc_t HardwareMessage_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define HardwareMessage_fields &HardwareMessage_msg
/* Maximum encoded size of messages (where known) */
#define HardwareMessage_size 24
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,126 @@
#include <Arduino.h>
#include <functional>
/*
Steps:
- Compress the .js file to .js.gz
- Convert to hex:
http://tomeko.net/online_tools/file_to_hex.php?lang=en
- Paste into the array
- Note the filesize of your .gz file and write the file
size into the length int.
*/
// Length of the binary data
const int FAVICON_LENGTH = 2238;
// Binary data for the favicon
const byte FAVICON_DATA[] = {
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0xA8, 0x08, 0x00, 0x00, 0x16, 0x00, 0x00,
0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x84,
0xDC, 0x3D, 0x00, 0x84, 0xDC, 0x3C, 0x00, 0x85, 0xDC, 0x3F, 0x00, 0x86, 0xDD, 0x40, 0x00, 0x83, 0xDC, 0x3C, 0x00, 0x85, 0xDC,
0x3E, 0x00, 0x82, 0xDC, 0x3A, 0x00, 0x8B, 0xDE, 0x49, 0x00, 0x84, 0xDB, 0x3E, 0x00, 0x82, 0xD9, 0x3C, 0x00, 0x89, 0xDD, 0x45,
0x00, 0x83, 0xDB, 0x3C, 0x00, 0x83, 0xD8, 0x3D, 0x00, 0x81, 0xD8, 0x3A, 0x00, 0x8D, 0xE0, 0x49, 0x00, 0x88, 0xE4, 0x3F, 0x00,
0x89, 0xE9, 0x3E, 0x00, 0x84, 0xD8, 0x40, 0x00, 0x85, 0xDF, 0x3C, 0x00, 0x8E, 0xF2, 0x40, 0x00, 0x8D, 0xF6, 0x3D, 0x00, 0x90,
0xEA, 0x49, 0x00, 0x82, 0xD5, 0x3E, 0x00, 0x78, 0xC1, 0x3A, 0x00, 0x90, 0xE9, 0x4A, 0x00, 0x8E, 0xF5, 0x3D, 0x00, 0x84, 0xDD,
0x3D, 0x00, 0x91, 0xF7, 0x43, 0x00, 0x87, 0xE5, 0x3D, 0x00, 0x6C, 0xA2, 0x38, 0x00, 0x53, 0x65, 0x31, 0x00, 0x41, 0x39, 0x2E,
0x00, 0x3A, 0x27, 0x2B, 0x00, 0x34, 0x1A, 0x2A, 0x00, 0x41, 0x38, 0x2E, 0x00, 0x82, 0xD8, 0x3D, 0x00, 0x88, 0xE7, 0x3D, 0x00,
0x8E, 0xF3, 0x41, 0x00, 0x69, 0x95, 0x39, 0x00, 0x3E, 0x33, 0x2C, 0x00, 0x31, 0x11, 0x29, 0x00, 0x2E, 0x0A, 0x29, 0x00, 0x2D,
0x0B, 0x27, 0x00, 0x30, 0x10, 0x29, 0x00, 0x34, 0x18, 0x2A, 0x00, 0x3E, 0x31, 0x2C, 0x00, 0x68, 0x95, 0x39, 0x00, 0x88, 0xE7,
0x3E, 0x00, 0x82, 0xD7, 0x3C, 0x00, 0x84, 0xDD, 0x3C, 0x00, 0x8B, 0xEE, 0x3E, 0x00, 0x85, 0xDF, 0x3D, 0x00, 0x47, 0x48, 0x2E,
0x00, 0x30, 0x0F, 0x29, 0x00, 0x31, 0x13, 0x29, 0x00, 0x48, 0x4D, 0x2E, 0x00, 0x61, 0x7F, 0x39, 0x00, 0x6A, 0x9C, 0x38, 0x00,
0x75, 0xB8, 0x39, 0x00, 0x85, 0xDE, 0x3D, 0x00, 0x8C, 0xEF, 0x3E, 0x00, 0x89, 0xDE, 0x44, 0x00, 0x80, 0xD1, 0x3C, 0x00, 0x3A,
0x28, 0x2C, 0x00, 0x32, 0x16, 0x2A, 0x00, 0x33, 0x17, 0x2A, 0x00, 0x4B, 0x50, 0x30, 0x00, 0x76, 0xBA, 0x3A, 0x00, 0x8A, 0xEF,
0x3C, 0x00, 0x9A, 0xFE, 0x4D, 0x00, 0x95, 0xFF, 0x43, 0x00, 0x93, 0xFF, 0x40, 0x00, 0x4B, 0x52, 0x30, 0x00, 0x7E, 0xCE, 0x3C,
0x00, 0x87, 0xD9, 0x44, 0x00, 0x34, 0x1B, 0x2A, 0x00, 0x65, 0x90, 0x36, 0x00, 0x8E, 0xF6, 0x3D, 0x00, 0x8F, 0xF7, 0x40, 0x00,
0x8B, 0xDD, 0x48, 0x00, 0x73, 0xB1, 0x3A, 0x00, 0x66, 0x95, 0x35, 0x00, 0x66, 0x93, 0x35, 0x00, 0x35, 0x1B, 0x2A, 0x00, 0x8D,
0xE8, 0x45, 0x00, 0x82, 0xD9, 0x3B, 0x00, 0x72, 0xAA, 0x3C, 0x00, 0x95, 0xFD, 0x46, 0x00, 0x8D, 0xF0, 0x40, 0x00, 0x57, 0x70,
0x32, 0x00, 0x3C, 0x2D, 0x2C, 0x00, 0x2F, 0x0D, 0x29, 0x00, 0x81, 0xD4, 0x3D, 0x00, 0x8D, 0xF1, 0x40, 0x00, 0x94, 0xFC, 0x46,
0x00, 0x73, 0xAE, 0x3D, 0x00, 0x45, 0x44, 0x2D, 0x00, 0x94, 0xF5, 0x49, 0x00, 0x90, 0xF0, 0x45, 0x00, 0x73, 0xAF, 0x3B, 0x00,
0x38, 0x21, 0x2C, 0x00, 0x30, 0x11, 0x29, 0x00, 0x2F, 0x0F, 0x28, 0x00, 0x72, 0xAC, 0x3B, 0x00, 0x6A, 0x93, 0x3D, 0x00, 0x2E,
0x0D, 0x27, 0x00, 0x35, 0x1C, 0x2B, 0x00, 0x36, 0x20, 0x2A, 0x00, 0x5E, 0x77, 0x39, 0x00, 0x78, 0xBE, 0x3B, 0x00, 0x36, 0x21,
0x2A, 0x00, 0x71, 0xAB, 0x3B, 0x00, 0x4C, 0x54, 0x30, 0x00, 0x3D, 0x31, 0x2B, 0x00, 0x82, 0xD6, 0x3D, 0x00, 0x79, 0xC5, 0x39,
0x00, 0x9A, 0xFF, 0x4D, 0x00, 0x8A, 0xE8, 0x40, 0x00, 0x8A, 0xE7, 0x40, 0x00, 0x7A, 0xC6, 0x39, 0x00, 0x3D, 0x2E, 0x2C, 0x00,
0x81, 0xD5, 0x3D, 0x00, 0x77, 0xBC, 0x3A, 0x00, 0x31, 0x12, 0x2A, 0x00, 0x69, 0x9B, 0x37, 0x00, 0x8E, 0xF3, 0x40, 0x00, 0x83,
0xDC, 0x3B, 0x00, 0x8C, 0xF6, 0x3B, 0x00, 0x88, 0xD9, 0x45, 0x00, 0x86, 0xE1, 0x3D, 0x00, 0x85, 0xE0, 0x3D, 0x00, 0x7B, 0xC8,
0x39, 0x00, 0x36, 0x1F, 0x29, 0x00, 0x55, 0x6B, 0x32, 0x00, 0x8A, 0xEE, 0x3C, 0x00, 0x48, 0x4B, 0x2E, 0x00, 0x51, 0x61, 0x31,
0x00, 0x8C, 0xE0, 0x48, 0x00, 0x8B, 0xDE, 0x47, 0x00, 0x98, 0xEE, 0x55, 0x00, 0x5D, 0x79, 0x36, 0x00, 0x3A, 0x2A, 0x2B, 0x00,
0x3A, 0x29, 0x2B, 0x00, 0x5C, 0x78, 0x36, 0x00, 0x60, 0x7C, 0x3A, 0x00, 0x3D, 0x30, 0x2C, 0x00, 0x99, 0xFD, 0x4C, 0x00, 0x66,
0x8A, 0x3C, 0x00, 0x2D, 0x0C, 0x27, 0x00, 0x42, 0x3C, 0x2E, 0x00, 0x84, 0xDA, 0x3E, 0x00, 0x88, 0xE5, 0x3F, 0x00, 0x37, 0x22,
0x2B, 0x00, 0x2E, 0x0B, 0x28, 0x00, 0x6A, 0x9B, 0x37, 0x00, 0x72, 0xAF, 0x3A, 0x00, 0x32, 0x15, 0x29, 0x00, 0x2A, 0x00, 0x28,
0x00, 0x5B, 0x75, 0x35, 0x00, 0x89, 0xE8, 0x3D, 0x00, 0x78, 0xBF, 0x3A, 0x00, 0x73, 0xB4, 0x38, 0x00, 0x83, 0xDA, 0x3C, 0x00,
0x84, 0xDE, 0x3C, 0x00, 0x85, 0xDD, 0x3E, 0x00, 0x86, 0xDE, 0x40, 0x00, 0x84, 0xDE, 0x3B, 0x00, 0x86, 0xE2, 0x3C, 0x00, 0x85,
0xDD, 0x3F, 0x00, 0x87, 0xE2, 0x3F, 0x00, 0x87, 0xE1, 0x3E, 0x00, 0x85, 0xDE, 0x3E, 0x00, 0x89, 0xE2, 0x41, 0x00, 0x89, 0xE2,
0x43, 0x00, 0x84, 0xDC, 0x3E, 0x00, 0x83, 0xD8, 0x3E, 0x00, 0x90, 0xF6, 0x41, 0x00, 0x2B, 0x04, 0x28, 0x00, 0x8C, 0xE3, 0x47,
0x00, 0x8B, 0xDE, 0x48, 0x00, 0x8A, 0xDC, 0x47, 0x00, 0x8A, 0xDD, 0x47, 0x00, 0x8D, 0xDD, 0x4A, 0x00, 0x8A, 0xDE, 0x47, 0x00,
0x8B, 0xDD, 0x49, 0x00, 0x8B, 0xE0, 0x46, 0x00, 0x9A, 0xF2, 0x55, 0x00, 0x59, 0x70, 0x35, 0x00, 0x8F, 0xDE, 0x4F, 0x00, 0x82,
0xDC, 0x3B, 0x00, 0x82, 0xDB, 0x39, 0x00, 0x7F, 0xD7, 0x38, 0x00, 0x92, 0xF0, 0x48, 0x00, 0x33, 0x19, 0x29, 0x00, 0x87, 0xDD,
0x42, 0x00, 0x87, 0xDD, 0x41, 0x00, 0x92, 0xEC, 0x4B, 0x00, 0x78, 0xBD, 0x3C, 0x00, 0x86, 0xDD, 0x3F, 0x00, 0x81, 0xD9, 0x39,
0x00, 0x7B, 0xC4, 0x3C, 0x00, 0x34, 0x1A, 0x29, 0x00, 0x89, 0xDD, 0x44, 0x00, 0x86, 0xDC, 0x40, 0x00, 0x88, 0xDD, 0x44, 0x00,
0x87, 0xDE, 0x41, 0x00, 0x99, 0xFA, 0x4F, 0x00, 0x7B, 0xC3, 0x3E, 0x00, 0x83, 0xD7, 0x3F, 0x00, 0x8B, 0xED, 0x3E, 0x00, 0x40,
0x33, 0x2F, 0x00, 0x39, 0x27, 0x2B, 0x00, 0x81, 0xD7, 0x3B, 0x00, 0x3B, 0x2C, 0x2A, 0x00, 0x33, 0x18, 0x29, 0x00, 0x38, 0x22,
0x2B, 0x00, 0x85, 0xDA, 0x40, 0x00, 0x89, 0xEA, 0x3D, 0x00, 0x6F, 0xA9, 0x38, 0x00, 0x70, 0xAB, 0x38, 0x00, 0x85, 0xDD, 0x3D,
0x00, 0x88, 0xE1, 0x40, 0x00, 0x36, 0x1F, 0x2B, 0x00, 0x30, 0x13, 0x28, 0x00, 0x68, 0x9A, 0x36, 0x00, 0x90, 0xFB, 0x3F, 0x00,
0x8A, 0xDD, 0x46, 0x00, 0x8D, 0xE9, 0x45, 0x00, 0x5A, 0x71, 0x36, 0x00, 0x27, 0x00, 0x24, 0x00, 0x73, 0x9F, 0x45, 0x00, 0x97,
0xFE, 0x4A, 0x00, 0x86, 0xD8, 0x43, 0x00, 0x73, 0xA1, 0x45, 0x00, 0x8E, 0xDF, 0x4C, 0x00, 0x85, 0xDB, 0x40, 0x00, 0x72, 0xB5,
0x37, 0x00, 0x95, 0xF4, 0x4B, 0x00, 0x73, 0xB6, 0x37, 0x00, 0x88, 0xE9, 0x3C, 0x00, 0x8A, 0xDB, 0x48, 0x00, 0x8C, 0xDE, 0x49,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0xAE, 0x06, 0xF1, 0x02, 0x04, 0x04, 0x02, 0xF1, 0x06, 0xAE, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01,
0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0xAE, 0xC7, 0xF1, 0x02, 0x04,
0x04, 0x02, 0xF1, 0xC7, 0xAE, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x03, 0x0B, 0xAE, 0xEF, 0xF0, 0x02, 0x01, 0x01, 0x02, 0xB4, 0xEF, 0xAE, 0x0B, 0x03, 0x02, 0x01, 0x00,
0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0xEB, 0xA7, 0xD1, 0xEC, 0xED, 0x96,
0x04, 0x04, 0x96, 0xED, 0xEE, 0xD1, 0xA7, 0xEB, 0x05, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0xCA, 0xCA, 0xCA, 0xCA,
0xCA, 0xCA, 0xCA, 0xCC, 0xE2, 0x8A, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE8, 0xE7, 0xE9, 0xE5, 0xBB, 0xE3, 0x8A, 0xE2, 0xCC,
0xCA, 0xCC, 0xEA, 0xCC, 0xCA, 0xCA, 0xCA, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, 0xDD, 0x55, 0xDE, 0x2C, 0xDF,
0xE0, 0xE1, 0xE1, 0xE0, 0xDF, 0x2C, 0xDE, 0x55, 0xDD, 0x08, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0xC6, 0xD8, 0xD9, 0xAB, 0x78, 0x6A, 0x28, 0xDA, 0xDB, 0x28, 0x6A, 0x5A, 0xDC, 0xD9, 0xD8, 0xC6,
0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0x03, 0xD4, 0xD1, 0x31,
0xD5, 0xD6, 0x98, 0xD7, 0xD6, 0xD5, 0x0B, 0x32, 0xD4, 0x03, 0x05, 0x04, 0x01, 0x04, 0xCA, 0x04, 0x01, 0x01, 0x01, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x05, 0xC3, 0xC2, 0xA4, 0xD0, 0xD1, 0xB3, 0xD2, 0xD3, 0xD3, 0xD2, 0x4F, 0x32, 0xD0, 0xA4, 0xC2,
0xC3, 0x05, 0x02, 0x05, 0xB7, 0x05, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xCB, 0xC2, 0xCC, 0x02, 0xCD,
0x79, 0xCE, 0xCF, 0xC1, 0xC1, 0xCF, 0xCE, 0x79, 0xCD, 0x02, 0xCC, 0xC2, 0xCB, 0x03, 0xCB, 0xB3, 0xCB, 0x03, 0x03, 0x03, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x7E, 0x05, 0xC6, 0x7E, 0x00, 0xC7, 0x15, 0xC8, 0xC9, 0xC9, 0xC8, 0x15, 0xC7, 0x00, 0x7E,
0xC6, 0x05, 0x7E, 0x04, 0x7E, 0xCA, 0x7E, 0x04, 0x04, 0x04, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0x00, 0x03, 0xC3, 0x00,
0x05, 0x55, 0xC4, 0xC5, 0xC1, 0xC1, 0xC5, 0xC4, 0x55, 0x05, 0x00, 0xC3, 0x03, 0x00, 0xAE, 0x00, 0x3D, 0x00, 0xAE, 0xAE, 0xAE,
0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0x7E, 0xBE, 0x00, 0x05, 0xBE, 0x7E, 0xBF, 0xC0, 0x5C, 0xC1, 0xC1, 0x5C, 0xC0, 0xBF, 0x7E,
0xBE, 0x05, 0x00, 0xBE, 0x7E, 0xBE, 0xC2, 0x06, 0xBD, 0xBD, 0xBD, 0xB3, 0xB3, 0xB3, 0xB4, 0xB5, 0xB3, 0xB3, 0xB5, 0xB6, 0xB6,
0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0x6B, 0x6B, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, 0xB5, 0xB3, 0xB5, 0xBC, 0xB4, 0xB3, 0xB3,
0xB3, 0x02, 0x02, 0xA8, 0xA9, 0xAA, 0xA8, 0x02, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0x8F, 0xB1, 0x71, 0x2D, 0xB1, 0x9E, 0xB0,
0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0x02, 0xA4, 0xB2, 0xAA, 0xA8, 0x02, 0x02, 0x04, 0x31, 0xA3, 0x04, 0x31, 0x82, 0x3B, 0xA3, 0xA4,
0xA5, 0xA6, 0x82, 0xA7, 0x8E, 0x20, 0x78, 0x78, 0x20, 0x8E, 0xA7, 0x82, 0xA6, 0xA5, 0xA4, 0xA3, 0x3B, 0x82, 0x3D, 0x04, 0xA3,
0x31, 0x04, 0x09, 0x9F, 0xA0, 0x21, 0x2C, 0xA1, 0x47, 0x52, 0x5B, 0x5A, 0xA2, 0x1C, 0x81, 0x8D, 0x8E, 0x91, 0x91, 0x8E, 0x8D,
0x81, 0x1C, 0xA2, 0x5A, 0x5B, 0x52, 0x47, 0xA1, 0x2C, 0x21, 0xA0, 0x9F, 0x09, 0x96, 0x97, 0x16, 0x98, 0x99, 0x9A, 0x46, 0x9B,
0x28, 0x9C, 0x6D, 0x76, 0x7D, 0x8C, 0x9D, 0x8E, 0x8E, 0x9D, 0x9E, 0x7D, 0x75, 0x6D, 0x9C, 0x65, 0x9B, 0x46, 0x39, 0x99, 0x98,
0x16, 0x97, 0x96, 0x4F, 0x89, 0x15, 0x1F, 0x69, 0x38, 0x45, 0x8A, 0x78, 0x66, 0x6C, 0x74, 0x4A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x8B, 0x80, 0x45, 0x90, 0x66, 0x91, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x15, 0x89, 0x4F, 0x7E, 0x0D, 0x14, 0x1E, 0x29, 0x37, 0x44,
0x14, 0x59, 0x65, 0x6B, 0x73, 0x7F, 0x80, 0x25, 0x81, 0x82, 0x25, 0x80, 0x7F, 0x83, 0x84, 0x65, 0x85, 0x4D, 0x86, 0x87, 0x29,
0x88, 0x14, 0x0D, 0x7E, 0x05, 0x0C, 0x13, 0x1D, 0x28, 0x2C, 0x43, 0x4E, 0x72, 0x64, 0x53, 0x5A, 0x73, 0x74, 0x75, 0x1C, 0x1C,
0x76, 0x74, 0x77, 0x78, 0x6A, 0x64, 0x79, 0x4E, 0x7A, 0x2C, 0x7B, 0x7C, 0x7D, 0x0C, 0x05, 0x04, 0x0B, 0x12, 0x1C, 0x27, 0x36,
0x42, 0x4D, 0x5D, 0x63, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x1A, 0x1A, 0x6D, 0x6C, 0x6E, 0x53, 0x69, 0x6F, 0x5D, 0x19, 0x70, 0x36,
0x71, 0x24, 0x12, 0x0B, 0x04, 0x03, 0x03, 0x11, 0x1B, 0x2E, 0x35, 0x41, 0x4C, 0x5E, 0x62, 0x63, 0x64, 0x65, 0x66, 0x2C, 0x5A,
0x5A, 0x2C, 0x66, 0x65, 0x64, 0x67, 0x62, 0x5E, 0x52, 0x40, 0x65, 0x68, 0x1B, 0x11, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x25,
0x34, 0x40, 0x4B, 0x56, 0x57, 0x58, 0x16, 0x59, 0x5A, 0x41, 0x5B, 0x5B, 0x41, 0x5A, 0x59, 0x5C, 0x5D, 0x5E, 0x5F, 0x21, 0x41,
0x60, 0x61, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x09, 0x24, 0x33, 0x3F, 0x2C, 0x4B, 0x4C, 0x4D, 0x4E, 0x14, 0x4F, 0x50,
0x51, 0x51, 0x50, 0x4F, 0x14, 0x4E, 0x4D, 0x52, 0x53, 0x2C, 0x3F, 0x01, 0x54, 0x55, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1A,
0x23, 0x32, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x46, 0x45, 0x44, 0x43, 0x48, 0x41, 0x40, 0x3F,
0x49, 0x3C, 0x4A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36, 0x2C, 0x37, 0x38,
0x39, 0x3A, 0x3A, 0x39, 0x38, 0x37, 0x2C, 0x36, 0x35, 0x34, 0x3B, 0x3C, 0x30, 0x3D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1A, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x2D, 0x2E, 0x13,
0x2F, 0x30, 0x31, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x09, 0x02, 0x1B, 0x1C, 0x1D, 0x1E,
0x1F, 0x20, 0x21, 0x21, 0x20, 0x22, 0x1E, 0x1D, 0x1C, 0x1B, 0x02, 0x09, 0x1A, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x16, 0x18, 0x19, 0x13, 0x12, 0x11,
0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
0x03, 0x02, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

View File

@@ -6,6 +6,7 @@
#include "meshwifi/meshhttp.h"
#include "target_specific.h"
#include <DNSServer.h>
#include <ESPmDNS.h>
#include <WiFi.h>
static void WiFiEvent(WiFiEvent_t event);
@@ -17,8 +18,8 @@ static WiFiServerPort *apiPort;
uint8_t wifiDisconnectReason = 0;
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
static char ourHost[16];
// Stores our hostname
char ourHost[16];
bool isWifiAvailable()
{
@@ -29,9 +30,6 @@ bool isWifiAvailable()
// strcpy(radioConfig.preferences.wifi_password, "");
if (*wifiName && *wifiPsw) {
// Once every 10 seconds, try to reconnect.
return 1;
} else {
return 0;
@@ -52,9 +50,11 @@ void deinitWifi()
saving on the 2.4g transceiver.
*/
WiFi.mode(WIFI_MODE_NULL);
DEBUG_MSG("WiFi Turned Off\n");
// WiFi.printDiag(Serial);
if (isWifiAvailable()) {
WiFi.mode(WIFI_MODE_NULL);
DEBUG_MSG("WiFi Turned Off\n");
// WiFi.printDiag(Serial);
}
}
// Startup WiFi
@@ -64,6 +64,8 @@ void initWifi()
return;
}
createSSLCert();
if (radioConfig.has_preferences) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
@@ -117,12 +119,23 @@ void initWifi()
}
}
}
if (!MDNS.begin("Meshtastic")) {
DEBUG_MSG("Error setting up MDNS responder!\n");
while (1) {
delay(1000);
}
}
DEBUG_MSG("mDNS responder started\n");
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
} else
DEBUG_MSG("Not using WIFI\n");
}
static void initApiServer()
{
// Start API server on port 4403

View File

@@ -15,6 +15,7 @@
#include <WiFi.h>
static bool pinShowing;
static uint32_t doublepressed;
static void startCb(uint32_t pin)
{
@@ -123,6 +124,7 @@ static int gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
uint32_t now = millis();
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
@@ -221,8 +223,17 @@ static int gap_event(struct ble_gap_event *event, void *arg)
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
pkey.action = event->passkey.params.action;
pkey.passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
DEBUG_MSG("dp: %d now:%d\n",doublepressed, now);
if (doublepressed > 0 && (doublepressed + (30*1000)) > now)
{
DEBUG_MSG("User has overridden passkey or no display available\n");
pkey.passkey = defaultBLEPin;
}
else {
DEBUG_MSG("Using random passkey\n");
pkey.passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
}
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", pkey.passkey);
startCb(pkey.passkey);
@@ -381,6 +392,7 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
}
}
/**
* A helper function that implements simple read and write handling for a uint32_t
*
@@ -404,6 +416,7 @@ int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt)
if (len < sizeof(le)) {
DEBUG_MSG("Error: wrongsized write32\n");
*v = 0;
return BLE_ATT_ERR_UNLIKELY;
} else {
*v = get_le32(le);
DEBUG_MSG("BLE writing a uint32\n");
@@ -430,8 +443,10 @@ int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt)
auto rc = ble_hs_mbuf_to_flat(ctxt->om, v, vlen, &len);
assert(rc == 0);
if (len < vlen)
if (len < vlen) {
DEBUG_MSG("Error: wrongsized write\n");
return BLE_ATT_ERR_UNLIKELY;
}
else {
DEBUG_MSG("BLE writing bytes\n");
}
@@ -443,6 +458,13 @@ int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt)
return 0; // success
}
void disablePin()
{
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
// keep track of when it was pressed, so we know it was within X seconds
doublepressed = millis();
}
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{

View File

@@ -15,6 +15,7 @@ void updateBatteryLevel(uint8_t level);
void deinitBLE();
void loopBLE();
void reinitBluetooth();
void disablePin();
/**
* A helper function that implements simple read and write handling for a uint32_t

100
src/nrf52/BQ25713.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "BQ25713.h"
#include "configuration.h"
#include <Wire.h>
#ifdef BQ25703A_ADDR
const uint8_t BQ25713::devAddr = BQ25703A_ADDR;
bool BQ25713::setup()
{
DEBUG_MSG("Init BQ25713\n");
// if(!writeReg(0x34,0x9034)) return false;
//
// if(!writeReg(0x34,0x8034)) return false;
if (!writeReg(0x00, 0x0F0A))
return false; // Config Charge Option 0
if (!writeReg(0x02, 0x0224))
return false; // Config Charge Current
if (!writeReg(0x04, 0x1070))
return false; // Config Charge Voltage
if (!writeReg(0x06, 0x099C))
return false; // Config OTG Voltage
if (!writeReg(0x08, 0x5000))
return false; // Config OTG Current
// if(!writeReg(0x0A,0x0100)) return false;//Config Input Voltage
if (!writeReg(0x0C, 0x1800))
return false; // Config Minimum System Voltage
if (!writeReg(0x0E, 0x4900))
return false; // Config Input Current
if (!writeReg(0x30, 0xE210))
return false; // Config Charge Option 1
if (!writeReg(0x32, 0x32BF))
return false; // Config Charge Option 2
if (!writeReg(0x34, 0x0834))
return false; // Config Charge Option 3
if (!writeReg(0x36, 0x4A65))
return false; // Config Prochot Option 0
if (!writeReg(0x38, 0x81FF))
return false; // Config Prochot Option 1
if (!writeReg(0x3A, 0xA0FF))
return false; // Config ADC Option
return true;
}
uint16_t BQ25713::readReg(uint8_t reg)
{
Wire.beginTransmission(devAddr);
Wire.write(reg);
byte err = Wire.endTransmission();
if (!err) {
int readLen = 2;
Wire.requestFrom(devAddr, (int)(readLen + 1));
if (Wire.available() >= readLen) {
uint8_t lsb = Wire.read(), msb = Wire.read();
return (((uint16_t)msb) << 8) + lsb;
} else
return 0;
} else {
return 0;
}
}
bool BQ25713::writeReg(uint8_t reg, uint16_t v)
{
Wire.beginTransmission(devAddr);
Wire.write(reg);
Wire.write(v & 0xff);
Wire.write((v >> 8) & 0xff);
byte err = Wire.endTransmission(); // 0 for success
if (!err) {
// Do a test readback for early debugging
uint16_t found = readReg(reg);
if (found != v) {
DEBUG_MSG("Readback reg=0x%0x test failed, expected 0x%0x, found 0x%0x!\n", reg, v, found);
return true; // claim success - FIXME
}
}
return !err;
}
#endif

22
src/nrf52/BQ25713.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <Arduino.h>
/**
* Driver class to control/monitor BQ25713 charge controller
*/
class BQ25713 {
static const uint8_t devAddr;
public:
/// Return true for success
bool setup();
private:
uint16_t readReg(uint8_t reg);
/// Return true for success
bool writeReg(uint8_t reg, uint16_t v);
};

View File

@@ -202,6 +202,13 @@ void setupMeshService(void)
// FIXME, turn off soft device access for debugging
static bool isSoftDeviceAllowed = true;
void NRF52Bluetooth::shutdown()
{
// Shutdown bluetooth for minimum power draw
DEBUG_MSG("Disable NRF52 bluetooth\n");
Bluefruit.Advertising.stop();
}
void NRF52Bluetooth::setup()
{
// Initialise the Bluefruit module

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