From ec61d7b9e82e6d653c02df14f34acdba8fc060db Mon Sep 17 00:00:00 2001 From: Nedim Hadzic Date: Wed, 23 Oct 2013 17:33:36 +0200 Subject: Implemented Bluetooth Low Energy gatt service and characteristics discovery Bluez v4.x does not have total support for LE devices, a new approach, using gatttool command was implemented. Auto-tests and documentation will be in other commits. Change-Id: Iee711cc111199e15956052eebb7593bd3a5e27c8 Reviewed-by: Alex Blasche --- src/bluetooth/bluetooth.pro | 40 ++- src/bluetooth/bluez/bluez.pri | 6 +- src/bluetooth/bluez/characteristic.cpp | 54 +++ src/bluetooth/bluez/characteristic_p.h | 111 ++++++ .../qbluetoothdevicediscoveryagent_bluez.cpp | 10 + .../qbluetoothdevicediscoveryagent_qnx.cpp | 25 +- src/bluetooth/qbluetoothdeviceinfo.cpp | 60 +++- src/bluetooth/qbluetoothdeviceinfo.h | 9 + src/bluetooth/qbluetoothdeviceinfo_p.h | 1 + src/bluetooth/qbluetoothservicediscoveryagent.cpp | 1 - src/bluetooth/qbluetoothservicediscoveryagent.h | 2 + .../qbluetoothservicediscoveryagent_bluez.cpp | 189 +++++++++- src/bluetooth/qbluetoothservicediscoveryagent_p.h | 17 +- .../qbluetoothservicediscoveryagent_qnx.cpp | 91 +++-- src/bluetooth/qbluetoothuuid.cpp | 308 ++++++++++++++-- src/bluetooth/qbluetoothuuid.h | 122 ++++++- src/bluetooth/qlowenergycharacteristicinfo.cpp | 287 +++++++++++++++ src/bluetooth/qlowenergycharacteristicinfo.h | 111 ++++++ .../qlowenergycharacteristicinfo_bluez.cpp | 199 +++++++++++ src/bluetooth/qlowenergycharacteristicinfo_p.cpp | 92 +++++ src/bluetooth/qlowenergycharacteristicinfo_p.h | 122 +++++++ src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp | 318 +++++++++++++++++ src/bluetooth/qlowenergycontroller.cpp | 282 +++++++++++++++ src/bluetooth/qlowenergycontroller.h | 88 +++++ src/bluetooth/qlowenergycontroller_p.h | 68 ++++ src/bluetooth/qlowenergydescriptorinfo.cpp | 133 +++++++ src/bluetooth/qlowenergydescriptorinfo.h | 76 ++++ src/bluetooth/qlowenergydescriptorinfo_p.h | 59 ++++ src/bluetooth/qlowenergyprocess_bluez.cpp | 143 ++++++++ src/bluetooth/qlowenergyprocess_p.cpp | 68 ++++ src/bluetooth/qlowenergyprocess_p.h | 98 ++++++ src/bluetooth/qlowenergyprocess_qnx.cpp | 95 +++++ src/bluetooth/qlowenergyserviceinfo.cpp | 263 ++++++++++++++ src/bluetooth/qlowenergyserviceinfo.h | 114 ++++++ src/bluetooth/qlowenergyserviceinfo_bluez.cpp | 391 +++++++++++++++++++++ src/bluetooth/qlowenergyserviceinfo_p.cpp | 72 ++++ src/bluetooth/qlowenergyserviceinfo_p.h | 132 +++++++ src/bluetooth/qlowenergyserviceinfo_qnx.cpp | 265 ++++++++++++++ 38 files changed, 4426 insertions(+), 96 deletions(-) create mode 100644 src/bluetooth/bluez/characteristic.cpp create mode 100644 src/bluetooth/bluez/characteristic_p.h create mode 100644 src/bluetooth/qlowenergycharacteristicinfo.cpp create mode 100644 src/bluetooth/qlowenergycharacteristicinfo.h create mode 100644 src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp create mode 100644 src/bluetooth/qlowenergycharacteristicinfo_p.cpp create mode 100644 src/bluetooth/qlowenergycharacteristicinfo_p.h create mode 100644 src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp create mode 100644 src/bluetooth/qlowenergycontroller.cpp create mode 100644 src/bluetooth/qlowenergycontroller.h create mode 100644 src/bluetooth/qlowenergycontroller_p.h create mode 100644 src/bluetooth/qlowenergydescriptorinfo.cpp create mode 100644 src/bluetooth/qlowenergydescriptorinfo.h create mode 100644 src/bluetooth/qlowenergydescriptorinfo_p.h create mode 100644 src/bluetooth/qlowenergyprocess_bluez.cpp create mode 100644 src/bluetooth/qlowenergyprocess_p.cpp create mode 100644 src/bluetooth/qlowenergyprocess_p.h create mode 100644 src/bluetooth/qlowenergyprocess_qnx.cpp create mode 100644 src/bluetooth/qlowenergyserviceinfo.cpp create mode 100644 src/bluetooth/qlowenergyserviceinfo.h create mode 100644 src/bluetooth/qlowenergyserviceinfo_bluez.cpp create mode 100644 src/bluetooth/qlowenergyserviceinfo_p.cpp create mode 100644 src/bluetooth/qlowenergyserviceinfo_p.h create mode 100644 src/bluetooth/qlowenergyserviceinfo_qnx.cpp (limited to 'src/bluetooth') diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index 7c9f9f00..4e509299 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -2,6 +2,7 @@ TARGET = QtBluetooth QT = core QT_PRIVATE = concurrent + QMAKE_DOCS = $$PWD/doc/qtbluetooth.qdocconf OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator @@ -22,7 +23,11 @@ PUBLIC_HEADERS += \ qbluetoothlocaldevice.h \ qbluetoothtransfermanager.h \ qbluetoothtransferrequest.h \ - qbluetoothtransferreply.h + qlowenergyserviceinfo.h \ + qlowenergycharacteristicinfo.h \ + qlowenergydescriptorinfo.h \ + qbluetoothtransferreply.h \ + qlowenergycontroller.h PRIVATE_HEADERS += \ qbluetoothaddress_p.h\ @@ -36,7 +41,12 @@ PRIVATE_HEADERS += \ qbluetoothtransferreply_p.h \ qbluetoothtransferrequest_p.h \ qprivatelinearbuffer_p.h \ - qbluetoothlocaldevice_p.h + qbluetoothlocaldevice_p.h \ + qlowenergyserviceinfo_p.h \ + qlowenergycharacteristicinfo_p.h \ + qlowenergyprocess_p.h \ + qlowenergydescriptorinfo_p.h \ + qlowenergycontroller_p.h SOURCES += \ qbluetoothaddress.cpp\ @@ -52,7 +62,11 @@ SOURCES += \ qbluetooth.cpp \ qbluetoothtransfermanager.cpp \ qbluetoothtransferrequest.cpp \ - qbluetoothtransferreply.cpp + qbluetoothtransferreply.cpp \ + qlowenergyserviceinfo.cpp \ + qlowenergycharacteristicinfo.cpp \ + qlowenergydescriptorinfo.cpp \ + qlowenergycontroller.cpp config_bluez:qtHaveModule(dbus) { QT *= dbus @@ -70,7 +84,10 @@ config_bluez:qtHaveModule(dbus) { qbluetoothsocket_bluez.cpp \ qbluetoothserver_bluez.cpp \ qbluetoothlocaldevice_bluez.cpp \ - qbluetoothtransferreply_bluez.cpp + qbluetoothtransferreply_bluez.cpp \ + qlowenergyprocess_bluez.cpp \ + qlowenergyserviceinfo_bluez.cpp \ + qlowenergycharacteristicinfo_bluez.cpp } else:qnx{ DEFINES += QT_QNX_BLUETOOTH #BT_BBPPSDEBUG @@ -92,7 +109,10 @@ config_bluez:qtHaveModule(dbus) { qbluetoothservicediscoveryagent_qnx.cpp \ qbluetoothsocket_qnx.cpp \ qbluetoothserver_qnx.cpp \ - qbluetoothtransferreply_qnx.cpp + qbluetoothtransferreply_qnx.cpp \ + qlowenergycharacteristicinfo_qnx.cpp \ + qlowenergyserviceinfo_qnx.cpp \ + qlowenergyprocess_qnx.cpp } else { message("Unsupported bluetooth platform, will not build a working QBluetooth library") @@ -103,8 +123,11 @@ config_bluez:qtHaveModule(dbus) { qbluetoothserviceinfo_p.cpp \ qbluetoothservicediscoveryagent_p.cpp \ qbluetoothsocket_p.cpp \ - qbluetoothserver_p.cpp - + qbluetoothserver_p.cpp \ + qbluetoothtransfermanager_p.cpp \ + qlowenergyserviceinfo_p.cpp \ + qlowenergycharacteristicinfo_p.cpp \ + qlowenergyprocess_p.cpp } OTHER_FILES += @@ -112,3 +135,6 @@ OTHER_FILES += HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS + + + diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri index 5a679091..a4b597a0 100644 --- a/src/bluetooth/bluez/bluez.pri +++ b/src/bluetooth/bluez/bluez.pri @@ -20,7 +20,8 @@ HEADERS += bluez/manager_p.h \ bluez/obex_client_p.h \ bluez/obex_agent_p.h \ bluez/obex_transfer_p.h \ - bluez/obex_manager_p.h + bluez/obex_manager_p.h \ + bluez/characteristic_p.h SOURCES += bluez/manager.cpp \ @@ -32,4 +33,5 @@ SOURCES += bluez/manager.cpp \ bluez/obex_client.cpp \ bluez/obex_agent.cpp \ bluez/obex_transfer.cpp \ - bluez/obex_manager.cpp + bluez/obex_manager.cpp \ + bluez/characteristic.cpp diff --git a/src/bluetooth/bluez/characteristic.cpp b/src/bluetooth/bluez/characteristic.cpp new file mode 100644 index 00000000..ed4b8485 --- /dev/null +++ b/src/bluetooth/bluez/characteristic.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "characteristic_p.h" + +/* + * Implementation of interface class OrgBluezCharacteristicInterface + */ + +OrgBluezCharacteristicInterface::OrgBluezCharacteristicInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgBluezCharacteristicInterface::~OrgBluezCharacteristicInterface() +{ +} diff --git a/src/bluetooth/bluez/characteristic_p.h b/src/bluetooth/bluez/characteristic_p.h new file mode 100644 index 00000000..ef510ab2 --- /dev/null +++ b/src/bluetooth/bluez/characteristic_p.h @@ -0,0 +1,111 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CHARACTERISTIC_P_H +#define CHARACTERISTIC_P_H + +#endif // CHARACTERISTIC_P_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Proxy class for interface org.bluez.Device + */ +class OrgBluezCharacteristicInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.bluez.Characteristic"; } + +public: + OrgBluezCharacteristicInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + ~OrgBluezCharacteristicInterface(); + +public Q_SLOTS: + inline QDBusPendingReply GetProperties() + { + QList argumentList; + return asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + } + + inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1) + { + QList argumentList; + argumentList << qVariantFromValue(in0) << qVariantFromValue(in1); + return asyncCallWithArgumentList(QLatin1String("SetProperty"), argumentList); + } + inline QDBusPendingReply > DiscoverCharacteristics() + { + QList argumentList; + return asyncCallWithArgumentList(QLatin1String("DiscoverCharacteristics"), argumentList); + } + + inline QDBusPendingReply<> RegisterCharacteristicsWatcher(const QDBusObjectPath &in0) + { + QList argumentList; + argumentList << qVariantFromValue(in0); + return asyncCallWithArgumentList(QLatin1String("RegisterCharacteristicsWatcher"), argumentList); + } + + inline QDBusPendingReply<> UnregisterCharacteristicsWatcher(const QDBusObjectPath &in0) + { + QList argumentList; + argumentList << qVariantFromValue(in0); + return asyncCallWithArgumentList(QLatin1String("UnregisterCharacteristicsWatcher"), argumentList); + } + +Q_SIGNALS: + void PropertyChanged(const QString &in0, const QDBusVariant &in1); +}; + +namespace org { + namespace bluez { + typedef ::OrgBluezCharacteristicInterface Characteristic; + } +} diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 257ebf3d..017f8410 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -177,6 +177,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &addres } device.setServiceUuids(uuids, QBluetoothDeviceInfo::DataIncomplete); device.setCached(dict.value(QLatin1String("Cached")).toBool()); + + /* + * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth + * Low Energy device and the way to discover it is with Class property of the Bluetooth device. + * Low Energy devices do not have property Class. + */ + if (btClass == 0) + device.setCoreConfiguration(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + else + device.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration); for(int i = 0; i < discoveredDevices.size(); i++){ if(discoveredDevices[i].address() == device.address()) { if(discoveredDevices[i] == device) { diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp index f911a212..7cc8ea93 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_qnx.cpp @@ -165,11 +165,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) int cod = 0; int dev_type = 0; int rssi = 0; - + bool hasGatt = false; pps_decoder_get_bool(&ppsDecoder, "paired", &paired); pps_decoder_get_int(&ppsDecoder, "cod", &cod); pps_decoder_get_int(&ppsDecoder, "dev_type", &dev_type); pps_decoder_get_int(&ppsDecoder, "rssi", &rssi); + pps_decoder_push(&ppsDecoder, "gatt_available_services"); + const char *next_service = 0; + + for (int service_count=0; pps_decoder_get_string(&ppsDecoder, 0, &next_service ) == PPS_DECODER_OK; service_count++) { + hasGatt = true; + //qBluetoothDebug() << next_service; + } pps_decoder_cleanup(&ppsDecoder); QBluetoothDeviceInfo deviceInfo(deviceAddr, deviceName, cod); @@ -191,7 +198,21 @@ void QBluetoothDeviceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) //Starts the timer again m_finishedTimer.start(7000); if (!deviceAddr.isNull()) { - qBBBluetoothDebug() << "Device discovered: " << deviceName << deviceAddr.toString(); + //qDebug() << "Device discovered: " << deviceName << deviceAddr.toString(); + /* Looking for device type. Only Low energy devices will be added + * BT_DEVICE_TYPE_LE_PUBLIC is 0 --->LE device + * BT_DEVICE_TYPE_LE_PRIVATE is 1 ---> LE device + * BT_DEVICE_TYPE_REGULAR is 32 + * BT_DEVICE_TYPE_UNKNOWN is 255 + */ + if (dev_type == 0 || dev_type == 1) + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); + else{ + if (hasGatt) + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration); + else + deviceInfo.setCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration); + } discoveredDevices.append(deviceInfo); if (!updated)//We are not allowed to emit a signal with the updated version emit q_ptr->deviceDiscovered(discoveredDevices.last()); diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp index 7a8e882b..d451bc49 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.cpp +++ b/src/bluetooth/qbluetoothdeviceinfo.cpp @@ -249,12 +249,24 @@ QT_BEGIN_NAMESPACE \value DataUnavailable No data is available. */ +/*! + \enum QBluetoothDeviceInfo::CoreConfiguration + + This enum describes the configuration of the device. + + \value BaseRateCoreConfiguration The device is a standard Bluetooth device. + \value BaseRateAndLowEnergyConfiguration The device is a Bluetooth Smart device with support + for standard and Low Energy device. + \value LowEnergyCoreCOnfiguration The device is a Bluetooth Low Energy device. +*/ + QBluetoothDeviceInfoPrivate::QBluetoothDeviceInfoPrivate() : valid(false), cached(false), rssi(1), serviceClasses(QBluetoothDeviceInfo::NoService), majorDeviceClass(QBluetoothDeviceInfo::MiscellaneousDevice), minorDeviceClass(0), - serviceUuidsCompleteness(QBluetoothDeviceInfo::DataUnavailable) + serviceUuidsCompleteness(QBluetoothDeviceInfo::DataUnavailable), + deviceCoreConfiguration(QBluetoothDeviceInfo::BaseRateCoreConfiguration) { } @@ -361,6 +373,7 @@ QBluetoothDeviceInfo &QBluetoothDeviceInfo::operator=(const QBluetoothDeviceInfo d->serviceUuidsCompleteness = other.d_func()->serviceUuidsCompleteness; d->serviceUuids = other.d_func()->serviceUuids; d->rssi = other.d_func()->rssi; + d->deviceCoreConfiguration = other.d_func()->deviceCoreConfiguration; return *this; } @@ -372,25 +385,27 @@ bool QBluetoothDeviceInfo::operator==(const QBluetoothDeviceInfo &other) const { Q_D(const QBluetoothDeviceInfo); - if(d->cached != other.d_func()->cached) + if (d->cached != other.d_func()->cached) return false; - if(d->valid != other.d_func()->valid) + if (d->valid != other.d_func()->valid) return false; - if(d->majorDeviceClass != other.d_func()->majorDeviceClass) + if (d->majorDeviceClass != other.d_func()->majorDeviceClass) return false; - if(d->minorDeviceClass != other.d_func()->minorDeviceClass) + if (d->minorDeviceClass != other.d_func()->minorDeviceClass) return false; - if(d->serviceClasses != other.d_func()->serviceClasses) + if (d->serviceClasses != other.d_func()->serviceClasses) return false; - if(d->name != other.d_func()->name) + if (d->name != other.d_func()->name) return false; - if(d->address != other.d_func()->address) + if (d->address != other.d_func()->address) return false; - if(d->serviceUuidsCompleteness != other.d_func()->serviceUuidsCompleteness) + if (d->serviceUuidsCompleteness != other.d_func()->serviceUuidsCompleteness) return false; - if(d->serviceUuids.count() != other.d_func()->serviceUuids.count()) + if (d->serviceUuids.count() != other.d_func()->serviceUuids.count()) return false; - if(d->serviceUuids != other.d_func()->serviceUuids) + if (d->serviceUuids != other.d_func()->serviceUuids) + return false; + if (d->deviceCoreConfiguration != other.d_func()->deviceCoreConfiguration) return false; return true; @@ -499,6 +514,29 @@ QBluetoothDeviceInfo::DataCompleteness QBluetoothDeviceInfo::serviceUuidsComplet return d->serviceUuidsCompleteness; } +/*! + Sets the CoreConfiguration of the device to a \a coreConfig. This will help to make a difference + between regular and Low Energy devices. +*/ +void QBluetoothDeviceInfo::setCoreConfiguration(const CoreConfiguration &coreConfig) +{ + Q_D(QBluetoothDeviceInfo); + + d->deviceCoreConfiguration = coreConfig; +} + +/*! + Returns the configuration of the device. If device configuration is not set, + basic rate device configuration will be returned. + \sa setCoreConfiguration +*/ +QBluetoothDeviceInfo::CoreConfiguration QBluetoothDeviceInfo::coreConfiguration() const +{ + Q_D(const QBluetoothDeviceInfo); + + return d->deviceCoreConfiguration; +} + /*! Returns true if the QBluetoothDeviceInfo object is created from cached data. */ diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h index ee8be191..3e403954 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.h +++ b/src/bluetooth/qbluetoothdeviceinfo.h @@ -196,6 +196,13 @@ public: DataUnavailable }; + enum CoreConfiguration { + BaseRateCoreConfiguration = 0x01, + BaseRateAndLowEnergyCoreConfiguration = 0x02, + LowEnergyCoreConfiguration = 0x03 + }; + Q_DECLARE_FLAGS(CoreConfigurations, CoreConfiguration) + QBluetoothDeviceInfo(); QBluetoothDeviceInfo(const QBluetoothAddress &address, const QString &name, quint32 classOfDevice); QBluetoothDeviceInfo(const QBluetoothDeviceInfo &other); @@ -223,6 +230,8 @@ public: void setServiceUuids(const QList &uuids, DataCompleteness completeness); QList serviceUuids(DataCompleteness *completeness = 0) const; DataCompleteness serviceUuidsCompleteness() const; + void setCoreConfiguration(const CoreConfiguration &coreConfig); + CoreConfiguration coreConfiguration() const; protected: QBluetoothDeviceInfoPrivate *d_ptr; diff --git a/src/bluetooth/qbluetoothdeviceinfo_p.h b/src/bluetooth/qbluetoothdeviceinfo_p.h index b08a8fec..d6c63a24 100644 --- a/src/bluetooth/qbluetoothdeviceinfo_p.h +++ b/src/bluetooth/qbluetoothdeviceinfo_p.h @@ -69,6 +69,7 @@ public: QBluetoothDeviceInfo::DataCompleteness serviceUuidsCompleteness; QList serviceUuids; + QBluetoothDeviceInfo::CoreConfiguration deviceCoreConfiguration; }; QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp index 1bf31245..cff8b813 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp @@ -206,7 +206,6 @@ bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress & if (!address.isNull()) d_ptr->singleDevice = true; d_ptr->deviceAddress = address; - return true; } diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h index f923c2d0..bbb105fa 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent.h @@ -49,6 +49,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public Q_SLOTS: Q_SIGNALS: void serviceDiscovered(const QBluetoothServiceInfo &info); + void serviceDiscovered(const QLowEnergyServiceInfo &info); void finished(); void canceled(); void error(QBluetoothServiceDiscoveryAgent::Error error); diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index 1d86fed7..06b8b59a 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -41,10 +41,13 @@ #include "qbluetoothservicediscoveryagent.h" #include "qbluetoothservicediscoveryagent_p.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyserviceinfo_p.h" #include "bluez/manager_p.h" #include "bluez/adapter_p.h" #include "bluez/device_p.h" +#include "bluez/characteristic_p.h" #include @@ -73,7 +76,7 @@ QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate( void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address) { - Q_Q(QBluetoothServiceDiscoveryAgent); + Q_Q(QBluetoothServiceDiscoveryAgent); #ifdef QT_SERVICEDISCOVERY_DEBUG qDebug() << "Full discovery on: " << address.toString(); @@ -174,20 +177,54 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWa #endif return; } - QVariantMap v = deviceReply.value(); - QStringList device_uuids = v.value(QLatin1String("UUIDs")).toStringList(); - - QString pattern; - foreach (const QBluetoothUuid &uuid, uuidFilter) - pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' '); + QVariantMap deviceProperties = deviceReply.value(); + QString classType = deviceProperties.value(QStringLiteral("Class")).toString(); + /* + * Low Energy services in bluez are represented as the list of the paths that can be + * accessed with org.bluez.Characteristic + */ + //QDBusArgument services = v.value(QLatin1String("Services")).value(); + const QStringList deviceUuids = deviceProperties.value(QStringLiteral("UUIDs")).toStringList(); + + for (int i = 0; i < deviceUuids.size(); i++) { + QString b = deviceUuids.at(i); + b = b.remove(QLatin1Char('{')).remove(QLatin1Char('}')); + QString leServiceCheck = QString(b.at(4)) + QString(b.at(5)); + /* + * In this part we want to emit only Bluetooth Low Energy service. BLE services + * have 18xx UUID. Some LE Services contain zeros in last part of UUID. + * In the end in case there is an uuidFilter we need to prevent emitting LE services + */ + if ((leServiceCheck == QStringLiteral("18") || b.contains(QStringLiteral("000000000000"))) && uuidFilter.size() == 0) { + QBluetoothUuid uuid(b); + QLowEnergyServiceInfo lowEnergyService(uuid); + lowEnergyService.d_ptr->adapterAddress = m_deviceAdapterAddress; + lowEnergyService.setDevice(discoveredDevices.at(0)); + q_ptr->serviceDiscovered(lowEnergyService); + } -#ifdef QT_SERVICEDISCOVERY_DEBUG - qDebug() << Q_FUNC_INFO << "Discover: " << pattern.trimmed(); -#endif - QDBusPendingReply discoverReply = device->DiscoverServices(pattern.trimmed()); - watcher = new QDBusPendingCallWatcher(discoverReply, q); - QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), - q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*))); + } + /* + * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth + * Low Energy device and the way to discover it is with Class property of the Bluetooth device. + * Low Energy devices do not have property Class. + * In case we have have LE device finish service discovery; otherwise search for regular services. + */ + if (classType.isEmpty()) + q_ptr->finished(); + else { + QString pattern; + foreach (const QBluetoothUuid &uuid, uuidFilter) + pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' '); + + #ifdef QT_SERVICEDISCOVERY_DEBUG + qDebug() << Q_FUNC_INFO << "Discover: " << pattern.trimmed(); + #endif + QDBusPendingReply discoverReply = device->DiscoverServices(pattern.trimmed()); + watcher = new QDBusPendingCallWatcher(discoverReply, q); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + q, SLOT(_q_discoveredServices(QDBusPendingCallWatcher*))); + } } @@ -269,6 +306,130 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingC _q_serviceDiscoveryFinished(); } +/* + * Following three methods are implemented in this way to avoid blocking the main thread. + * We first go through list of services path and then through services characteristics paths. + * + * Bluez v4.x does not have support for LE devices through org.bluez interfaces. Because of that + * these functions will not be used now. I propose to leave them commented because in Bluez v5.x + * we have support for LE devices and we can use these functions. + */ +/* +void QBluetoothServiceDiscoveryAgentPrivate::_g_discoveredGattService() +{ + + if (!gattServices.empty()) { + qDebug() << gattServices.at(0) << gattServices.size(); + gattService = QLowEnergyServiceInfo(gattServices.at(0)); + gattService.getProperties(); + QObject::connect(gattService.d_ptr.data(), SIGNAL(finished()), this, SLOT(_g_discoveredGattService())); + characteristic = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattServices.at(0), QDBusConnection::systemBus()); + QDBusPendingReply > characterictisReply = characteristic->DiscoverCharacteristics(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(characterictisReply, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(_q_discoverGattCharacteristics(QDBusPendingCallWatcher*))); + + gattServices.removeFirst(); + q_ptr->lowEnergyServiceDiscovered(gattService); + emit gattService.d_ptr->finished(); + } + else + q_ptr->finished(); + +} + +void QBluetoothServiceDiscoveryAgentPrivate::_q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher) +{ + + QDBusPendingReply > characterictisReply = *watcher; + if (characterictisReply.isError()){ + qDebug()<< "Discovering service characteristic error" << characterictisReply.error().message(); + Q_Q(QBluetoothServiceDiscoveryAgent); + error = QBluetoothServiceDiscoveryAgent::UnknownError; + errorString = characterictisReply.error().message(); + emit q->error(error); + _q_serviceDiscoveryFinished(); + return; + } + + foreach (const QDBusObjectPath &characteristicPath, characterictisReply.value()) + gattCharacteristics.append(characteristicPath.path()); + characteristic = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattCharacteristics.at(0), QDBusConnection::systemBus()); + QDBusPendingReply characteristicProperty = characteristic->GetProperties(); + watcher = new QDBusPendingCallWatcher(characteristicProperty, this); + _q_discoveredGattCharacteristic(watcher); + +} + +void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher) +{ + + QDBusPendingReply characteristicProperty = *watcher; + //qDebug()<error(error); + _q_serviceDiscoveryFinished(); + return; + } + QStringList serviceName; + + if (characteristicProperty.isError()) + qDebug()<lowEnergyServiceDiscovered(gattService); + emit gattService.d_ptr->finished(); + } + else{ + OrgBluezCharacteristicInterface *characteristicProperties = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattCharacteristics.at(0), QDBusConnection::systemBus()); + QDBusPendingReply characteristicProperty = characteristicProperties->GetProperties(); + watcher = new QDBusPendingCallWatcher(characteristicProperty, this); + QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(_q_discoveredGattCharacteristic(QDBusPendingCallWatcher*))); + } + +} +*/ + QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamReader &xml) { if (xml.name() == QLatin1String("boolean")) { diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h index 0691b490..b4281530 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h @@ -46,13 +46,16 @@ #include "qbluetoothdeviceinfo.h" #include "qbluetoothserviceinfo.h" #include "qbluetoothservicediscoveryagent.h" +#include "qlowenergyserviceinfo.h" #include +#include #ifdef QT_BLUEZ_BLUETOOTH class OrgBluezManagerInterface; class OrgBluezAdapterInterface; class OrgBluezDeviceInterface; +class OrgBluezCharacteristicInterface; QT_BEGIN_NAMESPACE class QDBusPendingCallWatcher; class QXmlStreamReader; @@ -102,7 +105,6 @@ public: void setDiscoveryMode(QBluetoothServiceDiscoveryAgent::DiscoveryMode m) { mode = m; } QBluetoothServiceDiscoveryAgent::DiscoveryMode DiscoveryMode() { return mode; } - // private slots void _q_deviceDiscoveryFinished(); void _q_deviceDiscovered(const QBluetoothDeviceInfo &info); void _q_serviceDiscoveryFinished(); @@ -110,6 +112,12 @@ public: #ifdef QT_BLUEZ_BLUETOOTH void _q_discoveredServices(QDBusPendingCallWatcher *watcher); void _q_createdDevice(QDBusPendingCallWatcher *watcher); + //Slots below are used for discovering Bluetooth Low Energy devices. It will be used with Bluez 5.x version. + /* + void _g_discoveredGattService(); + void _q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher); + void _q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher); + */ #endif private: @@ -135,6 +143,7 @@ private: QSocketNotifier *rdNotifier; QTimer m_queryTimer; bool m_btInitialized; + bool m_serviceScanDone; #endif public: @@ -153,12 +162,16 @@ private: QBluetoothServiceDiscoveryAgent::DiscoveryMode mode; bool singleDevice; - #ifdef QT_BLUEZ_BLUETOOTH OrgBluezManagerInterface *manager; OrgBluezAdapterInterface *adapter; OrgBluezDeviceInterface *device; QBluetoothAddress m_deviceAdapterAddress; + //Varibles below are used for discovering Bluetooth Low Energy devices + OrgBluezCharacteristicInterface *characteristic; + QStringList gattServices; + QStringList gattCharacteristics; + QLowEnergyCharacteristicInfo gattCharacteristic; #endif protected: diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp index 319e631f..442c30e8 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_qnx.cpp @@ -45,16 +45,22 @@ #include "qbluetoothdeviceinfo.h" #include "qbluetoothdevicediscoveryagent.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyserviceinfo_p.h" + #include #include "qbluetoothuuid.h" - +#include +#include #include #ifdef QT_QNX_BT_BLUETOOTH #include #include #endif - #include +#include +#include +#include #include @@ -194,35 +200,36 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr else _q_serviceDiscoveryFinished(); #else - qBBBluetoothDebug() << "Starting Service discovery for" << address.toString(); - const char *filePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(address.toString().toUtf8().constData()).constData(); - if ((m_rdfd = qt_safe_open(filePath, O_RDONLY)) == -1) { - if (QFile::exists(QLatin1String(filePath) + QLatin1String("-00")) || - QFile::exists(QLatin1String(filePath) + QLatin1String("-01"))) { - qBBBluetoothDebug() << "LE device discovered...skipping"; - } else { - qWarning() << "Failed to open " << filePath; - error = QBluetoothServiceDiscoveryAgent::InputOutputError; - errorString = QStringLiteral("Failed to open remote device file"); - q->error(error); + QString devicePath = address.toString(); + const char *filePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData(); + if ( (m_rdfd = qt_safe_open(filePath, O_RDONLY)) == -1) { + devicePath = address.toString() + "-00"; + const char *lowEnergyPublicPath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData(); + if ((m_rdfd = qt_safe_open(lowEnergyPublicPath, O_RDONLY)) == -1) { + devicePath = address.toString() + "-01";qDebug() << "teessttt inside 01"; + const char *lowEnergyPrivatePath = QByteArray("/pps/services/bluetooth/remote_devices/").append(devicePath.toUtf8().constData()).constData(); + if ((m_rdfd = qt_safe_open(lowEnergyPrivatePath, O_RDONLY)) == -1) { + qWarning() << "Failed to open " << filePath; + error = QBluetoothServiceDiscoveryAgent::InputOutputError; + errorString = QStringLiteral("Failed to open remote device file"); + q->error(error); + } } + } + if (rdNotifier) + delete rdNotifier; + rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this); + if (rdNotifier) { + connect(rdNotifier, SIGNAL(activated(int)), this, SLOT(remoteDevicesChanged(int))); + } else { + qWarning() << "Service Discovery: Failed to connect to rdNotifier"; + error = QBluetoothServiceDiscoveryAgent::InputOutputError; + errorString = QStringLiteral("Failed to connect to rdNotifier"); + q->error(error); _q_serviceDiscoveryFinished(); return; - } else { - if (rdNotifier) - delete rdNotifier; - rdNotifier = new QSocketNotifier(m_rdfd, QSocketNotifier::Read, this); - if (rdNotifier) { - connect(rdNotifier, SIGNAL(activated(int)), this, SLOT(remoteDevicesChanged(int))); - } else { - qWarning() << "Service Discovery: Failed to connect to rdNotifier"; - error = QBluetoothServiceDiscoveryAgent::InputOutputError; - errorString = QStringLiteral("Failed to connect to rdNotifier"); - q->error(error); - _q_serviceDiscoveryFinished(); - return; - } } + m_queryTimer.start(10000); ppsSendControlMessage("service_query", QStringLiteral("{\"addr\":\"%1\"}").arg(address.toString()), this); #endif @@ -325,7 +332,35 @@ void QBluetoothServiceDiscoveryAgentPrivate::remoteDevicesChanged(int fd) } } + pps_decoder_push(&ppsDecoder, "gatt_available_services"); + + for (int service_count=0; pps_decoder_get_string(&ppsDecoder, 0, &next_service ) == PPS_DECODER_OK; service_count++) { + if (next_service == 0) + break; + + QString lowEnergyUuid(next_service); + lowEnergyUuid = QStringLiteral("0x") + lowEnergyUuid; + qBBBluetoothDebug() << "LE Service: " << lowEnergyUuid << next_service; + QBluetoothUuid leUuid; + + //In case of UUIDs that are id development phase (e.g. Texas Instruments SenstorTag LE Device) + if ( lowEnergyUuid.toUShort(0, 0) == 0 && lowEnergyUuid.contains("000000000000") ) { + lowEnergyUuid = lowEnergyUuid.remove(0,2); + leUuid = QBluetoothUuid(lowEnergyUuid); + } + else + leUuid = QBluetoothUuid(lowEnergyUuid.toUShort(0,0)); + + QLowEnergyServiceInfo lowEnergyService(leUuid); + lowEnergyService.setDevice(discoveredDevices.at(0)); + qBBBluetoothDebug() << "Adding Low Energy service" << lowEnergyService.uuid(); + q_ptr->serviceDiscovered(lowEnergyService); + } + pps_decoder_cleanup(&ppsDecoder); + //Deleting notifier since services will not change. + delete rdNotifier; + rdNotifier = 0; } void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result) @@ -338,6 +373,8 @@ void QBluetoothServiceDiscoveryAgentPrivate::controlReply(ppsResult result) if (!result.errorMsg.isEmpty()) { qWarning() << Q_FUNC_INFO << result.errorMsg; errorString = result.errorMsg; + if (errorString == QObject::tr("Operation canceled")) + _q_serviceDiscoveryFinished(); error = QBluetoothServiceDiscoveryAgent::InputOutputError; q->error(error); } else { diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp index fcf5a5f7..9bb8ef67 100644 --- a/src/bluetooth/qbluetoothuuid.cpp +++ b/src/bluetooth/qbluetoothuuid.cpp @@ -106,40 +106,40 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34 This enum is a convienience type for Bluetooth service class UUIDs. Values of this type will be implicitly converted into a QBluetoothUuid when necessary. - \value PublicBrowseGroup Public browse group service class. Services which have the public + \value PublicBrowseGroup Public browse group service class. Services which have the public browse group in their \l {QBluetoothServiceInfo::BrowseGroupList}{browse group list} are discoverable by the remote devices. - \value ObexObjectPush OBEX object push service UUID. + \value ObexObjectPush OBEX object push service UUID. \value ServiceDiscoveryServer - \value BrowseGroupDescriptor Browser group descriptor - \value SerialPort Serial Port Profile UUID - \value LANAccessUsingPPP LAN Access Profile UUID - \value DialupNetworking Dial-up Networking Profile UUID - \value IrMCSync Synchronization Profile UUID - \value OBEXFileTransfer File Transfer Profile (FTP) UUID - \value IrMCSyncCommand Synchronization Profile UUID - \value Headset Headset Profile (HSP) UUID - \value AudioSource Advanced Audio Distribution Profile (A2DP) UUID - \value AudioSink Advanced Audio Distribution Profile (A2DP) UUID - \value AV_RemoteControlTarget Audio/Video Remote Control Profile (AVRCP) UUID - \value AdvancedAudioDistribution Advanced Audio Distribution Profile (A2DP) UUID - \value AV_RemoteControl Audio/Video Remote Control Profile (AVRCP) UUID + \value BrowseGroupDescriptor Browser group descriptor + \value SerialPort Serial Port Profile UUID + \value LANAccessUsingPPP LAN Access Profile UUID + \value DialupNetworking Dial-up Networking Profile UUID + \value IrMCSync Synchronization Profile UUID + \value OBEXFileTransfer File Transfer Profile (FTP) UUID + \value IrMCSyncCommand Synchronization Profile UUID + \value Headset Headset Profile (HSP) UUID + \value AudioSource Advanced Audio Distribution Profile (A2DP) UUID + \value AudioSink Advanced Audio Distribution Profile (A2DP) UUID + \value AV_RemoteControlTarget Audio/Video Remote Control Profile (AVRCP) UUID + \value AdvancedAudioDistribution Advanced Audio Distribution Profile (A2DP) UUID + \value AV_RemoteControl Audio/Video Remote Control Profile (AVRCP) UUID \value AV_RemoteControlController Audio/Video Remote Control Profile UUID - \value HeadsetAG Headset Profile (HSP) UUID - \value PANU Personal Area Networking Profile (PAN) UUID - \value NAP Personal Area Networking Profile (PAN) UUID - \value GN Personal Area Networking Profile (PAN) UUID - \value DirectPrinting Basic Printing Profile (BPP) UUID - \value ReferencePrinting Related to Basic Printing Profile (BPP) UUID - \value ImagingResponder Basic Imaging Profile (BIP) UUID - \value ImagingAutomaticArchive Basic Imaging Profile (BIP) UUID - \value ImagingReferenceObjects Basic Imaging Profile (BIP) UUID - \value Handsfree Hands-Free Profile (HFP) Service Class Identifier and Profile Identifier - \value HandsfreeAudioGateway Hands-free Profile (HFP) UUID + \value HeadsetAG Headset Profile (HSP) UUID + \value PANU Personal Area Networking Profile (PAN) UUID + \value NAP Personal Area Networking Profile (PAN) UUID + \value GN Personal Area Networking Profile (PAN) UUID + \value DirectPrinting Basic Printing Profile (BPP) UUID + \value ReferencePrinting Related to Basic Printing Profile (BPP) UUID + \value ImagingResponder Basic Imaging Profile (BIP) UUID + \value ImagingAutomaticArchive Basic Imaging Profile (BIP) UUID + \value ImagingReferenceObjects Basic Imaging Profile (BIP) UUID + \value Handsfree Hands-Free Profile (HFP) Service Class Identifier and Profile Identifier + \value HandsfreeAudioGateway Hands-free Profile (HFP) UUID \value DirectPrintingReferenceObjectsService Basic Printing Profile (BPP) UUID - \value ReflectedUI Basic Printing Profile (BPP) UUID - \value BasicPrinting Basic Printing Profile (BPP) UUID - \value PrintingStatus Basic Printing Profile (BPP) UUID + \value ReflectedUI Basic Printing Profile (BPP) UUID + \value BasicPrinting Basic Printing Profile (BPP) UUID + \value PrintingStatus Basic Printing Profile (BPP) UUID \value HumanInterfaceDeviceService Human Interface Device (HID) UUID \value HardcopyCableReplacement Hardcopy Cable Replacement Profile (HCRP) \value HCRPrint Hardcopy Cable Replacement Profile (HCRP) @@ -165,6 +165,246 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34 \value HDPSink Health Device Profile \sa QBluetoothServiceInfo::ServiceClassIds + + \value HardcopyCableReplacement Hardcopy Cable Replacement Profile (HCRP) + \value HCRPrint Hardcopy Cable Replacement Profile (HCRP) + \value HCRScan Hardcopy Cable Replacement Profile (HCRP) + \value SIMAccess SIM Access Profile (SAP) UUID + \value PhonebookAccessPCE Phonebook Access Profile (PBAP) UUID + \value PhonebookAccessPSE Phonebook Access Profile (PBAP) UUID + \value PhonebookAccess Phonebook Access Profile (PBAP) + \value HeadsetHS Headset Profile (HSP) UUID + \value MessageAccessServer Message Access Profile (MAP) UUID + \value MessageNotificationServer Message Access Profile (MAP) UUID + \value MessageAccessProfile Message Access Profile (MAP) UUID + \value PnPInformation Device Identification (DID) UUID + \value GenericNetworking Generic networking + \value GenericFileTransfer Generic file transfer + \value GenericAudio Generic audio + \value GenericTelephony Generic telephone + \value VideoSource Video Distribution Profile (VDP) + \value VideoSink Video Distribution Profile (VDP) + \value VideoDistribution Video Distribution Profile (VDP) + \value HDP Health Device Profile + \value HDPSource Health Device Profile + \value HDPSink Health Device Profile + \value AlertNotificationService The Alert Notification service exposes alert information on a device. + \value BatteryService The Battery Service exposes the state of a battery within a device. + \value BloodPressure This service exposes blood pressure and other data from a blood pressure + monitor intended for healthcare applications. + \value CurrentTimeService This service defines how the current time can be exposed using + the Generic Attribute Profile (GATT). + \value CyclingPower This service exposes power- and force-related data and + optionally speed- and cadence-related data from a Cycling Power + sensor intended for sports and fitness applications. + \value CyclingSpeedAndCadence This service exposes speed-related and cadence-related data from + a Cycling Speed and Cadence sensor intended for fitness applications. + \value DeviceInformation The Device Information Service exposes manufacturer and/or vendor + information about a device. + \value GenericAccess The generic_access service contains generic information about the device. + All available Characteristics are readonly. + \value GenericAttribute + \value Glucose This service exposes glucose and other data from a glucose sensor for use + in consumer and professional healthcare applications. + \value HealthThermometer The Health Thermometer service exposes temperature and other data from + a thermometer intended for healthcare and fitness applications. + \value HeartRate This service exposes heart rate and other data from a Heart Rate Sensor + intended for fitness applications. + \value HumanInterfaceDevice This service exposes the HID reports and other HID data intended for + HID Hosts and HID Devices. + \value ImmediateAlert This service exposes a control point to allow a peer device to cause + the device to immediately alert. + \value LinkLoss This service defines behavior when a link is lost between two devices. + \value LocationAndNavigation This service exposes location and navigation-related data from + a Location and Navigation sensor intended for outdoor activity applications. + \value NextDSTChangeService This service defines how the information about an upcoming DST change can be + exposed using the Generic Attribute Profile (GATT). + \value PhoneAlertStatusService This service dexposes the phone alert status when in a connection. + \value ReferenceTimeUpdateService This service defines how a client can request an update from a reference + time source from a time server using the Generic Attribute Profile (GATT) + \value RunningSpeedAndCadence This service exposes speed, cadence and other data from a Running Speed and + Cadence Sensor intended for fitness applications. + \value ScanParameters The Scan Parameters Service enables a GATT Server device to expose a characteristic + for the GATT Client to write its scan interval and scan window on the GATT Server device. + \value TxPower This service exposes a device’s current transmit power level when in a connection +*/ + +/*! + \enum QBluetoothUuid::CharacteristicId + + This enum is a convienience type for Bluetooth low energy service characteristics class UUIDs. Values of this type + will be implicitly converted into a QBluetoothUuid when necessary. + + \value AlertCategoryID Categories of alerts/messages. + \value AlertCategoryIDBitMask Categories of alerts/messages. + \value AlertLevel The level of an alert a device is to sound. + If this level is changed while the alert is being sounded, + the new level should take effect. + \value AlertNotificationControlPoint Control point of the Alert Notification server. + Client can write the command here to request the several + functions toward the server. + \value AlertStatus The Alert Status characteristic defines the Status of alert. + \value Appearance The external appearance of this device. The values are composed + of a category (10-bits) and sub-categories (6-bits). + \value BatteryLevel The current charge level of a battery. 100% represents fully charged + while 0% represents fully discharged. + \value BloodPressureFeature The Blood Pressure Feature characteristic is used to describe the supported + features of the Blood Pressure Sensor. + \value BloodPressureMeasurement The Blood Pressure Measurement characteristic is a variable length structure + containing a Flags field, a Blood Pressure Measurement Compound Value field, + and contains additional fields such as Time Stamp, Pulse Rate and User ID + as determined by the contents of the Flags field. + \value BodySensorLocation + \value BootKeyboardInputReport The Boot Keyboard Input Report characteristic is used to transfer fixed format + and length Input Report data between a HID Host operating in Boot Protocol Mode + and a HID Service corresponding to a boot keyboard. + \value BootKeyboardOutputReport The Boot Keyboard Output Report characteristic is used to transfer fixed format + and length Output Report data between a HID Host operating in Boot Protocol Mode + and a HID Service corresponding to a boot keyboard. + \value BootMouseInputReport The Boot Mouse Input Report characteristic is used to transfer fixed format and + length Input Report data between a HID Host operating in Boot Protocol Mode and + a HID Service corresponding to a boot mouse. + \value CSCFeature The CSC (Cycling Speed and Cadence) Feature characteristic is used to describe + the supported features of the Server. + \value CSCMeasurement The CSC Measurement characteristic (CSC refers to Cycling Speed and Cadence) + is a variable length structure containing a Flags field and, based on the contents + of the Flags field, may contain one or more additional fields as shown in the tables + below. + \value CurrentTime + \value CyclingPowerControlPoint The Cycling Power Control Point characteristic is used to request a specific function + to be executed on the receiving device. + \value CyclingPowerFeature The CP Feature characteristic is used to report a list of features supported by + the device. + \value CyclingPowerMeasurement The Cycling Power Measurement characteristic is a variable length structure containing + a Flags field, an Instantaneous Power field and, based on the contents of the Flags + field, may contain one or more additional fields as shown in the table below. + \value CyclingPowerVector The Cycling Power Vector characteristic is a variable length structure containing + a Flags fieldand based on the contents of the Flags field, may contain one or more + additional fields as shown in the table below. + \value DateTime The Date Time characteristic is used to represent time. + \value DayDateTime + \value DayOfWeek + \value DeviceName + \value DSTOffset + \value ExactTime256 + \value FirmwareRevisionString The value of this characteristic is a UTF-8 string representing the firmware revision + for the firmware within the device. + \value GlucoseFeature The Glucose Feature characteristic is used to describe the supported features + of the Server. When read, the Glucose Feature characteristic returns a value + that is used by a Client to determine the supported features of the Server. + \value GlucoseMeasurement The Glucose Measurement characteristic is a variable length structure containing + a Flags field, a Sequence Number field, a Base Time field and, based upon the contents + of the Flags field, may contain a Time Offset field, Glucose Concentration field, + Type-Sample Location field and a Sensor Status Annunciation field. + \value GlucoseMeasurementContext + \value HardwareRevisionString The value of this characteristic is a UTF-8 string representing the hardware revision + for the hardware within the device. + \value HeartRateControlPoint + \value HeartRateMeasurement + \value HIDControlPoint The HID Control Point characteristic is a control-point attribute that defines the + HID Commands when written. + \value HIDInformation The HID Information Characteristic returns the HID attributes when read. + \value IEEE1107320601RegulatoryCertificationDataList The value of the characteristic is an opaque structure listing + various regulatory and/or certification compliance items to which the device + claims adherence. + \value IntermediateCuffPressure This characteristic has the same format as the Blood Pressure Measurement + characteristic. + \value IntermediateTemperature The Intermediate Temperature characteristic has the same format as the + Temperature Measurement characteristic + \value LNControlPoint The LN Control Point characteristic is used to request a specific function + to be executed on the receiving device. + \value LNFeature The LN Feature characteristic is used to report a list of features supported + by the device. + \value LocalTimeInformation + \value LocationAndSpeed The Location and Speed characteristic is a variable length structure containing + a Flags field and, based on the contents of the Flags field, may contain a combination + of data fields. + \value ManufacturerNameString The value of this characteristic is a UTF-8 string representing the name of the + manufacturer of the device. + \value MeasurementInterval The Measurement Interval characteristic defines the time between measurements. + \value ModelNumberString The value of this characteristic is a UTF-8 string representing the model number + assigned by the device vendor. + \value Navigation The Navigation characteristic is a variable length structure containing a Flags field, + a Bearing field, a Heading field and, based on the contents of the Flags field. + \value NewAlert This characteristic defines the category of the alert and how many new alerts of + that category have occurred in the server device. + \value PeripheralPreferredConnectionParameters + \value PeripheralPrivacyFlag + \value PnPID The PnP_ID characteristic returns its value when read using the GATT Characteristic + Value Read procedure. + \value PositionQuality The Position Quality characteristic is a variable length structure containing a + Flags field and at least one of the optional data + \value ProtocolMode The Protocol Mode characteristic is used to expose the current protocol mode of + the HID Service with which it is associated, or to set the desired protocol + mode of the HID Service. + \value ReconnectionAddress The Information included in this page is informative. The normative descriptions + are contained in the applicable specification. + \value RecordAccessControlPoint This control point is used with a service to provide basic management functionality + for the Glucose Sensor patient record database. + \value ReferenceTimeInformation + \value Report The Report characteristic is used to exchange data between a HID Device and a HID Host. + \value ReportMap Only a single instance of this characteristic exists as part of a HID Service. + \value RingerControlPoint The Ringer Control Point characteristic defines the Control Point of Ringer. + \value RingerSetting The Ringer Setting characteristic defines the Setting of the Ringer. + \value RSCFeature The RSC (Running Speed and Cadence) Feature characteristic is used to describe the + supported features of the Server. + \value RSCMeasurement RSC refers to Running Speed and Cadence. + \value SCControlPoint The SC Control Point characteristic is used to request a specific function to be + executed on the receiving device. + \value ScanIntervalWindow The Scan Interval Window characteristic is used to store the scan parameters of + the GATT Client. + \value ScanRefresh The Scan Refresh characteristic is used to notify the Client that the Server + requires the Scan Interval Window characteristic to be written with the latest + values upon notification. + \value SensorLocation The Sensor Location characteristic is used to expose the location of the sensor. + \value SerialNumberString The value of this characteristic is a variable-length UTF-8 string representing + the serial number for a particular instance of the device. + \value ServiceChanged + \value SoftwareRevisionString The value of this characteristic is a UTF-8 string representing the software + revision for the software within the device. + \value SupportedNewAlertCategory Category that the server supports for new alert. + \value SupportedUnreadAlertCategory Category that the server supports for unread alert. + \value SystemID If the system ID is based of a Bluetooth Device Address with a Company Identifier + (OUI) is 0x123456 and the Company Assigned Identifier is 0x9ABCDE, then the System + Identifier is required to be 0x123456FFFE9ABCDE. + \value TemperatureMeasurement The Temperature Measurement characteristic is a variable length structure containing + a Flags field, a Temperature Measurement Value field and, based upon the contents of + the Flags field, optionally a Time Stamp field and/or a Temperature Type field. + \value TemperatureType The Temperature Type characteristic is an enumeration that indicates where the + temperature was measured. + \value TimeAccuracy + \value TimeSource + \value TimeUpdateControlPoint + \value TimeUpdateState + \value TimeWithDST + \value TimeZone + \value TxPowerLevel The value of the characteristic is a signed 8 bit integer that has a fixed point + exponent of 0. + \value UnreadAlertStatus This characteristic shows how many numbers of unread alerts exist in the specific + category in the device. +*/ + +/*! + \enum QBluetoothUuid::DescriptorID + + This enum is a convienience type for Bluetooth low energy service descriptor class UUIDs. Values of this type + will be implicitly converted into a QBluetoothUuid when necessary. + + \value CharacteristicExtendedProperties Descriptor defines additional Characteristic Properties. + \value CharacteristicUserDescription Descriptor provides a textual user description for a characteristic value. + \value ClientCharacteristicConfiguration Descriptor defines how the characteristic may be configured by a specific client. + \value ServerCharacteristicConfiguration Descriptor defines how the characteristic descriptor is associated with may be + configured for the server. + \value CharacteristicPresentationFormat Descriptor defines the format of the Characteristic Value. + \value CharacteristicAggregateFormat Descriptor defines the format of an aggregated Characteristic Value. + \value ValidRange descriptor is used for defining the range of a characteristics. + Two mandatory fields are contained (upper and lower bounds) which define the range. + \value ExternalReportReference Allows a HID Host to map information from the Report Map characteristic value for + Input Report, Output Report or Feature Report data to the Characteristic UUID of + external service characteristics used to transfer the associated data. + \value ReportReference Mapping information in the form of a Report ID and Report Type which maps the + current parent characteristic to the Report ID(s) and Report Type (s) defined + within the Report Map characteristic. */ /*! @@ -195,6 +435,16 @@ QBluetoothUuid::QBluetoothUuid(ServiceClassUuid uuid) { } +/*! + Constructs a new Bluetooth UUID from the characteristic id \a uuid. +*/ +QBluetoothUuid::QBluetoothUuid(CharacteristicId uuid) +: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1], + baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5], + baseUuid()->data4[6], baseUuid()->data4[7]) +{ +} + /*! Constructs a new Bluetooth UUID from the 16 bit \a uuid. */ diff --git a/src/bluetooth/qbluetoothuuid.h b/src/bluetooth/qbluetoothuuid.h index ef69e983..cec11533 100644 --- a/src/bluetooth/qbluetoothuuid.h +++ b/src/bluetooth/qbluetoothuuid.h @@ -143,12 +143,132 @@ public: VideoDistribution = 0x1305, HDP = 0x1400, HDPSource = 0x1401, - HDPSink = 0x1402 + HDPSink = 0x1402, + GenericAccess = 0x1800, + GenericAttribute = 0x1801, + ImmediateAlert = 0x1802, + LinkLoss = 0x1803, + TxPower = 0x1804, + CurrentTimeService = 0x1805, + ReferenceTimeUpdateService = 0x1806, + NextDSTChangeService = 0x1807, + Glucose = 0x1808, + HealthThermometer = 0x1809, + DeviceInformation = 0x180a, + HeartRate = 0x180d, + PhoneAlertStatusService = 0x180e, + BatteryService = 0x180f, + BloodPressure = 0x1810, + AlertNotificationService = 0x1811, + HumanInterfaceDevice = 0x1812, + ScanParameters = 0x1813, + RunningSpeedAndCadence = 0x1814, + CyclingSpeedAndCadence = 0x1816, + CyclingPower = 0x1818, + LocationAndNavigation = 0x1819, + TISimpleKeyService = 0xffe0 + }; + + enum CharacteristicId { + AlertCategoryID = 0x2a43, + AlertCategoryIDBitMask = 0x2a42, + AlertLevel = 0x2a06, + AlertNotificationControlPoint = 0x2a44, + AlertStatus = 0x2a3f, + Appearance = 0x2a01, + BatteryLevel = 0x2a19, + BloodPressureFeature = 0x2a49, + BloodPressureMeasurement = 0x2a35, + BodySensorLocation = 0x2a38, + BootKeyboardInputReport = 0x2a22, + BootKeyboardOutputReport = 0x2a32, + BootMouseInputReport = 0x2a33, + CSCFeature = 0x2a5c, + CSCMeasurement = 0x2a5b, + CurrentTime = 0x2a2b, + CyclingPowerControlPoint = 0x2a66, + CyclingPowerFeature = 0x2a65, + CyclingPowerMeasurement = 0x2a63, + CyclingPowerVector = 0x2a64, + DateTime = 0x2a08, + DayDateTime = 0x2a0a, + DayOfWeek = 0x2a09, + DeviceName = 0x2a00, + DSTOffset = 0x2a0d, + ExactTime256 = 0x2a0c, + FirmwareRevisionString = 0x2a26, + GlucoseFeature = 0x2a51, + GlucoseMeasurement = 0x2a18, + GlucoseMeasurementContext = 0x2a34, + HardwareRevisionString = 0x2a27, + HeartRateControlPoint = 0x2a39, + HeartRateMeasurement = 0x2a37, + HIDControlPoint = 0x2a4c, + HIDInformation = 0x2a4a, + IEEE1107320601RegulatoryCertificationDataList = 0x2a2a, + IntermediateCuffPressure = 0x2a36, + IntermediateTemperature = 0x2a1e, + LNControlPoint = 0x2a6b, + LNFeature = 0x2a6a, + LocalTimeInformation = 0x2a0f, + LocationAndSpeed = 0x2a67, + ManufacturerNameString = 0x2a29, + MeasurementInterval = 0x2a21, + ModelNumberString = 0x2a24, + Navigation = 0x2a68, + NewAlert = 0x2a46, + PeripheralPreferredConnectionParameters = 0x2a04, + PeripheralPrivacyFlag = 0x2a02, + PnPID = 0x2a50, + PositionQuality = 0x2a69, + ProtocolMode = 0x2a4e, + ReconnectionAddress = 0x2a03, + RecordAccessControlPoint = 0x2a52, + ReferenceTimeInformation = 0x2a14, + Report = 0x2a4d, + ReportMap = 0x2a4b, + RingerControlPoint = 0x2a40, + RingerSetting = 0x2a41, + RSCFeature = 0x2a54, + RSCMeasurement = 0x2a53, + SCControlPoint = 0x2a55, + ScanIntervalWindow = 0x2a4f, + ScanRefresh = 0x2a31, + SensorLocation = 0x2a5d, + SerialNumberString = 0x2a25, + ServiceChanged = 0x2a05, + SoftwareRevisionString = 0x2a28, + SupportedNewAlertCategory = 0x2a47, + SupportedUnreadAlertCategory = 0x2a48, + SystemID = 0x2a23, + TemperatureMeasurement = 0x2a1c, + TemperatureType = 0x2a1d, + TimeAccuracy = 0x2a12, + TimeSource = 0x2a13, + TimeUpdateControlPoint = 0x2a16, + TimeUpdateState = 0x2a17, + TimeWithDST = 0x2a11, + TimeZone = 0x2a0e, + TxPowerLevel = 0x2a07, + UnreadAlertStatus = 0x2a45 + }; + + enum DescriptorID { + CharacteristicExtendedProperties = 0x2900, + CharacteristicUserDescription = 0x2901, + ClientCharacteristicConfiguration = 0x2902, + ServerCharacteristicConfiguration = 0x2903, + CharacteristicPresentationFormat = 0x2904, + CharacteristicAggregateFormat = 0x2905, + ValidRange = 0x2906, + ExternalReportReference = 0x2907, + ReportReference = 0x2908 }; QBluetoothUuid(); QBluetoothUuid(ProtocolUuid uuid); QBluetoothUuid(ServiceClassUuid uuid); + QBluetoothUuid(CharacteristicId uuid); explicit QBluetoothUuid(quint16 uuid); explicit QBluetoothUuid(quint32 uuid); explicit QBluetoothUuid(quint128 uuid); diff --git a/src/bluetooth/qlowenergycharacteristicinfo.cpp b/src/bluetooth/qlowenergycharacteristicinfo.cpp new file mode 100644 index 00000000..765791ed --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include + +QT_BEGIN_NAMESPACE + +/*! + \enum QLowEnergyCharacteristicInfo::Error + + This enum describes the type of an error that can appear. + + \value NotificationFail Could not subscribe or could not get notifications from wanted characteristic. + \value NotConnected GATT Service is not connected. + \value UnknownError Unknown error. +*/ + +/*! + \enum QLowEnergyCharacteristicInfo::Property + + This enum describes the properties of a characteristic. + + \value Broadcasting Allow for the broadcasting of Generic Attributes (GATT) characteristic values. + \value Read Allow the characteristic values to be read. + \value WriteNoResponse Allow characteristic values without responses to be written. + \value Write Allow for characteristic values to be written. + \value Notify Permits notification of characteristic values. + \value Indicate Permits indications of characteristic values. + \value WriteSigned Permits signed writes of the GATT characteristic values. + \value ExtendedProperty Additional characteristic properties are defined in the characteristic + extended properties descriptor. +*/ + +/*! + Method for parsing the characteristic name with given \a uuid. + * \brief parseUuid + * \param uuid + * \return + */ +QString parseUuid(QBluetoothUuid uuid) { + static QHash uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x2a43] = QStringLiteral("Alert Category ID"); + uuidnames[0x2A42] = QStringLiteral("Alert Category ID Bit Mask"); + uuidnames[0x2A06] = QStringLiteral("Alert Level"); + uuidnames[0x2A44] = QStringLiteral("Alert Notification Control Point"); + uuidnames[0x2A3F] = QStringLiteral("Alert Status"); + uuidnames[0x2A01] = QStringLiteral("GAP Appearance"); + uuidnames[0x2A19] = QStringLiteral("Battery Level"); + uuidnames[0x2A49] = QStringLiteral("Blood Pressure Feature"); + uuidnames[0x2A35] = QStringLiteral("Blood Pressure Measurement"); + uuidnames[0x2A38] = QStringLiteral("Body Sensor Location"); + uuidnames[0x2A22] = QStringLiteral("Boot Keyboard Input Report"); + uuidnames[0x2A32] = QStringLiteral("Boot Keyboard Output Report"); + uuidnames[0x2A33] = QStringLiteral("Boot Mouse Input Report"); + uuidnames[0x2A2B] = QStringLiteral("Current Time"); + uuidnames[0x2A08] = QStringLiteral("Date Time"); + uuidnames[0x2A0A] = QStringLiteral("Day Date Time"); + uuidnames[0x2A09] = QStringLiteral("Day of Week"); + uuidnames[0x2A00] = QStringLiteral("GAP Device Name"); + uuidnames[0x2A0D] = QStringLiteral("DST Offset"); + uuidnames[0x2A0C] = QStringLiteral("Exact Time 256"); + uuidnames[0x2A26] = QStringLiteral("Firmware Revision String"); + uuidnames[0x2A51] = QStringLiteral("Glucose Feature"); + uuidnames[0x2A18] = QStringLiteral("Glucose Measurement"); + uuidnames[0x2A34] = QStringLiteral("Glucose Measurement Context"); + uuidnames[0x2A27] = QStringLiteral("Hardware Revision String"); + uuidnames[0x2A39] = QStringLiteral("Heart Rate Control Point"); + uuidnames[0x2A37] = QStringLiteral("Heart Rate Measurement"); + uuidnames[0x2A4C] = QStringLiteral("HID Control Point"); + uuidnames[0x2A4A] = QStringLiteral("HID Information"); + uuidnames[0x2A2A] = QStringLiteral("IEEE 11073 20601 Regulatory Certification Data List"); + uuidnames[0x2A36] = QStringLiteral("Intermediate Blood Pressure"); + uuidnames[0x2A1E] = QStringLiteral("Iintermediate Temperature"); + uuidnames[0x2A0F] = QStringLiteral("Local Time Information"); + uuidnames[0x2A29] = QStringLiteral("Manufacturer Name String"); + uuidnames[0x2A21] = QStringLiteral("Measurement Interval"); + uuidnames[0x2A24] = QStringLiteral("Model Number String"); + uuidnames[0x2A46] = QStringLiteral("New Alert"); + uuidnames[0x2A04] = QStringLiteral("GAP Peripheral Preferred Connection Parameters"); + uuidnames[0x2A02] = QStringLiteral("GAP Peripheral Privacy Flag"); + uuidnames[0x2A50] = QStringLiteral("PNP ID"); + uuidnames[0x2A4E] = QStringLiteral("Protocol Mode"); + uuidnames[0x2A03] = QStringLiteral("GAP Reconnection Address"); + uuidnames[0x2A52] = QStringLiteral("Record Access Control Point"); + uuidnames[0x2A14] = QStringLiteral("Reference Time Information"); + uuidnames[0x2A4D] = QStringLiteral("Report"); + uuidnames[0x2A4B] = QStringLiteral("Report Map"); + uuidnames[0x2A40] = QStringLiteral("Ringer Control Point"); + uuidnames[0x2A41] = QStringLiteral("Ringer Setting"); + uuidnames[0x2A4F] = QStringLiteral("Scan Interval Window"); + uuidnames[0x2A31] = QStringLiteral("Scan Refresh"); + uuidnames[0x2A25] = QStringLiteral("Serial Number String"); + uuidnames[0x2A05] = QStringLiteral("GATT Service Changed"); + uuidnames[0x2A28] = QStringLiteral("Software Revision String"); + uuidnames[0x2A47] = QStringLiteral("Supported New Alert Category"); + uuidnames[0x2A48] = QStringLiteral("Supported Unread Alert Category"); + uuidnames[0x2A23] = QStringLiteral("System ID"); + uuidnames[0x2A1C] = QStringLiteral("Temperature Measurement"); + uuidnames[0x2A1D] = QStringLiteral("Temperature Type"); + uuidnames[0x2A12] = QStringLiteral("Time Accuracy"); + uuidnames[0x2A13] = QStringLiteral("Time Source"); + uuidnames[0x2A16] = QStringLiteral("Time Update Control Point"); + uuidnames[0x2A17] = QStringLiteral("Time Update State"); + uuidnames[0x2A11] = QStringLiteral("Time With DST"); + uuidnames[0x2A0E] = QStringLiteral("Time Zone"); + uuidnames[0x2A07] = QStringLiteral("TX Power"); + uuidnames[0x2A45] = QStringLiteral("Unread Alert Status"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknown Characteristic")); + return name; + +} + +/*! + Construct a new QLowEnergyCharacteristicInfo. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(): + d_ptr(new QLowEnergyCharacteristicInfoPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + Construct a new QLowEnergyCharacteristicInfo with given \a uuid. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(const QBluetoothUuid &uuid): + d_ptr(new QLowEnergyCharacteristicInfoPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->uuid = uuid; +} + +/*! + Construct a new QLowEnergyCharacteristicInfo that is a copy of \a other. + + The two copies continue to share the same underlying data which does not detach + upon write. +*/ +QLowEnergyCharacteristicInfo::QLowEnergyCharacteristicInfo(const QLowEnergyCharacteristicInfo &other): + d_ptr(other.d_ptr) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys the QLowEnergyCharacteristicInfo object. +*/ +QLowEnergyCharacteristicInfo::~QLowEnergyCharacteristicInfo() +{ + +} + +/*! + Returns the name of the gatt characteristic. +*/ +QString QLowEnergyCharacteristicInfo::name() const +{ + d_ptr->name = parseUuid(d_ptr->uuid); + return d_ptr->name; +} + +/*! + Returns the UUID of the gatt characteristic. +*/ +QBluetoothUuid QLowEnergyCharacteristicInfo::uuid() const +{ + return d_ptr->uuid; +} + +/*! + Returns the properties value of the gatt characteristic. +*/ +QVariantMap QLowEnergyCharacteristicInfo::properties() const +{ + return d_ptr->properties; +} + +/*! + Returns permissions of the gatt characteristic. +*/ +int QLowEnergyCharacteristicInfo::permissions() const +{ + return d_ptr->permission; +} + +/*! + Returns value of the gatt characteristic. +*/ +QByteArray QLowEnergyCharacteristicInfo::value() const +{ + return d_ptr->value; +} + +/*! + Returns the handle of the gatt characteristic. +*/ +QString QLowEnergyCharacteristicInfo::handle() const +{ + return d_ptr->handle; +} + +/*! + Returns the true or false statement depending whether the characteristic is notification + (enables conctant updates when value is changed on LE device). +*/ +bool QLowEnergyCharacteristicInfo::isNotificationCharacteristic() const +{ + return d_ptr->notification; +} + +/*! + Writes the value \a value directly to LE device. + + \sa setValue() +*/ +void QLowEnergyCharacteristicInfo::writeValue(const QByteArray &value) +{ + d_ptr->setValue(value); +} + +/*! + Makes a copy of the \a other and assigns it to this QLowEnergyCharacteristicInfo object. + The two copies continue to share the same service and registration details. +*/ +QLowEnergyCharacteristicInfo &QLowEnergyCharacteristicInfo::operator=(const QLowEnergyCharacteristicInfo &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +/*! + Returns true if the QLowEnergyCharacteristicInfo object is valid, otherwise returns false. + If it returns false, it means that service that this characteristic belongs was not connected. +*/ +bool QLowEnergyCharacteristicInfo::isValid() const +{ + if (d_ptr->uuid == QBluetoothUuid()) + return false; + if (d_ptr->handle.toUShort(0,0) == 0) + return false; + if (!d_ptr->valid()) + return false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo.h b/src/bluetooth/qlowenergycharacteristicinfo.h new file mode 100644 index 00000000..b7a5b662 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo.h @@ -0,0 +1,111 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGATTCHARACTERISTICINFO_H +#define QGATTCHARACTERISTICINFO_H +#include "qbluetoothuuid.h" +#include "qlowenergydescriptorinfo.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyCharacteristicInfoPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyCharacteristicInfo +{ + Q_DECLARE_PRIVATE(QLowEnergyCharacteristicInfo) + friend class QLowEnergyServiceInfo; + friend class QLowEnergyServiceInfoPrivate; + friend class QLowEnergyController; + friend class QLowEnergyControllerPrivate; +public: + + enum Error { + NotificationFail = 0x001, + NotConnected = 0x002, + UnknownError = 0x003 + }; + + enum Property { + Broadcasting = 0x01, + Read = 0x02, + WriteNoResponse = 0x04, + Write = 0x08, + Notify = 0x10, + Indicate = 0x20, + WriteSigned = 0x40, + ExtendedProperty = 0x80 + }; + + QLowEnergyCharacteristicInfo(); + QLowEnergyCharacteristicInfo(const QBluetoothUuid &uuid); + QLowEnergyCharacteristicInfo(const QLowEnergyCharacteristicInfo &other); + ~QLowEnergyCharacteristicInfo(); + + QLowEnergyCharacteristicInfo &operator=(const QLowEnergyCharacteristicInfo &other); + + QString name() const; + + QBluetoothUuid uuid() const; + + void writeValue(const QByteArray &value); + QByteArray value() const; + + int permissions() const; + QVariantMap properties() const; + QString handle() const; + + bool isNotificationCharacteristic() const; + + QList getDescriptors() const; + + bool isValid() const; + +protected: + QSharedPointer d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QGATTCHARACTERISTICINFO_H diff --git a/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp new file mode 100644 index 00000000..49f18610 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_bluez.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "bluez/characteristic_p.h" +#include "qlowenergyprocess_p.h" + +#include + +#define QT_LOWENERGYCHARACTERISTIC_DEBUG + +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG +#include +#endif + +QT_BEGIN_NAMESPACE + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate(): + value (QByteArray()), permission(0), notification (false), handle(QStringLiteral("0x0000")), properties(QVariantMap()), characteristic(0), m_signalConnected(false) +{ + process = process->instance(); + t=0; +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + delete characteristic; +} + +void QLowEnergyCharacteristicInfoPrivate::replyReceived(const QString &reply) +{ + QStringList update, row; + update = QStringList(); + row = QStringList(); + if (reply.contains(QStringLiteral("[CON]"))) { +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG + qDebug() << "Char connected" << t; +#endif + } + if (reply.contains(QStringLiteral("[CON]")) && t == 1) { + QString command = QStringLiteral("char-read-hnd ") + handle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + t++; + } + if (reply.contains(QStringLiteral("Notification handle"))) { + update = reply.split(QStringLiteral("\n")); +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG + qDebug() << update.size(); +#endif + for (int i = 0; i< update.size(); i ++) { + if (update.at(i).contains(QStringLiteral("Notification handle"))) { + row = update.at(i).split(QRegularExpression("\\W+"), QString::SkipEmptyParts); +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG + qDebug() << "Handle : "<< handle << row; +#endif + if (row.at(2) == handle) { + + QString notificationValue = QStringLiteral(""); + for (int j = 4 ; j< row.size(); j++) + notificationValue += row.at(j); +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG + qDebug() << notificationValue; +#endif + value = notificationValue.toUtf8(); + properties[QStringLiteral("value")] = value; + emit notifyValue(uuid); + } + } + + } + } + + if (reply.contains(QStringLiteral("Characteristic value/descriptor:"))) { + update = reply.split(QStringLiteral("\n")); + for (int i = 0; i< update.size(); i ++) { + if (update.at(i).contains(QStringLiteral("Characteristic value/descriptor:"))) { + row = update.at(i).split(QRegularExpression("\\W+"), QString::SkipEmptyParts); + QString val = QStringLiteral(""); + for ( int j = 3; jinstance(); + if (!m_signalConnected) { + connect(process, SIGNAL(replySend(const QString &)), this, SLOT(replyReceived(const QString &))); + m_signalConnected = true; + } + value = wantedValue; + QString command; + if (notification == true) + command = QStringLiteral("char-write-req ") + notificationHandle + QStringLiteral(" ") + QString(value.constData()); + else + command = QStringLiteral("char-write-req ") + handle + QStringLiteral(" ") + QString(value.constData()); + + +#ifdef QT_LOWENERGYCHARACTERISTIC_DEBUG + qDebug() << command << t << process; +#endif + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + + t++; + +} + +void QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + /* + * Wanted value to enable notifications is 0100 + */ + QByteArray val; + val.append(48); + val.append(49); + val.append(48); + val.append(48); + setValue(val); +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + /* + * Wanted value to disable notifications is 0000 + */ + QByteArray val; + val.append(48); + val.append(48); + val.append(48); + val.append(48); + setValue(val); +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + QString command = QStringLiteral("char-read-hnd ") + handle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo_p.cpp b/src/bluetooth/qlowenergycharacteristicinfo_p.cpp new file mode 100644 index 00000000..741aa8e6 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo_p.h" + +QT_BEGIN_NAMESPACE + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate() +{ + +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::propertyChanged(QString valueName, QDBusVariant value) +{ + Q_UNUSED(valueName); + Q_UNUSED(value); +} + +void QLowEnergyCharacteristicInfoPrivate::setValue(const QByteArray &wantedValue) +{ + Q_UNUSED(wantedValue); +} + +void QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + return false; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycharacteristicinfo_p.h b/src/bluetooth/qlowenergycharacteristicinfo_p.h new file mode 100644 index 00000000..0a0891c1 --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_p.h @@ -0,0 +1,122 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCHARACTERISTICINFO_P_H +#define QLOWENERGYCHARACTERISTICINFO_P_H +#include "qbluetoothuuid.h" +#include "qlowenergycharacteristicinfo.h" + +#ifdef QT_BLUEZ_BLUETOOTH +#include +#include +#endif +#ifdef QT_QNX_BLUETOOTH +#include +#include +#include +#include +#endif +#ifdef QT_BLUEZ_BLUETOOTH +class OrgBluezCharacteristicInterface; +class QLowEnergyProcess; +#endif + +QT_BEGIN_NAMESPACE +class QBluetoothUuid; +class QLowEnergyCharacteristicInfo; + +class QLowEnergyCharacteristicInfoPrivate: public QObject +{ + Q_OBJECT + Q_DECLARE_PUBLIC(QLowEnergyCharacteristicInfo) +public: + QLowEnergyCharacteristicInfoPrivate(); + ~QLowEnergyCharacteristicInfoPrivate(); + + void setValue(const QByteArray &wantedValue); + void readValue(); + bool valid(); + void enableNotification(); + void disableNotification(); + void readDescriptors(); + + QString name; + QBluetoothUuid uuid; + QByteArray value; + int permission; + bool notification; + QString handle; + QString notificationHandle; + int instance; + QVariantMap properties; + QList descriptorsList; +#ifdef QT_QNX_BLUETOOTH + bt_gatt_characteristic_t characteristic; + int characteristicMtu; + bt_gatt_char_prop_mask characteristicProperties; + static void serviceNotification(int, short unsigned int, const unsigned char*, short unsigned int, void *); +#endif +#ifdef QT_BLUEZ_BLUETOOTH + QString path; + int t; + QString startingHandle; +public Q_SLOTS: + + void replyReceived(const QString &reply); +#endif + +Q_SIGNALS: + void notifyValue(const QBluetoothUuid &); + +private: +#ifdef QT_BLUEZ_BLUETOOTH + OrgBluezCharacteristicInterface *characteristic; + QLowEnergyProcess *process; + bool m_signalConnected; +#endif + + +protected: + QLowEnergyCharacteristicInfo *q_ptr; +}; +QT_END_NAMESPACE + +#endif // QLOWENERGYCHARACTERISTICINFO_P_H diff --git a/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp new file mode 100644 index 00000000..add2f13d --- /dev/null +++ b/src/bluetooth/qlowenergycharacteristicinfo_qnx.cpp @@ -0,0 +1,318 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycharacteristicinfo_p.h" +#include +#include +#include +#include +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergydescriptorinfo_p.h" +#include "qnx/ppshelpers_p.h" + + +QT_BEGIN_NAMESPACE + +int hexValue(char inChar) +{ + if (isxdigit(inChar)) { + if (isdigit(inChar)) { + return (inChar - '0'); + } else { + return (toupper(inChar) - 'A' + 10); + } + } else { + return -1; + } +} + +int stringToBuffer(const QString &stringData, uint8_t *buffer, int bufferLength) +{ + int consumed = 0; + for (int i = 0; i < bufferLength; i++) { + const int hex = hexValue(stringData.at(i).toLatin1()); + if (hex >= 0) { + if ((consumed % 2) == 0) { + buffer[(consumed / 2)] = hex << 4; + } else { + buffer[(consumed / 2)] |= hex; + } + + consumed++; + } + } + + // Round up the number of bytes we consumed to a multiple of 2. + if ((consumed % 2) != 0) + ++consumed; + + return consumed; +} + +QLowEnergyCharacteristicInfoPrivate::QLowEnergyCharacteristicInfoPrivate(): + name(QString()), value(QByteArray()), permission(0), instance(-1), properties(QVariantMap()), handle(QStringLiteral("0x0000")) +{ + +} + +QLowEnergyCharacteristicInfoPrivate::~QLowEnergyCharacteristicInfoPrivate() +{ + +} + +void QLowEnergyCharacteristicInfoPrivate::serviceNotification(int instance, short unsigned int handle, const unsigned char*val, short unsigned int len, void *userData) +{ + if (val == 0) + return; + QPointer *ClassPointer = static_cast *>(userData); + QLowEnergyServiceInfoPrivate *p = ClassPointer->data(); + qBBBluetoothDebug() << "---------------------------------------------------"; + qBBBluetoothDebug() << "[Notification] received (service uuid, handle, value, instance):" << p->uuid << handle << val << instance; + qBBBluetoothDebug() << "---------------------------------------------------"; + //Check if the notification from wanted characteristic + bool current = false; + QLowEnergyCharacteristicInfo chars; + for (int i = 0; i < p->characteristicList.size(); i++) { + QString charHandle; + charHandle.setNum(handle); + charHandle = charHandle; + if (charHandle == ((QLowEnergyCharacteristicInfo)p->characteristicList.at(i)).handle() ) { + chars = QLowEnergyCharacteristicInfo((QLowEnergyCharacteristicInfo)p->characteristicList.at(i)); + QByteArray receivedValue; + + for (int j = 0; j < len; j++) { + QString hexadecimal; + hexadecimal.setNum(val[j], 16); + receivedValue.append(hexadecimal.toLatin1()); + } + + p->characteristicList.at(i).d_ptr->setValue(receivedValue); + current = true; + } + } + + if (!current) + qBBBluetoothDebug() << "Notificiation received and does not belong to this characteristic."; +} + +void QLowEnergyCharacteristicInfoPrivate::enableNotification() +{ + if (instance == -1) { + qBBBluetoothDebug() << " GATT service not connected "; + //q_ptr->error(QLowEnergyCharacteristicInfo::NotConnected); + return; + } + if ( (permission & QLowEnergyCharacteristicInfo::Notify) == 0) { + qBBBluetoothDebug() << "Notification changes not allowed"; + return; + } + + int rc = bt_gatt_enable_notify(instance, &characteristic, 1); + if (rc != 0) { + qBBBluetoothDebug() << "bt_gatt_enable_notify errno=" << errno << strerror(errno); + //emit q_ptr->error(QLowEnergyCharacteristicInfo::NotificationFail); + return; + } else + qBBBluetoothDebug() << "bt_gatt_enable_notify was presumably OK"; +} + +void QLowEnergyCharacteristicInfoPrivate::setValue(const QByteArray &wantedValue) +{ + if (permission & QLowEnergyCharacteristicInfo::Write) { + const int characteristicLen = wantedValue.size(); + uint8_t *characteristicBuffer = (uint8_t *)alloca(characteristicLen / 2 + 1); + if (!characteristicBuffer) { + qBBBluetoothDebug() << "GATT characteristic: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + const int consumed = stringToBuffer(QString::fromLocal8Bit(wantedValue), characteristicBuffer, characteristicLen); + + if (consumed > 0) { + int byteCount; + byteCount = bt_gatt_write_value(instance, handle.toUShort(), 0, characteristicBuffer, (consumed / 2)); + + if (byteCount < 0) { + qBBBluetoothDebug() << "Unable to write characteristic value: " << errno << strerror(errno); + } + } + } + value = wantedValue; + properties[QStringLiteral("value")] = value; + emit notifyValue(uuid); + +} + +void QLowEnergyCharacteristicInfoPrivate::disableNotification() +{ + int rc = bt_gatt_enable_notify(instance, &characteristic, 0); + if (rc != 0) + qBBBluetoothDebug() << "bt_gatt_enable_notify errno=" << errno << strerror(errno); + else + qBBBluetoothDebug() << "bt_gatt_enable_notify was presumably OK"; + +} + +void QLowEnergyCharacteristicInfoPrivate::readDescriptors() +{ + descriptorsList.clear(); + int count = bt_gatt_descriptors_count(instance, &characteristic); + + if (count == -1) { + qWarning() << "GATT descriptors count failed:" << errno << "(" << strerror(errno) << ")"; + bt_gatt_disconnect_instance(instance); + return; + } + + bt_gatt_descriptor_t *descriptorList = 0; + if (count > 0) { + descriptorList = (bt_gatt_descriptor_t*)alloca(count * sizeof(bt_gatt_descriptor_t)); + if (!descriptorList) { + qBBBluetoothDebug() <<"GATT descriptors: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + /* BEGIN WORKAROUND - Temporary fix to address race condition */ + int number = 0; + do { + number = bt_gatt_descriptors(instance, &characteristic, descriptorList, count); + } while ((number == -1) && (errno == EBUSY)); + + count = number; + /* END WORKAROUND */ + } + + if (count == -1) { + qBBBluetoothDebug() << "GATT descriptors failed: %1 (%2)" << errno << strerror(errno); + bt_gatt_disconnect_instance(instance); + return; + } + + characteristicMtu = bt_gatt_get_mtu(instance); + + uint8_t *descriptorBuffer = (uint8_t *)alloca(characteristicMtu); + if (!descriptorBuffer) { + qBBBluetoothDebug() <<"GATT descriptors: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + for (int i = 0; i < count; i++) { + QVariantMap map; + + map[QStringLiteral("uuid")] = QString::fromLatin1(descriptorList[i].uuid); + + map[QStringLiteral("handle")] = descriptorList[i].handle; + QString descHanlde; + descHanlde.setNum(descriptorList[i].handle); + QString descriptorUuid(descriptorList[i].uuid); + QBluetoothUuid descUuid(descriptorUuid); + QLowEnergyDescriptorInfo descriptor(descUuid, descHanlde); + + uint8_t more = 1; + int byteCount; + for (int offset = 0; more; offset += byteCount) { + byteCount = bt_gatt_read_value(instance, descriptorList[i].handle, offset, descriptorBuffer, characteristicMtu, &more); + if (byteCount < 0) { + qBBBluetoothDebug() << "Unable to read descriptor value:"<< errno<< strerror(errno); + break; + } + descriptor.d_ptr->m_value = QByteArray(); + for (int j = 0; j < byteCount; j++) { + QString hexadecimal; + hexadecimal.setNum(descriptorBuffer[j], 16); + descriptor.d_ptr->m_value.append(hexadecimal.toLatin1()); + } + + } + + map[QStringLiteral("value")] = descriptor.d_ptr->m_value; + descriptor.d_ptr->m_properties = map; + descriptorsList.append(descriptor); + + } +} + +void QLowEnergyCharacteristicInfoPrivate::readValue() +{ + if ((permission & QLowEnergyCharacteristicInfo::Read) == 0) { + qBBBluetoothDebug() << "GATT characteristic: Read not permitted"; + return; + } + + uint8_t *characteristicBuffer = (uint8_t *)alloca(characteristicMtu); + if (!characteristicBuffer) { + qBBBluetoothDebug() << "GATT characteristic: Not enough memory"; + bt_gatt_disconnect_instance(instance); + return; + } + + QString descriptorString; + + int byteCount = 0; + uint8_t more = 1; + for (int offset = 0; more; offset += byteCount) { + byteCount = bt_gatt_read_value(instance, handle.toUShort(), offset, characteristicBuffer, characteristicMtu, &more); + if (byteCount < 0) { + qBBBluetoothDebug() << "Unable to read characteristic value: " << errno << strerror(errno); + break; + } + value = QByteArray(); + for (int j = 0; j < byteCount; j++) { + QString hexadecimal; + hexadecimal.setNum(characteristicBuffer[j], 16); + value.append(hexadecimal.toLatin1()); + } + properties["value"] = value; + } +} + +bool QLowEnergyCharacteristicInfoPrivate::valid() +{ + if (instance == -1) + return false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp new file mode 100644 index 00000000..abba8edc --- /dev/null +++ b/src/bluetooth/qlowenergycontroller.cpp @@ -0,0 +1,282 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergycontroller.h" +#include "qlowenergycontroller_p.h" +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "moc_qlowenergycontroller.cpp" + +QT_BEGIN_NAMESPACE +/*! + \class QLowEnergyController + \inmodule QtBluetooth + \brief The QLowEnergyController class is used for connecting and reading data from LE device + services. + + To read data contained in LE service characteristics, the LE device must be paired and turned on. + First, connect necessary signals from the class and then connect to service by passing the wanted service + to \l connectoToService() function. \l connected() signal will be emitted on success or \l error() + signal in case of failure. It is possible to get error message by calling errorString function + in QLowEnergyServiceInfo class. + + In case of disconnecting from service, pass the wanted service to \l disconnectFromService() + function and \l disconnected signal will be emitted. + + It is enough to use one instance of this class to connect to more service on more devices, + but it is not possible to create more QLowEnergyController classes and connect to same + service on the same LE device. + + + \sa QLowEnergyServiceInfo, QLowEnergyCharacteristicInfo +*/ + +/*! + \fn void QLowEnergyController::connected(const QLowEnergyServiceInfo &) + + This signal is emitted when a LE service is connected, passing connected QLowEnergyServiceInfo + instance. + + \sa connectToService(const QLowEnergyServiceInfo &leService) +*/ + +/*! + \fn void QLowEnergyController::error(const QLowEnergyServiceInfo &) + + This signal is emitted when an error occurs. + + \sa QLowEnergyServiceInfo::errorString() +*/ + +/*! + \fn void QLowEnergyController::disconnected(const QLowEnergyServiceInfo &) + + Emits disconnected signal with disconnected LE service. +*/ + +/*! + \fn QLowEnergyController::valueChanged(const QLowEnergyCharacteristicInfo &) + + Emits a signal when the characteristic value is changed. This signal is emitted + after calling \l enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) + function. + + \sa enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +*/ + +QLowEnergyControllerPrivate::QLowEnergyControllerPrivate() +{ + +} + +QLowEnergyControllerPrivate::~QLowEnergyControllerPrivate() +{ + +} + +void QLowEnergyControllerPrivate::_q_serviceConnected(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).uuid() == uuid) + emit q_ptr->connected((QLowEnergyServiceInfo)m_leServices.at(i)); + + } +} + +void QLowEnergyControllerPrivate::_q_serviceError(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).uuid() == uuid) + emit q_ptr->error((QLowEnergyServiceInfo)m_leServices.at(i)); + } +} + + +void QLowEnergyControllerPrivate::_q_valueReceived(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + QList characteristics = m_leServices.at(i).getCharacteristics(); + for (int j = 0; j < characteristics.size(); j++) { + if (characteristics.at(j).uuid() == uuid) + emit q_ptr->valueChanged(characteristics.at(j)); + } + } +} + + + +void QLowEnergyControllerPrivate::_q_serviceDisconnected(const QBluetoothUuid &uuid) +{ + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).uuid() == uuid) { + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(connectedToService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceConnected(QBluetoothUuid))); + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(error(QBluetoothUuid)), q_ptr, SLOT(_q_serviceError(QBluetoothUuid))); + QObject::disconnect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(disconnectedFromService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceDisconnected(QBluetoothUuid))); + emit q_ptr->disconnected((QLowEnergyServiceInfo)m_leServices.at(i)); + } + } +} + +void QLowEnergyControllerPrivate::connectService(const QLowEnergyServiceInfo &service) +{ + bool in = false; + if (service.isValid()) { + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).uuid() == service.uuid() && !((QLowEnergyServiceInfo)m_leServices.at(i)).isConnected()) { + in = true; + QObject::connect(m_leServices.at(i).d_ptr.data(), SIGNAL(connectedToService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceConnected(QBluetoothUuid))); + QObject::connect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(error(QBluetoothUuid)), q_ptr, SLOT(_q_serviceError(QBluetoothUuid))); + QObject::connect(((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr.data(), SIGNAL(disconnectedFromService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceDisconnected(QBluetoothUuid))); + ((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr->registerServiceWatcher(); + break; + } + } + if (!in) { + m_leServices.append(service); + QObject::connect(((QLowEnergyServiceInfo)m_leServices.last()).d_ptr.data(), SIGNAL(connectedToService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceConnected(QBluetoothUuid))); + QObject::connect(((QLowEnergyServiceInfo)m_leServices.last()).d_ptr.data(), SIGNAL(error(QBluetoothUuid)), q_ptr, SLOT(_q_serviceError(QBluetoothUuid))); + QObject::connect(((QLowEnergyServiceInfo)m_leServices.last()).d_ptr.data(), SIGNAL(disconnectedFromService(QBluetoothUuid)), q_ptr, SLOT(_q_serviceDisconnected(QBluetoothUuid))); + ((QLowEnergyServiceInfo)m_leServices.last()).d_ptr->registerServiceWatcher(); + } + } +} + +void QLowEnergyControllerPrivate::disconnectService(const QLowEnergyServiceInfo &service) +{ + if (service.isValid()) { + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).uuid() == service.uuid() && service.isConnected()) { + ((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr->unregisterServiceWatcher(); + break; + } + } + } + else { + for (int i = 0; i < m_leServices.size(); i++) { + if (((QLowEnergyServiceInfo)m_leServices.at(i)).isConnected()) { + ((QLowEnergyServiceInfo)m_leServices.at(i)).d_ptr->unregisterServiceWatcher(); + break; + } + } + } +} + +/*! + Construct a new QLowEnergyInfo object with the \a parent. +*/ +QLowEnergyController::QLowEnergyController(QObject *parent): + QObject(parent), d_ptr(new QLowEnergyControllerPrivate) +{ + d_ptr->q_ptr = this; +} + +QLowEnergyController::~QLowEnergyController() +{ + +} + +/*! + Returns the list of all Bluetooth LE Services that were added. +*/ +QList QLowEnergyController::services() const +{ + return d_ptr->m_leServices; +} + +/*! + Connects to the given \a leService. If the given service is not valid, or if + the given service is already connected, nothing will happen. + +*/ +void QLowEnergyController::connectToService(const QLowEnergyServiceInfo &leService) +{ + d_ptr->connectService(leService); +} + + +/*! + Disconnects the given \a leService. If the given service was not connected, nothing will be done. + + If the \a leService is not passed or it is invalid, all connected services will be disconnected. + +*/ +void QLowEnergyController::disconnectFromService(const QLowEnergyServiceInfo &leService) +{ + d_ptr->disconnectService(leService); +} + + +/*! + Enables receiving notifications from the given \a characteristic. If the service characteristic + does not belong to one of the services, nothing wil lbe done. + + \sa addLeService +*/ +void QLowEnergyController::enableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +{ + for (int i = 0; i < d_ptr->m_leServices.size(); i++) { + for (int j = 0; j < d_ptr->m_leServices.at(i).getCharacteristics().size(); j++) { + if (d_ptr->m_leServices.at(i).getCharacteristics().at(j).uuid() == characteristic.uuid()) { + connect(d_ptr->m_leServices.at(i).getCharacteristics().at(j).d_ptr.data(), SIGNAL(notifyValue(QBluetoothUuid)), this, SLOT(_q_valueReceived(QBluetoothUuid))); + d_ptr->m_leServices.at(i).getCharacteristics().at(j).d_ptr->enableNotification(); + } + } + } +} + +/*! + Disables receiving notifications from the given \a characteristic. If the service characteristic + does not belong to one of the services, nothing wil lbe done. + + \sa addLeService +*/ +void QLowEnergyController::disableNotifications(const QLowEnergyCharacteristicInfo &characteristic) +{ + for (int i = 0; i < d_ptr->m_leServices.size(); i++) { + for (int j = 0; j < d_ptr->m_leServices.at(i).getCharacteristics().size(); j++) { + if (d_ptr->m_leServices.at(i).getCharacteristics().at(j).uuid() == characteristic.uuid()){ + disconnect(d_ptr->m_leServices.at(i).getCharacteristics().at(j).d_ptr.data(), SIGNAL(notifyValue(QBluetoothUuid)), this, SLOT(_q_valueReceived(QBluetoothUuid))); + d_ptr->m_leServices.at(i).getCharacteristics().at(j).d_ptr->disableNotification(); + } + } + } +} +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h new file mode 100644 index 00000000..bfdfe25c --- /dev/null +++ b/src/bluetooth/qlowenergycontroller.h @@ -0,0 +1,88 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCONTROLLER_H +#define QLOWENERGYCONTROLLER_H +#include + +#include +#include "qlowenergyserviceinfo.h" +#include "qlowenergycharacteristicinfo.h" +#include "qbluetoothaddress.h" + + +QT_BEGIN_NAMESPACE + +class QLowEnergyControllerPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyController: public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QLowEnergyController) +public: + QLowEnergyController(QObject *parent = 0); + ~QLowEnergyController(); + QList services() const; + void connectToService(const QLowEnergyServiceInfo &leService); + void disconnectFromService(const QLowEnergyServiceInfo &leService = QLowEnergyServiceInfo()); + void enableNotifications(const QLowEnergyCharacteristicInfo &characteristic); + void disableNotifications(const QLowEnergyCharacteristicInfo &characteristic); + +Q_SIGNALS: + void connected(const QLowEnergyServiceInfo &); + void error(const QLowEnergyServiceInfo &); + void disconnected(const QLowEnergyServiceInfo &); + void valueChanged(const QLowEnergyCharacteristicInfo &); + + + +private: + QLowEnergyControllerPrivate *d_ptr; + + Q_PRIVATE_SLOT(d_func(), void _q_serviceConnected(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceError(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_valueReceived(const QBluetoothUuid &uuid)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDisconnected(const QBluetoothUuid &uuid)) +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYCONTROLLER_H diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h new file mode 100644 index 00000000..96ec3730 --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QLOWENERGYCONTROLLER_P_H +#define QLOWENERGYCONTROLLER_P_H +#include "qlowenergycontroller.h" +QT_BEGIN_NAMESPACE + +class QLowEnergyController; + +class QLowEnergyControllerPrivate +{ + Q_DECLARE_PUBLIC(QLowEnergyController) +public: + QLowEnergyControllerPrivate(); + ~QLowEnergyControllerPrivate(); + void connectService(const QLowEnergyServiceInfo &service); + void disconnectService(const QLowEnergyServiceInfo &leService = QLowEnergyServiceInfo()); + + void _q_serviceConnected(const QBluetoothUuid &uuid); + void _q_serviceError(const QBluetoothUuid &uuid); + void _q_valueReceived(const QBluetoothUuid &uuid); + void _q_serviceDisconnected(const QBluetoothUuid &uuid); + + QList m_leServices; + +private: + QLowEnergyController *q_ptr; +}; +QT_END_NAMESPACE +#endif // QLOWENERGYCONTROLLER_P_H diff --git a/src/bluetooth/qlowenergydescriptorinfo.cpp b/src/bluetooth/qlowenergydescriptorinfo.cpp new file mode 100644 index 00000000..763c3aaf --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_p.h" + +QT_BEGIN_NAMESPACE + +QString parseDescriptorUuid(const QBluetoothUuid &uuid) +{ + static QHash uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x2905] = QStringLiteral("Characteristic Aggregate Format"); + uuidnames[0x2900] = QStringLiteral("Characteristic Extended Properties"); + uuidnames[0x2904] = QStringLiteral("Characteristic Presentation Format"); + uuidnames[0x2901] = QStringLiteral("Characteristic User Description"); + uuidnames[0x2902] = QStringLiteral("Client Characteristic Configuration"); + uuidnames[0x2907] = QStringLiteral("External Report Reference"); + uuidnames[0x2908] = QStringLiteral("Report Reference"); + uuidnames[0x2903] = QStringLiteral("Server Characteristic Configuration"); + uuidnames[0x2906] = QStringLiteral("Valid Range"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknow Descriptor")); + return name; +} + +QLowEnergyDescriptorInfoPrivate::QLowEnergyDescriptorInfoPrivate(const QBluetoothUuid &uuid, const QString &handle): + m_uuid(uuid), m_handle(handle), m_value(QByteArray()) +{ + +} + +QLowEnergyDescriptorInfoPrivate::~QLowEnergyDescriptorInfoPrivate() +{ + +} + +/*! + Construct a new QLowEnergyDescriptorInfo with given \a uuid and the \a handle. +*/ +QLowEnergyDescriptorInfo::QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid, const QString &handle): + d_ptr(new QLowEnergyDescriptorInfoPrivate(uuid, handle)) +{ + d_ptr->m_name = parseDescriptorUuid(uuid); +} + +/*! + Destroys the QLowEnergyDescriptorInfo object. +*/ +QLowEnergyDescriptorInfo::~QLowEnergyDescriptorInfo() +{ + +} + +/*! + Returns the UUID of the descriptor. +*/ +QBluetoothUuid QLowEnergyDescriptorInfo::uuid() const +{ + return d_ptr->m_uuid; +} + +/*! + Returns the handle of the descriptor. +*/ +QString QLowEnergyDescriptorInfo::handle() const +{ + return d_ptr->m_handle; +} + +/*! + Returns the value of the descriptor. +*/ +QByteArray QLowEnergyDescriptorInfo::value() +{ + return d_ptr->m_value; +} + +/*! + Returns the properties of the descriptor. +*/ +QVariantMap QLowEnergyDescriptorInfo::properties() const +{ + return d_ptr->m_properties; +} + +/*! + Returns the name of the descriptor. +*/ +QString QLowEnergyDescriptorInfo::name() const +{ + return d_ptr->m_name; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergydescriptorinfo.h b/src/bluetooth/qlowenergydescriptorinfo.h new file mode 100644 index 00000000..e3ebc294 --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo.h @@ -0,0 +1,76 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYDESCRIPTORINFO_H +#define QLOWENERGYDESCRIPTORINFO_H + +#include "qbluetoothuuid.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyCharacteristicInfo; +class QLowEnergyDescriptorInfoPrivate; + +class Q_BLUETOOTH_EXPORT QLowEnergyDescriptorInfo +{ + friend class QLowEnergyCharacteristicInfo; + friend class QLowEnergyCharacteristicInfoPrivate; + friend class QLowEnergyServiceInfoPrivate; +public: + QLowEnergyDescriptorInfo(const QBluetoothUuid &uuid, const QString &handle); + ~QLowEnergyDescriptorInfo(); + QByteArray value(); + QBluetoothUuid uuid() const; + QString handle() const; + QVariantMap properties() const; + QString name() const; + +private: + QSharedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QLOWENERGYDESCRIPTORINFO_H diff --git a/src/bluetooth/qlowenergydescriptorinfo_p.h b/src/bluetooth/qlowenergydescriptorinfo_p.h new file mode 100644 index 00000000..e167859f --- /dev/null +++ b/src/bluetooth/qlowenergydescriptorinfo_p.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYDESCRIPTORINFO_P_H +#define QLOWENERGYDESCRIPTORINFO_P_H + +QT_BEGIN_NAMESPACE + +class QLowEnergyDescriptorInfoPrivate +{ +public: + QLowEnergyDescriptorInfoPrivate(const QBluetoothUuid &uuid, const QString &handle); + ~QLowEnergyDescriptorInfoPrivate(); + QByteArray m_value; + QBluetoothUuid m_uuid; + QString m_handle; + QVariantMap m_properties; + QString m_name; +}; +QT_END_NAMESPACE +#endif // QLOWENERGYDESCRIPTORINFO_P_H diff --git a/src/bluetooth/qlowenergyprocess_bluez.cpp b/src/bluetooth/qlowenergyprocess_bluez.cpp new file mode 100644 index 00000000..81a34266 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_bluez.cpp @@ -0,0 +1,143 @@ + +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" + +Q_GLOBAL_STATIC(QLowEnergyProcess, processInstance) + +/*! + * Private constructor. Constructs the new QLowEnergyProcess, sets variables and connects + * signal to a slot. + */ +QLowEnergyProcess::QLowEnergyProcess() +{ + m_process = new QProcess(); + connected = false; + m_counter = 0; + connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(replyRead())); +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + delete m_process; +} + +/*! + Returns the instance of this clas. This class is a singleton class. +*/ + +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return processInstance(); +} + +/*! + Returns the QProcess that this class is using. +*/ +QProcess *QLowEnergyProcess::getProcess() +{ + + return m_process; +} + +/*! + Slot that emits a signal replySend. This slot is connected with QProcess signal + and it is called whenever something comes to output. +*/ +void QLowEnergyProcess::replyRead() +{ + QByteArray result = m_process->readAll(); + QString back = QString(result.data()); + if (back.size() > 10) + emit replySend(back); +} + +/*! + Starts the process with \a command. This method is used only when starting the + process. + + \sa executeCommand() +*/ +void QLowEnergyProcess::startCommand(const QString &command) +{ + m_process->start(command); + if (!m_process->waitForStarted()) + qDebug() << "Could not start the process under the command: "<write(command.toUtf8().constData()); +} + +/*! + Terminate running process. +*/ +void QLowEnergyProcess::endProcess() +{ + m_counter--; + if (m_counter == 0) { + executeCommand(QStringLiteral("disconnect")); + executeCommand(QStringLiteral("\n")); + connected = false; + m_process->terminate(); + } +} + +bool QLowEnergyProcess::isConnected() const +{ + return connected; +} + +void QLowEnergyProcess::addConnection() +{ + m_counter++; + connected = true; +} diff --git a/src/bluetooth/qlowenergyprocess_p.cpp b/src/bluetooth/qlowenergyprocess_p.cpp new file mode 100644 index 00000000..3303bef0 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_p.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" + +QLowEnergyProcess::QLowEnergyProcess() +{ + +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + +} + +/*! + Returns the instance of this class. This class is a singleton class. +*/ +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return 0; +} + +bool QLowEnergyProcess::isConnected() const +{ + return false; +} diff --git a/src/bluetooth/qlowenergyprocess_p.h b/src/bluetooth/qlowenergyprocess_p.h new file mode 100644 index 00000000..3f65b1e7 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_p.h @@ -0,0 +1,98 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYPROCESS_H +#define QLOWENERGYPROCESS_H + +#include +#include +#ifdef QT_QNX_BLUETOOTH +#include +#include +#include "qlowenergyserviceinfo_p.h" +#endif +#ifdef QT_BLUEZ_BLUETOOTH +#include +#endif +QT_BEGIN_NAMESPACE + +class QLowEnergyProcess: public QObject +{ + Q_OBJECT + friend class QLowEnergyServiceInfoPrivate; +public: + QLowEnergyProcess(); + ~QLowEnergyProcess(); + + static QLowEnergyProcess *instance(); + bool isConnected() const; +#ifdef QT_QNX_BLUETOOTH + static void handleEvent(const int, const char *, const char *); + void addPointer(QLowEnergyServiceInfoPrivate* classPointer); +#endif +#ifdef QT_BLUEZ_BLUETOOTH + QProcess *getProcess(); + + void startCommand(const QString &command); + void executeCommand(const QString &command); + void endProcess(); + void addConnection(); + +Q_SIGNALS: + void replySend(const QString &reply); + +private slots: + void replyRead(); +#endif + +private: +#ifdef QT_BLUEZ_BLUETOOTH + QProcess *m_process; + int m_counter; +#endif +#ifdef QT_QNX_BLUETOOTH + QList m_classPointers; +#endif + bool connected; +}; +QT_END_NAMESPACE + +#endif // QLOWENERGYPROCESS_H diff --git a/src/bluetooth/qlowenergyprocess_qnx.cpp b/src/bluetooth/qlowenergyprocess_qnx.cpp new file mode 100644 index 00000000..04e9bc23 --- /dev/null +++ b/src/bluetooth/qlowenergyprocess_qnx.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyprocess_p.h" +#include +#include +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" +#include +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QLowEnergyProcess, processInstance) + +void QLowEnergyProcess::handleEvent(const int event, const char *bt_address, const char *event_data) +{ + qDebug() << "[HANDLE Event] (event, address, event data): " << event << bt_address << event_data; +} + +QLowEnergyProcess::QLowEnergyProcess() +{ + connected = false; + if (bt_device_init( &(this->handleEvent) ) < 0) + qDebug() << "[INIT] Init problem." << errno << strerror(errno); + else + connected = true; + +} + +/*! + Destroys the QLowEnergyProcess object. +*/ +QLowEnergyProcess::~QLowEnergyProcess() +{ + bt_device_deinit(); + bt_gatt_deinit(); + m_classPointers.clear(); +} + +/*! + Returns the instance of this clas. This class is a singleton class. +*/ + +QLowEnergyProcess *QLowEnergyProcess::instance() +{ + return processInstance(); +} + +bool QLowEnergyProcess::isConnected() const +{ + return connected; +} + +void QLowEnergyProcess::addPointer(QLowEnergyServiceInfoPrivate* classPointer) +{ + m_classPointers.append(classPointer); +} +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo.cpp b/src/bluetooth/qlowenergyserviceinfo.cpp new file mode 100644 index 00000000..92758da1 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo.cpp @@ -0,0 +1,263 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo.h" +#include "qlowenergyserviceinfo_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \enum QLowEnergyServiceInfo::ServiceType + + This enum describes the type of the service. One LE device can have one or more primary services. + + \value PrimaryService The primary service. The primary service can have one or + more included services. + \value IncludedService The included service by primary services. +*/ + +/*! + \enum QLowEnergyServiceInfo::Error + + This enum describes the type of an error that can appear. + + \value ConnectionRefused The connection to the service was refused. This can be caused if the device + got turned off or it has a random device address. To solve + the case if device has a random address on linux platform + setRandomAddress() method must be called before connecting. + \value DeviceBusy The device is already connected to another Bluetooth device. + \value InitializationFailed Could not initialize GATT callbacks. + \value MemoryAllocation Could not initialize memory needed for reading GATT characteristics. + \value DisconnectFail Could not disconnect from the service. + \value UnknownError Unknown error. +*/ + +/*! + Method for parsing the service name with given \a uuid. + * \brief parseUuid + * \param uuid + * \return + */ +QString parseUuid(const QBluetoothUuid &uuid) +{ + static QHash uuidnames; + if ( uuidnames.isEmpty() ) { + uuidnames[0x1800] = QStringLiteral("Generic Access"); + uuidnames[0x1801] = QStringLiteral("Generic Attribute"); + uuidnames[0x1802] = QStringLiteral("ImmediateAlert"); + uuidnames[0x1803] = QStringLiteral("Link Loss"); + uuidnames[0x1804] = QStringLiteral("Tx Power"); + uuidnames[0x1805] = QStringLiteral("Current Time Service"); + uuidnames[0x1806] = QStringLiteral("Reference Time Update Service"); + uuidnames[0x1807] = QStringLiteral("Next DST Change Service"); + uuidnames[0x1808] = QStringLiteral("Glucose"); + uuidnames[0x1809] = QStringLiteral("Health Thermometer"); + uuidnames[0x180A] = QStringLiteral("Device Information"); + uuidnames[0x180D] = QStringLiteral("Heart Rate"); + uuidnames[0x180E] = QStringLiteral("Phone Alert Status Service"); + uuidnames[0x180F] = QStringLiteral("Battery Service"); + uuidnames[0x1810] = QStringLiteral("Blood Pressure"); + uuidnames[0x1811] = QStringLiteral("Alert Notification Service"); + uuidnames[0x1812] = QStringLiteral("Human Interface Device"); + uuidnames[0x1813] = QStringLiteral("Scan Parameters"); + uuidnames[0x1814] = QStringLiteral("Running Speed and Cadance"); + uuidnames[0x1816] = QStringLiteral("Cycling Speed and Cadance"); + uuidnames[0x1818] = QStringLiteral("Cycling Power"); + uuidnames[0x1819] = QStringLiteral("Location and Navigation"); + } + QString name = uuidnames.value(uuid.toUInt16(), QStringLiteral("Unknow Service")); + return name; +} + +/*! + Construct a new QLowEnergyServiceInfo. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(): + d_ptr(QSharedPointer(new QLowEnergyServiceInfoPrivate)) +{ + d_ptr->q_ptr = this; +} + +/*! + Construct a new QLowEnergyServiceInfo object with the given \a uuid. + + Based on uuid, corresponsing service name is given. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(const QBluetoothUuid &uuid): + d_ptr(QSharedPointer(new QLowEnergyServiceInfoPrivate)) +{ + d_ptr->uuid = QBluetoothUuid(uuid); + d_ptr->q_ptr = this; + d_ptr->serviceName = parseUuid(d_ptr->uuid); +} + +/*! + Construct a new QLowEnergyServiceInfo that is a copy of \a other. + + The two copies continue to share the same underlying data which does not detach + upon write. +*/ +QLowEnergyServiceInfo::QLowEnergyServiceInfo(const QLowEnergyServiceInfo &other): + d_ptr(other.d_ptr) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys the QLowEnergyServiceInfo object. +*/ +QLowEnergyServiceInfo::~QLowEnergyServiceInfo() +{ + +} + +/*! + Returns the gatt service uuid. +*/ +QBluetoothUuid QLowEnergyServiceInfo::uuid() const +{ + return d_ptr->uuid; +} + +/*! + Returns the list of service characteristics. If service was not connected, an empty + list will be returned. +*/ +QList QLowEnergyServiceInfo::getCharacteristics() const +{ + return d_ptr->characteristicList; +} + +/*! + Returns the service name. +*/ +QString QLowEnergyServiceInfo::name() const +{ + return d_ptr->serviceName; +} + +/*! + Sets service type with \a type. +*/ +void QLowEnergyServiceInfo::setServiceType(QLowEnergyServiceInfo::ServiceType type) +{ + d_ptr->serviceType = type; +} + +/*! + Returns the service type. If setServiceType is not called default service type + (PrimaryService) is returned. +*/ +QLowEnergyServiceInfo::ServiceType QLowEnergyServiceInfo::getServiceType() const +{ + return d_ptr->serviceType; +} + +/*! + Makes a copy of the \a other and assigns it to this QLowEnergyServiceInfo object. + The two copies continue to share the same service and registration details. +*/ +QLowEnergyServiceInfo &QLowEnergyServiceInfo::operator=(const QLowEnergyServiceInfo &other) +{ + d_ptr = other.d_ptr; + d_ptr->q_ptr = this; + return *this; +} + +/*! + Checks whether service is connected. + */ +bool QLowEnergyServiceInfo::isConnected() const +{ + return d_ptr->connected; +} + +/*! + This method is called if a device has a random device address that is used for connecting. + It should be called before connecting to a service; otherwise connecting will not be + successful and ConnectionRefused error will be emitted. + */ +void QLowEnergyServiceInfo::setRandomAddress() +{ + d_ptr->randomAddress = true; +} + +/*! + Returns an error string if error occurred. + */ +QString QLowEnergyServiceInfo::errorString() const +{ + return d_ptr->errorString; +} + +/*! + Returns the address of the Bluetooth device that provides this service. +*/ +QBluetoothDeviceInfo QLowEnergyServiceInfo::device() const +{ + return d_ptr->deviceInfo; +} + +/*! + Sets the Bluetooth device that provides this service to \a device. +*/ +void QLowEnergyServiceInfo::setDevice(const QBluetoothDeviceInfo &device) +{ + d_ptr->deviceInfo = device; +} + +/*! + Returns true if the QLowEnergyServiceInfo object is valid, otherwise returns false. +*/ +bool QLowEnergyServiceInfo::isValid() const +{ + if (d_ptr->uuid == QBluetoothUuid()) + return false; + if (!d_ptr->deviceInfo.isValid()) + return false; + if (!d_ptr->valid()) + return false; + return true; +} + +QT_END_NAMESPACE + + diff --git a/src/bluetooth/qlowenergyserviceinfo.h b/src/bluetooth/qlowenergyserviceinfo.h new file mode 100644 index 00000000..deacf050 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo.h @@ -0,0 +1,114 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGATTSERVICEINFO_H +#define QGATTSERVICEINFO_H +#include "qbluetoothuuid.h" +#include "qlowenergycharacteristicinfo.h" +#include "qbluetoothdevicediscoveryagent.h" +#include "qbluetoothaddress.h" +#include + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyServiceInfoPrivate; +class QBluetoothAddress; +class QBluetoothDeviceInfo; + +class Q_BLUETOOTH_EXPORT QLowEnergyServiceInfo +{ + Q_DECLARE_PRIVATE(QLowEnergyServiceInfo) + friend class QBluetoothServiceDiscoveryAgent; + friend class QBluetoothServiceDiscoveryAgentPrivate; + friend class QLowEnergyController; + friend class QLowEnergyControllerPrivate; +public: + enum ServiceType { + PrimaryService = 0x00000001, + IncludedService = 0x00000002 + }; + + enum Error { + ConnectionRefused = 0x001, + DeviceBusy = 0x002, + InitializationFailed = 0x003, + MemoryAllocation = 0x004, + DisconnectFail = 0x005, + UnknownError = 0x006 + }; + + QLowEnergyServiceInfo(); + QLowEnergyServiceInfo(const QBluetoothUuid &uuid); + QLowEnergyServiceInfo(const QLowEnergyServiceInfo &other); + + ~QLowEnergyServiceInfo(); + + QLowEnergyServiceInfo &operator=(const QLowEnergyServiceInfo &other); + + void setDevice(const QBluetoothDeviceInfo &info); + QBluetoothDeviceInfo device() const; + + QBluetoothUuid uuid() const; + + QList getCharacteristics() const; + + QString name() const; + + void setServiceType(QLowEnergyServiceInfo::ServiceType type); + QLowEnergyServiceInfo::ServiceType getServiceType() const; + + void setRandomAddress(); + + bool isConnected() const; + + QString errorString() const; + + bool isValid() const; + +protected: + QSharedPointer d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QGATTSERVICEINFO_H diff --git a/src/bluetooth/qlowenergyserviceinfo_bluez.cpp b/src/bluetooth/qlowenergyserviceinfo_bluez.cpp new file mode 100644 index 00000000..bf7c1816 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_bluez.cpp @@ -0,0 +1,391 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergyserviceinfo.h" +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyprocess_p.h" +#include "qbluetoothlocaldevice.h" +#include "bluez/characteristic_p.h" +#include "qlowenergydescriptorinfo.h" +#include "qlowenergydescriptorinfo_p.h" + +//#define QT_LOWENERGYSERVICE_DEBUG + +#ifdef QT_LOWENERGYSERVICE_DEBUG +#include +#endif + +QT_BEGIN_NAMESPACE + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(): + serviceType(QLowEnergyServiceInfo::PrimaryService), connected(false), characteristic(0), m_valueCounter(0), m_readCounter(0) +{ + m_step = 0; + randomAddress = false; + QBluetoothLocalDevice localDevice; + adapterAddress = localDevice.address(); +} + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(const QString &servicePath): + serviceType(QLowEnergyServiceInfo::PrimaryService), connected(false), path(servicePath), characteristic(0) +{ + m_step = 0; + randomAddress = false; +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + delete characteristic; +} + +void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +{ + characteristicList.clear(); + process = process->instance(); + if (!process->isConnected()) { + connect(process, SIGNAL(replySend(const QString &)), this, SLOT(replyReceived(const QString &))); + QString command; + if (randomAddress) + command = QStringLiteral("gatttool -i ") + adapterAddress.toString() + QStringLiteral(" -b ") + deviceInfo.address().toString() +QStringLiteral(" -I -t random"); + else + command = QStringLiteral("gatttool -i ") + adapterAddress.toString() + QStringLiteral(" -b ") + deviceInfo.address().toString() + QStringLiteral(" -I"); +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "[REGISTER] uuid inside: " << uuid << command; +#endif + process->startCommand(command); + process->addConnection(); + } + else { + m_step++; + connect(process, SIGNAL(replySend(const QString &)), this, SLOT(replyReceived(const QString &))); + } +} + +void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() +{ + if (connected) { + process = process->instance(); + //process->executeCommand(QStringLiteral("disconnect")); + //process->executeCommand(QStringLiteral("\n")); + //process->executeCommand(QStringLiteral("exit")); + //process->executeCommand(QStringLiteral("\n")); + process->endProcess(); + connected = false; + m_step = 0; + m_valueCounter = 0; + disconnect(process, SIGNAL(replySend(const QString &)), this, SLOT(replyReceived(const QString &))); + emit disconnectedFromService(uuid); + } +} + +void QLowEnergyServiceInfoPrivate::replyReceived(const QString &reply) +{ +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << uuid << "m step: " << m_step << reply; +#endif + bool stepSet = false; + switch (m_step) { + case 0: + connectToTerminal(); + break; + case 1: + if (reply.contains(QStringLiteral("[CON]"))) { + connected = true; + setHandles(); + } + else { + connected = false; + if (reply.contains(QStringLiteral("Connection refused (111)"))) { +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Connection refused (111)"; +#endif + errorString = QStringLiteral("Connection refused (111)"); + emit error(uuid); + } + else if (reply.contains(QStringLiteral("Device busy"))) { +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Device busy"; +#endif + errorString = QStringLiteral("Connection refused (111)"); + emit error(uuid); + } + } + break; + case 2: + if (reply.contains(QStringLiteral("attr")) && reply.contains(QStringLiteral("uuid"))){ + QStringList chars = reply.split(QStringLiteral("\n")); + for (int i = 1; i= startingHandle.toUShort(0,0) && charHandle.toUShort(0,0) <= endingHandle.toUShort(0,0)) { + QString uuidParts = l.at(10) + "-" + l.at(11) + "-" + l.at(12) + "-" + l.at(13) + "-" + l.at(14); + QBluetoothUuid charUuid(uuidParts); + QVariantMap map = QVariantMap(); + + QLowEnergyCharacteristicInfo chars(charUuid); + chars.d_ptr->handle = charHandle; + chars.d_ptr->startingHandle = l.at(1); + QString perm = l.at(4); + chars.d_ptr->permission = perm.toUShort(0,0); + map[QStringLiteral("uuid")] = charUuid.toString(); + map[QStringLiteral("handle")] = charHandle; + map[QStringLiteral("permission")] = chars.d_ptr->permission; + chars.d_ptr->properties = map; + if ((chars.d_ptr->permission & QLowEnergyCharacteristicInfo::Read) == 0) { +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "GATT characteristic: Read not permitted: " << chars.d_ptr->uuid; +#endif + } + else + m_readCounter++; + characteristicList.append(chars); + stepSet = true; + } + } + + } +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "COUNTER : " << m_readCounter; +#endif + if ( stepSet ) + setNotifications(); + } + break; + case 4: + stepSet = false; + if (reply.contains(QStringLiteral("handle")) && reply.contains(QStringLiteral("value"))) { + QStringList chars = reply.split(QStringLiteral("\n")); + for (int i = 1; i chars.handle().toUShort(0,0) && l.at(1).toUShort(0,0) < charsNext.handle().toUShort(0,0)) { + chars.d_ptr->notificationHandle = l.at(1); + chars.d_ptr->notification = true; + QString notUuid = QStringLiteral("0x2902"); + QBluetoothUuid descUuid(notUuid.toUShort(0,0)); + QLowEnergyDescriptorInfo descriptor(descUuid, l.at(1)); + QString val = QStringLiteral(""); + for (int k = 0; k < l.size(); k++) + val = val + l.at(k); + descriptor.d_ptr->m_value = val.toUtf8(); + QVariantMap map = QVariantMap(); + map[QStringLiteral("uuid")] = descUuid.toString(); + map[QStringLiteral("handle")] = l.at(1); + map[QStringLiteral("value")] = val.toUtf8(); + characteristicList[j].d_ptr->descriptorsList.append(descriptor); +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Notification characteristic set." << chars.d_ptr->handle << chars.d_ptr->notificationHandle; +#endif + } + } + + } + + } + + } +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "COUNTER : " << m_readCounter; +#endif + if (m_readCounter > 0) + readCharacteristicValue(); + else { +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Ready to emit connected signal" << uuid; +#endif + m_step = 6; + connected = true; + emit connectedToService(uuid); + } + } + break; + case 5: + // This part is for reading characteristic values + if (reply.contains(QStringLiteral("handle")) && reply.contains(QStringLiteral("value"))) { + QStringList chars = reply.split(QStringLiteral("\n")); + for (int i = 1; ivalue = value.toUtf8(); +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Characteristic value set." << chars.d_ptr->handle << value; +#endif + m_valueCounter++; + } + } + + } + + } + + } + if (m_valueCounter == m_readCounter) { + m_step++; +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Ready to emit connected signal" << uuid; +#endif + connected = true; + emit connectedToService(uuid); + } + } + break; + default: + break; + + } + +} + +void QLowEnergyServiceInfoPrivate::connectToTerminal() +{ +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "[CONNECT TO TERMINAL] uuid inside: " << uuid; +#endif + process->executeCommand(QStringLiteral("connect")); + process->executeCommand(QStringLiteral("\n")); + m_step++; +} + +void QLowEnergyServiceInfoPrivate::setHandles() +{ + QString command = QStringLiteral("primary "); +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Setting handles: " << command; +#endif + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + m_step++; +} + +void QLowEnergyServiceInfoPrivate::setCharacteristics() +{ + QString command = QStringLiteral("characteristics ") + startingHandle + QStringLiteral(" ") + endingHandle; +#ifdef QT_LOWENERGYSERVICE_DEBUG + qDebug() << "Setting characteristics: " <executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + m_step++; +} + +void QLowEnergyServiceInfoPrivate::setNotifications() +{ + QString command = QStringLiteral("char-read-uuid 2902"); + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + m_step++; +} + +void QLowEnergyServiceInfoPrivate::readCharacteristicValue() +{ + for (int i = 0; i < characteristicList.size(); i++) { + if ((characteristicList.at(i).d_ptr->permission & QLowEnergyCharacteristicInfo::Read) != 0) { + QString uuidHandle = characteristicList.at(i).uuid().toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + QString command = QStringLiteral("char-read-uuid ") + uuidHandle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + } + } + m_step++; +} + +void QLowEnergyServiceInfoPrivate::readDescriptors() +{ + QString command = QStringLiteral("char-desc ") + startingHandle + QStringLiteral(" ") + endingHandle; + process->executeCommand(command); + process->executeCommand(QStringLiteral("\n")); + + m_step++; +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + if (adapterAddress == QBluetoothAddress()) + return false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo_p.cpp b/src/bluetooth/qlowenergyserviceinfo_p.cpp new file mode 100644 index 00000000..4b11c559 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_p.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo_p.h" + +QT_BEGIN_NAMESPACE + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate() +{ + +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + +} + +void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +{ + +} + +void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() +{ + +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + return false; +} + + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergyserviceinfo_p.h b/src/bluetooth/qlowenergyserviceinfo_p.h new file mode 100644 index 00000000..a71e09f2 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_p.h @@ -0,0 +1,132 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited all rights reserved +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGATTSERVICEINFO_P_H +#define QGATTSERVICEINFO_P_H +#include "qbluetoothuuid.h" +#include "qlowenergyserviceinfo.h" +#include "qlowenergycharacteristicinfo.h" +#include "stdint.h" +#include + +#ifdef QT_BLUEZ_BLUETOOTH +class OrgBluezCharacteristicInterface; +#endif + +QT_BEGIN_NAMESPACE + +class QBluetoothUuid; +class QLowEnergyServiceInfo; +class QLowEnergyCharacteristicInfo; +class QLowEnergyProcess; + +class QLowEnergyServiceInfoPrivate: public QObject +{ + Q_OBJECT + Q_DECLARE_PUBLIC(QLowEnergyServiceInfo) + +public: + QLowEnergyServiceInfoPrivate(); +#ifdef QT_BLUEZ_BLUETOOTH + QLowEnergyServiceInfoPrivate(const QString &servicePath); +#endif + ~QLowEnergyServiceInfoPrivate(); + + void registerServiceWatcher(); + void unregisterServiceWatcher(); + bool valid(); + + QString serviceName; + + QBluetoothUuid uuid; + + QList characteristicList; + QLowEnergyServiceInfo::ServiceType serviceType; + bool connected; + QBluetoothDeviceInfo deviceInfo; + QString errorString; +#ifdef QT_BLUEZ_BLUETOOTH + QString startingHandle; + QString endingHandle; + QString path; + QBluetoothAddress adapterAddress; + void connectToTerminal(); + void setHandles(); + void setCharacteristics(); + void setNotifications(); + void readCharacteristicValue(); + void readDescriptors(); +public slots: + void replyReceived(const QString &reply); +#endif + +#ifdef QT_QNX_BLUETOOTH + static void serviceConnected(const char*, const char*, int, int, short unsigned int, short unsigned int, short unsigned int, void*); + static void serviceUpdate(const char *, int , short unsigned int, short unsigned int, short unsigned int, void *); + static void serviceDisconnected(const char *, const char *, int, int, void *); + static void serviceNotification(int, short unsigned int, const char unsigned *, short unsigned int, void *); + //static void handleEvent(const int, const char *, const char *); +#endif + +Q_SIGNALS: + void finished(); + void connectedToService(const QBluetoothUuid &); + void error(const QBluetoothUuid &); + void disconnectedFromService(const QBluetoothUuid &); + +private: + QLowEnergyProcess *process; +#ifdef QT_BLUEZ_BLUETOOTH + OrgBluezCharacteristicInterface *characteristic; + int m_step; + int m_valueCounter; + int m_readCounter; +#endif + bool randomAddress; + int m_instance; + +protected: + QLowEnergyServiceInfo *q_ptr; +}; + +QT_END_NAMESPACE + +#endif // QGATTSERVICEINFO_P_H diff --git a/src/bluetooth/qlowenergyserviceinfo_qnx.cpp b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp new file mode 100644 index 00000000..c33b6da2 --- /dev/null +++ b/src/bluetooth/qlowenergyserviceinfo_qnx.cpp @@ -0,0 +1,265 @@ + +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $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 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlowenergyserviceinfo_p.h" +#include "qlowenergycharacteristicinfo.h" +#include "qlowenergycharacteristicinfo_p.h" +#include "qlowenergyprocess_p.h" +#include +#include +#include +#include +#include +#include +#include "qnx/ppshelpers_p.h" + +QT_BEGIN_NAMESPACE + +void QLowEnergyServiceInfoPrivate::serviceConnected(const char *bdaddr, const char *service, int instance, int err, short unsigned int connInt, short unsigned int latency, short unsigned int superTimeout, void *userData) +{ + Q_UNUSED(latency); + Q_UNUSED(connInt); + Q_UNUSED(superTimeout); + QPointer *classPointer = static_cast *>(userData); + QLowEnergyServiceInfoPrivate *p = classPointer->data(); + qBBBluetoothDebug() << "---------------------------------------------------"; + qBBBluetoothDebug() << "[SERVICE: Connected] (service uuid, instance):" << p->uuid << instance; + qBBBluetoothDebug() << "[SERVICE: Connected] Device address: " << bdaddr; + qBBBluetoothDebug() << "[SERVICE: Connected] Device service: " << service; + qBBBluetoothDebug() << "[SERVICE: Connected] Possible error: " << err; + if (err != 0) { + qBBBluetoothDebug() << "An error occurred in service connected callback: " << strerror(err); + p->errorString = QString::fromLatin1(strerror(err)); + p->error(p->uuid); + } + p->characteristicList.clear(); + bt_gatt_characteristic_t* data; + data = (bt_gatt_characteristic_t*) malloc(sizeof(bt_gatt_characteristic_t)); + if (0 == data) { + qBBBluetoothDebug() << "[SERVICE: Connected] GATT characteristics: Not enough memory"; + bt_gatt_disconnect_instance(instance); + p->errorString = QStringLiteral("GATT characteristics: Not enough memory"); + p->error(p->uuid); + return; + } + + int num_characteristics = bt_gatt_characteristics_count(instance); + + if (num_characteristics > -1) { + qBBBluetoothDebug() << "Characteristics number: "<< num_characteristics; + bt_gatt_characteristic_t *allCharacteristicList; + + allCharacteristicList = (bt_gatt_characteristic_t*) malloc(num_characteristics * sizeof(bt_gatt_characteristic_t)); + if (0 == allCharacteristicList) { + qBBBluetoothDebug() <<" GATT characteristics: Not enough memory"; + bt_gatt_disconnect_instance(instance); + p->errorString = QStringLiteral("GATT characteristics: Not enough memory"); + p->error(p->uuid); + return; + } + + /* BEGIN WORKAROUND - Temporary fix to address race condition */ + int number = 0; + do { + number = bt_gatt_characteristics(instance, allCharacteristicList, num_characteristics); + } while ((number == -1) && (errno== EBUSY)); + //Using sub to subscribe notification callback only once + bool sub = false; + int characteristicListSize = number; + + for (int i = 0; i < characteristicListSize; i++) { + qBBBluetoothDebug() << "Characteristic: uuid,handle,value_handle, properties:" << allCharacteristicList[i].uuid << "," << allCharacteristicList[i].handle << "," << allCharacteristicList[i].value_handle << ", " << allCharacteristicList[i].properties; + QString charUuid = QString::fromLatin1(allCharacteristicList[i].uuid); + QString handleUuid; + handleUuid.setNum(allCharacteristicList[i].value_handle); + QBluetoothUuid characteristicUuid; + if (charUuid.toUShort(0,0) == 0) { + charUuid = charUuid.remove(0,2); + characteristicUuid = QBluetoothUuid(charUuid); + } + else + characteristicUuid = QBluetoothUuid(charUuid.toUShort(0,0)); + QVariantMap map; + QLowEnergyCharacteristicInfo characteristicInfo(characteristicUuid); + characteristicInfo.d_ptr->handle = handleUuid; + characteristicInfo.d_ptr->instance = instance; + characteristicInfo.d_ptr->characteristic = allCharacteristicList[i]; + characteristicInfo.d_ptr->permission = allCharacteristicList[i].properties; + map[QStringLiteral("uuid")] = characteristicUuid.toString(); + map[QStringLiteral("handle")] = handleUuid; + map[QStringLiteral("permission")] = characteristicInfo.d_ptr->permission; + characteristicInfo.d_ptr->properties = map; + characteristicInfo.d_ptr->readDescriptors(); + + characteristicInfo.d_ptr->readValue(); + //Subscribe only once since it is static function + if (sub == false) { + int rc = bt_gatt_reg_notifications(instance, &(characteristicInfo.d_ptr->serviceNotification)); + if (rc != 0) { + qBBBluetoothDebug() << "[SERVICE: Connected] bt_gatt_reg_notifications failed." << errno << strerror(errno); + p->errorString = QString::fromLatin1(strerror(errno)); + p->error(p->uuid); + } + else + qBBBluetoothDebug() << "[SERVICE: Connected] bt_gatt_reg_notifications was presumably OK"; + sub = true; + } + p->characteristicList.append(characteristicInfo); + + } + + if (allCharacteristicList != NULL) { + free(allCharacteristicList); + allCharacteristicList = NULL; + } + + /* END WORKAROUND */ + } + + p->connected = true; + qBBBluetoothDebug() << p; + emit p->connectedToService(p->uuid); + qBBBluetoothDebug() << "---------------------------------------------------------------------------------"; +} + +void QLowEnergyServiceInfoPrivate::serviceUpdate(const char *bdaddr, int instance, short unsigned int connInt, short unsigned int latency, short unsigned int superTimeout, void *userData) +{ + Q_UNUSED(latency); + Q_UNUSED(connInt); + Q_UNUSED(superTimeout); + Q_UNUSED(userData); + qBBBluetoothDebug() << "---------------------------------------------------"; + qBBBluetoothDebug() << "[SERVICE: Update] (instance):" << instance; + qBBBluetoothDebug() << "[SERVICE: Update] Device address: " << bdaddr; + qBBBluetoothDebug() << "---------------------------------------------------"; +} + +void QLowEnergyServiceInfoPrivate::serviceDisconnected(const char *bdaddr, const char *service, int instance, int reason, void *userData) +{ + QPointer *classPointer = static_cast *>(userData); + QLowEnergyServiceInfoPrivate *p = classPointer->data(); + emit p->disconnectedFromService(p->uuid); + qBBBluetoothDebug() << "---------------------------------------------------"; + qBBBluetoothDebug() << "[SERVICE: Disconnect] (service, instance, reason):" << service << instance << reason; + qBBBluetoothDebug() << "[SERVICE: Disconnect] Device address: " << bdaddr; + qBBBluetoothDebug() << "---------------------------------------------------"; + delete p; + delete classPointer; +} + +QLowEnergyServiceInfoPrivate::QLowEnergyServiceInfoPrivate(): + errorString(QString()), m_instance(0) +{ + qRegisterMetaType("QBluetoothUuid"); +} + +QLowEnergyServiceInfoPrivate::~QLowEnergyServiceInfoPrivate() +{ + +} + +void QLowEnergyServiceInfoPrivate::registerServiceWatcher() +{ + bt_gatt_callbacks_t gatt_callbacks = { &(this->serviceConnected), this->serviceDisconnected, this->serviceUpdate }; + errno=0; + process = process->instance(); + if (!process->isConnected()) { + qBBBluetoothDebug() << "[INIT] Init problem." << errno << strerror(errno); + errorString = QStringLiteral("Initialization of device falied. ") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + return; + } + + errno=0; + if (bt_gatt_init(&gatt_callbacks) < 0) { + qBBBluetoothDebug() << "[INIT] GAT Init problem." << errno << strerror(errno); + errorString = QStringLiteral("Callbacks initialization failed. ") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + return; + } + if (bt_le_init(0) != EOK) { + qWarning() << "LE initialization failure " << errno; + } + + QPointer *classPointer = new QPointer(this); + process->addPointer(classPointer->data()); + QString serviceUuid = uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (serviceUuid.contains(QStringLiteral("000000000000"))) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + errno=0; + bt_gatt_conn_parm_t conParm; + conParm.minConn = 0x30; + conParm.maxConn = 0x50; + conParm.latency = 0; + conParm.superTimeout = 50; + if (bt_gatt_connect_service(deviceInfo.address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData(), 0, &conParm, classPointer) < 0) { + qBBBluetoothDebug() << "[SERVICE] Connection to service failed." << errno << strerror(errno); + errorString = QStringLiteral("[SERVICE] Connection to service failed.") + QString::fromLatin1(strerror(errno)); + emit error(uuid); + } + qBBBluetoothDebug() << "errno after connect: " << errno; +} + +void QLowEnergyServiceInfoPrivate::unregisterServiceWatcher() +{ + QString serviceUuid = uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')); + if (serviceUuid.contains(QStringLiteral("000000000000"))) + serviceUuid = QStringLiteral("0x") + serviceUuid.toUpper(); + else + serviceUuid = QStringLiteral("0x") + serviceUuid[4] + serviceUuid[5] + serviceUuid[6] + serviceUuid[7]; + if (bt_gatt_disconnect_service(deviceInfo.address().toString().toLocal8Bit().constData(), serviceUuid.toLocal8Bit().constData()) < 0) { + qBBBluetoothDebug() << "[SERVICE] Disconnect service request failed. " << errno << strerror(errno); + emit error(uuid); + } else { + emit disconnectedFromService(uuid); + qBBBluetoothDebug() << "[SERVICE] Disconnected from service OK."; + } +} + +bool QLowEnergyServiceInfoPrivate::valid() +{ + return true; +} + +QT_END_NAMESPACE -- cgit v1.2.3