Index: denali.pro =================================================================== diff -u -r9b34a391e7401e9a045270744902a20d0e66d650 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- denali.pro (.../denali.pro) (revision 9b34a391e7401e9a045270744902a20d0e66d650) +++ denali.pro (.../denali.pro) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -50,6 +50,7 @@ sources/canbus \ sources/utility \ sources/wifi \ + sources/bluetooth \ sources/abstract \ sources/model \ sources/model/settings \ @@ -114,6 +115,7 @@ sources/storage/TreatmentLog.h \ sources/view/hd/data/post/VHDPOSTData.h \ sources/wifi/WifiInterface.h \ + sources/bluetooth/BluetoothInterface.h \ \ # ---------- Models ---------- sources/model/MModel.h \ sources/model/MAbstract.h \ @@ -126,6 +128,7 @@ \ # ---------- Models - settings sources/model/settings/MSettings.h \ sources/model/settings/MWifiNetwork.h \ + sources/model/settings/MBluetooth.h \ sources/model/dg/adjustment/settings/MAdjustDGSerialNumberResponse.h \ sources/model/dg/adjustment/settings/MAdjustDGServiceResponse.h \ sources/model/hd/adjustment/settings/MAdjustHDSerialNumberResponse.h \ @@ -252,8 +255,9 @@ \ # ---------- Views - Settings sources/view/settings/VDateTime.h \ sources/view/settings/VSettings.h \ - sources/view/settings/VAdjustmentVersions.h \ + sources/view/settings/VBluetooth.h \ sources/view/settings/VNetworkModel.h \ + sources/view/settings/VAdjustmentVersions.h \ sources/view/settings/VAdjustmentAlarmVolume.h \ sources/view/settings/VAdjustmentService.h \ \ # ---------- Views - Alarm @@ -358,6 +362,7 @@ sources/storage/TreatmentLog.cpp \ sources/view/hd/data/post/VHDPOSTData.cpp \ sources/wifi/WifiInterface.cpp \ + sources/bluetooth/BluetoothInterface.cpp \ \ # ---------- Models ---------- sources/model/MAbstract.cpp \ sources/device/DeviceModels.cpp \ @@ -368,6 +373,7 @@ sources/model/hd/data/post/MHDPostSingleResultData.cpp \ \ # ---------- Models - settings sources/model/settings/MSettings.cpp \ + sources/model/settings/MBluetooth.cpp \ sources/model/dg/adjustment/settings/MAdjustDGSerialNumberResponse.cpp \ sources/model/dg/adjustment/settings/MAdjustDGServiceResponse.cpp \ sources/model/hd/adjustment/settings/MAdjustHDSerialNumberResponse.cpp \ @@ -489,8 +495,9 @@ \ # ---------- Views - Settings sources/view/settings/VSettings.cpp \ sources/view/settings/VDateTime.cpp \ - sources/view/settings/VAdjustmentVersions.cpp \ + sources/view/settings/VBluetooth.cpp \ sources/view/settings/VNetworkModel.cpp \ + sources/view/settings/VAdjustmentVersions.cpp \ sources/view/settings/VAdjustmentAlarmVolume.cpp \ sources/view/settings/VAdjustmentService.cpp \ \ # ---------- Views - HD - Adjustment Index: denali.pro.user =================================================================== diff -u -r9b34a391e7401e9a045270744902a20d0e66d650 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- denali.pro.user (.../denali.pro.user) (revision 9b34a391e7401e9a045270744902a20d0e66d650) +++ denali.pro.user (.../denali.pro.user) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -1,6 +1,6 @@ - + EnvironmentId Index: main.cpp =================================================================== diff -u -rfc329c788fe9453983072bee937ccbc95b4ed6e4 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- main.cpp (.../main.cpp) (revision fc329c788fe9453983072bee937ccbc95b4ed6e4) +++ main.cpp (.../main.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -51,6 +51,7 @@ #include "Logger.h" #include "DeviceController.h" #include "WifiInterface.h" +#include "BluetoothInterface.h" #include "Threads.h" // #include "FileHandler.h" @@ -149,7 +150,7 @@ // --- -0 : enable-keep-awake (the fast mode) QCommandLineOption optionSendEmptyKeepAwake(QStringList() << "0" << "enable-keep-awake", - QCoreApplication::translate("main", "Enable send low priority, empty message on the CANBus just to keep UI board CAN driver awake")); + QCoreApplication::translate("main", "Enable send low priority, empty message on the CANBus just to keep UI board CAN driver awake")); parser.addOption(optionSendEmptyKeepAwake); // --- -i : fake-interval @@ -163,8 +164,8 @@ QCommandLineOption optionFakeData( QStringList() << "f" << "fake-message", QCoreApplication::translate("main", "Test fake message data\n" - "will use default sequenced long fake message if set to 00(default)\n" - "will used only if correct integer value assigned for interval option"), + "will use default sequenced long fake message if set to 00(default)\n" + "will used only if correct integer value assigned for interval option"), QCoreApplication::translate("main", "data")); parser.addOption(optionFakeData); @@ -176,12 +177,12 @@ // --- -u : disable-unhandled-report QCommandLineOption optionDisableUnhandledReport(QStringList() << "u" << "disable-unhandled-report", - QCoreApplication::translate("main", "Disable unhandled messages report as an error in the log")); + QCoreApplication::translate("main", "Disable unhandled messages report as an error in the log")); parser.addOption(optionDisableUnhandledReport); // --- -q : disable-timeout QCommandLineOption optionDisableTimeout(QStringList() << "q" << "disable-timeout", - QCoreApplication::translate("main", "Disables HD communication timeout")); + QCoreApplication::translate("main", "Disables HD communication timeout")); parser.addOption(optionDisableTimeout); // --- parse command lines @@ -235,8 +236,8 @@ bool isOnMaster = ver_branch == "master"; bool isNotStory = isOnMaster - || ver_branch == "staging" - || ver_branch == "develop"; + || ver_branch == "staging" + || ver_branch == "develop"; if (isNotStory) { if (isOnServer) { if (isOnMaster ) { @@ -250,19 +251,19 @@ if ( ! ver_branch.isEmpty()) ver_branch += '.'; QCoreApplication::setApplicationVersion( - QString("%1%2%3%4%5.%6") - .arg(ver_branch) - .arg(ver_major) - .arg(ver_minor) - .arg(ver_micro) - .arg(ver_revis) - .arg(ver_comp ) + QString("%1%2%3%4%5.%6") + .arg(ver_branch) + .arg(ver_major) + .arg(ver_minor) + .arg(ver_micro) + .arg(ver_revis) + .arg(ver_comp ) ); } #ifdef UNIT_TEST - #include TEST_CLASS_INCLUDE - QTEST_MAIN(TEST_CLASS_NAME) +#include TEST_CLASS_INCLUDE +QTEST_MAIN(TEST_CLASS_NAME) #else /*! * \brief Application Initialization @@ -357,14 +358,20 @@ //! - Initializing WiFi Interface _WifiInterface.init(Threads::_Wifi_Thread); - _WifiInterface.start(); + _BluetoothInterface.init(Threads::_Bluetooth_Thread); + //! - Initialize the QML Viewer and starts GUI int app_exec = -1; LOG_DEBUG("UI Initializing"); if ( startGui() ) { LOG_DEBUG("UI Initialized"); - _ApplicationController.startPOST(); + _ApplicationController .startPOST(); + + // TODO: check if the POST for the interfaces below are passed do the start. + _WifiInterface .start(); + _BluetoothInterface .start(); + app_exec = app.exec(); } Index: sources/Threads.cpp =================================================================== diff -u -r1c18f738693756ca1f0342c2cc158e32bc28f90b -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/Threads.cpp (.../Threads.cpp) (revision 1c18f738693756ca1f0342c2cc158e32bc28f90b) +++ sources/Threads.cpp (.../Threads.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -35,7 +35,7 @@ QThread _Logger_Thread ; QThread _Application_Thread ; QThread _Wifi_Thread ; - + QThread _Bluetooth_Thread ; /*! * \brief registerTypes * \details this method has to be called before any class which uses these types @@ -90,9 +90,10 @@ quitThread(_CanAcknow_Thread ); quitThread(_CanMessage_Thread ); quitThread(_DeviceController_Thread ); - quitThread(_Logger_Thread ); + quitThread(_Bluetooth_Thread ); quitThread(_Wifi_Thread ); quitThread(_Application_Thread ); + quitThread(_Logger_Thread ); } // coco end } Index: sources/Threads.h =================================================================== diff -u -r61f16c988a159401c92730b4cbfca5085c77222f -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/Threads.h (.../Threads.h) (revision 61f16c988a159401c92730b4cbfca5085c77222f) +++ sources/Threads.h (.../Threads.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -26,6 +26,7 @@ extern QThread _Logger_Thread ; extern QThread _Application_Thread ; extern QThread _Wifi_Thread ; + extern QThread _Bluetooth_Thread ; void registerTypes(); void quitThread (QThread &vThread); Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u --- sources/bluetooth/BluetoothInterface.cpp (revision 0) +++ sources/bluetooth/BluetoothInterface.cpp (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,384 @@ +/*! + * \copyright + * 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 BluetoothInterface.h + * \author (last) Behrouz NematiPour + * \author (original) Behrouz NematiPour + * \date (last) 22-Aug-2021 + * \date (original) 22-Aug-2021 + */ +#include "BluetoothInterface.h" + +// Qt +#include +#include + +#include +#include + +// Project +#include "Logger.h" + +// namespace +using namespace Bluetooth; +using namespace Model; + +/*! + * \brief BluetoothInterface::BluetoothInterface + * \details Constructor + * \param parent - QObject parent owner object. + * Qt handles the children destruction by their parent objects life-cycle. + */ +BluetoothInterface::BluetoothInterface(QObject *parent) : QObject(parent) { + _local = new QBluetoothLocalDevice (this); + _agent = new QBluetoothDeviceDiscoveryAgent (this); + startTimer(_interval); +} + +/*! + * \brief BluetoothInterface::init + * \details Initializes the class + * \return False if it has been called before. + */ +bool BluetoothInterface::init() +{ + if ( _init ) return false; + _init = true; + + // runs in BluetoothInterface thread + initConnections(); + LOG_DEBUG("UI," + tr("%1 Initialized").arg(metaObject()->className())); + + return true; +} + +/*! + * \brief BluetoothInterface::init + * \details Initialized the Class by calling the init() method first + * And initializes the thread vThread by calling initThread + * on success init(). + * \param vThread - the thread + * \return returns the return value of the init() method + */ +bool BluetoothInterface::init(QThread &vThread) +{ + if ( ! init() ) return false; + initThread(vThread); + return true; +} + +/*! + * \brief BluetoothInterface::quit + * \details quits the class + * Calls quitThread + */ +void BluetoothInterface::quit() +{ + // 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; +} +// 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() +{ + connect(this , &BluetoothInterface :: destroyed , + this , &BluetoothInterface ::onDestroy ); + + // Local connections + connect(_local , &QBluetoothLocalDevice :: pairingFinished , + this , &BluetoothInterface ::onLocalPairingFinish ); + connect(_local , &QBluetoothLocalDevice :: pairingDisplayConfirmation , + this , &BluetoothInterface ::onLocalPairingDisplayConfirmation ); + connect(_local , &QBluetoothLocalDevice :: pairingDisplayPinCode , + this , &BluetoothInterface ::onLocalPairingDisplayPinCode ); + connect(_local , &QBluetoothLocalDevice :: deviceConnected , + this , &BluetoothInterface ::onLocalDeviceConnect ); + connect(_local , &QBluetoothLocalDevice :: deviceDisconnected , + this , &BluetoothInterface ::onLocalDeviceDisconnect ); + connect(_local , &QBluetoothLocalDevice :: error , + this , &BluetoothInterface ::onLocalError ); + + // 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 ); +} + +/*! + * \brief BluetoothInterface::initThread + * \details Moves this object into the thread vThread. + * And checks that this method is called from main thread. + * Also connects quitThread to application aboutToQuit. + * \param vThread - the thread + */ +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" ); + _thread = &vThread; + _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); + connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); + _thread->start(); + moveToThread(_thread); +} + +/*! + * \brief BluetoothInterface::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * And to be destroyed there. + */ +void BluetoothInterface::quitThread() +{ + // coco begin validated: Application termination is not correctly done in coco!!! + // it has been tested and works perfectly fine in normal run. + + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); // validated +} +// coco end + +// ~~~~~~~~~~~ Local +#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 )); +#define NOTIFY_LOCAL_ERROR_OFF notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error_Off )); +#define NOTIFY_LOCAL_ERROR_INVALID notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error_Invalid )); +#define NOTIFY_LOCAL_DISCONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Disconnect , vAddress.toString()) ); +// ~~~~~~~~~~~ Pair +#define NOTIFY_PAIR_START notifyStateChange(MBluetooth(MBluetooth::eIS_Pair_Start , _device->remoteAddress().toString())); +#define NOTIFY_PAIR_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Pair_Done , vAddress.toString(), "", "", vPairing)); +#define NOTIFY_PAIR_CONFIRM notifyStateChange(MBluetooth(MBluetooth::eIS_Pair_Confirm , vAddress.toString(), "", vPin ) ); +#define NOTIFY_PAIR_PINCODE notifyStateChange(MBluetooth(MBluetooth::eIS_Pair_PinCode , vAddress.toString(), "", vPin ) ); +#define NOTIFY_PAIR_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Pair_Error )); +// ~~~~~~~~~~~ Scan +#define NOTIFY_SCAN_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Discover , \ + vInfo.address().toString() , \ + vInfo.name(), "" , \ + _local->pairingStatus(vInfo.address()) , \ + 0 , \ + vInfo.isValid() , \ + vInfo.deviceUuid().toString() )); +#define NOTIFY_SCAN_FOUND _model = MBluetooth(MBluetooth::eIS_Scan_Found , \ + _info.address().toString() , \ + _info.name(), "" , \ + _local->pairingStatus(vInfo.address()) , \ + 0 , \ + _info.isValid() , \ + _info.deviceUuid().toString() );\ + 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_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 , \ + _info.address().toString() , \ + _info.name() )); +// ~~~~~~~~~ Device +#define NOTIFY_DEVICE_INIT_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Error_Init )); +#define NOTIFY_DEVICE_INIT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Init , \ + _info.address().toString() , \ + _info.name() )); +#define NOTIFY_DEVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Start , \ + _info.address().toString() , \ + _info.name() )); +#define NOTIFY_DEVICE_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Connect , \ + _info.address().toString() , \ + _info.name() )); +#define NOTIFY_DEVICE_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Error , \ + _info.address().toString() , \ + _info.name() , \ + "",0, vError, false )); +#define NOTIFY_DEVICE_DISCONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Disconnect , \ + _info.address().toString() , \ + _info.name() )); + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Local Device Slots +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void BluetoothInterface::onLocalDeviceConnect(const QBluetoothAddress &vAddress) { + NOTIFY_LOCAL_CONNECT +} + +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) { + NOTIFY_PAIR_CONFIRM + //_local->pairingConfirmation(true); +} + +void BluetoothInterface::onLocalPairingDisplayPinCode(const QBluetoothAddress &vAddress, const QString &vPin) { + NOTIFY_PAIR_PINCODE + //_local->pairingConfirmation(true); +} + +void BluetoothInterface::onLocalError(QBluetoothLocalDevice::Error vError) { + switch (vError) { + case QBluetoothLocalDevice::PairingError: NOTIFY_PAIR_ERROR break; + default : NOTIFY_LOCAL_ERROR break; + } +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~ Discovery Agent Slots +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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") ) { + _info = QBluetoothDeviceInfo(vInfo.address(), vInfo.name(), QBluetoothDeviceInfo::HealthBloodPressureMonitor); + NOTIFY_SCAN_FOUND + if (_agent->isActive()) + _agent->stop(); + } + } +} + +void BluetoothInterface::onAgentDiscoverFinish() +{ + NOTIFY_SCAN_DONE + discoverFinish(); +} + +void BluetoothInterface::onAgentDiscoverCancel() +{ + NOTIFY_SCAN_STOP + discoverFinish(); +} + +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; + } +} + +void BluetoothInterface::doScan() +{ + if (_agent && _agent->isActive()) { + NOTIFY_SCAN_REJECT + return; + } + emit didstart(); +} + +void BluetoothInterface::onstart() +{ + _info = QBluetoothDeviceInfo(); // reset the device + + _local->powerOn(); + if (! _local->isValid() ) { + NOTIFY_LOCAL_ERROR_INVALID + return; + } + + 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); +} + +bool BluetoothInterface::discoverFinish() +{ + if (! _local->isValid() ) { + NOTIFY_LOCAL_ERROR_INVALID + return false; + } + 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 + 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(); + // } + }); + 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"; + _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) +{ + _state = vData.state; + emit didStateChange(vData); +} + +void BluetoothInterface::timerEvent(QTimerEvent *) +{ + if ( _bpRead ) { + + } +} Index: sources/bluetooth/BluetoothInterface.h =================================================================== diff -u --- sources/bluetooth/BluetoothInterface.h (revision 0) +++ sources/bluetooth/BluetoothInterface.h (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,105 @@ +/*! + * \copyright + * 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 BluetoothInterface.h + * \author (last) Behrouz NematiPour + * \author (original) Behrouz NematiPour + * \date (last) 22-Aug-2021 + * \date (original) 22-Aug-2021 + */ +#pragma once + +// Qt +#include +#include +#include +#include + +// Project +#include "main.h" // Doxygen : do not remove +#include "MBluetooth.h" + +// Define +#define _BluetoothInterface Bluetooth::BluetoothInterface::I() + +// forward declarations +class tst_initializations; + +// namespace +namespace Bluetooth { + +using namespace Model; +/*! + * \brief The MessageAcknowModel class + * \details The wrapper class of the AcknowModel which does the thread handling. + */ +class BluetoothInterface : public QObject +{ + Q_OBJECT + + // Singleton + SINGLETON(BluetoothInterface) + + // friends + friend class ::tst_initializations; + + 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 + +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); + + // Discovery Agent Slots + void onAgentDiscoverDevice(const QBluetoothDeviceInfo &vDevice); + void onAgentDiscoverFinish(); + void onAgentDiscoverCancel(); + void onAgentDiscoverError (QBluetoothDeviceDiscoveryAgent::Error vError); + +private: + void initConnections(); + + void initThread(QThread &vThread); + void quitThread(); + + bool discoverStart (); + bool discoverFinish (); + + void notifyStateChange(const MBluetooth &vData); +signals: + void didStateChange(const Model::MBluetooth &vData); + + SAFE_CALL(start) +}; +} + Index: sources/gui/GuiGlobals.cpp =================================================================== diff -u -rebc82b5efe26c1081606fab06a1c99bb4f9c0098 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/gui/GuiGlobals.cpp (.../GuiGlobals.cpp) (revision ebc82b5efe26c1081606fab06a1c99bb4f9c0098) +++ sources/gui/GuiGlobals.cpp (.../GuiGlobals.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -41,6 +41,7 @@ #include "VDateTime.h" #include "VNetworkModel.h" #include "VAdjustmentAlarmVolume.h" +#include "VBluetooth.h" // states data #include "VHDOperationModeData.h" #include "VPreTreatmentStatesData.h" Index: sources/gui/qml/components/StackItem.qml =================================================================== diff -u -r821bf955d0ba7e028bccfee7c04ca77cf80a0bd4 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/gui/qml/components/StackItem.qml (.../StackItem.qml) (revision 821bf955d0ba7e028bccfee7c04ca77cf80a0bd4) +++ sources/gui/qml/components/StackItem.qml (.../StackItem.qml) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -36,6 +36,8 @@ * \brief prints out the list of the items in the stack by their index position in the stack. */ function info(vInfo) { + // DEBUG: + return; console.debug('-----') if ( vInfo !== undefined ) console.debug(vInfo) for( var i = 0; i < _stackView.depth; i++ ) { Index: sources/gui/qml/main.qml =================================================================== diff -u -r3f555c49ddd2c983f469709e3c001d0e76159248 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/gui/qml/main.qml (.../main.qml) (revision 3f555c49ddd2c983f469709e3c001d0e76159248) +++ sources/gui/qml/main.qml (.../main.qml) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -39,6 +39,7 @@ import VDateTime 0.1 import VNetworkModel 0.1 import VAdjustmentAlarmVolume 0.1 +import VBluetooth 0.1 // States views import VHDOperationMode 0.1 @@ -131,6 +132,8 @@ VDateTime { id: vDateTime } VNetworkModel { id: vNetwork } VAdjustmentAlarmVolume { id: vAdjustmentAlarmVolume } + VBluetooth { id: vBluetooth } + // ---- States VHDOperationMode { id: vHDOperationMode } VPreTreatmentStates { id: vPreTreatmentStates } Index: sources/gui/qml/pages/settings/SettingsStack.qml =================================================================== diff -u -r9b34a391e7401e9a045270744902a20d0e66d650 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 9b34a391e7401e9a045270744902a20d0e66d650) +++ sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -166,16 +166,74 @@ SettingsBase { id: _settingsBluetooth itemIndex : SettingsStack.Bluetooth + confirmVisible : false Image { id: _image width : 640 height : 480 source: "qrc:/images/iCuff-Omron-BP7000" anchors { - horizontalCenter: parent.horizontalCenter - top: parent.top - topMargin: _settingsBluetooth.topMarginContent + top : parent.top + topMargin : _settingsBluetooth.topMarginContent + right : parent.right + rightMargin : 50 } } + Column { id : _deviceColumn + property int labelHeight: 25 + + anchors.top : _image.top + anchors.topMargin : 100 + anchors.left : parent.left + anchors.leftMargin : 50 + spacing : 10 + Label { id : _deviceTitle + text : vBluetooth.devicePair ? qsTr("Found Paired Device") : qsTr("Found Device") + } + Row { id : _deviceNameRow + leftPadding : 25 + Label { id : _deviceNameLabel + height : _deviceColumn.labelHeight + text : qsTr("Name") + labelWidth : 125 + verticalAlignment : Text.AlignVCenter + } + Label { id : _deviceName + height : _deviceColumn.labelHeight + text : ": " + vBluetooth.deviceName + font.pixelSize : Fonts.fontPixelNotification + verticalAlignment : Text.AlignVCenter + } + } + Row { + leftPadding : 25 + Label { id : _deviceAddressLabel + height : _deviceColumn.labelHeight + text : qsTr("Address") + labelWidth : 125 + verticalAlignment : Text.AlignVCenter + + } + Label { id : _deviceAddress + height : _deviceColumn.labelHeight + text : ": " + vBluetooth.deviceAddr + font.pixelSize : Fonts.fontPixelNotification + verticalAlignment : Text.AlignVCenter + } + } + } + TouchRect { id : _scanButton + anchors.bottom : parent.bottom + anchors.bottomMargin: Variables.mainMenuHeight * 2 + Variables.minVGap + anchors.left : parent.left + anchors.leftMargin : 100 + text.text : qsTr("SCAN") + width : 300 + isDefault : false + enabled :!vBluetooth.scanInProgress + onClicked : vBluetooth.doScan() + } + + notificationText : vBluetooth.notification } SettingsDG { id: _settingsDGSettings Index: sources/model/MModel.h =================================================================== diff -u -rebc82b5efe26c1081606fab06a1c99bb4f9c0098 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/model/MModel.h (.../MModel.h) (revision ebc82b5efe26c1081606fab06a1c99bb4f9c0098) +++ sources/model/MModel.h (.../MModel.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -18,6 +18,7 @@ // device #include "DeviceModels.h" +#include "MBluetooth.h" // models #include "MSettings.h" @@ -262,6 +263,7 @@ /* Settings */ \ REGISTER_METATYPE( SettingsData ) \ REGISTER_METATYPE( WifiNetworkData ) \ + REGISTER_METATYPE( BluetoothData ) \ /* Data */ \ REGISTER_METATYPE( HDOperationModeData ) \ REGISTER_METATYPE( PreTreatmentStatesData ) \ Index: sources/model/hd/alarm/MAlarmTriggered.cpp =================================================================== diff -u -r2bc6542cebc264eb343f791f75223a1ca151465e -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/model/hd/alarm/MAlarmTriggered.cpp (.../MAlarmTriggered.cpp) (revision 2bc6542cebc264eb343f791f75223a1ca151465e) +++ sources/model/hd/alarm/MAlarmTriggered.cpp (.../MAlarmTriggered.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -53,16 +53,16 @@ params += {zero, zero}; break; case Gui::GuiAlarmDataTypes::ALARM_DATA_TYPE_U32 : - params += {_data.mFieldDescriptor1.value, _data.mDataFieldU2.value}; + params += {_data.mFieldDescriptor2.value, _data.mDataFieldU2.value}; break; case Gui::GuiAlarmDataTypes::ALARM_DATA_TYPE_S32 : - params += {_data.mFieldDescriptor1.value, _data.mDataFieldS2.value}; + params += {_data.mFieldDescriptor2.value, _data.mDataFieldS2.value}; break; case Gui::GuiAlarmDataTypes::ALARM_DATA_TYPE_F32 : - params += {_data.mFieldDescriptor1.value, _data.mDataFieldF2.value}; + params += {_data.mFieldDescriptor2.value, _data.mDataFieldF2.value}; break; case Gui::GuiAlarmDataTypes::ALARM_DATA_TYPE_BOOL : - params += {_data.mFieldDescriptor1.value, _data.mDataFieldB2.value}; + params += {_data.mFieldDescriptor2.value, _data.mDataFieldB2.value}; break; default: params += {zero, zero}; @@ -85,6 +85,7 @@ _data.mDataFieldS2 .value = 0; _data.mDataFieldF2 .value = 0; _data.mDataFieldB2 .value = 0; + if (GetValue(vByteArray, index, _data.mAlarmID )) if (GetValue(vByteArray, index, _data.mFieldDescriptor1 )) { @@ -119,8 +120,8 @@ if (GetValue(vByteArray, index, _data.mFieldDescriptor2 )) { - Gui::GuiAlarmDataTypes field1Type = static_cast(_data.mFieldDescriptor2.value); - switch (field1Type) { + Gui::GuiAlarmDataTypes field2Type = static_cast(_data.mFieldDescriptor2.value); + switch (field2Type) { case Gui::GuiAlarmDataTypes::ALARM_DATA_TYPE_NONE : return true; Index: sources/model/settings/MBluetooth.cpp =================================================================== diff -u --- sources/model/settings/MBluetooth.cpp (revision 0) +++ sources/model/settings/MBluetooth.cpp (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,38 @@ +/*! + * + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright + * 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 MBluetooth.cpp + * \author (last) Behrouz NematiPour + * \date (last) 23-Aug-2021 + * \author (original) Behrouz NematiPour + * \date (original) 23-Aug-2021 + * + */ + +#include "MBluetooth.h" + +using namespace Model; + +MBluetooth::MBluetooth( + InterfaceStates vState , + QString vDeviceAddr , + QString vDeviceName , + QString vDevicePin , + quint8 vDevicePair , + qint16 vError , + bool vValid , + QString vUUID ) + : state (vState ) + , deviceAddr (vDeviceAddr ) + , deviceName (vDeviceName ) + , devicePin (vDevicePin ) + , devicePair (vDevicePair ) + , error (vError ) + , valid (vValid ) + , uuid (vUUID ) +{} + Index: sources/model/settings/MBluetooth.h =================================================================== diff -u --- sources/model/settings/MBluetooth.h (revision 0) +++ sources/model/settings/MBluetooth.h (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,92 @@ +/*! + * + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright + * 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 MBluetooth.h + * \author (last) Behrouz NematiPour + * \date (last) 23-Aug-2021 + * \author (original) Behrouz NematiPour + * \date (original) 23-Aug-2021 + * + */ +#pragma once + +// Qt +#include +#include + +// Project +#include "main.h" // Doxygen : do not remove + +// namespace +namespace Model { + +class MBluetooth +{ + Q_GADGET + +public: + enum InterfaceStates { + eIS_Idle , + + eIS_Local_Connect , + eIS_Local_Error_Invalid , + eIS_Local_Error_Off , + eIS_Local_Error_IO , + eIS_Local_Error_Unknown , + eIS_Local_Disconnect , + + eIS_Scan_Start , + eIS_Scan_Reject , + eIS_Scan_NotFound , + eIS_Scan_Discover , + eIS_Scan_Found , + eIS_Scan_Detail , + eIS_Scan_Stop , + eIS_Scan_Done , + + eIS_Pair_Start , + eIS_Pair_Error , + eIS_Pair_PinCode , + eIS_Pair_Confirm , + eIS_Pair_Done , + + eIS_Device_Init , + eIS_Device_Start , + eIS_Device_Connect , + eIS_Device_Error_Init , + eIS_Device_Error , + eIS_Device_Done , + eIS_Device_Disconnect , + + + }; + Q_ENUM(InterfaceStates) + + InterfaceStates state ; + QString deviceAddr ; + QString deviceName ; + QString devicePin ; + quint8 devicePair ; + qint16 error ; + bool valid ; + QString uuid ; + + MBluetooth( + InterfaceStates vState = eIS_Idle, + QString vDeviceAddr = "", + QString vDeviceName = "", + QString vDevicePin = "", + quint8 vDevicePair = 0, + qint16 vError = 0, + bool vValid = true, + QString vUUID = "" + ); +}; + +} + +typedef Model::MBluetooth BluetoothData; Index: sources/view/VView.h =================================================================== diff -u -rebc82b5efe26c1081606fab06a1c99bb4f9c0098 -r2dd767833cf0cf706c457951c2d78e7e20aff768 --- sources/view/VView.h (.../VView.h) (revision ebc82b5efe26c1081606fab06a1c99bb4f9c0098) +++ sources/view/VView.h (.../VView.h) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -113,6 +113,7 @@ REGISTER_TYPE( VDateTime ) \ REGISTER_TYPE( VNetworkModel ) \ REGISTER_TYPE( VAdjustmentAlarmVolume ) \ + REGISTER_TYPE( VBluetooth ) \ /* Alarm */ \ REGISTER_TYPE( VAlarmStatus ) \ REGISTER_TYPE( VAlarmActiveList ) \ Index: sources/view/settings/VBluetooth.cpp =================================================================== diff -u --- sources/view/settings/VBluetooth.cpp (revision 0) +++ sources/view/settings/VBluetooth.cpp (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,114 @@ +/*! + * + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright + * 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 VBluetooth.cpp + * \author (last) Behrouz NematiPour + * \date (last) 8/23/2021 + * \author (original) Behrouz NematiPour + * \date (original) 8/23/2021 + * + */ +#include "VBluetooth.h" + +// Qt + +// Project +#include "GuiController.h" +#include "MBluetooth.h" + +VIEW_DEF_CLASS(VBluetooth) + +using namespace Bluetooth; +using namespace Model; + +/*! + * \brief VBluetooth::initConnections + * Makes the necessary connections. Called inside VIEW_DEF_CLASS + */ +void View::VBluetooth::initConnections() +{ + ACTION_VIEW_CONNECTION(AdjustSerialNumberHDResponseData); + connect(&_BluetoothInterface, &BluetoothInterface::didStateChange, + this , &VBluetooth::onStateChange ); +} + +void View::VBluetooth::onActionReceive(const AdjustSerialNumberHDResponseData &vData) +{ + LOG_EVENT( QString() + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + vData.mSerialNumber); + _BluetoothInterface.doScan(); +} + +void View::VBluetooth::onStateChange(const Model::MBluetooth &vData) +{ + scanInProgress( ! ( vData.state == MBluetooth::eIS_Idle || + vData.state == MBluetooth::eIS_Device_Disconnect || + vData.state == MBluetooth::eIS_Device_Error || + vData.state == MBluetooth::eIS_Device_Error_Init || + vData.state == MBluetooth::eIS_Scan_NotFound || + vData.state == MBluetooth::eIS_Local_Disconnect )); + + switch (vData.state) { + // The device name is not always available and the interface may be in investigation. + case MBluetooth::eIS_Scan_Found : + case MBluetooth::eIS_Scan_NotFound : + case MBluetooth::eIS_Scan_Discover : + deviceAddr (vData.deviceAddr ); + deviceName (vData.deviceName ); + devicePair (vData.devicePair ); + break; + default: + break; + } + + error (vData.error ); + devicePin (vData.devicePin ); + + QString message; + switch (vData.state) { + case MBluetooth::eIS_Idle : message = "" ; break; + + case MBluetooth::eIS_Local_Error_Invalid : message = tr("No Valid Bluetooth Adapter" ); 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_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_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_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; + } + + notification(message); + message = QString::number(_error) + " " + _deviceAddr + " " + QString::number(_devicePair) + " " + message + " " + _deviceName; + qDebug().noquote().nospace() << message.trimmed(); +} + +void View::VBluetooth::doScan() +{ + _BluetoothInterface.doScan(); +} Index: sources/view/settings/VBluetooth.h =================================================================== diff -u --- sources/view/settings/VBluetooth.h (revision 0) +++ sources/view/settings/VBluetooth.h (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) @@ -0,0 +1,64 @@ +/*! + * + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright + * 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 VBluetooth.h + * \author (last) Behrouz NematiPour + * \date (last) 8/23/2021 + * \author (original) Behrouz NematiPour + * \date (original) 8/23/2021 + * + */ +#pragma once + +// Qt +#include + +// Project +#include "main.h" // Doxygen : do not remove +#include "VView.h" +#include "MAdjustHDSerialNumberResponse.h" +#include "BluetoothInterface.h" + +// forward declarations +class tst_views; + +namespace View { + +/*! + * \brief The VBluetooth class + * \details View for BluetoothInterface. + */ +class VBluetooth : public QObject { + Q_OBJECT + + // friends + friend class ::tst_views; + + PROPERTY(QString , notification , "" ) + + PROPERTY(bool , scanInProgress , false ) + PROPERTY(QString , deviceName , "" ) + PROPERTY(QString , deviceAddr , "" ) + PROPERTY(QString , devicePin , "" ) + PROPERTY(quint8 , devicePair , 0 ) + PROPERTY(qint16 , error , 0 ) + + + VIEW_DEC_CLASS(VBluetooth) + VIEW_DEC_SLOT (AdjustSerialNumberHDResponseData) + +signals: + +private slots: + void onStateChange(const Model::MBluetooth &vData); + +public slots: + void doScan(); + + +}; +}