summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-07-24 16:16:19 +0200
committerAlex Blasche <alexander.blasche@digia.com>2014-08-13 13:47:47 +0200
commit02a9784b2b502ade67710632c2872bda097770e3 (patch)
tree6f289cdf22b3bc023486712b5b6f433af78a318c
parent0e367adbfe8e0971930315d1c58b4ef0bf80a9ba (diff)
Support reading of chars & descs if their value is larger than MTU
Change-Id: I49945b13f9b2ee025541c7f689b55fa994c8057d Reviewed-by: Fabian Bumberger <fbumberger@rim.com>
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp37
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp117
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h15
3 files changed, 149 insertions, 20 deletions
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index c8ffc802..d0c70ba3 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -174,26 +174,45 @@ QLowEnergyDescriptor QLowEnergyControllerPrivate::descriptorForHandle(
return QLowEnergyDescriptor();
}
-void QLowEnergyControllerPrivate::updateValueOfCharacteristic(
- QLowEnergyHandle charHandle, const QByteArray &value)
+/*!
+ Returns the length of the updated characteristic value.
+ */
+quint16 QLowEnergyControllerPrivate::updateValueOfCharacteristic(
+ QLowEnergyHandle charHandle,const QByteArray &value, bool appendValue)
{
QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
- if (!service.isNull() && service->characteristicList.contains(charHandle))
- service->characteristicList[charHandle].value = value;
+ if (!service.isNull() && service->characteristicList.contains(charHandle)) {
+ if (appendValue)
+ service->characteristicList[charHandle].value += value;
+ else
+ service->characteristicList[charHandle].value = value;
+
+ return service->characteristicList[charHandle].value.size();
+ }
+
+ return 0;
}
-void QLowEnergyControllerPrivate::updateValueOfDescriptor(
+/*!
+ Returns the length of the updated descriptor value.
+ */
+quint16 QLowEnergyControllerPrivate::updateValueOfDescriptor(
QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle,
- const QByteArray &value)
+ const QByteArray &value, bool appendValue)
{
QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
if (service.isNull() || !service->characteristicList.contains(charHandle))
- return;
+ return 0;
if (!service->characteristicList[charHandle].descriptorList.contains(descriptorHandle))
- return;
+ return 0;
+
+ if (appendValue)
+ service->characteristicList[charHandle].descriptorList[descriptorHandle].value += value;
+ else
+ service->characteristicList[charHandle].descriptorList[descriptorHandle].value = value;
- service->characteristicList[charHandle].descriptorList[descriptorHandle].value = value;
+ return service->characteristicList[charHandle].descriptorList[descriptorHandle].value.size();
}
QLowEnergyController::QLowEnergyController(
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index f92d188d..fe0ae9f2 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -70,6 +70,8 @@
#define ATT_OP_READ_BY_TYPE_RESPONSE 0x9
#define ATT_OP_READ_REQUEST 0xA //read characteristic & descriptor values
#define ATT_OP_READ_RESPONSE 0xB
+#define ATT_OP_READ_BLOB_REQUEST 0xC //read values longer than MTU-1
+#define ATT_OP_READ_BLOB_RESPONSE 0xD
#define ATT_OP_READ_BY_GROUP_REQUEST 0x10 //discover services
#define ATT_OP_READ_BY_GROUP_RESPONSE 0x11
#define ATT_OP_WRITE_REQUEST 0x12 //write characteristic
@@ -83,6 +85,7 @@
#define GRP_TYPE_REQ_SIZE 7
#define READ_BY_TYPE_REQ_SIZE 7
#define READ_REQUEST_SIZE 3
+#define READ_BLOB_REQUEST_SIZE 5
#define WRITE_REQUEST_SIZE 3
#define MTU_EXCHANGE_SIZE 3
@@ -105,6 +108,9 @@
#define ATT_ERROR_APPLICATION 0x10
#define ATT_ERROR_INSUF_RESOURCES 0x11
+#define APPEND_VALUE true
+#define NEW_VALUE false
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
@@ -585,20 +591,29 @@ void QLowEnergyControllerPrivate::processReply(
//Reading characteristics and descriptors
Q_ASSERT(request.command == ATT_OP_READ_REQUEST);
- uint ref = request.reference.toUInt();
- const QLowEnergyHandle charHandle = (ref & 0xffff);
- const QLowEnergyHandle descriptorHandle = ((ref >> 16) & 0xffff);
+ uint handleData = request.reference.toUInt();
+ const QLowEnergyHandle charHandle = (handleData & 0xffff);
+ const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff);
// we ignore error response
if (!isErrorResponse) {
if (!descriptorHandle)
- updateValueOfCharacteristic(charHandle, response.mid(1));
+ updateValueOfCharacteristic(charHandle, response.mid(1), NEW_VALUE);
else
updateValueOfDescriptor(charHandle, descriptorHandle,
- response.mid(1));
+ response.mid(1), NEW_VALUE);
+
+ if (response.size() == mtuSize) {
+ // Potentially more data -> switch to blob reads
+ readServiceValuesByOffset(handleData, mtuSize-1,
+ request.reference2.toBool());
+ break;
+ }
}
if (request.reference2.toBool()) {
+ //last characteristic -> progress to descriptor discovery
+ //last descriptor -> service discovery is done
QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
Q_ASSERT(!service.isNull());
if (!descriptorHandle)
@@ -608,6 +623,44 @@ void QLowEnergyControllerPrivate::processReply(
}
}
break;
+ case ATT_OP_READ_BLOB_REQUEST: //error case
+ case ATT_OP_READ_BLOB_RESPONSE:
+ {
+ //Reading characteristic or descriptor with value longer 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);
+
+ //ignore errors
+ if (!isErrorResponse) {
+ quint16 length = 0;
+ if (!descriptorHandle)
+ length = updateValueOfCharacteristic(charHandle, response.mid(1), APPEND_VALUE);
+ else
+ length = updateValueOfDescriptor(charHandle, descriptorHandle,
+ response.mid(1), APPEND_VALUE);
+ if (response.size() == mtuSize) {
+ readServiceValuesByOffset(handleData, length,
+ request.reference2.toBool());
+ break;
+ }
+ }
+
+ 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
+ service->setState(QLowEnergyService::ServiceDiscovered);
+ }
+
+ }
+ break;
case ATT_OP_FIND_INFORMATION_REQUEST: //error case
case ATT_OP_FIND_INFORMATION_RESPONSE:
{
@@ -919,6 +972,58 @@ void QLowEnergyControllerPrivate::readServiceValues(
sendNextPendingRequest();
}
+/*!
+ \internal
+
+ This function is used when reading a handle value that is
+ longer than the mtuSize.
+
+ The BLOB read request is prepended to the list of
+ open requests to finish the current value read up before
+ starting the next read request.
+ */
+void QLowEnergyControllerPrivate::readServiceValuesByOffset(
+ quint16 handleData, quint16 offset, bool isLastValue)
+{
+ const QLowEnergyHandle charHandle = (handleData & 0xffff);
+ const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff);
+ quint8 packet[READ_REQUEST_SIZE];
+
+ packet[0] = ATT_OP_READ_BLOB_REQUEST;
+
+ QLowEnergyHandle handleToRead = charHandle;
+ if (descriptorHandle) {
+ handleToRead = descriptorHandle;
+ qCDebug(QT_BT_BLUEZ) << "Reading descriptor via blob request"
+ << hex << descriptorHandle;
+ } else {
+ //charHandle is not the char's value handle
+ QSharedPointer<QLowEnergyServicePrivate> service =
+ serviceForHandle(charHandle);
+ if (!service.isNull()
+ && service->characteristicList.contains(charHandle)) {
+ handleToRead = service->characteristicList[charHandle].valueHandle;
+ qCDebug(QT_BT_BLUEZ) << "Reading characteristic via blob request"
+ << hex << handleToRead;
+ } else {
+ Q_ASSERT(false);
+ }
+ }
+
+ bt_put_unaligned(htobs(handleToRead), (quint16 *) &packet[1]);
+ bt_put_unaligned(htobs(offset), (quint16 *) &packet[3]);
+
+ QByteArray data(READ_BLOB_REQUEST_SIZE, Qt::Uninitialized);
+ memcpy(data.data(), packet, READ_BLOB_REQUEST_SIZE);
+
+ Request request;
+ request.payload = data;
+ request.command = ATT_OP_READ_BLOB_REQUEST;
+ request.reference = handleData;
+ request.reference2 = isLastValue;
+ openRequests.prepend(request);
+}
+
void QLowEnergyControllerPrivate::discoverServiceDescriptors(
const QBluetoothUuid &serviceUuid)
{
@@ -954,7 +1059,7 @@ void QLowEnergyControllerPrivate::processUnsolicitedReply(const QByteArray &payl
const QLowEnergyCharacteristic ch = characteristicForHandle(changedHandle);
if (ch.isValid() && ch.handle() == changedHandle) {
- updateValueOfCharacteristic(ch.attributeHandle(), payload.mid(3));
+ updateValueOfCharacteristic(ch.attributeHandle(), payload.mid(3), NEW_VALUE);
emit ch.d_ptr->characteristicChanged(ch, payload.mid(3));
} else {
qCWarning(QT_BT_BLUEZ) << "Cannot find matching characteristic for "
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index c3743320..ef21fbff 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -85,11 +85,13 @@ public:
QLowEnergyDescriptor descriptorForHandle(
QLowEnergyHandle handle);
- void updateValueOfCharacteristic(QLowEnergyHandle charHandle,
- const QByteArray &value);
- void updateValueOfDescriptor(QLowEnergyHandle charHandle,
+ quint16 updateValueOfCharacteristic(QLowEnergyHandle charHandle,
+ const QByteArray &value,
+ bool appendValue);
+ quint16 updateValueOfDescriptor(QLowEnergyHandle charHandle,
QLowEnergyHandle descriptorHandle,
- const QByteArray &value);
+ const QByteArray &value,
+ bool appendValue);
// write data
@@ -136,7 +138,10 @@ private:
void sendReadByTypeRequest(QSharedPointer<QLowEnergyServicePrivate> serviceData,
QLowEnergyHandle nextHandle, quint16 attributeType);
void sendReadValueRequest(QLowEnergyHandle attributeHandle, bool isDescriptor);
- void readServiceValues(const QBluetoothUuid &service, bool readCharacteristics);
+ void readServiceValues(const QBluetoothUuid &service,
+ bool readCharacteristics);
+ void readServiceValuesByOffset(quint16 handleData, quint16 offset,
+ bool isLastValue);
void discoverServiceDescriptors(const QBluetoothUuid &serviceUuid);
void discoverNextDescriptor(QSharedPointer<QLowEnergyServicePrivate> serviceData,