-
Notifications
You must be signed in to change notification settings - Fork 336
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
Add support for writing to descriptors #453
base: master
Are you sure you want to change the base?
Conversation
thanks! so far it looks good |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good. Good job, @ened 👍
There is at least one "TODO" mark out there, so I consider this a work-in-progress for now.
) | ||
} | ||
} | ||
}.first(CharOperationFailed(deviceId, "Writechar timed-out")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@remonh87 CharOperation*
types are used multiple types in this method (and possibly in other places), while it's not exactly about characteristics, but rather about descriptors (which, admittedly, are associated with characteristics). Do you think it's fine or do you think a new set of types should be introduced?
I don't have a strong opinion on this, mainly because I'm not that familiar with the Android part. Just drawing your attention.
throw Failure.descriptorNotFound(qualifiedDescriptor) | ||
} | ||
|
||
guard let response = characteristic.service?.peripheral?.writeValue(value, for: descriptor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ened Is writing to a descriptor inherently a "without response" (without acknowledgement) operation? If so, then using -WithoutResponse
is reasonable, but please clarify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing to descriptors works via https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519107-writevalue . There is no response per se, but the docs at https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1519062-peripheral state that a delegate method will be called once the write is completed. If it fails, the error is given as well. Do you think the plugin should implement that delegate and return a value only once that is done?
WithoutResponse
still applies based on that logic, but I am wondering what the plugin should do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think the plugin should implement that delegate and return a value only once that is done?
If waiting for the events delivered to the delegate adds anything, it might be a potential improvement, but as of now, I'd say, this method should be implemented similar to
flutter_reactive_ble/packages/reactive_ble_mobile/ios/Classes/ReactiveBle/Central.swift
Line 264 in d3d2781
func writeWithoutResponse( |
As long as they match, it should be enough.
@@ -70,6 +70,16 @@ message WriteCharacteristicInfo { | |||
GenericFailure failure = 3; | |||
} | |||
|
|||
message WriteDescriptorRequest { | |||
DescriptorAddress descriptor = 1; | |||
bytes value = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ened Do descriptors always have 16-bit IDs and cannot have longer or shorter IDs?
source: hosted | ||
path: "../reactive_ble_platform_interface" | ||
relative: true | ||
source: path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure this should be committed.
CC @remonh87
@werediver @remonh87 944e2a9 is not strictly part of this MR, but was needed for compatibility when including this package on iOS. Should it be separate? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments regarding 944e2a9.
I suppose it's fine to include those changes in this pull request, but please go through all the comments already left by me. Aside from those comments, the commit history of this pull request is dirty: contains merge commits (better rebase your feature branches), doesn't seem well structured and includes commit messages mentioning work-in-progress (WIP). If you are not going to clean the history up at some point (through interactive rebase), the pull request should be squashed before merging (can be done at the moment of merging through GitHub interface). It's okay, just don't be surprised. |
OK & yes will do.
Oh yes, I was fully expecting to squash all the commits before removing the Thank you for the reviews. |
I can test the project setup on the m1 machine (I have one) if needed. |
completion(.success(result)) | ||
} else { | ||
do { | ||
try central.discoverDescriptors( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@werediver @remonh87 would like your opinion if this is the correct approach. I think there is no need to discover all characteristics from the get go. It may also imply a API change to declare what to discover.
The code currently discovers on-demand but may change the library behavior from what the use expects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Characteristic discovery works differently on iOS and Android. On iOS a client can specify a list of services and characteristics to discover when connecting to a device (the client is only allowed to interact with the discovered characteristics later on), while on Android no discovery is triggered beforehand (I think it's happening on the fly then, but not entirely sure; CC @remonh87).
In terms of design, a simple solution is to extend the existing discovery mechanism to also discover descriptors, as specified when connecting. That would be consistent and quite efficient.
Discovering descriptors one by one is definitely not as efficient (the more descriptors a client uses, the larger the overhead is). This is also not consistent with how the library works with characteristics (on iOS).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@werediver got you regarding the differences - and will think how to extend the initial discovery. It does mean the existing iOS discovery code will get another layer (currently counts how many services are left to discover, this will be extended with the number of characteristics to explore).
Reminding of my earlier question:
I'd suggest to find a suitable example in existing Protobuf structures and reuse it.
|
At the moment, the code defines
and
So that looks good? |
Oh, sure, it looks good. I misread a piece of protobuf specification, sorry. |
} | ||
|
||
guard let peripheral = central.activePeripherals[descriptor.peripheralID], | ||
let service = peripheral.services?.first(where: { service in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how will .first
work with devices that provide several instances of the same service (UUID)? Same for several instances of the same characteristic UUID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Devices can provide multiple services with the same UUID? I have to admit that's a part of the spec I do not know about!
Technically this May be a more fundamental problem in this package then, looking as QualifiedCharacteristic for example, a full lookup is done using the UUIDs but not via index?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case anyone wants to continue with this in the future. Have a look at #776 where the problem of multiple characteristics of services with the same id has been addressed. Something similar would be needed here.
I need to be able to read a characteristic's user descriptor... Does this PR just include writes? |
Extends the plugins to support writing to specific descriptors.
I have copied the approach from
QualifiedCharacteristic
to become aQualifiedDescriptor
.There are quite a few generated files (tests, protobuf) which are a bit tedious to handle. Appreciate if someone could point me to a developer docs page.
iOS implementation is still TBD.