aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/BTGattHandler.hpp95
-rw-r--r--src/direct_bt/BTDevice.cpp58
-rw-r--r--src/direct_bt/BTGattHandler.cpp249
3 files changed, 208 insertions, 194 deletions
diff --git a/api/direct_bt/BTGattHandler.hpp b/api/direct_bt/BTGattHandler.hpp
index 45590fe2..beee8b5a 100644
--- a/api/direct_bt/BTGattHandler.hpp
+++ b/api/direct_bt/BTGattHandler.hpp
@@ -209,8 +209,9 @@ namespace direct_bt {
* Reply to an exchange MTU request
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.3.1 Exchange MTU (Server configuration)
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyExchangeMTUReq(const AttExchangeMTU * pdu) noexcept = 0;
+ virtual bool replyExchangeMTUReq(const AttExchangeMTU * pdu) noexcept = 0;
/**
* Reply to a read request
@@ -218,8 +219,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.3 Read Long Characteristic Value
* - For any follow up request, which previous request reply couldn't fit in ATT_MTU (Long Write)
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyReadReq(const AttPDUMsg * pdu) noexcept = 0;
+ virtual bool replyReadReq(const AttPDUMsg * pdu) noexcept = 0;
/**
* Reply to a write request.
@@ -237,8 +239,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value
*
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyWriteReq(const AttPDUMsg * pdu) noexcept = 0;
+ virtual bool replyWriteReq(const AttPDUMsg * pdu) noexcept = 0;
/**
* Reply to a find info request
@@ -247,8 +250,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.7.1 Discover All Characteristic Descriptors
*
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyFindInfoReq(const AttFindInfoReq * pdu) noexcept = 0;
+ virtual bool replyFindInfoReq(const AttFindInfoReq * pdu) noexcept = 0;
/**
* Reply to a find by type value request
@@ -256,8 +260,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part F ATT: 3.4.3.4 ATT_FIND_BY_TYPE_VALUE_RSP
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.2 Discover Primary Service by Service UUID
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyFindByTypeValueReq(const AttFindByTypeValueReq * pdu) noexcept = 0;
+ virtual bool replyFindByTypeValueReq(const AttFindByTypeValueReq * pdu) noexcept = 0;
/**
* Reply to a read by type request
@@ -266,8 +271,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service
*
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyReadByTypeReq(const AttReadByNTypeReq * pdu) noexcept = 0;
+ virtual bool replyReadByTypeReq(const AttReadByNTypeReq * pdu) noexcept = 0;
/**
* Reply to a read by group type request
@@ -276,8 +282,9 @@ namespace direct_bt {
* - BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.1 Discover All Primary Services
*
* @param pdu
+ * @return true if transmission was successful, otherwise false
*/
- virtual void replyReadByGroupTypeReq(const AttReadByNTypeReq * pdu) noexcept = 0;
+ virtual bool replyReadByGroupTypeReq(const AttReadByNTypeReq * pdu) noexcept = 0;
};
/**
@@ -470,7 +477,12 @@ namespace direct_bt {
DBGattCharRef findServerGattCharByValueHandle(const uint16_t char_value_handle) noexcept;
- void replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noexcept;
+ /**
+ * Reply given ATT message using the installed GattServerHandler gattServerHandler
+ * @param pdu the message
+ * @return true if transmission was successful, otherwise false
+ */
+ bool replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noexcept;
void l2capReaderWork(jau::service_runner& sr) noexcept;
void l2capReaderEndLocked(jau::service_runner& sr) noexcept;
@@ -486,7 +498,7 @@ namespace direct_bt {
*
* @see initClientGatt()
*/
- uint16_t clientMTUExchange(const int32_t timeout);
+ uint16_t clientMTUExchange(const int32_t timeout) noexcept;
/**
* Discover all primary services _only_.
@@ -498,7 +510,7 @@ namespace direct_bt {
* @see initClientGatt()
* @see discoverCompletePrimaryServices()
*/
- bool discoverPrimaryServices(std::shared_ptr<BTGattHandler> shared_this, jau::darray<BTGattServiceRef> & result);
+ bool discoverPrimaryServices(std::shared_ptr<BTGattHandler> shared_this, jau::darray<BTGattServiceRef> & result) noexcept;
/**
* Discover all characteristics of a service and declaration attributes _only_.
@@ -508,7 +520,7 @@ namespace direct_bt {
* @see initClientGatt()
* @see discoverCompletePrimaryServices()
*/
- bool discoverCharacteristics(BTGattServiceRef & service);
+ bool discoverCharacteristics(BTGattServiceRef & service) noexcept;
/**
* Discover all descriptors of a service _only_.
@@ -517,7 +529,7 @@ namespace direct_bt {
* @see initClientGatt()
* @see discoverCompletePrimaryServices()
*/
- bool discoverDescriptors(BTGattServiceRef & service);
+ bool discoverDescriptors(BTGattServiceRef & service) noexcept;
/**
* Discover all primary services _and_ all its characteristics declarations
@@ -535,7 +547,7 @@ namespace direct_bt {
* @return BTGattHandler's internal BTGattService vector of discovered services
* @see initClientGatt()
*/
- jau::darray<BTGattServiceRef> & discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this);
+ jau::darray<BTGattServiceRef> & discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) noexcept;
public:
/**
@@ -637,21 +649,17 @@ namespace direct_bt {
/**
* Sends the given AttPDUMsg to the connected device via l2cap.
*
- * Implementation throws an IllegalStateException if not connected,
- * a IllegalArgumentException if message size exceeds usedMTU-1.
- *
* ATT_MTU range
* - ATT_MTU minimum is 23 bytes (Vol 3, Part G: 5.2.1)
* - ATT_MTU is negotiated, maximum attribute value length is 512 bytes (Vol 3, Part F: 3.2.8-9)
* - ATT Value sent: [1 .. ATT_MTU-1] (Vol 3, Part F: 3.2.8-9)
*
- * Implementation disconnect() and throws an BluetoothException
- * if an l2cap write errors occurs.
+ * Implementation disconnect() and returns false if an unexpected l2cap write errors occurs.
*
- * In case method completes, the message has been send out successfully.
* @param msg the message to be send
+ * @return true if successful otherwise false if write error, not connected or if message size exceeds usedMTU-1.
*/
- void send(const AttPDUMsg & msg);
+ bool send(const AttPDUMsg & msg) noexcept;
/**
* Sends the given AttPDUMsg to the connected device via l2cap using {@link #send()}.
@@ -659,18 +667,17 @@ namespace direct_bt {
* Implementation waits for timeout milliseconds receiving the response
* from the ringbuffer, filled from the reader-thread.
*
- * Implementation disconnect() and throws an BluetoothException
+ * Implementation disconnect() and returns nullptr
* if no matching reply has been received within timeout milliseconds.
*
- * In case method completes, the message has been send out successfully
- * and a reply has also been received and is returned as a result.<br>
- * Hence this method either throws an exception or returns a matching reply.
+ * In case method completes successfully,
+ * the message has been send out and a reply has also been received and is returned as the result.
*
* @param msg the message to be send
* @param timeout milliseconds to wait for a reply
- * @return a valid reply, never nullptrs
+ * @return non nullptr for a valid reply, otherwise nullptr
*/
- std::unique_ptr<const AttPDUMsg> sendWithReply(const AttPDUMsg & msg, const int timeout);
+ std::unique_ptr<const AttPDUMsg> sendWithReply(const AttPDUMsg & msg, const int timeout) noexcept;
/**
* Generic read GATT value and long value
@@ -686,7 +693,7 @@ namespace direct_bt {
* if required until the response returns zero.
* </p>
*/
- bool readValue(const uint16_t handle, jau::POctets & res, int expectedLength=-1);
+ bool readValue(const uint16_t handle, jau::POctets & res, int expectedLength=-1) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.1 Read Characteristic Value
@@ -705,7 +712,7 @@ namespace direct_bt {
* if required until the response returns zero.
* </p>
*/
- bool readCharacteristicValue(const BTGattChar & c, jau::POctets & res, int expectedLength=-1);
+ bool readCharacteristicValue(const BTGattChar & c, jau::POctets & res, int expectedLength=-1) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.1 Read Characteristic Descriptor
@@ -724,12 +731,12 @@ namespace direct_bt {
* if required until the response returns zero.
* </p>
*/
- bool readDescriptorValue(BTGattDesc & cd, int expectedLength=-1);
+ bool readDescriptorValue(BTGattDesc & cd, int expectedLength=-1) noexcept;
/**
* Generic write GATT value and long value
*/
- bool writeValue(const uint16_t handle, const jau::TROOctets & value, const bool withResponse);
+ bool writeValue(const uint16_t handle, const jau::TROOctets & value, const bool withResponse) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.3 Write Characteristic Descriptors
@@ -740,17 +747,17 @@ namespace direct_bt {
* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration
* </p>
*/
- bool writeDescriptorValue(const BTGattDesc & cd);
+ bool writeDescriptorValue(const BTGattDesc & cd) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value
*/
- bool writeCharacteristicValue(const BTGattChar & c, const jau::TROOctets & value);
+ bool writeCharacteristicValue(const BTGattChar & c, const jau::TROOctets & value) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.1 Write Characteristic Value Without Response
*/
- bool writeCharacteristicValueNoResp(const BTGattChar & c, const jau::TROOctets & value);
+ bool writeCharacteristicValueNoResp(const BTGattChar & c, const jau::TROOctets & value) noexcept;
/**
* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration
@@ -765,7 +772,7 @@ namespace direct_bt {
* Throws an IllegalArgumentException if the given BTGattDesc is not a ClientCharacteristicConfiguration.
* </p>
*/
- bool configNotificationIndication(BTGattDesc & cd, const bool enableNotification, const bool enableIndication);
+ bool configNotificationIndication(BTGattDesc & cd, const bool enableNotification, const bool enableIndication) noexcept;
/**
* Send a notification event consisting out of the given `value` representing the given characteristic value handle
@@ -778,7 +785,7 @@ namespace direct_bt {
* @param char_value_handle valid characteristic value handle, must be sourced from referenced DBGattServer
* @return true if successful, otherwise false
*/
- bool sendNotification(const uint16_t char_value_handle, const jau::TROOctets & value);
+ bool sendNotification(const uint16_t char_value_handle, const jau::TROOctets & value) noexcept;
/**
* Send an indication event consisting out of the given `value` representing the given characteristic value handle
@@ -791,7 +798,7 @@ namespace direct_bt {
* @param char_value_handle valid characteristic value handle, must be sourced from referenced DBGattServer
* @return true if successful, otherwise false
*/
- bool sendIndication(const uint16_t char_value_handle, const jau::TROOctets & value);
+ bool sendIndication(const uint16_t char_value_handle, const jau::TROOctets & value) noexcept;
/**
* Add the given listener to the list if not already present.
@@ -800,7 +807,7 @@ namespace direct_bt {
* otherwise false.
* </p>
*/
- bool addCharListener(std::shared_ptr<BTGattCharListener> l);
+ bool addCharListener(std::shared_ptr<BTGattCharListener> l) noexcept;
/**
* Remove the given listener from the list.
@@ -840,7 +847,7 @@ namespace direct_bt {
* otherwise false.
* </p>
*/
- bool addCharListener(std::shared_ptr<NativeGattCharListener> l);
+ bool addCharListener(std::shared_ptr<NativeGattCharListener> l) noexcept;
/**
* Remove the given listener from the list.
@@ -965,7 +972,7 @@ namespace direct_bt {
* This setting is per BTGattHandler and hence per BTDevice.
* </p>
*/
- void setSendIndicationConfirmation(const bool v);
+ void setSendIndicationConfirmation(const bool v) noexcept;
/**
* Returns whether sending an immediate confirmation for received indication events from the device is enabled.
@@ -982,11 +989,11 @@ namespace direct_bt {
/** Higher level semantic functionality **/
/*****************************************************/
- std::shared_ptr<GattGenericAccessSvc> getGenericAccess(jau::darray<BTGattServiceRef> & primServices);
- std::shared_ptr<GattGenericAccessSvc> getGenericAccess(jau::darray<BTGattCharRef> & genericAccessCharDeclList);
+ std::shared_ptr<GattGenericAccessSvc> getGenericAccess(jau::darray<BTGattServiceRef> & primServices) noexcept;
+ std::shared_ptr<GattGenericAccessSvc> getGenericAccess(jau::darray<BTGattCharRef> & genericAccessCharDeclList) noexcept;
- std::shared_ptr<GattDeviceInformationSvc> getDeviceInformation(jau::darray<BTGattServiceRef> & primServices);
- std::shared_ptr<GattDeviceInformationSvc> getDeviceInformation(jau::darray<BTGattCharRef> & deviceInfoCharDeclList);
+ std::shared_ptr<GattDeviceInformationSvc> getDeviceInformation(jau::darray<BTGattServiceRef> & primServices) noexcept;
+ std::shared_ptr<GattDeviceInformationSvc> getDeviceInformation(jau::darray<BTGattCharRef> & deviceInfoCharDeclList) noexcept;
/**
* Issues a ping to the device, validating whether it is still reachable.
@@ -999,7 +1006,7 @@ namespace direct_bt {
* </p>
* @return `true` if successful, otherwise false in case no GATT services exists etc.
*/
- bool ping();
+ bool ping() noexcept;
std::string toString() const noexcept;
};
diff --git a/src/direct_bt/BTDevice.cpp b/src/direct_bt/BTDevice.cpp
index 67569771..68ca0e65 100644
--- a/src/direct_bt/BTDevice.cpp
+++ b/src/direct_bt/BTDevice.cpp
@@ -1975,28 +1975,25 @@ jau::darray<BTGattServiceRef> BTDevice::getGattServices() noexcept {
ERR_PRINT2("BTDevice::getGattServices: No primary services discovered");
return gattServices;
}
- try {
- // 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);
- }
+
+ // 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);
}
- } else {
- // else: Actually an error w/o valid mandatory GenericAccess
- WARN_PRINT("No GenericAccess: %s", toString().c_str());
}
- } catch (std::exception &e) {
- WARN_PRINT("Caught exception: '%s' on %s", e.what(), toString().c_str());
+ } else {
+ // else: Actually an error w/o valid mandatory GenericAccess
+ WARN_PRINT("No GenericAccess: %s", toString().c_str());
}
return gattServices; // return copy
}
@@ -2051,12 +2048,7 @@ bool BTDevice::sendNotification(const uint16_t char_value_handle, const jau::TRO
WARN_PRINT("GATTHandler not connected -> disconnected on %s", toString().c_str());
return false;
}
- try {
- return gh->sendNotification(char_value_handle, value);
- } catch (std::exception &e) {
- IRQ_PRINT("Potential disconnect, exception: '%s' on %s", e.what(), toString().c_str());
- }
- return false;
+ return gh->sendNotification(char_value_handle, value);
}
bool BTDevice::sendIndication(const uint16_t char_value_handle, const jau::TROOctets & value) noexcept {
@@ -2069,12 +2061,7 @@ bool BTDevice::sendIndication(const uint16_t char_value_handle, const jau::TROOc
WARN_PRINT("GATTHandler not connected -> disconnected on %s", toString().c_str());
return false;
}
- try {
- return gh->sendIndication(char_value_handle, value);
- } catch (std::exception &e) {
- IRQ_PRINT("Potential disconnect, exception: '%s' on %s", e.what(), toString().c_str());
- }
- return false;
+ return gh->sendIndication(char_value_handle, value);
}
@@ -2085,12 +2072,7 @@ bool BTDevice::pingGATT() noexcept {
disconnect(HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION);
return false;
}
- try {
- return gh->ping();
- } catch (std::exception &e) {
- IRQ_PRINT("Potential disconnect, exception: '%s' on %s", e.what(), toString().c_str());
- }
- return false;
+ return gh->ping();
}
bool BTDevice::addCharListener(std::shared_ptr<BTGattCharListener> l) {
diff --git a/src/direct_bt/BTGattHandler.cpp b/src/direct_bt/BTGattHandler.cpp
index 3ce64501..714937ea 100644
--- a/src/direct_bt/BTGattHandler.cpp
+++ b/src/direct_bt/BTGattHandler.cpp
@@ -105,9 +105,10 @@ bool BTGattHandler::validateConnected() noexcept {
static jau::cow_darray<std::shared_ptr<BTGattCharListener>>::equal_comparator _btGattCharListenerRefEqComparator =
[](const std::shared_ptr<BTGattCharListener> &a, const std::shared_ptr<BTGattCharListener> &b) -> bool { return *a == *b; };
-bool BTGattHandler::addCharListener(std::shared_ptr<BTGattCharListener> l) {
+bool BTGattHandler::addCharListener(std::shared_ptr<BTGattCharListener> l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("GATTEventListener ref is null", E_FILE_LINE);
+ ERR_PRINT("GATTCharacteristicListener ref is null");
+ return false;
}
return btGattCharListenerList.push_back_unique(l, _btGattCharListenerRefEqComparator);
}
@@ -140,9 +141,10 @@ bool BTGattHandler::removeCharListener(const BTGattCharListener * l) noexcept {
static jau::cow_darray<std::shared_ptr<BTGattHandler::NativeGattCharListener>>::equal_comparator _nativeGattCharListenerRefEqComparator =
[](const std::shared_ptr<BTGattHandler::NativeGattCharListener> &a, const std::shared_ptr<BTGattHandler::NativeGattCharListener> &b) -> bool { return *a == *b; };
-bool BTGattHandler::addCharListener(std::shared_ptr<NativeGattCharListener> l){
+bool BTGattHandler::addCharListener(std::shared_ptr<NativeGattCharListener> l) noexcept {
if( nullptr == l ) {
- throw jau::IllegalArgumentException("NativeGattCharListener ref is null", E_FILE_LINE);
+ ERR_PRINT("NativeGattCharListener ref is null");
+ return false;
}
return nativeGattCharListenerList.push_back_unique(l, _nativeGattCharListenerRefEqComparator);
}
@@ -319,7 +321,7 @@ void BTGattHandler::notifyNativeReadResponse(const uint16_t handle, const uint16
}
}
-void BTGattHandler::setSendIndicationConfirmation(const bool v) {
+void BTGattHandler::setSendIndicationConfirmation(const bool v) noexcept {
sendIndicationConfirmation = v;
}
@@ -327,43 +329,37 @@ bool BTGattHandler::getSendIndicationConfirmation() noexcept {
return sendIndicationConfirmation;
}
-void BTGattHandler::replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noexcept {
+bool BTGattHandler::replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noexcept {
if( !validateConnected() ) { // shall not happen
DBG_PRINT("GATT-Req: disconnected: req %s from %s",
pdu->toString().c_str(), toString().c_str());
- return;
+ return false;
}
switch( pdu->getOpcode() ) {
case AttPDUMsg::Opcode::EXCHANGE_MTU_REQ: { // 2
- gattServerHandler->replyExchangeMTUReq( static_cast<const AttExchangeMTU*>( pdu.get() ) );
- return;
+ return gattServerHandler->replyExchangeMTUReq( static_cast<const AttExchangeMTU*>( pdu.get() ) );
}
case AttPDUMsg::Opcode::FIND_INFORMATION_REQ: { // 4
- gattServerHandler->replyFindInfoReq( static_cast<const AttFindInfoReq*>( pdu.get() ) );
- return;
+ return gattServerHandler->replyFindInfoReq( static_cast<const AttFindInfoReq*>( pdu.get() ) );
}
case AttPDUMsg::Opcode::FIND_BY_TYPE_VALUE_REQ: { // 6
- gattServerHandler->replyFindByTypeValueReq( static_cast<const AttFindByTypeValueReq*>( pdu.get() ) );
- return;
+ return gattServerHandler->replyFindByTypeValueReq( static_cast<const AttFindByTypeValueReq*>( pdu.get() ) );
}
case AttPDUMsg::Opcode::READ_BY_TYPE_REQ: { // 8
- gattServerHandler->replyReadByTypeReq( static_cast<const AttReadByNTypeReq*>( pdu.get() ) );
- return;
+ return gattServerHandler->replyReadByTypeReq( static_cast<const AttReadByNTypeReq*>( pdu.get() ) );
}
case AttPDUMsg::Opcode::READ_REQ: // 10
[[fallthrough]];
case AttPDUMsg::Opcode::READ_BLOB_REQ: { // 12
- gattServerHandler->replyReadReq( pdu.get() );
- return;
+ return gattServerHandler->replyReadReq( pdu.get() );
}
case AttPDUMsg::Opcode::READ_BY_GROUP_TYPE_REQ: { // 16
- gattServerHandler->replyReadByGroupTypeReq( static_cast<const AttReadByNTypeReq*>( pdu.get() ) );
- return;
+ return gattServerHandler->replyReadByGroupTypeReq( static_cast<const AttReadByNTypeReq*>( pdu.get() ) );
}
case AttPDUMsg::Opcode::WRITE_REQ: // 18
@@ -373,8 +369,7 @@ void BTGattHandler::replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noex
case AttPDUMsg::Opcode::PREPARE_WRITE_REQ: // 22
[[fallthrough]];
case AttPDUMsg::Opcode::EXECUTE_WRITE_REQ: { // 24
- gattServerHandler->replyWriteReq( pdu.get() );
- return;
+ return gattServerHandler->replyWriteReq( pdu.get() );
}
// TODO: Add support for the following requests
@@ -386,15 +381,21 @@ void BTGattHandler::replyAttPDUReq(std::unique_ptr<const AttPDUMsg> && pdu) noex
case AttPDUMsg::Opcode::SIGNED_WRITE_CMD: { // 18 + 64 + 128 = 210
AttErrorRsp rsp(AttErrorRsp::ErrorCode::UNSUPPORTED_REQUEST, pdu->getOpcode(), 0);
WARN_PRINT("GATT Req: Ignored: %s -> %s from %s", pdu->toString().c_str(), rsp.toString().c_str(), toString().c_str());
- send(rsp);
- return;
+ if( !send(rsp) ) {
+ ERR_PRINT2("l2cap send: Error req %s; %s", rsp.toString().c_str(), toString().c_str());
+ return false;
+ }
+ return true;
}
default:
AttErrorRsp rsp(AttErrorRsp::ErrorCode::FORBIDDEN_VALUE, pdu->getOpcode(), 0);
ERR_PRINT("GATT Req: Unhandled: %s -> %s from %s", pdu->toString().c_str(), rsp.toString().c_str(), toString().c_str());
- send(rsp);
- return;
+ if( !send(rsp) ) {
+ ERR_PRINT2("l2cap send: Error req %s; %s", rsp.toString().c_str(), toString().c_str());
+ return false;
+ }
+ return true;
}
}
@@ -462,7 +463,12 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
bool cfmSent = false;
if( sendIndicationConfirmation ) {
AttHandleValueCfm cfm;
- send(cfm);
+ if( !send(cfm) ) {
+ ERR_PRINT2("Indication Confirmation: Error req %s; %s", cfm.toString().c_str(), toString().c_str());
+ sr.set_shall_stop();
+ has_ioerror = true;
+ return;
+ }
cfmSent = true;
}
const uint64_t a_timestamp = a->ts_creation;
@@ -503,7 +509,12 @@ void BTGattHandler::l2capReaderWork(jau::service_runner& sr) noexcept {
COND_PRINT(env.DEBUG_DATA, "GATTHandler::reader: Ring: %s", attPDU->toString().c_str());
attPDURing.putBlocking( std::move(attPDU) );
} else if( AttPDUMsg::OpcodeType::REQUEST == opc_type ) {
- replyAttPDUReq( std::move( attPDU ) );
+ if( !replyAttPDUReq( std::move( attPDU ) ) ) {
+ ERR_PRINT2("ATT Reply: %s", toString().c_str());
+ sr.set_shall_stop();
+ has_ioerror = true;
+ return;
+ }
} else {
ERR_PRINT("Unhandled: %s", attPDU->toString().c_str());
}
@@ -679,57 +690,64 @@ bool BTGattHandler::disconnect(const bool disconnect_device, const bool ioerr_ca
return true;
}
-void BTGattHandler::send(const AttPDUMsg & msg) {
+bool BTGattHandler::send(const AttPDUMsg & msg) noexcept {
if( !validateConnected() ) {
- throw jau::IllegalStateException("GATTHandler::send: Invalid IO State: req "+msg.toString()+" to "+toString(), E_FILE_LINE);
+ if( !l2capReaderInterrupted() ) {
+ ERR_PRINT("Invalid IO State: req %s to %s", msg.toString().c_str(), toString().c_str());
+ }
+ return false;
}
// [1 .. ATT_MTU-1] BT Core Spec v5.2: Vol 3, Part F 3.2.9 Long attribute values
if( msg.pdu.size() > usedMTU ) {
- throw jau::IllegalArgumentException("Msg PDU size "+std::to_string(msg.pdu.size())+" >= usedMTU "+std::to_string(usedMTU)+
- ", "+msg.toString()+" to "+toString(), E_FILE_LINE);
+ ERR_PRINT("Msg PDU size %zu >= used MTU %u, req %s to $s",
+ msg.pdu.size(), usedMTU.load(), msg.toString().c_str(), toString().c_str());
+ return false;
}
// Thread safe l2cap.write(..) operation..
const jau::snsize_t len = l2cap.write(msg.pdu.get_ptr(), msg.pdu.size());
if( len != L2CAPClient::number(L2CAPClient::RWExitCode::INTERRUPTED) ) { // expected exits
if( 0 > len ) {
- IRQ_PRINT("l2cap write: Error res %d (%s); %s; %s -> disconnect: %s",
+ ERR_PRINT("l2cap write: Error res %d (%s); %s; %s -> disconnect: %s",
len, L2CAPClient::getRWExitCodeString(len).c_str(), getStateString().c_str(),
msg.toString().c_str(), toString().c_str());
has_ioerror = true;
disconnect(true /* disconnect_device */, true /* ioerr_cause */); // state -> Disconnected
- throw BTException("GATTHandler::send: l2cap write: Error: req "+msg.toString()+" -> disconnect: "+toString(), E_FILE_LINE);
+ return false;
}
if( static_cast<size_t>(len) != msg.pdu.size() ) {
ERR_PRINT("l2cap write: Error: Message size has %d != exp %zu: %s -> disconnect: %s",
len, msg.pdu.size(), msg.toString().c_str(), toString().c_str());
has_ioerror = true;
disconnect(true /* disconnect_device */, true /* ioerr_cause */); // state -> Disconnected
- throw BTException("GATTHandler::send: l2cap write: Error: Message size has "+std::to_string(len)+" != exp "+std::to_string(msg.pdu.size())
- +": "+msg.toString()+" -> disconnect: "+toString(), E_FILE_LINE);
+ return false;
}
+ return true;
} else {
WORDY_PRINT("GATTHandler::reader: l2cap read: IRQed res %d (%s); %s",
len, L2CAPClient::getRWExitCodeString(len).c_str(), getStateString().c_str());
+ return false;
}
}
-std::unique_ptr<const AttPDUMsg> BTGattHandler::sendWithReply(const AttPDUMsg & msg, const int timeout) {
- send( msg );
+std::unique_ptr<const AttPDUMsg> BTGattHandler::sendWithReply(const AttPDUMsg & msg, const int timeout) noexcept {
+ if( !send( msg ) ) {
+ return nullptr;
+ }
// Ringbuffer read is thread safe
std::unique_ptr<const AttPDUMsg> res;
if( !attPDURing.getBlocking(res, timeout) || nullptr == res ) {
errno = ETIMEDOUT;
- IRQ_PRINT("GATTHandler::sendWithReply: nullptr result (timeout %d): req %s to %s", timeout, msg.toString().c_str(), toString().c_str());
+ ERR_PRINT("GATTHandler::sendWithReply: nullptr result (timeout %d): req %s to %s", timeout, msg.toString().c_str(), toString().c_str());
has_ioerror = true;
disconnect(true /* disconnect_device */, true /* ioerr_cause */);
- throw BTException("GATTHandler::sendWithReply: nullptr result (timeout "+std::to_string(timeout)+"): req "+msg.toString()+" to "+toString(), E_FILE_LINE);
+ return nullptr;
}
return res;
}
-uint16_t BTGattHandler::clientMTUExchange(const int32_t timeout) {
+uint16_t BTGattHandler::clientMTUExchange(const int32_t timeout) noexcept {
if( GATTRole::Client != getRole() ) {
ERR_PRINT("GATT MTU exchange only allowed in client mode");
return usedMTU;
@@ -744,9 +762,11 @@ uint16_t BTGattHandler::clientMTUExchange(const int32_t timeout) {
uint16_t mtu = 0;
DBG_PRINT("GATT MTU-REQ send: %s to %s", req.toString().c_str(), toString().c_str());
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, timeout);
- if( pdu->getOpcode() == AttPDUMsg::Opcode::EXCHANGE_MTU_RSP ) {
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ } else if( pdu->getOpcode() == AttPDUMsg::Opcode::EXCHANGE_MTU_RSP ) {
const AttExchangeMTU * p = static_cast<const AttExchangeMTU*>(pdu.get());
mtu = p->getMTUSize();
DBG_PRINT("GATT MTU-RSP recv: %u, %s from %s", mtu, pdu->toString().c_str(), toString().c_str());
@@ -779,7 +799,7 @@ DBGattCharRef BTGattHandler::findServerGattCharByValueHandle(const uint16_t char
}
}
-bool BTGattHandler::sendNotification(const uint16_t char_value_handle, const jau::TROOctets & value) {
+bool BTGattHandler::sendNotification(const uint16_t char_value_handle, const jau::TROOctets & value) noexcept {
if( GATTRole::Server != role ) {
ERR_PRINT("GATTRole not server");
return false;
@@ -797,11 +817,10 @@ bool BTGattHandler::sendNotification(const uint16_t char_value_handle, const jau
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
AttHandleValueRcv data(true /* isNotify */, char_value_handle, value, usedMTU);
COND_PRINT(env.DEBUG_DATA, "GATT SEND NTF: %s to %s", data.toString().c_str(), toString().c_str());
- send(data);
- return true;
+ return send(data);
}
-bool BTGattHandler::sendIndication(const uint16_t char_value_handle, const jau::TROOctets & value) {
+bool BTGattHandler::sendIndication(const uint16_t char_value_handle, const jau::TROOctets & value) noexcept {
if( GATTRole::Server != role ) {
ERR_PRINT("GATTRole not server");
return false;
@@ -818,7 +837,11 @@ bool BTGattHandler::sendIndication(const uint16_t char_value_handle, const jau::
}
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
AttHandleValueRcv req(false /* isNotify */, char_value_handle, value, usedMTU);
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, write_cmd_reply_timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, write_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
if( pdu->getOpcode() == AttPDUMsg::Opcode::HANDLE_VALUE_CFM ) {
COND_PRINT(env.DEBUG_DATA, "GATT SENT IND: %s -> %s to/from %s",
req.toString().c_str(), pdu->toString().c_str(), toString().c_str());
@@ -863,17 +886,8 @@ bool BTGattHandler::initClientGatt(std::shared_ptr<BTGattHandler> shared_this, b
if( !clientMTUExchanged) {
// First point of failure if remote device exposes no GATT functionality. Allow a longer timeout!
const int32_t initial_command_reply_timeout = std::min<int32_t>(10000, std::max<int32_t>(env.GATT_INITIAL_COMMAND_REPLY_TIMEOUT, 2*supervision_timeout));
- uint16_t mtu = 0;
- try {
- DBG_PRINT("GATTHandler::initClientGatt: Local GATT Client: MTU Exchange Start: %s", toString().c_str());
- mtu = clientMTUExchange(initial_command_reply_timeout);
- } catch (std::exception &e) {
- ERR_PRINT2("ExchangeMTU failed: %s", e.what());
- } catch (std::string &msg) {
- ERR_PRINT2("ExchangeMTU failed: %s", msg.c_str());
- } catch (const char *msg) {
- ERR_PRINT2("ExchangeMTU failed: %s", msg);
- }
+ DBG_PRINT("GATTHandler::initClientGatt: Local GATT Client: MTU Exchange Start: %s", toString().c_str());
+ uint16_t mtu = clientMTUExchange(initial_command_reply_timeout);
if( 0 == mtu ) {
ERR_PRINT2("Local GATT Client: Zero serverMTU -> disconnect: %s", toString().c_str());
disconnect(true /* disconnect_device */, false /* ioerr_cause */);
@@ -890,24 +904,19 @@ bool BTGattHandler::initClientGatt(std::shared_ptr<BTGattHandler> shared_this, b
return true;
}
- try {
- // 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");
- disconnect(true /* disconnect_device */, false /* ioerr_cause */);
- return false;
- }
- DBG_PRINT("GATTHandler::initClientGatt: %zu Services Discovered: %s", gattServices.size(), toString().c_str());
- return true;
- } catch (std::exception &e) {
- WARN_PRINT("GATTHandler::initClientGatt: Caught exception: '%s' on %s", e.what(), toString().c_str());
+ // 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");
+ disconnect(true /* disconnect_device */, false /* ioerr_cause */);
+ return false;
}
- return false;
+ DBG_PRINT("GATTHandler::initClientGatt: %zu Services Discovered: %s", gattServices.size(), toString().c_str());
+ return true;
}
-jau::darray<BTGattServiceRef> & BTGattHandler::discoverCompletePrimaryServices(std::shared_ptr<BTGattHandler> shared_this) {
+jau::darray<BTGattServiceRef> & 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;
@@ -922,13 +931,13 @@ jau::darray<BTGattServiceRef> & BTGattHandler::discoverCompletePrimaryServices(s
return services;
}
-bool BTGattHandler::discoverPrimaryServices(std::shared_ptr<BTGattHandler> shared_this, jau::darray<BTGattServiceRef> & result) {
+bool BTGattHandler::discoverPrimaryServices(std::shared_ptr<BTGattHandler> shared_this, jau::darray<BTGattServiceRef> & result) noexcept {
{
// validate shared_this first!
BTGattHandler *given_this = shared_this.get();
if( given_this != this ) {
- throw jau::IllegalArgumentException("Given shared GATTHandler reference "+
- jau::to_hexstring(given_this)+" not matching this "+jau::to_hexstring(this), E_FILE_LINE);
+ ABORT("Given shared GATTHandler reference %s not matching this %s, %s",
+ jau::to_hexstring(given_this).c_str(), jau::to_hexstring(this).c_str(), toString().c_str());
}
}
/***
@@ -949,7 +958,11 @@ bool BTGattHandler::discoverPrimaryServices(std::shared_ptr<BTGattHandler> share
const AttReadByNTypeReq req(true /* group */, startHandle, 0xffff, groupType);
COND_PRINT(env.DEBUG_DATA, "GATT PRIM SRV discover send: %s to %s", req.toString().c_str(), toString().c_str());
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
COND_PRINT(env.DEBUG_DATA, "GATT PRIM SRV discover recv: %s on %s", pdu->toString().c_str(), toString().c_str());
if( pdu->getOpcode() == AttPDUMsg::Opcode::READ_BY_GROUP_TYPE_RSP ) {
@@ -986,7 +999,7 @@ bool BTGattHandler::discoverPrimaryServices(std::shared_ptr<BTGattHandler> share
return result.size() > 0;
}
-bool BTGattHandler::discoverCharacteristics(BTGattServiceRef & service) {
+bool BTGattHandler::discoverCharacteristics(BTGattServiceRef & service) noexcept {
/***
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service
* <p>
@@ -1009,7 +1022,11 @@ bool BTGattHandler::discoverCharacteristics(BTGattServiceRef & service) {
const AttReadByNTypeReq req(false /* group */, handle, service->end_handle, characteristicTypeReq);
COND_PRINT(env.DEBUG_DATA, "GATT C discover send: %s to %s", req.toString().c_str(), toString().c_str());
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
COND_PRINT(env.DEBUG_DATA, "GATT C discover recv: %s from %s", pdu->toString().c_str(), toString().c_str());
if( pdu->getOpcode() == AttPDUMsg::Opcode::READ_BY_TYPE_RSP ) {
@@ -1050,7 +1067,7 @@ bool BTGattHandler::discoverCharacteristics(BTGattServiceRef & service) {
return service->characteristicList.size() > 0;
}
-bool BTGattHandler::discoverDescriptors(BTGattServiceRef & service) {
+bool BTGattHandler::discoverDescriptors(BTGattServiceRef & service) noexcept {
/***
* BT Core Spec v5.2: Vol 3, Part G GATT: 4.7.1 Discover All Characteristic Descriptors
* <p>
@@ -1081,7 +1098,11 @@ bool BTGattHandler::discoverDescriptors(BTGattServiceRef & service) {
const AttFindInfoReq req(cd_handle_iter, cd_handle_end);
COND_PRINT(env.DEBUG_DATA, "GATT CD discover send: %s", req.toString().c_str());
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, read_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
COND_PRINT(env.DEBUG_DATA, "GATT CD discover recv: %s from ", pdu->toString().c_str(), toString().c_str());
if( pdu->getOpcode() == AttPDUMsg::Opcode::FIND_INFORMATION_RSP ) {
@@ -1138,7 +1159,7 @@ bool BTGattHandler::discoverDescriptors(BTGattServiceRef & service) {
return service->characteristicList.size() > 0;
}
-bool BTGattHandler::readDescriptorValue(BTGattDesc & desc, int expectedLength) {
+bool BTGattHandler::readDescriptorValue(BTGattDesc & desc, int expectedLength) noexcept {
COND_PRINT(env.DEBUG_DATA, "GATTHandler::readDescriptorValue expLen %d, desc %s", expectedLength, desc.toString().c_str());
const bool res = readValue(desc.handle, desc.value, expectedLength);
if( !res ) {
@@ -1148,7 +1169,7 @@ bool BTGattHandler::readDescriptorValue(BTGattDesc & desc, int expectedLength) {
return res;
}
-bool BTGattHandler::readCharacteristicValue(const BTGattChar & decl, jau::POctets & resValue, int expectedLength) {
+bool BTGattHandler::readCharacteristicValue(const BTGattChar & decl, jau::POctets & resValue, int expectedLength) noexcept {
COND_PRINT(env.DEBUG_DATA, "GATTHandler::readCharacteristicValue expLen %d, decl %s", expectedLength, decl.toString().c_str());
const bool res = readValue(decl.value_handle, resValue, expectedLength);
if( !res ) {
@@ -1157,7 +1178,7 @@ bool BTGattHandler::readCharacteristicValue(const BTGattChar & decl, jau::POctet
return res;
}
-bool BTGattHandler::readValue(const uint16_t handle, jau::POctets & res, int expectedLength) {
+bool BTGattHandler::readValue(const uint16_t handle, jau::POctets & res, int expectedLength) noexcept {
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.1 Read Characteristic Value */
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.8.3 Read Long Characteristic Value */
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
@@ -1181,7 +1202,11 @@ bool BTGattHandler::readValue(const uint16_t handle, jau::POctets & res, int exp
const AttReadBlobReq req1(handle, offset);
const AttPDUMsg & req = ( 0 == offset ) ? static_cast<const AttPDUMsg &>(req0) : static_cast<const AttPDUMsg &>(req1);
COND_PRINT(env.DEBUG_DATA, "GATT RV send: %s", req.toString().c_str());
- pdu = sendWithReply(req, read_cmd_reply_timeout); // valid reply or exception
+ pdu = sendWithReply(req, read_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
COND_PRINT(env.DEBUG_DATA, "GATT RV recv: %s from %s", pdu->toString().c_str(), toString().c_str());
if( pdu->getOpcode() == AttPDUMsg::Opcode::READ_RSP ) {
@@ -1230,7 +1255,7 @@ bool BTGattHandler::readValue(const uint16_t handle, jau::POctets & res, int exp
return offset > 0;
}
-bool BTGattHandler::writeDescriptorValue(const BTGattDesc & cd) {
+bool BTGattHandler::writeDescriptorValue(const BTGattDesc & cd) noexcept {
/* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration */
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value */
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.11 Characteristic Value Indication */
@@ -1244,7 +1269,7 @@ bool BTGattHandler::writeDescriptorValue(const BTGattDesc & cd) {
return res;
}
-bool BTGattHandler::writeCharacteristicValue(const BTGattChar & c, const jau::TROOctets & value) {
+bool BTGattHandler::writeCharacteristicValue(const BTGattChar & c, const jau::TROOctets & value) noexcept {
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value */
COND_PRINT(env.DEBUG_DATA, "GATTHandler::writeCharacteristicValue desc %s, value %s", c.toString().c_str(), value.toString().c_str());
const bool res = writeValue(c.value_handle, value, true);
@@ -1254,13 +1279,13 @@ bool BTGattHandler::writeCharacteristicValue(const BTGattChar & c, const jau::TR
return res;
}
-bool BTGattHandler::writeCharacteristicValueNoResp(const BTGattChar & c, const jau::TROOctets & value) {
+bool BTGattHandler::writeCharacteristicValueNoResp(const BTGattChar & c, const jau::TROOctets & value) noexcept {
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.1 Write Characteristic Value Without Response */
COND_PRINT(env.DEBUG_DATA, "GATT writeCharacteristicValueNoResp decl %s, value %s", c.toString().c_str(), value.toString().c_str());
- return writeValue(c.value_handle, value, false); // complete or exception
+ return writeValue(c.value_handle, value, false);
}
-bool BTGattHandler::writeValue(const uint16_t handle, const jau::TROOctets & value, const bool withResponse) {
+bool BTGattHandler::writeValue(const uint16_t handle, const jau::TROOctets & value, const bool withResponse) noexcept {
/* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration */
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value */
/* BT Core Spec v5.2: Vol 3, Part G GATT: 4.11 Characteristic Value Indication */
@@ -1279,16 +1304,25 @@ bool BTGattHandler::writeValue(const uint16_t handle, const jau::TROOctets & val
AttWriteCmd req(handle, value);
COND_PRINT(env.DEBUG_DATA, "GATT WV send(resp %d): %s to %s", withResponse, req.toString().c_str(), toString().c_str());
- send( req ); // complete or exception
+ const bool res = send( req );
PERF2_TS_TD("GATT writeValue (no-resp)");
- return true;
+ if( !res ) {
+ ERR_PRINT2("Send failed; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ } else {
+ return true;
+ }
}
AttWriteReq req(handle, value);
COND_PRINT(env.DEBUG_DATA, "GATT WV send(resp %d): %s to %s", withResponse, req.toString().c_str(), toString().c_str());
bool res = false;
- std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, write_cmd_reply_timeout); // valid reply or exception
+ std::unique_ptr<const AttPDUMsg> pdu = sendWithReply(req, write_cmd_reply_timeout);
+ if( nullptr == pdu ) {
+ ERR_PRINT2("No reply; req %s from %s", req.toString().c_str(), toString().c_str());
+ return false;
+ }
COND_PRINT(env.DEBUG_DATA, "GATT WV recv: %s from %s", pdu->toString().c_str(), toString().c_str());
if( pdu->getOpcode() == AttPDUMsg::Opcode::WRITE_RSP ) {
@@ -1303,9 +1337,10 @@ bool BTGattHandler::writeValue(const uint16_t handle, const jau::TROOctets & val
return res;
}
-bool BTGattHandler::configNotificationIndication(BTGattDesc & cccd, const bool enableNotification, const bool enableIndication) {
+bool BTGattHandler::configNotificationIndication(BTGattDesc & cccd, const bool enableNotification, const bool enableIndication) noexcept {
if( !cccd.isClientCharConfig() ) {
- throw jau::IllegalArgumentException("Not a ClientCharacteristicConfiguration: "+cccd.toString(), E_FILE_LINE);
+ ERR_PRINT("Not a ClientCharacteristicConfiguration: %s", cccd.toString().c_str());
+ return false;
}
/* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration */
const uint16_t ccc_value = enableNotification | ( enableIndication << 1 );
@@ -1313,17 +1348,7 @@ bool BTGattHandler::configNotificationIndication(BTGattDesc & cccd, const bool e
cccd.toString().c_str(), enableNotification, enableIndication);
cccd.value.resize(2, 2);
cccd.value.put_uint16_nc(0, ccc_value);
- try {
- return writeDescriptorValue(cccd);
- } catch (BTException & bte) {
- if( !enableNotification && !enableIndication ) {
- // OK to have lost connection @ disable
- WORDY_PRINT("GATTHandler::configNotificationIndication(disable) on %s caught exception: %s", toString().c_str(), bte.what());
- return false;
- } else {
- throw; // re-throw current exception
- }
- }
+ return writeDescriptorValue(cccd);
}
/*********************************************************************************************************************/
@@ -1346,7 +1371,7 @@ static const jau::uuid16_t _MANUFACTURER_NAME_STRING(GattCharacteristicType::MAN
static const jau::uuid16_t _REGULATORY_CERT_DATA_LIST(GattCharacteristicType::REGULATORY_CERT_DATA_LIST);
static const jau::uuid16_t _PNP_ID(GattCharacteristicType::PNP_ID);
-std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darray<BTGattCharRef> & genericAccessCharDeclList) {
+std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darray<BTGattCharRef> & genericAccessCharDeclList) noexcept {
std::shared_ptr<GattGenericAccessSvc> res = nullptr;
jau::POctets value(number(Defaults::MAX_ATT_MTU), 0, jau::endian::little);
std::string deviceName = "";
@@ -1381,7 +1406,7 @@ std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darra
return res;
}
-std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darray<BTGattServiceRef> & primServices) {
+std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darray<BTGattServiceRef> & primServices) noexcept {
for(size_t i=0; i<primServices.size(); i++) {
BTGattServiceRef service = primServices.at(i);
if( _GENERIC_ACCESS == *service->type ) {
@@ -1391,7 +1416,7 @@ std::shared_ptr<GattGenericAccessSvc> BTGattHandler::getGenericAccess(jau::darra
return nullptr;
}
-bool BTGattHandler::ping() {
+bool BTGattHandler::ping() noexcept {
const std::lock_guard<std::recursive_mutex> lock(mtx_command); // RAII-style acquire and relinquish via destructor
bool readOK = true;
@@ -1409,7 +1434,7 @@ bool BTGattHandler::ping() {
if( readCharacteristicValue(charDecl, value.resize(0)) ) {
return true; // unique success case
}
- // read failure, but not disconnected as no exception thrown from sendWithReply
+ // read failure, might be disconnected
readOK = false;
}
}
@@ -1423,7 +1448,7 @@ bool BTGattHandler::ping() {
return false;
}
-std::shared_ptr<GattDeviceInformationSvc> BTGattHandler::getDeviceInformation(jau::darray<BTGattCharRef> & characteristicDeclList) {
+std::shared_ptr<GattDeviceInformationSvc> BTGattHandler::getDeviceInformation(jau::darray<BTGattCharRef> & characteristicDeclList) noexcept {
std::shared_ptr<GattDeviceInformationSvc> res = nullptr;
jau::POctets value(number(Defaults::MAX_ATT_MTU), 0, jau::endian::little);
@@ -1493,7 +1518,7 @@ std::shared_ptr<GattDeviceInformationSvc> BTGattHandler::getDeviceInformation(ja
return res;
}
-std::shared_ptr<GattDeviceInformationSvc> BTGattHandler::getDeviceInformation(jau::darray<BTGattServiceRef> & primServices) {
+std::shared_ptr<GattDeviceInformationSvc> BTGattHandler::getDeviceInformation(jau::darray<BTGattServiceRef> & primServices) noexcept {
for(size_t i=0; i<primServices.size(); i++) {
BTGattServiceRef service = primServices.at(i);
if( _DEVICE_INFORMATION == *service->type ) {