Compare commits

..

122 Commits

Author SHA1 Message Date
Kevin Hester
661a75d796 Merge pull request #298 from geeksville/master
oops - I missed some 0.9.1 files in the last merge into master
2020-07-24 13:35:25 -07:00
geeksville
b617010a46 Merge branch 'post1'
# Conflicts:
#	docs/software/TODO.md
#	docs/software/nrf52-TODO.md
2020-07-24 13:07:33 -07:00
Kevin Hester
5a70c45a3e Merge pull request #297 from geeksville/master
Pull in NimBLE changes into master
2020-07-24 12:59:06 -07:00
geeksville
cb2b36811a Merge remote-tracking branch 'root/master' 2020-07-24 12:50:39 -07:00
geeksville
92edcb97ed Merge remote-tracking branch 'origin/post1'
# Conflicts:
#	docs/software/TODO.md
#	docs/software/nrf52-TODO.md
2020-07-24 12:49:24 -07:00
Kevin Hester
7f1ec15cab Merge pull request #296 from geeksville/nimble
Change BLE implementation to NimBLE rather than Bluedroid
2020-07-24 12:46:37 -07:00
geeksville
1aa7451866 0.9.1 2020-07-24 12:41:14 -07:00
geeksville
d5c46dc114 use max mtusize for speed 2020-07-24 12:39:48 -07:00
geeksville
5bab16636d Switch to NimBLE from Bluedroid
Meshtastic patched version esp-idf commit #e7f316d5a4eb64ca52d40575cb20815d456a9c4f
    used.

    In support of: https://github.com/meshtastic/Meshtastic-device/issues/266
2020-07-24 12:39:35 -07:00
geeksville
204f2c1a68 software update service now registered with NimBLE 2020-07-24 11:39:48 -07:00
geeksville
a5b7501a4e nimble add debug output 2020-07-24 10:12:25 -07:00
geeksville
b0e2c81666 nimble software update WIP builds 2020-07-23 15:57:31 -07:00
geeksville
00ca351169 WIP begin changing software update service over to nimble 2020-07-23 13:01:31 -07:00
geeksville
0415a3c369 Clean up nimble files 2020-07-23 08:10:36 -07:00
geeksville
4eb27b637d Nimble sleep now works nicely 2020-07-22 22:18:47 -07:00
geeksville
107b56a346 move bluetooth enable 2020-07-22 21:41:56 -07:00
geeksville
abdc4dfae8 remove old mesh ble service 2020-07-22 21:29:32 -07:00
geeksville
014eea2f56 Nimble sleep almost works 2020-07-22 21:26:32 -07:00
geeksville
9b4ca95660 nimble basically works now. Started long bake for bug #266 2020-07-22 18:00:56 -07:00
geeksville
78ff9a8116 Nimble WIP - make notify work 2020-07-22 16:40:00 -07:00
geeksville
66b147fb31 Nimble WIP fix bluetooth pairing screen 2020-07-22 16:16:28 -07:00
geeksville
c5df1bc885 Nimble WIP - woot! basic device API works now 2020-07-22 15:44:45 -07:00
geeksville
00cf3a768e nimble WIP turn on bonding and security 2020-07-22 13:50:30 -07:00
geeksville
b6a3deb341 nimble WIP - writes kinda work now 2020-07-22 12:08:54 -07:00
geeksville
531f488fe8 WIP nimble ugly but advertise works 2020-07-22 10:46:01 -07:00
geeksville
d674aaaa29 sometimes save config fails on ublox, don't cause a reboot for that 2020-07-22 10:45:38 -07:00
geeksville
7f6dc104f0 nimble WIP - add advertising boilerplate 2020-07-22 09:51:57 -07:00
geeksville
102085808f WIP nimble now builds 2020-07-21 12:42:24 -07:00
geeksville
2645730329 Merge branch 'post1' into nimble
# Conflicts:
#	docs/software/TODO.md
#	docs/software/nrf52-TODO.md
#	platformio.ini
#	src/esp32/MeshBluetoothService.cpp
2020-07-21 11:20:09 -07:00
geeksville
6aa28f55dd WIP stubify to get app building without CONFIG_BLUEDROID (BLE disabled) 2020-07-21 11:16:14 -07:00
geeksville
1e86365167 MITM_BOND supposedly doesn't have the problem mentioned in #266
(and it is good / more secure anyways - the old code was just
based on the example docs)
2020-07-19 15:01:15 -07:00
geeksville
62c20f8ab9 add todo items 2020-07-19 14:59:53 -07:00
Kevin Hester
7706f65921 Merge pull request #294 from geeksville/master
fix build for non tbeams
2020-07-18 17:12:02 -07:00
geeksville
68490336b8 0.8.2 2020-07-18 16:28:14 -07:00
geeksville
20ac8d71fd make PSRAM optional - new flag in ESPIDF - fix #293 2020-07-18 16:26:43 -07:00
geeksville
ec082b7c9a 0.8.2 2020-07-18 16:26:03 -07:00
geeksville
ece75d1d7f make PSRAM optional - new flag in ESPIDF - fix #293 2020-07-18 16:25:53 -07:00
geeksville
9e10ce487c Merge branch 'master' into post1 2020-07-18 13:32:30 -07:00
Kevin Hester
d248c6be4b Merge pull request #290 from geeksville/master
get ready for release 0.8.1
2020-07-18 13:24:11 -07:00
geeksville
39b0a89821 0.8.1 2020-07-18 13:19:35 -07:00
geeksville
d9f43d3e2f update protobufs related to https://github.com/meshtastic/Meshtastic-device/issues/269 2020-07-18 09:12:51 -07:00
Kevin Hester
94f03bee01 Merge pull request #289 from geeksville/post1
geeksvilles periodic merging from master
2020-07-18 08:58:13 -07:00
geeksville
08c77caaa9 fix #266 ble forced to re-pair details below
The NVS copies of hte BLE pairing info for clients were getting corrupted
occasionally.  So I went googling and found some plausible bug reports
but nothing that was an exact match.  Then I looked at the arduino-esp32
binaries for the ESP-IDF framework.  They were fairly old (Jan 20).

Looking through the commits on ESP-IDF release3.3 it seems like there have
been a few fixes for mutual exclusion errors wrt bluetooth.  So I punted
and tried updating ESP-IDF to latest and everything seems fairly solid
now.  Currently running a long test run with three nodes.
2020-07-18 08:54:52 -07:00
geeksville
cfedc97cd0 Show NVS flash utilization at boot (for debugging ble things?) 2020-07-18 08:49:42 -07:00
geeksville
cfad226b2b use new ttgo-lora build names 2020-07-17 14:11:27 -07:00
geeksville
859642d2e4 Merge remote-tracking branch 'root/master' into post1
# Conflicts:
#	src/configuration.h
2020-07-17 12:06:57 -07:00
Kevin Hester
8316419a01 Merge pull request #288 from geeksville/post1
Improvements for NRF52 targets
2020-07-17 11:22:20 -07:00
Kevin Hester
96f5069742 Merge branch 'post1' into post1 2020-07-17 11:17:12 -07:00
geeksville
e433249bb1 Default back to tbeam in builds, so it will work for others 2020-07-17 11:14:18 -07:00
geeksville
2a6df797ca NRF52 BLE API now works! 2020-07-17 11:12:05 -07:00
geeksville
28aa48c8d2 NRF52 reads now work, but not long reads 2020-07-17 10:40:03 -07:00
geeksville
582f77e4ec NRF52 BLE now works, except for reads having the wrong payload 2020-07-17 10:02:07 -07:00
geeksville
5700cf96d5 redefine printf to use the segger output system (NRF52) 2020-07-17 09:14:23 -07:00
geeksville
769a98f1f4 nrf52 ble - move service in into the scan info 2020-07-17 09:13:47 -07:00
Kevin Hester
4ee35a0612 Merge pull request #280 from aHVzY2g/master
fix #272 add support for tlora-v2-1-1.6
2020-07-16 11:12:40 -07:00
Kevin Hester
64f6741f82 Merge pull request #282 from slavino/patch-7
Create SupportedHardware.md
2020-07-16 11:11:44 -07:00
Kevin Hester
6ad5abcab2 Merge branch 'post1' into patch-7 2020-07-15 21:28:13 -07:00
Kevin Hester
5480f10184 Merge pull request #283 from slavino/patch-8
Update README.md
2020-07-15 21:27:44 -07:00
Kevin Hester
41dfbdd331 Merge branch 'post1' into patch-8 2020-07-15 21:22:21 -07:00
Kevin Hester
903268c52a Merge pull request #281 from slavino/patch-6
Update README.md
2020-07-15 21:21:50 -07:00
Kevin Hester
b60c630922 Merge branch 'post1' into patch-6 2020-07-15 21:16:22 -07:00
Kevin Hester
95588b420c Merge branch 'post1' into patch-8 2020-07-15 21:15:52 -07:00
Kevin Hester
b141ec2e35 Merge pull request #285 from Professr/issue#284
UBlox GPS now detects loss of lock
2020-07-15 21:15:19 -07:00
geeksville
3d0c611896 android app can now talk to NRF52, but writes are lost WIP 2020-07-15 17:09:09 -07:00
geeksville
6cb92143ec OOM allocing the BLE stack for adafruit 2020-07-15 13:45:57 -07:00
geeksville
f919eb6a64 Install a hardfault handler on NRF52 2020-07-15 13:29:09 -07:00
geeksville
4147786b12 WIP of adding NRF52 bluetooth API, we take a hardfault in Bluefruit init 2020-07-15 13:10:56 -07:00
geeksville
3400bcde85 Merge branch 'master' into post1
# Conflicts:
#	docs/README.md
2020-07-15 11:51:05 -07:00
Professr
e5fac4b78d UBlox GPS now detects loss of lock 2020-07-14 22:53:36 -07:00
Slavomir Hustaty
4d20865c67 Update README.md
the board referenced in that "buy" link has also label reference on board stating that it is V1.1
2020-07-14 18:28:14 +02:00
Slavomir Hustaty
8b4cf91f1f Create SupportedHardware.md
idea on supported hardware matrix - maybe to be referenced from main README.md
2020-07-14 18:20:13 +02:00
Slavomir Hustaty
6a6a10fb9b Update README.md 2020-07-14 17:26:17 +02:00
Marlon Spangenberg
44749470a4 fix #272 add support for tlora-v2-1-1.6 2020-07-14 16:16:49 +02:00
Kevin Hester
8fe714d8b1 Merge pull request #278 from geeksville/master
Fix URL
2020-07-13 17:58:42 -07:00
Kevin Hester
22137ff1bd Merge branch 'master' into master 2020-07-13 17:56:08 -07:00
geeksville
da3b6d1958 Fix URL 2020-07-13 17:55:30 -07:00
geeksville
c7213fb710 Fix URL 2020-07-13 17:54:12 -07:00
Kevin Hester
637960edde Merge pull request #277 from geeksville/master
fix doc typo
2020-07-13 17:51:46 -07:00
geeksville
be7e4fea6a Merge branch 'master' into post1 2020-07-13 17:49:54 -07:00
geeksville
d9209ffaea fix doc typo 2020-07-13 17:47:22 -07:00
Kevin Hester
9fb94796c8 Merge pull request #276 from rezl/master
Added Beginner's Guide to README.md
2020-07-13 17:46:02 -07:00
Rezl
f060f7faad Merge pull request #1 from rezl/rezl-beginners-guide
Added Beginner's Guide
2020-07-13 19:35:09 -05:00
Rezl
55673fcd66 Added Beginner's Guide 2020-07-13 19:34:14 -05:00
geeksville
2ff94cb11d Update device protocol docs 2020-07-13 14:41:04 -07:00
geeksville
e46bebc06f rename docs 2020-07-13 14:21:28 -07:00
geeksville
80e8b4adcc turn off gps debug output for now RAK815 2020-07-13 14:20:49 -07:00
Kevin Hester
e9be03b76c Merge pull request #275 from geeksville/post1
NRF52 / RAK815 work items
2020-07-13 14:14:40 -07:00
geeksville
98dfecdb79 Add external RF switch management for RF95 (needed for RAK815) 2020-07-13 13:18:32 -07:00
geeksville
8ba8278fb5 Merge remote-tracking branch 'root/master' into post1 2020-07-13 12:02:14 -07:00
geeksville
f2f17c81d4 Merge branch 'dev' into post1 2020-07-11 17:17:27 -07:00
geeksville
a687aa8e75 update nrf52 todo 2020-07-11 17:08:03 -07:00
geeksville
ed6b89b3b1 RAK-815 GPS now kinda works (must update associated libs). comms to it
still a bit yucky
2020-07-10 20:34:03 -07:00
geeksville
9d3ca0d0f9 fix esp32 build 2020-07-10 18:46:33 -07:00
geeksville
05a0405709 GPS not yet ready RAK815 WIP 2020-07-10 14:57:33 -07:00
geeksville
efd8b70089 RAK815 GPS WIP 2020-07-10 14:54:32 -07:00
geeksville
e12c057c31 RAK815 lora works 2020-07-10 14:37:01 -07:00
geeksville
0b5b18653a Panic if new ever returns NULL 2020-07-10 13:52:54 -07:00
geeksville
dc54e7331f memory is tight on the nrf52832 board (for now) - so don't allocate too much 2020-07-10 13:52:26 -07:00
geeksville
6fbf6b2986 RAK815 WIP - use 115200 for serial to USB on this board, best it can do 2020-07-10 13:24:00 -07:00
geeksville
feb9992d7d on rak815 use serial port for console 2020-07-10 13:11:29 -07:00
geeksville
fb4ac82d45 fix rf95 renaming 2020-07-10 12:47:10 -07:00
geeksville
acbe8c159b move rak815 variant to arduino repo 2020-07-10 12:38:11 -07:00
geeksville
63474dd952 Only try for NEMA if we have serial 2020-07-10 12:16:10 -07:00
geeksville
cc35ed7782 update build instructions for RAK815 2020-07-10 12:12:03 -07:00
geeksville
d9fd227862 have CI build RAK815 2020-07-10 11:44:46 -07:00
geeksville
1415f2bed7 WIP add support for i2C GPS 2020-07-10 11:43:14 -07:00
geeksville
5b07d454b1 WIP RAK815 now builds correctly 2020-07-10 11:29:32 -07:00
geeksville
0c04ba4776 use my fixed nrf52832 support in arduino 2020-07-10 11:28:18 -07:00
geeksville
b00a936f41 WIP RAK815 support 2020-07-10 11:02:29 -07:00
geeksville
5b11c1ca86 Merge branch 'dev' into post1 2020-07-10 10:03:18 -07:00
geeksville
9ba9e82706 try to fix adafruit-nrfutil bin being in path? 2020-07-09 21:49:07 -07:00
geeksville
ea6c33f3d2 add adafruit-nrfutil to CI build 2020-07-09 21:37:45 -07:00
geeksville
82e5e1858a build for 2 ESP32 targets and 2 NRF52 targets in the CI build 2020-07-09 21:30:52 -07:00
geeksville
80b14c0a6f add support for adafruit feather nrf52832 - which is close to a RAK815 2020-07-09 21:27:34 -07:00
geeksville
6954d0d5f4 Checkout submodules for CI build 2020-07-09 20:31:16 -07:00
geeksville
7e53731fe6 Use our custom variants files and fixes 2020-07-09 20:22:40 -07:00
geeksville
c7290e6ccc don't turn wifi on yet, because my fixes for arduino-esp32 haven't been pushed 2020-07-09 20:11:33 -07:00
geeksville
284317cb25 add nrf52 to CI builds 2020-07-09 20:08:36 -07:00
geeksville
311d1a56b4 make a bare nrf52840dk build which will work for everyone 2020-07-09 20:05:39 -07:00
geeksville
ed589727d6 Update NRF52 build to work again 2020-07-09 19:57:55 -07:00
geeksville
62c9bad183 WIP TCP API server over wifi 2020-07-07 18:37:42 -07:00
geeksville
616da8228e enable wifi for ESP32 2020-07-07 17:41:35 -07:00
69 changed files with 18165 additions and 1093 deletions

