2020-10-08 20:01:21 +02:00
# include "qbluetoothleuart.h"
QBluetoothLeUart : : QBluetoothLeUart ( QObject * parent ) : QObject ( parent )
{
currentBluetoothDevice = nullptr ;
bluetoothController = nullptr ;
bluetoothService = nullptr ;
state = Idle ;
2020-10-08 22:03:31 +02:00
this - > setUUIDs ( " 6e400001-b5a3-f393-e0a9-e50e24dcca9e " , " 6e400002-b5a3-f393-e0a9-e50e24dcca9e " , " 6e400003-b5a3-f393-e0a9-e50e24dcca9e " ) ;
2020-10-09 12:06:33 +02:00
// init device discovery agent for scanning
2020-10-08 20:01:21 +02:00
this - > bluetoothDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent ( this ) ;
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 ) ;
2020-10-11 15:49:51 +02:00
// device model for QML
this - > availableDevicesModel = new QBluetoothLeUartDeviceModel ( this - > availableDevices , this ) ;
2020-10-08 20:01:21 +02:00
}
QBluetoothLeUart : : ~ QBluetoothLeUart ( ) {
}
2020-10-09 12:06:33 +02:00
// ------------------------------
// - Slots for QBluetoothLeUart -
// ------------------------------
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : startScanningForDevices ( ) {
2020-10-11 15:49:51 +02:00
if ( this - > state ! = Idle & & this - > state ! = ScanFinished )
2020-10-09 12:06:33 +02:00
return false ;
2020-10-08 20:01:21 +02:00
2020-10-11 15:49:51 +02:00
this - > availableDevicesModel - > clear ( ) ;
2020-10-08 20:01:21 +02:00
foreach ( QBluetoothLeUartDevice * oldDevice , this - > availableDevices )
oldDevice - > deleteLater ( ) ;
this - > availableDevices . clear ( ) ;
2020-10-09 12:06:33 +02:00
this - > setState ( Scanning ) ;
this - > bluetoothDeviceDiscoveryAgent - > start ( ) ;
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
return true ;
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : stopScanningForDevices ( ) {
if ( this - > state ! = Scanning )
return false ;
2020-10-08 20:01:21 +02:00
this - > bluetoothDeviceDiscoveryAgent - > stop ( ) ;
this - > setState ( ScanFinished ) ;
2020-10-09 12:06:33 +02:00
return true ;
2020-10-08 20:01:21 +02:00
}
QList < QBluetoothLeUartDevice * > QBluetoothLeUart : : getAvailableDevices ( ) {
return this - > availableDevices ;
}
2020-10-09 12:06:33 +02:00
QVariantList QBluetoothLeUart : : getAvailableDevicesDetailList ( ) {
2020-10-11 15:49:51 +02:00
2020-10-09 00:03:51 +02:00
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 ;
}
2020-10-11 15:49:51 +02:00
QBluetoothLeUartDeviceModel * QBluetoothLeUart : : getAvailableDevicesModel ( ) {
return this - > availableDevicesModel ;
}
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : connectToDevice ( int deviceId ) {
2020-10-09 00:03:51 +02:00
if ( deviceId < 0 | | deviceId > = this - > availableDevices . length ( ) )
2020-10-09 12:06:33 +02:00
return false ;
2020-10-09 00:03:51 +02:00
this - > connectToDevice ( this - > availableDevices [ deviceId ] ) ;
2020-10-09 12:06:33 +02:00
return true ;
2020-10-09 00:03:51 +02:00
}
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : connectToDevice ( QBluetoothLeUartDevice * device ) {
if ( ! this - > availableDevices . contains ( device ) )
return false ;
2020-10-08 20:01:21 +02:00
2020-10-11 15:49:51 +02:00
if ( this - > state = = Scanning )
this - > stopScanningForDevices ( ) ;
2020-10-08 20:01:21 +02:00
this - > currentBluetoothDevice = device ;
if ( bluetoothController ) {
bluetoothController - > disconnectFromDevice ( ) ;
delete bluetoothController ;
bluetoothController = 0 ;
}
2020-10-09 12:06:33 +02:00
// initialize QLowEnergyController
2020-10-08 20:01:21 +02:00
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 ) ;
2020-10-09 12:06:33 +02:00
return true ;
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : disconnectFromDevice ( ) {
2020-10-11 15:49:51 +02:00
if ( this - > state < Connecting )
2020-10-09 12:06:33 +02:00
return false ;
2020-10-11 15:49:51 +02:00
if ( this - > state > = Connected )
this - > bluetoothController - > disconnectFromDevice ( ) ;
2020-10-08 20:01:21 +02:00
this - > bluetoothController - > deleteLater ( ) ;
2020-10-09 12:06:33 +02:00
this - > bluetoothController = nullptr ;
2020-10-11 15:49:51 +02:00
if ( this - > bluetoothService ! = nullptr ) {
this - > bluetoothService - > deleteLater ( ) ;
this - > bluetoothService = nullptr ;
}
this - > setState ( Idle ) ;
2020-10-09 12:06:33 +02:00
return true ;
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
bool QBluetoothLeUart : : sendData ( QString data ) {
if ( this - > state ! = Connected )
return false ;
const QLowEnergyCharacteristic RxChar = bluetoothService - > characteristic ( QBluetoothUuid ( QUuid ( this - > txUUID ) ) ) ;
QByteArray Data ;
Data . append ( data ) ;
bluetoothService - > writeCharacteristic ( RxChar , Data , QLowEnergyService : : WriteWithoutResponse ) ;
return true ;
}
// -------------------------------------------
// - Slots for QBluetothDeviceDiscoveryAgent -
// -------------------------------------------
void QBluetoothLeUart : : handleDeviceDiscovered ( const QBluetoothDeviceInfo & device )
2020-10-08 20:01:21 +02:00
{
2020-10-09 12:06:33 +02:00
// Is it a BLE device?
if ( device . coreConfigurations ( ) & QBluetoothDeviceInfo : : LowEnergyCoreConfiguration ) {
//qWarning() << "Discovered BLE Device: name: " << device.name() << " Address: " << device.address().toString();
2020-10-11 15:49:51 +02:00
// ignore all devices that to not support our service
if ( ! device . serviceUuids ( ) . contains ( QBluetoothUuid ( this - > uartServiceUUID ) ) )
return ;
2020-10-09 12:06:33 +02:00
QBluetoothLeUartDevice * dev = new QBluetoothLeUartDevice ( device , this ) ;
2020-10-11 15:49:51 +02:00
this - > availableDevices . append ( dev ) ;
this - > availableDevicesModel - > append ( dev ) ;
2020-10-09 12:06:33 +02:00
emit this - > foundNewDevice ( dev ) ;
emit this - > avaliableDevicesChanged ( this - > availableDevices ) ;
}
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : handleScanFinished ( )
2020-10-08 20:01:21 +02:00
{
2020-10-09 12:06:33 +02:00
if ( this - > availableDevices . size ( ) = = 0 )
{
qWarning ( ) < < " No Low Energy devices found " < < endl ;
}
emit this - > scanFinished ( this - > availableDevices ) ;
setState ( ScanFinished ) ;
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : handleDeviceScanError ( QBluetoothDeviceDiscoveryAgent : : Error error )
2020-10-08 20:01:21 +02:00
{
2020-10-09 12:06:33 +02:00
if ( error = = QBluetoothDeviceDiscoveryAgent : : PoweredOffError )
emit this - > scanningErrorOccured ( AdapterTurnedOffError ) ;
else if ( error = = QBluetoothDeviceDiscoveryAgent : : InputOutputError )
emit this - > scanningErrorOccured ( InputOutputError ) ;
else
emit this - > scanningErrorOccured ( UnknownError ) ;
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
// ----------------------------------
// - Slots for QLowEnergyController -
// ----------------------------------
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : handleServiceDiscovered ( const QBluetoothUuid & uuid ) {
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
qDebug ( ) < < " Found service with ID: " < < uuid ;
if ( uuid = = QBluetoothUuid ( QUuid ( this - > uartServiceUUID ) ) ) {
2020-10-08 20:01:21 +02:00
foundValidUARTService = true ;
qDebug ( ) < < " UART service found! " ;
}
}
void QBluetoothLeUart : : handleServiceScanDone ( ) {
delete bluetoothService ;
bluetoothService = 0 ;
if ( foundValidUARTService ) {
qDebug ( ) < < " Connecting to UART service... " ;
2020-10-08 22:03:31 +02:00
bluetoothService = bluetoothController - > createServiceObject ( QBluetoothUuid ( QUuid ( this - > uartServiceUUID ) ) , this ) ;
2020-10-08 20:01:21 +02:00
}
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 ) ;
}
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : handleControllerError ( QLowEnergyController : : Error error )
{
qDebug ( ) < < " Cannot connect to remote device. " ;
qWarning ( ) < < " Controller Error: " < < error ;
2020-10-11 15:49:51 +02:00
this - > disconnectFromDevice ( ) ;
2020-10-09 12:06:33 +02:00
}
void QBluetoothLeUart : : handleDeviceConnected ( )
{
qDebug ( ) < < " Device connected " ;
bluetoothController - > discoverServices ( ) ;
setState ( ScanningForService ) ;
}
void QBluetoothLeUart : : handleDeviceDisconnected ( )
{
this - > setState ( Idle ) ;
qDebug ( ) < < " UART service disconnected " ;
qWarning ( ) < < " Remote device disconnected " ;
}
// -------------------------------
// - Slots for QLowEnergyService -
// -------------------------------
2020-10-08 20:01:21 +02:00
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 :
{
2020-10-09 12:06:33 +02:00
//looking for the RX characteristic
const QLowEnergyCharacteristic TxChar = bluetoothService - > characteristic ( QBluetoothUuid ( QUuid ( this - > rxUUID ) ) ) ;
2020-10-08 20:01:21 +02:00
if ( ! TxChar . isValid ( ) ) {
2020-10-09 12:06:33 +02:00
qDebug ( ) < < " Rx characteristic not found " ;
2020-10-08 20:01:21 +02:00
this - > disconnectFromDevice ( ) ;
return ;
}
2020-10-09 12:06:33 +02:00
//looking for the TX characteristic
const QLowEnergyCharacteristic RxChar = bluetoothService - > characteristic ( QBluetoothUuid ( QUuid ( this - > txUUID ) ) ) ;
2020-10-08 20:01:21 +02:00
if ( ! RxChar . isValid ( ) ) {
2020-10-09 12:06:33 +02:00
qDebug ( ) < < " Tx characteristic not found " ;
2020-10-08 20:01:21 +02:00
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 " ) ) ;
2020-10-09 12:06:33 +02:00
setState ( Connected ) ;
2020-10-08 20:01:21 +02:00
emit this - > connectedToDevice ( ) ;
}
break ;
}
default :
//nothing for now
break ;
}
}
void QBluetoothLeUart : : handleServiceCharacteristicChange ( const QLowEnergyCharacteristic & c , const QByteArray & value )
{
// ignore any other characteristic change
2020-10-09 12:06:33 +02:00
if ( c . uuid ( ) ! = QBluetoothUuid ( QUuid ( this - > rxUUID ) ) )
2020-10-08 20:01:21 +02:00
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
2020-10-09 12:06:33 +02:00
this - > disconnectFromDevice ( ) ;
2020-10-08 20:01:21 +02:00
}
}
2020-10-09 12:06:33 +02:00
// --------------------
// - Helper functions -
// --------------------
2020-10-08 20:01:21 +02:00
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : init ( ) {
# ifdef QBluetoothLeUart_QML
2020-10-11 15:49:51 +02:00
qmlRegisterUncreatableType < QBluetoothLeUartDevice > ( " de.itsblue.bluetoothleuart " , 1 , 0 , " QBluetoothLeUartDevice " , " QBluetoothLeUartDevice cannot be created " ) ;
qmlRegisterUncreatableType < QBluetoothLeUartDeviceModel > ( " de.itsblue.bluetoothleuart " , 1 , 0 , " QBluetoothLeUartDeviceModel " , " QBluetoothLeUartDeviceModel cannot be created " ) ;
2020-10-09 12:06:33 +02:00
qmlRegisterType < QBluetoothLeUart > ( " de.itsblue.bluetoothleuart " , 1 , 0 , " QBluetoothLeUart " ) ;
qRegisterMetaType < QBluetoothLeUart : : BluetoothLeUartState > ( " QBluetoothLeUart::BluetoothLeUartState " ) ;
qRegisterMetaType < QBluetoothLeUart : : BluetoothScanError > ( " QBluetoothLeUart::BluetoothScanError " ) ;
# endif
2020-10-08 20:01:21 +02:00
}
void QBluetoothLeUart : : setState ( QBluetoothLeUart : : BluetoothLeUartState newState )
{
if ( state = = newState )
return ;
state = newState ;
emit stateChanged ( newState ) ;
}
QBluetoothLeUart : : BluetoothLeUartState QBluetoothLeUart : : getState ( ) const {
return state ;
}
2020-10-08 22:03:31 +02:00
2020-10-09 12:06:33 +02:00
void QBluetoothLeUart : : setUUIDs ( const char uartServiceUUID [ 36 ] , const char txUUID [ 36 ] , const char rxUUID [ 36 ] ) {
2020-10-08 22:03:31 +02:00
this - > uartServiceUUID = uartServiceUUID ;
this - > txUUID = txUUID ;
2020-10-09 12:06:33 +02:00
this - > rxUUID = rxUUID ;
2020-10-08 22:03:31 +02:00
}