diff options
author | Alex Blasche <alexander.blasche@digia.com> | 2014-06-23 08:16:28 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@digia.com> | 2014-06-26 16:36:15 +0200 |
commit | 3c9c77c94d747a568a22421c0b0ada086463dbad (patch) | |
tree | f948d74a67e7aada343f7a4af4fefca18fcff4db /src | |
parent | 417ac65051bba0f91185f437c90a3d6f36b99d60 (diff) |
Read characteristic values on Bluez
Change-Id: I6427c6dad133ca11852f5295cf37720addec7644
Reviewed-by: Fabian Bumberger <fbumberger@rim.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/bluetooth/qlowenergycharacteristic.cpp | 13 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycharacteristic.h | 2 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew.cpp | 18 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew_bluez.cpp | 109 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew_p.h | 11 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyservice.cpp | 14 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyservice.h | 7 |
7 files changed, 134 insertions, 40 deletions
diff --git a/src/bluetooth/qlowenergycharacteristic.cpp b/src/bluetooth/qlowenergycharacteristic.cpp index 0d0ad60c..10136c10 100644 --- a/src/bluetooth/qlowenergycharacteristic.cpp +++ b/src/bluetooth/qlowenergycharacteristic.cpp @@ -100,17 +100,10 @@ QLowEnergyCharacteristic::QLowEnergyCharacteristic(): upon write. */ QLowEnergyCharacteristic::QLowEnergyCharacteristic(const QLowEnergyCharacteristic &other): - d_ptr(other.d_ptr) + d_ptr(other.d_ptr), data(0) { - if (!other.data) { - if (data) { - delete data; - data = 0; - } - } else { - if (!data) - data = new QLowEnergyCharacteristicPrivate(); - + if (other.data) { + data = new QLowEnergyCharacteristicPrivate(); data->handle = other.data->handle; } } diff --git a/src/bluetooth/qlowenergycharacteristic.h b/src/bluetooth/qlowenergycharacteristic.h index 7dc91f43..6454ef67 100644 --- a/src/bluetooth/qlowenergycharacteristic.h +++ b/src/bluetooth/qlowenergycharacteristic.h @@ -92,6 +92,8 @@ public: protected: QSharedPointer<QLowEnergyServicePrivate> d_ptr; + + friend class QLowEnergyService; QLowEnergyCharacteristicPrivate *data; QLowEnergyCharacteristic(QSharedPointer<QLowEnergyServicePrivate> p, QLowEnergyHandle handle); diff --git a/src/bluetooth/qlowenergycontrollernew.cpp b/src/bluetooth/qlowenergycontrollernew.cpp index 8b98c6b9..75fcce86 100644 --- a/src/bluetooth/qlowenergycontrollernew.cpp +++ b/src/bluetooth/qlowenergycontrollernew.cpp @@ -108,6 +108,24 @@ void QLowEnergyControllerNewPrivate::invalidateServices() serviceList.clear(); } +QSharedPointer<QLowEnergyServicePrivate> QLowEnergyControllerNewPrivate::serviceForHandle( + QLowEnergyHandle handle) +{ + foreach (QSharedPointer<QLowEnergyServicePrivate> service, serviceList.values()) + if (service->startHandle <= handle && handle <= service->endHandle) + return service; + + return QSharedPointer<QLowEnergyServicePrivate>(); +} + +void QLowEnergyControllerNewPrivate::updateValueOfCharacteristic( + QLowEnergyHandle charHandle, const QByteArray &value) +{ + QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); + if (!service.isNull() && service->characteristicList.contains(charHandle)) + service->characteristicList[charHandle].value = value; +} + QLowEnergyControllerNew::QLowEnergyControllerNew( const QBluetoothAddress &remoteDevice, QObject *parent) diff --git a/src/bluetooth/qlowenergycontrollernew_bluez.cpp b/src/bluetooth/qlowenergycontrollernew_bluez.cpp index 8249f1fc..1b5ea1db 100644 --- a/src/bluetooth/qlowenergycontrollernew_bluez.cpp +++ b/src/bluetooth/qlowenergycontrollernew_bluez.cpp @@ -56,9 +56,11 @@ // GATT commands #define ATT_OP_ERROR_RESPONSE 0x1 -#define ATT_OP_READ_BY_TYPE_REQUEST 0x8 +#define ATT_OP_READ_BY_TYPE_REQUEST 0x8 //discover characteristics #define ATT_OP_READ_BY_TYPE_RESPONSE 0x9 -#define ATT_OP_READ_BY_GROUP_REQUEST 0x10 +#define ATT_OP_READ_REQUEST 0xA //read characteristic value +#define ATT_OP_READ_RESPONSE 0xB +#define ATT_OP_READ_BY_GROUP_REQUEST 0x10 //discover services #define ATT_OP_READ_BY_GROUP_RESPONSE 0x11 // GATT error codes @@ -80,9 +82,6 @@ #define ATT_ERROR_APPLICATION 0x10 #define ATT_ERROR_INSUF_RESOURCES 0x11 - - - QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) @@ -231,7 +230,7 @@ void QLowEnergyControllerNewPrivate::l2cpReadyRead() { requestPending = false; const QByteArray reply = l2cpSocket->readAll(); - //qDebug() << response.size() << "data:" << response.toHex(); + qDebug() << reply.size() << "data:" << reply.toHex(); if (reply.isEmpty()) return; @@ -248,8 +247,8 @@ void QLowEnergyControllerNewPrivate::sendNextPendingRequest() return; const Request &request = openRequests.head(); - qCDebug(QT_BT_BLUEZ) << "Sending request, type:" << hex << request.command - << request.payload.toHex(); +// qCDebug(QT_BT_BLUEZ) << "Sending request, type:" << hex << request.command +// << request.payload.toHex(); requestPending = true; qint64 result = l2cpSocket->write(request.payload.constData(), @@ -285,7 +284,7 @@ void QLowEnergyControllerNewPrivate::processReply( if (isErrorResponse) { q->discoveryFinished(); - return; + break; } QLowEnergyHandle start = 0, end = 0; @@ -308,8 +307,8 @@ void QLowEnergyControllerNewPrivate::processReply( offset += elementLength; - //qDebug() << "Found uuid:" << uuid << "start handle:" << hex - // << start << "end handle:" << end; +// qDebug() << "Found uuid:" << uuid << "start handle:" << hex +// << start << "end handle:" << end; QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate(); priv->uuid = uuid; @@ -327,7 +326,6 @@ void QLowEnergyControllerNewPrivate::processReply( sendReadByGroupRequest(end+1, 0xFFFF); else emit q->discoveryFinished(); - } break; case ATT_OP_READ_BY_TYPE_REQUEST: //in case of error @@ -341,8 +339,8 @@ void QLowEnergyControllerNewPrivate::processReply( if (isErrorResponse) { //we reached end of service handle //just finish up characteristic discovery - p->setState(QLowEnergyService::ServiceDiscovered); - return; + readServiceCharacteristicValues(p->uuid); + break; } /* packet format: @@ -378,23 +376,42 @@ void QLowEnergyControllerNewPrivate::processReply( p->characteristicList[startHandle] = characteristic; - qDebug() << "Found handle:" << hex << startHandle - << "properties:" << flags - << "value handle:" << valueHandle - << "uuid:" << uuid.toString(); +// qDebug() << "Found handle:" << hex << startHandle +// << "properties:" << flags +// << "value handle:" << valueHandle +// << "uuid:" << uuid.toString(); } if (startHandle + 1 < p->endHandle) // more chars to discover sendReadByTypeRequest(p, startHandle + 1); else - p->setState(QLowEnergyService::ServiceDiscovered); + readServiceCharacteristicValues(p->uuid); + } + break; + case ATT_OP_READ_REQUEST: //error case + case ATT_OP_READ_RESPONSE: + { + Q_ASSERT(request.command == ATT_OP_READ_REQUEST); + + if (isErrorResponse) { + // we ignore any error and go over to next message + break; + } + + QLowEnergyHandle charHandle = (QLowEnergyHandle) request.reference.toUInt(); + QByteArray a = response.mid(1); + updateValueOfCharacteristic(charHandle, response.mid(1).toHex()); + if (request.reference2.toBool()) { + QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle); + Q_ASSERT(!service.isNull()); + service->setState(QLowEnergyService::ServiceDiscovered); + } } break; default: qCDebug(QT_BT_BLUEZ) << "Unknown packet: " << response.toHex(); + break; } - - } void QLowEnergyControllerNewPrivate::discoverServices() @@ -419,6 +436,8 @@ void QLowEnergyControllerNewPrivate::sendReadByGroupRequest( QByteArray data(GRP_TYPE_REQ_SIZE, Qt::Uninitialized); memcpy(data.data(), packet, GRP_TYPE_REQ_SIZE); +// qDebug() << "Sending read_by_group_type request, startHandle:" << hex +// << start << "endHandle:" << end; Request request; request.payload = data; @@ -458,9 +477,9 @@ void QLowEnergyControllerNewPrivate::sendReadByTypeRequest( QByteArray data(READ_BY_TYPE_REQ_SIZE, Qt::Uninitialized); memcpy(data.data(), packet, READ_BY_TYPE_REQ_SIZE); - qDebug() << "Sending read_by_type request, startHandle:" << hex - << nextHandle << "endHandle:" << serviceData->endHandle - << "packet:" << data.toHex(); +// qDebug() << "Sending read_by_type request, startHandle:" << hex +// << nextHandle << "endHandle:" << serviceData->endHandle +// << "packet:" << data.toHex(); Request request; request.payload = data; @@ -471,5 +490,47 @@ void QLowEnergyControllerNewPrivate::sendReadByTypeRequest( sendNextPendingRequest(); } +void QLowEnergyControllerNewPrivate::readServiceCharacteristicValues( + const QBluetoothUuid &serviceUuid) +{ +#define READ_REQUEST_SIZE 3 + quint8 packet[READ_REQUEST_SIZE]; + qCDebug(QT_BT_BLUEZ) << "Reading characteristic values for" + << serviceUuid.toString(); + + bool oneReadRequested = false; + QSharedPointer<QLowEnergyServicePrivate> service = serviceList.value(serviceUuid); + const QList<QLowEnergyHandle> &keys = service->characteristicList.keys(); + for (int i = 0; i < keys.count(); i++) { + QLowEnergyHandle charHandle = keys[i]; + const QLowEnergyServicePrivate::CharData &charDetails = + service->characteristicList[charHandle]; + + //Don't try to read readOnly property + if (!(charDetails.properties & QLowEnergyCharacteristic::Read)) + continue; + + packet[0] = ATT_OP_READ_REQUEST; + bt_put_unaligned(htobs(charDetails.valueHandle), (quint16 *) &packet[1]); + + QByteArray data(READ_REQUEST_SIZE, Qt::Uninitialized); + memcpy(data.data(), packet, READ_REQUEST_SIZE); + + Request request; + request.payload = data; + request.command = ATT_OP_READ_REQUEST; + request.reference = charHandle; + //last entry? + request.reference2 = QVariant((bool)(i + 1 == keys.count())); + openRequests.enqueue(request); + oneReadRequested = true; + } + + if (!oneReadRequested) + service->setState(QLowEnergyService::ServiceDiscovered); + + sendNextPendingRequest(); +} + QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontrollernew_p.h b/src/bluetooth/qlowenergycontrollernew_p.h index 3f1862dc..f6bc06e5 100644 --- a/src/bluetooth/qlowenergycontrollernew_p.h +++ b/src/bluetooth/qlowenergycontrollernew_p.h @@ -83,6 +83,13 @@ public: void discoverServiceDetails(const QBluetoothUuid &service); + // misc lookup helpers + QSharedPointer<QLowEnergyServicePrivate> serviceForHandle( + QLowEnergyHandle handle); + void updateValueOfCharacteristic(QLowEnergyHandle charHandle, + const QByteArray &value); + + QBluetoothAddress remoteDevice; QBluetoothAddress localAdapter; @@ -100,7 +107,10 @@ private: struct Request { quint8 command; QByteArray payload; + // TODO reference below is ugly but until we know all commands and their + // requirements this is WIP QVariant reference; + QVariant reference2; }; QQueue<Request> openRequests; bool requestPending; @@ -111,6 +121,7 @@ private: void sendReadByGroupRequest(QLowEnergyHandle start, QLowEnergyHandle end); void sendReadByTypeRequest(QSharedPointer<QLowEnergyServicePrivate> serviceData, QLowEnergyHandle nextHandle); + void readServiceCharacteristicValues(const QBluetoothUuid &service); private slots: void l2cpConnected(); diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp index 0080dee9..d8f80397 100644 --- a/src/bluetooth/qlowenergyservice.cpp +++ b/src/bluetooth/qlowenergyservice.cpp @@ -44,6 +44,8 @@ #include <QtBluetooth/QLowEnergyService> #include <QtBluetooth/QLowEnergyCharacteristicInfo> +#include <algorithm> + #include "qlowenergycontrollernew_p.h" #include "qlowenergyserviceprivate_p.h" @@ -94,10 +96,16 @@ QLowEnergyService::ServiceType QLowEnergyService::type() const } -QList<QLowEnergyCharacteristicInfo> QLowEnergyService::characteristics() const +QList<QLowEnergyCharacteristic> QLowEnergyService::characteristics() const { - //TODO implement - QList<QLowEnergyCharacteristicInfo> results; + QList<QLowEnergyCharacteristic> results; + QList<QLowEnergyHandle> handles = d_ptr->characteristicList.keys(); + std::sort(handles.begin(), handles.end()); + + foreach (const QLowEnergyHandle &handle, handles) { + QLowEnergyCharacteristic characteristic(d_ptr, handle); + results.append(characteristic); + } return results; } diff --git a/src/bluetooth/qlowenergyservice.h b/src/bluetooth/qlowenergyservice.h index af4b657d..c2ecc6b0 100644 --- a/src/bluetooth/qlowenergyservice.h +++ b/src/bluetooth/qlowenergyservice.h @@ -42,7 +42,8 @@ #define QLOWENERGYSERVICE_H #include <QtBluetooth/QBluetoothAddress> -#include <QtBluetooth/QLowEnergyCharacteristicInfo> +#include <QtBluetooth/QBluetoothUuid> +#include <QtBluetooth/QLowEnergyCharacteristic> QT_BEGIN_NAMESPACE @@ -76,7 +77,7 @@ public: QLowEnergyService::ServiceState state() const; - QList<QLowEnergyCharacteristicInfo> characteristics() const; + QList<QLowEnergyCharacteristic> characteristics() const; QBluetoothUuid serviceUuid() const; QString serviceName() const; @@ -87,7 +88,7 @@ public: Q_SIGNALS: void stateChanged(QLowEnergyService::ServiceState newState); - void characteristicChanged(const QLowEnergyCharacteristicInfo &info, + void characteristicChanged(const QLowEnergyCharacteristic &info, const QByteArray &value); void descriptorChanged(const QLowEnergyDescriptorInfo &info, const QByteArray &value); |