Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreBluetooth: number of bytes sent != number of bytes received

I have an app that is acting as a peripheral and another app that is acting as a central. The central app is reading a characteristic on the peripheral:

    [self.service.peripheral readValueForCharacteristic:self.packetCharacteristic]

The peripheral handles the request as such:

    - (void)peripheralManager:(CBPeripheralManager *)manager didReceiveWriteRequests:(NSArray *)requests
    {
        for (CBATTRequest *request in requests)
        {
            if ([request.characteristic.UUID isEqual:self.service.packetCharacteristic.UUID])
            {
                NSData *value = self.packets[0]; // This value's length logs at 512 bytes, tested 500 bytes too
                request.value = value;
                [self.peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
            }
        }
    }

The size of NSData *value is equal to 512 bytes. Note that I have also tested this with 500 bytes.
The central then receives the the delegate call as such:

    - (void)didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    {
        if (characteristic == self.packetCharacteristic)
        {
            NSLog(@"PACKET RECEIVED: %lu bytes", (unsigned long)characteristic.value.length);
        }
    }

The NSLog statement states that the value received is 536 bytes regardless of if I send 500 or 512 bytes. The bytes sent and the bytes received are identical until about a quarter of the way through (by looking at the HEX value provided by Xcode), the rest of the bytes are completely different.

The questions are as follows:
1. Why am I receiving more bytes than I have sent?
2. What are these bytes? What do they represent?
3. Where can I find documentation on this? I have reviewed the CoreBluetooth docs/guides over and over and can't find anything indicating that this could happen. 4. Could this be related to endianness?

EDIT #1

Ok, so I have done a little bit more testing and found out the following... The MTU seems to be 134 bytes (from iOS to iOS). As soon as the data being sent is equal or bigger than 134 bytes, CoreBluetooth is calling peripheralManager:didReceiveReadRequest: 4 times.

My assumption is that because the data being sent is at least equal to the MTU, CoreBluetooth doesn't know whether or not it is done sending all the data. Therefore it calls peripheralManager:didReceiveReadRequest: N number of times until N x MTU covers the maximum possible size of a characteristic's value (512 bytes). In my particular case, 4 x 134 bytes equals the magical 536 bytes.

Note that the request's offset is being updated every time, in my particular case, 0, 134, 268, 402.

Edit #2

Ok, figured it out. I was semi-right in my assumption. CoreBluetooth calls peripheralManager:didReceiveReadRequest: N time until the data being sent is smaller than the MTU. If the data being sent is equal or larger than the MTU, CoreBluetooth will keep calling peripheralManager:didReceiveReadRequest: until it N x MTU covers the max size (512 bytes). If the data % MTU == 0 then peripheralManager:didReceiveReadRequest: will be called one last time where you have to return 0 bytes.

like image 800
bsarrazin Avatar asked Apr 03 '14 18:04

bsarrazin


1 Answers

Answering my own question. Look at edit #2.

like image 101
bsarrazin Avatar answered Nov 05 '22 12:11

bsarrazin