diff options
author | Sven Gothel <[email protected]> | 2020-05-15 12:09:59 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-05-15 12:09:59 +0200 |
commit | b12a3e3adf8159a0c252cee67beae35e1b5b879f (patch) | |
tree | b8fc2970fed0b23179dfe6bc5607204787236eae | |
parent | 768169322ff9652cbb9b080a8049fe2db10a8adc (diff) |
GATT Cleanup of method + field names; GATT discoverDescriptors: Use more reasonable and efficient traversal...
GATT Cleanup of method + field names
- the service and characteristic uuid's specify types, hence name field *type* being of value-type uuid_t.
- use short and clear names like 'Characteristic' and simply 'Descriptor' for 'Characteristic Descriptor'.
- etc etc
GATT discoverDescriptors: Use more reasonable and efficient traversal through Charactecteristics
- Previous we traversed through all handle of services for Descriptors,
only to find the matching Charactecteristic to attach to.
The latter was done via another loop through all Charactecteristic and hence even reduced
performance by one magnitude.
Further, not all handles reflect Descriptors ;-)
- Simply iterate through all Charactecteristic and find their Descriptors within
their value handle range as per BT spec.
Also read the Descriptor value right away.
-rw-r--r-- | api/direct_bt/GATTHandler.hpp | 24 | ||||
-rw-r--r-- | api/direct_bt/GATTTypes.hpp | 96 | ||||
-rw-r--r-- | examples/direct_bt_scanner/dbt_scanner.cpp | 4 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 2 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattService.cxx | 4 | ||||
-rw-r--r-- | src/direct_bt/GATTHandler.cpp | 240 | ||||
-rw-r--r-- | src/direct_bt/GATTTypes.cpp | 39 |
7 files changed, 213 insertions, 196 deletions
diff --git a/api/direct_bt/GATTHandler.hpp b/api/direct_bt/GATTHandler.hpp index c016bf95..da3778a0 100644 --- a/api/direct_bt/GATTHandler.hpp +++ b/api/direct_bt/GATTHandler.hpp @@ -174,30 +174,30 @@ namespace direct_bt { /** * Find and return the GATTCharacterisicsDecl within internal primary services - * via given characteristic handle. + * via given characteristic value handle. * <p> * Returns nullptr if not found. * </p> */ - GATTCharacteristicRef findCharacterisics(const uint16_t charHandle); + GATTCharacteristicRef findCharacterisicsByValueHandle(const uint16_t charValueHandle); /** * Find and return the GATTCharacterisicsDecl within given list of primary services - * via given characteristic handle. + * via given characteristic value handle. * <p> * Returns nullptr if not found. * </p> */ - GATTCharacteristicRef findCharacterisics(const uint16_t charHandle, std::vector<GATTServiceRef> &services); + GATTCharacteristicRef findCharacterisicsByValueHandle(const uint16_t charValueHandle, std::vector<GATTServiceRef> &services); /** * Find and return the GATTCharacterisicsDecl within given primary service - * via given characteristic handle. + * via given characteristic value handle. * <p> * Returns nullptr if not found. * </p> */ - GATTCharacteristicRef findCharacterisics(const uint16_t charHandle, GATTServiceRef service); + GATTCharacteristicRef findCharacterisicsByValueHandle(const uint16_t charValueHandle, GATTServiceRef service); /** * Discover all primary services _and_ all its characteristics declarations @@ -271,7 +271,7 @@ namespace direct_bt { * if required until the response returns zero. * </p> */ - bool readCharacteristicValue(const GATTCharacteristic & decl, POctets & res, int expectedLength=-1); + bool readCharacteristicValue(const GATTCharacteristic & c, POctets & res, int expectedLength=-1); /** * BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.1 Read Characteristic Descriptor @@ -290,7 +290,7 @@ namespace direct_bt { * if required until the response returns zero. * </p> */ - bool readCharacteristicDescValue(GATTDescriptor & characteristicDescriptor, int expectedLength=-1); + bool readDescriptorValue(GATTDescriptor & cd, int expectedLength=-1); /** * Generic write GATT value and long value @@ -306,17 +306,17 @@ namespace direct_bt { * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration * </p> */ - bool writeCharacteristicDescValue(const GATTDescriptor & cd, const TROOctets & value); + bool writeDescriptorValue(const GATTDescriptor & cd, const TROOctets & value); /** * BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value */ - bool writeCharacteristicValue(const GATTCharacteristic & decl, const TROOctets & value); + bool writeCharacteristicValue(const GATTCharacteristic & c, const TROOctets & value); /** * BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.1 Write Characteristic Value Without Response */ - bool writeCharacteristicValueNoResp(const GATTCharacteristic & decl, const TROOctets & value); + bool writeCharacteristicValueNoResp(const GATTCharacteristic & c, const TROOctets & value); /*****************************************************/ /** Higher level semantic functionality **/ @@ -331,7 +331,7 @@ namespace direct_bt { /** * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.3 Client Characteristic Configuration */ - bool configIndicationNotification(const GATTDescriptor & desc, const bool enableNotification, const bool enableIndication); + bool configIndicationNotification(const GATTDescriptor & cd, const bool enableNotification, const bool enableIndication); }; } // namespace direct_bt diff --git a/api/direct_bt/GATTTypes.hpp b/api/direct_bt/GATTTypes.hpp index 8c1702ac..0fb5e66f 100644 --- a/api/direct_bt/GATTTypes.hpp +++ b/api/direct_bt/GATTTypes.hpp @@ -65,6 +65,13 @@ namespace direct_bt { INCLUDE_DECLARATION = 0x2802, /* BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service */ CHARACTERISTIC = 0x2803, + + CHARACTERISTIC_APPEARANCE = 0x2A01, + CHARACTERISTIC_PERIPHERAL_PRIV_FLAG = 0x2A02, + CHARACTERISTIC_RECONNECTION_ADDRESS = 0x2A03, + CHARACTERISTIC_PERIPHERAL_PREF_CONN = 0x2A04, + CHARACTERISTIC_SERVICE_CHANGED = 0x2A05, + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.1 Characteristic Extended Properties */ CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900, /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.2 Characteristic User Description (Characteristic Descriptor, optional, single, string) */ @@ -76,46 +83,9 @@ namespace direct_bt { /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.5 Characteristic Presentation Format (Characteristic Descriptor, optional, single, complex) */ CHARACTERISTIC_PRESENTATION_FORMAT = 0x2904, CHARACTERISTIC_AGGREGATE_FORMAT = 0x2905 - }; - /** - * uuid -> handle-range[ startHandle .. endHandle ] - * <p> - * BT Core Spec v5.2: Vol 3, Part G GATT: 4.4.1 Discover All Primary Services - * - * Here the uuid is a service uuid - * and the handle-range it's characteristics-declaration - * </p> - */ - class GATTUUIDHandleRange { - public: - enum Type : uint8_t { - Service = 0, - Characteristic = 1 - }; - const Type type; - const uint16_t startHandle; - const uint16_t endHandle; - std::shared_ptr<const uuid_t> uuid; - - GATTUUIDHandleRange(const Type t, const uint16_t startHandle, const uint16_t endHandle, std::shared_ptr<const uuid_t> uuid) - : type(t), startHandle(startHandle), endHandle(endHandle), uuid(uuid) {} - - std::string toString() const { - std::string name = ""; - if( uuid_t::UUID16_SZ == uuid->getTypeSize() ) { - const uint16_t uuid16 = (static_cast<const uuid16_t*>(uuid.get()))->value; - if( Type::Service == type ) { - name = " - "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16)); - } else if( Type::Characteristic == type ) { - name = " - "+GattCharacteristicTypeToString(static_cast<GattCharacteristicType>(uuid16)); - } - } - return "uuid "+uuid->toString()+", handle [ "+uint16HexString(startHandle, true)+".."+uint16HexString(endHandle, true)+" ]"+name; - } }; - /** * * JavaUplink Semantic Types @@ -143,6 +113,12 @@ namespace direct_bt { * BT Core Spec v5.2: Vol 3, Part G GATT: 3.4 Summary of GATT Profile Attribute Types */ enum Type : uint16_t { + CHARACTERISTIC_APPEARANCE = 0x2A01, + CHARACTERISTIC_PERIPHERAL_PRIV_FLAG = 0x2A02, + CHARACTERISTIC_RECONNECTION_ADDRESS = 0x2A03, + CHARACTERISTIC_PERIPHERAL_PREF_CONN = 0x2A04, + CHARACTERISTIC_SERVICE_CHANGED = 0x2A05, + /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.1 Characteristic Extended Properties */ CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900, /* BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.3.2 Characteristic User Description (Characteristic Descriptor, optional, single, string) */ @@ -165,7 +141,7 @@ namespace direct_bt { /** Actual type of descriptor */ std::shared_ptr<const uuid_t> type; - /* Characteristics Descriptor's Handle */ + /* Characteristic Descriptor Handle */ const uint16_t handle; /* Characteristics Descriptor's Value */ @@ -191,7 +167,7 @@ namespace direct_bt { } virtual std::string toString() const { - return "Descriptor[type "+type->toString()+", handle "+uint16HexString(handle)+", value["+value.toString()+"]]"; + return "[type 0x"+type->toString()+", handle "+uint16HexString(handle)+", value["+value.toString()+"]]"; } /** Value is uint16_t bitfield */ @@ -247,23 +223,25 @@ namespace direct_bt { /* Characteristics's Service Handle - key to service's handle range, retrieved from Characteristics data */ const uint16_t service_handle; + /* Characteristic Handle of this instance */ + const uint16_t handle; /* Characteristics Property */ const PropertyBitVal properties; /* Characteristics Value Handle */ - const uint16_t handle; - /* Characteristics UUID */ - std::shared_ptr<const uuid_t> uuid; + const uint16_t value_handle; + /* Characteristics Value Type UUID */ + std::shared_ptr<const uuid_t> value_type; /** List of Characteristic Descriptions as shared reference */ - std::vector<GATTDescriptorRef> characteristicDescList; + std::vector<GATTDescriptorRef> descriptorList; /* Optional Client Characteristic Configuration index within characteristicDescList */ int clientCharacteristicsConfigIndex = -1; - GATTCharacteristic(const GATTServiceRef & service, const uint16_t service_handle, - const PropertyBitVal properties, const uint16_t handle, std::shared_ptr<const uuid_t> uuid) - : service(service), service_handle(service_handle), - properties(properties), handle(handle), uuid(uuid) {} + GATTCharacteristic(const GATTServiceRef & service, const uint16_t service_handle, const uint16_t handle, + const PropertyBitVal properties, const uint16_t value_handle, std::shared_ptr<const uuid_t> value_type) + : service(service), service_handle(service_handle), handle(handle), + properties(properties), value_handle(value_handle), value_type(value_type) {} std::string get_java_class() const override { return java_class(); @@ -279,11 +257,16 @@ namespace direct_bt { } std::string toString() const; + void clearDescriptors() { + descriptorList.clear(); + clientCharacteristicsConfigIndex = -1; + } + GATTDescriptorRef getClientCharacteristicConfig() { if( 0 > clientCharacteristicsConfigIndex ) { return nullptr; } - return characteristicDescList.at(clientCharacteristicsConfigIndex); + return descriptorList.at(clientCharacteristicsConfigIndex); } }; @@ -301,15 +284,20 @@ namespace direct_bt { const bool isPrimary; - /** The primary service declaration itself */ - const GATTUUIDHandleRange declaration; + /** Service start handle */ + const uint16_t startHandle; + /** Service end handle */ + const uint16_t endHandle; + /** Service type UUID */ + std::shared_ptr<const uuid_t> type; /** List of Characteristic Declarations as shared reference */ - std::vector<GATTCharacteristicRef> characteristicDeclList; + std::vector<GATTCharacteristicRef> characteristicList; - GATTService(const std::shared_ptr<DBTDevice> &device, const bool isPrimary, const GATTUUIDHandleRange serviceDecl) - : device(device), isPrimary(isPrimary), declaration(serviceDecl), characteristicDeclList() { - characteristicDeclList.reserve(10); + GATTService(const std::shared_ptr<DBTDevice> &device, const bool isPrimary, + const uint16_t startHandle, const uint16_t endHandle, std::shared_ptr<const uuid_t> type) + : device(device), isPrimary(isPrimary), startHandle(startHandle), endHandle(endHandle), type(type), characteristicList() { + characteristicList.reserve(10); } std::string get_java_class() const override { diff --git a/examples/direct_bt_scanner/dbt_scanner.cpp b/examples/direct_bt_scanner/dbt_scanner.cpp index 267312bc..93c98b90 100644 --- a/examples/direct_bt_scanner/dbt_scanner.cpp +++ b/examples/direct_bt_scanner/dbt_scanner.cpp @@ -103,7 +103,7 @@ class MyGATTIndicationListener : public direct_bt::GATTIndicationListener { confirmationSent, (tR-charValue->ts_creation), (tR-dev->ts_creation), dev->toString().c_str()); if( nullptr != charDecl ) { fprintf(stderr, "****** decl %s\n", charDecl->toString().c_str()); - if( _TEMPERATURE_MEASUREMENT == *charDecl->uuid ) { + if( _TEMPERATURE_MEASUREMENT == *charDecl->value_type ) { std::shared_ptr<TemperatureMeasurementCharateristic> temp = TemperatureMeasurementCharateristic::get(charValue->getValue()); if( nullptr != temp ) { fprintf(stderr, "****** valu %s\n", temp->toString().c_str()); @@ -284,7 +284,7 @@ int main(int argc, char *argv[]) GATTService & primService = *primServices.at(i); fprintf(stderr, " [%2.2d] Service %s\n", (int)i, primService.toString().c_str()); fprintf(stderr, " [%2.2d] Service Characteristics\n", (int)i); - std::vector<GATTCharacteristicRef> & serviceCharacteristics = primService.characteristicDeclList; + std::vector<GATTCharacteristicRef> & serviceCharacteristics = primService.characteristicList; for(size_t j=0; j<serviceCharacteristics.size() && gatt->isOpen(); j++) { GATTCharacteristic & serviceChar = *serviceCharacteristics.at(j); fprintf(stderr, " [%2.2d.%2.2d] Decla: %s\n", (int)i, (int)j, serviceChar.toString().c_str()); diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index c9a60258..9d5d9e1f 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -176,7 +176,7 @@ jobject Java_direct_1bt_tinyb_DBTDevice_getServices(JNIEnv *env, jobject obj) { JavaGlobalObj::check(service->device->getJavaObject(), E_FILE_LINE); jobject jdevice = JavaGlobalObj::GetObject(service->device->getJavaObject()); const jboolean isPrimary = service->isPrimary; - const jstring uuid = from_string_to_jstring(env, service->declaration.uuid->toString()); + const jstring uuid = from_string_to_jstring(env, service->type->toString()); if( java_exception_check(env, E_FILE_LINE) ) { return nullptr; } jobject jservice = env->NewObject(clazz, clazz_ctor, (jlong)service, jdevice, isPrimary, uuid); diff --git a/java/jni/direct_bt/DBTGattService.cxx b/java/jni/direct_bt/DBTGattService.cxx index 0e893031..3361a44c 100644 --- a/java/jni/direct_bt/DBTGattService.cxx +++ b/java/jni/direct_bt/DBTGattService.cxx @@ -55,7 +55,7 @@ jobject Java_direct_1bt_tinyb_DBTGattService_getCharacteristics(JNIEnv *env, job GATTService *service = getInstance<GATTService>(env, obj); JavaGlobalObj::check(service->getJavaObject(), E_FILE_LINE); - std::vector<std::shared_ptr<GATTCharacteristic>> & characteristics = service->characteristicDeclList; + std::vector<std::shared_ptr<GATTCharacteristic>> & characteristics = service->characteristicList; // DBTGattCharacteristic(final long nativeInstance, final BluetoothGattService service, final String[] properties, final String uuid) @@ -78,7 +78,7 @@ jobject Java_direct_1bt_tinyb_DBTGattService_getCharacteristics(JNIEnv *env, job } if( java_exception_check(env, E_FILE_LINE) ) { return nullptr; } - const jstring uuid = from_string_to_jstring(env, characteristic->uuid->toString()); + const jstring uuid = from_string_to_jstring(env, characteristic->value_type->toString()); if( java_exception_check(env, E_FILE_LINE) ) { return nullptr; } jobject jchar = env->NewObject(clazz, clazz_ctor, (jlong)characteristic, jservice, jproperties, uuid); diff --git a/src/direct_bt/GATTHandler.cpp b/src/direct_bt/GATTHandler.cpp index 67463c4a..b5691a73 100644 --- a/src/direct_bt/GATTHandler.cpp +++ b/src/direct_bt/GATTHandler.cpp @@ -39,10 +39,21 @@ extern "C" { #include <signal.h> } -// #define PERF_PRINT_ON 1 +#define PERF_PRINT_ON 1 +// #define PERF2_PRINT_ON 1 // #define VERBOSE_ON 1 #include <dbt_debug.hpp> +// PERF2_PRINT_ON for read/write single values +#ifdef PERF2_PRINT_ON + #define PERF2_TS_T0() PERF_TS_T0() + #define PERF2_TS_TD(m) PERF_TS_TD(m) +#else + #define PERF2_TS_T0() + #define PERF2_TS_TD(m) +#endif + + #include "L2CAPIoctl.hpp" #include "GATTNumbers.hpp" @@ -126,7 +137,7 @@ void GATTHandler::l2capReaderThreadImpl() { const AttHandleValueRcv * a = static_cast<const AttHandleValueRcv*>(attPDU); DBG_PRINT("GATTHandler: NTF: %s", a->toString().c_str()); if( nullptr != gattNotificationListener ) { - GATTCharacteristicRef decl = findCharacterisics(a->getHandle()); + GATTCharacteristicRef decl = findCharacterisicsByValueHandle(a->getHandle()); gattNotificationListener->notificationReceived(this->l2cap->getDevice(), decl, std::shared_ptr<const AttHandleValueRcv>(a)); attPDU = nullptr; } @@ -140,7 +151,7 @@ void GATTHandler::l2capReaderThreadImpl() { DBG_PRINT("GATTHandler: CFM send: %s, confirmationSent %d", cfm.toString().c_str(), cfmSent); } if( nullptr != gattIndicationListener ) { - GATTCharacteristicRef decl = findCharacterisics(a->getHandle()); + GATTCharacteristicRef decl = findCharacterisicsByValueHandle(a->getHandle()); gattIndicationListener->indicationReceived(this->l2cap->getDevice(), decl, std::shared_ptr<const AttHandleValueRcv>(a), cfmSent); attPDU = nullptr; } @@ -313,13 +324,13 @@ uint16_t GATTHandler::exchangeMTU(const uint16_t clientMaxMTU) { return mtu; } -GATTCharacteristicRef GATTHandler::findCharacterisics(const uint16_t charHandle) { - return findCharacterisics(charHandle, services); +GATTCharacteristicRef GATTHandler::findCharacterisicsByValueHandle(const uint16_t charValueHandle) { + return findCharacterisicsByValueHandle(charValueHandle, services); } -GATTCharacteristicRef GATTHandler::findCharacterisics(const uint16_t charHandle, std::vector<GATTServiceRef> &services) { +GATTCharacteristicRef GATTHandler::findCharacterisicsByValueHandle(const uint16_t charValueHandle, std::vector<GATTServiceRef> &services) { for(auto it = services.begin(); it != services.end(); it++) { - GATTCharacteristicRef decl = findCharacterisics(charHandle, *it); + GATTCharacteristicRef decl = findCharacterisicsByValueHandle(charValueHandle, *it); if( nullptr != decl ) { return decl; } @@ -327,10 +338,10 @@ GATTCharacteristicRef GATTHandler::findCharacterisics(const uint16_t charHandle, return nullptr; } -GATTCharacteristicRef GATTHandler::findCharacterisics(const uint16_t charHandle, GATTServiceRef service) { - for(auto it = service->characteristicDeclList.begin(); it != service->characteristicDeclList.end(); it++) { +GATTCharacteristicRef GATTHandler::findCharacterisicsByValueHandle(const uint16_t charValueHandle, GATTServiceRef service) { + for(auto it = service->characteristicList.begin(); it != service->characteristicList.end(); it++) { GATTCharacteristicRef decl = *it; - if( charHandle == decl->handle ) { + if( charValueHandle == decl->value_handle ) { return decl; } } @@ -380,12 +391,10 @@ bool GATTHandler::discoverPrimaryServices(std::vector<GATTServiceRef> & result) const int ePDUOffset = p->getElementPDUOffset(i); const int esz = p->getElementTotalSize(); result.push_back( GATTServiceRef( new GATTService( device, true, - GATTUUIDHandleRange( - GATTUUIDHandleRange::Type::Service, p->pdu.get_uint16(ePDUOffset), // start-handle p->pdu.get_uint16(ePDUOffset + 2), // end-handle p->pdu.get_uuid( ePDUOffset + 2 + 2, uuid_t::toTypeSize(esz-2-2) ) // uuid - ) ) ) ); + ) ) ); DBG_PRINT("GATT PRIM SRV discovered[%d/%d]: %s", i, count, result.at(result.size()-1)->toString().c_str()); } startHandle = p->getElementEndHandle(count-1); @@ -421,38 +430,40 @@ bool GATTHandler::discoverCharacteristics(GATTServiceRef & service) { * </p> */ const uuid16_t characteristicTypeReq = uuid16_t(GattAttributeType::CHARACTERISTIC); + DBG_PRINT("GATT discoverCharacteristics Service: %s", service->toString().c_str()); PERF_TS_T0(); bool done=false; - uint16_t handle=service->declaration.startHandle; - service->characteristicDeclList.clear(); + uint16_t handle=service->startHandle; + service->characteristicList.clear(); while(!done) { - const AttReadByNTypeReq req(false /* group */, handle, service->declaration.endHandle, characteristicTypeReq); - DBG_PRINT("GATT CCD discover send: %s", req.toString().c_str()); + const AttReadByNTypeReq req(false /* group */, handle, service->endHandle, characteristicTypeReq); + DBG_PRINT("GATT C discover send: %s", req.toString().c_str()); std::shared_ptr<const AttPDUMsg> pdu = sendWithReply(req); if( nullptr != pdu ) { - DBG_PRINT("GATT CCD discover recv: %s", pdu->toString().c_str()); + DBG_PRINT("GATT C discover recv: %s", pdu->toString().c_str()); if( pdu->getOpcode() == AttPDUMsg::ATT_READ_BY_TYPE_RSP ) { const AttReadByTypeRsp * p = static_cast<const AttReadByTypeRsp*>(pdu.get()); - const int count = p->getElementCount(); + const int e_count = p->getElementCount(); - for(int i=0; i<count; i++) { + for(int e_iter=0; e_iter<e_count; e_iter++) { // handle: handle for the Characteristics declaration // value: Characteristics Property, Characteristics Value Handle _and_ Characteristics UUID - const int ePDUOffset = p->getElementPDUOffset(i); + const int ePDUOffset = p->getElementPDUOffset(e_iter); const int esz = p->getElementTotalSize(); - service->characteristicDeclList.push_back( GATTCharacteristicRef( new GATTCharacteristic( + service->characteristicList.push_back( GATTCharacteristicRef( new GATTCharacteristic( service, - p->pdu.get_uint16(ePDUOffset), // service-handle - static_cast<GATTCharacteristic::PropertyBitVal>(p->pdu.get_uint8(ePDUOffset + 2)), // properties - p->pdu.get_uint16(ePDUOffset + 2 + 1), // handle - p->pdu.get_uuid(ePDUOffset + 2 + 1 + 2, uuid_t::toTypeSize(esz-2-1-2) ) ) ) ); // uuid - DBG_PRINT("GATT CCD discovered[%d/%d]: %s", i, count, service->characteristicDeclList.at(service->characteristicDeclList.size()-1)->toString().c_str()); + p->pdu.get_uint16(ePDUOffset), // Characteristics's Service Handle + p->getElementHandle(e_iter), // Characteristic Handle + static_cast<GATTCharacteristic::PropertyBitVal>(p->pdu.get_uint8(ePDUOffset + 2)), // Characteristics Property + p->pdu.get_uint16(ePDUOffset + 2 + 1), // Characteristics Value Handle + p->pdu.get_uuid(ePDUOffset + 2 + 1 + 2, uuid_t::toTypeSize(esz-2-1-2) ) ) ) ); // Characteristics Value Type UUID + DBG_PRINT("GATT C discovered[%d/%d]: %s", e_iter, e_count, service->characteristicList.at(service->characteristicList.size()-1)->toString().c_str()); } - handle = p->getElementHandle(count-1); - if( handle < service->declaration.endHandle ) { + handle = p->getElementHandle(e_count-1); // Last Characteristic Handle + if( handle < service->endHandle ) { handle++; } else { done = true; // OK by spec: End of communication @@ -471,107 +482,116 @@ bool GATTHandler::discoverCharacteristics(GATTServiceRef & service) { PERF_TS_TD("GATT discoverCharacteristics"); - return service->characteristicDeclList.size() > 0; + return service->characteristicList.size() > 0; } bool GATTHandler::discoverDescriptors(GATTServiceRef & service) { /*** - * BT Core Spec v5.2: Vol 3, Part G GATT: 4.6.1 Discover All Characteristics of a Service + * BT Core Spec v5.2: Vol 3, Part G GATT: 4.7.1 Discover All Characteristic Descriptors * <p> * BT Core Spec v5.2: Vol 3, Part G GATT: 3.3.1 Characteristic Declaration Attribute Value * </p> */ + DBG_PRINT("GATT discoverDescriptors Service: %s", service->toString().c_str()); PERF_TS_T0(); bool done=false; - uint16_t handle=service->declaration.startHandle; - // list.clear(); - while(!done) { - const AttFindInfoReq req(handle, service->declaration.endHandle); - DBG_PRINT("GATT CD discover send: %s", req.toString().c_str()); + const int charCount = service->characteristicList.size(); + for(int charIter=0; !done && charIter < charCount; charIter++ ) { + GATTCharacteristicRef charDecl = service->characteristicList[charIter]; + charDecl->clearDescriptors(); + DBG_PRINT("GATT discoverDescriptors Characteristic[%d/%d]: %s", charIter, charCount, charDecl->toString().c_str()); + + uint16_t cd_handle_iter = charDecl->value_handle + 1; // Start @ Characteristic Value Handle + 1 + uint16_t cd_handle_end; + if( charIter+1 < charCount ) { + cd_handle_end = service->characteristicList.at(charIter+1)->value_handle; + } else { + cd_handle_end = service->endHandle; + } - std::shared_ptr<const AttPDUMsg> pdu = sendWithReply(req); - if( nullptr != pdu ) { + while( !done && cd_handle_iter <= cd_handle_end ) { + const AttFindInfoReq req(cd_handle_iter, cd_handle_end); + DBG_PRINT("GATT CD discover send: %s", req.toString().c_str()); + + std::shared_ptr<const AttPDUMsg> pdu = sendWithReply(req); + if( nullptr == pdu ) { + ERR_PRINT("GATT discoverDescriptors send failed: %s", req.toString().c_str()); + done = true; + break; + } DBG_PRINT("GATT CD discover recv: %s", pdu->toString().c_str()); + if( pdu->getOpcode() == AttPDUMsg::ATT_FIND_INFORMATION_RSP ) { const AttFindInfoRsp * p = static_cast<const AttFindInfoRsp*>(pdu.get()); - const int count = p->getElementCount(); + const int e_count = p->getElementCount(); - for(int i=0; i<count; i++) { - // handle: handle of Characteristic Descriptor Declaration. + for(int e_iter=0; e_iter<e_count; e_iter++) { + // handle: handle of Characteristic Descriptor. // value: Characteristic Descriptor UUID. - const uint16_t cd_handle = p->getElementHandle(i); - const std::shared_ptr<const uuid_t> cd_uuid = p->getElementValue(i); - // locate the matching GATTClientCharacteristicConfigDesc and attach it - bool attached = false; - for(size_t j=0; !attached && j<service->characteristicDeclList.size(); j++) { - GATTCharacteristicRef decl = service->characteristicDeclList[j]; - uint16_t decl_handle_end; - if( j+1 < service->characteristicDeclList.size() ) { - decl_handle_end = service->characteristicDeclList.at(j+1)->handle; - } else { - decl_handle_end = service->declaration.endHandle; - } - if( cd_handle > decl->handle && cd_handle <= decl_handle_end ) { - std::shared_ptr<GATTDescriptor> cd( new GATTDescriptor(decl, cd_uuid, cd_handle) ); - if( !readCharacteristicDescValue(*cd, 0) ) { - break; // oops - } - if( cd->isClientCharacteristicConfiguration() ) { - decl->clientCharacteristicsConfigIndex = decl->characteristicDescList.size(); - } - decl->characteristicDescList.push_back(cd); - attached = true; - DBG_PRINT("GATT CD discovered[%d/%d]: %s", i, count, cd->toString().c_str()); - } + const uint16_t cd_handle = p->getElementHandle(e_iter); + const std::shared_ptr<const uuid_t> cd_uuid = p->getElementValue(e_iter); + + std::shared_ptr<GATTDescriptor> cd( new GATTDescriptor(charDecl, cd_uuid, cd_handle) ); + if( cd_handle <= charDecl->value_handle || cd_handle > cd_handle_end ) { // should never happen! + ERR_PRINT("GATT discoverDescriptors CD handle %s not in range ]%s..%s]: %s", + uint16HexString(cd_handle).c_str(), + uint16HexString(charDecl->value_handle).c_str(), uint16HexString(cd_handle_end).c_str(), + cd->toString().c_str()); + done = true; + break; + } - if( !attached ) { - WARN_PRINT("GATT discoverCharacteristicDescriptors couldn't attach CharacteristicDescriptor uuid %s, handle %s", - cd_uuid->toString().c_str(), uint16HexString(cd_handle).c_str()); + if( !readDescriptorValue(*cd, 0) ) { + ERR_PRINT("GATT discoverDescriptors readDescriptorValue failed: %s . %s", + req.toString().c_str(), cd->toString().c_str()); + done = true; + break; } + if( cd->isClientCharacteristicConfiguration() ) { + charDecl->clientCharacteristicsConfigIndex = charDecl->descriptorList.size(); + } + charDecl->descriptorList.push_back(cd); + DBG_PRINT("GATT CD discovered[%d/%d]: %s", e_iter, e_count, cd->toString().c_str()); } - handle = p->getElementHandle(count-1); - if( handle < service->declaration.endHandle ) { - handle++; + cd_handle_iter = p->getElementHandle(e_count-1); // Last Descriptor Handle + if( cd_handle_iter < cd_handle_end ) { + cd_handle_iter++; } else { done = true; // OK by spec: End of communication } } else if( pdu->getOpcode() == AttPDUMsg::ATT_ERROR_RSP ) { done = true; // OK by spec: End of communication } else { - WARN_PRINT("GATT discoverCharacteristicDescriptors unexpected opcode reply %s", pdu->toString().c_str()); + WARN_PRINT("GATT discoverDescriptors unexpected opcode reply %s", pdu->toString().c_str()); done = true; } - } else { - ERR_PRINT("GATT discoverCharacteristicDescriptors send failed"); - done = true; } } + PERF_TS_TD("GATT discoverDescriptors"); - PERF_TS_TD("GATT discoverCharacteristicDescriptors"); - - return service->characteristicDeclList.size() > 0; + return service->characteristicList.size() > 0; } -bool GATTHandler::readCharacteristicDescValue(GATTDescriptor & desc, int expectedLength) { - DBG_PRINT("GATTHandler::readCharacteristicDescValue expLen %d, desc %s", expectedLength, desc.toString().c_str()); +bool GATTHandler::readDescriptorValue(GATTDescriptor & desc, int expectedLength) { + DBG_PRINT("GATTHandler::readDescriptorValue expLen %d, desc %s", expectedLength, desc.toString().c_str()); return readValue(desc.handle, desc.value, expectedLength); } bool GATTHandler::readCharacteristicValue(const GATTCharacteristic & decl, POctets & res, int expectedLength) { DBG_PRINT("GATTHandler::readCharacteristicValue expLen %d, decl %s", expectedLength, decl.toString().c_str()); - return readValue(decl.handle, res, expectedLength); + return readValue(decl.value_handle, res, expectedLength); } bool GATTHandler::readValue(const uint16_t handle, POctets & res, int expectedLength) { /* 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 */ - PERF_TS_T0(); + PERF2_TS_T0(); bool done=false; int offset=0; - DBG_PRINT("GATTHandler::readValue expLen %d, handle %s", expectedLength, uint16HexString(handle)); + DBG_PRINT("GATTHandler::readValue expLen %d, handle %s", expectedLength, uint16HexString(handle).c_str()); while(!done) { if( 0 < expectedLength && expectedLength <= offset ) { @@ -639,29 +659,29 @@ bool GATTHandler::readValue(const uint16_t handle, POctets & res, int expectedLe done = true; } } - PERF_TS_TD("GATT readValue"); + PERF2_TS_TD("GATT readValue"); return offset > 0; } -bool GATTHandler::writeCharacteristicDescValue(const GATTDescriptor & cd, const TROOctets & value) { +bool GATTHandler::writeDescriptorValue(const GATTDescriptor & cd, const TROOctets & value) { /* 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 */ /* BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.3 Write Characteristic Descriptor */ - DBG_PRINT("GATTHandler::writeCharacteristicDescValue desc %s, value %s", desc.toString().c_str(), value.toString().c_str()); + DBG_PRINT("GATTHandler::writeDesccriptorValue desc %s, value %s", cd.toString().c_str(), value.toString().c_str()); return writeValue(cd.handle, value, true); } -bool GATTHandler::writeCharacteristicValue(const GATTCharacteristic & decl, const TROOctets & value) { +bool GATTHandler::writeCharacteristicValue(const GATTCharacteristic & c, const TROOctets & value) { /* BT Core Spec v5.2: Vol 3, Part G GATT: 4.9.3 Write Characteristic Value */ - DBG_PRINT("GATTHandler::writeCharacteristicValue desc %s, value %s", desc.toString().c_str(), value.toString().c_str()); - return writeValue(decl.handle, value, true); + DBG_PRINT("GATTHandler::writeCharacteristicValue desc %s, value %s", c.toString().c_str(), value.toString().c_str()); + return writeValue(c.value_handle, value, true); } -bool GATTHandler::writeCharacteristicValueNoResp(const GATTCharacteristic & decl, const TROOctets & value) { - DBG_PRINT("GATT writeCharacteristicValueNoResp decl %s, value %s", decl.toString().c_str(), value.toString().c_str()); - return writeValue(decl.handle, value, false); +bool GATTHandler::writeCharacteristicValueNoResp(const GATTCharacteristic & c, const TROOctets & value) { + DBG_PRINT("GATT writeCharacteristicValueNoResp decl %s, value %s", c.toString().c_str(), value.toString().c_str()); + return writeValue(c.value_handle, value, false); } bool GATTHandler::writeValue(const uint16_t handle, const TROOctets & value, const bool expResponse) { @@ -671,6 +691,7 @@ bool GATTHandler::writeValue(const uint16_t handle, const TROOctets & value, con /* BT Core Spec v5.2: Vol 3, Part G GATT: 4.12.3 Write Characteristic Descriptor */ // TODO: Long Value! + PERF2_TS_T0(); AttWriteReq req(handle, value); DBG_PRINT("GATT WV send(resp %d): %s", expResponse, req.toString().c_str()); @@ -695,6 +716,7 @@ bool GATTHandler::writeValue(const uint16_t handle, const TROOctets & value, con } else { ERR_PRINT("GATT writeValue send failed"); } + PERF2_TS_TD("GATT writeValue"); return res; } @@ -705,7 +727,7 @@ bool GATTHandler::configIndicationNotification(const GATTDescriptor & cccd, cons cccd.toString().c_str(), enableNotification, enableIndication); POctets ccc(2); ccc.put_uint16(0, ccc_value); - return writeCharacteristicDescValue(cccd, ccc); + return writeDescriptorValue(cccd, ccc); } /*********************************************************************************************************************/ @@ -737,18 +759,18 @@ std::shared_ptr<GenericAccess> GATTHandler::getGenericAccess(std::vector<GATTCha for(size_t i=0; i<genericAccessCharDeclList.size(); i++) { const GATTCharacteristic & charDecl = *genericAccessCharDeclList.at(i); - if( _GENERIC_ACCESS != *charDecl.service->declaration.uuid ) { + if( _GENERIC_ACCESS != *charDecl.service->type ) { continue; } - if( _DEVICE_NAME == *charDecl.uuid ) { + if( _DEVICE_NAME == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { deviceName = GattNameToString(value); } - } else if( _APPEARANCE == *charDecl.uuid ) { + } else if( _APPEARANCE == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { category = static_cast<GenericAccess::AppearanceCat>(value.get_uint16(0)); } - } else if( _PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS == *charDecl.uuid ) { + } else if( _PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { prefConnParam = new PeriphalPreferredConnectionParameters(value); } @@ -766,7 +788,7 @@ std::shared_ptr<GenericAccess> GATTHandler::getGenericAccess(std::vector<GATTCha std::shared_ptr<GenericAccess> GATTHandler::getGenericAccess(std::vector<GATTServiceRef> & primServices) { std::shared_ptr<GenericAccess> res = nullptr; for(size_t i=0; i<primServices.size() && nullptr == res; i++) { - res = getGenericAccess(primServices.at(i)->characteristicDeclList); + res = getGenericAccess(primServices.at(i)->characteristicList); } return res; } @@ -788,43 +810,43 @@ std::shared_ptr<DeviceInformation> GATTHandler::getDeviceInformation(std::vector for(size_t i=0; i<characteristicDeclList.size(); i++) { const GATTCharacteristic & charDecl = *characteristicDeclList.at(i); - if( _DEVICE_INFORMATION != *charDecl.service->declaration.uuid ) { + if( _DEVICE_INFORMATION != *charDecl.service->type ) { continue; } found = true; - if( _SYSTEM_ID == *charDecl.uuid ) { + if( _SYSTEM_ID == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, systemID.resize(0)) ) { // nop } - } else if( _REGULATORY_CERT_DATA_LIST == *charDecl.uuid ) { + } else if( _REGULATORY_CERT_DATA_LIST == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, regulatoryCertDataList.resize(0)) ) { // nop } - } else if( _PNP_ID == *charDecl.uuid ) { + } else if( _PNP_ID == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { pnpID = new PnP_ID(value); } - } else if( _MODEL_NUMBER_STRING == *charDecl.uuid ) { + } else if( _MODEL_NUMBER_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { modelNumber = GattNameToString(value); } - } else if( _SERIAL_NUMBER_STRING == *charDecl.uuid ) { + } else if( _SERIAL_NUMBER_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { serialNumber = GattNameToString(value); } - } else if( _FIRMWARE_REVISION_STRING == *charDecl.uuid ) { + } else if( _FIRMWARE_REVISION_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { firmwareRevision = GattNameToString(value); } - } else if( _HARDWARE_REVISION_STRING == *charDecl.uuid ) { + } else if( _HARDWARE_REVISION_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { hardwareRevision = GattNameToString(value); } - } else if( _SOFTWARE_REVISION_STRING == *charDecl.uuid ) { + } else if( _SOFTWARE_REVISION_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { softwareRevision = GattNameToString(value); } - } else if( _MANUFACTURER_NAME_STRING == *charDecl.uuid ) { + } else if( _MANUFACTURER_NAME_STRING == *charDecl.value_type ) { if( readCharacteristicValue(charDecl, value.resize(0)) ) { manufacturer = GattNameToString(value); } @@ -845,7 +867,7 @@ std::shared_ptr<DeviceInformation> GATTHandler::getDeviceInformation(std::vector std::shared_ptr<DeviceInformation> GATTHandler::getDeviceInformation(std::vector<GATTServiceRef> & primServices) { std::shared_ptr<DeviceInformation> res = nullptr; for(size_t i=0; i<primServices.size() && nullptr == res; i++) { - res = getDeviceInformation(primServices.at(i)->characteristicDeclList); + res = getDeviceInformation(primServices.at(i)->characteristicList); } return res; } diff --git a/src/direct_bt/GATTTypes.cpp b/src/direct_bt/GATTTypes.cpp index b5dda186..70e3f59e 100644 --- a/src/direct_bt/GATTTypes.cpp +++ b/src/direct_bt/GATTTypes.cpp @@ -105,38 +105,45 @@ std::vector<std::unique_ptr<std::string>> GATTCharacteristic::getPropertiesStrin } std::string GATTCharacteristic::toString() const { - const std::shared_ptr<const uuid_t> & service_uuid = service->declaration.uuid; - const uint16_t service_handle_end = service->declaration.endHandle; + const std::shared_ptr<const uuid_t> & service_uuid = service->type; + const uint16_t service_handle_end = service->endHandle; std::string service_name = ""; std::string char_name = ""; - std::string config_str = ", config["; + std::string desc_str = ", descr[ "; if( uuid_t::UUID16_SZ == service_uuid->getTypeSize() ) { const uint16_t uuid16 = (static_cast<const uuid16_t*>(service_uuid.get()))->value; service_name = ", "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16)); } - if( uuid_t::UUID16_SZ == uuid->getTypeSize() ) { - const uint16_t uuid16 = (static_cast<const uuid16_t*>(uuid.get()))->value; + if( uuid_t::UUID16_SZ == value_type->getTypeSize() ) { + const uint16_t uuid16 = (static_cast<const uuid16_t*>(value_type.get()))->value; char_name = ", "+GattCharacteristicTypeToString(static_cast<GattCharacteristicType>(uuid16)); } - for(size_t i=0; i<characteristicDescList.size(); i++) { - const GATTDescriptorRef cd = characteristicDescList[i]; - config_str += cd->toString() + ", "; + for(size_t i=0; i<descriptorList.size(); i++) { + const GATTDescriptorRef cd = descriptorList[i]; + desc_str += cd->toString() + ", "; } - config_str += "]"; - return "props "+uint8HexString(properties, true)+" "+getPropertiesString()+", handle "+uint16HexString(handle, true)+ - ", uuid "+uuid->toString()+char_name+config_str+ - ", service[ "+service_uuid->toString()+ - ", handle[ "+uint16HexString(service_handle, true)+".."+uint16HexString(service_handle_end, true)+" ]"+ + desc_str += " ]"; + return "handle "+uint16HexString(handle)+", props "+uint8HexString(properties)+" "+getPropertiesString()+ + ", value[type 0x"+value_type->toString()+", handle "+uint16HexString(value_handle)+char_name+desc_str+ + "], service[type 0x"+service_uuid->toString()+ + ", handle[ "+uint16HexString(service_handle)+".."+uint16HexString(service_handle_end)+" ]"+ service_name+" ]"; } std::string GATTService::toString() const { - std::string res = declaration.toString()+"[ "; - for(size_t i=0; i<characteristicDeclList.size(); i++) { + std::string name = ""; + if( uuid_t::UUID16_SZ == type->getTypeSize() ) { + const uint16_t uuid16 = (static_cast<const uuid16_t*>(type.get()))->value; + name = " - "+GattServiceTypeToString(static_cast<GattServiceType>(uuid16)); + } + std::string res = "type 0x"+type->toString()+", handle ["+uint16HexString(startHandle, true)+".."+uint16HexString(endHandle, true)+"]"+ + name+"[ "; + + for(size_t i=0; i<characteristicList.size(); i++) { if( 0 < i ) { res += ", "; } - res += std::to_string(i)+"[ "+characteristicDeclList[i]->toString()+" ]"; + res += std::to_string(i)+"[ "+characteristicList[i]->toString()+" ]"; } res += " ]"; return res; |