How to correctly account for ATT MTU size in peripheral/central?

If I understand correctly, ATT MTU size negotiation is managed by CoreBluetooth automatically and transparently. (Just in case - I'm not talking about Bluetooth 4.2 PDU size negotiation here - as far as I know, it is rarely supported).


I'm not sure if / how to adjust my code to account for the actual MTU size to make communication as efficient as possible.


Let's say, I want to implement duplex serial-like data exchange between two devices (at least iOS 8). As I have seen, common approach (and maybe the best one) is to have two characteristics on the peripheral : one characteristic is "notifiable", the other one - writable. The peripheral sends data to the central through notifications, the central sends data to the peripheral through the writable characteristic.


The most technically useful answer that gave useful hints and highglighted possible caveats was http://stackoverflow.com/a/20321542/217823 by Justin Middleton. Is this even today, after 4 years, the most efficient way to implement BLE communication using CoreBluetooth?


I have seen a suggestion to use central.maximumUpdateValueLength on the peripheral to avoid pushing more data than the central can accept. Is this value affected by the ATT MTU size? Is there any similar way for the central side also to determine actual current MTU size when writing the data to the peripheral's writable characteristic? Or I should write in safe chunks of 20 bytes and ATT subsystem will automatically collect MTU-sized messages?


Also, I have heard that on some implementations you have to add a short sleep() after the first connection to give ATT subsystem some time to negotiate MTU sizes. Is this necessary for CoreBluetooth or does it happen automatically and I won't receive connection delegate calls sooner than MTU size negotiation was complete?

Answered by prognars in 228833022

It's really strange that noone could respond to this. The answer turned out to be pretty simple, although not well documented: I had to use maximumWriteValueLengthForType, which is available since iOS 9 and, unfortunately, not documented in Apple's API portal but at least it was documented in Obj-C headers.


https://developer.apple.com/reference/corebluetooth/cbperipheral/1620312-maximumwritevaluelengthfortype

I'll try to rephrase it simpler with a hope that someone might be able to help:


On iOS, we don't have control over ATT MTU (no methods like `requestMtu` on Android) and we can only find out current MTU size on the peripheral side using `central.maximumUpdateValueLength` (since iOS 7).


As I understand, this value is available only on peripheral side and I can use it to adjust my characteristic updates when sending notifications.


But what should I do on the central side when writing to a characteristic? How do I know what amount of data I can write at once?


It would be inefficient pushing data by default 20 byte packets if the central and the peripheral have already negotiated larger MTU size. But how can I find it out on the central side?


If there is any person reading this, who have been successfully written more than 20 bytes at once from the central side, I would be really grateful to hear from you - how did you know what exact MTU value to use when writing data to a peripheral's characteristic?

Accepted Answer

It's really strange that noone could respond to this. The answer turned out to be pretty simple, although not well documented: I had to use maximumWriteValueLengthForType, which is available since iOS 9 and, unfortunately, not documented in Apple's API portal but at least it was documented in Obj-C headers.


https://developer.apple.com/reference/corebluetooth/cbperipheral/1620312-maximumwritevaluelengthfortype

Hi prognars,

I'm searching like you a method to requestMtu in iOS, but I did not found anything !

But I can send send WriteRequest with more than 20 bytes in one packets, I can send 155 bytes, I retrieve this value (155) after sniffing the connection between the iPhone (Central) and my peripheral, I saw that the iPhone triggered automatically an ATT MTU nogociation with a value of 158, as my peripheral supports this value, It accepts, and use it as ATT_MTU value.

It's too bad not to have like in Andoid a method to call with a desired ATT MTU value.

Hi prognars,

Im having the same problem with my app.. I would like to send packets in the most efficient way possible. First of all and after 3 years could find a solution ? I was wondering to have a readable characteristic in the peripheral with the value of doing central.maximumUpdateValueLength, and from the central I will be able to have both MTUS, the central one by reading that characteristic from the peripheral and the peripherals by doing peripheral.maximumWriteValueLengthForType. This way my MTU will be the smallest value
How to correctly account for ATT MTU size in peripheral/central?
 
 
Q