2020-10-17 21:51:06 +02:00
# include "qbluetoothleuartclient.h"
2020-10-08 20:01:21 +02:00
2020-10-17 21:51:06 +02:00
QBluetoothLeUartClient : : QBluetoothLeUartClient ( QObject * parent ) : QObject ( parent )
2020-10-08 20:01:21 +02:00
{
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 ) ;
2020-10-17 21:51:06 +02:00
connect ( this - > bluetoothDeviceDiscoveryAgent , & QBluetoothDeviceDiscoveryAgent : : deviceDiscovered , this , & QBluetoothLeUartClient : : handleDeviceDiscovered ) ;
2020-10-08 20:01:21 +02:00
connect ( bluetoothDeviceDiscoveryAgent , SIGNAL ( error ( QBluetoothDeviceDiscoveryAgent : : Error ) ) ,
this , SLOT ( handleDeviceScanError ( QBluetoothDeviceDiscoveryAgent : : Error ) ) ) ;
2020-10-17 21:51:06 +02:00
connect ( this - > bluetoothDeviceDiscoveryAgent , & QBluetoothDeviceDiscoveryAgent : : finished , this , & QBluetoothLeUartClient : : 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
}
2020-10-17 21:51:06 +02:00
QBluetoothLeUartClient : : ~ QBluetoothLeUartClient ( ) {
2020-10-08 20:01:21 +02:00
}
2020-10-09 12:06:33 +02:00
// ------------------------------
// - Slots for QBluetoothLeUart -
// ------------------------------
2020-10-08 20:01:21 +02:00
2020-10-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : startScanningForDevices ( ) {
2020-10-18 03:26:02 +02:00
if ( this - > state ! = Idle & & this - > state ! = AdapterTurnedOff & & this - > state ! = ScanFinished & & this - > state ! = LocationPermissionDenied )
2020-10-09 12:06:33 +02:00
return false ;
2020-10-18 03:26:02 +02:00
# ifdef Q_OS_ANDROID
else if ( this - > state = = LocationPermissionDenied ) {
// try to get permission
QtAndroid : : PermissionResultMap resultMap = QtAndroid : : requestPermissionsSync ( { " android.permission.ACCESS_FINE_LOCATION " , " android.permission.ACCESS_COARSE_LOCATION " } , 5000 ) ;
bool resultBool = true ;
for ( QtAndroid : : PermissionResult result : resultMap ) {
if ( result ! = QtAndroid : : PermissionResult : : Granted ) {
resultBool = false ;
break ;
}
}
if ( ! resultBool ) {
emit this - > scanningErrorOccured ( LocationPermissionDeniedError ) ;
}
}
# endif
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 ) ;
2020-10-15 17:20:51 +02:00
this - > bluetoothDeviceDiscoveryAgent - > start ( QBluetoothDeviceDiscoveryAgent : : LowEnergyMethod ) ;
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-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : stopScanningForDevices ( ) {
2020-10-09 12:06:33 +02:00
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
}
2020-10-17 21:51:06 +02:00
QList < QBluetoothLeUartDevice * > QBluetoothLeUartClient : : getAvailableDevices ( ) {
2020-10-08 20:01:21 +02:00
return this - > availableDevices ;
}
2020-10-17 21:51:06 +02:00
QVariantList QBluetoothLeUartClient : : 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-17 21:51:06 +02:00
QBluetoothLeUartDeviceModel * QBluetoothLeUartClient : : getAvailableDevicesModel ( ) {
2020-10-11 15:49:51 +02:00
return this - > availableDevicesModel ;
}
2020-10-17 21:51:06 +02:00
QBluetoothLeUartDevice * QBluetoothLeUartClient : : getCurrentDevice ( ) {
2020-10-13 01:56:54 +02:00
return this - > currentBluetoothDevice ;
}
2020-10-11 15:49:51 +02:00
2020-10-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : 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-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : connectToDevice ( QBluetoothLeUartDevice * device ) {
2020-10-09 12:06:33 +02:00
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 ;
2020-10-13 01:56:54 +02:00
emit this - > currentDeviceChanged ( ) ;
2020-10-08 20:01:21 +02:00
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 ) ;
2020-10-15 16:57:07 +02:00
bluetoothController - > setRemoteAddressType ( QLowEnergyController : : RandomAddress ) ;
2020-10-08 20:01:21 +02:00
2020-10-17 21:51:06 +02:00
connect ( this - > bluetoothController , & QLowEnergyController : : serviceDiscovered , this , & QBluetoothLeUartClient : : handleServiceDiscovered ) ;
connect ( this - > bluetoothController , & QLowEnergyController : : discoveryFinished , this , & QBluetoothLeUartClient : : handleServiceScanDone ) ;
2020-10-08 20:01:21 +02:00
connect ( bluetoothController , SIGNAL ( error ( QLowEnergyController : : Error ) ) ,
this , SLOT ( handleControllerError ( QLowEnergyController : : Error ) ) ) ;
2020-10-17 21:51:06 +02:00
connect ( this - > bluetoothController , & QLowEnergyController : : connected , this , & QBluetoothLeUartClient : : handleDeviceConnected ) ;
connect ( this - > bluetoothController , & QLowEnergyController : : disconnected , this , & QBluetoothLeUartClient : : handleDeviceDisconnected ) ;
2020-10-08 20:01:21 +02:00
/* 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-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : 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 ;
}
2020-10-13 01:56:54 +02:00
this - > currentBluetoothDevice - > deleteLater ( ) ;
this - > currentBluetoothDevice = nullptr ;
emit this - > currentDeviceChanged ( ) ;
2020-10-11 15:49:51 +02:00
this - > setState ( Idle ) ;
2020-10-09 12:06:33 +02:00
return true ;
2020-10-08 20:01:21 +02:00
}
2020-10-17 21:51:06 +02:00
bool QBluetoothLeUartClient : : sendData ( QString data , bool asynchronous ) {
2020-10-13 01:56:54 +02:00
Q_UNUSED ( asynchronous )
2020-10-09 12:06:33 +02:00
if ( this - > state ! = Connected )
return false ;
const QLowEnergyCharacteristic RxChar = bluetoothService - > characteristic ( QBluetoothUuid ( QUuid ( this - > txUUID ) ) ) ;
2020-10-18 03:26:02 +02:00
bluetoothService - > writeCharacteristic ( RxChar , data . toUtf8 ( ) , QLowEnergyService : : WriteWithoutResponse ) ;
2020-10-09 12:06:33 +02:00
return true ;
}
// -------------------------------------------
// - Slots for QBluetothDeviceDiscoveryAgent -
// -------------------------------------------
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : 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 ) {
2020-10-18 01:37:09 +02:00
//qWarning() << "Discovered BLE Device: name: " << device.name() << " Address: " << device.address().toString() << " UUIDs: " << device.serviceUuids();
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-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleScanFinished ( )
2020-10-08 20:01:21 +02:00
{
2020-10-09 12:06:33 +02:00
if ( this - > availableDevices . size ( ) = = 0 )
{
2020-10-13 01:56:54 +02:00
qWarning ( ) < < " No Low Energy devices found " ;
2020-10-09 12:06:33 +02:00
}
emit this - > scanFinished ( this - > availableDevices ) ;
setState ( ScanFinished ) ;
2020-10-08 20:01:21 +02:00
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleDeviceScanError ( QBluetoothDeviceDiscoveryAgent : : Error error )
2020-10-08 20:01:21 +02:00
{
2020-10-18 03:26:02 +02:00
qWarning ( ) < < " Scanning ERROR: " < < error ;
this - > availableDevices . clear ( ) ;
this - > availableDevicesModel - > clear ( ) ;
if ( error = = QBluetoothDeviceDiscoveryAgent : : PoweredOffError ) {
this - > setState ( AdapterTurnedOff ) ;
2020-10-09 12:06:33 +02:00
emit this - > scanningErrorOccured ( AdapterTurnedOffError ) ;
2020-10-18 03:26:02 +02:00
}
else if ( error = = QBluetoothDeviceDiscoveryAgent : : InputOutputError ) {
this - > setState ( AdapterTurnedOff ) ;
2020-10-09 12:06:33 +02:00
emit this - > scanningErrorOccured ( InputOutputError ) ;
2020-10-18 03:26:02 +02:00
}
# ifdef Q_OS_ANDROID
else if ( error = = QBluetoothDeviceDiscoveryAgent : : UnknownError ) {
// check for permission error
QtAndroid : : PermissionResult fineLocationAccess = QtAndroid : : checkPermission ( " android.permission.ACCESS_FINE_LOCATION " ) ;
QtAndroid : : PermissionResult coarseLocationAccess = QtAndroid : : checkPermission ( " android.permission.ACCESS_COARSE_LOCATION " ) ;
if ( fineLocationAccess ! = QtAndroid : : PermissionResult : : Granted | | coarseLocationAccess ! = QtAndroid : : PermissionResult : : Granted ) {
this - > setState ( LocationPermissionDenied ) ;
emit this - > scanningErrorOccured ( LocationPermissionDeniedError ) ;
}
else
emit this - > scanningErrorOccured ( UnknownError ) ;
}
# endif
2020-10-09 12:06:33 +02:00
else
emit this - > scanningErrorOccured ( UnknownError ) ;
2020-10-18 01:37:09 +02:00
this - > stopScanningForDevices ( ) ;
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-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleServiceDiscovered ( const QBluetoothUuid & uuid ) {
2020-10-08 20:01:21 +02:00
2020-10-18 01:37:09 +02:00
//qDebug() << "Found service with ID: " << uuid;
2020-10-09 12:06:33 +02:00
if ( uuid = = QBluetoothUuid ( QUuid ( this - > uartServiceUUID ) ) ) {
2020-10-08 20:01:21 +02:00
foundValidUARTService = true ;
2020-10-18 01:37:09 +02:00
//qDebug() << "UART service found!";
2020-10-08 20:01:21 +02:00
}
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleServiceScanDone ( ) {
2020-10-08 20:01:21 +02:00
delete bluetoothService ;
bluetoothService = 0 ;
if ( foundValidUARTService ) {
2020-10-18 01:37:09 +02:00
//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 ) {
2020-10-18 01:37:09 +02:00
//qDebug() <<"UART service not found";
2020-10-08 20:01:21 +02:00
this - > disconnectFromDevice ( ) ;
return ;
}
/* 3 Step: Service Discovery */
2020-10-17 21:51:06 +02:00
connect ( this - > bluetoothService , & QLowEnergyService : : stateChanged , this , & QBluetoothLeUartClient : : handleServiceStateChange ) ;
connect ( this - > bluetoothService , & QLowEnergyService : : characteristicChanged , this , & QBluetoothLeUartClient : : handleServiceCharacteristicChange ) ;
connect ( this - > bluetoothService , & QLowEnergyService : : descriptorWritten , this , & QBluetoothLeUartClient : : handleServiceDescriptorWritten ) ;
2020-10-08 20:01:21 +02:00
bluetoothService - > discoverDetails ( ) ;
setState ( ServiceFound ) ;
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleControllerError ( QLowEnergyController : : Error error )
2020-10-09 12:06:33 +02:00
{
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
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleDeviceConnected ( )
2020-10-09 12:06:33 +02:00
{
2020-10-18 01:37:09 +02:00
//qDebug() << "Device connected";
2020-10-09 12:06:33 +02:00
bluetoothController - > discoverServices ( ) ;
setState ( ScanningForService ) ;
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleDeviceDisconnected ( )
2020-10-09 12:06:33 +02:00
{
this - > setState ( Idle ) ;
2020-10-18 01:37:09 +02:00
//qDebug() << "UART service disconnected";
2020-10-09 12:06:33 +02:00
qWarning ( ) < < " Remote device disconnected " ;
}
// -------------------------------
// - Slots for QLowEnergyService -
// -------------------------------
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleServiceStateChange ( QLowEnergyService : : ServiceState s )
2020-10-08 20:01:21 +02:00
{
// 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-18 01:37:09 +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-18 01:37:09 +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 ;
}
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleServiceCharacteristicChange ( const QLowEnergyCharacteristic & c , const QByteArray & value )
2020-10-08 20:01:21 +02:00
{
// 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 ) ;
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : handleServiceDescriptorWritten ( const QLowEnergyDescriptor & d ,
2020-10-08 20:01:21 +02:00
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-17 21:51:06 +02:00
void QBluetoothLeUartClient : : init ( ) {
2020-10-09 12:06:33 +02:00
# 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-17 21:51:06 +02:00
qmlRegisterType < QBluetoothLeUartClient > ( " de.itsblue.bluetoothleuart " , 1 , 0 , " QBluetoothLeUart " ) ;
qRegisterMetaType < QBluetoothLeUartClient : : BluetoothLeUartClientState > ( " QBluetoothLeUart::BluetoothLeUartState " ) ;
qRegisterMetaType < QBluetoothLeUartClient : : BluetoothScanError > ( " QBluetoothLeUart::BluetoothScanError " ) ;
2020-10-09 12:06:33 +02:00
# endif
2020-10-08 20:01:21 +02:00
}
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : setState ( QBluetoothLeUartClient : : BluetoothLeUartClientState newState )
2020-10-08 20:01:21 +02:00
{
if ( state = = newState )
return ;
state = newState ;
emit stateChanged ( newState ) ;
}
2020-10-17 21:51:06 +02:00
QBluetoothLeUartClient : : BluetoothLeUartClientState QBluetoothLeUartClient : : getState ( ) const {
2020-10-08 20:01:21 +02:00
return state ;
}
2020-10-08 22:03:31 +02:00
2020-10-17 21:51:06 +02:00
void QBluetoothLeUartClient : : 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
}