From 28ee10141fbd4874f8f78c0c699d5e62635f77f6 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sat, 25 Jul 2020 07:45:50 +0200
Subject: GATTCharacteristic: Add enableNotificationOrIndication(..)..;
DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT
GATTCharacteristic (Java/C++): Add enableNotificationOrIndication(..) and use it as default for BLE active addCharacteristicListener(..).
It is recommended to utilize notification over indication, as its link-layer handshake
and higher potential bandwidth may deliver material higher performance.
+++
Add setting BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT
(and also document DEBUG and VERBOSE).
DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT
Have direct_bt provide compatibility to TinyB's BluetoothGattCharacteristic
API: BluetoothGattCharacteristic#getValue() value cache and
BluetoothGattCharacteristic#enableValueNotifications(BluetoothNotification) value notification.
DBTGattCharacteristic benefits from _disabled_ compatibility (and DEBUG)
performance wise, as no listener nor cache needs to be added in this case!
---
api/direct_bt/DBTDevice.hpp | 9 ++-
api/direct_bt/GATTCharacteristic.hpp | 53 +++++++++++++----
api/direct_bt/GATTHandler.hpp | 4 ++
examples/java/ScannerTinyB10.java | 3 +
java/direct_bt/tinyb/DBTGattCharacteristic.java | 79 +++++++++++++++++++++----
java/org/tinyb/BluetoothDevice.java | 7 +++
java/org/tinyb/BluetoothFactory.java | 32 ++++++++++
java/org/tinyb/BluetoothGattCharacteristic.java | 54 +++++++++++++++--
java/org/tinyb/BluetoothGattService.java | 7 ++-
java/tinyb/dbus/DBusGattCharacteristic.java | 7 ++-
src/direct_bt/GATTCharacteristic.cpp | 43 +++++++++++---
11 files changed, 255 insertions(+), 43 deletions(-)
diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp
index 4b8eb806..4b9453fb 100644
--- a/api/direct_bt/DBTDevice.hpp
+++ b/api/direct_bt/DBTDevice.hpp
@@ -392,11 +392,16 @@ namespace direct_bt {
void disconnectGATT();
/**
- * Add the given {@link GATTCharacteristicListener} to the listener list if not already present.
+ * Add the given GATTCharacteristicListener to the listener list if not already present.
*
* Convenience delegation call to GATTHandler
*
- * @param listener A {@link GATTCharacteristicListener} instance, listening to all {@link BluetoothGattCharacteristic} events of this device
+ *
+ * To enable the actual BLE notification and/or indication, one needs to call
+ * GATTCharacteristic::configNotificationIndication(bool, bool, bool[])
+ * or GATTCharacteristic::enableNotificationOrIndication(bool enabledState[2]).
+ *
+ * @param listener A GATTCharacteristicListener instance, listening to all BluetoothGattCharacteristic events of this device
* @return true if the given listener is not element of the list and has been newly added, otherwise false.
* @throws IllegalStateException if the GATTHandler is null, i.e. not connected
*/
diff --git a/api/direct_bt/GATTCharacteristic.hpp b/api/direct_bt/GATTCharacteristic.hpp
index 7734c35f..67274a32 100644
--- a/api/direct_bt/GATTCharacteristic.hpp
+++ b/api/direct_bt/GATTCharacteristic.hpp
@@ -75,6 +75,8 @@ namespace direct_bt {
private:
/** Characteristics's service weak back-reference */
std::weak_ptr wbr_service;
+ bool enabledNotifyState = false;
+ bool enabledIndicateState = false;
public:
/** BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1.1 Characteristic Properties */
@@ -176,12 +178,16 @@ namespace direct_bt {
* Method enables notification and/or indication for this characteristic at BLE level.
*
*
- * Convenience delegation call to GATTHandler via DBTDevice
- *
- *
* Implementation masks this Characteristic properties PropertyBitVal::Notify and PropertyBitVal::Indicate
* with the respective user request parameters, hence removes unsupported requests.
*
+ *
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ *
+ * It is recommended to utilize notification over indication, as its link-layer handshake
+ * and higher potential bandwidth may deliver material higher performance.
+ *
* @param enableNotification
* @param enableIndication
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication.
@@ -193,10 +199,33 @@ namespace direct_bt {
*/
bool configNotificationIndication(const bool enableNotification, const bool enableIndication, bool enabledState[2]);
+ /**
+ * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration
+ *
+ * Method will attempt to enable notification on the BLE level, if available,
+ * otherwise indication if available.
+ *
+ *
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ *
+ * It is recommended to utilize notification over indication, as its link-layer handshake
+ * and higher potential bandwidth may deliver material higher performance.
+ *
+ * @param enabledState array of size 2, holding the resulting enabled state for notification and indication.
+ * @return false if this characteristic has no PropertyBitVal::Notify or PropertyBitVal::Indication present,
+ * or there is no GATTDescriptor of type ClientCharacteristicConfiguration, or if the operation has failed.
+ * Otherwise returns true.
+ * @throws IllegalStateException if notification or indication is set to be enabled
+ * and the {@link DBTDevice's}'s {@link GATTHandler} is null, i.e. not connected
+ */
+ bool enableNotificationOrIndication(bool enabledState[2]);
+
/**
* Add the given GATTCharacteristicListener to the listener list if not already present.
*
- * Occurring notifications and indications, if enabled via {@link #configNotificationIndication(bool, bool, bool[])}},
+ * Occurring notifications and indications, if enabled via configNotificationIndication(bool, bool, bool[])
+ * or enableNotificationOrIndication(bool[]),
* will call the respective GATTCharacteristicListener callback method.
*
*
@@ -219,9 +248,15 @@ namespace direct_bt {
/**
* Add the given GATTCharacteristicListener to the listener list if not already present
- * and if enabling the notification and/or indication for this characteristic at BLE level was successful.
+ * and if enabling the notification or indication for this characteristic at BLE level was successful.
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ * Implementation will attempt to enable notification only, if available,
+ * otherwise indication if available.
+ * Implementation uses enableNotificationOrIndication(bool[]) to enable either.
+ *
*
- * Occurring notifications and indications will call the respective {@link GATTCharacteristicListener}
+ * Occurring notifications and indications will call the respective GATTCharacteristicListener
* callback method.
*
*
@@ -230,10 +265,6 @@ namespace direct_bt {
* otherwise false.
*
*
- * Convenience delegation call to GATTHandler via DBTDevice
- * performing both, configNotificationIndication(..) and addCharacteristicListener(..).
- *
- *
* To restrict the listener to listen only to this GATTCharacteristic instance,
* user has to implement GATTCharacteristicListener::match(GATTCharacteristicRef) accordingly.
*
@@ -241,7 +272,7 @@ namespace direct_bt {
* which provides these simple matching filter facilities.
*
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication
- * using {@link #configNotificationIndication(bool, bool, bool[])}}
+ * using enableNotificationOrIndication(bool[])
* @throws IllegalStateException if the {@link DBTDevice's}'s {@link GATTHandler} is null, i.e. not connected
*/
bool addCharacteristicListener(std::shared_ptr l, bool enabledState[2]);
diff --git a/api/direct_bt/GATTHandler.hpp b/api/direct_bt/GATTHandler.hpp
index 40162184..3f671fe8 100644
--- a/api/direct_bt/GATTHandler.hpp
+++ b/api/direct_bt/GATTHandler.hpp
@@ -313,6 +313,10 @@ namespace direct_bt {
* Method enables notification and/or indication for the corresponding characteristic at BLE level.
*
*
+ * It is recommended to utilize notification over indication, as its link-layer handshake
+ * and higher potential bandwidth may deliver material higher performance.
+ *
+ *
* Throws an IllegalArgumentException if the given GATTDescriptor is not a ClientCharacteristicConfiguration.
*
*/
diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java
index 78235138..0a9b3114 100644
--- a/examples/java/ScannerTinyB10.java
+++ b/examples/java/ScannerTinyB10.java
@@ -416,6 +416,9 @@ public class ScannerTinyB10 {
System.setProperty("org.tinyb.verbose", "true");
}
}
+ // Drop BluetoothGattCharacteristic value cache and notification compatibility using direct_bt.
+ System.setProperty("direct_bt.tinyb.characteristic.compat", "false");
+
if( null == bluetoothManagerClazzName ) {
bluetoothManagerClazzName = BluetoothFactory.DirectBTImplementationID.BluetoothManagerClassName;
}
diff --git a/java/direct_bt/tinyb/DBTGattCharacteristic.java b/java/direct_bt/tinyb/DBTGattCharacteristic.java
index 22c341bd..3ce74c05 100644
--- a/java/direct_bt/tinyb/DBTGattCharacteristic.java
+++ b/java/direct_bt/tinyb/DBTGattCharacteristic.java
@@ -30,6 +30,7 @@ import java.util.Arrays;
import java.util.List;
import org.tinyb.BluetoothException;
+import org.tinyb.BluetoothFactory;
import org.tinyb.BluetoothGattCharacteristic;
import org.tinyb.BluetoothGattDescriptor;
import org.tinyb.BluetoothGattService;
@@ -75,6 +76,9 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
/* pp */ final List descriptorList;
+ boolean enabledNotifyState = false;
+ boolean enabledIndicateState = false;
+
private byte[] cachedValue = null;
private BluetoothNotification valueNotificationCB = null;
@@ -113,7 +117,10 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
this.clientCharacteristicsConfigIndex = clientCharacteristicsConfigIndex;
this.descriptorList = getDescriptorsImpl();
- if( hasNotify || hasIndicate ) {
+ if( ( BluetoothFactory.DEBUG || BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT ) &&
+ ( hasNotify || hasIndicate )
+ )
+ {
// This characteristicListener serves TinyB 'enableValueNotification(..)' and 'getValue()' (cached value)
// backwards compatibility only!
final GATTCharacteristicListener characteristicListener = new GATTCharacteristicListener(this) {
@@ -124,10 +131,15 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
throw new InternalError("Filtered GATTCharacteristicListener.notificationReceived: Wrong Characteristic: Got "+charDecl+
", expected "+DBTGattCharacteristic.this.toString());
}
- final boolean valueChanged = updateCachedValue(value, true);
+ final boolean valueChanged;
+ if( BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT ) {
+ valueChanged = updateCachedValue(value, true);
+ } else {
+ valueChanged = true;
+ }
if( DEBUG ) {
System.err.println("GATTCharacteristicListener.notificationReceived: "+charDecl+
- ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]");
+ ", value[changed "+valueChanged+", len "+value.length+": "+BluetoothUtils.bytesHexString(value, true, true)+"]");
}
}
@Override
@@ -138,10 +150,16 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
throw new InternalError("Filtered GATTCharacteristicListener.indicationReceived: Wrong Characteristic: Got "+charDecl+
", expected "+DBTGattCharacteristic.this.toString());
}
- final boolean valueChanged = updateCachedValue(value, true);
+ final boolean valueChanged;
+ if( BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT ) {
+ valueChanged = updateCachedValue(value, true);
+ } else {
+ valueChanged = true;
+ }
if( DEBUG ) {
System.err.println("GATTCharacteristicListener.indicationReceived: "+charDecl+
- ", value[changed "+valueChanged+", data "+BluetoothUtils.bytesHexString(value, true, true)+"]");
+ ", value[changed "+valueChanged+", len "+value.length+": "+BluetoothUtils.bytesHexString(value, true, true)+
+ "], confirmationSent "+confirmationSent);
}
}
};
@@ -204,15 +222,19 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
@Override
public final byte[] readValue() throws BluetoothException {
- final byte[] value = readValueImpl();
- updateCachedValue(value, true);
- return cachedValue;
+ if( BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT ) {
+ final byte[] value = readValueImpl();
+ updateCachedValue(value, true);
+ return cachedValue;
+ } else {
+ return readValueImpl();
+ }
}
@Override
public final boolean writeValue(final byte[] value) throws BluetoothException {
final boolean res = writeValueImpl(value);
- if( res ) {
+ if( BluetoothFactory.DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT && res ) {
updateCachedValue(value, false);
}
return res;
@@ -226,16 +248,39 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
throws IllegalStateException
{
if( hasNotify || hasIndicate ) {
+ final boolean resEnableNotification = hasNotify && enableNotification;
+ final boolean resEnableIndication = hasIndicate && enableIndication;
+
+ if( resEnableNotification == enabledNotifyState &&
+ resEnableIndication == enabledIndicateState )
+ {
+ enabledState[0] = resEnableNotification;
+ enabledState[1] = resEnableIndication;
+ if( DEBUG ) {
+ System.err.printf("GATTCharacteristic.configNotificationIndication: Unchanged: notification[shall %b, has %b: %b == %b], indication[shall %b, has %b: %b == %b]\n",
+ enableNotification, hasNotify, enabledNotifyState, resEnableNotification,
+ enableIndication, hasIndicate, enabledIndicateState, resEnableIndication);
+ }
+ return true;
+ }
+
final boolean res = configNotificationIndicationImpl(enableNotification, enableIndication, enabledState);
if( DEBUG ) {
- System.err.println("GATTCharacteristicListener.configNotificationIndication: "+res+", enableResult "+Arrays.toString(enabledState));
+ System.err.printf("GATTCharacteristic.configNotificationIndication: res %b, notification[shall %b, has %b: %b -> %b], indication[shall %b, has %b: %b -> %b]\n",
+ res,
+ enableNotification, hasNotify, enabledNotifyState, resEnableNotification,
+ enableIndication, hasIndicate, enabledIndicateState, resEnableIndication);
+ }
+ if( res ) {
+ enabledNotifyState = resEnableNotification;
+ enabledIndicateState = resEnableIndication;
}
return res;
} else {
enabledState[0] = false;
enabledState[1] = false;
if( DEBUG ) {
- System.err.println("GATTCharacteristicListener.configNotificationIndication: FALSE*: hasNotify "+hasNotify+", hasIndicate "+hasIndicate);
+ System.err.println("GATTCharacteristic.configNotificationIndication: FALSE*: hasNotify "+hasNotify+", hasIndicate "+hasIndicate);
}
return false;
}
@@ -243,6 +288,16 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
private native boolean configNotificationIndicationImpl(boolean enableNotification, boolean enableIndication, final boolean enabledState[/*2*/])
throws IllegalStateException;
+ @Override
+ public boolean enableNotificationOrIndication(final boolean enabledState[/*2*/])
+ throws IllegalStateException
+ {
+ final boolean enableNotification = hasNotify;
+ final boolean enableIndication = !enableNotification && hasIndicate;
+
+ return configNotificationIndication(enableNotification, enableIndication, enabledState);
+ }
+
@Override
public final boolean addCharacteristicListener(final GATTCharacteristicListener listener) {
return getService().getDevice().addCharacteristicListener(listener);
@@ -250,7 +305,7 @@ public class DBTGattCharacteristic extends DBTObject implements BluetoothGattCha
@Override
public final boolean addCharacteristicListener(final GATTCharacteristicListener listener, final boolean enabledState[/*2*/]) {
- if( !configNotificationIndication(true /* enableNotification */, true /* enableIndication */, enabledState) ) {
+ if( !enableNotificationOrIndication(enabledState) ) {
return false;
}
return getService().getDevice().addCharacteristicListener(listener);
diff --git a/java/org/tinyb/BluetoothDevice.java b/java/org/tinyb/BluetoothDevice.java
index d3b004f9..fe84cce8 100644
--- a/java/org/tinyb/BluetoothDevice.java
+++ b/java/org/tinyb/BluetoothDevice.java
@@ -442,10 +442,17 @@ public interface BluetoothDevice extends BluetoothObject
/**
* Add the given {@link GATTCharacteristicListener} to the listener list if not already present.
+ *
+ * To enable the actual BLE notification and/or indication, one needs to call
+ * {@link BluetoothGattCharacteristic#configNotificationIndication(boolean, boolean, boolean[])}
+ * or {@link BluetoothGattCharacteristic#enableNotificationOrIndication(boolean[])}.
+ *
* @param listener A {@link GATTCharacteristicListener} instance, listening to all {@link BluetoothGattCharacteristic} events of this device
* @return true if the given listener is not element of the list and has been newly added, otherwise false.
* @throws IllegalStateException if the {@link BluetoothDevice}'s GATTHandler is null, i.e. not connected
* @throws IllegalStateException if the given {@link GATTCharacteristicListener} is already in use, i.e. added.
+ * @see BluetoothGattCharacteristic#configNotificationIndication(boolean, boolean, boolean[])
+ * @see BluetoothGattCharacteristic#enableNotificationOrIndication(boolean[])
* @since 2.0.0
* @implNote not implemented in tinyb.dbus
*/
diff --git a/java/org/tinyb/BluetoothFactory.java b/java/org/tinyb/BluetoothFactory.java
index 1e27069d..c8443a5e 100644
--- a/java/org/tinyb/BluetoothFactory.java
+++ b/java/org/tinyb/BluetoothFactory.java
@@ -37,6 +37,13 @@ import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
+/**
+ * One stop {@link BluetoothManager} API entry point.
+ *
+ * Further provides access to certain property settings,
+ * see {@link #DEBUG}, {@link #VERBOSE}, {@link #DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT}.
+ *
+ */
public class BluetoothFactory {
/**
@@ -126,8 +133,29 @@ public class BluetoothFactory {
public static final String getImplVersion() { return ImplVersion; }
private static String ImplVersion;
+ /**
+ * Verbose logging enabled or disabled.
+ *
+ * System property {@code org.tinyb.verbose}, boolean, default {@code false}.
+ *
+ */
public static final boolean VERBOSE;
+ /**
+ * Debug logging enabled or disabled.
+ *
+ * System property {@code org.tinyb.debug}, boolean, default {@code false}.
+ *
+ */
public static final boolean DEBUG;
+ /**
+ * Have direct_bt provide compatibility to TinyB's {@link BluetoothGattCharacteristic}
+ * API: {@link BluetoothGattCharacteristic#getValue() value cache} and
+ * {@link BluetoothGattCharacteristic#enableValueNotifications(BluetoothNotification) value notification}.
+ *
+ * System property {@code direct_bt.tinyb.characteristic.compat}, boolean, default {@code true}.
+ *
+ */
+ public static final boolean DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT;
static {
{
@@ -138,6 +166,10 @@ public class BluetoothFactory {
final String v = System.getProperty("org.tinyb.debug", "false");
DEBUG = Boolean.valueOf(v);
}
+ {
+ final String v = System.getProperty("direct_bt.tinyb.characteristic.compat", "true");
+ DIRECTBT_CHARACTERISTIC_VALUE_CACHE_NOTIFICATION_COMPAT = Boolean.valueOf(v);
+ }
implIDs.add(DirectBTImplementationID);
implIDs.add(DBusImplementationID);
}
diff --git a/java/org/tinyb/BluetoothGattCharacteristic.java b/java/org/tinyb/BluetoothGattCharacteristic.java
index 586e7b2c..338f94be 100644
--- a/java/org/tinyb/BluetoothGattCharacteristic.java
+++ b/java/org/tinyb/BluetoothGattCharacteristic.java
@@ -79,6 +79,13 @@ public interface BluetoothGattCharacteristic extends BluetoothObject
* Implementation masks this Characteristic properties PropertyBitVal::Notify and PropertyBitVal::Indicate
* with the respective user request parameters, hence removes unsupported requests.
*
+ *
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ *
+ * It is recommended to utilize notification over indication, as its link-layer handshake
+ * and higher potential bandwidth may deliver material higher performance.
+ *
* @param enableNotification
* @param enableIndication
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication.
@@ -87,22 +94,52 @@ public interface BluetoothGattCharacteristic extends BluetoothObject
* Otherwise returns true.
* @throws IllegalStateException if notification or indication is set to be enabled
* and the {@link BluetoothDevice}'s GATTHandler is null, i.e. not connected
+ * @see #enableNotificationOrIndication(boolean[])
* @since 2.0.0
* @implNote not implemented in tinyb.dbus
*/
public boolean configNotificationIndication(final boolean enableNotification, final boolean enableIndication, final boolean enabledState[/*2*/])
throws IllegalStateException;
+ /**
+ * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration
+ *
+ * Method will attempt to enable notification on the BLE level, if available,
+ * otherwise indication if available.
+ *
+ *
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ *
+ * It is recommended to utilize notification over indication, as its link-layer handshake
+ * and higher potential bandwidth may deliver material higher performance.
+ *
+ * @param enabledState array of size 2, holding the resulting enabled state for notification and indication.
+ * @return false if this characteristic has no PropertyBitVal::Notify or PropertyBitVal::Indication present,
+ * or there is no GATTDescriptor of type ClientCharacteristicConfiguration, or if the operation has failed.
+ * Otherwise returns true.
+ * @throws IllegalStateException if notification or indication is set to be enabled
+ * and the {@link BluetoothDevice}'s GATTHandler is null, i.e. not connected
+ * @see #configNotificationIndication(boolean, boolean, boolean[])
+ * @since 2.0.0
+ * @implNote not implemented in tinyb.dbus
+ */
+ public boolean enableNotificationOrIndication(final boolean enabledState[/*2*/])
+ throws IllegalStateException;
+
/**
* Add the given {@link GATTCharacteristicListener} to the listener list if not already present.
*
- * Occurring notifications and indications, if enabled via {#link {@link #configNotificationIndication(boolean, boolean, boolean[])}},
+ * Occurring notifications and indications, if enabled via {@link #configNotificationIndication(boolean, boolean, boolean[])}
+ * or {@link #enableNotificationOrIndication(boolean[])},
* will call the respective GATTCharacteristicListener callback method.
*
* @param listener A {@link GATTCharacteristicListener} instance, listening to this {@link BluetoothGattCharacteristic}'s events
* @return true if the given listener is not element of the list and has been newly added, otherwise false.
* @throws IllegalStateException if the DBTDevice's GATTHandler is null, i.e. not connected
* @throws IllegalStateException if the given {@link GATTCharacteristicListener} is already in use, i.e. added.
+ * @see #enableNotificationOrIndication(boolean[])
+ * @see #configNotificationIndication(boolean, boolean, boolean[])
* @since 2.0.0
* @implNote not implemented in tinyb.dbus
*/
@@ -111,18 +148,25 @@ public interface BluetoothGattCharacteristic extends BluetoothObject
/**
* Add the given {@link GATTCharacteristicListener} to the listener list if not already present
- * and if enabling the notification and/or indication for this characteristic at BLE level was successful.
+ * and if enabling the notification or indication for this characteristic at BLE level was successful.
+ * Notification and/or indication configuration is only performed per characteristic if changed.
+ *
+ * Implementation will attempt to enable notification only, if available,
+ * otherwise indication if available.
+ * Implementation uses {@link #enableNotificationOrIndication(boolean[])} to enable one.
+ *
*
* Occurring notifications and indications will call the respective {@link GATTCharacteristicListener}
* callback method.
*
* @param listener A {@link GATTCharacteristicListener} instance, listening to this {@link BluetoothGattCharacteristic}'s events
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication
- * using #configNotificationIndication(boolean, boolean, boolean[])
+ * using {@link #enableNotificationOrIndication(boolean[])}
* @return true if enabling the notification and/or indication was successful
* and if the given listener is not element of the list and has been newly added, otherwise false.
* @throws IllegalStateException if the {@link BluetoothDevice}'s GATTHandler is null, i.e. not connected
* @throws IllegalStateException if the given {@link GATTCharacteristicListener} is already in use, i.e. added.
+ * @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
* @since 2.0.0
* @implNote not implemented in tinyb.dbus
@@ -140,7 +184,7 @@ public interface BluetoothGattCharacteristic extends BluetoothObject
*
* @param listener A {@link GATTCharacteristicListener} instance
* @param disableIndicationNotification if true, disables the notification and/or indication for this characteristic
- * using {@link #configNotificationIndication(boolean, boolean, boolean[])
+ * using {@link #configNotificationIndication(boolean, boolean, boolean[])}
* @return true if the given listener is an element of the list and has been removed, otherwise false.
* @see #configNotificationIndication(boolean, boolean, boolean[])
* @since 2.0.0
@@ -162,7 +206,7 @@ public interface BluetoothGattCharacteristic extends BluetoothObject
*
*
* @param disableIndicationNotification if true, disables the notification and/or indication for this characteristic
- * using {@link #configNotificationIndication(boolean, boolean, boolean[])
+ * using {@link #configNotificationIndication(boolean, boolean, boolean[])}
* @return number of removed listener.
* @see #configNotificationIndication(boolean, boolean, boolean[])
* @see BluetoothDevice#removeAllAssociatedCharacteristicListener(BluetoothGattCharacteristic)
diff --git a/java/org/tinyb/BluetoothGattService.java b/java/org/tinyb/BluetoothGattService.java
index 52f766ea..5190fdce 100644
--- a/java/org/tinyb/BluetoothGattService.java
+++ b/java/org/tinyb/BluetoothGattService.java
@@ -87,7 +87,8 @@ public interface BluetoothGattService extends BluetoothObject
public List getCharacteristics();
/**
- * Adds the given {@link GATTCharacteristicListener} to the {@link BluetoothDevice} for all {@link BluetoothGattCharacteristic}s.
+ * Adds the given {@link GATTCharacteristicListener} to the {@link BluetoothDevice}
+ * and {@link BluetoothGattCharacteristic#enableNotificationOrIndication(boolean[])} for all {@link BluetoothGattCharacteristic} instances.
* @param listener {@link GATTCharacteristicListener} to add to the {@link BluetoothDevice}.
* It is important to have hte listener's {@link GATTCharacteristicListener#getAssociatedCharacteristic() associated characteristic} == null,
* otherwise the listener can't be used for all characteristics.
@@ -96,7 +97,7 @@ public interface BluetoothGattService extends BluetoothObject
* is not null.
* @since 2.0.0
* @implNote not implemented in tinyb.dbus
- * @see BluetoothGattCharacteristic#configNotificationIndication(boolean, boolean, boolean[])
+ * @see BluetoothGattCharacteristic#enableNotificationOrIndication(boolean[])
* @see BluetoothDevice#addCharacteristicListener(GATTCharacteristicListener, BluetoothGattCharacteristic)
*/
public static boolean addCharacteristicListenerToAll(final BluetoothDevice device, final List services,
@@ -112,7 +113,7 @@ public interface BluetoothGattService extends BluetoothObject
final BluetoothGattService s = is.next();
final List characteristics = s.getCharacteristics();
for(final Iterator ic = characteristics.iterator(); ic.hasNext(); ) {
- ic.next().configNotificationIndication(true /* enableNotification */, true /* enableIndication */, new boolean[2]);
+ ic.next().enableNotificationOrIndication(new boolean[2]);
}
}
return res;
diff --git a/java/tinyb/dbus/DBusGattCharacteristic.java b/java/tinyb/dbus/DBusGattCharacteristic.java
index 2cf874bc..2fcbfb39 100644
--- a/java/tinyb/dbus/DBusGattCharacteristic.java
+++ b/java/tinyb/dbus/DBusGattCharacteristic.java
@@ -113,7 +113,12 @@ public class DBusGattCharacteristic extends DBusObject implements BluetoothGattC
{
return false; // FIXME
}
-
+ @Override
+ public boolean enableNotificationOrIndication(final boolean[] enabledState)
+ throws IllegalStateException
+ {
+ return false; // FIXME
+ }
@Override
public boolean addCharacteristicListener(final GATTCharacteristicListener listener, final boolean[] enabledState)
throws IllegalStateException
diff --git a/src/direct_bt/GATTCharacteristic.cpp b/src/direct_bt/GATTCharacteristic.cpp
index b36091b4..4be91ab5 100644
--- a/src/direct_bt/GATTCharacteristic.cpp
+++ b/src/direct_bt/GATTCharacteristic.cpp
@@ -23,7 +23,6 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include
#include
#include
#include
@@ -33,6 +32,9 @@
#include
+// #define VERBOSE_ON 1
+#include
+
#include "GATTCharacteristic.hpp"
#include "GATTHandler.hpp"
#include "DBTDevice.hpp"
@@ -141,7 +143,7 @@ std::string GATTCharacteristic::toString() const {
", value[type 0x"+value_type->toString()+", handle "+uint16HexString(value_handle)+char_name+desc_str+
"], service[type 0x"+service_uuid_str+
", handle[ "+uint16HexString(service_handle)+".."+uint16HexString(service_handle_end)+" ]"+
- service_name+" ]";
+ service_name+", enabled[notify "+std::to_string(enabledNotifyState)+", indicate "+std::to_string(enabledIndicateState)+"] ]";
}
bool GATTCharacteristic::configNotificationIndication(const bool enableNotification, const bool enableIndication, bool enabledState[2]) {
@@ -166,8 +168,19 @@ bool GATTCharacteristic::configNotificationIndication(const bool enableNotificat
throw IllegalStateException("Characteristic's device GATTHandle not connected: "+
toString() + ", " + device->toString(), E_FILE_LINE);
}
- const bool resEnableNotification = hasEnableNotification & enableNotification;
- const bool resEnableIndication = hasEnableIndication & enableIndication;
+ const bool resEnableNotification = hasEnableNotification && enableNotification;
+ const bool resEnableIndication = hasEnableIndication && enableIndication;
+
+ if( resEnableNotification == enabledNotifyState &&
+ resEnableIndication == enabledIndicateState )
+ {
+ enabledState[0] = resEnableNotification;
+ enabledState[1] = resEnableIndication;
+ DBG_PRINT("GATTCharacteristic::configNotificationIndication: Unchanged: notification[shall %d, has %d: %d == %d], indication[shall %d, has %d: %d == %d]",
+ enableNotification, hasEnableNotification, enabledNotifyState, resEnableNotification,
+ enableIndication, hasEnableIndication, enabledIndicateState, resEnableIndication);
+ return true;
+ }
GATTDescriptorRef cccd = this->getClientCharacteristicConfig();
if( nullptr == cccd ) {
@@ -175,23 +188,35 @@ bool GATTCharacteristic::configNotificationIndication(const bool enableNotificat
return false;
}
bool res = gatt->configNotificationIndication(*cccd, resEnableNotification, resEnableIndication);
+ DBG_PRINT("GATTCharacteristic::configNotificationIndication: res %d, notification[shall %d, has %d: %d -> %d], indication[shall %d, has %d: %d -> %d]",
+ res,
+ enableNotification, hasEnableNotification, enabledNotifyState, resEnableNotification,
+ enableIndication, hasEnableIndication, enabledIndicateState, resEnableIndication);
if( res ) {
+ enabledNotifyState = resEnableNotification;
+ enabledIndicateState = resEnableIndication;
enabledState[0] = resEnableNotification;
enabledState[1] = resEnableIndication;
}
- DBG_PRINT("GATTCharacteristic::configNotificationIndication: res %d, notification[shall %d, has %d = %d], indication[shall %s, has %d = %d]",
- res,
- enableNotification. hasEnableNotification, resEnableNotification,
- enableIndication. hasEnableIndication, resEnableIndication);
return res;
}
+bool GATTCharacteristic::enableNotificationOrIndication(bool enabledState[2]) {
+ const bool hasEnableNotification = hasProperties(GATTCharacteristic::PropertyBitVal::Notify);
+ const bool hasEnableIndication = hasProperties(GATTCharacteristic::PropertyBitVal::Indicate);
+
+ const bool enableNotification = hasEnableNotification;
+ const bool enableIndication = !enableNotification && hasEnableIndication;
+
+ return configNotificationIndication(enableNotification, enableIndication, enabledState);
+}
+
bool GATTCharacteristic::addCharacteristicListener(std::shared_ptr l) {
return getDevice()->addCharacteristicListener(l);
}
bool GATTCharacteristic::addCharacteristicListener(std::shared_ptr l, bool enabledState[2]) {
- if( !configNotificationIndication(true, true, enabledState) ) {
+ if( !enableNotificationOrIndication(enabledState) ) {
return false;
}
return addCharacteristicListener(l);
--
cgit v1.2.3