27

I'm working on a BluetoothLE sensor device, for which I need to form a one-to-many broadcast of data. As per the spec, peripherals may only have a single master, and due to limitations of the chip and stack I'm designing on, a master can only have three slaves. From what I understand, Android cannot become a BLE slave anyway, so having my device as a master is not an option.

Both the BT4 spec and manufacturer documentation talk about another mode of operation, referred to as Broadcast mode. In broadcast mode, a connection is never made, and the application data is transmitted as part of the advertising packet. This will exactly fit my needs, as many Android/iOS phones can simultaneously scan down each packet. An advertising packet is transmitted multiple times in bursts, so I suspect reception of data to be mostly reliable. If a packet is lost here and there, it can be tolerated.

Where this gets interesting, is that I want these packets to carry live sensor data, that updates at a rate of 10-20Hz. From examples I've found on the web, BLE in this mode is mostly being used for "iBeacon" type implementations, where they are broadcasting static data. I cannot find any information on how advertising packets are filtered within the Android stack. It could be that they return one result per Bluetooth hardware address, or it could be the unique combination of address and data. The second option would work for this application. If starting and stopping the scan resets the filter, I can make something work as well.

The Android documentation mentions nothing about how device filtering in the scan method works. I've been able to find one post on the net attempting to solve this same problem, which has an unresolved response: BLE: Multiple discovery of the same peripheral during scan. In iOS, my colleague informs me that there is a parameter that can be passed to the scan function that makes this possible.

I've attempted to trace the code back from the startLeScan() call in the Android source, but the code is quite complex, and the use of abstraction has made it difficult to identify the implementation of the object that contains it. The farthest I've gotten is to an IBluetoothGatt object returned from the BluetoothManagerService class method getBluetoothGatt(). This object receives the request to start scanning. It is being instantiated around line 790 of BluetoothManagerService.java on the current revision live on github. The object is being cast from the result of a message, so I suspect maybe the result is phone/driver specific. It is beyond my expertise to be able to trace it any further.

Another question I would like to resolve is how rapidly the scanning can be switched on and off. Scanning is a power intensive operation, yet the broadcast of data will happen periodically on a fairly precise, real time timer. As a result, it would be a great optimization if the scan can be switched on and off, such that the broadcast and scan are synchronized, with the scanner shut down the other 90%+ of the time. This will likely need to be tested experimentally.

I'm still doing feasibility research to see if this is possible for our accessory for Android. My present phone cannot yet run version 4.3, so I have no way of testing/hacking this experimentally.

mattthebaker
  • 271
  • 1
  • 3
  • 4

5 Answers5

27

With Android 4.3 and 4.4 so far, it appears to be a mess: Some devices call onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) multiple times for one device in one scan, some don't. There is no way to configure the filtering like in iOS (see answer of Arkadiusz Konior). So, I now start a list, because I can't ask my users such a question about their device.

However, restarting scaning is also no problem on "not filtering" devices. So, I restart scaning on every device now.

Not filtering (Continuously calling onLeScan())

  • Samsung Galaxy S4 with 4.2.2 using Samsung BLE sdk (I owned that device)
  • Nexus 5 with 4.4 (added by [vegarwe]. The device will give scan records continuously for nearby devices while scanning)
  • Samsung Galaxy S3 with 4.3 (JSS15J.I9300XXUGMK6, I was testing on that device)
  • Samsung Galaxy S4 with 4.3 and 4.4.2 using Android SDK (added by arnaud.b, no build provided)
  • HTC One with 4.4.2 (added by arnaud.b, no build number provided)

Filtering devices (applies to Standard)

  • Nexus 4 with 4.3, 4.4 (I own that device)
  • Nexus 7 2013 4G with 4.4.2 (KOT49H, I was testing on that device)
  • Samsung Galaxy S4 mini with 4.2.2 (I was testing on this device)
  • Motorola Moto X (added by user1603602, no information about android version provided)
  • Motorola Moto G with 4.3 (falcon_umts, My testing device)
  • Sony Xperia Tablet Z Wifi with Android 4.3 (Build 10.4.B.0.577, Model SGP311, my testing device)
  • OnePlus One with 5.0.1 and 5.1.1 (Cyanogen 12.1)