View File

@@ -9,6 +9,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Checkout submodules
uses: textbook/git-checkout-submodule-action@master
- name: Setup Python
uses: actions/setup-python@master
with:
@@ -17,5 +19,8 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -U platformio
- name: Install extra python tools
run: |
pip install -U adafruit-nrfutil
- name: Build
run: platformio run
run: platformio run -e tbeam -e heltec -e nrf52840dk -e rak815

View File

@@ -47,7 +47,8 @@
"memory_resource": "cpp",
"optional": "cpp",
"string_view": "cpp",
"cassert": "cpp"
"cassert": "cpp",
"iterator": "cpp"
},
"cSpell.words": [
"Blox",

View File

@@ -24,14 +24,16 @@ We currently support three models of radios.
- TTGO T-Beam (usually the recommended choice)
- [T-Beam V1.1 w/ NEO-6M - special Meshtastic version](https://www.aliexpress.com/item/4001178678568.html) (Includes built-in OLED display and they have **preinstalled** the meshtastic software)
- [T-Beam V1.0 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
- [T-Beam V1.1 w/ NEO-M8N](https://www.aliexpress.com/item/33047631119.html) (slightly better GPS)
- [T-Beam V0.7 w/ NEO-6M](https://www.aliexpress.com/item/4000574335430.html) (will work but **you must use the tbeam0.7 firmware ** - but the T-Beam V1.0 or later are better!)
- board labels "TTGO T22_V07 20180711"
- 3D printable cases
- [T-Beam V0](https://www.thingiverse.com/thing:3773717)
- [T-Beam V1](https://www.thingiverse.com/thing:3830711)
- [TTGO LORA32](https://www.aliexpress.com/item/4000211331316.html) - No GPS
- version 2.1
- board labels "TTGO T3_V1.6 20180606"
- 3D printable case
- [TTGO LORA32 v1](https://www.thingiverse.com/thing:3385109)

View File

@@ -8,7 +8,7 @@ COUNTRIES="US EU433 EU865 CN JP"
#COUNTRIES=US
#COUNTRIES=CN
BOARDS="ttgo-lora32-v2 ttgo-lora32-v1 tbeam heltec tbeam0.7"
BOARDS="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
#BOARDS=tbeam
OUTDIR=release/latest

View File

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

47
boards/nrf52840_dk.json Normal file
View File

@@ -0,0 +1,47 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4404"]],
"usb_product": "nrf52840dk",
"mcu": "nrf52840",
"variant": "pca10056",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd"
},
"frameworks": ["arduino"],
"name": "A modified NRF52840-DK devboard (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": ["jlink", "nrfjprog", "stlink"]
},
"url": "https://meshtastic.org/",
"vendor": "Nordic Semi"
}

View File

@@ -8,7 +8,7 @@
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [["0x239A", "0x4404"]],
"usb_product": "SimPPR",
"usb_product": "nrf52840dk",
"mcu": "nrf52840",
"variant": "pca10056-rc-clock",
"variants_dir": "variants",

55
boards/rak815.json Normal file
View File

@@ -0,0 +1,55 @@
{
"build": {
"arduino":{
"ldscript": "nrf52832_s132_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52832_XXAA -DNRF52",
"f_cpu": "64000000L",
"hwids": [
[
"0x10c4",
"0xea60"
]
],
"usb_product": "RAK815",
"mcu": "nrf52832",
"variant": "rak815",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS132",
"sd_name": "s132",
"sd_version": "6.1.1",
"sd_fwid": "0x00B7"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52832_xxAA",
"svd_path": "nrf52.svd"
},
"frameworks": [
"arduino"
],
"name": "RAK RAK815",
"upload": {
"maximum_ram_size": 65536,
"maximum_size": 524288,
"require_upload_port": true,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
},
"url": "https://store.rakwireless.com/products/rak815-hybrid-location-tracker",
"vendor": "RAK"
}

View File

@@ -35,6 +35,10 @@ This project is currently in beta testing but it is fairly stable and feature co
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [forum](https://meshtastic.discourse.group/).
### Beginner's Guide
For an detailed walk-through aimed at beginners, we recommend [meshtastic.letstalkthis.com](https://meshtastic.letstalkthis.com/).
# Updates
Note: Updates are happening almost daily, only major updates are listed below. For more details see our forum.

View File

@@ -0,0 +1,8 @@
| Vendor | Product line | Version | Board labels | Notes | URL |
|---|---|---|---|---|---|
| TTGO | T-Beam | 0.7 | T22_V07 20180711 | LoRa 433/470MHz *OR* LoRa 868/915MHz , <br/>GPS ublox NEO-6M , <br/>battery holder for Li-Ion 18650 | [buy](https://www.aliexpress.com/item/4000574335430.html) |
| TTGO | T-Beam | 1.0 | | | [buy](https://www.aliexpress.com/item/4001178678568.html) |
| TTGO | T-Beam | 1.1 | T22_V11 20191212 | LoRa 433/470MHz *OR* LoRa 868/915MHz *OR* LoRa 923MHz , <br/>GPS ublox NEO-M8N , <br/>battery holder for Li-Ion 18650 | [buy](https://www.aliexpress.com/item/4001178678568.html) |
| TTGO | Lora32 | 2.0 | *missing* | LoRa 433/470MHz *OR* LoRa 868/915MHz , <br/>OLED SSD1306 , <br/>SD card holder | [buy](https://www.aliexpress.com/item/4000211331316.html) |
| TTGO | Lora32 | 2.1 | T3_V1.6 20180606 | LoRa 32 (V2) , <br/>SD card holder | [buy](https://www.aliexpress.com/item/4000119208093.html) |
| Heltec | Lora 32 | V2 | V2 | LoRa 433/470MHz *OR* LoRa 868/915MHz | [buy](https://heltec.org/project/wifi-lora-32/) |

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,21 @@
You probably don't care about this section - skip to the next one.
Nimble tasks:
- readerror.txt stress test bug
- started RPA long test, jul 22 6pm
- implement nimble software update api
- update to latest bins, test OTA again (measure times) and then checkin bins
- do alpha release
* update protocol description per cyclomies email thread
* update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2
* update faq on recommended android version and phones
* add help link inside the app, reference a page on the wiki
* turn on amazon reviews support
* add a tablet layout (with map next to messages) in the android app
# Medium priority
Items to complete before 1.0.
@@ -19,6 +34,10 @@ Items to complete before 1.0.
Items after the first final candidate release.
- implement nimble battery level service
- Nimble implement device info service remaining fields (hw version etc)
- Turn on RPA addresses for the device side in Nimble
- Try to teardown less of the Nimble protocol stack across sleep
- 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)

14
docs/software/ant.md Normal file
View File

@@ -0,0 +1,14 @@
# ANT protocol notes
SD340 terms are reasonable for NRF52
https://www.thisisant.com/developer/components/nrf52832#tab_protocol_stacks_tab
Profiles to implement:
tracker
https://www.thisisant.com/developer/ant-plus/device-profiles/#4365_tab
ebike
https://www.thisisant.com/developer/ant-plus/device-profiles/#527_tab
no profile for messaging?

View File

@@ -1,12 +1,26 @@
# Bluetooth API
# Device API
The Bluetooth API is design to have only a few characteristics and most polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone.
The Device API is design to have only a simple stream of ToRadio and FromRadio packets and all polymorphism comes from the flexible set of Google Protocol Buffers which are sent over the wire. We use protocol buffers extensively both for the bluetooth API and for packets inside the mesh or when providing packets to other applications on the phone.
## A note on MTU sizes
## Streaming version
This device will work with any MTU size, but it is highly recommended that you call your phone's "setMTU function to increase MTU to 512 bytes" as soon as you connect to a service. This will dramatically improve performance when reading/writing packets.
This protocol is **almost** identical when it is deployed over BLE, Serial/USB or TCP (our three currently supported transports for connecting to phone/PC). Most of this document is in terms of the original BLE version, but this section describes the small changes when this API is exposed over a Streaming (non datagram) transport. The streaming version has the following changes:
## MeshBluetoothService
- We assume the stream is reliable (though the protocol will resynchronize if bytes are lost or corrupted). i.e. we do not include CRCs or error correction codes.
- Packets always have a four byte header (described below) prefixed before each packet. This header provides framing characters and length.
- The stream going towards the radio is only a series of ToRadio packets (with the extra 4 byte headers)
- The stream going towards the PC is a stream of FromRadio packets (with the 4 byte headers), or if the receiver state machine does not see valid header bytes it can (optionally) print those bytes as the debug console from the radio. This allows the device to emit regular serial debugging messages (which can be understood by a terminal program) but also switch to a more structured set of protobufs once it sees that the PC client has sent a protobuf towards it.
The 4 byte header is constructed to both provide framing and to not look line 'normal' 7 bit ASCII.
- Byte 0: START1 (0x94)
- Byte 1: START2 (0xc3)
- Byte 2: MSB of protobuf length
- Byte 3: LSB of protobuf length
The receiver will validate length and if >512 it will assume the packet is corrupted and return to looking for START1. While looking for START1 any other characters are printed as "debug output". For small example implementation of this reader see the meshtastic-python implementation.
## MeshBluetoothService (the BLE API)
This is the main bluetooth service for the device and provides the API your app should use to get information about the mesh, send packets or provision the radio.
@@ -71,16 +85,20 @@ Not all messages are kept in the fromradio queue (filtered based on SubPacket):
- No WantNodeNum / DenyNodeNum messages are kept
A variable keepAllPackets, if set to true will suppress this behavior and instead keep everything for forwarding to the phone (for debugging)
## Protobuf API
### A note on MTU sizes
This device will work with any MTU size, but it is highly recommended that you call your phone's "setMTU function to increase MTU to 512 bytes" as soon as you connect to a service. This will dramatically improve performance when reading/writing packets.
### Protobuf API
On connect, you should send a want_config_id protobuf to the device. This will cause the device to send its node DB and radio config via the fromradio endpoint. After sending the full DB, the radio will send a want_config_id to indicate it is done sending the configuration.
## Other bluetooth services
### Other bluetooth services
This document focuses on the core mesh service, but it is worth noting that the following other Bluetooth services are also
This document focuses on the core device protocol, but it is worth noting that the following other Bluetooth services are also
provided by the device.
### BluetoothSoftwareUpdate
#### BluetoothSoftwareUpdate
The software update service. For a sample function that performs a software update using this API see [startUpdate](https://github.com/meshtastic/Meshtastic-Android/blob/master/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt).
@@ -98,10 +116,10 @@ Characteristics
| GATT_UUID_MANU_NAME/0x2a29 | read | |
| GATT_UUID_HW_VERSION_STR/0x2a27 | read | |
### DeviceInformationService
#### DeviceInformationService
Implements the standard BLE contract for this service (has software version, hardware model, serial number, etc...)
### BatteryLevelService
#### BatteryLevelService
Implements the standard BLE contract service, provides battery level in a way that most client devices should automatically understand (i.e. it should show in the bluetooth devices screen automatically)

View File

@@ -12,5 +12,12 @@ you'll automatically get our fixed libraries.
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/
cp -ar components/arduino/* ~/.platformio/packages/framework-arduinoespressif32
/// @src-fba9d33740f719f712e9f8b07da6ea13/
or
cp -ar out/tools/sdk/* ~/.platformio/packages/framework-arduinoespressif32/tools/sdk
```

View File

@@ -1,13 +1,22 @@
# NRF52 TODO
- Possibly switch from softdevice to Apachy Newt: https://github.com/espressif/esp-nimble
https://github.com/apache/mynewt-core - use nimble BLE on both ESP32 and NRF52
## RAK815
### Bootloader
Installing the adafruit bootloader is optional - I think the stock bootloader will work okay for most.
TODO:
- i2c gps comms not quite right
- ble: AdafruitBluefruit::begin - adafruit_ble_task was assigned an invalid stack pointer. out of memory?
- measure power draw
### Bootloader
Install our (temporarily hacked up) adafruit bootloader
```
kevinh@kevin-server:~/development/meshtastic/Adafruit_nRF52_Bootloader$ make BOARD=rak815 flash
kevinh@kevin-server:~/development/meshtastic/Adafruit_nRF52_Bootloader$ make BOARD=rak815 sd flash
LD rak815_bootloader-0.3.2-111-g9478eb7-dirty.out
text data bss dec hex filename
20888 1124 15006 37018 909a _build/build-rak815/rak815_bootloader-0.3.2-111-g9478eb7-dirty.out
@@ -31,20 +40,52 @@ Applying system reset.
Run.
```
### Appload
tips on installing https://github.com/platformio/platform-nordicnrf52/issues/8#issuecomment-374017768
to see console output over jlink:
```
12:17
in one tab run "bin/nrf52832-gdbserver.sh" - leave this running the whole time while developing/debugging
12:17
~/development/meshtastic/meshtastic-esp32$ bin/nrf52-console.sh
###RTT Client: ************************************************************
###RTT Client: * SEGGER Microcontroller GmbH *
###RTT Client: * Solutions for real time microcontroller applications *
###RTT Client: ************************************************************
###RTT Client: * *
###RTT Client: * (c) 2012 - 2016 SEGGER Microcontroller GmbH *
###RTT Client: * *
###RTT Client: * www.segger.com Support: support@segger.com *
###RTT Client: * *
###RTT Client: ************************************************************
###RTT Client: * *
###RTT Client: * SEGGER J-Link RTT Client Compiled Apr 7 2020 15:01:22 *
###RTT Client: * *
###RTT Client: ************************************************************
###RTT Client: -----------------------------------------------
###RTT Client: Connecting to J-Link RTT Server via localhost:19021 ..............
###RTT Client: Connected.
SEGGER J-Link V6.70c - Real time terminal output
SEGGER J-Link ARM V9.6, SN=69663845
Process: JLinkGDBServerCLExein another tab run:
12:18
On NRF52 I've been using the jlink fake serial console. But since the rak815 has the serial port hooked up we can switch back to that once the basics are working.
```
## Misc work items
RAM investigation.
nRF52832-QFAA 64KB ram, 512KB flash vs
nrf52832-QFAB 32KB ram, 512kb flash
nrf52833 128KB RAM
nrf52840 256KB RAM, 1MB flash
platform.json
Manual hacks needed to build (for now):
"framework-arduinoadafruitnrf52": {
"type": "framework",
"optional": true,
"version": "https://github.com/meshtastic/Adafruit_nRF52_Arduino.git"
},
kevinh@kevin-server:~/.platformio/packages/framework-arduinoadafruitnrf52/variants\$ ln -s ~/development/meshtastic/meshtastic-esp32/variants/\* .
## Initial work items

6
docs/software/rak815.md Normal file
View File

@@ -0,0 +1,6 @@
# RAK815
Notes on trying to get the RAK815 working with meshtastic.
good tutorial: https://www.hackster.io/naresh-krish/getting-started-with-rak815-tracker-module-and-arduino-1c7bc9
(includes software serial link - possibly useful for GPS)

View File

@@ -0,0 +1,148 @@
nimble stress test error (private notes for @geeksville)
findings:
only happens when stress testing multiple sleepwake cycles?
failed packets all have initial mbuflen of zero (should be 1)
restarting the connection on phone sometimes (but not always) fixes it (is the larger config nonce pushing packet size up too large?)
- packets >= 79 bytes (FromRadio) cause INVALID_OFFSET (7) gatt errors to be sent to the app
- some packets are missing
theory:
some sort of leak in mbuf storage during unfortunately timed sleep shutdowns
device side
connection updated; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=00:24:62:ab:dd:df
our_id_addr_type=0 our_id_addr=00:24:62:ab:dd:df
peer_ota_addr_type=0 peer_ota_addr=00:7c:d9:5c:ba:2e
peer_id_addr_type=0 peer_id_addr=00:7c:d9:5c:ba:2e
conn_itvl=36 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1
BLE fromRadio called
getFromRadio, !available
toRadioWriteCb data 0x3ffc3d72, len 4
Trigger powerFSM 9
Transition powerFSM transition=Contact from phone, from=DARK to=DARK
Client wants config, nonce=6864
Reset nodeinfo read pointer
toRadioWriteCb data 0x3ffc3d72, len 4
Trigger powerFSM 9
Transition powerFSM transition=Contact from phone, from=DARK to=DARK
Client wants config, nonce=6863
Reset nodeinfo read pointer
BLE fromRadio called
getFromRadio, state=2
encoding toPhone packet to phone variant=3, 50 bytes
BLE fromRadio called
getFromRadio, state=3
encoding toPhone packet to phone variant=6, 83 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0xabdddf38, lastseen=1595606850, id=!2462abdddf38, name=Bob b
encoding toPhone packet to phone variant=4, 67 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0x28b200b4, lastseen=1595606804, id=!246f28b200b4, name=Unknown 00b4
encoding toPhone packet to phone variant=4, 80 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0xabf84098, lastseen=1593680756, id=!2462abf84098, name=bx n
encoding toPhone packet to phone variant=4, 72 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0x83f0d8e5, lastseen=1594686931, id=!e8e383f0d8e5, name=Unknown d8e5
encoding toPhone packet to phone variant=4, 64 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0xd1dc7764, lastseen=1595602082, id=!f008d1dc7764, name=dg
encoding toPhone packet to phone variant=4, 52 bytes
BLE fromRadio called
getFromRadio, state=4
Sending nodeinfo: num=0xd1dc7828, lastseen=1595598298, id=!f008d1dc7828, name=ryan
encoding toPhone packet to phone variant=4, 54 bytes
BLE fromRadio called
getFromRadio, state=4
Done sending nodeinfos
getFromRadio, state=5
phone side
2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Attempting reconnect
2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: connect
2020-07-24 09:11:00.642 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: connect
2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: connect() - device: 24:62:AB:DD:DF:3A, auto: false
2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: registerApp()
2020-07-24 09:11:00.643 6478-6545/com.geeksville.mesh D/BluetoothGatt: registerApp() - UUID=026baf7f-d2de-43f1-961f-4e00e04c6fbb
2020-07-24 09:11:00.645 6478-27868/com.geeksville.mesh D/BluetoothGatt: onClientRegistered() - status=0 clientIf=4
2020-07-24 09:11:01.022 6478-27868/com.geeksville.mesh D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=4 device=24:62:AB:DD:DF:3A
2020-07-24 09:11:01.022 6478-27868/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: new bluetooth connection state 2, status 0
2020-07-24 09:11:01.023 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work connect is completed, resuming status=0, res=kotlin.Unit
2020-07-24 09:11:01.023 6478-6545/com.geeksville.mesh I/com.geeksville.mesh.service.BluetoothInterface: Connected to radio!
2020-07-24 09:11:01.023 6478-6545/com.geeksville.mesh D/BluetoothGatt: refresh() - device: 24:62:AB:DD:DF:3A
2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: discover
2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: discover
2020-07-24 09:11:01.526 6478-6545/com.geeksville.mesh D/BluetoothGatt: discoverServices() - device: 24:62:AB:DD:DF:3A
2020-07-24 09:11:01.829 6478-27868/com.geeksville.mesh D/BluetoothGatt: onConnectionUpdated() - Device=24:62:AB:DD:DF:3A interval=6 latency=0 timeout=500 status=0
2020-07-24 09:11:02.008 6478-27868/com.geeksville.mesh D/BluetoothGatt: onSearchComplete() = Device=24:62:AB:DD:DF:3A Status=0
2020-07-24 09:11:02.009 6478-27868/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work discover is completed, resuming status=0, res=kotlin.Unit
2020-07-24 09:11:02.009 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Discovered services!
2020-07-24 09:11:02.095 6478-27868/com.geeksville.mesh D/BluetoothGatt: onConnectionUpdated() - Device=24:62:AB:DD:DF:3A interval=36 latency=0 timeout=500 status=0
2020-07-24 09:11:03.010 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.RadioInterfaceService: Broadcasting connection=true
2020-07-24 09:11:03.012 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.012 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED
2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED
2020-07-24 09:11:03.012 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=6878
2020-07-24 09:11:03.013 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7 *** sending start config
2020-07-24 09:11:03.013 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7
2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.CONNECT_CHANGED
2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: onConnectionChanged=CONNECTED
2020-07-24 09:11:03.015 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Starting config nonce=6877
2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: device sleep timeout cancelled
2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: queuing 4 bytes to f75c76d2-129e-4dad-a1dd-7866124401e7
2020-07-24 09:11:03.016 6478-6545/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7
2020-07-24 09:11:03.130 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7
2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315
2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Done reading from radio, fromradio is empty
2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: starting setNotify(ed9da18c-a800-4f66-a670-aa7547e34453, true) *** start notify
2020-07-24 09:11:03.132 6478-19966/com.geeksville.mesh D/BluetoothGatt: setCharacteristicNotification() - uuid: ed9da18c-a800-4f66-a670-aa7547e34453 enable: true
2020-07-24 09:11:03.133 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: writeD
2020-07-24 09:11:03.220 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeC f75c76d2-129e-4dad-a1dd-7866124401e7
2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@2d2062a
2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed
2020-07-24 09:11:03.221 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.310 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: writeD
2020-07-24 09:11:03.311 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeC f75c76d2-129e-4dad-a1dd-7866124401e7 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@2d2062a
2020-07-24 09:11:03.311 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: write of 4 bytes completed
2020-07-24 09:11:03.400 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.402 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work writeD is completed, resuming status=0, res=android.bluetooth.BluetoothGattDescriptor@fc99c1b
2020-07-24 09:11:03.402 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Notify enable=true completed
2020-07-24 09:11:03.769 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315
2020-07-24 09:11:03.769 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 80 bytes from radio **** received an 80 byte fromradio. Why did we miss three previous reads?
2020-07-24 09:11:03.774 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.774 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:03.774 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO
2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=80 (exception Protocol message had invalid UTF-8.)
2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO
2020-07-24 09:11:03.776 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=80 (exception Protocol message had invalid UTF-8.)
2020-07-24 09:11:04.031 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=0, res=android.bluetooth.BluetoothGattCharacteristic@556a315
2020-07-24 09:11:04.031 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.BluetoothInterface: Received 52 bytes from radio *** received 52 bytes - where did the previous two read results go?
2020-07-24 09:11:04.033 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: Enqueuing work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:04.033 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth$BluetoothContinuation: Starting work: readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:04.034 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO
2020-07-24 09:11:04.035 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=52 (exception While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.)
2020-07-24 09:11:04.036 6478-6478/com.geeksville.mesh D/com.geeksville.mesh.service.MeshService: Received broadcast com.geeksville.mesh.RECEIVE_FROMRADIO
2020-07-24 09:11:04.036 6478-6478/com.geeksville.mesh E/com.geeksville.mesh.service.MeshService: Invalid Protobuf from radio, len=52 (exception While parsing a protocol message, the input ended unexpectedly in the middle of a field. This could mean either that the input has been truncated or that an embedded message misreported its own length.)
2020-07-24 09:11:04.210 6478-19966/com.geeksville.mesh D/com.geeksville.mesh.service.SafeBluetooth: work readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5 is completed, resuming status=7, res=android.bluetooth.BluetoothGattCharacteristic@556a315 *** read failed
2020-07-24 09:11:04.211 6478-19966/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Scheduling reconnect because error during doReadFromRadio - disconnecting, Bluetooth status=7 while doing readC 8ba2bcc2-ee02-4a55-a531-c525c5e454d5
2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh W/com.geeksville.mesh.service.BluetoothInterface: Forcing disconnect and hopefully device will comeback (disabling forced refresh)
2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Closing our GATT connection
2020-07-24 09:11:04.211 6478-6545/com.geeksville.mesh D/BluetoothGatt: cancelOpen() - device: 24:62:AB:DD:DF:3A
2020-07-24 09:11:04.214 6478-19966/com.geeksville.mesh D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=4 device=24:62:AB:DD:DF:3A
2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: new bluetooth connection state 0, status 0
2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh I/com.geeksville.mesh.service.SafeBluetooth: Got disconnect because we are shutting down, closing gatt
2020-07-24 09:11:04.215 6478-19966/com.geeksville.mesh D/BluetoothGatt: close()

View File

@@ -37,13 +37,6 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n
-DAPP_VERSION=${sysenv.APP_VERSION}
-DHW_VERSION=${sysenv.HW_VERSION}
; not needed included in ttgo-t-beam board file
; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
@@ -74,7 +67,7 @@ lib_deps =
Wire ; explicitly needed here because the AXP202 library forgets to add it
https://github.com/meshtastic/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
https://github.com/meshtastic/RadioLib.git#6aa38a85856012c99c4e9b4e7cee35e37671a4bc
https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
https://github.com/meshtastic/TinyGPSPlus.git
; Common settings for ESP targes, mixin with extends = esp32_base
@@ -85,12 +78,20 @@ src_filter =
upload_speed = 921600
debug_init_break = tbreak setup
build_flags =
${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue
${env.build_flags} -Wall -Wextra -Isrc/esp32 -mfix-esp32-psram-cache-issue -lnimble -std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
# 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#71ed4002c953d8c87f44ed27e34fe0735f99013e
framework-arduinoespressif32 @ https://github.com/meshtastic/arduino-esp32.git#1adba3f11ca8406ac0a704d151697b572058b53d
; not needed included in ttgo-t-beam board file
; also to use PSRAM https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue
; -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; The 1.0 release of the TBEAM board
[env:tbeam]
@@ -115,18 +116,24 @@ build_flags =
extends = esp32_base
board = heltec_wifi_lora_32_V2
[env:ttgo-lora32-v1]
[env:tlora-v1]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TTGO_LORA_V1
${esp32_base.build_flags} -D TLORA_V1
; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works
[env:ttgo-lora32-v2]
[env:tlora-v2]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TTGO_LORA_V2
${esp32_base.build_flags} -D TLORA_V2
[env:tlora-v2-1-1.6]
extends = esp32_base
board = ttgo-lora32-v1
build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_16
; 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.
@@ -141,15 +148,19 @@ src_filter =
; Common settings for NRF52 based targets
[nrf52_base]
platform = nordicnrf52
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
; platform = nordicnrf52
platform = https://github.com/meshtastic/platform-nordicnrf52.git#62d185fe61b6c84c554046106529b4fd8f155e2c
debug_tool = jlink
build_type = debug ; I'm debugging with ICE a lot now
; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME)
build_flags =
${env.build_flags} -Wno-unused-variable -Isrc/nrf52 -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
${env.build_flags} -Wno-unused-variable
-Isrc/nrf52
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.3
;-DCFG_DEBUG=3
src_filter =
${env.src_filter} -<esp32/>
${env.src_filter} -<esp32/> -<nimble/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
@@ -166,10 +177,30 @@ debug_init_break =
;debug_init_break = tbreak Reset_Handler
; The NRF52840-dk development board
[env:nrf52dk]
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
extends = nrf52_base
board = nrf52840_dk
; The NRF52840-dk development board, but @geeksville's board - which has a busted oscilliator
[env:nrf52840dk-geeksville]
extends = nrf52_base
board = nrf52840_dk_modified
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:feather_nrf52832]
extends = nrf52_base
board = adafruit_feather_nrf52832
[env:rak815]
extends = nrf52_base
board = rak815
debug_tool = jlink
upload_protocol = jlink
monitor_port = /dev/ttyUSB0
; this board's serial chip can only run at 115200, not faster
monitor_speed = 115200
# For experimenting with RAM sizes
# board_build.ldscript = linker/nrf52840_s140_sim832.ld

2
proto

Submodule proto updated: ab281311c4...0523977d1f

12
src/BluetoothCommon.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "BluetoothCommon.h"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f,
0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b};
const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1,
0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7};
const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5,
0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b};
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};

20
src/BluetoothCommon.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include <Arduino.h>
/**
* Common lib functions for all platforms that have bluetooth
*/
#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[];
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level);

View File

@@ -1,7 +1,13 @@
#include "Thread.h"
#include "timing.h"
#include <assert.h>
namespace concurrency {
#ifdef ARDUINO_ARCH_ESP32
#include "esp_task_wdt.h"
#endif
namespace concurrency
{
void Thread::start(const char *name, size_t stackSize, uint32_t priority)
{
@@ -14,4 +20,27 @@ void Thread::callRun(void *_this)
((Thread *)_this)->doRun();
}
void Thread::serviceWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
esp_task_wdt_reset();
#endif
}
void Thread::startWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
auto r = esp_task_wdt_add(taskHandle);
assert(r == ESP_OK);
#endif
}
void Thread::stopWatchdog()
{
#ifdef ARDUINO_ARCH_ESP32
auto r = esp_task_wdt_delete(taskHandle);
assert(r == ESP_OK);
#endif
}
} // namespace concurrency

View File

@@ -1,7 +1,6 @@
#pragma once
#include "freertosinc.h"
#include "esp_task_wdt.h"
namespace concurrency {
@@ -36,17 +35,9 @@ class Thread
*
* 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);
}
void serviceWatchdog();
void startWatchdog();
void stopWatchdog();
private:
static void callRun(void *_this);

View File

@@ -55,13 +55,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/// Convert a preprocessor name into a quoted string and if that string is empty use "unset"
#define optstr(s) (xstr(s)[0] ? xstr(s) : "unset")
#ifdef NRF52840_XXAA // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
// board specific
#ifdef NRF52_SERIES // All of the NRF52 targets are configured using variant.h, so this section shouldn't need to be
// board specific
//
// Standard definitions for NRF52 targets
//
// Nop definition for these attributes - not used on NRF52
#define EXT_RAM_ATTR
#define IRAM_ATTR
#define NO_ESP32 // Don't use ESP32 libs (mainly bluetooth)
// We bind to the GPS using variant.h instead for this platform (Serial1)
@@ -70,7 +74,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RTC_DATA_ATTR
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
// If the variant filed defines as standard button
#ifdef PIN_BUTTON1
#define BUTTON_PIN PIN_BUTTON1
#endif
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
#elif defined(CubeCell_BoardPlus)
@@ -105,10 +113,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// LoRa SPI
// -----------------------------------------------------------------------------
#define SCK_GPIO 5
#define MISO_GPIO 19
#define MOSI_GPIO 27
#define NSS_GPIO 18
// NRF52 boards will define this in variant.h
#ifndef RF95_SCK
#define RF95_SCK 5
#define RF95_MISO 19
#define RF95_MOSI 27
#define RF95_NSS 18
#endif
#endif
@@ -148,11 +159,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
#ifndef USE_JTAG
#define RESET_GPIO 14
#define RF95_RESET 14
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board
#define RF95_IRQ 26
#define RF95_DIO1 33 // Note: not really used on this board
#define RF95_DIO2 32 // Note: not really used on this board
// Leave undefined to disable our PMU IRQ handler
#define PMU_IRQ 35
@@ -171,11 +182,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN 39
#ifndef USE_JTAG
#define RESET_GPIO 23
#define RF95_RESET 23
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 33 // Note: not really used on this board
#define DIO2_GPIO 32 // Note: not really used on this board
#define RF95_IRQ 26
#define RF95_DIO1 33 // Note: not really used on this board
#define RF95_DIO2 32 // Note: not really used on this board
// This board has different GPS pins than all other boards
#undef GPS_RX_PIN
@@ -206,14 +217,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#ifndef USE_JTAG
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#endif
#define RF95_IRQ_GPIO 26
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V1)
#define RF95_IRQ 26
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TLORA_V1)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v1"
#define HW_VENDOR "tlora-v1"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
@@ -228,13 +239,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LED_PIN 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TTGO_LORA_V2)
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ 26 // IRQ line for the LORA radio
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TLORA_V2)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "ttgo-lora32-v2"
#define HW_VENDOR "tlora-v2"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
@@ -250,12 +262,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
// between this pin and ground
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#elif defined(TLORA_V2_1_16)
// This string must exactly match the case used in release file names or the android updater won't work
#define HW_VENDOR "tlora-v2-1-1.6"
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define GPS_RX_PIN 36
#define GPS_TX_PIN 39
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define BUTTON_PIN \
12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground
#define RF95_RESET 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ 26 // IRQ line for the LORA radio
#define RF95_DIO1 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define RF95_DIO2 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#endif
#ifdef ARDUINO_NRF52840_PCA10056
@@ -267,25 +304,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#undef LED_INVERTED
#define LED_INVERTED 1
// Uncomment to confirm if we can build the RF95 driver for NRF52
#if 0
#define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio
#define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio
#define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number
#endif
#elif defined(ARDUINO_NRF52840_PPR)
#define HW_VENDOR "ppr"
#elif NRF52_SERIES
#define HW_VENDOR "nrf52unknown" // FIXME - unknown nrf52 board
#endif
// -----------------------------------------------------------------------------
// DEBUG
// -----------------------------------------------------------------------------
#ifdef CONSOLE_MAX_BAUD
#define SERIAL_BAUD CONSOLE_MAX_BAUD
#else
#define SERIAL_BAUD 921600 // Serial debug baud rate
#endif
#include "SerialConsole.h"
@@ -293,13 +330,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// What platforms should use SEGGER?
#ifdef NRF52_SERIES
// Always include the SEGGER code on NRF52 - because useful for debugging
#include "SEGGER_RTT.h"
// Debug printing to segger console
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
// nrf52 gets its settings via variant files
#ifndef PIN_SERIAL_RX
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
#else
#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32
#endif
#ifdef USE_SEGGER
#include "SEGGER_RTT.h"
#define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#ifdef DEBUG_PORT

View File

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

View File

@@ -1,48 +1,41 @@
#include "BluetoothSoftwareUpdate.h"
#include "BluetoothUtil.h"
#include "CallbackCharacteristic.h"
#include "RadioLibInterface.h"
#include "configuration.h"
#include <Arduino.h>
#include "../concurrency/LockGuard.h"
#include "../timing.h"
#include <Arduino.h>
#include <BLE2902.h>
#include "BluetoothSoftwareUpdate.h"
#include "PowerFSM.h"
#include "RadioLibInterface.h"
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include <CRC32.h>
#include <Update.h>
#include <esp_gatt_defs.h>
//using namespace meshtastic;
int16_t updateResultHandle = -1;
CRC32 crc;
uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
static CRC32 crc;
static uint32_t rebootAtMsec = 0; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
uint32_t updateExpectedSize, updateActualSize;
static uint32_t updateExpectedSize, updateActualSize;
concurrency::Lock *updateLock;
static concurrency::Lock *updateLock;
class TotalSizeCharacteristic : public CallbackCharacteristic
/// Handle writes & reads to total size
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
public:
TotalSizeCharacteristic()
: CallbackCharacteristic("e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e",
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
{
}
concurrency::LockGuard g(updateLock);
void onWrite(BLECharacteristic *c)
{
concurrency::LockGuard g(updateLock);
// Check if there is enough to OTA Update
uint32_t len = getValue32(c, 0);
updateExpectedSize = len;
// Check if there is enough to OTA Update
chr_readwrite32le(&updateExpectedSize, ctxt);
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
updateActualSize = 0;
crc.reset();
bool canBegin = Update.begin(len);
DEBUG_MSG("Setting update size %u, result %d\n", len, canBegin);
bool canBegin = Update.begin(updateExpectedSize);
DEBUG_MSG("Setting update size %u, result %d\n", updateExpectedSize, canBegin);
if (!canBegin) {
// Indicate failure by forcing the size to 0
uint32_t zero = 0;
c->setValue(zero);
// Indicate failure by forcing the size to 0 (client will read it back)
updateExpectedSize = 0;
} else {
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
// talk to one service during the sw update.
@@ -55,73 +48,81 @@ class TotalSizeCharacteristic : public CallbackCharacteristic
// writing flash - shut the radio off during updates
}
}
};
return 0;
}
#define MAX_BLOCKSIZE 512
class DataCharacteristic : public CallbackCharacteristic
/// Handle writes to data
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
public:
DataCharacteristic() : CallbackCharacteristic("e272ebac-d463-4b98-bc84-5cc1a39ee517", BLECharacteristic::PROPERTY_WRITE) {}
concurrency::LockGuard g(updateLock);
void onWrite(BLECharacteristic *c)
{
concurrency::LockGuard g(updateLock);
std::string value = c->getValue();
uint32_t len = value.length();
assert(len <= MAX_BLOCKSIZE);
static uint8_t
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
memcpy(data, c->getData(), len);
// DEBUG_MSG("Writing %u\n", len);
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
}
};
static uint8_t
data[MAX_BLOCKSIZE]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
static BLECharacteristic *resultC;
uint16_t len = 0;
class CRC32Characteristic : public CallbackCharacteristic
auto rc = ble_hs_mbuf_to_flat(ctxt->om, data, sizeof(data), &len);
assert(rc == 0);
// DEBUG_MSG("Writing %u\n", len);
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
return 0;
}
static uint8_t update_result;
/// Handle writes to crc32
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
public:
CRC32Characteristic() : CallbackCharacteristic("4826129c-c22a-43a3-b066-ce8f0d5bacc6", BLECharacteristic::PROPERTY_WRITE) {}
concurrency::LockGuard g(updateLock);
uint32_t expectedCRC = 0;
chr_readwrite32le(&expectedCRC, ctxt);
void onWrite(BLECharacteristic *c)
uint32_t actualCRC = crc.finalize();
DEBUG_MSG("expected CRC %u\n", expectedCRC);
uint8_t result = 0xff;
if (updateActualSize != updateExpectedSize) {
DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
result = 0xe1; // FIXME, use real error codes
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
{
concurrency::LockGuard g(updateLock);
uint32_t expectedCRC = getValue32(c, 0);
uint32_t actualCRC = crc.finalize();
DEBUG_MSG("expected CRC %u\n", expectedCRC);
uint8_t result = 0xff;
if (updateActualSize != updateExpectedSize) {
DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
result = 0xe1; // FIXME, use real error codes
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
{
DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
result = 0xe0; // FIXME, use real error codes
DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
result = 0xe0; // FIXME, use real error codes
} else {
if (Update.end()) {
DEBUG_MSG("OTA done, rebooting in 5 seconds!\n");
rebootAtMsec = timing::millis() + 5000;
} else {
if (Update.end()) {
DEBUG_MSG("OTA done, rebooting in 5 seconds!\n");
rebootAtMsec = timing::millis() + 5000;
} else {
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
}
result = Update.getError();
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
}
if (RadioLibInterface::instance)
RadioLibInterface::instance->startReceive(); // Resume radio
assert(resultC);
resultC->setValue(&result, 1);
resultC->notify();
result = Update.getError();
}
};
if (RadioLibInterface::instance)
RadioLibInterface::instance->startReceive(); // Resume radio
assert(updateResultHandle >= 0);
update_result = result;
DEBUG_MSG("BLE notify update result\n");
auto res = ble_gattc_notify(curConnectionHandle, updateResultHandle);
assert(res == 0);
return 0;
}
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite8(&update_result, sizeof(update_result), ctxt);
}
void bluetoothRebootCheck()
{
@@ -135,45 +136,15 @@ void bluetoothRebootCheck()
See bluetooth-api.md
*/
BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion)
void reinitUpdateService()
{
if (!updateLock)
updateLock = new concurrency::Lock();
// Create the BLE Service
BLEService *service = server->createService(BLEUUID("cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"), 25, 0);
auto res = ble_gatts_count_cfg(gatt_update_svcs); // assigns handles? see docstring for note about clearing the handle list
// before calling SLEEP SUPPORT
assert(res == 0);
assert(!resultC);
resultC = new BLECharacteristic("5e134862-7411-4424-ac4a-210937432c77",
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(service, new TotalSizeCharacteristic, "total image size");
addWithDesc(service, new DataCharacteristic, "data");
addWithDesc(service, new CRC32Characteristic, "crc32");
addWithDesc(service, resultC, "result code");
resultC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
BLECharacteristic *swC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_SW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
swC->setValue(swVersion);
service->addCharacteristic(addBLECharacteristic(swC));
BLECharacteristic *mfC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_MANU_NAME), BLECharacteristic::PROPERTY_READ);
mfC->setValue(hwVendor);
service->addCharacteristic(addBLECharacteristic(mfC));
BLECharacteristic *hwvC =
new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_HW_VERSION_STR), BLECharacteristic::PROPERTY_READ);
hwvC->setValue(hwVersion);
service->addCharacteristic(addBLECharacteristic(hwvC));
return service;
res = ble_gatts_add_svcs(gatt_update_svcs);
assert(res == 0);
}
void destroyUpdateService()
{
assert(resultC);
resultC = NULL;
}

View File

@@ -1,11 +1,26 @@
#pragma once
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include "nimble/NimbleDefs.h"
BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion);
void reinitUpdateService();
void destroyUpdateService();
void bluetoothRebootCheck();
void bluetoothRebootCheck();
#ifdef __cplusplus
extern "C" {
#endif
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
extern const struct ble_gatt_svc_def gatt_update_svcs[];
extern const ble_uuid128_t update_result_uuid;
extern int16_t updateResultHandle;
#ifdef __cplusplus
};
#endif

View File

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

View File

@@ -1,42 +0,0 @@
#pragma once
#include <functional>
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include "SimpleAllocator.h"
// Now handled by BluetoothUtil.cpp
// BLEService *createDeviceInfomationService(BLEServer* server, uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
// Help routine to add a description to any BLECharacteristic and add it to the service
void addWithDesc(BLEService *service, BLECharacteristic *c, const char *description);
void dumpCharacteristic(BLECharacteristic *c);
/** converting endianness pull out a 32 bit value */
uint32_t getValue32(BLECharacteristic *c, uint32_t defaultValue);
// TODO(girts): create a class for the bluetooth utils helpers?
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
using StopBluetoothPinScreenCallback = std::function<void(void)>;
void loopBLE();
BLEServer *initBLE(
StartBluetoothPinScreenCallback startBtPinScreen, StopBluetoothPinScreenCallback stopBtPinScreen,
std::string devName, std::string hwVendor, std::string swVersion, std::string hwVersion = "");
void deinitBLE();
/// Add a characteristic that we will delete when we restart
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

@@ -1,143 +0,0 @@
#include "MeshBluetoothService.h"
#include "BluetoothUtil.h"
#include <Arduino.h>
#include <BLE2902.h>
#include <assert.h>
#include <esp_gatt_defs.h>
#include "CallbackCharacteristic.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PhoneAPI.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
#include "mesh.pb.h"
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
static CallbackCharacteristic *meshFromNumCharacteristic;
BLEService *meshService;
class BluetoothPhoneAPI : public PhoneAPI
{
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
if (meshFromNumCharacteristic) { // this ptr might change from sleep to sleep, or even be null
meshFromNumCharacteristic->setValue(fromRadioNum);
meshFromNumCharacteristic->notify();
}
}
};
BluetoothPhoneAPI *bluetoothPhoneAPI;
class ToRadioCharacteristic : public CallbackCharacteristic
{
public:
ToRadioCharacteristic() : CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE) {}
void onWrite(BLECharacteristic *c)
{
bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length());
}
};
class FromRadioCharacteristic : public CallbackCharacteristic
{
public:
FromRadioCharacteristic() : CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ)
{
}
void onRead(BLECharacteristic *c)
{
size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes);
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty
if (numBytes) {
c->setValue(trBytes, numBytes);
} else {
c->setValue((uint8_t *)"", 0);
}
}
};
class FromNumCharacteristic : public CallbackCharacteristic
{
public:
FromNumCharacteristic()
: CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453", BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY)
{
// observe(&service.fromNumChanged);
}
void onRead(BLECharacteristic *c) { DEBUG_MSG("FIXME implement fromnum read\n"); }
};
/*
See bluetooth-api.md for documentation.
*/
BLEService *createMeshBluetoothService(BLEServer *server)
{
// Only create our phone API object once
if (!bluetoothPhoneAPI) {
bluetoothPhoneAPI = new BluetoothPhoneAPI();
bluetoothPhoneAPI->init();
}
// Create the BLE Service, we need more than the default of 15 handles
BLEService *service = server->createService(BLEUUID("6ba1b218-15a8-461f-9fa8-5dcae273eafd"), 30, 0);
assert(!meshFromNumCharacteristic);
meshFromNumCharacteristic = new FromNumCharacteristic;
addWithDesc(service, meshFromNumCharacteristic, "fromRadio");
addWithDesc(service, new ToRadioCharacteristic, "toRadio");
addWithDesc(service, new FromRadioCharacteristic, "fromNum");
meshFromNumCharacteristic->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
service->start();
// We only add to advertisting once, because the ESP32 arduino code is dumb and that object never dies
static bool firstTime = true;
if (firstTime) {
firstTime = false;
server->getAdvertising()->addServiceUUID(service->getUUID());
}
DEBUG_MSG("*** Mesh service:\n");
service->dump();
meshService = service;
return service;
}
void stopMeshBluetoothService()
{
assert(meshService);
meshService->stop();
meshService->executeDelete();
}
void destroyMeshBluetoothService()
{
assert(meshService);
delete meshService;
meshFromNumCharacteristic = NULL;
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include <Arduino.h>
#include <BLEServer.h>
#include <BLEService.h>
BLEService *createMeshBluetoothService(BLEServer *server);
void destroyMeshBluetoothService();
/**
* Tell any bluetooth clients that the number of rx packets has changed
*/
void bluetoothNotifyFromNum(uint32_t newValue);
void stopMeshBluetoothService();

View File

@@ -0,0 +1,61 @@
#include "BluetoothSoftwareUpdate.h"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
// "cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"
const ble_uuid128_t update_service_uuid =
BLE_UUID128_INIT(0x30, 0xee, 0x44, 0x31, 0x2e, 0x44, 0xbb, 0xbd, 0x0d, 0x4c, 0x4c, 0xa8, 0x0b, 0x9a, 0x0b, 0xcb);
// "e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e" write|read
const ble_uuid128_t update_size_uuid =
BLE_UUID128_INIT(0x1e, 0x8e, 0xea, 0xdb, 0xe1, 0xf0, 0xa1, 0x95, 0x6f, 0x4a, 0x01, 0xa3, 0xc0, 0xd9, 0x4d, 0xe7);
// "e272ebac-d463-4b98-bc84-5cc1a39ee517" write
const ble_uuid128_t update_data_uuid =
BLE_UUID128_INIT(0x17, 0xe5, 0x9e, 0xa3, 0xc1, 0x5c, 0x84, 0xbc, 0x98, 0x4b, 0x63, 0xd4, 0xac, 0xeb, 0x72, 0xe2);
// "4826129c-c22a-43a3-b066-ce8f0d5bacc6" write
const ble_uuid128_t update_crc32_uuid =
BLE_UUID128_INIT(0xc6, 0xac, 0x5b, 0x0d, 0x8f, 0xce, 0x66, 0xb0, 0xa3, 0x43, 0x2a, 0xc2, 0x9c, 0x12, 0x26, 0x48);
// "5e134862-7411-4424-ac4a-210937432c77" read|notify
const ble_uuid128_t update_result_uuid =
BLE_UUID128_INIT(0x77, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
const struct ble_gatt_svc_def gatt_update_svcs[] = {
{
/*** Service: Security test. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &update_service_uuid.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
.uuid = &update_size_uuid.u,
.access_cb = update_size_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ |
BLE_GATT_CHR_F_READ_AUTHEN,
},
{
.uuid = &update_data_uuid.u,
.access_cb = update_data_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &update_crc32_uuid.u,
.access_cb = update_crc32_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &update_result_uuid.u,
.access_cb = update_size_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
},
{
0, /* No more characteristics in this service. */
}},
},
{
0, /* No more services. */
},
};

