diff --git a/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h b/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h index 2e0510854b..d5e88eedfb 100644 --- a/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h +++ b/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h @@ -24,6 +24,16 @@ #include "ble/gatt/GattAttribute.h" #include "ble/gatt/GattCallbackParamTypes.h" +// Forward declare ble::impl::GattServer +namespace ble { + +#if !defined(DOXYGEN_ONLY) +namespace impl { +class GattServer; +} +#endif // !defined(DOXYGEN_ONLY) +} + /** * @addtogroup ble * @{ @@ -1429,6 +1439,11 @@ public: GattCharacteristic(const GattCharacteristic &) = delete; GattCharacteristic& operator=(const GattCharacteristic &) = delete; + ~GattCharacteristic() { + delete _implicit_cccd; + _implicit_cccd = nullptr; + } + public: /** @@ -1714,7 +1729,7 @@ public: */ uint8_t getDescriptorCount() const { - return _descriptorCount; + return (_implicit_cccd == nullptr? _descriptorCount : _descriptorCount+1); } /** @@ -1750,16 +1765,45 @@ public: * * @return A pointer the requested descriptor if @p index is within the * range of the descriptor array or nullptr otherwise. + * + * @note if this characteristic has an implicitly-created CCCD this + * descriptor will be available at the highest index + * (ie: return of getDescriptorCount() - 1) */ GattAttribute *getDescriptor(uint8_t index) { - if (index >= _descriptorCount) { + + if(index == _descriptorCount) { + // If _implicit_cccd is nullptr, we want to return that anyway + return _implicit_cccd; + } + else if (index > _descriptorCount) { return nullptr; } return _descriptors[index]; } + +private: + + friend ble::impl::GattServer; + +#if !defined(DOXYGEN_ONLY) + /** + * Sets this GattCharacteristic's implicitly-created CCCD, if + * applicable. + * + * @note once this is called, the pointed-to GattAttribute + * is owned by this GattCharacteristic and will be deleted + * during this object's destructor + */ + void setImplicitCCCD(GattAttribute *implicit_cccd) { + _implicit_cccd = implicit_cccd; + } +#endif // !defined(DOXYGEN_ONLY) + + private: /** @@ -1783,6 +1827,16 @@ private: */ uint8_t _descriptorCount; + /** + * Pointer to characteristic's implicit CCCD, if applicable + * + * @note this is only populated if the stack creates an implicit CCCD + * for this GattCharacteristic. If the descriptors array passed into + * the constructor includes a CCCD this field is left as nullptr to + * indicate the CCCD was explicitly created. + */ + GattAttribute* _implicit_cccd = nullptr; + /** * The registered callback handler for read authorization reply. */ diff --git a/connectivity/FEATURE_BLE/source/cordio/source/GattServerImpl.cpp b/connectivity/FEATURE_BLE/source/cordio/source/GattServerImpl.cpp index a7ca14d567..24c8c35805 100644 --- a/connectivity/FEATURE_BLE/source/cordio/source/GattServerImpl.cpp +++ b/connectivity/FEATURE_BLE/source/cordio/source/GattServerImpl.cpp @@ -23,6 +23,8 @@ #include "wsf_types.h" #include "att_api.h" +#include + namespace ble { namespace impl { @@ -588,6 +590,28 @@ ble_error_t GattServer::insert_cccd( cccds[cccd_cnt].secLevel = characteristic->getUpdateSecurityRequirement().value(); cccd_handles[cccd_cnt] = characteristic->getValueAttribute().getHandle(); + /** + * Set the characteristic's implicitly-created CCCD + * + * Ownership is passed to the GattCharacteristic + */ + GattAttribute* implicit_cccd = new (std::nothrow) GattAttribute( + CCCD_UUID, + attribute_it->pValue, + *attribute_it->pLen, + attribute_it->maxLen, + false); + + if(implicit_cccd == nullptr) { + currentHandle--; + return BLE_ERROR_NO_MEM; + } + + implicit_cccd->setHandle(cccds[cccd_cnt].handle); + implicit_cccd->allowRead(true); + implicit_cccd->allowWrite(true); + characteristic->setImplicitCCCD(implicit_cccd); + cccd_cnt++; attribute_it++;