Unknown filtering behavior (Please help to associate the device to a certain group)

  • Nexus 7 2013 (Different behavior is reported like here. But I have read more reports that it's belonging to first group.)
  • Other SAMSUNG, HTC, Motorola, ..., devices
Community
  • 1
  • 1
OneWorld
  • 16,782
  • 18
  • 79
  • 130
  • 2
    It seems that the same android version doesn't have the same behaviour on all devices. So I suppose that this is the bluetooth driver that filter the devices ? (Any expert can confirm that ?) Also, Nexus 5 use the Snapdragon 800 (8974-AA) chipset, same as some versions of the Samsung Galaxy S4 (GT-I9506). Galaxy S4 has other versions: GT-I9505 based on snapdragon 600 (APQ8064T) and GT-I9500 (exynos) Nexus 4, sony xperia tablet Z use the same chipset (snapdragon s4 pro APQ8064). Moto X and Moto G is also based on a snapdragon s4 Nexus 7 2013 has differents chipset (all ?) based on the snapdrago – Benoit Feb 05 '14 at 15:47
  • For my opinion it depends on the BLE implementation (software) which may depend on the chipset. For instance the chipmaker could provide the BLE implementation to the handset manufacturer. I also have seen, that continuously scanning is more often on reference BLE implementations present. Meaning SGS4 was the first device that got BLE implemented and therefore is still in some kind of developer mode. After all, you shouldn't count on the continuously scanning mode. It's more likely removed with further updates. – OneWorld Feb 13 '14 at 10:02
  • Not filtering (Continuously calling onLeScan()) Galaxy S2 M250s(Tested) – H4SN Nov 18 '14 at 06:08
  • Any info about filtering devices using the new Android 5.0 BluetoothLeScanner? Do they become non filtering? – sorianiv Nov 26 '14 at 15:27
  • 1
    From my testing with Nexus 4 & 5 only, my experiments have found that it's hardware-dependent, not OS dependent. My Nexus 4 filters on both 4.4 and 5.0, my Nexus 5 doesn't filter on both 4.4 and 5.0 -- what a mess! – Jonathan Ellis Feb 12 '15 at 00:42
  • @OneWorld Checked with new API21 also..but result same. There are API for filter scanning based on device/manufacture/Service info, But no access to over duplicate advertise data API. Any luck here ? – CoDe Jun 15 '15 at 09:23
  • Xiaomi redmi note 2 is not filtering aswell. – arbel03 Apr 27 '16 at 09:35
15

The text in pages 2535-2536 in the Bluetooth specification (Core_v4.1.pdf) about duplicate advertising reports is somewhat unclear. However the text on page 1258 is clear. It specifies a Filter_Duplicates parameter to the HCI_LE_Set_Scan_Enable command. In Android version 4.4 (Kitkat) this parameter is 0x00 (Duplicate filtering disabled).

There is a simple way to find out if any filtering is done in the Bluetooth chip from Android versions 4.4 (Kitkat). Make the phone a developer phone, enter developer options and check “Enable Bluetooth HCI snoop log”. Then turn Bluetooth OFF and ON once to make the settings bite. From now on all HCI packets between the application processor and the Bluetooth chip will be stored on the phone in a file which is pulled by adb pull storage/emulated/legacy/btsnoop_hci.log . This is not a text file and you need a program from http://www.fte.com/products/default.aspx or wireshark to view btsnoop_hci.log. For wireshark you need a pretty recent version, because older versions does not support BLE. My experience is that there is never any filtering in the Bluetooth chip, i.e. the HCI Event “LE Advertising Report Event ” is sent for every ADV_IND and ADV_NONCONN_IND that the Bluetooth chip receives. This goes for phones with Bluetooth chips Qualcomm/Atheros WCN 3680 and Broadcom BCM 4339.

Correction: the path to btsnoop_hci.log can be different depending on the phone manufacturer. You can find the correct path by adb shell cat etc/bluetooth/bt_stack.conf | grep BtSnoopFileName

TobiasMelin
  • 231
  • 2
  • 5
8

I'm developing the application for Android 4.3 (Nexus 4&7) using BLE and from my observations scanning returns the same device multiple times if there was no SCAN REQUEST send back to the peripheral.

Device may advertise in 2 ways: passive and active. In passive mode the peripheral device is just advertising all of it's data and doesn't listen after sending periodic packet. It's just sending, sleeping, sending, sleeping... In active mode the sensor also advertises but the message is as short as possible. After sending it it switches to listening for some very short time. When scanned detects the short message, it immediately sends SCAN REQUEST command to the peripheral and gets response with more details. As far as I can see Android doesn't sent SCAN REQUEST multiple times during one scanning.

Let's assume that we have 2 devices in range. One is f.e. Nordic's nRF Temp sensor (passive advertising) and one other connectible device. I've received the following scan response:

11-10 21:32:54.281: D/BluetoothAdapter(13468): startLeScan(): null
11-10 21:32:54.281: D/BluetoothAdapter(13468): onClientRegistered() - status=0 clientIf=4
11-10 21:32:54.321: D/BluetoothAdapter(13468): onScanResult() - Device=CD:61:1A:A8:BC:BE RSSI=-94
11-10 21:32:55.122: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:56.414: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:32:57.715: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-61
11-10 21:32:59.016: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:01.609: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:02.901: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-63
11-10 21:33:04.212: D/BluetoothAdapter(13468): onScanResult() - Device=CB:32:81:CF:FD:00 RSSI=-62
11-10 21:33:04.282: D/BluetoothAdapter(13468): stopLeScan()

As you can see the connectible device showed up just once while the other one 7 times.

Another question I would like to resolve is how rapidly the scanning can be switched on and off. Scanning is a power intensive operation, yet the broadcast of data will happen periodically on a fairly precise, real time timer. As a result, it would be a great optimization if the scan can be switched on and off, such that the broadcast and scan are synchronized, with the scanner shut down the other 90%+ of the time. This will likely need to be tested experimentally.

Scanning frequency depends on the device. Furthermore advertising is usually done on 3 channels: 37, 38 and 39 to increase probability of being found. However this might be quite good idea to get advertising packets from 'active' devices multiple times.

Ziem
  • 6,059
  • 7
  • 49
  • 83
philips77
  • 1,264
  • 14
  • 22
  • I've tested the same case on Samsung S4 with official 4.3 update and I receive updates for both devices multiple times. Actually I got updates from 61:1A:A8:BC:BE much often than the later one. So in conclusion it depends on what device are you using. Not good at all for developers :/ – philips77 Nov 11 '13 at 13:08
  • Thanks for commenting, this is really useful information. It is interesting and useful that the device returns multiple scan results when using the passive advertising mode. In this application, ideally I'd like Android to behave like the passive scanner with active advertisement -- so that I can have a device broadcasting data, as well as allowing a connection to change settings. – mattthebaker Dec 03 '13 at 23:26
  • Regarding switching the Android Scanner on and off: I succeeded in my test application to switch the startBleScan on and off, and receive active advertisement packets at a rate of 20Hz. There is unfortunately some latency in the phone when switching on and off, so the scanning process ends up being active 80% to 90% of the time. At lower packet rates this method may be viable as an "Observer" hack. – mattthebaker Dec 03 '13 at 23:31
  • @philips77: A typical use case for running the scanner is to be able to present to the user a list of nearby devices, sorted by the one with the best signal first. In this case you really want updates for the devices continously to be able to update and sort the list (based on RSSI) – Vegar Westerlund Dec 19 '13 at 21:32
6

The actual bluetooth spec says:

Duplicate advertising reports are not required to be sent to the Host. A duplicate advertising report is an advertising report for the same device address while the Link Layer stays in the Scanning State. The advertising data may change; advertising data or scan response data is not considered significant when determining duplicate advertising reports.

According to the spec this applies within a scan period, which suggest that the correct way around this is to stop and restart scanning every time you receive an advertisement.

Based on my experience with BLE, it seems like sending variable data in advertisments is just not a very good idea. Almost everything assumes that the data from advertisements does not change. If you want to actually send variable data (e.g. thermometer readings) then it is much better to actually connect to the device and do it via a characteristic. It is more reliable and uses much less power. The downside is you can only connect to 8 devices at once.

Advertisements are meant for detecting the presence of devices and identifying them.

Timmmm
  • 68,359
  • 51
  • 283
  • 367
  • Also note there is a new BLE scanner API in Android 5.0. I get every advertisment on my Nexus 4 with Android 5.0. (The advertisments are undirected, not connectable.) – Timmmm Nov 27 '14 at 10:06
  • What u mean here .." get every advertisment", are u getting continuous(duplicate) packet ? – CoDe Jun 11 '15 at 11:06
  • Yes on a Nexus 4 I was notified about every advertisment packet, even if they were identical. This is allowed behaviour, but it is also allowed to not do that. The spec is annoyingly forgiving. – Timmmm Jun 12 '15 at 12:10
  • This is interesting..did u cross check on other mobile also? Also Like you suggesting "This is allowed behaviour, but it is also allowed to not do that" then is there way to get idea that advertise has been stopped by Peripheral !! – CoDe Jun 13 '15 at 08:01
  • There's no way of detecting when advertising has *stopped* - you can merely wait a bit and see if you get any advertising packets or not. As I said, if you want to receive every advertisement then you have top stop and restart the scan every time you receive one. I haven't tested that. – Timmmm Jun 17 '15 at 08:23
  • Yes, same I'm doing. But some of ROM-BLE implementation take time to find advertising packet while restart scanning(4 Sec I;m using). Any suggestion over it. – CoDe Jun 17 '15 at 08:52
  • Yes I have noticed this too. I believe it is a power saving feature - while "scanning" I think devices aren't required to be receiving on all three advertising channels 100% of the time, so they miss a lot of advertising packets. I don't think there's any way around it. In Android 5 there is [`SCAN_MODE_LOW_LATENCY`](https://developer.android.com/reference/android/bluetooth/le/ScanSettings.html#SCAN_MODE_LOW_LATENCY) which may help. – Timmmm Jun 17 '15 at 09:53
  • Yes I checked that but didn't found any difference, in this case..you still required restart scanning and that's take time anyway. And even "CALLBACK_TYPE_ALL_MATCHES" say "Trigger a callback for every Bluetooth advertisement found that matches the filter criteria" but that is also not helping. – CoDe Jun 17 '15 at 10:40
0

In iOS this flag is named CBCentralManagerScanOptionAllowDuplicatesKey. Passing it to scan function causes notification for every advertisement packet. I couldn't find similar flag in Android.

Arkadiusz Konior
  • 1,109
  • 12
  • 11
  • That's true! It must have been something similar at least in Android 4.4 to avoid those different behaviour and being the default one the one which meets the standard. – GoRoS Apr 01 '14 at 08:43