This is deep in the weeds, but: Various examples and Zephyr code appear to assume that the handle of the Characteristic Value declaration is one more than the handle of the characteristic declaration. See e.g. 80bc21e03c5e2397ae3f5a12d154c626aa53b45d from #12254.
bt_gatt_attr_read_chrc for example sets it this way, citing V3G3.3.2 that the Characteristic Value declaration is the first Attribute after the characteristic declaration. This seems fine if this code is implementing Zephyr's handle assignment policy, but I'm not convinced that's what it does in all cases.
V3G2.5.1 specifies there may be gaps in handles between adjacent attributes, even when the specification requires adjacency. The O'Reilly "Getting Started with Bluetooth Low Energy" book has (p. 61):
Although it鈥檚 often the case, you should never assume that this [Characteristic Value] handle will be contiguous (i.e., 0xNNNN+1 ) to the one containing the declaration.
I noticed this because the central_hr sample also assume this when it subscribes using a handle one past the handle of the characteristc.
I'm concerned a non-Zephyr device implementing a standard service may not follow the same policy.
Is what Zephyr's doing really guaranteed to be correct? The characteristic declaration value includes the actual value handle, but it's ignored in parse_characteristic where the other information in the value is preserved.
I have a patch that I think fixes this, but want a sanity check on my understanding before going further.
This is a very interesting question, and I think it comes down to whether the spec sentence you quote:
The Characteristic Value declaration contains the value of the characteristic. It
is the first Attribute after the characteristic declaration. All characteristic
definitions shall have a Characteristic Value declaration.
can be interpreted as "sequential in number" or "next attribute with gaps". I think it's the latter, as reflected in the book you mention that I co-authored. Also what would be the point of having the "Characteristic Value Attribute Handle" in the Characteristic Declaration otherwise?
I noticed this because the central_hr sample also assume this when it writes to the CCCD value at one past the handle of the CCCD.
A CCCD is a single attribute. there's no "CCCD" and then "CCCD value" attributes, just a single one. I think what you mean to say here is "it calculates the Characteristic Value Attribute Handle, which is required for the API to subscribe to a characteristic, by adding one to the Characteristic Declaration Handle".
I noticed this because the central_hr sample also assume this when it writes to the CCCD value at one past the handle of the CCCD.
A CCCD is a single attribute. there's no "CCCD" and then "CCCD value" attributes, just a single one. I think what you mean to say here is "it calculates the Characteristic Value Attribute Handle, which is required for the API to subscribe to a characteristic, by adding one to the Characteristic Declaration
Handle".
Thank you; I've corrected the description. I'm still getting a handle [sic] on Bluetooth at this level.
A similar appears to be present for notify and indicate from #8253.
Yep, the spec actually have the following line to say there could be gaps even when in case of adjacents handles:
When the specification requires two attribute
handles to be adjacent or for one to immediately follow one the other, such
gaps are still permitted and shall be ignored.
That obviusly only apply to GATT client code since for the server we guaranteed values are +1 of the declaration, to be honest I think the spec author lost a very good oportunity to optimize things like discovery by allowing gaps within service handles since an implementation cannot really put anything other than the value it seems pointless to allow gaps in between characteristics and values.
I noticed this because the central_hr sample also assume this when it writes to the CCCD value at one past the handle of the CCCD.
A CCCD is a single attribute. there's no "CCCD" and then "CCCD value" attributes, just a single one. I think what you mean to say here is "it calculates the Characteristic Value Attribute Handle, which is required for the API to subscribe to a characteristic, by adding one to the Characteristic Declaration
Handle".Thank you; I've corrected the description. I'm still getting a handle [sic] on Bluetooth at this level.
A similar appears to be present for notify and indicate from #8253.
Those are server APIs where Zephyr garantees we can do such optimizations.
@Vudentz I was sensitive to this possibility because I was intending to use the feature to encode information in the handle value in a GATT server I never got around to implementing.
Thanks for the feedback; based on this I'll complete my patch and send in a PR.
That obviusly only apply to GATT client code since for the server we guaranteed values are +1 of the declaration, to be honest I think the spec author lost a very good oportunity to optimize things like discovery by allowing gaps within service handles since an implementation cannot really put anything other than the value it seems pointless to allow gaps in between characteristics and values.
Yes, I concur. That said maybe they were thinking about implementations that would use a linked list from items in a memory pool and use the pool number in the pool as handle or something like that.
That obviusly only apply to GATT client code since for the server we guaranteed values are +1 of the declaration, to be honest I think the spec author lost a very good oportunity to optimize things like discovery by allowing gaps within service handles since an implementation cannot really put anything other than the value it seems pointless to allow gaps in between characteristics and values.
Yes, I concur. That said maybe they were thinking about implementations that would use a linked list from items in a memory pool and use the pool number in the pool as handle or something like that.
Well even then I don't thing one would skip entries on the pool since that cannot be reused without removing the chrc declaration, anyway it is too late to speculate so we can only optimize the server and for things like discovery, etc, we will need to locate the handle with either the characteristic declaration or by doing things like read by UUID to discovery things like a CCC descriptor.
we will need to locate the handle with either the characteristic declaratio
@Vudentz
Read by Type with 0x2803? That's the usual approach
FWIW I had first tried that with a BlueZ server and got "attribute not found". Could well have been pilot error.
@pabigot "Attribute Not Found" doesn't necessarily mean error, it usually means there's nothing else to discover. If the handle was wrongly set and you'd try to read or write to it you would instead get "Invalid Handle".