What is the nature of BLE characteristic notify property? - ios

I need to provide communication via Bluetooth Low Energy 4.0 between iOS-device from one side and certain peripheral device, which has bluetooth-module onboard.
Peripheral device was assembled with DORJI DBM01 bluetooth LE 4.0 module which allow to communicate with it using one characteristic with READ property (UUID = 0xFFF4) and one characteristic with WRITE property (UUID = 0xFFF1). Technical manual of DORJI DBM01 is here: http://dorji.com/docs/data/DBM01.pdf
I succeeded in establishing bluetooth LE connection between iOS-device (using Core Bluetooth Framework) and described above peripheral device, but characteristic with READ property doesn't have a property of notify (CBCharacteristicPropertyNotify in Core Bluetooth Framework). So I have to use some kind of infinite loop to scan and read new information from characteristic with READ property (by calling method of CBPeripheral instance - readValueForCharacteristic:) instead of subscribing to a characteristing value (by calling method setNotifyValue:forCharacteristic:).
Is it possible to add notify property to read characteristic of peripheral device (for instance, by engineer who built peripheral device or adding some low-level code which run on peripheral device) or notify property is an integral part of BLE-module (DORJI DBM01) and it can't be added without using another BLE-module?

The DBM01 is based on a Texas Instruments CC2540, like many other BLE-to-serial modules, which do implement notifications, so technically, it is definitely possible to do it.
However, this requires the firmware of the DBM01 to support it, and you'll of course have the issue of upgrading said firmware in existing modules. Unless there are undocumented features on the module, I doubt there would be a way to change the behaviour of the module without touching the firmware.
Another option could be (but that really depends on your scenario) to switch the central and peripheral roles, so that the iOS app would be notified when the BLE module writes data. As I understand it, this needs to be done in hardware (the level on a specific pin needs to be changed).

Related

No connectionEventDidOccur for GATT over BR/EDR (aka Classic) using CoreBluetooth

I'm trying to use the iOS 13 introduced capability in CoreBluetooth to do GATT over BR/EDR.
The accessory I'm using obviously implements GATT over BR/EDR (it even publishes its services using SDP).
According to the session WWDC 2019 What's New in Core Bluetooth session, we have to use the registerForConnectionEvents API on a CBCentralManager instance, providing services UUIDs (CBUUIDs) that will be available to use on the BR/EDR accessory.
In the session, they explicitly say:
Your app will have instantiated a CBCentralManager, passed us a known
service UID, and in the case of a BR/EDR or classic device, your user
will go to the Bluetooth settings and search for the device, in this
case let's say it's a headset running heart rate.
They'll discover the device, find it, and attempt to connect.
Pairing will be triggered, and then afterwards when we're connected,
we'll run a service discovery of the GATT services.
If we find a service that you want, then you'll get the delegate
callback.
So when doing a manual connection in the Settings app to the accessory, iOS does a GATT service discovery and if it matches, we receive an associated connectionEventDidOccur delegate callback with the event (peerConnected) and the associated CBPeripheral.
However, this delegate callback never happens.
I'm using the UsingCoreBluetoothClassic sample from Apple, with custom service CBUUIDs implemented by my accessory.
I did multiple attempts: providing only one service CBUUID, severals CBUUIDs, none, generic ones, very specific ones... It never fires.
Note that on Android, it seems to work: connection is possible using the MAC address directly, and a service discovery using SDP lists the accessory services.
Also note that the event fires when I'm scanning using scanForPeripherals and connect to my accessory (because my accessory also does GATT over BLE, but for specific reasons we explicitly want to perform GATT over BR/EDR).
Is there something I have to do on the accessory that I probably missed ?

How to match EAAccessory and CBPeripheral with MFi device?

I have MFi device which uses BLE for control and Classic Bluetooth for audio streaming.
In the App, i use coreBluetooth framework to scan BLE and EAAccessory framework to scan Classic Bluetooth.
I don't want the BLE of target device to be connected if its Classic Bluetooth is not yet connected. So i need to know which EAAccessory is corresponding to target CBPeripheral.
I am familiar with coreBluetooth, there is UUID string to identify the CBPeripheral. But it looks not exist in EAAccessory.
I have an idea but not sure: maybe firmware side can config EAAccessory's serial number and CBPeripheral's manufacture data in advertisement data with the same
serial number, so that App side can check if they are the same.
Dose anyone knows the general way to implement this in App side and firmware side?
I really do not think there is s relationship between the 2. BT and BTLE are managed by different chip at peripheral side and phone side.
Usually in BT you use the MAC address to identify the peripheral on BTLE side the MAC address is not used anymore since iOS at the first connection give its own identifier to the peripheral.
What you can do is probably at firmware side, by exposing a service with a characteristic that somehow relate the 2.
UPDATE AFTER COMMENT
I see, as far as I know there a best practice doesn't exist.The worst part is that you have to handle connections differently, mostly due to how connection are made on iOS side. While on the BLE you can choose a not encrypted connection that would not require paring or bonding, on BT side I guess that bonding is required.
Probably the most simple flow would be, user bond the BT device. Once you are in the app and detect the connected BT device, use a scan method for detect BLE companion device by filtering for a specific service id that your device exposes, once you do that you can also filter discoveries using BLE name without still making a connection.
Adv packet are restricted in size (29 usable byte) but you can also use the scan response (31 byte), that exposes some additional properties such as manufacturer data that will be exposed in a dictionary (kCBAdvDataManufacturerData).
Once you know that is the correct device you can start a connection, that does not require pair or bond but is NOT encrypted (Pair and Bond will require the user to accept the connection inside your app).

