Max achievable polling frequency using Bluetooth LE GATT profile? - ios

I am trying to understand BLE and GATT in more depth. My interest is in the max achievable number of reads you would able to make per second over the GATT profile.
I am aware of some of the post made on this topic before, for instance:
Bluetooth Low Energy - updating a characteristic value repeatedly
However, I am trying to explain these results looking at the BLE specification.
What is the relationship between connection events and GATT? Does each ATT read/write require a new connection event? If not, is it possible to say anything about how many ATT read/writes can be made per connection event?
Say I want to poll a BLE connected light sensor for a single byte value, what would be the max Hz I could achieve? Would it always be best to set the mininum connection interval as low a possible?
Would I be able to achieve better results using "GATT server notifications? In the BLE spec (Core_v4.0) it says that "The master initiates the beginning of each connection event". Then how are GATT server notifications implemented? I would think that would require the server to initiate a connection event.
Finally, if anybody knows about any specific iOS imposed limitations on the throughput I would be able to achieve when polling a sensor intensively, I would love to hear about it.

I can answer a portion of of those questions...
What is the relationship between connection events and GATT?
They're different levels of the protocol. You handle connections and connection events via HCI. GATT is something you use after you've connected.
Does each ATT read/write require a new connection event?
No. Once you're connected you can do multiple read/write or other GATT commands.
If not, is it possible to say anything about how many ATT read/writes can be made per connection event?
I think the best method is to actually benchmark the speed yourself. However, the whole point of BLE is a reduction in power usage at the expense of speed. If you're concerned about speed that you probably shouldn't be doing it with BLE. The whole point of notifications/indications is so you don't have to poll an attribute but only get a message when a certain event has occurred.
Say I want to poll a BLE connected light sensor for a single byte value, what would be the max Hz I could achieve? Would it always be best to set the mininum connection interval as low a possible?
See above 2 answers.
Then how are GATT server notifications implemented?
Once you've implemented a GATT connection there's 2 way communication going on between the master and slave-device. Either device can send events to the other. In order to use notifications, you set a bit on a particular attribute to say you want notifications on that information. Then, depending on how that notification works, you'll get events sent back to you whenever there's something to report. I have a feeling that a lightbulb wouldn't have any sort of notification unless there's some interface on it besides the BLE connection. I typical application would be something like a thermometer where it would send a notification every time the temperature changed by 1 degree.
Conclusion:
If you're polling attributes you're doing it wrong. But it's possible that you have to do it wrong because the device didn't properly implement notifications in the way you need and you can't modify the device. However, polling will ramp up the battery usage significantly and you'll have loss the benefit of using BLE.

Related

CoreBluetooth data package lost when sending via withoutResponse

On iOS some data packets are lost via BLE.
On a characteristic we have the type .withoutResponse we check of course for canSendWriteWithoutResponse and func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral).
This is also stated in the documentation.
On the other hand, if you specify the write type as
CBCharacteristicWriteType.withoutResponse, Core Bluetooth attempts to
write the value but doesn't guarantee success. If the write doesn't
succeed in this case, you aren't notified and you don't receive an
error indicating the cause of the failure.
Anyone have an idea how I can fix this without switching to withResponse ?
BLE is a distributed protocol. It is always possible to lose data. The only way you can ensure that you haven't lost data is to receive some notification back that the data was received correctly (often called an ACK for Acknowledge). The standard BLE way to achieve this is with responses. But you're free to implement your own ACK scheme if you don't want to use the standard one.
As an example, you can create a "confirmation" characteristic in your peripheral that your central subscribes to. When you send a write, you would wait until you receive a notification from that characteristic. If you don't see a notification after some timeout, the write may have been lost. This re-implements the standard write-with-response system at a higher layer.
Several of the BLE protocols I work on are actually serial protocols (we write to a characteristic, and read responses from the same characteristic). We often implement the ACK directly into the serial protocol (for example, returning <msgid>OK) without needing a BLE write-response.
Another solution is to write to the characteristic, and then read from the characteristic to see if it's updated, provided the characteristic is symmetric in that way (many aren't). I am fairly certain that there's no write-caching that would bite you here, since BLE reads and writes often aren't symmetric, but you should double-check that before relying on it. (See the Core Bluetooth WWDC videos from 2019 and 2017.)
As with all distributed systems, it's also never possible to know that data was lost. It's possible that the data arrived, and that the response was lost. This is the nature of distributed protocols, and just has to be figured into the system. This is why it's possible to build a system that will deliver a message at least once (provided that delivery is ever possible), or a system that will deliver a message at most once, but it's impossible to build a system that will deliver a message exactly once.
If you have no control over your peripheral, and it doesn't provide any error detection mechanisms, then there's nothing you can do on the central (phone) side. You have to have some cooperation from both sides to build a fault-tolerant distributed protocol.

Does iOS delay peripheralManager:didReceiveWriteRequests: and peripheralManager:didReceiveReadRequest:?

