2

While developing a BLE app for iOS, I keep getting a disconnect immediately after discoverServices is called. I am testing with 4 exact BLE devices (OEM), and I keep getting this disconnect on exactly the same two devices. Every time. I know the devices are ok, because I've also built the same app on Android, and with the same devices, all 4 stay connected. This is using Titanium, but everything here is implemented in iOS. Here's the relevant iOS code:

- (void)centralManagerDidUpdateState:(CBCentralManager *)central

    {
TiLogMessage(@"[INFO] ===== %@ - centralManagerDidUpdateState: entry",self);

NSString *state = nil;

switch (central.state) {
    case CBCentralManagerStatePoweredOn:
        state = @"CentralManagerStatePoweredOn";
        break;

    case CBCentralManagerStateUnknown:
        state = @"CentralManagerStateUnknown";
        break;

    case CBCentralManagerStateResetting:
        state = @"CentralManagerStateResetting";
        break;

    case CBCentralManagerStateUnsupported:
        state = @"CentralManagerStateUnsupported";
        break;

    case CBCentralManagerStateUnauthorized:
        state = @"CentralManagerStateUnauthorized";
        break;

    case CBCentralManagerStatePoweredOff:
        state = @"CentralManagerStatePoweredOff";
        break;

    default:
        TiLogMessage(@"[INFO] ===== %@ - centralManagerDidUpdateState default -> break",self);
        break;
}

TiLogMessage(@"[INFO] ===== %@ - centralManagerDidUpdateState state changed to: %@",self, state);

NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:state, @"state", nil];

if ([self _hasListeners:@"centralManagerStateChange"]) {
    [self fireEvent:@"centralManagerStateChange" withObject: event];
}

TiLogMessage(@"[INFO] ===== %@ - centralManagerDidUpdateState: exit",self);

}

- (void) connectPeripheral:(id)args
    {
TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - entry",self);

NSString* uuid = [[[args objectAtIndex:0] objectForKey:@"peripheral"] objectForKey: @"UUID"];

for (CBPeripheral *peripheral in self.discoveredPeripherals){
    if ([[peripheral.identifier UUIDString] isEqualToString:uuid]){
        TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - device is %@",self, peripheral);
        TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - attempting to connect to %@",self, peripheral.name);

        if (self.connectedPeripherals){
            TiLogMessage(@"[INFO] ===== %@ : connectedPeripheral - connectedPeripherals is ok...",self);

            if (![self.connectedPeripherals containsObject:peripheral]){
                TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - device is not connected. Connecting.",self);

                if (centralManager.state == CBCentralManagerStatePoweredOn){
                    [centralManager connectPeripheral:peripheral options:nil];
                }
            }
            else{
                TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - device is already connected. %@",self,peripheral);
            }
        }

    }
}

TiLogMessage(@"[INFO] ===== %@ : connectPeripheral - exit",self);

}

- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral

    {
TiLogMessage(@"[INFO] ===== %@ : didConnectPeripheral - entry",self);

if ( [manuallyDisconnectedPeripherals containsObject:[peripheral.identifier UUIDString]] ){
    [manuallyDisconnectedPeripherals removeObject:[peripheral.identifier UUIDString]];
}

if (![self.connectedPeripherals containsObject:peripheral]){

    [peripheral setDelegate:self];
    [self.connectedPeripherals addObject: peripheral];

    NSNumber *RSSI = 0;
    if (peripheral.RSSI != nil){
        RSSI = peripheral.RSSI;
    }

    NSDictionary *peripheralObj = [NSDictionary dictionaryWithObjectsAndKeys: [peripheral.identifier UUIDString], @"UUID",
                               peripheral.name, @"name",[NSNumber numberWithInteger:1], @"isConnected", RSSI, @"RSSI", nil];

    NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys: peripheralObj, @"peripheral",
                       [peripheral.identifier UUIDString], @"UUID",nil];

    if ([self _hasListeners:@"didConnectPeripheral"]) {
        [self fireEvent:@"didConnectPeripheral" withObject: event];
    }
}

TiLogMessage(@"[INFO] ===== %@ : didConnectPeripheral - exit",self);

}

- (void) discoverServices:(id)args
    {
TiLogMessage(@"[INFO] ===== %@ : discoverServices - entry",self);

ENSURE_SINGLE_ARG(args,NSDictionary);
NSString *peripheralUUID = [[args objectForKey:@"peripheral"] objectForKey:@"UUID"];

TiLogMessage(@"[INFO] ===== %@ : discoverServices - for %@",self,peripheralUUID);

if (self.connectedPeripherals){
    for (CBPeripheral *peripheral in self.connectedPeripherals){
         if ([[peripheral.identifier UUIDString] isEqualToString:peripheralUUID]){
             TiLogMessage(@"[INFO] ===== %@ : discoverServices - , attempting to discover services for %@",self,peripheral);

             [peripheral discoverServices: [BLEServicesCBUUIDs count] > 0 ? BLEServicesCBUUIDs : nil];
         }
    }
}

TiLogMessage(@"[INFO] ===== %@ : discoverServices - exit",self);

}

Marco
  • 6,692
  • 2
  • 27
  • 38
Chuksy
  • 43
  • 2
  • 6

2 Answers2

3

You need to keep CBPeripheral instance (by which you are working) strongly. For example in your view controller you need to have a property

@property (strong, nonatomic) CBPeripheral *activePeripheral;

Assign found peripheral to activePeripheral, after which do your staff (connecting/discovering/etc...)


I think using Framework like a CoreBluetooth is not a good way to achieve good results, you need something high level, block based. Here is a library that I have just commited for you https://github.com/LGBluetooth/LGBluetooth

It will make life with bluetooth much more easier.

iHarshil
  • 739
  • 10
  • 22
l0gg3r
  • 8,864
  • 3
  • 26
  • 46
  • Thanks. I did finally got it working. I used a strong NSMutableArray to hold the discovered objects, that fulfils the same as using the property you referenced because I am doing discovery of multiple objects. – Chuksy Feb 08 '14 at 15:48
  • I'm already doing this with no luck to get it work. I'm still don't why !!! any help/suggestion please? – Maystro Jul 08 '14 at 10:30
  • The problem is that I'm doing my own library that's why I don't need to use it – Maystro Jul 08 '14 at 11:22
1

I was able to get this working with CoreBluetooth, using an NSMutableArray to hold the objects. This did the trick:

@property (strong, nonatomic) NSMutableArray *discoveredPeripherals;

//then in your didDiscoverPeripheral delegate:
if ( ![discoveredPeripherals containsObject peripheral]{
    [discoveredPeripherals addObject peripheral];       //this right here retains the obj
}
Chuksy
  • 43
  • 2
  • 6