Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Bluetooth slow down when sending packets

I'm experiencing an issue where the time between writing a value to a characteristic using the

[peripheral writeValue:dataPacket forCharacteristic:writeChar type:CBCharacteristicWithResponse]

and the iOS device actually physically sending the bluetooth packet is progressively taking longer and longer.

This can be illustrated in the following output from the debugger:

2013-10-23 14:12:17.510 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:17.595 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:17.598 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:17.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:17.656 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:17.657 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:22.601 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:23.123 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:23.125 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:27.601 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:28.111 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:28.113 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:32.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:34.595 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:34.597 Test App iOS[1561:60b] Packet response received


2013-10-23 14:12:37.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:39.582 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:39.585 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:42.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:44.570 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:44.573 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:47.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:49.558 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:49.560 Test App iOS[1561:60b] Packet response received

// Several packets omitted...

2013-10-23 14:13:07.610 Test App iOS[1561:60b] Packet sent
2013-10-23 14:13:09.508 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:13:09.511 Test App iOS[1561:60b] Packet response received

2013-10-23 14:13:12.610 Test App iOS[1561:60b] Packet sent
2013-10-23 14:13:14.496 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:13:14.498 Test App iOS[1561:60b] Packet response received

// And so on...

The Packet sent message is output at the line immediately after the writeValue command to write the packet of data to the characteristic.

The packet sent confirmation is output in the first line in the didWriteValueForCharacteristic delegate method.

The packet response received message is output in the didUpdateValueForCharacteristic which is called when the BTLE device sends the response packet (via a secondary notification characteristic) to confirm receipt of my sent packet.

As can be seen initially the time between my calling the writeValue forCharacteristic method and the callback to confirm the packet has been sent in didWriteValueForCharacteristic is initially 85ms (which is already slow but bearable). I send these packets approx every 5 seconds, and after only a small number of packets sent this increases to ~2 seconds after which is seems to be static continually at 2 seconds. The response packet sent back from the BTLE device is always ~2ms after the confirmation of the packet being sent.

I don't understand why I'm getting this delay in the CoreBluetooth libraries between calling writeValue and the confirmation callback didWriteValueForCharacteristic.

In all other respects the code is working perfectly (the BTLE device is doing exactly what it is being instructed to do and none of the packets go missing).

I have a sample app that is provided by the BT4.0 module manufacturer (including source) which does not experience this growing delay - unfortunately the sample app is designed to cope with a large range of implementations of the module, not just our specific implementation and so is massively complex containing much code that is just not relevant to our implementation - I've placed breakpoints in every function in the sample and manually stepped through to determine exactly which commands they are issuing, and I believe I am copying them perfectly (but obviously not).

I can see nothing that they are doing that I am not doing and vice versa. The only difference I can spot between the two projects is that mine uses ARC and theirs uses manual reference counting.

Other information: Everything is running on the main thread (as it is with the module manufacturers sample app) I create the Central Manager using the main queue (similarly in module manufacturers sample app) CPU load on the iOS device is only at 3% whilst my app is running and nothing seems to be being delayed due CPU load etc.

I'm tearing my hair out with this, and if anyone can suggest any possible causes or solutions for this problem I would be eternally grateful!

Thanks, Rich

like image 560
Richard Baxter Avatar asked Oct 23 '13 13:10

Richard Baxter


2 Answers

I have made some progress on this and the news isn't good. It turns out that my original description of the problem is incorrect. I'd assumed (always a bad thing to do) that the sample app produced by the module supplier would be correct however the timing figures it's reporting are wrong - when they report ~3ms to send the packet and retrieve the response they are only timing from the -didWriteValueForCharacteristic and do not include the time between calling the writeValueForCharacteristic and the didWriteValueForCharacteristic - once I included this time their app behaves as slowly as mine.

After all the further investigation it appears that the iOS CoreBluetooth libraries are causing the delay between requesting the packet be sent and it actually begin sent - these arbitrary delays can be anywhere between 80ms and 2seconds. Does anyone know why the iOS libraries are so slow at sending the actual packet? Our equivalent code running under Android is more or less instant.

If I had my cynical hat on I would say Apple are deliberately doing this to prevent applications requiring a fast response from being developed using BTLE and thereby force the hardware developers to use Bluetooth 3 which requires the apple security chip and thereby effectively incurs an apple licensing cost on units manufactured...

like image 64
Richard Baxter Avatar answered Oct 08 '22 01:10

Richard Baxter


First of all check what you get in:

-(void) peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
 error:(NSError *)error {

}

if the error code is 0 that means you are sending value to peripheral WITHOUT confirming it. Check if your periheral implements this method:

//assuming 
@property (strong, nonatomic) CBPeripheralManager       *peripheralManager;

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
    NSLog(@"WRITE REQUEST!!! %lu",(unsigned long)requests.count);
    //check if there are data

   for (CBATTRequest * req in requests) {
   //send reposnse to Central that you recivied write value and eg / accept / reject the write request
    [self.peripheralManager respondToRequest:req
                                          withResult:CBATTErrorSuccess];
   }


}
like image 27
Marcin Małysz Avatar answered Oct 08 '22 00:10

Marcin Małysz