View File

@@ -0,0 +1,57 @@
#include "WiFiServerAPI.h"
#include "PowerFSM.h"
#include "configuration.h"
#include <Arduino.h>
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
{
DEBUG_MSG("Incoming connection from %s\n", client.remoteIP().toString().c_str());
}
WiFiServerAPI::~WiFiServerAPI()
{
client.stop();
// FIXME - delete this if the client dropps the connection!
}
/// Hookable to find out when connection changes
void WiFiServerAPI::onConnectionChanged(bool connected)
{
// FIXME - we really should be doing global reference counting to see if anyone is currently using serial or wifi and if so,
// block sleep
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
} else {
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
}
}
void WiFiServerAPI::loop()
{
if (client.connected()) {
StreamAPI::loop();
} else {
DEBUG_MSG("Client dropped connection, closing UDP server\n");
delete this;
}
}
#define MESHTASTIC_PORTNUM 4403
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM) {}
void WiFiServerPort::init()
{
DEBUG_MSG("Listening on TCP port %d\n", MESHTASTIC_PORTNUM);
begin();
}
void WiFiServerPort::loop()
{
auto client = available();
if (client) {
new WiFiServerAPI(client);
}
}

38
src/esp32/WiFiServerAPI.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include "StreamAPI.h"
#include <WiFi.h>
/**
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
class WiFiServerAPI : public StreamAPI
{
private:
WiFiClient client;
public:
WiFiServerAPI(WiFiClient &_client);
virtual ~WiFiServerAPI();
virtual void loop(); // Check for dropped client connections
protected:
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected);
};
/**
* Listens for incoming connections and does accepts and creates instances of WiFiServerAPI as needed
*/
class WiFiServerPort : public WiFiServer
{
public:
WiFiServerPort();
void init();
void loop();
};

View File

@@ -1,59 +1,14 @@
#include "BluetoothUtil.h"
#include "MeshBluetoothService.h"
#include "BluetoothSoftwareUpdate.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "esp_task_wdt.h"
#include "main.h"
#include "nimble/BluetoothUtil.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
bool bluetoothOn;
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{
DEBUG_MSG("Starting bluetooth\n");
// FIXME - we are leaking like crazy
// AllocatorScope scope(btPool);
// Note: these callbacks might be coming in from a different thread.
BLEServer *serve = initBLE(
[](uint32_t pin) {
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen.startBluetoothPinScreen(pin);
},
[]() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, optstr(APP_VERSION),
optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
createMeshBluetoothService(serve);
// Start advertising - this must be done _after_ creating all services
serve->getAdvertising()->start();
}
// Enable/disable bluetooth.
void setBluetoothEnable(bool on)
{
if (on != bluetoothOn) {
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
bluetoothOn = on;
if (on) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
} else {
// We have to totally teardown our bluetooth objects to prevent leaks
stopMeshBluetoothService(); // Must do before shutting down bluetooth
deinitBLE();
destroyMeshBluetoothService(); // must do after deinit, because it frees our service
Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_stop() );
// heap_trace_dump();
}
}
}
#include <nvs.h>
#include <nvs_flash.h>
void getMacAddr(uint8_t *dmac)
{
@@ -83,13 +38,19 @@ void esp32Setup()
DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize());
DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram());
nvs_stats_t nvs_stats;
auto res = nvs_get_stats(NULL, &nvs_stats);
assert(res == ESP_OK);
DEBUG_MSG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d\n", nvs_stats.used_entries, nvs_stats.free_entries,
nvs_stats.total_entries);
// 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);
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
assert(res == ESP_OK);
res = esp_task_wdt_add(NULL);
@@ -121,6 +82,7 @@ void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
loopBLE();
bluetoothRebootCheck();
// for debug printing
// radio.radioIf.canSleep();

