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