I use an iPhone as a peripheral to communicate with a micro controller (BLE chip in question is the BGM113). After connecting from the MCU, the MCU sends a couple of read and write requests for characteristics serially. Each request takes only a few ms in the MCU. On the iPhone side, responding to each request also only takes a few ms in the relevant methods (peripheralManager:didReceiveWriteRequests: and peripheralManager:didReceiveReadRequest:).
Still, I have roughly 500ms delay between each request. I have a support request running with the bluetooth chip manufacturer to clarify, but my gut feeling tells me that the fruity company is to blame...
Can anyone confirm such delays when reading or writing characteristics?
(more details: all characteristics are in the same service, read and write may happen on the same characteristic serially, there are several characteristics that I operate on.)
Your delay will be between 1 and 2 times the connection interval, so you set the connection interval to match your maximum delay requirement. Note that the energy consumption for the radio is linear to the inverse of the connection interval though.

Core Bluetooth Peripheral disconnects every 30 seconds

I have an app that acts as a Bluetooth LE peripheral. I have a single service with four characteristics. 2 out of the 4 are read and write only, the other two are configured as notify.
If I subscribe to one of the "notify" characteristics then the app will not disconnect until I do so manually, works well.
My issue is, If I read or write to the other characteristics, and the then am inactive for around 30 seconds, the BTLE connection disconnects from the peripheral. This may be a limitation set by apple, not sure.
Anyone know of a solution to keep the peripheral active even when there aren't any subscribers and no read or write command has been received in 30 seconds??
This is a by-product of the BLE 4.0 specs. Bluetooth Low Energy is explicitly designed to not maintain a connection for long periods which is what you are describing.
The only way to bypass this (beyond subscribing to a characteristic as you have found) would be to modify the implementation of the BLE stack on the peripheral you are connecting to and removing or elongating the interval of connection to a point that you find satisfactory.
Although this may not help you either as both sides of the BLE communication negotiate these values and iOS may impose a maximum below your requested threshold.
In my case reason was in a mismatch between characteristic properties. I wrote data to a characteristic with "waiting for response" option, but characteristic was in 'without response' state.
The symptom: write callback in delegate does not work when BLE peripheral did not write a response.

Sending only one iBeacon Packet

Is it possible to send only 1 iBeacon packet? I have tried using CBPeripheralManager,but since there are only 2 method to start and stop advertising, so I can't control how many packet is being broadcast.
What I want to try to do is use an iBeacon packet as a command, instead of just a broadcasting some ID. So I could send 1 iBeacon packet, and if the receiver got the message, it can send back Acknowledgement with another iBeacon packet. The intention is to avoid the pairing of bluetooth to send very simple data. The information will be linked to UUID, major, and minor of the packet.
Or are there better ways to do this than using iBeacon.
Yes, you can use iBeacon technology to send information back and forth between two iOS devices without pairing. If you have two devices, Device A and Device B, you set both of them up to range for beacons with a common ProximityUUID, say, E2C56DB5-DFFB-48D2-B060-D0F5A71096E0. And then you can exchange information in the two byte major and minor fields.
What you can't do is control the transmitter enough to send only a single iBeacon advertisement. The transmitter in iOS sends out 10 advertisement packets per second, so the best you could do is start the transmitter then stop it on a timer about 100ms later. (You probably shouldn't do this, because there is no guarantee that a single iBeacon advertising packet will be received successfully by the other device -- it may be lost due to a CRC error in the radio noise. You are probably better off letting the packet continue to transmit until you can confirm from a response from the other device that it was received.)
You can see an example of starting and stopping a transmitter on a timer in my answer here.
Of course, there may be easier and more robust ways of accomplishing what you want with built-in Bluetooth data exchange mechanisms. But that doesn't change the fact that what you propose is certainly possible.
No you can't since iBeacon is uni-direction device

iOS Bluetooth Low Energy emission rate

Apologise for the probably use of the wrong word in my question but for the life of me I can't think of the right one.
Anyway, I've been playing about with the Bluetooth Low Energy and I'm trying to create something that is going to use the RSSI signal strength the BLE device emits. For this, I need it to emit its pulse multiple times per second.
Is there a way I can up the amount of times my devices either scan for a signal, or broadcast their signal through code on iOS devices?
No, there is no API for you to change the advertisement speed or radio power.
This aspect is fully controlled by the system. You can only start and stop the advertisement and add some metadata to the packets: device local name, advertised services, etc. Moreover, the contents of the advertisement packets will differ depending on whether your app is in the background or foreground and, additionally, in background it will be slowed down. These effects have been documented in various SO questions and in the header files.
If your clients are iOS applications, then they should use either the RSSI in the advertisement packets (centralManager:didDiscoverPeripheral:advertisementData:RSSI: method) or when connected, the readRSSI method on the peripheral object (just make sure you don't call it too often).

Resources