diff options
-rw-r--r-- | api/direct_bt/BTGattHandler.hpp | 95 | ||||
-rw-r--r-- | src/direct_bt/BTDevice.cpp | 58 | ||||
-rw-r--r-- | src/direct_bt/BTGattHandler.cpp | 249 |
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 ) { |