diff options
Diffstat (limited to 'src/bluetooth/qlowenergycontroller_p.h')
-rw-r--r-- | src/bluetooth/qlowenergycontroller_p.h | 213 |
1 files changed, 197 insertions, 16 deletions
diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index fae26149..2256025c 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtBluetooth module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -65,7 +71,9 @@ QT_END_NAMESPACE #include <qglobal.h> #include <QtCore/QQueue> +#include <QtCore/QVector> #include <QtBluetooth/qbluetooth.h> +#include <QtBluetooth/qlowenergycharacteristic.h> #include "qlowenergycontroller.h" #include "qlowenergyserviceprivate_p.h" @@ -76,10 +84,16 @@ QT_END_NAMESPACE #include "android/lowenergynotificationhub_p.h" #endif +#include <functional> + QT_BEGIN_NAMESPACE +class QLowEnergyServiceData; + #if defined(QT_BLUEZ_BLUETOOTH) && !defined(QT_BLUEZ_NO_BTLE) class HciManager; +class LeCmacCalculator; +class QSocketNotifier; #elif defined(QT_ANDROID_BLUETOOTH) class LowEnergyNotificationHub; #endif @@ -87,6 +101,7 @@ class LowEnergyNotificationHub; extern void registerQLowEnergyControllerMetaType(); typedef QMap<QBluetoothUuid, QSharedPointer<QLowEnergyServicePrivate> > ServiceDataMap; +class QLeAdvertiser; class QLowEnergyControllerPrivate : public QObject { @@ -111,6 +126,13 @@ public: void discoverServiceDetails(const QBluetoothUuid &service); + void startAdvertising(const QLowEnergyAdvertisingParameters ¶ms, + const QLowEnergyAdvertisingData &advertisingData, + const QLowEnergyAdvertisingData &scanResponseData); + void stopAdvertising(); + + void requestConnectionUpdate(const QLowEnergyConnectionParameters ¶ms); + // misc helpers QSharedPointer<QLowEnergyServicePrivate> serviceForHandle( QLowEnergyHandle handle); @@ -137,15 +159,18 @@ public: // write data void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service, const QLowEnergyHandle charHandle, - const QByteArray &newValue, bool writeWithResponse = true); + const QByteArray &newValue, QLowEnergyService::WriteMode mode); void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service, const QLowEnergyHandle charHandle, const QLowEnergyHandle descriptorHandle, const QByteArray &newValue); + void addToGenericAttributeList(const QLowEnergyServiceData &service, + QLowEnergyHandle startHandle); QBluetoothAddress remoteDevice; QBluetoothAddress localAdapter; + QLowEnergyController::Role role; QString remoteName; @@ -156,10 +181,29 @@ public: // list of all found service uuids ServiceDataMap serviceList; + QLowEnergyHandle lastLocalHandle; + ServiceDataMap localServices; + + struct Attribute { + Attribute() : handle(0) {} + + QLowEnergyHandle handle; + QLowEnergyHandle groupEndHandle; + QLowEnergyCharacteristic::PropertyTypes properties; + QBluetooth::AttAccessConstraints readConstraints; + QBluetooth::AttAccessConstraints writeConstraints; + QBluetoothUuid type; + QByteArray value; + int minLength; + int maxLength; + }; + QVector<Attribute> localAttributes; + QLowEnergyController::RemoteAddressType addressType; private: #if defined(QT_BLUEZ_BLUETOOTH) && !defined(QT_BLUEZ_NO_BTLE) + quint16 connectionHandle = 0; QBluetoothSocket *l2cpSocket; struct Request { quint8 command; @@ -170,14 +214,79 @@ private: QVariant reference2; }; QQueue<Request> openRequests; + + struct WriteRequest { + WriteRequest() {} + WriteRequest(quint16 h, quint16 o, const QByteArray &v) + : handle(h), valueOffset(o), value(v) {} + quint16 handle; + quint16 valueOffset; + QByteArray value; + }; + QVector<WriteRequest> openPrepareWriteRequests; + + // Invariant: !scheduledIndications.isEmpty => indicationInFlight == true + QVector<QLowEnergyHandle> scheduledIndications; + bool indicationInFlight = false; + + struct TempClientConfigurationData { + TempClientConfigurationData(QLowEnergyServicePrivate::DescData *dd = nullptr, + QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0) + : descData(dd), charValueHandle(chHndl), configHandle(coHndl) {} + + QLowEnergyServicePrivate::DescData *descData; + QLowEnergyHandle charValueHandle; + QLowEnergyHandle configHandle; + }; + + struct ClientConfigurationData { + ClientConfigurationData(QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0, + quint16 val = 0) + : charValueHandle(chHndl), configHandle(coHndl), configValue(val) {} + + QLowEnergyHandle charValueHandle; + QLowEnergyHandle configHandle; + quint16 configValue; + bool charValueWasUpdated = false; + }; + QHash<quint64, QVector<ClientConfigurationData>> clientConfigData; + + struct SigningData { + SigningData() = default; + SigningData(const quint128 &csrk, quint32 signCounter = quint32(-1)) + : key(csrk), counter(signCounter) {} + + quint128 key; + quint32 counter = quint32(-1); + }; + QHash<quint64, SigningData> signingData; + LeCmacCalculator *cmacCalculator = nullptr; + bool requestPending; quint16 mtuSize; int securityLevelValue; bool encryptionChangePending; + bool receivedMtuExchangeRequest = false; HciManager *hciManager; + QLeAdvertiser *advertiser; + QSocketNotifier *serverSocketNotifier; + + void handleConnectionRequest(); + void closeServerSocket(); + + bool isBonded() const; + QVector<TempClientConfigurationData> gatherClientConfigData(); + void storeClientConfigurations(); + void restoreClientConfigurations(); - void sendCommand(const QByteArray &packet); + enum SigningKeyType { LocalSigningKey, RemoteSigningKey }; + void loadSigningDataIfNecessary(SigningKeyType keyType); + void storeSignCounter(SigningKeyType keyType) const; + QString signingKeySettingsGroup(SigningKeyType keyType) const; + QString keySettingsFilePath() const; + + void sendPacket(const QByteArray &packet); void sendNextPendingRequest(); void processReply(const Request &request, const QByteArray &reply); @@ -208,6 +317,76 @@ private: void resetController(); + void handleAdvertisingError(); + + bool checkPacketSize(const QByteArray &packet, int minSize, int maxSize = -1); + bool checkHandle(const QByteArray &packet, QLowEnergyHandle handle); + bool checkHandlePair(quint8 request, QLowEnergyHandle startingHandle, + QLowEnergyHandle endingHandle); + + void handleExchangeMtuRequest(const QByteArray &packet); + void handleFindInformationRequest(const QByteArray &packet); + void handleFindByTypeValueRequest(const QByteArray &packet); + void handleReadByTypeRequest(const QByteArray &packet); + void handleReadRequest(const QByteArray &packet); + void handleReadBlobRequest(const QByteArray &packet); + void handleReadMultipleRequest(const QByteArray &packet); + void handleReadByGroupTypeRequest(const QByteArray &packet); + void handleWriteRequestOrCommand(const QByteArray &packet); + void handlePrepareWriteRequest(const QByteArray &packet); + void handleExecuteWriteRequest(const QByteArray &packet); + + void sendErrorResponse(quint8 request, quint16 handle, quint8 code); + + using ElemWriter = std::function<void(const Attribute &, char *&)>; + void sendListResponse(const QByteArray &packetStart, int elemSize, + const QVector<Attribute> &attributes, const ElemWriter &elemWriter); + + void sendNotification(QLowEnergyHandle handle); + void sendIndication(QLowEnergyHandle handle); + void sendNotificationOrIndication(quint8 opCode, QLowEnergyHandle handle); + void sendNextIndication(); + + void ensureUniformAttributes(QVector<Attribute> &attributes, const std::function<int(const Attribute &)> &getSize); + void ensureUniformUuidSizes(QVector<Attribute> &attributes); + void ensureUniformValueSizes(QVector<Attribute> &attributes); + + using AttributePredicate = std::function<bool(const Attribute &)>; + QVector<Attribute> getAttributes(QLowEnergyHandle startHandle, QLowEnergyHandle endHandle, + const AttributePredicate &attributePredicate = [](const Attribute &) { return true; }); + + int checkPermissions(const Attribute &attr, QLowEnergyCharacteristic::PropertyType type); + int checkReadPermissions(const Attribute &attr); + int checkReadPermissions(QVector<Attribute> &attributes); + + bool verifyMac(const QByteArray &message, const quint128 &csrk, quint32 signCounter, + quint64 expectedMac); + + void updateLocalAttributeValue( + QLowEnergyHandle handle, + const QByteArray &value, + QLowEnergyCharacteristic &characteristic, + QLowEnergyDescriptor &descriptor); + + void writeCharacteristicForPeripheral( + QLowEnergyServicePrivate::CharData &charData, + const QByteArray &newValue); + void writeCharacteristicForCentral(const QSharedPointer<QLowEnergyServicePrivate> &service, + QLowEnergyHandle charHandle, + QLowEnergyHandle valueHandle, + const QByteArray &newValue, + QLowEnergyService::WriteMode mode); + + void writeDescriptorForPeripheral( + const QSharedPointer<QLowEnergyServicePrivate> &service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle, + const QByteArray &newValue); + void writeDescriptorForCentral( + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle, + const QByteArray &newValue); + private slots: void l2cpConnected(); void l2cpDisconnected(); @@ -241,6 +420,8 @@ private: }; +Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivate::Attribute, Q_MOVABLE_TYPE); + QT_END_NAMESPACE #endif // QT_OSX_BLUETOOTH || QT_IOS_BLUETOOTH |