QBluetoothLeUart/qbluetoothleuart.cpp

279 lines
9.8 KiB
C++

#include "qbluetoothleuart.h"
QBluetoothLeUart::QBluetoothLeUart(QObject *parent) : QObject(parent)
{
currentBluetoothDevice = nullptr;
bluetoothController = nullptr;
bluetoothService = nullptr;
state = Idle;
/* 1 Step: Bluetooth LE Device Discovery */
this->bluetoothDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
/* Device Discovery Initialization */
connect(this->bluetoothDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &QBluetoothLeUart::handleDeviceDiscovered);
connect(bluetoothDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
this, SLOT(handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error)));
connect(this->bluetoothDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &QBluetoothLeUart::handleScanFinished);
}
QBluetoothLeUart::~QBluetoothLeUart(){
}
void QBluetoothLeUart::init() {
#ifdef QBluetoothLeUart_QML
qmlRegisterUncreatableType<QBluetoothLeUartDevice>("de.itsblue.bluetoothleuart", 1, 0, "BluetoothDeviceInfo", "BluetoothDeviceInfo cannot be created");
qmlRegisterType<QBluetoothLeUart>("de.itsblue.bluetoothleuart", 1, 0, "BluetoothLeUART");
qRegisterMetaType<QBluetoothLeUart::BluetoothLeUartState>("QBluetoothLeUart::BluetoothLeUartState");
qRegisterMetaType<QBluetoothLeUart::BluetoothScanError>("QBluetoothLeUart::BluetoothScanError");
#endif
}
void QBluetoothLeUart::startScanningForDevices(){
foreach(QBluetoothLeUartDevice* oldDevice, this->availableDevices)
oldDevice->deleteLater();
this->availableDevices.clear();
setState(Scanning);
bluetoothDeviceDiscoveryAgent->start();
qDebug()<< "Searching for low energy devices..." ;
}
void QBluetoothLeUart::stopScanningForDevices() {
this->bluetoothDeviceDiscoveryAgent->stop();
this->setState(ScanFinished);
}
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();
QBluetoothLeUartDevice *dev = new QBluetoothLeUartDevice(device, this);
availableDevices.append(dev);
emit this->foundNewDevice(dev);
emit this->avaliableDevicesChanged(this->availableDevices);
}
}
void QBluetoothLeUart::handleScanFinished()
{
if (availableDevices.size() == 0)
{
qWarning() << "No Low Energy devices found" << endl;
}
setState(ScanFinished);
}
QList<QBluetoothLeUartDevice*> QBluetoothLeUart::getAvailableDevices() {
return this->availableDevices;
}
void QBluetoothLeUart::handleDeviceScanError(QBluetoothDeviceDiscoveryAgent::Error error)
{
if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError)
emit this->scanningErrorOccured(AdapterTurnedOffError);
else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError)
emit this->scanningErrorOccured(InputOutputError);
else
emit this->scanningErrorOccured(UnknownError);
}
void QBluetoothLeUart::connectToDevice(QBluetoothLeUartDevice *device){
m_qvMeasurements.clear();
this->currentBluetoothDevice = device;
if (bluetoothController) {
bluetoothController->disconnectFromDevice();
delete bluetoothController;
bluetoothController = 0;
}
/* 2 Step: QLowEnergyController */
bluetoothController = new QLowEnergyController(currentBluetoothDevice->getDevice(), this);
bluetoothController ->setRemoteAddressType(QLowEnergyController::RandomAddress);
connect(this->bluetoothController, &QLowEnergyController::serviceDiscovered, this, &QBluetoothLeUart::handleServiceDiscovered);
connect(this->bluetoothController, &QLowEnergyController::discoveryFinished, this, &QBluetoothLeUart::handleServiceScanDone);
connect(bluetoothController, SIGNAL(error(QLowEnergyController::Error)),
this, SLOT(handleControllerError(QLowEnergyController::Error)));
connect(this->bluetoothController, &QLowEnergyController::connected, this, &QBluetoothLeUart::handleDeviceConnected);
connect(this->bluetoothController, &QLowEnergyController::disconnected, this, &QBluetoothLeUart::handleDeviceDisconnected);
/* Start connecting to device */
bluetoothController->connectToDevice();
setState(Connecting);
}
void QBluetoothLeUart::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();
}
void QBluetoothLeUart::handleDeviceDisconnected()
{
this->setState(Idle);
qDebug() << "UART service disconnected";
qWarning() << "Remote device disconnected";
}
void QBluetoothLeUart::handleDeviceConnected()
{
qDebug() << "Device connected";
bluetoothController->discoverServices();
setState(Connected);
}
void QBluetoothLeUart::handleControllerError(QLowEnergyController::Error error)
{
qDebug() << "Cannot connect to remote device.";
qWarning() << "Controller Error:" << error;
}
void QBluetoothLeUart::handleServiceDiscovered(const QBluetoothUuid &gatt){
qDebug() << "Found service with ID: " << gatt;
if(gatt==QBluetoothUuid(QUuid(UARTSERVICEUUID))){
foundValidUARTService =true;
qDebug() << "UART service found!";
}
}
void QBluetoothLeUart::handleServiceScanDone(){
delete bluetoothService;
bluetoothService=0;
if(foundValidUARTService){
qDebug() << "Connecting to UART service...";
bluetoothService = bluetoothController->createServiceObject(QBluetoothUuid(QUuid(UARTSERVICEUUID)),this);
}
if(!bluetoothService){
qDebug() <<"UART service not found";
this->disconnectFromDevice();
return;
}
/* 3 Step: Service Discovery */
connect(this->bluetoothService, &QLowEnergyService::stateChanged, this, &QBluetoothLeUart::handleServiceStateChange);
connect(this->bluetoothService, &QLowEnergyService::characteristicChanged, this, &QBluetoothLeUart::handleServiceCharacteristicChange);
connect(this->bluetoothService, &QLowEnergyService::descriptorWritten, this, &QBluetoothLeUart::handleServiceDescriptorWritten);
bluetoothService->discoverDetails();
setState(ServiceFound);
}
/* Slots for QLowEnergyService */
void QBluetoothLeUart::handleServiceStateChange(QLowEnergyService::ServiceState s)
{
// A descriptoc can only be written if the service is in the ServiceDiscovered state
switch (s) {
case QLowEnergyService::ServiceDiscovered:
{
//looking for the TX characteristic
const QLowEnergyCharacteristic TxChar = bluetoothService->characteristic(QBluetoothUuid(QUuid(TXUUID)));
if (!TxChar.isValid()){
qDebug() << "Tx characteristic not found";
this->disconnectFromDevice();
return;
}
//looking for the RX characteristic
const QLowEnergyCharacteristic RxChar = bluetoothService->characteristic(QBluetoothUuid(QUuid(RXUUID)));
if (!RxChar.isValid()) {
qDebug() << "Rx characteristic not found";
this->disconnectFromDevice();
return;
}
// Bluetooth LE spec Where a characteristic can be notified, a Client Characteristic Configuration descriptor
// shall be included in that characteristic as required by the Bluetooth Core Specification
// Tx notify is enabled
const QLowEnergyDescriptor m_notificationDescTx = TxChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if (m_notificationDescTx.isValid()) {
// enable notification
bluetoothService->writeDescriptor(m_notificationDescTx, QByteArray::fromHex("0100"));
setState(AcquireData);
emit this->connectedToDevice();
}
break;
}
default:
//nothing for now
break;
}
}
void QBluetoothLeUart::handleServiceCharacteristicChange(const QLowEnergyCharacteristic &c,const QByteArray &value)
{
// ignore any other characteristic change
if (c.uuid() != QBluetoothUuid(QUuid(TXUUID)))
return;
emit dataReceived((QString) value);
}
void QBluetoothLeUart::handleServiceDescriptorWritten(const QLowEnergyDescriptor &d,
const QByteArray &value)
{
if (d.isValid() && d == bluetoothTransmissionDescriptor && value == QByteArray("0000")) {
//disabled notifications -> assume disconnect intent
bluetoothController->disconnectFromDevice();
delete bluetoothService;
bluetoothService = 0;
}
}
void QBluetoothLeUart::sendData(QString s){
const QLowEnergyCharacteristic RxChar = bluetoothService->characteristic(QBluetoothUuid(QUuid(RXUUID)));
qDebug()<< s;
QByteArray Data;
Data.append(s);
bluetoothService->writeCharacteristic(RxChar, Data,QLowEnergyService::WriteWithoutResponse);
}
void QBluetoothLeUart::setState(QBluetoothLeUart::BluetoothLeUartState newState)
{
if (state == newState)
return;
state = newState;
emit stateChanged(newState);
}
QBluetoothLeUart::BluetoothLeUartState QBluetoothLeUart::getState() const {
return state;
}