labs.beatcraft.com
Android

1. About BLE (Bluetooth Low Energy)

BLE is the abbreviation of Bluetooth Low Energy and a part of Bluetooth 4.0 standard.

Technical Overview:

  • Ultra-low power consumption (being capable of operating more than a year in a button battery.)
  • No compatibility with the previous version of Bluetooth (Classic Bluetooth)
  • Communication distance is 2.5m to 10m.
  • A single BLE unit does not have restrictions on the number of concurrent connections. (Classic Bluetooth allows a single unit to connect with 7 units at most.)

2. Basic knowledges of BLE communication

In the communication of BLE, GATT (Generic Attribute Profile), a client-server model, is employed.
A device (server) consists of Profile (GATT), Service, Characteristic, and Descriptor. The diagram below describes the design of model.

gatt.png

Profile

GATT (Generic Attribute Profile) is a theoretical design for data communication between BLE devices.~ This handles to read the data structure, to write data, and to notify the change in data.

GATT consists of three elements, such as Service, Characteristic, and Descriptor.
Profile does have more than one Service.

Service

Service shows the functions of Profile.
Service consists of several nesting Services and several Characteristics.

Characteristic

Characteristic does have a single value, which indicate its attribute.
It consists of own value, property, which defines how to access the value, and several Descriptors.

Descriptor

Descriptor shows the attribute value, which is used when a characteristic needs the additional information.
Some Characteristics do NOT contain any Descriptors.

3. BLE on Android

Android 4.3 or above (API Level 18 or greater) supports BLE.

Bluetooth Package

android.bluetooth.*

BluetoothManager

It manages the functions of Bluetooth.
It acquires BluetoothAdapter from BluetoothAdapter.

BluetoothAdapter

It controls Bluetooth set at a mobile device.
It scans Bluetooth devices.

BluetoothGatt

It operates GATT profile.
It manages the search for Services, and the configuration of Descriptor.

BluetoothDevice

It receives the scanning results of BluetoothAdapter.
It is the information of Bluet device.

BluetoothGattService

It is the information of (GATT) Services. It holds Characteristic (BluetoothGattCharacteristic).

BluetoothGattCharacteristic

It is the information of Characteristic.
It holds Descriptor (BluetoothGattDescriptor). Some Characteristics do NOT have Descriptors.

BluetoothGattDescriptor

The information of Descriptor.

4. Implementation of BLE on App

Permission

Please add these tags listed below to Manifest (AndroidManifest.xml) for making BLE effective.
Configuration for Permission

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>


Please add the tag to Manifest for making sure that the API only work with Android devices, which support BLE.

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

Initializing

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();


Making BLE effective

As the app is executed, this checks whether Bluetooth function is available or not, If BLE is not effective, a dialog appears for confirmation to make BLE effective.

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
                return false;
        }
        // Checking Bluetooth function effective or not. If it is not effective, a dialog appears for confirmation to enable BLE
        if (mBluetoothAdapter.isEnabled()) {
                // Bluetooth is effective
        } else {
                // Bluetooth is NOT enabled, and the confirmation dialog appears. 
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                activity.startActivityForResult(enableBtIntent, 1);
        }

Scanning

 // Stop scanning 10 seconds later.
        private static final long SCAN_PERIOD = 10000;
        ...
        private void scanLeDevice(final boolean enable) {
            if (enable) {
                // Stops scanning after a pre-defined scan period.
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mScanning = false;
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    }
                }, SCAN_PERIOD);
                mScanning = true;
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
            ...
        }
        private LeDeviceListAdapter mLeDeviceListAdapter;
        ...
        // The callback function after device scanning is completed
        private BluetoothAdapter.LeScanCallback mLeScanCallback =
                new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(final BluetoothDevice device, int rssi,
                    byte[] scanRecord) {
                runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                                        String msg = "name =" + device.getName() + ", bondstate = "
                        + device.getBondState() + ", address = "
                        + device.getAddress() + ", type" + device.getType()
                        + ", uuid = " + device.getUuid().toString();
                                Log.d("Scan", msg);}
               });
           }
        };