View File

@@ -5,12 +5,21 @@
#include <assert.h>
#include <time.h>
// If we have a serial GPS port it will not be null
#ifdef GPS_RX_PIN
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
HardwareSerial &GPS::_serial_gps = _serial_gps_real;
HardwareSerial *GPS::_serial_gps = &_serial_gps_real;
#elif defined(NRF52840_XXAA)
// Assume NRF52840
HardwareSerial *GPS::_serial_gps = &Serial1;
#else
// Assume NRF52
HardwareSerial &GPS::_serial_gps = Serial1;
HardwareSerial *GPS::_serial_gps = NULL;
#endif
#ifdef GPS_I2C_ADDRESS
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
#else
uint8_t GPS::i2cAddress = 0;
#endif
bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep
@@ -63,7 +72,7 @@ void perhapsSetRTC(struct tm &t)
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300)
DEBUG_MSG("Ignoring invalid GPS time\n");
DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
else
perhapsSetRTC(&tv);
}

View File

@@ -1,8 +1,8 @@
#pragma once
#include "Observer.h"
#include "GPSStatus.h"
#include "../concurrency/PeriodicTask.h"
#include "GPSStatus.h"
#include "Observer.h"
#include "sys/time.h"
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
@@ -30,12 +30,17 @@ class GPS : public Observable<void *>
protected:
bool hasValidLocation = false; // default to false, until we complete our first read
static HardwareSerial &_serial_gps;
public:
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
/** If !0 we will attempt to connect to the GPS over I2C */
static uint8_t i2cAddress;
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
uint32_t numSatellites = 0;

View File

@@ -13,9 +13,8 @@ static int32_t toDegInt(RawDegrees d)
void NEMAGPS::loop()
{
while (_serial_gps.available() > 0) {
int c = _serial_gps.read();
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// Serial.write(c);
reader.encode(c);
}

View File

@@ -1,4 +1,5 @@
#include "UBloxGPS.h"
#include "error.h"
#include "sleep.h"
#include <assert.h>
@@ -7,23 +8,46 @@ UBloxGPS::UBloxGPS() : concurrency::PeriodicTask()
notifySleepObserver.observe(&notifySleep);
}
bool UBloxGPS::tryConnect()
{
isConnected = false;
if (_serial_gps)
isConnected = ublox.begin(*_serial_gps);
if (!isConnected && i2cAddress) {
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
// supports the newer API
neo6M = true;
isConnected = ublox.begin(Wire, i2cAddress);
}
return isConnected;
}
bool UBloxGPS::setup()
{
if (_serial_gps) {
#ifdef GPS_RX_PIN
_serial_gps.begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#else
_serial_gps.begin(GPS_BAUDRATE);
_serial_gps->begin(GPS_BAUDRATE);
#endif
// _serial_gps.setRxBufferSize(1024); // the default is 256
// _serial_gps.setRxBufferSize(1024); // the default is 256
}
#ifdef GPS_POWER_EN
pinMode(GPS_POWER_EN, OUTPUT);
digitalWrite(GPS_POWER_EN, 1);
delay(200); // Give time for the GPS to startup after we gave power
#endif
// ublox.enableDebugging(Serial);
// note: the lib's implementation has the wrong docs for what the return val is
// it is not a bool, it returns zero for success
isConnected = ublox.begin(_serial_gps);
// try a second time, the ublox lib serial parsing is buggy?
if (!isConnected)
isConnected = ublox.begin(_serial_gps);
if (!tryConnect())
tryConnect();
if (isConnected) {
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
@@ -35,14 +59,21 @@ bool UBloxGPS::setup()
// GPS_TX connected)
ublox.factoryReset();
delay(3000);
isConnected = ublox.begin(_serial_gps);
tryConnect();
DEBUG_MSG("Factory reset success=%d\n", isConnected);
ok = ublox.saveConfiguration(3000);
assert(ok);
return false;
} else {
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
assert(ok);
if (_serial_gps) {
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
assert(ok);
}
if (i2cAddress) {
ok = ublox.setI2COutput(COM_TYPE_UBX, 500);
assert(ok);
}
ok = ublox.setNavigationFrequency(1, 500); // Produce 4x/sec to keep the amount of time we stall in getPVT low
assert(ok);
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
@@ -53,7 +84,8 @@ bool UBloxGPS::setup()
assert(ok);
}
ok = ublox.saveConfiguration(3000);
assert(ok);
if (!ok)
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
@@ -80,20 +112,22 @@ void UBloxGPS::doTask()
// Consume all characters that have arrived
// getPVT automatically calls checkUblox
// if using i2c or serial look too see if any chars are ready
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
// 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(0);
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
fixtype = ublox.getFixType(maxWait);
DEBUG_MSG("GPS fix type %d\n", fixtype);
// DEBUG_MSG("sec %d\n", ublox.getSecond());
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
// any fix that has time
if (ublox.getT(0)) {
if (ublox.getT(maxWait)) {
/* 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).
@@ -109,19 +143,21 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
perhapsSetRTC(t);
}
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(0)) // rd fixes only
{
// we only notify if position has changed
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
heading = ublox.getHeading(0);
numSatellites = ublox.getSIV(0);
latitude = ublox.getLatitude(0);
longitude = ublox.getLongitude(0);
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
heading = ublox.getHeading(0);
numSatellites = ublox.getSIV(0);
// 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);
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
hasValidLocation =
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
// we only notify if position has changed due to a new fix
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
{
if (hasValidLocation) {
wantNewLocation = false;
notifyObservers(NULL);
@@ -131,7 +167,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
wantNewLocation = true;
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
const meshtastic::GPSStatus status =
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over

View File

@@ -38,4 +38,7 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
};

View File

@@ -25,17 +25,17 @@
#include "MeshService.h"
#include "NEMAGPS.h"
#include "NodeDB.h"
#include "concurrency/Periodic.h"
#include "PowerFSM.h"
#include "UBloxGPS.h"
#include "concurrency/Periodic.h"
#include "configuration.h"
#include "error.h"
#include "power.h"
// #include "rom/rtc.h"
#include "DSRRouter.h"
#include "debug.h"
#include "main.h"
// #include "debug.h"
#include "graphics/Screen.h"
#include "main.h"
#include "sleep.h"
#include "timing.h"
#include <OneButton.h>
@@ -43,8 +43,7 @@
// #include <driver/rtc_io.h>
#ifndef NO_ESP32
#include "BluetoothUtil.h"
#include "WiFi.h"
#include "nimble/BluetoothUtil.h"
#endif
#include "RF95Interface.h"
@@ -149,29 +148,6 @@ void userButtonPressedLong()
screen.adjustBrightness();
}
#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()
{
#ifdef USE_SEGGER
@@ -259,12 +235,18 @@ void setup()
// Init GPS - first try ublox
gps = new UBloxGPS();
if (!gps->setup()) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NEMA at 9600 baud.
DEBUG_MSG("ERROR: No UBLOX GPS found, hoping that NEMA might work\n");
delete gps;
gps = new NEMAGPS();
gps->setup();
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
if (GPS::_serial_gps) {
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NEMA at 9600 baud.
DEBUG_MSG("Hoping that NEMA might work\n");
delete gps;
// dumb NEMA access only work for serial GPSes)
gps = new NEMAGPS();
gps->setup();
}
}
#else
gps = new NEMAGPS();
@@ -274,10 +256,6 @@ void setup()
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
@@ -290,15 +268,15 @@ void setup()
SPI.begin();
#else
// ESP32
SPI.begin(SCK_GPIO, MISO_GPIO, MOSI_GPIO, NSS_GPIO);
SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
SPI.setFrequency(4000000);
#endif
// MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
RadioInterface *rIf =
#if defined(RF95_IRQ_GPIO)
#if defined(RF95_IRQ)
// new CustomRF95(); old Radiohead based driver
new RF95Interface(NSS_GPIO, RF95_IRQ_GPIO, RESET_GPIO, SPI);
new RF95Interface(RF95_NSS, RF95_IRQ, RF95_RESET, SPI);
#elif defined(SX1262_CS)
new SX1262Interface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI);
#else

View File

@@ -5,14 +5,14 @@
#include "GPS.h"
//#include "MeshBluetoothService.h"
#include "../concurrency/Periodic.h"
#include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
#include "MeshService.h"
#include "NodeDB.h"
#include "../concurrency/Periodic.h"
#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
#include "timing.h"
/*
@@ -283,8 +283,6 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
sendToMesh(p);
}
int MeshService::onGPSChanged(void *unused)
{
// DEBUG_MSG("got gps notify\n");

View File

@@ -356,7 +356,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
info->position.time = oldtime;
info->has_position = true;
updateGUIforNode = info;
notifyObservers(true); //Force an update whether or not our node counts have changed
notifyObservers(true); // Force an update whether or not our node counts have changed
break;
}
@@ -371,7 +371,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
devicestate.has_rx_text_message = true;
updateTextMessage = true;
powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
notifyObservers(true); //Force an update whether or not our node counts have changed
notifyObservers(true); // Force an update whether or not our node counts have changed
}
}
break;
@@ -390,7 +390,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
if (changed) {
updateGUIforNode = info;
powerFSM.trigger(EVENT_NODEDB_UPDATED);
notifyObservers(true); //Force an update whether or not our node counts have changed
notifyObservers(true); // Force an update whether or not our node counts have changed
// Not really needed - we will save anyways when we go to sleep
// We just changed something important about the user, store our DB
@@ -400,7 +400,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
}
default: {
notifyObservers(); //If the node counts have changed, notify observers
notifyObservers(); // If the node counts have changed, notify observers
}
}
}

View File

@@ -28,7 +28,7 @@ class NodeDB
NodeInfo *nodes;
pb_size_t *numNodes;
int readPointer = 0;
uint32_t readPointer = 0;
public:
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled

View File

@@ -12,6 +12,18 @@ RF95Interface::RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOL
// FIXME - we assume devices never get destroyed
}
/** Some boards require GPIO control of tx vs rx paths */
void RF95Interface::setTransmitEnable(bool txon)
{
#ifdef RF95_TXEN
digitalWrite(RF95_TXEN, txon ? 1 : 0);
#endif
#ifdef RF95_RXEN
digitalWrite(RF95_RXEN, txon ? 0 : 1);
#endif
}
/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
@@ -24,8 +36,30 @@ bool RF95Interface::init()
power = MAX_POWER;
iface = lora = new RadioLibRF95(&module);
#ifdef RF95_TCXO
pinMode(RF95_TCXO, OUTPUT);
digitalWrite(RF95_TCXO, 1);
#endif
/*
#define RF95_TXEN (22) // If defined, this pin should be set high prior to transmit (controls an external analog switch)
#define RF95_RXEN (23) // If defined, this pin should be set high prior to receive (controls an external analog switch)
*/
#ifdef RF95_TXEN
pinMode(RF95_TXEN, OUTPUT);
digitalWrite(RF95_TXEN, 0);
#endif
#ifdef RF95_RXEN
pinMode(RF95_RXEN, OUTPUT);
digitalWrite(RF95_RXEN, 1);
#endif
setTransmitEnable(false);
int res = lora->begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength);
DEBUG_MSG("LORA init result %d\n", res);
DEBUG_MSG("RF95 init result %d\n", res);
if (res == ERR_NONE)
res = lora->setCRC(SX126X_LORA_CRC_ON);
@@ -98,8 +132,18 @@ void RF95Interface::setStandby()
completeSending(); // If we were sending, not anymore
}
/** We override to turn on transmitter power as needed.
*/
void RF95Interface::configHardwareForSend()
{
setTransmitEnable(true);
RadioLibInterface::configHardwareForSend();
}
void RF95Interface::startReceive()
{
setTransmitEnable(false);
setStandby();
int err = lora->startReceive();
assert(err == ERR_NONE);

View File

@@ -52,4 +52,13 @@ class RF95Interface : public RadioLibInterface
virtual void addReceiveMetadata(MeshPacket *mp);
virtual void setStandby();
/**
* We override to turn on transmitter power as needed.
*/
virtual void configHardwareForSend();
private:
/** Some boards require GPIO control of tx vs rx paths */
void setTransmitEnable(bool txon);
};

View File

@@ -161,6 +161,11 @@ class SimRadio : public RadioInterface
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init() { return true; }
/// Apply any radio provisioning changes
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool reconfigure() { return true; }
};
/// Debug printing for packets

