-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
write
suspends indefinitely on subsequent calls when WithoutResponse
is used
#157
Comments
Thanks for the report! Can you provide logs using the Kable logging mechanism? With log |
@twyatt Do you want Scanner log level or Peripheral? |
@twyatt I got the Datalog over Peripheral, but I needed to censure some information. FYI: I have retry treatment for reconnection. So when I get a response with disconnected status I try to reconnect again and the library executes 2 times the last write event that had no response. |
If I understand correctly, you have a characteristic you're writing to and responses come back on a dedicated characteristic (via characteristic change notifications), right? Looking at a snippet of your logs, is this where it is problematic?
Whereas you wrote to According to the log snippet, the OS wrote your two requests and also provided the two characteristic changes but Kable didn't have the 2 change events come through the If possible, it would be helpful if you could provide a simple code snippet of how you're doing the "write for response" operation. |
Yes.
So... I've 2 problems. 1 - I'm not able to write on characteristic more than one time per connection. So, If I need to write on characteristic for the second time, I need to disconnect and connect again to achieve it. 2 - When I attempt to write on the characteristic for a second time and after waiting some time for a characteristic value change notification, I receive the
Yes
No.. When debugging my peripheral, the second writing is not performed. I can only write once after connecting to the peripheral. Look below for my implementation
|
@twyatt did you find the problem? |
Sorry, I have not had time to look at this yet. |
@renatosmf until I have time to look over your code sample, have you explored the sample app? It may provide some helpful patterns for peripheral I/O. I do notice you're leaning a lot on flows, which are great, but having too many of the |
Hi @twyatt , I already looked at the sample app and your example is considering only Mac OS hardware and running IO events over the main thread, which is different for the iOS context. I can not execute the write event over the main thread because freezes the UI thread of the App. In my context, I run each command only after the end message received over the characteristic notification, therefore I do not execute simultaneous write events in parallel. |
Looking over your logs, it does appear that it wrote twice? Can you clarify what in the logs is indicating otherwise?
Looks like you've implemented a form of queueing? This isn't entirely necessary as Kable won't execute If you were to implement code similar to: private val inbound = peripheral.observe(...).shareIn(scope, started = Eagerly)
private val outbound = characteristicOf(...)
suspend fun Peripheral.writeForResponse(data: ByteArray): ByteArray =
inbound.onSubscription { write(outbound, data) }.first()
suspend fun Peripheral.connectAndWriteTwice() {
connect()
val response1 = writeForResponse(request1)
val response2 = writeForResponse(request2)
} ...does it perform the expected writes and see the responses? |
Hi @twyatt, I tried your suggestion but it didn't work. Ps.: This behavior is only happening in the iOS environment, on Android, it works fine. |
@twyatt |
@twyatt |
Debugging the library, I found a different behavior for
|
No worries at all. I really appreciate you taking the time to try and debug/solve the issue.
What you are describing can happen if Core Bluetooth doesn't call one of the kable/core/src/appleMain/kotlin/PeripheralDelegate.kt Lines 220 to 236 in 6b4ca38
It would be helpful if you provided the Kable logs that lead up to the stalling of the |
@twyatt The problem isn't in PerfipheralDelegate and yes in the Peripheral class. kable/core/src/appleMain/kotlin/Peripheral.kt Lines 249 to 266 in 6b4ca38
Line 264 is never executed after the first time. I believe that the I had put an extra log with the prefix
Look at the output log with the logs. |
Wow, great debugging. Looked into the expected behavior of Core Bluetooth and my assumptions that it behaves similar to Android's APIs was completely wrong. In other words, Kable needs to treat According to Core Bluetooth documentation (emphasis mine):
Currently, Kable is expecting (waiting for) a response on the According to PunchThrough's The Ultimate Guide to Apple’s Core Bluetooth, Kable needs to use I'll try to find some time soon to make this change. Thanks again for the investigation and tracking down the issue! |
write
suspends indefinitely on subsequent calls when WithoutResponse
is used
@renatosmf what iOS version are you seeing the issue on? According to The Ultimate Guide to Apple’s Core Bluetooth, the callback Kable needs to listen for ( If you're testing pre-iOS 11 then it would make sense the behavior you are seeing where it stalls on subsequent writes. Although if you're testing on iOS 11 or newer, then I would've thought that Kable would (incorrectly) try to cast to kable/core/src/appleMain/kotlin/Peripheral.kt Lines 263 to 265 in 6b4ca38
Knowing what iOS version you're testing on will help me decide the best approach to fix the issue. Thanks! |
@twyatt I'm in iOS 13 or newer |
Thanks, though that means that the Going to have to do some more research of what the correct way to approach this is. Without any callback (from iOS) or other means of knowing when iOS is ready to process more messages makes this complete guesswork as to when the next There must be a standard way to do this, otherwise it would be very error-prone to perform writes without response on iOS. |
@twyatt I believe the kable library should act as a broadcast, simply passing the data to the Bluetooth Core. As the Core Bluetooth itself doesn't guarantee message delivery and doesn't have a delivery success fallback, I don't see much that can be done in this case. You should probably assume that every message you send should release the channel for new messages |
It may come to that, but it would totally surprise me that Apple didn't provide a way to not overwhelm their BLE stack. I know there are only so many messages that can be queued, it would only make sense for Apple to provide an API to know when that queue is full and you should stop flooding it. Otherwise I imagine it must either drop requests (or crash). To your point, yes, Kable could simply allow writes to go through without any checks, I just worry library consumers will use Kable with the expectation that that function won't allow the system to be overwhelmed, since that guarantee can be provided for every other supported OS/operation. I'll do a bit more research before resorting to lifting the semaphore for iOS write operations (without response). |
Hi @twyatt, did you found some solution to handle with write events |
Sorry, been swamped with some other internal work projects. I hope to get some time allocated for Kable updates soon (hopefully in the coming week or two). If you have the opportunity to try and find how "without response" is usually implemented on iOS, it'd be great to see how others solve this problem. |
hi @twyatt, Do you have some news about this fix? |
Another project I'm working on should be winding down next week and give me more time to focus on Kable. At that time I'll start researching how other libraries / iOS implementations handle writing without response. If you happen to find any examples of code that does consecutive writes without response, that would be incredibly helpful. |
Hi @twyatt , Unfortunately I don't found any solution to cover this scenario for iOS 11 and earlier. |
Hi @twyatt, |
Unfortunately, the API that was supposed to exist to allow proper usage in iOS >11 didn't work; at least not in the logs you provided. Although according to https://stackoverflow.com/a/52527853 it should exist/work. I'll try to find some time to test out of API mentioned in the Stackoverflow answer. |
@twyatt, |
Other work has wrapped up, so I'll hopefully be able to find some time to look into this again soon. Although I can't really offer an estimate as to when this might be fixed. |
Hi @twyatt, have you some news? |
This comment was marked as outdated.
This comment was marked as outdated.
Apologies it took so long to dedicate enough time to this issue; but I think I have a fix for this (#312). |
You should be able to perform writes "without response" (should be fixed) in 0.16.1. |
I’m attempting to send a write command sequentially. This approach works over android Bluetooth API, but in iOS I’m receiving the notification that the characteristics change only for the first command.
For the iOS write command, I'm using the write without response. In another way, If I set to write with the response, I'm receiving the error for the write permission.
The text was updated successfully, but these errors were encountered: