summaryrefslogtreecommitdiffstats
path: root/src/bluetooth
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-08-27 10:57:08 +0200
committerAlex Blasche <alexander.blasche@digia.com>2014-09-02 20:18:21 +0200
commit4ab9c732a466dc793e5ec162a928d4350a29281c (patch)
treeb5fb9c1e074fb8228936d34894ab61dd452e003f /src/bluetooth
parentbb4de7e992fc673884db553977b2756a165278b5 (diff)
Add support for BTLE write command (BlueZ/Linux)
So far, we only supported write requests which reply with write responses. Change-Id: Ibdad36dcf18dec23260f003911b9361cc4ab1e3d Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/bluetooth')
-rw-r--r--src/bluetooth/qlowenergycharacteristic.cpp11
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp25
-rw-r--r--src/bluetooth/qlowenergycontroller_p.cpp6
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h2
-rw-r--r--src/bluetooth/qlowenergydescriptor.cpp2
-rw-r--r--src/bluetooth/qlowenergyservice.cpp71
-rw-r--r--src/bluetooth/qlowenergyservice.h9
7 files changed, 100 insertions, 26 deletions
diff --git a/src/bluetooth/qlowenergycharacteristic.cpp b/src/bluetooth/qlowenergycharacteristic.cpp
index 69f68a59..8b7297d0 100644
--- a/src/bluetooth/qlowenergycharacteristic.cpp
+++ b/src/bluetooth/qlowenergycharacteristic.cpp
@@ -182,10 +182,19 @@ QLowEnergyCharacteristic::PropertyTypes QLowEnergyCharacteristic::properties() c
}
/*!
- Returns the value of the characteristic.
+ Returns the cached value of the characteristic.
If the characteristic's \l properties() permit writing of new values,
the value can be updated using \l QLowEnergyService::writeCharacteristic().
+
+ The cache is updated during the associated service's
+ \l {QLowEnergyService::discoverDetails()} {detail discovery}, a successful
+ \l {QLowEnergyService::writeCharacteristic()}{write operation} or when an update
+ notification is received.
+
+ The returned \l QByteArray is empty if the characteristic does not have the
+ \l {QLowEnergyCharacteristic::Read}{read permission}. However, a non-readable
+ characteristic may obtain a non-empty value via a related notification or write operation.
*/
QByteArray QLowEnergyCharacteristic::value() const
{
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index 2540791f..97eb429b 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -64,11 +64,12 @@
#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
+#define ATT_OP_WRITE_REQUEST 0x12 //write characteristic with response
#define ATT_OP_WRITE_RESPONSE 0x13
#define ATT_OP_HANDLE_VAL_NOTIFICATION 0x1b //informs about value change
#define ATT_OP_HANDLE_VAL_INDICATION 0x1d //informs about value change -> requires reply
#define ATT_OP_HANDLE_VAL_CONFIRMATION 0x1e //answer for ATT_OP_HANDLE_VAL_INDICATION
+#define ATT_OP_WRITE_COMMAND 0x52 //write characteristic without response
//GATT command sizes in bytes
#define FIND_INFO_REQUEST_SIZE 5
@@ -76,7 +77,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 WRITE_REQUEST_SIZE 3 // same size for WRITE_COMMAND
#define MTU_EXCHANGE_SIZE 3
// GATT error codes
@@ -1122,7 +1123,8 @@ void QLowEnergyControllerPrivate::discoverNextDescriptor(
void QLowEnergyControllerPrivate::writeCharacteristic(
const QSharedPointer<QLowEnergyServicePrivate> service,
const QLowEnergyHandle charHandle,
- const QByteArray &newValue)
+ const QByteArray &newValue,
+ bool writeWithResponse)
{
Q_ASSERT(!service.isNull());
@@ -1134,16 +1136,27 @@ void QLowEnergyControllerPrivate::writeCharacteristic(
const int size = 1 + 2 + newValue.size();
quint8 packet[WRITE_REQUEST_SIZE];
- packet[0] = ATT_OP_WRITE_REQUEST;
- bt_put_unaligned(htobs(valueHandle), (quint16 *) &packet[1]);
+ if (writeWithResponse)
+ packet[0] = ATT_OP_WRITE_REQUEST;
+ else
+ packet[0] = ATT_OP_WRITE_COMMAND;
+ bt_put_unaligned(htobs(valueHandle), (quint16 *) &packet[1]);
QByteArray data(size, Qt::Uninitialized);
memcpy(data.data(), packet, WRITE_REQUEST_SIZE);
memcpy(&(data.data()[WRITE_REQUEST_SIZE]), newValue.constData(), newValue.size());
qCDebug(QT_BT_BLUEZ) << "Writing characteristic" << hex << charHandle
- << "(size:" << size << ")";
+ << "(size:" << size << "response:" << writeWithResponse << ")";
+
+ // Advantage of write without response is the quick turnaround.
+ // It can be send at any time and does not produce responses.
+ // Therefore we will not put them into the openRequest queue at all.
+ if (!writeWithResponse) {
+ sendCommand(data);
+ return;
+ }
Request request;
request.payload = data;
diff --git a/src/bluetooth/qlowenergycontroller_p.cpp b/src/bluetooth/qlowenergycontroller_p.cpp
index 0135df1c..7de0c604 100644
--- a/src/bluetooth/qlowenergycontroller_p.cpp
+++ b/src/bluetooth/qlowenergycontroller_p.cpp
@@ -66,10 +66,10 @@ void QLowEnergyControllerPrivate::discoverServiceDetails(const QBluetoothUuid &/
}
-void QLowEnergyControllerPrivate::writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
+void QLowEnergyControllerPrivate::writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
const QLowEnergyHandle /*charHandle*/,
- const QByteArray &/*newValue*/)
+ const QByteArray &/*newValue*/,
+ bool /*writeWithResponse*/)
{
}
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h
index 150c1690..d9f75625 100644
--- a/src/bluetooth/qlowenergycontroller_p.h
+++ b/src/bluetooth/qlowenergycontroller_p.h
@@ -89,7 +89,7 @@ public:
// write data
void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
const QLowEnergyHandle charHandle,
- const QByteArray &newValue);
+ const QByteArray &newValue, bool writeWithResponse = true);
void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
const QLowEnergyHandle charHandle,
const QLowEnergyHandle descriptorHandle,
diff --git a/src/bluetooth/qlowenergydescriptor.cpp b/src/bluetooth/qlowenergydescriptor.cpp
index c7ee87ad..976ee73f 100644
--- a/src/bluetooth/qlowenergydescriptor.cpp
+++ b/src/bluetooth/qlowenergydescriptor.cpp
@@ -229,7 +229,7 @@ QLowEnergyHandle QLowEnergyDescriptor::handle() const
}
/*!
- Returns the value of the descriptor.
+ Returns the cached value of the descriptor.
A descriptor value may be updated using
\l QLowEnergyService::writeDescriptor().
diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp
index a55ed6e9..d60b4e81 100644
--- a/src/bluetooth/qlowenergyservice.cpp
+++ b/src/bluetooth/qlowenergyservice.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Javier S. Pedro <maemo@javispedro.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -166,6 +167,32 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QLowEnergyService::WriteMode
+
+ This enum describes the mode to be used when writing a characteristic value.
+ The characteristic advertises its supported write modes via its
+ \l {QLowEnergyCharacteristic::properties()}{properties}.
+
+ \value WriteWithResponse If a characteristic is written using this mode, the peripheral
+ shall send a write confirmation. If the operation is
+ successful, the confirmation is emitted via the
+ \l characteristicChanged() signal. Otherwise the
+ \l CharacteristicWriteError is emitted.
+ A characteristic must have set the
+ \l QLowEnergyCharacteristic::Write property to support this
+ write mode.
+
+ \value WriteWithoutResponse If a characteristic is written using this mode, the remote peripheral
+ shall not send a write confirmation. The operation's success
+ cannot be determined and the payload must not be longer than 20 bytes.
+ A characteristic must have set the
+ \l QLowEnergyCharacteristic::WriteNoResponse property to support this
+ write mode. Its adavantage is a quicker
+ write operation as it may happen in between other
+ device interactions.
+ */
+
+/*!
\fn void QLowEnergyService::stateChanged(QLowEnergyService::ServiceState newState)
This signal is emitted when the service's state changes. The \a newState can also be
@@ -189,6 +216,10 @@ QT_BEGIN_NAMESPACE
by calling \l writeCharacteristic() or otherwise triggering a change
notification on the peripheral device.
+ \note Change notifications must first be activated via the characteristic's
+ \l {QBluetoothUuid::ClientCharacteristicConfiguration}{ClientCharacteristicConfiguration}
+ descriptor.
+
\sa writeCharacteristic()
*/
@@ -419,13 +450,21 @@ bool QLowEnergyService::contains(const QLowEnergyCharacteristic &characteristic)
Writes \a newValue as value for the \a characteristic. If the operation is successful,
the \l characteristicChanged() signal is emitted.
+ The \a mode parameter determines whether the remote device should send a write
+ confirmation. The to-be-written \a characteristic must support the relevant
+ write mode. The characteristic's supported write modes are indicated by its
+ \l QLowEnergyCharacteristic::Write and \l QLowEnergyCharacteristic::WriteNoResponse
+ properties.
+
A characteristic can only be written if this service is in the \l ServiceDiscovered state,
belongs to the service and is writable.
+
+ \sa QLowEnergyCharacteristic::properties()
*/
void QLowEnergyService::writeCharacteristic(
- const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
+ const QLowEnergyCharacteristic &characteristic,
+ const QByteArray &newValue, QLowEnergyService::WriteMode mode)
{
- //TODO check behavior when writing to WriteNoResponse characteristic
//TODO check behavior when writing to WriteSigned characteristic
//TODO add support for write long characteristic value (newValue.size() > MTU - 3)
Q_D(QLowEnergyService);
@@ -434,23 +473,29 @@ void QLowEnergyService::writeCharacteristic(
if (!contains(characteristic))
return;
- // don't write if we don't have to
- if (characteristic.value() == newValue)
- return;
-
- // don't write write-protected or undiscovered characteristic
- if (!(characteristic.properties() & QLowEnergyCharacteristic::Write)
- || state() != ServiceDiscovered) {
+ if (state() != ServiceDiscovered)
d->setError(QLowEnergyService::OperationError);
- return;
- }
if (!d->controller)
return;
- d->controller->writeCharacteristic(characteristic.d_ptr,
+ // don't write if properties don't permit it
+ if (mode == WriteWithResponse
+ && (characteristic.properties() & QLowEnergyCharacteristic::Write))
+ {
+ d->controller->writeCharacteristic(characteristic.d_ptr,
characteristic.attributeHandle(),
- newValue);
+ newValue,
+ true);
+ } else if (mode == WriteWithoutResponse
+ && (characteristic.properties() & QLowEnergyCharacteristic::WriteNoResponse)) {
+ d->controller->writeCharacteristic(characteristic.d_ptr,
+ characteristic.attributeHandle(),
+ newValue,
+ false);
+ } else {
+ d->setError(QLowEnergyService::OperationError);
+ }
}
/*!
diff --git a/src/bluetooth/qlowenergyservice.h b/src/bluetooth/qlowenergyservice.h
index 37fa82d7..7bb2c0d3 100644
--- a/src/bluetooth/qlowenergyservice.h
+++ b/src/bluetooth/qlowenergyservice.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Javier S. Pedro <maemo@javispedro.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
@@ -66,6 +67,11 @@ public:
ServiceDiscovered, // all details have been synchronized
};
+ enum WriteMode {
+ WriteWithResponse = 0,
+ WriteWithoutResponse
+ };
+
~QLowEnergyService();
QList<QBluetoothUuid> includedServices() const;
@@ -84,7 +90,8 @@ public:
bool contains(const QLowEnergyCharacteristic &characteristic) const;
void writeCharacteristic(const QLowEnergyCharacteristic &characteristic,
- const QByteArray &newValue);
+ const QByteArray &newValue,
+ WriteMode mode = WriteWithResponse);
bool contains(const QLowEnergyDescriptor &descriptor) const;
void writeDescriptor(const QLowEnergyDescriptor &descriptor,