In Bluetooth development, some cases do not need to be connected, as long as the peripherals broadcast their own data, such as Apple’s iBeacon. Since Android 5.0 updated the Bluetooth API, the phone can broadcast data as a peripheral.
There are two types of broadcast packages:
- Advertising Data
- Response Package (Scan Response)
The broadcast packet is mandatory for each peripheral, and the response packet is optional. The length of each broadcast packet must be 31 bytes. If the length is less than 31 bytes, the rest of the packet is filled with zeros. This part of the data is invalid
Broadcast data unit
The broadcast package contains several broadcast data units, which are also called AD Structure.
Broadcast Data unit = Length + AD Type + AD Data.
The Length value Length takes only one byte and is the first byte of the broadcast data unit.
The concept of something abstract, first take a look at the following broadcast message:
0x indicates that the string is a hexadecimal string. Two hexadecimal numbers represent one byte. The maximum size of a two-character hexadecimal string is FF, which is 255, and the Java byte type ranges from -128 to 127, which is just the size of 255. So two hexadecimal strings represent one byte.
Continue to view the contents of the message and start reading the first broadcast data unit. Read the first byte :0x07, converted to decimal 7, meaning that the next 7 bytes are the data contents of this broadcast data unit. Any data content exceeding these seven bytes represents a new broadcast data unit.
For the second broadcast data unit, the value of the first byte is 0x16, which in decimal form is 22, indicating that the following 22 bytes are the second broadcast data unit.
In the data section of a broadcast data unit, the first byte represents the data type (AD type), which determines what data the data section represents. (the second byte of the broadcast data unit is AD type)
The AD Type is as follows:
- Flags: TYPE =0x01. It identifies the physical connection of the device LE.
- Bit 0: LE limited discovery mode
- Bit 1: LE common discovery mode
- Bit 2: Does not support BR/EDR
- Bit 3: Support BLE and BR/EDR for Same Device Capable(Controller)
- Bit 4: Support BLE and BR/EDR simultaneously for Same Device Capable(Host)
- bit 5.. 7: the reserved
Bits 1 to 7 represent the physical connection status of the Bluetooth chip that sends the broadcast. When the bit value is 1, the function is supported. Ex. :
-
Service UUID. In the broadcast data, the UUID of the GATT Service supported by the device can be broadcast to inform the central device of the supported Service. The UUID type for different bits varies:
- Incomplete 16 bits
UUID
: TYPE = 0x02; - The complete 16 bit
UUID
List: TYPE =0x03; - Incomplete 32bit
UUID
List: TYPE =0x04; - Full of 32 bit
UUID
List: TYPE =0x05; - An incomplete 128bit
UUID
List: TYPE =0x06; - The full 128 – bit
UUID
: TYPE = 0x07;
- Incomplete 16 bits
-
TX Power Level: TYPE = 0x0A: indicates the signal strength of the broadcast packet sent by the device. Value range: ±127 dBm.
-
Device name. DATA is a string of the device name. It can be the full name or the abbreviation of the device name.
- Abbreviated device name: TYPE = 0x08
- Complete device name: TYPE = 0x09
-
Service Data: Data of the Service.
- 16 bit
UUID
Service: TYPE = 0x16, the first two bytes areUUID
, followed by the Service data; - 32 bit
UUID
Service: TYPE = 0x20, the first 4 bytes areUUID
, followed by the Service data; - 128 bit
UUID
Service: TYPE = 0x21, the first 16 bytes areUUID
, followed by the Service data;
- 16 bit
-
Vendor – defined data: TYPE = 0xFF. In the vendor data, the first two bytes represent the vendor ID, and the remaining data are customized by the vendor.
BLE radio
The data format of Bluetooth broadcast is briefly introduced to help understand the following broadcast operations.
The customUUID
:
//`UUID`
public static `UUID` UUID_SERVICE = `UUID`.fromString("0000fff7-0000-1000-8000-00805f9b34fb");
Copy the code
Generally, three to four objects are required to enable broadcast: AdvertiseSettings, AdvertiseData, scanning package (optional), and AdvertiseCallback.
Radio set
AdvertiseSettings (AdvertiseSettings)
/ / initialize the radio set mAdvertiseSettings = new AdvertiseSettings. Builder () / / set broadcasting mode, to control the power of the radio and delays. SetAdvertiseMode (AdvertiseSettings. ADVERTISE_MODE_LOW_POWER) / / transmission power level SetTxPowerLevel (AdvertiseSettings. ADVERTISE_TX_POWER_HIGH) / / no more than 180000 milliseconds. A value of 0 disables time limits. .setTimeout(3000) // Set whether to connect. SetConnectable (false)
.build();
Copy the code
(1), through AdvertiseSettings. Builder# setAdvertiseMode () sets the radio mode. There are three modes:
- Perform bluetooth LE broadcast in balanced power mode:
AdvertiseSettings#ADVERTISE_MODE_BALANCED
- Perform Bluetooth LE broadcast in low latency, high power mode:
AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY
- Perform Bluetooth LE broadcast in low power mode:
AdvertiseSettings#ADVERTISE_MODE_LOW_POWER
(2), through AdvertiseSettings. Builder# setAdvertiseMode () sets the radio transmission power. There are 4 power modes:
- Broadcast with high TX power levels:
AdvertiseSettings#ADVERTISE_TX_POWER_HIGH
- Broadcast with low TX power levels:
AdvertiseSettings#ADVERTISE_TX_POWER_LOW
- Broadcast with medium TX power levels:
AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM
- Broadcast using the lowest transmission (TX) power level:
AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW
. (3), through AdvertiseSettings Builder# setTimeout () sets the continuous broadcasting time, milliseconds. At most 180,000 milliseconds. When 0, there is no time limit and the broadcast continues unless BluetoothLeAdvertiser#stopAdvertising() is called to stop the broadcast.
(4), through AdvertiseSettings. Builder# setConnectable () can set the radio connection.
Broadcast packets
As mentioned earlier, peripherals must broadcast broadcast packets, and scanning packets is optional. But adding a scan packet also means broadcasting more data, up to 62 bytes.
// Initialize the broadcast packet mAdvertiseData = new advertisedata.builder () // Set the name of the broadcast device.setincludeDevicename (trueSetIncludeDeviceName () setIncludeDeviceName()true) .build(); // Initialize the scan response package mScanResponseData = new advertisedata.builder () // Hide the broadcast device name.setincludeDevicename (false) // Hide the transmitted power level.setincludeDevicename (falseAddService 'UUID' (new Parcel 'UUID' (UUID_SERVICE)) // Set vendor data .addManufacturerData(0x11,hexStrToByte(mData)) .build();Copy the code
It can be seen that the AdvertiseData class is used to encapsulate the contents of both AdvertiseData and scan packets.
Advertisedata.builder# setIncludeDeviceName(), which can set whether the broadcast package contains the name of Bluetooth.
Advertisedata.builder #setIncludeTxPowerLevel() method, which can set whether the broadcast package contains bluetooth transmission power.
Advertisedata.builder #addServiceUUID(ParcelUUID) method that can set a specific UUID in the broadcast package.
Advertisedata.builder #addServiceData(ParcelUUID, byte[]) method that sets the specific UUID and its data in the broadcast package.
Advertisedata.builder# addManufacturerData(int, byte[]) method that sets the specific manufacturer Id and its data in the broadcast package.
As can be seen from the setup of advertiseData.Builder, if a peripheral needs to broadcast data externally without being connected, its data can be stored in the data corresponding to the UUID or in the vendor data. However, since the vendor ID needs to be assigned by Bluetooth SIG, the data between vendors is generally set to the vendor data.
Radio name
The name of the broadcast can also be set through BluetoothAdapter#setName()
BluetoothManager BluetoothManager = (BluetoothManager) getSystemService(context.bluetooth_service); mBluetoothAdapter = bluetoothManager.getAdapter(); / / set equipment bluetooth name mBluetoothAdapter. Elegantly-named setName ("daqi");
Copy the code
Send BLE broadcast
For an example, we set each advertiseData. Builder broadcast packet parameter in broadcast packet and scan packet respectively and get the following packet content:
(1), Type = 0x01 indicates the physical connection of the device LE.
(2), Type = 0x09 indicates the full name of the device
(3), Type = 0x03 indicates a complete 16-bit UUID. The value is 0xFFF7.
(4), Type = 0xFF indicates manufacturer data. The first two bytes indicate the vendor ID, that is, the vendor ID is 0x11. The following information is the manufacturer data, which is customized by users.
(5) Type = 0x16 indicates 16-bit UUID data. Therefore, the first two bytes are UUID data, that is, UUID is 0xF117, and the subsequent bytes are UUID data, which can be customized by users.
Finally, inherit AdvertiseCallback to customize the broadcast callback.
Private class daqiAdvertiseCallback extends AdvertiseCallback {// Callback for successfully enabling broadcast @override public void onStartSuccess(AdvertiseSettings settingsInEffect){ super.onStartSuccess(settingsInEffect); Log.d("daqi"."Service started successfully"); } // Cannot start broadcast callback. @Override public void onStartFailure(int errorCode) { super.onStartFailure(errorCode); Log.d("daqi"."Failed to start service, failure code ="+ errorCode); }}Copy the code
After initializing the above objects, we can broadcast:
// Get the BLE broadcast operation object. // Null is returned if Bluetooth is off or the device does not support Bluetooth LE broadcast. mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); //mBluetoothLeAdvertiser is not empty and Bluetooth is enabledif(mBluetoothAdapter.isEnabled()){
if(mBluetoothLeAdvertiser ! = null) {/ / open radio mBluetoothLeAdvertiser. StartAdvertising (mAdvertiseSettings mAdvertiseData, mScanResponseData, mAdvertiseCallback); }else {
Log.d("daqi"."This phone does not support BLE broadcast."); }}else{
Log.d("daqi"."Bluetooth is not enabled.");
}
Copy the code
Broadcasting is mainly implemented through the BluetoothLeAdvertiser#startAdvertising() method, but before that you need to get the BluetoothLeAdvertiser object.
The BluetoothLeAdvertiser object is Null in two cases:
- The Bluetooth module of mobile phones does not support BLE broadcast
- Bluetooth is not enabled
So, before calling BluetoothAdapter#getBluetoothLeAdvertiser(), we need to call bluetoothleadvertiser, And determine whether to obtain in the BluetoothAdapter BluetoothLeAdvertiser is empty (tested some huawei mobile phone mBluetoothAdapter. IsMultipleAdvertisementSupported () is false, But can send BLE broadcast).
And radio paired is BluetoothLeAdvertiser. StopAdvertising () stopped broadcasting, to open the radio transmission radio callback object, then close the radio:
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback)
Copy the code
Start GATT Services and Characteristic
The phone itself does not initialize Gattd’s Service, although it broadcasts that it owns these services. As a result, the external central device cannot find the corresponding GATT Service and obtain the corresponding data after connecting to the mobile phone.
Create the Gatt Service
There are two levels of Service types:
BluetoothGattService#SERVICE_TYPE_PRIMARY
The main serviceBluetoothGattService#SERVICE_TYPE_SECONDARY
Secondary services (services that exist in the master service)
BluetoothGattService creates the BluetoothGattService by passing in two parameters: UUID and Service type:
BluetoothGattService service = new BluetoothGattService(UUID_SERVICE,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
Copy the code
Create the Gatt Characteristic
As we all know in Gatt, the next level of Service is Characteristic, which is the smallest communication unit and communicates with read and write operations on Characteristic.
/ / initialize the eigenvalue mGattCharacteristic = new BluetoothGattCharacteristic (UUID_CHARACTERISTIC, BluetoothGattCharacteristic.PROPERTY_WRITE| BluetoothGattCharacteristic.PROPERTY_NOTIFY| BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_WRITE| BluetoothGattCharacteristic.PERMISSION_READ);Copy the code
Create BluetoothGattCharacteristic, introduced to three parameters: UUID, characteristics and permission attribute.
Representing the BluetoothGattCharacteristic has what function attributes to what BluetoothGattCharacteristic operation. There are three main types:
BluetoothGattCharacteristic#PROPERTY_WRITE
Indicates that the feature supports writeBluetoothGattCharacteristic#PROPERTY_READ
Indicates that features support readBluetoothGattCharacteristic#PROPERTY_NOTIFY
Indicates that the feature supports notification
The permission attribute is used to configure the functions of the feature value. There are two main types:
BluetoothGattCharacteristic#PERMISSION_WRITE
Feature write permissionBluetoothGattCharacteristic#PERMISSION_READ
Feature Read permission
Matters needing attention
- Called when the eigenvalue has only read permission
BluetoothGatt#writeCharacteristic()
When an eigenvalue is modified, false is returned and cannot be written. It doesn’t triggerBluetoothGattCallback#onCharacteristicWrite()
The callback. - Called when the eigenvalue has only write permission
BluetoothGatt#readCharacteristic()
When an eigenvalue is read, it returns false and cannot be written. It doesn’t triggerBluetoothGattCallback#onCharacteristicRead()
The callback.
Create the Gatt Descriptor
And then Characteristic Descriptor, so when you initialize the Bluetoothgate Descriptor you pass in the Descriptor UUID and the permission attribute
/ / initialize describe mGattDescriptor = new BluetoothGattDescriptor (UUID_DESCRIPTOR, BluetoothGattDescriptor. PERMISSION_WRITE);Copy the code
Add Characteristic and Descriptor
Add Characteristic to Service, add Characteristic to Descriptor:
/ / Service add eigenvalue mGattService addCharacteristic (mGattCharacteristic); mGattService.addCharacteristic(mGattReadCharacteristic); . / / characteristic value added describe mGattCharacteristic addDescriptor (mGattDescriptor);Copy the code
Obtain the Gatt Server through the Bluetooth manager mBluetoothManager to add the Gatt Service. After the Gatt Service is added, the external central device can obtain the corresponding Gatt Service and data when it connects to the mobile phone
/ / initialize GattServer callback mBluetoothGattServerCallback = new daqiBluetoothGattServerCallback ();if(mBluetoothManager ! = null) mBluetoothGattServer = mBluetoothManager.openGattServer(this, mBluetoothGattServerCallback); boolean result = mBluetoothGattServer.addService(mGattService);if (result){
Toast.makeText(daqiActivity.this,"Service added successfully",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(daqiActivity.this,"Failed to add service",Toast.LENGTH_SHORT).show();
}
Copy the code
Define Gatt Server callbacks. When the central device connects the mobile phone peripheral, modifies the characteristic value, reads the characteristic value and so on, it will get the corresponding callback.
Private class daqiBluetoothGattServerCallback extends BluetoothGattServerCallback {/ / equipment connect/disconnect the callback @ Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { super.onConnectionStateChange(device, status, newState); } @override public void onServiceAdded(int status, BluetoothGattService service) { super.onServiceAdded(status, service); } / / eigenvalue reading back adjustable @ Override public void onCharacteristicReadRequest (BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { super.onCharacteristicReadRequest(device, requestId, offset, characteristic); } / / characteristic value write callback @ Override public void onCharacteristicWriteRequest (BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); } @override public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { super.onDescriptorReadRequest(device, requestId, offset, descriptor); } @override public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); }}Copy the code
Finally, after broadcasting is enabled, the eigenvalue information seen after nRF connection is shown as follows :(an additional eigenvalue that can only be both is added)
Android BLE series:
Android Bluetooth BLE (I) — Scan
Android Bluetooth BLE (2) — Communication
Android Bluetooth BLE (3) — Broadcast
Android Bluetooth BLE (4) — Practical