summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/BTDevice.hpp14
-rw-r--r--api/direct_bt/BTGattHandler.hpp11
-rw-r--r--java/org/direct_bt/BTDevice.java23
-rw-r--r--src/direct_bt/BTDevice.cpp52
-rw-r--r--src/direct_bt/BTGattHandler.cpp41
5 files changed, 84 insertions, 57 deletions
diff --git a/api/direct_bt/BTDevice.hpp b/api/direct_bt/BTDevice.hpp
index fc109d56..56333965 100644
--- a/api/direct_bt/BTDevice.hpp
+++ b/api/direct_bt/BTDevice.hpp
@@ -1033,19 +1033,25 @@ namespace direct_bt {
std::shared_ptr<BTGattHandler> getGattHandler() noexcept;
/**
- * Returns a list of shared GATTService available on this device if successful,
- * otherwise returns an empty list if an error occurred.
+ * Returns a complete list of shared BTGattService available on this device,
+ * initially retrieved via GATT discovery.
+ *
+ * In case of transmission error, zero services or no GattGenericAccessSvc,
+ * method will return zero services indicating an error.
+ * In this case, user can assume that the connection is or will be disconnected.
*
* Method is only functional on a remote BTDevice in BTRole::Slave, a GATT server (GATTRole::Server),
* i.e. the local BTAdapter acting as a BTRole::Master GATT client.
*
* The HCI connectLE(..) or connectBREDR(..) must be performed first, see {@link #connectDefault()}.
*
- * If this method has been called for the first time or no services have been detected yet:
+ * If this method has been called for the first time:
* - the client MTU exchange will be performed
- * - a list of GATTService will be retrieved
+ * - a complete list of BTGattService inclusive their BTGattChar and BTGattDesc will be retrieved
+ * - the GattGenericAccessSvc is extracted from the services, see getGattGenericAccess().
*
* A GATT connection will be created via connectGATT() if not established yet.
+ * @see getGattGenericAccess()
*/
jau::darray<BTGattServiceRef> getGattServices() noexcept;
diff --git a/api/direct_bt/BTGattHandler.hpp b/api/direct_bt/BTGattHandler.hpp
index 4dc08c9e..5f20d56c 100644
--- a/api/direct_bt/BTGattHandler.hpp
+++ b/api/direct_bt/BTGattHandler.hpp
@@ -555,17 +555,17 @@ namespace direct_bt {
* <p>
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.1 Discover All Primary Services
* </p>
- * Method returns reference to BTGattHandler's internal BTGattService vector of discovered services
+ * Populates the internal internal BTGattService vector of discovered services.
*
* Service discovery may consume 500ms - 2000ms, depending on bandwidth.
*
- * Method usually called via initClientGatt() and is only exposed special applications.
+ * Method called from initClientGatt().
*
* @param shared_this shared pointer of this instance, used to forward a weak_ptr to BTGattService for back-reference. Reference is validated.
- * @return BTGattHandler's internal BTGattService vector of discovered services
+ * @return true if successful, otherwise false
* @see initClientGatt()
*/
- jau::darray<BTGattServiceRef> & discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) noexcept;
+ bool discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) noexcept;
public:
/**
@@ -635,12 +635,13 @@ namespace direct_bt {
* Initialize the connection and internal data set for GATT client operations:
* - Exchange MTU
* - Discover all primary services, its characteristics and its descriptors
+ * - Extracts the GattGenericAccessSvc from the services, see getGenericAccess()
*
* Service discovery may consume 500ms - 2000ms, depending on bandwidth.
*
* @param shared_this the shared BTGattHandler reference
* @param already_init if already initialized true, will hold true, otherwise false
- * @return true if already initialized or newly initialized, otherwise false
+ * @return true if already initialized or successfully newly initialized with at least GattGenericAccessSvc available, otherwise false
* @see clientMTUExchange()
* @see discoverCompletePrimaryServices()
*/
diff --git a/java/org/direct_bt/BTDevice.java b/java/org/direct_bt/BTDevice.java
index efa640f0..57187d6b 100644
--- a/java/org/direct_bt/BTDevice.java
+++ b/java/org/direct_bt/BTDevice.java
@@ -628,20 +628,23 @@ public interface BTDevice extends BTObject
boolean isValid();
/**
- * Returns a list of shared BTGattService available on this device if successful,
- * otherwise returns an empty list if an error occurred.
- * <p>
+ * Returns a complete list of shared BTGattService available on this device,
+ * initially retrieved via GATT discovery.
+ *
+ * In case of transmission error, zero services or no GATT GenericAccess,
+ * method will return zero services indicating an error.
+ * In this case, user can assume that the connection is or will be disconnected.
+ *
* Method is only functional on a remote BTDevice in {@link BTRole#Slave}, a GATT server,
* i.e. the local BTAdapter acting as a {@link BTRole#Master} GATT client.
- * </p>
- * <p>
+ *
* The HCI connectLE(..) or connectBREDR(..) must be performed first, see {@link #connectDefault()}.
- * </p>
- * <p>
- * If this method has been called for the first time or no services have been detected yet:
+ *
+ * If this method has been called for the first time:
* - the client MTU exchange will be performed
- * - a list of GATTService will be retrieved
- * </p>
+ * - a complete list of BTGattService inclusive their BTGattChar and BTGattDesc will be retrieved
+ * - the GATT GenericAccess is extracted from the services.
+ *
* @since 2.4.0
*/
List<BTGattService> getGattServices();
diff --git a/src/direct_bt/BTDevice.cpp b/src/direct_bt/BTDevice.cpp
index 22887aee..1f89018d 100644
--- a/src/direct_bt/BTDevice.cpp
+++ b/src/direct_bt/BTDevice.cpp
@@ -1962,41 +1962,41 @@ jau::darray<BTGattServiceRef> BTDevice::getGattServices() noexcept {
}
bool gatt_already_init = false;
- const bool gatt_client_init = gh->initClientGatt(gh, gatt_already_init);
- jau::darray<BTGattServiceRef>& gattServices = gh->getServices();
- if( !gatt_client_init ) {
- ERR_PRINT2("BTDevice::getGattServices: Client GATT Initialization failed");
- return gattServices; // copy previous discovery result (zero sized)
+ if( !gh->initClientGatt(gh, gatt_already_init) ) {
+ ERR_PRINT2("Client GATT Initialization failed");
+ return jau::darray<BTGattServiceRef>(); // return zero size
}
if( gatt_already_init ) {
- return gattServices; // copy previous discovery result
+ return gh->getServices(); // copy previous discovery result
}
- // FIXME: GATTHandler::sendWithReply() == nullptr but gattServices.size() > 0 !!!
- if( gattServices.size() == 0 ) { // nothing discovered
- ERR_PRINT2("BTDevice::getGattServices: No primary services discovered");
- return gattServices;
+
+ jau::darray<BTGattServiceRef> result = gh->getServices(); // copy
+ if( result.size() == 0 ) { // nothing discovered, actually a redundant check done @ BTGattHandler::initClientGatt() 1st
+ ERR_PRINT2("No primary services discovered");
+ return jau::darray<BTGattServiceRef>(); // return zero size
}
// discovery success, parse GenericAccess
std::shared_ptr<GattGenericAccessSvc> gattGenericAccess = gh->getGenericAccess();
- if( nullptr != gattGenericAccess ) {
- const uint64_t ts = jau::getCurrentMilliseconds();
- EIRDataType updateMask = update(*gattGenericAccess, ts);
- DBG_PRINT("BTDevice::getGattServices: GenericAccess updated %s:\n %s\n -> %s",
- to_string(updateMask).c_str(), gattGenericAccess->toString().c_str(), toString().c_str());
- if( EIRDataType::NONE != updateMask ) {
- std::shared_ptr<BTDevice> sharedInstance = getSharedInstance();
- if( nullptr == sharedInstance ) {
- ERR_PRINT("Device unknown to adapter and not tracked: %s", toString().c_str());
- } else {
- adapter.sendDeviceUpdated("getGattServices", sharedInstance, ts, updateMask);
- }
+ if( nullptr == gattGenericAccess ) {
+ // no GenericAccess discovered, actually a redundant check done @ BTGattHandler::initClientGatt() 1st
+ ERR_PRINT2("No GenericAccess: %s", toString().c_str());
+ return jau::darray<BTGattServiceRef>(); // return zero size
+ }
+
+ const uint64_t ts = jau::getCurrentMilliseconds();
+ EIRDataType updateMask = update(*gattGenericAccess, ts);
+ DBG_PRINT("BTDevice::getGattServices: GenericAccess updated %s:\n %s\n -> %s",
+ to_string(updateMask).c_str(), gattGenericAccess->toString().c_str(), toString().c_str());
+ if( EIRDataType::NONE != updateMask ) {
+ std::shared_ptr<BTDevice> sharedInstance = getSharedInstance();
+ if( nullptr == sharedInstance ) {
+ ERR_PRINT("Device unknown to adapter and not tracked: %s", toString().c_str());
+ } else {
+ adapter.sendDeviceUpdated("getGattServices", sharedInstance, ts, updateMask);
}
- } else {
- // else: Actually an error w/o valid mandatory GenericAccess
- WARN_PRINT("No GenericAccess: %s", toString().c_str());
}
- return gattServices; // return copy
+ return result; // return the copy, copy elision shall be used
}
std::shared_ptr<GattGenericAccessSvc> BTDevice::getGattGenericAccess() {
diff --git a/src/direct_bt/BTGattHandler.cpp b/src/direct_bt/BTGattHandler.cpp
index ebb30be2..60cddd23 100644
--- a/src/direct_bt/BTGattHandler.cpp
+++ b/src/direct_bt/BTGattHandler.cpp
@@ -905,7 +905,7 @@ BTGattCharRef BTGattHandler::findCharacterisicsByValueHandle(const BTGattService
bool BTGattHandler::initClientGatt(std::shared_ptr<BTGattHandler> shared_this, bool& already_init) noexcept {
const std::lock_guard<std::recursive_mutex> lock(mtx_command);
- already_init = clientMTUExchanged && services.size() > 0;
+ already_init = clientMTUExchanged && services.size() > 0 && nullptr != genericAccess;
if( already_init ) {
return true;
}
@@ -929,36 +929,53 @@ bool BTGattHandler::initClientGatt(std::shared_ptr<BTGattHandler> shared_this, b
DBG_PRINT("GATTHandler::initClientGatt: Local GATT Client: MTU Exchanged: server %u -> used %u, %s", serverMTU.load(), usedMTU.load(), toString().c_str());
}
- if( services.size() > 0 ) {
+ if( services.size() > 0 && nullptr != genericAccess ) {
// already initialized
return true;
}
+ services.clear();
// Service discovery may consume 500ms - 2000ms, depending on bandwidth
DBG_PRINT("GATTHandler::initClientGatt: Local GATT Client: Service Discovery Start: %s", toString().c_str());
- jau::darray<BTGattServiceRef>& gattServices = discoverCompletePrimaryServices(shared_this);
- if( gattServices.size() == 0 ) { // nothing discovered
- ERR_PRINT2("No primary services discovered");
+ if( !discoverCompletePrimaryServices(shared_this) ) {
+ ERR_PRINT2("Failed service discovery");
+ services.clear();
+ disconnect(true /* disconnect_device */, true /* ioerr_cause */);
+ return false;
+ }
+ if( services.size() == 0 ) { // nothing discovered
+ ERR_PRINT2("No services discovered");
+ services.clear();
+ disconnect(true /* disconnect_device */, false /* ioerr_cause */);
+ return false;
+ }
+ genericAccess = getGenericAccess(services);
+ if( nullptr == genericAccess ) {
+ ERR_PRINT2("No GenericAccess discovered");
+ services.clear();
disconnect(true /* disconnect_device */, false /* ioerr_cause */);
return false;
}
- DBG_PRINT("GATTHandler::initClientGatt: %zu Services Discovered: %s", gattServices.size(), toString().c_str());
+ DBG_PRINT("GATTHandler::initClientGatt: End: %zu services discovered: %s, %s",
+ services.size(), genericAccess->toString().c_str(), toString().c_str());
return true;
}
-jau::darray<BTGattServiceRef> & BTGattHandler::discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) noexcept {
+bool BTGattHandler::discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) noexcept {
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
if( !discoverPrimaryServices(shared_this, services) ) {
- return services;
+ return false;
}
for(auto it = services.begin(); it != services.end(); it++) {
BTGattServiceRef primSrv = *it;
- if( discoverCharacteristics(primSrv) ) {
- discoverDescriptors(primSrv);
+ if( !discoverCharacteristics(primSrv) ) {
+ return false;
+ }
+ if( !discoverDescriptors(primSrv) ) {
+ return false;
}
}
- genericAccess = getGenericAccess(services);
- return services;
+ return true;
}
bool BTGattHandler::discoverPrimaryServices(std::shared_ptr<BTGattHandler> shared_this, jau::darray<BTGattServiceRef> & result) noexcept {