diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2015-03-31 10:08:02 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@theqtcompany.com> | 2015-04-15 05:43:42 +0000 |
commit | eceb93bda82e45dab9bb85b592533a7d7c5ccac0 (patch) | |
tree | 4cdf08b9c08187e45907944a56ce1f8b5c542e2f | |
parent | 3162d33d98a96e506a4d8dfc6813f1fb0fe44c18 (diff) |
Bluez: Implement QLES::readCharacteristic()/readDescriptor()
Change-Id: I418db6ea375b8e29def136b28b4fc25154d4ffe8
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
-rw-r--r-- | src/bluetooth/qlowenergycontroller_android.cpp | 15 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 140 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.cpp | 13 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.h | 6 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyservice.cpp | 11 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyserviceprivate_p.h | 4 |
6 files changed, 178 insertions, 11 deletions
diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp index 65b3964e..2794fe17 100644 --- a/src/bluetooth/qlowenergycontroller_android.cpp +++ b/src/bluetooth/qlowenergycontroller_android.cpp @@ -235,6 +235,21 @@ void QLowEnergyControllerPrivate::writeDescriptor( service->setError(QLowEnergyService::DescriptorWriteError); } +void QLowEnergyControllerPrivate::readCharacteristic( + const QSharedPointer<QLowEnergyServicePrivate> /*service*/, + const QLowEnergyHandle /*charHandle*/) +{ + +} + +void QLowEnergyControllerPrivate::readDescriptor( + const QSharedPointer<QLowEnergyServicePrivate> /*service*/, + const QLowEnergyHandle /*charHandle*/, + const QLowEnergyHandle /*descriptorHandle*/) +{ + +} + void QLowEnergyControllerPrivate::connectionUpdated( QLowEnergyController::ControllerState newState, QLowEnergyController::Error errorCode) diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index d355b070..bb490ba9 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -704,6 +704,11 @@ void QLowEnergyControllerPrivate::processReply( const QLowEnergyHandle charHandle = (handleData & 0xffff); const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff); + QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); + Q_ASSERT(!service.isNull()); + bool isServiceDiscoveryRun + = !(service->state == QLowEnergyService::ServiceDiscovered); + if (isErrorResponse) { Q_ASSERT(!encryptionChangePending); encryptionChangePending = increaseEncryptLevelfRequired(response.constData()[4]); @@ -712,6 +717,12 @@ void QLowEnergyControllerPrivate::processReply( // Retry the same command again once the change has happened openRequests.prepend(request); break; + } else if (!isServiceDiscoveryRun) { + // not encryption problem -> abort readCharacteristic()/readDescriptor() run + if (!descriptorHandle) + emit service->error(QLowEnergyService::CharacteristicReadError); + else + emit service->error(QLowEnergyService::DescriptorReadError); } } else { if (!descriptorHandle) @@ -721,18 +732,32 @@ void QLowEnergyControllerPrivate::processReply( response.mid(1), NEW_VALUE); if (response.size() == mtuSize) { + qCDebug(QT_BT_BLUEZ) << "Switching to blob reads for" + << charHandle << descriptorHandle + << service->characteristicList[charHandle].uuid.toString(); // Potentially more data -> switch to blob reads readServiceValuesByOffset(handleData, mtuSize-1, request.reference2.toBool()); break; + } else if (!isServiceDiscoveryRun) { + // readCharacteristic() or readDescriptor() ongoing + if (!descriptorHandle) { + QLowEnergyCharacteristic ch(service, charHandle); + emit service->characteristicRead(ch, response.mid(1)); + } else { + QLowEnergyDescriptor descriptor(service, charHandle, descriptorHandle); + emit service->descriptorRead(descriptor, response.mid(1)); + } + break; } } - if (request.reference2.toBool()) { + if (request.reference2.toBool() && isServiceDiscoveryRun) { + // we only run into this code path during the initial service discovery + // and not when processing readCharacteristics() after service discovery + //last characteristic -> progress to descriptor discovery //last descriptor -> service discovery is done - QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); - Q_ASSERT(!service.isNull()); if (!descriptorHandle) discoverServiceDescriptors(service->uuid); else @@ -743,13 +768,16 @@ void QLowEnergyControllerPrivate::processReply( case ATT_OP_READ_BLOB_REQUEST: //error case case ATT_OP_READ_BLOB_RESPONSE: { - //Reading characteristic or descriptor with value longer than MTU + //Reading characteristic or descriptor with value longer value than MTU Q_ASSERT(request.command == ATT_OP_READ_BLOB_REQUEST); uint handleData = request.reference.toUInt(); const QLowEnergyHandle charHandle = (handleData & 0xffff); const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff); + QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); + Q_ASSERT(!service.isNull()); + /* * READ_BLOB does not require encryption setup code. BLOB commands * are only issued after read request if the read request is too long @@ -763,18 +791,33 @@ void QLowEnergyControllerPrivate::processReply( else length = updateValueOfDescriptor(charHandle, descriptorHandle, response.mid(1), APPEND_VALUE); + if (response.size() == mtuSize) { readServiceValuesByOffset(handleData, length, request.reference2.toBool()); break; + } else if (service->state == QLowEnergyService::ServiceDiscovered) { + // readCharacteristic() or readDescriptor() ongoing + if (!descriptorHandle) { + QLowEnergyCharacteristic ch(service, charHandle); + emit service->characteristicRead(ch, ch.value()); + } else { + QLowEnergyDescriptor descriptor(service, charHandle, descriptorHandle); + emit service->descriptorRead(descriptor, descriptor.value()); + } + break; } + } else { + qWarning() << "READ BLOB for char:" << charHandle + << "descriptor:" << descriptorHandle << "on service" + << service->uuid.toString() << "failed (service discovery run:" + << (service->state == QLowEnergyService::ServiceDiscovered) << ")"; } if (request.reference2.toBool()) { //last overlong characteristic -> progress to descriptor discovery //last overlong descriptor -> service discovery is done - QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); - Q_ASSERT(!service.isNull()); + if (!descriptorHandle) discoverServiceDescriptors(service->uuid); else @@ -1080,7 +1123,8 @@ void QLowEnergyControllerPrivate::sendReadByTypeRequest( /*! \internal - Reads the value of characteristics and descriptors. + Reads all values of specific characteristic and descriptor. This function is + used during the initial service discovery process. \a readCharacteristics determines whether we intend to read a characteristic; otherwise we read a descriptor. @@ -1091,10 +1135,10 @@ void QLowEnergyControllerPrivate::readServiceValues( quint8 packet[READ_REQUEST_HEADER_SIZE]; if (QT_BT_BLUEZ().isDebugEnabled()) { if (readCharacteristics) - qCDebug(QT_BT_BLUEZ) << "Reading characteristic values for" + qCDebug(QT_BT_BLUEZ) << "Reading all characteristic values for" << serviceUuid.toString(); else - qCDebug(QT_BT_BLUEZ) << "Reading descriptor values for" + qCDebug(QT_BT_BLUEZ) << "Reading all descriptor values for" << serviceUuid.toString(); } @@ -1583,6 +1627,84 @@ void QLowEnergyControllerPrivate::writeDescriptor( } /*! + \internal + + Reads the value of one specific characteristic. + */ +void QLowEnergyControllerPrivate::readCharacteristic( + const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle) +{ + Q_ASSERT(!service.isNull()); + if (!service->characteristicList.contains(charHandle)) + return; + + const QLowEnergyServicePrivate::CharData &charDetails + = service->characteristicList[charHandle]; + if (!(charDetails.properties & QLowEnergyCharacteristic::Read)) { + // if this succeeds the device has a bug, char is advertised as + // non-readable. We try to be permissive and let the remote + // device answer to the read attempt + qCWarning(QT_BT_BLUEZ) << "Reading non-readable char" << charHandle; + } + + quint8 packet[READ_REQUEST_HEADER_SIZE]; + packet[0] = ATT_OP_READ_REQUEST; + bt_put_unaligned(htobs(charDetails.valueHandle), (quint16 *) &packet[1]); + + QByteArray data(READ_REQUEST_HEADER_SIZE, Qt::Uninitialized); + memcpy(data.data(), packet, READ_REQUEST_HEADER_SIZE); + + qCDebug(QT_BT_BLUEZ) << "Targeted reading characteristic" << hex << charHandle; + + Request request; + request.payload = data; + request.command = ATT_OP_READ_REQUEST; + request.reference = charHandle; + // reference2 not really required but false prevents service discovery + // code from running in ATT_OP_READ_RESPONSE handler + request.reference2 = false; + openRequests.enqueue(request); + + sendNextPendingRequest(); +} + +void QLowEnergyControllerPrivate::readDescriptor( + const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle) +{ + Q_ASSERT(!service.isNull()); + if (!service->characteristicList.contains(charHandle)) + return; + + const QLowEnergyServicePrivate::CharData &charDetails + = service->characteristicList[charHandle]; + if (!charDetails.descriptorList.contains(descriptorHandle)) + return; + + quint8 packet[READ_REQUEST_HEADER_SIZE]; + packet[0] = ATT_OP_READ_REQUEST; + bt_put_unaligned(htobs(descriptorHandle), (quint16 *) &packet[1]); + + QByteArray data(READ_REQUEST_HEADER_SIZE, Qt::Uninitialized); + memcpy(data.data(), packet, READ_REQUEST_HEADER_SIZE); + + qCDebug(QT_BT_BLUEZ) << "Targeted reading descriptor" << hex << descriptorHandle; + + Request request; + request.payload = data; + request.command = ATT_OP_READ_REQUEST; + request.reference = (charHandle | (descriptorHandle << 16)); + // reference2 not really required but false prevents service discovery + // code from running in ATT_OP_READ_RESPONSE handler + request.reference2 = false; + openRequests.enqueue(request); + + sendNextPendingRequest(); +} + +/*! * Returns true if the encryption change was successfully requested. * The request is triggered if we got a related ATT error. */ diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp index 79f463ef..b3c718b5 100644 --- a/src/bluetooth/qlowenergycontroller_p.cpp +++ b/src/bluetooth/qlowenergycontroller_p.cpp @@ -74,6 +74,19 @@ void QLowEnergyControllerPrivate::discoverServiceDetails(const QBluetoothUuid &/ } +void QLowEnergyControllerPrivate::readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> /*service*/, + const QLowEnergyHandle /*charHandle*/) +{ + +} + +void QLowEnergyControllerPrivate::readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> /*service*/, + const QLowEnergyHandle /*charHandle*/, + const QLowEnergyHandle /*descriptorHandle*/) +{ + +} + void QLowEnergyControllerPrivate::writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> /*service*/, const QLowEnergyHandle /*charHandle*/, const QByteArray &/*newValue*/, diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index 408cc72a..9e2cedbc 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -112,6 +112,12 @@ public: const QByteArray &value, bool appendValue); + // read data + void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle); + void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle); // write data void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service, diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp index 14b9777b..0db349f1 100644 --- a/src/bluetooth/qlowenergyservice.cpp +++ b/src/bluetooth/qlowenergyservice.cpp @@ -339,6 +339,10 @@ QLowEnergyService::QLowEnergyService(QSharedPointer<QLowEnergyServicePrivate> p, this, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray))); connect(p.data(), SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray)), this, SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray))); + connect(p.data(), SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)), + this, SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray))); + connect(p.data(), SIGNAL(descriptorRead(QLowEnergyDescriptor,QByteArray)), + this, SIGNAL(descriptorRead(QLowEnergyDescriptor,QByteArray))); } /*! @@ -574,7 +578,8 @@ void QLowEnergyService::readCharacteristic( return; } - //TODO + d->controller->readCharacteristic(characteristic.d_ptr, + characteristic.attributeHandle()); } /*! @@ -688,7 +693,9 @@ void QLowEnergyService::readDescriptor( return; } - //TODO implement QLowEnergyService::readDescriptor() + d->controller->readDescriptor(descriptor.d_ptr, + descriptor.characteristicHandle(), + descriptor.handle()); } /*! diff --git a/src/bluetooth/qlowenergyserviceprivate_p.h b/src/bluetooth/qlowenergyserviceprivate_p.h index cc9b452f..a020341f 100644 --- a/src/bluetooth/qlowenergyserviceprivate_p.h +++ b/src/bluetooth/qlowenergyserviceprivate_p.h @@ -80,8 +80,12 @@ signals: void error(QLowEnergyService::ServiceError error); void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void characteristicRead(const QLowEnergyCharacteristic &info, + const QByteArray &value); void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue); + void descriptorRead(const QLowEnergyDescriptor &info, + const QByteArray &value); void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue); |