diff options
-rw-r--r-- | src/bluetooth/android/devicediscoverybroadcastreceiver.cpp | 23 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper.cpp | 2 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper_p.h | 3 | ||||
-rw-r--r-- | src/bluetooth/bluez/device1_bluez5_p.h | 6 | ||||
-rw-r--r-- | src/bluetooth/bluez/org.bluez.Device1.xml | 4 | ||||
-rw-r--r-- | src/bluetooth/darwin/btledeviceinquiry.mm | 16 | ||||
-rw-r--r-- | src/bluetooth/darwin/btutility.mm | 8 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp | 7 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp | 14 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm | 8 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_p.h | 4 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp | 83 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdeviceinfo.cpp | 90 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdeviceinfo.h | 7 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothdeviceinfo_p.h | 1 |
15 files changed, 251 insertions, 25 deletions
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp index 869d948b..228cdb0d 100644 --- a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp +++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp @@ -250,6 +250,9 @@ enum ADType { ADType128BitUuidComplete = 0x07, ADTypeShortenedLocalName = 0x08, ADTypeCompleteLocalName = 0x09, + ADTypeServiceData16Bit = 0x16, + ADTypeServiceData32Bit = 0x20, + ADTypeServiceData128Bit = 0x21, ADTypeManufacturerSpecificData = 0xff, // .. more will be added when required }; @@ -542,6 +545,25 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(const foundService = QBluetoothUuid(qToBigEndian<quint128>(qFromLittleEndian<quint128>(dataPtr))); break; + case ADTypeServiceData16Bit: + if (nBytes >= 3) { + info.setServiceData(QBluetoothUuid(qFromLittleEndian<quint16>(dataPtr)), + QByteArray(dataPtr + 2, nBytes - 3)); + } + break; + case ADTypeServiceData32Bit: + if (nBytes >= 5) { + info.setServiceData(QBluetoothUuid(qFromLittleEndian<quint32>(dataPtr)), + QByteArray(dataPtr + 4, nBytes - 5)); + } + break; + case ADTypeServiceData128Bit: + if (nBytes >= 17) { + info.setServiceData(QBluetoothUuid(qToBigEndian<quint128>( + qFromLittleEndian<quint128>(dataPtr))), + QByteArray(dataPtr + 16, nBytes - 17)); + } + break; case ADTypeManufacturerSpecificData: if (nBytes >= 3) { info.setManufacturerData(qFromLittleEndian<quint16>(dataPtr), @@ -592,4 +614,3 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(const } QT_END_NAMESPACE - diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp index 8133b36a..d4af7d51 100644 --- a/src/bluetooth/bluez/bluez5_helper.cpp +++ b/src/bluetooth/bluez/bluez5_helper.cpp @@ -75,6 +75,7 @@ void initializeBluez5() qDBusRegisterMetaType<InterfaceList>(); qDBusRegisterMetaType<ManagedObjectList>(); qDBusRegisterMetaType<ManufacturerDataList>(); + qDBusRegisterMetaType<ServiceDataList>(); QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects(); reply.waitForFinished(); @@ -190,6 +191,7 @@ QVersionNumber bluetoothdVersion() qDBusRegisterMetaType<InterfaceList>(); qDBusRegisterMetaType<ManagedObjectList>(); qDBusRegisterMetaType<ManufacturerDataList>(); + qDBusRegisterMetaType<ServiceDataList>(); qCDebug(QT_BT_BLUEZ) << "Detecting bluetoothd version"; //Order of matching diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h index 58b87da8..7f3d1c04 100644 --- a/src/bluetooth/bluez/bluez5_helper_p.h +++ b/src/bluetooth/bluez/bluez5_helper_p.h @@ -53,15 +53,18 @@ #include <QtCore/QObject> #include <QtDBus/QtDBus> +#include <QtBluetooth/QBluetoothUuid> #include <QtBluetooth/QBluetoothAddress> #include <QtBluetooth/private/qtbluetoothglobal_p.h> typedef QMap<QString, QVariantMap> InterfaceList; typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList; typedef QMap<quint16, QDBusVariant> ManufacturerDataList; +typedef QMap<QString, QDBusVariant> ServiceDataList; Q_DECLARE_METATYPE(InterfaceList) Q_DECLARE_METATYPE(ManufacturerDataList) +Q_DECLARE_METATYPE(ServiceDataList) Q_DECLARE_METATYPE(ManagedObjectList) QT_BEGIN_NAMESPACE diff --git a/src/bluetooth/bluez/device1_bluez5_p.h b/src/bluetooth/bluez/device1_bluez5_p.h index b9523a56..c03a1bd8 100644 --- a/src/bluetooth/bluez/device1_bluez5_p.h +++ b/src/bluetooth/bluez/device1_bluez5_p.h @@ -96,9 +96,9 @@ public: inline short rSSI() const { return qvariant_cast< short >(property("RSSI")); } - Q_PROPERTY(QVariantMap ServiceData READ serviceData) - inline QVariantMap serviceData() const - { return qvariant_cast< QVariantMap >(property("ServiceData")); } + Q_PROPERTY(ServiceDataList ServiceData READ serviceData) + inline ServiceDataList serviceData() const + { return qvariant_cast< ServiceDataList >(property("ServiceData")); } Q_PROPERTY(bool ServicesResolved READ servicesResolved) inline bool servicesResolved() const diff --git a/src/bluetooth/bluez/org.bluez.Device1.xml b/src/bluetooth/bluez/org.bluez.Device1.xml index 554d0b53..cd4cba77 100644 --- a/src/bluetooth/bluez/org.bluez.Device1.xml +++ b/src/bluetooth/bluez/org.bluez.Device1.xml @@ -29,10 +29,10 @@ <property name="Adapter" type="o" access="read"></property> <!-- ManufacturerData & ServiceData introduced by Bluez 5.31 --> <property name="ManufacturerData" type="a{qv}" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/> </property> <property name="ServiceData" type="a{sv}" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="ServiceDataList"/> </property> <!-- TxPower and ServicesResolved introduced by Bluez 5.42 --> <property name="TxPower" type="n" access="read"></property> diff --git a/src/bluetooth/darwin/btledeviceinquiry.mm b/src/bluetooth/darwin/btledeviceinquiry.mm index 38ed5f45..6cc61955 100644 --- a/src/bluetooth/darwin/btledeviceinquiry.mm +++ b/src/bluetooth/darwin/btledeviceinquiry.mm @@ -83,6 +83,7 @@ struct AdvertisementData { QString localName; QList<QBluetoothUuid> serviceUuids; QHash<quint16, QByteArray> manufacturerData; + QHash<QBluetoothUuid, QByteArray> serviceData; // TODO: other keys probably? AdvertisementData(NSDictionary *AdvertisementData); }; @@ -108,6 +109,13 @@ AdvertisementData::AdvertisementData(NSDictionary *advertisementData) serviceUuids << qt_uuid(cbUuid); } + NSDictionary *advdict = [advertisementData objectForKey:CBAdvertisementDataServiceDataKey]; + if (advdict) { + [advdict enumerateKeysAndObjectsUsingBlock:^(CBUUID *key, NSData *val, BOOL *) { + serviceData.insert(qt_uuid(key), QByteArray::fromNSData(static_cast<NSData *>(val))); + }]; + } + value = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey]; if (value && [value isKindOfClass:[NSData class]]) { QByteArray data = QByteArray::fromNSData(static_cast<NSData *>(value)); @@ -359,10 +367,14 @@ QT_USE_NAMESPACE if (qtAdvData.serviceUuids.size()) newDeviceInfo.setServiceUuids(qtAdvData.serviceUuids); - const QList<quint16> keys = qtAdvData.manufacturerData.keys(); - for (quint16 key : keys) + const QList<quint16> keysManufacturer = qtAdvData.manufacturerData.keys(); + for (quint16 key : keysManufacturer) newDeviceInfo.setManufacturerData(key, qtAdvData.manufacturerData.value(key)); + const QList<QBluetoothUuid> keysService = qtAdvData.serviceData.keys(); + for (QBluetoothUuid key : keysService) + newDeviceInfo.setServiceData(key, qtAdvData.serviceData.value(key)); + // CoreBluetooth scans only for LE devices. newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); emit notifier->deviceDiscovered(newDeviceInfo); diff --git a/src/bluetooth/darwin/btutility.mm b/src/bluetooth/darwin/btutility.mm index 859624d4..2faa8911 100644 --- a/src/bluetooth/darwin/btutility.mm +++ b/src/bluetooth/darwin/btutility.mm @@ -182,8 +182,7 @@ QBluetoothUuid qt_uuid(CBUUID *uuid) { // Apples' docs say "128 bit" and "16-bit UUIDs are implicitly // pre-filled with the Bluetooth Base UUID." - // But Core Bluetooth can return CBUUID objects of length 2 - // (16-bit, so they are not pre-filled?). + // But Core Bluetooth can return CBUUID objects of length 2, 4, and 16. if (!uuid) return QBluetoothUuid(); @@ -195,6 +194,9 @@ QBluetoothUuid qt_uuid(CBUUID *uuid) // Seems to be in big-endian. const uchar *const src = static_cast<const uchar *>(uuid.data.bytes); return QBluetoothUuid(qFromBigEndian<quint16>(src)); + } else if (uuid.data.length == 4) { + const uchar *const src = static_cast<const uchar *>(uuid.data.bytes); + return QBluetoothUuid(qFromBigEndian<quint32>(src)); } else if (uuid.data.length == 16) { quint128 qtUuidData = {}; const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes); @@ -203,7 +205,7 @@ QBluetoothUuid qt_uuid(CBUUID *uuid) return QBluetoothUuid(qtUuidData); } - qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2 or 16 bytes expected, but got " + qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2, 4, or 16 bytes expected, but got " << uuid.data.length << " bytes length"; return QBluetoothUuid(); } diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp index b2744164..d5ac2bc3 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp @@ -345,6 +345,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevices( discoveredDevices[i].setManufacturerData(key, info.manufacturerData(key)); updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); } + if (discoveredDevices[i].serviceData() != info.serviceData()) { + qCDebug(QT_BT_ANDROID) << "Updating service data for" << info.address(); + const QList<QBluetoothUuid> keys = info.serviceIds(); + for (auto key : keys) + discoveredDevices[i].setServiceData(key, info.serviceData(key)); + updatedFields.setFlag(QBluetoothDeviceInfo::Field::ServiceData); + } if (lowEnergySearchTimeout > 0) { if (discoveredDevices[i] != info) { diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp index 471f6a62..f509f649 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp @@ -276,11 +276,18 @@ static QBluetoothDeviceInfo createDeviceInfoFromBluez5Device(const QVariantMap& } const ManufacturerDataList deviceManufacturerData = qdbus_cast<ManufacturerDataList>(properties[QStringLiteral("ManufacturerData")]); - const QList<quint16> keys = deviceManufacturerData.keys(); - for (quint16 key : keys) + const QList<quint16> keysManufacturer = deviceManufacturerData.keys(); + for (quint16 key : keysManufacturer) deviceInfo.setManufacturerData( key, deviceManufacturerData.value(key).variant().toByteArray()); + const ServiceDataList deviceServiceData = + qdbus_cast<ServiceDataList>(properties[QStringLiteral("ServiceData")]); + const QList<QString> keysService = deviceServiceData.keys(); + for (QString key : keysService) + deviceInfo.setServiceData(QBluetoothUuid(key), + deviceServiceData.value(key).variant().toByteArray()); + return deviceInfo; } @@ -305,7 +312,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QString &devicePat << "Num UUIDs" << deviceInfo.serviceUuids().count() << "total device" << discoveredDevices.count() << "cached" << "RSSI" << deviceInfo.rssi() - << "Num ManufacturerData" << deviceInfo.manufacturerData().size(); + << "Num ManufacturerData" << deviceInfo.manufacturerData().size() + << "Num ServiceData" << deviceInfo.serviceData().size(); // Cache the properties so we do not have to access dbus every time to get a value devicesProperties[devicePath] = properties; diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm index 01a71db8..635e91eb 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm @@ -522,6 +522,14 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); } + if (discoveredDevices[i].serviceData() != newDeviceInfo.serviceData()) { + qCDebug(QT_BT_DARWIN) << "Updating service data for" << newDeviceInfo.address(); + const QList<QBluetoothUuid> keys = newDeviceInfo.serviceIds(); + for (auto key : keys) + discoveredDevices[i].setServiceData(key, newDeviceInfo.serviceData(key)); + updatedFields.setFlag(QBluetoothDeviceInfo::Field::ServiceData); + } + if (lowEnergySearchTimeout > 0) { if (discoveredDevices[i] != newDeviceInfo) { discoveredDevices.replace(i, newDeviceInfo); diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h index a1abf75a..c1260305 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h @@ -89,7 +89,9 @@ QT_END_NAMESPACE #include <QtCore/QTimer> using ManufacturerData = QHash<quint16, QByteArray>; +using ServiceData = QHash<QBluetoothUuid, QByteArray>; Q_DECLARE_METATYPE(ManufacturerData) +Q_DECLARE_METATYPE(ServiceData) #endif QT_BEGIN_NAMESPACE @@ -175,7 +177,7 @@ private: private slots: void registerDevice(const QBluetoothDeviceInfo &info); void updateDeviceData(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields fields, - qint16 rssi, ManufacturerData manufacturerData); + qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData); void onErrorOccured(QBluetoothDeviceDiscoveryAgent::Error e); void onScanFinished(); diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp index 1aa0c6c9..bc047644 100644 --- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp +++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp @@ -47,6 +47,7 @@ #include <QtCore/QLoggingCategory> #include <QtCore/qmutex.h> #include <QtCore/private/qfunctions_winrt_p.h> +#include <QtCore/qendian.h> #include <robuffer.h> #include <wrl.h> @@ -90,6 +91,15 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS) continue; \ } +// Endianness conversion for quint128 doesn't exist in qtendian.h +inline quint128 qbswap(const quint128 src) +{ + quint128 dst; + for (int i = 0; i < 16; i++) + dst.data[i] = src.data[15 - i]; + return dst; +} + static ManufacturerData extractManufacturerData(ComPtr<IBluetoothLEAdvertisement> ad) { ManufacturerData ret; @@ -117,6 +127,54 @@ static ManufacturerData extractManufacturerData(ComPtr<IBluetoothLEAdvertisement return ret; } +static ServiceData extractServiceData(ComPtr<IBluetoothLEAdvertisement> ad) +{ + ServiceData ret; + + int serviceDataTypes[3] = { 0x16, 0x20, 0x21 }; + + for (const auto &serviceDataType : serviceDataTypes) { + ComPtr<IVectorView<BluetoothLEAdvertisementDataSection *>> data_sections; + HRESULT hr = ad->GetSectionsByType(serviceDataType, &data_sections); + WARN_AND_RETURN_IF_FAILED("Could not obtain list of advertisement data sections.", + return ret); + + quint32 size; + hr = data_sections->get_Size(&size); + WARN_AND_RETURN_IF_FAILED("Could not obtain advertisement data sections list size.", + return ret); + + for (quint32 i = 0; i < size; ++i) { + ComPtr<IBluetoothLEAdvertisementDataSection> d; + hr = data_sections->GetAt(i, &d); + WARN_AND_CONTINUE_IF_FAILED("Could not obtain service data."); + + BYTE datatype; + hr = d->get_DataType(&datatype); + WARN_AND_CONTINUE_IF_FAILED("Could not obtain service data type."); + + ComPtr<IBuffer> buffer; + hr = d->get_Data(&buffer); + WARN_AND_CONTINUE_IF_FAILED("Could not obtain service data buffer."); + const QByteArray bufferData = byteArrayFromBuffer(buffer); + + if (datatype == 0x16) { + ret.insert(QBluetoothUuid(qFromLittleEndian<quint16>(bufferData.constData())), + bufferData + 2); + } else if (datatype == 0x20) { + ret.insert(QBluetoothUuid(qFromLittleEndian<quint32>(bufferData.constData())), + bufferData + 4); + } else if (datatype == 0x21) { + ret.insert(QBluetoothUuid(qToBigEndian<quint128>( + qFromLittleEndian<quint128>(bufferData.constData()))), + bufferData + 16); + } + } + } + + return ret; +} + class QWinRTBluetoothDeviceDiscoveryWorker : public QObject { Q_OBJECT @@ -155,7 +213,7 @@ public slots: Q_SIGNALS: void deviceFound(const QBluetoothDeviceInfo &info); void deviceDataChanged(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields, - qint16 rssi, ManufacturerData manufacturerData); + qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData); void errorOccured(QBluetoothDeviceDiscoveryAgent::Error error); void scanFinished(); @@ -169,6 +227,7 @@ private: struct LEAdvertisingInfo { QList<QBluetoothUuid> services; ManufacturerData manufacturerData; + ServiceData serviceData; qint16 rssi = 0; }; @@ -336,6 +395,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEAdvertisementReceived QBluetoothDeviceDiscoveryAgent::Error::UnknownError, return S_OK); const ManufacturerData manufacturerData = extractManufacturerData(ad); + const ServiceData serviceData = extractServiceData(ad); QBluetoothDeviceInfo::Fields changedFields = QBluetoothDeviceInfo::Field::None; ComPtr<IVector<GUID>> guids; hr = ad->get_ServiceUuids(&guids); @@ -373,6 +433,11 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEAdvertisementReceived if (adInfo.manufacturerData != m_foundLEDevicesMap[address].manufacturerData) changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData); } + if (adInfo.serviceData != serviceData) { + m_foundLEDevicesMap[address].serviceData.insert(serviceData); + if (adInfo.serviceData != m_foundLEDevicesMap[address].serviceData) + changedFields.setFlag((QBluetoothDeviceInfo::Field::ServiceData)); + } bool newServiceAdded = false; for (const QBluetoothUuid &uuid : qAsConst(serviceUuids)) { if (!foundServices.contains(uuid)) { @@ -386,7 +451,8 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEAdvertisementReceived Q_ARG(QBluetoothAddress, QBluetoothAddress(address)), Q_ARG(QBluetoothDeviceInfo::Fields, changedFields), Q_ARG(qint16, rssi), - Q_ARG(ManufacturerData, manufacturerData)); + Q_ARG(ManufacturerData, manufacturerData), + Q_ARG(ServiceData, serviceData)); } return S_OK; } @@ -395,6 +461,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEAdvertisementReceived LEAdvertisingInfo info; info.services = std::move(serviceUuids); info.manufacturerData = std::move(manufacturerData); + info.serviceData = std::move(serviceData); info.rssi = rssi; m_foundLEDevicesMap.insert(address, info); } @@ -700,6 +767,7 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address); const ManufacturerData manufacturerData = adInfo.manufacturerData; + const ServiceData serviceData = adInfo.serviceData; const qint16 rssi = adInfo.rssi; // Use the services obtained from the advertisement data if the device is not paired if (!isPaired) { @@ -732,7 +800,8 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB qCDebug(QT_BT_WINDOWS) << "Discovered BTLE device: " << QString::number(address) << btName << "Num UUIDs" << uuids.count() << "RSSI:" << rssi - << "Num manufacturer data" << manufacturerData.count(); + << "Num manufacturer data" << manufacturerData.count() + << "Num service data" << serviceData.count(); QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0); info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration); @@ -740,6 +809,8 @@ HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IB info.setRssi(rssi); for (quint16 key : manufacturerData.keys()) info.setManufacturerData(key, manufacturerData.value(key)); + for (QBluetoothUuid key : serviceData.keys()) + info.setServiceData(key, serviceData.value(key)); info.setCached(true); QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection, @@ -838,7 +909,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDevic void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields fields, qint16 rssi, - ManufacturerData manufacturerData) + ManufacturerData manufacturerData, + ServiceData serviceData) { if (fields.testFlag(QBluetoothDeviceInfo::Field::None)) return; @@ -853,6 +925,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAdd if (fields.testFlag(QBluetoothDeviceInfo::Field::ManufacturerData)) for (quint16 key : manufacturerData.keys()) iter->setManufacturerData(key, manufacturerData.value(key)); + if (fields.testFlag(QBluetoothDeviceInfo::Field::ServiceData)) + for (QBluetoothUuid key : serviceData.keys()) + iter->setServiceData(key, serviceData.value(key)); emit q->deviceUpdated(*iter, fields); return; } diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp index 36d24b91..41d1f4af 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.cpp +++ b/src/bluetooth/qbluetoothdeviceinfo.cpp @@ -80,6 +80,7 @@ QT_BEGIN_NAMESPACE \value None None of the values changed. \value RSSI The \l rssi() value of the device changed. \value ManufacturerData The \l manufacturerData() field changed + \value ServiceData The \l serviceData() field changed \value All Matches every possible field. \since 5.12 @@ -396,6 +397,7 @@ QBluetoothDeviceInfo &QBluetoothDeviceInfo::operator=(const QBluetoothDeviceInfo d->cached = other.d_func()->cached; d->serviceUuids = other.d_func()->serviceUuids; d->manufacturerData = other.d_func()->manufacturerData; + d->serviceData = other.d_func()->serviceData; d->rssi = other.d_func()->rssi; d->deviceCoreConfiguration = other.d_func()->deviceCoreConfiguration; d->deviceUuid = other.d_func()->deviceUuid; @@ -441,6 +443,8 @@ bool QBluetoothDeviceInfo::equals(const QBluetoothDeviceInfo &a, const QBluetoot return false; if (a.d_func()->manufacturerData != b.d_func()->manufacturerData) return false; + if (a.d_func()->serviceData != b.d_func()->serviceData) + return false; if (a.d_func()->deviceCoreConfiguration != b.d_func()->deviceCoreConfiguration) return false; if (a.d_func()->deviceUuid != b.d_func()->deviceUuid) @@ -533,9 +537,9 @@ void QBluetoothDeviceInfo::setServiceUuids(const QList<QBluetoothUuid> &uuids) } /*! - Returns the list of service UUIDS supported by the device. Most commonly this - list of uuids represents custom uuids or a uuid value specified by - \l QBluetoothUuid::ServiceClassUuid. + Returns the list of service UUIDs supported by the device. Most commonly this + list of UUIDs represents custom service UUIDs or a service UUID value specified + by \l QBluetoothUuid::ServiceClassUuid. \sa serviceUuids() \since 6.0 @@ -547,7 +551,7 @@ QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids() const } /*! - Returns all manufacturer ids attached to this device information. + Returns all manufacturer IDs from advertisement packets attached to this device information. \sa manufacturerData(), setManufacturerData() @@ -556,7 +560,7 @@ QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids() const QList<quint16> QBluetoothDeviceInfo::manufacturerIds() const { Q_D(const QBluetoothDeviceInfo); - return d->manufacturerData.keys().toVector(); + return d->manufacturerData.keys().toList(); } /*! @@ -613,7 +617,7 @@ bool QBluetoothDeviceInfo::setManufacturerData(quint16 manufacturerId, const QBy } /*! - Returns the complete set of all manufacturer data. + Returns the complete set of all manufacturer data from advertisement packets. Some devices may provide multiple manufacturer data entries per manufacturer ID. An example might be a Bluetooth Low Energy device that sends a different manufacturer data via @@ -630,6 +634,80 @@ QMultiHash<quint16, QByteArray> QBluetoothDeviceInfo::manufacturerData() const } /*! + Returns all service data IDs from advertisement packets attached to this device information. + + \sa serviceData(), setServiceData() + \since 6.3 + */ +QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceIds() const +{ + Q_D(const QBluetoothDeviceInfo); + return d->serviceData.keys().toList(); +} + +/*! + Returns the data associated with the given \a serviceId. + + Service data is defined by + the Supplement to the Bluetooth Core Specification and consists of two segments: + + \list + \li Service UUID + \li Sequence of arbitrary data octets + \endlist + + \note The remote device may provide multiple data entries per \a serviceId. + This function only returns the first entry. If all entries are needed use + \l serviceData() which returns a multi hash. + + \sa serviceIds(), setServiceData() + \since 6.3 + */ +QByteArray QBluetoothDeviceInfo::serviceData(const QBluetoothUuid &serviceId) const +{ + Q_D(const QBluetoothDeviceInfo); + return d->serviceData.value(serviceId); +} + +/*! + Sets the advertised service \a data for the given \a serviceId. + Returns \c true if it was inserted, \c false if it was already known. + + \sa serviceData + \since 6.3 +*/ +bool QBluetoothDeviceInfo::setServiceData(const QBluetoothUuid &serviceId, const QByteArray &data) +{ + Q_D(QBluetoothDeviceInfo); + auto it = d->serviceData.constFind(serviceId); + while (it != d->serviceData.cend() && it.key() == serviceId) { + if (*it == data) + return false; + it++; + } + + d->serviceData.insert(serviceId, data); + return true; +} + +/*! + Returns the complete set of all service data from advertisement packets. + + Some devices may provide multiple service data entries per service data ID. + An example might be a Bluetooth Low Energy device that sends a different service data via + advertisement packets and scan response packets respectively. Therefore the returned hash table + may have multiple entries per service data ID or hash key. + + \sa setServiceData + \since 6.3 +*/ +QMultiHash<QBluetoothUuid, QByteArray> QBluetoothDeviceInfo::serviceData() const +{ + Q_D(const QBluetoothDeviceInfo); + return d->serviceData; +} + +/*! Sets the CoreConfigurations of the device to \a coreConfigs. This will help to make a difference between regular and Low Energy devices. diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h index 3219e629..6fd250ec 100644 --- a/src/bluetooth/qbluetoothdeviceinfo.h +++ b/src/bluetooth/qbluetoothdeviceinfo.h @@ -41,6 +41,7 @@ #define QBLUETOOTHDEVICEINFO_H #include <QtBluetooth/qtbluetoothglobal.h> +#include <QtBluetooth/QBluetoothUuid> #include <QtCore/qbytearray.h> #include <QtCore/qlist.h> @@ -195,6 +196,7 @@ public: None = 0x0000, RSSI = 0x0001, ManufacturerData = 0x0002, + ServiceData = 0x0004, All = 0x7fff }; Q_DECLARE_FLAGS(Fields, Field) @@ -249,6 +251,11 @@ public: bool setManufacturerData(quint16 manufacturerId, const QByteArray &data); QMultiHash<quint16, QByteArray> manufacturerData() const; + QList<QBluetoothUuid> serviceIds() const; + QByteArray serviceData(const QBluetoothUuid &serviceId) const; + bool setServiceData(const QBluetoothUuid &serviceId, const QByteArray &data); + QMultiHash<QBluetoothUuid, QByteArray> serviceData() const; + void setCoreConfigurations(QBluetoothDeviceInfo::CoreConfigurations coreConfigs); QBluetoothDeviceInfo::CoreConfigurations coreConfigurations() const; diff --git a/src/bluetooth/qbluetoothdeviceinfo_p.h b/src/bluetooth/qbluetoothdeviceinfo_p.h index 25c70960..854ab00f 100644 --- a/src/bluetooth/qbluetoothdeviceinfo_p.h +++ b/src/bluetooth/qbluetoothdeviceinfo_p.h @@ -78,6 +78,7 @@ public: QList<QBluetoothUuid> serviceUuids; QMultiHash<quint16, QByteArray> manufacturerData; + QMultiHash<QBluetoothUuid, QByteArray> serviceData; QBluetoothDeviceInfo::CoreConfigurations deviceCoreConfiguration = QBluetoothDeviceInfo::UnknownCoreConfiguration; QBluetoothUuid deviceUuid; |