diff options
-rw-r--r-- | src/bluetooth/qbluetoothsocket.h | 1 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_bluez.cpp | 13 | ||||
-rw-r--r-- | src/bluetooth/qbluetoothsocket_p.h | 5 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew.cpp | 41 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew.h | 12 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew_bluez.cpp | 73 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew_p.cpp | 13 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontrollernew_p.h | 38 | ||||
-rw-r--r-- | tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp | 37 |
9 files changed, 223 insertions, 10 deletions
diff --git a/src/bluetooth/qbluetoothsocket.h b/src/bluetooth/qbluetoothsocket.h index 0cc765cd..c6a8bd72 100644 --- a/src/bluetooth/qbluetoothsocket.h +++ b/src/bluetooth/qbluetoothsocket.h @@ -161,6 +161,7 @@ protected: private: Q_PRIVATE_SLOT(d_func(), void _q_readNotify()) Q_PRIVATE_SLOT(d_func(), void _q_writeNotify()) + friend class QLowEnergyControllerNewPrivate; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp index 31a5535c..16977f74 100644 --- a/src/bluetooth/qbluetoothsocket_bluez.cpp +++ b/src/bluetooth/qbluetoothsocket_bluez.cpp @@ -74,7 +74,8 @@ QBluetoothSocketPrivate::QBluetoothSocketPrivate() readNotifier(0), connectWriteNotifier(0), connecting(false), - discoveryAgent(0) + discoveryAgent(0), + isLowEnergySocket(false) { } @@ -161,7 +162,15 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = port; + // This is an ugly hack but the socket class does what's needed already. + // For L2CP GATT we need a channel rather than a socket and the LE address type + // We don't want to make this public API offering + if (isLowEnergySocket) { + addr.l2_cid = port; + addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + } else { + addr.l2_psm = port; + } convertAddress(address.toUInt64(), addr.l2_bdaddr.b); diff --git a/src/bluetooth/qbluetoothsocket_p.h b/src/bluetooth/qbluetoothsocket_p.h index 63309069..2c44bb0c 100644 --- a/src/bluetooth/qbluetoothsocket_p.h +++ b/src/bluetooth/qbluetoothsocket_p.h @@ -187,6 +187,11 @@ private slots: void controlReply(ppsResult result); void controlEvent(ppsResult result); #endif + +#ifdef QT_BLUEZ_BLUETOOTH +public: + bool isLowEnergySocket; +#endif }; diff --git a/src/bluetooth/qlowenergycontrollernew.cpp b/src/bluetooth/qlowenergycontrollernew.cpp index 8a958205..a30d18b7 100644 --- a/src/bluetooth/qlowenergycontrollernew.cpp +++ b/src/bluetooth/qlowenergycontrollernew.cpp @@ -44,7 +44,7 @@ #include <QtBluetooth/QBluetoothLocalDevice> - +QT_BEGIN_NAMESPACE void QLowEnergyControllerNewPrivate::setError( QLowEnergyControllerNew::Error newError) @@ -53,9 +53,15 @@ void QLowEnergyControllerNewPrivate::setError( error = newError; switch (newError) { + case QLowEnergyControllerNew::UnknownRemoteDeviceError: + errorString = QLowEnergyControllerNew::tr("Remote device cannot be found"); + break; case QLowEnergyControllerNew::InvalidBluetoothAdapterError: errorString = QLowEnergyControllerNew::tr("Cannot find local adapter"); break; + case QLowEnergyControllerNew::NetworkError: + errorString = QLowEnergyControllerNew::tr("Error occurred during connection I/O"); + break; case QLowEnergyControllerNew::UnknownError: default: errorString = QLowEnergyControllerNew::tr("Unknown Error"); @@ -90,6 +96,17 @@ void QLowEnergyControllerNewPrivate::validateLocalAdapter() setError(QLowEnergyControllerNew::InvalidBluetoothAdapterError); } +void QLowEnergyControllerNewPrivate::setState( + QLowEnergyControllerNew::ControllerState newState) +{ + Q_Q(QLowEnergyControllerNew); + if (state == newState) + return; + + state = newState; + emit q->stateChanged(state); +} + QLowEnergyControllerNew::QLowEnergyControllerNew( const QBluetoothAddress &remoteDevice, QObject *parent) @@ -136,6 +153,26 @@ QLowEnergyControllerNew::ControllerState QLowEnergyControllerNew::state() const return d_ptr->state; } +void QLowEnergyControllerNew::connectToDevice() +{ + Q_D(QLowEnergyControllerNew); + + if (state() != QLowEnergyControllerNew::UnconnectedState) + return; + + d->connectToDevice(); +} + +void QLowEnergyControllerNew::disconnectFromDevice() +{ + Q_D(QLowEnergyControllerNew); + + if (state() == QLowEnergyControllerNew::UnconnectedState) + return; + + d->disconnectFromDevice(); +} + QLowEnergyControllerNew::Error QLowEnergyControllerNew::error() const { return d_ptr->error; @@ -145,3 +182,5 @@ QString QLowEnergyControllerNew::errorString() const { return d_ptr->errorString; } + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontrollernew.h b/src/bluetooth/qlowenergycontrollernew.h index 727b0618..16882f58 100644 --- a/src/bluetooth/qlowenergycontrollernew.h +++ b/src/bluetooth/qlowenergycontrollernew.h @@ -45,6 +45,8 @@ #include <QObject> #include <QtBluetooth/QBluetoothAddress> +QT_BEGIN_NAMESPACE + class QLowEnergyControllerNewPrivate; class Q_BLUETOOTH_EXPORT QLowEnergyControllerNew : public QObject { @@ -53,7 +55,8 @@ public: enum Error { NoError, UnknownError, - ConnectionRefused, + UnknownRemoteDeviceError, + NetworkError, InvalidBluetoothAdapterError }; @@ -76,11 +79,14 @@ public: ControllerState state() const; + void connectToDevice(); + void disconnectFromDevice(); + Error error() const; QString errorString() const; -signals: +Q_SIGNALS: void connected(); void disconnected(); void stateChanged(QLowEnergyControllerNew::ControllerState state); @@ -91,4 +97,6 @@ private: QLowEnergyControllerNewPrivate *d_ptr; }; +QT_END_NAMESPACE + #endif // QLOWENERGYCONTROLLERNEW_H diff --git a/src/bluetooth/qlowenergycontrollernew_bluez.cpp b/src/bluetooth/qlowenergycontrollernew_bluez.cpp index 5b779088..9386fe33 100644 --- a/src/bluetooth/qlowenergycontrollernew_bluez.cpp +++ b/src/bluetooth/qlowenergycontrollernew_bluez.cpp @@ -40,6 +40,79 @@ ****************************************************************************/ #include "qlowenergycontrollernew_p.h" +#include "qbluetoothsocket_p.h" +#include <QtCore/QLoggingCategory> +#include <QtBluetooth/QBluetoothSocket> +#define ATTRIBUTE_CHANNEL_ID 4 +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) + +void QLowEnergyControllerNewPrivate::connectToDevice() +{ + setState(QLowEnergyControllerNew::ConnectingState); + if (l2cpSocket) + delete l2cpSocket; + + l2cpSocket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol, this); + connect(l2cpSocket, SIGNAL(connected()), this, SLOT(l2cpConnected())); + connect(l2cpSocket, SIGNAL(disconnected()), this, SLOT(l2cpDisconnected())); + connect(l2cpSocket, SIGNAL(error(QBluetoothSocket::SocketError)), + this, SLOT(l2cpErrorChanged(QBluetoothSocket::SocketError))); + + l2cpSocket->d_ptr->isLowEnergySocket = true; + l2cpSocket->connectToService(remoteDevice, ATTRIBUTE_CHANNEL_ID); +} + +void QLowEnergyControllerNewPrivate::l2cpConnected() +{ + Q_Q(QLowEnergyControllerNew); + + setState(QLowEnergyControllerNew::ConnectedState); + emit q->connected(); +} + +void QLowEnergyControllerNewPrivate::disconnectFromDevice() +{ + setState(QLowEnergyControllerNew::ClosingState); + l2cpSocket->close(); +} + +void QLowEnergyControllerNewPrivate::l2cpDisconnected() +{ + Q_Q(QLowEnergyControllerNew); + + setState(QLowEnergyControllerNew::UnconnectedState); + emit q->disconnected(); +} + +void QLowEnergyControllerNewPrivate::l2cpErrorChanged(QBluetoothSocket::SocketError e) +{ + switch (e) { + case QBluetoothSocket::HostNotFoundError: + setError(QLowEnergyControllerNew::UnknownRemoteDeviceError); + qCDebug(QT_BT_BLUEZ) << "The passed remote device address cannot be found"; + break; + case QBluetoothSocket::NetworkError: + setError(QLowEnergyControllerNew::NetworkError); + qCDebug(QT_BT_BLUEZ) << "Network IO error while talking to LE device"; + break; + case QBluetoothSocket::UnknownSocketError: + case QBluetoothSocket::UnsupportedProtocolError: + case QBluetoothSocket::OperationError: + case QBluetoothSocket::ServiceNotFoundError: + default: + // these errors shouldn't happen -> as it means + // the code in this file has bugs + qCDebug(QT_BT_BLUEZ) << "Unknown l2cp socket error: " << e << l2cpSocket->errorString(); + setError(QLowEnergyControllerNew::UnknownError); + break; + } + + setState(QLowEnergyControllerNew::UnconnectedState); +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontrollernew_p.cpp b/src/bluetooth/qlowenergycontrollernew_p.cpp index 933adbe7..fd761dc9 100644 --- a/src/bluetooth/qlowenergycontrollernew_p.cpp +++ b/src/bluetooth/qlowenergycontrollernew_p.cpp @@ -41,3 +41,16 @@ #include "qlowenergycontrollernew_p.h" +QT_BEGIN_NAMESPACE + +void QLowEnergyControllerNewPrivate::connectToDevice() +{ + +} + +void QLowEnergyControllerNewPrivate::disconnectFromDevice() +{ + +} + +QT_END_NAMESPACE diff --git a/src/bluetooth/qlowenergycontrollernew_p.h b/src/bluetooth/qlowenergycontrollernew_p.h index 3e6ac402..737a8dfd 100644 --- a/src/bluetooth/qlowenergycontrollernew_p.h +++ b/src/bluetooth/qlowenergycontrollernew_p.h @@ -39,24 +39,39 @@ ** ****************************************************************************/ -#include <qglobal.h> +#ifndef QLOWENERGYCONTROLLERNEWPRIVATE_P_H +#define QLOWENERGYCONTROLLERNEWPRIVATE_P_H +#include <qglobal.h> #include "qlowenergycontrollernew.h" -#ifndef QLOWENERGYCONTROLLERNEWPRIVATE_P_H -#define QLOWENERGYCONTROLLERNEWPRIVATE_P_H +#ifdef QT_BLUEZ_BLUETOOTH +#include <QtBluetooth/QBluetoothSocket> +#endif -class QLowEnergyControllerNewPrivate + +QT_BEGIN_NAMESPACE + +class QLowEnergyControllerNewPrivate : QObject { + Q_OBJECT Q_DECLARE_PUBLIC(QLowEnergyControllerNew) public: QLowEnergyControllerNewPrivate() - : state(QLowEnergyControllerNew::UnconnectedState), + : QObject(), + state(QLowEnergyControllerNew::UnconnectedState), error(QLowEnergyControllerNew::NoError) +#ifdef QT_BLUEZ_BLUETOOTH + , l2cpSocket(0) +#endif {} void setError(QLowEnergyControllerNew::Error newError); void validateLocalAdapter(); + void setState(QLowEnergyControllerNew::ControllerState newState); + + void connectToDevice(); + void disconnectFromDevice(); QBluetoothAddress remoteDevice; QBluetoothAddress localAdapter; @@ -65,7 +80,20 @@ public: QLowEnergyControllerNew::Error error; QString errorString; + +private: +#ifdef QT_BLUEZ_BLUETOOTH + QBluetoothSocket *l2cpSocket; + +private slots: + void l2cpConnected(); + void l2cpDisconnected(); + void l2cpErrorChanged(QBluetoothSocket::SocketError); +#endif +private: QLowEnergyControllerNew *q_ptr; }; +QT_END_NAMESPACE + #endif // QLOWENERGYCONTROLLERNEWPRIVATE_P_H diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp index 0984b410..35ffe1d6 100644 --- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp +++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp @@ -753,12 +753,49 @@ void tst_QLowEnergyController::tst_connectNew() const QBluetoothAddress localAdapter = localAdapters.at(0).address(); QLowEnergyControllerNew control(remoteDevice); + QSignalSpy connectedSpy(&control, SIGNAL(connected())); + QSignalSpy disconnectedSpy(&control, SIGNAL(disconnected())); + QCOMPARE(control.localAddress(), localAdapter); QVERIFY(!control.localAddress().isNull()); QCOMPARE(control.remoteAddress(), remoteDevice); QCOMPARE(control.state(), QLowEnergyControllerNew::UnconnectedState); QCOMPARE(control.error(), QLowEnergyControllerNew::NoError); QVERIFY(control.errorString().isEmpty()); + QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.count(), 0); + + bool wasError = false; + control.connectToDevice(); + QTRY_IMPL(control.state() != QLowEnergyControllerNew::ConnectingState, + 10000); + QCOMPARE(disconnectedSpy.count(), 0); + if (control.error() != QLowEnergyControllerNew::NoError) { + //error during connect + QCOMPARE(connectedSpy.count(), 0); + QCOMPARE(control.state(), QLowEnergyControllerNew::UnconnectedState); + wasError = true; + } else if (control.state() == QLowEnergyControllerNew::ConnectingState) { + //timeout + QCOMPARE(connectedSpy.count(), 0); + QVERIFY(control.errorString().isEmpty()); + QCOMPARE(control.error(), QLowEnergyControllerNew::NoError); + QSKIP("Connection to LE device cannot be established. Skipping test."); + return; + } else { + QCOMPARE(control.state(), QLowEnergyControllerNew::ConnectedState); + QCOMPARE(connectedSpy.count(), 1); + QCOMPARE(control.error(), QLowEnergyControllerNew::NoError); + QVERIFY(control.errorString().isEmpty()); + } + + control.disconnectFromDevice(); + QTRY_VERIFY_WITH_TIMEOUT(control.state() == QLowEnergyControllerNew::UnconnectedState, + 10000); + if (wasError) + QCOMPARE(disconnectedSpy.count(), 0); + else + QCOMPARE(disconnectedSpy.count(), 1); } void tst_QLowEnergyController::tst_defaultBehavior() |