Bluetooth Low Energy Connection Parameters for And

2019-01-31 10:20发布

问题:

I've been looking all over the place for the required bluetooth connection parameters that will work for all three of these operating platforms. I'm using the HOGP (Bluetooth over HID GATT) profile for this project.

My project is an embedded system written by myself with a BLE module that I have control over the following parameters for connection.

  1. Connection Interval Min
  2. Connection Interval Max
  3. Slave Latency
  4. Supervision Timeout
  5. Advertising Interval Min
  6. Advertising Interval Max

My target devices to connect will be to satisfy connnections with Android >= 4.3, iOS7, and >= Win 8.1.

Apple was kind enough to give a document with the appropriate parameters on page 22 in the link below. I have not been able to find any information about Android and Win 8.

https://developer.apple.com/hardwaredrivers/bluetoothdesignguidelines.pdf

My current working settings for iOS7 tested fully with bidirection communication with freeware lightBlue is as follows. My embedded code and host software for iOS7 works.

  1. Connection Interval Min 30ms
  2. Connection Interval Max 56.25ms
  3. Slave Latency 3
  4. Supervision Timeout 5000ms

I've found from another stack overflow page that android allegedly works on 7.5ms Connection Interval from the following links.

  1. Android BLE Connection time interval
  2. http://processors.wiki.ti.com/index.php/Bluetooth_SensorTag?DCMP=lprf-stdroid&HQS=lprf-stdroid-pr-wiki1#Supported_Android_devices

Unfortunately the second requirement from apple iOS spec is that "Interval Min ≥ 20 ms".

Am I not understanding these ranges or how they are interpreted? If I set the Interval min to 7.5ms for Android wouldn't that void apples requirements? How can I satisfy both systems and also Win8 if possible?

My understanding is that the slave device offers a suggested setting in between the min and max and the master (smartphone) alerts the user of the actual selected value in that range.

I appreciated any help with this issue and hope this post could benefit others considering the fairly new and incomplete knowledge base for BLE.

Thanks in advance!

回答1:

First, the connection interval defines a time window during which both devices use the same frequency to transfer data. There are 37 data channels in total, and connected devices hop through them every Connection Interval.

Thus, both devices has to agree on precise values for these parameters from the beginning in order to be in sync, i.e., connected.

Second, when connection is established the master (or Central) sends connection parameters it supports. The other device (or peripheral) just blindly takes them. iOS by default sets connection interval to 30 ms. After the connection is established the peripheral can request connection parameters update, by defining the min and max values, according to the guidelines apple has provide you with. The receiving part, read iOS in this case, will pick whatever it find best for it between [min;max], and will send back response with exact values it has picked. It also can reject the request, if the values do not comply with the guidelines.

Lastly, 7.5ms is the minimum length of the connection interval defined by Bluetooth specification. The maximum value is 4 s. The lower it is, the higher bandwidth, but higher power consumption. And the opposite in the higher values. The best value depends on the specific application. Considering that you work with HID profile I assume latency is important to you.

iOS says that it supports connection intervals down to 20ms (although I found it hard to achieve this some times), but in your case (HID profile) they also allow 11.25 ms.

Hope that helps.



回答2:

To modify parameters in Android (requesting from Central to Peripheral) you can do something like this:

private String CONN_SERVICE_UUID = "00001800-0000-1000-8000-00805f9b34fb";
private static final UUID CONN_CHARACTERISTIC_UUID = UUID.fromString("00002a04-0000-1000-8000-00805F9B34FB");
private static final int CONN_INTERVAL = 0x0006;
private static final int SUPERVISION_TIMEOUT = 0x000A;
private void findServiceForConnectionParams(List<BluetoothGattService> gattServices){
    BluetoothGattService connGattService = filterServices(gattServices, CONN_SERVICE_UUID);
    if (connGattService != null) {
        setConnectionInterval(connGattService);
    }
}
private void setConnectionInterval(BluetoothGattService gattService) {
    if (gattService == null) {
        Log.e(TAG, "setConnectionInterval. Gatt service is null!");
        return;
    }
    BluetoothGattCharacteristic connCharacteristic = 
            gattService.getCharacteristic(CONN_CHARACTERISTIC_UUID);
    if (connCharacteristic != null) {
        byte[] value = { (byte) (CONN_INTERVAL & 0x00FF), // gets LSB of 2 byte value
                (byte) ((CONN_INTERVAL & 0xFF00) >> 8), // gets MSB of 2 byte value
                (byte) (CONN_INTERVAL & 0x00FF),
                (byte) ((CONN_INTERVAL & 0xFF00) >> 8),
                0, 0,
                (byte) (SUPERVISION_TIMEOUT & 0x00FF),
                (byte) ((SUPERVISION_TIMEOUT & 0xFF00) >> 8)
        };
        connCharacteristic.setValue(value);
        boolean status = mBluetoothGatt.writeCharacteristic(connCharacteristic);
        Log.d(TAG, "setConnectionInterval. Change connection interval result: " + status);
    } else {
        Log.e(TAG, "setConnectionInterval. Connection characteristic is null!");
    }

}
private BluetoothGattService filterServices(List<BluetoothGattService> gattServices, String targetUuid) {
    for(BluetoothGattService gattService : gattServices){
        String serviceUUID = gattService.getUuid().toString();
        Log.i(TAG, "serviceUUID: " + serviceUUID);

        if(serviceUUID.equals(targetUuid)){
            Log.i(TAG, "serviceUUID matches! UUID: " + serviceUUID + " Type: " + gattService.getType());
            // no needed, just to check which characteristics are offered
            for(BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
                Log.i(TAG, "serviceUUID characteristics: " + characteristic.getUuid().toString());
            }
            return gattService;
        }
    }
    return null;
}

I must say though that it didn't work for me using Android 5 devices both as peripheral and central, because Generic Acces Service (0x1800) is not offering in my device Characteristic 0x2a04 for Preferred Connection Parameters. It's only offering 0x2a00 (device name) and 0x2a01 (appearance). References:

http://www.cumulations.com/blogs/7/Doing-firmware-upgrade-over-BLE-in-Android

https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters.xml

https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_access.xml

https://farwestab.wordpress.com/2011/02/05/some-tips-on-android-and-bluetooth/



回答3:

I believe that this characteristic is only meant to provide information to the Central device. That is why it is generally read-only (for me, and cxphong). Bingen's answer does not universally work, and I am not certain it is meant to work that way. Has anybody actually got it to work on a specific device?

It appears that Android and iOS do not consult the information in this read-only characteristic, and so I am not certain that it is very useful.

What works for me is described below, for Cypress peripheral and Android central. A similar approach should work with other devices.

  1. On peripheral, define the preferred connection parameters in a CYBLE_GAP_CONN_UPDATE_PARAM_T structure "params".
  2. After GATT connection, in CYBLE_EVT_GATT_CONNECT_IND event handler (for example), call CyBle_L2capLeConnectionParamUpdateRequest(connHandle, &params).

On the central side, there is nothing to do. After it receives the request, it will initiate the parameter update a bit later.

Cheers,

David