diff options
-rw-r--r-- | src/bluetooth/bluez/bluez_data_p.h | 4 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager.cpp | 44 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager_p.h | 4 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 11 |
4 files changed, 63 insertions, 0 deletions
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h index 8c2dc43e..25edc661 100644 --- a/src/bluetooth/bluez/bluez_data_p.h +++ b/src/bluetooth/bluez/bluez_data_p.h @@ -99,6 +99,10 @@ struct bt_security { #define BDADDR_LE_PUBLIC 0x01 #define BDADDR_LE_RANDOM 0x02 +#define SCO_LINK 0x00 +#define ACL_LINK 0x01 +#define ESCO_LINK 0x02 +#define LE_LINK 0x80 // based on hcitool.c -> no fixed constant available /* Byte order conversions */ #if __BYTE_ORDER == __LITTLE_ENDIAN diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp index 93bf941b..c524117c 100644 --- a/src/bluetooth/bluez/hcimanager.cpp +++ b/src/bluetooth/bluez/hcimanager.cpp @@ -288,6 +288,50 @@ QBluetoothAddress HciManager::addressForConnectionHandle(quint16 handle) const return QBluetoothAddress(); } +QVector<quint16> HciManager::activeLowEnergyConnections() const +{ + if (!isValid()) + return QVector<quint16>(); + + hci_conn_info *info; + hci_conn_list_req *infoList; + + const int maxNoOfConnections = 20; + infoList = (hci_conn_list_req *) + malloc(sizeof(hci_conn_list_req) + maxNoOfConnections * sizeof(hci_conn_info)); + + if (!infoList) + return QVector<quint16>(); + + QScopedPointer<hci_conn_list_req, QScopedPointerPodDeleter> p(infoList); + p->conn_num = maxNoOfConnections; + p->dev_id = hciDev; + info = p->conn_info; + + if (ioctl(hciSocket, HCIGETCONNLIST, (void *) infoList) < 0) { + qCWarning(QT_BT_BLUEZ) << "Cannot retrieve connection list"; + return QVector<quint16>(); + } + + QVector<quint16> activeLowEnergyHandles; + for (int i = 0; i < infoList->conn_num; i++) { + switch (info[i].type) { + case SCO_LINK: + case ACL_LINK: + case ESCO_LINK: + continue; + case LE_LINK: + activeLowEnergyHandles.append(info[i].handle); + break; + default: + qCWarning(QT_BT_BLUEZ) << "Unknown active connection type:" << hex << info[i].type; + break; + } + } + + return activeLowEnergyHandles; +} + quint16 forceIntervalIntoRange(double connectionInterval) { return qMin<double>(qMax<double>(7.5, connectionInterval), 4000) / 1.25; diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h index 3bae92e5..3127a747 100644 --- a/src/bluetooth/bluez/hcimanager_p.h +++ b/src/bluetooth/bluez/hcimanager_p.h @@ -55,6 +55,7 @@ #include <QtCore/QSet> #include <QtCore/QSocketNotifier> #include <QtBluetooth/QBluetoothAddress> +#include <QVector> #include "bluez/bluez_data_p.h" QT_BEGIN_NAMESPACE @@ -82,6 +83,9 @@ public: void stopEvents(); QBluetoothAddress addressForConnectionHandle(quint16 handle) const; + // active connections + QVector<quint16> activeLowEnergyConnections() const; + bool sendConnectionUpdateCommand(quint16 handle, const QLowEnergyConnectionParameters ¶ms); bool sendConnectionParameterUpdateRequest(quint16 handle, const QLowEnergyConnectionParameters ¶ms); diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 3873664a..40744670 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -527,6 +527,17 @@ void QLowEnergyControllerPrivate::connectToDevice() if (l2cpSocket) delete l2cpSocket; + // check for active running connections + // BlueZ 5.37+ (maybe even earlier versions) can have pending BTLE connections + // Only one active L2CP socket to CID 0x4 possible at a time + QVector<quint16> activeHandles = hciManager->activeLowEnergyConnections(); + if (!activeHandles.isEmpty()) { + qCWarning(QT_BT_BLUEZ) << "Cannot connect due to pending active LE connections"; + setError(QLowEnergyController::ConnectionError); + setState(QLowEnergyController::UnconnectedState); + return; + } + l2cpSocket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol, this); connect(l2cpSocket, SIGNAL(connected()), this, SLOT(l2cpConnected())); connect(l2cpSocket, SIGNAL(disconnected()), this, SLOT(l2cpDisconnected())); |