QBluetoothLeUart/qbluetoothleuartclient.h

368 lines
12 KiB
C
Raw Normal View History

2020-10-08 20:01:21 +02:00
#ifndef BLUETOOTHLEUART_H
#define BLUETOOTHLEUART_H
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothDeviceInfo>
#include <QLowEnergyController>
#include <QLowEnergyService>
#ifdef Q_OS_ANDROID
#include <QtAndroidExtras>
#endif
2020-10-08 20:01:21 +02:00
#ifdef QBluetoothLeUart_QML
#include <QQmlApplicationEngine>
#endif
2020-10-08 22:03:31 +02:00
#include <qbluetoothleuartdevice.h>
#include <qbluetoothleuartdevicemodel.h>
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
/*!
* \mainpage Qt BluetoothLE UART library
*
* \section intro_sec Introduction
*
* This library can be used to talk to BLE devices via UART in Qt.
2020-10-11 21:01:01 +02:00
* It was designed to make talking to devices like the ESP32 from Qt easier.
2020-10-09 12:06:33 +02:00
*
* \section section Installation
* \code{.sh}
* cd yourRepo
* git submodule add https://itsblue.dev/itsblue-development/QBluetoothLeUart.git
* git submodule update --init --recursive
* \endcode
*
* And in your MyProject.pro include the .pri file:
* \code{.pro}
* # Optional: enable QML stuff
* CONFIG += QBluetoothLeUart_QML
* # Include library
* include($$PWD/QBluetoothLeUart/QBluetoothLeUart.pri)
* \endcode
2020-10-11 21:01:01 +02:00
*
* To enable the QML module you need to call
* \code{.cpp}
* QBluetoothLeUart::init();
* \endcode
* somewhere before app.exec(); in your main.cpp.
2020-10-26 22:48:15 +01:00
*
2020-10-26 22:56:42 +01:00
* \section Getting_started
2020-10-26 22:48:15 +01:00
* This library currently supports: BluetoothLE UART client
* \subsection BluetoothLE UART client
* To get started with the BLE client, see the docs of QBluetoothLeUartClient.
*
2020-10-09 12:06:33 +02:00
*/
/*!
2020-10-26 22:48:15 +01:00
* \brief The QBluetoothLeUartClient class can be used to talk to BluetoothLE devices via UART effordlessly.
2020-10-09 12:06:33 +02:00
* It can be used via C++ and QML.
2020-10-09 12:31:39 +02:00
*
* C++ example:
* \code{.cpp}
2020-10-26 22:56:42 +01:00
* #include <qbluetoothleuartclient.h>
2020-10-09 12:31:39 +02:00
* class MyBluetoothLeClass : QObject {
* public:
* MyBluetoothLeClass(QObject* parent = nullptr) : QObject(parent) {
2020-10-26 22:48:15 +01:00
* this->ble = new QBluetoothLeUartClient();
2020-10-09 12:31:39 +02:00
*
2020-10-26 22:48:15 +01:00
* connect(this->ble, &QBluetoothLeUartClient::foundNewDevice, this, &MyBluetoothLeClass::handleFoundNewDevice);
* connect(this->ble, &QBluetoothLeUartClient::connectedToDevice, this, &MyBluetoothLeClass::handleBluetoothDeviceConected);
* connect(this->ble, &QBluetoothLeUartClient::dataReceived, this, &MyBluetoothLeClass::handleDataReceived);
2020-10-09 12:31:39 +02:00
*
* this->ble->startScanningForDevices();
* }
*
* private:
2020-10-26 22:48:15 +01:00
* QBluetoothLeUartClient *ble;
2020-10-09 12:31:39 +02:00
*
* private slots:
* void handleFoundNewDevice(QBluetoothLeUartDevice* device) {
* qDebug() << "Found a device: name: " << device->getName() << " address: " << device->getAddress();
*
* if(device->getName() == "My device name"){
* this->ble->stopScanningForDevices();
* this->ble->connectToDevice(device);
* }
* }
*
* void handleBluetoothDeviceConected() {
* this->ble->sendData("This is my test message");
* }
*
* void handleDataReceived(const QString &s) {
* qDebug() << "Data received: " << s;
* }
* };
* \endcode
*
* QML example:
* \code{.qml}
* import de.itsblue.bluetoothleuart 1.0
*
2020-10-26 22:48:15 +01:00
* QBluetoothLeUartClient {
2020-10-09 12:31:39 +02:00
* id: ble
* Component.onCompleted: {
* ble.startScanningForDevices()
* }
2020-10-09 12:31:39 +02:00
*
* onFoundNewDevice: {
* console.log("Found a device: name: " + device.name + " address: " + device.address)
2020-10-09 12:34:56 +02:00
* if(device.name === "My device name") {
2020-10-09 12:31:39 +02:00
* ble.stopScanningForDevices()
* ble.connectToDevice(device)
* }
* }
*
* onConnectedToDevice: {
* ble.sendData("This is my test message")
* }
*
* onDataReceived: {
* console.log("Data received: " + data)
* }
* }
* \endcode
2020-10-26 22:56:42 +01:00
*
* To get all available devices in a model, use the QBluetoothLeUartDeviceModel.
2020-10-09 12:06:33 +02:00
*/
2020-10-17 21:51:06 +02:00
class QBluetoothLeUartClient : public QObject
2020-10-08 20:01:21 +02:00
{
Q_OBJECT
Q_PROPERTY(QVariantList availableDevices READ getAvailableDevicesDetailList NOTIFY avaliableDevicesChanged)
Q_PROPERTY(QBluetoothLeUartDeviceModel* availableDevicesModel READ getAvailableDevicesModel NOTIFY avaliableDevicesModelChanged)
2020-10-13 01:56:54 +02:00
Q_PROPERTY(QBluetoothLeUartDevice* currentDevice READ getCurrentDevice NOTIFY currentDeviceChanged)
2020-10-17 21:51:06 +02:00
Q_PROPERTY(BluetoothLeUartClientState state READ getState NOTIFY stateChanged)
2020-10-08 20:01:21 +02:00
public:
2020-10-09 12:06:33 +02:00
/*!
* \brief The BluetoothLeUartState enum contains all state of the QBluetoothLeUart class.
*/
2020-10-17 21:51:06 +02:00
enum BluetoothLeUartClientState {
2020-10-09 12:06:33 +02:00
Idle = 0, /*!< Waiting for instrucions */
AdapterTurnedOff, /*!< The bluetooth adapter is turned off */
LocationPermissionDenied, /*!< The location permssion was denied and we are therfor unable to scan! */
2020-10-09 12:06:33 +02:00
Scanning, /*!< Scanning for devices */
ScanFinished, /*!< Scanning has finished, we are ready to connect */
Connecting, /*!< Trying to connect */
ScanningForService, /*!< Connection was successfull, now scanning for services */
ServiceFound, /*!< Services were found */
Connected /*!< Connected. We are now ready to send and receive */
2020-10-08 20:01:21 +02:00
};
2020-10-17 21:51:06 +02:00
Q_ENUM(BluetoothLeUartClientState)
2020-10-08 20:01:21 +02:00
enum BluetoothScanError {
UnknownError,
AdapterTurnedOffError,
InputOutputError,
LocationPermissionDeniedError
2020-10-08 20:01:21 +02:00
};
Q_ENUM(BluetoothScanError);
2020-10-17 21:51:06 +02:00
QBluetoothLeUartClient(QObject *parent = nullptr);
~QBluetoothLeUartClient();
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
/*!
* \brief Function to register QMl types
*/
2020-10-08 20:01:21 +02:00
static void init();
2020-10-09 12:06:33 +02:00
/*!
* \brief Function to set the UUIDs of the bluetooth service
* \param uartServiceUUID Service UUID
* \param txUUID UUID of the characteristic used to send data
* \param rxUUID UUID of the characteristic used to receive data
*/
void setUUIDs(const char uartServiceUUID[36], const char txUUID[36], const char rxUUID[36]);
2020-10-08 22:03:31 +02:00
2020-10-08 20:01:21 +02:00
private:
2020-10-09 12:06:33 +02:00
// The UUIDs
2020-10-08 22:03:31 +02:00
QString uartServiceUUID;
QString txUUID;
2020-10-09 12:06:33 +02:00
QString rxUUID;
2020-10-08 22:03:31 +02:00
2020-10-09 12:06:33 +02:00
// current state
2020-10-17 21:51:06 +02:00
QBluetoothLeUartClient::BluetoothLeUartClientState state;
2020-10-09 12:06:33 +02:00
// QBluetooth controllers
2020-10-08 20:01:21 +02:00
QBluetoothDeviceDiscoveryAgent *bluetoothDeviceDiscoveryAgent;
QLowEnergyController *bluetoothController;
QLowEnergyService *bluetoothService;
2020-10-09 12:06:33 +02:00
// Bluetooth device
QBluetoothLeUartDevice *currentBluetoothDevice;
QList<QBluetoothLeUartDevice*> availableDevices;
2020-10-08 20:01:21 +02:00
QLowEnergyDescriptor bluetoothTransmissionDescriptor;
bool foundValidUARTService;
// for QML
QBluetoothLeUartDeviceModel* availableDevicesModel;
2020-10-08 20:01:21 +02:00
public slots:
Q_INVOKABLE bool requestLocationPermission();
Q_INVOKABLE bool isLocationPermissionGranted();
2020-10-09 12:06:33 +02:00
/*!
* \brief Fuction to start scanning for devices
*
* This function will start the device scanning process and might emit
* the following signals during scanning:
* - foundNewDevice() when a new device is found
* - avaliableDevicesChanged() when a new device is found
* - scanFinished() when the scan has finished
* - scanningErrorOccured() when an error occured
*
* \see foundNewDevice()
* \see avaliableDevicesChanged()
* \see scanFinished()
* \see scanningErrorOccured()
*
* \return true if the scan started, false if the current state was not Idle
*/
Q_INVOKABLE bool startScanningForDevices();
/*!
* \brief Function to stop scanning for devices
*
* \return true if the scan was stopped, false if the current state was not Scanning
*/
Q_INVOKABLE bool stopScanningForDevices();
/*!
* \brief Function to get all devices that were found during the last scan
*
* A QBluetoothLeUartDevice object can be used to connect to the specific device
*
* \see connectToDevice()
*
* \return List of all devices found during last scan
*/
2020-10-08 20:01:21 +02:00
Q_INVOKABLE QList<QBluetoothLeUartDevice*> getAvailableDevices();
2020-10-09 12:06:33 +02:00
/*!
* \brief Function to get a variant list of all devices that were found during the last scan
*
* This will return a QVariantList that contains QVariantMaps.
* The maps contain the following keys:
* - "id" (int): the internal id of the device (used to connect to it)
* - "name" (QString): the name of the device
* - "address" (QString): the bluetooth address of the device
*
* \see connectToDevice()
*
* \return Variant list of all devices found during last scan
*/
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();
2020-10-13 01:56:54 +02:00
/*!
* \brief Function to get the currently connected device
* \return The currently connected device or nullptr if no device is connected
*/
Q_INVOKABLE QBluetoothLeUartDevice* getCurrentDevice();
2020-10-09 12:06:33 +02:00
/*!
* \brief Function connect to a device using its internal id
*
* The id can be found using getAvailableDevicesDetailList()
* The connectedToDevice() signal will be emited as soon as the connection was successfull.
* As soon as that signal was emited, the sendData() slot can be used to send data and
* the dataReceived() signal will be emited whenever data is received.
*
* \param deviceId the internal id of the device
*
* \see getAvailableDevicesDetailList()
* \see connectedToDevice()
* \see dataReceived()
*
* \return false if the device was not found in the internal list of discovered devices, true otherwise
*/
Q_INVOKABLE bool connectToDevice(int deviceId);
/*!
* \brief Function connect to a device using a QBluetoothLeUartDevice object
*
* The QBluetoothLeUartDevice can be found using getAvailableDevices()
* The connectedToDevice() signal will be emited as soon as the connection was successfull.
* As soon as that signal was emited, the sendData() slot can be used to send data and
* the dataReceived() signal will be emited whenever data is received.
*
* \param device The device to connect to
*
* \see getAvailableDevices()
* \see connectedToDevice()
* \see dataReceived()
*
* \return false if the device was not found in the internal list of discovered devices, true otherwise
*/
Q_INVOKABLE bool connectToDevice(QBluetoothLeUartDevice *device);
/*!
* \brief Function to disconnect from the current device
*
* \return false if no device was connected, true otherwise
*/
Q_INVOKABLE bool disconnectFromDevice();
/*!
* \brief Function to send data to the connected device
* \param data The data to send
* \return false if there was not device connected, true otherwise
*/
2020-10-13 01:56:54 +02:00
Q_INVOKABLE bool sendData(QString data, bool asynchronous = true);
2020-10-09 12:06:33 +02:00
/*!
* \brief Function to get the current state of QBluetoothLeUart
* \see BluetoothLeUartState
* \return The current state
*/
2020-10-17 21:51:06 +02:00
Q_INVOKABLE QBluetoothLeUartClient::BluetoothLeUartClientState getState() const;
2020-10-08 20:01:21 +02:00
private slots:
2020-10-17 21:51:06 +02:00
void setState(QBluetoothLeUartClient::BluetoothLeUartClientState newState);
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
// Slots for QBluetothDeviceDiscoveryAgent
2020-10-08 20:01:21 +02:00
void handleDeviceDiscovered(const QBluetoothDeviceInfo&);
void handleScanFinished();
void handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error);
2020-10-09 12:06:33 +02:00
// Slots for QLowEnergyController
void handleServiceDiscovered(const QBluetoothUuid & uuid);
2020-10-08 20:01:21 +02:00
void handleServiceScanDone();
void handleControllerError(QLowEnergyController::Error);
void handleDeviceConnected();
void handleDeviceDisconnected();
2020-10-09 12:06:33 +02:00
// Slots for QLowEnergyService
2020-10-08 20:01:21 +02:00
void handleServiceStateChange(QLowEnergyService::ServiceState s);
void handleServiceCharacteristicChange(const QLowEnergyCharacteristic &c, const QByteArray &value);
void handleServiceDescriptorWritten(const QLowEnergyDescriptor &d, const QByteArray &value);
signals:
2020-10-17 21:51:06 +02:00
void stateChanged(QBluetoothLeUartClient::BluetoothLeUartClientState newState);
2020-10-09 12:06:33 +02:00
2020-10-08 20:01:21 +02:00
void foundNewDevice(QBluetoothLeUartDevice* device);
2020-10-09 12:06:33 +02:00
void avaliableDevicesChanged(QList<QBluetoothLeUartDevice*> avaliableDevices);
void avaliableDevicesModelChanged();
2020-10-13 01:56:54 +02:00
void currentDeviceChanged();
2020-10-09 12:06:33 +02:00
void scanFinished(QList<QBluetoothLeUartDevice*> availableDevices);
2020-10-17 21:51:06 +02:00
void scanningErrorOccured(QBluetoothLeUartClient::BluetoothScanError error);
2020-10-09 12:06:33 +02:00
2020-10-08 20:01:21 +02:00
void connectedToDevice();
2020-10-09 12:31:39 +02:00
void dataReceived(QString data);
2020-10-09 12:06:33 +02:00
2020-10-08 20:01:21 +02:00
};
#endif // BLUETOOTHLEUART_H