MOTOROLA BLUETOOTH LOW ENERGY API
Created: November 14, 2011

sf500-hrm-headphones.jpgThis document details the API that applications can use to interface with Bluetooth LE (Low Energy) profiles implemented by certain Motorola Mobility devices. This API is intended for use by applications that provide a user interface to the LE profiles; it is not used to implement the profile itself. All of the data processing for a specific profile happens in the profile implemented by Motorola. Applications only use the computed data and present it to the user. The Bluetooth Low Energy API allows an application to connect to a remote device on a specific LE profile and perform read and write operations in adherence to the profile specification. All error handling is done in the profile layer: appropriate error codes are sent to the application using Intents.

A sample application showing the use of this API can be found in the SDK Add-Ons for each Motorola device that supports Bluetooth LE.

Application requirements

Applications using the Bluetooth Low Energy API must meet the following requirements:

  • Applications must use standard Android API for non-LE Bluetooth operations such as device discovery and Bluetooth device pairing.
  • Data received by and sent to the application must conform to the profile specification. Application requirements that fall outside the profile specification may not be supported.

The application must register a callback with the profile (during connect) to receive user data from the peer device.

Classes used by applications

Applications that interact with a Bluetooth LE device (such as a heart rate monitor) typically rely upon the following classes:

  • android.bluetooth.BluetoothDevice
  • android.bluetooth.BluetoothClass
  • android.bluetooth.BluetoothAdapter
  • com.motorola.bluetooth.hrm.IBluetoothHrm
  • com.motorola.bluetooth.hrm.IBluetoothHrmCallback
  • com.motorola.bluetoothle.BluetoothGatt

The android.bluetooth classes are part of the Android SDK. The com.motorola.bluetooth... classes are packaged in the MotBTLE_API_stubs.jar library file (which can be found in the SDK add-on for devices that support this API); add this JAR file to your project in order to use them. You do this by opening your project's properties, navigating to Java Build Path, clicking the Libraries tab, and then using either Add JARs (if the JAR file is among the files that make up your project) or Add External JARs (if the JAR file is on your development computer but not within your project).

Architecture

The following architecture diagram shows how the components are placed in the Android space. Third-party applications use the API described in this document to communicate with the LE profiles.

architecture.png 

Basic heart rate use case

  1. User invokes the Heart Rate app on their phone.
  2. The app triggers the Heart Profile Service (Connect MSC).
  3. The app/user scans for LE devices, then pairs and connects to it (Connect MSC).
  4. Based on the app configuration, the heart rate data is received from the peer device at every interval using callbacks. (Receive Data MSC).
  5. Received data is displayed by the app to the user. This data format needs to be negotiated for each profile implementation. For HRM we have Beats Per Minute, Energy Expended, R-R Intervals, sent in the data argument as an array of bytes. 

IBluetoothHrm methods used by applications

connectLe

int connectLe (BluetoothDevice device, String service, IBluetoothHrmCallback callback)

Connects to a remote LE device. Before invoking this method you must have used the Android Bluetooth API to discover and pair with a device. This method requires you to supply the device address of the remote LE device and the UUID of the profile/service to which your app is to connect. You also supply a callback object, which receives user data sent from the peer device. See IBluetoothHrmCallback interface for information on the callback object.

This method is asynchronous: after calling it you need to wait for confirmation of the disconnection, which is delivered using an Intent with its action set to the following:

BluetoothGatt.CONNECT_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.CONNECT_COMPLETE")

This Intent includes the following extra data:

Extra name Data type Data
"device" BluetoothDevice Address of the remote device that was connected.
"uuid" String UUID of the service that was connected.
"status" int An integer status code: one of the values listed under Status codes.

Parameters

device
address of the remote device being connected to.
service
UUID of the service to which your app is to connect.
callback
IBluetoothHRMCallback object that receives user data from the connected device/service.

Returns

An integer status code: one of the values listed under Status codes.

 

disconnectLe

int disconnectLe (BluetoothDevice device, String service)

Disconnects from a remote LE device. You must supply the address of the remote LE device and the UUID of the profile/service from which you want to disconnect.

