Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -87,37 +87,7 @@ } // coco end -/*! - * \brief BluetoothInterface::initConnections - * \details Initializes the required signal/slot connection between this class and other objects - * to be able to communicate. - */ -void BluetoothInterface::initConnections() -{ - if ( ! isLocalValid() ) return; - // Local connections - connect(_local , &QBluetoothLocalDevice :: deviceConnected , - this , &BluetoothInterface ::onLocalDeviceConnect ); - connect(_local , &QBluetoothLocalDevice :: deviceDisconnected , - this , &BluetoothInterface ::onLocalDeviceDisconnect ); - connect(_local , &QBluetoothLocalDevice :: error , - this , &BluetoothInterface ::onLocalError ); - if ( ! isAgentValid() ) return; - // Agent connections - connect(_agent , &QBluetoothDeviceDiscoveryAgent ::deviceDiscovered , - this , &BluetoothInterface ::onAgentDiscoverDevice ); - connect(_agent , &QBluetoothDeviceDiscoveryAgent :: finished , - this , &BluetoothInterface ::onAgentDiscoverFinish ); - connect(_agent , &QBluetoothDeviceDiscoveryAgent :: canceled , - this , &BluetoothInterface ::onAgentDiscoverCancel ); - connect(_agent , static_cast(&QBluetoothDeviceDiscoveryAgent::error), - this , &BluetoothInterface ::onAgentDiscoverError ); - - connect(this , SIGNAL(didDeviceSelect(BluetoothDeviceData)), - this , SLOT( onDeviceSelect(BluetoothDeviceData))); -} - /*! * \brief BluetoothInterface::initThread * \details Moves this object into the thread vThread. @@ -162,7 +132,7 @@ // ~~~~~~~~~~ Local #define NOTIFY_LOCAL_INIT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Init , \ _local->address().toString() , \ - _local->name(),0,1 )); + _local->name(), 0, true )); #define NOTIFY_LOCAL_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Connect , vAddress.toString()) ); #define NOTIFY_LOCAL_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error )); @@ -174,14 +144,14 @@ // ~~~~~~~~~~ Scan #define NOTIFY_SCAN_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Discover , \ vInfo.address().toString() , \ - vInfo.name(), "" , \ + vInfo.name(), 0 , \ _local->pairingStatus(vInfo.address()) , \ 0 , \ vInfo.isValid() , \ vInfo.deviceUuid().toString() )); #define NOTIFY_SCAN_FOUND notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Found , \ vInfo.address().toString() , \ - vInfo.name(), "" , \ + vInfo.name(), 0 , \ _local->pairingStatus(vInfo.address()) , \ 0 , \ vInfo.isValid() , \ @@ -199,6 +169,9 @@ #define NOTIFY_DEVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Start , \ _device->remoteAddress().toString() , \ _device->remoteName() )); +#define NOTIFY_DEVICE_WAITING notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Waiting , \ + _device->remoteAddress().toString() , \ + _device->remoteName(), _tempBatt )); #define NOTIFY_DEVICE_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Connect , \ _device->remoteAddress().toString() , \ _device->remoteName() )); @@ -208,37 +181,37 @@ #define NOTIFY_DEVICE_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Error , \ _device->remoteAddress().toString() , \ _device->remoteName() , \ - "",0, vError, false )); + 0,0, vError, false )); #define NOTIFY_DEVICE_DISCONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Disconnect , \ _device->remoteAddress().toString() , \ _device->remoteName() )); // ~~~~~~~~~~ Service #define NOTIFY_SERVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Start )); #define NOTIFY_SERVICE_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Discover )); +#define NOTIFY_SERVICE_INVALID notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Invalid )); #define NOTIFY_SERVICE_DETAILS(vS) notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ vS->serviceUuid().toString() , \ vS->serviceName() )); #define NOTIFY_SERVICE_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Error , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), vError, 0 , \ service->serviceUuid().toString() , \ service->serviceName() )); #define NOTIFY_SERVICE_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Done )); // ~~~~~~~~~~ Details/Characteristics #define NOTIFY_DETAILS_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Error , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), vState, 0 , \ service->serviceUuid().toString() , \ service->serviceName() )); -#define NOTIFY_DETAILS_INVALID notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Invalid )); #define NOTIFY_DETAILS_CHANGE notifyStateChange(MBluetooth(MBluetooth::eIS_Detail_Change , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() , \ @@ -247,7 +220,7 @@ QString(vValue) )); #define NOTIFY_DETAILS_READ notifyStateChange(MBluetooth(MBluetooth::eIS_Detail_Read , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() , \ @@ -256,7 +229,7 @@ QString(vValue) )); #define NOTIFY_DETAILS_WRITE notifyStateChange(MBluetooth(MBluetooth::eIS_Detail_Write , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() , \ @@ -265,7 +238,7 @@ QString(vValue) )); #define NOTIFY_CONFIG_READ notifyStateChange(MBluetooth(MBluetooth::eIS_Config_Read , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() , \ @@ -274,7 +247,7 @@ QString(vValue) )); #define NOTIFY_CONFIG_WRITE notifyStateChange(MBluetooth(MBluetooth::eIS_Config_Write , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() , \ @@ -283,15 +256,112 @@ QString(vValue) )); #define NOTIFY_SERVICE_DETAILS_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Done , \ _device->remoteAddress().toString() , \ - _device->remoteName(), "" , \ + _device->remoteName(), 0 , \ _local->pairingStatus(_device->remoteAddress()), 0, 1 , \ service->serviceUuid().toString() , \ service->serviceName() )); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Initializing the connections +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/*! + * \brief BluetoothInterface::initConnections + * \details Initializes the required signal/slot connection between this class and other objects, for the Local Bluetooth and Discovery Agent. + * to be able to communicate. + */ +void BluetoothInterface::initConnections() +{ + if ( ! isLocalValid() ) return; + // Local connections + connect(_local , SIGNAL( deviceConnected (QBluetoothAddress )), + this , SLOT(onLocalDeviceConnect (QBluetoothAddress ))); + connect(_local , SIGNAL( deviceDisconnected (QBluetoothAddress )), + this , SLOT(onLocalDeviceDisconnect (QBluetoothAddress ))); + connect(_local , SIGNAL( error (QBluetoothLocalDevice::Error )), + this , SLOT(onLocalError (QBluetoothLocalDevice::Error ))); + + if ( ! isAgentValid() ) return; + // Agent connections + connect(_agent , SIGNAL( deviceDiscovered (QBluetoothDeviceInfo )), + this , SLOT(onAgentDiscoverDevice (QBluetoothDeviceInfo ))); + connect(_agent , SIGNAL( error (QBluetoothDeviceDiscoveryAgent::Error )), + this , SLOT(onAgentDiscoverError (QBluetoothDeviceDiscoveryAgent::Error ))); + connect(_agent , SIGNAL( finished ( )), + this , SLOT(onAgentDiscoverFinish ( ))); + connect(_agent , SIGNAL( canceled ( )), + this , SLOT(onAgentDiscoverCancel ( ))); + + connect(this , SIGNAL(didDeviceSelect (BluetoothDeviceData )), + this , SLOT( onDeviceSelect (BluetoothDeviceData ))); +} + +/*! + * \brief BluetoothInterface::initConnectionsDevice + * \details sets up the remote Bluetooth device _device connections. + */ +void BluetoothInterface::initConnectionsDevice() { + if ( ! isDeviceValid() ) return; + // Device controller + // The _device, SIGNAL(stateChanged(QLowEnergyController::ControllerState )) signal is not used, + // because it's good to know the state but there are not much things can be done at the moment state changes. + connect( _device, SIGNAL( connected ( )), + this , SLOT(onDeviceConnect ( ))); + connect( _device, SIGNAL( error (QLowEnergyController::Error )), + this , SLOT(onDeviceError (QLowEnergyController::Error ))); + connect( _device, SIGNAL( disconnected ( )), + this , SLOT(onDeviceDisconnect ( ))); + // Device Services + connect( _device, SIGNAL(serviceDiscovered (const QBluetoothUuid &)), + this , SLOT(onDeviceDiscoverService(const QBluetoothUuid &))); + connect( _device, SIGNAL(discoveryFinished ()), + this , SLOT(onDeviceDiscoverFinish ())); +} + +/*! + * \brief BluetoothInterface::initConnectionsService + * \details The Services connection + * \param vService + */ +void BluetoothInterface::initConnectionsService(QLowEnergyService *vService) +{ + if ( ! vService ) return; + + connect(vService, SIGNAL( characteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &)), + this , SLOT(onServiceCharacteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &))); + connect(vService, SIGNAL( characteristicRead (const QLowEnergyCharacteristic &, const QByteArray &)), + this , SLOT(onServiceCharacteristicRead (const QLowEnergyCharacteristic &, const QByteArray &))); + connect(vService, SIGNAL( characteristicWritten (const QLowEnergyCharacteristic &, const QByteArray &)), + this , SLOT(onServiceCharacteristicWritten (const QLowEnergyCharacteristic &, const QByteArray &))); + + connect(vService, SIGNAL( descriptorRead (const QLowEnergyDescriptor &, const QByteArray &)), + this , SLOT(onServiceDescriptorRead (const QLowEnergyDescriptor &, const QByteArray &))); + connect(vService, SIGNAL( descriptorWritten (const QLowEnergyDescriptor &, const QByteArray &)), + this , SLOT(onServiceDescriptorWritten (const QLowEnergyDescriptor &, const QByteArray &))); + + connect(vService, SIGNAL( error ( QLowEnergyService::ServiceError )), + this , SLOT(onServiceError ( QLowEnergyService::ServiceError ))); + connect(vService, SIGNAL( stateChanged ( QLowEnergyService::ServiceState )), + this , SLOT(onServiceStateChanged ( QLowEnergyService::ServiceState ))); +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~ Public interface to initialize and start the scan // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /*! + * \brief BluetoothInterface::notifyStateChange + * \details sends a notification signal to the observers (view: VBluetooth) on any reported state changes. + * \param vData - the Bluetooth data model containing information about the current state and device. + */ +void BluetoothInterface::notifyStateChange(const BluetoothData &vData) +{ + emit didStateChange(vData); +} + +/*! * \brief BluetoothInterface::doNotifyStatePOSTError * \details The public slot for public notification on POST error, * since the POST is done by ApplicationPOST class, @@ -343,7 +413,7 @@ } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// ~~~~~ Local Device Slots +// ~~~~~ Local Bluetooth Slots // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Set of notifications on each event /*! @@ -414,10 +484,6 @@ } } -void BluetoothInterface::ondoConnectToDevice() { - connectToDevice(); -} - /*! * \brief BluetoothInterface::onAgentDiscoverFinish * \details Notifies the observers (view: VBluetooth) that the discovery agent has done discovery, and @@ -440,64 +506,47 @@ } /*! - * \brief BluetoothInterface::connectToDevice - * \return false if - * the local Bluetooth device _local is not valid - * the device info _temp is not valid. - * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Start, - * on successfully connecting initializing the remove Bluetooth device _device. + * \brief BluetoothInterface::onDeviceSelect + * \details the signal which will be called from a View created in the QML namespace to safely set the current selected device. + * \param vDevice */ -bool BluetoothInterface::connectToDevice() -{ - if ( ! isLocalValid() ) return false; - if ( ! isAgentValid() ) return false; - if ( ! isInfoValid () ) return false; - if ( ! initDevice () ) return false; - - NOTIFY_DEVICE_START - _device->connectToDevice(); - - return true; +void BluetoothInterface::onDeviceSelect(const BluetoothDeviceData &vDevice) { + _temp = QBluetoothDeviceInfo(QBluetoothAddress(vDevice.addr), vDevice.name, QBluetoothDeviceInfo::HealthBloodPressureMonitor); + connectToDevice(); } -bool BluetoothInterface::reconnectToDevice() -{ - if ( ! isLocalValid() ) return false; - if ( ! isAgentValid() ) return false; +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Remote Device Slots +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - NOTIFY_DEVICE_START - _device->connectToDevice(); - return true; -} - -void BluetoothInterface::ondoDiscoverServices() { - discoverServices(); -} - /*! - * \brief BluetoothInterface::discoverServices - * \details The function to be called to start retrieving the remote Bluetooth device _device's services, and - * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Service_Start. - */ -void BluetoothInterface::discoverServices() -{ - if ( ! isDeviceValid() ) return; - NOTIFY_SERVICE_START - _device->discoverServices(); -} - -/*! * \brief BluetoothInterface::onDeviceConnect * \details The slot to be called when the remote Bluetooth device _device is connected to start to retrieve its services, * by calling discoverServices(). * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Connect. */ void BluetoothInterface::onDeviceConnect() { + _reconnectionActive = false; NOTIFY_DEVICE_CONNECT discoverServices(); } /*! + * \brief BluetoothInterface::onDeviceError + * \details The slot to be called when the remote Bluetooth device _device has an error vError, and + * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Error. + * \param vError + */ +void BluetoothInterface::onDeviceError(QLowEnergyController::Error vError) +{ + // if reconnect is active it should display "Device Connecting ..." and shouldn't display the "Connection Error", + // because we know we will always get the error since we are trying to connected to a device which is probably off. + if ( ! _reconnectionActive ) + NOTIFY_DEVICE_ERROR + +} + +/*! * \brief BluetoothInterface::onDeviceDisconnect * \details The slot to be called when the remote Bluetooth device _device is disconnected, and * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Disconnect. @@ -507,247 +556,187 @@ NOTIFY_DEVICE_DISCONNECT } +/*! + * \brief BluetoothInterface::onDeviceDiscoverService + * \details The slot to be called when the remote Bluetooth device _device is discovering a service. + * \param vService - The discovered service + */ void BluetoothInterface::onDeviceDiscoverService(const QBluetoothUuid &vService) { initServices(vService); } +/*! + * \brief BluetoothInterface::onDeviceDiscoverFinish + * \details The slot to be called when the remote Bluetooth device _device finishes the current service discovering. + */ void BluetoothInterface::onDeviceDiscoverFinish() { NOTIFY_SERVICE_DISCOVER discoverServicesDetails(); } -void BluetoothInterface::discoverServicesDetails() -{ - if ( ! isValid() ) return; - if ( _serviceDeviceInformation ) { - NOTIFY_SERVICE_DETAILS (_serviceDeviceInformation ) - _serviceDeviceInformation ->discoverDetails(); - } - if ( _serviceCurrentTime ) { - NOTIFY_SERVICE_DETAILS (_serviceCurrentTime ) - qDebug() << _serviceCurrentTime ->type(); - _serviceCurrentTime ->discoverDetails(); - } - if ( _serviceBloodPressure ) { - NOTIFY_SERVICE_DETAILS (_serviceBloodPressure ) - qDebug() << _serviceBloodPressure ->type(); - _serviceBloodPressure ->discoverDetails(); - } - if ( _serviceBattery ) { - NOTIFY_SERVICE_DETAILS (_serviceBattery ) - qDebug() << _serviceBattery ->type(); - _serviceBattery ->discoverDetails(); - } -} +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ The Services Slots +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*! - * \brief BluetoothInterface::onDeviceError - * \details The slot to be called when the remote Bluetooth device _device has an error vError, and - * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Error. - * \param vError + * \brief BluetoothInterface::onServiceCharacteristicChanged + * \details If the associated controller object is in the central role, + * this signal handler is called when the value of characteristic is changed by an event on the peripheral/device side. + * In that case, the signal handler call implies that change notifications must have been activated via the characteristic's + * ClientCharacteristicConfiguration descriptor prior to the change event on the peripheral. + * \param vCharacteristic - The characteristic object + * \param vValue - The characteristic's value */ -void BluetoothInterface::onDeviceError(QLowEnergyController::Error vError) -{ - // if reconnect is active it should display "Device Connecting ..." and shouldn't display the "Connection Error", - // because we know we will always get the error since we are trying to connected to a device which is probably off. - if ( ! _reconnectionActive ) - NOTIFY_DEVICE_ERROR - -} - -void BluetoothInterface::onServiceDescriptorRead (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue) { - QLowEnergyService *service = reinterpret_cast(sender()); - NOTIFY_CONFIG_READ -} -void BluetoothInterface::onServiceDescriptorWritten (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue) { - QLowEnergyService *service = reinterpret_cast(sender()); - NOTIFY_CONFIG_WRITE -} -void BluetoothInterface::onServiceCharacteristicRead (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { - QLowEnergyService *service = reinterpret_cast(sender()); - NOTIFY_DETAILS_READ - // By document reading shall occur here (onServiceCharacteristicRead) but seems it only happens onServiceCharacteristicChanged. - // Did not seem to cause any issue having one read here in case the value has been passed in here. - if (vCharacteristic.uuid() == QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)) - { - interpretBloodPressure(vValue); - } -} -void BluetoothInterface::onServiceCharacteristicWritten (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { - QLowEnergyService *service = reinterpret_cast(sender()); - NOTIFY_DETAILS_WRITE -} void BluetoothInterface::onServiceCharacteristicChanged (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { QLowEnergyService *service = reinterpret_cast(sender()); NOTIFY_DETAILS_CHANGE - // ManufacturerNameString : OMRONHEALTHCARE - // ModelNumberString : BP7000 if (vCharacteristic.uuid() == QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)) { interpretBloodPressure(vValue); } + qDebug() << "---------" << vCharacteristic.name() << vValue; } -void BluetoothInterface::interpretBloodPressure(const QByteArray &vData) -{ - MUIBloodPressure model; - model.fromByteArray(vData); - emit didActionReceive(model.data()); - LOG_EVENT(model.toString()); +/*! + * \brief BluetoothInterface::onServiceCharacteristicRead + * \details This signal handler is called when the read request for characteristic successfully returned its value. + * The source signal might be triggered by calling characteristicRead(). + * If the read operation is not successful, the error() signal is emitted using the CharacteristicReadError flag. + * \param vCharacteristic + * \param vValue + */ +void BluetoothInterface::onServiceCharacteristicRead (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { + QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_DETAILS_READ } /*! - * \brief BluetoothInterface::initConnectionsDevice - * \details sets up the remote Bluetooth device _device connections. + * \brief BluetoothInterface::onServiceCharacteristicWritten + * \details This signal handler is called when the value of characteristic is successfully changed to new vValue. + * The change must have been triggered by calling writeCharacteristic(). If the write operation is not successful, + * the error() signal is emitted using the CharacteristicWriteError flag. + * The reception of the written signal can be considered as a sign that the target device received the to-be-written value + * and reports back the status of write request. + * \param vCharacteristic - The characteristic object + * \param vValue - The characteristic's value */ -void BluetoothInterface::initConnectionsDevice() { - if ( ! isDeviceValid() ) return; - // Device controller - connect( _device, SIGNAL( connected ( )), - this , SLOT(onDeviceConnect ( ))); - connect( _device, SIGNAL( error (QLowEnergyController::Error )), - this , SLOT(onDeviceError (QLowEnergyController::Error ))); - connect( _device, SIGNAL( disconnected ( )), - this , SLOT(onDeviceDisconnect ( ))); - // Device Services - connect( _device, SIGNAL(serviceDiscovered (const QBluetoothUuid &)), - this , SLOT(onDeviceDiscoverService(const QBluetoothUuid &))); - connect( _device, SIGNAL(discoveryFinished ()), - this , SLOT(onDeviceDiscoverFinish ())); +void BluetoothInterface::onServiceCharacteristicWritten (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { + QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_DETAILS_WRITE } -void BluetoothInterface::initConnectionsService(QLowEnergyService *vService) -{ - if ( ! vService ) return; - - connect(vService, SIGNAL( characteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &)), - this , SLOT(onServiceCharacteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &))); - - connect(vService, SIGNAL( characteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &)), - this , SLOT(onServiceCharacteristicChanged (const QLowEnergyCharacteristic &, const QByteArray &))); - connect(vService, SIGNAL( characteristicRead (const QLowEnergyCharacteristic &, const QByteArray &)), - this , SLOT(onServiceCharacteristicRead (const QLowEnergyCharacteristic &, const QByteArray &))); - connect(vService, SIGNAL( characteristicWritten (const QLowEnergyCharacteristic &, const QByteArray &)), - this , SLOT(onServiceCharacteristicWritten (const QLowEnergyCharacteristic &, const QByteArray &))); - - connect(vService, SIGNAL( descriptorRead (const QLowEnergyDescriptor &, const QByteArray &)), - this , SLOT(onServiceDescriptorRead (const QLowEnergyDescriptor &, const QByteArray &))); - connect(vService, SIGNAL( descriptorWritten (const QLowEnergyDescriptor &, const QByteArray &)), - this , SLOT(onServiceDescriptorWritten (const QLowEnergyDescriptor &, const QByteArray &))); - - connect(vService, SIGNAL( error ( QLowEnergyService::ServiceError )), - this , SLOT(onServiceError ( QLowEnergyService::ServiceError ))); - connect(vService, SIGNAL( stateChanged ( QLowEnergyService::ServiceState )), - this , SLOT(onServiceStateChanged ( QLowEnergyService::ServiceState ))); -} - -void BluetoothInterface::onServiceError(QLowEnergyService::ServiceError vError) { +/*! + * \brief BluetoothInterface::onServiceDescriptorRead + * \details This signal handler is called when the read request for descriptor successfully returned its value. + * The signal might be triggered by calling descriptorRead(). + * If the read operation is not successful, the error() signal is emitted using the DescriptorReadError flag. + * \param vCharacteristic - The characteristic object + * \param vValue - The characteristic's value + */ +void BluetoothInterface::onServiceDescriptorRead (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue) { QLowEnergyService *service = reinterpret_cast(sender()); - NOTIFY_SERVICE_ERROR + NOTIFY_CONFIG_READ } -void BluetoothInterface::ondoReadMeasurements() { - readMeasurements(); -} - -void BluetoothInterface::readMeasurements() -{ - if ( ! _serviceBloodPressure ) { - NOTIFY_DETAILS_INVALID - return; +/*! + * \brief BluetoothInterface::onServiceDescriptorWritten + * \details This signal is emitted when the value of descriptor is successfully changed to new vValue. + * If the associated controller object is in the central role, the change must have been caused by calling writeDescriptor(). + * Otherwise, the signal is the result of a write request or command from a GATT client to the respective descriptor. + * \param vCharacteristic - The characteristic object + * \param vValue - The characteristic's value + */ +void BluetoothInterface::onServiceDescriptorWritten (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue) { + QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_CONFIG_WRITE + if ( vDescriptor.uuid() == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration) && vValue == _bloodPressureNotifyValue ) { + _reconnectionActive = true; } - // blood pressure feature - const QLowEnergyCharacteristic detailBPFeat = _serviceBloodPressure->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureFeature)); - if (!detailBPFeat.isValid()) { - qDebug() << "Blood pressure feature not found."; - return; - } - _serviceBloodPressure->readCharacteristic(detailBPFeat); } -void BluetoothInterface::ondoReadInformation() { - readInformation(); +/*! + * \brief BluetoothInterface::onServiceError + * \details Returns the current service's last occurred error or NoError. + * \param vError - the error code in case of error + */ +void BluetoothInterface::onServiceError (QLowEnergyService::ServiceError vError) { + QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_SERVICE_ERROR } -void BluetoothInterface::readInformation() -{ - if ( ! _serviceDeviceInformation ) { - NOTIFY_DETAILS_INVALID - return; - } - - // device information - const QLowEnergyCharacteristic detailInfo = _serviceDeviceInformation->characteristic(QBluetoothUuid(QBluetoothUuid::DeviceInformation)); - if (!detailInfo.isValid()) { - qDebug() << "Device Information feature not found."; - return; - } - _serviceDeviceInformation->readCharacteristic(detailInfo); -} - -void BluetoothInterface::printCharacteristics(QLowEnergyService *vService) -{ - for ( auto const &detail: vService->characteristics()) { - qDebug() << " ~~~~~ " << detail.name() << detail.uuid() << detail.value(); - } -} - -void BluetoothInterface::ondoEnableNotify() { - enableNotify(); -} - -void BluetoothInterface::enableNotify() { - if ( ! _serviceBloodPressure ) { - NOTIFY_DETAILS_INVALID - return; - } - - // blood pressure measurements - const QLowEnergyCharacteristic detailBPMeas = _serviceBloodPressure->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)); - QLowEnergyDescriptor configBPMeas = detailBPMeas.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); - if (configBPMeas.isValid()) _serviceBloodPressure->writeDescriptor(configBPMeas, QByteArray::fromHex("0100")); -} - -void BluetoothInterface::onServiceStateChanged(QLowEnergyService::ServiceState vState) { +/*! + * \brief BluetoothInterface::onServiceStateChanged + * \details This signal is emitted when the service's state changes. + * The new vState can also be retrieved via state(). + * \param vState - The new service state. + */ +void BluetoothInterface::onServiceStateChanged (QLowEnergyService::ServiceState vState) { if ( ! sender() ) return; QLowEnergyService *service = reinterpret_cast(sender()); - qDebug() << "Service State:" << service->serviceUuid() << service->serviceName() << vState; switch (vState) { case QLowEnergyService::InvalidService : - NOTIFY_DETAILS_ERROR + // After disconnection the services are invalidated by Qt. + // NOTIFY_DETAILS_ERROR break; - case QLowEnergyService::ServiceDiscovered : + case QLowEnergyService::ServiceDiscovered : { NOTIFY_SERVICE_DETAILS_DONE - printCharacteristics(service); - if ( service->serviceUuid() == QBluetoothUuid (QBluetoothUuid::BloodPressure )) { + switch( service->serviceUuid().toUInt32() ) { + case QBluetoothUuid::BloodPressure: enableNotify(); - readMeasurements(); - _reconnectionActive = true; + break; + + case QBluetoothUuid::DeviceInformation: + interpretInformation(); + break; + + case QBluetoothUuid::BatteryService : { + int index = 0; + QByteArray data = service->characteristic(QBluetoothUuid::BatteryLevel).value(); + Types::U08 batteryLevel; + if (GetValue(data, index, batteryLevel)) { + _tempBatt = batteryLevel.value; + LOG_DEBUG("UI," + tr("BCUFF Battery: %1").arg(_tempBatt)); + } + break; } - if (service->serviceUuid() == QBluetoothUuid (QBluetoothUuid::DeviceInformation )) { - readInformation(); + default: + break; } - break; - + // DEBUG: printCharacteristics(service); + } default: break; } } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Local Bluetooth Device +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*! - * \brief BluetoothInterface::onDeviceSelect - * \details the signal which will be called from a View created in the QML namespace to safely set the current selected device. - * \param vDevice + * \brief BluetoothInterface::isLocalValid + * \details checks if the local Bluetooth device is valid, and + * notifies the observers (view: VBluetooth) that local is not valid if fails. + * \return false if the local Bluetooth device _local is not valid */ -void BluetoothInterface::onDeviceSelect(const BluetoothDeviceData &vDevice) { - _temp = QBluetoothDeviceInfo(QBluetoothAddress(vDevice.addr), vDevice.name, QBluetoothDeviceInfo::HealthBloodPressureMonitor); - connectToDevice(); +bool BluetoothInterface::isLocalValid() { + if ( ! _isValid ) return false; + if ( ! _local ) return false; + if ( ! _local->isValid() ) { + NOTIFY_LOCAL_ERROR_INVALID + quitDevice(); + return false; + } + return true; } + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Discovery Agent +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*! * \brief BluetoothInterface::startScan * \details Stars the agent device scan @@ -763,11 +752,41 @@ } NOTIFY_SCAN_START + quitDevice(); _agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); return true; } /*! + * \brief BluetoothInterface::isAgentValid + * \details Check if the discovery agent is a valid pointer. + * \return false if not. + */ +bool BluetoothInterface::isAgentValid() { + if (! _agent ) { + return false; + } + return true; +} + +/*! + * \brief BluetoothInterface::isInfoValid + * \details checks if the device info _temp is valid. + * notifies the observers (view: VBluetooth) that the device info is not valid. + * \return false if the device info _local is not valid + * \note the device info _temp is set to a default QBluetoothDeviceInfo which is invalid by default, + * when the interface initialized (doStart), and + * when a scan started (ondoScan) + */ +bool BluetoothInterface::isInfoValid() { + if ( ! _temp.isValid() ) { + NOTIFY_SCAN_NOTFOUND // not a valid device found + return false; + } + return true; +} + +/*! * \brief BluetoothInterface::stopScan * \details Stops the agent device scan * \return true if the agent is currently active and is stopped or false if it was not active. @@ -780,6 +799,9 @@ return true; } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Remote Device Controller Creation [init/make/valid/supported/connect/reconnect/details(services)/quit] +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*! * \brief BluetoothInterface::initDevice * \return Initializes the device by making a new device and initializes its connections @@ -813,25 +835,16 @@ } /*! - * \brief BluetoothInterface::notifyStateChange - * \details sends a notification signal to the observers (view: VBluetooth) on any reported state changes. - * \param vData - the Bluetooth data model containing information about the current state and device. + * \brief BluetoothInterface::isDeviceValid + * \details checks if the remote Bluetooth device has been setup. + * \return returns false if no device is setup. */ -void BluetoothInterface::notifyStateChange(const BluetoothData &vData) -{ - emit didStateChange(vData); -} - -/*! - * \brief BluetoothInterface::timerEvent - * \details The main QObject's timer which has been set with the interval of the _interval (1s) - * The main purpose is to reconnect to the device on each second interval to get any new measurement data. - */ -void BluetoothInterface::timerEvent(QTimerEvent *) -{ - if ( _reconnectionActive ) { - reconnectToDevice(); +bool BluetoothInterface::isDeviceValid() { + if ( ! _device ) { + NOTIFY_DEVICE_INIT_ERROR + return false; } + return true; } /*! @@ -847,75 +860,105 @@ } /*! - * \brief BluetoothInterface::isLocalValid - * \details checks if the local Bluetooth device is valid, and - * notifies the observers (view: VBluetooth) that local is not valid if fails. - * \return false if the local Bluetooth device _local is not valid + * \brief BluetoothInterface::connectToDevice + * \return false if + * the local Bluetooth device _local is not valid + * the device info _temp is not valid. + * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Device_Start, + * on successfully connecting initializing the remove Bluetooth device _device. */ -bool BluetoothInterface::isLocalValid() { - if ( ! _isValid ) return false; - if ( ! _local ) return false; - if ( ! _local->isValid() ) { - NOTIFY_LOCAL_ERROR_INVALID - quitDevice(); - return false; - } - return true; -} +bool BluetoothInterface::connectToDevice() +{ + if ( ! isLocalValid() ) return false; + if ( ! isAgentValid() ) return false; + if ( ! isInfoValid () ) return false; + if ( ! initDevice () ) return false; -bool BluetoothInterface::isAgentValid() { - if (! _agent ) { - return false; - } + NOTIFY_DEVICE_START + _device->connectToDevice(); + return true; } /*! - * \brief BluetoothInterface::isInfoValid - * \details checks if the device info _temp is valid. - * notifies the observers (view: VBluetooth) that the device info is not valid. - * \return false if the device info _local is not valid - * \note the device info _temp is set to a default QBluetoothDeviceInfo which is invalid by default, - * when the interface initialized (doStart), and - * when a scan started (ondoScan) + * \brief BluetoothInterface::reconnectToDevice + * \details After the device is paired and notification is set, here each second a device re-connection happens. + * If the device cannot be connected by two tries, tries to disconnect and re-connect again. + * \return false if the Bluetooth interface is not ready. */ -bool BluetoothInterface::isInfoValid() { - if ( ! _temp.isValid() ) { - NOTIFY_SCAN_NOTFOUND // not a valid device found - return false; +bool BluetoothInterface::reconnectToDevice() +{ + if ( ! _reconnectionActive ) return false; + if ( ! isLocalValid() ) return false; + if ( ! isAgentValid() ) return false; + if ( ! _device ) return false; + + // SKIPPER_DEF(10) // notify each 10 times. + // SKIPPER_TST({ + // SKIPPER_TRY; + // }) + // else { + // NOTIFY_DEVICE_WAITING + // SKIPPER_RST; + // } + NOTIFY_DEVICE_WAITING + + SKIPPER_DEF(2) // lets give the controller 2 try. + // the device connection and disconnection is very device state dependent. + switch(_device->state()) { + case QLowEnergyController::ConnectingState : + SKIPPER_TRY; + Q_FALLTHROUGH(); + + case QLowEnergyController::DiscoveredState : + // - For QLowEnergyController::DiscoveredState : + // This is the first time after the device is free and reconnect starts. + // And the last state of the device after it is done with services and all the things. + // At this moment the device has to disconnect to be able to reconnect and read measurements. + // - For QLowEnergyController::ConnectingState : + // After some testing figured the connecting state take so long to reconnect. + // so to move to Unconnected state if instead of waiting for the connecting state timeout (nowhere int the Qt documentation, cannot find a timeout for connecting state.). + SKIPPER_TST(break); + _device->disconnectFromDevice(); + SKIPPER_RST; + break; + + case QLowEnergyController::UnconnectedState : + _device->connectToDevice(); + break; + + case QLowEnergyController::ConnectedState : + case QLowEnergyController::DiscoveringState : + case QLowEnergyController::ClosingState : + case QLowEnergyController::AdvertisingState : + break; + } return true; } /*! - * \brief BluetoothInterface::isDeviceValid - * \details checks if the remote Bluetooth device has been setup. - * \return returns false if no device is setup. + * \brief BluetoothInterface::timerEvent + * \details The main QObject's timer which has been set with the interval of the _interval (1s) + * The main purpose is to reconnect to the device on each second interval to get any new measurement data. */ -bool BluetoothInterface::isDeviceValid() { - if ( _device ) { NOTIFY_DEVICE_INIT } - else { NOTIFY_DEVICE_INIT_ERROR - return false; +void BluetoothInterface::timerEvent(QTimerEvent *) +{ + if ( _reconnectionActive ) { + reconnectToDevice(); } - return true; } -// bool BluetoothInterface::isServiceValid(QLowEnergyService *vService) -// { -// if ( vService ) { NOTIFY_SERVICE_INIT } -// else { NOTIFY_SERVICE_INIT_ERROR -// return false; -// } -// return true; -// } - -bool BluetoothInterface::isDetailValid(const QLowEnergyCharacteristic &vDetail) +/*! + * \brief BluetoothInterface::discoverServices + * \details The function to be called to start retrieving the remote Bluetooth device _device's services, and + * notifies the observers (view: VBluetooth) that the state is MBluetooth::eIS_Service_Start. + */ +void BluetoothInterface::discoverServices() { - if ( ! vDetail.isValid() ) { - NOTIFY_DETAILS_INVALID - return false; - } - return true; + if ( ! isDeviceValid() ) return; + NOTIFY_SERVICE_START + _device->discoverServices(); } /*! @@ -933,15 +976,23 @@ } } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Services Creation [init/make/details(characteristics)/quit] +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /*! * \brief BluetoothInterface::initService - * \details + * \details initializes the service by its uuid vService. */ void BluetoothInterface::initServices(const QBluetoothUuid &vService) { makeServices(vService); } +/*! + * \brief BluetoothInterface::makeServices + * \details Make remote device's service handler withe the given service uuid information vService. + * \param vService - The service uuid + */ void BluetoothInterface::makeServices(const QBluetoothUuid &vService) { if (vService == QBluetoothUuid (QBluetoothUuid::DeviceInformation )) { @@ -967,6 +1018,35 @@ } /*! + * \brief BluetoothInterface::discoverServicesDetails + * \details After a service discovered its detail needs to be discovered by this function. + * \note Note that this function is implemented in regards of a Blood Pressure Cuff Device and does not support any other device. + */ +void BluetoothInterface::discoverServicesDetails() +{ + if ( ! isValid() ) return; + if ( _serviceDeviceInformation ) { + NOTIFY_SERVICE_DETAILS (_serviceDeviceInformation ) + _serviceDeviceInformation ->discoverDetails(); + } + if ( _serviceCurrentTime ) { + NOTIFY_SERVICE_DETAILS (_serviceCurrentTime ) + qDebug() << _serviceCurrentTime ->type(); + _serviceCurrentTime ->discoverDetails(); + } + if ( _serviceBloodPressure ) { + NOTIFY_SERVICE_DETAILS (_serviceBloodPressure ) + qDebug() << _serviceBloodPressure ->type(); + _serviceBloodPressure ->discoverDetails(); + } + if ( _serviceBattery ) { + NOTIFY_SERVICE_DETAILS (_serviceBattery ) + qDebug() << _serviceBattery ->type(); + _serviceBattery ->discoverDetails(); + } +} + +/*! * \brief BluetoothInterface::quitServices * \details quits and deletes the old remote services. */ @@ -989,3 +1069,114 @@ _serviceBattery = nullptr; } } + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Characteristics +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +/*! + * \brief BluetoothInterface::enableNotify + * \details Enabling the Blood Pressure measurement notification. + * This has to be done to first get the OK on the Bluetooth Cuff device. + * Second it has to be set to let the Bluetooth Cuff know to notify the Local Device about the Blood Pressure service's characteristics change. + */ +void BluetoothInterface::enableNotify() { + if ( ! _serviceBloodPressure ) { + NOTIFY_SERVICE_INVALID + return; + } + + // blood pressure measurements + const QLowEnergyCharacteristic detailBPMeas = _serviceBloodPressure->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)); + QLowEnergyDescriptor configBPMeas = detailBPMeas.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + if (configBPMeas.isValid()) _serviceBloodPressure->writeDescriptor(configBPMeas, _bloodPressureNotifyValue); +} + +/*! + * \brief BluetoothInterface::interpretBloodPressure + * \details Interpreting the blood pressure message QByteArray vData and extracting the values of Systolic, Diastolic, HeartRate. + * \param vData - the received QByteArray of data. + */ +void BluetoothInterface::interpretBloodPressure(const QByteArray &vData) +{ + MUIBloodPressure model; + model.fromByteArray(vData); + UIBloodPressureData data = model.data(); + qDebug() << "==========" << data.mSystolic << data.mDiastolic << data.mPulseRate; + emit didActionReceive(data); + LOG_EVENT(model.toString()); +} + +/*! + * \brief BluetoothInterface::interpretInformation + * \details Interpreting the Remote device information QByteArray vData, currently just consoles out. + */ +void BluetoothInterface::interpretInformation() +{ + for ( auto const &detail: _serviceDeviceInformation->characteristics()) { + qDebug() << " ~~~~~ " << detail.name() << detail.uuid() << detail.value(); + } +} + +/*! + * \brief BluetoothInterface::printCharacteristics + * \details Printing out to the console all the service(vService)'s characteristics' name and current value. + * \param vService + */ +void BluetoothInterface::printCharacteristics(QLowEnergyService *vService) +{ + for ( auto const &detail: vService->characteristics()) { + qDebug() << " ~~~~~ " << detail.name() << detail.uuid() << detail.value(); + } +} + +/*! + * \brief BluetoothInterface::requestMeasurements + * \details Currently not used, kept for later. + */ +void BluetoothInterface::requestMeasurements() +{ + if ( ! _serviceBloodPressure ) { + NOTIFY_SERVICE_INVALID + return; + } + // blood pressure feature + const QLowEnergyCharacteristic detailBPFeat = _serviceBloodPressure->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureFeature)); + if (!detailBPFeat.isValid()) { + qDebug() << "Blood Pressure Feature not found."; + return; + } + _serviceBloodPressure->readCharacteristic(detailBPFeat); +} + +/*! + * \brief BluetoothInterface::requestInformation + * \details Currently not used, kept for later. + */ +void BluetoothInterface::requestInformation() +{ + if ( ! _serviceDeviceInformation ) { + NOTIFY_SERVICE_INVALID + return; + } + printCharacteristics(_serviceDeviceInformation); +} + +/*! + * \brief BluetoothInterface::requestBattery + * \details Currently not used, kept for later. + */ +void BluetoothInterface::requestBattery() +{ + if ( ! _serviceBattery ) { + NOTIFY_SERVICE_INVALID + return; + } + // battery level percent + const QLowEnergyCharacteristic detail = _serviceBloodPressure->characteristic(QBluetoothUuid(QBluetoothUuid::BatteryLevel)); + if (!detail.isValid()) { + qDebug() << "Battery Level not found."; + return; + } + _serviceBloodPressure->readCharacteristic(detail); +}