diff options
Diffstat (limited to 'src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp')
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp | 189 |
1 files changed, 175 insertions, 14 deletions
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 <QtDBus/QDBusPendingCallWatcher> @@ -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<QDBusArgument>(); + 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<ServiceMap> 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<ServiceMap> 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<QList<QDBusObjectPath> > 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<QList<QDBusObjectPath> > 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<QVariantMap> characteristicProperty = characteristic->GetProperties(); + watcher = new QDBusPendingCallWatcher(characteristicProperty, this); + _q_discoveredGattCharacteristic(watcher); + +} + +void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher) +{ + + QDBusPendingReply<QVariantMap> characteristicProperty = *watcher; + //qDebug()<<characteristicProperty.value(); + if (characteristicProperty.isError()){ + qDebug() << "Characteristic properties error" << characteristicProperty.error().message(); + Q_Q(QBluetoothServiceDiscoveryAgent); + error = QBluetoothServiceDiscoveryAgent::UnknownError; + errorString = characteristicProperty.error().message(); + emit q->error(error); + _q_serviceDiscoveryFinished(); + return; + } + QStringList serviceName; + + if (characteristicProperty.isError()) + qDebug()<<characteristicProperty.error().message(); + + QVariantMap properties = characteristicProperty.value(); + QString name = properties.value(QLatin1String("Name")).toString(); + QString description = properties.value(QLatin1String("Description")).toString(); + serviceName = description.split(QStringLiteral(" ")); + QString charUuid = properties.value(QLatin1String("UUID")).toString(); + QBluetoothUuid characteristicUuid(charUuid); + + QVariant value = properties.value(QLatin1String("Value")); + QByteArray byteValue = QByteArray(); + if (value.type() == QVariant::ByteArray) + byteValue = value.toByteArray(); + + //qDebug() << name << description << characteristicUuid.toString()<< byteValue.size(); + gattCharacteristic = QLowEnergyCharacteristicInfo(name, description, characteristicUuid, byteValue); + gattCharacteristic.setPath(gattCharacteristics.at(0)); + qDebug() << gattCharacteristics.at(0); + gattService.addCharacteristic(gattCharacteristic); + + + //Testing part for setting the property + QString b = "f000aa02-0451-4000-b000-000000000000"; + QBluetoothUuid u(b); + if (gattCharacteristic.uuid() == u){ + for (int j = 0; j< byteValue.size(); j++){ + qDebug() << (int) byteValue.at(j); + byteValue[j]=1; + qDebug() << (int) byteValue.at(j); + } + bool s = gattCharacteristic.setPropertyValue(QStringLiteral("Value"), byteValue); + qDebug() <<s; + } + + QString serName = serviceName.at(0) + " Service"; + + gattCharacteristics.removeFirst(); + if (gattCharacteristics.isEmpty()){ + q_ptr->lowEnergyServiceDiscovered(gattService); + emit gattService.d_ptr->finished(); + } + else{ + OrgBluezCharacteristicInterface *characteristicProperties = new OrgBluezCharacteristicInterface(QLatin1String("org.bluez"), gattCharacteristics.at(0), QDBusConnection::systemBus()); + QDBusPendingReply<QVariantMap> 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")) { |