Skip to content
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

Characteristic write without request does not return #282

Closed
t4rj4n opened this issue Sep 3, 2018 · 7 comments
Closed

Characteristic write without request does not return #282

t4rj4n opened this issue Sep 3, 2018 · 7 comments

Comments

@t4rj4n
Copy link

t4rj4n commented Sep 3, 2018

Hallo,

first, many thanks for this great library. I appreciate all the efforts you put into this work.

In my code I am sending fragments (20bytes) to a peripheral as fast as possible using
write without request which itself is using the iOS property canSendWriteWithoutResponse and the corresponding delegate callback to avoid driver congestion.

Sometimes, lets say once in 20000 tries the call does not return. I know that are there are issues with iOS not setting the property right: https://forums.developer.apple.com/thread/80376
But i am using lates iOS 11.4.1 and this is supposed to work right now.

If I am looking into the code, I am wondering if there is the slightest possibility, that this delegate callback peripheralIsReadyToSendWriteWithoutResponse calls once before the observer is setup and after the property is queried (master code snippet in https://github.com/Polidea/RxBluetoothKit/blob/master/Source/Peripheral.swift):

return Observable.deferred { [weak self] in
guard let strongSelf = self else { throw BluetoothError.destroyed }
return strongSelf.observeWriteWithoutResponseReadiness()
.map { _ in true }
.startWith(strongSelf.canSendWriteWithoutResponse)
.filter { $0 }
.take(1)
.flatMap { _ in
writeOperationPerformingAndListeningObservable(Observable.just(characteristic))
}
}.asSingle()

I see that this is deferred but is it really assured that the observer for Readiness is setup before the flag strongSelf.canSendWriteWithoutResponse is evaluated?

Maybe this is still a bug in iOS Framework?

I am grateful, for any help solving this matter.

To Reproduce
Steps to reproduce the behavior:
Send 20 bytes per write without request as fast as possible until response is missing.

Expected behavior
I expect that onSuccess or onError subscription is called

Environment:

  • iPhone 8
  • iOS 11.4.1
  • Lib Version 5.1.3
  • RxSwift Version 4.2.0
  • Swift version 4.1
@t4rj4n
Copy link
Author

t4rj4n commented Sep 3, 2018

Here are some loglines for two cases. First call returns, second not.
I added log output to the do operator.

2018-09-03 12:35:59.070885+0200 ErDemoApp[363:117921] start writing of item = 971 with canSendWriteWithoutResponse = false
2018-09-03 12:35:59.071080+0200 ErDemoApp[363:117921] onSubscribe of item = 971
2018-09-03 12:35:59.071091+0200 ErDemoApp[363:117911] onDispose of item = 970
2018-09-03 12:35:59.071210+0200 ErDemoApp[363:117921] onSubscribed of item = 971
[RxBLEKit|DEBG|10:35:59.089]: Peripheral(uuid: 107E508F-258E-75E5-1AD0-A540171ED6CC, name: Optional("46489670000000000")) peripheralIsReady(toSendWriteWithoutResponse)
2018-09-03 12:35:59.091187+0200 ErDemoApp[363:117884] onSuccess of item = 971
2018-09-03 12:35:59.091293+0200 ErDemoApp[363:117884] writing succeded

2018-09-03 12:35:59.091440+0200 ErDemoApp[363:117921] start writing of item = 972 with canSendWriteWithoutResponse = false
2018-09-03 12:35:59.091645+0200 ErDemoApp[363:117884] onDispose of item = 971
2018-09-03 12:35:59.091732+0200 ErDemoApp[363:117921] onSubscribe of item = 972
2018-09-03 12:35:59.092147+0200 ErDemoApp[363:117921] onSubscribed of item = 972
[RxBLEKit|DEBG|10:35:59.092]: Peripheral(uuid: 107E508F-258E-75E5-1AD0-A540171ED6CC, name: Optional("46489670000000000")) peripheralIsReady(toSendWriteWithoutResponse)

Seems that readiness callback happens but was not used.
timestamps of subscribed and ready event is:
.071210 .089 (first case)
.092147 .092 (second case)
very close in the second case

@t4rj4n
Copy link
Author

t4rj4n commented Sep 3, 2018

Another problem is that sometimes the peripheralIsReady delegate is never called maybe cause of iOS bug.
Currently I may have working piece of code following the following strategy:

-write char with timeout (50ms)
-if timeout is hit:

  • retry 2 times (using retryWhen)
  • then send 0 bytes nativly without using RxAndroidBle (resets a stuck canSendWriteWithoutResponse flag) and retry again

@c0diq
Copy link
Contributor

c0diq commented Sep 15, 2018

I have the same problem on OSX. My write without response are not sent (and received). That's because 5.1.3 relies on canSendWriteWithoutResponse which is broken. See https://forums.developer.apple.com/thread/80376

@c0diq
Copy link
Contributor

c0diq commented Sep 15, 2018

So this started happening around April when the candSendWriteWithoutResponse availability check was added for macOS 10.13 and tvOS.
Since this is broken on OSX, is there a way you could extend the RxBluetoothKit API to allow disabling that check? We have built our own back pressure system on top of Gatt for iOS < 11 and and OSX < 10.13 so we can away without that feature.

@bartoszstelmaszuk
Copy link
Contributor

@c0diq We will look into it and introduce availability check until Apple will fix it on their side.

@bartoszstelmaszuk
Copy link
Contributor

Thanks for discussion. I am closing this issue since availability check was introduced in 5.1.4 version.

@c0diq
Copy link
Contributor

c0diq commented Sep 27, 2018

Thanks a bunch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants