summaryrefslogtreecommitdiffstats
path: root/api/direct_bt
diff options
context:
space:
mode:
Diffstat (limited to 'api/direct_bt')
-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
6 files changed, 114 insertions, 174 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 */ }