Compare commits

...

167 Commits

Author SHA1 Message Date
Kevin Hester
6dec6af5dc Merge pull request #240 from tobymurray/master
Add Canada to list of countries that use 915 MHz
2020-07-01 11:59:04 -07:00
Kevin Hester
11444621ae Merge branch 'master' into master 2020-07-01 10:26:31 -07:00
Kevin Hester
98f1b3296c Merge pull request #241 from geeksville/dev
Dev
2020-07-01 10:26:13 -07:00
geeksville
26c43e7091 minor docs 2020-07-01 10:22:17 -07:00
Toby Murray
9b9447858a Add Canada to list of countries that use 915 MHz
Meshtastic prompted me to get a couple boards to try, and I had to figure out what frequency. Canada uses the same US902-928 as the US, add it to the list for simplicity.

Not sure where to find an "official" reference, but there's a reference here: https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html
2020-07-01 13:12:00 -04:00
geeksville
3151cfb064 0.7.10 2020-07-01 10:09:32 -07:00
geeksville
c327fee986 Fix formatting 2020-07-01 10:09:06 -07:00
geeksville
a4f53270e8 fix heltec build (and fix formatting) 2020-07-01 10:08:38 -07:00
geeksville
a7456a1126 all targets are arduino - for now 2020-07-01 10:08:09 -07:00
geeksville
8381512ce4 todo updates 2020-07-01 09:32:01 -07:00
Kevin Hester
20a669029b Merge pull request #237 from Professr/issue#182
Switch main display to event-driven model, abstract the three main status info categories, work on power.h
2020-06-28 19:10:42 -07:00
Professr
f2e6c6de58 Fixed filename case sensitivity 2020-06-28 19:03:39 -07:00
Professr
8fa44c3590 Disabled the display heartbeat pixel for pull request 2020-06-28 18:55:51 -07:00
Professr
f5b7c33d4e Refactored status handlers and merged 2020-06-28 18:17:52 -07:00
Kevin Hester
be8e663d39 Merge pull request #236 from geeksville/dev
turn on thread watchdog
2020-06-28 11:24:03 -07:00
geeksville
0d4a9748e3 Merge remote-tracking branch 'root/master' into dev 2020-06-28 11:13:05 -07:00
geeksville
bd477f0fb2 turn on thread watchdog 2020-06-28 11:12:12 -07:00
Professr
5317895a5e Merged 2020-06-27 21:26:57 -07:00
Professr
542b8b26ce Abstracted statuses, made display event-driven 2020-06-27 21:19:49 -07:00
Kevin Hester
64da384fc1 Merge pull request #234 from geeksville/dev
Dev
2020-06-26 16:16:54 -07:00
geeksville
a595fc4642 Fix #233 - init distance string before drawing it
(and violating my own "no formatting checkins with other changes" rule
to restore proper indentation for this file)
2020-06-26 15:04:22 -07:00
geeksville
ac135be8cd move geeksville's personal todos somewhere else (mostly android) 2020-06-25 15:49:49 -07:00
Kevin Hester
5ea59a1c4d Merge pull request #230 from aHVzY2g/pr/228
fix pr #228 int float casting & made fillRect 2px smaller
2020-06-25 11:41:40 -07:00
Kevin Hester
8bafd87b76 Merge branch 'master' into pr/228 2020-06-25 11:26:37 -07:00
Kevin Hester
6b40e9a5e0 Merge pull request #232 from geeksville/dev
Add optional external GPS for TTGO Lora V2
2020-06-25 11:25:46 -07:00
Kevin Hester
a2f6fd9298 Merge branch 'master' into dev 2020-06-25 10:07:06 -07:00
Marlon Spangenberg
bc604fc9ba Merge branch 'master' into pr/228 2020-06-25 18:56:20 +02:00
geeksville
9baaa13897 Add optional external GPS for TTGO Lora V2
per this request: https://meshtastic.discourse.group/t/gps-pin-assignments-for-custom-boards/501/9?u=geeksville
2020-06-25 09:45:21 -07:00
Kevin Hester
65e53be8b0 Merge pull request #231 from geeksville/dev
Add an initial pull-request template
2020-06-25 09:37:40 -07:00
geeksville
7f5283e95d Add an initial pull-request template 2020-06-25 09:33:29 -07:00
Marlon Spangenberg
ae4ab48ddc fixed int float casting & made fillRect 2px smaller 2020-06-25 18:26:32 +02:00
Kevin Hester
afccf1da02 Merge pull request #229 from meshtastic/geeksville-patch-1
Update issue templates
2020-06-25 09:21:38 -07:00
Kevin Hester
fc07c7c01f Update issue templates 2020-06-25 09:18:54 -07:00
Kevin Hester
aeb906414f Merge pull request #228 from mrvdb/sh1106-support
Take configured SCREEN_WIDTH into account for brightness bar
2020-06-25 08:44:34 -07:00
Marcel van der Boom
a6c6b45576 Take different screen widths into account for brightness bar
width of sh1106 display is 132 for example
2020-06-25 16:20:49 +02:00
Kevin Hester
13806cce93 Merge pull request #221 from geeksville/dev
Dev
2020-06-24 16:18:44 -07:00
geeksville
e7eee0995a fix line endings 2020-06-24 16:14:38 -07:00
geeksville
5687bd09c6 Merge remote-tracking branch 'root/master' into dev 2020-06-24 14:08:36 -07:00
Kevin Hester
f3db895832 Merge pull request #222 from aHVzY2g/master
Fix #207 adjust OLED Brightness by attachDuringLongPress
2020-06-24 14:07:52 -07:00
Kevin Hester
dd2ffe5d14 Merge branch 'master' into master 2020-06-24 14:03:56 -07:00
Professr
ec10e784e1 Fix #207 adjust OLED Brightness by attachDuringLongPress
adjust the OLED Brightness by "attachDuringLongPress" from "OneButton". It will cycle trough 0 to 254 as long as the button is pressed
2020-06-24 22:58:20 +02:00
geeksville
649faa1d93 Merge remote-tracking branch 'root/master' into dev 2020-06-24 13:56:48 -07:00
Kevin Hester
669f96b367 Merge pull request #223 from geeksville/whiteheadfix
Fix #150 by @zjwhitehead
2020-06-24 13:46:39 -07:00
geeksville
996821d18e Merge remote-tracking branch 'root/master' 2020-06-24 13:33:16 -07:00
geeksville
2e172b019e Undo @zjwhitehead changes to platformio.ini 2020-06-24 13:29:56 -07:00
Zach Whitehead
3df05cd5c1 break out compass display
Show question mark if unknown location
2020-06-24 13:27:02 -07:00
geeksville
8bb85cdc69 personal TODO list updates (sorry github reviewers) 2020-06-24 13:13:20 -07:00
geeksville
9f6e23754c Add a no_save development flag to allow using settings that
we don't want to save to flash.  Use that flag to guard BLE
stress testing code that makes device repeatedly sleep wake
to force numerous BLE resets
2020-06-24 13:10:36 -07:00
geeksville
5a7cfdffb3 Add links to the preinstalled version of the TBEAMs 2020-06-24 12:49:31 -07:00
Kevin Hester
caafddfdfa Merge pull request #219 from Professr/issue#154
Fixed #154 - Cleaned up UTF-8 conversion, tweaked screen.cpp to replace a hardcoded constant
2020-06-24 08:22:29 -07:00
Kevin Hester
ee0e31be97 Merge branch 'master' into issue#154 2020-06-24 08:19:03 -07:00
Kevin Hester
f1da6469a3 Merge pull request #220 from aHVzY2g/patch-1
added ttgo-lora32-v1 gps pins again :D
2020-06-24 08:18:47 -07:00
Marlon Spangenberg
68e57dd3a7 added ttgo-lora32-v1 gps pins again :D
Sry I messed up as I closed #213, so here are the pin definitions again.
2020-06-24 12:15:50 +02:00
Ellie Hussey
2504311671 Merge branch 'master' into issue#154 2020-06-23 18:30:09 -07:00
Ellie Hussey
aa29315624 Merge pull request #218 from aHVzY2g/patch-2
added Bluetooth Name to paring screen
2020-06-23 18:28:18 -07:00
Professr
e3bcb87cf0 Removed prefix chars, fixed issues related to custom font mappings 2020-06-23 18:02:41 -07:00
Professr
2530dc44c7 Changed unconvertable-character symbol to ¿ and made it return only one per unconvertable sequence 2020-06-23 16:46:41 -07:00
Professr
70a8fe30b7 Merge https://github.com/meshtastic/Meshtastic-device into issue#154 2020-06-23 16:45:40 -07:00
Marlon Spangenberg
30e538e5ed added Bluetooth Name to paring screen
& changed the order
2020-06-24 01:08:23 +02:00
Kevin Hester
58dbc3c702 Merge pull request #216 from Professr/issue#162
Use spare TBeam GPIO for an alternate middle button - Issue#162
2020-06-23 15:42:19 -07:00
Kevin Hester
210c904604 Merge branch 'master' into issue#162 2020-06-23 15:40:02 -07:00
Kevin Hester
27fdab7c8d Merge pull request #214 from geeksville/dev
Dev
2020-06-23 15:39:28 -07:00
Kevin Hester
ba3e1abb5e Merge branch 'master' into dev 2020-06-23 15:37:07 -07:00
Kevin Hester
ce194e2162 Merge pull request #212 from Professr/issue#197
Add cpp clamp function to utils.h, converted signal strength to %
2020-06-23 15:36:53 -07:00
Kevin Hester
595166db8e Merge branch 'master' into dev 2020-06-23 15:35:55 -07:00
Kevin Hester
38d9e34a66 Merge branch 'master' into issue#197 2020-06-23 15:34:15 -07:00
Kevin Hester
c1e0977db3 Merge branch 'master' into issue#162 2020-06-23 15:28:54 -07:00
Kevin Hester
b4f32e7645 thank you @rorosaurus!
update README per issue #189
2020-06-23 15:26:40 -07:00
Rory Hayes
6bb0c95c95 update README per issue #189 2020-06-23 14:28:38 -07:00
geeksville
4e958c9230 make software update keep device from sleeping 2020-06-22 17:10:41 -07:00
geeksville
64cf1890f2 prebump to 0.7.9 build number, though not doing a release yet...
Because I want to pick a min build number for 'BLE OTA update allowed'
2020-06-22 17:10:18 -07:00
Professr
6a857b00db Add cpp clamp function to util.h, switched battery and signal strength percentage calcs to it #197 2020-06-22 14:06:02 -07:00
Professr
6d60a061bc Merge https://github.com/meshtastic/Meshtastic-device into issue#154 2020-06-22 12:27:44 -07:00
Professr
6a09ddef18 Resolved merge conflict 2020-06-22 12:25:59 -07:00
Professr
d48e803b7b Custom utf8 conversion replaces unconvertable chars with ? instead of blanks, #154 2020-06-22 12:03:26 -07:00
Kevin Hester
9061b3d8c3 Merge pull request #206 from geeksville/dev
Dev
2020-06-22 11:39:13 -07:00
geeksville
2839539c6c todo for my personal work queue 2020-06-22 11:36:48 -07:00
geeksville
f77a1798f3 Merge remote-tracking branch 'root/master' into dev 2020-06-22 11:36:06 -07:00
Kevin Hester
664b558a36 Merge pull request #210 from aHVzY2g/patch-1
Just a link to a need little case for the TTGO LORA32 v1
2020-06-22 11:26:18 -07:00
geeksville
c1865f127c make sure people who are not just me, get the fixed arduino-esp32 2020-06-22 11:17:08 -07:00
Marlon Spangenberg
3a69539192 Just a link to a need little case for the TTGO LORA32 v1 2020-06-22 20:15:19 +02:00
Professr
cfcaf28ace Switched user button to OneButton, added alt button GPIO for #162 2020-06-22 11:09:26 -07:00
geeksville
d9e93f3944 Try turning my software update service back on...
Now that I've fixed a couple of nasty esp32-arduino bugs
2020-06-22 10:06:35 -07:00
geeksville
60470211e5 expose battery level via the standard BLE battery service 2020-06-22 10:04:26 -07:00
geeksville
c5851a4a0c Report battery level to other nodes in mesh (and apps).
Also today I'll turn back on the the standard "has a battery" BLE
device profile, so the locally connected radio should show up in the
phone's bluetooth popup of battery levels (similar to how a BLE
headphone battery level appears)

cc @lgoix - using code from @professr

