Index: denali.pro.user =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- denali.pro.user (.../denali.pro.user) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ denali.pro.user (.../denali.pro.user) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -1,6 +1,6 @@ - + EnvironmentId Index: en_US.udic =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- en_US.udic (.../en_US.udic) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ en_US.udic (.../en_US.udic) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -176,3 +176,4 @@ BCuff Mesur ApplicationPOST +MBluetooth Fisheye: Tag aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b refers to a dead (removed) revision in file `scripts/bluetooth_kill.sh'. Fisheye: No comparison available. Pass `N' to diff? Index: scripts/bluetooth_remove_paired.sh =================================================================== diff -u --- scripts/bluetooth_remove_paired.sh (revision 0) +++ scripts/bluetooth_remove_paired.sh (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -0,0 +1,35 @@ +#!/bin/sh +########################################################################### +# +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +# WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# @file bluetooth_reset.sh +# +# @author (last) Behrouz NematiPour +# @date (last) 30-Aug-2021 +# @author (original) Behrouz NematiPour +# @date (original) 30-Aug-2021 +# +############################################################################ + +DEVICES=$(echo "devices" | bluetoothctl | grep ^Device | cut -b 8-25) +if [ ! -z "$DEVICES" ]; then + for device in $DEVICES; do + if [ ! -z "$device" ]; then + echo "remove $device" | bluetoothctl + fi + done +fi + +PAIRED_DEVICES=$(echo "paired-devices" | bluetoothctl | grep ^Device | cut -b 8-25) +if [ ! -z "$PAIRED_DEVICES" ]; then + for paired_device in $PAIRED_DEVICES; do + if [ ! -z "$paired_device" ]; then + echo "remove $paired_device" | bluetoothctl + fi + done +fi + Fisheye: Tag aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b refers to a dead (removed) revision in file `scripts/bluetooth_reset.sh'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b refers to a dead (removed) revision in file `scripts/bluetooth_start.sh'. Fisheye: No comparison available. Pass `N' to diff? 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); +} Index: sources/bluetooth/BluetoothInterface.h =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -57,6 +57,7 @@ bool _isValid = false ; + const QByteArray _bloodPressureNotifyValue = QByteArray::fromHex("0100"); const char *_invalidLocalAddress = "00:00:00:00:00:00"; QStringList _supportedDeviceKeywords { "BP7000", "BLEsmart", "BLESmart" }; // Regarding to Omron Documents. QBluetoothLocalDevice *_local = nullptr ; @@ -69,6 +70,7 @@ QLowEnergyService *_serviceBattery = nullptr ; QBluetoothDeviceInfo _temp ; + quint8 _tempBatt = 0 ; bool _reconnectionActive = false ; const quint16 _interval = 1000 ; // the interface timer base interval in mSec @@ -141,22 +143,24 @@ bool isAgentValid (); bool isInfoValid (); bool isDeviceValid (); - // bool isServiceValid (QLowEnergyService *vService); - bool isDetailValid (const QLowEnergyCharacteristic &vDetail); bool isDeviceSupported (const QString &vName ); bool connectToDevice (); bool reconnectToDevice (); void discoverServices (); void discoverServicesDetails(); void enableNotify (); - void readMeasurements (); - void readInformation (); + void requestMeasurements (); + void requestInformation (); + void requestBattery (); void printCharacteristics (QLowEnergyService *vService); void notifyStateChange (const BluetoothData &vData); void interpretBloodPressure (const QByteArray &vData); + void interpretInformation (); + void interpretBattery (const QByteArray &vData); + signals: void didStateChange (const BluetoothData &vData); void didActionReceive (const UIBloodPressureData &vData); @@ -165,10 +169,5 @@ SAFE_CALL(doStart ) SAFE_CALL(doScan ) - SAFE_CALL(doConnectToDevice ) - SAFE_CALL(doDiscoverServices ) - SAFE_CALL(doEnableNotify ) - SAFE_CALL(doReadMeasurements ) - SAFE_CALL(doReadInformation ) }; } Index: sources/gui/qml/globals/Colors.qml =================================================================== diff -u -rf7392d985121b21e9f9814e444b0810cd1d00b18 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision f7392d985121b21e9f9814e444b0810cd1d00b18) +++ sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -54,18 +54,19 @@ readonly property color rangeMarker : white readonly property color rangeMarkerShort : "#9fb6d1" - readonly property color textMain : "#FCFCFC" - readonly property color textButton : "#FCFCFC" //"#E8E8E8" - readonly property color textDisableButton : "#607A91" - readonly property color textTickMark : "#438FEB" - readonly property color textInvalid : red + readonly property color textMain : "#FCFCFC" + readonly property color textButton : "#FCFCFC" //"#E8E8E8" + readonly property color textDisableButton : "#607A91" + readonly property color textTickMark : "#438FEB" + readonly property color textInvalid : red - readonly property color borderButton : "#4290EC" //K:D //"#438FEB" - readonly property color borderButtonHalfDarker : Qt.darker(borderButton, 1.50) - readonly property color borderButtonUnselected : "#53667d" - readonly property color borderDisableButton : "#607A91" - readonly property color boderSeparatorLine : "#476982" - readonly property color borderDialog : transparent // different colors for different displays // "#D01A344D" // "#D00F0F0F" //"#F51A344D" + readonly property color borderButton : "#4290EC" //K:D //"#438FEB" + readonly property color borderButtonHalfDarker : Qt.darker(borderButton, 1.50) + readonly property color borderButtonSelected : "#db8f00" + readonly property color borderButtonUnselected : "#53667d" + readonly property color borderDisableButton : "#607A91" + readonly property color boderSeparatorLine : "#476982" + readonly property color borderDialog : transparent // different colors for different displays // "#D01A344D" // "#D00F0F0F" //"#F51A344D" readonly property color touchTextAreaTitle : "#a0b6d0" Index: sources/gui/qml/pages/posttreatment/PostTreatmentStack.qml =================================================================== diff -u -rab7ffd27ecea1277d8645a8b62ff48c0cb3f6ff4 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/gui/qml/pages/posttreatment/PostTreatmentStack.qml (.../PostTreatmentStack.qml) (revision ab7ffd27ecea1277d8645a8b62ff48c0cb3f6ff4) +++ sources/gui/qml/pages/posttreatment/PostTreatmentStack.qml (.../PostTreatmentStack.qml) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -85,7 +85,7 @@ /* No wait for Rsp, so navigates => */ page( _treatmentReviewConfirm ) /* After navigate ask for Tx data */ vPostTreatmentAdjustmentTreatmentLog .doRequest( )} onTreatmentReviewConfirm : { page( _disposablesRemovalConfirm ) - vTreatmentVitals.doReset() + vTreatmentVitals.doReset(false) } onDisposablesRemovalConfirm : { vPostTreatmentAdjustmentDisposablesRemovalConfirm .doConfirm( )} onDisposablesRemovalBack : { page( _treatmentReviewConfirm )} Index: sources/gui/qml/pages/pretreatment/connection/PreTreatmentConnectionStack.qml =================================================================== diff -u -rab7ffd27ecea1277d8645a8b62ff48c0cb3f6ff4 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/gui/qml/pages/pretreatment/connection/PreTreatmentConnectionStack.qml (.../PreTreatmentConnectionStack.qml) (revision ab7ffd27ecea1277d8645a8b62ff48c0cb3f6ff4) +++ sources/gui/qml/pages/pretreatment/connection/PreTreatmentConnectionStack.qml (.../PreTreatmentConnectionStack.qml) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -64,7 +64,7 @@ } onVisibleChanged: { if ( visible ) - vTreatmentVitals.doReset() + vTreatmentVitals.doReset(true) } } Index: sources/gui/qml/pages/settings/SettingsBluetoothCuff.qml =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/gui/qml/pages/settings/SettingsBluetoothCuff.qml (.../SettingsBluetoothCuff.qml) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/gui/qml/pages/settings/SettingsBluetoothCuff.qml (.../SettingsBluetoothCuff.qml) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -62,12 +62,16 @@ height : 300 model : vBluetooth delegate: TouchRect { id: _deviceTouchrect + readonly property color selectedColor: Colors.borderButtonSelected + readonly property color pairedColor: Colors.borderButton + readonly property color normalColor: Colors.borderButtonUnselected + property bool selectedDevice: addr === vBluetooth.pairedAddr clip : true radius : 10 width : 500 - 10 // give room to scrollbar height : 70 color : Colors.transparent - border.color: pair ? Colors.borderButton : Colors.borderButtonUnselected + border.color: selectedDevice ? selectedColor : (pair ? pairedColor : normalColor) text { text: addr + '\n' + name anchors.horizontalCenter: undefined @@ -77,6 +81,25 @@ onClicked: { vBluetooth.didDeviceSelect(addr, name); } + ProgressCircle { + minimum : 0 + maximum : 100 + value : vBluetooth.pairedBatt + color : _deviceTouchrect.border.color + visible : selectedDevice + diameter : 25 + anchors.margins: 5 + anchors.top: parent.top + anchors.right: parent.right + Text { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color : Colors.white + anchors.fill: parent + font.pixelSize: 10 + text: vBluetooth.pairedBatt + } + } } } } Index: sources/main.h =================================================================== diff -u -re4a0e2fc4c7ae0cbce0d670772276bf7f5ff3845 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/main.h (.../main.h) (revision e4a0e2fc4c7ae0cbce0d670772276bf7f5ff3845) +++ sources/main.h (.../main.h) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -61,6 +61,17 @@ extern bool gDisableTimeout; //--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------// +#define SKIPPER_DEF(X) \ + const quint8 skipperMaxTry = X; \ + static quint8 skipperCounter = 0; +#define SKIPPER_TST(WHAT) \ + if ( skipperCounter < skipperMaxTry ) WHAT +#define SKIPPER_TRY \ + skipperCounter++ +#define SKIPPER_RST \ + skipperCounter = 0 +//--------------------------------------------------------------------------------// +//--------------------------------------------------------------------------------// #define DEBUG_PROPERTY_CHANGED(vVARIABLE, PREFIX) // qDebug() << "#" << #vVARIABLE << PREFIX##vVARIABLE; //--------------------------------------------------------------------------------// #define PROPERTY_SLOT( vTYPE , vVARIABLE ) \ Index: sources/model/settings/MBluetooth.cpp =================================================================== diff -u -rf11dd9cd2c07f96d9d939d70ed9c4ce2edef2a9d -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/model/settings/MBluetooth.cpp (.../MBluetooth.cpp) (revision f11dd9cd2c07f96d9d939d70ed9c4ce2edef2a9d) +++ sources/model/settings/MBluetooth.cpp (.../MBluetooth.cpp) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -17,11 +17,10 @@ using namespace Model; -MBluetooth::MBluetooth( - InterfaceStates vState , +MBluetooth::MBluetooth(InterfaceStates vState , QString vDeviceAddr , QString vDeviceName , - QString vDevicePin , + quint8 vDeviceBatt , quint8 vDevicePair , qint16 vError , bool vValid , @@ -33,7 +32,7 @@ state (vState ), deviceAddr (vDeviceAddr ), deviceName (vDeviceName ), - devicePin (vDevicePin ), + deviceBatt (vDeviceBatt ), devicePair (vDevicePair ), error (vError ), valid (vValid ), Index: sources/model/settings/MBluetooth.h =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -52,16 +52,17 @@ eIS_Device_Init , eIS_Device_Start , eIS_Device_Connect , + eIS_Device_Waiting , eIS_Device_Error_Init , eIS_Device_Error , eIS_Device_Done , eIS_Device_Disconnect , eIS_Service_Start , + eIS_Service_Invalid , eIS_Service_Error , eIS_Service_Discover , eIS_Service_Detail , - eIS_Service_Detail_Invalid , eIS_Service_Detail_Error , eIS_Service_Detail_Done , eIS_Service_Done , @@ -77,13 +78,12 @@ Q_ENUM(InterfaceStates) struct BluetoothDevice { - QString addr = ""; - QString name = ""; - bool pair = 0; + QString addr = ""; ///< the device address + QString name = ""; ///< the device name + bool pair = 0; ///< the device pairing status bool operator ==(const BluetoothDevice &vDevice) const { return vDevice.addr == addr && - vDevice.name == name && - vDevice.pair == pair ; + vDevice.name == name ; } QString toString() const { return addr + "," + pair + "," + name; @@ -95,7 +95,7 @@ QString localName = ""; QString deviceAddr = ""; QString deviceName = ""; - QString devicePin = ""; + quint8 deviceBatt = 0; quint8 devicePair = 0; qint16 error = 0; bool valid = 1; @@ -110,7 +110,7 @@ InterfaceStates vState = eIS_Idle, QString vDeviceAddr = "", QString vDeviceName = "", - QString vDevicePin = "", + quint8 vDeviceBatt = 0, quint8 vDevicePair = 0, qint16 vError = 0, bool vValid = 1, Index: sources/view/hd/adjustment/common/VCommonAdjustmentVitals.cpp =================================================================== diff -u -raa8f2c87c14c68d1fda6da2540d47144990a596c -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/view/hd/adjustment/common/VCommonAdjustmentVitals.cpp (.../VCommonAdjustmentVitals.cpp) (revision aa8f2c87c14c68d1fda6da2540d47144990a596c) +++ sources/view/hd/adjustment/common/VCommonAdjustmentVitals.cpp (.../VCommonAdjustmentVitals.cpp) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -103,14 +103,17 @@ /*! * \brief View::VTreatmentVitals::doReset * \details reset the previously read vital values + * \param vEnabled - Disable or enable the vitals. + * \note it's still unknown that how to stop in case of the treatment ended by alarm or system fault. */ -void View::VTreatmentVitals::doReset() +void View::VTreatmentVitals::doReset(bool vEnabled) { epoch ( 0 ); lastRead ( ""); systolic ( 0 ); diastolic ( 0 ); heartRate ( 0 ); + enabled (vEnabled); // force notify the Gui emit epochChanged ( 0 ); Index: sources/view/hd/adjustment/common/VCommonAdjustmentVitals.h =================================================================== diff -u -raa8f2c87c14c68d1fda6da2540d47144990a596c -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/view/hd/adjustment/common/VCommonAdjustmentVitals.h (.../VCommonAdjustmentVitals.h) (revision aa8f2c87c14c68d1fda6da2540d47144990a596c) +++ sources/view/hd/adjustment/common/VCommonAdjustmentVitals.h (.../VCommonAdjustmentVitals.h) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -93,7 +93,7 @@ void doConfirm (quint16 vSystolic, quint16 vDiastolic, quint16 vHeartRate); void doSkip (); void doTimeout (); - void doReset (); + void doReset (bool vEnabled); signals: /*! Index: sources/view/settings/VBluetooth.cpp =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -42,99 +42,157 @@ this , SLOT( onDeviceSelect(QString, QString ))); } +/*! + * \brief View::VBluetooth::rowCount + * \details QAbstractItemModel::rowCount override + * \return Returns the number of rows under the given parent. When the parent is valid it means that rowCount is returning the number of children of parent. + */ int View::VBluetooth::rowCount(const QModelIndex &) const { return _devices.count(); } +/*! + * \brief View::VBluetooth::data + * \details QAbstractItemModel::data override + * \param index - the row index + * \param role - the row role + * \return Returns the data stored under the given role for the item referred to by the index. + */ +QVariant View::VBluetooth::data(const QModelIndex &index, int role) const +{ + if (index.row() < rowCount()) + switch (role) { + case ToStringRole : return _devices.at(index.row()).toString(); + case AddrRole : return _devices.at(index.row()).addr; + case NameRole : return _devices.at(index.row()).name; + case PairRole : return _devices.at(index.row()).pair; + default: return QVariant(); + } + return QVariant(); +} + +/*! + * \brief View::VBluetooth::roleNames + * \details QAbstractItemModel::roleNames override + * \return Returns the model's role names. + */ +QHash View::VBluetooth::roleNames() const +{ + static const QHash roles { + { ToStringRole, "toString" }, + { AddrRole, "addr" }, + { NameRole, "name" }, + { PairRole, "pair" } + }; + return roles; +} + +/*! + * \brief View::VBluetooth::reset + * \details Clears the list of the devices. + */ void View::VBluetooth::reset() { beginResetModel(); _devices.clear(); endResetModel(); } +/*! + * \brief View::VBluetooth::onStateChange + * \details Updates the View when the Bluetooth Interface state change signal is received. + * \param vData - The Bluetooth Interface information data. + */ void View::VBluetooth::onStateChange(const BluetoothData &vData) { - if ( vData.state == MBluetooth::eIS_Local_Error_POST ) { + pairedAddr(""); + Model::MBluetooth::InterfaceStates state = vData.state; + if ( state == MBluetooth::eIS_Local_Error_POST ) { isInvalid( true ); - notify( vData.state ); + notify( state ); return; } - scanEnabled( ! (vData.state == MBluetooth::eIS_Close || - // local - vData.state == MBluetooth::eIS_Local_Init || - // device - vData.state == MBluetooth::eIS_Device_Connect || - // service - vData.state == MBluetooth::eIS_Service_Start || - vData.state == MBluetooth::eIS_Service_Discover || - vData.state == MBluetooth::eIS_Service_Detail )); + // TODO: re-evaluate the states for the scan button enable/disable. + // scanEnabled(state == MBluetooth::eIS_Idle || + // state == MBluetooth::eIS_Scan_Done || + // state == MBluetooth::eIS_Scan_NotFound || + // state == MBluetooth::eIS_Device_Error || + // state == MBluetooth::eIS_Device_Waiting + // ); - switch (vData.state) { + switch (state) { // The device name is not always available and the interface may be in investigation. - case MBluetooth::eIS_Scan_NotFound : - case MBluetooth::eIS_Scan_Discover : - case MBluetooth::eIS_Scan_Found : - deviceAddr (vData.deviceAddr ); - deviceName (vData.deviceName ); - devicePair (vData.devicePair ); - break; - case MBluetooth::eIS_Local_Init : localAddr (vData.localAddr ); localName (vData.localName ); break; - case MBluetooth::eIS_Detail_Change : - case MBluetooth::eIS_Detail_Read : - case MBluetooth::eIS_Detail_Write : - case MBluetooth::eIS_Config_Read : - case MBluetooth::eIS_Config_Write : - detailName (vData.detailName ); - detailAddr (vData.detailAddr ); - detailValue (vData.detailValue ); + case MBluetooth::eIS_Scan_Start : + reset(); break; - case MBluetooth::eIS_Scan_Start : - reset(); + case MBluetooth::eIS_Scan_Done : + if (! _devices.count()) state = MBluetooth::eIS_Scan_NotFound; break; - case MBluetooth::eIS_Idle : - case MBluetooth::eIS_Local_Connect : - case MBluetooth::eIS_Local_Error_Invalid : - case MBluetooth::eIS_Local_Error_POST : - case MBluetooth::eIS_Local_Error_Off : - case MBluetooth::eIS_Local_Error_IO : - case MBluetooth::eIS_Local_Error : - case MBluetooth::eIS_Local_Disconnect : - case MBluetooth::eIS_Scan_Reject : - case MBluetooth::eIS_Scan_Stop : - case MBluetooth::eIS_Scan_Done : - case MBluetooth::eIS_Device_Init : - case MBluetooth::eIS_Device_Start : - case MBluetooth::eIS_Device_Connect : - case MBluetooth::eIS_Device_Error_Init : - case MBluetooth::eIS_Device_Error : - case MBluetooth::eIS_Device_Done : - case MBluetooth::eIS_Device_Disconnect : - case MBluetooth::eIS_Service_Start : - case MBluetooth::eIS_Service_Error : - case MBluetooth::eIS_Service_Discover : - case MBluetooth::eIS_Service_Detail : - case MBluetooth::eIS_Service_Detail_Invalid : - case MBluetooth::eIS_Service_Detail_Error : - case MBluetooth::eIS_Service_Detail_Done : - case MBluetooth::eIS_Service_Done : - case MBluetooth::eIS_Close : + + case MBluetooth::eIS_Device_Waiting : // Selected device connected and is in waiting mode for read. + pairedAddr(vData.deviceAddr); + pairedBatt(vData.deviceBatt); break; + + case MBluetooth::eIS_Idle : + case MBluetooth::eIS_Local_Connect : + case MBluetooth::eIS_Local_Error_Invalid : + case MBluetooth::eIS_Local_Error_POST : + case MBluetooth::eIS_Local_Error_Off : + case MBluetooth::eIS_Local_Error_IO : + case MBluetooth::eIS_Local_Error : + case MBluetooth::eIS_Local_Disconnect : + + case MBluetooth::eIS_Scan_Reject : + case MBluetooth::eIS_Scan_NotFound : + case MBluetooth::eIS_Scan_Discover : + case MBluetooth::eIS_Scan_Found : + case MBluetooth::eIS_Scan_Stop : + + case MBluetooth::eIS_Device_Init : + case MBluetooth::eIS_Device_Start : + case MBluetooth::eIS_Device_Connect : + case MBluetooth::eIS_Device_Error_Init : + case MBluetooth::eIS_Device_Error : + case MBluetooth::eIS_Device_Done : + case MBluetooth::eIS_Device_Disconnect : + + case MBluetooth::eIS_Service_Start : + case MBluetooth::eIS_Service_Invalid : + case MBluetooth::eIS_Service_Error : + case MBluetooth::eIS_Service_Discover : + case MBluetooth::eIS_Service_Detail : + case MBluetooth::eIS_Service_Detail_Error : + case MBluetooth::eIS_Service_Detail_Done : + case MBluetooth::eIS_Service_Done : + + case MBluetooth::eIS_Detail_Change : + case MBluetooth::eIS_Detail_Read : + case MBluetooth::eIS_Detail_Write : + case MBluetooth::eIS_Config_Read : + case MBluetooth::eIS_Config_Write : + + case MBluetooth::eIS_Close : + break; } error (vData.error ); - devicePin (vData.devicePin ); - notify( vData.state ); + notify( state ); } +/*! + * \brief View::VBluetooth::onDeviceChange + * \details updates the list of devices when a device data has been received. Used with Discovery Agent to populate list of discovered devices to the QML/UI. + * \param vDevice - The device information + */ void View::VBluetooth::onDeviceChange(const BluetoothDeviceData &vDevice) { int row = 0; @@ -143,14 +201,21 @@ _devices.insert(row, vDevice); endInsertRows(); + /* DEBUG: Found BCuff devices debug qDebug() << _devices.count(); - for (auto device: _devices) { qDebug() << device.addr << device.name << device.pair; } + */ } +/*! + * \brief View::VBluetooth::onDeviceSelect + * \details The signal handler of the device selection by user on the Bluetooth Cuff setting screen + * \param vAddr - The selected device address + * \param vName - The selected device name + */ void View::VBluetooth::onDeviceSelect(const QString &vAddr, const QString &vName) { BluetoothDeviceData data; @@ -159,6 +224,12 @@ emit _BluetoothInterface.didDeviceSelect(data); } +/*! + * \brief View::VBluetooth::toText + * \details Maps the BluetoothInterface state vState to its corresponding text message. + * \param vState - current state. + * \return corresponding message text mapped from the state cState. + */ QString View::VBluetooth::toText(MBluetooth::InterfaceStates vState) const { QString message; @@ -178,25 +249,26 @@ case MBluetooth::eIS_Scan_NotFound : message = tr("No Valid device found" ); break; case MBluetooth::eIS_Scan_Start : message = tr("Scanning ..." ); break; case MBluetooth::eIS_Scan_Reject : message = tr("Scanning Rejected" ); break; - case MBluetooth::eIS_Scan_Discover : message = tr("Device Discovered" ); break; + case MBluetooth::eIS_Scan_Discover : message = tr("Device Discovering ..." ); break; case MBluetooth::eIS_Scan_Found : message = tr("Blood Pressure Device Found" ); break; case MBluetooth::eIS_Scan_Stop : message = tr("Scanning Stopped" ); break; case MBluetooth::eIS_Scan_Done : message = tr("Scanning Finished" ); break; case MBluetooth::eIS_Device_Init : message = tr("Device Initializing ..." ); break; case MBluetooth::eIS_Device_Error_Init : message = tr("Device Initialization Error" ); break; case MBluetooth::eIS_Device_Start : message = tr("Device Connecting ..." ); break; + case MBluetooth::eIS_Device_Waiting : message = tr("Device Waiting ..." ); break; case MBluetooth::eIS_Device_Error : message = tr("Device Connection Error" ); break; case MBluetooth::eIS_Device_Connect : message = tr("Device Connected" ); break; case MBluetooth::eIS_Device_Done : message = tr("Device Clean Up" ); break; case MBluetooth::eIS_Device_Disconnect : message = tr("Device Disconnected" ); break; case MBluetooth::eIS_Service_Start : message = tr("Service Scanning ..." ); break; case MBluetooth::eIS_Service_Error : message = tr("Service Error: %1" ).arg(_error ); break; + case MBluetooth::eIS_Service_Invalid : message = tr("Service Invalid" ); break; case MBluetooth::eIS_Service_Discover : message = tr("Service Discovered" ); break; case MBluetooth::eIS_Service_Detail : message = tr("Service Detail Discovering ..." ); break; case MBluetooth::eIS_Service_Detail_Error : message = tr("Service Detail Error" ); break; - case MBluetooth::eIS_Service_Detail_Invalid : message = tr("Service Detail Invalid" ); break; case MBluetooth::eIS_Service_Detail_Done : message = tr("Service Detail Done" ); break; case MBluetooth::eIS_Service_Done : message = tr("Service Clean Up" ); break; @@ -210,6 +282,11 @@ return message; } +/*! + * \brief View::VBluetooth::notify + * \details Notifies the QML/UI about the state change and sends its test mapping to the QML/UI observers. + * \param vState - The current state + */ void View::VBluetooth::notify(MBluetooth::InterfaceStates vState) { QString message = toText(vState); @@ -226,9 +303,9 @@ } } -void View::VBluetooth::doScan () { _BluetoothInterface.doScan (); } -void View::VBluetooth::doConnectToDevice () { _BluetoothInterface.doConnectToDevice (); } -void View::VBluetooth::doDiscoverServices () { _BluetoothInterface.doDiscoverServices (); } -void View::VBluetooth::doEnableNotify () { _BluetoothInterface.doEnableNotify (); } -void View::VBluetooth::doReadMeasurements () { _BluetoothInterface.doReadMeasurements (); } -void View::VBluetooth::doReadInformation () { _BluetoothInterface.doReadInformation (); } +/*! + * \brief View::VBluetooth::doScan + * \details calls the Bluetooth Interface scan to start discovering the Bluetooth devices. + */ +void View::VBluetooth::doScan() { + _BluetoothInterface.doScan(); } Index: sources/view/settings/VBluetooth.h =================================================================== diff -u -rb252cd2777aadbce2d04aa32cc275f193de0cf52 -raeb915075b9e13e5c1aaf2800ba6db03b6c24a0b --- sources/view/settings/VBluetooth.h (.../VBluetooth.h) (revision b252cd2777aadbce2d04aa32cc275f193de0cf52) +++ sources/view/settings/VBluetooth.h (.../VBluetooth.h) (revision aeb915075b9e13e5c1aaf2800ba6db03b6c24a0b) @@ -46,19 +46,12 @@ PROPERTY(QString , localName , "" ) PROPERTY(QString , localAddr , "" ) - PROPERTY(bool , scanEnabled , false ) - PROPERTY(QString , deviceName , "" ) - PROPERTY(QString , deviceAddr , "" ) - PROPERTY(QString , devicePin , "" ) - PROPERTY(quint8 , devicePair , 0 ) + PROPERTY(bool , scanEnabled , true ) PROPERTY(qint16 , error , 0 ) + PROPERTY(QString , pairedAddr , "" ) + PROPERTY(quint8 , pairedBatt , 0 ) - PROPERTY(QString , detailAddr , "" ) - PROPERTY(QString , detailName , "" ) - PROPERTY(QString , detailValue , "" ) - - // List Model public: enum DataRole { @@ -71,32 +64,11 @@ private: BluetoothDeviceListData _devices {}; - int rowCount(const QModelIndex & = QModelIndex()) const; void reset(); - QVariant data(const QModelIndex &index, int role) const - { - if (index.row() < rowCount()) - switch (role) { - case ToStringRole : return _devices.at(index.row()).toString(); - case AddrRole : return _devices.at(index.row()).addr; - case NameRole : return _devices.at(index.row()).name; - case PairRole : return _devices.at(index.row()).pair; - default: return QVariant(); - } - return QVariant(); - } + int rowCount (const QModelIndex & = QModelIndex()) const override; + QVariant data (const QModelIndex &index, int role ) const override; + QHash roleNames ( ) const override; - QHash roleNames() const - { - static const QHash roles { - { ToStringRole, "toString" }, - { AddrRole, "addr" }, - { NameRole, "name" }, - { PairRole, "pair" } - }; - return roles; - } - VIEW_DEC_CLASS(VBluetooth) signals: @@ -113,10 +85,5 @@ public slots: void doScan (); - void doConnectToDevice (); - void doDiscoverServices (); - void doEnableNotify (); - void doReadMeasurements (); - void doReadInformation (); }; }