Запись данных в Bluetooth LE характеристика в Android
Хотя подобные вопросы были заданы, но это немного отличается. Я знаю, как передавать данные на подключенное устройство BLE, но я думаю, что делаю что-то не так, для чего мне нужна помощь. Код ниже содержит все методы из моего класса, который расширяет BroadcastReceiver.
- Я сканирую и подключаюсь к устройству, указанному в `PEN_ADDRESS`.
- В методе onServicesDiscovered я ищу службу, в которой UUID содержит abcd.
- Затем я перебираю характеристики этих сервисов и ищу три характеристики с конкретными строками в их `UUID`.
- Третья характеристика - это записываемая характеристика, в которой я пытаюсь записать данные, вызывая метод `writeCharac(mGatt,writeChar1,123);` Переданные выше данные `123` являются просто фиктивными данными.
Я отлаживал свой код, пытаясь записать эту характеристику, но поставив точки останова внутри writeCharac
метод, я обнаружил, что status
значение равно false, что означает, что запись не была успешной. Я что-то здесь упускаю? Пожалуйста, помогите!
public class BackgroundReceiverFire extends BroadcastReceiver {
Context context;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mGatt;
private BluetoothLeService mBluetoothLeService;
private boolean mScanning;
private final String TAG = "READING: ";
private BluetoothDevice mDevice;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private final String PEN_ADDRESS = "FB:23:AF:42:5C:56";
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
public void onReceive(Context context, Intent intent) {
this.context = context;
Toast.makeText(context, "Started Scanning", LENGTH_SHORT).show();
initializeBluetooth();
startScan();
}
private void initializeBluetooth() {
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this.context, "No Bluetooth", LENGTH_SHORT).show();
return;
}
}
private void startScan() {
scanLeDevice(true);
}
private void stopScan() {
scanLeDevice(false);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
//Scanning for the device
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getAddress().matches(PEN_ADDRESS)) {
connectBluetooth(device);
Toast.makeText(context, "Device Found: " + device.getAddress(), Toast.LENGTH_LONG).show();
}
}
};
private void connectBluetooth(BluetoothDevice insulinPen) {
if (mGatt == null) {
Log.d("connectToDevice", "connecting to device: " + insulinPen.toString());
mDevice = insulinPen;
mGatt = insulinPen.connectGatt(context, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private void enableBluetooth() {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
scanLeDevice(true);
}
private void disableBluetooth() {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
Log.i("gattCallback", "reconnecting...");
BluetoothDevice mDevice = gatt.getDevice();
mGatt = null;
connectBluetooth(mDevice);
break;
default:
Log.e("gattCallback", "STATE_OTHER");
break;
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
mGatt = gatt;
List<BluetoothGattService> services = mGatt.getServices();
Log.i("onServicesDiscovered", services.toString());
Iterator<BluetoothGattService> serviceIterator = services.iterator();
while(serviceIterator.hasNext()){
BluetoothGattService bleService = serviceIterator.next();
if(bleService.getUuid().toString().contains("abcd")){
//Toast.makeText(context,"Got the service",Toast.LENGTH_SHORT);
BluetoothGattCharacteristic readChar1 = bleService.getCharacteristics().get(0);
for (BluetoothGattDescriptor descriptor : readChar1.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar1, true);
}
//mGatt.readCharacteristic(readChar1);
BluetoothGattCharacteristic readChar2 = bleService.getCharacteristics().get(1);
for (BluetoothGattDescriptor descriptor : readChar2.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(readChar2, true);
}
//mGatt.readCharacteristic(readChar2);
BluetoothGattCharacteristic writeChar1 = bleService.getCharacteristics().get(2);
for (BluetoothGattDescriptor descriptor : writeChar1.getDescriptors()) {
descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mGatt.writeDescriptor(descriptor);
mGatt.setCharacteristicNotification(writeChar1, true);
}
writeCharac(mGatt,writeChar1,123);
}
}
//gatt.readCharacteristic(therm_char);
}
public void writeCharac(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int value ){
if (mBluetoothAdapter == null || gatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*
BluetoothGattCharacteristic charac = gattService
.getCharacteristic(uuid);
*/
if (charac == null) {
Log.e(TAG, "char not found!");
}
int unixTime = value;
String unixTimeString = Integer.toHexString(unixTime);
byte[] byteArray = hexStringToByteArray(unixTimeString);
charac.setValue(byteArray);
boolean status = mGatt.writeCharacteristic(charac);
if(status){
Toast.makeText(context,"Written Successfully",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,"Error writing characteristic",Toast.LENGTH_SHORT).show();
}
}
public byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
String characteristicValue = characteristic.getValue().toString();
Log.d("CHARACTERISTIC VALUE: ", characteristicValue);
gatt.disconnect();
}
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic) {
String value = characteristic.getValue().toString();
Log.d(TAG,value);
}
};
3 ответа
Хотя API BLE является асинхронным по своей природе, фактическая передача сигнала неизбежно является синхронной. Вы должны дождаться предыдущего вызова подключения / записи / чтения к обратному вызову, прежде чем начинать любую операцию подключения / записи / чтения.
В вашем коде onServicesDiscovered(BluetoothGatt gatt, int status)
функция, которую вы назвали mGatt.writeDescriptor(descriptor)
дважды, прежде чем пытаться написать характеристику. API откажется запустить ваш запрос на запись, так как он занят написанием дескриптора, и вернет false для вашего mGatt.writeCharacteristic(charac)
вызов.
Так что просто дождитесь обратного вызова writeDescriptor перед вызовом writeCharacteristic. Эта природа плохо документирована, но вы можете найти источник здесь и здесь.
Спасибо @reTs и @pooja за предложения. Проблема была из-за этих двух строк mGatt = null
connectBluetooth(mDevice);
в STATE_DISCONNECTED. Я понял это, но не помню точную причину. Размещение на всякий случай, если это полезно.
Вы проверили, является ли 'writechar1' btcharacteristic значением, которое вы передаете writeCharac(), пустым?