Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to improve performance of CBCentralManager while CBPeripheralManager is active

We've created an iOS app that implements a CBCentralManager to connect to a device that we've created, that transmits data at 10Hz. It's vitally important that this data comes through and displays quickly, so we have built tight latency checks around this, if too many points are missed or if the local clock detects that incoming values are slowed, we will fault and break the connection.

The client has asked us top implement a second iOS app that will observe the first one. We implemented a CBPeripheralManager in the original app which advertises, can be connected to, and will periodically publish its data to a few outgoing characteristics.

What we are finding is that we cannot seem to connect the observer iOS app to the original iOS app (i.e., the original iOS app has both a CBCentral connection to the device and CBPeripheral connection to the observer app active at the same time), without tripping up our latency checks on the incoming data from the device.

I've tried everything I can think of, I've used separate queues for both CBPeripheralManager and CBCentralManager, as follows:

    q = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
    ptr_CBPeriphMgr = [[CBPeripheralManager alloc] initWithDelegate:self queue:q];

Also,

  • I logged and timestamped everything, verified none of my code is taking too long
  • I moved almost all of my code out of BLE handlers to make them very light and not blocking,
  • I tried the separate queues (example shown above), with low priorities
  • I have tried slowing my CBPeripheralManager data rates to a trickle, a few updates a second
  • I have tried suspending the latency checks for three seconds after a CBPeripheralManager connection is established (which is very not ideal), but the problem seems to kick in randomly, not just after a connection.

It seems like no matter what I try, after 4-5 minutes of both peripheral and central connections being active (we have a loop where the second App repeatedly connects and disconnects every five seconds, to challenge the device connection) my incoming value updates from the device to the central slows to about 1/4 or 1/5 speed, or they stop for a full second and then three or four updates come in nearly simultaneously -- both of which trip our latency checks. It's like some queue is getting filled up and performance flatlines, but as I mentioned above I think I'm using separate queues.

I'm at my wits end... does anybody have any thoughts about how to prioritize my central functions over my peripheral functions in the iOS app, or to somehow improve performance to prevent this from being an issue and keep my app responsive to 10Hz updates from the device, even when being observed as a peripheral?

(Edited to state that we are connecting/disconnecting the second App repeatedly... perhaps I'm not cleaning up after the disconnection properly, and the garbage piles up and screws up BLE? That would explain why the problem seems to occur after 4-5 minutes regardless of the frequency of data updates over the second connection.)

like image 541
Chris Avatar asked Oct 29 '22 06:10

Chris


1 Answers

Here are some suggestions:

  • Try creating queues using QOS_CLASS_USER_INITIATED or higher instead of QOS_CLASS_UTILITY.
  • Make sure that you call -[CBCentralManager stopScan] whenever you do not need to be scanning for peripherals, and -[CBPeripheralManager stopAdvertising] whenever you do not need to be prepared for incoming connections (probably whenever you are connected).
  • Call -[CBPeripheralManager setDesiredConnectionLatency:forCentral:] to reserve more resources.

However, if you can target iOS 11+, what I would recommend to decrease latency and increase speed is using a L2CAP channel. Although CoreBluetooth's L2CAP support is not documented well, here is a list of the available APIs.

like image 113
Coder-256 Avatar answered Nov 15 '22 10:11

Coder-256