summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qlowenergycontroller.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qlowenergycontroller.cpp')
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
new file mode 100644
index 00000000..32fbd37e
--- /dev/null
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlowenergycontroller.h"
+#include "qlowenergycontroller_p.h"
+
+#include <QtBluetooth/QBluetoothLocalDevice>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+void QLowEnergyControllerPrivate::setError(
+ QLowEnergyController::Error newError)
+{
+ Q_Q(QLowEnergyController);
+ error = newError;
+
+ switch (newError) {
+ case QLowEnergyController::UnknownRemoteDeviceError:
+ errorString = QLowEnergyController::tr("Remote device cannot be found");
+ break;
+ case QLowEnergyController::InvalidBluetoothAdapterError:
+ errorString = QLowEnergyController::tr("Cannot find local adapter");
+ break;
+ case QLowEnergyController::NetworkError:
+ errorString = QLowEnergyController::tr("Error occurred during connection I/O");
+ break;
+ case QLowEnergyController::UnknownError:
+ default:
+ errorString = QLowEnergyController::tr("Unknown Error");
+ break;
+ }
+
+ emit q->error(newError);
+}
+
+bool QLowEnergyControllerPrivate::isValidLocalAdapter()
+{
+ if (localAdapter.isNull())
+ return false;
+
+ const QList<QBluetoothHostInfo> foundAdapters = QBluetoothLocalDevice::allDevices();
+ bool adapterFound = false;
+
+ foreach (const QBluetoothHostInfo &info, foundAdapters) {
+ if (info.address() == localAdapter) {
+ adapterFound = true;
+ break;
+ }
+ }
+
+ return adapterFound;
+}
+
+void QLowEnergyControllerPrivate::setState(
+ QLowEnergyController::ControllerState newState)
+{
+ Q_Q(QLowEnergyController);
+ if (state == newState)
+ return;
+
+ state = newState;
+ emit q->stateChanged(state);
+}
+
+void QLowEnergyControllerPrivate::invalidateServices()
+{
+ foreach (const QSharedPointer<QLowEnergyServicePrivate> service, serviceList.values()) {
+ service->setController(0);
+ service->setState(QLowEnergyService::InvalidService);
+ }
+
+ serviceList.clear();
+}
+
+QSharedPointer<QLowEnergyServicePrivate> QLowEnergyControllerPrivate::serviceForHandle(
+ QLowEnergyHandle handle)
+{
+ foreach (QSharedPointer<QLowEnergyServicePrivate> service, serviceList.values())
+ if (service->startHandle <= handle && handle <= service->endHandle)
+ return service;
+
+ return QSharedPointer<QLowEnergyServicePrivate>();
+}
+
+/*!
+ Returns a valid characteristic if the given handle is the
+ handle of the characteristic itself or one of its descriptors
+ */
+QLowEnergyCharacteristic QLowEnergyControllerPrivate::characteristicForHandle(
+ QLowEnergyHandle handle)
+{
+ QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(handle);
+ if (service.isNull())
+ return QLowEnergyCharacteristic();
+
+ if (service->characteristicList.isEmpty())
+ return QLowEnergyCharacteristic();
+
+ // check whether it is the handle of a characteristic header
+ if (service->characteristicList.contains(handle))
+ return QLowEnergyCharacteristic(service, handle);
+
+ // check whether it is the handle of the characteristic value or its descriptors
+ QList<QLowEnergyHandle> charHandles = service->characteristicList.keys();
+ std::sort(charHandles.begin(), charHandles.end());
+ for (int i = charHandles.size() - 1; i >= 0; i--) {
+ if (charHandles.at(i) > handle)
+ continue;
+
+ return QLowEnergyCharacteristic(service, charHandles.at(i));
+ }
+
+ return QLowEnergyCharacteristic();
+}
+
+/*!
+ Returns a valid descriptor if \a handle blongs to a descriptor;
+ otherwise an invalid one.
+ */
+QLowEnergyDescriptor QLowEnergyControllerPrivate::descriptorForHandle(
+ QLowEnergyHandle handle)
+{
+ const QLowEnergyCharacteristic matchingChar = characteristicForHandle(handle);
+ if (!matchingChar.isValid())
+ return QLowEnergyDescriptor();
+
+ const QLowEnergyServicePrivate::CharData charData = matchingChar.
+ d_ptr->characteristicList[matchingChar.attributeHandle()];
+
+ if (charData.descriptorList.contains(handle))
+ return QLowEnergyDescriptor(matchingChar.d_ptr, matchingChar.attributeHandle(),
+ handle);
+
+ return QLowEnergyDescriptor();
+}
+
+void QLowEnergyControllerPrivate::updateValueOfCharacteristic(
+ QLowEnergyHandle charHandle, const QByteArray &value)
+{
+ QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
+ if (!service.isNull() && service->characteristicList.contains(charHandle))
+ service->characteristicList[charHandle].value = value;
+}
+
+void QLowEnergyControllerPrivate::updateValueOfDescriptor(
+ QLowEnergyHandle charHandle, QLowEnergyHandle descriptorHandle,
+ const QByteArray &value)
+{
+ QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
+ if (service.isNull() || !service->characteristicList.contains(charHandle))
+ return;
+
+ if (!service->characteristicList[charHandle].descriptorList.contains(descriptorHandle))
+ return;
+
+ service->characteristicList[charHandle].descriptorList[descriptorHandle].value = value;
+}
+
+QLowEnergyController::QLowEnergyController(
+ const QBluetoothAddress &remoteDevice,
+ QObject *parent)
+ : QObject(parent), d_ptr(new QLowEnergyControllerPrivate())
+{
+ Q_D(QLowEnergyController);
+ d->q_ptr = this;
+ d->remoteDevice = remoteDevice;
+ d->localAdapter = QBluetoothLocalDevice().address();
+}
+
+QLowEnergyController::QLowEnergyController(
+ const QBluetoothAddress &remoteDevice,
+ const QBluetoothAddress &localDevice,
+ QObject *parent)
+ : QObject(parent), d_ptr(new QLowEnergyControllerPrivate())
+{
+ Q_D(QLowEnergyController);
+ d->q_ptr = this;
+ d->remoteDevice = remoteDevice;
+ d->localAdapter = localDevice;
+}
+
+QLowEnergyController::~QLowEnergyController()
+{
+ disconnectFromDevice(); //in case we were connected
+ delete d_ptr;
+}
+
+/*!
+ Returns the address of the local Bluetooth adapter being used for the
+ communication.
+
+ If this class instance was requested to use the default adapter
+ but there was no default adapter when creating this
+ class instance, the returned \l QBluetoothAddress will be null.
+
+ \sa QBluetoothAddress::isNull()
+ */
+QBluetoothAddress QLowEnergyController::localAddress() const
+{
+ return d_ptr->localAdapter;
+}
+
+QBluetoothAddress QLowEnergyController::remoteAddress() const
+{
+ return d_ptr->remoteDevice;
+}
+
+QLowEnergyController::ControllerState QLowEnergyController::state() const
+{
+ return d_ptr->state;
+}
+
+void QLowEnergyController::connectToDevice()
+{
+ Q_D(QLowEnergyController);
+
+ if (!d->isValidLocalAdapter()) {
+ d->setError(QLowEnergyController::InvalidBluetoothAdapterError);
+ return;
+ }
+
+ if (state() != QLowEnergyController::UnconnectedState)
+ return;
+
+ d->connectToDevice();
+}
+
+void QLowEnergyController::disconnectFromDevice()
+{
+ Q_D(QLowEnergyController);
+
+ if (state() == QLowEnergyController::UnconnectedState)
+ return;
+
+ d->invalidateServices();
+ d->disconnectFromDevice();
+}
+
+void QLowEnergyController::discoverServices()
+{
+ Q_D(QLowEnergyController);
+
+ if (d->state != QLowEnergyController::ConnectedState)
+ return;
+
+ d->discoverServices();
+}
+
+QList<QBluetoothUuid> QLowEnergyController::services() const
+{
+ return d_ptr->serviceList.keys();
+}
+
+QLowEnergyService *QLowEnergyController::createServiceObject(
+ const QBluetoothUuid &serviceUuid, QObject *parent)
+{
+ Q_D(QLowEnergyController);
+ if (!d->serviceList.contains(serviceUuid))
+ return 0;
+
+ QLowEnergyService *service = new QLowEnergyService(
+ d->serviceList.value(serviceUuid), parent);
+
+ return service;
+}
+
+QLowEnergyController::Error QLowEnergyController::error() const
+{
+ return d_ptr->error;
+}
+
+QString QLowEnergyController::errorString() const
+{
+ return d_ptr->errorString;
+}
+
+QT_END_NAMESPACE