This method is asynchronous: after calling it you need to wait for confirmation of the disconnection, which is delivered using an Intent with its action set to the following:

BluetoothGatt.DISCONNECT_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.DISCONNECT_COMPLETE")

This Intent includes the following extra data:

Extra name Data type Data
"device" BluetoothDevice Address of the remote device that was disconnected.
"uuid" String UUID of the service that was disconnected.
"status" int An integer status code: one of the values listed under Status codes.

Parameters

device
address of the remote device from which the app is to disconnect.
service
UUID of the service from which the app is to disconnect.

Returns

An integer status code: one of the values listed under Status codes.

 

getLeData

int getLeData (BluetoothDevice device, String service, int operationType)

Obtains data from a remote LE device. You must supply the address of the remote LE device, the UUID of the profile/service from which you want to get data, and the type of operation to be performed (from the list under OperationType values).

This method is asynchronous: after calling it you need to wait for confirmation, which is delivered using an Intent with its action set to the following:

BluetoothGatt.GET_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.GET_COMPLETE")

This Intent not only confirms the operation but, if the operation was successful, also contains the requested data. It includes the following extra data:

Extra name Data type Data
"device" BluetoothDevice Address of the remote device from which the data was sent.
"uuid" String UUID of the service that sent the data.
"status" int An integer status code: one of the values listed under Status codes.
"length" int The number of bytes of data that was sent.
"data" byte[] The data.

Parameters

device
address of the remote device with which your app is communicating.
service
UUID of the service with which your app is communicating.
operationType
an integer indicating the operation to be performed: one of the values from the list under OperationType values.

Returns

An integer status code: one of the values listed under Status codes.

 

setLeData

int setLeData (BluetoothDevice device, String service, int operationType, byte [] data, int length)

Writes data to a remote LE device. You must supply the address of the remote LE device and the UUID of the profile/service to which you want to write data. You also supply an operation type (a 16-bit unsigned integer from the list under OperationType values) and the data to be written.

This method is asynchronous: after calling it you need to wait for confirmation, which is delivered using an Intent with its action set to the following:

BluetoothGatt.SET_COMPLETE ("com.motorola.bluetoothle.bluetoothgatt.SET_COMPLETE")

This Intent includes the following extra data:

Extra name Data type Data
"device" BluetoothDevice Address of the remote device to which the data was sent.
"uuid" String UUID of the service to which the data was sent.
"status" int An integer status code: one of the values listed under Status codes.

Parameters

device
address of the remote device with which your app is communicating.
service
UUID of the service with which your app is communicating.
operationType
an integer indicating the operation to be performed: one of the values from the list under OperationType values.
data
the data to be written to the specified device/service.
length
the length of data, in bytes.

Returns

An integer status code: one of the values listed under Status codes.

 

IBluetoothHrmCallback interface

Data sent from a Bluetooth LE device is sent to a registered object that implements the IBluetoothHrmCallback interface. Per the GATT profile specification, data can be received either as an Indication or as a Notification. Accordingly, the callback should implement both of the following methods and should expect data to come in through either.

indicationLeCb

void indicationLeCb (in BluetoothDevice device, String service, in int length, in Byte [] data)

Parameters

device
address of the remote device from which the data was sent.
service
UUID of the service from which the data was sent.
length
length of the sent data, in bytes.
data
the data.

notificationLeCb

void notificationLeCb (in BluetoothDevice device, String service, in int length, in byte [] data)

Parameters

device
address of the remote device from which the data was sent.
service
UUID of the service from which the data was sent.
length
length of the sent data, in bytes.
data
the data.
 

OperationType values

The following enums represent different operation types that apps can use to perform read or write operations. These enum values cover all operations as defined by the GATT profile for Bluetooth LE and are extensible if needed.

Constant Value
OPERATION_READ_PRIMARY_SERVICES 0
OPERATION_READ_CHARACTERISTICS 1
OPERATION_RESET_ENERGY_EXPENDED 2
OPERATION_READ_SENSOR_LOCATION 3
OPERATION_ENABLE_INDICATION 4
OPERATION_ENABLE_NOTIFICATION 5
OPERATION_DISABLE_INDICATION 6
OPERATION_DISABLE_NOTIFICATION 7

Status codes

The following codes indicate the status of an operation. These status codes are used both as API return values and as status in the Intents.

Constant Value
SUCCESS 0
PENDING 1
CONNECTION_EXISTS 2
FAILURE 3
INVALID_OPERATION 4
FORBIDDEN 5
SERVICE_UNAVAILABLE 6
UNKNOWN_ERROR 7

Other constants

Constant Value Description
EXTRA_PRIMARY_UUID "com.motorola.bluetoothle.bluetoothgatt.extra.PRIMARY_UUID" Key used for extra data containing the heart rate monitor UUID; use this when constructing a BluetoothGatt.ACTION_START_LE intent.

HRM data format

The HRM data is passed from the HRM profile to the app through the notificationLeCb callback. The data is delivered as an array of bytes and should be interpreted by the application as follows:

Bytes Description
0-1 The heart rate measurement value. A value of 0 in byte 1 indicates the incoming heart rate data is an unsigned 8-bit integer.
2-3 The energy expended value. A value of 0 implies energy expended data is not supported by the heart rate sensor. The maximum energy expended value can be 0xFFFF. If the app receives this maximum value it needs to provide the user with an option to reset the energy expended.
4-n The R-R interval values. The application needs to calculate the number of R-R interval values sent based on the total length of incoming data. If the length of the incoming data is 4 it implies the R-R interval values are not present.

Using the heart rate monitor profile

To use the above API for a heart rate monitor application, the following needs to be done:

  1. Import the following aidl files in the app's source code:
    • com.motorola.bluetooth.hrm.IBluetoothHrm
    • com.motorola.bluetooth.hrm.IBluetoothHrmCallback
    • com.motorola.bluetoothle.BluetoothGatt
  2. Bind to the HRM service using the IBluetoothHrm interface:
    Intent intent1 = new Intent(IBluetoothHrm.class.getName());
    getApplicationContext().bindService(intent1, mConnection, Context.BIND_AUTO_CREATE);
    
  3. In your code that handles the service connection, invoke the connectLe() method and pass an HrmCallback object as an argument:
    callback callback1 = new callback(hrmUUID);
    	...
    mHrmService = IBluetoothHrm.Stub.asInterface(service);
    	...
    int status = mHrmService.connectLe(device1, hrmUUID,  callback1);
    
  4. Start the BluetoothGatt service, passing it the service UUID for the heart rate monitor:
    Intent intent2 = new Intent(BluetoothGatt.ACTION_START_LE);
    intent2.putExtra(BluetoothGatt.EXTRA_PRIMARY_UUID, hrmUUID);
    sendBroadcast(intent2);
    

Message sequence diagrams

Connect

connect.png 

Disconnect

disconnect.png 

Get data

get_data.png 

Set data

set_data.png 

Receiving user data from peer device

 receive_data.png

Checking for Bluetooth LE support

At runtime, apps can check for Bluetooth Low Energy support by verifying the presence of the BluetoothGattService class, like this:

try {
	@SuppressWarnings("unused")
	Class object = Class.forName("android.server.BluetoothGattService");
	deviceSupportsLE = true;
} catch (Exception e) {
	deviceSupportsLE = false;
}

References

 

 

Created: November 14, 2011

ECCN 5D992.a: In accordance with United States Export Administration Regulations (EAR), and specifically the Commerce Control List (CCL), this item has been classified 5D992.a. Export or re-export of this commodity and compliance with the U.S. Export Administration Regulations is ultimately the responsibility of the exporter. For more detailed information related to export or re-export of this item, please consult the EAR at http://www.access.gpo.gov/bis/ear/ear_data.html.

Copyright © 2011, Motorola Mobility, Inc. All rights reserved unless otherwise explicitly indicated. Sample source code written by Motorola Mobility, Inc. is provided to you under the conditions of the Motorola Modified BSD License.

print the page