```
meshtastic --info
Connected to radio...
my_node_num: 2883444536
has_gps: true
num_channels: 13
region: "unset"
hw_model: "tbeam"
firmware_version: "unset"
packet_id_bits: 32
current_packet_id: 91018534
node_num_bits: 32
message_timeout_msec: 300000
min_app_version: 172

preferences {
  position_broadcast_secs: 900
  send_owner_interval: 4
  wait_bluetooth_secs: 120
  screen_on_secs: 300
  phone_timeout_secs: 900
  phone_sds_timeout_sec: 7200
  mesh_sds_timeout_secs: 7200
  sds_secs: 31536000
  ls_secs: 3600
}
channel_settings {
  tx_power: 23
  modem_config: Bw125Cr48Sf4096
  psk: "\324\361\273: )\007Y\360\274\377\253\317Ni\277"
  name: "Default"
}

Nodes in mesh:
{'num': 2883444536, 'user': {'id': '!2462abdddf38', 'longName': 'Unknown df38', 'shortName': '?38', 'macaddr': 'JGKr3d84'}, 'position': {'altitude': 96, 'batteryLevel': 100, 'latitudeI': 375210641, 'longitudeI': -1223090398, 'time': 1592843564, 'latitude': 37.5210641, 'longitude': -122.3090398}}
```
2020-06-22 09:36:19 -07:00
geeksville
0c0b2446b7 Merge remote-tracking branch 'root/master' into dev 2020-06-22 09:22:54 -07:00
Kevin Hester
ce9352fd23 Merge pull request #209 from Professr/issue#134
Converted status text to graphical header, Issue#134
2020-06-22 09:22:37 -07:00
Kevin Hester
375ae5fe77 Merge pull request #208 from Professr/issue#196
Added battery charge percentage support, Issue#196
2020-06-22 09:19:10 -07:00
geeksville
665d35196d never wait on GPS reads 2020-06-22 09:17:15 -07:00
geeksville
9757f9ae53 geeksville personal todo list 2020-06-22 09:17:04 -07:00
Professr
e45d0c4dcf Offset battery bars by 1 to reflect room between BAT_MILLIVOLTS_EMPTY and MIN_BAT_MILLIVOLTS 2020-06-22 00:10:04 -07:00
Professr
5c9f22bc18 Moved node count graphic slightly to the left, to allow room for triple-digit node counts 2020-06-21 19:44:32 -07:00
Professr
d8287e9cdb Removed DOP to string utility function from GPS.cpp since it's now drawn directly in screen.cpp 2020-06-21 17:43:34 -07:00
Professr
c66e064f42 Replaced battery, node, and gps text with a graphical header. Added hash to the beginning of the channel name. 2020-06-21 17:28:37 -07:00
Professr
364fc84aaa Removed unnecessary include, ready for consideration for issue #196 2020-06-21 16:31:09 -07:00
Professr
fe4f86bc84 Added battery charge percent estimation 2020-06-21 16:21:34 -07:00
geeksville
982b2e33ff Merge remote-tracking branch 'root/master' into dev 2020-06-21 14:11:53 -07:00
geeksville
8190098bb8 experiment with wifi connections for nodes 2020-06-21 14:11:38 -07:00
Kevin Hester
c99411311b Merge pull request #204 from Professr/issue#199
@professr Added GPS DOP support (#199)
2020-06-21 14:05:05 -07:00
Professr
da8a048dce Added GPS DOP support (#199) 2020-06-20 18:59:41 -07:00
geeksville
b4de495154 show app version on boot screen 2020-06-20 17:07:17 -07:00
Kevin Hester
aaa6af3f38 Merge pull request #202 from geeksville/dev
0.7.8 - build with new fixed arduino-esp32 lib
2020-06-20 14:58:19 -07:00
geeksville
b11b322581 0.7.8 2020-06-20 14:53:25 -07:00
geeksville
60b38215ce fix docs per @feh123 2020-06-20 09:58:45 -07:00
geeksville
53e68515dd Merge remote-tracking branch 'root/master' into dev 2020-06-19 13:57:21 -07:00
geeksville
7676ae9184 typo 2020-06-19 13:57:10 -07:00
Kevin Hester
b385feefa5 Merge pull request #201 from geeksville/dev
Fix crypto doc links
2020-06-19 13:50:19 -07:00
Kevin Hester
fc50b4abc0 Merge branch 'master' into dev 2020-06-19 13:47:52 -07:00
geeksville
0104a2eb3a Fix crypto doc links 2020-06-19 13:47:00 -07:00
Kevin Hester
23fdc9d1a9 Merge pull request #195 from geeksville/dev
Dev
2020-06-19 13:30:53 -07:00
geeksville
ea4a678308 Add reviewer comments on crypto 2020-06-19 13:27:31 -07:00
geeksville
6566c4f15e don't send bogus latitudes 2020-06-18 14:09:13 -07:00
geeksville
6f39f1740f add pinetab work queue 2020-06-18 11:57:29 -07:00
geeksville
7b61bdbfd2 Merge remote-tracking branch 'root/master' into dev 2020-06-18 11:50:44 -07:00
geeksville
8e65db19b0 Add notes on linux drivers & pins for pinetab #143 2020-06-18 11:50:04 -07:00
Kevin Hester
698fcdad36 Merge pull request #194 from geeksville/dev
Fix #187, Ublox GPS fixes, see below:
2020-06-18 11:25:45 -07:00
geeksville
c25d6e974f sometimes first read might return 0 for EITHER lat or lon 2020-06-18 11:22:38 -07:00
geeksville
35aae48932 0.7.7 2020-06-18 11:18:53 -07:00
geeksville
f8afa2703f Merge remote-tracking branch 'root/master' into dev 2020-06-18 11:18:15 -07:00
geeksville
cd903dceb9 Fix #187, Ublox GPS fixes, see below:
This was a good one. Two problems
1) We've apparently always been using hte sparkfun API the wrong way, but
but we mostly got lucky.
2) Changing to use the API correctly (asyncronously) exposed a bug in
the library - fixed in a seperate commit
2020-06-18 11:17:01 -07:00
Kevin Hester
5843c6f25e Merge pull request #193 from geeksville/dev
misc fixes
2020-06-17 19:29:14 -07:00
geeksville
3005373760 fix wording of GPS screen messages to be less confusing. Now:
No GPS
No Sats
GPS OK
2020-06-17 17:26:37 -07:00
geeksville
7678540a93 For #187 was not reporting GPS status on new API 2020-06-17 17:25:55 -07:00
geeksville
463666aec5 oops - can't call DEBUG_MSG this early on ESP32 2020-06-17 16:04:37 -07:00
geeksville
5847f94ece Merge remote-tracking branch 'mine/dev' into dev 2020-06-17 15:48:04 -07:00
geeksville
09855b76ef TODO updates 2020-06-17 15:45:49 -07:00
Kevin Hester
f4d476d160 Merge pull request #191 from geeksville/dev
merge cubecell/memory experiments
2020-06-17 11:41:31 -07:00
Kevin Hester
d88d4be63e Merge branch 'master' into dev 2020-06-17 11:39:23 -07:00
geeksville
154114e900 merge cubecell experiments back into master (might delete later) 2020-06-17 11:35:21 -07:00
geeksville
03f019dea2 memory size debugging 2020-06-16 19:55:14 -07:00
geeksville
a47524b762 cubecell wip 2020-06-16 17:13:26 -07:00
geeksville
fd2f5a5ba4 Merge branch 'dev' into cubecell 2020-06-16 16:18:30 -07:00
geeksville
e66b2234f6 Experiment with small ram NRF52s 2020-06-16 15:27:08 -07:00
geeksville
f35b15b09c Shrink devicestate for small mcus 2020-06-16 15:26:30 -07:00
geeksville
99dac51b9d Don't use a (huge - 16KB) scratch buffer for device state loading 2020-06-16 15:02:11 -07:00
geeksville
656faf4ce9 ram investigation notes 2020-06-16 15:01:39 -07:00
geeksville
d9ab6986ad per @dafeman 1.8V works on E22 2020-06-16 12:02:13 -07:00
geeksville
514d45c219 oops supposed to be TXEN 2020-06-16 06:38:08 -07:00
Kevin Hester
94b7fc76c1 Merge pull request #188 from geeksville/ppr
sx1262 for dafeman
2020-06-16 06:30:15 -07:00
geeksville
e9923ac257 fix LCD build for devboard 2020-06-16 06:26:34 -07:00
geeksville
60ad1793e4 sx1262 improvements attn @dafeman 2020-06-16 06:26:21 -07:00
geeksville
96a15bec3b doc updates 2020-06-16 06:25:54 -07:00
Kevin Hester
fba676fc07 Merge pull request #185 from geeksville/bringup
nrf52 backmerge into master
2020-06-15 14:53:11 -07:00
geeksville
9ad14ad98b Cleanup to merge NR52 support back into mainline 2020-06-15 14:47:14 -07:00
geeksville
477c62082d E22 SX1262 module now works!
Thanks mostly to an old github comment by @beegee-tokyo the fix was easy
(comment here https://github.com/jgromes/RadioLib/issues/12#issuecomment-520450429)

We now set DIO3 to 2.4 volts to power the oscillator inside the E22
module (undocumented in the E22 docs)
2020-06-15 14:38:09 -07:00
geeksville
82169d4115 make recent changes work on non ESP hardware 2020-06-15 13:32:06 -07:00
geeksville
362d5452d5 remove unused chip 2020-06-15 13:31:53 -07:00
geeksville
92e5a15399 Merge branch 'master' into cubecell 2020-06-15 12:42:01 -07:00
geeksville
114e0c4ada Merge branch 'master' into bringup 2020-06-15 12:41:22 -07:00
Kevin Hester
075ff26499 @mrvdb added support for SH1106 displays!
Add support for SH1106 controller
2020-06-15 12:29:59 -07:00
Kevin Hester
d65f2ede81 Merge branch 'master' into sh1106-support 2020-06-15 12:26:12 -07:00
Kevin Hester
4a9248a451 @zombodotcom added support for optional external GPS on heltec lora v2!
Fixed GPS pin Definitions for Heltec Lora V2
2020-06-15 12:25:56 -07:00
Zombodotcom
1c6092c430 Fixed GPS pin Definitions 2020-06-15 11:38:15 -06:00
Kevin Hester
0e9ed1e82f Merge pull request #183 from geeksville/dev
Dev
2020-06-15 07:19:45 -07:00
geeksville
02ce0558b9 Merge remote-tracking branch 'root/master' into dev 2020-06-15 07:13:34 -07:00
geeksville
63110f0134 Merge remote-tracking branch 'mine/dev' into dev 2020-06-15 07:12:31 -07:00
geeksville
d8db4449be 0.7.6 2020-06-15 07:04:03 -07:00
geeksville
fda98bbf58 oops BLE auth should not change 2020-06-14 15:52:06 -07:00
geeksville
aadba1f694 add printPacket for debug printing packets 2020-06-14 15:30:42 -07:00
geeksville
2c8d152885 Use old style (pre BLE 4.2) pairing, it seems more reliable 2020-06-14 15:30:21 -07:00
Marcel van der Boom
37c598833c Add support for SH1106 controller
The SH1106 is almost indistinguisable from a SSD1306.

- the nr of columns in the sh1106 is 132 vs 128
- use the proper includes/library functions when in use
2020-06-14 10:28:23 +02:00
geeksville
e382a181f7 Merge remote-tracking branch 'root/master' into dev 2020-06-13 16:50:01 -07:00
geeksville
f02a2c0853 Merge branch 'usb' into bringup 2020-06-09 18:20:34 -07:00
geeksville
71a4cfefd5 bringup WIP 2020-06-08 15:01:55 -07:00
geeksville
1c63a70673 cubecell WIP 2020-06-05 17:30:09 -07:00
geeksville
8022f3b920 Merge branch 'master' into bringup 2020-06-05 16:02:54 -07:00
geeksville
4db176867b WIP - bringup on PPR 2020-06-05 11:00:58 -07:00
78 changed files with 1947 additions and 651 deletions

View File

@@ -0,0 +1,38 @@
---
name: Bug report or feature proposal
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Please - if you just have a question (i.e. not a bug report or a feature proposal), post in our [forum](https://meshtastic.discourse.group/) instead.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device info:**
- Device model: [e.g. TBEAM]
- Software Version [e.g. 0.7.8]
**Smartphone information (if relevant):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- App Version [e.g. 0.7.2]
**Additional context**
Add any other context about the problem here.

13
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,13 @@
## Thank you for sending in a pull request, here's some tips to get started!
(Please delete all these tips and replace with your text)
- Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first
to say "hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
- Please do not check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on
- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor,
because automatically follows our indentation rules and it's auto reformatting will not cause spurious changes to lines.
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.

View File

@@ -59,6 +59,7 @@
"cfsr",
"descs",
"ocrypto",
"protobufs"
"protobufs",
"wifi"
]
}

View File

