Bluetooth data update notifications not getting fired - ios

I am facing some issue while reading data from bluetooth peripheral. We have a bluetooth device with the following gatt details.
<service uuid="service id" advertise="true">
<description>XXXX service</description>
<characteristic uuid="characteristic id" id="xgatt_data">
<description>Data</description>
<properties write="true" indicate="true" />
<value variable_length="true" length="20" type="user" />
</characteristic>
</service>
What i am doing is
Search for the peripheral who is having "service id"
Connect to the peripheral once found and keeping a strong reference to it.
After connecting setting delegate and searching for all the services
it providing
loop all services and scan for characteristics once we discover
service
after i found desired characteristic i am enabling notification
On button click i am writing data to characteristic
I am able to connect to the device. and i can send commands(data) to peripheral also. Once we send any command to device it will send some data in response. I can see logs at the device, it is sending some data back once it receive any command. But in my iOS device i am not able to read the data by using either notification or normal read functions. What i am missing here?

Notifications and Indiciations are two different things: If you enable indications you won't receive notifications, and if you enable indications then the application sending the indications expects a response to every sent indiciation (from the application layer).
Also your permissions seem not quite right: the xgatt_data characteristic does not necessarily need the "Write" permission, unless you intend to let a client change it's value. It requires the "Read" permission if you want to read data from the notification, other than simply being notified that it was received.
To enable notifications a client characteristic configuration descriptor is required (UUID 00002901-..) within the xgatt_data characteristic. This CCCD requires "Read+Write" permissions to enable notifications/indications (some work without read permission, some dont).
And finally make sure that your device never agrees to an Attribute MTU of less than the size of your notification, it will not be received by the peripheral if it doesnt fit into a single package. If data length extensions are used, dont enable notifications until after DLE was negotiated, or keep the notification value size below your device's original minimum attribute MTU.

I found the issue. Actually issue is with the emulator. And now i can get data update indications and able to write data to BLE with only "read" and "indicate" properties.

Related

central unsubscribes from characteristic when restart app

IOS app is a peripheral. After pairing, peripheral can successfully update characteristic value to and indicate to subscribed central via updateValue:forCharacteristic:onSubscribedCentrals:
When I call this method successfully (after pairing), logs show that characteristic had 1 subscribed central, via characteristic.subscribedCentrals.
However, If I use Xcode to stop and start the app again and try to update characteristic value, logs show that characteristic now has 0 subscribed centrals, and central device doesnt do expected behavior so I'm assuming it wasnt received.
How I make sure the central remains subscribed to my services characteristic after reboot/reconnect?
Thanks
I believe that the only way you can do this is to create a bond between the devices. Usually, once the app is killed/restarted, the value of the CCCD (Client Characteristic Configuration Descriptor) is reset and therefore the remote central app needs to re-enable it every time upon connection. However, when the two devices bond, the GATT server stores the information on which CCCDs are enabled, and then upon each subsequent connection those CCCD values are loaded. You can find more information here:-
What does CCCD mean
How to know if the notification/indication of a characteristic is enabled
GATT (Services and Characteristics) - check attribute caching
The ultimate guide to iOS's CoreBluetooth - check Pairing and Bonding

Is it possible to know if a user rejected bluetooth pairing on iOS?

So I am developing an application which interacts with a bluetooth peripheral, and I am running into the issue that there is currently no way to tell if the user rejected the peripheral's pairing request or not.
The current flow which is implemented is:
Scan for peripherals
Connect to peripheral
Discover services
Discover characteristics
(Pairing request is sent here by the peripheral, and the OS presents the pairing permission popup)
Read from characteristics
I would like to present an error state if the user rejects the pairing request, but I do not seem to be able to tell whether this has happened:
There is no error callback executed on the CBCentralManagerDelegate or CBPeripheralDeleagate
All the characteristics are discovered, whether or not paring has been accepted
Reading from/ writing to characteristics fails silently: i.e. the peripheral just doesn't return a value when a characteristic is read from, but there's no affirmative error to let me know that it's because of a permission failure.
According to this article it indicates that there's no direct way to know that the pairing request was cancelled.
According to this answer it looks as if there is not currently a direct way to detect whether a peripheral is bonded in iOS.
Is there any known workaround for this issue?

subscribe notification characteristics linux/ios

I am trying to write a simple Gatt peripheral on linux device. I am currently able to see my service thanks to btgatt-client binary. I can read/write characteristics, enable notification, etc... I am using API from src/shared/gatt-db.h from bluez5, inspiration comes from tools/btgatt-server.c
However I am not able to make it work with my ios application without success. The subscription to notification failed. This ios application is able to work with a CC2541 bluetooth device so this is not an issue in ios side.
To enable the notification subscription I put some changes on the property value in the creation of the characteristics function like this :
gatt_db_service_add_characteristic(service, &uuid,
BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY
signal_live_read_cb,
signal_live_write_cb,
server);
Do I forget to call some specific code to make it work correctly ?

