aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/CMakeLists.txt1
-rw-r--r--core/btdiscovery.cpp165
-rw-r--r--core/btdiscovery.h64
-rw-r--r--core/downloadfromdcthread.cpp56
-rw-r--r--core/downloadfromdcthread.h11
-rw-r--r--mobile-widgets/qml/DownloadFromDiveComputer.qml10
-rw-r--r--mobile-widgets/qmlmanager.cpp168
-rw-r--r--mobile-widgets/qmlmanager.h29
8 files changed, 305 insertions, 199 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index b2effd519..77521d6a1 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -26,6 +26,7 @@ endif()
# compile the core library, in C.
set(SUBSURFACE_CORE_LIB_SRCS
+ btdiscovery.cpp
cochran.c
datatrak.c
deco.c
diff --git a/core/btdiscovery.cpp b/core/btdiscovery.cpp
new file mode 100644
index 000000000..cf68bf8eb
--- /dev/null
+++ b/core/btdiscovery.cpp
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "btdiscovery.h"
+#include "downloadfromdcthread.h"
+#include <QDebug>
+
+BTDiscovery *BTDiscovery::m_instance = NULL;
+
+BTDiscovery::BTDiscovery(QObject *parent)
+{
+ Q_UNUSED(parent)
+ if (m_instance) {
+ qDebug() << "trying to create an additional BTDiscovery object";
+ return;
+ }
+ m_instance = this;
+#if defined(BT_SUPPORT)
+ if (localBtDevice.isValid() &&
+ localBtDevice.hostMode() == QBluetoothLocalDevice::HostConnectable) {
+ btPairedDevices.clear();
+ qDebug() << "localDevice " + localBtDevice.name() + " is valid, starting discovery";
+#if defined(Q_OS_LINUX)
+ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BTDiscovery::btDeviceDiscovered);
+ discoveryAgent->start();
+#endif
+#if defined(Q_OS_ANDROID) && defined(BT_SUPPORT)
+ getBluetoothDevices();
+#endif
+ for (int i = 0; i < btPairedDevices.length(); i++) {
+ qDebug() << "Paired =" << btPairedDevices[i].name << btPairedDevices[i].address.toString();
+ }
+#if defined(Q_OS_LINUX)
+ discoveryAgent->stop();
+#endif
+ } else {
+ qDebug() << "localBtDevice isn't valid";
+ }
+#endif
+}
+
+BTDiscovery::~BTDiscovery()
+{
+ m_instance = NULL;
+#if defined(BT_SUPPORT)
+ free(discoveryAgent);
+#endif
+}
+
+BTDiscovery *BTDiscovery::instance()
+{
+ if (!m_instance)
+ m_instance = new BTDiscovery();
+ return m_instance;
+}
+
+#if defined(BT_SUPPORT)
+
+extern void addBtUuid(QBluetoothUuid uuid);
+extern QHash<QString, QStringList> productList;
+extern QStringList vendorList;
+
+void BTDiscovery::btDeviceDiscovered(const QBluetoothDeviceInfo &device)
+{
+ btPairedDevice this_d;
+ this_d.address = device.address();
+ this_d.name = device.name();
+ btPairedDevices.append(this_d);
+
+ QString newDevice = device.name();
+
+ // all the HW OSTC BT computers show up as "OSTC" + some other text, depending on model
+ if (newDevice.startsWith("OSTC"))
+ newDevice = "OSTC 3";
+ QList<QBluetoothUuid> serviceUuids = device.serviceUuids();
+ foreach (QBluetoothUuid id, serviceUuids) {
+ addBtUuid(id);
+ qDebug() << id.toByteArray();
+ }
+ qDebug() << "Found new device " + newDevice + " (" + device.address().toString() + ")";
+ QString vendor, product;
+ foreach (vendor, productList.keys()) {
+ if (productList[vendor].contains(newDevice)) {
+ qDebug() << "this could be a " + vendor + " " +
+ (newDevice == "OSTC 3" ? "OSTC family" : newDevice);
+ struct btVendorProduct btVP;
+ btVP.btdi = device;
+ btVP.vendorIdx = vendorList.indexOf(vendor);
+ btVP.productIdx = productList[vendor].indexOf(newDevice);
+ qDebug() << "adding new btDCs entry" << newDevice << btVP.vendorIdx << btVP.productIdx;
+ btDCs << btVP;
+ }
+ }
+}
+
+QList <struct btVendorProduct> BTDiscovery::getBtDcs()
+{
+ return btDCs;
+}
+
+
+// Android: As Qt is not able to pull the pairing data from a device, i
+// a lengthy discovery process is needed to see what devices are paired. On
+// https://forum.qt.io/topic/46075/solved-bluetooth-list-paired-devices
+// user s.frings74 does, however, present a solution to this using JNI.
+// Currently, this code is taken "as is".
+
+#if defined(Q_OS_ANDROID)
+void BTDiscovery::getBluetoothDevices()
+{
+ struct BTDiscovery::btPairedDevice result;
+ // Query via Android Java API.
+
+ // returns a BluetoothAdapter
+ QAndroidJniObject adapter=QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter","getDefaultAdapter","()Landroid/bluetooth/BluetoothAdapter;");
+ if (checkException("BluetoothAdapter.getDefaultAdapter()", &adapter)) {
+ return;
+ }
+ // returns a Set<BluetoothDevice>
+ QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;");
+ if (checkException("BluetoothAdapter.getBondedDevices()", &pairedDevicesSet)) {
+ return;
+ }
+ jint size=pairedDevicesSet.callMethod<jint>("size");
+ checkException("Set<BluetoothDevice>.size()", &pairedDevicesSet);
+ if (size > 0) {
+ // returns an Iterator<BluetoothDevice>
+ QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;");
+ if (checkException("Set<BluetoothDevice>.iterator()", &iterator)) {
+ return;
+ }
+ for (int i = 0; i < size; i++) {
+ // returns a BluetoothDevice
+ QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;");
+ if (checkException("Iterator<BluetoothDevice>.next()", &dev)) {
+ continue;
+ }
+
+ result.address = QBluetoothAddress(dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString());
+ result.name = dev.callObjectMethod("getName", "()Ljava/lang/String;").toString();
+
+ btPairedDevices.append(result);
+ }
+ }
+}
+
+bool BTDiscovery::checkException(const char* method, const QAndroidJniObject *obj)
+{
+ static QAndroidJniEnvironment env;
+ bool result = false;
+
+ if (env->ExceptionCheck()) {
+ qCritical("Exception in %s", method);
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ result=true;
+ }
+ if (!(obj == NULL || obj->isValid())) {
+ qCritical("Invalid object returned by %s", method);
+ result=true;
+ }
+ return result;
+}
+#endif // Q_OS_ANDROID
+#endif // BT_SUPPORT
diff --git a/core/btdiscovery.h b/core/btdiscovery.h
new file mode 100644
index 000000000..796be908a
--- /dev/null
+++ b/core/btdiscovery.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef BTDISCOVERY_H
+#define BTDISCOVERY_H
+
+#include <QObject>
+#include <QString>
+#include <QLoggingCategory>
+#if defined(BT_SUPPORT)
+#include <QBluetoothLocalDevice>
+#include <QBluetoothDeviceDiscoveryAgent>
+#include <QBluetoothUuid>
+
+struct btVendorProduct {
+ QBluetoothDeviceInfo btdi;
+ int vendorIdx;
+ int productIdx;
+};
+
+#endif
+#if defined(Q_OS_ANDROID)
+#include <QAndroidJniObject>
+#endif
+
+class BTDiscovery : public QObject {
+ Q_OBJECT
+
+public:
+ BTDiscovery(QObject *parent = NULL);
+ ~BTDiscovery();
+ static BTDiscovery *instance();
+
+#if defined(BT_SUPPORT)
+ struct btPairedDevice {
+ QBluetoothAddress address;
+ QString name;
+ };
+ void btDeviceDiscovered(const QBluetoothDeviceInfo &device);
+#if defined(Q_OS_ANDROID)
+ void getBluetoothDevices();
+#endif
+ QList<struct btVendorProduct> getBtDcs();
+#endif
+private:
+ static BTDiscovery *m_instance;
+#if defined(BT_SUPPORT)
+ QList<struct btVendorProduct> btDCs;
+#endif
+#if defined(Q_OS_ANDROID)
+ bool checkException(const char* method, const QAndroidJniObject* obj);
+#endif
+
+#if defined(BT_SUPPORT)
+ QList<struct btPairedDevice> btPairedDevices;
+ QBluetoothLocalDevice localBtDevice;
+ QBluetoothDeviceDiscoveryAgent *discoveryAgent;
+#endif
+
+signals:
+ void dcVendorChanged();
+ void dcProductChanged();
+ void dcBtChanged();
+};
+
+#endif // BTDISCOVERY_H
diff --git a/core/downloadfromdcthread.cpp b/core/downloadfromdcthread.cpp
index 20f170125..bd8a637f1 100644
--- a/core/downloadfromdcthread.cpp
+++ b/core/downloadfromdcthread.cpp
@@ -99,8 +99,15 @@ void fill_computer_list()
#endif
}
+DCDeviceData *DCDeviceData::m_instance = NULL;
+
DCDeviceData::DCDeviceData(QObject *parent) : QObject(parent)
{
+ if (m_instance) {
+ qDebug() << "already have an instance of DCDevieData";
+ return;
+ }
+ m_instance = this;
memset(&data, 0, sizeof(data));
data.trip = nullptr;
data.download_table = nullptr;
@@ -108,6 +115,18 @@ DCDeviceData::DCDeviceData(QObject *parent) : QObject(parent)
data.deviceid = 0;
}
+DCDeviceData *DCDeviceData::instance()
+{
+ if (!m_instance)
+ m_instance = new DCDeviceData();
+ return m_instance;
+}
+
+QStringList DCDeviceData::getProductListFromVendor(const QString &vendor)
+{
+ return productList[vendor];
+}
+
DCDeviceData * DownloadThread::data()
{
return m_data;
@@ -222,3 +241,40 @@ device_data_t* DCDeviceData::internalData()
{
return &data;
}
+
+int DCDeviceData::getDetectedVendorIndex()
+{
+#if defined(BT_SUPPORT)
+ QList<btVendorProduct> btDCs = BTDiscovery::instance()->getBtDcs();
+ if (!btDCs.isEmpty()) {
+ qDebug() << "getVendorIdx" << btDCs.first().vendorIdx;
+ return btDCs.first().vendorIdx;
+ }
+#endif
+ return -1;
+}
+
+int DCDeviceData::getDetectedProductIndex()
+{
+#if defined(BT_SUPPORT)
+ QList<btVendorProduct> btDCs = BTDiscovery::instance()->getBtDcs();
+ if (!btDCs.isEmpty()) {
+ qDebug() << "getProductIdx" << btDCs.first().productIdx;
+ return btDCs.first().productIdx;
+ }
+#endif
+ return -1;
+}
+
+QString DCDeviceData::getDetectedDeviceAddress()
+{
+#if BT_SUPPORT
+ QList<btVendorProduct> btDCs = BTDiscovery::instance()->getBtDcs();
+ if (!btDCs.isEmpty()) {
+ QString btAddr = btDCs.first().btdi.address().toString();
+ qDebug() << "getBtAddress" << btAddr;
+ return btAddr;
+ }
+ return QString();
+#endif
+}
diff --git a/core/downloadfromdcthread.h b/core/downloadfromdcthread.h
index bf203a85f..13cca1438 100644
--- a/core/downloadfromdcthread.h
+++ b/core/downloadfromdcthread.h
@@ -4,9 +4,11 @@
#include <QThread>
#include <QMap>
#include <QHash>
+#include <QLoggingCategory>
#include "dive.h"
#include "libdivecomputer.h"
+#include "core/btdiscovery.h"
/* Helper object for access of Device Data in QML */
class DCDeviceData : public QObject {
@@ -25,6 +27,7 @@ class DCDeviceData : public QObject {
public:
DCDeviceData(QObject *parent = nullptr);
+ static DCDeviceData *instance();
QString vendor() const;
QString product() const;
@@ -41,6 +44,11 @@ public:
/* this needs to be a pointer to make the C-API happy */
device_data_t* internalData();
+ Q_INVOKABLE QStringList getProductListFromVendor(const QString& vendor);
+ Q_INVOKABLE int getDetectedVendorIndex();
+ Q_INVOKABLE int getDetectedProductIndex();
+ Q_INVOKABLE QString getDetectedDeviceAddress();
+
public slots:
void setVendor(const QString& vendor);
void setProduct(const QString& product);
@@ -53,6 +61,7 @@ public slots:
void setSaveDump(bool dumpMode);
void setSaveLog(bool saveLog);
private:
+ static DCDeviceData *m_instance;
device_data_t data;
};
@@ -64,7 +73,7 @@ public:
DownloadThread();
void run() override;
- DCDeviceData *data();
+ Q_INVOKABLE DCDeviceData *data();
QString error;
private:
diff --git a/mobile-widgets/qml/DownloadFromDiveComputer.qml b/mobile-widgets/qml/DownloadFromDiveComputer.qml
index b05c1fc9f..8b9f642ff 100644
--- a/mobile-widgets/qml/DownloadFromDiveComputer.qml
+++ b/mobile-widgets/qml/DownloadFromDiveComputer.qml
@@ -57,11 +57,11 @@ Kirigami.Page {
id: comboVendor
Layout.fillWidth: true
model: vendorList
- currentIndex: manager.getVendorIndex()
+ currentIndex: downloadThread.data().getDetectedVendorIndex()
onCurrentTextChanged: {
- comboProduct.model = manager.getDCListFromVendor(comboVendor.currentText)
- if (currentIndex == manager.getVendorIndex())
- comboProduct.currentIndex = manager.getProductIndex()
+ comboProduct.model = downloadThread.data().getProductListFromVendor(comboVendor.currentText)
+ if (currentIndex == downloadThread.data().getDetectedVendorIndex())
+ comboProduct.currentIndex = downloadThread.data().getDetectedProductIndex()
}
}
Kirigami.Label { text: qsTr(" Dive Computer:") }
@@ -74,7 +74,7 @@ Kirigami.Page {
Kirigami.Label { text: qsTr("Bluetooth download:") }
CheckBox {
id: isBluetooth
- checked: manager.getVendorIndex() != -1
+ checked: downloadThread.data().getDetectedVendorIndex() != -1
}
}
diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp
index 856dec03b..96bdab51e 100644
--- a/mobile-widgets/qmlmanager.cpp
+++ b/mobile-widgets/qmlmanager.cpp
@@ -94,28 +94,9 @@ QMLManager::QMLManager() : m_locationServiceEnabled(false),
alreadySaving(false)
{
#if defined(BT_SUPPORT)
- if (localBtDevice.isValid() &&
- localBtDevice.hostMode() == QBluetoothLocalDevice::HostConnectable) {
- btPairedDevices.clear();
- QString localDeviceName = "localDevice " + localBtDevice.name() + " is valid, starting discovery";
- appendTextToLog(localDeviceName.toUtf8().data());
-#if defined(Q_OS_LINUX)
- discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
- connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &QMLManager::btDeviceDiscovered);
- discoveryAgent->start();
-#endif
-#if defined(Q_OS_ANDROID)
- getBluetoothDevices();
-#endif
- for (int i = 0; i < btPairedDevices.length(); i++) {
- qDebug() << "Paired =" << btPairedDevices[i].name << btPairedDevices[i].address.toString();
- }
-#if defined(Q_OS_LINUX)
- discoveryAgent->stop();
-#endif
- } else {
- appendTextToLog("localBtDevice isn't valid");
- }
+ // ensure that we start the BTDiscovery - this should be triggered by the export of the class
+ // to QML, but that doesn't seem to always work
+ BTDiscovery *btDiscovery = BTDiscovery::instance();
#endif
m_instance = this;
m_lastDevicePixelRatio = qApp->devicePixelRatio();
@@ -217,78 +198,6 @@ void QMLManager::mergeLocalRepo()
process_dives(true, false);
}
-#if defined(BT_SUPPORT)
-
-extern void addBtUuid(QBluetoothUuid uuid);
-
-void QMLManager::btDeviceDiscovered(const QBluetoothDeviceInfo &device)
-{
- btPairedDevice this_d;
- this_d.address = device.address();
- this_d.name = device.name();
- btPairedDevices.append(this_d);
-
- QString newDevice = device.name();
-
- // all the HW OSTC BT computers show up as "OSTC" + some other text, depending on model
- if (newDevice.startsWith("OSTC"))
- newDevice = "OSTC 3";
- QList<QBluetoothUuid> serviceUuids = device.serviceUuids();
- foreach (QBluetoothUuid id, serviceUuids) {
- addBtUuid(id);
- qDebug() << id.toByteArray();
- }
- appendTextToLog("Found new device " + newDevice + " (" + device.address().toString() + ")");
- QString vendor, product;
- foreach (vendor, productList.keys()) {
- if (productList[vendor].contains(newDevice)) {
- appendTextToLog("this could be a " + vendor + " " +
- (newDevice == "OSTC 3" ? "OSTC family" : newDevice));
- struct btVendorProduct btVP;
- btVP.btdi = device;
- btVP.vendorIdx = vendorList.indexOf(vendor);
- btVP.productIdx = productList[vendor].indexOf(newDevice);
- qDebug() << "adding new btDCs entry" << newDevice << btVP.vendorIdx << btVP.productIdx;
- btDCs << btVP;
- }
- }
-}
-#endif
-
-int QMLManager::getVendorIndex()
-{
-#if defined(BT_SUPPORT)
- if (!btDCs.isEmpty()) {
- qDebug() << "getVendorIdx" << btDCs.first().vendorIdx;
- return btDCs.first().vendorIdx;
- }
-#endif
- return -1;
-}
-
-int QMLManager::getProductIndex()
-{
-#if defined(BT_SUPPORT)
- if (!btDCs.isEmpty()) {
- qDebug() << "getProductIdx" << btDCs.first().productIdx;
- return btDCs.first().productIdx;
- }
-#endif
- return -1;
-}
-
-QString QMLManager::getBtAddress()
-{
-#if BT_SUPPORT
- if (!btDCs.isEmpty()) {
- QString btAddr = btDCs.first().btdi.address().toString();
- qDebug() << "getBtAddress" << btAddr;
- return btAddr;
- }
- return QString();
-#endif
-}
-
void QMLManager::finishSetup()
{
// Initialize cloud credentials.
@@ -1611,74 +1520,3 @@ void QMLManager::setShowPin(bool enable)
m_showPin = enable;
emit showPinChanged();
}
-
-QStringList QMLManager::getDCListFromVendor(const QString& vendor)
-{
- return productList[vendor];
-}
-
-// Android: As Qt is not able to pull the pairing data from a device, i
-// a lengthy discovery process is needed to see what devices are paired. On
-// https://forum.qt.io/topic/46075/solved-bluetooth-list-paired-devices
-// user s.frings74 does, however, present a solution to this using JNI.
-// Currently, this code is taken "as is".
-
-void QMLManager::getBluetoothDevices()
-{
-#if defined(Q_OS_ANDROID) && defined(BT_SUPPORT)
- struct QMLManager::btPairedDevice result;
- // Query via Android Java API.
-
- // returns a BluetoothAdapter
- QAndroidJniObject adapter=QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter","getDefaultAdapter","()Landroid/bluetooth/BluetoothAdapter;");
- if (checkException("BluetoothAdapter.getDefaultAdapter()", &adapter)) {
- return;
- }
- // returns a Set<BluetoothDevice>
- QAndroidJniObject pairedDevicesSet=adapter.callObjectMethod("getBondedDevices","()Ljava/util/Set;");
- if (checkException("BluetoothAdapter.getBondedDevices()", &pairedDevicesSet)) {
- return;
- }
- jint size=pairedDevicesSet.callMethod<jint>("size");
- checkException("Set<BluetoothDevice>.size()", &pairedDevicesSet);
- if (size > 0) {
- // returns an Iterator<BluetoothDevice>
- QAndroidJniObject iterator=pairedDevicesSet.callObjectMethod("iterator","()Ljava/util/Iterator;");
- if (checkException("Set<BluetoothDevice>.iterator()", &iterator)) {
- return;
- }
- for (int i = 0; i < size; i++) {
- // returns a BluetoothDevice
- QAndroidJniObject dev=iterator.callObjectMethod("next","()Ljava/lang/Object;");
- if (checkException("Iterator<BluetoothDevice>.next()", &dev)) {
- continue;
- }
-
- result.address = QBluetoothAddress(dev.callObjectMethod("getAddress","()Ljava/lang/String;").toString());
- result.name = dev.callObjectMethod("getName", "()Ljava/lang/String;").toString();
-
- btPairedDevices.append(result);
- }
-}
-#endif
-}
-
-#if defined(Q_OS_ANDROID)
-bool QMLManager::checkException(const char* method, const QAndroidJniObject *obj)
-{
- static QAndroidJniEnvironment env;
- bool result = false;
-
- if (env->ExceptionCheck()) {
- qCritical("Exception in %s", method);
- env->ExceptionDescribe();
- env->ExceptionClear();
- result=true;
- }
- if (!(obj == NULL || obj->isValid())) {
- qCritical("Invalid object returned by %s", method);
- result=true;
- }
- return result;
-}
-#endif
diff --git a/mobile-widgets/qmlmanager.h b/mobile-widgets/qmlmanager.h
index b10ae9af2..a41ee509a 100644
--- a/mobile-widgets/qmlmanager.h
+++ b/mobile-widgets/qmlmanager.h
@@ -16,6 +16,7 @@
#include <QAndroidJniObject>
#endif
+#include "core/btdiscovery.h"
#include "core/gpslocation.h"
#include "qt-models/divelistmodel.h"
@@ -121,18 +122,6 @@ public:
QStringList cylinderInit() const;
bool showPin() const;
void setShowPin(bool enable);
- Q_INVOKABLE QStringList getDCListFromVendor(const QString& vendor);
- Q_INVOKABLE int getVendorIndex();
- Q_INVOKABLE int getProductIndex();
- Q_INVOKABLE QString getBtAddress();
-#if defined(BT_SUPPORT)
- struct btPairedDevice {
- QBluetoothAddress address;
- QString name;
- };
- void btDeviceDiscovered(const QBluetoothDeviceInfo &device);
- void getBluetoothDevices();
-#endif
public slots:
void applicationStateChanged(Qt::ApplicationState state);
@@ -216,22 +205,6 @@ private:
bool currentGitLocalOnly;
bool m_showPin;
-#if defined(Q_OS_ANDROID)
- bool checkException(const char* method, const QAndroidJniObject* obj);
-#endif
-
-#if defined(BT_SUPPORT)
- QList<struct btPairedDevice> btPairedDevices;
- QBluetoothLocalDevice localBtDevice;
- QBluetoothDeviceDiscoveryAgent *discoveryAgent;
- struct btVendorProduct {
- QBluetoothDeviceInfo btdi;
- int vendorIdx;
- int productIdx;
- };
- QList<struct btVendorProduct> btDCs;
-#endif
-
signals:
void cloudUserNameChanged();
void cloudPasswordChanged();