286 lines
10 KiB
C++
286 lines
10 KiB
C++
#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<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(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;
|
|
}
|