From bd4df296b0ef54189e4713e510ed3596b13e20e6 Mon Sep 17 00:00:00 2001 From: Markus Bullmann Date: Wed, 20 Feb 2019 14:57:54 +0100 Subject: [PATCH] Code --- .gitignore | 1 + QtUwbTest.pro | 35 ++++++ bt.h | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 23 ++++ main.qml | 27 +++++ manager.cpp | 26 +++++ manager.h | 20 ++++ qml.qrc | 5 + 8 files changed, 452 insertions(+) create mode 100644 QtUwbTest.pro create mode 100644 bt.h create mode 100644 main.cpp create mode 100644 main.qml create mode 100644 manager.cpp create mode 100644 manager.h create mode 100644 qml.qrc diff --git a/.gitignore b/.gitignore index a44462f..db08f05 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake +*.pro.user \ No newline at end of file diff --git a/QtUwbTest.pro b/QtUwbTest.pro new file mode 100644 index 0000000..1107f87 --- /dev/null +++ b/QtUwbTest.pro @@ -0,0 +1,35 @@ +QT += quick +QT += bluetooth +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Refer to the documentation for the +# deprecated API to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + manager.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + bt.h \ + manager.h diff --git a/bt.h b/bt.h new file mode 100644 index 0000000..23a6fa1 --- /dev/null +++ b/bt.h @@ -0,0 +1,315 @@ +#ifndef BT_H +#define BT_H + +#include +#include +#include + +#include +#include +#include +#include + +class BT : public QObject { + + Q_OBJECT + + QBluetoothDeviceDiscoveryAgent* m_deviceDiscoveryAgent = nullptr; + QLowEnergyService* m_service = nullptr; + + QLowEnergyCharacteristic* charM1 = nullptr; + QLowEnergyCharacteristic* charM2 = nullptr; + + QBluetoothDeviceInfo m_uwbDevice; + + enum State { + DISCONNECTED, + CONNECTING, + CONNECTED + }; + State state = State::DISCONNECTED; + +public: + + + void setChar(int idx, std::vector data) { + + if (!m_service) {return;} + if (m_service->characteristics().empty()) {return;} + + auto c = m_service->characteristics().at(idx); + + //qDebug() << "write char" << c.uuid() << " to " << data; + + QByteArray arr; + for (uint8_t val : data) {arr.append(val);} + m_service->writeCharacteristic(c, arr); + + + } + + BT() { + + //findDevices(); + + } + + void start() { + findDevices(); + } + + void connectToDevice() { + assert(m_uwbDevice.isValid()); + + connectTo(m_uwbDevice); + } + + void findDevices() { + + qDebug() << "findDevices()"; + + // helper class to find nearby BLE devices + m_deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this); + m_deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(5000); + + // connect events + assert(connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BT::daDeviceDiscovered)); + assert(connect(m_deviceDiscoveryAgent, static_cast(&QBluetoothDeviceDiscoveryAgent::error), this, &BT::daError)); + assert(connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BT::daScanFinished)); + assert(connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &BT::daScanCanceled)); + + // start scan + m_deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); + + } + + void daDeviceDiscovered(const QBluetoothDeviceInfo& device) { + + qDebug() << "daDeviceDiscovered() " << device.name() << " " << device.address(); + + if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { + if (device.name() == "DWDA96" && device.address().toString() == "D1:6C:7A:99:57:71") { + m_uwbDevice = device; + + //connectTo(device); + } + } + + } + + void daError(QBluetoothDeviceDiscoveryAgent::Error error) { + qDebug() << "daError() " << error; + } + + void daScanFinished() { + qDebug() << "daScanFinished()"; + + connectToDevice(); + } + + void daScanCanceled() { + qDebug() << "daScanCanceled()"; + } + + + + + + + + QLowEnergyController* m_control = nullptr; + + void connectTo(const QBluetoothDeviceInfo& dev) { + + if (state != State::DISCONNECTED) { + qDebug() << "connectTo() already called. skipping"; + return; + } + state = State::CONNECTING; + + qDebug() << "connectTo() " << dev.name() << " " << dev.address(); + + // delte previous connection + if (m_control) { + m_control->disconnectFromDevice(); + delete m_control; + m_control = nullptr; + } + + /* 2 Step: QLowEnergyController */ + m_control = new QLowEnergyController(dev, this); + m_control ->setRemoteAddressType(QLowEnergyController::RandomAddress); + + assert(connect(m_control, &QLowEnergyController::serviceDiscovered, this, &BT::lecServiceDiscovered)); + assert(connect(m_control, &QLowEnergyController::discoveryFinished, this, &BT::lecServiceScanDone)); + assert(connect(m_control, static_cast(&QLowEnergyController::error), this, &BT::lecError)); + assert(connect(m_control, &QLowEnergyController::connected, this, &BT::lecDeviceConnected)); + assert(connect(m_control, &QLowEnergyController::disconnected, this, &BT::lecDeviceDisconnected)); + assert(connect(m_control, &QLowEnergyController::connectionUpdated, this, &BT::lecConnectionUpdated)); + + /* Start connecting to device */ + m_control->connectToDevice(); + // setState(Connecting); + + } + + void lecServiceDiscovered(const QBluetoothUuid& gatt) { + + qDebug() << "lecServiceDiscovered() " << gatt; + if (gatt.toString() == "{680c21d9-c946-4c1f-9c11-baa1c21329e7}") { + qDebug() << "is our service"; + //_createService(gatt); + } + + } + + void _createService(const QBluetoothUuid& uuid) { + + // cleanup previous service (if any) + if (m_service) { + delete m_service; + m_service = nullptr; + } + + // create new service + m_service = m_control->createServiceObject(uuid, this); + + // connect events + assert(connect(m_service, &QLowEnergyService::stateChanged , this, &BT::lesServiceStateChanged)); + assert(connect(m_service, &QLowEnergyService::characteristicChanged, this, &BT::lesUpdateData)); + assert(connect(m_service, &QLowEnergyService::descriptorWritten , this, &BT::lesConfirmedDescriptorWrite)); + assert(connect(m_service, &QLowEnergyService::characteristicRead , this, &BT::lesCharacteristicRead)); + // start discovering all characteristics and descriptors on this service + qDebug() << "discoverDetails()"; + m_service->characteristics().clear(); + //m_service->discoverDetails(); + + auto c = m_service->characteristic(QBluetoothUuid(QString("{003bbdf2-c634-4b3d-ab56-7ec889b89a37}"))); + + assert(c.isValid()); + + QLowEnergyDescriptor m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100")); + + } + + void lecServiceScanDone() { + qDebug() << "lecServiceScanDone()"; + + _createService(QBluetoothUuid::fromString(QString("{680c21d9-c946-4c1f-9c11-baa1c21329e7}"))); + } + + void lecError(QLowEnergyController::Error err) { + qDebug() << "lecError() " << err; + } + + void _faster() { + QLowEnergyConnectionParameters param; + //param.setIntervalRange(100,100); + param.setIntervalRange(7.5, 7.5); + //param.setSupervisionTimeout(1000); + param.setLatency(100); + m_control->requestConnectionUpdate(param); + } + + void lecDeviceConnected() { + + state = State::CONNECTED; + qDebug() << "lecDeviceConnected()"; + + // faster!! + //_faster(); + + + + // trigger service discovery; + m_control->discoverServices(); + + } + + void lecConnectionUpdated(const QLowEnergyConnectionParameters& params) { + qDebug() << "lecConnectionUpdated(" << params.minimumInterval() << "," << params.maximumInterval() << ")"; + } + + void lecDeviceDisconnected() { + state = State::DISCONNECTED; + qDebug() << "lecDeviceDisconnected()"; + } + + + void lesServiceStateChanged(QLowEnergyService::ServiceState s) { + qDebug() << "lesServiceStateChanged()" << s; + + // A descriptoc can only be written if the service is in the ServiceDiscovered state + switch (s) { + case QLowEnergyService::ServiceDiscovered: + _gotServiceCharacteristics(); + break; + default: + break; + } + + } + + QLowEnergyDescriptor m_notificationDesc; + QLowEnergyCharacteristic m_DeviceInfoChar; + QTimer* m_readTimer; + + void _gotServiceCharacteristics() { + for (const auto& c : m_service->characteristics()) { + char read = c.properties().testFlag(QLowEnergyCharacteristic::Read) ? 'R' : ' '; + char write = c.properties().testFlag(QLowEnergyCharacteristic::Write) ? 'W' : ' '; + char notify = c.properties().testFlag(QLowEnergyCharacteristic::Notify) ? 'N' : ' '; + char broad = c.properties().testFlag(QLowEnergyCharacteristic::Broadcasting) ? 'B' : ' '; + + qDebug() << "char: " << c.uuid() << read << write << notify << broad; +// QByteArray arr; arr.append(30); +// m_service->writeCharacteristic(c, arr); + + if (c.uuid().toString() == "{1e63b1eb-d4ed-444e-af54-c1e965192501}") { +// m_DeviceInfoChar = c; + //m_service->readCharacteristic(m_DeviceInfoChar); + +// QTimer::singleShot(100, this, SLOT(doRead())); +// qDebug() << "Test"; + +// if(!m_readTimer){ +// m_readTimer = new QTimer(this); +// connect(m_readTimer, &QTimer::timeout, this, &BT::doRead); +// m_readTimer->start(100); // in ms +// } + } + + if (c.uuid().toString() == "{003bbdf2-c634-4b3d-ab56-7ec889b89a37}") { + QLowEnergyDescriptor m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100")); + } + } + } + +public slots: + void doRead() + { + qDebug() << "DoRead"; + m_service->readCharacteristic(m_DeviceInfoChar); + } + +public: + + void lesCharacteristicRead(const QLowEnergyCharacteristic& info, const QByteArray& value) + { + qDebug() << "lesCharacteristicRead() " << info.uuid() << value; + } + + void lesUpdateData(const QLowEnergyCharacteristic& c,const QByteArray& value) { + qDebug() << "lesUpdateData() " << c.uuid() << value; + } + + void lesConfirmedDescriptorWrite(const QLowEnergyDescriptor& d, const QByteArray &value) { + qDebug() << "lesConfirmedDescriptorWrite()" << d.uuid() << value; + } + + +}; + +#endif // BT_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e97ae0d --- /dev/null +++ b/main.cpp @@ -0,0 +1,23 @@ +#include +#include + +#include + +#include "manager.h" +extern Manager mgmt; + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + engine.rootContext()->setContextProperty("mgmt", &mgmt); + + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..aa568fa --- /dev/null +++ b/main.qml @@ -0,0 +1,27 @@ +import QtQuick 2.9 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 + +Window { + id: window + visible: true + width: 640 + height: 480 + title: qsTr("Hello World") + + Text { + id: helloText + x: 0 + text: "Hello world!" + y: 99 + anchors.horizontalCenter: page.horizontalCenter + font.pointSize: 24; font.bold: true + } + + Button { + text: "party hard 2"; + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + onClicked: mgmt.trigger(); + } +} diff --git a/manager.cpp b/manager.cpp new file mode 100644 index 0000000..d4dd2c5 --- /dev/null +++ b/manager.cpp @@ -0,0 +1,26 @@ +#include "manager.h" + +#include "bt.h" + +Manager mgmt; + +Manager::Manager(QObject *parent) : QObject(parent) +{ + +} + +void Manager::trigger() { + + printf("HALLO"); + + BT* bt = new BT(); + bt->start(); + +#ifdef ANDROID + +#else + +#endif + + +} diff --git a/manager.h b/manager.h new file mode 100644 index 0000000..c2ff059 --- /dev/null +++ b/manager.h @@ -0,0 +1,20 @@ +#ifndef MANAGER_H +#define MANAGER_H + +#include + +class Manager : public QObject +{ + Q_OBJECT +public: + explicit Manager(QObject *parent = nullptr); + + + Q_INVOKABLE void trigger(); + +signals: + +public slots: +}; + +#endif // MANAGER_H diff --git a/qml.qrc b/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + +