summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/CMakeLists.txt5
-rw-r--r--core/qt-ble.cpp228
-rw-r--r--core/qt-ble.h38
-rw-r--r--core/qtserialbluetooth.cpp14
4 files changed, 284 insertions, 1 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 77521d6a1..5622f5e65 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -24,6 +24,11 @@ if(BTSUPPORT)
set(BT_CORE_SRC_FILES qtserialbluetooth.cpp)
endif()
+if(BLESUPPORT)
+ add_definitions(-DBLE_SUPPORT)
+ set(BT_CORE_SRC_FILES qt-ble.cpp)
+endif()
+
# compile the core library, in C.
set(SUBSURFACE_CORE_LIB_SRCS
btdiscovery.cpp
diff --git a/core/qt-ble.cpp b/core/qt-ble.cpp
new file mode 100644
index 000000000..3fe7e3eea
--- /dev/null
+++ b/core/qt-ble.cpp
@@ -0,0 +1,228 @@
+#include <errno.h>
+
+#include <QtBluetooth/QBluetoothAddress>
+#include <QLowEnergyController>
+#include <QEventLoop>
+#include <QTimer>
+#include <QDebug>
+
+#include <libdivecomputer/version.h>
+
+#include "libdivecomputer.h"
+#include "core/qt-ble.h"
+
+#if defined(SSRF_CUSTOM_IO)
+
+#include <libdivecomputer/custom_io.h>
+
+extern "C" {
+
+void BLEObject::serviceStateChanged(QLowEnergyService::ServiceState s)
+{
+ QList<QLowEnergyCharacteristic> list;
+
+ list = service->characteristics();
+
+ Q_FOREACH(QLowEnergyCharacteristic c, list) {
+ fprintf(stderr, " %s\n", c.uuid().toString().toUtf8().data());
+ }
+}
+
+void BLEObject::characteristcStateChanged(const QLowEnergyCharacteristic &c, const QByteArray &value)
+{
+ receivedPackets.append(value);
+ waitForPacket.exit();
+}
+
+void BLEObject::writeCompleted(const QLowEnergyDescriptor &d, const QByteArray &value)
+{
+ fprintf(stderr, "Write completed\n");
+}
+
+void BLEObject::addService(const QBluetoothUuid &newService)
+{
+ const char *uuid = newService.toString().toUtf8().data();
+
+ fprintf(stderr, "Found service %s\n", uuid);
+ if (uuid[1] == '0') {
+ fprintf(stderr, " .. ignoring\n");
+ return;
+ }
+ service = controller->createServiceObject(newService, this);
+ fprintf(stderr, " .. created service object %p\n", service);
+ if (service) {
+ connect(service, &QLowEnergyService::stateChanged, this, &BLEObject::serviceStateChanged);
+ connect(service, &QLowEnergyService::characteristicChanged, this, &BLEObject::characteristcStateChanged);
+ connect(service, &QLowEnergyService::descriptorWritten, this, &BLEObject::writeCompleted);
+ service->discoverDetails();
+ }
+}
+
+BLEObject::BLEObject(QLowEnergyController *c)
+{
+ controller = c;
+}
+
+BLEObject::~BLEObject()
+{
+fprintf(stderr, "Deleting BLE object\n");
+}
+
+dc_status_t BLEObject::write(const void* data, size_t size, size_t *actual)
+{
+ QList<QLowEnergyCharacteristic> list = service->characteristics();
+ QByteArray bytes((const char *)data, (int) size);
+
+ if (!list.isEmpty()) {
+ const QLowEnergyCharacteristic &c = list.constFirst();
+ QLowEnergyService::WriteMode mode;
+
+ mode = (c.properties() & QLowEnergyCharacteristic::WriteNoResponse) ?
+ QLowEnergyService::WriteWithoutResponse :
+ QLowEnergyService::WriteWithResponse;
+
+ service->writeCharacteristic(c, bytes, mode);
+ return DC_STATUS_SUCCESS;
+ }
+
+ return DC_STATUS_IO;
+}
+
+dc_status_t BLEObject::read(void* data, size_t size, size_t *actual)
+{
+ if (receivedPackets.isEmpty()) {
+ QList<QLowEnergyCharacteristic> list = service->characteristics();
+ if (list.isEmpty())
+ return DC_STATUS_IO;
+
+ const QLowEnergyCharacteristic &c = list.constLast();
+
+ QTimer timer;
+ int msec = 5000;
+ timer.setSingleShot(true);
+
+ waitForPacket.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
+ timer.start(msec);
+ waitForPacket.exec();
+ }
+
+ // Still no packet?
+ if (receivedPackets.isEmpty())
+ return DC_STATUS_IO;
+
+ QByteArray packet = receivedPackets.takeFirst();
+ if (size > packet.size())
+ size = packet.size();
+ memcpy(data, packet.data(), size);
+ *actual = size;
+ return DC_STATUS_SUCCESS;
+}
+
+dc_status_t qt_ble_open(dc_custom_io_t *io, dc_context_t *context, const char *devaddr)
+{
+ QBluetoothAddress remoteDeviceAddress(devaddr);
+
+ // HACK ALERT! Qt 5.9 needs this for proper Bluez operation
+ qputenv("QT_DEFAULT_CENTRAL_SERVICES", "1");
+
+ QLowEnergyController *controller = new QLowEnergyController(remoteDeviceAddress);
+
+fprintf(stderr, "qt_ble_open(%s)\n", devaddr);
+
+ // Wait until the connection succeeds or until an error occurs
+ QEventLoop loop;
+ loop.connect(controller, SIGNAL(connected()), SLOT(quit()));
+ loop.connect(controller, SIGNAL(error(QLowEnergyController::Error)), SLOT(quit()));
+
+ // Create a timer. If the connection doesn't succeed after five seconds or no error occurs then stop the opening step
+ QTimer timer;
+ int msec = 5000;
+ timer.setSingleShot(true);
+ loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
+
+ // Try to connect to the device
+ controller->connectToDevice();
+ timer.start(msec);
+ loop.exec();
+
+ switch (controller->state()) {
+ case QLowEnergyController::ConnectedState:
+ break;
+ default:
+ report_error("Failed to connect to %s: '%s'", devaddr, controller->errorString().toUtf8().data());
+ controller->disconnectFromDevice();
+ delete controller;
+ return DC_STATUS_IO;
+ }
+
+fprintf(stderr, "Connected to device %s\n", devaddr);
+
+ /* We need to discover services etc here! */
+ BLEObject *ble = new BLEObject(controller);
+ loop.connect(controller, SIGNAL(discoveryFinished()), SLOT(quit()));
+ ble->connect(controller, SIGNAL(serviceDiscovered(QBluetoothUuid)), SLOT(addService(QBluetoothUuid)));
+
+fprintf(stderr, " .. discovering services\n");
+
+ controller->discoverServices();
+ timer.start(msec);
+ loop.exec();
+
+fprintf(stderr, " .. done discovering services\n");
+
+fprintf(stderr, " .. discovering details\n");
+
+ timer.start(msec);
+ loop.exec();
+
+fprintf(stderr, " .. done waiting\n");
+
+fprintf(stderr, " .. enabling notifications\n");
+
+ /* Enable notifications */
+ QList<QLowEnergyCharacteristic> list = ble->service->characteristics();
+
+ if (!list.isEmpty()) {
+ const QLowEnergyCharacteristic &c = list.constLast();
+ QList<QLowEnergyDescriptor> l = c.descriptors();
+
+fprintf(stderr, "Descriptor list (%p, %d)\n", l, l.length());
+
+ if (!l.isEmpty()) {
+ QLowEnergyDescriptor d = l.first();
+
+fprintf(stderr, "Descriptor: %s uuid: %s\n", d.name().toUtf8().data(), d.uuid().toString().toUtf8().data());
+
+ ble->service->writeDescriptor(d, QByteArray::fromHex("0100"));
+ }
+ }
+
+ // Fill in info
+ io->userdata = (void *)ble;
+ return DC_STATUS_SUCCESS;
+}
+
+dc_status_t qt_ble_close(dc_custom_io_t *io)
+{
+ BLEObject *ble = (BLEObject *) io->userdata;
+
+ io->userdata = NULL;
+ delete ble;
+
+ return DC_STATUS_SUCCESS;
+}
+
+dc_status_t qt_ble_read(dc_custom_io_t *io, void* data, size_t size, size_t *actual)
+{
+ BLEObject *ble = (BLEObject *) io->userdata;
+ return ble->read(data, size, actual);
+}
+
+dc_status_t qt_ble_write(dc_custom_io_t *io, const void* data, size_t size, size_t *actual)
+{
+ BLEObject *ble = (BLEObject *) io->userdata;
+ return ble->write(data, size, actual);
+}
+
+} /* extern "C" */
+#endif
diff --git a/core/qt-ble.h b/core/qt-ble.h
new file mode 100644
index 000000000..b819b0123
--- /dev/null
+++ b/core/qt-ble.h
@@ -0,0 +1,38 @@
+#ifndef QT_BLE_H
+#define QT_BLE_H
+
+#include <QLowEnergyController>
+#include <QEventLoop>
+
+class BLEObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ BLEObject(QLowEnergyController *c);
+ ~BLEObject();
+ dc_status_t write(const void* data, size_t size, size_t *actual);
+ dc_status_t read(void* data, size_t size, size_t *actual);
+ QLowEnergyService *service;
+
+public slots:
+ void addService(const QBluetoothUuid &newService);
+ void serviceStateChanged(QLowEnergyService::ServiceState s);
+ void characteristcStateChanged(const QLowEnergyCharacteristic &c, const QByteArray &value);
+ void writeCompleted(const QLowEnergyDescriptor &d, const QByteArray &value);
+
+private:
+ QLowEnergyController *controller;
+ QList<QByteArray> receivedPackets;
+ QEventLoop waitForPacket;
+};
+
+
+extern "C" {
+dc_status_t qt_ble_open(dc_custom_io_t *io, dc_context_t *context, const char *name);
+dc_status_t qt_ble_read(dc_custom_io_t *io, void* data, size_t size, size_t *actual);
+dc_status_t qt_ble_write(dc_custom_io_t *io, const void* data, size_t size, size_t *actual);
+dc_status_t qt_ble_close(dc_custom_io_t *io);
+}
+
+#endif
diff --git a/core/qtserialbluetooth.cpp b/core/qtserialbluetooth.cpp
index d23265d42..ab05a1c73 100644
--- a/core/qtserialbluetooth.cpp
+++ b/core/qtserialbluetooth.cpp
@@ -19,6 +19,10 @@
#include <libdivecomputer/custom_io.h>
+#ifdef BLE_SUPPORT
+# include "qt-ble.h"
+#endif
+
QList<QBluetoothUuid> registeredUuids;
static QBluetoothUuid getBtUuid()
@@ -414,7 +418,15 @@ dc_custom_io_t qt_serial_ops = {
.serial_set_dtr = NULL,
.serial_set_rts = NULL,
.serial_set_halfduplex = NULL,
- .serial_set_break = NULL
+ .serial_set_break = NULL,
+
+#ifdef BLE_SUPPORT
+ .packet_size = 20,
+ .packet_open = qt_ble_open,
+ .packet_close = qt_ble_close,
+ .packet_read = qt_ble_read,
+ .packet_write = qt_ble_write,
+#endif
};
dc_custom_io_t* get_qt_serial_ops() {