LE Coded PHY on Android - android

LE Coded PHY (Bluetooth 5 long range) is pretty new, and information on it is scarce. My primary question: how do you use it? Suppose you have an Android phone emitting a BT signal, and another Android phone receiving. Assume that both sides CAN use LE Coded PHY - how do you ensure they are using it? My default tentative assumption is that, lacking documentation claiming otherwise, it switches modes when signal strength gets too low. However, I'm not at all sure of that. Indeed, there's a little evidence that it must be triggered manually: "Set the primary PHY to a LE Coded PHY (GAP_ADV_PRIM_PHY_CODED_S2 or GAP_ADV_PRIM_PHY_CODED_S8) in the advertisement parameters." (from the link above.) However, I have been unable to find any mention of how to do that from Android.
Now, note that using Android on both ends is just a test - we have a peripheral that is supposed to support LE Coded PHY, but range seems unaffected whether we connect it to a phone with LE Coded PHY support or without. We want to set up a test where we know Coded is being used, so we can compare the performance of other devices. Are there flags that need to be set? Modes to be switched? Jigs to be danced, hijinks to be enacted?

You are right, CODED PHY is relatively new and information on it is scarce. According to the Bluetooth spec, there are three main modes of CODED PHY:-
CODED PHY advertisements/scanning: this is when advertising/broadcasting and scanning/observing is performed on
CODED PHY 1.
CODED PHY Connection Initiation: This is when a device is advertising over CODED PHY, and then a remote device connects to it over the CODED PHY modulation [2].
CODED PHY Connection Switch: This is when you are already in a connection and then you request to switch to CODED PHY. If the remote device accepts the request, then the connection changes to CODED PHY and all packet exchanges are performed over that modulation [3].
Now that is not to say you can not tweak that. You can write an Android app that requests a switch to CODED PHY (third method) when the RSSI is low,or you can modify your application so thata it only scans for adverts over CODED PHY if it can't find anything over normal 1MPHY, etc.
If you want to see this in play, I recommend checking the nRF Connect app on Android and a phone that supports the CODED PHY features (e.g. One Plus 7, Galaxy S10, etc). You'll notice that once you're in a connection, you can manually switch to CODED PHY or 2MPHY from the connection settings. You can find out if your phone supports the CODED PHY feature by checking the "Device Information" from the menu.
For further reading, I recommend checking the following:-
Bluetooth specification, Version 5.1, Vol 1, Part A, Section
4.2.2.2
https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/taking-a-deeper-dive-into-bluetooth-5
References
Bluetooth Specificaiton Version 5.1, Vol 1, Part A, Section
3.3.2.2.2
Bluetooth Specification Version 5.1, Vol 6, Part B, Section 4.4.4.2
Bluetooth Specification Version 5.1, Vol 2, Part
E, Section 7.8.49
I hope this helps.

Related

BLE peripheral pairing pin on android

