4
votes

We have an app that is communicating with our own BLE device. When we push a new firmware we reboot and we get the centralManager: didDisconnectPeripheral: error: and the centralManager: didConnectPeripheral: but when we call [peripheral discoverServices:nil] we never get the callback for peripheral: didDiscoverServices:. We get it when we initially connect but not when we reconnect. CoreBluetooth seems to know what the services and characteristics are because we can interact with the device but we want to be able to write a characteristic right after the reboot but can't find a reliable way to tell when that is.

-= EDIT =- This is the code we're using for writing characteristics. When we try calling it on the second call to didConnect it fails because the peripheral doesn't have any services:

+(void)writeData:(NSData*)data toPeripheral:(CBPeripheral*)peripheral service:(NSString*)sCBUUID characteristic:(NSString*)cCBUUID
{
    // Sends data to BLE peripheral to process HID and send EHIF command to PC
    for(CBService *service in peripheral.services)
    {
        if([service.UUID.stringValue isEqualToString:sCBUUID])
        {
            for(CBCharacteristic *characteristic in service.characteristics)
            {
                if([characteristic.UUID.stringValue isEqualToString:cCBUUID])
                {
                    /* EVERYTHING IS FOUND, WRITE characteristic ! */
                    [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
                    return;
                }
            }
        }
    }
}
1
Can't you read once you get the second call to didConnectPeripheral? - Paulw11
We tried but it fails because the peripheral doesn't know its services at that point. I updated my question with more information. - CaseyB
I've had a similar issue. It turned out that iOS was internally caching characteristic descriptors. After the firmware was updated, the descriptors table in the peripheral changed somehow and the phone couldn't discover them anymore (until the phone was rebooted). I'll ask my colleagues working on firmware for further details. - Michał Ciuba
@MichałCiuba Very cool! I look forward to hearing your response. - CaseyB
Yes, we did. We call NSArray * peripherals = [self.centralManager retrieveConnectedPeripheralsWithServices:self.allServices]; which returns a list of devices that CoreBluetooth thinks it's connected to. Since it has those caches calling discoverServices never actually does anything. - CaseyB

1 Answers

1
votes

I remember from my work with CoreBluetooth that this behavior is intended because it's documented this way. We shouldn't reuse the same peripheral instance once disconnected. Instead we should ask CBCentralManager to give us a fresh CBPeripheral using its known peripheral UUID. See also: CBCentralManager.retrievePeripheralsWithIdentifiers: