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