简体   繁体   English

onCharacteristicChanged 没有被击中。 Android BLE

[英]onCharacteristicChanged not being hit. Android BLE

I have an app that is using BLE connectivity with my device.我有一个与我的设备使用 BLE 连接的应用程序。 Everything works from connecting to the device, discovering the services, writing the characteristic and descriptor.从连接到设备、发现服务、编写特征和描述符,一切都有效。 But for some reason, onCharacteristicChanged is not triggering.但由于某种原因, onCharacteristicChanged 没有触发。 The goal is to retrieve the data from the characteristic that is in the characteristic.目标是从特征中的特征中检索数据。 I have tried using a different characteristic from the same service and this works as in retrieving the data.我尝试使用来自同一服务的不同特征,这与检索数据一样有效。 Not sure why this specific characteristic is not working when others are.不知道为什么这个特定的特性在其他特性不起作用时不起作用。

Here is my code: //Descriptor public final static UUID UUID_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG);这是我的代码: //Descriptor public final static UUID UUID_CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG);

// Huneo Service
public final static UUID UUID_HUNEO_SERVICE = UUID.fromString(GattAttributes.HUNEO_SERVICE);
public final static UUID UUID_HUNEO_VIBRATOR = UUID.fromString(GattAttributes.HUNEO_VIBRATOR);
public final static UUID UUID_HUNEO_MONITOR = UUID.fromString(GattAttributes.HUNEO_MONITOR);
public final static UUID UUID_HUNEO_RATES = UUID.fromString(GattAttributes.HUNEO_RATES);
public final static UUID UUID_HUNEO_LED = UUID.fromString(GattAttributes.HUNEO_LED);
public final static UUID UUID_HUNEO_ACCEL = UUID.fromString(GattAttributes.HUNEO_ACCEL);
public final static UUID UUID_HUNEO_GYRO = UUID.fromString(GattAttributes.HUNEO_GYRO);
public final static UUID UUID_HUNEO_COMBINED = UUID.fromString(GattAttributes.HUNEO_COMBINED);

// Battery Service
public final static UUID UUID_BATTERY_SERVICE = UUID.fromString(GattAttributes.BATTERY_SERVICE);
public final static UUID UUID_BATTERY_LEVEL = UUID.fromString(GattAttributes.BATTERY_LEVEL);

// Device Info Service
public final static UUID UUID_DEVICE_INFO_SERVICE = UUID.fromString(GattAttributes.DEVICE_INFO_SERVICE);
public final static UUID UUID_MODEL_NUMBER = UUID.fromString(GattAttributes.MODEL_NUMBER);
public final static UUID UUID_SERIAL_NUMBER = UUID.fromString(GattAttributes.SERIAL_NUMBER);
public final static UUID UUID_FIRMWARE_REV = UUID.fromString(GattAttributes.FIRMWARE_REV);
public final static UUID UUID_HARDWARE_REV = UUID.fromString(GattAttributes.HARDWARE_REV);
public final static UUID UUID_MANUFACTURER_NAME = UUID.fromString(GattAttributes.MANUFACTURER_NAME);

private final static String TAG = "UNITY";

private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
private final BluetoothDevice mDevice;
private final IBinder mBinder = new LocalBinder();

private TaskCompletionSource<Void> mConnectionTask = new TaskCompletionSource<>();
private TaskCompletionSource<String> mFirmwareRevTask = new TaskCompletionSource<>();
private TaskCompletionSource<Void> mServicesDiscovered = new TaskCompletionSource<>();
private TaskCompletionSource<Integer> mBatteryLevelTask = new TaskCompletionSource<>();
private TaskCompletionSource<SensorValues> mStartStreamingTask = new TaskCompletionSource<>();
private TaskCompletionSource<String> mSerialNumberTask = new TaskCompletionSource<>();

private SensorValues mSensorValues = new SensorValues();
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private boolean mIsStreaming = false;

// Implements callback methods for GATT events that the app cares about.  For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            mConnectionState = STATE_CONNECTED;
            Log.i(TAG, "Connected to GATT server.");
            // Attempts to discover services after successful connection.
            Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            mConnectionState = STATE_DISCONNECTED;
            mIsStreaming = false;
            Log.i(TAG, "Disconnected from GATT server.");
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            mServicesDiscovered.setResult(null);
            startStreaming();
            Log.w(TAG, "onServicesDiscovered success.");
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic,
                                     int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            String characteristicUuid = characteristic.getUuid().toString();
            if (characteristicUuid.equals(GattAttributes.FIRMWARE_REV)) {
                String firmwareRev = characteristic.getStringValue(0);
                mFirmwareRevTask.setResult(firmwareRev);
            }

            if (characteristicUuid.equals(GattAttributes.BATTERY_LEVEL)) {
                int batteryLevel = characteristic.getIntValue(FORMAT_UINT8, 0);
                mBatteryLevelTask.setResult(batteryLevel);
            }

            if (characteristicUuid.equals(GattAttributes.SERIAL_NUMBER)) {
                String serialNumber = characteristic.getStringValue(0);
                mSerialNumberTask.setResult(serialNumber);
            }
        }
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt,
                                      BluetoothGattCharacteristic characteristic,
                                      int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (characteristic.getUuid().equals(UUID_HUNEO_MONITOR)) {
                if (characteristic.getIntValue(FORMAT_UINT8, 0) == 1) {
                    startCombined();
                } else {
                    stopCombined();
                }
            }
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        String characteristicUuid = characteristic.getUuid().toString();
        //Combined value changed
        if (characteristicUuid.equals(GattAttributes.HUNEO_COMBINED)) {
            byte[] data = characteristic.getValue();
            int id = unsignedShortToInt(data[0], data[1]);
            int x = unsignedShortToInt(data[2], data[3]);
            int y = unsignedShortToInt(data[4], data[5]);
            int z = unsignedShortToInt(data[6], data[7]);

            mSensorValues.combined = new CartesianValues(id,x,y,z);
            mStartStreamingTask.setResult(mSensorValues);
        }
    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt,
                                  BluetoothGattDescriptor descriptor,
                                  int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            //Combined
            if (descriptor.getCharacteristic().getUuid().equals(UUID_HUNEO_COMBINED)) {
                mIsStreaming = Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mStartStreamingTask.setResult(null);
            }
        }
    }
};

