- update example
- some fixes - added QBluetoothLeUartDeviceModel for use with QML
This commit is contained in:
parent
7f5ad16ba9
commit
60d10f056b
7 changed files with 191 additions and 20 deletions
|
@ -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
|
||||||
|
|
|
@ -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>"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
this->bluetoothController->disconnectFromDevice();
|
if(this->state >= Connected)
|
||||||
|
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;
|
||||||
this->bluetoothService->deleteLater();
|
|
||||||
this->bluetoothService = nullptr;
|
if(this->bluetoothService != nullptr) {
|
||||||
|
this->bluetoothService->deleteLater();
|
||||||
|
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");
|
||||||
|
|
|
@ -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,11 +81,13 @@
|
||||||
*
|
*
|
||||||
* QML example:
|
* QML example:
|
||||||
* \code{.qml}
|
* \code{.qml}
|
||||||
|
* import de.itsblue.bluetoothleuart 1.0
|
||||||
|
*
|
||||||
* QBluetoothLeUart {
|
* QBluetoothLeUart {
|
||||||
* id: ble
|
* id: ble
|
||||||
* Component.onCompleted: {
|
* Component.onCompleted: {
|
||||||
* ble.startScanningForDevices()
|
* ble.startScanningForDevices()
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* onFoundNewDevice: {
|
* onFoundNewDevice: {
|
||||||
* console.log("Found a device: name: " + device.name + " address: " + device.address)
|
* console.log("Found a device: name: " + device.name + " address: " + device.address)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,10 @@ QBluetoothLeUartDevice::QBluetoothLeUartDevice(QBluetoothDeviceInfo info, QObjec
|
||||||
|
|
||||||
QString QBluetoothLeUartDevice::getName()
|
QString QBluetoothLeUartDevice::getName()
|
||||||
{
|
{
|
||||||
return bluetoothDeviceInfo.name();
|
if(bluetoothDeviceInfo.isValid())
|
||||||
|
return bluetoothDeviceInfo.name();
|
||||||
|
else
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
QBluetoothDeviceInfo QBluetoothLeUartDevice::getDevice()
|
QBluetoothDeviceInfo QBluetoothLeUartDevice::getDevice()
|
||||||
|
|
64
qbluetoothleuartdevicemodel.cpp
Normal file
64
qbluetoothleuartdevicemodel.cpp
Normal 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);
|
||||||
|
}
|
65
qbluetoothleuartdevicemodel.h
Normal file
65
qbluetoothleuartdevicemodel.h
Normal 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
|
Loading…
Reference in a new issue