Documente BluetoothLeService
This commit is contained in:
parent
9bdd404fc6
commit
3e78c1e9b0
4 changed files with 88 additions and 10 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
* Copyright (C) 2017 Louis-Guillaume Dubois
|
* Copyright (C) 2017 CentraleSupélec
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -57,6 +57,7 @@ public class BluetoothLeService extends Service {
|
||||||
private static final int STATE_CONNECTING = 1;
|
private static final int STATE_CONNECTING = 1;
|
||||||
private static final int STATE_CONNECTED = 2;
|
private static final int STATE_CONNECTED = 2;
|
||||||
|
|
||||||
|
// Nom des actions envoyées lors des Intents broadcastés
|
||||||
public final static String ACTION_GATT_CONNECTED =
|
public final static String ACTION_GATT_CONNECTED =
|
||||||
"fr.cenralesupelec.students.clientble.ACTION_GATT_CONNECTED";
|
"fr.cenralesupelec.students.clientble.ACTION_GATT_CONNECTED";
|
||||||
public final static String ACTION_GATT_DISCONNECTED =
|
public final static String ACTION_GATT_DISCONNECTED =
|
||||||
|
@ -73,6 +74,8 @@ public class BluetoothLeService extends Service {
|
||||||
|
|
||||||
// Implements callback methods for GATT events that the app cares about. For example,
|
// Implements callback methods for GATT events that the app cares about. For example,
|
||||||
// connection change and services discovered.
|
// connection change and services discovered.
|
||||||
|
// Envoie des Intents broadcastés pour permettre à SimpleDetailActivity de récupérer
|
||||||
|
// les valeurs reçues de l’appareil BLE.
|
||||||
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
|
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||||
|
@ -103,6 +106,13 @@ public class BluetoothLeService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie dans une Intent broadcastée la valeur lue de la caractéristique
|
||||||
|
* demandée.
|
||||||
|
* @param gatt
|
||||||
|
* @param characteristic
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCharacteristicRead(BluetoothGatt gatt,
|
public void onCharacteristicRead(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic,
|
BluetoothGattCharacteristic characteristic,
|
||||||
|
@ -111,8 +121,10 @@ public class BluetoothLeService extends Service {
|
||||||
|
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) {
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) {
|
||||||
|
// Valeur du potentiomètre.
|
||||||
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic);
|
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic);
|
||||||
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) {
|
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) {
|
||||||
|
// Valeur de la caractéristique longue.
|
||||||
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic);
|
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "UUID non reconnue.");
|
Log.w(TAG, "UUID non reconnue.");
|
||||||
|
@ -120,6 +132,13 @@ public class BluetoothLeService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie dans une Intent broadcastée la valeur écrite de la caractéristique
|
||||||
|
* demandée.
|
||||||
|
* @param gatt
|
||||||
|
* @param characteristic
|
||||||
|
* @param status
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCharacteristicWrite(BluetoothGatt gatt,
|
public void onCharacteristicWrite(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic,
|
BluetoothGattCharacteristic characteristic,
|
||||||
|
@ -128,8 +147,10 @@ public class BluetoothLeService extends Service {
|
||||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||||
Log.d(TAG, "Réusssite de l’écriture de la caractéristique.");
|
Log.d(TAG, "Réusssite de l’écriture de la caractéristique.");
|
||||||
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) {
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) {
|
||||||
|
// Valeur du potentiomètre – ne devrait pas se produire (lecture seule.)
|
||||||
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic);
|
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic);
|
||||||
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) {
|
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) {
|
||||||
|
// Valeur de la caractéristique longue et éditable.
|
||||||
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic);
|
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,6 +158,12 @@ public class BluetoothLeService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie dans une Intent broadcastée la valeur mise à jour d’une caractéristique
|
||||||
|
* (en cas de notification par exemple.)
|
||||||
|
* @param gatt
|
||||||
|
* @param characteristic
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCharacteristicChanged(BluetoothGatt gatt,
|
public void onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic) {
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
@ -152,50 +179,81 @@ public class BluetoothLeService extends Service {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode d’envoi d’une Intent broadcastée.
|
||||||
|
* @param action nom de l’action
|
||||||
|
*/
|
||||||
private void broadcastUpdate(final String action) {
|
private void broadcastUpdate(final String action) {
|
||||||
Log.d(TAG, "broadcastUpdate(String) appelé.");
|
Log.d(TAG, "broadcastUpdate(String) appelé.");
|
||||||
final Intent intent = new Intent(action);
|
final Intent intent = new Intent(action);
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode d’envoi d’une Intent broadcastée, avec la valeur d’une caractéristique.
|
||||||
|
* @param action nom de l’action
|
||||||
|
* @param characteristic caractéristique lue, écrite ou mise à jour (notifiée)
|
||||||
|
*/
|
||||||
private void broadcastUpdate(final String action,
|
private void broadcastUpdate(final String action,
|
||||||
final BluetoothGattCharacteristic characteristic) {
|
final BluetoothGattCharacteristic characteristic) {
|
||||||
|
|
||||||
final Intent intent = new Intent(action);
|
final Intent intent = new Intent(action);
|
||||||
Log.d(TAG, "broadcastUpdate(String, BluetoothGattChar.) appelé.");
|
Log.d(TAG, "broadcastUpdate(String, BluetoothGattChar.) appelé.");
|
||||||
|
|
||||||
|
// Valeur brute de la caractéristique.
|
||||||
final byte[] data = characteristic.getValue();
|
final byte[] data = characteristic.getValue();
|
||||||
|
|
||||||
if (data != null && data.length > 0) {
|
if (data != null && data.length > 0) {
|
||||||
|
// Si c’est la valeur du potentiomètre
|
||||||
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
|
||||||
|
// Lecture de l’entier non signé, d’un ou deux octets (lecture par le CAN sur 16 bits.)
|
||||||
final long value =
|
final long value =
|
||||||
(data.length == 2) ? (data[0] << 8) & 0x0000ff00 | (data[1] << 0) & 0x000000ff
|
(data.length == 2) ? (data[0] << 8) & 0x0000ff00 | (data[1] << 0) & 0x000000ff
|
||||||
: (data[0] << 0) & 0x000000ff;
|
: (data[0] << 0) & 0x000000ff;
|
||||||
final long max = 65535; // 2^16 - 1
|
final long max = 65535; // 2^16 - 1 : valeur maximale (16 bits)
|
||||||
|
// Envoi d’un pourcentage
|
||||||
final double percent = ((double) (100 * value)) / ((double) max);
|
final double percent = ((double) (100 * value)) / ((double) max);
|
||||||
|
// Envoi sous forme d’une chaîne de caractère, avec la date, pour affichage direct.
|
||||||
final String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG).format(new Date());
|
final String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG).format(new Date());
|
||||||
intent.putExtra(EXTRA_DATA, String.format("%.3f %%\n(%s)", percent, date));
|
intent.putExtra(EXTRA_DATA, String.format("%.3f %%\n(%s)", percent, date));
|
||||||
} else {
|
} else {
|
||||||
|
// Sinon, caractéristique longue éditable.
|
||||||
final StringBuilder stringBuilder = new StringBuilder(data.length);
|
final StringBuilder stringBuilder = new StringBuilder(data.length);
|
||||||
//stringBuilder.append(String.format("%d", data));/
|
// Représentation au format hexadécimal.
|
||||||
//stringBuilder.append(" --- ");
|
|
||||||
for (byte byteChar : data)
|
for (byte byteChar : data)
|
||||||
stringBuilder.append(String.format("%02X ", byteChar));
|
stringBuilder.append(String.format("%02X ", byteChar));
|
||||||
Log.d(TAG, String.format(stringBuilder.toString()));
|
Log.d(TAG, String.format(stringBuilder.toString()));
|
||||||
|
// Envoi de la représentation ASCII puis sur une autre ligne, en hexadécimal.
|
||||||
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
|
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe permettant à une activité d’appeler les méthodes du service.
|
||||||
|
*/
|
||||||
public class LocalBinder extends Binder {
|
public class LocalBinder extends Binder {
|
||||||
BluetoothLeService getService() {
|
BluetoothLeService getService() {
|
||||||
return BluetoothLeService.this;
|
return BluetoothLeService.this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demande de lien à une activité.
|
||||||
|
* @param intent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return mBinder;
|
return mBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arrêt du lien avec une activité.
|
||||||
|
* @param intent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onUnbind(Intent intent) {
|
public boolean onUnbind(Intent intent) {
|
||||||
// After using a given device, you should make sure that BluetoothGatt.close() is called
|
// After using a given device, you should make sure that BluetoothGatt.close() is called
|
||||||
|
@ -205,6 +263,9 @@ public class BluetoothLeService extends Service {
|
||||||
return super.onUnbind(intent);
|
return super.onUnbind(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance de la classe de liaison avec une activité.
|
||||||
|
*/
|
||||||
private final IBinder mBinder = new LocalBinder();
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,6 +375,11 @@ public class BluetoothLeService extends Service {
|
||||||
mBluetoothGatt.readCharacteristic(characteristic);
|
mBluetoothGatt.readCharacteristic(characteristic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Écriture d’une caractéristique sur le serveur BLE de l’appareil connecté.
|
||||||
|
* @param characteristic caractéristique où écrire
|
||||||
|
* @param data données brutes à envoyer pour écriture
|
||||||
|
*/
|
||||||
public void writeCharacterisitic(BluetoothGattCharacteristic characteristic, byte[] data) {
|
public void writeCharacterisitic(BluetoothGattCharacteristic characteristic, byte[] data) {
|
||||||
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
|
||||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||||
|
@ -335,7 +401,9 @@ public class BluetoothLeService extends Service {
|
||||||
Log.w(TAG, "BluetoothAdapter not initialized");
|
Log.w(TAG, "BluetoothAdapter not initialized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.d(TAG, "setChar.Notification() appelé");
|
Log.d(TAG, "setCharacteristicNotification() appelé");
|
||||||
|
// Ne pas oublier d’écrire le descripteur de la caractéristique pour que les serveur
|
||||||
|
// BLE de l’appareil connecté envoie les notifications.
|
||||||
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
|
||||||
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(GattConstants.CHARACTERISTIC_CONFIG_UUID);
|
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(GattConstants.CHARACTERISTIC_CONFIG_UUID);
|
||||||
descriptor.setValue(
|
descriptor.setValue(
|
||||||
|
@ -343,12 +411,16 @@ public class BluetoothLeService extends Service {
|
||||||
: BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
|
: BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
|
// Parfois plusieurs essais sont nécessaires (l’interface BLE peut être
|
||||||
|
// occupée avec d’autres opérations.)
|
||||||
while (!mBluetoothGatt.writeDescriptor(descriptor))
|
while (!mBluetoothGatt.writeDescriptor(descriptor))
|
||||||
sleep(500);
|
sleep(500);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Demande à l’appareil Android d’écouter et de prendre en compte les notifications
|
||||||
|
// envoyées par l’appareil connecté.
|
||||||
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
|
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +435,10 @@ public class BluetoothLeService extends Service {
|
||||||
return mBluetoothGatt.getServices();
|
return mBluetoothGatt.getServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne notre service privé.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public BluetoothGattService getPrivateService() {
|
public BluetoothGattService getPrivateService() {
|
||||||
if (mBluetoothGatt == null) return null;
|
if (mBluetoothGatt == null) return null;
|
||||||
return mBluetoothGatt.getService(GattConstants.PRIVATE_SERVICE_UUID);
|
return mBluetoothGatt.getService(GattConstants.PRIVATE_SERVICE_UUID);
|
||||||
|
|
|
@ -41,6 +41,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Activité proposée dans l’application de démonstration, non utilisée dans notre application.
|
||||||
|
*
|
||||||
* For a given BLE device, this Activity provides the user interface to connect, display data,
|
* For a given BLE device, this Activity provides the user interface to connect, display data,
|
||||||
* and display GATT services and characteristics supported by the device. The Activity
|
* and display GATT services and characteristics supported by the device. The Activity
|
||||||
* communicates with {@code BluetoothLeService}, which in turn interacts with the
|
* communicates with {@code BluetoothLeService}, which in turn interacts with the
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
* Copyright (C) 2017 Louis-Guillaume Dubois
|
* Copyright (C) 2017 CentraleSupélec
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes a small subset of standard GATT attributes for demonstration purposes.
|
* Stockage des UUID des services et caractéristiques BLE interrogées.
|
||||||
*/
|
*/
|
||||||
public class GattConstants {
|
public class GattConstants {
|
||||||
private static HashMap<String, String> attributes = new HashMap();
|
private static HashMap<String, String> attributes = new HashMap();
|
||||||
|
@ -40,7 +40,7 @@ public class GattConstants {
|
||||||
UUID.fromString(SENSOR_CHARACTERISTIC_UUID_STRING);
|
UUID.fromString(SENSOR_CHARACTERISTIC_UUID_STRING);
|
||||||
|
|
||||||
// UUID (v4, cf. supra) de notre caractéristiuqe privée, lisible, éditable et notifiable,
|
// UUID (v4, cf. supra) de notre caractéristiuqe privée, lisible, éditable et notifiable,
|
||||||
// de trois octets.
|
// de vingt octets.
|
||||||
public static final String WRITABLE_CHARACTERISTIC_UUID_STRING =
|
public static final String WRITABLE_CHARACTERISTIC_UUID_STRING =
|
||||||
"c093685d-005f-4d3c-8240-6d3020a2c608";
|
"c093685d-005f-4d3c-8240-6d3020a2c608";
|
||||||
public static final UUID WRITABLE_CHARACTERISTIC_UUID =
|
public static final UUID WRITABLE_CHARACTERISTIC_UUID =
|
||||||
|
@ -54,7 +54,7 @@ public class GattConstants {
|
||||||
public static final UUID CHARACTERISTIC_CONFIG_UUID =
|
public static final UUID CHARACTERISTIC_CONFIG_UUID =
|
||||||
UUID.fromString(CHARACTERISTIC_CONFIG_UUID_STRING);
|
UUID.fromString(CHARACTERISTIC_CONFIG_UUID_STRING);
|
||||||
|
|
||||||
// UUID de services connus — utilisés dans DeviceControlActivity
|
// UUID de services connus — utilisés dans DeviceControlActivity uniquement
|
||||||
static {
|
static {
|
||||||
// Sample Services.
|
// Sample Services.
|
||||||
attributes.put("0000180a-0000-1000-8000-00805f9b34fb", "Device Information");
|
attributes.put("0000180a-0000-1000-8000-00805f9b34fb", "Device Information");
|
||||||
|
@ -73,7 +73,7 @@ public class GattConstants {
|
||||||
attributes.put(WRITABLE_CHARACTERISTIC_UUID_STRING, "3-byte rw notif. char.");
|
attributes.put(WRITABLE_CHARACTERISTIC_UUID_STRING, "3-byte rw notif. char.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// recherche du nom de services connus — utilisé dans DeviceControlActivity
|
// recherche du nom de services connus — utilisé dans DeviceControlActivity uniquement
|
||||||
public static String lookup(String uuid, String defaultName) {
|
public static String lookup(String uuid, String defaultName) {
|
||||||
String name = attributes.get(uuid);
|
String name = attributes.get(uuid);
|
||||||
return name == null ? defaultName : name;
|
return name == null ? defaultName : name;
|
||||||
|
|
Loading…
Reference in a new issue