I am new to BLE, and trying to understand Read Blob Request's offset. When ATT_MTU is 23 bytes, offset got incremented by 22..from 0,22,44.... 512.if I update MTU to 517(near to 512),then how far this offset goes? only till 512 or 0,512,1024...? Also, Is this possible: If it get incremented further, for each iteration 512 bytes data can be transferred which implies more data transfer. Please someone help me out.
CodePudding user response:
From Bluetooth Core specification v5.3, Vol 3, Part F (ATT):
Section 3.2.9 Long attribute values:
The longest attribute that can be sent in a single packet is (ATT_MTU-1) octets in size. At a minimum, the Attribute Opcode is included in an Attribute PDU. An attribute value may be defined to be larger than (ATT_MTU-1) octets in size. These attributes are called long attributes.
To read the entire value of an attributes larger than (ATT_MTU-1) octets, the ATT_READ_BLOB_REQ PDU is used. It is possible to read the first (ATT_MTU-1) octets of a long attribute value using the ATT_READ_REQ PDU.
...
The maximum length of an attribute value shall be 512 octets.
Section 3.4.4.5 ATT_READ_BLOB_REQ:
If the value offset of the Read Blob Request is greater than the length of the attribute value, an ATT_ERROR_RSP PDU shall be sent with the Error Code parameter set to Invalid Offset (0x07).
From Vol 3, Part G (GATT):
Section 4.8.3 Read Long Characteristic Values
This sub-procedure is used to read a Characteristic Value from a server when the client knows the Characteristic Value Handle and the length of the Characteristic Value is longer than can be sent in a single ATT_READ_RSP PDU.
The ATT_READ_REQ and ATT_READ_BLOB_REQ PDUs are used to perform this sub-procedure. The Attribute Handle shall be set to the Characteristic Value Handle of the Characteristic Value to be read. To read the complete Characteristic Value an ATT_READ_REQ PDU should be used for the first part of the value and ATT_READ_BLOB_REQ PDUs shall used for the rest. The Value Offset parameter of each ATT_READ_BLOB_REQ PDU shall be set to the offset of the next octet within the Characteristic Value that has yet to be read. The ATT_READ_BLOB_REQ PDU is repeated until the ATT_READ_BLOB_RSP PDU’s Part Attribute Value parameter is shorter than (ATT_MTU – 1).
For each ATT_READ_BLOB_REQ PDU a ATT_READ_BLOB_RSP PDU is received with a portion of the Characteristic Value contained in the Part Attribute Value parameter.
So the idea is that the GATT server puts a value inside the characteristic, which is only allowed to be at most 512 bytes. Then whenever the GATT client wants to read this value (which can be up to 512 bytes), it can read the whole value in one go if the ATT_MTU is at most 513 using ATT_READ_REQ. When ATT_MTU is smaller so that the full value does not fit in an ATT_READ_RSP, the client must issue multiple ATT_READ_BLOB_REQs, with increasing offset for every request. It terminates when the returned value is smaller than the maximum size that can fit in an ATT_READ_BLOB_RSP. Note that ATT_READ_BLOB_REQ is usually not used when MTU >= 513, since all possible attribute values can always be read using a normal ATT_READ_REQ.
Since the maximum attribute value size is 512, an ATT_READ_BLOB_REQ containing an offset > 512 shall always result in a response having the error "Invalid Offset" (assuming the other conditions pass such as the handle exists and the attribute is readable in the first place etc.).
GATT is not designed for transferring data larger than 512 bytes. If you need to do that, you have some options:
Use notifications instead. Split up the data and send multiple notifications. The application programmer must somehow define a way to correctly reconstruct the full value from multiple notifications. To trigger the GATT server to start sending the value, the application programmer can design the GATT server so that the client first writes some instruction using a write characteristic operation, and when this operation is received, the server starts to send the notifications.
Use multiple reads. First split up the data in multiple chunks. The GATT server first places the first 512 bytes in the characteristic value. Whenever it detects that the GATT client has read the 512 first bytes, it places the next 512 bytes in the characteristic value so the client can read the next chunk. This option has lower throughput than using notifications, so there is not much of reasons to use this option over using notifications.
Use L2CAP CoC instead of using GATT. L2CAP CoC is made for large data transfers compared to GATT. Android supports this as of Android 10 and later.