summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bluetooth/qlowenergycontroller_win.cpp126
-rw-r--r--src/bluetooth/qlowenergycontroller_win_p.h43
2 files changed, 140 insertions, 29 deletions
diff --git a/src/bluetooth/qlowenergycontroller_win.cpp b/src/bluetooth/qlowenergycontroller_win.cpp
index f7a1611f..27bfb7c7 100644
--- a/src/bluetooth/qlowenergycontroller_win.cpp
+++ b/src/bluetooth/qlowenergycontroller_win.cpp
@@ -45,11 +45,10 @@
#include <QtCore/QIODevice> // for open modes
#include <QtCore/QEvent>
#include <QtCore/QMutex>
+#include <QtCore/QThread>
#include <algorithm> // for std::max
-#include <windows/qwinlowenergybluetooth_p.h>
-
#include <setupapi.h>
QT_BEGIN_NAMESPACE
@@ -690,12 +689,22 @@ QLowEnergyControllerPrivateWin32::QLowEnergyControllerPrivateWin32()
qCWarning(QT_BT_WINDOWS) << "LE is not supported on this OS";
return;
}
+
+ thread = new QThread;
+ threadWorker = new ThreadWorker;
+ threadWorker->moveToThread(thread);
+ connect(threadWorker, &ThreadWorker::jobFinished, this, &QLowEnergyControllerPrivateWin32::jobFinished);
+ connect(thread, &QThread::finished, threadWorker, &ThreadWorker::deleteLater);
+ connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+ thread->start();
}
QLowEnergyControllerPrivateWin32::~QLowEnergyControllerPrivateWin32()
{
QMutexLocker locker(&controllersGuard);
qControllers()->removeAll(this);
+ if (thread)
+ thread->quit();
}
void QLowEnergyControllerPrivateWin32::init()
@@ -1020,17 +1029,20 @@ void QLowEnergyControllerPrivateWin32::writeCharacteristic(
QLowEnergyService::WriteMode mode)
{
Q_ASSERT(!service.isNull());
- if (!service->characteristicList.contains(charHandle))
- return;
- int systemErrorCode = NO_ERROR;
+ if (!service->characteristicList.contains(charHandle)) {
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return;
+ }
- const HANDLE hService = openSystemService(
- remoteDevice, service->uuid, QIODevice::ReadWrite, &systemErrorCode);
+ WriteCharData data;
+ data.systemErrorCode = NO_ERROR;
+ data.hService = openSystemService(
+ remoteDevice, service->uuid, QIODevice::ReadWrite, &data.systemErrorCode);
- if (systemErrorCode != NO_ERROR) {
+ if (data.systemErrorCode != NO_ERROR) {
qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service->uuid.toString()
- << ":" << qt_error_string(systemErrorCode);
+ << ":" << qt_error_string(data.systemErrorCode);
service->setError(QLowEnergyService::CharacteristicWriteError);
return;
}
@@ -1038,35 +1050,58 @@ void QLowEnergyControllerPrivateWin32::writeCharacteristic(
const QLowEnergyServicePrivate::CharData &charDetails
= service->characteristicList[charHandle];
- BTH_LE_GATT_CHARACTERISTIC gattCharacteristic = recoverNativeLeGattCharacteristic(
+ data.gattCharacteristic = recoverNativeLeGattCharacteristic(
service->startHandle, charHandle, charDetails);
- const DWORD flags = (mode == QLowEnergyService::WriteWithResponse)
+ data.flags = (mode == QLowEnergyService::WriteWithResponse)
? BLUETOOTH_GATT_FLAG_NONE
: BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE;
- // TODO: If a device is not connected, this function will block
- // for some time. So, need to re-implement of writeCharacteristic()
- // with use QFutureWatcher.
- setGattCharacteristicValue(hService, &gattCharacteristic,
- newValue, flags, &systemErrorCode);
- closeSystemDevice(hService);
+ ThreadWorkerJob job;
+ job.operation = ThreadWorkerJob::WriteChar;
+ data.newValue = newValue;
+ data.mode = mode;
+ job.data = QVariant::fromValue(data);
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to set value for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(systemErrorCode);
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return;
- }
+ QMetaObject::invokeMethod(threadWorker, "putJob", Qt::QueuedConnection,
+ Q_ARG(ThreadWorkerJob, job));
+}
- updateValueOfCharacteristic(charHandle, newValue, false);
+void QLowEnergyControllerPrivateWin32::jobFinished(const ThreadWorkerJob &job)
+{
+ switch (job.operation) {
+ case ThreadWorkerJob::WriteChar:
+ {
+ const WriteCharData data = job.data.value<WriteCharData>();
+ closeSystemDevice(data.hService);
+ const QLowEnergyHandle charHandle = static_cast<QLowEnergyHandle>(data.gattCharacteristic.AttributeHandle);
+ const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
+
+ if (data.systemErrorCode != NO_ERROR) {
+ const QLowEnergyServicePrivate::CharData &charDetails = service->characteristicList[charHandle];
+ qCWarning(QT_BT_WINDOWS) << "Unable to set value for characteristic"
+ << charDetails.uuid.toString()
+ << "of the service" << service->uuid.toString()
+ << ":" << qt_error_string(data.systemErrorCode);
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return;
+ }
+
+ updateValueOfCharacteristic(charHandle, data.newValue, false);
- if (mode == QLowEnergyService::WriteWithResponse) {
- const QLowEnergyCharacteristic ch(service, charHandle);
- emit service->characteristicWritten(ch, newValue);
+ if (data.mode == QLowEnergyService::WriteWithResponse) {
+ const QLowEnergyCharacteristic ch = characteristicForHandle(charHandle);
+ emit service->characteristicWritten(ch, data.newValue);
+ }
+ }
+ break;
+ case ThreadWorkerJob::ReadChar:
+ case ThreadWorkerJob::WriteDescr:
+ case ThreadWorkerJob::ReadDescr:
+ break;
}
+
+ QMetaObject::invokeMethod(threadWorker, "runPendingJob", Qt::QueuedConnection);
}
void QLowEnergyControllerPrivateWin32::readDescriptor(
@@ -1219,4 +1254,37 @@ void QLowEnergyControllerPrivateWin32::addToGenericAttributeList(const QLowEnerg
Q_UNIMPLEMENTED();
}
+void ThreadWorker::putJob(const ThreadWorkerJob &job)
+{
+ m_jobs.append(job);
+ if (m_jobs.count() == 1)
+ runPendingJob();
+}
+
+void ThreadWorker::runPendingJob()
+{
+ if (!m_jobs.count())
+ return;
+
+ ThreadWorkerJob job = m_jobs.first();
+
+ switch (job.operation) {
+ case ThreadWorkerJob::WriteChar:
+ {
+ WriteCharData data = job.data.value<WriteCharData>();
+ setGattCharacteristicValue(data.hService, &data.gattCharacteristic,
+ data.newValue, data.flags, &data.systemErrorCode);
+ job.data = QVariant::fromValue(data);
+ }
+ break;
+ case ThreadWorkerJob::ReadChar:
+ case ThreadWorkerJob::WriteDescr:
+ case ThreadWorkerJob::ReadDescr:
+ break;
+ }
+
+ m_jobs.removeFirst();
+ emit jobFinished(job);
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_win_p.h b/src/bluetooth/qlowenergycontroller_win_p.h
index 9c2d4f92..64f824e6 100644
--- a/src/bluetooth/qlowenergycontroller_win_p.h
+++ b/src/bluetooth/qlowenergycontroller_win_p.h
@@ -59,8 +59,47 @@
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+#include <windows/qwinlowenergybluetooth_p.h>
+
QT_BEGIN_NAMESPACE
+class QThread;
+class QLowEnergyControllerPrivateWin32;
+
+class ThreadWorkerJob
+{
+public:
+ enum Operation { WriteChar, ReadChar, WriteDescr, ReadDescr };
+ Operation operation;
+ QVariant data;
+};
+
+Q_DECLARE_METATYPE(ThreadWorkerJob)
+
+struct WriteCharData
+{
+ QByteArray newValue;
+ QLowEnergyService::WriteMode mode;
+ HANDLE hService;
+ DWORD flags;
+ BTH_LE_GATT_CHARACTERISTIC gattCharacteristic;
+ int systemErrorCode;
+};
+
+Q_DECLARE_METATYPE(WriteCharData)
+
+class ThreadWorker : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE void putJob(const ThreadWorkerJob &job);
+ Q_INVOKABLE void runPendingJob();
+signals:
+ void jobFinished(const ThreadWorkerJob &job);
+private:
+ QVector<ThreadWorkerJob> m_jobs;
+};
+
class QLowEnergyServiceData;
extern void registerQLowEnergyControllerMetaType();
@@ -105,9 +144,13 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+public slots:
+ void jobFinished(const ThreadWorkerJob &job);
protected:
void customEvent(QEvent *e);
private:
+ QThread *thread = nullptr;
+ ThreadWorker *threadWorker = nullptr;
QString deviceSystemPath;
};