Connecting with a device

Call BluetoothDevice$connectGatt(), which is returned form onLeScan(), and connect with a device.

        BluetoothDevice:
        BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) 

Implementation of BluetoothGattCallback

private final BluetoothGattCallback callback =&#12288;new BluetoothGattCallback() {
                //      This is executed when the status of connection is changed.
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                // It is connected
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    Log.i(TAG, "Connected to GATT server.");
                    // Searching for Services
                    Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
                    // It is disconnected.
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    Log.i(TAG, "Disconnected from GATT server.");
                }
            }
            @Override
            // Return the search results of Services
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                // Success 
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    // Acquire the list of Services.
                    List<BluetoothGattService> gattService = getSupportedGattServices(address);
                    for(BluetoothGattService service : gattService) {
                        UUID uuid = service.getUuid();
                        // Acquire the list of Characteristics from Services.
                        List<BluetoothGattCharacteristic> charastics    = service.getCharacteristics();
                                        // Set up Characteristic for a reception request of Notification
                        for(BluetoothGattCharacteristic charastic : charastics) {
                                                //
                            gatt.setCharacteristicNotification(charastic, true);
                        }
                    }
                } else {
                    Log.w(TAG, "onServicesDiscovered received: " + status);
                }
            }
            // Notification for reading
            @Override
            public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                                // Characteristic is successfully read. 
                }
            }
            // Notification for writing
            @Override
            public void  onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                                // Characteristic is successfully written.
                }
         ...
        };

Reading

Since reading is asynchronous, the reading process requires reading request and reading notification.

Execute BluetoothGatt#readCharacteristic().
The results are returned to BluetoothGattCallBack#onCharacteristicRead().

Reading request

mBluetoothGatt.readCharacteristic(characteristic);

Reading notification

public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // Characteristic is successfully read.
            }
        }

Writing

Since writing is asynchronous, the writing process requires writing request and writing notification.

Execute BluetoothGatt#writeCharacteristic()
The results are returned to BluetoothGattCallBack#onCharacteristicWrite().

Writing request

mBluetoothGatt.writeCharacteristic(characteristic);

Writing notification

         public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // Characteristic is successfully written.
            }
        }

Releasing the connection

Execute BluetoothGatt#close().

Connecting multiple devices

To connect multiple devices, do not connect them simultaneously but connect them one by one.
If the new connection attempt is started before the current connection attempt has been completed, the operation of device becomes unstable.
If the new connection attempt is started before the scanning process is ended, the operation of device also becomes unstable.

Case (Example)

Connect with Device A, B, and C.

Processing procedure

1. Connect to Device A
BluetoothDevice#connectGatt()
2. Wait for the results of connection to Device A
BluetoothGattCallback#onConnectionStateChange()
3. Connect to Device B
BluetoothDevice#connectGatt()
4. Wait for the results of connection to Device B
BluetoothGattCallback#onConnectionStateChange()
5. Connect to Device C
BluetoothDevice#connectGatt()
6. Wait for the results of connection to Device C
BluetoothGattCallback#onConnectionStateChange()

About demonstration at Embedded Technology 2015

Exhibiting a single Android device is connected to 6 BLE devices, demonstrate how to handle these 6 devices with BLE connection.

Multiple device connection

Multiple BLE devices are connected.
6 devices are connected one by one.

LED light

There are three LED lights, and each light is capable of shifting six different brightness.
The brightness of LED lights is changed individually or collectively.

Switch

Employing three relays, turn on/off LED lights. It manages LEDs individually or collectively.

LED color light valve

It controls the color (RGB) of LED color light valve.

Revision History

  • 2016-02-19 This article is initially released.

Attach file: filegatt.png 1851 download [Information]

Front page   Edit Freeze Diff Backup Upload Copy Rename Reload   New List of pages Search Recent changes   RSS of recent changes
Last-modified: 2016-02-19 (Fri) 03:45:10 (3215d)