1 year ago
#29974
Mohamed El Kayal
How to enable notifications on exactly 2 characteristics in Android?
I want to be able to receive notifications on exactly 2 characteristics. Said characteristics are RX and TX from the perspective of the BLE device I am communicating with. I have succeeded in doing it for the RX, but apparently I need to do the same for the TX.
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
with(gatt) {
if (status == BluetoothGatt.GATT_SUCCESS) {
val services = gatt.services
Timber.w("Discovered ${services.size} services for ${device.address}.")
printGattTable()
requestMtu(device, GATT_MAX_MTU_SIZE)
val characteristic: BluetoothGattCharacteristic = this.getService(XpressStreamingServiceUUID).getCharacteristic(peripheralRX)
this.setCharacteristicNotification(characteristic, true)
setBleCharacteristic(characteristic)
listeners.forEach { it.get()?.onConnectionSetupComplete?.invoke(this) }
} else {
Timber.e("Service discovery failed due to status $status")
teardownConnection(gatt.device)
disconnect()
}
}
if (pendingOperation is Connect) {
signalEndOfOperation()
}
}
how do I go about changing that? Would a function like this suffice?:
private fun setNotification(
characteristic: BluetoothGattCharacteristic,
enabled: Boolean
) {
bluetoothGattRef.let { gatt ->
gatt.setCharacteristicNotification(characteristic, enabled)
if (peripheralTX == characteristic.uuid) {
val descriptor = characteristic.getDescriptor(UUID.fromString(CCC_DESCRIPTOR_UUID))
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
gatt.writeDescriptor(descriptor)
} else if (peripheralRX == characteristic.uuid) {
val descriptor = characteristic.getDescriptor(UUID.fromString(CCC_DESCRIPTOR_UUID))
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
gatt.writeDescriptor(descriptor)
}
else{
Timber.i("Neither characteristic RX nor TX detected")
}
}
}
I basically want to be notified by either one of them when send or receiving data
UPDATE: would this be a proper queuing mechanism?
@Synchronized
private fun enqueueOperation(operation: BleOperationType) {
operationQueue.add(operation)
if (pendingOperation == null) {
doNextOperation()
}
}
@Synchronized
private fun signalEndOfOperation() {
Timber.d("End of $pendingOperation")
pendingOperation = null
if (operationQueue.isNotEmpty()) {
doNextOperation()
}
}
@Synchronized
private fun doNextOperation() {
if (pendingOperation != null) {
Timber.e("doNextOperation() called when an operation is pending! Aborting.")
return
}
val operation = operationQueue.poll() ?: run {
Timber.v("Operation queue empty, returning")
return
}
pendingOperation = operation
// Handle Connect separately from other operations that require device to be connected
if (operation is Connect) {
with(operation) {
Timber.w("Connecting to ${device.name} | ${device.address}")
device.connectGatt(context, false, gattCallback)
isConnected.value = true
}
return
}
// Check BluetoothGatt availability for other operations
val gatt = deviceGattMap[operation.device]
?: this@BleConnectionManager.run {
Timber.e("Not connected to ${operation.device.address}! Aborting $operation operation.")
signalEndOfOperation()
return
}
// TODO: Make sure each operation ultimately leads to signalEndOfOperation()
// TODO: Refactor this into an BleOperationType abstract or extension function
when (operation) {
is Disconnect -> with(operation) {
Timber.w("Disconnecting from ${device.address}")
gatt.close()
deviceGattMap.remove(device)
listeners.forEach { it.get()?.onDisconnect?.invoke(device) }
signalEndOfOperation()
setConnectionStatus(STATE_DISCONNECTED)
isConnected.value = false
}
is CharacteristicWrite -> with(operation) {
gatt.findCharacteristic(characteristicUUID)?.let { characteristic ->
characteristic.writeType = writeType
characteristic.value = payLoad
gatt.writeCharacteristic(characteristic)
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $characteristicUUID to write to")
signalEndOfOperation()
}
}
is CharacteristicRead -> with(operation) {
gatt.findCharacteristic(characteristicUUID)?.let { characteristic ->
gatt.readCharacteristic(characteristic)
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $characteristicUUID to read from")
signalEndOfOperation()
}
}
is DescriptorWrite -> with(operation) {
gatt.findDescriptor(descriptorUUID)?.let { descriptor ->
descriptor.value = payLoad
gatt.writeDescriptor(descriptor)
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $descriptorUUID to write to")
signalEndOfOperation()
}
}
is DescriptorRead -> with(operation) {
gatt.findDescriptor(descriptorUUID)?.let { descriptor ->
gatt.readDescriptor(descriptor)
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $descriptorUUID to read from")
signalEndOfOperation()
}
}
is EnableNotifications -> with(operation) {
gatt.findCharacteristic(characteristicUUID)?.let { characteristic ->
val cccdUuid = UUID.fromString(CCC_DESCRIPTOR_UUID)
val payload = when {
characteristic.isIndicatable() ->
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
characteristic.isNotifiable() ->
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
else ->
error("${characteristic.uuid} doesn't support notifications/indications")
}
characteristic.getDescriptor(cccdUuid)?.let { cccDescriptor ->
if (!gatt.setCharacteristicNotification(characteristic, true)) {
Timber.e("setCharacteristicNotification failed for ${characteristic.uuid}")
signalEndOfOperation()
return
}
cccDescriptor.value = payload
gatt.writeDescriptor(cccDescriptor)
} ?: this@BleConnectionManager.run {
Timber.e("${characteristic.uuid} doesn't contain the CCC descriptor!")
signalEndOfOperation()
}
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $characteristicUUID! Failed to enable notifications.")
signalEndOfOperation()
}
}
is DisableNotifications -> with(operation) {
gatt.findCharacteristic(characteristicUUID)?.let { characteristic ->
val cccdUuid = UUID.fromString(CCC_DESCRIPTOR_UUID)
characteristic.getDescriptor(cccdUuid)?.let { cccDescriptor ->
if (!gatt.setCharacteristicNotification(characteristic, false)) {
Timber.e("setCharacteristicNotification failed for ${characteristic.uuid}")
signalEndOfOperation()
return
}
cccDescriptor.value = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
gatt.writeDescriptor(cccDescriptor)
} ?: this@BleConnectionManager.run {
Timber.e("${characteristic.uuid} doesn't contain the CCC descriptor!")
signalEndOfOperation()
}
} ?: this@BleConnectionManager.run {
Timber.e("Cannot find $characteristicUUID! Failed to disable notifications.")
signalEndOfOperation()
}
}
is MtuRequest -> with(operation) {
gatt.requestMtu(mtu)
}
}
}
android
kotlin
bluetooth-lowenergy
characteristics
0 Answers
Your Answer