mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-06 02:30:38 -08:00
170 lines
4.8 KiB
C++
170 lines
4.8 KiB
C++
#include "ble.h"
|
|
#include <QBluetoothAddress>
|
|
#include <QBluetoothDeviceDiscoveryAgent>
|
|
#include <QBluetoothDeviceInfo>
|
|
#include <QBluetoothServiceDiscoveryAgent>
|
|
#include <QList>
|
|
#include <QMetaEnum>
|
|
#include <QTimer>
|
|
#include <QDebug>
|
|
|
|
BLE::BLE(const QBluetoothUuid& uuid) : mainServiceUuid(uuid) {
|
|
discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
|
|
discoveryAgent->setLowEnergyDiscoveryTimeout(5000);
|
|
|
|
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
|
|
this, &BLE::addDevice);
|
|
connect(discoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
|
|
this, &BLE::deviceScanError);
|
|
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BLE::deviceScanFinished);
|
|
}
|
|
|
|
void BLE::startDeviceDiscovery() {
|
|
devices.clear();
|
|
qDebug() << "scanning for devices...";
|
|
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
|
|
}
|
|
|
|
void BLE::addDevice(const QBluetoothDeviceInfo& device) {
|
|
if (deviceFilter(device)) {
|
|
qDebug() << "device added:" << device.name() << device.address().toString();
|
|
}
|
|
}
|
|
|
|
void BLE::deviceScanFinished() {
|
|
const QList<QBluetoothDeviceInfo> found = discoveryAgent->discoveredDevices();
|
|
for (auto device : found) {
|
|
if (deviceFilter(device)) {
|
|
devices << device;
|
|
}
|
|
}
|
|
if (devices.isEmpty()) {
|
|
qDebug() << "no BLE devices found";
|
|
} else {
|
|
qDebug() << "device scan done";
|
|
}
|
|
QTimer::singleShot(0, this, &BLE::scanServices);
|
|
}
|
|
|
|
void BLE::scanServices() {
|
|
if (devices.isEmpty()) {
|
|
return;
|
|
}
|
|
if (!currentDevice.isValid()) {
|
|
currentDevice = devices.at(0);
|
|
}
|
|
services.clear();
|
|
qDebug() << "connecting to device...";
|
|
if (controller && (previousAddress != currentDevice.address())) {
|
|
Q_EMIT deviceDisconnecting();
|
|
controller->disconnectFromDevice();
|
|
delete controller; controller = nullptr;
|
|
}
|
|
|
|
if (!controller) {
|
|
controller = QLowEnergyController::createCentral(currentDevice);
|
|
connect(controller, &QLowEnergyController::connected,
|
|
this, &BLE::deviceConnected);
|
|
connect(controller, QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),
|
|
this, &BLE::errorReceived);
|
|
connect(controller, &QLowEnergyController::disconnected,
|
|
this, &BLE::deviceDisconnected);
|
|
connect(controller, &QLowEnergyController::serviceDiscovered,
|
|
this, &BLE::addLowEnergyService);
|
|
connect(controller, &QLowEnergyController::discoveryFinished,
|
|
this, &BLE::serviceScanDone);
|
|
}
|
|
|
|
controller->connectToDevice();
|
|
previousAddress = currentDevice.address();
|
|
}
|
|
|
|
void BLE::setCurrentDevice(const QBluetoothDeviceInfo& device) {
|
|
if (device != currentDevice) {
|
|
currentDevice = device;
|
|
scanned = false;
|
|
retryScan();
|
|
}
|
|
}
|
|
|
|
void BLE::addLowEnergyService(const QBluetoothUuid& serviceUuid) {
|
|
QLowEnergyService* service = controller->createServiceObject(serviceUuid);
|
|
if (!service) {
|
|
qDebug() << "cannot create service for UUID";
|
|
return;
|
|
}
|
|
services << service;
|
|
|
|
if (serviceUuid == mainServiceUuid) {
|
|
mainService = service;
|
|
}
|
|
}
|
|
|
|
void BLE::serviceScanDone() {
|
|
scanned = true;
|
|
Q_EMIT mainServiceReady();
|
|
qDebug() << "service scan done";
|
|
}
|
|
|
|
void BLE::connectToService(const QString& uuid) {
|
|
QLowEnergyService* service = nullptr;
|
|
for (auto s : qAsConst(services)) {
|
|
if (s->serviceUuid().toString() == uuid) {
|
|
service = s;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!service) {
|
|
return;
|
|
}
|
|
|
|
if (service->state() == QLowEnergyService::DiscoveryRequired) {
|
|
service->discoverDetails();
|
|
qDebug() << "discovering details...";
|
|
return;
|
|
}
|
|
}
|
|
|
|
void BLE::deviceConnected() {
|
|
connected = true;
|
|
controller->discoverServices();
|
|
}
|
|
|
|
void BLE::retryScan() {
|
|
if (connected && !scanned) {
|
|
QTimer::singleShot(0, this, &BLE::scanServices);
|
|
}
|
|
}
|
|
|
|
void BLE::errorReceived(QLowEnergyController::Error) {
|
|
qDebug() << "BLE error: " << controller->errorString();
|
|
retryScan();
|
|
}
|
|
|
|
void BLE::disconnectFromDevice() {
|
|
if (controller->state() != QLowEnergyController::UnconnectedState) {
|
|
controller->disconnectFromDevice();
|
|
} else {
|
|
deviceDisconnected();
|
|
}
|
|
}
|
|
|
|
void BLE::deviceDisconnected() {
|
|
connected = false;
|
|
qDebug() << "disconnect from device";
|
|
}
|
|
|
|
void BLE::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error) {
|
|
if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError) {
|
|
qDebug() << "the Bluetooth adaptor is powered off, power it on before doing discovery";
|
|
} else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError) {
|
|
qDebug() << "writing or reading from the device resulted in an error";
|
|
} else {
|
|
static QMetaEnum qme = discoveryAgent->metaObject()->enumerator(
|
|
discoveryAgent->metaObject()->indexOfEnumerator("Error"));
|
|
qDebug() << "error: " + QLatin1String(qme.valueToKey(error));
|
|
}
|
|
retryScan();
|
|
}
|
|
|