This article will consider ATT_MTU equal to 23. See Part 1 for more details.
If you have read Part 2 of this series, you might already guess how things work when writing values for long attributes on a GATT Server.
Instead of the ATT_WRITE_REQUEST packet, the Client would instead split the value into multiple parts and for each part it would send pairs of data value bytes and offset where the bytes should be written.
Things are a little tricky here though. What happens if we have a 300-byte long attribute, and simultaneously a few Clients begin writing parts of this same attribute? The result is that different parts of the attribute are written at different times, and in the end none of the values any of the Clients intended will get there in one piece.
For that (and other reasons), the mechanism used to write long attributes involves writing queues. Each Client is allocated a write queue where it should first send all the parts of the attribute, and in the end the Server would execute the writing of all attribute parts in one single, atomic operation.
First, the Client should begin sending ATT_PREPARE_WRITE_REQUEST packets, which include: operation code (1 byte), attribute handle (2 bytes), attribute part offset (2 bytes), and finally the remaining 18 bytes will contain the attribute part’s value. Therefore, the actual attribute value will be split into 18-byte chunks. The Server will store all these parameters, but will not do any modifications to the attribute in the database.
After all the parts have been sent, the Client finally sends an ATT_EXECUTE_WRITE_REQUEST, at which the Server writes all the data in the order received, in one atomic operation (here “atomic” means that no other Client request may interrupt this operation).
A Client may always cancel a queue instead of executing it (and of course nothing changes in the database). Also, the queue may contain parts of different attributes.
More details in the Bluetooth Core 4.1 specification, vol. 3, section 3.4.6.
Continue reading: Part 4