@@ -24,20 +24,23 @@ We currently support three models of radios.
- TTGO T-Beam
- [T-Beam V1.0 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (Recommended)
- [T-Beam V1.0 w/ NEO-6M](https://www.aliexpress.com/item/33050391850.html)
- [T-Beam V1.0 w/ NEO-6M - special Meshtastic version](https://www.aliexpress.com/item/4001178678568.html) (Includes built-in OLED display and they have **preinstalled** the meshtastic software)
- [T-Beam V1.0 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
- 3D printable case
- [TTGO LORA32 v1](https://www.thingiverse.com/thing:3385109)
- [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/) - No GPS
- [3D Printable case](https://www.thingiverse.com/thing:3125854)
**Make sure to get the frequency for your country**
- US/JP/AU/NZ - 915MHz
- US/JP/AU/NZ/CA - 915MHz
- CN - 470MHz
- EU - 868MHz, 433MHz
@@ -47,6 +50,8 @@ Getting a version that includes a screen is optional, but highly recommended.
Prebuilt binaries for the supported radios are available in our [releases](https://github.com/meshtastic/Meshtastic-esp32/releases). Your initial installation has to happen over USB from your Mac, Windows or Linux PC. Once our software is installed, all future software updates happen over bluetooth from your phone.
Be **very careful** to install the correct load for your board. In particular the popular 'T-BEAM' radio from TTGO is not called 'TTGO-Lora' (that is a different board). So don't install the 'TTGO-Lora' build on a TBEAM, it won't work correctly.
Please post comments on our [group chat](https://meshtastic.discourse.group/) if you have problems or successes.
### Installing from a GUI - Windows and Mac
@@ -168,7 +173,7 @@ Hard resetting via RTS pin...
# Meshtastic Android app
The companion (optional) Meshtastic Android app is [here](https://github.com/meshtastic/Meshtastic-Android). You can also download it on Google Play.
The companion (optional) Meshtastic Android app is [here](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub-dev-readme). You can also download it on Google Play.
# Python API

3
bin/dump-ram-users.sh Executable file
View File

@@ -0,0 +1,3 @@
arm-none-eabi-readelf -s -e .pio/build/nrf52dk/firmware.elf | head -80
nm -CSr --size-sort .pio/build/nrf52dk/firmware.elf | grep '^200'

View File

@@ -1,3 +1,3 @@
export VERSION=0.7.5
export VERSION=0.7.10

View File

@@ -39,6 +39,7 @@ This software is 100% open source and developed by a group of hobbyist experimen
Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum.
- 06/24/2020 - 0.7.x Now with over 1000 android users, over 600 people using the radios and translated into 13 languages. Fairly stable and we are working through bugs to get to 1.0.
- 06/04/2020 - 0.6.7 Beta releases of both the application and the device code are released. Features are fairly solid now with a sizable number of users.
- 04/28/2020 - 0.6.0 [Python API](https://pypi.org/project/meshtastic/) released. Makes it easy to use meshtastic devices as "zero config / just works" mesh transport adapters for other projects.
- 04/20/2020 - 0.4.3 Pretty solid now both for the android app and the device code. Many people have donated translations and code. Probably going to call it a beta soon.
@@ -51,7 +52,7 @@ Note: Updates are happening almost daily, only major updates are listed below. F
Our Android application is available here:
[![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dhomepage%26anid%3Dadmob)
[![Download at https://play.google.com/store/apps/details?id=com.geeksville.mesh](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=com.geeksville.mesh&referrer=utm_source%3Dgithub-homepage)
The link above will return older more stable releases. We would prefer if you join our alpha-test group, because the application is rapidly improving. Three steps to opt-in to the alpha- test:
@@ -63,8 +64,9 @@ If you'd like to help with development, the source code is [on github](https://g
## Supported hardware
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4000119152086.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than \$35). Make
sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen is optional, but highly recommended.
We currently support two brands of radios. The [TTGO T-Beam](https://www.aliexpress.com/item/4001178678568.html) and the [Heltec LoRa 32](https://heltec.org/project/wifi-lora-32/). Most people should buy the T-Beam and a 18650 battery (total cost less than \$35). Also, the version of the T-Beam we link to is shipped with Meshtastic **preinstalled** by TTGO, so you don't have to install it yourself.
Make sure to buy the frequency range which is legal for your country. For the USA, you should buy the 915MHz version. Getting a version that include a screen is optional, but highly recommended.
Instructions for installing prebuilt firmware can be found [here](https://github.com/meshtastic/Meshtastic-esp32/blob/master/README.md).

View File

@@ -4,7 +4,7 @@ This project is still pretty young but moving at a pretty good pace. Not all fea
Most of these problems should be solved by the beta release (within three months):
- We don't make these devices and they haven't been tested by UL or the FCC. If you use them you are experimenting and we can't promise they won't burn your house down ;-)
- The encryption [implementation](software/crypto.md) has not been reviewed by an expert. (Are you an expert? Please help us)
- The encryption implementation is good but see this list of [caveats](software/crypto.md#summary-of-strengthsweaknesses-of-our-current-implementation) to determine risks you might face.
- A number of (straightforward) software work items have to be completed before battery life matches our measurements, currently battery life is about three days. Join us on chat if you want the spreadsheet of power measurements/calculations.
- The Android API needs to be documented better
- No one has written an iOS app yet. But some good souls [are talking about it](https://github.com/meshtastic/Meshtastic-esp32/issues/14) ;-)

View File

@@ -0,0 +1,6 @@
https://heltec-automation-docs.readthedocs.io/en/latest/cubecell/index.html
https://github.com/HelTecAutomation/ASR650x-Arduino?utm_source=platformio.org&utm_medium=docs
* Either portfreertos or make not theaded versions of Lock, WorkerThread, Queue (probably the latter).

View File

@@ -1,37 +1,28 @@
# High priority
# Geeksville's current work queue
- why is the net so chatty now?
- do a release
- device wakes, turns BLE on and phone doesn't notice (while phone was sitting in auto-connect)
- E22 bringup
- encryption review findings writeup
- turn on modem-sleep mode - https://github.com/espressif/arduino-esp32/issues/1142#issuecomment-512428852
You probably don't care about this section - skip to the next one.
- implement first cut of router mode: preferentially handle flooding, and change sleep and GPS behaviors (plan for geofence mode and battery save mode)
- NRF52 BLE support
# Medium priority
Items to complete before the first beta release.
Items to complete before 1.0.
- turn on watchdog timer (because lib code seems buggy)
- show battery level as % full
- rx signal measurements -3 marginal, -9 bad, 10 great, -10 means almost unusable. So scale this into % signal strength. preferably as a graph, with an X indicating loss of comms.
# Pre-beta priority
During the beta timeframe the following improvements 'would be nice'
# Post 1.0 ideas
- finish DSR for unicast
- check fcc rules on duty cycle. we might not need to freq hop. https://www.sunfiretesting.com/LoRa-FCC-Certification-Guide/ . Might need to add enforcement for europe though.
- pick channel center frequency based on channel name? "dolphin" would hash to 900Mhz, "cat" to 905MHz etc? allows us to hide the concept of channel # from hte user.
- make a no bluetooth configured yet screen - include this screen in the loop if the user hasn't yet paired
- if radio params change fundamentally, discard the nodedb
- re-enable the bluetooth battery level service on the T-BEAM
- implement first cut of router mode: preferentially handle flooding, and change sleep and GPS behaviors
- provide generalized (but slow) internet message forwarding service if one of our nodes has internet connectivity (MQTT) [ Not a requirement but a personal interest ]
# Low priority
# Low priority ideas
Items after the first final candidate release.
- dynamic frequency scaling could save a lot of power on ESP32, but it seems to corrupt uart (even with ref_tick set correctly)
- Change back to using a fixed sized MemoryPool rather than MemoryDynamic (see bug #149)
- scan to find channels with low background noise? (Use CAD mode of the RF95 to automatically find low noise channels)
- If the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs
@@ -57,9 +48,16 @@ Items after the first final candidate release.
- split out the software update utility so other projects can use it. Have the appload specify the URL for downloads.
- read the PMU battery fault indicators and blink/led/warn user on screen
- discard very old nodedb records (> 1wk)
- add a watchdog timer
- handle millis() rollover in GPS.getTime - otherwise we will break after 50 days
- report esp32 device code bugs back to the mothership via android
- change BLE bonding to something more secure. see comment by pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND)
Changes related to wifi support on ESP32:
- iram space: https://esp32.com/viewtopic.php?t=8460
- set https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/external-ram.html spi ram bss
- figure out if iram or bluetooth classic caused ble problems
- post bug on esp32-arduino with BLE bug findings
# Spinoff project ideas

View File

@@ -7,7 +7,7 @@ in these instructions I describe use of their command line tool.
2. Install [PlatformIO](https://platformio.org/platformio-ide)
3. Download this git repo and cd into it
4. Run `git submodule update --init --recursive` to pull in dependencies this project needs.
5. If you are outside the USA, edit [platformio.ini](/platformio.ini) to set the correct frequency range for your country. The line you need to change starts with `hw_version` and instructions are provided above that line. Options are provided for `EU433`, `EU835`, `CN`, `JP` and `US` (default). Pull-requests eagerly accepted for other countries.
5. If you are outside the USA, run "export COUNTRY=EU865" (or whatever) to set the correct frequency range for your country. Options are provided for `EU433`, `EU865`, `CN`, `JP` and `US` (default). Pull-requests eagerly accepted for other countries.
6. Plug the radio into your USB port
7. Type `pio run --environment XXX -t upload` (This command will fetch dependencies, build the project and install it on the board via USB). For XXX, use the board type you have (either `tbeam`, `heltec`, `ttgo-lora32-v1`, `ttgo-lora32-v2`).
8. Platform IO also installs a very nice VisualStudio Code based IDE, see their [tutorial](https://docs.platformio.org/en/latest/tutorials/espressif32/arduino_debugging_unit_testing.html) if you'd like to use it.

View File

@@ -5,33 +5,47 @@ the project developers are not cryptography experts. Therefore we ask two things
- If you are a cryptography expert, please review these notes and our questions below. Can you help us by reviewing our
notes below and offering advice? We will happily give as much or as little credit as you wish ;-).
- Consider our existing solution 'alpha' and probably fairly secure against a not particularly aggressive adversary. But until
it is reviewed by someone smarter than us, assume it might have flaws.
- Consider our existing solution 'alpha' and probably fairly secure against a not particularly aggressive adversary
(but we can't yet make a more confident statement).
## Notes on implementation
## Summary of strengths/weaknesses of our current implementation
Based on comments from reviewers (see below), here's some tips for usage of these radios. So you can know the level of protection offered:
* It is pretty likely that the AES256 security is implemented 'correctly' and an observer will not be able to decode your messages.
* Warning: If an attacker is able to get one of the radios in their position, they could either a) extract the channel key from that device or b) use that radio to listen to new communications.
* Warning: If an attacker is able to get the "Channel QR code/URL" that you share with others - that attacker could then be able to read any messages sent on the channel (either tomorrow or in the past - if they kept a raw copy of those broadcast packets)
Possible future areas of work (if there is enough interest - post in our [forum](https://meshtastic.discourse.group) if you want this):
1. Optionally requiring users to provide a PIN to regain access to the mesh. This could be based on: intentionally locking the device, time since last use, or any member could force all members to reauthenticate,
2. Until a device reauthenticates, any other access via BLE or USB would be blocked (this would protect against attackers who are not prepared to write custom software to extract and reverse engineer meshtastic flash memory)
3. Turning on read-back protection in the device fuse-bits (this would extend protection in #2 to block all but **extremely** advanced attacks involving chip disassembly)
4. Time limiting keys used for message transmission and automatically cycling them on a schedule. This would protect past messages from being decoded even if an attacker learns the current key.
### Notes for reviewers
If you are reviewing our implementation, this is a brief statement of our method.
- We do all crypto at the SubPacket (payload) level only, so that all meshtastic nodes will route for others - even those channels which are encrypted with a different key.
- Mostly based on reading [Wikipedia](<https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)>) and using the modes the ESP32 provides support for in hardware.
- We use AES256-CTR as a stream cypher (with zero padding on the last BLOCK) because it is well supported with hardware acceleration.
Parameters for our CTR implementation:
- Our AES key is 128 or 256 bits, shared as part of the 'Channel' specification.
- Each SubPacket will be sent as a series of 16 byte BLOCKS.
- The node number concatenated with the packet number is used as the NONCE. This counter will be stored in flash in the device and should essentially never repeat. If the user makes a new 'Channel' (i.e. picking a new random 256 bit key), the packet number will start at zero. The packet number is sent
in cleartext with each packet. The node number can be derived from the "from" field of each packet.
- Each BLOCK for a packet has an incrementing COUNTER. COUNTER starts at zero for the first block of each packet.
- The IV for each block is constructed by concatenating the NONCE as the upper 96 bits of the IV and the COUNTER as the bottom 32 bits. Note: since our packets are small counter will really never be higher than 32 (five bits).
- The node number concatenated with the packet number is used as the NONCE. This nonce will be stored in flash in the device and should essentially never repeat. If the user makes a new 'Channel' (i.e. picking a new random 256 bit key), the packet number will start at zero.
- The packet number is sent in cleartext with each packet. The node number can be derived from the "from" field of each packet. (Cleartext is acceptable because it merely provides IV for each encryption run)
- Each 16 byte BLOCK for a packet has an incrementing COUNTER. COUNTER starts at zero for the first block of each packet.
- The IV for each block is constructed by concatenating the NONCE as the upper 96 bits of the IV and the COUNTER as the bottom 32 bits. Since our packets are small counter portion will really never be higher than 32 (five bits).
```
You can encrypt separate messages by dividing the nonce_counter buffer in two areas: the first one used for a per-message nonce, handled by yourself, and the second one updated by this function internally.
For example, you might reserve the first 12 bytes for the per-message nonce, and the last 4 bytes for internal use. In that case, before calling this function on a new message you need to set the first 12 bytes of nonce_counter to your chosen nonce value, the last 4 to 0, and nc_off to 0 (which will cause stream_block to be ignored). That way, you can encrypt at most 2**96 messages of up to 2**32 blocks each with the same key.
## Comments from reviewer #1
The per-message nonce (or information sufficient to reconstruct it) needs to be communicated with the ciphertext and must be unique. The recommended way to ensure uniqueness is to use a message counter. An alternative is to generate random nonces, but this limits the number of messages that can be securely encrypted: for example, with 96-bit random nonces, you should not encrypt more than 2**32 messages with the same key.
This reviewer is a cryptography professional, but would like to remain anonymous. We thank them for their comments ;-):
Note that for both stategies, sizes are measured in blocks and that an AES block is 16 bytes.
```
I'm assuming that meshtastic is being used to hike in places where someone capable is trying to break it - like you were going to walk around DefCon using these. I spent about an hour reviewing the encryption, and have the following notes:
## Remaining todo
* The write-up isn't quite as clear as the code.
* The code is using AES-CTR mode correctly to ensure confidentiality.
* The comment for initNonce really covers the necessary information.
* I think the bigger encryption question is "what does the encryption need to do"? As it stands, an attacker who has yet to capture any of the devices cannot reasonably capture text or location data. An attacker who captures any device in the channel/mesh can read everything going to that device, everything stored on that device, and any other communication within the channel that they captured in encrypted form. If that capability basically matches your expectations, it is suitable for whatever adventures this was intended for, then, based on information publicly available or widely disclosed, the encryption is good. If those properties are distressing (like, device history is deliberately limited and you don't want a device captured today to endanger the information sent over the channel yesterday) we could talk about ways to achieve that (most likely synchronizing time and replacing the key with its own SHA256 every X hours, and ensuring the old key is not retained unnecessarily).
* Two other things to keep in mind are that AES-CTR does not itself provide authenticity (e.g. an attacker can flip bits in replaying data and scramble the resulting plaintext), and that the current scheme gives some hints about transmission in the size. So, if you worry about an adversary deliberately messing-up messages or knowing the length of a text message, it looks like those might be possible.
- Have the app change the crypto key when the user generates a new channel
I'm guessing that the network behaves somewhat like a store-and-forward network - or, at least, that the goal is to avoid establishing a two-way connection to transmit data. I'm afraid I haven't worked with mesh networks much, but remember studying them briefly in school about ten years ago.

View File

@@ -0,0 +1,16 @@
# esp32-arduino build instructions
We build our own custom version of esp32-arduino, in order to get some fixes we've made but haven't yet been merged in master.
These are a set of currently unformatted notes on how to build and install them. Most developers should not care about this, because
you'll automatically get our fixed libraries.
```
last EDF release in arduino is: https://github.com/espressif/arduino-esp32/commit/1977370e6fc069e93ffd8818798fbfda27ae7d99
IDF release/v3.3 46b12a560
IDF release/v3.3 367c3c09c
https://docs.espressif.com/projects/esp-idf/en/release-v3.3/get-started/linux-setup.html
kevinh@kevin-server:~/development/meshtastic/esp32-arduino-lib-builder\$ python /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/esp-idf/components/esptool*py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 /home/kevinh/development/meshtastic/esp32-arduino-lib-builder/build/bootloader/bootloader.bin
cp -a out/tools/sdk/* components/arduino/tools/sdk
cp -ar components/arduino/* ~/.platformio/packages/framework-arduinoespressif32@src-fba9d33740f719f712e9f8b07da6ea13/
```

View File

@@ -19,20 +19,21 @@ reliable messaging tasks (stage one for DSR):
- DONE once an ack comes in, remove the packet from the retry list and deliver the ack to the original sender
- DONE after three retries, deliver a no-ack packet to the original sender (i.e. the phone app or mesh router service)
- DONE test one hop ack/nak with the python framework
- Do stress test with acks
- DONE Do stress test with acks
dsr tasks
- oops I might have broken message reception
- DONE oops I might have broken message reception
- DONE Don't use broadcasts for the network pings (close open github issue)
- DONE add ignoreSenders to radioconfig to allow testing different mesh topologies by refusing to see certain senders
- test multihop delivery with the python framework
- DONE test multihop delivery with the python framework
optimizations / low priority:
- read this [this](http://pages.cs.wisc.edu/~suman/pubs/nadv-mobihoc05.pdf) paper and others and make our naive flood routing less naive
- read @cyclomies long email with good ideas on optimizations and reply
- Remove NodeNum assignment algorithm (now that we use 4 byte node nums)
- make android app warn if firmware is too old or too new to talk to
- DONE Remove NodeNum assignment algorithm (now that we use 4 byte node nums)
- DONE make android app warn if firmware is too old or too new to talk to
- change nodenums and packetids in protobuf to be fixed32
- low priority: think more careful about reliable retransmit intervals
- make ReliableRouter.pending threadsafe

View File

@@ -2,11 +2,24 @@
## Misc work items
RAM investigation.
nRF52832-QFAA 64KB ram, 512KB flash vs
nrf52832-QFAB 32KB ram, 512kb flash
nrf52840 256KB RAM, 1MB flash
platform.json
"framework-arduinoadafruitnrf52": {
"type": "framework",
"optional": true,
"version": "https://github.com/meshtastic/Adafruit_nRF52_Arduino.git"
},
## Initial work items
Minimum items needed to make sure hardware is good.
- set power UICR per https://devzone.nordicsemi.com/f/nordic-q-a/28562/nrf52840-regulator-configuration
- DONE set power UICR per https://devzone.nordicsemi.com/f/nordic-q-a/28562/nrf52840-regulator-configuration
- switch charge controller into / out of performance mode (see 8.3.1 in datasheet)
- write UC1701 wrapper
- Test hardfault handler for null ptrs (if one isn't already installed)

27
docs/software/pinetab.md Normal file
View File

@@ -0,0 +1,27 @@
# Pinetab
These are **preliminary** notes on support for Meshtastic in the Pinetab.
A RF95 is connected via a CS341 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
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/
## 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
Use ARM linux: https://platformio.org/platforms/linux_arm
And linux native: https://platformio.org/platforms/native
* Test cs341 driver - just test reading/writing a register and detecting interrupts, confirm can see rf95
* Make a radiolib spi module that targets the cs341 (and builds on linux)
* use new radiolib module to hook pinebook lora to meshtastic, confirm mesh discovery works
* Make a subclass of StreamAPI that works as a posix TCP server
* Use new TCP endpoint from meshtastic-python

View File

@@ -0,0 +1,202 @@
23K + messages
+ heap of 70ish packets, 300ish bytes per packet: 20KB
+ 14KB soft device RAM
With max length Data inside the packet
Size of NodeInfo 104
Size of SubPacket 272
Size of MeshPacket 304
If Data was smaller: for 70 data packets we would save 7KB. We would need to make SubPacket.data and MeshPacket.encrypted into "type:FT_POINTER" - variably sized mallocs
Size of NodeInfo 104
Size of SubPacket 96
Size of MeshPacket 292 (could have been much smaller but I forgot to shrink MeshPacket.encrypted)
therefore:
a) we should store all ToPhone message queued messages compressed as protobufs (since they will become that anyways)
b) shrink packet pool size because none of that storage will be used for ToPhone packets
c) don't allocate any storage in RAM for the tophone messages we save inside device state, instead just use nanopb callbacks to save/load those
d) a smarter MeshPacket in memory representation would save about 7KB of RAM. call pb_release before freeing each freshly malloced MeshPacket
- nrf52 free memory https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/hathach-memory-map
2000790c 00003558 B devicestate // 16KB
2000b53c 00001000 b _cache_buffer // 4KB flash filesystem support
20003b1c 000006b0 B console
2000d5f4 00000400 b vApplicationGetTimerTaskMemory::uxTimerTaskStack
2000da04 00000400 b _acUpBuffer
2000c558 0000036c B Bluefruit
2000c8d8 00000358 b _cdcd_itf
2000e54c 00000258 B _midid_itf
2000d0dc 00000200 b ucStaticTimerQueueStorage.9390
2000e044 00000200 b _mscd_buf
2000e284 000001cc b _vendord_itf
2000d410 00000190 b vApplicationGetIdleTaskMemory::uxIdleTaskStack
2000374c 0000016c D __global_locale
2000de48 0000012c B USBDevice
2000afa4 00000100 b Router::send(_MeshPacket*)::bytes
2000aea4 00000100 b Router::perhapsDecode(_MeshPacket*)::bytes
200039b0 000000f4 B powerFSM
20004258 000000f0 B screen
2000cd7c 000000c4 b _dcd
2000cc68 000000c0 b _usbd_qdef_buf
2000b3c4 000000bc B Wire
2000cef4 000000a8 B Serial2
2000ce4c 000000a8 B Serial1
2000e498 000000a8 B _SEGGER_RTT
2000b498 000000a4 B InternalFS
2000dfb8 0000008c b _hidd_itf
2000b260 00000088 b meshtastic::normalFrames
2000cfdc 00000064 b pxReadyTasksLists
2000b340 00000060 b meshtastic::drawTextMessageFrame(OLEDDisplay*, OLEDDisplayUiState*, short, short)::tempBuf
200036ec 00000060 d impure_data
2000b104 00000060 B bledfu
2000b0a4 00000060 B blebas
20003684 00000058 D _usbd_qdef
200038c0 00000058 d tzinfo
2000d5a0 00000054 b vApplicationGetTimerTaskMemory::xTimerTaskTCB
2000d3bc 00000054 b vApplicationGetIdleTaskMemory::xIdleTaskTCB
2000d308 00000050 b xStaticTimerQueue.9389
2000b1f4 00000050 B hrmc
2000b1a4 00000050 B bslc
20004360 0000004c B service
2000d374 00000048 b m_cb
2000df74 00000042 b _desc_str
2000cd3c 00000040 b _usbd_ctrl_buf
20004214 00000040 B realRouter
2000e244 00000040 b _mscd_itf
2000b164 00000040 B bledis
20003634 00000038 d _InternalFSConfig
2000cc30 00000031 b _usbd_dev
2000398c 00000020 B periodicScheduler
2000cfa4 00000020 b callbacksInt
2000de10 0000001f b fw_str.13525
20003974 00000018 b object.9934
2000ae68 00000018 B nodeDB
2000366c 00000018 d _cache
2000b314 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::signalStr
2000b300 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::lastStr
2000b2ec 00000014 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::distStr
200041e0 00000014 b getDeviceName()::name
2000d0b8 00000014 b xTasksWaitingTermination
2000d0a4 00000014 b xSuspendedTaskList
2000d08c 00000014 b xPendingReadyList
2000d06c 00000014 b xDelayedTaskList2
2000d058 00000014 b xDelayedTaskList1
2000d2f0 00000014 b xActiveTimerList2
2000d2dc 00000014 b xActiveTimerList1
2000b480 00000014 B SPI
2000c8c4 00000014 B Serial
2000cd28 00000014 b _ctrl_xfer
2000de30 00000011 b serial_str.13534
2000c544 00000010 b BLEAdvertising::_start(unsigned short, unsigned short)::gap_adv
20003614 00000010 d meshtastic::btPIN
2000434c 00000010 b sendOwnerPeriod
2000ae8c 00000010 b staticPool
2000e484 00000010 B xQueueRegistry
20003b04 00000010 B stateSERIAL
20003af4 00000010 B stateSDS
20003ae4 00000010 B stateON
20003ad4 00000010 B stateNB
20003ac4 00000010 B stateLS
20003ab4 00000010 B stateDARK
20003aa4 00000010 B stateBOOT
200041f8 00000010 B ledPeriodic
2000b244 00000010 B hrms
2000d9f4 00000010 b _acDownBuffer
2000b3b8 0000000c B preflightSleep
20004208 0000000c B powerStatus
2000e540 0000000c B nrf_nvic_state
2000b3ac 0000000c B notifySleep
2000b3a0 0000000c B notifyDeepSleep
2000e463 0000000b b __tzname_std
2000e458 0000000b b __tzname_dst
2000b338 00000008 b meshtastic::estimatedHeading(double, double)::oldLon
2000b330 00000008 b meshtastic::estimatedHeading(double, double)::oldLat
200041d0 00000008 b zeroOffsetSecs
2000ae80 00000008 b spiSettings
200038b8 00000008 D _tzname
20003b14 00000008 B noopPrint
2000cfc4 00000008 b channelMap
2000cf9c 00000008 b callbackDeferred
200043ac 00000006 b ourMacAddr
2000435c 00000004 b MeshService::onGPSChanged(void*)::lastGpsSend
2000b32c 00000004 b meshtastic::estimatedHeading(double, double)::b
2000b328 00000004 b meshtastic::drawNodeInfo(OLEDDisplay*, OLEDDisplayUiState*, short, short)::simRadian
2000362c 00000004 d meshtastic::Screen::setup()::bootFrames
20003628 00000004 d meshtastic::Screen::handleStartBluetoothPinScreen(unsigned long)::btFrames
200039ac 00000004 b onEnter()::lastPingMs
2000ae9c 00000004 b generatePacketId()::i
2000ae88 00000004 B RadioLibInterface::instance
2000b2e8 00000004 b meshtastic::nodeIndex
20003610 00000004 d meshtastic::targetFramerate
2000c554 00000004 B BLEService::lastService
200041cc 00000004 b timeStartMsec
200036dc 00000004 d sbrk_heap_top
2000d364 00000004 b _loopHandle
2000c540 00000004 b guard variable for BLEAdvertising::_start(unsigned short, unsigned short)::gap_adv
2000d0d0 00000004 b xYieldPending
2000d35c 00000004 b xTimerTaskHandle
2000d358 00000004 b xTimerQueue
2000d0cc 00000004 b xTickCount
2000d0a0 00000004 b xSchedulerRunning
2000d088 00000004 b xNumOfOverflows
2000d084 00000004 b xNextTaskUnblockTime
2000d304 00000004 b xLastTime.9343
2000d080 00000004 b xIdleTaskHandle
2000d054 00000004 b uxTopReadyPriority
2000d050 00000004 b uxTaskNumber
2000d04c 00000004 b uxSchedulerSuspended
2000d048 00000004 b uxPendedTicks
2000d044 00000004 b uxDeletedTasksWaitingCleanUp
2000d040 00000004 b uxCurrentNumberOfTasks
2000d360 00000004 b uxCriticalNesting
2000cc64 00000004 b _usbd_q
2000e478 00000004 B _timezone
200036e0 00000004 D SystemCoreClock
2000c53c 00000004 b _sem
2000d0d8 00000004 b pxOverflowTimerList
2000cfd8 00000004 b pxOverflowDelayedTaskList
2000cfd4 00000004 b pxDelayedTaskList
2000d0d4 00000004 b pxCurrentTimerList
2000cfd0 00000004 B pxCurrentTCB
2000e470 00000004 b prev_tzenv
2000360c 00000004 D preftmp
20003608 00000004 D preffile
2000b25c 00000004 B nrf52Bluetooth
2000d370 00000004 b m_usbevt_handler
2000d36c 00000004 b m_sleepevt_handler
2000d368 00000004 b m_pofwarn_handler
2000e454 00000004 B __malloc_sbrk_start
2000e450 00000004 B __malloc_free_list
2000e480 00000004 B MAIN_MonCnt
2000e47c 00000004 b initial_env
200036e8 00000004 D _impure_ptr
200041d8 00000004 B gps
2000e7a4 00000004 B errno
20003918 00000004 D environ
2000cfcc 00000004 b enabled
2000ae64 00000004 B displayedNodeNum
2000e474 00000004 B _daylight
2000b254 00000004 B crypto
2000ce44 00000004 B count_duration
2000de0c 00000004 b _cb_task
2000de08 00000004 b _cb_queue
2000de04 00000004 b _cb_qdepth
2000de44 00000004 B bootloaderVersion
200041f5 00000001 b ledBlinker()::ledOn
20003604 00000001 d loop::showingBootScreen
200041f4 00000001 b loop::wasPressed
2000b494 00000001 b DefaultFontTableLookup(unsigned char)::LASTCHAR
2000aea0 00000001 b generatePacketId()::didInit
20003624 00000001 d meshtastic::prevFrame
2000b258 00000001 b bleOn
200041dc 00000001 B timeSetFromGPS
20004348 00000001 B ssd1306_found
2000ce49 00000001 B pin_sound
2000e494 00000001 B nrfx_power_irq_enabled
2000ce48 00000001 B no_stop
20003630 00000001 D neo6M
2000ce40 00000001 b _initialized
200036e4 00000001 D __fdlib_version
20003970 00000001 b completed.9929

View File

@@ -11,7 +11,7 @@
*****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
#define PB_ENABLE_MALLOC 1
/* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. */

View File

@@ -0,0 +1,18 @@
/* This section is only included if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
is set, to link some sections to BSS in PSRAM */
SECTIONS
{
/* external memory bss, from any global variable with EXT_RAM_ATTR attribute*/
.ext_ram.bss (NOLOAD) :
{
_ext_ram_bss_start = ABSOLUTE(.);
*(.ext_ram.bss*)
*libnet80211.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
*libpp.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
*liblwip.a:(.dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
*libbt.a:(EXCLUDE_FILE (libbtdm_app.a) .dynsbss .sbss .sbss.* .gnu.linkonce.sb.* .scommon .sbss2.* .gnu.linkonce.sb2.* .dynbss .bss .bss.* .share.mem .gnu.linkonce.b.* COMMON)
. = ALIGN(4);
_ext_ram_bss_end = ABSOLUTE(.);
} > extern_ram_seg
}

View File

@@ -0,0 +1,46 @@
/* Linker script to configure memory regions.
geeksville: modified this to simulate a nrf52832 but with a sd140 soft device. So I can
see how the memory footprint works on this lower end CPU. Note: to work with sd140 in my bootloader
I need to start ram at 0x6000 (instead of the correct 0x3600 for sd132) - so I have less
RAM available than on a real 832.
*/
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0x6D000 - 0x26000
/* FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000 */
/* SRAM required by S132 depend on
* - Attribute Table Size
* - Vendor UUID count
* - Max ATT MTU
* - Concurrent connection peripheral + central + secure links
* - Event Len, HVN queue, Write CMD queue
*/
/* RAM (rwx) : ORIGIN = 0x20003600, LENGTH = 0x20010000 - 0x20003600 */
RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20010000 - 0x20006000
}
SECTIONS
{
. = ALIGN(4);
.svc_data :
{
PROVIDE(__start_svc_data = .);
KEEP(*(.svc_data))
PROVIDE(__stop_svc_data = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
} INSERT AFTER .data;
INCLUDE "nrf52_common.ld"

View File

@@ -17,12 +17,14 @@ default_envs = tbeam ; Note: the github actions CI test build can't yet build NR
; REQUIRED environment variables - if not set the specified default will be sued
; The following environment variables must be set in the shell if you'd like to override them.
; They are used in this ini file as systenv.VARNAME, so in your shell do export "VARNAME=fish"
; HW_VERSION (default US)
; COUNTRY (default US), i.e. "export COUNTRY=EU865"
; APP_VERSION (default emptystring)
; HW_VERSION (default emptystring)
[env]
framework = arduino
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
@@ -67,7 +69,7 @@ debug_tool = jlink
lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
SPI
; 1260 ; OneButton - not used yet
1260 ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
Wire ; explicitly needed here because the AXP202 library forgets to add it
https://github.com/meshtastic/arduino-fsm.git
@@ -78,16 +80,17 @@ lib_deps =
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
platform = espressif32
framework = arduino
src_filter =
${env.src_filter} -<nrf52/>
upload_speed = 921600
debug_init_break = tbreak setup
build_flags =
${env.build_flags} -Wall -Wextra -Isrc/esp32
${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue
# Hmm - this doesn't work yet
# board_build.ldscript = linker/esp32.extram.bss.ld
lib_ignore = segger_rtt
platform_packages =
framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git
framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#f26c4f96fefd13ed0ed042e27954f8aba6328f6b
; The 1.0 release of the TBEAM board
[env:tbeam]
@@ -96,6 +99,7 @@ board = ttgo-t-beam
lib_deps =
${env.lib_deps}
https://github.com/meshtastic/AXP202X_Library.git
build_flags =
${esp32_base.build_flags} -D TBEAM_V10
@@ -125,10 +129,20 @@ board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TTGO_LORA_V2
; The Heltec Cubecell plus
; IMPORTANT NOTE: This target doesn't yet work and probably won't ever work. I'm keeping it around for now.
; For more details see my post in the forum.
[env:cubecellplus]
platform = https://github.com/HelTecAutomation/platform-asrmicro650x.git ; we use top-of-tree because stable version has too many bugs - asrmicro650x
board = cubecell_board_plus
; FIXME, bug in cubecell arduino - they are supposed to set ARDUINO
build_flags = ${env.build_flags} -DARDUINO=100 -Isrc/cubecell
src_filter =
${env.src_filter} -<esp32/> -<nrf52/>
; Common settings for NRF52 based targets
[nrf52_base]
platform = nordicnrf52
framework = arduino
debug_tool = jlink
build_type = debug ; I'm debugging with ICE a lot now
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
@@ -156,8 +170,9 @@ debug_init_break =
[env:nrf52dk]
extends = nrf52_base
board = nrf52840_dk_modified
lib_deps =
UC1701 ; for temp testing
# For experimenting with RAM sizes
# board_build.ldscript = linker/nrf52840_s140_sim832.ld
; The PPR board
[env:ppr]
@@ -166,7 +181,7 @@ board = ppr
lib_deps =
${env.lib_deps}
UC1701
https://github.com/meshtastic/BQ25703A.git

2
proto

Submodule proto updated: e7f181ef6f...ab281311c4

108
src/GPSStatus.h Normal file
View File

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

73
src/NodeStatus.h Normal file
View File

@@ -0,0 +1,73 @@
#pragma once
#include <Arduino.h>
#include "Status.h"
#include "configuration.h"
namespace meshtastic {
/// Describes the state of the NodeDB system.
class NodeStatus : public Status
{
private:
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver = CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
uint8_t numOnline = 0;
uint8_t numTotal = 0;
public:
NodeStatus() {
statusType = STATUS_TYPE_NODE;
}
NodeStatus( uint8_t numOnline, uint8_t numTotal ) : Status()
{
this->numOnline = numOnline;
this->numTotal = numTotal;
}
NodeStatus(const NodeStatus &);
NodeStatus &operator=(const NodeStatus &);
void observe(Observable<const NodeStatus *> *source)
{
statusObserver.observe(source);
}
uint8_t getNumOnline() const
{
return numOnline;
}
uint8_t getNumTotal() const
{
return numTotal;
}
bool matches(const NodeStatus *newStatus) const
{
return (
newStatus->getNumOnline() != numOnline ||
newStatus->getNumTotal() != numTotal
);
}
int updateStatus(const NodeStatus *newStatus) {
// Only update the status if values have actually changed
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
numOnline = newStatus->getNumOnline();
numTotal = newStatus->getNumTotal();
}
if(isDirty) {
DEBUG_MSG("Node status update: %d online, %d total\n", numOnline, numTotal);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
}
extern meshtastic::NodeStatus *nodeStatus;

180
src/Power.cpp Normal file
View File

@@ -0,0 +1,180 @@
#include "power.h"
#include "PowerFSM.h"
#include "main.h"
#include "utils.h"
#include "sleep.h"
#ifdef TBEAM_V10
// FIXME. nasty hack cleanup how we load axp192
#undef AXP192_SLAVE_ADDRESS
#include "axp20x.h"
AXP20X_Class axp;
bool pmu_irq = false;
Power *power;
bool Power::setup()
{
axp192Init();
PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
setPeriod(1);
return axp192_found;
}
/// Reads power status to powerStatus singleton.
//
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
void Power::readPowerStatus()
{
bool hasBattery = axp.isBatteryConnect();
int batteryVoltageMv = 0;
uint8_t batteryChargePercent = 0;
if (hasBattery) {
batteryVoltageMv = axp.getBattVoltage();
// If the AXP192 returns a valid battery percentage, use it
if (axp.getBattPercentage() >= 0) {
batteryChargePercent = axp.getBattPercentage();
} else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
// In that case, we compute an estimate of the charge percent based on maximum and minimum voltages defined in power.h
batteryChargePercent = clamp((int)(((batteryVoltageMv - BAT_MILLIVOLTS_EMPTY) * 1e2) / (BAT_MILLIVOLTS_FULL - BAT_MILLIVOLTS_EMPTY)), 0, 100);
}
}
// Notify any status instances that are observing us
const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus(hasBattery, axp.isVBUSPlug(), axp.isChargeing(), batteryVoltageMv, batteryChargePercent);
newStatus.notifyObservers(&powerStatus);
// If we have a battery at all and it is less than 10% full, force deep sleep
if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() &&
axp.getBattVoltage() < MIN_BAT_MILLIVOLTS)
powerFSM.trigger(EVENT_LOW_BATTERY);
}
void Power::doTask()
{
readPowerStatus();
// Only read once every 20 seconds once the power status for the app has been initialized
if(statusHandler && statusHandler->isInitialized())
setPeriod(1000 * 20);
}
#endif // TBEAM_V10
#ifdef AXP192_SLAVE_ADDRESS
/**
* Init the power manager chip
*
* axp192 power
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*/
void Power::axp192Init()
{
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
DEBUG_MSG("AXP192 Begin PASS\n");
// axp.setChgLEDMode(LED_BLINK_4HZ);
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("----------------------------------------\n");
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
axp.setDCDC1Voltage(3300); // for the OLED power
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
#if 0
// Not connected
//val = 0xfc;
//axp._writeByte(AXP202_VHTF_CHGSET, 1, &val); // Set temperature protection
//not used
//val = 0x46;
//axp._writeByte(AXP202_OFF_CTL, 1, &val); // enable bat detection
#endif
axp.debugCharging();
#ifdef PMU_IRQ
pinMode(PMU_IRQ, INPUT);
attachInterrupt(
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
axp.enableIRQ(AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | AXP202_CHARGING_FINISHED_IRQ | AXP202_CHARGING_IRQ |
AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
1);
axp.clearIRQ();
#endif
readPowerStatus();
} else {
DEBUG_MSG("AXP192 Begin FAIL\n");
}
} else {
DEBUG_MSG("AXP192 not found\n");
}
}
#endif
void Power::loop()
{
#ifdef PMU_IRQ
if (pmu_irq) {
pmu_irq = false;
axp.readIRQ();
DEBUG_MSG("pmu irq!\n");
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
}
if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n");
}
if (axp.isBattRemoveIRQ()) {
DEBUG_MSG("Battery removed\n");
}
if (axp.isPEKShortPressIRQ()) {
DEBUG_MSG("PEK short button press\n");
}
readPowerStatus();
axp.clearIRQ();
}
#endif // T_BEAM_V10
}

103
src/PowerStatus.h Normal file
View File

@@ -0,0 +1,103 @@
#pragma once
#include <Arduino.h>
#include "Status.h"
#include "configuration.h"
namespace meshtastic {
/// Describes the state of the GPS system.
class PowerStatus : public Status
{
private:
CallbackObserver<PowerStatus, const PowerStatus *> statusObserver = CallbackObserver<PowerStatus, const PowerStatus *>(this, &PowerStatus::updateStatus);
/// Whether we have a battery connected
bool hasBattery;
/// Battery voltage in mV, valid if haveBattery is true
int batteryVoltageMv;
/// Battery charge percentage, either read directly or estimated
uint8_t batteryChargePercent;
/// Whether USB is connected
bool hasUSB;
/// Whether we are charging the battery
bool isCharging;
public:
PowerStatus() {
statusType = STATUS_TYPE_POWER;
}
PowerStatus( bool hasBattery, bool hasUSB, bool isCharging, int batteryVoltageMv, uint8_t batteryChargePercent ) : Status()
{
this->hasBattery = hasBattery;
this->hasUSB = hasUSB;
this->isCharging = isCharging;
this->batteryVoltageMv = batteryVoltageMv;
this->batteryChargePercent = batteryChargePercent;
}
PowerStatus(const PowerStatus &);
PowerStatus &operator=(const PowerStatus &);
void observe(Observable<const PowerStatus *> *source)
{
statusObserver.observe(source);
}
bool getHasBattery() const
{
return hasBattery;
}
bool getHasUSB() const
{
return hasUSB;
}
bool getIsCharging() const
{
return isCharging;
}
int getBatteryVoltageMv() const
{
return batteryVoltageMv;
}
uint8_t getBatteryChargePercent() const
{
return batteryChargePercent;
}
bool matches(const PowerStatus *newStatus) const
{
return (
newStatus->getHasBattery() != hasBattery ||
newStatus->getHasUSB() != hasUSB ||
newStatus->getBatteryVoltageMv() != batteryVoltageMv
);
}
int updateStatus(const PowerStatus *newStatus) {
// Only update the status if values have actually changed
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
hasBattery = newStatus->getHasBattery();
batteryVoltageMv = newStatus->getBatteryVoltageMv();
batteryChargePercent = newStatus->getBatteryChargePercent();
hasUSB = newStatus->getHasUSB();
isCharging = newStatus->getIsCharging();
}
if(isDirty) {
DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
}
extern meshtastic::PowerStatus *powerStatus;

72
src/Status.h Normal file
View File

@@ -0,0 +1,72 @@
#pragma once
#include "Observer.h"
// Constants for the various status types, so we can tell subclass instances apart
#define STATUS_TYPE_BASE 0
#define STATUS_TYPE_POWER 1
#define STATUS_TYPE_GPS 2
#define STATUS_TYPE_NODE 3
namespace meshtastic
{
// A base class for observable status
class Status
{
protected:
// Allows us to observe an Observable
CallbackObserver<Status, const Status *> statusObserver = CallbackObserver<Status, const Status *>(this, &Status::updateStatus);
bool initialized = false;
// Workaround for no typeid support
int statusType;
public:
// Allows us to generate observable events
Observable<const Status *> onNewStatus;
// Enable polymorphism ?
virtual ~Status() = default;
Status() {
if (!statusType)
{
statusType = STATUS_TYPE_BASE;
}
}
// Prevent object copy/move
Status(const Status &) = delete;
Status &operator=(const Status &) = delete;
// Start observing a source of data
void observe(Observable<const Status *> *source)
{
statusObserver.observe(source);
}
// Determines whether or not existing data matches the data in another Status instance
bool matches(const Status *otherStatus) const
{
return true;
}
bool isInitialized() const
{
return initialized;
}
int getStatusType() const
{
return statusType;
}
// Called when the Observable we're observing generates a new notification
int updateStatus(const Status *newStatus)
{
return 0;
}
};
};

0
src/StatusHandler.h Normal file
View File

View File

@@ -2,6 +2,8 @@
#include "debug.h"
#include <assert.h>
#ifdef configUSE_PREEMPTION
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
{
auto r = xTaskCreate(callRun, name, stackSize, this, priority, &taskHandle);
@@ -15,8 +17,15 @@ void Thread::callRun(void *_this)
void WorkerThread::doRun()
{
startWatchdog();
while (!wantExit) {
stopWatchdog();
block();
startWatchdog();
// no need - startWatchdog is guaranteed to give us one full watchdog interval
// serviceWatchdog(); // Let our loop worker have one full watchdog interval (at least) to run
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
@@ -28,6 +37,8 @@ void WorkerThread::doRun()
loop();
}
stopWatchdog();
}
/**
@@ -43,3 +54,5 @@ void NotifiedWorkerThread::block()
xTaskNotifyWait(0, // don't clear notification on entry
clearOnRead, &notification, portMAX_DELAY); // Wait forever
}
#endif

View File

@@ -1,5 +1,9 @@
#include "esp_task_wdt.h"
#include "freertosinc.h"
#include <Arduino.h>
#ifdef HAS_FREE_RTOS
class Thread
{
protected:
@@ -23,6 +27,23 @@ class Thread
*/
virtual void doRun() = 0;
/**
* All thread run methods must periodically call serviceWatchdog, or the system will declare them hung and panic.
*
* this only applies after startWatchdog() has been called. If you need to sleep for a long time call stopWatchdog()
*/
void serviceWatchdog() { esp_task_wdt_reset(); }
void startWatchdog()
{
auto r = esp_task_wdt_add(taskHandle);
assert(r == ESP_OK);
}
void stopWatchdog()
{
auto r = esp_task_wdt_delete(taskHandle);
assert(r == ESP_OK);
}
private:
static void callRun(void *_this);
};
@@ -89,3 +110,5 @@ class NotifiedWorkerThread : public WorkerThread
*/
virtual void block();
};
#endif

View File

@@ -73,6 +73,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN PIN_BUTTON1
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#elif defined(CubeCell_BoardPlus)
//
// Standard definitions for CubeCell targets
//
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
// FIXME, not yet ready for NRF52
#define RTC_DATA_ATTR
#define LED_PIN -1 // FIXME totally bogus
#define BUTTON_PIN -1
#else
//
@@ -104,6 +118,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SSD1306_ADDRESS 0x3C
// 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.
//#define USE_SH1106
// 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
@@ -126,7 +144,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define I2C_SDA 21
#define I2C_SCL 22
#define BUTTON_PIN 38
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
#ifndef USE_JTAG
#define RESET_GPIO 14
@@ -168,6 +187,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "heltec"
// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine.
// Tested on Neo6m module.
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
@@ -188,6 +214,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#elif defined(TTGO_LORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v1"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 37
#define I2C_SDA 4 // I2C pins for this board
#define I2C_SCL 15
@@ -206,6 +236,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v2"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 13 // per @eugene
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
@@ -256,7 +291,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DEBUG_PORT console // Serial debug port
#ifdef NO_ESP32
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
#define USE_SEGGER
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32

1
src/cubecell/FS.h Normal file
View File

@@ -0,0 +1 @@
// Placeholder FIXME

View File

@@ -76,6 +76,7 @@ class DataCharacteristic : public CallbackCharacteristic
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
}
};
@@ -123,8 +124,10 @@ class CRC32Characteristic : public CallbackCharacteristic
void bluetoothRebootCheck()
{
if (rebootAtMsec && millis() > rebootAtMsec)
if (rebootAtMsec && millis() > rebootAtMsec) {
DEBUG_MSG("Rebooting for update\n");
ESP.restart();
}
}
/*

View File

@@ -8,7 +8,6 @@
SimpleAllocator btPool;
bool _BLEClientConnected = false;
class MyServerCallbacks : public BLEServerCallbacks
@@ -67,7 +66,8 @@ BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendo
{
BLEService *deviceInfoService = server->createService(BLEUUID((uint16_t)ESP_GATT_UUID_DEVICE_INFO_SVC));
BLECharacteristic *swC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
BLECharacteristic *swC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR),
// BLECharacteristic::PROPERTY_READ);
@@ -106,7 +106,6 @@ BLEService *createDeviceInfomationService(BLEServer *server, std::string hwVendo
return deviceInfoService;
}
static BLECharacteristic *batteryLevelC;
/**
@@ -123,7 +122,7 @@ BLEService *createBatteryService(BLEServer *server)
addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100");
batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
// I don't think we need to advertise this
// I don't think we need to advertise this? and some phones only see the first thing advertised anyways...
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery->start();
@@ -136,8 +135,8 @@ BLEService *createBatteryService(BLEServer *server)
*/
void updateBatteryLevel(uint8_t level)
{
// Pretend to update battery levels - fixme do elsewhere
if (batteryLevelC) {
DEBUG_MSG("set BLE battery level %u\n", level);
batteryLevelC->setValue(&level, 1);
batteryLevelC->notify();
}
@@ -216,7 +215,7 @@ class MySecurity : public BLESecurityCallbacks
BLEServer *pServer;
BLEService *pDevInfo, *pUpdate;
BLEService *pDevInfo, *pUpdate, *pBattery;
void deinitBLE()
{
@@ -231,6 +230,9 @@ void deinitBLE()
pUpdate->executeDelete();
}
pBattery->stop();
pBattery->executeDelete();
pDevInfo->stop();
pDevInfo->executeDelete();
@@ -243,6 +245,7 @@ void deinitBLE()
if (pUpdate != NULL)
delete pUpdate;
delete pDevInfo;
delete pBattery;
delete pServer;
batteryLevelC = NULL; // Don't let anyone generate bogus notifies
@@ -280,10 +283,9 @@ BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoo
pDevInfo = createDeviceInfomationService(pServer, hwVendor, swVersion, hwVersion);
// We now let users create the battery service only if they really want (not all devices have a battery)
// BLEService *pBattery = createBatteryService(pServer);
pBattery = createBatteryService(pServer);
// #define BLE_SOFTWARE_UPDATE
#define BLE_SOFTWARE_UPDATE
#ifdef BLE_SOFTWARE_UPDATE
pUpdate = createUpdateService(pServer, hwVendor, swVersion,
hwVersion); // We need to advertise this so our android ble scan operation can see it
@@ -304,7 +306,11 @@ BLEServer *initBLE(StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoo
static BLESecurity security; // static to avoid allocs
BLESecurity *pSecurity = &security;
pSecurity->setCapability(ESP_IO_CAP_OUT);
// FIXME - really should be ESP_LE_AUTH_REQ_SC_BOND but it seems there is a bug right now causing that bonding info to be lost
// occasionally?
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
return pServer;

View File

@@ -35,5 +35,8 @@ BLECharacteristic *addBLECharacteristic(BLECharacteristic *c);
/// Add a characteristic that we will delete when we restart
BLEDescriptor *addBLEDescriptor(BLEDescriptor *c);
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level);
/// Any bluetooth objects you allocate _must_ come from this pool if you want to be able to call deinitBLE()
extern SimpleAllocator btPool;

View File

@@ -2,9 +2,11 @@
#include "MeshBluetoothService.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "esp_task_wdt.h"
#include "main.h"
#include "power.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
bool bluetoothOn;
@@ -58,101 +60,17 @@ void getMacAddr(uint8_t *dmac)
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
}
#ifdef TBEAM_V10
/*
static void printBLEinfo() {
int dev_num = esp_ble_get_bond_device_num();
// FIXME. nasty hack cleanup how we load axp192
#undef AXP192_SLAVE_ADDRESS
#include "axp20x.h"
AXP20X_Class axp;
bool pmu_irq = false;
/// Reads power status to powerStatus singleton.
//
// TODO(girts): move this and other axp stuff to power.h/power.cpp.
void readPowerStatus()
{
powerStatus.haveBattery = axp.isBatteryConnect();
if (powerStatus.haveBattery) {
powerStatus.batteryVoltageMv = axp.getBattVoltage();
esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
esp_ble_get_bond_device_list(&dev_num, dev_list);
for (int i = 0; i < dev_num; i++) {
// esp_ble_remove_bond_device(dev_list[i].bd_addr);
}
powerStatus.usb = axp.isVBUSPlug();
powerStatus.charging = axp.isChargeing();
}
#endif // TBEAM_V10
#ifdef AXP192_SLAVE_ADDRESS
/**
* Init the power manager chip
*
* axp192 power
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
*/
void axp192Init()
{
if (axp192_found) {
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
DEBUG_MSG("AXP192 Begin PASS\n");
// axp.setChgLEDMode(LED_BLINK_4HZ);
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("----------------------------------------\n");
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
axp.setDCDC1Voltage(3300); // for the OLED power
DEBUG_MSG("DCDC1: %s\n", axp.isDCDC1Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC2: %s\n", axp.isDCDC2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO2: %s\n", axp.isLDO2Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("LDO3: %s\n", axp.isLDO3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
#if 0
// Not connected
//val = 0xfc;
//axp._writeByte(AXP202_VHTF_CHGSET, 1, &val); // Set temperature protection
//not used
//val = 0x46;
//axp._writeByte(AXP202_OFF_CTL, 1, &val); // enable bat detection
#endif
axp.debugCharging();
#ifdef PMU_IRQ
pinMode(PMU_IRQ, INPUT);
attachInterrupt(
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
axp.enableIRQ(AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | AXP202_CHARGING_FINISHED_IRQ | AXP202_CHARGING_IRQ |
AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
1);
axp.clearIRQ();
#endif
readPowerStatus();
} else {
DEBUG_MSG("AXP192 Begin FAIL\n");
}
} else {
DEBUG_MSG("AXP192 not found\n");
}
}
#endif
} */
void esp32Setup()
{
@@ -165,9 +83,17 @@ void esp32Setup()
DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize());
DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram());
#ifdef AXP192_SLAVE_ADDRESS
axp192Init();
#endif
// enableModemSleep();
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now.
#define APP_WATCHDOG_SECS 45
auto res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
assert(res == ESP_OK);
res = esp_task_wdt_add(NULL);
assert(res == ESP_OK);
}
#if 0
@@ -190,60 +116,12 @@ uint32_t axpDebugRead()
Periodic axpDebugOutput(axpDebugRead);
#endif
/**
* Per @spattinson
* MIN_BAT_MILLIVOLTS seems high. Typical 18650 are different chemistry to LiPo, even for LiPos that chart seems a bit off, other
* charts put 3690mV at about 30% for a lipo, for 18650 i think 10% remaining iis in the region of 3.2-3.3V. Reference 1st graph
* in [this test report](https://lygte-info.dk/review/batteries2012/Samsung%20INR18650-30Q%203000mAh%20%28Pink%29%20UK.html)
* looking at the red line - discharge at 0.2A - he gets a capacity of 2900mah, 90% of 2900 = 2610, that point in the graph looks
* to be a shade above 3.2V
*/
#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per https://blog.ampow.com/lipo-voltage-chart/
/// loop code specific to ESP32 targets
void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
loopBLE();
// for debug printing
// radio.radioIf.canSleep();
#ifdef PMU_IRQ
if (pmu_irq) {
pmu_irq = false;
axp.readIRQ();
DEBUG_MSG("pmu irq!\n");
if (axp.isChargingIRQ()) {
DEBUG_MSG("Battery start charging\n");
}
if (axp.isChargingDoneIRQ()) {
DEBUG_MSG("Battery fully charged\n");
}
if (axp.isVbusRemoveIRQ()) {
DEBUG_MSG("USB unplugged\n");
}
if (axp.isVbusPlugInIRQ()) {
DEBUG_MSG("USB plugged In\n");
}
if (axp.isBattPlugInIRQ()) {
DEBUG_MSG("Battery inserted\n");
}
if (axp.isBattRemoveIRQ()) {
DEBUG_MSG("Battery removed\n");
}
if (axp.isPEKShortPressIRQ()) {
DEBUG_MSG("PEK short button press\n");
}
readPowerStatus();
axp.clearIRQ();
}
if (powerStatus.haveBattery && !powerStatus.usb &&
axp.getBattVoltage() < MIN_BAT_MILLIVOLTS) // If we have a battery at all and it is less than 10% full, force deep sleep
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif // T_BEAM_V10
}

View File

@@ -1,16 +1,30 @@
#pragma once
// The FreeRTOS includes are in a different directory on ESP32 and I can't figure out how to make that work with platformio gcc options
// so this is my quick hack to make things work
// The FreeRTOS includes are in a different directory on ESP32 and I can't figure out how to make that work with platformio gcc
// options so this is my quick hack to make things work
#ifdef ARDUINO_ARCH_ESP32
#define HAS_FREE_RTOS
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#else
// not yet supported on cubecell
#ifndef CubeCell_BoardPlus
#define HAS_FREE_RTOS
#include <FreeRTOS.h>
#include <task.h>
#include <semphr.h>
#include <queue.h>
#include <semphr.h>
#include <task.h>
#else
#include <Arduino.h>
typedef uint32_t TickType_t;
typedef uint32_t BaseType_t;
#define portMAX_DELAY UINT32_MAX
#endif
#endif

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Observer.h"
#include "GPSStatus.h"
#include "PeriodicTask.h"
#include "sys/time.h"
@@ -8,6 +9,9 @@
void perhapsSetRTC(const struct timeval *tv);
void perhapsSetRTC(struct tm &t);
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
/// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero
uint32_t getTime();
@@ -31,10 +35,14 @@ class GPS : public Observable<void *>
public:
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
bool isConnected = false; // Do we have a GPS we are talking to
virtual ~GPS() {}
Observable<const meshtastic::GPSStatus *> newStatus;
/**
* Returns true if we succeeded
*/

View File

@@ -53,13 +53,21 @@ void NEMAGPS::loop()
latitude = toDegInt(loc.lat);
longitude = toDegInt(loc.lng);
}
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if(reader.hdop.isValid()) {
dop = reader.hdop.value();
}
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d\n", latitude * 1e-7, longitude * 1e-7, altitude);
DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2);
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
if (hasValidLocation)
notifyObservers(NULL);
}
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop);
newStatus.notifyObservers(&status);
}
}

View File

@@ -86,38 +86,40 @@ void UBloxGPS::doTask()
// If we don't have a fix (a quick check), don't try waiting for a solution)
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
// turn off for now
// fixtype = ublox.getFixType();
// DEBUG_MSG("fix type %d\n", fixtype);
fixtype = ublox.getFixType(0);
DEBUG_MSG("GPS fix type %d\n", fixtype);
// DEBUG_MSG("sec %d\n", ublox.getSecond());
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
// any fix that has time
if (ublox.getT()) {
if (ublox.getT(0)) {
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970
(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = ublox.getSecond();
t.tm_min = ublox.getMinute();
t.tm_hour = ublox.getHour();
t.tm_mday = ublox.getDay();
t.tm_mon = ublox.getMonth() - 1;
t.tm_year = ublox.getYear() - 1900;
t.tm_sec = ublox.getSecond(0);
t.tm_min = ublox.getMinute(0);
t.tm_hour = ublox.getHour(0);
t.tm_mday = ublox.getDay(0);
t.tm_mon = ublox.getMonth(0) - 1;
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(t);
}
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP()) // rd fixes only
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(0)) // rd fixes only
{
// we only notify if position has changed
latitude = ublox.getLatitude();
longitude = ublox.getLongitude();
altitude = ublox.getAltitude() / 1000; // in mm convert to meters
DEBUG_MSG("new gps pos lat=%f, lon=%f, alt=%d\n", latitude * 1e-7, longitude * 1e-7, altitude);
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
hasValidLocation = (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000);
if (hasValidLocation) {
wantNewLocation = false;
notifyObservers(NULL);
@@ -126,6 +128,10 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
} else // we didn't get a location update, go back to sleep and hope the characters show up
wantNewLocation = true;
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop);
newStatus.notifyObservers(&status);
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over
// the serial
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);

View File

@@ -4,7 +4,12 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
const
const uint8_t imgUSB[] PROGMEM = { 0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C };
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 };
const uint8_t imgUser[] PROGMEM = { 0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C };
const uint8_t imgPositionEmpty[] PROGMEM = { 0x20, 0x30, 0x28, 0x24, 0x42, 0xFF };
const uint8_t imgPositionSolid[] PROGMEM = { 0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF };
#include "icon.xbm"
// We now programmatically draw our compass

View File

@@ -5,6 +5,7 @@
namespace meshtastic
{
#ifdef configUSE_PREEMPTION
Lock::Lock()
{
handle = xSemaphoreCreateBinary();
@@ -21,6 +22,20 @@ void Lock::unlock()
{
assert(xSemaphoreGive(handle));
}
#else
Lock::Lock()
{
}
void Lock::lock()
{
}
void Lock::unlock()
{
}
#endif
LockGuard::LockGuard(Lock *lock) : lock(lock)
{

View File

@@ -25,7 +25,9 @@ class Lock
void unlock();
private:
#ifdef configUSE_PREEMPTION
SemaphoreHandle_t handle;
#endif
};
// RAII lock guard.

View File

@@ -37,18 +37,33 @@
#include "main.h"
#include "screen.h"
#include "sleep.h"
#include <OneButton.h>
#include <Wire.h>
// #include <driver/rtc_io.h>
#ifndef NO_ESP32
#include "BluetoothUtil.h"
#include "WiFi.h"
#endif
#include "RF95Interface.h"
#include "SX1262Interface.h"
#ifdef NRF52_SERIES
#include "variant.h"
#endif
// We always create a screen object, but we only init it if we find the hardware
meshtastic::Screen screen(SSD1306_ADDRESS);
// Global power status singleton
meshtastic::PowerStatus powerStatus;
// Global power status
meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus();
// Global GPS status
meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus();
// Global Node status
meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus();
bool ssd1306_found;
bool axp192_found;
@@ -112,16 +127,48 @@ static uint32_t ledBlinker()
setLed(ledOn);
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus.charging ? 1000 : (ledOn ? 2 : 1000);
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 2 : 1000);
}
Periodic ledPeriodic(ledBlinker);
#include "RF95Interface.h"
#include "SX1262Interface.h"
// Prepare for button presses
#ifdef BUTTON_PIN
OneButton userButton;
#endif
#ifdef BUTTON_PIN_ALT
OneButton userButtonAlt;
#endif
void userButtonPressed()
{
powerFSM.trigger(EVENT_PRESS);
}
void userButtonPressedLong()
{
screen.adjustBrightness();
}
#ifdef NO_ESP32
#include "variant.h"
#ifndef NO_ESP32
void initWifi()
{
strcpy(radioConfig.preferences.wifi_ssid, "geeksville");
strcpy(radioConfig.preferences.wifi_password, "xxx");
if (radioConfig.has_preferences) {
const char *wifiName = radioConfig.preferences.wifi_ssid;
if (*wifiName) {
const char *wifiPsw = radioConfig.preferences.wifi_password;
if (radioConfig.preferences.wifi_ap_mode) {
// DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw));
} else {
// WiFi.mode(WIFI_MODE_STA);
DEBUG_MSG("JOINING WIFI: ssid=%s\n", wifiName);
// WiFi.begin(wifiName, wifiPsw);
}
}
} else
DEBUG_MSG("Not using WIFI\n");
}
#endif
void setup()
@@ -152,12 +199,21 @@ void setup()
#else
Wire.begin();
#endif
// i2c still busted on new board
#ifndef ARDUINO_NRF52840_PPR
scanI2Cdevice();
#endif
// Buttons & LED
#ifdef BUTTON_PIN
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite(BUTTON_PIN, 1);
userButton = OneButton(BUTTON_PIN, true, true);
userButton.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
userButtonAlt.attachClick(userButtonPressed);
userButton.attachDuringLongPress(userButtonPressedLong);
#endif
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
@@ -177,6 +233,14 @@ void setup()
esp32Setup();
#endif
#ifdef TBEAM_V10
// Currently only the tbeam has a PMU
power = new Power();
power->setup();
power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus);
#endif
#ifdef NRF52_SERIES
nrf52Setup();
#endif
@@ -205,8 +269,14 @@ void setup()
gps = new NEMAGPS();
gps->setup();
#endif
gpsStatus->observe(&gps->newStatus);
nodeStatus->observe(&nodeDB.newStatus);
service.init();
#ifndef NO_ESP32
// Must be after we init the service, because the wifi settings are loaded by NodeDB (oops)
initWifi();
#endif
#ifdef SX1262_ANT_SW
// make analog PA vs not PA switch on SX1262 eval board work properly
@@ -234,7 +304,7 @@ void setup()
new SimRadio();
#endif
if (!rIf->init())
if (!rIf || !rIf->init())
recordCriticalError(ErrNoRadio);
else
router.addInterface(rIf);
@@ -288,26 +358,15 @@ void loop()
#ifndef NO_ESP32
esp32Loop();
#endif
#ifdef TBEAM_V10
power->loop();
#endif
#ifdef BUTTON_PIN
// if user presses button for more than 3 secs, discard our network prefs and reboot (FIXME, use a debounce lib instead of
// this boilerplate)
static bool wasPressed = false;
if (!digitalRead(BUTTON_PIN)) {
if (!wasPressed) { // just started a new press
DEBUG_MSG("pressing\n");
// doLightSleep();
// esp_pm_dump_locks(stdout); // FIXME, do this someplace better
wasPressed = true;
powerFSM.trigger(EVENT_PRESS);
}
} else if (wasPressed) {
// we just did a release
wasPressed = false;
}
userButton.tick();
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt.tick();
#endif
// Show boot screen for first 3 seconds, then switch to normal operation.
@@ -326,11 +385,8 @@ void loop()
#endif
// Update the screen last, after we've figured out what to show.
screen.debug()->setNodeNumbersStatus(nodeDB.getNumOnlineNodes(), nodeDB.getNumNodes());
screen.debug()->setChannelNameStatus(channelSettings.name);
screen.debug()->setPowerStatus(powerStatus);
// TODO(#4): use something based on hdop to show GPS "signal" strength.
screen.debug()->setGPSStatus(gps->hasLock() ? "good" : "bad");
// screen.debug()->setPowerStatus(powerStatus);
// No GPS lock yet, let the OS put the main CPU in low power mode for 100ms (or until another interrupt comes in)
// i.e. don't just keep spinning in loop as fast as we can.

View File

@@ -1,6 +1,9 @@
#pragma once
#include "screen.h"
#include "PowerStatus.h"
#include "GPSStatus.h"
#include "NodeStatus.h"
extern bool axp192_found;
extern bool ssd1306_found;
@@ -9,6 +12,11 @@ extern bool isUSBPowered;
// Global Screen singleton.
extern meshtastic::Screen screen;
//extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class
//extern meshtastic::PowerStatus *powerStatus;
//extern meshtastic::GPSStatus *gpsStatus;
//extern meshtastic::NodeStatusHandler *nodeStatusHandler;
// Return a human readable string of the form "Meshtastic_ab13"
const char *getDeviceName();

View File

@@ -107,6 +107,7 @@ template <class T> class MemoryPool : public Allocator<T>
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
}
#ifdef HAS_FREE_RTOS
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
{
@@ -115,6 +116,7 @@ template <class T> class MemoryPool : public Allocator<T>
(size_t)(p - buf) <
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
}
#endif
protected:
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you

View File

@@ -11,6 +11,8 @@
#include "PowerFSM.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "power.h"
#include "BluetoothUtil.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
/*
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
@@ -160,7 +162,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
if (mp) {
DEBUG_MSG("Forwarding to phone, from=0x%x, rx_time=%u\n", mp->from, mp->rx_time);
printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
fromNum++;
@@ -280,6 +282,8 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
sendToMesh(p);
}
int MeshService::onGPSChanged(void *unused)
{
// DEBUG_MSG("got gps notify\n");
@@ -298,6 +302,10 @@ int MeshService::onGPSChanged(void *unused)
pos.time = getValidTime();
}
// Include our current battery voltage in our position announcement
pos.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(pos.battery_level);
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();

View File

@@ -3,7 +3,6 @@
#include <assert.h>
#include "FS.h"
#include "SPIFFS.h"
#include "CryptoEngine.h"
#include "GPS.h"
@@ -20,7 +19,7 @@
NodeDB nodeDB;
// we have plenty of ram so statically alloc this tempbuf (for now)
DeviceState devicestate;
EXT_RAM_ATTR DeviceState devicestate;
MyNodeInfo &myNodeInfo = devicestate.my_node;
RadioConfig &radioConfig = devicestate.radio;
ChannelSettings &channelSettings = radioConfig.channel_settings;
@@ -30,15 +29,18 @@ DeviceState versions used to be defined in the .proto file but really only this
#define here.
*/
#define DEVICESTATE_CUR_VER 9
#define DEVICESTATE_CUR_VER 10
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
#ifndef 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()
@@ -101,17 +103,22 @@ void NodeDB::resetRadioConfig()
crypto->setKey(channelSettings.psk.size, channelSettings.psk.bytes);
// temp hack for quicker testing
// devicestate.no_save = true;
if (devicestate.no_save) {
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.position_broadcast_secs = 6 * 60;
radioConfig.preferences.ls_secs = 60;
*/
}
}
void NodeDB::init()
void NodeDB::installDefaultDeviceState()
{
memset(&devicestate, 0, sizeof(devicestate));
// init our devicestate with valid flags so protobuf writing/reading will work
devicestate.has_my_node = true;
devicestate.has_radio = true;
@@ -119,7 +126,7 @@ void NodeDB::init()
devicestate.radio.has_channel_settings = true;
devicestate.radio.has_preferences = true;
devicestate.node_db_count = 0;
devicestate.receive_queue_count = 0;
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
resetRadioConfig();
@@ -139,12 +146,17 @@ void NodeDB::init()
pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid
// owner.short_name now
sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]);
sprintf(owner.short_name, "?%02X", myNodeInfo.my_node_num & 0xff);
sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff));
}
void NodeDB::init()
{
installDefaultDeviceState();
if (!FSBegin()) // FIXME - do this in main?
{
DEBUG_MSG("ERROR filesystem mount Failed\n");
// FIXME - report failure to phone
assert(0); // FIXME - report failure to phone
}
// saveToDisk();
@@ -210,7 +222,7 @@ const char *preftmp = "/db.proto.tmp";
void NodeDB::loadFromDisk()
{
#ifdef FS
static DeviceState scratch;
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
auto f = FS.open(preffile);
if (f) {
@@ -219,16 +231,17 @@ void NodeDB::loadFromDisk()
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
memset(&scratch, 0, sizeof(scratch));
if (!pb_decode(&stream, DeviceState_fields, &scratch)) {
memset(&devicestate, 0, sizeof(devicestate));
if (!pb_decode(&stream, DeviceState_fields, &devicestate)) {
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
// FIXME - report failure to phone
} else {
if (scratch.version < DEVICESTATE_MIN_VER)
if (devicestate.version < DEVICESTATE_MIN_VER) {
DEBUG_MSG("Warn: devicestate is old, discarding\n");
else {
DEBUG_MSG("Loaded saved preferences version %d\n", scratch.version);
devicestate = scratch;
installDefaultDeviceState();
} else {
DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version);
}
// DEBUG_MSG("Postload channel name=%s\n", channelSettings.name);
@@ -238,6 +251,7 @@ void NodeDB::loadFromDisk()
} else {
DEBUG_MSG("No saved preferences found\n");
}
#else
DEBUG_MSG("ERROR: Filesystem not implemented\n");
#endif
@@ -246,6 +260,7 @@ void NodeDB::loadFromDisk()
void NodeDB::saveToDisk()
{
#ifdef FS
if (!devicestate.no_save) {
auto f = FS.open(preftmp, FILE_O_WRITE);
if (f) {
DEBUG_MSG("Writing preferences\n");
@@ -273,6 +288,9 @@ void NodeDB::saveToDisk()
} else {
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
}
} else {
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
}
#else
DEBUG_MSG("ERROR filesystem not implemented\n");
#endif
@@ -324,8 +342,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
int oldNumNodes = *numNodes;
NodeInfo *info = getOrCreateNode(mp.from);
if (oldNumNodes != *numNodes)
updateGUI = true; // we just created a nodeinfo
notifyObservers();
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
info->has_position = true; // at least the time is valid

View File

@@ -2,9 +2,11 @@
#include <Arduino.h>
#include <assert.h>
#include "Observer.h"
#include "MeshTypes.h"
#include "mesh-pb-constants.h"
#include "NodeStatus.h"
extern DeviceState devicestate;
extern MyNodeInfo &myNodeInfo;
@@ -32,6 +34,7 @@ class NodeDB
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)
/// instead just store in flash - possibly even in the initial alpha release do this hack
@@ -91,8 +94,18 @@ class NodeDB
/// Find a node in our DB, create an empty NodeInfo if missing
NodeInfo *getOrCreateNode(NodeNum n);
/// Notify observers of changes to the DB
void notifyObservers() {
// Notify observers of the current node state
const meshtastic::NodeStatus status = meshtastic::NodeStatus(getNumOnlineNodes(), getNumNodes());
newStatus.notifyObservers(&status);
}
/// read our db from flash
void loadFromDisk();
/// Reinit device state from scratch (not loading from disk)
void installDefaultDeviceState();
};
/**

View File

@@ -2,8 +2,6 @@
#include "configuration.h"
#include "mesh-pb-constants.h"
PacketHistory::PacketHistory()
{
recentPackets.reserve(MAX_NUM_NODES); // Prealloc the worst case # of records - to prevent heap fragmentation
@@ -48,7 +46,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
r.sender = p->from;
r.rxTimeMsec = now;
recentPackets.push_back(r);
DEBUG_MSG("Adding packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
printPacket("Adding packet record", p);
}
return false;

View File

@@ -35,9 +35,8 @@ class PacketRecordOrderFunction
// If the timer ticks have rolled over the difference between times will be _enormous_. Handle that case specially
uint32_t t1 = p1.rxTimeMsec, t2 = p2.rxTimeMsec;
if (abs(t1 - t2) >
UINT32_MAX /
2) { // time must have rolled over, swap them because the new little number is 'bigger' than the old big number
if (t1 - t2 > UINT32_MAX / 2) {
// time must have rolled over, swap them because the new little number is 'bigger' than the old big number
t1 = t2;
t2 = p1.rxTimeMsec;
}

View File

@@ -2,6 +2,8 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioInterface.h"
#include "GPS.h"
#include <assert.h>
PhoneAPI::PhoneAPI()
@@ -43,8 +45,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
switch (toRadioScratch.which_variant) {
case ToRadio_packet_tag: {
MeshPacket &p = toRadioScratch.variant.packet;
DEBUG_MSG("PACKET FROM PHONE: id=%d, to=%x, want_ack=%d, which1=%d, which2=%d, typ=%d, buflen=%d\n", p.id, p.to, p.want_ack, p.which_payload,
p.decoded.which_payload, p.decoded.data.typ, bufLength);
printPacket("PACKET FROM PHONE", &p);
service.handleToRadio(p);
break;
}
@@ -78,6 +79,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
}
}
/**
* Get the next packet we want to send to the phone, or NULL if no such packet is available.
*
@@ -108,6 +110,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break;
case STATE_SEND_MY_INFO:
myNodeInfo.has_gps = gps && gps->isConnected; // Update with latest GPS connect info
fromRadioScratch.which_variant = FromRadio_my_info_tag;
fromRadioScratch.variant.my_info = myNodeInfo;
state = STATE_SEND_RADIO;

View File

@@ -18,6 +18,7 @@ template <class T> class PointerQueue : public TypedQueue<T *>
return this->dequeue(&p, maxWait) ? p : nullptr;
}
#ifdef HAS_FREE_RTOS
// returns a ptr or null if the queue was empty
T *dequeuePtrFromISR(BaseType_t *higherPriWoken)
{
@@ -25,4 +26,5 @@ template <class T> class PointerQueue : public TypedQueue<T *>
return this->dequeueFromISR(&p, higherPriWoken) ? p : nullptr;
}
#endif
};

View File

@@ -24,6 +24,52 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
// 1kb was too small
#define RADIO_STACK_SIZE 4096
void printPacket(const char *prefix, const MeshPacket *p)
{
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
p->hop_limit);
if (p->which_payload == MeshPacket_decoded_tag) {
auto &s = p->decoded;
switch (s.which_payload) {
case SubPacket_data_tag:
DEBUG_MSG(" Payload:Data");
break;
case SubPacket_position_tag:
DEBUG_MSG(" Payload:Position");
break;
case SubPacket_user_tag:
DEBUG_MSG(" Payload:User");
break;
case 0:
DEBUG_MSG(" Payload:None");
break;
default:
DEBUG_MSG(" Payload:%d", s.which_payload);
break;
}
if (s.want_response)
DEBUG_MSG(" WANTRESP");
if (s.source != 0)
DEBUG_MSG(" source=%08x", s.source);
if (s.dest != 0)
DEBUG_MSG(" dest=%08x", s.dest);
if (s.which_ack == SubPacket_success_id_tag)
DEBUG_MSG(" successId=%08x", s.ack.success_id);
else if (s.which_ack == SubPacket_fail_id_tag)
DEBUG_MSG(" failId=%08x", s.ack.fail_id);
} else {
DEBUG_MSG(" encrypted");
}
if (p->rx_time != 0) {
DEBUG_MSG(" rxtime=%u", p->rx_time);
}
DEBUG_MSG(")\n");
}
RadioInterface::RadioInterface()
{
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected

View File

@@ -162,3 +162,6 @@ class SimRadio : public RadioInterface
/// \return true if initialisation succeeded.
virtual bool init() { return true; }
};
/// Debug printing for packets
void printPacket(const char *prefix, const MeshPacket *p);

View File

@@ -114,8 +114,8 @@ bool RadioLibInterface::canSendImmediately()
/// bluetooth comms code. If the txmit queue is empty it might return an error
ErrorCode RadioLibInterface::send(MeshPacket *p)
{
DEBUG_MSG("enqueuing for send on mesh fr=0x%x,to=0x%x,id=%d (txGood=%d,rxGood=%d,rxBad=%d)\n", p->from, p->to, p->id, txGood,
rxGood, rxBad);
printPacket("enqueuing for send", p);
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
@@ -237,7 +237,7 @@ void RadioLibInterface::completeSending()
{
if (sendingPacket) {
txGood++;
DEBUG_MSG("Completed sending to=0x%x, id=%u\n", sendingPacket->to, sendingPacket->id);
printPacket("Completed sending", sendingPacket);
// We are done sending that packet, release it
packetPool.release(sendingPacket);
@@ -291,7 +291,7 @@ void RadioLibInterface::handleReceiveInterrupt()
memcpy(mp->encrypted.bytes, payload, payloadLen);
mp->encrypted.size = payloadLen;
DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id);
printPacket("Lora RX", mp);
deliverToReceiver(mp);
}
@@ -301,9 +301,11 @@ void RadioLibInterface::handleReceiveInterrupt()
/** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket *txp)
{
DEBUG_MSG("Starting low level send from=0x%x, to=0x%x, id=%u, want_ack=%d\n", txp->from, txp->to, txp->id, txp->want_ack);
printPacket("Starting low level send", txp);
setStandby(); // Cancel any already in process receives
configHardwareForSend(); // must be after setStandby
size_t numbytes = beginSending(txp);
int res = iface->startTransmit(radiobuf, numbytes);

View File

@@ -3,6 +3,10 @@
#include "PeriodicTask.h"
#include "RadioInterface.h"
#ifdef CubeCell_BoardPlus
#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#endif
#include <RadioLib.h>
// ESP32 has special rules about ISR code
@@ -91,9 +95,6 @@ class RadioLibInterface : public RadioInterface, private PeriodicTask
virtual void startReceive() = 0;
private:
/** start an immediate transmit */
void startSend(MeshPacket *txp);
/** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing
* the transmit
*
@@ -108,12 +109,20 @@ class RadioLibInterface : public RadioInterface, private PeriodicTask
virtual void doTask();
/** start an immediate transmit
* This method is virtual so subclasses can hook as needed, subclasses should not call directly
*/
virtual void startSend(MeshPacket *txp);
protected:
/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init();
/** 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...
*

View File

@@ -27,7 +27,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
{
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
DEBUG_MSG("Received someone rebroadcasting for us fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
printPacket("Rx someone rebroadcasting for us", p);
// We are seeing someone rebroadcast one of our broadcast attempts.
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for

View File

@@ -48,7 +48,7 @@ struct PendingPacket {
PendingPacket() {}
PendingPacket(MeshPacket *p);
void setNextTx() { nextTxMsec = millis() + random(20 * 1000, 22 * 1000); }
void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); }
};
class GlobalPacketIdHashFunction

View File

@@ -34,7 +34,14 @@ Allocator<MeshPacket> &packetPool = staticPool;
*
* Currently we only allow one interface, that may change in the future
*/
Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO) {}
Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO)
{
// This is called pre main(), don't touch anything here, the following code is not safe
/* DEBUG_MSG("Size of NodeInfo %d\n", sizeof(NodeInfo));
DEBUG_MSG("Size of SubPacket %d\n", sizeof(SubPacket));
DEBUG_MSG("Size of MeshPacket %d\n", sizeof(MeshPacket)); */
}
/**
* do idle processing
@@ -150,8 +157,8 @@ ErrorCode Router::send(MeshPacket *p)
*/
void Router::sniffReceived(const MeshPacket *p)
{
DEBUG_MSG("FIXME-update-db Sniffing packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
// FIXME, update nodedb
DEBUG_MSG("FIXME-update-db Sniffing packet\n");
// FIXME, update nodedb here for any packet that passes through us
}
bool Router::perhapsDecode(MeshPacket *p)
@@ -202,7 +209,7 @@ void Router::handleReceived(MeshPacket *p)
sniffReceived(p);
if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) {
DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
printPacket("Delivering rx packet", p);
notifyPacketReceived.notifyObservers(p);
}
}

View File

@@ -14,7 +14,19 @@ bool SX1262Interface::init()
{
RadioLibInterface::init();
#ifdef SX1262_RXEN // set not rx or tx mode
pinMode(SX1262_RXEN, OUTPUT);
#endif
#ifdef SX1262_TXEN
pinMode(SX1262_TXEN, OUTPUT);
#endif
#ifndef SX1262_E22
float tcxoVoltage = 0; // None - we use an XTAL
#else
float tcxoVoltage =
1.8; // E22 uses DIO3 to power tcxo per https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575
#endif
bool useRegulatorLDO = false; // Seems to depend on the connection to pin 9/DCC_SW - if an inductor DCDC?
applyModemConfig();
@@ -23,6 +35,12 @@ bool SX1262Interface::init()
int res = lora.begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
DEBUG_MSG("LORA init result %d\n", res);
#ifdef SX1262_TXEN
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
if (res == ERR_NONE)
res = lora.setDio2AsRfSwitch(false);
#endif
if (res == ERR_NONE)
res = lora.setCRC(SX126X_LORA_CRC_ON);
@@ -81,6 +99,13 @@ void SX1262Interface::setStandby()
int err = lora.standby();
assert(err == ERR_NONE);
#ifdef SX1262_RXEN // we have RXEN/TXEN control - turn off RX and TX power
digitalWrite(SX1262_RXEN, LOW);
#endif
#ifdef SX1262_TXEN
digitalWrite(SX1262_TXEN, LOW);
#endif
isReceiving = false; // If we were receiving, not any more
disableInterrupt();
completeSending(); // If we were sending, not anymore
@@ -94,6 +119,18 @@ void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
mp->rx_snr = lora.getSNR();
}
/** start an immediate transmit
* We override to turn on transmitter power as needed.
*/
void SX1262Interface::configHardwareForSend()
{
#ifdef SX1262_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
digitalWrite(SX1262_TXEN, HIGH);
#endif
RadioLibInterface::configHardwareForSend();
}
// For power draw measurements, helpful to force radio to stay sleeping
// #define SLEEP_ONLY
@@ -102,7 +139,13 @@ void SX1262Interface::startReceive()
#ifdef SLEEP_ONLY
sleep();
#else
setStandby();
#ifdef SX1262_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
digitalWrite(SX1262_RXEN, HIGH);
#endif
// int err = lora.startReceive();
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in
// standby mostly.

View File

@@ -43,6 +43,12 @@ class SX1262Interface : public RadioLibInterface
* Start waiting to receive a message
*/
virtual void startReceive();
/**
* We override to turn on transmitter power as needed.
*/
virtual void configHardwareForSend();
/**
* Add SNR data to received messages
*/
@@ -51,5 +57,4 @@ class SX1262Interface : public RadioLibInterface
virtual void setStandby();
private:
};

View File

@@ -5,6 +5,8 @@
#include "freertosinc.h"
#ifdef HAS_FREE_RTOS
/**
* A wrapper for freertos queues. Note: each element object should be small
* and POD (Plain Old Data type) as elements are memcpied by value.
@@ -35,3 +37,45 @@ template <class T> class TypedQueue
bool dequeueFromISR(T *p, BaseType_t *higherPriWoken) { return xQueueReceiveFromISR(h, p, higherPriWoken); }
};
#else
#include <queue>
/**
* A wrapper for freertos queues. Note: each element object should be small
* and POD (Plain Old Data type) as elements are memcpied by value.
*/
template <class T> class TypedQueue
{
std::queue<T> q;
public:
TypedQueue(int maxElements) {}
// int numFree() { return uxQueueSpacesAvailable(h); }
bool isEmpty() { return q.empty(); }
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
{
q.push(x);
return true;
}
// bool enqueueFromISR(T x, BaseType_t *higherPriWoken) { return xQueueSendToBackFromISR(h, &x, higherPriWoken) == pdTRUE; }
bool dequeue(T *p, TickType_t maxWait = portMAX_DELAY)
{
if (isEmpty())
return false;
else {
*p = q.front();
q.pop();
return true;
}
}
// bool dequeueFromISR(T *p, BaseType_t *higherPriWoken) { return xQueueReceiveFromISR(h, p, higherPriWoken); }
};
#endif

View File

@@ -8,7 +8,9 @@
#define member_size(type, member) sizeof(((type *)0)->member)
/// max number of packets which can be waiting for delivery to android - note, this value comes from mesh.options protobuf
#define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
// FIXME - max_count is actually 32 but we save/load this as one long string of preencoded MeshPacket bytes - not a big array in RAM
// #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
#define MAX_RX_TOPHONE 32
/// max number of nodes allowed in the mesh
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))

View File

@@ -39,7 +39,7 @@ PB_BIND(NodeInfo, NodeInfo, AUTO)
PB_BIND(MyNodeInfo, MyNodeInfo, AUTO)
PB_BIND(DeviceState, DeviceState, 4)
PB_BIND(DeviceState, DeviceState, 2)
PB_BIND(DebugString, DebugString, 2)

View File

@@ -101,8 +101,9 @@ typedef struct _RadioConfig_UserPreferences {
uint32_t sds_secs;
uint32_t ls_secs;
uint32_t min_wake_secs;
bool keep_all_packets;
bool promiscuous_mode;
char wifi_ssid[33];
char wifi_password[64];
bool wifi_ap_mode;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
} RadioConfig_UserPreferences;
@@ -183,10 +184,11 @@ typedef struct _DeviceState {
pb_size_t node_db_count;
NodeInfo node_db[32];
pb_size_t receive_queue_count;
MeshPacket receive_queue[32];
MeshPacket receive_queue[1];
bool has_rx_text_message;
MeshPacket rx_text_message;
uint32_t version;
bool no_save;
} DeviceState;
typedef struct _FromRadio {
@@ -241,10 +243,10 @@ typedef struct _ToRadio {
#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}}, ""}
#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, 0, 0, {0, 0, 0}}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 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, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, false, MeshPacket_init_default, 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}
#define DebugString_init_default {""}
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}}
@@ -257,10 +259,10 @@ typedef struct _ToRadio {
#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}}, ""}
#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, 0, 0, {0, 0, 0}}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 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, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}, false, MeshPacket_init_zero, 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}
#define DebugString_init_zero {""}
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
@@ -308,8 +310,9 @@ typedef struct _ToRadio {
#define RadioConfig_UserPreferences_sds_secs_tag 9
#define RadioConfig_UserPreferences_ls_secs_tag 10
#define RadioConfig_UserPreferences_min_wake_secs_tag 11
#define RadioConfig_UserPreferences_keep_all_packets_tag 100
#define RadioConfig_UserPreferences_promiscuous_mode_tag 101
#define RadioConfig_UserPreferences_wifi_ssid_tag 12
#define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_ignore_incoming_tag 102
#define RouteDiscovery_route_tag 2
#define User_id_tag 1
@@ -351,6 +354,7 @@ typedef struct _ToRadio {
#define DeviceState_receive_queue_tag 5
#define DeviceState_version_tag 8
#define DeviceState_rx_text_message_tag 7
#define DeviceState_no_save_tag 9
#define FromRadio_packet_tag 2
#define FromRadio_my_info_tag 3
#define FromRadio_node_info_tag 4
@@ -456,8 +460,9 @@ X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \
X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \
X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \
X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \
X(a, STATIC, SINGULAR, BOOL, keep_all_packets, 100) \
X(a, STATIC, SINGULAR, BOOL, promiscuous_mode, 101) \
X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 102)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
@@ -498,7 +503,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \
X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \
X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8)
X(a, STATIC, SINGULAR, UINT32, version, 8) \
X(a, STATIC, SINGULAR, BOOL, no_save, 9)
#define DeviceState_CALLBACK NULL
#define DeviceState_DEFAULT NULL
#define DeviceState_radio_MSGTYPE RadioConfig
@@ -592,11 +598,11 @@ extern const pb_msgdesc_t ManufacturingData_msg;
#define SubPacket_size 274
#define MeshPacket_size 313
#define ChannelSettings_size 60
#define RadioConfig_size 157
#define RadioConfig_UserPreferences_size 93
#define RadioConfig_size 253
#define RadioConfig_UserPreferences_size 188
#define NodeInfo_size 132
#define MyNodeInfo_size 110
#define DeviceState_size 15100
#define DeviceState_size 5403
#define DebugString_size 258
#define FromRadio_size 322
#define ToRadio_size 316

View File

@@ -1,100 +0,0 @@
#ifdef ARDUINO_NRF52840_PPR
#include "PmuBQ25703A.h"
#include <assert.h>
// Default address for device. Note, it is without read/write bit. When read with analyser,
// this will appear 1 bit shifted to the left
#define BQ25703ADevaddr 0xD6
const byte Lorro_BQ25703A::BQ25703Aaddr = BQ25703ADevaddr;
void PmuBQ25703A::init()
{
// Set the watchdog timer to not have a timeout
regs.chargeOption0.set_WDTMR_ADJ(0);
assert(writeRegEx(regs.chargeOption0)); // FIXME, instead log a critical hw failure and reboot
delay(15); // FIXME, why are these delays required? - check datasheet
// Set the ADC on IBAT and PSYS to record values
// When changing bitfield values, call the writeRegEx function
// This is so you can change all the bits you want before sending out the byte.
regs.chargeOption1.set_EN_IBAT(1);
regs.chargeOption1.set_EN_PSYS(1);
assert(writeRegEx(regs.chargeOption1));
delay(15);
// Set ADC to make continuous readings. (uses more power)
regs.aDCOption.set_ADC_CONV(1);
// Set individual ADC registers to read. All have default off.
regs.aDCOption.set_EN_ADC_VBUS(1);
regs.aDCOption.set_EN_ADC_PSYS(1);
regs.aDCOption.set_EN_ADC_IDCHG(1);
regs.aDCOption.set_EN_ADC_ICHG(1);
regs.aDCOption.set_EN_ADC_VSYS(1);
regs.aDCOption.set_EN_ADC_VBAT(1);
// Once bits have been twiddled, send bytes to device
assert(writeRegEx(regs.aDCOption));
delay(15);
}
#endif
/*
//Initialise the device and library
Lorro_BQ25703A BQ25703A;
//Instantiate with reference to global set
extern Lorro_BQ25703A::Regt BQ25703Areg;
uint32_t previousMillis;
uint16_t loopInterval = 1000;
void setup() {
Serial.begin(115200);
}
void loop() {
uint32_t currentMillis = millis();
if( currentMillis - previousMillis > loopInterval ){
previousMillis = currentMillis;
Serial.print( "Voltage of VBUS: " );
Serial.print( BQ25703Areg.aDCVBUSPSYS.get_VBUS() );
Serial.println( "mV" );
delay( 15 );
Serial.print( "System power usage: " );
Serial.print( BQ25703Areg.aDCVBUSPSYS.get_sysPower() );
Serial.println( "W" );
delay( 15 );
Serial.print( "Voltage of VBAT: " );
Serial.print( BQ25703Areg.aDCVSYSVBAT.get_VBAT() );
Serial.println( "mV" );
delay( 15 );
Serial.print( "Voltage of VSYS: " );
Serial.print( BQ25703Areg.aDCVSYSVBAT.get_VSYS() );
Serial.println( "mV" );
delay( 15 );
Serial.print( "Charging current: " );
Serial.print( BQ25703Areg.aDCIBAT.get_ICHG() );
Serial.println( "mA" );
delay( 15 );
Serial.print( "Voltage of VSYS: " );
Serial.print( BQ25703Areg.aDCIBAT.get_IDCHG() );
Serial.println( "mA" );
delay( 15 );
}
}*/

View File

@@ -1,22 +0,0 @@
#pragma once
#include <Lorro_BQ25703A.h>
class PmuBQ25703A : private Lorro_BQ25703A
{
Lorro_BQ25703A::Regt regs;
public:
/**
* Configure the PMU for our board
*/
void init();
// Methods to have a common API with AXP192
bool isBatteryConnect() { return true; } // FIXME
bool isVBUSPlug() { return true; }
bool isChargeing() { return true; } // FIXME, intentional misspelling
/// battery voltage in mV
int getBattVoltage() { return 3200; }
};

View File

@@ -1,3 +0,0 @@
#pragma once
// FIXME - make a FS abstraction for NRF52

View File

@@ -36,11 +36,13 @@ class UC1701Spi : public OLEDDisplay
};
#include "variant.h"
#ifdef ERC12864_CS
#include <UC1701.h>
static UC1701 lcd(PIN_SPI_SCK, PIN_SPI_MOSI, ERC12864_CS, ERC12864_CD);
void testLCD() {
void testLCD()
{
// PCD8544-compatible displays may have a different resolution...
lcd.begin();
@@ -48,3 +50,4 @@ void testLCD() {
lcd.setCursor(0, 0);
lcd.print("Hello, World!");
}
#endif

View File

@@ -59,12 +59,6 @@ void setBluetoothEnable(bool on)
}
}
#ifdef ARDUINO_NRF52840_PPR
#include "PmuBQ25703A.h"
PmuBQ25703A pmu;
#endif
void nrf52Setup()
{

View File

@@ -1,20 +1,40 @@
#pragma once
#include "PeriodicTask.h"
#include "PowerStatus.h"
namespace meshtastic
/**
* Per @spattinson
* MIN_BAT_MILLIVOLTS seems high. Typical 18650 are different chemistry to LiPo, even for LiPos that chart seems a bit off, other
* charts put 3690mV at about 30% for a lipo, for 18650 i think 10% remaining iis in the region of 3.2-3.3V. Reference 1st graph
* in [this test report](https://lygte-info.dk/review/batteries2012/Samsung%20INR18650-30Q%203000mAh%20%28Pink%29%20UK.html)
* looking at the red line - discharge at 0.2A - he gets a capacity of 2900mah, 90% of 2900 = 2610, that point in the graph looks
* to be a shade above 3.2V
*/
#define MIN_BAT_MILLIVOLTS 3250 // millivolts. 10% per https://blog.ampow.com/lipo-voltage-chart/
#define BAT_MILLIVOLTS_FULL 4100
#define BAT_MILLIVOLTS_EMPTY 3500
class Power : public PeriodicTask
{
/// Describes the state of the power system.
struct PowerStatus {
/// Whether we have a battery connected
bool haveBattery;
/// Battery voltage in mV, valid if haveBattery is true
int batteryVoltageMv;
/// Whether USB is connected
bool usb;
/// Whether we are charging the battery
bool charging;
public:
Observable<const meshtastic::PowerStatus *> newStatus;
void readPowerStatus();
void loop();
virtual bool setup();
virtual void doTask();
void setStatusHandler(meshtastic::PowerStatus *handler)
{
statusHandler = handler;
}
protected:
meshtastic::PowerStatus *statusHandler;
virtual void axp192Init();
};
} // namespace meshtastic
extern meshtastic::PowerStatus powerStatus;
extern Power *power;

View File

@@ -31,13 +31,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h"
#include "mesh-pb-constants.h"
#include "screen.h"
#include "utils.h"
#define FONT_HEIGHT 14 // actually 13 for "ariel 10" but want a little extra space
#define FONT_HEIGHT_16 (ArialMT_Plain_16[1] + 1)
#ifdef USE_SH1106
#define SCREEN_WIDTH 132
#else
#define SCREEN_WIDTH 128
#endif
#define SCREEN_HEIGHT 64
#define TRANSITION_FRAMERATE 30 // fps
#define IDLE_FRAMERATE 10 // in fps
#define IDLE_FRAMERATE 1 // in fps
#define COMPASS_DIAM 44
#define NUM_EXTRA_FRAMES 2 // text message and debug frame
@@ -50,6 +55,14 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
static uint32_t targetFramerate = IDLE_FRAMERATE;
static char btPIN[16] = "888888";
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
// if defined a pixel will blink to show redraws
// #define SHOW_REDRAWS
#ifdef SHOW_REDRAWS
static bool heartbeat = false;
#endif
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
@@ -60,20 +73,34 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
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;
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);
}
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_16);
display->drawString(64 + x, 2 + y, "Bluetooth");
display->drawString(64 + x, y, "Bluetooth");
display->setFont(ArialMT_Plain_10);
display->drawString(64 + x, SCREEN_HEIGHT - FONT_HEIGHT + y, "Enter this code");
display->drawString(64 + x, FONT_HEIGHT + y + 2, "Enter this code");
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_24);
display->drawString(64 + x, 22 + y, btPIN);
display->drawString(64 + x, 26 + y, btPIN);
display->setFont(ArialMT_Plain_10);
char buf[30];
const char *name = "Name: ";
strcpy(buf, name);
strcat(buf, getDeviceName());
display->drawString(64 + x, 48 + y, buf);
}
/// Draw the last text message we received
@@ -122,10 +149,11 @@ static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char *
}
}
/// Draw a series of fields in a row, wrapping to multiple rows if needed
/// @return the max y we ended up printing to
static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
{
#if 0
/// Draw a series of fields in a row, wrapping to multiple rows if needed
/// @return the max y we ended up printing to
static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
{
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
@@ -150,6 +178,76 @@ static uint32_t drawRows(OLEDDisplay *display, int16_t x, int16_t y, const char
}
return yo;
}
#endif
// Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage.
static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus)
{
static const uint8_t powerBar[3] = {0x81, 0xBD, 0xBD};
static const uint8_t lightning[8] = {0xA1, 0xA1, 0xA5, 0xAD, 0xB5, 0xA5, 0x85, 0x85};
// Clear the bar area on the battery image
for (int i = 1; i < 14; i++) {
imgBuffer[i] = 0x81;
}
// If charging, draw a charging indicator
if (powerStatus->getIsCharging()) {
memcpy(imgBuffer + 3, lightning, 8);
// If not charging, Draw power bars
} else {
for (int i = 0; i < 4; i++) {
if (powerStatus->getBatteryChargePercent() >= 25 * i)
memcpy(imgBuffer + 1 + (i * 3), powerBar, 3);
}
}
display->drawFastImage(x, y, 16, 8, imgBuffer);
}
// Draw nodes status
static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *nodeStatus)
{
char usersString[20];
sprintf(usersString, "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
display->drawFastImage(x, y, 8, 8, imgUser);
display->drawString(x + 10, y - 2, usersString);
}
// Draw GPS status summary
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
if (!gps->getIsConnected()) {
display->drawString(x, y - 2, "No GPS");
return;
}
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
if (!gps->getHasLock()) {
display->drawString(x + 8, y - 2, "No sats");
return;
}
if (gps->getDOP() <= 100) {
display->drawString(x + 8, y - 2, "Ideal");
return;
}
if (gps->getDOP() <= 200) {
display->drawString(x + 8, y - 2, "Exc.");
return;
}
if (gps->getDOP() <= 500) {
display->drawString(x + 8, y - 2, "Good");
return;
}
if (gps->getDOP() <= 1000) {
display->drawString(x + 8, y - 2, "Mod.");
return;
}
if (gps->getDOP() <= 2000) {
display->drawString(x + 8, y - 2, "Fair");
return;
}
if (gps->getDOP() > 0) {
display->drawString(x + 8, y - 2, "Poor");
return;
}
}
/// Ported from my old java code, returns distance in meters along the globe
@@ -291,6 +389,30 @@ static bool hasPosition(NodeInfo *n)
static size_t nodeIndex;
static int8_t prevFrame = -1;
// Draw the compass and arrow pointing to location
static void drawCompass(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian)
{
// display->drawXbm(compassX, compassY, compass_width, compass_height,
// (const uint8_t *)compass_bits);
Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
Point *points[] = {&tip, &tail, &leftArrow, &rightArrow};
for (int i = 0; i < 4; i++) {
points[i]->rotate(headingRadian);
points[i]->scale(COMPASS_DIAM * 0.6);
points[i]->translate(compassX, compassY);
}
drawLine(display, tip, tail);
drawLine(display, leftArrow, tip);
drawLine(display, rightArrow, tip);
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
}
/// Convert an integer GPS coords to a floating point
#define DegD(i) (i * 1e-7)
@@ -324,7 +446,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *username = node->has_user ? node->user.long_name : "Unknown Name";
static char signalStr[20];
snprintf(signalStr, sizeof(signalStr), "Signal: %.0f", node->snr);
snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100));
uint32_t agoSecs = sinceLastSeen(node);
static char lastStr[20];
@@ -335,15 +457,16 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
else
snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60);
static float simRadian;
simRadian += 0.1; // For testing, have the compass spin unless both
// locations are valid
static char distStr[20];
*distStr = 0; // might not have location data
float headingRadian = simRadian;
strcpy(distStr, "? km"); // might not have location data
float headingRadian;
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
if (ourNode && hasPosition(ourNode) && hasPosition(node)) {
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
// coordinates for the center of the compass/circle
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 1, compassY = y + SCREEN_HEIGHT / 2;
if (ourNode && hasPosition(ourNode) && hasPosition(node)) { // display direction toward node
Position &op = ourNode->position, &p = node->position;
float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
if (d < 2000)
@@ -356,35 +479,17 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
float bearingToOther = bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
float myHeading = estimatedHeading(DegD(p.latitude_i), DegD(p.longitude_i));
headingRadian = bearingToOther - myHeading;
} else {
drawCompass(display, compassX, compassY, headingRadian);
} else { // 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));
}
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
drawColumns(display, x, y, fields);
// coordinates for the center of the compass
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 1, compassY = y + SCREEN_HEIGHT / 2;
// display->drawXbm(compassX, compassY, compass_width, compass_height,
// (const uint8_t *)compass_bits);
Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
Point *points[] = {&tip, &tail, &leftArrow, &rightArrow};
for (int i = 0; i < 4; i++) {
points[i]->rotate(headingRadian);
points[i]->scale(COMPASS_DIAM * 0.6);
points[i]->translate(compassX, compassY);
}
drawLine(display, tip, tail);
drawLine(display, leftArrow, tip);
drawLine(display, rightArrow, tip);
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?");
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
}
// Must be after distStr is populated
drawColumns(display, x, y, fields);
}
#if 0
@@ -452,6 +557,9 @@ void Screen::setup()
// Store a pointer to Screen so we can get to it from static functions.
ui.getUiState()->userData = this;
// Set the utf8 conversion function
dispdev.setFontTableLookupFunction(customFontTableLookup);
// Add frames.
static FrameCallback bootFrames[] = {drawBootScreen};
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
@@ -476,6 +584,11 @@ void Screen::setup()
// twice initially.
ui.update();
ui.update();
// Subscribe to status updates
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
}
void Screen::doTask()
@@ -537,14 +650,7 @@ void Screen::doTask()
// While showing the bootscreen or Bluetooth pair screen all of our
// standard screen switching is stopped.
if (showingNormalScreen) {
// TODO(girts): decouple nodeDB from screen.
// standard screen loop handling ehre
// If the # nodes changes, we need to regen our list of screens
if (nodeDB.updateGUI || nodeDB.updateTextMessage) {
setFrames();
nodeDB.updateGUI = false;
nodeDB.updateTextMessage = false;
}
// standard screen loop handling here
}
ui.update();
@@ -569,8 +675,8 @@ void Screen::setFrames()
DEBUG_MSG("showing standard frames\n");
showingNormalScreen = true;
size_t numnodes = nodeDB.getNumNodes();
// We don't show the node info our our node (if we have it yet - we should)
size_t numnodes = nodeStatus->getNumTotal();
if (numnodes > 0)
numnodes--;
@@ -644,35 +750,58 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT);
char usersStr[20];
char channelStr[20];
char batStr[20];
char gpsStr[20];
{
LockGuard guard(&lock);
snprintf(usersStr, sizeof(usersStr), "Users %d/%d", nodesOnline, nodesTotal);
snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str());
if (powerStatus.haveBattery) {
// TODO: draw a battery icon instead of letter "B".
int batV = powerStatus.batteryVoltageMv / 1000;
int batCv = (powerStatus.batteryVoltageMv % 1000) / 10;
snprintf(batStr, sizeof(batStr), "B %01d.%02dV%c%c", batV, batCv, powerStatus.charging ? '+' : ' ',
powerStatus.usb ? 'U' : ' ');
} else {
snprintf(batStr, sizeof(batStr), "%s", powerStatus.usb ? "USB" : "");
snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str());
// Display power status
if (powerStatus->getHasBattery())
drawBattery(display, x, y + 2, imgBattery, powerStatus);
else
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
// Display nodes status
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
// Display GPS status
drawGPS(display, x + (SCREEN_WIDTH * 0.66), y + 2, gpsStatus);
}
if (!gpsStatus.empty()) {
snprintf(gpsStr, sizeof(gpsStr), "GPS %s", gpsStatus.c_str());
} else {
gpsStr[0] = '\0'; // Just show empty string.
}
}
display->drawString(x, y + FONT_HEIGHT, channelStr);
const char *fields[] = {batStr, gpsStr, usersStr, channelStr, nullptr};
uint32_t yo = drawRows(display, x, y, fields);
display->drawLogBuffer(x, y + (FONT_HEIGHT * 2));
display->drawLogBuffer(x, yo);
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS
if (heartbeat)
display->setPixel(0, 0);
heartbeat = !heartbeat;
#endif
}
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
void Screen::adjustBrightness()
{
if (brightness == 254) {
brightness = 0;
} else {
brightness++;
}
int width = brightness / (254.00 / SCREEN_WIDTH);
dispdev.drawRect(0, 30, SCREEN_WIDTH, 4);
dispdev.fillRect(0, 31, width, 2);
dispdev.display();
dispdev.setBrightness(brightness);
}
int Screen::handleStatusUpdate(const Status *arg)
{
DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
setFrames();
break;
}
setPeriod(1); // Update the screen right away
return 0;
}
} // namespace meshtastic

