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