summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-06-06 17:08:05 +0200
committerAlex Blasche <alexander.blasche@digia.com>2014-06-16 14:17:25 +0200
commit9f973ffb423b9c6721162ede29e18b7950152a08 (patch)
tree8b1e01c41625f5631fed4c8762e90b66cb256c26
parent9ad271c1448e1d08ccfece022fc2a8c571a6fd1f (diff)
Connect to BTLE device
Change-Id: Iaae61b6a872124d17855d80d106f2b10996501de Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
-rw-r--r--src/bluetooth/qbluetoothsocket.h1
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez.cpp13
-rw-r--r--src/bluetooth/qbluetoothsocket_p.h5
-rw-r--r--src/bluetooth/qlowenergycontrollernew.cpp41
-rw-r--r--src/bluetooth/qlowenergycontrollernew.h12
-rw-r--r--src/bluetooth/qlowenergycontrollernew_bluez.cpp73
-rw-r--r--src/bluetooth/qlowenergycontrollernew_p.cpp13
-rw-r--r--src/bluetooth/qlowenergycontrollernew_p.h38
-rw-r--r--tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp37
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()