diff --git a/bin/version.sh b/bin/version.sh
index 836fd5aa1..bf6adf67a 100644
--- a/bin/version.sh
+++ b/bin/version.sh
@@ -1,3 +1,3 @@
-export VERSION=0.8.2
\ No newline at end of file
+export VERSION=0.9.1
\ No newline at end of file
diff --git a/docs/software/TODO.md b/docs/software/TODO.md
index a66a41325..4a63cf040 100644
--- a/docs/software/TODO.md
+++ b/docs/software/TODO.md
@@ -2,14 +2,20 @@
You probably don't care about this section - skip to the next one.
-- brf52 ble
-- update protocol description per cyclomies
-- esp32 pairing
-- 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
+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
@@ -28,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)
diff --git a/docs/software/esp32-arduino-build-notes.md b/docs/software/esp32-arduino-build-notes.md
index b9fd68505..94b64f621 100644
--- a/docs/software/esp32-arduino-build-notes.md
+++ b/docs/software/esp32-arduino-build-notes.md
@@ -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
+
```
diff --git a/docs/software/read-error.txt b/docs/software/read-error.txt
new file mode 100644
index 000000000..bb060c0bf
--- /dev/null
+++ b/docs/software/read-error.txt
@@ -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()
diff --git a/platformio.ini b/platformio.ini
index 179fc8166..be9fcc5cf 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -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
@@ -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#b7f106cd11a04573b902228ea97025c8b5814dd9
+ 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]
@@ -154,10 +155,12 @@ 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} -
+ ${env.src_filter} - -
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1
diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp
new file mode 100644
index 000000000..a12a52cf9
--- /dev/null
+++ b/src/BluetoothCommon.cpp
@@ -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};
\ No newline at end of file
diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h
index 61a8fe5ea..26c7b2cef 100644
--- a/src/BluetoothCommon.h
+++ b/src/BluetoothCommon.h
@@ -12,5 +12,9 @@
#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);
\ No newline at end of file
diff --git a/src/error.h b/src/error.h
index 6adcc0ecb..6a2bae249 100644
--- a/src/error.h
+++ b/src/error.h
@@ -3,7 +3,7 @@
#include
/// 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);
diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp
index 3b455b56a..ea1a50ef4 100644
--- a/src/esp32/BluetoothSoftwareUpdate.cpp
+++ b/src/esp32/BluetoothSoftwareUpdate.cpp
@@ -1,48 +1,41 @@
-#include "BluetoothSoftwareUpdate.h"
-#include "BluetoothUtil.h"
-#include "CallbackCharacteristic.h"
-#include "RadioLibInterface.h"
-#include "configuration.h"
+#include
+
#include "../concurrency/LockGuard.h"
#include "../timing.h"
-#include
-#include
+#include "BluetoothSoftwareUpdate.h"
+#include "PowerFSM.h"
+#include "RadioLibInterface.h"
+#include "configuration.h"
+#include "nimble/BluetoothUtil.h"
+
#include
#include
-#include
-//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;
-}
\ No newline at end of file
diff --git a/src/esp32/BluetoothSoftwareUpdate.h b/src/esp32/BluetoothSoftwareUpdate.h
index 60517a7f2..c7a412d69 100644
--- a/src/esp32/BluetoothSoftwareUpdate.h
+++ b/src/esp32/BluetoothSoftwareUpdate.h
@@ -1,11 +1,26 @@
#pragma once
-#include
-#include
-#include
-#include
+#include "nimble/NimbleDefs.h"
-BLEService *createUpdateService(BLEServer *server, std::string hwVendor, std::string swVersion, std::string hwVersion);
+void reinitUpdateService();
-void destroyUpdateService();
-void bluetoothRebootCheck();
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/src/esp32/BluetoothUtil.cpp b/src/esp32/BluetoothUtil.cpp
deleted file mode 100644
index 03b7c974c..000000000
--- a/src/esp32/BluetoothUtil.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-#include "BluetoothUtil.h"
-#include "BluetoothSoftwareUpdate.h"
-#include "configuration.h"
-#include
-#include
-#include
-#include
-
-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_MITM_BOND);
-
- pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
-
- return pServer;
-}
-
-// Called from loop
-void loopBLE()
-{
- bluetoothRebootCheck();
-}
diff --git a/src/esp32/BluetoothUtil.h b/src/esp32/BluetoothUtil.h
deleted file mode 100644
index b1aa77db1..000000000
--- a/src/esp32/BluetoothUtil.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-#include
-
-#include
-#include
-#include
-#include
-#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;
-using StopBluetoothPinScreenCallback = std::function;
-
-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);
-
-/// Any bluetooth objects you allocate _must_ come from this pool if you want to be able to call deinitBLE()
-extern SimpleAllocator btPool;
diff --git a/src/esp32/MeshBluetoothService.cpp b/src/esp32/MeshBluetoothService.cpp
deleted file mode 100644
index 044bbc4e4..000000000
--- a/src/esp32/MeshBluetoothService.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "MeshBluetoothService.h"
-#include "BluetoothUtil.h"
-#include
-#include
-#include
-#include
-
-#include "BluetoothCommon.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();
- }
- }
-};
-
-static BluetoothPhoneAPI *bluetoothPhoneAPI;
-
-class ToRadioCharacteristic : public CallbackCharacteristic
-{
- public:
- ToRadioCharacteristic() : CallbackCharacteristic(TORADIO_UUID, BLECharacteristic::PROPERTY_WRITE) {}
-
- void onWrite(BLECharacteristic *c) { bluetoothPhoneAPI->handleToRadio(c->getData(), c->getValue().length()); }
-};
-
-class FromRadioCharacteristic : public CallbackCharacteristic
-{
- public:
- FromRadioCharacteristic() : CallbackCharacteristic(FROMRADIO_UUID, 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(FROMNUM_UUID, 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(MESH_SERVICE_UUID), 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;
-}
diff --git a/src/esp32/MeshBluetoothService.h b/src/esp32/MeshBluetoothService.h
deleted file mode 100644
index 17916fa91..000000000
--- a/src/esp32/MeshBluetoothService.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-
-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();
\ No newline at end of file
diff --git a/src/esp32/NimbleSoftwareUpdate.c b/src/esp32/NimbleSoftwareUpdate.c
new file mode 100644
index 000000000..e02cd4a9d
--- /dev/null
+++ b/src/esp32/NimbleSoftwareUpdate.c
@@ -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. */
+ },
+};
diff --git a/src/esp32/main-esp32.cpp b/src/esp32/main-esp32.cpp
index 0a0b98cde..aa85f9524 100644
--- a/src/esp32/main-esp32.cpp
+++ b/src/esp32/main-esp32.cpp
@@ -1,62 +1,15 @@
-#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"
#include
#include
-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();
- }
- }
-}
-
void getMacAddr(uint8_t *dmac)
{
assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
@@ -129,6 +82,7 @@ void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
loopBLE();
+ bluetoothRebootCheck();
// for debug printing
// radio.radioIf.canSleep();
diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp
index b63241c38..0ed506f64 100644
--- a/src/gps/UBloxGPS.cpp
+++ b/src/gps/UBloxGPS.cpp
@@ -1,4 +1,5 @@
#include "UBloxGPS.h"
+#include "error.h"
#include "sleep.h"
#include
@@ -83,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
@@ -150,7 +152,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
// 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);
+ 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
diff --git a/src/main.cpp b/src/main.cpp
index 92c8f424d..3d5dd6975 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,8 +43,7 @@
// #include
#ifndef NO_ESP32
-#include "BluetoothUtil.h"
-#include "WiFi.h"
+#include "nimble/BluetoothUtil.h"
#endif
#include "RF95Interface.h"
@@ -149,35 +148,6 @@ void userButtonPressedLong()
screen.adjustBrightness();
}
-#ifndef NO_ESP32
-void initWifi()
-{
-#if 0
- // strcpy(radioConfig.preferences.wifi_ssid, "xxx");
- // 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);
- if (WiFi.begin(wifiName, wifiPsw) == WL_CONNECTED) {
- DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.localIP().toString().c_str());
- } else {
- DEBUG_MSG("FAILED JOINING WIFI\n");
- }
- }
- }
- } else
- DEBUG_MSG("Not using WIFI\n");
-#endif
-}
-#endif
-
void setup()
{
#ifdef USE_SEGGER
@@ -286,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
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index fe816a202..92f47adfe 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -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
}
}
}
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index 2465c2021..f8bbb4d69 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -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
diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp
new file mode 100644
index 000000000..efc378d03
--- /dev/null
+++ b/src/nimble/BluetoothUtil.cpp
@@ -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
+
+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(&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
\ No newline at end of file
diff --git a/src/nimble/BluetoothUtil.h b/src/nimble/BluetoothUtil.h
new file mode 100644
index 000000000..453fadb54
--- /dev/null
+++ b/src/nimble/BluetoothUtil.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include
+#include
+
+/// 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;
+using StopBluetoothPinScreenCallback = std::function;
+
+/// 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);
\ No newline at end of file
diff --git a/src/nimble/NimbleBluetoothAPI.cpp b/src/nimble/NimbleBluetoothAPI.cpp
new file mode 100644
index 000000000..dde9171a3
--- /dev/null
+++ b/src/nimble/NimbleBluetoothAPI.cpp
@@ -0,0 +1,68 @@
+#include "NimbleBluetoothAPI.h"
+#include "PhoneAPI.h"
+#include "configuration.h"
+#include "nimble/BluetoothUtil.h"
+#include "nimble/NimbleDefs.h"
+#include
+
+// 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);
+}
diff --git a/src/nimble/NimbleBluetoothAPI.h b/src/nimble/NimbleBluetoothAPI.h
new file mode 100644
index 000000000..5fa66cc24
--- /dev/null
+++ b/src/nimble/NimbleBluetoothAPI.h
@@ -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;
\ No newline at end of file
diff --git a/src/nimble/NimbleDefs.c b/src/nimble/NimbleDefs.c
new file mode 100644
index 000000000..179cbebf6
--- /dev/null
+++ b/src/nimble/NimbleDefs.c
@@ -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. */
+ },
+};
diff --git a/src/nimble/NimbleDefs.h b/src/nimble/NimbleDefs.h
new file mode 100644
index 000000000..6b1db22e5
--- /dev/null
+++ b/src/nimble/NimbleDefs.h
@@ -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
+
+#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
\ No newline at end of file
diff --git a/src/nrf52/NRF52Bluetooth.cpp b/src/nrf52/NRF52Bluetooth.cpp
index 2ae864aae..9309e645e 100644
--- a/src/nrf52/NRF52Bluetooth.cpp
+++ b/src/nrf52/NRF52Bluetooth.cpp
@@ -4,16 +4,7 @@
#include "main.h"
#include
-// 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};
+
static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 59106494c..f7d61eb77 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -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
#include
-#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