|
|
|
@ -1,6 +1,6 @@ |
|
|
|
/* |
|
|
|
* 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"); |
|
|
|
* 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_CONNECTED = 2; |
|
|
|
|
|
|
|
// Nom des actions envoyées lors des Intents broadcastés
|
|
|
|
public final static String ACTION_GATT_CONNECTED = |
|
|
|
"fr.cenralesupelec.students.clientble.ACTION_GATT_CONNECTED"; |
|
|
|
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,
|
|
|
|
// 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() { |
|
|
|
@Override |
|
|
|
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 |
|
|
|
public void onCharacteristicRead(BluetoothGatt gatt, |
|
|
|
BluetoothGattCharacteristic characteristic, |
|
|
|
@ -111,8 +121,10 @@ public class BluetoothLeService extends Service { |
|
|
|
|
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) { |
|
|
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) { |
|
|
|
// Valeur du potentiomètre.
|
|
|
|
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic); |
|
|
|
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) { |
|
|
|
// Valeur de la caractéristique longue.
|
|
|
|
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic); |
|
|
|
} else { |
|
|
|
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 |
|
|
|
public void onCharacteristicWrite(BluetoothGatt gatt, |
|
|
|
BluetoothGattCharacteristic characteristic, |
|
|
|
@ -128,8 +147,10 @@ public class BluetoothLeService extends Service { |
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) { |
|
|
|
Log.d(TAG, "Réusssite de l’écriture de la caractéristique."); |
|
|
|
if (GattConstants.SENSOR_CHARACTERISTIC_UUID.equals(uuid)) { |
|
|
|
// Valeur du potentiomètre – ne devrait pas se produire (lecture seule.)
|
|
|
|
broadcastUpdate(ACTION_SENSOR_VALUE_AVAILABLE, characteristic); |
|
|
|
} else if (GattConstants.WRITABLE_CHARACTERISTIC_UUID.equals(uuid)) { |
|
|
|
// Valeur de la caractéristique longue et éditable.
|
|
|
|
broadcastUpdate(ACTION_WRITABLE_VALUE_AVAILABLE, characteristic); |
|
|
|
} |
|
|
|
} 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 |
|
|
|
public void onCharacteristicChanged(BluetoothGatt gatt, |
|
|
|
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) { |
|
|
|
Log.d(TAG, "broadcastUpdate(String) appelé."); |
|
|
|
final Intent intent = new Intent(action); |
|
|
|
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, |
|
|
|
final BluetoothGattCharacteristic characteristic) { |
|
|
|
|
|
|
|
final Intent intent = new Intent(action); |
|
|
|
Log.d(TAG, "broadcastUpdate(String, BluetoothGattChar.) appelé."); |
|
|
|
|
|
|
|
// Valeur brute de la caractéristique.
|
|
|
|
final byte[] data = characteristic.getValue(); |
|
|
|
|
|
|
|
if (data != null && data.length > 0) { |
|
|
|
// Si c’est la valeur du potentiomètre
|
|
|
|
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 = |
|
|
|
(data.length == 2) ? (data[0] << 8) & 0x0000ff00 | (data[1] << 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); |
|
|
|
// 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()); |
|
|
|
intent.putExtra(EXTRA_DATA, String.format("%.3f %%\n(%s)", percent, date)); |
|
|
|
} else { |
|
|
|
// Sinon, caractéristique longue éditable.
|
|
|
|
final StringBuilder stringBuilder = new StringBuilder(data.length); |
|
|
|
//stringBuilder.append(String.format("%d", data));/
|
|
|
|
//stringBuilder.append(" --- ");
|
|
|
|
// Représentation au format hexadécimal.
|
|
|
|
for (byte byteChar : data) |
|
|
|
stringBuilder.append(String.format("%02X ", byteChar)); |
|
|
|
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()); |
|
|
|
} |
|
|
|
} |
|
|
|
sendBroadcast(intent); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Classe permettant à une activité d’appeler les méthodes du service. |
|
|
|
*/ |
|
|
|
public class LocalBinder extends Binder { |
|
|
|
BluetoothLeService getService() { |
|
|
|
return BluetoothLeService.this; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Demande de lien à une activité. |
|
|
|
* @param intent |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public IBinder onBind(Intent intent) { |
|
|
|
return mBinder; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Arrêt du lien avec une activité. |
|
|
|
* @param intent |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public boolean onUnbind(Intent intent) { |
|
|
|
// 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); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Instance de la classe de liaison avec une activité. |
|
|
|
*/ |
|
|
|
private final IBinder mBinder = new LocalBinder(); |
|
|
|
|
|
|
|
/** |
|
|
|
@ -314,6 +375,11 @@ public class BluetoothLeService extends Service { |
|
|
|
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) { |
|
|
|
if (mBluetoothAdapter == null || mBluetoothGatt == null) { |
|
|
|
Log.w(TAG, "BluetoothAdapter not initialized"); |
|
|
|
@ -335,7 +401,9 @@ public class BluetoothLeService extends Service { |
|
|
|
Log.w(TAG, "BluetoothAdapter not initialized"); |
|
|
|
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())) { |
|
|
|
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(GattConstants.CHARACTERISTIC_CONFIG_UUID); |
|
|
|
descriptor.setValue( |
|
|
|
@ -343,12 +411,16 @@ public class BluetoothLeService extends Service { |
|
|
|
: BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE |
|
|
|
); |
|
|
|
try { |
|
|
|
// Parfois plusieurs essais sont nécessaires (l’interface BLE peut être
|
|
|
|
// occupée avec d’autres opérations.)
|
|
|
|
while (!mBluetoothGatt.writeDescriptor(descriptor)) |
|
|
|
sleep(500); |
|
|
|
} catch (Exception e) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
@ -363,6 +435,10 @@ public class BluetoothLeService extends Service { |
|
|
|
return mBluetoothGatt.getServices(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Retourne notre service privé. |
|
|
|
* @return |
|
|
|
*/ |
|
|
|
public BluetoothGattService getPrivateService() { |
|
|
|
if (mBluetoothGatt == null) return null; |
|
|
|
return mBluetoothGatt.getService(GattConstants.PRIVATE_SERVICE_UUID); |
|
|
|
|