View File

@@ -3,6 +3,10 @@
#define RF95_CHIP_VERSION 0x12
#define RF95_ALT_VERSION 0x11 // Supposedly some versions of the chip have id 0x11
// From datasheet but radiolib doesn't know anything about this
#define SX127X_REG_TCXO 0x4B
RadioLibRF95::RadioLibRF95(Module *mod) : SX1278(mod) {}
int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit,
@@ -18,6 +22,11 @@ int16_t RadioLibRF95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_
state = config();
RADIOLIB_ASSERT(state);
#ifdef RF95_TCXO
state = _mod->SPIsetRegValue(SX127X_REG_TCXO, 0x10 | _mod->SPIgetRegValue(SX127X_REG_TCXO));
RADIOLIB_ASSERT(state);
#endif
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);

View File

@@ -24,8 +24,8 @@
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
// static MemoryDynamic<MeshPacket> staticPool;
// static MemoryPool<MeshPacket> staticPool(MAX_PACKETS);
static MemoryDynamic<MeshPacket> staticPool;
Allocator<MeshPacket> &packetPool = staticPool;
@@ -36,7 +36,7 @@ Allocator<MeshPacket> &packetPool = staticPool;
*/
Router::Router() : fromRadioQueue(MAX_RX_FROMRADIO)
{
// This is called pre main(), don't touch anything here, the following code is not safe
// 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));

View File

@@ -33,7 +33,7 @@ bool SX1262Interface::init()
if (power > 22) // This chip has lower power limits than some
power = 22;
int res = lora.begin(freq, bw, sf, cr, syncWord, power, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO);
DEBUG_MSG("LORA init result %d\n", res);
DEBUG_MSG("SX1262 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
@@ -119,8 +119,7 @@ void SX1262Interface::addReceiveMetadata(MeshPacket *mp)
mp->rx_snr = lora.getSNR();
}
/** start an immediate transmit
* We override to turn on transmitter power as needed.
/** We override to turn on transmitter power as needed.
*/
void SX1262Interface::configHardwareForSend()
{

View File

@@ -45,6 +45,10 @@ typedef struct _ChannelSettings {
ChannelSettings_ModemConfig modem_config;
ChannelSettings_psk_t psk;
char name[12];
uint32_t bandwidth;
uint32_t spread_factor;
uint32_t coding_rate;
uint32_t channel_num;
} ChannelSettings;
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
@@ -241,7 +245,7 @@ typedef struct _ToRadio {
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, ""}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
@@ -257,7 +261,7 @@ typedef struct _ToRadio {
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, ""}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, 0, {0, 0, 0}}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
@@ -271,6 +275,10 @@ typedef struct _ToRadio {
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSettings_tx_power_tag 1
#define ChannelSettings_modem_config_tag 3
#define ChannelSettings_bandwidth_tag 6
#define ChannelSettings_spread_factor_tag 7
#define ChannelSettings_coding_rate_tag 8
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5
#define Data_typ_tag 1
@@ -436,7 +444,11 @@ X(a, STATIC, SINGULAR, BOOL, want_ack, 11)
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \
X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \
X(a, STATIC, SINGULAR, BYTES, psk, 4) \
X(a, STATIC, SINGULAR, STRING, name, 5)
X(a, STATIC, SINGULAR, STRING, name, 5) \
X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \
X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \
X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \
X(a, STATIC, SINGULAR, UINT32, channel_num, 9)
#define ChannelSettings_CALLBACK NULL
#define ChannelSettings_DEFAULT NULL
@@ -597,12 +609,12 @@ extern const pb_msgdesc_t ManufacturingData_msg;
#define RouteDiscovery_size 88
#define SubPacket_size 274
#define MeshPacket_size 313
#define ChannelSettings_size 60
#define RadioConfig_size 253
#define ChannelSettings_size 84
#define RadioConfig_size 277
#define RadioConfig_UserPreferences_size 188
#define NodeInfo_size 132
#define MyNodeInfo_size 110
#define DeviceState_size 5403
#define DeviceState_size 5427
#define DebugString_size 258
#define FromRadio_size 322
#define ToRadio_size 316

View File

@@ -0,0 +1,601 @@
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h"
#include "NimbleBluetoothAPI.h"
#include "NodeDB.h" // FIXME - we shouldn't really douch this here - we are using it only because we currently do wifi setup when ble gets turned on
#include "PhoneAPI.h"
#include "PowerFSM.h"
#include "WiFi.h"
#include "configuration.h"
#include "esp_bt.h"
#include "host/util/util.h"
#include "main.h"
#include "nimble/NimbleDefs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include <Arduino.h>
static bool pinShowing;
static void startCb(uint32_t pin)
{
pinShowing = true;
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen.startBluetoothPinScreen(pin);
};
static void stopCb()
{
if (pinShowing) {
pinShowing = false;
screen.stopBluetoothPinScreen();
}
};
static uint8_t own_addr_type;
// Force arduino to keep ble data around
extern "C" bool btInUse()
{
return true;
}
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level)
{
// FIXME
}
void deinitBLE()
{
// DEBUG_MSG("Shutting down bluetooth\n");
// ble_gatts_show_local();
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
auto ret = nimble_port_stop();
assert(ret == ESP_OK);
nimble_port_deinit(); // teardown nimble datastructures
// DEBUG_MSG("BLE port_deinit done\n");
ret = esp_nimble_hci_and_controller_deinit();
assert(ret == ESP_OK);
// DEBUG_MSG("BLE task exiting\n");
DEBUG_MSG("Done shutting down bluetooth\n");
}
void loopBLE()
{
// FIXME
}
extern "C" void ble_store_config_init(void);
/// Print a macaddr - bytes are sometimes stored in reverse order
static void print_addr(const uint8_t v[], bool isReversed = true)
{
const int macaddrlen = 6;
for (int i = 0; i < macaddrlen; i++) {
DEBUG_MSG("%02x%c", v[isReversed ? macaddrlen - i : i], (i == macaddrlen - 1) ? '\n' : ':');
}
}
/**
* Logs information about a connection to the console.
*/
static void print_conn_desc(struct ble_gap_conn_desc *desc)
{
DEBUG_MSG("handle=%d our_ota_addr_type=%d our_ota_addr=", desc->conn_handle, desc->our_ota_addr.type);
print_addr(desc->our_ota_addr.val);
DEBUG_MSG(" our_id_addr_type=%d our_id_addr=", desc->our_id_addr.type);
print_addr(desc->our_id_addr.val);
DEBUG_MSG(" peer_ota_addr_type=%d peer_ota_addr=", desc->peer_ota_addr.type);
print_addr(desc->peer_ota_addr.val);
DEBUG_MSG(" peer_id_addr_type=%d peer_id_addr=", desc->peer_id_addr.type);
print_addr(desc->peer_id_addr.val);
DEBUG_MSG(" conn_itvl=%d conn_latency=%d supervision_timeout=%d "
"encrypted=%d authenticated=%d bonded=%d\n",
desc->conn_itvl, desc->conn_latency, desc->supervision_timeout, desc->sec_state.encrypted,
desc->sec_state.authenticated, desc->sec_state.bonded);
}
static void advertise();
/**
* The nimble host executes this callback when a GAP event occurs. The
* application associates a GAP event callback with each connection that forms.
* bleprph uses the same callback for all connections.
*
* @param event The type of event being signalled.
* @param ctxt Various information pertaining to the event.
* @param arg Application-specified argument; unused by
* bleprph.
*
* @return 0 if the application successfully handled the
* event; nonzero on failure. The semantics
* of the return code is specific to the
* particular GAP event being signalled.
*/
static int gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed. */
DEBUG_MSG("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
if (event->connect.status == 0) {
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
curConnectionHandle = event->connect.conn_handle;
}
DEBUG_MSG("\n");
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
advertise();
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
DEBUG_MSG("disconnect; reason=%d ", event->disconnect.reason);
print_conn_desc(&event->disconnect.conn);
DEBUG_MSG("\n");
curConnectionHandle = -1;
/* Connection terminated; resume advertising. */
advertise();
return 0;
case BLE_GAP_EVENT_CONN_UPDATE:
/* The central has updated the connection parameters. */
DEBUG_MSG("connection updated; status=%d ", event->conn_update.status);
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
DEBUG_MSG("\n");
return 0;
case BLE_GAP_EVENT_ADV_COMPLETE:
DEBUG_MSG("advertise complete; reason=%d", event->adv_complete.reason);
advertise();
return 0;
case BLE_GAP_EVENT_ENC_CHANGE:
/* Encryption has been enabled or disabled for this connection. */
DEBUG_MSG("encryption change event; status=%d ", event->enc_change.status);
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
DEBUG_MSG("\n");
// Remove our custom PIN request screen.
stopCb();
return 0;
case BLE_GAP_EVENT_SUBSCRIBE:
DEBUG_MSG("subscribe event; conn_handle=%d attr_handle=%d "
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
event->subscribe.conn_handle, event->subscribe.attr_handle, event->subscribe.reason,
event->subscribe.prev_notify, event->subscribe.cur_notify, event->subscribe.prev_indicate,
event->subscribe.cur_indicate);
return 0;
case BLE_GAP_EVENT_MTU:
DEBUG_MSG("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id,
event->mtu.value);
return 0;
case BLE_GAP_EVENT_REPEAT_PAIRING:
DEBUG_MSG("repeat pairing event; conn_handle=%d "
"cur_key_sz=%d cur_auth=%d cur_sc=%d "
"new_key_sz=%d new_auth=%d new_sc=%d "
"new_bonding=%d\n",
event->repeat_pairing.conn_handle, event->repeat_pairing.cur_key_size, event->repeat_pairing.cur_authenticated,
event->repeat_pairing.cur_sc, event->repeat_pairing.new_key_size, event->repeat_pairing.new_authenticated,
event->repeat_pairing.new_sc, event->repeat_pairing.new_bonding);
/* We already have a bond with the peer, but it is attempting to
* establish a new secure link. This app sacrifices security for
* convenience: just throw away the old bond and accept the new link.
*/
/* Delete the old bond. */
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
assert(rc == 0);
ble_store_util_delete_peer(&desc.peer_id_addr);
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
* continue with the pairing operation.
*/
return BLE_GAP_REPEAT_PAIRING_RETRY;
case BLE_GAP_EVENT_PASSKEY_ACTION:
DEBUG_MSG("PASSKEY_ACTION_EVENT started \n");
struct ble_sm_io pkey = {0};
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
pkey.action = event->passkey.params.action;
pkey.passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", pkey.passkey);
startCb(pkey.passkey);
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
DEBUG_MSG("ble_sm_inject_io result: %d\n", rc);
} else {
DEBUG_MSG("FIXME - unexpected auth type %d\n", event->passkey.params.action);
}
return 0;
}
return 0;
}
/**
* Enables advertising with the following parameters:
* o General discoverable mode.
* o Undirected connectable mode.
*/
static void advertise(void)
{
/**
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info).
* o Advertising tx power.
* o Device name.
* o 16-bit service UUIDs (alert notifications).
*/
struct ble_hs_adv_fields adv_fields;
memset(&adv_fields, 0, sizeof adv_fields);
/* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported).
*/
adv_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
/* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assigning the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
adv_fields.tx_pwr_lvl_is_present = 1;
adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
const char *name = ble_svc_gap_device_name();
adv_fields.name = (uint8_t *)name;
adv_fields.name_len = strlen(name);
adv_fields.name_is_complete = 1;
auto rc = ble_gap_adv_set_fields(&adv_fields);
if (rc != 0) {
DEBUG_MSG("error setting advertisement data; rc=%d\n", rc);
return;
}
// add scan response fields
struct ble_hs_adv_fields scan_fields;
memset(&scan_fields, 0, sizeof scan_fields);
scan_fields.uuids128 = const_cast<ble_uuid128_t *>(&mesh_service_uuid);
scan_fields.num_uuids128 = 1;
scan_fields.uuids128_is_complete = 1;
rc = ble_gap_adv_rsp_set_fields(&scan_fields);
if (rc != 0) {
DEBUG_MSG("error setting scan response data; rc=%d\n", rc);
return;
}
/* Begin advertising. */
struct ble_gap_adv_params adv_params;
memset(&adv_params, 0, sizeof adv_params);
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
// FIXME - use RPA for first parameter
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, gap_event, NULL);
if (rc != 0) {
DEBUG_MSG("error enabling advertisement; rc=%d\n", rc);
return;
}
}
static void on_reset(int reason)
{
// 19 == BLE_HS_ETIMEOUT_HCI
DEBUG_MSG("Resetting state; reason=%d\n", reason);
}
static void on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
DEBUG_MSG("error determining address type; rc=%d\n", rc);
return;
}
/* Printing ADDR */
uint8_t addr_val[6] = {0};
int isPrivate = 0;
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, &isPrivate);
assert(rc == 0);
DEBUG_MSG("Addr type %d, Private=%d, Device Address: ", own_addr_type, isPrivate);
print_addr(addr_val);
DEBUG_MSG("\n");
/* Begin advertising. */
advertise();
}
static void ble_host_task(void *param)
{
DEBUG_MSG("BLE task running\n");
nimble_port_run(); // This function will return only when nimble_port_stop() is executed.
// DEBUG_MSG("BLE run complete\n");
nimble_port_freertos_deinit(); // delete the task
}
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
DEBUG_MSG("registered service %s with handle=%d\n", ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
DEBUG_MSG("registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), ctxt->chr.def_handle, ctxt->chr.val_handle);
if (ctxt->chr.chr_def->uuid == &fromnum_uuid.u) {
fromNumValHandle = ctxt->chr.val_handle;
DEBUG_MSG("FromNum handle %d\n", fromNumValHandle);
}
if (ctxt->chr.chr_def->uuid == &update_result_uuid.u) {
updateResultHandle = ctxt->chr.val_handle;
DEBUG_MSG("update result handle %d\n", updateResultHandle);
}
break;
case BLE_GATT_REGISTER_OP_DSC:
DEBUG_MSG("registering descriptor %s with handle=%d\n", ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
/**
* A helper function that implements simple read and write handling for a uint32_t
*
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
* will be written into the variable.
*/
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt)
{
uint8_t le[4];
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
DEBUG_MSG("BLE reading a uint32\n");
put_le32(le, *v);
auto rc = os_mbuf_append(ctxt->om, le, sizeof(le));
assert(rc == 0);
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(ctxt->om, le, sizeof(le), &len);
assert(rc == 0);
if (len < sizeof(le)) {
DEBUG_MSG("Error: wrongsized write32\n");
*v = 0;
} else {
*v = get_le32(le);
DEBUG_MSG("BLE writing a uint32\n");
}
} else {
DEBUG_MSG("Unexpected readwrite32 op\n");
return BLE_ATT_ERR_UNLIKELY;
}
return 0; // success
}
/**
* A helper for readwrite access to an array of bytes (with no endian conversion)
*/
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt)
{
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
DEBUG_MSG("BLE reading bytes\n");
auto rc = os_mbuf_append(ctxt->om, v, vlen);
assert(rc == 0);
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(ctxt->om, v, vlen, &len);
assert(rc == 0);
if (len < vlen)
DEBUG_MSG("Error: wrongsized write\n");
else {
DEBUG_MSG("BLE writing bytes\n");
}
} else {
DEBUG_MSG("Unexpected readwrite8 op\n");
return BLE_ATT_ERR_UNLIKELY;
}
return 0; // success
}
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{
auto isFirstTime = !bluetoothPhoneAPI;
DEBUG_MSG("Starting bluetooth\n");
if (isFirstTime) {
bluetoothPhoneAPI = new BluetoothPhoneAPI();
bluetoothPhoneAPI->init();
}
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
auto res = esp_nimble_hci_and_controller_init(); // : esp_nimble_hci_init();
// DEBUG_MSG("BLE result %d\n", res);
assert(res == ESP_OK);
nimble_port_init();
ble_att_set_preferred_mtu(512);
res = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers
assert(res == ESP_OK);
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = on_reset;
ble_hs_cfg.sync_cb = on_sync;
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY;
ble_hs_cfg.sm_bonding = 1;
ble_hs_cfg.sm_mitm = 1;
ble_hs_cfg.sm_sc = 1;
// per https://github.com/espressif/esp-idf/issues/5530#issuecomment-652933685
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC;
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC;
// add standard GAP services
ble_svc_gap_init();
ble_svc_gatt_init();
res = ble_gatts_count_cfg(gatt_svr_svcs); // assigns handles? see docstring for note about clearing the handle list
// before calling SLEEP SUPPORT
assert(res == 0);
res = ble_gatts_add_svcs(gatt_svr_svcs);
assert(res == 0);
reinitUpdateService();
/* Set the default device name. */
res = ble_svc_gap_device_name_set(getDeviceName());
assert(res == 0);
/* XXX Need to have template for store */
ble_store_config_init();
nimble_port_freertos_init(ble_host_task);
}
void initWifi()
{
// Note: Wifi is not yet supported ;-)
strcpy(radioConfig.preferences.wifi_ssid, "");
strcpy(radioConfig.preferences.wifi_password, "");
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);
if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) {
DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str());
} else {
DEBUG_MSG("Started Joining WIFI\n");
}
}
}
} else
DEBUG_MSG("Not using WIFI\n");
}
bool bluetoothOn;
// Enable/disable bluetooth.
void setBluetoothEnable(bool on)
{
if (on != bluetoothOn) {
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
bluetoothOn = on;
if (on) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
initWifi();
} else {
// We have to totally teardown our bluetooth objects to prevent leaks
deinitBLE();
WiFi.mode(WIFI_MODE_NULL); // shutdown wifi
Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_stop() );
// heap_trace_dump();
}
}
}
#if 0
static BLECharacteristic *batteryLevelC;
/**
* Create a battery level service
*/
BLEService *createBatteryService(BLEServer *server)
{
// Create the BLE Service
BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F));
batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL),
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100");
batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
// I don't think we need to advertise this? and some phones only see the first thing advertised anyways...
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery->start();
return pBattery;
}
/**
* Update the battery level we are currently telling clients.
* level should be a pct between 0 and 100
*/
void updateBatteryLevel(uint8_t level)
{
if (batteryLevelC) {
DEBUG_MSG("set BLE battery level %u\n", level);
batteryLevelC->setValue(&level, 1);
batteryLevelC->notify();
}
}
// Note: these callbacks might be coming in from a different thread.
BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION),
optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
#endif

