I am working on a project for configuring beacons. A certain amount of time after being powered on, a beacon becomes unconfigurable until it is power-cycled. In order to show a list of the configurable beacons, I am looking at certain characteristics (Bluetooth device name, certain manufacturer data in the advertising packet). I also need to know if it is "connectable", i. e. if the PDU Type in the BLE advertising packet for the device indicates that it is connectable. I've searched the Android Bluetooth classes high and low, both in Android 4.X and 5.X and haven't been able to find anything that will tell me this information.
I realize that one way to determine the beacon connectability is to connect up to it, e. g.: device.connectGatt(...). However, I've seen it take over two minutes sometimes before a callback to onConnectionStateChange comes back with STATE_DISCONNECTED. Also, there may be many of these beacons in an environment, and connecting up to every single one that might be configurable would be inefficient.
The iOS equivalent of this attribute can be found in the advertisementData dictionary under the key CBAdvertisementDataIsConnectable in the CBCentralManagerDelegate callback method centralManager:didDiscoverPeripheral:advertisementData:RSSI.
So, the question is: is there a way on Android to determine whether or not a BLE device is "connectable" from advertising data or scan result or ... ?
UPDATE: AS of the finalized APIs in the Android O SDK, the ScanResult class (itself added as of Android 5.0) now has the isConnectable() method. Detecting connectable advertisements is possible only on Android 8.0+. See here for more info: https://developer.android.com/reference/android/bluetooth/le/ScanResult.html#isConnectable()
Prior to Android 8.0, unfortunately it is not possible.
A connectable advertisement is determined by the PDU Header byte 0. You can see this in the example structure below:
d6 be 89 8e # Access address for advertising data (this is always the same fixed value)
40 # Advertising Channel PDU Header byte 0. Contains: (type = 0), (tx add = 1), (rx add = 0)
24 # Advertising Channel PDU Header byte 1. Contains: (length = total bytes of the advertising payload + 6 bytes for the BLE mac address.)
05 a2 17 6e 3d 71 # Bluetooth Mac
The problem is on devices prior to Anroid 8.0, the Android scanning APIs give you no access to these headers. You get exactly three fields in the callback from Android 4.x:
onLeScan(BluetoothDevice device, rssi, byte[] scan data)
The scan data byte array starts after the header bytes mentioned above. And from what I can see of the BluetoothDevice definition, none of the fields or methods tell you if it is a connectable advertisement -- the class is just a container for the bluetooth mac address with methods to exercise functions on the bluetooth stack. And there are no methods in IBluetooth.aidl which is the private interface to the bluetooth stack (and what BluetoothDevice calls to get its info) that can get this flag.
It appears that this information is not passed up to the Java layer from the BlueDroid stack prior to Android 8.0.
It should be possible since Nordic's nRF Master Control Panel does this.
After some digging I think I know how it does this. I'm not sure it's the right way to do it though.
I tried using the LE Advertiser and setting the device as connectable. In the Nordic app, a device is set as connectable depending on the bytes found at scanResult.getFlags().
I found that this code works for my devices:
int flags = scanResult.getScanRecord().getAdvertiseFlags();
if ((flags & 2) == 2) {
//connectable
}
Related
Long Description:
I have a DJI Osmo Mobile 3 gimbal with Bluetooth 5.0, which supports ActiveTrack 3.0 technology. It connects to your phone via Bluetooth and using the DJI Mimo app you can select an object and track it.
I want to implement this technique in Python using OpenCV.
As I understood, the phone calculates position of the object using computer vision and then sends the coordinates via Bluetooth to the gimbal, which then follows them. I connected to the gimbal with NRF Connect app for android and looked for its services and characteristics, and this is what I found:
Services
Some unknown information getting sent
UPD: looks like the 4 bytes after 57 on the picture mean the joystick values. Fisrt 2 are responsible for left-right tilt, the other ones indicate up-down state. Looks like all of them can be max. 256, but I don't understand, why do they need 2 bytes for each action?
First 2 Bytes:
d2, 03 (210, 3) - full right
c2, fb (194 251) - full left
Last 2 Bytes:
5a, 04 (90, 4) - full up
a6, fc (166, 252) - full down
HID Control, which doesn't return any information
The characteristic with UUID
0xFFF5
Looks like what I need, but now I need to find out, in which format the coordinates are getting sent. For this purpose I want do simulate same BLE services as on the gimbal and let the phone think it is a real one. After the connection it should send data to some of the characteristics. So now the main question.
Main question:
How to emulate BLE Services and their Characteristics using Android, RPI, ESP32 or whatever to get data being sent to those characteristics? Is there any app, library or piece of code for such purpose?
I've seen dongles like CC2045, which are designed to work on 2.4GHz frequencies and sniff BLE Traffic, but it will take for a long time for them to arrive to me. Also nRF52840 based donglas are not an option right now. So I want to implement it using things I have. Is it possible? Thanks!
The information being sought with this question is I think similar (but not the same) as the information sought here...
"How many devices we can pair via Bluetooth of BLE to Android?"
...and so let's re-ask it a different way:
Let's say we have a use case where someone with a mobile phone may want to connect securely (using industry standard security mechanisms) to a Bluetooth LE device using Pairing. When Pairing occurs, bonding information is stored in the mobile phones - - > Settings - - > Wireless - -> Bluetooth - - > Paired Devices window (dialog).
These 'Paired Devices' will remain present in this list regardless of whether or not active connections are maintained, correct?
And if this answer is correct, how many hundreds or thousands of previously Paired/bonded devices can be accrued in this list before the Android OS (or iPhone's iOS) begins to start to incur performance issues?
My understanding is... neither Android OS or iPhone OS offer programmatic ability to 'clean out' the list of old paired / bonded devices. And mobile phone users who neglect to remove those devices manually could have a challenging task at hand if they've allowed the list of Paired/Bonded devices to get out-of-hand.
Thoughts? Thanks much in advance, --DJ Regan
2018-November-12 Update... New news today: In profiling many BLE paired devices with Android - - > a team mate of mine discovered their Bluetooth radio had become unavailable (as in un-useable) after attempting to pair to the 102nd device+ today. Additional profiling is on-going. So... perhaps this is a use case that neither iOS or Android should be trusted to support? --DJ Regan
From sources I guess 100 is the right number pointing to the max devices you can bond with. Also proved in practise.
/* The number of security records for peer devices. */
#ifndef BTM_SEC_MAX_DEVICE_RECORDS
#define BTM_SEC_MAX_DEVICE_RECORDS 100
#endif
...
/************************************************************************************
** Local type definitions
************************************************************************************/
typedef struct
{
uint32_t num_devices;
bt_bdaddr_t devices[BTM_SEC_MAX_DEVICE_RECORDS];
} btif_bonded_devices_t;
According to the bluetooth implementation, if there are more than 100 device records the allocation will fail.
The responsible BTM_SEC_MAX_DEVICE_RECORDS is defined in bt_target.h:
/* The number of security records for peer devices. */
#ifndef BTM_SEC_MAX_DEVICE_RECORDS
#define BTM_SEC_MAX_DEVICE_RECORDS 100
#endif
This is then used inside btm_dev.c, specifically in BTM_SecAddDevice which returns false after 100 pairings:
/* There is no device record, allocate one.
* If we can not find an empty spot for this one, let it fail. */
for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
You can connect maximum 8 devices via bluetooth.
We're trying to emulate a beacon on a Android device and would like to include some 50 bytes of application data in payload? We found that with AltBeacon format this is not possible? How can it be done with help of AltBeacon lib for Android?
Moreover, what are primary and secondary beacon advertisements?
What is role of GattBeacon in this context and when and how should it be used?
There are two basic types of BLE beacon advertisements:
Manufacturer advertisements (iBeacon, AltBeacon, Gimbal)
GATT Service Advertisements (Eddystone, UriBeacon, GattBeacon)
They differ mainly by the bluetoorh PDU type, but in both cases the number of bytes that can be transmitted are similarly limited. It is 23 bytes for manufacturer advertisements (not counting the two byte manufacturer code).
With Bluetooth 4.x, you just won't get close to 50 bytes in a single packet. Bluetooth 5.0 is expected to increase this at some point in the future.
None of the beacon layouts let you go beyond this limit. GattBeacon is merely a generic example layout of a beacon based on GATT Service advertisements, and is not meant for practical use.
I'm writing an BLE application, where need to track if peripherals device is advertising or has stop.
I followed getting peripherals without duplications this and BLE Filtering behaviour of startLeScan() and I completely agree over here.
To make it feasible I kept timer which re-scan for peripherals after certain time (3 sec). But with new device available on market(with 5.0 update), some time re-scan take bit time to find peripherals.
Any suggestion or if anyone have achieved this?
Sounds like you're interested in scanning advertisements rather than connecting to devices. This is the "observer" role in Bluetooth Low Evergy, and corresponds to the "broadcaster" role more commonly known as a Beacon. (Bluetooth Core 4.1 Vol 1 Part A Section 6.2)
Typically you enable passive scanning, looking for ADV_IND packets broadcast by beacons. These may or may not contain a UUID. Alternatively, you can active scan by transmitting SCAN_REQ to which you may receive a SCAN_RSP. Many devices use different advertising content in ADV_IND and SCAN_RSP to increase the amount of information that can be broadcast - you could, for instance, fit a UUID128 into the ADV_IND followed by the Device Name in the SCAN_RSP. (Bluetooth Core 4.1 Vol 2 Part E Section 7.8.10)
Now you need to define "go away" - are you expecting the advertisements to stop or to fade away? You will get a Receive Signal Strength Indication "RSSI" with each advertisement (Bluetooth Core 4.1 Vol 2 Part E Section 7.7.65.2) - this is how iBeacon positioning works and there's plenty of support for beacon receivers in Android.
Alternatively you wait for N seconds for an advertisement that should be transmitted every T seconds where N>2T. The downside of the timed approach is that probably not receiving a beacon isn't the same as definitely receiving a weak beacon; to be sure you need N to be large and that impacts the latency between the broadcaster being switched off or moving out of range and your app detecting it.
One more thing - watch out that Advertising stops if something connects to a Peripheral (if you really are scanning for peripherals) another good reason to monitor RSSI.
First scenario: Bonded Devices
We know that if a bond is made, then most of the commercially available devices send directed advertisements in during re-connection. In situations such as this, according to BLE 4.0 specification, you cannot scan these devices on any BLE sniffer.
Second scenario: Connectable Devices
Peripheral devices are usually in this mode when they are initially in the reset phase. The central sends a connect initiator in response to an advertisement packet. This scenario offers you a lot of flexibility since you can play around with two predominant configuration options to alter connection time. These are: slavelatency on the peripheral and conninterval on the central. Now, I don't know how much effort it's going to take get it working on the Android platform, but if you use the Bluez BLE stack and a configurable peripheral such as a TI Sensor tag, then you can play around with these values.
Third scenario: Beacon devices
Since this is what your question revolves around, according to the BLE architecture, there are no parameters to play with. In this scenario, the central is just a dumb device left at the mercy of when a peripheral chooses to send it's beaconing signal.
Reference:
http://www.amazon.com/Inside-Bluetooth-Communications-Sensing-Library/dp/1608075796/ref=pd_bxgy_14_img_z
http://www.amazon.com/Bluetooth-Low-Energy-Developers-Handbook/dp/013288836X/ref=pd_bxgy_14_img_y
Edit: I forgot, have you tried setting the advertiser to non-connectable? That way you should be able to get duplicate scan results
I am dealing with a similar issue, that is, reliably track the RSSI values of multiple advertising devices over time.
It is sad, the most reliable way i found is not nice, rather dirty and battery consuming. It seems due to the number of android devices that handle BLE differently the most reliable.
I start LE scan, as soon as i get a callback i set a flag to stop and start scan again. That way you work around that DUPLICATE_PACKET filter issue since it resets whenever you start a fresh scan.
The ScanResults i dump into a sqlite db wich i shrink and evaluate once every x seconds.
It should be easy to adapt the shrinking to your use case, i.e. removing entries that are older than X, and then query for existance of a device to find out if you received a ScanResult in the last X seconds. However dont put that X value too low, as you must take into account that you still lose alot of advertisement packets on android LE scan, compared to a BLE scan on i.e. bluez..
Edit:
I can add some information i already found for speeding up the performance on Advertisement discovery. It involves modifying and compiling the bluedroid sources and root access to the device. Easiest would be building a full android yourself, i.e. Cyanogenmod.
When a LE scan is running, the bluetooth module sends the scan sesponse via HCI to the bluedroid stack. There various checks are done until it finally gets handed to the Java onScanResult(...) which is accessed via JNI.
By comparing the log of the hci data sent from the bluetooth module (can be enabled in /etc/bluetooth/bt_stack.conf) with debug output in the bluedroid stack aswell as the Java side i noticed that alot of advertisement packets are discarded, especially in some check. i dont really understand, beside that it has something to do with the bluedroid inquiry database
From the documentation of ScanResult we see that the ScanRecord includes the advertisement data plus the scan response data. So it might be that android blocks the report until it got the scan response data/ until it is clear there is no scan response data. This i could not verify, however a possibility.
As i am only interested in rapid updates on the RSSI of those packets, i simply commented that check out. It seems that way every single packet i get from the bluetooth moduly by hci is handed through to the Java side.
In file btm_ble_gap.c in function BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
comment out to_report = FALSE; in the following check starting on line 2265.
/* active scan, always wait until get scan_rsp to report the result */
if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
(evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)))
{
BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
p_i->scan_rsp = FALSE;
// to_report = FALSE; // to_report is initialized as TRUE, so we basically leave it to report it anyways.
}
else
p_i->scan_rsp = TRUE;
Recently I got a iBeacon device with the intention of creating Android Apps than can recognize it and use it. I'm new using bluetooth in Android Apps and there many things than I still don't know. Looking in the Internet and in this forum I found recommendations to use the Radius Networks' Android IBeacon Library but, alas, now it's no longer available:
https://github.com/RadiusNetworks/android-ibeacon-service
So I started by using the code shown in Android Developers' guide about Bluetooth Low Energy:
https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
Using this code I can detect the device, even connect to it, but I don't know how to get the Proximity Uuid and the Major and Minor values: the app shows a lot of Uuids from services and characteristics of the device, but none is the Proximity Uuid of the device.
Anyone could tell me how to get that data using the Android Bluetooth LE API, or help me to get the Radius Networks' Android iBeacon library for Eclipse and a guide to use it or sample showing how to use it?
Thank you.
EDIT/UPDATE:
It gets better.. AltBeacon !
Check the AltBeacon specifications
AltBeacon brings greater transparency to what a beacon transmits and
how that data can be used by Android, Windows and other devices.
Why the Android iBeacon Library by RadiusNetworks is no longer available:
Vendors have started complying with guidelines set by Apple and have,
as a result, been forced to ‘scrub’ their products of any references
or connection between Android devices and their detection of iBeacon
protocols.
Read more:
Apple cracks down on iBeacon for Android
I think the best bet seems to be from somebody who has been using it, already has it, can share it with you, as from previous commits, you may not get every component - library, sample, service
Also: A note from the CEO for Android iBeacon Lib, RadiusNetworks
Now, coming to Proximity UUID and major, minors:
I have not found a direct way to get it, in terms of a parameter, though you can have a look at read major, minor, uuid of beacons in android and SensorTag using iBeacon Technology. In the latter, there is an indication of major, minor, uuid after iBeacon Service, however TI instruments might be the restriction.
In android, as an identifier.. you can recover the device addressby device.getAddress() of the beacon/for each BluetoothDevice device;.
The following two are totally different things, although both are called UUID.
UUIDs of GATT services which are hosted on a BLE peripheral device.
Proximity UUID of iBeacon.
What you should know about "UUIDs of GATT services":
BLE peripheral devices may implement a GATT server.
A GATT server hosts GATT services.
What the API "android.bluetooth.BluetoothGatt.getServices()" returns is a list of GATT services (List<BluetoothGattService>).
BluetoothGattService.getUuid() returns the ID of the service.
What you should know about "Proximity UUID of iBeacon":
BLE peripheral devices broadcast advertising packets.
The payload part of an advertising packet contains a list of AD structures.
An AD structure consists of (1) Length (1 byte), (2) AD Type (1 byte) and (3) AD Data. The AD structure format is described in "11 ADVERTISING AND SCAN RESPONSE DATA FORMAT" of "Bluetooth Core Specification 4.2".
iBeacon is a kind of AD structures.
AD Type of iBeacon is 0xFF (which means Manufacturer Specific Data).
The first 4 bytes of AD Data of iBeacon are 0x4C, 0x00, 0x02 and 0x15. The first 2 bytes (0x4C, 0x00) mean "Apple, Inc." and the next 2 bytes (0x02, 0x15) mean "iBeacon format".
Proximity UUID (16 bytes), major number (2 bytes in big endian), minor number (2 bytes in big endian), and power (1 byte) follow the first 4 bytes.
So, what you have to do to get iBeacon information (Proximity UUID, major, minor, power) are as follows.
Parse a payload of an advertising packets as a list of AD structures.
For each AD structure, check if AD Type is 0xFF and the first 4 bytes of AD Data are 0x4C, 0x00, 0x02 and 0x15.
When the conditions of 2. are satisfied, parse the remaining bytes as Proximity UUID, major number, minor number, and power.
If you use nv-bluetooth, you can extract iBeacon from an advertising packet like the following:
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
// Parse the payload of the advertising packet.
List<ADStructure> structures =
ADPayloadParser.getInstance().parse(scanRecord);
// For each AD structure contained in the advertising packet.
for (ADStructure structure : structures)
{
if (structure instanceof IBeacon)
{
// iBeacon was found.
IBeacon iBeacon = (IBeacon)structure;
// Proximity UUID, major number, minor number and power.
UUID uuid = iBeacon.getUUID();
int major = iBeacon.getMajor();
int minor = iBeacon.getMinor();
int power = iBeacon.getPower();
........
See "iBeacon as a kind of AD structures" for details.
RadiusNetworks has "re-released" the libraries and examples in conjunction with a new cross platform beacon proximity spec.
New AltBeacon Standard Allows Cross-Platform Proximity Apps
Check out altbeacon.org.