iOS determine data length of CBCharacteristic

Viewed 390

Is there any way to dynamically sniff out the data length of a CBCharacteristic?

I'm evolving the characteristic API on a gadget I have, and I want to change the field width of one of the characteristics. If I make the change in the iOS side so that it writes a value of 9 bytes instead of 7 bytes, a device that has the old API (characteristic field width of 7) on it causes the following to occur when I attempt to write the value:

Error Domain=CBATTErrorDomain Code=13 "The value's length is invalid." UserInfo={NSLocalizedDescription=The value's length is invalid.}

What I'd like to determine is whether or not I can catch that error, and then somehow query the CBCharacteristic what its current field width is. Obviously at some point, it determined that 9 > 7 and caused the error to bubble up. I've tried reading the descriptor associated with the characteristic, but there's just one descriptor (<CBDescriptor: 0x2830cbe40, UUID = Client Characteristic Configuration, value = 2>) which doesn't tell me much.

2 Answers

This is a standard ATT protocol error that's generated by the peripheral, not iOS. It means you sent a value and the peripheral responded that the value was the wrong length. Characteristics do not necessarily have specific lengths. The correct length might be context dependent. For example, a characteristic might accept 2 bytes, 4 bytes, or 8 bytes. If you write 7 bytes, it could return this error. Or the first byte might be a command selector, and the rest might be the payload that needs to be of a specific length for that command. There's no simple "what's the length of this characteristic" for these designs.

There's no general way to know what a remote service wants. You need to know that through API documentation. This is the equivalent of getting back a 405 Method not allowed error from an HTTP server. It's up to you to know what methods are allowed. A particular system might give you a way to query it, and it might not. It's not part of the HTTP spec to provide that, and similarly it's not part of the BLE spec.

You can query the maximum packet length allowed by a characteristic with peripheral.maximumWriteValueLength(for:CBCharacteristicWriteType.<>)

Related