diff options
author | Alex Blasche <alexander.blasche@digia.com> | 2014-08-27 10:57:08 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@digia.com> | 2014-09-02 20:18:21 +0200 |
commit | 4ab9c732a466dc793e5ec162a928d4350a29281c (patch) | |
tree | b5fb9c1e074fb8228936d34894ab61dd452e003f /src/bluetooth | |
parent | bb4de7e992fc673884db553977b2756a165278b5 (diff) | |
download | qtconnectivity-4ab9c732a466dc793e5ec162a928d4350a29281c.tar.gz |
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.cpp | 11 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 25 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.cpp | 6 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.h | 2 | ||||
-rw-r--r-- | src/bluetooth/qlowenergydescriptor.cpp | 2 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyservice.cpp | 71 | ||||
-rw-r--r-- | src/bluetooth/qlowenergyservice.h | 9 |
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, |