... | ... | @@ -230,11 +230,17 @@ Peer advertisement happens using BLE's advertisement protocol, which allows a pe |
|
|
* <https://j2abro.blogspot.com/2014/06/understanding-bluetooth-advertising.html>
|
|
|
* <https://source.android.com/docs/core/connect/bluetooth/ble_advertising>
|
|
|
|
|
|
Some devices (eg Huawei P8 Lite 2015) don't support advertising. Others (eg Moto G 4G) appear to support it, but aren't discovered by other devices.
|
|
|
Some devices (eg Huawei P8 Lite 2015) don't support advertising.
|
|
|
Others (eg Moto G 4G) appear to support it, but aren't discovered by other devices.
|
|
|
Advertising is more likely to be supported (and functional) on newer devices.
|
|
|
|
|
|
Advertising continues in the background until stopped by the application. If advertising is started while the app is in the foreground then it can continue in the background without needing background location permission (on Android versions that require location permissions for Bluetooth operations). Advertisements seem to be sent less frequently when the app is in the background and the screen is turned off.
|
|
|
Advertising continues in the background until stopped by the application.
|
|
|
If advertising is started while the app is in the foreground then it can continue in the background without needing the background location permission (on Android versions that require location permissions for Bluetooth operations). Advertisements seem to be sent less frequently when the app is in the background and the screen is turned off, but this needs to be tested on a wider range of devices.
|
|
|
|
|
|
A BLE advertisement may be "connectable" or "scannable" (or neither). Connectable means that a device receiving the advertisement can connect to the device that sent it. Scannable means that a device receiving the advertisement can request additional data - the "scan record" - from the device that sent the advertisement. However, we found that some devices (eg Samsung J5 2016) receive the advertisement packet but not the scan record, so any information we make available via scan records also needs to be made available by other means.
|
|
|
A BLE advertisement may be "connectable" or "scannable" (or neither).
|
|
|
Connectable means that a device receiving the advertisement can connect to the device that sent it.
|
|
|
Scannable means that a device receiving the advertisement can request additional data - the "scan record" - from the device that sent the advertisement.
|
|
|
However, we found that some devices (eg Samsung J5 2016) receive the advertisement packet but not the scan record, so any information an app makes available via scan records also needs to be made available by other means.
|
|
|
|
|
|
A connectable or scannable advertisement can include up to 31 bytes of data. To save energy, it's useful to include a UUID to identify the service being advertised. This allows devices listening for advertisements to filter out irrelevant advertisements without waking the CPU, as filtering can be done by the Bluetooth chipset. Self-assigned service UUIDs are 128 bits long, so including a service UUID in the advertisement uses 18 of the 31 available bytes (vendors who obtain UUIDs from the Bluetooth standards body can use shorter representations).
|
|
|
|
... | ... | @@ -296,34 +302,61 @@ Then, whenever we discover an L2CAP-compatible device, we can connect to it usin |
|
|
|
|
|
#### Notes
|
|
|
|
|
|
- BLESSED doesn't provide a wrapper for the new advertising set API, which supports new Bluetooth 5 advertising features such as periodic advertising, extended advertising and coded PHY, so if we want to use those features we'll need to use the Android API directly
|
|
|
- If we use any Bluetooth 5 advertising features then we also need to use the Android API for scanning (or submit a pull request upstream to allow legacy mode to be turned off for scanning)
|
|
|
- BLESSED doesn't provide a wrapper for the new advertising set API (added in API level 26), which supports Bluetooth 5 advertising features such as periodic advertising, extended advertising and coded PHY, so if we want to use those features we'll need to use the Android API directly, rather than going through BLESSED
|
|
|
- If we use any Bluetooth 5 advertising features then we also need to use the Android API directly for scanning (or submit a pull request upstream for BLESSED to allow legacy mode to be turned off for scanning)
|
|
|
- We can, however, use BLESSED to request coded PHY for GATT connections
|
|
|
- BLESSED also makes it relatively painless to send and receive information via GATT characteristics
|
|
|
- Some devices allow connections to multiple peripherals when acting as a central
|
|
|
- Some devices also support connections from multiple centrals when acting as a peripheral, but since GATT doesn't provide a way to send data to a specific central we'd need to do some creative thinking to make use of this
|
|
|
- L2CAP connection-oriented channels (CoC) seem to work as advertised. The server socket provides a PSM (something like a dynamic port number) that needs to be communicated to the client somehow (eg via BLE advertising). We can use L2CAP when the central and peripheral both support it and fall back to GATT when they don't
|
|
|
- The Moto G never receives the result of starting advertising (no callback to `onAdvertisingStarted()` or `onAdvertiseFailure()`)
|
|
|
- The Moto G and P8 Lite can discover the J5, but it can't discover them and they can't discover each other
|
|
|
- The Moto G 4G never receives the result of starting advertising (no callback to `onAdvertisingStarted()` or `onAdvertiseFailure()`)
|
|
|
- The Moto G 4G and Huawei P8 Lite 2015 can discover the Samsung Galaxy J5 2016, but it can't discover them and they can't discover each other
|
|
|
- The P8 Lite can connect to the J5 via GATT and exchange pings and pongs
|
|
|
- The Moto G can't connect to the J5 via GATT: it receives a callback to `onConnectingPeripheral()`, never receives `onConnectedPeripheral()`, and eventually receives `onDisconnectedPeripheral()` with status `LMP_OR_LL_RESPONSE_TIMEOUT`. The J5 receives onCentralConnected() and onCentralDisconnected() as expected. The J5 can subsequently connect back to the Moto G, using the address it learned from the unsuccessful connection, and exchange pings and pongs
|
|
|
- When the J5 receives a connection from the Moto G or P8 Lite, the J5 sees the same address that the Moto G/P8 Lite gets from its own BluetoothAdapter, ie the BT classic address. So it may be possible for the Moto G/P8 Lite to advertise this address via WFD (since BLE advertising isn't available) and use the address to receive GATT connections and/or BT classic connections.
|
|
|
- When the J5 receives a connection from the Moto G or P8 Lite, the J5 sees the same address that the Moto G/P8 Lite gets from its own BluetoothAdapter, ie the BT classic address
|
|
|
|
|
|
### Socket-Like Communication via GATT
|
|
|
|
|
|
GATT makes it easy to implement services in which a central and a peripheral exchange small pieces of data in a predefined structure.
|
|
|
However, as we're interested in building a protocol stack where the higher-layer protocols may operate over a mixture of transport layers, it would be useful if the various transport layers could provide similar abstractions.
|
|
|
|
|
|
The various LAN and Wi-Fi transports we investigated can use TCP sockets, while Bluetooth RFCOMM and L2CAP CoC both provide socket-like abstractions, so it would be useful if GATT could provide a socket-like abstraction too.
|
|
|
|
|
|
This can be done by defining a service with two characteristics: a "read characteristic" that allows the central to read data from the peripheral, and a "write characteristic" that allows the central to write data to the peripheral. By enabling notifications for the read characteristic, the peripheral can push data to the central, so either peer can send data to the other.
|
|
|
|
|
|
This `blessed-gatt` testbed branch demonstrates this technique.
|
|
|
|
|
|
### BLE Allocator Characteristic
|
|
|
|
|
|
The `blessed-gatt` testbed branch exemplifies how individual connections can be made using BLE. However, the one of the core features for a performative ad-hoc mesh system is the ability to make simultaneous p2p connections between 3+ devices. In order to support multi-device scenarios, we developed the "allocator characteristic" system which guides incoming central devices to the correct read characteristic, in order to read arbitrary amounts of data from the advertising peripheral device.
|
|
|
The high level structure of the allocator characteristic system is built using two main characteristics:
|
|
|
One of the core features for a performative ad-hoc mesh system is the ability to make simultaneous p2p connections between multiple devices.
|
|
|
We found that some of the test devices could support simultaneous GATT connections to multiple peripherals when acting as a central.
|
|
|
Some of the test devices could also support connections from multiple centrals when acting as a peripheral, but here we ran into a difficulty: when multiple centrals are connected to the same peripheral, GATT does not provide a way for the peripheral to send data to a specific central.
|
|
|
If the peripheral updates the value of a read characteristic, the new value is seen by all connected centrals.
|
|
|
|
|
|
In order to support multi-device scenarios, we developed the "allocator characteristic" system, which uses a separate read characteristic for each connected central, together with a characteristic called the allocator that tells each central which read characteristic to use.
|
|
|
|
|
|
In more detail, the allocator characteristic system uses the following characteristics:
|
|
|
|
|
|
- Read Characteristic
|
|
|
- Array of Read Characteristics
|
|
|
|
|
|
This is a characteristic that a single central will connect to and read data from.
|
|
|
At Bluetooth service startup the number of read characteristics is known so for each device there is an upper limit to the amount of simultaneous central connections.
|
|
|
Each element of this array is a characteristic that a single central will read data from.
|
|
|
The number of read characteristics is defined when the peripheral starts its GATT service, based on the number of simultaneous central connections the peripheral can support, or a hardcoded value if the number of supported connections isn't known.
|
|
|
|
|
|
- Allocator Characteristic
|
|
|
|
|
|
The allocator characteristic is a readable characteristic that displays a list of `SESSION_ID`'s of connected devices.
|
|
|
When a new central tries to make a connection to the peripheral device, it will first check this list to confirm it is not already currently reading from that peripheral device.
|
|
|
This system also allows centrals to monitor when a peripheral is fully busy with devices reading from it.
|
|
|
This is a read characteristic that contains a list of values, each of which is either a null value or the session identifier of a connected central.
|
|
|
The elements of this list correspond to the elements of the array of read characteristics: a null value means the corresponding read characteristic is unallocated, while a non-null value means the corresponding read characteristic is allocated to the central with the given session identifier.
|
|
|
|
|
|
- Write Characteristic
|
|
|
|
|
|
All connected centrals write to the same characteristic.
|
|
|
The peripheral can tell which central is the source of each write, so there's no need for an array of write characteristics.
|
|
|
|
|
|
When a central connects to the peripheral, it first reads the value of the allocator characteristic to check whether the peripheral has already allocated all of its read characteristics.
|
|
|
If the peripheral has capacity available then the central writes a session identifier to the write characteristic and then waits for the peripheral to update the allocator characteristic.
|
|
|
|
|
|
The peripheral allocates a read characteristic to the newly connected central and puts the central's session identifier in the corresponding element of the allocator characteristic.
|
|
|
When the central receives the new value of the allocator characteristic, it knows which read characteristic it should use for receiving data from the peripheral.
|
|
|
|
|
|
The newly connected central and the peripheral can then communicate in a socket-like fashion via the allocated read characteristic and the shared write characteristic.
|
|
|
|
|
|
When the central disconnects, the peripheral deallocates the read characteristic and puts a null value in the corresponding element of the allocator characteristic, indicating that it has capacity available for another central.
|
|
|
|
|
|
#### Peer Advertisement
|
|
|
|
... | ... | |