bluetooth-le
bluetooth-le copied to clipboard
Calling twice BleClient.write() one after another
Describe the bug
Something happens when await BleClient.write() called twice, one after another and second write is not performs at all
To Reproduce Steps to reproduce the behavior: Was used following method to send string to LE device:
async sendMsgToDevice(msg: string) {
console.log(`vova: sendMsgToDevice: ${msg}`);
await BleClient.write(this.getDeviceId(), this.uuids!.srv, this.uuids!.txCh, textToDataView(msg))
}
Most of time when we call sendMsgToDevice() two times is correct behavior:
I/Capacitor/Console: File: http://localhost/main.js - Line 12840 - Msg: vova: sendMsgToDevice: b8d8
I/Capacitor/Console: File: http://localhost/main.js - Line 12840 - Msg: vova: sendMsgToDevice: go
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 20997892, pluginId: BluetoothLe, methodName: write
V/Capacitor: callback: 20997892, pluginId: BluetoothLe, methodName: write, methodData:
D/Device: resolve: write|f5351050-b2c9-11ec-a0c0-b3bc53b08d33|f53513ca-b2c9-11ec-a0c1-639b8957db99 Characteristic successfully written.
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 20997894, pluginId: BluetoothLe, methodName: write
V/Capacitor: callback: 20997894, pluginId: BluetoothLe, methodName: write, methodData: {"deviceId":"34:AB:95:8F:62:5A","service":"f5351050-b2c9-11ec-a0c0-b3bc53b08d33","characteristic":"f53513ca-b2c9-11ec-a0c1-639b8957db99","value":"67 6f"}
D/Device: resolve: write|f5351050-b2c9-11ec-a0c0-b3bc53b08d33|f53513ca-b2c9-11ec-a0c1-639b8957db99 Characteristic successfully written.
and go is sent after b8d8. But happens when go is not sent to LE device. Than in logs I see only:
I/Capacitor/Console: File: http://localhost/main.js - Line 12840 - Msg: vova: sendMsgToDevice: f3e5
I/Capacitor/Console: File: http://localhost/main.js - Line 12840 - Msg: vova: sendMsgToDevice: go
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 20997930, pluginId: BluetoothLe, methodName: write
V/Capacitor: callback: 20997930, pluginId: BluetoothLe, methodName: write, methodData: {"deviceId":"34:AB:95:8F:62:5A","service":"f5351050-b2c9-11ec-a0c0-b3bc53b08d33","characteristic":"f53513ca-b2c9-11ec-a0c1-639b8957db99","value":"66 33 65 35"}
D/Device: resolve: write|f5351050-b2c9-11ec-a0c0-b3bc53b08d33|f53513ca-b2c9-11ec-a0c1-639b8957db99 Characteristic successfully written.
Expected behavior Each string is sent/written in same order
Screenshots N/A
Plugin version:
- @capacitor-community/bluetooth-le: 1.7.0
Smartphone (please complete the following information):
- Device: Samsung A3 or any other
- OS: Android
- Browser N/A
- Version N/A
Additional context N/A
Adding mutex solves issue:
async sendMsgToDevice(msg: string) {
await this.lock.acquire()
console.log(`vova: sendMsgToDevice: ${msg}`);
await BleClient.write(this.getDeviceId(), this.uuids!.srv, this.uuids!.txCh, textToDataView(msg))
this.lock.release()
}
And we see:
I/Capacitor/Console: File: http://localhost/main.js - Line 12949 - Msg: vova: sendMsgToDevice: f1b5
D/Device: resolve: write|f5351050-b2c9-11ec-a0c0-b3bc53b08d33|f53513ca-b2c9-11ec-a0c1-639b8957db99 Characteristic successfully written.
I/Capacitor/Console: File: http://localhost/main.js - Line 12949 - Msg: vova: sendMsgToDevice: go
V/Capacitor/Plugin: To native (Capacitor plugin): callbackId: 100409782, pluginId: BluetoothLe, methodName: write
V/Capacitor: callback: 100409782, pluginId: BluetoothLe, methodName: write, methodData: {"deviceId":"34:AB:95:8F:62:5A","service":"f5351050-b2c9-11ec-a0c0-b3bc53b08d33","characteristic":"f53513ca-b2c9-11ec-a0c1-639b8957db99","value":"67 6f"}
D/Device: resolve: write|f5351050-b2c9-11ec-a0c0-b3bc53b08d33|f53513ca-b2c9-11ec-a0c1-639b8957db99 Characteristic successfully written.
Should BleClient.write() be multi-thread protected?
Thank you for using this plugin.
I cannot reproduce the behavior you're describing. The BleClient has an internal queue which should handle this. Are you by any chance calling BleClient.disableQueue() (which is not recommended)?
All is by default (queue is enabled I guess). Issue reproduces even with BleClient.disableQueue().
It happens not immediately, but after a while (a couple of chess games). And than I see this behavior each time when BleClient.write() is called immediately one after another (additionally two BleClient.write() called in the same thread/function).
I think You can reproduce it by:
async reproduce() {
while (true) {
await BleClient.write(..., textToDataView("text1"))
await BleClient.write(..., textToDataView("text2"))
}
}
And wait when only "text1" will be received on peripheral side
Or this one:
/*not async*/ reproduce() {
while (true) {
write("text1")
write("text2")
}
}
async write(msg: string) {
await BleClient.write(..., textToDataView(msg))
}
I still cannot reproduce it. I can write 30 times in a row and every write goes through in the correct order.
Do you get any errors? Anything else in the logs that looks suspicious?
If I disable the queue, I get the error "Error: Writing characteristic failed." which is expected, because Android cannot handle simultaneous operations. (That's why the queue should not be disabled on Android).
A write call has a timeout of 5 seconds by default, so if your code calls the seconds write, there should at least be a timeout error.
I still cannot reproduce it. I can write 30 times in a row and every write goes through in the correct order.
I think in my case it occurs after >~80 writes
Do you get any errors? Anything else in the logs that looks suspicious?
No, all logs that I see are attached here
Are you trying both methods of reproduction with async and non async reproduce()?
Are you trying both methods of reproduction with async and non async reproduce()?
Yes, I tried both async and non async and got the same successful result (in case the queue is enabled).
I think in my case it occurs after >~80 writes
Also 200 writes is no problem in my tests.
Hi, I have been able to reproduce this. Having several users of our app reporting issues, whilst most fine, I had initially put it down to faulty hardware. It seems all devices are Android 11 and budget devices. We picked up a cheap TCL 10" Android device, split our write down into smaller chunks and loop through. If we send too fast the device receiving errors out after 4-5 runs, around 80-150 writes.
I have put a small 20ms wait after each write and the issue has completely gone away. I hope this is helpful.
Thanks again for the plugin.
Currently I don't see how this could be fixed in the plugin, as it's an issue with specific Android devices. Therefore I'm closing this issue for now. If anyone has an idea how this could be fixed, let me know and I'm happy to take another look.