I implemented a GATT Server and Client App on Android. The connection is working and I forced pairing by adding PERMISSION_READ/WRITE_ENCRYPTED_MITM to all of the GattCharacteristics.
But the pairing behavior differs on different clients:
1) Pin is shown on the client/central (Android 5 on Samsung Galaxy S3) and should be insert on the server/peripheral (Android 7 on Nexus 5).
2) Passkey is shown on both devices client/central (Android 5 on Samsung Galaxy S3) and server/peripheral (Android 6 on Nexus 7)
3) Pairing with Windows or iOS fails with server/peripheral expecing a pin for input.
What I expected and want to happen is:
Pin is shown on the server/peripheral and has to be insert on client/central
Is there any way to configure that behavior?
Thanks in advance!
EDIT
Here is my setup:
BluetoothGattService gattService = new BluetoothGattService(
serviceUUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
gattService.addCharacteristic(new BluetoothGattCharacteristic(
charReadUUID,
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM
));
gattService.addCharacteristic(new BluetoothGattCharacteristic(
charWriteUUID,
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM
));
gattServer.addService(gattService);
...
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(true)
.build();
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeTxPowerLevel(false)
.addServiceUuid(serviceUUID)
.build();
BluetoothLeAdvertiser advertiser = adaper.getBluetoothLeAdvertiser()
advertiser.startAdvertising(settings, data, callback);
Summary: Set the I/O Capabilites of your client to "Keyboard Only".
Explanation:
I am not fully sure what happens "under the hood" of your system. But I can tell you what should be happening according to the BLE CoreSpec. First see CoreSpec V4.2, Vol. 3, Part H, chap. 2.3.5.1, table 2.7 & 2.8. There it is defined which pairing is used, depending on the authentication requirements and the I/O capabilities of the devices.
What you want is described as "Passkey Entry: responder displays, initiator inputs". This is the case if legacy pairing (pairing according to Bluetooth V4.0) is used, and if:
the server (responder) has a display AND
the client (initiator) has a keyboard AND
server and client do NOT both have display AND keyboard.
(And if OOB data is not used and MITM is enforced, but I assume this as given.) Note that if both client and server have display and keyboard, the default case is that the client displays and the server inputs. It would seem that if your protocol automatically handles pairing, it will also automatically chose the pairing method as defined in the CoreSpec.
So what you see is corresponding to different I/O capabilities of different servers. It seems that your client has display and keyboard, so if you use a server with display and keyboard, the client will display the passkey and the responder will wait for input (which fits to your case 1). For case 2, we have Numeric Comparison; this is only possible if LE Secure Connections (pairing according to Bluetooth V4.2) is supported by both client and server.
For case 3, I don't know what is going on, but it may be a problem between an Android system and an iOS system not operating well together (but I have no idea why).
Since pairing seems to be fully automized here, the only possibility to change things is to change the I/O capabilities. There should be a function to change these capabilities, check your manual. If you do not want to use a display on the client, set its I/O capabilities to "Keyboard Only" and it will exhibit the behavior you expect.(*)
(*) This holds only if you use legacy pairing. If both devices support LE Secure Connections, it is recommended that you use this newer pairing protocol, since it removes security issues with the old protocol. (I would however assume that in this case, the newer protocol is used automatically anyway.)

Get BLE Scan without filter duplicate UUID

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;

Detecting whether a BLE device is connectable on Android

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
}

Use Find Me Profile in Android 4.3

I a trying to understand and modify the BLE sample von Android.com, now I can discover my sample BLE Device (HTC Fetch) and now I want to understand all that GATT and BLE stuff.
What are Characteristics and what are Profile and what are Serivces and what do they mean in the Bluetooth Low Energy World? I used HTC Dev and found a Service and a Characteristics UUID.
https://www.htcdev.com/devcenter/opensense-sdk/bluetooth-smart/htc-fetch/
But I guess what I need is the Find Me Profile, cause for the first steps I only want to get the Find Me react to a Button click.
https://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
How to implement this in my App?
When I understand everything I try Power and Proximity (reading RSSI and compare with defined range).
Can some one help me understanding Bluetooth LE?
Here's a related post
How to use the profile of PROXIMITY PROFILE,IMMEDIATE ALERT SERVICE and Find Me Profile in android 4.3 BLE?
Basically you can approximate a proximity level using tx+power - rssi or distance roughly with
d = (rssi-A)/-20 (where A = rssi at one meter) or simply use rssi mapping out ranges to display You could also initially base it on just the connection range and skip rssi.
As for the FindMe, simply write the low or high alert values to make it sound when you press a button in your app. For pressing a button on the device use the UUIDs shown in the documentation.
sample code for that device is forthcoming

RSSI from Bluetooth Low Energy (BLE) Tags?

I'm writing an app (on android) to read RSSI from bluetooth devices, for location recognition using rssi fingerprinting. I have working code for reading RSSI from non-paired and discoverable bluetooth devices that are not BT4.0/BLE. I would like to know if I get some BLE-based tags (such as stick-n-find) would I be able to read their RSSI only by putting myself (my android phone to be precise), into bt-discovery mode.
In BT Low Energy the roles are switched.
The Stick-n-find would be Advertising it's service(s) Name or other information. When you receive that Advertisement from your iOS APP you will get an RSSI value with that Advertisement.
So just do something like:
#property (strong, nonatomic) CBCentralManager *CM;
#define SERVICE_ID_STR "4d1dc300-424d-13e2-a661-0002a55dc51b"
self.CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber
numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
CBUUID *peripheralUUID = [CBUUID UUIDWithString:#SERVICE_ID_STR];
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:myUUID]
options:scanOptions];
then when it hears the Advertisement package from a Peripheral you will get
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
where you get the RSSI.
If you only want a callback to didDiscoverPeripheral for the FIRST time the peripheral is heard then don't use the ScanOptions
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:myUUID] options:nil];
From what I gather, some Android phone manufacturers may include BLE support, but it is not currently supported by Android directly (as of 4.2 Jellybean). See Issue 33371 for more info.
It looks like BLE may be coming in the next Android version as hinted in this Google Groups discussion.

Categories

Resources