- update example

- some fixes
- added QBluetoothLeUartDeviceModel for use with QML
This commit is contained in:
Dorian Zedler 2020-10-11 15:49:51 +02:00
parent 7f5ad16ba9
commit 60d10f056b
Signed by: dorian
GPG key ID: D3B255CB8BC7CD37
7 changed files with 191 additions and 20 deletions

View file

@ -20,8 +20,10 @@ INCLUDEPATH += $$PWD/
SOURCES += \ SOURCES += \
$$PWD/qbluetoothleuart.cpp \ $$PWD/qbluetoothleuart.cpp \
$$PWD/qbluetoothleuartdevice.cpp $$PWD/qbluetoothleuartdevice.cpp \
$$PWD/qbluetoothleuartdevicemodel.cpp
HEADERS += \ HEADERS += \
$$PWD/qbluetoothleuart.h \ $$PWD/qbluetoothleuart.h \
$$PWD/qbluetoothleuartdevice.h $$PWD/qbluetoothleuartdevice.h \
$$PWD/qbluetoothleuartdevicemodel.h

View file

@ -15,4 +15,4 @@ M_THEME_COLOR = #0094ff
M_LINKS_NAVBAR1 = M_LINKS_NAVBAR1 =
M_LINKS_NAVBAR2 = "<a href=\"index.html\">Introduction</a>" \ M_LINKS_NAVBAR2 = "<a href=\"index.html\">Introduction</a>" \
annotated \ annotated \
"<a href=\"ScStwSharedLibraries.pdf\">Download</a>" "<a href=\"QBluetoothLeUart.pdf\">Download</a>"

View file

@ -17,6 +17,9 @@ QBluetoothLeUart::QBluetoothLeUart(QObject *parent) : QObject(parent)
connect(bluetoothDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), connect(bluetoothDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
this, SLOT(handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error))); this, SLOT(handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error)));
connect(this->bluetoothDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &QBluetoothLeUart::handleScanFinished); connect(this->bluetoothDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &QBluetoothLeUart::handleScanFinished);
// device model for QML
this->availableDevicesModel = new QBluetoothLeUartDeviceModel(this->availableDevices, this);
} }
QBluetoothLeUart::~QBluetoothLeUart(){ QBluetoothLeUart::~QBluetoothLeUart(){
@ -28,9 +31,11 @@ QBluetoothLeUart::~QBluetoothLeUart(){
// ------------------------------ // ------------------------------
bool QBluetoothLeUart::startScanningForDevices(){ bool QBluetoothLeUart::startScanningForDevices(){
if(this->state != Idle) if(this->state != Idle && this->state != ScanFinished)
return false; return false;
this->availableDevicesModel->clear();
foreach(QBluetoothLeUartDevice* oldDevice, this->availableDevices) foreach(QBluetoothLeUartDevice* oldDevice, this->availableDevices)
oldDevice->deleteLater(); oldDevice->deleteLater();
@ -56,6 +61,7 @@ QList<QBluetoothLeUartDevice*> QBluetoothLeUart::getAvailableDevices() {
} }
QVariantList QBluetoothLeUart::getAvailableDevicesDetailList() { QVariantList QBluetoothLeUart::getAvailableDevicesDetailList() {
QVariantList result; QVariantList result;
for(int i=0; i < this->availableDevices.length(); i++) { for(int i=0; i < this->availableDevices.length(); i++) {
@ -74,6 +80,11 @@ QVariantList QBluetoothLeUart::getAvailableDevicesDetailList() {
return result; return result;
} }
QBluetoothLeUartDeviceModel* QBluetoothLeUart::getAvailableDevicesModel() {
return this->availableDevicesModel;
}
bool QBluetoothLeUart::connectToDevice(int deviceId) { bool QBluetoothLeUart::connectToDevice(int deviceId) {
if(deviceId < 0 || deviceId >= this->availableDevices.length()) if(deviceId < 0 || deviceId >= this->availableDevices.length())
return false; return false;
@ -86,6 +97,9 @@ bool QBluetoothLeUart::connectToDevice(QBluetoothLeUartDevice *device){
if(!this->availableDevices.contains(device)) if(!this->availableDevices.contains(device))
return false; return false;
if(this->state == Scanning)
this->stopScanningForDevices();
this->currentBluetoothDevice = device; this->currentBluetoothDevice = device;
if (bluetoothController) { if (bluetoothController) {
@ -113,22 +127,21 @@ bool QBluetoothLeUart::connectToDevice(QBluetoothLeUartDevice *device){
} }
bool QBluetoothLeUart::disconnectFromDevice() { bool QBluetoothLeUart::disconnectFromDevice() {
if(this->state < ScanningForService) if(this->state < Connecting)
return false; return false;
if(this->state >= Connected)
this->bluetoothController->disconnectFromDevice(); 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);
this->bluetoothController->deleteLater(); this->bluetoothController->deleteLater();
this->bluetoothController = nullptr; this->bluetoothController = nullptr;
if(this->bluetoothService != nullptr) {
this->bluetoothService->deleteLater(); this->bluetoothService->deleteLater();
this->bluetoothService = nullptr; this->bluetoothService = nullptr;
}
this->setState(Idle);
return true; return true;
} }
@ -156,8 +169,13 @@ void QBluetoothLeUart::handleDeviceDiscovered(const QBluetoothDeviceInfo &device
// Is it a BLE device? // Is it a BLE device?
if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
//qWarning() << "Discovered BLE Device: name: " << device.name() << " Address: " << device.address().toString(); //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); QBluetoothLeUartDevice *dev = new QBluetoothLeUartDevice(device, this);
availableDevices.append(dev); this->availableDevices.append(dev);
this->availableDevicesModel->append(dev);
emit this->foundNewDevice(dev); emit this->foundNewDevice(dev);
emit this->avaliableDevicesChanged(this->availableDevices); emit this->avaliableDevicesChanged(this->availableDevices);
} }
@ -228,6 +246,7 @@ void QBluetoothLeUart::handleControllerError(QLowEnergyController::Error error)
{ {
qDebug() << "Cannot connect to remote device."; qDebug() << "Cannot connect to remote device.";
qWarning() << "Controller Error:" << error; qWarning() << "Controller Error:" << error;
this->disconnectFromDevice();
} }
void QBluetoothLeUart::handleDeviceConnected() void QBluetoothLeUart::handleDeviceConnected()
@ -317,7 +336,8 @@ void QBluetoothLeUart::handleServiceDescriptorWritten(const QLowEnergyDescriptor
void QBluetoothLeUart::init() { void QBluetoothLeUart::init() {
#ifdef QBluetoothLeUart_QML #ifdef QBluetoothLeUart_QML
qmlRegisterUncreatableType<QBluetoothLeUartDevice>("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDevice", "BluetoothDeviceInfo cannot be created"); qmlRegisterUncreatableType<QBluetoothLeUartDevice>("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDevice", "QBluetoothLeUartDevice cannot be created");
qmlRegisterUncreatableType<QBluetoothLeUartDeviceModel>("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUartDeviceModel", "QBluetoothLeUartDeviceModel cannot be created");
qmlRegisterType<QBluetoothLeUart>("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUart"); qmlRegisterType<QBluetoothLeUart>("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUart");
qRegisterMetaType<QBluetoothLeUart::BluetoothLeUartState>("QBluetoothLeUart::BluetoothLeUartState"); qRegisterMetaType<QBluetoothLeUart::BluetoothLeUartState>("QBluetoothLeUart::BluetoothLeUartState");
qRegisterMetaType<QBluetoothLeUart::BluetoothScanError>("QBluetoothLeUart::BluetoothScanError"); qRegisterMetaType<QBluetoothLeUart::BluetoothScanError>("QBluetoothLeUart::BluetoothScanError");

View file

@ -11,6 +11,7 @@
#endif #endif
#include <qbluetoothleuartdevice.h> #include <qbluetoothleuartdevice.h>
#include <qbluetoothleuartdevicemodel.h>
/*! /*!
* \mainpage Qt BluetoothLE UART library * \mainpage Qt BluetoothLE UART library
@ -80,6 +81,8 @@
* *
* QML example: * QML example:
* \code{.qml} * \code{.qml}
* import de.itsblue.bluetoothleuart 1.0
*
* QBluetoothLeUart { * QBluetoothLeUart {
* id: ble * id: ble
* Component.onCompleted: { * Component.onCompleted: {
@ -107,7 +110,8 @@
class QBluetoothLeUart : public QObject class QBluetoothLeUart : public QObject
{ {
Q_OBJECT 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) Q_PROPERTY(BluetoothLeUartState state READ getState NOTIFY stateChanged)
public: public:
@ -169,6 +173,9 @@ private:
QLowEnergyDescriptor bluetoothTransmissionDescriptor; QLowEnergyDescriptor bluetoothTransmissionDescriptor;
bool foundValidUARTService; bool foundValidUARTService;
// for QML
QBluetoothLeUartDeviceModel* availableDevicesModel;
public slots: public slots:
/*! /*!
@ -223,6 +230,15 @@ public slots:
*/ */
Q_INVOKABLE QVariantList getAvailableDevicesDetailList(); 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 * \brief Function connect to a device using its internal id
* *
@ -305,6 +321,7 @@ signals:
void foundNewDevice(QBluetoothLeUartDevice* device); void foundNewDevice(QBluetoothLeUartDevice* device);
void avaliableDevicesChanged(QList<QBluetoothLeUartDevice*> avaliableDevices); void avaliableDevicesChanged(QList<QBluetoothLeUartDevice*> avaliableDevices);
void avaliableDevicesModelChanged();
void scanFinished(QList<QBluetoothLeUartDevice*> availableDevices); void scanFinished(QList<QBluetoothLeUartDevice*> availableDevices);
void scanningErrorOccured(QBluetoothLeUart::BluetoothScanError error); void scanningErrorOccured(QBluetoothLeUart::BluetoothScanError error);

View file

@ -7,7 +7,10 @@ QBluetoothLeUartDevice::QBluetoothLeUartDevice(QBluetoothDeviceInfo info, QObjec
QString QBluetoothLeUartDevice::getName() QString QBluetoothLeUartDevice::getName()
{ {
if(bluetoothDeviceInfo.isValid())
return bluetoothDeviceInfo.name(); return bluetoothDeviceInfo.name();
else
return "";
} }
QBluetoothDeviceInfo QBluetoothLeUartDevice::getDevice() QBluetoothDeviceInfo QBluetoothLeUartDevice::getDevice()

View file

@ -0,0 +1,64 @@
#include "qbluetoothleuartdevicemodel.h"
QBluetoothLeUartDeviceModel::QBluetoothLeUartDeviceModel(QList<QBluetoothLeUartDevice*> 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<int, QByteArray> QBluetoothLeUartDeviceModel::roleNames() const
{
static const QHash<int, QByteArray> 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);
}

View file

@ -0,0 +1,65 @@
#ifndef QBLUETOOTHLEUARTDEVICEMODEL_H
#define QBLUETOOTHLEUARTDEVICEMODEL_H
#include <QAbstractListModel>
#include <QObject>
#include <qbluetoothleuartdevice.h>
/*!
* \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<int, QByteArray> roleNames() const;
protected:
QBluetoothLeUartDeviceModel(QList<QBluetoothLeUartDevice*> availableDevices, QObject *parent = nullptr);
void append(QBluetoothLeUartDevice* device);
void remove(int row);
void clear();
private:
QList<QBluetoothLeUartDevice*> availableDevices;
};
#endif // QBLUETOOTHLEUARTDEVICEMODEL_H