summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/BTAdapter.hpp50
-rw-r--r--api/direct_bt/BTDevice.hpp15
-rw-r--r--api/direct_bt/BTGattChar.hpp150
-rw-r--r--api/direct_bt/BTGattCmd.hpp2
-rw-r--r--api/direct_bt/BTGattHandler.hpp49
-rw-r--r--api/direct_bt/BTGattService.hpp22
-rw-r--r--examples/dbt_scanner10.cpp5
-rw-r--r--examples/java/DBTScanner10.java5
-rw-r--r--java/jau/direct_bt/DBTDevice.java9
-rw-r--r--java/jau/direct_bt/DBTGattChar.java33
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx2
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx121
-rw-r--r--java/org/direct_bt/AdapterStatusListener.java3
-rw-r--r--java/org/direct_bt/BTDevice.java10
-rw-r--r--java/org/direct_bt/BTGattChar.java111
-rw-r--r--java/org/direct_bt/BTGattCharListener.java53
-rw-r--r--java/org/direct_bt/BTGattCmd.java16
-rw-r--r--java/org/direct_bt/BTGattService.java3
-rw-r--r--scripts/build.sh4
-rw-r--r--src/direct_bt/BTAdapter.cpp79
-rw-r--r--src/direct_bt/BTDevice.cpp23
-rw-r--r--src/direct_bt/BTGattChar.cpp94
-rw-r--r--src/direct_bt/BTGattHandler.cpp82
-rw-r--r--src/direct_bt/BTGattService.cpp17
-rw-r--r--trial/direct_bt/dbt_client00.hpp140
-rw-r--r--trial/direct_bt/dbt_client01.hpp56
-rw-r--r--trial/java/trial/org/direct_bt/DBTClient00.java146
-rw-r--r--trial/java/trial/org/direct_bt/DBTClient01.java61
28 files changed, 610 insertions, 751 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp
index ee16f881..54574bc1 100644
--- a/api/direct_bt/BTAdapter.hpp
+++ b/api/direct_bt/BTAdapter.hpp
@@ -263,7 +263,7 @@ namespace direct_bt {
(void)timestamp;
}
- virtual ~AdapterStatusListener() {}
+ ~AdapterStatusListener() noexcept override {}
std::string toString() const noexcept override { return "AdapterStatusListener["+jau::to_hexstring(this)+"]"; }
@@ -292,24 +292,6 @@ namespace direct_bt {
// *************************************************
// *************************************************
- namespace impl {
- struct StatusListenerPair {
- /** The actual listener */
- AdapterStatusListenerRef listener;
- /** The optional weak device reference. Weak, b/c it shall not block destruction */
- std::weak_ptr<BTDevice> wbr_device;
-
- bool match(const BTDeviceRef& device) const noexcept {
- BTDeviceRef sda = wbr_device.lock();
- if( nullptr != sda && nullptr != device ) {
- return *sda == *device;
- } else {
- return true;
- }
- }
- };
- }
-
/**
* BTAdapter represents one local Bluetooth Controller.
*
@@ -397,7 +379,23 @@ namespace direct_bt {
jau::simple_timer smp_watchdog;
jau::fraction_i64 smp_timeoutfunc(jau::simple_timer& timer);
- typedef jau::cow_darray<impl::StatusListenerPair> statusListenerList_t;
+ struct StatusListenerPair {
+ /** The actual listener */
+ AdapterStatusListenerRef listener;
+ /** The optional weak device reference. Weak, b/c it shall not block destruction */
+ std::weak_ptr<BTDevice> wbr_device;
+
+ bool match(const BTDeviceRef& device) const noexcept {
+ BTDeviceRef sda = wbr_device.lock();
+ if( nullptr != sda && nullptr != device ) {
+ return *sda == *device;
+ } else {
+ return true;
+ }
+ }
+ };
+ typedef jau::cow_darray<StatusListenerPair> statusListenerList_t;
+ static statusListenerList_t::equal_comparator adapterStatusListenerRefEqComparator;
statusListenerList_t statusListenerList;
// Storing SMPKeyBin entries, referenced by their remote address, i.e. BTDevice address.
@@ -563,7 +561,7 @@ namespace direct_bt {
void sendDeviceUpdated(std::string cause, BTDeviceRef device, uint64_t timestamp, EIRDataType updateMask) noexcept;
- int removeAllStatusListener(const BTDevice& d);
+ int removeAllStatusListener(const BTDevice& d) noexcept;
public:
@@ -961,14 +959,14 @@ namespace direct_bt {
* @see removeStatusListener()
* @see removeAllStatusListener()
*/
- bool addStatusListener(const AdapterStatusListenerRef& l);
+ bool addStatusListener(const AdapterStatusListenerRef& l) noexcept;
/**
* Please use BTDevice::addStatusListener() for clarity, merely existing here to allow JNI access.
*/
- bool addStatusListener(const BTDeviceRef& d, const AdapterStatusListenerRef& l);
+ bool addStatusListener(const BTDeviceRef& d, const AdapterStatusListenerRef& l) noexcept;
- bool addStatusListener(const BTDevice& d, const AdapterStatusListenerRef& l);
+ bool addStatusListener(const BTDevice& d, const AdapterStatusListenerRef& l) noexcept;
/**
* Remove the given listener from the list.
@@ -979,7 +977,7 @@ namespace direct_bt {
* @see BTDevice::removeStatusListener()
* @see addStatusListener()
*/
- bool removeStatusListener(const AdapterStatusListenerRef& l);
+ bool removeStatusListener(const AdapterStatusListenerRef& l) noexcept;
/**
* Remove the given listener from the list.
@@ -990,7 +988,7 @@ namespace direct_bt {
* @see BTDevice::removeStatusListener()
* @see addStatusListener()
*/
- bool removeStatusListener(const AdapterStatusListener * l);
+ bool removeStatusListener(const AdapterStatusListener * l) noexcept;
/**
* Remove all status listener from the list.
diff --git a/api/direct_bt/BTDevice.hpp b/api/direct_bt/BTDevice.hpp
index bf2f5266..fc109d56 100644
--- a/api/direct_bt/BTDevice.hpp
+++ b/api/direct_bt/BTDevice.hpp
@@ -384,7 +384,7 @@ namespace direct_bt {
* @see BTAdapter::removeAllStatusListener()
* @see removeStatusListener()
*/
- bool addStatusListener(const AdapterStatusListenerRef& l);
+ bool addStatusListener(const AdapterStatusListenerRef& l) noexcept;
/**
* Remove the given listener from the list.
@@ -398,7 +398,7 @@ namespace direct_bt {
* @see BTAdapter::removeAllStatusListener()
* @see addStatusListener()
*/
- bool removeStatusListener(const AdapterStatusListenerRef& l);
+ bool removeStatusListener(const AdapterStatusListenerRef& l) noexcept;
/**
* Retrieves the current connection info for this device and returns the ConnectionInfo reference if successful,
@@ -1161,7 +1161,12 @@ namespace direct_bt {
* @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
*/
- bool addCharListener(std::shared_ptr<BTGattCharListener> l);
+ bool addCharListener(const BTGattCharListenerRef& l) noexcept;
+
+ /**
+ * Please use BTGattChar::addCharListener() for clarity, merely existing here to allow JNI access.
+ */
+ bool addCharListener(const BTGattCharListenerRef& l, const BTGattCharRef& d) noexcept;
/**
* Remove the given {@link BTGattCharListener} from the listener list.
@@ -1171,7 +1176,7 @@ namespace direct_bt {
* @param listener A {@link BTGattCharListener} instance
* @return true if the given listener is an element of the list and has been removed, otherwise false.
*/
- bool removeCharListener(std::shared_ptr<BTGattCharListener> l) noexcept;
+ bool removeCharListener(const BTGattCharListenerRef& l) noexcept;
/**
* Remove all {@link BTGattCharListener} from the list, which are associated to the given {@link BTGattChar}.
@@ -1182,7 +1187,7 @@ namespace direct_bt {
* @param associatedCharacteristic the match criteria to remove any BTGattCharListener from the list
* @return number of removed listener.
*/
- int removeAllAssociatedCharListener(std::shared_ptr<BTGattChar> associatedCharacteristic) noexcept;
+ int removeAllAssociatedCharListener(const BTGattCharRef& associatedCharacteristic) noexcept;
int removeAllAssociatedCharListener(const BTGattChar * associatedCharacteristic) noexcept;
diff --git a/api/direct_bt/BTGattChar.hpp b/api/direct_bt/BTGattChar.hpp
index 8882778a..43727dfb 100644
--- a/api/direct_bt/BTGattChar.hpp
+++ b/api/direct_bt/BTGattChar.hpp
@@ -57,9 +57,17 @@
namespace direct_bt {
class BTGattHandler; // forward
+ typedef std::shared_ptr<BTGattHandler> BTGattHandlerRef;
+
+ class BTDevice; // forward
+ typedef std::shared_ptr<BTDevice> BTDeviceRef;
+
class BTGattService; // forward
typedef std::shared_ptr<BTGattService> BTGattServiceRef;
+ class BTGattCharListener; // forward
+ typedef std::shared_ptr<BTGattCharListener> BTGattCharListenerRef;
+
/**
* Representing a Gatt Characteristic object from the ::GATTRole::Client perspective.
*
@@ -96,61 +104,6 @@ namespace direct_bt {
};
/**
- * {@link BTGattChar} event listener for notification and indication events.
- * <p>
- * This listener instance is attached to a BTGattChar via
- * {@link BTGattChar::addCharListener(std::shared_ptr<BTGattChar::Listener>)} or
- * {@link BTGattChar::addCharListener(std::shared_ptr<BTGattChar::Listener>, bool[])}
- * to listen to events associated with the BTGattChar instance.
- * </p>
- * <p>
- * The listener manager maintains a unique set of listener instances without duplicates.
- * </p>
- * <p>
- * Implementation will utilize a BTGattCharListener instance for the listener manager,
- * delegating matching BTGattChar events to this instance.
- * </p>
- */
- class Listener {
- public:
- /**
- * Called from native BLE stack, initiated by a received notification associated
- * with the given {@link BTGattChar}.
- * @param charDecl {@link BTGattChar} related to this notification
- * @param charValue the notification value
- * @param timestamp monotonic timestamp at reception, jau::getCurrentMilliseconds()
- */
- virtual void notificationReceived(BTGattCharRef charDecl,
- const jau::TROOctets& charValue, const uint64_t timestamp) = 0;
-
- /**
- * Called from native BLE stack, initiated by a received indication associated
- * with the given {@link BTGattChar}.
- * @param charDecl {@link BTGattChar} related to this indication
- * @param charValue the indication value
- * @param timestamp monotonic timestamp at reception, see jau::getCurrentMilliseconds()
- * @param confirmationSent if true, the native stack has sent the confirmation, otherwise user is required to do so.
- */
- virtual void indicationReceived(BTGattCharRef charDecl,
- const jau::TROOctets& charValue, const uint64_t timestamp,
- const bool confirmationSent) = 0;
-
- virtual ~Listener() noexcept {}
-
- /**
- * Default comparison operator, merely testing for same memory reference.
- * <p>
- * Specializations may override.
- * </p>
- */
- virtual bool operator==(const Listener& rhs) const noexcept
- { return this == &rhs; }
-
- bool operator!=(const Listener& rhs) const noexcept
- { return !(*this == rhs); }
- };
-
- /**
* Characteristic Handle of this instance.
* <p>
* Attribute handles are unique for each device (server) (BT Core Spec v5.2: Vol 3, Part F Protocol..: 3.2.2 Attribute Handle).
@@ -193,9 +146,9 @@ namespace direct_bt {
return std::string(JAVA_DBT_PACKAGE "DBTGattChar");
}
- std::shared_ptr<BTGattService> getServiceUnchecked() const noexcept { return wbr_service.lock(); }
- std::shared_ptr<BTGattHandler> getGattHandlerUnchecked() const noexcept;
- std::shared_ptr<BTDevice> getDeviceUnchecked() const noexcept;
+ BTGattServiceRef getServiceUnchecked() const noexcept { return wbr_service.lock(); }
+ BTGattHandlerRef getGattHandlerUnchecked() const noexcept;
+ BTDeviceRef getDeviceUnchecked() const noexcept;
bool hasProperties(const PropertyBitVal v) const noexcept { return v == ( properties & v ); }
@@ -305,18 +258,15 @@ namespace direct_bt {
bool disableIndicationNotification() noexcept;
/**
- * Add the given BTGattChar::Listener to the listener list if not already present.
+ * Add the given BTGattCharListener to the listener list if not already present.
*
* Occurring notifications and indications for this characteristic,
* if enabled via configNotificationIndication(bool, bool, bool[]) or enableNotificationOrIndication(bool[]),
- * will call the respective BTGattChar::Listener callback method.
+ * will call the respective BTGattCharListener callback method.
*
* Returns true if the given listener is not element of the list and has been newly added,
* otherwise false.
*
- * Implementation wraps given BTGattChar::Listener into an AssociatedBTGattCharListener
- * to restrict the listener to listen only to this BTGattChar instance.
- *
* Convenience delegation call to BTGattHandler via BTDevice
*
* @see BTGattChar::disableIndicationNotification()
@@ -326,10 +276,10 @@ namespace direct_bt {
* @see BTGattChar::removeCharListener()
* @see BTGattChar::removeAllAssociatedCharListener()
*/
- bool addCharListener(std::shared_ptr<Listener> l) noexcept;
+ bool addCharListener(const BTGattCharListenerRef& l) noexcept;
/**
- * Add the given BTGattChar::Listener to the listener list if not already present
+ * Add the given BTGattCharListener to the listener list if not already present
* and if enabling the notification <i>or</i> indication for this characteristic at BLE level was successful.<br>
* Notification and/or indication configuration is only performed per characteristic if changed.
*
@@ -338,15 +288,12 @@ namespace direct_bt {
* Implementation uses enableNotificationOrIndication(bool[]) to enable either.
*
* Occurring notifications and indications for this characteristic
- * will call the respective BTGattChar::Listener callback method.
+ * will call the respective BTGattCharListener callback method.
*
* Returns 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.
*
- * Implementation wraps given BTGattChar::Listener into an AssociatedBTGattCharListener
- * to restrict the listener to listen only to this BTGattChar instance.
- *
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication
* using enableNotificationOrIndication(bool[])
*
@@ -357,10 +304,10 @@ namespace direct_bt {
* @see BTGattChar::removeCharListener()
* @see BTGattChar::removeAllAssociatedCharListener()
*/
- bool addCharListener(std::shared_ptr<Listener> l, bool enabledState[2]) noexcept;
+ bool addCharListener(const BTGattCharListenerRef& l, bool enabledState[2]) noexcept;
/**
- * Remove the given associated BTGattChar::Listener from the listener list if present.
+ * Remove the given associated BTGattCharListener from the listener list if present.
*
* To disables the notification and/or indication for this characteristic at BLE level
* use disableIndicationNotification() when desired.
@@ -376,10 +323,10 @@ namespace direct_bt {
* @see BTGattChar::removeAllAssociatedCharListener()
* @since 2.4.0
*/
- bool removeCharListener(std::shared_ptr<Listener> l) noexcept;
+ bool removeCharListener(const BTGattCharListenerRef& l) noexcept;
/**
- * Removes all associated BTGattChar::Listener and and {@link BTGattCharListener} from the listener list.
+ * Removes all associated BTGattCharListener and and {@link BTGattCharListener} from the listener list.
*
* Also disables the notification and/or indication for this characteristic at BLE level
* if `disableIndicationNotification == true`.
@@ -475,21 +422,18 @@ namespace direct_bt {
* {@link BTGattChar} event listener for notification and indication events.
* <p>
* A listener instance may be attached to a BTGattChar instance via
- * {@link BTGattChar::addCharListener(std::shared_ptr<BTGattChar::Listener>)} to listen to its events.
+ * {@link BTGattChar::addCharListener(BTGattCharListenerRef)} to listen to its events.
* </p>
* <p>
* A listener instance may be attached to a BTGattHandler via
- * {@link BTGattHandler::addCharListener(std::shared_ptr<BTGattCharListener>)}
+ * {@link BTGattHandler::addCharListener(BTGattCharListenerRef)}
* to listen to all events of the device or the matching filtered events.
* </p>
* <p>
- * User may utilize {@link AssociatedBTGattCharListener} to listen to only one {@link BTGattChar}.
- * </p>
- * <p>
* The listener manager maintains a unique set of listener instances without duplicates.
* </p>
*/
- class BTGattCharListener {
+ class BTGattCharListener : public jau::JavaUplink {
public:
/**
* Returns a unique string denominating the type of this instance.
@@ -500,22 +444,6 @@ namespace direct_bt {
virtual const char * type_name() const noexcept;
/**
- * Custom filter for all event methods,
- * which will not be called if this method returns false.
- * <p>
- * User may override this method to test whether the methods shall be called
- * for the given BTGattChar.
- * </p>
- * <p>
- * Defaults to true;
- * </p>
- */
- virtual bool match(const BTGattChar & characteristic) noexcept {
- (void)characteristic;
- return true;
- }
-
- /**
* Called from native BLE stack, initiated by a received notification associated
* with the given {@link BTGattChar}.
* @param charDecl {@link BTGattChar} related to this notification
@@ -537,13 +465,20 @@ namespace direct_bt {
const jau::TROOctets& charValue, const uint64_t timestamp,
const bool confirmationSent) = 0;
- virtual ~BTGattCharListener() noexcept {}
+ ~BTGattCharListener() noexcept override {}
/** Return a simple description about this instance. */
- virtual std::string toString() {
+ std::string toString() const noexcept override {
return std::string(type_name())+"["+jau::to_string(this)+"]";
}
+ std::string get_java_class() const noexcept override {
+ return java_class();
+ }
+ static std::string java_class() noexcept {
+ return std::string(JAVA_MAIN_PACKAGE "BTGattCharListener");
+ }
+
/**
* Default comparison operator, merely testing for same memory reference.
* <p>
@@ -558,27 +493,6 @@ namespace direct_bt {
};
typedef std::shared_ptr<BTGattCharListener> BTGattCharListenerRef;
- class AssociatedBTGattCharListener : public BTGattCharListener {
- private:
- const BTGattChar * associatedChar;
-
- public:
- /**
- * Passing the associated BTGattChar to filter out non matching events.
- */
- AssociatedBTGattCharListener(const BTGattChar * characteristicMatch) noexcept
- : associatedChar(characteristicMatch) { }
-
- const char * type_name() const noexcept override;
-
- bool match(const BTGattChar & characteristic) noexcept override {
- if( nullptr == associatedChar ) {
- return true;
- }
- return *associatedChar == characteristic;
- }
- };
-
} // namespace direct_bt
#endif /* BT_GATT_CHARACTERISTIC_HPP_ */
diff --git a/api/direct_bt/BTGattCmd.hpp b/api/direct_bt/BTGattCmd.hpp
index 80bda1d8..275968df 100644
--- a/api/direct_bt/BTGattCmd.hpp
+++ b/api/direct_bt/BTGattCmd.hpp
@@ -78,7 +78,7 @@ namespace direct_bt {
BTGattCharRef rspCharRef;
bool setup_done;
- class ResponseCharListener : public BTGattChar::Listener {
+ class ResponseCharListener : public BTGattCharListener {
private:
BTGattCmd& source;
jau::POctets& rsp_data;
diff --git a/api/direct_bt/BTGattHandler.hpp b/api/direct_bt/BTGattHandler.hpp
index 549ff5d3..4dc08c9e 100644
--- a/api/direct_bt/BTGattHandler.hpp
+++ b/api/direct_bt/BTGattHandler.hpp
@@ -438,8 +438,6 @@ namespace direct_bt {
typedef jau::cow_darray<NativeGattCharListenerRef> NativeGattCharListenerList_t;
typedef jau::darray<NativeGattCharListener::Section> NativeGattCharSections_t;
- typedef jau::cow_darray<BTGattCharListenerRef> BTGattCharListenerList_t;
-
private:
/** BTGattHandler's device weak back-reference */
std::weak_ptr<BTDevice> wbr_device;
@@ -462,7 +460,26 @@ namespace direct_bt {
/** send immediate confirmation of indication events from device, defaults to true. */
jau::relaxed_atomic_bool sendIndicationConfirmation = true;
- BTGattCharListenerList_t btGattCharListenerList;
+
+ struct GattCharListenerPair {
+ /** The actual listener */
+ BTGattCharListenerRef listener;
+ /** The optional weak device reference. Weak, b/c it shall not block destruction */
+ std::weak_ptr<BTGattChar> wbr_characteristic;
+
+ bool match(const BTGattChar& characteristic) const noexcept {
+ BTGattCharRef sda = wbr_characteristic.lock();
+ if( nullptr != sda ) {
+ return *sda == characteristic;
+ } else {
+ return true;
+ }
+ }
+ };
+ typedef jau::cow_darray<GattCharListenerPair> gattCharListenerList_t;
+ static gattCharListenerList_t::equal_comparator gattCharListenerRefEqComparator;
+ gattCharListenerList_t gattCharListenerList;
+
NativeGattCharListenerList_t nativeGattCharListenerList;
/** Pass through user Gatt-Server database, non-nullptr if ::GATTRole::Server */
@@ -811,6 +828,11 @@ namespace direct_bt {
bool addCharListener(const BTGattCharListenerRef& l) noexcept;
/**
+ * Please use BTGattChar::addCharListener() for clarity, merely existing here to allow JNI access.
+ */
+ bool addCharListener(const BTGattCharListenerRef& l, const BTGattCharRef& d) noexcept;
+
+ /**
* Remove the given listener from the list.
* <p>
* Returns true if the given listener is an element of the list and has been removed,
@@ -829,11 +851,9 @@ namespace direct_bt {
bool removeCharListener(const BTGattCharListener * l) noexcept;
/**
- * Remove all {@link BTGattCharListener} from the list, which are associated to the given {@link BTGattChar}.
- * <p>
- * Implementation tests all listener's BTGattCharListener::match(const BTGattChar & characteristic)
- * to match with the given associated characteristic.
- * </p>
+ * Remove all {@link BTGattCharListener} from the list, which are associated to the given {@link BTGattChar}
+ * when added via BTGattChar::addCharListener().
+ *
* @param associatedCharacteristic the match criteria to remove any BTGattCharListener from the list
* @return number of removed listener.
*/
@@ -870,17 +890,7 @@ namespace direct_bt {
/**
* Return event listener count.
*/
- jau::nsize_t getCharListenerCount() const noexcept { return btGattCharListenerList.size() + nativeGattCharListenerList.size(); }
-
- /**
- * Return a thread safe snapshot of the BTGattCharListener array
- */
- BTGattCharListenerList_t::storage_ref_t getBTGattCharListener() const noexcept { return btGattCharListenerList.snapshot(); }
-
- /**
- * Return a thread safe snapshot of the NativeGattCharListener array
- */
- NativeGattCharListenerList_t::storage_ref_t getNativeGattCharListener() const noexcept { return nativeGattCharListenerList.snapshot(); }
+ jau::nsize_t getCharListenerCount() const noexcept { return gattCharListenerList.size() + nativeGattCharListenerList.size(); }
/**
* Print a list of all BTGattCharListener and NativeGattCharListener.
@@ -1011,6 +1021,7 @@ namespace direct_bt {
std::string toString() const noexcept;
};
+ typedef std::shared_ptr<BTGattHandler> BTGattHandlerRef;
} // namespace direct_bt
diff --git a/api/direct_bt/BTGattService.hpp b/api/direct_bt/BTGattService.hpp
index 4feef69b..f4e6006b 100644
--- a/api/direct_bt/BTGattService.hpp
+++ b/api/direct_bt/BTGattService.hpp
@@ -57,7 +57,10 @@
namespace direct_bt {
class BTGattHandler; // forward
+ typedef std::shared_ptr<BTGattHandler> BTGattHandlerRef;
+
class BTDevice; // forward
+ typedef std::shared_ptr<BTDevice> BTDeviceRef;
/**
* Representing a Gatt Service object from the ::GATTRole::Client perspective.
@@ -113,11 +116,11 @@ namespace direct_bt {
return std::string(JAVA_DBT_PACKAGE "DBTGattService");
}
- std::shared_ptr<BTGattHandler> getGattHandlerUnchecked() const noexcept { return wbr_handler.lock(); }
- std::shared_ptr<BTGattHandler> getGattHandlerChecked() const;
+ BTGattHandlerRef getGattHandlerUnchecked() const noexcept { return wbr_handler.lock(); }
+ BTGattHandlerRef getGattHandlerChecked() const;
- std::shared_ptr<BTDevice> getDeviceUnchecked() const noexcept;
- std::shared_ptr<BTDevice> getDeviceChecked() const;
+ BTDeviceRef getDeviceUnchecked() const noexcept;
+ BTDeviceRef getDeviceChecked() const;
/**
* Find a BTGattChar by its char_uuid.
@@ -125,10 +128,19 @@ namespace direct_bt {
* @parameter char_uuid the jau::uuid_t of the desired BTGattChar, within this BTGattService.
* @return The matching characteristic or null if not found
*/
- std::shared_ptr<BTGattChar> findGattChar(const jau::uuid_t& char_uuid) noexcept;
+ BTGattCharRef findGattChar(const jau::uuid_t& char_uuid) noexcept;
+
+ /**
+ * Find a BTGattChar by itself, i.e. mapping BTGattChar instance to BTGattCharRef.
+ *
+ * @parameter characteristic the desired BTGattChar, within this BTGattService.
+ * @return The matching characteristic or null if not found
+ */
+ BTGattCharRef findGattChar(const BTGattChar& characteristic) noexcept;
std::string toString() const noexcept override;
};
+ typedef std::shared_ptr<BTGattService> BTGattServiceRef;
inline bool operator==(const BTGattService& lhs, const BTGattService& rhs) noexcept
{ return lhs.handle == rhs.handle && lhs.end_handle == rhs.end_handle; /** unique attribute handles */ }
diff --git a/examples/dbt_scanner10.cpp b/examples/dbt_scanner10.cpp
index b6db78b3..c3e28dad 100644
--- a/examples/dbt_scanner10.cpp
+++ b/examples/dbt_scanner10.cpp
@@ -324,7 +324,7 @@ class MyAdapterStatusListener : public AdapterStatusListener {
static const uuid16_t _TEMPERATURE_MEASUREMENT(GattCharacteristicType::TEMPERATURE_MEASUREMENT);
-class MyGATTEventListener : public BTGattChar::Listener {
+class MyGATTEventListener : public BTGattCharListener {
private:
int i, j;
@@ -559,8 +559,7 @@ static void processReadyDevice(BTDeviceRef device) {
bool cccdEnableResult[2];
if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
// ClientCharConfigDescriptor (CCD) is available
- std::shared_ptr<BTGattChar::Listener> cl = std::make_shared<MyGATTEventListener>(i, j);
- bool clAdded = serviceChar->addCharListener( cl );
+ bool clAdded = serviceChar->addCharListener( std::make_shared<MyGATTEventListener>(i, j) );
{
fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
(int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java
index 2845f9e0..98be7aea 100644
--- a/examples/java/DBTScanner10.java
+++ b/examples/java/DBTScanner10.java
@@ -39,6 +39,7 @@ import org.direct_bt.BTDeviceRegistry;
import org.direct_bt.BTException;
import org.direct_bt.BTFactory;
import org.direct_bt.BTGattChar;
+import org.direct_bt.BTGattCharListener;
import org.direct_bt.BTGattCmd;
import org.direct_bt.BTGattDesc;
import org.direct_bt.BTGattService;
@@ -277,7 +278,7 @@ public class DBTScanner10 {
}
};
- class MyGATTEventListener implements BTGattChar.Listener {
+ class MyGATTEventListener extends BTGattCharListener {
private final int i, j;
public MyGATTEventListener(final int i_, final int j_) { i=i_; j=j_; }
@@ -518,7 +519,7 @@ public class DBTScanner10 {
final boolean cccdEnableResult[] = { false, false };
if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
// ClientCharConfigDescriptor (CCD) is available
- final boolean clAdded = null != serviceChar.addCharListener( new MyGATTEventListener(i, j) );
+ final boolean clAdded = serviceChar.addCharListener( new MyGATTEventListener(i, j) );
{
BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
diff --git a/java/jau/direct_bt/DBTDevice.java b/java/jau/direct_bt/DBTDevice.java
index eb596a6a..1184b808 100644
--- a/java/jau/direct_bt/DBTDevice.java
+++ b/java/jau/direct_bt/DBTDevice.java
@@ -669,9 +669,14 @@ public class DBTDevice extends DBTObject implements BTDevice
@Override
public boolean addCharListener(final BTGattCharListener listener) {
- return addCharListener(listener, (DBTGattChar)listener.getAssociatedChar());
+ return addCharListenerImpl(listener, null);
}
- private native boolean addCharListener(final BTGattCharListener listener, final DBTGattChar associatedCharacteristic);
+
+ @Override
+ public boolean addCharListener(final BTGattCharListener listener, final BTGattChar associatedCharacteristic) {
+ return addCharListenerImpl(listener, associatedCharacteristic);
+ }
+ private native boolean addCharListenerImpl(final BTGattCharListener listener, final BTGattChar associatedCharacteristic);
@Override
public native boolean removeCharListener(final BTGattCharListener l);
diff --git a/java/jau/direct_bt/DBTGattChar.java b/java/jau/direct_bt/DBTGattChar.java
index 334b1b45..afa9c7d4 100644
--- a/java/jau/direct_bt/DBTGattChar.java
+++ b/java/jau/direct_bt/DBTGattChar.java
@@ -97,7 +97,7 @@ public class DBTGattChar extends DBTObject implements BTGattChar
final boolean hasIndicate = properties.isSet(GattCharPropertySet.Type.Indicate);
if( hasNotify || hasIndicate ) {
- final Listener characteristicListener = new Listener() {
+ final BTGattCharListener characteristicListener = new BTGattCharListener() {
@Override
public void notificationReceived(final BTGattChar charDecl, final byte[] value, final long timestamp) {
System.err.println("GATTCharacteristicListener.notificationReceived: "+charDecl+
@@ -243,38 +243,15 @@ public class DBTGattChar extends DBTObject implements BTGattChar
return configNotificationIndication(false /* enableNotification */, false /* enableIndication */, new boolean[2]);
}
- static private class DelegatedBTGattCharListener extends BTGattCharListener {
- private final Listener delegate;
-
- public DelegatedBTGattCharListener(final BTGattChar characteristicMatch, final Listener l) {
- super(characteristicMatch);
- delegate = l;
- }
-
- @Override
- public void notificationReceived(final BTGattChar charDecl,
- final byte[] value, final long timestamp) {
- delegate.notificationReceived(charDecl, value, timestamp);
- }
-
- @Override
- public void indicationReceived(final BTGattChar charDecl,
- final byte[] value, final long timestamp,
- final boolean confirmationSent) {
- delegate.indicationReceived(charDecl, value, timestamp, confirmationSent);
- }
- };
-
@Override
- public final BTGattCharListener addCharListener(final Listener listener) {
- final BTGattCharListener wl = new DelegatedBTGattCharListener(this, listener);
- return getService().getDevice().addCharListener( wl ) ? wl : null;
+ public final boolean addCharListener(final BTGattCharListener listener) {
+ return getService().getDevice().addCharListener( listener, this );
}
@Override
- public final BTGattCharListener addCharListener(final Listener listener, final boolean enabledState[/*2*/]) {
+ public final boolean addCharListener(final BTGattCharListener listener, final boolean enabledState[/*2*/]) {
if( !enableNotificationOrIndication(enabledState) ) {
- return null;
+ return false;
}
return addCharListener( listener );
}
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
index 7ea95178..7c509f90 100644
--- a/java/jni/direct_bt/DBTAdapter.cxx
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -509,7 +509,7 @@ jboolean Java_jau_direct_1bt_DBTAdapter_addStatusListenerImpl(JNIEnv *env, jobje
if( addRes ) {
return JNI_TRUE;
}
- ERR_PRINT("JNIAdapterStatusListener::addStatusListener: FAILED: %s", asl->toString().c_str());
+ ERR_PRINT("BTAdapter::addStatusListener: FAILED: %s", asl->toString().c_str());
} catch(...) {
rethrow_and_raise_java_exception(env);
}
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index 86d940f9..dcd73336 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -24,6 +24,7 @@
*/
#include "jau_direct_bt_DBTDevice.h"
+#include "org_direct_bt_BTGattCharListener.h"
// #define VERBOSE_ON 1
#include <jau/debug.hpp>
@@ -46,8 +47,6 @@ class JNIGattCharListener : public BTGattCharListener {
private:
/**
public abstract class BTGattCharListener {
- long nativeInstance;
-
public void notificationReceived(final BTGattChar charDecl,
final byte[] value, final long timestamp) {
}
@@ -59,17 +58,14 @@ class JNIGattCharListener : public BTGattCharListener {
};
*/
- std::shared_ptr<BTGattChar> associatedCharacteristicRef;
JNIGlobalRef listenerObj; // keep listener instance alive
- JNIGlobalRef associatedCharacteristicObj; // keeps associated characteristic alive, if not null
jmethodID mNotificationReceived = nullptr;
jmethodID mIndicationReceived = nullptr;
public:
- JNIGattCharListener(JNIEnv *env, const std::shared_ptr<BTDevice>& device, jobject listener, const std::shared_ptr<BTGattChar>& associatedCharacteristicRef_)
- : associatedCharacteristicRef(associatedCharacteristicRef_),
- listenerObj(listener)
+ JNIGattCharListener(JNIEnv *env, jobject listener)
+ : listenerObj(listener)
{
jclass listenerClazz = search_class(env, listenerObj.getObject());
java_exception_check_and_throw(env, E_FILE_LINE);
@@ -77,28 +73,11 @@ class JNIGattCharListener : public BTGattCharListener {
throw InternalError("BTGattCharListener not found", E_FILE_LINE);
}
- if( nullptr != associatedCharacteristicRef_ ) {
- JavaGlobalObj::check(associatedCharacteristicRef_->getJavaObject(), E_FILE_LINE);
- associatedCharacteristicObj = JavaGlobalObj::GetJavaObject(associatedCharacteristicRef_->getJavaObject()); // new global ref
- }
-
mNotificationReceived = search_method(env, listenerClazz, "notificationReceived", _notificationReceivedMethodArgs.c_str(), false);
java_exception_check_and_throw(env, E_FILE_LINE);
- if( nullptr == mNotificationReceived ) {
- throw InternalError("BTGattCharListener has no notificationReceived"+_notificationReceivedMethodArgs+" method, for "+device->toString(), E_FILE_LINE);
- }
+
mIndicationReceived = search_method(env, listenerClazz, "indicationReceived", _indicationReceivedMethodArgs.c_str(), false);
java_exception_check_and_throw(env, E_FILE_LINE);
- if( nullptr == mNotificationReceived ) {
- throw InternalError("BTGattCharListener has no indicationReceived"+_indicationReceivedMethodArgs+" method, for "+device->toString(), E_FILE_LINE);
- }
- }
-
- bool match(const BTGattChar & characteristic) noexcept override {
- if( nullptr == associatedCharacteristicRef ) {
- return true;
- }
- return characteristic == *associatedCharacteristicRef;
}
void notificationReceived(BTGattCharRef charDecl,
@@ -143,6 +122,41 @@ class JNIGattCharListener : public BTGattCharListener {
}
};
+/*
+ * Class: org_direct_bt_BTGattCharListener
+ * Method: ctorImpl
+ * Signature: ()J
+ */
+jlong Java_org_direct_1bt_BTGattCharListener_ctorImpl(JNIEnv *env, jobject obj) {
+ try {
+ // new instance
+ jau::shared_ptr_ref<JNIGattCharListener> ref( new JNIGattCharListener(env, obj) );
+
+ return ref.release_to_jlong();
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return (jlong) (intptr_t) nullptr;
+}
+
+
+/*
+ * Class: org_direct_bt_BTGattCharListener
+ * Method: deleteImpl
+ * Signature: (J)V
+ */
+void Java_org_direct_1bt_BTGattCharListener_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance) {
+ (void)obj;
+ try {
+ jau::shared_ptr_ref<JNIGattCharListener> sref(nativeInstance, false /* throw_on_nullptr */); // hold copy until done
+ if( nullptr != sref.pointer() ) {
+ std::shared_ptr<JNIGattCharListener>* sref_ptr = jau::castInstance<JNIGattCharListener>(nativeInstance);
+ delete sref_ptr;
+ }
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+}
void Java_jau_direct_1bt_DBTDevice_deleteImpl(JNIEnv *env, jobject obj, jlong nativeInstance)
{
@@ -201,35 +215,42 @@ jstring Java_jau_direct_1bt_DBTDevice_toStringImpl(JNIEnv *env, jobject obj) {
return nullptr;
}
-jboolean Java_jau_direct_1bt_DBTDevice_addCharListener(JNIEnv *env, jobject obj, jobject listener, jobject jAssociatedCharacteristic) {
+/*
+ * Class: jau_direct_bt_DBTDevice
+ * Method: addCharListenerImpl
+ * Signature: (Lorg/direct_bt/BTGattCharListener;Lorg/direct_bt/BTGattChar;)Z
+ */
+jboolean Java_jau_direct_1bt_DBTDevice_addCharListenerImpl(JNIEnv *env, jobject obj, jobject jlistener, jobject jAssociatedCharacteristic) {
try {
shared_ptr_ref<BTDevice> device(env, obj); // hold until done
jau::JavaAnonRef device_java = device->getJavaObject(); // hold until done!
JavaGlobalObj::check(device_java, E_FILE_LINE);
- if( nullptr == listener ) {
- throw IllegalArgumentException("BTGattCharListener argument is null", E_FILE_LINE);
- }
- {
- std::shared_ptr<JNIGattCharListener>* pre_orig = jau::getInstance<JNIGattCharListener>(env, listener, false /* throw_on_nullptr */);
- if( !( nullptr == pre_orig || nullptr == *pre_orig ) ) {
- throw IllegalStateException("BTGattCharListener's nativeInstance not null, already in use", E_FILE_LINE);
- return false;
- }
+ jau::shared_ptr_ref<JNIGattCharListener> gcl(env, jlistener); // hold until done
+ jau::JavaAnonRef gcl_java = gcl->getJavaObject(); // hold until done!
+ jau::JavaGlobalObj::check(gcl_java, E_FILE_LINE);
+
+ jau::shared_ptr_ref<BTGattChar> charMatchRef(env, jAssociatedCharacteristic, false /* throw_on_nullptr */);
+ if( !charMatchRef.is_null() ) {
+ jau::JavaGlobalObj::check(charMatchRef->getJavaObject(), E_FILE_LINE);
}
+
std::shared_ptr<BTGattHandler> gatt = device->getGattHandler();
if( nullptr == gatt ) {
- throw IllegalStateException("BTGattChar's device GATTHandle not connected: "+ device->toString(), E_FILE_LINE);
+ ERR_PRINT("BTGattChar's device GATTHandle not connected: %s", device->toString().c_str());
+ return false;
}
- jau::shared_ptr_ref<BTGattChar> associatedCharacteristicRef(env, jAssociatedCharacteristic, false /* throw_on_nullptr */);
-
- shared_ptr_ref<JNIGattCharListener> l(
- new JNIGattCharListener(env, device.shared_ptr(), listener, associatedCharacteristicRef.shared_ptr()) );
- if( gatt->addCharListener( l.shared_ptr() ) ) {
- l.release_into_object(env, listener);
+ bool addRes;
+ if( !charMatchRef.is_null() ) {
+ addRes = gatt->addCharListener( gcl.shared_ptr(), charMatchRef.shared_ptr() );
+ } else {
+ addRes = gatt->addCharListener( gcl.shared_ptr() );
+ }
+ if( addRes ) {
return JNI_TRUE;
}
+ ERR_PRINT("BTDevice::addCharListener: FAILED: %s", gcl->toString().c_str());
} catch(...) {
rethrow_and_raise_java_exception(env);
}
@@ -246,15 +267,9 @@ jboolean Java_jau_direct_1bt_DBTDevice_removeCharListener(JNIEnv *env, jobject o
jau::JavaAnonRef device_java = device->getJavaObject(); // hold until done!
JavaGlobalObj::check(device_java, E_FILE_LINE);
- if( nullptr == jlistener ) {
- throw IllegalArgumentException("BTGattCharListener argument is null", E_FILE_LINE);
- }
- shared_ptr_ref<JNIGattCharListener> pre( env, jlistener, false /* throw_on_nullptr */ ); // hold until done
- if( pre.is_null() ) {
- WARN_PRINT("BTGattCharListener's nativeInstance is null, not in use");
- return false;
- }
- jau::clearInstance<JNIGattCharListener>(env, jlistener);
+ jau::shared_ptr_ref<JNIGattCharListener> gcl(env, jlistener); // hold until done
+ jau::JavaAnonRef gcl_java = gcl->getJavaObject(); // hold until done!
+ jau::JavaGlobalObj::check(gcl_java, E_FILE_LINE);
std::shared_ptr<BTGattHandler> gatt = device->getGattHandler();
if( nullptr == gatt ) {
@@ -263,8 +278,8 @@ jboolean Java_jau_direct_1bt_DBTDevice_removeCharListener(JNIEnv *env, jobject o
return false;
}
- if( ! gatt->removeCharListener(pre.shared_ptr()) ) {
- WARN_PRINT("Failed to remove BTGattCharListener with nativeInstance: %p at %s", pre.shared_ptr().get(), device->toString().c_str());
+ if( ! gatt->removeCharListener(gcl.shared_ptr()) ) {
+ WARN_PRINT("Failed to remove BTGattCharListener with nativeInstance: %p at %s", gcl.shared_ptr().get(), device->toString().c_str());
return false;
}
return true;
diff --git a/java/org/direct_bt/AdapterStatusListener.java b/java/org/direct_bt/AdapterStatusListener.java
index 5f5e348f..6966c640 100644
--- a/java/org/direct_bt/AdapterStatusListener.java
+++ b/java/org/direct_bt/AdapterStatusListener.java
@@ -39,6 +39,9 @@ import jau.direct_bt.DBTNativeDownlink;
* A listener instance may be attached to a {@link BTAdapter} via
* {@link BTAdapter#addStatusListener(AdapterStatusListener, BTDevice)}.
* </p>
+ * <p>
+ * The listener receiver maintains a unique set of listener instances without duplicates.
+ * </p>
* @since 2.0.0
*/
public abstract class AdapterStatusListener extends DBTNativeDownlink {
diff --git a/java/org/direct_bt/BTDevice.java b/java/org/direct_bt/BTDevice.java
index 4894b04a..efa640f0 100644
--- a/java/org/direct_bt/BTDevice.java
+++ b/java/org/direct_bt/BTDevice.java
@@ -917,14 +917,16 @@ public interface BTDevice extends BTObject
* </p>
* @param listener A {@link BTGattCharListener} instance, listening to all {@link BTGattChar} 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 BTDevice}'s BTGattHandler is null, i.e. not connected
- * @throws IllegalStateException if the given {@link BTGattCharListener} is already in use, i.e. added.
* @see BTGattChar#configNotificationIndication(boolean, boolean, boolean[])
* @see BTGattChar#enableNotificationOrIndication(boolean[])
* @since 2.0.0
*/
- boolean addCharListener(final BTGattCharListener listener)
- throws IllegalStateException;
+ boolean addCharListener(final BTGattCharListener listener);
+
+ /**
+ * Please use {@link BTGattChar#addCharListener(BTGattCharListener)} for clarity.
+ */
+ boolean addCharListener(final BTGattCharListener listener, final BTGattChar associatedCharacteristic);
/**
* Remove the given {@link BTGattCharListener} from the listener list.
diff --git a/java/org/direct_bt/BTGattChar.java b/java/org/direct_bt/BTGattChar.java
index 62cd8653..bb185da7 100644
--- a/java/org/direct_bt/BTGattChar.java
+++ b/java/org/direct_bt/BTGattChar.java
@@ -45,45 +45,6 @@ import java.util.List;
public interface BTGattChar extends BTObject
{
/**
- * {@link BTGattChar} event listener for notification and indication events.
- * <p>
- * This listener instance is attached to a {@link BTGattChar} via
- * {@link BTGattChar#addCharListener(Listener)} or {@link BTGattChar#addCharListener(Listener, boolean[])}
- * to listen to events associated with the {@link BTGattChar} instance.
- * </p>
- * <p>
- * The listener manager maintains a unique set of listener instances without duplicates.
- * </p>
- * <p>
- * Implementation will utilize a {@link BTGattCharListener) for the listener manager,
- * delegating matching {@link BTGattChar} events to this instance.
- * </p>
- */
- static public interface Listener {
- /**
- * Called from native BLE stack, initiated by a received notification associated
- * with the given {@link BTGattChar}.
- * @param charDecl {@link BTGattChar} related to this notification
- * @param value the notification value
- * @param timestamp monotonic timestamp at reception, see {@link BTUtils#currentTimeMillis()}
- */
- void notificationReceived(final BTGattChar charDecl,
- final byte[] value, final long timestamp);
-
- /**
- * Called from native BLE stack, initiated by a received indication associated
- * with the given {@link BTGattChar}.
- * @param charDecl {@link BTGattChar} related to this indication
- * @param value the indication value
- * @param timestamp monotonic timestamp at reception, see {@link BTUtils#currentTimeMillis()}
- * @param confirmationSent if true, the native stack has sent the confirmation, otherwise user is required to do so.
- */
- void indicationReceived(final BTGattChar charDecl,
- final byte[] value, final long timestamp,
- final boolean confirmationSent);
- };
-
- /**
* Find a {@link BTGattDesc} by its desc_uuid.
*
* @parameter desc_uuid the UUID of the desired {@link BTGattDesc}
@@ -133,8 +94,9 @@ public interface BTGattChar extends BTObject
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.0.0
*/
@@ -163,8 +125,9 @@ public interface BTGattChar extends BTObject
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.0.0
*/
@@ -188,43 +151,41 @@ public interface BTGattChar extends BTObject
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.4.0
*/
boolean disableIndicationNotification() throws IllegalStateException;
/**
- * Add the given {@link BTGattChar.Listener} to the listener list if not already present.
+ * Add the given BTGattCharListener to the listener list if not already present.
*
* Occurring notifications and indications for this characteristic,
* if enabled via {@link #configNotificationIndication(boolean, boolean, boolean[])}
* or {@link #enableNotificationOrIndication(boolean[])},
- * will call the respective {@link BTGattChar.Listener} callback method.
- *
- * Implementation wraps given {@link BTGattChar.Listener} into a {@link BTGattCharListener}
- * to restrict the listener to listen only to this BTGattChar instance.
+ * will call the respective BTGattCharListener callback method.
*
- * {@link #removeCharListener(BTGattCharListener)} must be utilized with the returned {@link BTGattCharListener}.
+ * Returns true if the given listener is not element of the list and has been newly added,
+ * otherwise false.
*
- * @param listener A {@link BTGattChar.Listener} instance, listening to this {@link BTGattChar}'s events
- * @return if successful, {@link BTGattCharListener} instance wrapping the given {@link BTGattChar.Listener} is returned, otherwise null.
+ * @param listener A {@link {@link BTGattCharListener}} instance, listening to this {@link BTGattChar}'s events
+ * @return if successful, true is being returned, otherwise false.
* @throws IllegalStateException if the DBTDevice's GATTHandler is null, i.e. not connected
- * @throws IllegalStateException if the given {@link BTGattChar.Listener} is already in use, i.e. added.
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.4.0
*/
- BTGattCharListener addCharListener(final Listener listener)
- throws IllegalStateException;
+ boolean addCharListener(final BTGattCharListener listener) throws IllegalStateException;
/**
- * Add the given {@link BTGattChar.Listener} to the listener list if not already present
+ * Add the given BTGattCharListener to the listener list if not already present
* and if enabling the notification <i>or</i> indication for this characteristic at BLE level was successful.<br>
* Notification and/or indication configuration is only performed per characteristic if changed.
*
@@ -233,30 +194,28 @@ public interface BTGattChar extends BTObject
* Implementation uses {@link #enableNotificationOrIndication(boolean[])} to enable either.
*
* Occurring notifications and indications for this characteristic
- * will call the respective {@link BTGattChar.Listener} callback method.
+ * will call the respective BTGattCharListener callback method.
*
- * Implementation wraps given {@link BTGattChar.Listener} into a {@link BTGattCharListener}
- * to restrict the listener to listen only to this BTGattChar instance.
- *
- * {@link #removeCharListener(BTGattCharListener)} must be utilized with the returned {@link BTGattCharListener}.
+ * Returns 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.
*
* @param listener A {@link BTGattChar.Listener} instance, listening to this {@link BTGattChar}'s events
* @param enabledState array of size 2, holding the resulting enabled state for notification and indication
* using {@link #enableNotificationOrIndication(boolean[])}
- * @return 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,
- * {@link BTGattCharListener} instance wrapping the given {@link BTGattChar.Listener} is returned, otherwise null.
+ * @return if successful, true is being returned, otherwise false.
* @throws IllegalStateException if the {@link BTDevice}'s GATTHandler is null, i.e. not connected
* @throws IllegalStateException if the given {@link BTGattChar.Listener} is already in use, i.e. added.
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.4.0
*/
- BTGattCharListener addCharListener(final Listener listener, final boolean enabledState[/*2*/])
+ boolean addCharListener(final BTGattCharListener listener, final boolean enabledState[/*2*/])
throws IllegalStateException;
/**
@@ -268,13 +227,12 @@ public interface BTGattChar extends BTObject
* @param listener returned {@link BTGattCharListener} from {@link #addCharListener(Listener)} ...
* @return true if successful, otherwise false.
*
- * @throws IllegalStateException if the {@link BTDevice's}'s {@link BTGattHandler} is null, i.e. not connected
- *
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.4.0
*/
@@ -296,8 +254,9 @@ public interface BTGattChar extends BTObject
* @see #disableIndicationNotification()
* @see #enableNotificationOrIndication(boolean[])
* @see #configNotificationIndication(boolean, boolean, boolean[])
- * @see #addCharListener(Listener)
- * @see #removeCharListener(Listener)
+ * @see #addCharListener(BTGattCharListener)
+ * #see #addCharListener(BTGattCharListener, boolean[])
+ * @see #removeCharListener(BTGattCharListener)
* @see #removeAllAssociatedCharListener(boolean)
* @since 2.0.0
*/
diff --git a/java/org/direct_bt/BTGattCharListener.java b/java/org/direct_bt/BTGattCharListener.java
index 55dfa6a5..ffd0610a 100644
--- a/java/org/direct_bt/BTGattCharListener.java
+++ b/java/org/direct_bt/BTGattCharListener.java
@@ -25,7 +25,7 @@
package org.direct_bt;
-import java.lang.ref.WeakReference;
+import jau.direct_bt.DBTNativeDownlink;
/**
* {@link BTGattChar} event listener for notification and indication events.
@@ -39,49 +39,18 @@ import java.lang.ref.WeakReference;
* to listen to all events of the device or the matching filtered events.
* </p>
* <p>
- * One {@link BTGattCharListener} instance can only be attached to a listener manager once at a time,
- * i.e. you cannot attach the same instance more than once to a {@link BTDevice}
- * or {@link BTGattChar}.
- * <br>
- * To attach multiple listener, one instance per attachment must be created.
- * <br>
- * This restriction is due to implementation semantics of strictly associating
- * one Java {@link BTGattCharListener} instance to one C++ {@code BTGattCharListener} instance.
- * The latter will be added to the native list of listeners.
- * This class's {@code nativeInstance} field links the Java instance to mentioned C++ listener.
- * <br>
- * Since the listener manager maintains a unique set of listener instances without duplicates,
- * this restriction is more esoteric.
+ * The listener manager maintains a unique set of listener instances without duplicates.
* </p>
*/
-public abstract class BTGattCharListener {
- @SuppressWarnings("unused")
- private long nativeInstance;
- private final WeakReference<BTGattChar> associatedChar;
-
- /**
- * Returns the weakly associated {@link BTGattChar} to this listener instance.
- * <p>
- * Returns {@code null} if no association has been made
- * or if the associated {@link BTGattChar} has been garbage collected.
- * </p>
- */
- public final BTGattChar getAssociatedChar() {
- return null != associatedChar ? associatedChar.get() : null;
+public abstract class BTGattCharListener extends DBTNativeDownlink {
+ public BTGattCharListener() {
+ super(); // pending native ctor
+ initDownlink(ctorImpl());
}
+ private native long ctorImpl();
- /**
- * @param associatedCharacteristic weakly associates this listener instance to one {@link BTGattChar},
- * may be {@code null} for no association.
- * @see #getAssociatedChar()
- */
- public BTGattCharListener(final BTGattChar associatedCharacteristic) {
- if( null != associatedCharacteristic ) {
- this.associatedChar = new WeakReference<BTGattChar>(associatedCharacteristic);
- } else {
- this.associatedChar = null;
- }
- }
+ @Override
+ protected native void deleteImpl(long nativeInstance);
/**
* Called from native BLE stack, initiated by a received notification associated
@@ -109,8 +78,6 @@ public abstract class BTGattCharListener {
@Override
public String toString() {
- final BTGattChar c = getAssociatedChar();
- final String cs = null != c ? c.toString() : "null";
- return "BTGattCharListener[associated "+cs+"]";
+ return "BTGattCharListener[]";
}
};
diff --git a/java/org/direct_bt/BTGattCmd.java b/java/org/direct_bt/BTGattCmd.java
index d6c96296..1576756b 100644
--- a/java/org/direct_bt/BTGattCmd.java
+++ b/java/org/direct_bt/BTGattCmd.java
@@ -62,10 +62,11 @@ public class BTGattCmd implements AutoCloseable
private BTGattChar rspCharRef;
private boolean setup_done;
- private static class ResponseCharListener implements BTGattChar.Listener {
+ private static class ResponseCharListener extends BTGattCharListener {
private final BTGattCmd source;
public ResponseCharListener(final BTGattCmd source_) {
+ super();
source = source_;
}
@@ -97,7 +98,6 @@ public class BTGattCmd implements AutoCloseable
}
}
private final ResponseCharListener rspCharListener;
- private BTGattCharListener addedRspCharListener;
private boolean verbose;
private boolean isConnected() { return dev.getConnected(); }
@@ -143,8 +143,7 @@ public class BTGattCmd implements AutoCloseable
}
try {
final boolean cccdEnableResult[] = { false, false };
- addedRspCharListener = rspCharRef.addCharListener( rspCharListener, cccdEnableResult );
- if( null != addedRspCharListener ) {
+ if( rspCharRef.addCharListener( rspCharListener, cccdEnableResult ) ) {
return HCIStatusCode.SUCCESS;
} else {
if( verbose ) {
@@ -158,7 +157,6 @@ public class BTGattCmd implements AutoCloseable
BTUtils.fprintf_td(System.err, "Exception caught for %s: %s\n", e.toString(), toString());
cmdCharRef = null;
rspCharRef = null;
- addedRspCharListener = null;
return HCIStatusCode.TIMEOUT;
}
} else {
@@ -186,10 +184,8 @@ public class BTGattCmd implements AutoCloseable
public synchronized HCIStatusCode close0() {
final boolean wasResolved = isResolvedEq();
final BTGattChar rspCharRefCopy = rspCharRef;
- final BTGattCharListener addedRspCharListenerCopy = addedRspCharListener;
cmdCharRef = null;
rspCharRef = null;
- addedRspCharListener = null;
if( !setup_done ) {
return HCIStatusCode.SUCCESS;
}
@@ -200,9 +196,9 @@ public class BTGattCmd implements AutoCloseable
if( !isConnected() ) {
return HCIStatusCode.DISCONNECTED;
}
- if( null != addedRspCharListenerCopy && null != rspCharRefCopy) {
+ if( null != rspCharRefCopy) {
try {
- final boolean res1 = rspCharRefCopy.removeCharListener(addedRspCharListenerCopy);
+ final boolean res1 = rspCharRefCopy.removeCharListener(rspCharListener);
final boolean res2 = rspCharRefCopy.disableIndicationNotification();
if( res1 && res2 ) {
return HCIStatusCode.SUCCESS;
@@ -240,7 +236,6 @@ public class BTGattCmd implements AutoCloseable
rspCharRef = null;
setup_done = false;
rspCharListener = new ResponseCharListener(this);
- addedRspCharListener = null;
verbose = DEBUG;
}
@@ -264,7 +259,6 @@ public class BTGattCmd implements AutoCloseable
rspCharRef = null;
setup_done = false;
rspCharListener = null;
- addedRspCharListener = null;
verbose = DEBUG;
}
diff --git a/java/org/direct_bt/BTGattService.java b/java/org/direct_bt/BTGattService.java
index 62cd04ec..592ca9fc 100644
--- a/java/org/direct_bt/BTGattService.java
+++ b/java/org/direct_bt/BTGattService.java
@@ -88,9 +88,6 @@ public interface BTGattService extends BTObject
if( null == listener ) {
throw new IllegalArgumentException("listener argument null");
}
- if( null != listener.getAssociatedChar() ) {
- throw new IllegalArgumentException("listener's associated characteristic is not null");
- }
final boolean res = device.addCharListener(listener);
for(final Iterator<BTGattService> is = services.iterator(); is.hasNext(); ) {
final BTGattService s = is.next();
diff --git a/scripts/build.sh b/scripts/build.sh
index fdd6e238..d948e25c 100644
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -40,11 +40,11 @@ buildit() {
cd build-$archabi
# CLANG_ARGS="-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++"
- cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON ..
+ # cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON ..
# cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON -DDEBUG=ON ..
# cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DUSE_LIBUNWIND=OFF -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON ..
- # cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DUSE_LIBUNWIND=OFF -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON -DDEBUG=ON ..
+ cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DUSE_LIBUNWIND=OFF -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON -DDEBUG=ON ..
# cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON -DUSE_STRIP=OFF ..
# cmake $CLANG_ARGS -DCMAKE_INSTALL_PREFIX=$rootdir/dist-$archabi -DBUILDJAVA=ON -DBUILDEXAMPLES=ON -DBUILD_TRIAL=ON -DUSE_STRIP=ON -DJAVAC_DEBUG_ARGS="none" ..
diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp
index 0603b2ed..9abdcbe3 100644
--- a/src/direct_bt/BTAdapter.cpp
+++ b/src/direct_bt/BTAdapter.cpp
@@ -914,15 +914,16 @@ bool BTAdapter::removeDeviceFromWhitelist(const BDAddressAndType & addressAndTyp
return mgmt.removeDeviceFromWhitelist(dev_id, addressAndType);
}
-static jau::cow_darray<impl::StatusListenerPair>::equal_comparator _adapterStatusListenerRefEqComparator =
- [](const impl::StatusListenerPair &a, const impl::StatusListenerPair &b) -> bool { return *a.listener == *b.listener; };
+BTAdapter::statusListenerList_t::equal_comparator BTAdapter::adapterStatusListenerRefEqComparator =
+ [](const StatusListenerPair &a, const StatusListenerPair &b) -> bool { return *a.listener == *b.listener; };
-bool BTAdapter::addStatusListener(const AdapterStatusListenerRef& l) {
+bool BTAdapter::addStatusListener(const AdapterStatusListenerRef& l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("AdapterStatusListener ref is null", E_FILE_LINE);
+ ERR_PRINT("AdapterStatusListener ref is null");
+ return false;
}
- const bool added = statusListenerList.push_back_unique(impl::StatusListenerPair{l, std::weak_ptr<BTDevice>{} },
- _adapterStatusListenerRefEqComparator);
+ const bool added = statusListenerList.push_back_unique(StatusListenerPair{l, std::weak_ptr<BTDevice>{} },
+ adapterStatusListenerRefEqComparator);
if( added ) {
sendAdapterSettingsInitial(*l, jau::getCurrentMilliseconds());
}
@@ -933,15 +934,17 @@ bool BTAdapter::addStatusListener(const AdapterStatusListenerRef& l) {
return added;
}
-bool BTAdapter::addStatusListener(const BTDeviceRef& d, const AdapterStatusListenerRef& l) {
+bool BTAdapter::addStatusListener(const BTDeviceRef& d, const AdapterStatusListenerRef& l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("AdapterStatusListener ref is null", E_FILE_LINE);
+ ERR_PRINT("AdapterStatusListener ref is null");
+ return false;
}
if( nullptr == d ) {
- throw jau::IllegalArgumentException("Device is null", E_FILE_LINE);
+ ERR_PRINT("Device ref is null");
+ return false;
}
- const bool added = statusListenerList.push_back_unique(impl::StatusListenerPair{l, d},
- _adapterStatusListenerRefEqComparator);
+ const bool added = statusListenerList.push_back_unique(StatusListenerPair{l, d},
+ adapterStatusListenerRefEqComparator);
if( added ) {
sendAdapterSettingsInitial(*l, jau::getCurrentMilliseconds());
}
@@ -952,17 +955,18 @@ bool BTAdapter::addStatusListener(const BTDeviceRef& d, const AdapterStatusListe
return added;
}
-bool BTAdapter::addStatusListener(const BTDevice& d, const AdapterStatusListenerRef& l) {
+bool BTAdapter::addStatusListener(const BTDevice& d, const AdapterStatusListenerRef& l) noexcept {
return addStatusListener(getSharedDevice(d), l);
}
-bool BTAdapter::removeStatusListener(const AdapterStatusListenerRef& l) {
+bool BTAdapter::removeStatusListener(const AdapterStatusListenerRef& l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("AdapterStatusListener ref is null", E_FILE_LINE);
+ ERR_PRINT("AdapterStatusListener ref is null");
+ return false;
}
- const int count = statusListenerList.erase_matching(impl::StatusListenerPair{l, std::weak_ptr<BTDevice>{}},
+ const int count = statusListenerList.erase_matching(StatusListenerPair{l, std::weak_ptr<BTDevice>{}},
false /* all_matching */,
- _adapterStatusListenerRefEqComparator);
+ adapterStatusListenerRefEqComparator);
if( _print_device_lists || jau::environment::get().verbose ) {
jau::PLAIN_PRINT(true, "BTAdapter::removeStatusListener.1: res %d, %s", count>0, toString().c_str());
printDeviceLists();
@@ -970,25 +974,22 @@ bool BTAdapter::removeStatusListener(const AdapterStatusListenerRef& l) {
return count > 0;
}
-bool BTAdapter::removeStatusListener(const AdapterStatusListener * l) {
+bool BTAdapter::removeStatusListener(const AdapterStatusListener * l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("AdapterStatusListener ref is null", E_FILE_LINE);
+ ERR_PRINT("AdapterStatusListener ref is null");
+ return false;
}
bool res = false;
{
- auto begin = statusListenerList.begin(); // lock mutex and copy_store
- while ( !begin.is_end() ) {
- if ( *begin->listener == *l ) {
- begin.erase();
+ auto it = statusListenerList.begin(); // lock mutex and copy_store
+ for (; !it.is_end(); ++it ) {
+ if ( *it->listener == *l ) {
+ it.erase();
+ it.write_back();
res = true;
break;
- } else {
- ++begin;
}
}
- if( res ) {
- begin.write_back();
- }
}
if( _print_device_lists || jau::environment::get().verbose ) {
jau::PLAIN_PRINT(true, "BTAdapter::removeStatusListener.2: res %d, %s", res, toString().c_str());
@@ -997,7 +998,7 @@ bool BTAdapter::removeStatusListener(const AdapterStatusListener * l) {
return res;
}
-int BTAdapter::removeAllStatusListener(const BTDevice& d) {
+int BTAdapter::removeAllStatusListener(const BTDevice& d) noexcept {
int count = 0;
int res = statusListenerList.size();
@@ -1586,7 +1587,7 @@ void BTAdapter::sendAdapterSettingsChanged(const AdapterSetting old_settings_, c
const uint64_t timestampMS) noexcept
{
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
p.listener->adapterSettingsChanged(*this, old_settings_, current_settings, changes, timestampMS);
} catch (std::exception &e) {
@@ -1613,7 +1614,7 @@ void BTAdapter::sendAdapterSettingsInitial(AdapterStatusListener & asl, const ui
void BTAdapter::sendDeviceUpdated(std::string cause, BTDeviceRef device, uint64_t timestamp, EIRDataType updateMask) noexcept {
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(device) ) {
p.listener->deviceUpdated(device, updateMask, timestamp);
@@ -1696,7 +1697,7 @@ bool BTAdapter::mgmtEvDeviceDiscoveringAny(const ScanType eventScanType, const b
checkDiscoveryState();
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
p.listener->discoveringChanged(*this, currentMetaScanType, eventScanType, eventEnabled, discovery_policy, eventTimestamp);
} catch (std::exception &except) {
@@ -1996,7 +1997,7 @@ bool BTAdapter::mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept {
}
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(device) ) {
if( EIRDataType::NONE != updateMask ) {
@@ -2046,7 +2047,7 @@ bool BTAdapter::mgmtEvConnectFailedHCI(const MgmtEvent& e) noexcept {
if( !device->isConnSecurityAutoEnabled() ) {
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(device) ) {
p.listener->deviceDisconnected(device, event.getHCIStatus(), handle, event.getTimestamp());
@@ -2146,7 +2147,7 @@ bool BTAdapter::mgmtEvDeviceDisconnectedHCI(const MgmtEvent& e) noexcept {
if( !device->isConnSecurityAutoEnabled() ) {
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(device) ) {
p.listener->deviceDisconnected(device, event.getHCIReason(), event.getHCIHandle(), event.getTimestamp());
@@ -2393,7 +2394,7 @@ bool BTAdapter::mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept {
}
int i=0;
bool device_used = false;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(dev_shared) ) {
device_used = p.listener->deviceFound(dev_shared, eir->getTimestamp()) || device_used;
@@ -2433,7 +2434,7 @@ bool BTAdapter::mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept {
}
int i=0;
bool device_used = false;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(dev_shared) ) {
device_used = p.listener->deviceFound(dev_shared, eir->getTimestamp()) || device_used;
@@ -2472,7 +2473,7 @@ bool BTAdapter::mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept {
addSharedDevice(dev_discovered); // re-add to shared devices!
int i=0;
bool device_used = false;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(dev_discovered) ) {
device_used = p.listener->deviceFound(dev_discovered, eir->getTimestamp()) || device_used;
@@ -2615,7 +2616,7 @@ void BTAdapter::sendDevicePairingState(BTDeviceRef device, const SMPPairingState
}
}
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
if( p.match(device) ) {
p.listener->devicePairingState(device, state, mode, timestamp);
@@ -2646,7 +2647,7 @@ void BTAdapter::sendDeviceReady(BTDeviceRef device, uint64_t timestamp) noexcept
removeDevicePausingDiscovery(*device, false /* off_thread_enable */);
}
int i=0;
- jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
+ jau::for_each_fidelity(statusListenerList, [&](StatusListenerPair &p) {
try {
// Only issue if valid && received connected confirmation (HCI) && not have called disconnect yet.
if( device->isValidInstance() && device->getConnected() && device->allowDisconnect ) {
diff --git a/src/direct_bt/BTDevice.cpp b/src/direct_bt/BTDevice.cpp
index 351184f8..34004979 100644
--- a/src/direct_bt/BTDevice.cpp
+++ b/src/direct_bt/BTDevice.cpp
@@ -256,11 +256,11 @@ EIRDataType BTDevice::update(GattGenericAccessSvc const &data, const uint64_t ti
return res;
}
-bool BTDevice::addStatusListener(const AdapterStatusListenerRef& l) {
+bool BTDevice::addStatusListener(const AdapterStatusListenerRef& l) noexcept {
return adapter.addStatusListener(*this, l);
}
-bool BTDevice::removeStatusListener(const AdapterStatusListenerRef& l) {
+bool BTDevice::removeStatusListener(const AdapterStatusListenerRef& l) noexcept {
return adapter.removeStatusListener(l);
}
@@ -2076,16 +2076,25 @@ bool BTDevice::pingGATT() noexcept {
return gh->ping();
}
-bool BTDevice::addCharListener(std::shared_ptr<BTGattCharListener> l) {
+bool BTDevice::addCharListener(const BTGattCharListenerRef& l) noexcept {
std::shared_ptr<BTGattHandler> gatt = getGattHandler();
if( nullptr == gatt ) {
- throw jau::IllegalStateException("Device's GATTHandle not connected: "+
- toString(), E_FILE_LINE);
+ ERR_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
+ return false;
}
return gatt->addCharListener(l);
}
-bool BTDevice::removeCharListener(std::shared_ptr<BTGattCharListener> l) noexcept {
+bool BTDevice::addCharListener(const BTGattCharListenerRef& l, const BTGattCharRef& d) noexcept {
+ std::shared_ptr<BTGattHandler> gatt = getGattHandler();
+ if( nullptr == gatt ) {
+ ERR_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
+ return false;
+ }
+ return gatt->addCharListener(l, d);
+}
+
+bool BTDevice::removeCharListener(const BTGattCharListenerRef& l) noexcept {
std::shared_ptr<BTGattHandler> gatt = getGattHandler();
if( nullptr == gatt ) {
// OK to have GATTHandler being shutdown @ disable
@@ -2095,7 +2104,7 @@ bool BTDevice::removeCharListener(std::shared_ptr<BTGattCharListener> l) noexcep
return gatt->removeCharListener(l);
}
-int BTDevice::removeAllAssociatedCharListener(std::shared_ptr<BTGattChar> associatedCharacteristic) noexcept {
+int BTDevice::removeAllAssociatedCharListener(const BTGattCharRef& associatedCharacteristic) noexcept {
std::shared_ptr<BTGattHandler> gatt = getGattHandler();
if( nullptr == gatt ) {
// OK to have GATTHandler being shutdown @ disable
diff --git a/src/direct_bt/BTGattChar.cpp b/src/direct_bt/BTGattChar.cpp
index f33c4f80..c618cae4 100644
--- a/src/direct_bt/BTGattChar.cpp
+++ b/src/direct_bt/BTGattChar.cpp
@@ -49,17 +49,8 @@ using namespace jau;
*/
JAU_TYPENAME_CUE(direct_bt::BTGattCharListener)
-/**
- * Simple access and provision of a typename string representation
- * at compile time like RTTI via jau::type_name_cue.
- */
-JAU_TYPENAME_CUE(direct_bt::AssociatedBTGattCharListener)
-
const char * BTGattCharListener::type_name() const noexcept { return jau::type_name_cue<BTGattCharListener>::name(); }
-const char * AssociatedBTGattCharListener::type_name() const noexcept { return jau::type_name_cue<AssociatedBTGattCharListener>::name(); }
-
-
#define CHAR_DECL_PROPS_ENUM(X) \
X(BTGattChar,Broadcast,broadcast) \
X(BTGattChar,Read,read) \
@@ -180,7 +171,7 @@ std::string BTGattChar::toShortString() const noexcept {
"], ccd-idx "+std::to_string(clientCharConfigIndex)+notify_str+"]";
}
-std::shared_ptr<BTGattHandler> BTGattChar::getGattHandlerUnchecked() const noexcept {
+BTGattHandlerRef BTGattChar::getGattHandlerUnchecked() const noexcept {
std::shared_ptr<BTGattService> s = getServiceUnchecked();
if( nullptr != s ) {
return s->getGattHandlerUnchecked();
@@ -188,7 +179,7 @@ std::shared_ptr<BTGattHandler> BTGattChar::getGattHandlerUnchecked() const noexc
return nullptr;
}
-std::shared_ptr<BTDevice> BTGattChar::getDeviceUnchecked() const noexcept {
+BTDeviceRef BTGattChar::getDeviceUnchecked() const noexcept {
std::shared_ptr<BTGattService> s = getServiceUnchecked();
if( nullptr != s ) {
return s->getDeviceUnchecked();
@@ -266,88 +257,39 @@ bool BTGattChar::disableIndicationNotification() noexcept {
return configNotificationIndication(false, false, enabledState);
}
-class DelegatedBTGattCharListener : public BTGattCharListener {
- private:
- const BTGattChar * associatedChar;
- std::shared_ptr<BTGattChar::Listener> delegate;
-
- public:
- DelegatedBTGattCharListener(const BTGattChar * characteristicMatch, std::shared_ptr<BTGattChar::Listener> l) noexcept
- : associatedChar(characteristicMatch), delegate(l) { }
-
- const char * type_name() const noexcept override;
-
- bool match(const BTGattChar & characteristic) noexcept override {
- if( nullptr == associatedChar ) {
- return true;
- }
- return *associatedChar == characteristic;
- }
-
- void notificationReceived(BTGattCharRef charDecl,
- const TROOctets& charValue, const uint64_t timestamp) override {
- delegate->notificationReceived(charDecl, charValue, timestamp);
- }
-
- void indicationReceived(BTGattCharRef charDecl,
- const TROOctets& charValue, const uint64_t timestamp,
- const bool confirmationSent) override {
- delegate->indicationReceived(charDecl, charValue, timestamp, confirmationSent);
- }
-
- std::string toString() override {
- return std::string(type_name())+"["+jau::to_string(this)+", delegate "+jau::to_string(delegate.get())+"]";
- }
-
- /**
- * Comparison operator merely testing for same memory reference of the delegate.
- */
- bool operator==(const BTGattCharListener& rhs) const noexcept override;
-
- bool operator!=(const DelegatedBTGattCharListener& rhs) const noexcept
- { return !(*this == rhs); }
-};
-
-/**
- * Simple access and provision of a typename string representation
- * at compile time like RTTI via jau::type_name_cue.
- */
-JAU_TYPENAME_CUE(DelegatedBTGattCharListener)
-
-const char * DelegatedBTGattCharListener::type_name() const noexcept { return jau::type_name_cue<DelegatedBTGattCharListener>::name(); }
-
-bool DelegatedBTGattCharListener::operator==(const BTGattCharListener& rhs) const noexcept
-{
- if( 0 != strcmp(rhs.type_name(), jau::type_name_cue<DelegatedBTGattCharListener>::name()) ) {
- return false;
- }
- const DelegatedBTGattCharListener& rhs2 = static_cast<const DelegatedBTGattCharListener&>(rhs);
- return delegate.get() == rhs2.delegate.get();
-}
-
-bool BTGattChar::addCharListener(std::shared_ptr<BTGattChar::Listener> l) noexcept {
- std::shared_ptr<BTDevice> device = getDeviceUnchecked();
+bool BTGattChar::addCharListener(const BTGattCharListenerRef& l) noexcept {
+ BTDeviceRef device = getDeviceUnchecked();
if( nullptr == device ) {
ERR_PRINT("Characteristic's device null: %s", toShortString().c_str());
return false;
}
- return device->addCharListener( std::make_shared<DelegatedBTGattCharListener>( this, l ) );
+ BTGattServiceRef service = getServiceUnchecked();
+ if( nullptr == service ) {
+ ERR_PRINT("Characteristic's service null: %s", toShortString().c_str());
+ return false;
+ }
+ BTGattCharRef characteristic = service->findGattChar(*this);
+ if( nullptr == service ) {
+ ERR_PRINT("Characteristic not in service: %s", toShortString().c_str());
+ return false;
+ }
+ return device->addCharListener(l, characteristic);
}
-bool BTGattChar::addCharListener(std::shared_ptr<BTGattChar::Listener> l, bool enabledState[2]) noexcept {
+bool BTGattChar::addCharListener(const BTGattCharListenerRef& l, bool enabledState[2]) noexcept {
if( !enableNotificationOrIndication(enabledState) ) {
return false;
}
return addCharListener(l);
}
-bool BTGattChar::removeCharListener(std::shared_ptr<Listener> l) noexcept {
+bool BTGattChar::removeCharListener(const BTGattCharListenerRef& l) noexcept {
std::shared_ptr<BTDevice> device = getDeviceUnchecked();
if( nullptr == device ) {
ERR_PRINT("Characteristic's device null: %s", toShortString().c_str());
return false;
}
- return device->removeCharListener( std::make_shared<DelegatedBTGattCharListener>( this, l ) );
+ return device->removeCharListener(l);
}
int BTGattChar::removeAllAssociatedCharListener(bool shallDisableIndicationNotification) noexcept {
diff --git a/src/direct_bt/BTGattHandler.cpp b/src/direct_bt/BTGattHandler.cpp
index 20d46dd8..ebb30be2 100644
--- a/src/direct_bt/BTGattHandler.cpp
+++ b/src/direct_bt/BTGattHandler.cpp
@@ -102,15 +102,29 @@ bool BTGattHandler::validateConnected() noexcept {
return true;
}
-static jau::cow_darray<BTGattCharListenerRef>::equal_comparator _btGattCharListenerRefEqComparator =
- [](const BTGattCharListenerRef& a, const BTGattCharListenerRef& b) -> bool { return *a == *b; };
+BTGattHandler::gattCharListenerList_t::equal_comparator BTGattHandler::gattCharListenerRefEqComparator =
+ [](const GattCharListenerPair& a, const GattCharListenerPair& b) -> bool { return *a.listener == *b.listener; };
bool BTGattHandler::addCharListener(const BTGattCharListenerRef& l) noexcept {
if( nullptr == l ) {
ERR_PRINT("GATTCharacteristicListener ref is null");
return false;
}
- return btGattCharListenerList.push_back_unique(l, _btGattCharListenerRefEqComparator);
+ return gattCharListenerList.push_back_unique(GattCharListenerPair{l, std::weak_ptr<BTGattChar>{} },
+ gattCharListenerRefEqComparator);
+}
+
+bool BTGattHandler::addCharListener(const BTGattCharListenerRef& l, const BTGattCharRef& d) noexcept {
+ if( nullptr == l ) {
+ ERR_PRINT("GATTCharacteristicListener ref is null");
+ return false;
+ }
+ if( nullptr == d ) {
+ ERR_PRINT("BTGattChar ref is null");
+ return false;
+ }
+ return gattCharListenerList.push_back_unique(GattCharListenerPair{l, d},
+ gattCharListenerRefEqComparator);
}
bool BTGattHandler::removeCharListener(const BTGattCharListenerRef& l) noexcept {
@@ -118,7 +132,9 @@ bool BTGattHandler::removeCharListener(const BTGattCharListenerRef& l) noexcept
ERR_PRINT("GATTCharacteristicListener ref is null");
return false;
}
- const int count = btGattCharListenerList.erase_matching(l, false /* all_matching */, _btGattCharListenerRefEqComparator);
+ const int count = gattCharListenerList.erase_matching(GattCharListenerPair{l, std::weak_ptr<BTGattChar>{}},
+ false /* all_matching */,
+ gattCharListenerRefEqComparator);
return count > 0;
}
@@ -127,9 +143,9 @@ bool BTGattHandler::removeCharListener(const BTGattCharListener * l) noexcept {
ERR_PRINT("GATTCharacteristicListener ref is null");
return false;
}
- auto it = btGattCharListenerList.begin(); // lock mutex and copy_store
+ auto it = gattCharListenerList.begin(); // lock mutex and copy_store
for (; !it.is_end(); ++it ) {
- if ( **it == *l ) {
+ if ( *it->listener == *l ) {
it.erase();
it.write_back();
return true;
@@ -159,12 +175,12 @@ bool BTGattHandler::removeCharListener(const BTGattHandler::NativeGattCharListen
}
void BTGattHandler::printCharListener() noexcept {
- jau::INFO_PRINT("BTGattHandler: BTGattChar %u listener", btGattCharListenerList.size());
+ jau::INFO_PRINT("BTGattHandler: BTGattChar %u listener", gattCharListenerList.size());
{
int i=0;
- auto it = btGattCharListenerList.begin(); // lock mutex and copy_store
+ auto it = gattCharListenerList.begin(); // lock mutex and copy_store
for (; !it.is_end(); ++it, ++i ) {
- jau::INFO_PRINT("[%d]: %s", i, (*it)->toString().c_str());
+ jau::INFO_PRINT("[%d]: %s", i, it->listener->toString().c_str());
}
}
jau::INFO_PRINT("BTGattHandler: NativeGattChar %u listener", nativeGattCharListenerList.size());
@@ -191,9 +207,9 @@ int BTGattHandler::removeAllAssociatedCharListener(const BTGattChar * associated
return false;
}
int count = 0;
- auto it = btGattCharListenerList.begin(); // lock mutex and copy_store
+ auto it = gattCharListenerList.begin(); // lock mutex and copy_store
while( !it.is_end() ) {
- if ( (*it)->match(*associatedCharacteristic) ) {
+ if ( it->match(*associatedCharacteristic) ) {
it.erase();
++count;
} else {
@@ -207,8 +223,8 @@ int BTGattHandler::removeAllAssociatedCharListener(const BTGattChar * associated
}
int BTGattHandler::removeAllCharListener() noexcept {
- int count = btGattCharListenerList.size();
- btGattCharListenerList.clear();
+ int count = gattCharListenerList.size();
+ gattCharListenerList.clear();
count += nativeGattCharListenerList.size();
nativeGattCharListenerList.clear();
return count;
@@ -424,7 +440,7 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
} else if( AttPDUMsg::Opcode::HANDLE_VALUE_NTF == opc ) { // AttPDUMsg::OpcodeType::NOTIFICATION
const AttHandleValueRcv * a = static_cast<const AttHandleValueRcv*>(attPDU.get());
COND_PRINT(env.DEBUG_DATA, "GATTHandler::reader: NTF: %s, listener [native %zd, bt %zd]",
- a->toString().c_str(), nativeGattCharListenerList.size(), btGattCharListenerList.size());
+ a->toString().c_str(), nativeGattCharListenerList.size(), gattCharListenerList.size());
const uint64_t a_timestamp = a->ts_creation;
const uint16_t a_handle = a->getHandle();
const jau::TOctetSlice& a_value = a->getValue();
@@ -443,18 +459,18 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
i++;
});
}
- BTGattCharRef decl = findCharacterisicsByValueHandle(services, a_handle);
- if( nullptr != decl ) {
+ BTGattCharRef characteristic = findCharacterisicsByValueHandle(services, a_handle);
+ if( nullptr != characteristic ) {
int i=0;
- jau::for_each_fidelity(btGattCharListenerList, [&](std::shared_ptr<BTGattCharListener> &l) {
+ jau::for_each_fidelity(gattCharListenerList, [&](GattCharListenerPair &p) {
try {
- if( l->match(*decl) ) {
- l->notificationReceived(decl, a_data_view, a_timestamp);
+ if( p.match(*characteristic) ) {
+ p.listener->notificationReceived(characteristic, a_data_view, a_timestamp);
}
} catch (std::exception &e) {
ERR_PRINT("GATTHandler::notificationReceived-CBs %d/%zd: BTGattCharListener %s: Caught exception %s",
- i+1, btGattCharListenerList.size(),
- jau::to_hexstring((void*)l.get()).c_str(), e.what());
+ i+1, gattCharListenerList.size(),
+ jau::to_hexstring((void*)p.listener.get()).c_str(), e.what());
}
i++;
});
@@ -462,7 +478,7 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
} else if( AttPDUMsg::Opcode::HANDLE_VALUE_IND == opc ) { // AttPDUMsg::OpcodeType::INDICATION
const AttHandleValueRcv * a = static_cast<const AttHandleValueRcv*>(attPDU.get());
COND_PRINT(env.DEBUG_DATA, "GATTHandler::reader: IND: %s, sendIndicationConfirmation %d, listener [native %zd, bt %zd]",
- a->toString().c_str(), sendIndicationConfirmation.load(), nativeGattCharListenerList.size(), btGattCharListenerList.size());
+ a->toString().c_str(), sendIndicationConfirmation.load(), nativeGattCharListenerList.size(), gattCharListenerList.size());
bool cfmSent = false;
if( sendIndicationConfirmation ) {
AttHandleValueCfm cfm;
@@ -492,18 +508,18 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
i++;
});
}
- BTGattCharRef decl = findCharacterisicsByValueHandle(services, a_handle);
- if( nullptr != decl ) {
+ BTGattCharRef characteristic = findCharacterisicsByValueHandle(services, a_handle);
+ if( nullptr != characteristic ) {
int i=0;
- jau::for_each_fidelity(btGattCharListenerList, [&](std::shared_ptr<BTGattCharListener> &l) {
+ jau::for_each_fidelity(gattCharListenerList, [&](GattCharListenerPair &p) {
try {
- if( l->match(*decl) ) {
- l->indicationReceived(decl, a_data_view, a_timestamp, cfmSent);
+ if( p.match(*characteristic) ) {
+ p.listener->indicationReceived(characteristic, a_data_view, a_timestamp, cfmSent);
}
} catch (std::exception &e) {
ERR_PRINT("GATTHandler::indicationReceived-CBs %d/%zd: BTGattCharListener %s, cfmSent %d: Caught exception %s",
- i+1, btGattCharListenerList.size(),
- jau::to_hexstring((void*)l.get()).c_str(), cfmSent, e.what());
+ i+1, gattCharListenerList.size(),
+ jau::to_hexstring((void*)p.listener.get()).c_str(), cfmSent, e.what());
}
i++;
});
@@ -640,7 +656,7 @@ BTGattHandler::BTGattHandler(const BTDeviceRef &device, L2CAPClient& l2cap_att,
BTGattHandler::~BTGattHandler() noexcept {
DBG_PRINT("GATTHandler::dtor: Start: %s", toString().c_str());
disconnect(false /* disconnect_device */, false /* ioerr_cause */);
- btGattCharListenerList.clear();
+ gattCharListenerList.clear();
nativeGattCharListenerList.clear();
services.clear();
genericAccess = nullptr;
@@ -669,7 +685,7 @@ bool BTGattHandler::disconnect(const bool disconnect_device, const bool ioerr_ca
DBG_PRINT("GATTHandler::disconnect: Not connected: disconnect_device %d, ioerr %d: GattHandler[%s], l2cap[%s], stopped %d: %s",
disconnect_device, ioerr_cause, getStateString().c_str(), l2cap.getStateString().c_str(),
l2cap_service_stopped, toString().c_str());
- btGattCharListenerList.clear();
+ gattCharListenerList.clear();
nativeGattCharListenerList.clear();
return false;
}
@@ -685,7 +701,7 @@ bool BTGattHandler::disconnect(const bool disconnect_device, const bool ioerr_ca
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
DBG_PRINT("GATTHandler::disconnect: Start: disconnect_device %d, ioerr %d: GattHandler[%s], l2cap[%s]: %s",
disconnect_device, ioerr_cause, getStateString().c_str(), l2cap.getStateString().c_str(), toString().c_str());
- btGattCharListenerList.clear();
+ gattCharListenerList.clear();
nativeGattCharListenerList.clear();
clientMTUExchanged = false;
@@ -1546,7 +1562,7 @@ std::string BTGattHandler::toString() const noexcept {
return "GattHndlr["+to_string(getRole())+", "+deviceString+
", mode "+to_string(gattServerHandler->getMode())+
", mtu "+std::to_string(usedMTU.load())+
- ", listener[BTGatt "+std::to_string(btGattCharListenerList.size())+
+ ", listener[BTGatt "+std::to_string(gattCharListenerList.size())+
", Native "+std::to_string(nativeGattCharListenerList.size())+
"], l2capWorker[running "+std::to_string(l2cap_reader_service.is_running())+
", shallStop "+std::to_string(l2cap_reader_service.shall_stop())+
diff --git a/src/direct_bt/BTGattService.cpp b/src/direct_bt/BTGattService.cpp
index 01000854..a54e429d 100644
--- a/src/direct_bt/BTGattService.cpp
+++ b/src/direct_bt/BTGattService.cpp
@@ -43,7 +43,7 @@
using namespace direct_bt;
using namespace jau;
-std::shared_ptr<BTGattHandler> BTGattService::getGattHandlerChecked() const {
+BTGattHandlerRef BTGattService::getGattHandlerChecked() const {
std::shared_ptr<BTGattHandler> ref = wbr_handler.lock();
if( nullptr == ref ) {
throw IllegalStateException("GATTService's GATTHandler already destructed: "+toShortString(), E_FILE_LINE);
@@ -51,7 +51,7 @@ std::shared_ptr<BTGattHandler> BTGattService::getGattHandlerChecked() const {
return ref;
}
-std::shared_ptr<BTDevice> BTGattService::getDeviceUnchecked() const noexcept {
+BTDeviceRef BTGattService::getDeviceUnchecked() const noexcept {
std::shared_ptr<BTGattHandler> h = getGattHandlerUnchecked();
if( nullptr != h ) {
return h->getDeviceUnchecked();
@@ -59,11 +59,11 @@ std::shared_ptr<BTDevice> BTGattService::getDeviceUnchecked() const noexcept {
return nullptr;
}
-std::shared_ptr<BTDevice> BTGattService::getDeviceChecked() const {
+BTDeviceRef BTGattService::getDeviceChecked() const {
return getGattHandlerChecked()->getDeviceChecked();
}
-std::shared_ptr<BTGattChar> BTGattService::findGattChar(const jau::uuid_t& char_uuid) noexcept {
+BTGattCharRef BTGattService::findGattChar(const jau::uuid_t& char_uuid) noexcept {
for(BTGattCharRef& c : characteristicList) {
if( nullptr != c && char_uuid.equivalent( *(c->value_type) ) ) {
return c;
@@ -72,6 +72,15 @@ std::shared_ptr<BTGattChar> BTGattService::findGattChar(const jau::uuid_t& char_
return nullptr;
}
+BTGattCharRef BTGattService::findGattChar(const BTGattChar& characteristic) noexcept {
+ for(BTGattCharRef& c : characteristicList) {
+ if( nullptr != c && characteristic == *c ) {
+ return c;
+ }
+ }
+ return nullptr;
+}
+
std::string BTGattService::toString() const noexcept {
std::string name = "";
if( uuid_t::TypeSize::UUID16_SZ == type->getTypeSize() ) {
diff --git a/trial/direct_bt/dbt_client00.hpp b/trial/direct_bt/dbt_client00.hpp
index 36508f8a..345f9355 100644
--- a/trial/direct_bt/dbt_client00.hpp
+++ b/trial/direct_bt/dbt_client00.hpp
@@ -228,22 +228,21 @@ class DBTClient00 : public DBTClientTest {
};
- class MyGATTEventListener : public BTGattChar::Listener {
+ class MyGATTEventListener : public BTGattCharListener {
private:
DBTClient00& parent;
- int i, j;
public:
- MyGATTEventListener(DBTClient00& p, int i_, int j_) : parent(p), i(i_), j(j_) {}
+ MyGATTEventListener(DBTClient00& p) : parent(p) {}
void notificationReceived(BTGattCharRef charDecl, const TROOctets& char_value, const uint64_t timestamp) override {
if( GATT_VERBOSE ) {
const uint64_t tR = jau::getCurrentMilliseconds();
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n",
- i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp));
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
+ fprintf_td(stderr, "** Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n",
+ charDecl->value_type->toUUID128String().c_str(), (tR-timestamp));
+ fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str());
+ fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str());
+ fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
}
parent.notificationsReceived++;
}
@@ -254,11 +253,11 @@ class DBTClient00 : public DBTClientTest {
{
if( GATT_VERBOSE ) {
const uint64_t tR = jau::getCurrentMilliseconds();
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n",
- i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent);
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
+ fprintf_td(stderr, "** Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n",
+ charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent);
+ fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str());
+ fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str());
+ fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
}
parent.indicationsReceived++;
}
@@ -443,75 +442,76 @@ class DBTClient00 : public DBTClientTest {
// cmd.close(); // done via dtor
}
- for(size_t i=0; i<primServices.size(); i++) {
- BTGattService & primService = *primServices.at(i);
- if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d] Service UUID %s (%s)\n", i,
- primService.type->toUUID128String().c_str(),
- primService.type->getTypeSizeString().c_str());
- fprintf_td(stderr, " [%2.2d] %s\n", i, primService.toString().c_str());
- }
- jau::darray<BTGattCharRef> & serviceCharacteristics = primService.characteristicList;
- for(size_t j=0; j<serviceCharacteristics.size(); j++) {
- BTGattCharRef & serviceChar = serviceCharacteristics.at(j);
+ std::vector<BTGattCharListenerRef> gattListener;
+ int loop = 0;
+ do {
+ for(size_t i=0; i<primServices.size(); i++) {
+ BTGattService & primService = *primServices.at(i);
if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic: UUID %s (%s)\n", i, j,
- serviceChar->value_type->toUUID128String().c_str(),
- serviceChar->value_type->getTypeSizeString().c_str());
- fprintf_td(stderr, " [%2.2d.%2.2d] %s\n", i, j, serviceChar->toString().c_str());
+ fprintf_td(stderr, " [%2.2d] Service UUID %s (%s)\n", i,
+ primService.type->toUUID128String().c_str(),
+ primService.type->getTypeSizeString().c_str());
+ fprintf_td(stderr, " [%2.2d] %s\n", i, primService.toString().c_str());
}
- if( serviceChar->hasProperties(BTGattChar::PropertyBitVal::Read) ) {
- POctets value(BTGattHandler::number(BTGattHandler::Defaults::MAX_ATT_MTU), 0, jau::endian::little);
- if( serviceChar->readValue(value) ) {
- std::string sval = dfa_utf8_decode(value.get_ptr(), value.size());
+ jau::darray<BTGattCharRef> & serviceCharacteristics = primService.characteristicList;
+ for(size_t j=0; j<serviceCharacteristics.size(); j++) {
+ BTGattCharRef & serviceChar = serviceCharacteristics.at(j);
+ if( GATT_VERBOSE ) {
+ fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic: UUID %s (%s)\n", i, j,
+ serviceChar->value_type->toUUID128String().c_str(),
+ serviceChar->value_type->getTypeSizeString().c_str());
+ fprintf_td(stderr, " [%2.2d.%2.2d] %s\n", i, j, serviceChar->toString().c_str());
+ }
+ if( serviceChar->hasProperties(BTGattChar::PropertyBitVal::Read) ) {
+ POctets value(BTGattHandler::number(BTGattHandler::Defaults::MAX_ATT_MTU), 0, jau::endian::little);
+ if( serviceChar->readValue(value) ) {
+ std::string sval = dfa_utf8_decode(value.get_ptr(), value.size());
+ if( GATT_VERBOSE ) {
+ fprintf_td(stderr, " [%2.2d.%2.2d] value: %s ('%s')\n", (int)i, (int)j, value.toString().c_str(), sval.c_str());
+ }
+ }
+ }
+ jau::darray<BTGattDescRef> & charDescList = serviceChar->descriptorList;
+ for(size_t k=0; k<charDescList.size(); k++) {
+ BTGattDesc & charDesc = *charDescList.at(k);
if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d.%2.2d] value: %s ('%s')\n", (int)i, (int)j, value.toString().c_str(), sval.c_str());
+ fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] Descriptor: UUID %s (%s)\n", i, j, k,
+ charDesc.type->toUUID128String().c_str(),
+ charDesc.type->getTypeSizeString().c_str());
+ fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] %s\n", i, j, k, charDesc.toString().c_str());
}
}
- }
- jau::darray<BTGattDescRef> & charDescList = serviceChar->descriptorList;
- for(size_t k=0; k<charDescList.size(); k++) {
- BTGattDesc & charDesc = *charDescList.at(k);
- if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] Descriptor: UUID %s (%s)\n", i, j, k,
- charDesc.type->toUUID128String().c_str(),
- charDesc.type->getTypeSizeString().c_str());
- fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] %s\n", i, j, k, charDesc.toString().c_str());
+ if( 0 == loop ) {
+ bool cccdEnableResult[2];
+ if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
+ // ClientCharConfigDescriptor (CCD) is available
+ std::shared_ptr<BTGattCharListener> gattEventListener = std::make_shared<MyGATTEventListener>(*this);
+ bool clAdded = serviceChar->addCharListener( gattEventListener );
+ REQUIRE( true == clAdded );
+ if( clAdded ) {
+ gattListener.push_back(gattEventListener);
+ }
+ if( GATT_VERBOSE ) {
+ fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
+ (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
+ fprintf_td(stderr, "\n");
+ }
+ }
}
}
- bool cccdEnableResult[2];
- if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
- // ClientCharConfigDescriptor (CCD) is available
- std::shared_ptr<BTGattChar::Listener> cl = std::make_shared<MyGATTEventListener>(*this, i, j);
- bool clAdded = serviceChar->addCharListener( cl );
- if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
- (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
- fprintf_td(stderr, "\n");
- }
+ if( GATT_VERBOSE ) {
+ fprintf_td(stderr, "\n");
}
}
- if( GATT_VERBOSE ) {
- fprintf_td(stderr, "\n");
- }
- }
+ success = notificationsReceived >= 2 || indicationsReceived >= 2;
+ ++loop;
+ } while( !success && device->getConnected() );
- {
- const fraction_timespec t0 = getMonotonicTime();
- bool timeout = false;
- do {
- success = completedGATTCommands >= 1 && ( notificationsReceived >= 2 || indicationsReceived >= 2 );
- if( !success ) {
- const fraction_i64 td = ( getMonotonicTime() - t0 ).to_fraction_i64();
- timeout = 3_s < td;
- if( !timeout ) {
- jau::sleep_for( 17_ms );
- }
- }
- } while( !success && !timeout );
+ for(BTGattCharListenerRef gcl : gattListener) {
+ REQUIRE( true == device->removeCharListener(gcl) );
}
- {
+ if( device->getConnected() ) {
// Tell server we have successfully completed the test.
BTGattCmd cmd = BTGattCmd(*device, "FinalHandshake", DBTConstants::CommandUUID, DBTConstants::ResponseUUID, 256);
cmd.setVerbose(true);
diff --git a/trial/direct_bt/dbt_client01.hpp b/trial/direct_bt/dbt_client01.hpp
index 99e93b44..1490ab4e 100644
--- a/trial/direct_bt/dbt_client01.hpp
+++ b/trial/direct_bt/dbt_client01.hpp
@@ -245,22 +245,21 @@ class DBTClient01 : public DBTClientTest {
};
- class MyGATTEventListener : public BTGattChar::Listener {
+ class MyGATTEventListener : public BTGattCharListener {
private:
DBTClient01& parent;
- int i, j;
public:
- MyGATTEventListener(DBTClient01& p, int i_, int j_) : parent(p), i(i_), j(j_) {}
+ MyGATTEventListener(DBTClient01& p) : parent(p) {}
void notificationReceived(BTGattCharRef charDecl, const TROOctets& char_value, const uint64_t timestamp) override {
if( GATT_VERBOSE ) {
const uint64_t tR = jau::getCurrentMilliseconds();
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n",
- i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp));
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
+ fprintf_td(stderr, "** Characteristic-Notify: UUID %s, td %" PRIu64 " ******\n",
+ charDecl->value_type->toUUID128String().c_str(), (tR-timestamp));
+ fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str());
+ fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str());
+ fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
}
parent.notificationsReceived++;
}
@@ -271,11 +270,11 @@ class DBTClient01 : public DBTClientTest {
{
if( GATT_VERBOSE ) {
const uint64_t tR = jau::getCurrentMilliseconds();
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n",
- i, j, charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent);
- fprintf_td(stderr, "**[%2.2d.%2.2d] Characteristic: %s ******\n", i, j, charDecl->toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value R: %s ******\n", i, j, char_value.toString().c_str());
- fprintf_td(stderr, "**[%2.2d.%2.2d] Value S: %s ******\n", i, j, jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
+ fprintf_td(stderr, "** Characteristic-Indication: UUID %s, td %" PRIu64 ", confirmed %d ******\n",
+ charDecl->value_type->toUUID128String().c_str(), (tR-timestamp), confirmationSent);
+ fprintf_td(stderr, "** Characteristic: %s ******\n", charDecl->toString().c_str());
+ fprintf_td(stderr, "** Value R: %s ******\n", char_value.toString().c_str());
+ fprintf_td(stderr, "** Value S: %s ******\n", jau::dfa_utf8_decode(char_value.get_ptr(), char_value.size()).c_str());
}
parent.indicationsReceived++;
}
@@ -438,6 +437,8 @@ class DBTClient01 : public DBTClientTest {
td13, td12, td23, td35);
}
+ std::vector<BTGattCharListenerRef> gattListener;
+ int loop = 0;
do {
for(size_t i=0; i<primServices.size(); i++) {
BTGattService & primService = *primServices.at(i);
@@ -475,15 +476,21 @@ class DBTClient01 : public DBTClientTest {
fprintf_td(stderr, " [%2.2d.%2.2d.%2.2d] %s\n", i, j, k, charDesc.toString().c_str());
}
}
- bool cccdEnableResult[2];
- if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
- // ClientCharConfigDescriptor (CCD) is available
- std::shared_ptr<BTGattChar::Listener> cl = std::make_shared<MyGATTEventListener>(*this, i, j);
- bool clAdded = serviceChar->addCharListener( cl );
- if( GATT_VERBOSE ) {
- fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
- (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
- fprintf_td(stderr, "\n");
+ if( 0 == loop ) {
+ bool cccdEnableResult[2];
+ if( serviceChar->enableNotificationOrIndication( cccdEnableResult ) ) {
+ // ClientCharConfigDescriptor (CCD) is available
+ std::shared_ptr<BTGattCharListener> gattEventListener = std::make_shared<MyGATTEventListener>(*this);
+ bool clAdded = serviceChar->addCharListener( gattEventListener );
+ REQUIRE( true == clAdded );
+ if( clAdded ) {
+ gattListener.push_back(gattEventListener);
+ }
+ if( GATT_VERBOSE ) {
+ fprintf_td(stderr, " [%2.2d.%2.2d] Characteristic-Listener: Notification(%d), Indication(%d): Added %d\n",
+ (int)i, (int)j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
+ fprintf_td(stderr, "\n");
+ }
}
}
}
@@ -492,8 +499,13 @@ class DBTClient01 : public DBTClientTest {
}
}
success = notificationsReceived >= 2 || indicationsReceived >= 2;
+ ++loop;
} while( !success && device->getConnected() );
+ for(BTGattCharListenerRef gcl : gattListener) {
+ REQUIRE( true == device->removeCharListener(gcl) );
+ }
+
if( device->getConnected() ) {
// Tell server we have successfully completed the test.
BTGattCmd cmd = BTGattCmd(*device, "FinalHandshake", DBTConstants::CommandUUID, DBTConstants::ResponseUUID, 256);
diff --git a/trial/java/trial/org/direct_bt/DBTClient00.java b/trial/java/trial/org/direct_bt/DBTClient00.java
index 10da69b1..db9ec99f 100644
--- a/trial/java/trial/org/direct_bt/DBTClient00.java
+++ b/trial/java/trial/org/direct_bt/DBTClient00.java
@@ -24,6 +24,7 @@
package trial.org.direct_bt;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -37,6 +38,7 @@ import org.direct_bt.BTAdapter;
import org.direct_bt.BTDevice;
import org.direct_bt.BTDeviceRegistry;
import org.direct_bt.BTGattChar;
+import org.direct_bt.BTGattCharListener;
import org.direct_bt.BTGattCmd;
import org.direct_bt.BTGattDesc;
import org.direct_bt.BTGattService;
@@ -55,8 +57,7 @@ import org.direct_bt.SMPKeyBin;
import org.direct_bt.SMPPairingState;
import org.direct_bt.ScanType;
import org.jau.net.EUI48;
-
-import trial.org.direct_bt.DBTClient01.MyAdapterStatusListener;
+import org.junit.Assert;
/**
* This central BTRole::Master participant works with DBTServer00.
@@ -307,21 +308,17 @@ public class DBTClient00 implements DBTClientTest {
}
};
- class MyGATTEventListener implements BTGattChar.Listener {
- private final int i, j;
-
- public MyGATTEventListener(final int i_, final int j_) { i=i_; j=j_; }
-
+ class MyGATTEventListener extends BTGattCharListener {
@Override
public void notificationReceived(final BTGattChar charDecl,
final byte[] value, final long timestamp) {
if( GATT_VERBOSE ) {
final long tR = BTUtils.currentTimeMillis();
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Notify: UUID %s, td %d ******\n",
- i, j, charDecl.getUUID(), (tR-timestamp));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ BTUtils.fprintf_td(System.err, "** Characteristic-Notify: UUID %s, td %d ******\n",
+ charDecl.getUUID(), (tR-timestamp));
+ BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString());
+ BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", BTUtils.decodeUTF8String(value, 0, value.length));
}
notificationsReceived.incrementAndGet();
}
@@ -331,11 +328,11 @@ public class DBTClient00 implements DBTClientTest {
final byte[] value, final long timestamp, final boolean confirmationSent) {
if( GATT_VERBOSE ) {
final long tR = BTUtils.currentTimeMillis();
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n",
- i, j, charDecl.getUUID(), (tR-timestamp), confirmationSent);
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ BTUtils.fprintf_td(System.err, "** Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n",
+ charDecl.getUUID(), (tR-timestamp), confirmationSent);
+ BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString());
+ BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", BTUtils.decodeUTF8String(value, 0, value.length));
}
indicationsReceived.incrementAndGet();
}
@@ -469,74 +466,77 @@ public class DBTClient00 implements DBTClientTest {
cmd.close();
}
- try {
- int i=0;
- for(final Iterator<BTGattService> srvIter = primServices.iterator(); srvIter.hasNext(); i++) {
- final BTGattService primService = srvIter.next();
- if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d] Service UUID %s\n", i, primService.getUUID());
- BTUtils.fprintf_td(System.err, " [%02d] %s\n", i, primService.toString());
- }
- int j=0;
- final List<BTGattChar> serviceCharacteristics = primService.getChars();
- for(final Iterator<BTGattChar> charIter = serviceCharacteristics.iterator(); charIter.hasNext(); j++) {
- final BTGattChar serviceChar = charIter.next();
+ final List<BTGattCharListener> gattListener = new ArrayList<BTGattCharListener>();
+ int loop = 0;
+ do {
+ try {
+ int i=0;
+ for(final Iterator<BTGattService> srvIter = primServices.iterator(); srvIter.hasNext(); i++) {
+ final BTGattService primService = srvIter.next();
if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic: UUID %s\n", i, j, serviceChar.getUUID());
- BTUtils.fprintf_td(System.err, " [%02d.%02d] %s\n", i, j, serviceChar.toString());
+ BTUtils.fprintf_td(System.err, " [%02d] Service UUID %s\n", i, primService.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d] %s\n", i, primService.toString());
}
- final GattCharPropertySet properties = serviceChar.getProperties();
- if( properties.isSet(GattCharPropertySet.Type.Read) ) {
- final byte[] value = serviceChar.readValue();
- final String svalue = BTUtils.decodeUTF8String(value, 0, value.length);
+ int j=0;
+ final List<BTGattChar> serviceCharacteristics = primService.getChars();
+ for(final Iterator<BTGattChar> charIter = serviceCharacteristics.iterator(); charIter.hasNext(); j++) {
+ final BTGattChar serviceChar = charIter.next();
if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d.%02d] value: %s ('%s')\n", i, j, BTUtils.bytesHexString(value, 0, -1, true), svalue);
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic: UUID %s\n", i, j, serviceChar.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] %s\n", i, j, serviceChar.toString());
}
- }
- int k=0;
- final List<BTGattDesc> charDescList = serviceChar.getDescriptors();
- for(final Iterator<BTGattDesc> descIter = charDescList.iterator(); descIter.hasNext(); k++) {
- final BTGattDesc charDesc = descIter.next();
- if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] Descriptor: UUID %s\n", i, j, k, charDesc.getUUID());
- BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] %s\n", i, j, k, charDesc.toString());
+ final GattCharPropertySet properties = serviceChar.getProperties();
+ if( properties.isSet(GattCharPropertySet.Type.Read) ) {
+ final byte[] value = serviceChar.readValue();
+ final String svalue = BTUtils.decodeUTF8String(value, 0, value.length);
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] value: %s ('%s')\n", i, j, BTUtils.bytesHexString(value, 0, -1, true), svalue);
+ }
}
- }
- final boolean cccdEnableResult[] = { false, false };
- if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
- // ClientCharConfigDescriptor (CCD) is available
- final boolean clAdded = null != serviceChar.addCharListener( new MyGATTEventListener(i, j) );
- if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
- i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
- BTUtils.fprintf_td(System.err, "\n");
+ int k=0;
+ final List<BTGattDesc> charDescList = serviceChar.getDescriptors();
+ for(final Iterator<BTGattDesc> descIter = charDescList.iterator(); descIter.hasNext(); k++) {
+ final BTGattDesc charDesc = descIter.next();
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] Descriptor: UUID %s\n", i, j, k, charDesc.getUUID());
+ BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] %s\n", i, j, k, charDesc.toString());
+ }
+ }
+ if( 0 == loop ) {
+ final boolean cccdEnableResult[] = { false, false };
+ if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
+ // ClientCharConfigDescriptor (CCD) is available
+ final MyGATTEventListener gattEventListener = new MyGATTEventListener();
+ final boolean clAdded = serviceChar.addCharListener( gattEventListener );
+ Assert.assertTrue(clAdded);
+ if( clAdded ) {
+ gattListener.add(gattEventListener);
+ }
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
+ i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
+ BTUtils.fprintf_td(System.err, "\n");
+ }
+ }
}
}
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, "\n");
+ }
}
- if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, "\n");
- }
+ success = notificationsReceived.get() >= 2 || indicationsReceived.get() >= 2;
+ ++loop;
+ } catch( final Exception ex) {
+ BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+ex.getMessage());
+ ex.printStackTrace();
}
- } catch( final Exception ex) {
- BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+ex.getMessage());
- ex.printStackTrace();
- }
+ } while( !success && device.getConnected() );
- {
- final long t0 = BTUtils.currentTimeMillis();
- boolean timeout = false;
- do {
- success = completedGATTCommands.get() >= 1 && ( notificationsReceived.get() >= 2 || indicationsReceived.get() >= 2 );
- if( !success ) {
- timeout = 3000 < ( BTUtils.currentTimeMillis() - t0 ); // 3s timeout
- if( !timeout ) {
- try { Thread.sleep(17); } catch (final InterruptedException e) { }
- }
- }
- } while( !success && !timeout );
+ for(final BTGattCharListener gcl : gattListener) {
+ Assert.assertTrue( device.removeCharListener(gcl) );
}
- {
+ if( device.getConnected() ) {
// Tell server we have successfully completed the test.
final BTGattCmd cmd = new BTGattCmd(device, "FinalHandshake", null /* service_uuid */, DBTConstants.CommandUUID, DBTConstants.ResponseUUID);
cmd.setVerbose(true);
diff --git a/trial/java/trial/org/direct_bt/DBTClient01.java b/trial/java/trial/org/direct_bt/DBTClient01.java
index eca16ba8..6a9488a7 100644
--- a/trial/java/trial/org/direct_bt/DBTClient01.java
+++ b/trial/java/trial/org/direct_bt/DBTClient01.java
@@ -24,6 +24,7 @@
package trial.org.direct_bt;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -37,6 +38,7 @@ import org.direct_bt.BTAdapter;
import org.direct_bt.BTDevice;
import org.direct_bt.BTDeviceRegistry;
import org.direct_bt.BTGattChar;
+import org.direct_bt.BTGattCharListener;
import org.direct_bt.BTGattCmd;
import org.direct_bt.BTGattDesc;
import org.direct_bt.BTGattService;
@@ -55,6 +57,7 @@ import org.direct_bt.SMPKeyBin;
import org.direct_bt.SMPPairingState;
import org.direct_bt.ScanType;
import org.jau.net.EUI48;
+import org.junit.Assert;
/**
* This central BTRole::Master participant works with DBTServer00.
@@ -309,21 +312,17 @@ public class DBTClient01 implements DBTClientTest {
}
};
- class MyGATTEventListener implements BTGattChar.Listener {
- private final int i, j;
-
- public MyGATTEventListener(final int i_, final int j_) { i=i_; j=j_; }
-
+ class MyGATTEventListener extends BTGattCharListener {
@Override
public void notificationReceived(final BTGattChar charDecl,
final byte[] value, final long timestamp) {
if( GATT_VERBOSE ) {
final long tR = BTUtils.currentTimeMillis();
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Notify: UUID %s, td %d ******\n",
- i, j, charDecl.getUUID(), (tR-timestamp));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ BTUtils.fprintf_td(System.err, "** Characteristic-Notify: UUID %s, td %d ******\n",
+ charDecl.getUUID(), (tR-timestamp));
+ BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString());
+ BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", BTUtils.decodeUTF8String(value, 0, value.length));
}
notificationsReceived.incrementAndGet();
}
@@ -333,11 +332,11 @@ public class DBTClient01 implements DBTClientTest {
final byte[] value, final long timestamp, final boolean confirmationSent) {
if( GATT_VERBOSE ) {
final long tR = BTUtils.currentTimeMillis();
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n",
- i, j, charDecl.getUUID(), (tR-timestamp), confirmationSent);
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Characteristic: %s ******\n", i, j, charDecl.toString());
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value R: size %d, ro: %s ******\n", i, j, value.length, BTUtils.bytesHexString(value, 0, -1, true));
- BTUtils.fprintf_td(System.err, "**[%02d.%02d] Value S: %s ******\n", i, j, BTUtils.decodeUTF8String(value, 0, value.length));
+ BTUtils.fprintf_td(System.err, "** Characteristic-Indication: UUID %s, td %d, confirmed %b ******\n",
+ charDecl.getUUID(), (tR-timestamp), confirmationSent);
+ BTUtils.fprintf_td(System.err, "** Characteristic: %s ******\n", charDecl.toString());
+ BTUtils.fprintf_td(System.err, "** Value R: size %d, ro: %s ******\n", value.length, BTUtils.bytesHexString(value, 0, -1, true));
+ BTUtils.fprintf_td(System.err, "** Value S: %s ******\n", BTUtils.decodeUTF8String(value, 0, value.length));
}
indicationsReceived.incrementAndGet();
}
@@ -449,6 +448,8 @@ public class DBTClient01 implements DBTClientTest {
"PERF: get-gatt-services " + td35 + " ms,"+System.lineSeparator());
}
+ final List<BTGattCharListener> gattListener = new ArrayList<BTGattCharListener>();
+ int loop = 0;
do {
try {
int i=0;
@@ -483,14 +484,21 @@ public class DBTClient01 implements DBTClientTest {
BTUtils.fprintf_td(System.err, " [%02d.%02d.%02d] %s\n", i, j, k, charDesc.toString());
}
}
- final boolean cccdEnableResult[] = { false, false };
- if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
- // ClientCharConfigDescriptor (CCD) is available
- final boolean clAdded = null != serviceChar.addCharListener( new MyGATTEventListener(i, j) );
- if( GATT_VERBOSE ) {
- BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
- i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
- BTUtils.fprintf_td(System.err, "\n");
+ if( 0 == loop ) {
+ final boolean cccdEnableResult[] = { false, false };
+ if( serviceChar.enableNotificationOrIndication( cccdEnableResult ) ) {
+ // ClientCharConfigDescriptor (CCD) is available
+ final MyGATTEventListener gattEventListener = new MyGATTEventListener();
+ final boolean clAdded = serviceChar.addCharListener( gattEventListener );
+ Assert.assertTrue(clAdded);
+ if( clAdded ) {
+ gattListener.add(gattEventListener);
+ }
+ if( GATT_VERBOSE ) {
+ BTUtils.fprintf_td(System.err, " [%02d.%02d] Characteristic-Listener: Notification(%b), Indication(%b): Added %b\n",
+ i, j, cccdEnableResult[0], cccdEnableResult[1], clAdded);
+ BTUtils.fprintf_td(System.err, "\n");
+ }
}
}
}
@@ -498,15 +506,18 @@ public class DBTClient01 implements DBTClientTest {
BTUtils.fprintf_td(System.err, "\n");
}
}
-
success = notificationsReceived.get() >= 2 || indicationsReceived.get() >= 2;
-
+ ++loop;
} catch( final Exception ex) {
BTUtils.println(System.err, "****** Client Processing Ready Device: Exception.2 caught for " + device.toString() + ": "+ex.getMessage());
ex.printStackTrace();
}
} while( !success && device.getConnected() );
+ for(final BTGattCharListener gcl : gattListener) {
+ Assert.assertTrue( device.removeCharListener(gcl) );
+ }
+
if( device.getConnected() ) {
// Tell server we have successfully completed the test.
final BTGattCmd cmd = new BTGattCmd(device, "FinalHandshake", null /* service_uuid */, DBTConstants.CommandUUID, DBTConstants.ResponseUUID);