Dear Nordic Experts,
I've added buttonless BLE DFU to the generic level (Mesh) example. The firmware update is basically working; except for two minor little limitations for which I could really need your advise:
- DFU is working if the device has been provisioned into the mesh. Regardless if the app is connected to the proxy or not, DFU will succeed as long as the node to update is provisioned. (well, for the first time only, but we'll get to that next).
If the device is unprovisioned, the firmware update always fails. Logs follow at the end of the message. This is a 100% reproducible.
What's odd is the fact that DFU uses BT GATT, and (please correct me if I'm wrong) it shouldn't matter if the (mesh) node is provisioned or not. - The DFU works only once. Any subsequent update attempt fails with status 22:
14:27:58.849 D/BluetoothGatt: onClientConnectionState() - status=22 clientIf=31 device=EC:2A:09:58:7B:2E
The only workaround to make the node update-able again is to reset (unprovision) it, and provision it again. Then it can be DFU'd again, but only once...
Now the question is: What could possibly cause this behavior? What would be the most obvious thing to check here?
There are a few thing's I've tried so far:
- Copied the DFU specific code from LPN example (Mesh SDK). That was where the problem first showed up.
- Added the code from the buttonless example (BLE SDK). Nothing changed.
- Removed the code from the LPN example, so only the code from the buttonless example was left. And still the same behavior.
Which leads to the next questions: Which of those two examples should be used to add buttonless OTA DFU to a Mesh project? They do a few things a little different, is merging both of them the right approach? Or would one of them be sufficient? If so, which one?
I have this intuition that I've overlooked some essential settings in either sdk_config.h or nrf_mesh_config_app.h.
Which of those (hundreds) of defines are essential for DFU to reliably work?
Just as a reference, below follows the log output when trying to DFU an unprovisioned node.
Please note: These log messages are from my own app, which logs more verbose than Noridc's nRF connect app. The behavior is the same, regardless which app is used.
Interesting is the time at which the bootloader seems to get active:
10:56:44.638 I/flutter: Updating firmware: EC:2A:09:58:7B:2E
10:56:44.722 D/BluetoothGatt: connect() - device: EC:2A:09:58:7B:2E, auto: false
10:56:44.722 D/BluetoothGatt: registerApp()
10:56:44.722 D/BluetoothGatt: registerApp() - UUID=d961281a-56ba-4813-a35b-8c894daf560c
10:56:44.725 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=11
10:56:45.129 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=11 device=EC:2A:09:58:7B:2E
10:56:45.138 D/BluetoothGatt: discoverServices() - device: EC:2A:09:58:7B:2E
10:56:45.795 D/BluetoothGatt: onConnectionUpdated() - Device=EC:2A:09:58:7B:2E interval=192 latency=0 timeout=400 status=0
10:56:47.261 D/BluetoothGatt: onConnectionUpdated() - Device=EC:2A:09:58:7B:2E interval=6 latency=0 timeout=500 status=0
10:56:47.474 D/BluetoothGatt: onSearchComplete() = Device=EC:2A:09:58:7B:2E Status=0
10:56:47.711 D/BluetoothGatt: onConnectionUpdated() - Device=EC:2A:09:58:7B:2E interval=192 latency=0 timeout=400 status=0
10:56:48.502 D/BluetoothGatt: setCharacteristicNotification() - uuid: 8ec90003-f315-4f60-9fb8-838830daea50 enable: true
[The way it looks, the device enters bootloader mode at the time the following message appears - or shortly thereafter]
10:57:19.968 D/BluetoothGatt: onClientConnectionState() - status=22 clientIf=11 device=EC:2A:09:58:7B:2E
10:57:19.968 E/DfuBaseService: Connection state change error: 22 newState: 0
10:57:19.980 W/t.************: Accessing hidden method Landroid/bluetooth/BluetoothGatt;->refresh()Z (greylist, reflection, allowed)
10:57:19.981 D/BluetoothGatt: refresh() - device: EC:2A:09:58:7B:2E
10:57:19.985 D/BluetoothGatt: close()
10:57:19.986 D/BluetoothGatt: unregisterApp() - mClientIf=11
10:57:20.022 D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=11 mScannerId=0
10:57:27.108 D/BluetoothGatt: connect() - device: EC:2A:09:58:7B:2E, auto: false
10:57:27.108 D/BluetoothGatt: registerApp()
10:57:27.109 D/BluetoothGatt: registerApp() - UUID=326e75fd-dff8-4771-9c70-fd21da430532
10:57:27.118 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=11
10:57:57.132 D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=11 device=EC:2A:09:58:7B:2E
10:57:57.132 E/DfuBaseService: Connection state change error: 133 newState: 0
10:57:57.133 E/DfuBaseService: Device not reachable. Check if the device with address EC:2A:09:58:7B:2E is in range, is advertising and is connectable
10:57:57.142 D/BluetoothGatt: refresh() - device: EC:2A:09:58:7B:2E
10:57:57.148 D/BluetoothGatt: close()
10:57:57.149 D/BluetoothGatt: unregisterApp() - mClientIf=11
10:57:59.206 D/BluetoothGatt: connect() - device: EC:2A:09:58:7B:2E, auto: false
10:57:59.206 D/BluetoothGatt: registerApp()
10:57:59.207 D/BluetoothGatt: registerApp() - UUID=2ed8016c-d624-4132-b16d-e8133d23b9ac
10:57:59.219 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=11
SDKs in use are:
- nrf5_SDK_for_Mesh_v4.2.0
- nRF5_SDK_17.0.2_d674dde
- Softdevice 7.2.0
This issue keeps me awake at night for a few days now, and by now I completely run out of ideas, so your help is very much appreciated.
Thank you!