How to implement secure connection to CBPeripheral?

I want only trusted devices to connect to my peripheral. And I don't want anyone to be able to discover services and characteristics of my peripheral.
So before connecting to the peripheral I would like to show an alert with a pin code. Is it possible to do it and what is the easiest way?
I couldn't find the answer to this question and tried to implement encrypted characteristic by adding CBAttributePermissionsWriteEncryptionRequired to the permissions:
self.characteristic = [[CBMutableCharacteristic alloc] initWithType:[JUUIDBuilder uuidWith:#"1706"]
properties: CBCharacteristicPropertyWrite
value:nil permissions:CBAttributePermissionsWriteEncryptionRequired];
For some reason it didn't help because I'm able to write values from my second device all the time without any security checks. (Documentation for CBAttributePermissionsReadEncryptionRequired says:
...the characteristic is configured to allow only trusted devices to read or subscribe to its value. When a connected, remote central tries to read or subscribe to this characteristic’s value, Core Bluetooth tries to pair your local peripheral with the central to create a secure connection.
which doesn't make sense to me. What is "trusted devices" here?
Can anyone help me? What is the best practice to allow connections only from trusted devices with pin code confirmation?
You cannot prevent services and characteristics being discovered. You can advertise a primary service and have secondary services that aren't advertised, but once a connection is made all services and characteristics will be revealed.
If you specify that an attribute requires encryption, then a pairing (technically bonding) process will be initiated when you first try to read/write the characteristic. This process exchanges encryption keys and results in the devices 'trusting' each other.
If your peripheral and central are both iOS8 devices, then I have found that if both devices are configured with the same iCloud account then the trust is already established (presumably for functions such handoff) and you will never see the pairing dialog. This caused me quite a bit of confusion when I was trying to test encrypted characteristics.
If you test using devices with different iCloud accounts then you should see the pairing dialog.
Even the pairing process will not "protect" your service/characteristic if the "attacker" has control of both devices as they can simply complete the pairing process. Pairing/bonding does protect the data against eavesdropping as the transfer will be encrypted.
To actually protect the service you would need some form of challenge/response involving a characteristic before exposing data.
For example the central needs to read a value from characteristic "A" which is set at random by the peripheral. The central then needs to calculate the correct response to that value and write it back to "A". Only if this value is correct does the peripheral set values on the remaining characteristics (or accept inputs on the other characteristics from the central).
This solution is only secure as long as your challenge/response mechanism isn't compromised but will probably defeat non-determined attackers.

Concurrent delegate methods

I'm currently working with a Corebluetooth, with my phone acting as central, and a separate peripheral.
I'm successfully reading data from a peripheral device using the didUpdateValueFor delegate method. The problem I'm having is when I'm sending multiple packets of information at the same time.
For instance, I send "abc" first and "def" later. As the central updates the reading upon indication from the peripheral, I should be able to get "abcdef" at the end. This works fine if I am sending indications at a speed of 10 packets per second.
However, once my speed gets to the default indication speed, it's too fast for the central to keep up. I only get the first indication "abc", but I never receive the indication for "def".
Is there a way I can force the didUpdateValueFor method to run concurrently so it captures all incoming notifications regardless of speed?
The best-practices chapter of the Core Bluetooth Programming Guide recommends the use of subscription via setNotifyValue:forCharacteristic: rather than plain reads for characteristics that will change often.
It isn't clear from your question as to whether you are using subscription or polling via readValueForCharacteristic:
I think that you mean didUpdateValueForCharacteristic instead of didWriteValueForCharacteristic. Otherwise, the question doesn't seem correct as didWriteValueForCharacteristic can not be used to read data from the remote device (except if you are using error codes for communication - which you shouldn't ;) ).
There are two methods to push data from the peripheral to the central: indications and notifications.
Notifications may be discarded if sent too fast or for whatever reasons.
Indications can only be sent one at a time (you'll have to wait until the central replies with a confirmation that the indication has been processed, before sending another one!).
I see multiple ways how your current implementation may be incorrect:
You are not waiting for the Handle Value Confirmation packet and send the next indication too early.
You are sending indications / notifications before the Client Characteristic Configuration has been written by the central.
Your peripheral has flagged the characteristic to support both notifications and indications. In this case, Core Bluetooth only supports notifications and doesn't enable indications, in which case you are back at unreliable notifications ([CBPeripheral setNotifyValue:forCharacteristic:])
If the specified characteristic is configured to allow both notifications and indications, calling this method enables notifications only.

Resources