View File

@@ -3,12 +3,20 @@
#include <cstring>
#include <OLEDDisplayUi.h>
#ifdef USE_SH1106
#include <SH1106Wire.h>
#else
#include <SSD1306Wire.h>
#endif
#include "PeriodicTask.h"
#include "TypedQueue.h"
#include "lock.h"
#include "power.h"
#include "PowerStatus.h"
#include "GPSStatus.h"
#include "NodeStatus.h"
#include "Observer.h"
#include <string>
namespace meshtastic
@@ -24,14 +32,6 @@ class DebugInfo
DebugInfo(const DebugInfo &) = delete;
DebugInfo &operator=(const DebugInfo &) = delete;
/// Sets user statistics.
void setNodeNumbersStatus(int online, int total)
{
LockGuard guard(&lock);
nodesOnline = online;
nodesTotal = total;
}
/// Sets the name of the channel.
void setChannelNameStatus(const char *name)
{
@@ -39,25 +39,6 @@ class DebugInfo
channelName = name;
}
/// Sets battery/charging/etc status.
//
void setPowerStatus(const PowerStatus &status)
{
LockGuard guard(&lock);
powerStatus = status;
}
/// Sets GPS status.
//
// If this function never gets called, we assume GPS does not exist on this
// device.
// TODO(girts): figure out what the format should be.
void setGPSStatus(const char *status)
{
LockGuard guard(&lock);
gpsStatus = status;
}
private:
friend Screen;
@@ -66,15 +47,8 @@ class DebugInfo
/// Renders the debug screen.
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
int nodesOnline = 0;
int nodesTotal = 0;
PowerStatus powerStatus;
std::string channelName;
std::string gpsStatus;
/// Protects all of internal state.
Lock lock;
};
@@ -88,6 +62,10 @@ class DebugInfo
// simultaneously).
class Screen : public PeriodicTask
{
CallbackObserver<Screen, const Status *> powerStatusObserver = CallbackObserver<Screen, const Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const Status *> gpsStatusObserver = CallbackObserver<Screen, const Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const Status *> nodeStatusObserver = CallbackObserver<Screen, const Status *>(this, &Screen::handleStatusUpdate);
public:
Screen(uint8_t address, int sda = -1, int scl = -1);
@@ -112,6 +90,10 @@ class Screen : public PeriodicTask
/// Handles a button press.
void onPress() { enqueueCmd(CmdItem{.cmd = Cmd::ON_PRESS}); }
// Implementation to Adjust Brightness
void adjustBrightness();
int brightness = 150;
/// Starts showing the Bluetooth PIN screen.
//
// Switches over to a static frame showing the Bluetooth pairing screen
@@ -144,11 +126,44 @@ class Screen : public PeriodicTask
}
}
/// Overrides the default utf8 character conversion, to replace empty space with question marks
static char customFontTableLookup(const uint8_t ch) {
// UTF-8 to font table index converter
// Code form http://playground.arduino.cc/Main/Utf8ascii
static uint8_t LASTCHAR;
static bool SKIPREST; // Only display a single unconvertable-character symbol per sequence of unconvertable characters
if (ch < 128) { // Standard ASCII-set 0..0x7F handling
LASTCHAR = 0;
SKIPREST = false;
return ch;
}
uint8_t last = LASTCHAR; // get last char
LASTCHAR = ch;
switch (last) { // conversion depnding on first UTF8-character
case 0xC2: { SKIPREST = false; return (uint8_t) ch; }
case 0xC3: { SKIPREST = false; return (uint8_t) (ch | 0xC0); }
}
// We want to strip out prefix chars for two-byte char formats
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82) return (uint8_t) 0;
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the rest of it
if (SKIPREST) return (uint8_t) 0;
SKIPREST = true;
return (uint8_t) 191; // otherwise: return ¿ if character can't be converted (note that the font map we're using doesn't stick to standard EASCII codes)
}
/// Returns a handle to the DebugInfo screen.
//
// Use this handle to set things like battery status, user count, GPS status, etc.
DebugInfo *debug() { return &debugInfo; }
int handleStatusUpdate(const meshtastic::Status *arg);
protected:
/// Updates the UI.
//
@@ -211,7 +226,11 @@ class Screen : public PeriodicTask
/// Holds state for debug information
DebugInfo debugInfo;
/// Display device
#ifdef USE_SH1106
SH1106Wire dispdev;
#else
SSD1306Wire dispdev;
#endif
/// UI helper for rendering to frames and switching between them
OLEDDisplayUi ui;
};

