summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bluetooth/qlowenergycharacteristic.cpp13
-rw-r--r--src/bluetooth/qlowenergycharacteristic.h2
-rw-r--r--src/bluetooth/qlowenergycontrollernew.cpp18
-rw-r--r--src/bluetooth/qlowenergycontrollernew_bluez.cpp109
-rw-r--r--src/bluetooth/qlowenergycontrollernew_p.h11
-rw-r--r--src/bluetooth/qlowenergyservice.cpp14
-rw-r--r--src/bluetooth/qlowenergyservice.h7
-rw-r--r--tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp474
8 files changed, 607 insertions, 41 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);
diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
index 0c9e051c..f37d5d80 100644
--- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
+++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
@@ -42,9 +42,11 @@
#include <QtTest/QtTest>
#include <QBluetoothLocalDevice>
#include <QBluetoothServiceDiscoveryAgent>
+#include <QBluetoothUuid>
#include <QLowEnergyController>
#include <QLowEnergyControllerNew>
#include <QLowEnergyServiceInfo>
+#include <QLowEnergyCharacteristic>
#include <QDebug>
@@ -74,6 +76,7 @@ private slots:
private:
void verifyServiceProperties(const QLowEnergyServiceInfo &info);
+ void verifyServiceProperties(const QLowEnergyService *info);
QBluetoothServiceDiscoveryAgent *agent;
QBluetoothAddress remoteDevice;
@@ -823,7 +826,7 @@ void tst_QLowEnergyController::tst_connectNew()
// initiate characteristic discovery
foreach (QLowEnergyService *service, savedReferences) {
- //qDebug() << "Discoverying" << service->serviceUuid();
+ qDebug() << "Discoverying" << service->serviceUuid();
QSignalSpy stateSpy(service,
SIGNAL(stateChanged(QLowEnergyService::ServiceState)));
QSignalSpy errorSpy(service, SIGNAL(error(QLowEnergyService::ServiceError)));
@@ -835,6 +838,8 @@ void tst_QLowEnergyController::tst_connectNew()
QCOMPARE(errorSpy.count(), 0); //no error
QCOMPARE(stateSpy.count(), 2); //
+ verifyServiceProperties(service);
+
// for (int i = 0; i < stateSpy.count(); i++) {
// const QVariant v = stateSpy[i].at(0);
// //qDebug() << v;
@@ -860,6 +865,473 @@ void tst_QLowEnergyController::tst_connectNew()
uuid.toString().toLatin1());
}
}
+
+ qDeleteAll(savedReferences);
+ savedReferences.clear();
+}
+
+void tst_QLowEnergyController::verifyServiceProperties(
+ const QLowEnergyService *info)
+{
+ if (info->serviceUuid() ==
+ QBluetoothUuid(QString("00001800-0000-1000-8000-00805f9b34fb"))) {
+ qDebug() << "Verifying GAP Service";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 5);
+
+ // Device Name
+ QString temp("00002a00-0000-1000-8000-00805f9b34fb");
+ qDebug() << chars[0].uuid().toString() << temp;
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x3u);
+ QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Read);
+ QCOMPARE(chars[0].value(), QByteArray("544920424c452053656e736f7220546167"));
+ QVERIFY(chars[0].isValid());
+ QCOMPARE(chars[0].descriptors().count(), 0);
+
+ // Appearance
+ temp = QString("00002a01-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x5u);
+ QCOMPARE(chars[1].properties(), QLowEnergyCharacteristic::Read);
+ QCOMPARE(chars[1].value(), QByteArray("0000"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+
+ // Peripheral Privacy Flag
+ temp = QString("00002a02-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[2].handle(), 0x7u);
+ QCOMPARE(chars[2].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[2].value(), QByteArray("00"));
+ QVERIFY(chars[2].isValid());
+ QCOMPARE(chars[2].descriptors().count(), 0);
+
+ // Reconnection Address
+ temp = QString("00002a03-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[3].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[3].handle(), 0x9u);
+ QCOMPARE(chars[3].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[3].value(), QByteArray("000000000000"));
+ QVERIFY(chars[3].isValid());
+ QCOMPARE(chars[3].descriptors().count(), 0);
+
+ // Peripheral Preferred Connection Parameters
+ temp = QString("00002a04-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[4].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[4].handle(), 0xbu);
+ QCOMPARE(chars[4].properties(), QLowEnergyCharacteristic::Read);
+ QCOMPARE(chars[4].value(), QByteArray("5000a0000000e803"));
+ QVERIFY(chars[4].isValid());
+ QCOMPARE(chars[4].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("00001801-0000-1000-8000-00805f9b34fb"))) {
+ qDebug() << "Verifying GATT Service";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 1);
+
+ // Service Changed
+ QString temp("00002a05-0000-1000-8000-00805f9b34fb");
+ //this should really be readable according to GATT Service spec
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0xeu);
+ QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Indicate);
+ QCOMPARE(chars[0].value(), QByteArray(""));
+ QVERIFY(chars[0].isValid());
+ QCOMPARE(chars[0].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("0000180a-0000-1000-8000-00805f9b34fb"))) {
+ qDebug() << "Verifying Device Information";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 9);
+
+ // System ID
+ QString temp("00002a23-0000-1000-8000-00805f9b34fb");
+ //this should really be readable according to GATT Service spec
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x12u);
+ QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Read);
+ QCOMPARE(chars[0].value(), QByteArray("6e41ab0000296abc"));
+ QVERIFY(chars[0].isValid());
+ QCOMPARE(chars[0].descriptors().count(), 0);
+
+ // Model Number
+ temp = QString("00002a24-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x14u);
+ QCOMPARE(chars[1].properties(), QLowEnergyCharacteristic::Read);
+ QCOMPARE(chars[1].value(), QByteArray("4e2e412e00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+
+ // Serial Number
+ temp = QString("00002a25-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[2].handle(), 0x16u);
+ QCOMPARE(chars[2].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[2].value(), QByteArray("4e2e412e00"));
+ QVERIFY(chars[2].isValid());
+ QCOMPARE(chars[2].descriptors().count(), 0);
+
+ // Firmware Revision
+ temp = QString("00002a26-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[3].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[3].handle(), 0x18u);
+ QCOMPARE(chars[3].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[3].value(), QByteArray("312e3031202846656220203720323031332900"));
+ QVERIFY(chars[3].isValid());
+ QCOMPARE(chars[3].descriptors().count(), 0);
+
+ // Hardware Revision
+ temp = QString("00002a27-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[4].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[4].handle(), 0x1au);
+ QCOMPARE(chars[4].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[4].value(), QByteArray("4e2e412e00"));
+ QVERIFY(chars[4].isValid());
+ QCOMPARE(chars[4].descriptors().count(), 0);
+
+ // Software Revision
+ temp = QString("00002a28-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[5].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[5].handle(), 0x1cu);
+ QCOMPARE(chars[5].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[5].value(), QByteArray("4e2e412e00"));
+ QVERIFY(chars[5].isValid());
+ QCOMPARE(chars[5].descriptors().count(), 0);
+
+ // Manufacturer Name
+ temp = QString("00002a29-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[6].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[6].handle(), 0x1eu);
+ QCOMPARE(chars[6].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[6].value(), QByteArray("546578617320496e737472756d656e747300"));
+ QVERIFY(chars[6].isValid());
+ QCOMPARE(chars[6].descriptors().count(), 0);
+
+ // IEEE
+ temp = QString("00002a2a-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[7].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[7].handle(), 0x20u);
+ QCOMPARE(chars[7].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[7].value(), QByteArray("fe006578706572696d656e74616c"));
+ QVERIFY(chars[7].isValid());
+ QCOMPARE(chars[7].descriptors().count(), 0);
+
+ // PnP ID
+ temp = QString("00002a50-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[8].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[8].handle(), 0x22u);
+ QCOMPARE(chars[8].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[8].value(), QByteArray("010d0000001001"));
+ QVERIFY(chars[8].isValid());
+ QCOMPARE(chars[8].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa00-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Temperature";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 2);
+
+ // Temp Data
+ QString temp("f000aa01-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x25u);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ //QCOMPARE(chars[0].value(), QByteArray("30303030"));
+ QVERIFY(chars[0].isValid());
+// QCOMPARE(chars[0].descriptors().count(), 1);
+//
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x26u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(QBluetoothUuid(chars[0].descriptors().at(0).type()), QBluetoothUuid(temp));
+
+ // Temp Config
+ temp = QString("f000aa02-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x29u);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("0000ffe0-0000-1000-8000-00805f9b34fb"))) {
+ qDebug() << "Verifying Simple Keys";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 1);
+
+ // Temp Data
+ QString temp("0000ffe1-0000-1000-8000-00805f9b34fb");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x5fu);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray(""));
+ QVERIFY(chars[0].isValid());
+ QCOMPARE(chars[0].descriptors().count(), 0); //TODO should be 1?
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa10-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Accelerometer";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 3);
+
+ // Accel Data
+ QString temp("f000aa11-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x2du);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray("000000"));
+ QVERIFY(chars[0].isValid());
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x2eu);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(QBluetoothUuid(chars[0].descriptors().at(0).type()), QBluetoothUuid(temp));
+
+ // Accel Config
+ temp = QString("f000aa12-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x31u);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+
+ // Accel Period
+ temp = QString("f000aa13-0451-4000-b000-000000000000");
+ QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[2].handle(), 0x34u);
+ QCOMPARE(chars[2].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[2].value(), QByteArray("64")); // don't change it or set it to 0x64
+ QVERIFY(chars[2].isValid());
+ QCOMPARE(chars[2].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa20-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Humidity";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 2);
+
+ // Humidity Data
+ QString temp("f000aa21-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x38u);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray("00000000"));
+ QVERIFY(chars[0].isValid());
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x39u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(QBluetoothUuid(chars[0].descriptors().at(0).type()), QBluetoothUuid(temp));
+
+ // Humidity Config
+ temp = QString("f000aa22-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x3cu);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa30-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Magnetometer";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 3);
+
+ // Magnetometer Data
+ QString temp("f000aa31-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x40u);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray("000000000000"));
+ QVERIFY(chars[0].isValid());
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x41u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(QBluetoothUuid(chars[0].descriptors().at(0).type()), QBluetoothUuid(temp));
+
+ // Magnetometer Config
+ temp = QString("f000aa32-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x44u);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+
+ // Magnetometer Period
+ temp = QString("f000aa33-0451-4000-b000-000000000000");
+ QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[2].handle(), 0x47u);
+ QCOMPARE(chars[2].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[2].value(), QByteArray("c8")); // don't change it or set it to 0xc8
+ QVERIFY(chars[2].isValid());
+ QCOMPARE(chars[2].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa40-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Pressure";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 3);
+
+ // Pressure Data
+ QString temp("f000aa41-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x4bu);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray("00000000"));
+ QVERIFY(chars[0].isValid());
+ //QEXPECT_FAIL("", "0x4b has at least a notification", Continue);
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// if (!chars[0].descriptors().isEmpty()) {
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x41u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// }
+
+ // Pressure Config
+ temp = QString("f000aa42-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x4fu);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+
+ // Pressure Calibration
+ temp = QString("f000aa43-0451-4000-b000-000000000000");
+ QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[2].handle(), 0x52u);
+ QCOMPARE(chars[2].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[2].value(), QByteArray("00000000000000000000000000000000")); // don't change it
+ QVERIFY(chars[2].isValid());
+ QCOMPARE(chars[2].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa50-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Gyroscope";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 2);
+
+ // Gyroscope Data
+ QString temp("f000aa51-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x57u);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
+ QCOMPARE(chars[0].value(), QByteArray("000000000000"));
+ QVERIFY(chars[0].isValid());
+ //QEXPECT_FAIL("", "there is a notification under 0x0057", Continue);
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// if (!chars[0].descriptors().isEmpty()) {
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x39u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// }
+
+ // Gyroscope Config
+ temp = QString("f000aa52-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x5bu);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000aa60-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Test Service";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 2);
+
+ // Test Data
+ QString temp("f000aa61-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x64u);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Read));
+ QCOMPARE(chars[0].value(), QByteArray("3f00"));
+ QVERIFY(chars[0].isValid());
+ QCOMPARE(chars[0].descriptors().count(), 0);
+
+ // Test Config
+ temp = QString("f000aa62-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x67u);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
+ QCOMPARE(chars[1].value(), QByteArray("00"));
+ QVERIFY(chars[1].isValid());
+ QCOMPARE(chars[1].descriptors().count(), 0);
+ } else if (info->serviceUuid() ==
+ QBluetoothUuid(QString("f000ffc0-0451-4000-b000-000000000000"))) {
+ qDebug() << "Verifying Unknown Service";
+ QList<QLowEnergyCharacteristic> chars = info->characteristics();
+ QCOMPARE(chars.count(), 2);
+
+ // first characteristic
+ QString temp("f000ffc1-0451-4000-b000-000000000000");
+ QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[0].handle(), 0x6bu);
+ QCOMPARE(chars[0].properties(),
+ (QLowEnergyCharacteristic::Notify|QLowEnergyCharacteristic::Write|QLowEnergyCharacteristicInfo::WriteNoResponse));
+ QCOMPARE(chars[0].value(), QByteArray(""));
+ QVERIFY(chars[0].isValid());
+// QEXPECT_FAIL("", "there is a notification under 0x006b", Continue);
+// QCOMPARE(chars[0].descriptors().count(), 1);
+
+// if (!chars[0].descriptors().isEmpty()) {
+// temp = QString("00002902-0000-1000-8000-00805f9b34fb");
+// QCOMPARE(chars[0].descriptors().at(0).handle(), 0x39u);
+// QCOMPARE(chars[0].descriptors().at(0).uuid(), QBluetoothUuid(temp));
+// QCOMPARE(chars[0].descriptors().at(0).value(), QByteArray("0000"));
+// }
+
+ // second characteristic
+ temp = QString("f000ffc2-0451-4000-b000-000000000000");
+ QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
+ QCOMPARE(chars[1].handle(), 0x6fu);
+ QCOMPARE(chars[1].properties(),
+ (QLowEnergyCharacteristic::Notify|QLowEnergyCharacteristic::Write|QLowEnergyCharacteristicInfo::WriteNoResponse));
+ QCOMPARE(chars[1].value(), QByteArray(""));
+ QVERIFY(chars[1].isValid());
+// QEXPECT_FAIL("", "there is a notification under 0x006f", Continue);
+// QCOMPARE(chars[1].descriptors().count(), 1);
+ } else {
+ QFAIL(QString("Service not found" + info->serviceUuid().toString()).toUtf8().constData());
+ }
}
void tst_QLowEnergyController::tst_defaultBehavior()