-
Notifications
You must be signed in to change notification settings - Fork 399
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
GATTS long reads behavior #1090
Comments
I ran in to this as well. My callback contained a function that gathered data from an external source which would run multiple times and crash the microcontroller. I must say I found it quite confusing that this was happening, although I have now had a practical education on one of the inner workings of BLE, which is a good thing I suppose! I think @rojer's idea of buffering the data is a good one. It would also be useful to be able to tell inside the callback function if it is being run for the first time in a long read, the last time, or somewhere in the middle. |
Running into this sporadically. It is a confusing behaviour that the offset reads are handled, but the developer still needs to consider this case. Buffering internally in Nimble would be good, but I suppose that could be an equally nasty surprise in a low resource environment. @ivanholmes @rojer did you end up with any workarounds? I'm thinking of caching the value when it's first read, and returning the cached value if it's read again within some time period (e.g. 5 seconds). |
Hi, This is integral trait of long reads in GATT. Specification doesn't treat long read as atomic and thus server never knows what (if any) GATT procedure is executed by the client. It is up to higher layers (ie profiles) to define and handle this. This is from Core Spec 5.4 Vol 3 Part F 3.4.4.5 "ATT_READ_BLOB_REQ" |
that's fine, the problem is there is no way to do that currently. it's literally impossible to tell if the read being serviced is a part of long read or not. for example, my higher layer decision is to present consistent view to the client but how am i to tell the NimBLE api reads apart? right now i'm relying on MTU-1 read behavior, which is less than ideal. even as much as passing an offset for the read would be sufficient (as bluedroid does). |
ahh ok, I see now, I think we should be able to extend ble_gatt_access_ctxt with needed info without breaking API compatiblity |
@ivanholmes, @macksal, @rojer, I believe buffering the data inside the nimble stack is not an option here. Because it's up to the client to decide whether it wants to and will read the whole attribute or not, so there is no guarantee that after the first read request there would be others to consume the whole attribute. As provided in the comments |
In general, I like that NimBLE tries to hide the complexity of long reads and writes from the user, automatically servicing them within the stack, it's a welcome change from Bluedroid that spills all this onto the user of the API and expects the user to deal with all the complications.
However, currently observed behavior for long reads is that NimBLE will repeatedly request the value from the attribute callback while responding to central's requests and sending MTU chunks at a time (at least i suspect that's what's happening). However, if the value of the characteristic happens to change between reads, incorrect value will be returned to the client. As far as i can tell, there is current;y no way for the API user to tell if a particular BLE_GATT_ACCESS_OP_READ_CHR is part of the same long read or not - for example, read offset is not provided to the user, so user application cannot work this around either.
IMO, NimBLE should buffer the long response and serve long reads from internally buffered copy of the response and not rely on the value staying the same.
The text was updated successfully, but these errors were encountered: