#include "qbluetoothleuart.h" QBluetoothLeUart::QBluetoothLeUart(QObject *parent) : QObject(parent) { currentBluetoothDevice = nullptr; bluetoothController = nullptr; bluetoothService = nullptr; state = Idle; this->setUUIDs("6e400001-b5a3-f393-e0a9-e50e24dcca9e", "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "6e400003-b5a3-f393-e0a9-e50e24dcca9e"); /* 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("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothDeviceInfo", "BluetoothDeviceInfo cannot be created"); qmlRegisterType("de.itsblue.bluetoothleuart", 1, 0, "QBluetoothLeUART"); qRegisterMetaType("QBluetoothLeUart::BluetoothLeUartState"); qRegisterMetaType("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 QBluetoothLeUart::getAvailableDevices() { return this->availableDevices; } QVariantList QBluetoothLeUart::getAvailableDevicesQML() { QVariantList result; for(int i=0; i < this->availableDevices.length(); i++) { if(this->availableDevices[i]->getName().isEmpty()) continue; QVariantMap device; device.insert("id", i); device.insert("name", this->availableDevices[i]->getName()); device.insert("address", this->availableDevices[i]->getAddress()); result.append(device); } return result; } 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(int deviceId) { if(deviceId < 0 || deviceId >= this->availableDevices.length()) return; this->connectToDevice(this->availableDevices[deviceId]); } 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(this->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(this->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(this->txUUID))); if (!TxChar.isValid()){ qDebug() << "Tx characteristic not found"; this->disconnectFromDevice(); return; } //looking for the RX characteristic const QLowEnergyCharacteristic RxChar = bluetoothService->characteristic(QBluetoothUuid(QUuid(this->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(this->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(this->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; } void QBluetoothLeUart::setUUIDs(const char uartServiceUUID[36], const char rxUUID[36], const char txUUID[36]) { this->uartServiceUUID = uartServiceUUID; this->rxUUID = rxUUID; this->txUUID = txUUID; }