2

The basic problem I'm trying to solve is as follows. I have two iOS devices, one configured as a central, and the other as a peripheral. I would like the peripheral to know if the central moves away or becomes inactive for some reason (say the device running the central is turned off).

Under normal conditions, I have it set up so that as the central moves close to the peripheral, the central can use beacon regions and ranging to inform the peripheral via a characteristic-write when it is in the immediate proximity (CLProximityImmediate), and then again when it is still in range, but far off (CLProximityFar). This works well.

However, to catch a corner condition when the central device goes from being CLProximityImmediate to some unknown state, I was planning to used periodic indications from the peripheral to which the central can respond. If there is no response to the indication, then the peripheral can assume that the central is no longer in immediate proximity. However, I am not able to find a callback or delegate method that informs the peripheral manager that the indication failed.

The method updateValue:forCharacteristic:onSubscribedCentrals: returns NO when the underlying transmit queue is full-- and NOT because the central did not respond, the way I've understood it.

Am I missing something obvious here? Is there a way for the peripheral manager to tell that the central did not receive an indication? Or is there a missing callback in CoreBluetooth for this case?

Thanks for your help!

user108
  • 121
  • 2
  • 5

2 Answers2

5

There are two issues to let the peripheral know the location maneager lost contact with the CLBeacon:

  1. The iBeacons are passive, advertise and transmit only devices. As in the Apple implementation there are no connection made to them from the Core Location framework. Therefore the peripheral newer knows anyone listened to their broadcast.

  2. The CLBeacon will not expose the underlying BTLE peripheral as a CBPeripheral, so you would not be able to let the BTLE peripheral know your location monitor was in range.

Issue #2 can be resolved a rather complicated way:

  1. Start scanning for CBPeripherals where the advertisementData contains the proximityUUID.

  2. Make connections to that CBPeripheral and get notified of a characteristic value change.

  3. Change a characteristic value on the peripheral frequently, so when the Central sees no more notifications after a timeout period it indicates the peripheral is out of range.

  4. If you want to make it work for multiple iOS devices this gets way to complicated to switch between advertising and iBeacon and working as a GATT peripheral.

allprog
  • 15,913
  • 8
  • 54
  • 94
barbazoo
  • 977
  • 5
  • 11
3

Although this was not explicitly stated in the question, implicitly, I was stating that the peripheral was advertising a service with a couple of characteristics. This is in addition to the explicit iBeacon advertisement, which I agree is "passive". When the central is notified of the beacon region, it discovers and writes to one of the characteristics, and the peripheral can know that a central is in range.

My fundamental question is not regarding the passive nature of the beacon, but more about how "indications" work with CoreBluetooth. I think it is fairly safe to say that if a peripheral uses updateValue:forCharacteristic:onSubscribedCentrals: to inform a central subscribed to a characteristic defined as CBCharacteristicPropertyIndicate, there is no callback defined to capture the confirmation to the indication that should come back from the central (per GAP).

One workaround to this missing API is to define a third characteristic as a "confirmation" characteristic, and impose a protocol that the central should do a dummy read on this characteristic whenever the central receives peripheral:didUpdateValueForCharacteristic: to the indication which was subscribed. That should produce a call to peripheralManager:didReceiveReadRequest: on the peripheral to confirm that the indication was received.

This is more work, and not the most elegant way to do it, but it may be the best thing to do given that there is no API for indication confirmations.

user108
  • 121
  • 2
  • 5
  • Your answer does help and seems to be a decent work around. So, if the beacon advertisement is passive, there is no way we can have have something like a `session` between a particular beacon and a central device? Or is there? – Shobhit Puri Nov 01 '13 at 01:08
  • One can have a session between a peripheral advertising a beacon and a central. For this the central will have to be in the foreground though, to connect to the device advertising the beacon and discover other services. In the background, this will not currently work. See my response to another related question on backgrounding and CoreBluetooth here: http://stackoverflow.com/questions/9896562/what-exactly-can-corebluetooth-applications-do-whilst-in-the-background/19458200#19458200 – user108 Nov 03 '13 at 13:45
  • Thanks for your comment and the link. I read your other answer. However I'm still now sure how a `session` can be implemented. By session are you trying to say what the above answer suggests? i.e Writing to a different characteristic to tell the status of the session... – Shobhit Puri Nov 04 '13 at 23:53
  • Yes, in addition to a beacon you can implement a different set of read/write characteristics and establish a session. – user108 Nov 06 '13 at 02:47