How to send service UUID

We are developing an app which needs to scan for beacons in the background. This requires us for iOS to specify a service UUID while scanning. See Apple documentation:
Apps that have specified the bluetooth-central background mode are allowed to scan while in the background. That said, they must explicitly scan for one or more services by specifying them in the serviceUUIDs parameter. The CBCentralManagerOptionShowPowerAlertKey scan option is ignored while scanning in the background.
We are using a Raspberry Pi with a bluetooth adapter to send a beacon signal (conforming the AltBeacon spec). Unfortunately we are not able to find out how the service UUID should be set in the BLE Advertising PDU, is it part of the Bluetooth specification or part of the Manufacturer specific data structure? We did find examples for setting the service UUID for when you use an iOS device as beacon, but since we are using a generic bluetooth adapter we cannot use that.
Could anyone clarify us how and where the service UUID should be set in the beacon transmission?
is it part of the Bluetooth specification or part of the Manufacturer specific data structure?
the later.
generally when you setting the advertising parameters, you can set the UUID(or name, tx power, etc) to it.

Changing CBAdvertisementDataManufacturerDataKey from peripheral

Is there any way to modify CBAdvertisementDataManufacturerDataKey from CBPeripheralManager? I understand I can get the CBAdvertisementDataManufacturerDataKey from CBCentralManager.
The reason I want to do this is because I want the peripheral to advertise a 10-byte value without resorting to having the central connect to it, discover services, and then reading a characteristic which would contain the 10-byte value.
No, this is currently not possible as of iOS 7. The Manufacturer Data is reserved by Apple and is unmodifiable (at least on non-jailbroken devices). If you were writing the firmware for your own peripheral, this would not be a problem. But since the CoreBluetooth api is a layer above Apple's actual implementation of the iOS ble firmware, we face the limitations of what they actually expose. You may consider advertising you own custom service and displaying the same value you would have put in the manufacturer data, however.

Transmitting data with CoreBluetooth

I'm developing an iOS app with an accompanying Bluetooth LE peripheral. The one step I don't seem to be able to solve is how to actually transmit the data from my app to the peripheral or vice versa.
What I've built so far is a test app that can connect to my sample Bluetooth peripheral, and read all of its services/characteristics/descriptors. It can toggle notifications for a given characteristic, and write to given characteristics. It is just this last step of "transmit n bytes to the peripheral, and receive m bytes from the peripheral" that I can't seem to figure out.
Looking at the External Accessory Framework (what I would use if Apple would actually give me MFi approval for this project), they give you input and output streams on a given session to communicate with the accessory, but no such object exists for CoreBluetooth.
Is this simply an oversight on Apple's part on the functionality of CoreBluetooth? Or do I simply need to develop my own Bluetooth service profile to handle the inflow/outflow of data to and from the peripheral?
LE is fundamentally designed to work with these GATT based profiles, which are suited for monitoring sensors, not for data streams. While LE does allow for additional L2CAP streams to be opened for custom protocols, Apple's CoreBluetooth doesn't provide access to do so.
You can build a custom profile with private services and characteristics and have it work kind of like SSP; that's the way I'm using my BLE module to get data from some sensors to my app. The module I bought (Microchip's RN-4020) already has a custom profile made specifically for this known as MLDP (Microchip Low-energy Data Profile).
The way I get the data in my iOS app is by subscribing to the private characteristic, thus being notified when the values are updated. So far it has been working great, and the data rate can go up to 20 kbps according to Microchip (I haven't tested its limits, since I don't need much speed). Here's a link to Microchip's product page: http://www.microchip.com/wwwproducts/Devices.aspx?product=RN4020
Good luck!
You can use the bluetooth.org 'Immediate Alert Service' uuid=1802 with characteristic uuid=2A06 with property=write_no_response to send one byte values to your peripheral device from your iPhone. The peripheral device must be programmed to act on the data that is sent. For example, you might use a button on an iPhone app to send a hex address that causes one or more port pins to turn on or off on the peripheral. While this is not using the Alert Service as it was intended, it does provide an easy way to test out data transfer to a peripheral device. The same process could be used to send sequential data bytes similar to a serial data stream. I have not yet tried sending more complex data streams. The write_no_response does not provide any feedback to the app as to whether the data was received by the peripheral.
The IOS TemperatureSensor.xproj is an example of code for reading temperature data from a peripheral. The OSX HealthThermometerClient.xproj has the code needed to decode the somewhat complex thermometer data structure. The IOS TI-BLE-Demo.xproj TIBLECBKeyfob.m has code for reading and writing characteristic values, such as, reading temperature or battery levels from a peripheral device.

Resources