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

Fix MTU not updated when changed by the peripheral. (closes#293) #294

Merged
merged 8 commits into from
Oct 24, 2017

Conversation

dariuszseweryn
Copy link
Owner

Previously the RxBleConnection.currentMtu was updated only when the MTU was updated by the central. This prevented Long Writes from utilising the increased Maximum Transfer Unit or the used from having a valid current MTU value—this made the utilisation of available bandwidth suboptimal.

…hanged by the peripheral. (closes#293)

Previously the `RxBleConnection.currentMtu` was updated only when the MTU was updated by the central. This prevented Long Writes from utilising the increased Maximum Transfer Unit or the used from having a valid current MTU value—this made the utilisation of available bandwidth suboptimal.
@dariuszseweryn dariuszseweryn added the bug Bug that is caused by the library label Oct 16, 2017
@dariuszseweryn dariuszseweryn added this to the 1.4.2 milestone Oct 16, 2017
@dariuszseweryn dariuszseweryn requested a review from uKL October 16, 2017 09:03
Copy link
Collaborator

@uKL uKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest some changes.

@@ -83,6 +83,21 @@ public RxBleConnectionImpl(
this.longWriteOperationBuilderProvider = longWriteOperationBuilderProvider;
this.callbackScheduler = callbackScheduler;
this.illegalOperationChecker = illegalOperationChecker;

// unsubscription is not needed as all objects are on @ConnectionScope and will get GCed together
gattCallback.getOnMtuChanged()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first, this is a good spot that the field is not updated properly, however, the proposed fix is a big NO-NO by design. I dislike the fact that there is some kind of logic in the constructor.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking of a place, where we could put it and I think the ConnectorImpl layer is the best place. Its responsibility is to wire up the connection state.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True


// unsubscription is not needed as all objects are on @ConnectionScope and will get GCed together
gattCallback.getOnMtuChanged()
.retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need retryWhen here? Isn't a retry enough?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed

@@ -83,6 +83,21 @@ public RxBleConnectionImpl(
this.longWriteOperationBuilderProvider = longWriteOperationBuilderProvider;
this.callbackScheduler = callbackScheduler;
this.illegalOperationChecker = illegalOperationChecker;

// unsubscription is not needed as all objects are on @ConnectionScope and will get GCed together
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption on object lifecycle from within the object is generally not a good pattern, even if in this case it's true.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

Copy link
Collaborator

@uKL uKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more thoughts to discuss.

@Inject
MtuWatcher(
final RxBleGattCallback rxBleGattCallback,
final AtomicInteger atomicInteger,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason of injecting an AtomicInteger rather than creating it in place? It seems to be only a container for a state. It's more like an implementation detail and should be hidden.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is referenced in the new OnSubscribe() and it cannot be referenced there if it is a member of the MtuWatcher. The problem is that there is no easy way of extending a Completable. Maybe it is even an anti pattern as we can have independent Completable subscriptions and shared AtomicInteger

@ConnectionScope
class MtuWatcher extends Completable implements MtuProvider {

private final AtomicInteger currentMtuAtomicInteger;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have to be atomic? Do we expect concurrent updates from different threads?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be a reference so it could be referenced from the OnSubscribe

@Override
public void call(CompletableSubscriber completableSubscriber) {
Subscription mtuSubscription = rxBleGattCallback.getOnMtuChanged()
.retry()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the scenario for retry() is required at all?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the BluetoothGattCallback.onMtuChanged() would be called with status != GATT_SUCCESS

atomicInteger.set(newMtu);
}
});
completableSubscriber.onSubscribe(mtuSubscription);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be updated if no one is listening to this completable?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. That is why it is subscribed in the ConnectorImpl

return Observable.merge(
newConnectionObservable.delaySubscription(connectedObservable),
disconnectedErrorObservable,
connectionComponent.mtuWatcherCompletable().<RxBleConnection>toObservable()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is acceptable but I'm thinking about some better way. This introduces API of a Completable that doesn't do anything but stays subscribed. Is there any good way to watch for connect/disconnect events and notify MtuWatcher to subscribe/unsubscribe from the MTU changes? This would be more descriptive that merging with a magic Completable.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just try to avoid manual state management

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is manual state management bad? I think it might be more descriptive.

If you want to stick with this solution I would name the method some other way. It should clearly say that it is responsible for the watcher state.

import rx.functions.Action1;

@ConnectionScope
class MtuWatcher extends Completable implements MtuProvider {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MtuWatcher or just MtuCache?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it is watching the Mtu and providing the current value, name may be changed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Collaborator

@uKL uKL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please think about method name in MtuWatcher as it could refer to its responsibility. The rest is ok.

class MtuWatcher implements ConnectionSubscriptionWatcher, MtuProvider, Action1<Integer> {

private Integer currentMtu;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need empty lines here? In other places, we don't keep them.

@dariuszseweryn dariuszseweryn merged commit 55089f4 into master Oct 24, 2017
@dariuszseweryn dariuszseweryn deleted the fix/issue_293_mtu_update_by_peripheral branch October 24, 2017 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug that is caused by the library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants