There seems to be a race condition between the Peripheral connect() and setMTU() functions. If setMTU() is called immediately after connect(), the MTU is not always negotiated properly. The observed behavior is that the MTU appears to be negotiated properly, but then reading a characteristic that is supposed to return a "large" value (more than 22 bytes) results in only receiving the first 22 bytes.
This is a very intermittent issue, and appears to occur more frequently when running "fast". I see this issue up to 50% of the time when running my python application from the terminal, but I see it much less frequently when running in a debugger (pycharm).
It appears to have some relationship to which side initiates the MTU negotiation. Relevant btmon output below. Notice that in the success case, the remote device is the one that sends the first Exchange MTU Request, whereas in the failure case it is the local device that initiates the Exchange MTU Request. I would also note that I'm not sure why my local device is responding with Request Not Supported, but it does not seem to affect anything.
I seem to have resolved the issue by inserting a time.sleep(0.5) between the connect() and setMTU() calls. I'm not exactly sure how long of a sleep is required, but after adding the 1/2 second sleep(), I have yet to see this problem occur again.
Success case
> ACL Data RX: Handle 18 flags 0x02 dlen 7 #5989 [hci0] 5282.660245
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 104
< ACL Data TX: Handle 18 flags 0x00 dlen 9 #5990 [hci0] 5282.660660
ATT: Error Response (0x01) len 4
Exchange MTU Request (0x02)
Handle: 0x0000
Error: Request Not Supported (0x06)
< ACL Data TX: Handle 18 flags 0x00 dlen 7 #5991 [hci0] 5282.661032
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 185
> HCI Event: Number of Completed Packets (0x13) plen 5 #5992 [hci0] 5282.705223
Num handles: 1
Handle: 18
Count: 2
> ACL Data RX: Handle 18 flags 0x02 dlen 7 #5993 [hci0] 5282.749175
ATT: Exchange MTU Response (0x03) len 2
Server RX MTU: 104
Failure case
< ACL Data TX: Handle 64 flags 0x00 dlen 7 [hci0] 42.373367
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 185
> ACL Data RX: Handle 64 flags 0x02 dlen 7 [hci0] 42.417932
ATT: Exchange MTU Request (0x02) len 2
Client RX MTU: 104
< ACL Data TX: Handle 64 flags 0x00 dlen 9 [hci0] 42.418090
ATT: Error Response (0x01) len 4
Exchange MTU Request (0x02)
Handle: 0x0000
Error: Request Not Supported (0x06)
> HCI Event: Number of Completed Packets (0x13) plen 5 [hci0] 42.467363
Num handles: 1
Handle: 64
Count: 2
> ACL Data RX: Handle 64 flags 0x02 dlen 7 [hci0] 42.515483
ATT: Exchange MTU Response (0x03) len 2
Server RX MTU: 104
There seems to be a race condition between the Peripheral
connect()
andsetMTU()
functions. IfsetMTU()
is called immediately afterconnect()
, the MTU is not always negotiated properly. The observed behavior is that the MTU appears to be negotiated properly, but then reading a characteristic that is supposed to return a "large" value (more than 22 bytes) results in only receiving the first 22 bytes.This is a very intermittent issue, and appears to occur more frequently when running "fast". I see this issue up to 50% of the time when running my python application from the terminal, but I see it much less frequently when running in a debugger (pycharm).
It appears to have some relationship to which side initiates the MTU negotiation. Relevant
btmon
output below. Notice that in the success case, the remote device is the one that sends the firstExchange MTU Request
, whereas in the failure case it is the local device that initiates theExchange MTU Request
. I would also note that I'm not sure why my local device is responding withRequest Not Supported
, but it does not seem to affect anything.I seem to have resolved the issue by inserting a
time.sleep(0.5)
between theconnect()
andsetMTU()
calls. I'm not exactly sure how long of a sleep is required, but after adding the 1/2 secondsleep()
, I have yet to see this problem occur again.Success case
Failure case