public AlwaysOnHuneoBoard(BluetoothDevice device) {
    this.mDevice = device;
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

@Override
public boolean onUnbind(Intent intent) {
    // After using a given device, you should make sure that BluetoothGatt.close() is called
    // such that resources are cleaned up properly.  In this particular example, close() is
    // invoked when the UI is disconnected from the Service.
    close();
    return super.onUnbind(intent);
}

public static class LocalBinder extends Binder {

}

/**
 * Connect to the device
 *
 * @param ct CancellationToken that will make task return if cancelled
 * @return when task is complete the device is connected
 */
public Task<Void> connectAsync(CancellationToken ct) {
    if (ct.isCancellationRequested()) {
        Log.w(TAG, "Connection cancelled");
        mConnectionTask.setCancelled();
        return mConnectionTask.getTask();
    }

    if (mDevice == null) {
        Log.w(TAG, "BluetoothDevice not initialized");
        mConnectionTask.setError(new Exception("BluetoothDevice not initialized"));
        return mConnectionTask.getTask();
    }

    // Previously connected device. BluetoothGatt not closed. Try to reconnect.
    if (mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {
            mConnectionState = STATE_CONNECTING;
            mConnectionTask.setResult(null);
            return mConnectionTask.getTask();
        }
    }

    mBluetoothGatt = mDevice.connectGatt(this, false, mGattCallback);
    Log.d(TAG, "Trying to create a new connection.");
    mConnectionState = STATE_CONNECTING;
    mConnectionTask.setResult(null);
    return mConnectionTask.getTask();
}

/**
 * Disconnects an existing connection or cancel a pending connection. The disconnection result
 * is reported asynchronously through the
 * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 * callback.
 */
public void disconnect() {
    if (mDevice == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothDevice not initialized");
        return;
    }
    mBluetoothGatt.disconnect();
}

/**
 * After using a given BLE device, the app must call this method to ensure resources are
 * released properly.
 */
public void close() {
    if (mBluetoothGatt == null) {
        return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
}

/**
 * Determines if connected to the BLE device.
 *
 * @return true if connected, false otherwise.
 */
public boolean isConnected() {
    return mConnectionState == STATE_CONNECTED;
}

/**
 * Get the calibration for the sensor
 *
 * @return integer representation of the calibration
 */
public int getCalibration() {
    return 100;
}

/**
 * Get the firmware version of the sensor
 *
 * @return string representing the devices firmware version
 */
public String getFirmwareVersion() {
    try {
        // Wait for services to be discovered
        mServicesDiscovered.getTask().onSuccessTask(t -> {
            BluetoothGattService deviceInfoService = mBluetoothGatt.getService(UUID_DEVICE_INFO_SERVICE);
            BluetoothGattCharacteristic characteristic = deviceInfoService.getCharacteristic(UUID_FIRMWARE_REV);
            mBluetoothGatt.readCharacteristic(characteristic);
            mFirmwareRevTask.setResult(null);
            return mFirmwareRevTask.getTask();

            // Wait for deviceRevTask to be completed
        }).waitForCompletion(10, TimeUnit.SECONDS);

    } catch (InterruptedException e) {
        return "";
    }

    return mFirmwareRevTask.getTask().getResult();
}

/**
 * Get the device mac address
 *
 * @return string representation of the mac address
 */
public String getMacAddress() {
    return mDevice.getAddress();
}

/**
 * Get the model of the device
 *
 * @return string representation of the device model
 */
public String getModel() {
    return mDevice.getName();
}

public SensorValues getCombinedSensorValues() {
    if (!isConnected()) {
        Log.i("Unity", "Sensor disconnected, using default sensor values.");
        return mSensorValues;
    }
    if (!mIsStreaming) {
        Log.i("Unity", "Sensor not streaming, using default sensor values.");
        return mSensorValues;
    }
    try {
        mStartStreamingTask.getTask().waitForCompletion();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
        disconnect();
    }
    return mSensorValues;
}

/**
 * Read the current battery level from the device
 *
 * @return Task containing the sensors battery level as an integer
 */
public Task<Integer> getBatteryLevelAsync() {
    // Wait for services to be discovered
    return mServicesDiscovered.getTask().onSuccessTask(t -> {
        BluetoothGattService deviceInfoService = mBluetoothGatt.getService(UUID_BATTERY_SERVICE);
        BluetoothGattCharacteristic characteristic = deviceInfoService.getCharacteristic(UUID_BATTERY_LEVEL);
        mBluetoothGatt.readCharacteristic(characteristic);
        return mBatteryLevelTask.getTask();
    });
}

public Task<String> getSerialNumber() {
    return mServicesDiscovered.getTask().onSuccessTask(t -> {
        BluetoothGattService deviceInfoService = mBluetoothGatt.getService(UUID_DEVICE_INFO_SERVICE);
        BluetoothGattCharacteristic characteristic = deviceInfoService.getCharacteristic(UUID_SERIAL_NUMBER);
        mBluetoothGatt.readCharacteristic(characteristic);
        return mSerialNumberTask.getTask();
    });
}
/**
 * Issue command to sensor to begin streaming combined data
 */
public void startStreaming() {
    if (mIsStreaming) {
        return;
    }
    //Enable notifications for combined, set result
    //Write 0 to Monitor Characteristic
    BluetoothGattService huneoService = mBluetoothGatt.getService(UUID_HUNEO_SERVICE);
    BluetoothGattCharacteristic monitorCharacteristic = huneoService.getCharacteristic(UUID_HUNEO_MONITOR);
    monitorCharacteristic.setValue(1, FORMAT_UINT8, 0);
    mBluetoothGatt.writeCharacteristic(monitorCharacteristic);
}

/**
 * Issue command to sensor to stop streaming accel and gyro data
 */
public void stopStreaming() {
    if (!mIsStreaming) {
        return;
    }
    //Disable notifications for combined
    BluetoothGattService huneoService = mBluetoothGatt.getService(UUID_HUNEO_SERVICE);
    BluetoothGattCharacteristic monitorCharacteristic = huneoService.getCharacteristic(UUID_HUNEO_MONITOR);
    monitorCharacteristic.setValue(0, FORMAT_UINT8, 0);
    mBluetoothGatt.writeCharacteristic(monitorCharacteristic);
}

/**
 * Trigger vibration haptics on the sensor
 */
public void triggerHaptics() {
    mServicesDiscovered.getTask().onSuccessTask(t -> {
        BluetoothGattService huneoService = mBluetoothGatt.getService(UUID_HUNEO_SERVICE);

        // Set vibration characteristic to 1
        BluetoothGattCharacteristic characteristic = huneoService.getCharacteristic(UUID_HUNEO_VIBRATOR);
        characteristic.setValue(0, FORMAT_UINT8, 0);
        mBluetoothGatt.writeCharacteristic(characteristic);

        return t;
    });
}

//Start Combined Notifications
private void startCombined() {
    mServicesDiscovered.getTask().onSuccessTask(t -> {
        BluetoothGattService huneoService = mBluetoothGatt.getService(UUID_HUNEO_SERVICE);

        // Set Combined characteristic to send notifications
        BluetoothGattCharacteristic combinedCharacteristic = huneoService.getCharacteristic(UUID_HUNEO_COMBINED);
        mBluetoothGatt.setCharacteristicNotification(combinedCharacteristic, true);

        //Set Combined Client Characteristic Config Descriptor to enable notifications
        BluetoothGattDescriptor combinedDescriptor = combinedCharacteristic.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        combinedDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(combinedDescriptor);

        return t;
    });
}

//Stop Combined notifications
private void stopCombined() {
    mServicesDiscovered.getTask().onSuccessTask(t -> {
        BluetoothGattService huneoService = mBluetoothGatt.getService(UUID_HUNEO_SERVICE);

        // Set Accelerometer characteristic to send notifications
        BluetoothGattCharacteristic combinedCharacteristic = huneoService.getCharacteristic(UUID_HUNEO_COMBINED);
        mBluetoothGatt.setCharacteristicNotification(combinedCharacteristic, false);

        // Set Accelerometer Client Characteristic Config Descriptor to enable notifications
        BluetoothGattDescriptor combinedDescriptor = combinedCharacteristic.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        combinedDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(combinedDescriptor);

        return t;
    });
}

// Convert two bytes into a short
private int unsignedShortToInt(byte firstByte, byte secondByte) {
    ByteBuffer bb = ByteBuffer.allocate(2);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    bb.put(firstByte);
    bb.put(secondByte);
    short shortVal = bb.getShort(0);
    return shortVal >= 0 ? shortVal : 0x10000 + shortVal;
}

} }

Hopefully, someone can help me out.希望有人可以帮助我。 I'm out of ideas.我没主意了。

Found the solution.找到了解决方案。 The third-party forgot to mention that I had to set the right value to enable the characteristic.第三方忘记提及我必须设置正确的值才能启用该特性。 I tried that and it worked, Finally.我试过了,它奏效了,终于。 got data values.得到数据值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM