gpt4 book ai didi

安卓蓝牙 : onCharacteristicChanged never fires

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:06:56 25 4
gpt4 key购买 nike

我正在尝试编写一个 Android 应用程序来模仿我编写的 iOS 应用程序中已经存在的功能。我正在连接 2 个不同的 BLE 设备:

  1. 血压袖带
  2. 体重秤

在 iOS 上,我的两台设备都运行良好并报告数据。在 Android 上,我无法让它工作。经过数小时的研究和测试,我认为我要解决的基本问题是:

在 iOS 上,我调用以下代码使 BLE 设备在有数据要报告时通知我的 iOS 设备:

#pragma mark - CBPeripheralDelegate Protocol methods
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in [service characteristics]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}

就是这样。 iOS 中此方法的说明如下:

If the specified characteristic is configured to allow both notifications and indications, calling this method enables notifications only.

基于此(以及 它在 iOS 中工作 的事实),我认为我想要通知的特性的配置描述符应该像这样配置:

descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);

考虑到这一点,我的 BLEDevice 类如下所示:

public abstract class BLEDevice {
protected BluetoothAdapter.LeScanCallback mLeScanCallback;
protected BluetoothGattCallback mBluetoothGattCallback;
protected byte[] mBytes;
protected Context mContext;
protected GotReadingCallback mGotReadingCallback;
protected String mDeviceName;
public final static UUID UUID_WEIGHT_SCALE_SERVICE
= UUID.fromString(GattAttributes.WEIGHT_SCALE_SERVICE);
public final static UUID UUID_WEIGHT_SCALE_READING_CHARACTERISTIC
= UUID.fromString(GattAttributes.WEIGHT_SCALE_READING_CHARACTERISTIC);
public final static UUID UUID_WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC
= UUID.fromString(GattAttributes.WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC);
public final static UUID UUID_WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR
= UUID.fromString(GattAttributes.WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR);

abstract void processReading();

interface GotReadingCallback {
void gotReading(Object reading);
}

public BLEDevice(Context context, String deviceName, GotReadingCallback gotReadingCallback) {
mContext = context;
BluetoothManager btManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
final BluetoothAdapter btAdapter = btManager.getAdapter();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mContext.startActivity(enableIntent);
}
mDeviceName = deviceName;
mBluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
byte[] data = characteristic.getValue();
mBytes = data;
Log.d("BluetoothGattCallback.onCharacteristicChanged", "data: " + data.toString());
}
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
// this will get called when a device connects or disconnects
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if (mBytes != null) {
processReading();
}
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d("onDescriptorWrite", "descriptor: " + descriptor.getUuid() + ". characteristic: " + descriptor.getCharacteristic().getUuid() + ". status: " + status);
}
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
BluetoothGattService service = gatt.getService(UUID_WEIGHT_SCALE_SERVICE);
if (service != null) {
BluetoothGattCharacteristic characteristic;
characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_READING_CHARACTERISTIC);
if (characteristic != null) {
gatt.setCharacteristicNotification(characteristic, true);
}
characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_CONFIGURATION_CHARACTERISTIC);
if (characteristic != null) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID_WEIGHT_SCALE_CONFIGURATION_DESCRIPTOR);
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
}
};
mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
Log.d("LeScanCallback", device.toString());
if (device.getName().contains("{Device Name}")) {
BluetoothGatt bluetoothGatt = device.connectGatt(mContext, false, mBluetoothGattCallback);
btAdapter.stopLeScan(mLeScanCallback);
}
}
};
btAdapter.startLeScan(mLeScanCallback);
}
}

NOTE: It might be important to know that these 2 devices function in the following way:

  1. The BLE device is turned on an a measurement is initiated on the device.
  2. Once the measurement has been taken, the BLE device attempts to initiate a BLE connection.
  3. Once the BLE connection is made, the device pretty much immediately sends the data, sometimes sending a couple of data packets. (If previous data measurements haven't been successfully sent over BLE, it keeps them in memory and sends all of them, so I only really care about the final data packet.)
  4. Once the final data packet is sent, the BLE device disconnects rapidly.
  5. If the BLE device fails to send data (as is currently happening on the Android app), the BLE device disconnects pretty rapidly.

在我的 LogCat 中,我看到很多输出完全符合我的预期。

  1. 我看到了我期望的服务列表,包括我想要的数据服务。
  2. 我看到了我期望的特征列表,包括我想要的数据特征。
  3. 我看到了我预期的描述符列表,包括“配置”(0x2902) 描述符。

我最近遇到的失败是在 onCharacteristicWrite 中报告状态“128”。对问题 #3(下方)的评论似乎表明这是一个资源问题。

我看过以下问题:

  1. Android BLE onCharacteristicChanged not called
  2. Android BLE, read and write characteristics
  3. Android 4.3 onDescriptorWrite returns status 128

这就是为什么他们不给我我需要的东西:

  1. 这个问题的答案不是读取描述符的值。我没有那样做,所以这不可能是阻碍。
  2. 这基本上是对可用的各种方法的概述,我想我现在明白了。这个问题/答案的关键是不要多次写入不同的描述符,但我也没有这样做。我只关心一个特征。
  3. 这个问题/答案似乎与 BLE 资源限制有关,但我认为这不适用。我只连接了这台设备,我正在尝试进行非常非常简单的数据传输。我认为我没有达到资源上限。

我尝试了很多示例和教程,包括 Google 的 Android 示例代码。他们似乎都没有启用 BLE 设备来通知我的 Android 设备数据更新。它显然不是设备,因为 iOS 版本有效。那么,iOS 代码在后台做了什么来使通知正常工作,Android 端的哪些代码会模仿该功能?


编辑/更新

根据@yonran 的评论,我更新了我的代码,将 onServicesDiscovered 实现更改为:

@Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
BluetoothGattService service = gatt.getService(UUID_WEIGHT_SCALE_SERVICE);
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID_WEIGHT_SCALE_READING_CHARACTERISTIC);
if (characteristic != null) {
if (gatt.setCharacteristicNotification(characteristic, true) == true) {
Log.d("gatt.setCharacteristicNotification", "SUCCESS!");
} else {
Log.d("gatt.setCharacteristicNotification", "FAILURE!");
}
BluetoothGattDescriptor descriptor = characteristic.getDescriptors().get(0);
if (0 != (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE)) {
// It's an indicate characteristic
Log.d("onServicesDiscovered", "Characteristic (" + characteristic.getUuid() + ") is INDICATE");
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
} else {
// It's a notify characteristic
Log.d("onServicesDiscovered", "Characteristic (" + characteristic.getUuid() + ") is NOTIFY");
if (descriptor != null) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
}
}

确实似乎改变了一些事情。这是当前的 Logcat,代码更改后:

D/BluetoothGatt﹕ setCharacteristicNotification() - uuid: <UUID> enable: true
D/gatt.setCharacteristicNotification﹕ SUCCESS!
D/onServicesDiscovered﹕ Characteristic (<UUID>) is INDICATE
D/BluetoothGatt﹕ writeDescriptor() - uuid: 00002902-0000-1000-8000-00805f9b34fb
D/BluetoothGatt﹕ onDescriptorWrite() - Device=D0:5F:B8:01:6C:9E UUID=<UUID>
D/onDescriptorWrite﹕ descriptor: 00002902-0000-1000-8000-00805f9b34fb. characteristic: <UUID>. status: 0
D/BluetoothGatt﹕ onClientConnectionState() - status=0 clientIf=6 device=D0:5F:B8:01:6C:9E

所以,看来我现在正在正确设置所有内容(因为 setCharacteristicNotification 返回 true 并且 onDescriptorWrite 状态为 0)。但是,onCharacteristicChanged 仍然不会触发。


最佳答案

我已经能够通过以下方式成功捕获具有多个服务和特征的 onCharacteristicChanged():

  1. 服务发现完成后,在主循环中的 broadcastReceiver() 中写入描述符值。

    private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
    //more code...
    if (action.equals(uartservice.ACTION_GATT_SERVICES_DISCOVERED)) {
    mService.enableTXNotification();
    }

  1. 通过在描述符值设置之间添加延迟

    public void enableTXNotification(){ 
    /*
    if (mBluetoothGatt == null) {
    showMessage("mBluetoothGatt null" + mBluetoothGatt);
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
    return;
    }
    */
    /**
    * Enable Notifications for the IO service and characteristic
    *
    */
    BluetoothGattService IOService = mBluetoothGatt.getService(IO_SERVICE_UUID);
    if (IOService == null) {
    showMessage("IO service not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_IO);
    return;
    }
    BluetoothGattCharacteristic IOChar = IOService.getCharacteristic(IO_CHAR_UUID);
    if (IOChar == null) {
    showMessage("IO charateristic not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_IO);
    return;
    }
    mBluetoothGatt.setCharacteristicNotification(IOChar,true);
    BluetoothGattDescriptor descriptorIO = IOChar.getDescriptor(CCCD);
    descriptorIO.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    mBluetoothGatt.writeDescriptor(descriptorIO);

    /**
    * For some reason android (or the device) can't handle
    * writing one descriptor after another properly. Without
    * the delay only the first characteristic can be caught in
    * onCharacteristicChanged() method.
    */
    try {
    Thread.sleep(200);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    /**
    * Enable Indications for the RXTX service and characteristic
    */
    BluetoothGattService RxService = mBluetoothGatt.getService(RXTX_SERVICE_UUID);
    if (RxService == null) {
    showMessage("Rx service not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
    return;
    }
    BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RXTX_CHAR_UUID);
    if (RxChar == null) {
    showMessage("Tx charateristic not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
    return;
    }
    mBluetoothGatt.setCharacteristicNotification(RxChar,true);
    BluetoothGattDescriptor descriptor = RxChar.getDescriptor(CCCD);
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE );
    mBluetoothGatt.writeDescriptor(descriptor);

    try {
    Thread.sleep(200);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    /**
    * Enable Notifications for the Battery service and Characteristic?
    */
    BluetoothGattService batteryService = mBluetoothGatt.getService(BATTERY_SERVICE_UUID);
    if (batteryService == null) {
    showMessage("Battery service not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_BATTERY);
    return;
    }
    BluetoothGattCharacteristic batteryChar = batteryService.getCharacteristic(BATTERY_CHAR_UUID);
    if (batteryChar == null) {
    showMessage("Battery charateristic not found!");
    broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_BATTERY);
    return;
    }
    }

关于安卓蓝牙 : onCharacteristicChanged never fires,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28586111/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com