diff options
-rw-r--r-- | src/bluetooth/gatoattclient.cpp | 609 | ||||
-rw-r--r-- | src/bluetooth/gatoattclient.h | 135 | ||||
-rw-r--r-- | src/bluetooth/gatoperipheral.cpp | 866 | ||||
-rw-r--r-- | src/bluetooth/gatoperipheral.h | 111 | ||||
-rw-r--r-- | src/bluetooth/gatoperipheral_p.h | 108 | ||||
-rw-r--r-- | sync.profile | 3 |
6 files changed, 0 insertions, 1832 deletions
diff --git a/src/bluetooth/gatoattclient.cpp b/src/bluetooth/gatoattclient.cpp deleted file mode 100644 index d15e9d05..00000000 --- a/src/bluetooth/gatoattclient.cpp +++ /dev/null @@ -1,609 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Javier de San Pedro <dev.git@javispedro.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/QDataStream> -#include <QtCore/QDebug> - -#include "gatoattclient.h" -#include "helpers.h" - -#define PROTOCOL_DEBUG 0 - -#define ATT_CID 4 -#define ATT_PSM 31 - -#define ATT_DEFAULT_LE_MTU 23 -#define ATT_MAX_LE_MTU 0x200 - -QT_BEGIN_NAMESPACE - -enum AttOpcode { - AttOpNone = 0, - AttOpErrorResponse = 0x1, - AttOpExchangeMTURequest = 0x2, - AttOpExchangeMTUResponse = 0x3, - AttOpFindInformationRequest = 0x4, - AttOpFindInformationResponse = 0x5, - AttOpFindByTypeValueRequest = 0x6, - AttOpFindByTypeValueResponse = 0x7, - AttOpReadByTypeRequest = 0x8, - AttOpReadByTypeResponse = 0x9, - AttOpReadRequest = 0xA, - AttOpReadResponse = 0xB, - AttOpReadBlobRequest = 0xC, - AttOpReadBlobResponse = 0xD, - AttOpReadMultipleRequest = 0xE, - AttOpReadMultipleResponse = 0xF, - AttOpReadByGroupTypeRequest = 0x10, - AttOpReadByGroupTypeResponse = 0x11, - AttOpWriteRequest = 0x12, - AttOpWriteResponse = 0x13, - AttOpWriteCommand = 0x52, - AttOpPrepareWriteRequest = 0x16, - AttOpPrepareWriteResponse = 0x17, - AttOpExecuteWriteRequest = 0x18, - AttOpExecuteWriteResponse = 0x19, - AttOpHandleValueNotification = 0x1B, - AttOpHandleValueIndication = 0x1D, - AttOpHandleValueConfirmation = 0x1E, - AttOpSignedWriteCommand = 0xD2 -}; - -static QByteArray remove_method_signature(const char *sig) -{ - const char* bracketPosition = strchr(sig, '('); - if (!bracketPosition || !(sig[0] >= '0' && sig[0] <= '3')) { - qWarning("Invalid slot specification"); - return QByteArray(); - } - return QByteArray(sig + 1, bracketPosition - 1 - sig); -} - -GatoAttClient::GatoAttClient(QObject *parent) : - QObject(parent), socket(new GatoSocket(this)), cur_mtu(ATT_DEFAULT_LE_MTU), next_id(1) -{ - connect(socket, SIGNAL(connected()), SLOT(handleSocketConnected())); - connect(socket, SIGNAL(disconnected()), SLOT(handleSocketDisconnected())); - connect(socket, SIGNAL(readyRead()), SLOT(handleSocketReadyRead())); -} - -GatoAttClient::~GatoAttClient() -{ -} - -GatoSocket::State GatoAttClient::state() const -{ - return socket->state(); -} - -bool GatoAttClient::connectTo(const GatoAddress &addr) -{ - return socket->connectTo(addr, ATT_CID); -} - -void GatoAttClient::close() -{ - socket->close(); -} - -int GatoAttClient::mtu() const -{ - return cur_mtu; -} - -uint GatoAttClient::request(int opcode, const QByteArray &data, QObject *receiver, const char *member) -{ - Request req; - req.id = next_id++; - req.opcode = opcode; - req.pkt = data; - req.pkt.prepend(static_cast<char>(opcode)); - req.receiver = receiver; - req.member = remove_method_signature(member); - - pending_requests.enqueue(req); - - if (pending_requests.size() == 1) { - // So we can just send this request instead of waiting for others to complete - sendARequest(); - } - - return req.id; -} - -void GatoAttClient::cancelRequest(uint id) -{ - QQueue<Request>::iterator it = pending_requests.begin(); - while (it != pending_requests.end()) { - if (it->id == id) { - it = pending_requests.erase(it); - } else { - ++it; - } - } -} - -uint GatoAttClient::requestExchangeMTU(quint16 client_mtu, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << client_mtu; - - return request(AttOpExchangeMTURequest, data, receiver, member); -} - -uint GatoAttClient::requestFindInformation(GatoHandle start, GatoHandle end, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << start << end; - - return request(AttOpFindInformationRequest, data, receiver, member); -} - -uint GatoAttClient::requestFindByTypeValue(GatoHandle start, GatoHandle end, const GatoUUID &uuid, const QByteArray &value, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << start << end; - - bool uuid16_ok; - quint16 uuid16 = uuid.toUInt16(&uuid16_ok); - if (uuid16_ok) { - s << uuid16; - } else { - qWarning() << "FindByTypeValue does not support UUIDs other than UUID16"; - return -1; - } - - s << value; - - return request(AttOpFindByTypeValueRequest, data, receiver, member); -} - -uint GatoAttClient::requestReadByType(GatoHandle start, GatoHandle end, const GatoUUID &uuid, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << start << end; - write_gatouuid(s, uuid, true, false); - - return request(AttOpReadByTypeRequest, data, receiver, member); -} - -uint GatoAttClient::requestRead(GatoHandle handle, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << handle; - - return request(AttOpReadRequest, data, receiver, member); -} - -uint GatoAttClient::requestReadByGroupType(GatoHandle start, GatoHandle end, const GatoUUID &uuid, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << start << end; - write_gatouuid(s, uuid, true, false); - - return request(AttOpReadByGroupTypeRequest, data, receiver, member); -} - -uint GatoAttClient::requestWrite(GatoHandle handle, const QByteArray &value, QObject *receiver, const char *member) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << handle; - s.writeRawData(value.constData(), value.length()); - - return request(AttOpWriteRequest, data, receiver, member); -} - -void GatoAttClient::command(int opcode, const QByteArray &data) -{ - QByteArray packet = data; - packet.prepend(static_cast<char>(opcode)); - - socket->send(packet); - -#if PROTOCOL_DEBUG - qDebug() << "Wrote" << packet.size() << "bytes (command)" << packet.toHex(); -#endif -} - -void GatoAttClient::commandWrite(GatoHandle handle, const QByteArray &value) -{ - QByteArray data; - QDataStream s(&data, QIODevice::WriteOnly); - s.setByteOrder(QDataStream::LittleEndian); - s << handle; - s.writeRawData(value.constData(), value.length()); - - command(AttOpWriteCommand, data); -} - -void GatoAttClient::sendARequest() -{ - if (pending_requests.isEmpty()) { - return; - } - - Request &req = pending_requests.head(); - socket->send(req.pkt); - -#if PROTOCOL_DEBUG - qDebug() << "Wrote" << req.pkt.size() << "bytes (request)" << req.pkt.toHex(); -#endif -} - -bool GatoAttClient::handleEvent(const QByteArray &event) -{ - const char *data = event.constData(); - quint8 opcode = event[0]; - GatoHandle handle; - - switch (opcode) { - case AttOpHandleValueNotification: - handle = read_le<GatoHandle>(&data[1]); - emit attributeUpdated(handle, event.mid(3), false); - return true; - case AttOpHandleValueIndication: - handle = read_le<GatoHandle>(&data[1]); - - // Send the confirmation back - command(AttOpHandleValueConfirmation, QByteArray()); - - emit attributeUpdated(handle, event.mid(3), true); - return true; - default: - return false; - } -} - -bool GatoAttClient::handleResponse(const Request &req, const QByteArray &response) -{ - // If we know the request, we can provide a decoded answer - switch (req.opcode) { - case AttOpExchangeMTURequest: - if (response[0] == AttOpExchangeMTUResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(quint16, read_le<quint16>(response.constData() + 1))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpExchangeMTURequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(quint16, 0)); - } - return true; - } else { - return false; - } - break; - case AttOpFindInformationRequest: - if (response[0] == AttOpFindInformationResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::InformationData>, parseInformationData(response.mid(1)))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpFindInformationRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::InformationData>, QList<InformationData>())); - } - return true; - } else { - return false; - } - break; - case AttOpFindByTypeValueRequest: - if (response[0] == AttOpFindByTypeValueResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::HandleInformation>, parseHandleInformation(response.mid(1)))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpFindByTypeValueRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::HandleInformation>, QList<HandleInformation>())); - } - return true; - } else { - return false; - } - break; - case AttOpReadByTypeRequest: - if (response[0] == AttOpReadByTypeResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::AttributeData>, parseAttributeData(response.mid(1)))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpReadByTypeRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::AttributeData>, QList<AttributeData>())); - } - return true; - } else { - return false; - } - break; - case AttOpReadRequest: - if (response[0] == AttOpReadResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QByteArray, response.mid(1))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpReadRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QByteArray, QByteArray())); - } - return true; - } else { - return false; - } - break; - case AttOpReadByGroupTypeRequest: - if (response[0] == AttOpReadByGroupTypeResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::AttributeGroupData>, parseAttributeGroupData(response.mid(1)))); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpReadByGroupTypeRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(QList<GatoAttClient::AttributeGroupData>, QList<AttributeGroupData>())); - } - return true; - } else { - return false; - } - break; - case AttOpWriteRequest: - if (response[0] == AttOpWriteResponse) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(bool, true)); - } - return true; - } else if (response[0] == AttOpErrorResponse && response[1] == AttOpWriteRequest) { - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(uint, req.id), - Q_ARG(bool, false)); - } - return true; - } else { - return false; - } - break; - default: // Otherwise just send a QByteArray. - if (req.receiver) { - QMetaObject::invokeMethod(req.receiver, req.member.constData(), - Q_ARG(const QByteArray&, response)); - } - return true; - } -} - -QList<GatoAttClient::InformationData> GatoAttClient::parseInformationData(const QByteArray &data) -{ - const int format = data[0]; - QList<InformationData> list; - int item_len; - - switch (format) { - case 1: - item_len = 2 + 2; - break; - case 2: - item_len = 2 + 16; - break; - default: - qWarning() << "Unknown InformationData format!"; - return list; - } - - int items = (data.size() - 1) / item_len; - list.reserve(items); - - int pos = 1; - const char *s = data.constData(); - for (int i = 0; i < items; i++) { - InformationData d; - QByteArray uuid; - d.handle = read_le<GatoHandle>(&s[pos]); - switch (format) { - case 1: - uuid = data.mid(pos + 2, 2); - break; - case 2: - uuid = data.mid(pos + 2, 16); - break; - } - d.uuid = bytearray_to_gatouuid(uuid); - - list.append(d); - - pos += item_len; - } - - return list; -} - -QList<GatoAttClient::HandleInformation> GatoAttClient::parseHandleInformation(const QByteArray &data) -{ - const int item_len = 2; - const int items = data.size() / item_len; - QList<HandleInformation> list; - list.reserve(items); - - int pos = 0; - const char *s = data.constData(); - for (int i = 0; i < items; i++) { - HandleInformation d; - d.start = read_le<GatoHandle>(&s[pos]); - d.end = read_le<GatoHandle>(&s[pos + 2]); - list.append(d); - - pos += item_len; - } - - return list; -} - -QList<GatoAttClient::AttributeData> GatoAttClient::parseAttributeData(const QByteArray &data) -{ - const int item_len = data[0]; - const int items = (data.size() - 1) / item_len; - QList<AttributeData> list; - list.reserve(items); - - int pos = 1; - const char *s = data.constData(); - for (int i = 0; i < items; i++) { - AttributeData d; - d.handle = read_le<GatoHandle>(&s[pos]); - d.value = data.mid(pos + 2, item_len - 2); - list.append(d); - - pos += item_len; - } - - return list; -} - -QList<GatoAttClient::AttributeGroupData> GatoAttClient::parseAttributeGroupData(const QByteArray &data) -{ - const int item_len = data[0]; - const int items = (data.size() - 1) / item_len; - QList<AttributeGroupData> list; - list.reserve(items); - - int pos = 1; - const char *s = data.constData(); - for (int i = 0; i < items; i++) { - AttributeGroupData d; - d.start = read_le<GatoHandle>(&s[pos]); - d.end = read_le<GatoHandle>(&s[pos + 2]); - d.value = data.mid(pos + 4, item_len - 4); - list.append(d); - - pos += item_len; - } - - return list; -} - -void GatoAttClient::handleSocketConnected() -{ - requestExchangeMTU(ATT_MAX_LE_MTU, this, SLOT(handleServerMTU(quint16))); - emit connected(); -} - -void GatoAttClient::handleSocketDisconnected() -{ - emit disconnected(); -} - -void GatoAttClient::handleSocketReadyRead() -{ - QByteArray pkt = socket->receive(); - if (!pkt.isEmpty()) { -#if PROTOCOL_DEBUG - qDebug() << "Received" << pkt.size() << "bytes" << pkt.toHex(); -#endif - - // Check if it is an event - if (handleEvent(pkt)) { - return; - } - - // Otherwise, if we have a request waiting, check if this answers it - if (!pending_requests.isEmpty()) { - if (handleResponse(pending_requests.head(), pkt)) { - pending_requests.dequeue(); - // Proceed to next request - if (!pending_requests.isEmpty()) { - sendARequest(); - } - return; - } - } - - qDebug() << "No idea what this packet (" - << QString("0x%1").arg(uint(pkt.at(0)), 2, 16, QLatin1Char('0')) - << ") is"; - } -} - -void GatoAttClient::handleServerMTU(uint req, quint16 server_mtu) -{ - Q_UNUSED(req); - if (server_mtu) { - cur_mtu = server_mtu; - if (cur_mtu < ATT_DEFAULT_LE_MTU) { - cur_mtu = ATT_DEFAULT_LE_MTU; - } - } -} - -QT_END_NAMESPACE diff --git a/src/bluetooth/gatoattclient.h b/src/bluetooth/gatoattclient.h deleted file mode 100644 index 6a55b308..00000000 --- a/src/bluetooth/gatoattclient.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Javier de San Pedro <dev.git@javispedro.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GATOATTCLIENT_H -#define GATOATTCLIENT_H - -#include <QtCore/QObject> -#include <QtCore/QQueue> -#include "gatosocket.h" -#include "gatouuid.h" - -QT_BEGIN_NAMESPACE - -class GatoAttClient : public QObject -{ - Q_OBJECT - -public: - explicit GatoAttClient(QObject *parent = 0); - ~GatoAttClient(); - - GatoSocket::State state() const; - - bool connectTo(const GatoAddress& addr); - void close(); - - struct InformationData - { - GatoHandle handle; - GatoUUID uuid; - }; - struct HandleInformation - { - GatoHandle start; - GatoHandle end; - }; - struct AttributeData - { - GatoHandle handle; - QByteArray value; - }; - struct AttributeGroupData - { - GatoHandle start; - GatoHandle end; - QByteArray value; - }; - - int mtu() const; - - uint request(int opcode, const QByteArray &data, QObject *receiver, const char *member); - uint requestExchangeMTU(quint16 client_mtu, QObject *receiver, const char *member); - uint requestFindInformation(GatoHandle start, GatoHandle end, QObject *receiver, const char *member); - uint requestFindByTypeValue(GatoHandle start, GatoHandle end, const GatoUUID &uuid, const QByteArray& value, QObject *receiver, const char *member); - uint requestReadByType(GatoHandle start, GatoHandle end, const GatoUUID &uuid, QObject *receiver, const char *member); - uint requestRead(GatoHandle handle, QObject *receiver, const char *member); - uint requestReadByGroupType(GatoHandle start, GatoHandle end, const GatoUUID &uuid, QObject *receiver, const char *member); - uint requestWrite(GatoHandle handle, const QByteArray &value, QObject *receiver, const char *member); - void cancelRequest(uint id); - - void command(int opcode, const QByteArray &data); - void commandWrite(GatoHandle handle, const QByteArray &value); - -Q_SIGNALS: - void connected(); - void disconnected(); - - void attributeUpdated(GatoHandle handle, const QByteArray &value, bool confirmed); - -private: - struct Request - { - uint id; - quint8 opcode; - QByteArray pkt; - QObject *receiver; - QByteArray member; - }; - - void sendARequest(); - bool handleEvent(const QByteArray &event); - bool handleResponse(const Request& req, const QByteArray &response); - - QList<InformationData> parseInformationData(const QByteArray &data); - QList<HandleInformation> parseHandleInformation(const QByteArray &data); - QList<AttributeData> parseAttributeData(const QByteArray &data); - QList<AttributeGroupData> parseAttributeGroupData(const QByteArray &data); - -private Q_SLOTS: - void handleSocketConnected(); - void handleSocketDisconnected(); - void handleSocketReadyRead(); - - void handleServerMTU(uint req, quint16 server_mtu); - -private: - GatoSocket *socket; - quint16 cur_mtu; - uint next_id; - QQueue<Request> pending_requests; -}; - -QT_END_NAMESPACE - -#endif // GATOATTCLIENT_H diff --git a/src/bluetooth/gatoperipheral.cpp b/src/bluetooth/gatoperipheral.cpp deleted file mode 100644 index b20efbe6..00000000 --- a/src/bluetooth/gatoperipheral.cpp +++ /dev/null @@ -1,866 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Javier de San Pedro <dev.git@javispedro.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/QDebug> - -#include <assert.h> -#include <bluetooth/bluetooth.h> - -#include "gatoperipheral_p.h" -#include "gatoaddress.h" -#include "gatouuid.h" -#include "helpers.h" - -QT_BEGIN_NAMESPACE - -enum EIRDataFields { - EIRFlags = 0x01, - EIRIncompleteUUID16List = 0x02, - EIRCompleteUUID16List = 0x03, - EIRIncompleteUUID32List = 0x04, - EIRCompleteUUID32List = 0x05, - EIRIncompleteUUID128List = 0x06, - EIRCompleteUUID128List = 0x07, - EIRIncompleteLocalName = 0x08, - EIRCompleteLocalName = 0x09, - EIRTxPowerLevel = 0x0A, - EIRDeviceClass = 0x0D, - EIRSecurityManagerTKValue = 0x10, - EIRSecurityManagerOutOfBandFlags = 0x11, - EIRSolicitedUUID128List = 0x15 -}; - -GatoPeripheral::GatoPeripheral(const GatoAddress &addr, QObject *parent) : - QObject(parent), d_ptr(new GatoPeripheralPrivate(this)) -{ - Q_D(GatoPeripheral); - d->addr = addr; - d->att = new GatoAttClient(this); - - connect(d->att, SIGNAL(connected()), d, SLOT(handleAttConnected())); - connect(d->att, SIGNAL(disconnected()), d, SLOT(handleAttDisconnected())); - connect(d->att, SIGNAL(attributeUpdated(GatoHandle,QByteArray,bool)), d, SLOT(handleAttAttributeUpdated(GatoHandle,QByteArray,bool))); -} - -GatoPeripheral::~GatoPeripheral() -{ - if (state() != StateDisconnected) { - disconnect(); - } - delete d_ptr; -} - -GatoPeripheral::State GatoPeripheral::state() const -{ - Q_D(const GatoPeripheral); - return static_cast<State>(d->att->state()); -} - -GatoAddress GatoPeripheral::address() const -{ - Q_D(const GatoPeripheral); - return d->addr; -} - -QString GatoPeripheral::name() const -{ - Q_D(const GatoPeripheral); - return d->name; -} - -QList<GatoService> GatoPeripheral::services() const -{ - Q_D(const GatoPeripheral); - return d->services.values(); -} - -void GatoPeripheral::parseEIR(quint8 data[], int len) -{ - Q_D(GatoPeripheral); - - int pos = 0; - while (pos < len) { - int item_len = data[pos]; - pos++; - if (item_len == 0) break; - int type = data[pos]; - assert(pos + item_len <= len); - switch (type) { - case EIRFlags: - d->parseEIRFlags(&data[pos + 1], item_len - 1); - break; - case EIRIncompleteUUID16List: - d->parseEIRUUIDs(16/8, false, &data[pos + 1], item_len - 1); - break; - case EIRCompleteUUID16List: - d->parseEIRUUIDs(16/8, true, &data[pos + 1], item_len - 1); - break; - case EIRIncompleteUUID32List: - d->parseEIRUUIDs(32/8, false, &data[pos + 1], item_len - 1); - break; - case EIRCompleteUUID32List: - d->parseEIRUUIDs(32/8, true, &data[pos + 1], item_len - 1); - break; - case EIRIncompleteUUID128List: - d->parseEIRUUIDs(128/8, false, &data[pos + 1], item_len - 1); - break; - case EIRCompleteUUID128List: - d->parseEIRUUIDs(128/8, true, &data[pos + 1], item_len - 1); - break; - case EIRIncompleteLocalName: - d->parseName(false, &data[pos + 1], item_len - 1); - break; - case EIRCompleteLocalName: - d->parseName(true, &data[pos + 1], item_len - 1); - break; - case EIRTxPowerLevel: - case EIRSolicitedUUID128List: - qDebug() << "Unhandled EIR data type" << type; - break; - default: - qWarning() << "Unknown EIR data type" << type; - break; - } - - pos += item_len; - } - - assert(pos == len); -} - -bool GatoPeripheral::advertisesService(const GatoUUID &uuid) const -{ - Q_D(const GatoPeripheral); - return d->service_uuids.contains(uuid); -} - -void GatoPeripheral::connectPeripheral() -{ - Q_D(GatoPeripheral); - if (d->att->state() != GatoSocket::StateDisconnected) { - qDebug() << "Already connecting"; - return; - } - - d->att->connectTo(d->addr); -} - -void GatoPeripheral::disconnectPeripheral() -{ - Q_D(GatoPeripheral); - - d->att->close(); -} - -void GatoPeripheral::discoverServices() -{ - Q_D(GatoPeripheral); - if (!d->complete_services && state() == StateConnected) { - d->clearServices(); - d->att->requestReadByGroupType(0x0001, 0xFFFF, GatoUUID::GattPrimaryService, - d, SLOT(handlePrimary(QList<GatoAttClient::AttributeGroupData>))); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::discoverServices(const QList<GatoUUID> &serviceUUIDs) -{ - Q_D(GatoPeripheral); - if (serviceUUIDs.isEmpty()) return; - if (state() == StateConnected) { - foreach (const GatoUUID& uuid, serviceUUIDs) { - QByteArray value = gatouuid_to_bytearray(uuid, true, false); - uint req = d->att->requestFindByTypeValue(0x0001, 0xFFFF, GatoUUID::GattPrimaryService, value, - d, SLOT(handlePrimaryForService(uint,QList<GatoAttClient::HandleInformation>))); - d->pending_primary_reqs.insert(req, uuid); - } - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::discoverCharacteristics(const GatoService &service) -{ - Q_D(GatoPeripheral); - - if (!d->services.contains(service.startHandle())) { - qWarning() << "Unknown service for this peripheral"; - return; - } - - GatoService &our_service = d->services[service.startHandle()]; - - if (our_service.startHandle() != service.startHandle() || - our_service.endHandle() != service.endHandle() || - our_service.uuid() != service.uuid()) { - qWarning() << "Unknown service for this peripheral"; - return; - } - - if (state() == StateConnected) { - GatoHandle start = our_service.startHandle(); - GatoHandle end = our_service.endHandle(); - - d->clearServiceCharacteristics(&our_service); - - uint req = d->att->requestReadByType(start, end, GatoUUID::GattCharacteristic, - d, SLOT(handleCharacteristic(QList<GatoAttClient::AttributeData>))); - d->pending_characteristic_reqs.insert(req, start); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::discoverCharacteristics(const GatoService &service, const QList<GatoUUID> &characteristicUUIDs) -{ - // TODO There seems to be no way to ask for the peripheral to filter by uuid - Q_UNUSED(characteristicUUIDs); - discoverCharacteristics(service); -} - -void GatoPeripheral::discoverDescriptors(const GatoCharacteristic &characteristic) -{ - Q_D(GatoPeripheral); - - GatoHandle char_handle = characteristic.startHandle(); - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - - if (!service_handle) { - qWarning() << "Unknown characteristic for this peripheral"; - return; - } - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - GatoCharacteristic our_char = our_service.getCharacteristic(char_handle); - Q_ASSERT(our_char.startHandle() == char_handle); - - if (state() == StateConnected) { - d->clearCharacteristicDescriptors(&our_char); - our_service.addCharacteristic(our_char); // Update service with empty descriptors list - uint req = d->att->requestFindInformation(our_char.startHandle() + 1, our_char.endHandle(), - d, SLOT(handleDescriptors(uint,QList<GatoAttClient::InformationData>))); - d->pending_descriptor_reqs.insert(req, char_handle); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::readValue(const GatoCharacteristic &characteristic) -{ - Q_D(GatoPeripheral); - - GatoHandle char_handle = characteristic.startHandle(); - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - - if (!service_handle) { - qWarning() << "Unknown characteristic for this peripheral"; - return; - } - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - - if (state() == StateConnected) { - uint req = d->att->requestRead(characteristic.valueHandle(), - d, SLOT(handleCharacteristicRead(uint,QByteArray))); - d->pending_characteristic_read_reqs.insert(req, char_handle); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::readValue(const GatoDescriptor &descriptor) -{ - Q_D(GatoPeripheral); - - GatoHandle desc_handle = descriptor.handle(); - GatoHandle char_handle = d->descriptor_to_characteristic.value(desc_handle); - - if (!char_handle) { - qWarning() << "Unknown descriptor for this peripheral"; - return; - } - - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - Q_ASSERT(service_handle); - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - - if (state() == StateConnected) { - uint req = d->att->requestRead(descriptor.handle(), - d, SLOT(handleDescriptorRead(uint,QByteArray))); - d->pending_descriptor_read_reqs.insert(req, char_handle); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::writeValue(const GatoCharacteristic &characteristic, const QByteArray &data, WriteType type) -{ - Q_D(GatoPeripheral); - - GatoHandle char_handle = characteristic.startHandle(); - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - - if (!service_handle) { - qWarning() << "Unknown characteristic for this peripheral"; - return; - } - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - - if (state() == StateConnected) { - switch (type) { - case WriteWithResponse: - d->att->requestWrite(characteristic.valueHandle(), data, - d, SLOT(handleCharacteristicWrite(uint,bool))); - break; - case WriteWithoutResponse: - d->att->commandWrite(characteristic.valueHandle(), data); - break; - } - - - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::writeValue(const GatoDescriptor &descriptor, const QByteArray &data) -{ - Q_D(GatoPeripheral); - - GatoHandle desc_handle = descriptor.handle(); - GatoHandle char_handle = d->descriptor_to_characteristic.value(desc_handle); - - if (!char_handle) { - qWarning() << "Unknown descriptor for this peripheral"; - return; - } - - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - Q_ASSERT(service_handle); - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - - if (state() == StateConnected) { - d->att->requestWrite(descriptor.handle(), data, - d, SLOT(handleDescriptorWrite(uint,bool))); - } else { - qWarning() << "Not connected"; - } -} - -void GatoPeripheral::setNotification(const GatoCharacteristic &characteristic, bool enabled) -{ - Q_D(GatoPeripheral); - - GatoHandle char_handle = characteristic.startHandle(); - GatoHandle service_handle = d->characteristic_to_service.value(char_handle); - - if (!service_handle) { - qWarning() << "Unknown characteristic for this peripheral"; - return; - } - - GatoService &our_service = d->services[service_handle]; - Q_ASSERT(our_service.containsCharacteristic(char_handle)); - GatoCharacteristic our_char = our_service.getCharacteristic(char_handle); - - if (!(our_char.properties() & GatoCharacteristic::PropertyNotify)) { - qWarning() << "Characteristic does not support notifications"; - return; - } - - if (state() != StateConnected) { - qWarning() << "Not connected"; - return; - } - - const GatoUUID uuid(GatoUUID::GattClientCharacteristicConfiguration); - if (our_char.containsDescriptor(uuid)) { - GatoDescriptor desc = our_char.getDescriptor(uuid); - d->pending_set_notify.remove(char_handle); - writeValue(characteristic, d->genClientCharConfiguration(true, false)); - } else { - d->pending_set_notify[char_handle] = enabled; - discoverDescriptors(our_char); // May need to find appropiate descriptor - } -} - -GatoPeripheralPrivate::GatoPeripheralPrivate(GatoPeripheral *parent) - : QObject(parent), q_ptr(parent), - complete_name(false), complete_services(false) -{ -} - -GatoPeripheralPrivate::~GatoPeripheralPrivate() -{ - delete att; -} - -void GatoPeripheralPrivate::parseEIRFlags(quint8 data[], int len) -{ - Q_UNUSED(data); - Q_UNUSED(len); - // Nothing to do for now. -} - -void GatoPeripheralPrivate::parseEIRUUIDs(int size, bool complete, quint8 data[], int len) -{ - Q_UNUSED(complete); - - if (size != 16/8 && size != 32/8 && size != 128/8) { - qWarning() << "Unhandled UUID size: " << size; - return; - } - - for (int pos = 0; pos < len; pos += size) { - char *ptr = reinterpret_cast<char*>(&data[pos]); - QByteArray ba = QByteArray::fromRawData(ptr, size/8); - - service_uuids.insert(bytearray_to_gatouuid(ba)); - } -} - -void GatoPeripheralPrivate::parseName(bool complete, quint8 data[], int len) -{ - Q_Q(GatoPeripheral); - if (complete || !complete_name) { - name = QString::fromUtf8(reinterpret_cast<char*>(data), len); - complete_name = complete; - emit q->nameChanged(); - } -} - -GatoCharacteristic GatoPeripheralPrivate::parseCharacteristicValue(const QByteArray &ba) -{ - GatoCharacteristic characteristic; - const char *data = ba.constData(); - - quint8 properties = data[0]; - characteristic.setProperties(GatoCharacteristic::Properties(properties)); - - GatoHandle handle = read_le<quint16>(&data[1]); - characteristic.setValueHandle(handle); - - GatoUUID uuid = bytearray_to_gatouuid(ba.mid(3)); - characteristic.setUuid(uuid); - - return characteristic; -} - -QByteArray GatoPeripheralPrivate::genClientCharConfiguration(bool notification, bool indication) -{ - QByteArray ba; - ba.resize(sizeof(quint16)); - - quint16 val = 0; - if (notification) - val |= 0x1; - if (indication) - val |= 0x2; - - write_le<quint16>(val, ba.data()); - - return ba; -} - -void GatoPeripheralPrivate::clearServices() -{ - characteristic_to_service.clear(); - value_to_characteristic.clear(); - descriptor_to_characteristic.clear(); - services.clear(); -} - -void GatoPeripheralPrivate::clearServiceCharacteristics(GatoService *service) -{ - QList<GatoCharacteristic> chars = service->characteristics(); - QList<GatoCharacteristic>::iterator it; - for (it = chars.begin(); it != chars.end(); ++it) { - clearCharacteristicDescriptors(&*it); - characteristic_to_service.remove(it->startHandle()); - value_to_characteristic.remove(it->valueHandle()); - } - service->clearCharacteristics(); -} - -void GatoPeripheralPrivate::clearCharacteristicDescriptors(GatoCharacteristic *characteristic) -{ - QList<GatoDescriptor> descs = characteristic->descriptors(); - foreach (const GatoDescriptor& d, descs) { - descriptor_to_characteristic.remove(d.handle()); - } - characteristic->clearDescriptors(); -} - -void GatoPeripheralPrivate::finishSetNotifyOperations(const GatoCharacteristic &characteristic) -{ - Q_Q(GatoPeripheral); - - GatoHandle handle = characteristic.startHandle(); - - if (pending_set_notify.contains(handle)) { - const GatoUUID uuid(GatoUUID::GattClientCharacteristicConfiguration); - bool notify = pending_set_notify.value(handle); - - foreach (const GatoDescriptor &descriptor, characteristic.descriptors()) { - if (descriptor.uuid() == uuid) { - q->writeValue(descriptor, genClientCharConfiguration(notify, false)); - } - } - - pending_set_notify.remove(handle); - } -} - -void GatoPeripheralPrivate::handleAttConnected() -{ - Q_Q(GatoPeripheral); - - emit q->connected(); -} - -void GatoPeripheralPrivate::handleAttDisconnected() -{ - Q_Q(GatoPeripheral); - - // Forget about all pending requests - pending_primary_reqs.clear(); - pending_characteristic_reqs.clear(); - pending_characteristic_read_reqs.clear(); - pending_descriptor_reqs.clear(); - pending_descriptor_read_reqs.clear(); - - emit q->disconnected(); -} - -void GatoPeripheralPrivate::handleAttAttributeUpdated(GatoHandle handle, const QByteArray &value, bool confirmed) -{ - Q_Q(GatoPeripheral); - Q_UNUSED(confirmed); - - // Let's see if this is a handle we know about. - if (value_to_characteristic.contains(handle)) { - // Ok, it's a characteristic value. - GatoHandle char_handle = value_to_characteristic.value(handle); - GatoHandle service_handle = characteristic_to_service.value(char_handle); - if (!service_handle) { - qWarning() << "Got a notification for a characteristic I don't know about"; - return; - } - - GatoService &service = services[service_handle]; - GatoCharacteristic characteristic = service.getCharacteristic(char_handle); - - emit q->valueUpdated(characteristic, value); - } -} - -void GatoPeripheralPrivate::handlePrimary(uint req, const QList<GatoAttClient::AttributeGroupData> &list) -{ - Q_Q(GatoPeripheral); - Q_UNUSED(req); - - if (list.isEmpty()) { - complete_services = true; - emit q->servicesDiscovered(); - } else { - GatoHandle last_handle = 0; - - foreach (const GatoAttClient::AttributeGroupData &data, list) { - GatoUUID uuid = bytearray_to_gatouuid(data.value); - GatoService service; - - service.setUuid(uuid); - service.setStartHandle(data.start); - service.setEndHandle(data.end); - - services.insert(data.start, service); - service_uuids.insert(uuid); - - last_handle = data.end; - } - - // Fetch following attributes - att->requestReadByGroupType(last_handle + 1, 0xFFFF, GatoUUID::GattPrimaryService, - this, SLOT(handlePrimary(uint,QList<GatoAttClient::AttributeGroupData>))); - } -} - -void GatoPeripheralPrivate::handlePrimaryForService(uint req, const QList<GatoAttClient::HandleInformation> &list) -{ - Q_Q(GatoPeripheral); - - GatoUUID uuid = pending_primary_reqs.value(req, GatoUUID()); - if (uuid.isNull()) { - qDebug() << "Got primary for service response for a request I did not make"; - return; - } - pending_primary_reqs.remove(req); - - if (list.isEmpty()) { - if (pending_primary_reqs.isEmpty()) { - emit q->servicesDiscovered(); - } - } else { - GatoHandle last_handle = 0; - - foreach (const GatoAttClient::HandleInformation &data, list) { - GatoService service; - - service.setUuid(uuid); - service.setStartHandle(data.start); - service.setEndHandle(data.end); - - services.insert(data.start, service); - service_uuids.insert(uuid); - - last_handle = data.end; - } - - // Fetch following attributes - QByteArray value = gatouuid_to_bytearray(uuid, true, false); - uint req = att->requestFindByTypeValue(last_handle + 1, 0xFFFF, GatoUUID::GattPrimaryService, value, - this, SLOT(handlePrimaryForService(uint,QList<GatoAttClient::HandleInformation>))); - pending_primary_reqs.insert(req, uuid); - } -} - -void GatoPeripheralPrivate::handleCharacteristic(uint req, const QList<GatoAttClient::AttributeData> &list) -{ - Q_Q(GatoPeripheral); - - GatoHandle service_start = pending_characteristic_reqs.value(req, 0); - if (!service_start) { - qDebug() << "Got characteristics for a request I did not make"; - return; - } - pending_characteristic_reqs.remove(req); - - Q_ASSERT(services.contains(service_start)); - GatoService &service = services[service_start]; - Q_ASSERT(service.startHandle() == service_start); - - if (list.isEmpty()) { - emit q->characteristicsDiscovered(service); - } else { - GatoHandle last_handle = 0; - - // If we are continuing a characteristic list, this means the - // last service we discovered in the previous iteration was not - // the last one, so we have to reduce its endHandle! - QList<GatoCharacteristic> cur_chars = service.characteristics(); - if (!cur_chars.isEmpty()) { - GatoCharacteristic &last = cur_chars.back(); - last.setEndHandle(list.front().handle - 1); - service.addCharacteristic(last); - } - - for (int i = 0; i < list.size(); i++) { - const GatoAttClient::AttributeData &data = list.at(i); - GatoCharacteristic characteristic = parseCharacteristicValue(data.value); - - characteristic.setStartHandle(data.handle); - if (i + 1 < list.size()) { - characteristic.setEndHandle(list.at(i + 1).handle - 1); - } else { - characteristic.setEndHandle(service.endHandle()); - } - - service.addCharacteristic(characteristic); - characteristic_to_service.insert(data.handle, service_start); - value_to_characteristic.insert(characteristic.valueHandle(), data.handle); - - last_handle = data.handle; - } - - if (last_handle >= service.endHandle()) { - // Already finished, no need to send another request - emit q->characteristicsDiscovered(service); - return; - } - - // Fetch following attributes - uint req = att->requestReadByType(last_handle + 1, service.endHandle(), GatoUUID::GattCharacteristic, - this, SLOT(handleCharacteristic(uint,QList<GatoAttClient::AttributeData>))); - pending_characteristic_reqs.insert(req, service.startHandle()); - } -} - -void GatoPeripheralPrivate::handleDescriptors(uint req, const QList<GatoAttClient::InformationData> &list) -{ - Q_Q(GatoPeripheral); - - GatoHandle char_handle = pending_descriptor_reqs.value(req); - if (!char_handle) { - qDebug() << "Got descriptor for a request I did not make"; - return; - } - pending_descriptor_reqs.remove(req); - GatoHandle service_handle = characteristic_to_service.value(char_handle); - if (!service_handle) { - qWarning() << "Unknown characteristic during descriptor discovery: " << char_handle; - return; - } - - Q_ASSERT(services.contains(service_handle)); - GatoService &service = services[service_handle]; - Q_ASSERT(service.startHandle() == service_handle); - - Q_ASSERT(service.containsCharacteristic(char_handle)); - GatoCharacteristic characteristic = service.getCharacteristic(char_handle); - - if (list.isEmpty()) { - finishSetNotifyOperations(characteristic); - emit q->descriptorsDiscovered(characteristic); - } else { - GatoHandle last_handle = 0; - - foreach (const GatoAttClient::InformationData &data, list) { - // Skip the value attribute itself. - if (data.handle == characteristic.valueHandle()) continue; - - GatoDescriptor descriptor; - - descriptor.setHandle(data.handle); - descriptor.setUuid(data.uuid); - - characteristic.addDescriptor(descriptor); - - service.addCharacteristic(characteristic); - descriptor_to_characteristic.insert(data.handle, char_handle); - - last_handle = data.handle; - } - - service.addCharacteristic(characteristic); - - if (last_handle >= characteristic.endHandle()) { - // Already finished, no need to send another request - finishSetNotifyOperations(characteristic); - emit q->descriptorsDiscovered(characteristic); - return; - } - - // Fetch following attributes - uint req = att->requestFindInformation(last_handle + 1, characteristic.endHandle(), - this, SLOT(handleDescriptors(uint,QList<GatoAttClient::InformationData>))); - pending_descriptor_reqs.insert(req, char_handle); - - } -} - -void GatoPeripheralPrivate::handleCharacteristicRead(uint req, const QByteArray &value) -{ - Q_Q(GatoPeripheral); - - GatoHandle char_handle = pending_characteristic_read_reqs.value(req); - if (!char_handle) { - qDebug() << "Got characteristics for a request I did not make"; - return; - } - pending_characteristic_read_reqs.remove(req); - GatoHandle service_handle = characteristic_to_service.value(char_handle); - if (!service_handle) { - qWarning() << "Unknown characteristic during read: " << char_handle; - return; - } - - Q_ASSERT(services.contains(service_handle)); - GatoService &service = services[service_handle]; - Q_ASSERT(service.startHandle() == service_handle); - - Q_ASSERT(service.containsCharacteristic(char_handle)); - GatoCharacteristic characteristic = service.getCharacteristic(char_handle); - - emit q->valueUpdated(characteristic, value); -} - -void GatoPeripheralPrivate::handleDescriptorRead(uint req, const QByteArray &value) -{ - Q_Q(GatoPeripheral); - - GatoHandle desc_handle = pending_descriptor_read_reqs.value(req); - if (!desc_handle) { - qDebug() << "Got characteristics for a request I did not make"; - return; - } - pending_descriptor_read_reqs.remove(req); - GatoHandle char_handle = descriptor_to_characteristic.value(desc_handle); - if (!char_handle) { - qWarning() << "Unknown characteristic during read: " << char_handle; - return; - } - GatoHandle service_handle = characteristic_to_service.value(char_handle); - if (!service_handle) { - qWarning() << "Unknown characteristic during read: " << char_handle; - return; - } - - Q_ASSERT(services.contains(service_handle)); - GatoService &service = services[service_handle]; - Q_ASSERT(service.startHandle() == service_handle); - - Q_ASSERT(service.containsCharacteristic(char_handle)); - GatoCharacteristic characteristic = service.getCharacteristic(char_handle); - - Q_ASSERT(characteristic.containsDescriptor(desc_handle)); - GatoDescriptor descriptor = characteristic.getDescriptor(desc_handle); - - emit q->descriptorValueUpdated(descriptor, value); -} - -void GatoPeripheralPrivate::handleCharacteristicWrite(uint req, bool ok) -{ - Q_UNUSED(req); - if (!ok) { - qWarning() << "Failed to write some characteristic"; - } -} - -void GatoPeripheralPrivate::handleDescriptorWrite(uint req, bool ok) -{ - Q_UNUSED(req); - if (!ok) { - qWarning() << "Failed to write some characteristic"; - } -} - -QT_END_NAMESPACE diff --git a/src/bluetooth/gatoperipheral.h b/src/bluetooth/gatoperipheral.h deleted file mode 100644 index a8850678..00000000 --- a/src/bluetooth/gatoperipheral.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Javier de San Pedro <dev.git@javispedro.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GATOPERIPHERAL_H -#define GATOPERIPHERAL_H - -#include <QtCore/QObject> -#include "libgato_global.h" -#include "gatouuid.h" -#include "gatoaddress.h" - -QT_BEGIN_NAMESPACE - -class GatoService; -class GatoCharacteristic; -class GatoDescriptor; -class GatoPeripheralPrivate; - -class LIBGATO_EXPORT GatoPeripheral : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(GatoPeripheral) - Q_ENUMS(State) - Q_ENUMS(WriteType) - Q_PROPERTY(GatoAddress address READ address) - Q_PROPERTY(QString name READ name NOTIFY nameChanged) - -public: - GatoPeripheral(const GatoAddress& addr, QObject *parent = 0); - ~GatoPeripheral(); - - enum State { - StateDisconnected, - StateConnecting, - StateConnected - }; - - enum WriteType { - WriteWithResponse = 0, - WriteWithoutResponse - }; - - State state() const; - GatoAddress address() const; - QString name() const; - QList<GatoService> services() const; - - void parseEIR(quint8 data[], int len); - bool advertisesService(const GatoUUID &uuid) const; - -public Q_SLOTS: - void connectPeripheral(); - void disconnectPeripheral(); - void discoverServices(); - void discoverServices(const QList<GatoUUID>& serviceUUIDs); - void discoverCharacteristics(const GatoService &service); - void discoverCharacteristics(const GatoService &service, const QList<GatoUUID>& characteristicUUIDs); - void discoverDescriptors(const GatoCharacteristic &characteristic); - void readValue(const GatoCharacteristic &characteristic); - void readValue(const GatoDescriptor &descriptor); - void writeValue(const GatoCharacteristic &characteristic, const QByteArray &data, WriteType type = WriteWithResponse); - void writeValue(const GatoDescriptor &descriptor, const QByteArray &data); - void setNotification(const GatoCharacteristic &characteristic, bool enabled); - -Q_SIGNALS: - void connected(); - void disconnected(); - void nameChanged(); - void servicesDiscovered(); - void characteristicsDiscovered(const GatoService &service); - void descriptorsDiscovered(const GatoCharacteristic &characteristic); - void valueUpdated(const GatoCharacteristic &characteristic, const QByteArray &value); - void descriptorValueUpdated(const GatoDescriptor &descriptor, const QByteArray &value); - -private: - GatoPeripheralPrivate *const d_ptr; -}; - -QT_END_NAMESPACE - -#endif // GATOPERIPHERAL_H diff --git a/src/bluetooth/gatoperipheral_p.h b/src/bluetooth/gatoperipheral_p.h deleted file mode 100644 index 663d7541..00000000 --- a/src/bluetooth/gatoperipheral_p.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Javier de San Pedro <dev.git@javispedro.com> -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtBluetooth module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GATOPERIPHERAL_P_H -#define GATOPERIPHERAL_P_H - -#include "gatoperipheral.h" -#include "gatoservice.h" -#include "gatocharacteristic.h" -#include "gatodescriptor.h" -#include "gatoattclient.h" - -QT_BEGIN_NAMESPACE - -class GatoPeripheralPrivate : public QObject -{ - Q_OBJECT - - Q_DECLARE_PUBLIC(GatoPeripheral) - -public: - GatoPeripheralPrivate(GatoPeripheral *parent); - ~GatoPeripheralPrivate(); - - GatoPeripheral *q_ptr; - GatoAddress addr; - QString name; - QSet<GatoUUID> service_uuids; - QMap<GatoHandle, GatoService> services; - - bool complete_name : 1; - bool complete_services : 1; - - /** Maps attribute handles to service handles. */ - QMap<GatoHandle, GatoHandle> characteristic_to_service; - QMap<GatoHandle, GatoHandle> value_to_characteristic; - QMap<GatoHandle, GatoHandle> descriptor_to_characteristic; - - GatoAttClient *att; - QMap<uint, GatoUUID> pending_primary_reqs; - QMap<uint, GatoHandle> pending_characteristic_reqs; - QMap<uint, GatoHandle> pending_characteristic_read_reqs; - QMap<uint, GatoHandle> pending_descriptor_reqs; - QMap<uint, GatoHandle> pending_descriptor_read_reqs; - - QMap<GatoHandle, bool> pending_set_notify; - - void parseEIRFlags(quint8 data[], int len); - void parseEIRUUIDs(int size, bool complete, quint8 data[], int len); - void parseName(bool complete, quint8 data[], int len); - - static GatoCharacteristic parseCharacteristicValue(const QByteArray &ba); - - static QByteArray genClientCharConfiguration(bool notification, bool indication); - - void clearServices(); - void clearServiceCharacteristics(GatoService *service); - void clearCharacteristicDescriptors(GatoCharacteristic *characteristic); - - void finishSetNotifyOperations(const GatoCharacteristic &characteristic); - -public slots: - void handleAttConnected(); - void handleAttDisconnected(); - void handleAttAttributeUpdated(GatoHandle handle, const QByteArray &value, bool confirmed); - void handlePrimary(uint req, const QList<GatoAttClient::AttributeGroupData>& list); - void handlePrimaryForService(uint req, const QList<GatoAttClient::HandleInformation>& list); - void handleCharacteristic(uint req, const QList<GatoAttClient::AttributeData> &list); - void handleDescriptors(uint req, const QList<GatoAttClient::InformationData> &list); - void handleCharacteristicRead(uint req, const QByteArray &value); - void handleDescriptorRead(uint req, const QByteArray &value); - void handleCharacteristicWrite(uint req, bool ok); - void handleDescriptorWrite(uint req, bool ok); -}; - -QT_END_NAMESPACE - -#endif // GATOPERIPHERAL_P_H diff --git a/sync.profile b/sync.profile index 0ceddf44..1204b458 100644 --- a/sync.profile +++ b/sync.profile @@ -17,6 +17,3 @@ "qtxmlpatterns" => "", "qtandroidextras" => "", ); - -my @gato_headers = ("gatoattclient.h", "gatoperipheral.h"); -@ignore_for_master_contents = ( @gato_headers ); |