View File

@@ -129,7 +129,7 @@ static void waitEnterSleep()
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
recordCriticalError(ErrSleepEnterWait);
ESP.restart(); // FIXME - for now we just restart, need to fix bug #167
assert(0); // FIXME - for now we just restart, need to fix bug #167
break;
}
}
@@ -289,9 +289,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
return cause;
}
#endif
#if 0
// not legal on the stock android ESP build
/**
@@ -306,7 +304,7 @@ void enableModemSleep()
static esp_pm_config_esp32_t config; // filled with zeros because bss
config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
config.min_freq_mhz = 10; // 10Mhz is minimum recommended
config.min_freq_mhz = 20; // 10Mhz is minimum recommended
config.light_sleep_enable = false;
DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config));
}

View File

@@ -35,3 +35,5 @@ extern Observable<void *> notifySleep;
/// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0
extern Observable<void *> notifyDeepSleep;
void enableModemSleep();

7
src/utils.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
/// C++ v17+ clamp function, limits a given value to a range defined by lo and hi
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi ) {
return (v < lo) ? lo : (hi < v) ? hi : v;
}

View File

@@ -137,6 +137,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
// #define SX1262_ANT_SW (32 + 10)
#define SX1262_RXEN (22)
#define SX1262_TXEN (24)
#define SX1262_E22 // Indicates this SX1262 is inside of an ebyte E22 module and special config should be done for that
// ERC12864-10 LCD
#define ERC12864_CS (32 + 4)