Index: denali.pro.user =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- denali.pro.user (.../denali.pro.user) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ denali.pro.user (.../denali.pro.user) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -1,6 +1,6 @@ - + EnvironmentId Index: en_US.udic =================================================================== diff -u -r20453ac382a122d1dde3c399ed9fcaf8a39b4ad6 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- en_US.udic (.../en_US.udic) (revision 20453ac382a122d1dde3c399ed9fcaf8a39b4ad6) +++ en_US.udic (.../en_US.udic) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -167,3 +167,7 @@ SSID async uchar +VBluetooth +Omron +BLESmart +BLE Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -80,13 +80,10 @@ // coco begin validated: Application termination is not correctly done in coco!!! // it has been tested and works perfectly fine in normal run. quitThread(); // validated -} -void BluetoothInterface::onDestroy() -{ - qDebug() << "Destroy"; - delete _local; - delete _agent; + if ( _local ) _local ->deleteLater(); + if ( _agent ) _agent ->deleteLater(); + if ( _device ) _device ->deleteLater(); } // coco end @@ -97,9 +94,6 @@ */ void BluetoothInterface::initConnections() { - connect(this , &BluetoothInterface :: destroyed , - this , &BluetoothInterface ::onDestroy ); - // Local connections connect(_local , &QBluetoothLocalDevice :: pairingFinished , this , &BluetoothInterface ::onLocalPairingFinish ); @@ -135,7 +129,7 @@ void BluetoothInterface::initThread(QThread &vThread) { // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread" ); + Q_ASSERT_X(QThread::currentThread() == qApp->thread() , __func__, "The Class initialization must be done in Main Thread"); _thread = &vThread; _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); @@ -160,7 +154,13 @@ } // coco end +#define NOTIFY_IDLE notifyStateChange(MBluetooth(MBluetooth::eIS_Idle )); +#define NOTIFY_CLOSE notifyStateChange(MBluetooth(MBluetooth::eIS_Close )); + // ~~~~~~~~~~~ Local +#define NOTIFY_LOCAL_INIT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Init , \ + _local->address().toString() , \ + _local->name() )); #define NOTIFY_LOCAL_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Connect , vAddress.toString()) ); #define NOTIFY_LOCAL_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error_Unknown )); #define NOTIFY_LOCAL_ERROR_IO notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error_IO )); @@ -191,7 +191,7 @@ notifyStateChange(_model ); #define NOTIFY_SCAN_START notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Start )); #define NOTIFY_SCAN_REJECT notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Reject )); -#define NOTIFY_SCAN_NOTFOUND notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_NotFound ,"","" )); +#define NOTIFY_SCAN_NOTFOUND notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_NotFound ,"", "" )); #define NOTIFY_SCAN_STOP notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Stop )); #define NOTIFY_SCAN_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Done )); #define NOTIFY_SCAN_DETAIL notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Detail , \ @@ -208,6 +208,9 @@ #define NOTIFY_DEVICE_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Connect , \ _info.address().toString() , \ _info.name() )); +#define NOTIFY_DEVICE_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Done , \ + _info.address().toString() , \ + _info.name() )); #define NOTIFY_DEVICE_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Error , \ _info.address().toString() , \ _info.name() , \ @@ -216,48 +219,137 @@ _info.address().toString() , \ _info.name() )); -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#define NOTIFY_SERVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Start )); +/* +#define NOTIFY_SERVICE_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Discover , \ + _service->serviceUuid().toString() , \ + _service->serviceName() )); +*/ + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Public interface to initialize and start the scan +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*! + * \brief BluetoothInterface::onstart + * \details the thread safe slot to be called when the public function start is called. + * initializes the local Bluetooth device _local and setups up the interface. + */ +void BluetoothInterface::onstart() +{ + _local->powerOn(); + if (! _local->isValid() ) { + NOTIFY_LOCAL_ERROR_INVALID + return; + } + + resetDevice(); + + _agent->setLowEnergyDiscoveryTimeout(5000); + NOTIFY_LOCAL_INIT + NOTIFY_IDLE +} + +/*! + * \brief BluetoothInterface::ondoScan + * \details the thread safe slot to be called when the public function doScan is called. + * initializes/validates the discovery agent _agent and setups it up to start the discovery. + */ +void BluetoothInterface::ondoScan() +{ + if (_agent && _agent->isActive()) { + NOTIFY_SCAN_REJECT + return; + } + + NOTIFY_SCAN_START + _agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~ Local Device Slots -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void BluetoothInterface::onLocalDeviceConnect(const QBluetoothAddress &vAddress) { +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Set of notifications on each event +/*! + * \brief BluetoothInterface::onLocalDeviceConnect + * \details Notifies the observers (view: VBluetooth) that the Local Device Connected + * \param vAddress + */ +void BluetoothInterface::onLocalDeviceConnect (const QBluetoothAddress &vAddress ) { NOTIFY_LOCAL_CONNECT } -void BluetoothInterface::onLocalDeviceDisconnect(const QBluetoothAddress &vAddress) { +/*! + * \brief BluetoothInterface::onLocalDeviceDisconnect + * \details Notifies the observers (view: VBluetooth) that the Local Device Disconnected + * \param vAddress + */ +void BluetoothInterface::onLocalDeviceDisconnect (const QBluetoothAddress &vAddress ) { NOTIFY_LOCAL_DISCONNECT } -void BluetoothInterface::onLocalPairingFinish(const QBluetoothAddress &vAddress, QBluetoothLocalDevice::Pairing vPairing) { - NOTIFY_PAIR_DONE - //_local->pairingConfirmation(true); - _device->discoverServices(); -} - -void BluetoothInterface::onLocalPairingDisplayConfirmation(const QBluetoothAddress &vAddress, const QString &vPin) { +/*! + * \brief BluetoothInterface::onLocalPairingDisplayConfirmation + * \details Notifies the observers (view: VBluetooth) that the user needs to confirm paring. + * \param vAddress - remote device address + * \param vPin - remote device requested pin code + * \note Not used for now just logged for later use. + */ +void BluetoothInterface::onLocalPairingDisplayConfirmation (const QBluetoothAddress &vAddress, const QString &vPin ) { NOTIFY_PAIR_CONFIRM - //_local->pairingConfirmation(true); } -void BluetoothInterface::onLocalPairingDisplayPinCode(const QBluetoothAddress &vAddress, const QString &vPin) { +/*! + * \brief BluetoothInterface::onLocalPairingDisplayPinCode + * \details Notifies the observers (view: VBluetooth) the pin code to make sure this is the device it intends to connect. + * Signal by some platforms to display the pin to the user for address. + * The pin is automatically generated, and does not need to be confirmed. + * \param vAddress + * \param vPin + * \note Not used for now just logged for later use. + */ +void BluetoothInterface::onLocalPairingDisplayPinCode (const QBluetoothAddress &vAddress, const QString &vPin ) { NOTIFY_PAIR_PINCODE - //_local->pairingConfirmation(true); } -void BluetoothInterface::onLocalError(QBluetoothLocalDevice::Error vError) { +/*! + * \brief BluetoothInterface::onLocalPairingFinish + * \details Notifies the observers (view: VBluetooth) that the paring is successfully done + * \param vAddress - Paired remote address + * \param vPairing - The Paring status/Type + */ +void BluetoothInterface::onLocalPairingFinish (const QBluetoothAddress &vAddress, QBluetoothLocalDevice::Pairing vPairing ) { + NOTIFY_PAIR_DONE +} + +/*! + * \brief BluetoothInterface::onLocalError + * \details Notifies the observers (view: VBluetooth) that the local adapter has error + * \param vError - The error + */ +void BluetoothInterface::onLocalError ( QBluetoothLocalDevice::Error vError) { switch (vError) { case QBluetoothLocalDevice::PairingError: NOTIFY_PAIR_ERROR break; default : NOTIFY_LOCAL_ERROR break; } + if ( _device ) _device->disconnectFromDevice(); } -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~ Discovery Agent Slots -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*! + * \brief BluetoothInterface::onAgentDiscoverDevice + * \details The slot to handle each discovered Bluetooth Low Energy device. + * if the discovered BLE device , which its information provided in vInfo, has any identified keyword, the scan/discovery stops if it is still active, and + * notifies the observers (view: VBluetooth) that a device found. + * \param vInfo + * \note If multiple supported devices are near, the first one will be identified as found. + */ void BluetoothInterface::onAgentDiscoverDevice(const QBluetoothDeviceInfo &vInfo) { NOTIFY_SCAN_DISCOVER if (vInfo.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { - if ( vInfo.name().startsWith("BP7000") || vInfo.name().startsWith("BLEsmart") || vInfo.name().startsWith("BLESmart") ) { + if ( isDeviceSupported( vInfo.name() ) ) { _info = QBluetoothDeviceInfo(vInfo.address(), vInfo.name(), QBluetoothDeviceInfo::HealthBloodPressureMonitor); NOTIFY_SCAN_FOUND if (_agent->isActive()) @@ -266,119 +358,238 @@ } } +/*! + * \brief BluetoothInterface::onAgentDiscoverError + * \details Notifies the observers (view: VBluetooth) that the discovery agent has error, during discovery. + * \param vError - The discovery agent error + */ +void BluetoothInterface::onAgentDiscoverError(QBluetoothDeviceDiscoveryAgent::Error vError) +{ + switch (vError) { + case QBluetoothDeviceDiscoveryAgent::PoweredOffError : NOTIFY_LOCAL_ERROR_OFF break; + case QBluetoothDeviceDiscoveryAgent::InputOutputError : NOTIFY_LOCAL_ERROR_IO break; + default : NOTIFY_LOCAL_ERROR break; + } + if ( _device ) _device->disconnectFromDevice(); +} + +/*! + * \brief BluetoothInterface::onAgentDiscoverFinish + * \details Notifies the observers (view: VBluetooth) that the discovery agent has done discovery, and + * starts gathering details and setup the discovered device. + */ void BluetoothInterface::onAgentDiscoverFinish() { NOTIFY_SCAN_DONE - discoverFinish(); + connectToDevice(); } +/*! + * \brief BluetoothInterface::onAgentDiscoverCancel + * \details Notifies the observers (view: VBluetooth) that the discovery agent has stopped discovery, and + * starts gathering details and setup the discovered device. + * \note this slot is called when the discovery stopped before it is finished (currently by first supported found device). + */ void BluetoothInterface::onAgentDiscoverCancel() { NOTIFY_SCAN_STOP - discoverFinish(); + connectToDevice(); } -void BluetoothInterface::onAgentDiscoverError(QBluetoothDeviceDiscoveryAgent::Error vError) +/*! + * \brief BluetoothInterface::connectToDevice + * \return false if + * the local Bluetooth device _local is not valid + * the device info _info is not valid + * + */ +bool BluetoothInterface::connectToDevice() { - switch (vError) { - case QBluetoothDeviceDiscoveryAgent::PoweredOffError : NOTIFY_LOCAL_ERROR_OFF break; - case QBluetoothDeviceDiscoveryAgent::InputOutputError : NOTIFY_LOCAL_ERROR_IO break; - default : NOTIFY_LOCAL_ERROR break; - } + if ( ! isLocalValid() ) return false; + if ( ! isInfoValid () ) return false; + if ( ! initDevice () ) return false; + + NOTIFY_DEVICE_START + _device->connectToDevice(); + + return true; } -void BluetoothInterface::doScan() +void BluetoothInterface::onDeviceConnect() { + NOTIFY_DEVICE_CONNECT + _device->discoverServices(); + NOTIFY_SERVICE_START +} + +void BluetoothInterface::onDeviceDisconnect() { - if (_agent && _agent->isActive()) { - NOTIFY_SCAN_REJECT - return; - } - emit didstart(); + NOTIFY_DEVICE_DISCONNECT } -void BluetoothInterface::onstart() +void BluetoothInterface::onDeviceError(QLowEnergyController::Error vError) { - _info = QBluetoothDeviceInfo(); // reset the device + NOTIFY_DEVICE_ERROR +} - _local->powerOn(); - if (! _local->isValid() ) { - NOTIFY_LOCAL_ERROR_INVALID - return; - } +void BluetoothInterface::onDeviceStateChanged(QLowEnergyController::ControllerState vState) +{ + // qDebug() << "Device State Changed" << vState; +} - qDebug() << _local->address(); - qDebug() << _local->connectedDevices(); - qDebug() << _local->hostMode(); - qDebug() << _local->isValid(); - qDebug() << _local->name(); - - _agent->setLowEnergyDiscoveryTimeout(5000); - NOTIFY_SCAN_START - _agent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); +void BluetoothInterface::onDeviceConnectionUpdated(const QLowEnergyConnectionParameters &/*vParameters*/) +{ + // qDebug() << "Device Connection Changed"; } -bool BluetoothInterface::discoverFinish() +bool BluetoothInterface::initDevice() { - if (! _local->isValid() ) { - NOTIFY_LOCAL_ERROR_INVALID - return false; + if ( _device ) { + _device->disconnectFromDevice(); + delete _device; + _device = nullptr; } - if ( ! _info.isValid() ) { - NOTIFY_SCAN_NOTFOUND - return false; - } - - NOTIFY_SCAN_DETAIL - _device = QLowEnergyController::createCentral(_info, this); - if (_device) NOTIFY_DEVICE_INIT - else { NOTIFY_DEVICE_INIT_ERROR + if ( _device ) NOTIFY_DEVICE_INIT + else { NOTIFY_DEVICE_INIT_ERROR return false; } - QObject::connect(_device, &QLowEnergyController::connected, [=](){ - NOTIFY_DEVICE_CONNECT - // TODO: If the device is paired it can't be connected again !!!!!!!!!! - // -------------------------------------------------------------------- - // if ( _model.devicePair == QBluetoothLocalDevice::Unpaired ) { - // _local->requestPairing(_device->remoteAddress(), QBluetoothLocalDevice::AuthorizedPaired); - // qDebug() << " ~~~~~ Connected Request Paring"; - // NOTIFY_PAIR_START - // } - // else { - // qDebug() << " ~~~~~ Connected Discover Services"; - _device->discoverServices(); - // } + // 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 ( ))); + connect( _device, SIGNAL( stateChanged(QLowEnergyController::ControllerState )), + this , SLOT(onDeviceStateChanged(QLowEnergyController::ControllerState ))); + connect( _device, SIGNAL( connectionUpdated(QLowEnergyConnectionParameters )), + this , SLOT(onDeviceConnectionUpdated(QLowEnergyConnectionParameters ))); + // Device Services + connect( _device, &QLowEnergyController::serviceDiscovered, [=](const QBluetoothUuid &vService){ + if (vService == QBluetoothUuid (QBluetoothUuid::DeviceInformation )) { + if ( _serviceDeviceInformation )S + delete _serviceDeviceInformation ; + _serviceDeviceInformation = _device->createServiceObject(vService, this); + qDebug() << " ~~~~~ Inf Service Found" << vService; + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::CurrentTimeService )) { + if ( _serviceCurrentTime ) + delete _serviceCurrentTime ; + _serviceCurrentTime = _device->createServiceObject(vService, this); + qDebug() << " ~~~~~ TDt Service Found" << vService; + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::BloodPressure )) { + if ( _serviceBloodPressure ) + delete _serviceBloodPressure ; + _serviceBloodPressure = _device->createServiceObject(vService, this); + qDebug() << " ~~~~~ BPr Service Found" << vService; + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::BatteryService )) { + if ( _serviceBattery ) + delete _serviceBattery ; + _serviceBattery = _device->createServiceObject(vService, this); + qDebug() << " ~~~~~ Bat Service Found" << vService; + return; + } }); - QObject::connect(_device, &QLowEnergyController::serviceDiscovered, [=](const QBluetoothUuid &service){ - QLowEnergyService *m_service = _device->createServiceObject(service, this); - qDebug() << " ~~~~~ Controller Service : " << m_service->serviceUuid() << m_service->serviceName(); - }); - QObject::connect(_device, &QLowEnergyController::discoveryFinished, [=](){ - qDebug() << " ~~~~~ Controller Discovery Finished"; + connect(_device, &QLowEnergyController::discoveryFinished, [=](){ + // _serviceInformation->discoverDetails(); + NOTIFY_DEVICE_DONE _device->disconnectFromDevice(); }); - QObject::connect(_device, &QLowEnergyController::disconnected, [=](){ - NOTIFY_DEVICE_DISCONNECT - }); - QObject::connect(_device, QOverload::of(&QLowEnergyController::error),[=](QLowEnergyController::Error vError){ - NOTIFY_DEVICE_ERROR - }); - - _device->connectToDevice(); - NOTIFY_DEVICE_START return true; } -void BluetoothInterface::notifyStateChange(const MBluetooth &vData) +/*! + * \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) { _state = vData.state; 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 ( _bpRead ) { + if ( _bpRead ) { } +} +/*! + * \brief BluetoothInterface::isDeviceSupported + * \param vName - remote device name + * \return true if the name provided starts with one of the supported keywords mentioned in the Omron documentation + */ +bool BluetoothInterface::isDeviceSupported( const QString &vName ) { + for (const QString &name : _supportedDeviceKeywords ) + if ( vName.startsWith(name) ) + return true; + return false; +} + +/*! + * \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 + */ +bool BluetoothInterface::isLocalValid() { + if (! _local->isValid() ) { + NOTIFY_LOCAL_ERROR_INVALID + return false; } + return true; } + +/*! + * \brief BluetoothInterface::isInfoValid + * \details checks if the device info _info 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 _info is set to a default QBluetoothDeviceInfo which is invalid by default, + * when the interface initialized (onStart), and + * when a scan started (ondoScan) + */ +bool BluetoothInterface::isInfoValid() { + if ( ! _info.isValid() ) { + NOTIFY_SCAN_NOTFOUND // not a valid device found + return false; + } + return true; +} + +/*! + * \brief BluetoothInterface::isDeviceValid + * \details checks if the remote Bluetooth device has been setup. + * \return returns false if no device is setup. + */ +bool BluetoothInterface::isDeviceValid() { + if ( _device ) { NOTIFY_DEVICE_INIT } + else { NOTIFY_DEVICE_INIT_ERROR + return false; + } + return true; +} + +/*! + * \brief BluetoothInterface::resetDevice + * \details resets the remote device _device and the device info _info. + */ +void BluetoothInterface::resetDevice() { + _info = QBluetoothDeviceInfo(); // reset the found info + if ( _device ) { + _device->disconnectFromDevice(); + delete _device; + _device = nullptr; + } +} Index: sources/bluetooth/BluetoothInterface.h =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -17,6 +17,7 @@ #include #include #include +#include // Project #include "main.h" // Doxygen : do not remove @@ -46,46 +47,59 @@ // friends friend class ::tst_initializations; + typedef QMap< QBluetoothUuid::ServiceClassUuid, QLowEnergyService *> ServiceMap; + QThread *_thread = nullptr; bool _init = false; - QBluetoothLocalDevice *_local ; - QBluetoothDeviceDiscoveryAgent *_agent ; - QLowEnergyController *_device ; // Factory pointer - QBluetoothDeviceInfo _info ; - MBluetooth _model ; - MBluetooth::InterfaceStates _state ; - bool _bpRead = false; - const quint16 _interval = 1000 ; // the interface timer base interval in mSec + QStringList _supportedDeviceKeywords { "BP7000", "BLEsmart", "BLESmart" }; // Regarding to Omron Documents. + QBluetoothLocalDevice *_local = nullptr ; + QBluetoothDeviceDiscoveryAgent *_agent = nullptr ; + QLowEnergyController *_device = nullptr ; + QLowEnergyService *_serviceDeviceInformation = nullptr ; + QLowEnergyService *_serviceCurrentTime = nullptr ; + QLowEnergyService *_serviceBloodPressure = nullptr ; + QLowEnergyService *_serviceBattery = nullptr ; + + QBluetoothDeviceInfo _info ; + MBluetooth _model ; + MBluetooth::InterfaceStates _state ; + + bool _bpRead = false ; + const quint16 _interval = 1000 ; // the interface timer base interval in mSec + protected: void timerEvent(QTimerEvent *event) override; public slots: bool init(); bool init(QThread &vThread); - void doScan(); - private slots: void quit(); - void onDestroy(); // Local Device Slots - void onLocalPairingFinish (const QBluetoothAddress &vAddress, QBluetoothLocalDevice::Pairing vPairing); - void onLocalPairingDisplayConfirmation (const QBluetoothAddress &vAddress, const QString &vPin); - void onLocalPairingDisplayPinCode (const QBluetoothAddress &vAddress, const QString &vPin); - void onLocalDeviceConnect (const QBluetoothAddress &vAddress); - void onLocalDeviceDisconnect (const QBluetoothAddress &vAddress); - void onLocalError (QBluetoothLocalDevice::Error vError); + void onLocalPairingFinish (const QBluetoothAddress &vAddress, QBluetoothLocalDevice::Pairing vPairing ); + void onLocalPairingDisplayConfirmation (const QBluetoothAddress &vAddress, const QString &vPin ); + void onLocalPairingDisplayPinCode (const QBluetoothAddress &vAddress, const QString &vPin ); + void onLocalDeviceConnect (const QBluetoothAddress &vAddress ); + void onLocalDeviceDisconnect (const QBluetoothAddress &vAddress ); + void onLocalError ( QBluetoothLocalDevice::Error vError ); // Discovery Agent Slots - void onAgentDiscoverDevice(const QBluetoothDeviceInfo &vDevice); - void onAgentDiscoverFinish(); - void onAgentDiscoverCancel(); - void onAgentDiscoverError (QBluetoothDeviceDiscoveryAgent::Error vError); + void onAgentDiscoverDevice (const QBluetoothDeviceInfo & vDevice ); + void onAgentDiscoverFinish (); + void onAgentDiscoverCancel (); + void onAgentDiscoverError ( QBluetoothDeviceDiscoveryAgent::Error vError ); + // Device Slots + void onDeviceConnect ( ); + void onDeviceDisconnect ( ); + void onDeviceError ( QLowEnergyController::Error vError ); + void onDeviceStateChanged ( QLowEnergyController::ControllerState vState ); + void onDeviceConnectionUpdated (const QLowEnergyConnectionParameters & vParameters ); private: void initConnections(); @@ -95,11 +109,24 @@ bool discoverStart (); bool discoverFinish (); - void notifyStateChange(const MBluetooth &vData); + bool isLocalValid (); + bool isInfoValid (); + bool isDeviceValid (); + bool isDeviceSupported( const QString &vName ); + + bool initDevice (); + void resetDevice (); + + bool connectToDevice(); + bool discoverServices(); + + + void notifyStateChange(const BluetoothData &vData); + signals: - void didStateChange(const Model::MBluetooth &vData); + void didStateChange(const BluetoothData &vData); - SAFE_CALL(start) + SAFE_CALL(start ) + SAFE_CALL(doScan) }; } - Index: sources/gui/qml/pages/settings/SettingsStack.qml =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -175,7 +175,7 @@ top : parent.top topMargin : _settingsBluetooth.topMarginContent right : parent.right - rightMargin : 50 + rightMargin : 0 // the image itself has some margins // kept to make sure it was intentional. } } Column { id : _deviceColumn @@ -229,10 +229,18 @@ text.text : qsTr("SCAN") width : 300 isDefault : false - enabled :!vBluetooth.scanInProgress - onClicked : vBluetooth.doScan() + enabled : ! vBluetooth.scanInProgress + onClicked : vBluetooth.doScan() } + WaitDone { id : _scanIndication + anchors.horizontalCenter : parent.horizontalCenter + anchors.verticalCenter : _scanButton.verticalCenter + diameter : _scanButton.height + visible : vBluetooth.scanInProgress + // done : _delegate.stepDone + } + notificationText : vBluetooth.notification } Index: sources/main.h =================================================================== diff -u -r2bc6542cebc264eb343f791f75223a1ca151465e -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/main.h (.../main.h) (revision 2bc6542cebc264eb343f791f75223a1ca151465e) +++ sources/main.h (.../main.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -316,8 +316,12 @@ //--------------------------------------------------------------------------------// #define SAFE_CALL( vMETHOD) \ public : void vMETHOD() { \ + static bool init = false; \ + if ( ! init ) { \ connect(this, SIGNAL(did##vMETHOD()), \ this, SLOT( on##vMETHOD())); \ + init = true; \ + } \ emit did##vMETHOD();} \ Q_SIGNALS : void did##vMETHOD(); \ private Q_SLOTS : void on##vMETHOD(); Index: sources/model/settings/MBluetooth.h =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -32,6 +32,7 @@ enum InterfaceStates { eIS_Idle , + eIS_Local_Init , eIS_Local_Connect , eIS_Local_Error_Invalid , eIS_Local_Error_Off , @@ -59,14 +60,23 @@ eIS_Device_Connect , eIS_Device_Error_Init , eIS_Device_Error , + // eIS_Device_State , + // eIS_Device_Update , eIS_Device_Done , eIS_Device_Disconnect , + eIS_Service_Start , + eIS_Service_Error , + eIS_Service_Discover , + eIS_Service_Done , + eIS_Close , }; Q_ENUM(InterfaceStates) InterfaceStates state ; + QString localAddr ; + QString localName ; QString deviceAddr ; QString deviceName ; QString devicePin ; @@ -86,7 +96,6 @@ QString vUUID = "" ); }; - } typedef Model::MBluetooth BluetoothData; Index: sources/view/settings/VBluetooth.cpp =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -56,56 +56,77 @@ case MBluetooth::eIS_Scan_Found : case MBluetooth::eIS_Scan_NotFound : case MBluetooth::eIS_Scan_Discover : - deviceAddr (vData.deviceAddr ); - deviceName (vData.deviceName ); - devicePair (vData.devicePair ); + deviceAddr (vData.deviceAddr ); + deviceName (vData.deviceName ); + devicePair (vData.devicePair ); break; + + case MBluetooth::eIS_Local_Init : + localAddr (vData.localAddr ); + localName (vData.localName ); + break; + default: break; } - error (vData.error ); - devicePin (vData.devicePin ); + error (vData.error ); + devicePin (vData.devicePin ); QString message; switch (vData.state) { case MBluetooth::eIS_Idle : message = "" ; break; + case MBluetooth::eIS_Close : message = tr("BluetoothInterface Closed" ); break; // Used BluetoothInterface to be consistent with the - case MBluetooth::eIS_Local_Error_Invalid : message = tr("No Valid Bluetooth Adapter" ); break; + + case MBluetooth::eIS_Local_Init : message = tr("The Bluetooth Adapter Is Ready" ); break; case MBluetooth::eIS_Local_Connect : message = tr("The Bluetooth Adapter Connected" ); break; case MBluetooth::eIS_Local_Disconnect : message = tr("The Bluetooth Adapter Disconnected" ); break; + case MBluetooth::eIS_Local_Error_Invalid : message = tr("No Valid Bluetooth Adapter" ); break; case MBluetooth::eIS_Local_Error_Off : message = tr("The Bluetooth Adapter Is Off" ); break; case MBluetooth::eIS_Local_Error_IO : message = tr("The Bluetooth Adapter IO Error" ); break; case MBluetooth::eIS_Local_Error_Unknown : message = tr("The Bluetooth Adapter Unknown Error" ); break; 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_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_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_Scan_Detail : message = tr("Scanning Details" ); break; - case MBluetooth::eIS_Device_Init : message = tr("Initializing ... " ); break; - case MBluetooth::eIS_Device_Error_Init : message = tr("Initialization Error" ); break; - case MBluetooth::eIS_Device_Connect : message = tr("Connecting ... " ); break; - case MBluetooth::eIS_Device_Error : message = tr("Connection Error" ); break; - case MBluetooth::eIS_Device_Done : message = tr("Connecting Done" ); break; - case MBluetooth::eIS_Device_Disconnect : message = tr("Disconnected" ); 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_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 Connection Done" ); break; + case MBluetooth::eIS_Device_Disconnect : message = tr("Device Disconnected" ); break; - case MBluetooth::eIS_Pair_Start : message = tr("Pairing ... " ); break; + case MBluetooth::eIS_Service_Start : message = tr("Service Scanning ..." ); break; + case MBluetooth::eIS_Service_Error : message = tr("Service Scanning Error" ); break; + case MBluetooth::eIS_Service_Discover : message = tr("Service Discovered" ); break; + case MBluetooth::eIS_Service_Done : message = tr("Service Scanning Finished" ); break; + + case MBluetooth::eIS_Pair_Start : message = tr("Pairing ..." ); break; case MBluetooth::eIS_Pair_Error : message = tr("Pairing Error" ); break; case MBluetooth::eIS_Pair_PinCode : message = tr("Pairing PinCode" ); break; case MBluetooth::eIS_Pair_Confirm : message = tr("Pairing Confirm" ); break; case MBluetooth::eIS_Pair_Done : message = tr("Pairing Done" ); break; - default : message = "" ; break; + // IMPORTANT: Do not use the "default:" to let compiler check for all the enumeration which are not handled. } notification(message); + + // Console Log message = QString::number(_error) + " " + _deviceAddr + " " + QString::number(_devicePair) + " " + message + " " + _deviceName; - qDebug().noquote().nospace() << message.trimmed(); + message = message.trimmed().simplified(); + qDebug().noquote().nospace() << message; + + // Service Log + LOG_DEBUG(message); } void View::VBluetooth::doScan() Index: sources/view/settings/VBluetooth.h =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 --- sources/view/settings/VBluetooth.h (.../VBluetooth.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/view/settings/VBluetooth.h (.../VBluetooth.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) @@ -40,6 +40,9 @@ PROPERTY(QString , notification , "" ) + PROPERTY(QString , localName , "" ) + PROPERTY(QString , localAddr , "" ) + PROPERTY(bool , scanInProgress , false ) PROPERTY(QString , deviceName , "" ) PROPERTY(QString , deviceAddr , "" )