2

I'm Having an issue with Core Bluetooth under iOS. I'm programming an OTA updater, and running into a strange issue. When I switch the device into OTAU mode it disconnects and advertises different services under the same device UUID, problem is, when I try to find services from the newly connected device I'm given the old list of services, which are no longer valid. A telling part of the problem is that the CBPeripheral.name value is the original device name, but in the advertising dictionary returned to didDiscoverPeripheral it is the correct, new name.

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
for (id key in advertisementData) {
    NSLog(@"key: %@, value: %@ \n", key, [advertisementData objectForKey:key]);
}
NSLog(@"Discovered peripheral with identifer: %@, state: %d, name: %@, services: %@",
      [peripheral identifier],
      [peripheral state],
      [peripheral name],
      [peripheral services]);

if (!self.peripherals)
    self.peripherals = [[NSMutableArray alloc] initWithObjects:peripheral,nil];
else
{
    for(int i = 0; i < self.peripherals.count; i++)
    {
        CBPeripheral *p = [self.peripherals objectAtIndex:i];

        if ((p.identifier == NULL) || (peripheral.identifier == NULL))
            continue;

        if ([self UUIDSAreEqual:p.identifier UUID2:peripheral.identifier])
        {
            [self.peripherals replaceObjectAtIndex:i withObject:peripheral];
            NSLog(@"Duplicate UUID found updating...");
            return;
        }
    }
    peripheral.delegate = self;
    [self.peripherals addObject:peripheral];

    NSLog(@"New UUID, adding");
    }
}

Here's what I see back:

  key: kCBAdvDataChannel, value: 38 
  key: kCBAdvDataLocalName, value: Xxxx1000_boot 
  key: kCBAdvDataIsConnectable, value: 1 
  Discovered peripheral with identifer: <__NSConcreteUUID 0x156787d0> 9E7A4F82-29F2-08EF-F6A5-9ADCC0790B7F, state: 0, name: Xxxx1000, services: (null)

often, for the next clean run of the program it will show the other way around with the Xxxx_boot for the peripheral name and Xxxx for the advertised name (advertising always correct).

I don't know of any way to clear peripheral information saved within CBCentralManager, I've even tried creating a new instance of the CentralManager, but nothing seems to work. Any ideas?

Chris Howell
  • 29
  • 1
  • 4
  • 3
    To reliably discover the services of a peripheral you should connect to it and call `discoverServices`. Examining the advertising data directly is not reliable – Paulw11 Jul 24 '14 at 23:36
  • Actually, I am discovering services. My issue seems to be that my device wasn't sending a correct Service Changed characteristic, so that when I would request services after the device switched to bootloader I would still get back the old list of services. Apparently, there is no way to clear the saved list of services in iOS. It only will update it's list if it receives a Service Changed characteristic. – Chris Howell Aug 27 '14 at 15:48

1 Answers1

0

The advertisement is actually just a hint. It can contain practically anything from your "shoe size" to the hosted services. Just look at the iBeacon profile. You should never rely exclusively on this data and Core Bluetooth will not use this info in any other ways either.

The peripheral name is loaded from the corresponding characteristic on the peripheral. Once that is read by iOS, it will be used in the CBPeripheral.name property and the advertised name will simply be ignored. On reconnection, the name will be refreshed automatically.

In conclusion,

  1. don't judge before connection, the advertisement can lie and Core Bluetooth uses it cautiously
  2. always discover the services after connection
  3. mind the peripheralDidUpdateName: callback
Community
  • 1
  • 1
allprog
  • 16,540
  • 9
  • 56
  • 97
  • wah. you answering questions at such a time <3 – Etan Jul 28 '14 at 08:41
  • My problem seems to be with my device not sending a Service Changed characteristic. Unlike most other platforms, iOS doesn't seem to allow it's database of services and characteristics saved for a particular device to be erased, and doesn't automatically rescan, unless a Service Changed is received. So discovering services simply returns the same list that was retrieved the first time the device was connected. – Chris Howell Aug 27 '14 at 16:01
  • That's another possibility. It's true that the cache cannot be invalidated programmatically. But it is weird that CB requires the device to send the service changed. It seems to be not trivial to decide on the peripheral side whether this notification has to be sent for a specific central or not, so in practice it is probably not reasonable to build on this notification so strongly. May be worth a bug report. Let's hope you can fix the firmware. – allprog Aug 28 '14 at 10:14