[bluetooth.generic] Enable BLE notification for linked channels (#10122)
* [bluetooth] Add BluetoothDevice.isNotifying() * [bluetooth] Improve Characteristic properties support * [bluez] Improve Characteristic properties support * [bluetooth] Add BluetoothDevice.canNotify() * [bluez] Also catch DBusExecutionException on read value * [bluetooth.generic] Activate notifications for linked channels where characteristics are able to notify * [bluez] Adjust javadoc * [bluegiga] Add BluetoothDevice.isNotifying() support * [bluegiga] Fix notification enabled check * [bluetooth] move canNotify() to Characteristic * [bluegiga] rename notificationEnabled to notifying * [bluetooth.generic] use handlerToChannels to subscribe to notifications * [bluetooth.generic] implement TODOs of canRead()/canWrite() * [bluetooth.generic] optimize ChannelUID * [bluetooth.generic] use channelUids for link check Signed-off-by: Peter Rosenberg <prosenb.dev@gmail.com>
This commit is contained in:
@@ -58,6 +58,7 @@ import org.sputnikdev.bluetooth.gattparser.spec.Field;
|
||||
* channels based off of a bluetooth device's GATT characteristics.
|
||||
*
|
||||
* @author Connor Petty - Initial contribution
|
||||
* @author Peter Rosenberg - Use notifications
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@@ -68,6 +69,7 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
private final Map<ChannelUID, CharacteristicHandler> channelHandlers = new ConcurrentHashMap<>();
|
||||
private final BluetoothGattParser gattParser = BluetoothGattParserFactory.getDefault();
|
||||
private final CharacteristicChannelTypeProvider channelTypeProvider;
|
||||
private final Map<CharacteristicHandler, List<ChannelUID>> handlerToChannels = new ConcurrentHashMap<>();
|
||||
|
||||
private @Nullable ScheduledFuture<?> readCharacteristicJob = null;
|
||||
|
||||
@@ -84,12 +86,14 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
readCharacteristicJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
if (device.getConnectionState() == ConnectionState.CONNECTED) {
|
||||
if (resolved) {
|
||||
for (CharacteristicHandler charHandler : charHandlers.values()) {
|
||||
if (charHandler.canRead()) {
|
||||
handlerToChannels.forEach((charHandler, channelUids) -> {
|
||||
// Only read the value manually if notification is not on.
|
||||
// Also read it the first time before we activate notifications below.
|
||||
if (!device.isNotifying(charHandler.characteristic) && charHandler.canRead()) {
|
||||
device.readCharacteristic(charHandler.characteristic);
|
||||
try {
|
||||
// TODO the ideal solution would be to use locks/conditions and timeouts
|
||||
// between this code and `onCharacteristicReadComplete` but
|
||||
// Kbetween this code and `onCharacteristicReadComplete` but
|
||||
// that would overcomplicate the code a bit and I plan
|
||||
// on implementing a better more generalized solution later
|
||||
Thread.sleep(50);
|
||||
@@ -97,7 +101,20 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (charHandler.characteristic.canNotify()) {
|
||||
// Enabled/Disable notifications dependent on if the channel is linked.
|
||||
// TODO check why isLinked() is true for not linked channels
|
||||
if (channelUids.stream().anyMatch(this::isLinked)) {
|
||||
if (!device.isNotifying(charHandler.characteristic)) {
|
||||
device.enableNotifications(charHandler.characteristic);
|
||||
}
|
||||
} else {
|
||||
if (device.isNotifying(charHandler.characteristic)) {
|
||||
device.disableNotifications(charHandler.characteristic);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// if we are connected and still haven't been able to resolve the services, try disconnecting and
|
||||
// then connecting again
|
||||
@@ -117,6 +134,7 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
|
||||
charHandlers.clear();
|
||||
channelHandlers.clear();
|
||||
handlerToChannels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,9 +179,11 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
logger.trace("{} processing characteristic {}", address, characteristic.getUuid());
|
||||
CharacteristicHandler handler = getCharacteristicHandler(characteristic);
|
||||
List<Channel> chans = handler.buildChannels();
|
||||
for (Channel channel : chans) {
|
||||
channelHandlers.put(channel.getUID(), handler);
|
||||
List<ChannelUID> chanUids = chans.stream().map(Channel::getUID).collect(Collectors.toList());
|
||||
for (ChannelUID channel : chanUids) {
|
||||
channelHandlers.put(channel, handler);
|
||||
}
|
||||
handlerToChannels.put(handler, chanUids);
|
||||
return chans.stream();
|
||||
})//
|
||||
.collect(Collectors.toList());
|
||||
@@ -341,8 +361,7 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
if (gattParser.isKnownCharacteristic(charUUID)) {
|
||||
return gattParser.isValidForRead(charUUID);
|
||||
}
|
||||
// TODO: need to evaluate this from characteristic properties, but such properties aren't support yet
|
||||
return true;
|
||||
return characteristic.canRead();
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
@@ -350,8 +369,7 @@ public class GenericBluetoothHandler extends ConnectedBluetoothHandler {
|
||||
if (gattParser.isKnownCharacteristic(charUUID)) {
|
||||
return gattParser.isValidForWrite(charUUID);
|
||||
}
|
||||
// TODO: need to evaluate this from characteristic properties, but such properties aren't support yet
|
||||
return true;
|
||||
return characteristic.canWrite();
|
||||
}
|
||||
|
||||
private boolean isAdvanced() {
|
||||
|
||||
Reference in New Issue
Block a user