From 60d10f056b53b1816bd97559ad2d7527bbc158a8 Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Sun, 11 Oct 2020 15:49:51 +0200 Subject: [PATCH] - update example - some fixes - added QBluetoothLeUartDeviceModel for use with QML --- QBluetoothLeUart.pri | 6 ++- docs/Doxyfile-mcss | 2 +- qbluetoothleuart.cpp | 48 +++++++++++++++++------- qbluetoothleuart.h | 21 ++++++++++- qbluetoothleuartdevice.cpp | 5 ++- qbluetoothleuartdevicemodel.cpp | 64 ++++++++++++++++++++++++++++++++ qbluetoothleuartdevicemodel.h | 65 +++++++++++++++++++++++++++++++++ 7 files changed, 191 insertions(+), 20 deletions(-) create mode 100644 qbluetoothleuartdevicemodel.cpp create mode 100644 qbluetoothleuartdevicemodel.h diff --git a/QBluetoothLeUart.pri b/QBluetoothLeUart.pri index 4e812a7..c40eb9a 100644 --- a/QBluetoothLeUart.pri +++ b/QBluetoothLeUart.pri @@ -20,8 +20,10 @@ INCLUDEPATH += $$PWD/ SOURCES += \ $$PWD/qbluetoothleuart.cpp \ - $$PWD/qbluetoothleuartdevice.cpp + $$PWD/qbluetoothleuartdevice.cpp \ + $$PWD/qbluetoothleuartdevicemodel.cpp HEADERS += \ $$PWD/qbluetoothleuart.h \ - $$PWD/qbluetoothleuartdevice.h + $$PWD/qbluetoothleuartdevice.h \ + $$PWD/qbluetoothleuartdevicemodel.h diff --git a/docs/Doxyfile-mcss b/docs/Doxyfile-mcss index 8314df2..19712be 100644 --- a/docs/Doxyfile-mcss +++ b/docs/Doxyfile-mcss @@ -15,4 +15,4 @@ M_THEME_COLOR = #0094ff M_LINKS_NAVBAR1 = M_LINKS_NAVBAR2 = "Introduction" \ annotated \ - "Download" + "Download" diff --git a/qbluetoothleuart.cpp b/qbluetoothleuart.cpp index 2dee122..c39291e 100644 --- a/qbluetoothleuart.cpp +++ b/qbluetoothleuart.cpp @@ -17,6 +17,9 @@ QBluetoothLeUart::QBluetoothLeUart(QObject *parent) : QObject(parent) connect(bluetoothDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error))); connect(this->bluetoothDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &QBluetoothLeUart::handleScanFinished); + + // device model for QML + this->availableDevicesModel = new QBluetoothLeUartDeviceModel(this->availableDevices, this); } QBluetoothLeUart::~QBluetoothLeUart(){ @@ -28,9 +31,11 @@ QBluetoothLeUart::~QBluetoothLeUart(){ // ------------------------------ bool QBluetoothLeUart::startScanningForDevices(){ - if(this->state != Idle) + if(this->state != Idle && this->state != ScanFinished) return false; + this->availableDevicesModel->clear(); + foreach(QBluetoothLeUartDevice* oldDevice, this->availableDevices) oldDevice->deleteLater(); @@ -56,6 +61,7 @@ QList QBluetoothLeUart::getAvailableDevices() { } QVariantList QBluetoothLeUart::getAvailableDevicesDetailList() { + QVariantList result; for(int i=0; i < this->availableDevices.length(); i++) { @@ -74,6 +80,11 @@ QVariantList QBluetoothLeUart::getAvailableDevicesDetailList() { return result; } +QBluetoothLeUartDeviceModel* QBluetoothLeUart::getAvailableDevicesModel() { + return this->availableDevicesModel; +} + + bool QBluetoothLeUart::connectToDevice(int deviceId) { if(deviceId < 0 || deviceId >= this->availableDevices.length()) return false; @@ -86,6 +97,9 @@ bool QBluetoothLeUart::connectToDevice(QBluetoothLeUartDevice *device){ if(!this->availableDevices.contains(device)) return false; + if(this->state == Scanning) + this->stopScanningForDevices(); + this->currentBluetoothDevice = device; if (bluetoothController) { @@ -113,22 +127,21 @@ bool QBluetoothLeUart::connectToDevice(QBluetoothLeUartDevice *device){ } bool QBluetoothLeUart::disconnectFromDevice() { - if(this->state < ScanningForService) + if(this->state < Connecting) return false; - this->bluetoothController->disconnectFromDevice(); - - disconnect(this->bluetoothController, &QLowEnergyController::serviceDiscovered, this, &QBluetoothLeUart::handleServiceDiscovered); - disconnect(this->bluetoothController, &QLowEnergyController::discoveryFinished, this, &QBluetoothLeUart::handleServiceScanDone); - disconnect(bluetoothController, SIGNAL(error(QLowEnergyController::Error)), - this, SLOT(handleControllerError(QLowEnergyController::Error))); - disconnect(this->bluetoothController, &QLowEnergyController::connected, this, &QBluetoothLeUart::handleDeviceConnected); - disconnect(this->bluetoothController, &QLowEnergyController::disconnected, this, &QBluetoothLeUart::handleDeviceDisconnected); + if(this->state >= Connected) + this->bluetoothController->disconnectFromDevice(); this->bluetoothController->deleteLater(); this->bluetoothController = nullptr; - this->bluetoothService->deleteLater(); - this->bluetoothService = nullptr; + + if(this->bluetoothService != nullptr) { + this->bluetoothService->deleteLater(); + this->bluetoothService = nullptr; + } + + this->setState(Idle); return true; } @@ -156,8 +169,13 @@ void QBluetoothLeUart::handleDeviceDiscovered(const QBluetoothDeviceInfo &device // Is it a BLE device? if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { //qWarning() << "Discovered BLE Device: name: " << device.name() << " Address: " << device.address().toString(); + // ignore all devices that to not support our service + if(!device.serviceUuids().contains(QBluetoothUuid(this->uartServiceUUID))) + return; + QBluetoothLeUartDevice *dev = new QBluetoothLeUartDevice(device, this); - availableDevices.append(dev); + this->availableDevices.append(dev); + this->availableDevicesModel->append(dev); emit this->foundNewDevice(dev); emit this->avaliableDevicesChanged(this->availableDevices); } @@ -228,6 +246,7 @@ void QBluetoothLeUart::handleControllerError(QLowEnergyController::Error error) { qDebug() << "Cannot connect to remote device."; qWarning() << "Controller Error:" << error; + this->disconnectFromDevice(); } void QBluetoothLeUart::handleDeviceConnected() @@ -317,7 +336,8 @@ void QBluetoothLeUart::handleServiceDescriptorWritten(const QLowEnergyDescriptor void QBluetoothLeUart::init() { #ifdef QBluetoothLeUart_QML - qmlRegisterUncreatableType("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDevice", "BluetoothDeviceInfo cannot be created"); + qmlRegisterUncreatableType("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDevice", "QBluetoothLeUartDevice cannot be created"); + qmlRegisterUncreatableType("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDeviceModel", "QBluetoothLeUartDeviceModel cannot be created"); qmlRegisterType("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUart"); qRegisterMetaType("QBluetoothLeUart::BluetoothLeUartState"); qRegisterMetaType("QBluetoothLeUart::BluetoothScanError"); diff --git a/qbluetoothleuart.h b/qbluetoothleuart.h index fff1171..09a6784 100644 --- a/qbluetoothleuart.h +++ b/qbluetoothleuart.h @@ -11,6 +11,7 @@ #endif #include +#include /*! * \mainpage Qt BluetoothLE UART library @@ -80,11 +81,13 @@ * * QML example: * \code{.qml} + * import de.itsblue.bluetoothleuart 1.0 + * * QBluetoothLeUart { * id: ble * Component.onCompleted: { * ble.startScanningForDevices() - * } + * } * * onFoundNewDevice: { * console.log("Found a device: name: " + device.name + " address: " + device.address) @@ -107,7 +110,8 @@ class QBluetoothLeUart : public QObject { Q_OBJECT - Q_PROPERTY(QVariantList avaliableDevices READ getAvailableDevicesDetailList NOTIFY avaliableDevicesChanged) + Q_PROPERTY(QVariantList availableDevices READ getAvailableDevicesDetailList NOTIFY avaliableDevicesChanged) + Q_PROPERTY(QBluetoothLeUartDeviceModel* availableDevicesModel READ getAvailableDevicesModel NOTIFY avaliableDevicesModelChanged) Q_PROPERTY(BluetoothLeUartState state READ getState NOTIFY stateChanged) public: @@ -169,6 +173,9 @@ private: QLowEnergyDescriptor bluetoothTransmissionDescriptor; bool foundValidUARTService; + // for QML + QBluetoothLeUartDeviceModel* availableDevicesModel; + public slots: /*! @@ -223,6 +230,15 @@ public slots: */ Q_INVOKABLE QVariantList getAvailableDevicesDetailList(); + /*! + * \brief Function to get a QBluetoothLeUartDeviceModel with all available devices + * + * \see QBluetoothLeUartDeviceModel + * + * \return A QBluetoothLeUartDeviceModel with all available devices + */ + Q_INVOKABLE QBluetoothLeUartDeviceModel* getAvailableDevicesModel(); + /*! * \brief Function connect to a device using its internal id * @@ -305,6 +321,7 @@ signals: void foundNewDevice(QBluetoothLeUartDevice* device); void avaliableDevicesChanged(QList avaliableDevices); + void avaliableDevicesModelChanged(); void scanFinished(QList availableDevices); void scanningErrorOccured(QBluetoothLeUart::BluetoothScanError error); diff --git a/qbluetoothleuartdevice.cpp b/qbluetoothleuartdevice.cpp index d3f531d..8de9c51 100644 --- a/qbluetoothleuartdevice.cpp +++ b/qbluetoothleuartdevice.cpp @@ -7,7 +7,10 @@ QBluetoothLeUartDevice::QBluetoothLeUartDevice(QBluetoothDeviceInfo info, QObjec QString QBluetoothLeUartDevice::getName() { - return bluetoothDeviceInfo.name(); + if(bluetoothDeviceInfo.isValid()) + return bluetoothDeviceInfo.name(); + else + return ""; } QBluetoothDeviceInfo QBluetoothLeUartDevice::getDevice() diff --git a/qbluetoothleuartdevicemodel.cpp b/qbluetoothleuartdevicemodel.cpp new file mode 100644 index 0000000..e851178 --- /dev/null +++ b/qbluetoothleuartdevicemodel.cpp @@ -0,0 +1,64 @@ +#include "qbluetoothleuartdevicemodel.h" + +QBluetoothLeUartDeviceModel::QBluetoothLeUartDeviceModel(QList availableDevices, QObject* parent) : QAbstractListModel(parent) +{ + this->availableDevices = availableDevices; +} + +int QBluetoothLeUartDeviceModel::rowCount(const QModelIndex &) const +{ + return this->availableDevices.length(); +} + +QVariant QBluetoothLeUartDeviceModel::data(const QModelIndex &index, int role) const +{ + if (index.row() < rowCount()) + switch (role) { + case NameRole: return this->availableDevices[index.row()]->getName(); + case IdRole: return index.row(); + case AddressRole: return this->availableDevices[index.row()]->getAddress(); + case DeviceRole: return QVariant::fromValue(this->availableDevices[index.row()]); + default: return QVariant(); + } + return QVariant(); +} + +QHash QBluetoothLeUartDeviceModel::roleNames() const +{ + static const QHash roles { + { NameRole, "name" }, + { IdRole, "id" }, + { AddressRole, "address"}, + { DeviceRole, "device" } + }; + return roles; +} + +void QBluetoothLeUartDeviceModel::append(QBluetoothLeUartDevice* device) +{ + foreach(QBluetoothLeUartDevice* existingDevice, this->availableDevices){ + if(device == existingDevice) + // dublicates aren't allowed + return; + } + + int row = this->availableDevices.length(); + this->beginInsertRows(QModelIndex(), row, row); + this->availableDevices.insert(row, device); + this->endInsertRows(); +} + +void QBluetoothLeUartDeviceModel::remove(int row) +{ + if (row < 0 || row >= this->availableDevices.length()) + return; + + beginRemoveRows(QModelIndex(), row, row); + this->availableDevices.removeAt(row); + endRemoveRows(); +} + +void QBluetoothLeUartDeviceModel::clear() { + for(int i = 0; i < this->availableDevices.length(); i++) + this->remove(i); +} diff --git a/qbluetoothleuartdevicemodel.h b/qbluetoothleuartdevicemodel.h new file mode 100644 index 0000000..5c07cc8 --- /dev/null +++ b/qbluetoothleuartdevicemodel.h @@ -0,0 +1,65 @@ +#ifndef QBLUETOOTHLEUARTDEVICEMODEL_H +#define QBLUETOOTHLEUARTDEVICEMODEL_H + +#include +#include +#include + +/*! + * \brief The QBluetoothLeUartDeviceModel class can be used to display available devices in a QML ListView. + * + * Example implementation: + * \code{.qml} + * import de.itsblue.bluetoothleuart 1.0 + * + * QBluetoothLeUart { + * id: ble + * Component.onCompleted: { + * ble.startScanningForDevices() + * } + * } + * + * ListView { + * model: ble.availableDevicesModel + * + * delegate: ItemDelegate { + * width: parent.width + * + * text: name + * + * onClicked: backend.bleController.connectToDevice(device) + * } + * } + * \endcode + */ +class QBluetoothLeUartDeviceModel : public QAbstractListModel +{ + Q_OBJECT +public: + friend class QBluetoothLeUart; + + enum QBluetoothLeUartDeviceModelRole { + NameRole = Qt::DisplayRole, + IdRole, + AddressRole, + DeviceRole + }; + Q_ENUM(QBluetoothLeUartDeviceModelRole) + + int rowCount(const QModelIndex & = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QHash roleNames() const; + +protected: + QBluetoothLeUartDeviceModel(QList availableDevices, QObject *parent = nullptr); + + void append(QBluetoothLeUartDevice* device); + void remove(int row); + void clear(); + +private: + QList availableDevices; + +}; + +#endif // QBLUETOOTHLEUARTDEVICEMODEL_H