This commit is contained in:
2019-02-20 14:57:54 +01:00
parent 3a0b3d59ce
commit bd4df296b0
8 changed files with 452 additions and 0 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
*.pro.user

35
QtUwbTest.pro Normal file
View File

@@ -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

315
bt.h Normal file
View File

@@ -0,0 +1,315 @@
#ifndef BT_H
#define BT_H
#include <QObject>
#include <QDebug>
#include <QTimer>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothUuid>
#include <QLowEnergyController>
#include <QLowEnergyConnectionParameters>
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<uint8_t> 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<void (QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)>(&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<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&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

23
main.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#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();
}

27
main.qml Normal file
View File

@@ -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();
}
}

26
manager.cpp Normal file
View File

@@ -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
}

20
manager.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef MANAGER_H
#define MANAGER_H
#include <QObject>
class Manager : public QObject
{
Q_OBJECT
public:
explicit Manager(QObject *parent = nullptr);
Q_INVOKABLE void trigger();
signals:
public slots:
};
#endif // MANAGER_H

5
qml.qrc Normal file
View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>