Resources#

Silicon Labs Resources#

Bluetooth SIG Resources#

iOS: Complying with Encryption Export Regulations#

Every app submitted to TestFlight, or the App Store is uploaded to a server in the United States. It is a developer responsibility to make sure that the uploaded app is fully legal and contains all necessary information. For that reason, each developer should become familiar with Encryption Export Regulations. If the app uses, accesses, contains, implements, or incorporates encryption, this is considered an export of encryption software, which means that the app is subject to U.S. export compliance requirements, as well as the import compliance requirements of the countries where the app is distributed.

A more detailed explanation can be found at Encryption Export Regulations.

The following authentication, encryption and hash algorithms are used by the Bluetooth Mesh ADK:

  • AES, 256 bit

  • AES CCM, 128 bit

  • AES ECB, 128 bit

  • Elliptic Curve Diffie-Hellman

Android: Known Bluetooth Issues#

While developing applications using Bluetooth LE for Android devices many problems can occur. Unfortunately, troubleshooting is not as straightforward as for the iOS. This section describes collected information how Bluetooth LE on Android works, common issues, and advice on how to solve them. It can help you to develop your application faster.

Working with Bluetooth LE on Android is difficult, because:

  • Device manufacturers make changes to the Android Bluetooth LE stack. Your application can work well on one device but could have problems on another.

  • Documentation on Bluetooth LE describes only basic concepts, but does not provide enough information about managing connections, need for queuing operations, or dealing with bugs.

Scanning#

Scanning for Bluetooth LE devices is power consuming. Four scan modes are available:

  • SCAN_MODE_BALANCED: good trade-off between scan frequency and power consumption

  • SCAN_MODE_LOW_LATENCY: highest scanning frequency

  • SCAN_MODE_LOW_POWER: default scan mode consuming the least power

  • SCAN_MODE_OPPORTUNISTIC: application that is using this mode will get scan results if another application is scanning (it does not start its own scanning)

Some applications may scan continuously, which would consume the phone’s battery power. In order to limit this Android has implemented changes related to scanning. In Android 7.0 and newer versions there is protection against Bluetooth LE scanning abuse. If your app starts and stops Bluetooth LE scans more than 5 times within 30 seconds, scan results will not be received temporarily. Moreover, starting with Android 7.0, you can perform one scan with a maximum time of 30 minutes. After this time Android will change the scan mode to SCAN_MODE_OPPORTUNISTIC. As of Android 8.1, if you do not set any ScanFilters scanning will be paused when the user turns off the screen, and will resume after the screen is turned on again.

Remember that the scanning process has to be stopped in your application. If you know the devices the user is looking for, stop the process when all devices are found. If you do not know which devices the user is looking for, stop scanning after a fixed period. Also consider stopping the scanning process if the user goes to another Activity or your application goes background.

Connecting#

Some phones have problems with connecting during scanning, so it would be better to stop scanning if you do not need to find another device. It is also recommended to wait about 500 milliseconds after stopping the scan before trying to connect to a device in order to avoid GATT_ERROR.

Auto connect

When you get a proper BluetoothDevice object from ScanResult you can connect to it by calling one of connectGatt() method on BluetoothDevice. All versions of this method contain a parameter named autoConnect. Official documentation describes it only as “Boolean: It determines whether to directly connect to the remote device (false) or to automatically connect as soon as the remote device becomes available (true).”

When you connect to a device with autoConnect set to false (direct connect) Android will try to connect to the device with a 30 second timeout. After that (if there was no other callback) you will receive an update with status GATT_ERROR (code 133). If there are pending connection attempts with autoConnect set to true they will be suspended for this time. This direct connect attempt will not be executed until another pending direct connect is finished. A direct connect attempt usually takes less time to succeed than an auto connect one.

Android waits until it sees this device and connects when it is available. Using auto connect allows you to have more than one pending connection at the same time. These connections have no timeout, but they will be canceled when Bluetooth is turned off. If you are using autoConnect set to true, you could be able to reconnect to the device as well. But the device must be in Bluetooth cache or be bonded before. Remember that turning Bluetooth off, rebooting your phone or manually clearing cache in settings menu will clear device information, so check the cache before attempting to reconnect.

Managing a Connection#

Connection State

After trying to connect to a device with the connectGatt() method you should be informed about the result with the onConnectionStateChange callback. It provides information about status and newState, which you will use to perform appropriate steps.Remember to use the close() method on the BluetoothGatt object if the status is different than GATT_SUCCESS, or it is GATT_SUCCESS and the state is equal to STATE_DISCONNECTED, which means that device was successfully disconnected. If you do not call close() the client registered for this connection will not be removed. Once 30 clients are reached (usually 5 are used by default after rebooting the phone) the user will not be able to connect to another device (until they clear the cache).

Changing MTU

Maximum Transmission Unit (MTU) determines the maximum length of the data packet sent between phone and Bluetooth LE device. You can request changing MTU size after successfully connecting with the device, before exchanging data with it. The default value of MTU is 23 (GATT_DEF_BLE_MTU_SIZE), but usually 3 bytes contain ATT headers, so only 20 bytes can be sent. Change MTU by calling requestMtu(size) on the BluetoothGatt object, where size parameter is the new MTU length. Remember that the maximum available value is 517 (GATT_MAX_MTU_SIZE). If calling requestMtu(size) returns true, wait for the onMtuChanged callback with the result.

Discovering Services

Remember also that many Bluetooth LE operations are asynchronous, and you need to wait for a callback to perform next operation. For example, after getting onConnectionStateChange with status GATT_SUCCESS and newState STATE_CONNECTED you need to call discoverServices(). It returns true if service discovery started and you must wait for the onServicesDiscovered callback containing the status of this process. If you receive GATT_SUCCESS you can, for example, read/write characteristics, but if the result was not successful you need to disconnect from the device, because without services discovered you cannot perform those operations.

Reading/Writing Characteristics

These operations are also asynchronous, and you can perform only one operation at a time. To solve this, use a queue for your operations. Add the next operation to it and, when the first is completed, it is removed from queue and the next command is executed.

When writing data to a characteristic you can specify the write type. There are two available types: WRITE_TYPE_DEFAULT and WRITE_TYPE_NO_RESPONSE. Bluetooth Mesh supports only WRITE_TYPE_NO_RESPONSE.

Disconnecting

In Android you might have problems with performing some operations, as reconnecting, after improperly disconnecting from a device. There is a timeout while the phone continues opening connection events and the device is not fully disconnected, so you could have trouble connecting to it again. In Android this timeout was hardcoded to 20 seconds and has been changed to 5 seconds in Android 10, so it can take a lot of time until you are notified about the closed connection. In iOS this usually takes less than 1 second. If you want to reconnect immediately after disconnecting you could get status code 22, so it would be better to wait about 500 milliseconds before the connection attempt.

Errors#

Many errors can be received on some callback when working with a Bluetooth LE device. Unfortunately, not all of them have descriptions to help you to determine the problem. A common error is status 133 named GATT_ERROR. Unfortunately, no information about it is in BluetoothGatt class documentation. If you got this error, the problem could be one of the following:

  • You try to connect with autoConnect set to false and receive the error after the 30 second timeout.

  • After disconnecting from the device you do not invoke close() so you get the error when next trying to connect.

  • The Bluetooth cache contains some invalid data, so restart your phone.

  • You use a device that has problems with Bluetooth LE. Some models, for example older Huawei phones, are known to have low Bluetooth LE quality. Try using another phone.

  • There was a problem on the Bluetooth side. After calling close() and waiting a little time, try connecting again.