View File

@@ -0,0 +1,30 @@
#pragma once
#include <Arduino.h>
#include <functional>
/// We only allow one BLE connection at a time
extern int16_t curConnectionHandle;
// TODO(girts): create a class for the bluetooth utils helpers?
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
using StopBluetoothPinScreenCallback = std::function<void(void)>;
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level);
void deinitBLE();
void loopBLE();
void reinitBluetooth();
/**
* A helper function that implements simple read and write handling for a uint32_t
*
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
* will be written into the variable.
*/
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt);
/**
* A helper for readwrite access to an array of bytes (with no endian conversion)
*/
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt);

View File

@@ -0,0 +1,68 @@
#include "NimbleBluetoothAPI.h"
#include "PhoneAPI.h"
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include "nimble/NimbleDefs.h"
#include <Arduino.h>
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
static uint8_t trBytes[FromRadio_size < ToRadio_size ? ToRadio_size : FromRadio_size];
static uint32_t fromNum;
uint16_t fromNumValHandle;
/// We only allow one BLE connection at a time
int16_t curConnectionHandle = -1;
PhoneAPI *bluetoothPhoneAPI;
void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
fromNum = fromRadioNum;
if (curConnectionHandle >= 0 && fromNumValHandle) {
DEBUG_MSG("BLE notify fromNum\n");
auto res = ble_gattc_notify(curConnectionHandle, fromNumValHandle);
assert(res == 0);
} else {
DEBUG_MSG("No BLE notify\n");
}
}
int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
auto om = ctxt->om;
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(om, trBytes, sizeof(trBytes), &len);
if (rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
/// DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len);
bluetoothPhoneAPI->handleToRadio(trBytes, len);
return 0;
}
int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes);
DEBUG_MSG("BLE fromRadio called omlen=%d, ourlen=%d\n", OS_MBUF_PKTLEN(ctxt->om),
numBytes); // the normal case has omlen 1 here
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty
auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes);
assert(rc == 0);
return 0; // success
}
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite32le(&fromNum, ctxt);
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "PhoneAPI.h"
extern uint16_t fromNumValHandle;
class BluetoothPhoneAPI : public PhoneAPI
{
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum);
};
extern PhoneAPI *bluetoothPhoneAPI;

46
src/nimble/NimbleDefs.c Normal file
View File

@@ -0,0 +1,46 @@
#include "NimbleDefs.h"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
const ble_uuid128_t mesh_service_uuid =
BLE_UUID128_INIT(0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b);
static const ble_uuid128_t toradio_uuid =
BLE_UUID128_INIT(0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1, 0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7);
static const ble_uuid128_t fromradio_uuid =
BLE_UUID128_INIT(0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b);
const ble_uuid128_t fromnum_uuid =
BLE_UUID128_INIT(0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed);
const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/*** Service: Security test. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &mesh_service_uuid.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
.uuid = &toradio_uuid.u,
.access_cb = toradio_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &fromradio_uuid.u,
.access_cb = fromradio_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN,
},
{
.uuid = &fromnum_uuid.u,
.access_cb = fromnum_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
},
{
0, /* No more characteristics in this service. */
}},
},
{
0, /* No more services. */
},
};

32
src/nimble/NimbleDefs.h Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
// Keep nimble #defs from messing up the build
#ifndef max
#define max max
#define min min
#endif
#include "esp_nimble_hci.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include <Arduino.h>
#ifdef __cplusplus
extern "C" {
#endif
int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
extern const struct ble_gatt_svc_def gatt_svr_svcs[];
extern const ble_uuid128_t mesh_service_uuid, fromnum_uuid;
#ifdef __cplusplus
};
#endif

View File

@@ -1,22 +1,41 @@
#include "NRF52Bluetooth.h"
#include "BluetoothCommon.h"
#include "configuration.h"
#include "main.h"
#include <bluefruit.h>
/* HRM Service Definitions
* Heart Rate Monitor Service: 0x180D
* Heart Rate Measurement Char: 0x2A37
* Body Sensor Location Char: 0x2A38
*/
BLEService hrms = BLEService(UUID16_SVC_HEART_RATE);
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);
BLEDis bledis; // DIS (Device Information Service) helper class instance
BLEBas blebas; // BAS (Battery Service) helper class instance
BLEDfu bledfu; // DFU software update helper service
uint8_t bps = 0;
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
static BLEDis bledis; // DIS (Device Information Service) helper class instance
static BLEBas blebas; // BAS (Battery Service) helper class instance
static BLEDfu bledfu; // DFU software update helper service
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
static uint8_t fromRadioBytes[FromRadio_size];
static uint8_t toRadioBytes[ToRadio_size];
class BluetoothPhoneAPI : public PhoneAPI
{
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
DEBUG_MSG("BLE notify fromNum\n");
fromNum.notify32(fromRadioNum);
}
};
static BluetoothPhoneAPI *bluetoothPhoneAPI;
void connect_callback(uint16_t conn_handle)
{
@@ -26,7 +45,7 @@ void connect_callback(uint16_t conn_handle)
char central_name[32] = {0};
connection->getPeerName(central_name, sizeof(central_name));
DEBUG_MSG("Connected to %s\n", central_name);
DEBUG_MSG("BLE Connected to %s\n", central_name);
}
/**
@@ -37,9 +56,8 @@ void connect_callback(uint16_t conn_handle)
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void)conn_handle;
(void)reason;
DEBUG_MSG("Disconnected, reason = 0x%x\n", reason);
DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason);
}
void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
@@ -49,11 +67,11 @@ void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_valu
// Check the characteristic this CCCD update is associated with in case
// this handler is used for multiple CCCD records.
if (chr->uuid == hrmc.uuid) {
if (chr->uuid == fromNum.uuid) {
if (chr->notifyEnabled(conn_hdl)) {
DEBUG_MSG("Heart Rate Measurement 'Notify' enabled\n");
DEBUG_MSG("fromNum 'Notify' enabled\n");
} else {
DEBUG_MSG("Heart Rate Measurement 'Notify' disabled\n");
DEBUG_MSG("fromNum 'Notify' disabled\n");
}
}
}
@@ -62,13 +80,15 @@ void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include HRM Service UUID
Bluefruit.Advertising.addService(hrms);
// IncludeService UUID
// Bluefruit.ScanResponse.addService(meshBleService);
Bluefruit.ScanResponse.addTxPower();
Bluefruit.ScanResponse.addName();
// Include Name
Bluefruit.Advertising.addName();
// Bluefruit.Advertising.addName();
Bluefruit.Advertising.addService(meshBleService);
/* Start Advertising
* - Enable auto advertising if disconnected
@@ -82,74 +102,105 @@ void startAdv(void)
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
}
void setupHRM(void)
// Just ack that the caller is allowed to read
static void authorizeRead(uint16_t conn_hdl)
{
// Configure the Heart Rate Monitor service
// See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
// Supported Characteristics:
// Name UUID Requirement Properties
// ---------------------------- ------ ----------- ----------
// Heart Rate Measurement 0x2A37 Mandatory Notify
// Body Sensor Location 0x2A38 Optional Read
// Heart Rate Control Point 0x2A39 Conditional Write <-- Not used here
hrms.begin();
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ};
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
}
/**
* client is starting read, pull the bytes from our API class
*/
void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
{
if (request->offset == 0) {
// If the read is long, we will get multiple authorize invocations - we only populate data on the first
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
// DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes);
// if (numBytes >= 2) DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]);
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty
fromRadio.write(fromRadioBytes, numBytes);
} else {
// DEBUG_MSG("Ignoring successor read\n");
}
authorizeRead(conn_hdl);
}
void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
{
DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len);
bluetoothPhoneAPI->handleToRadio(data, len);
}
/**
* client is starting read, pull the bytes from our API class
*/
void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
{
DEBUG_MSG("fromNumAuthorizeCb\n");
authorizeRead(conn_hdl);
}
void setupMeshService(void)
{
bluetoothPhoneAPI = new BluetoothPhoneAPI();
bluetoothPhoneAPI->init();
meshBleService.begin();
// Note: You must call .begin() on the BLEService before calling .begin() on
// any characteristic(s) within that service definition.. Calling .begin() on
// a BLECharacteristic will cause it to be added to the last BLEService that
// was 'begin()'ed!
// Configure the Heart Rate Measurement characteristic
// See:
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
// Properties = Notify
// Min Len = 1
// Max Len = 8
// B0 = UINT8 - Flag (MANDATORY)
// b5:7 = Reserved
// b4 = RR-Internal (0 = Not present, 1 = Present)
// b3 = Energy expended status (0 = Not present, 1 = Present)
// b1:2 = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and
// detected) b0 = Value format (0 = UINT8, 1 = UINT16)
// B1 = UINT8 - 8-bit heart rate measurement value in BPM
// B2:3 = UINT16 - 16-bit heart rate measurement value in BPM
// B4:5 = UINT16 - Energy expended in joules
// B6:7 = UINT16 - RR Internal (1/1024 second resolution)
hrmc.setProperties(CHR_PROPS_NOTIFY);
hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
hrmc.setFixedLen(2);
hrmc.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
hrmc.begin();
uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and detected
hrmc.write(hrmdata, 2);
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
fromNum.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!!
fromNum.setFixedLen(
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
fromNum.setMaxLen(4);
fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates
// We don't yet need to hook the fromNum auth callback
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
fromNum.write32(0); // Provide default fromNum of 0
fromNum.begin();
// uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and
// detected
// hrmc.write(hrmdata, 2);
// Configure the Body Sensor Location characteristic
// See:
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
// Properties = Read
// Min Len = 1
// Max Len = 1
// B0 = UINT8 - Body Sensor Location
// 0 = Other
// 1 = Chest
// 2 = Wrist
// 3 = Finger
// 4 = Hand
// 5 = Ear Lobe
// 6 = Foot
// 7:255 = Reserved
bslc.setProperties(CHR_PROPS_READ);
bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
bslc.setFixedLen(1);
bslc.begin();
bslc.write8(2); // Set the characteristic to 'Wrist' (2)
fromRadio.setProperties(CHR_PROPS_READ);
fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this!
fromRadio.setMaxLen(sizeof(fromRadioBytes));
fromRadio.setReadAuthorizeCallback(
fromRadioAuthorizeCb,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
// for two copies
fromRadio.begin();
toRadio.setProperties(CHR_PROPS_WRITE);
toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this!
toRadio.setFixedLen(0);
toRadio.setMaxLen(512);
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
toRadio.setWriteCallback(
toRadioWriteCb,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
toRadio.begin();
}
// FIXME, turn off soft device access for debugging
static bool isSoftDeviceAllowed = false;
static bool isSoftDeviceAllowed = true;
void NRF52Bluetooth::setup()
{
@@ -158,7 +209,7 @@ void NRF52Bluetooth::setup()
Bluefruit.begin();
// Set the advertised device name (keep it short!)
Bluefruit.setName(getDeviceName()); // FIXME
Bluefruit.setName(getDeviceName());
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnectCallback(connect_callback);
@@ -166,21 +217,22 @@ void NRF52Bluetooth::setup()
// Configure and Start the Device Information Service
DEBUG_MSG("Configuring the Device Information Service\n");
bledis.setManufacturer("meshtastic.org");
bledis.setModel("NRF52-meshtastic"); // FIXME
bledis.setManufacturer(HW_VENDOR);
bledis.setModel(optstr(HW_VERSION));
bledis.setFirmwareRev(optstr(APP_VERSION));
bledis.begin();
// Start the BLE Battery Service and set it to 100%
DEBUG_MSG("Configuring the Battery Service\n");
blebas.begin();
blebas.write(42); // FIXME, report real power levels
blebas.write(0); // Unknown battery level for now
bledfu.begin(); // Install the DFU helper
// Setup the Heart Rate Monitor service using
// BLEService and BLECharacteristic classes
DEBUG_MSG("Configuring the Heart Rate Monitor Service\n");
setupHRM();
DEBUG_MSG("Configuring the Mesh bluetooth service\n");
setupMeshService();
// Supposedly debugging works with soft device if you disable advertising
if (isSoftDeviceAllowed) {
@@ -192,56 +244,8 @@ void NRF52Bluetooth::setup()
}
}
/*
void loop()
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level)
{
digitalToggle(LED_RED);
if ( Bluefruit.connected() ) {
uint8_t hrmdata[2] = { 0b00000110, bps++ }; // Sensor connected, increment BPS value
// Note: We use .notify instead of .write!
// If it is connected but CCCD is not enabled
// The characteristic's value is still updated although notification is not sent
if ( hrmc.notify(hrmdata, sizeof(hrmdata)) ){
Serial.print("Heart Rate Measurement updated to: "); Serial.println(bps);
}else{
Serial.println("ERROR: Notify not set in the CCCD or not connected!");
}
}
// Only send update once per second
delay(1000);
}
*/
/*
examples of advanced characteristics. use setReadAuthorizeCallback to prepare data for reads by others
err_t BLEDfu::begin(void)
{
// Invoke base class begin()
VERIFY_STATUS( BLEService::begin() );
// No need to keep packet & revision characteristics
BLECharacteristic chr_packet(UUID128_CHR_DFU_PACKET);
chr_packet.setTempMemory();
chr_packet.setProperties(CHR_PROPS_WRITE_WO_RESP);
chr_packet.setMaxLen(20);
VERIFY_STATUS( chr_packet.begin() );
_chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_NOTIFY);
_chr_control.setMaxLen(23);
_chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb);
VERIFY_STATUS( _chr_control.begin() );
BLECharacteristic chr_revision(UUID128_CHR_DFU_REVISON);
chr_revision.setTempMemory();
chr_revision.setProperties(CHR_PROPS_READ);
chr_revision.setFixedLen(2);
VERIFY_STATUS( chr_revision.begin());
chr_revision.write16(DFU_REV_APPMODE);
return ERROR_NONE;
}
*/
blebas.write(level);
}

31
src/nrf52/alloc.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include "rtos.h"
#include <assert.h>
#include <stdlib.h>
/**
* Custom new/delete to panic if out out memory
*/
void *operator new(size_t size)
{
auto p = rtos_malloc(size);
assert(p);
return p;
}
void *operator new[](size_t size)
{
auto p = rtos_malloc(size);
assert(p);
return p;
}
void operator delete(void *ptr)
{
rtos_free(ptr);
}
void operator delete[](void *ptr)
{
rtos_free(ptr);
}

View File

@@ -5,47 +5,49 @@
enum { r0, r1, r2, r3, r12, lr, pc, psr };
// we can't use the regular DEBUG_MSG for these crash dumps because it depends on threading still being running. Instead use the
// segger in memory tool
#define FAULT_MSG(...) SEGGER_MSG(__VA_ARGS__)
// Per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html
static void printUsageErrorMsg(uint32_t cfsr)
{
DEBUG_MSG("Usage fault: ");
FAULT_MSG("Usage fault: ");
cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb
if ((cfsr & (1 << 9)) != 0)
DEBUG_MSG("Divide by zero\n");
FAULT_MSG("Divide by zero\n");
if ((cfsr & (1 << 8)) != 0)
DEBUG_MSG("Unaligned\n");
FAULT_MSG("Unaligned\n");
}
static void printBusErrorMsg(uint32_t cfsr)
{
DEBUG_MSG("Usage fault: ");
FAULT_MSG("Bus fault: ");
cfsr >>= SCB_CFSR_BUSFAULTSR_Pos; // right shift to lsb
if ((cfsr & (1 << 0)) != 0)
DEBUG_MSG("Instruction bus error\n");
FAULT_MSG("Instruction bus error\n");
if ((cfsr & (1 << 1)) != 0)
DEBUG_MSG("Precise data bus error\n");
FAULT_MSG("Precise data bus error\n");
if ((cfsr & (1 << 2)) != 0)
DEBUG_MSG("Imprecise data bus error\n");
FAULT_MSG("Imprecise data bus error\n");
}
static void printMemErrorMsg(uint32_t cfsr)
{
DEBUG_MSG("Usage fault: ");
FAULT_MSG("Memory fault: ");
cfsr >>= SCB_CFSR_MEMFAULTSR_Pos; // right shift to lsb
if ((cfsr & (1 << 0)) != 0)
DEBUG_MSG("Instruction access violation\n");
FAULT_MSG("Instruction access violation\n");
if ((cfsr & (1 << 1)) != 0)
DEBUG_MSG("Data access violation\n");
FAULT_MSG("Data access violation\n");
}
static void HardFault_Impl(uint32_t stack[])
extern "C" void HardFault_Impl(uint32_t stack[])
{
DEBUG_MSG("In Hard Fault Handler\n");
DEBUG_MSG("SCB->HFSR = 0x%08lx\n", SCB->HFSR);
FAULT_MSG("Hard Fault occurred! SCB->HFSR = 0x%08lx\n", SCB->HFSR);
if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) {
DEBUG_MSG("Forced Hard Fault\n");
DEBUG_MSG("SCB->CFSR = 0x%08lx\n", SCB->CFSR);
FAULT_MSG("Forced Hard Fault: SCB->CFSR = 0x%08lx\n", SCB->CFSR);
if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) {
printUsageErrorMsg(SCB->CFSR);
@@ -57,21 +59,23 @@ static void HardFault_Impl(uint32_t stack[])
printMemErrorMsg(SCB->CFSR);
}
DEBUG_MSG("r0 = 0x%08lx\n", stack[r0]);
DEBUG_MSG("r1 = 0x%08lx\n", stack[r1]);
DEBUG_MSG("r2 = 0x%08lx\n", stack[r2]);
DEBUG_MSG("r3 = 0x%08lx\n", stack[r3]);
DEBUG_MSG("r12 = 0x%08lx\n", stack[r12]);
DEBUG_MSG("lr = 0x%08lx\n", stack[lr]);
DEBUG_MSG("pc = 0x%08lx\n", stack[pc]);
DEBUG_MSG("psr = 0x%08lx\n", stack[psr]);
asm volatile("bkpt #01");
while (1)
;
FAULT_MSG("r0 = 0x%08lx\n", stack[r0]);
FAULT_MSG("r1 = 0x%08lx\n", stack[r1]);
FAULT_MSG("r2 = 0x%08lx\n", stack[r2]);
FAULT_MSG("r3 = 0x%08lx\n", stack[r3]);
FAULT_MSG("r12 = 0x%08lx\n", stack[r12]);
FAULT_MSG("lr = 0x%08lx\n", stack[lr]);
FAULT_MSG("pc = 0x%08lx\n", stack[pc]);
FAULT_MSG("psr = 0x%08lx\n", stack[psr]);
}
FAULT_MSG("Done with fault report - Waiting to reboot\n");
asm volatile("bkpt #01"); // Enter the debugger if one is connected
while (1)
;
}
void HardFault_Handler(void)
extern "C" void HardFault_Handler(void)
{
asm volatile(" mrs r0,msp\n"
" b HardFault_Impl \n");

View File

@@ -3,7 +3,11 @@
#include <assert.h>
#include <ble_gap.h>
#include <memory.h>
#include <nrf52840.h>
#include <stdio.h>
#ifdef NRF52840_XXAA
// #include <nrf52840.h>
#endif
// #define USE_SOFTDEVICE
@@ -49,6 +53,7 @@ void setBluetoothEnable(bool on)
if (on != bleOn) {
if (on) {
if (!nrf52Bluetooth) {
// DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
nrf52Bluetooth = new NRF52Bluetooth();
nrf52Bluetooth->setup();
}
@@ -59,6 +64,18 @@ void setBluetoothEnable(bool on)
}
}
/**
* Override printf to use the SEGGER output library
*/
int printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
va_end(args);
return res;
}
void nrf52Setup()
{
@@ -80,4 +97,5 @@ void nrf52Setup()
// ble_controller_rand_vector_get_blocking(&r, sizeof(r));
// randomSeed(r);
DEBUG_MSG("FIXME, call randomSeed\n");
// ::printf("TESTING PRINTF\n");
}

View File

@@ -5,9 +5,9 @@
#include "NodeDB.h"
#include "configuration.h"
#include "error.h"
#include "timing.h"
#include "main.h"
#include "target_specific.h"
#include "timing.h"
#ifndef NO_ESP32
#include "esp32/pm.h"
@@ -16,7 +16,7 @@
#include <driver/rtc_io.h>
#include <driver/uart.h>
#include "BluetoothUtil.h"
#include "nimble/BluetoothUtil.h"
esp_sleep_source_t wakeCause; // the reason we booted this time
#endif
@@ -294,18 +294,18 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
/**
* enable modem sleep mode as needed and available. Should lower our CPU current draw to an average of about 20mA.
*
*
* per https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/power_management.html
*
*
* supposedly according to https://github.com/espressif/arduino-esp32/issues/475 this is already done in arduino
*/
void enableModemSleep()
{
static esp_pm_config_esp32_t config; // filled with zeros because bss
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 = 20; // 10Mhz is minimum recommended
config.light_sleep_enable = false;
DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config));
config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
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));
}
#endif

View File

@@ -128,25 +128,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_WIRE_SDA (32 + 2)
#define PIN_WIRE_SCL (32)
// CUSTOM GPIOs the SX1262
#define SX1262_CS (10)
#define SX1262_DIO1 (20)
#define SX1262_DIO2 (26)
#define SX1262_BUSY (31) // Supposed to be P0.18 but because of reworks, now on P0.31 (18)
#define SX1262_RESET (17)
// #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)
#define ERC12864_RESET (32 + 6)
#define ERC12864_CD (32 + 9)
// L80 GPS
#define L80_PPS (28)
#define L80_RESET (29)
#define GPS_I2C_ADDR FIXME
#ifdef __cplusplus
}