Index: denali.pro.user =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- denali.pro.user (.../denali.pro.user) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ denali.pro.user (.../denali.pro.user) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -1,6 +1,6 @@ - + EnvironmentId @@ -1481,7 +1481,7 @@ denali Qt4ProjectManager.Qt4RunConfiguration:/home/denali/Projects/application/denali.pro - --disable-timeout --logOut + --disable-timeout 3768 false true Index: en_US.udic =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- en_US.udic (.../en_US.udic) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ en_US.udic (.../en_US.udic) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -171,3 +171,5 @@ Omron BLESmart BLE +uuid +Addr Index: scripts/run.sh =================================================================== diff -u -rdaad774fa7aece882a72d6e579a7cb87988fd6a5 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- scripts/run.sh (.../run.sh) (revision daad774fa7aece882a72d6e579a7cb87988fd6a5) +++ scripts/run.sh (.../run.sh) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -33,6 +33,8 @@ POSTMSG_SDCARD="SD-CARD passed" POSTMSG_TOUCH="Touch passed" POSTMSG_RTC="RTC passed" +POSTMSG_BLUETOOTH="WiFi passed" +POSTMSG_BLUETOOTH="Bluetooth passed" # cleanup the POST log file @@ -121,6 +123,9 @@ # setup bluetooth /usr/share/silex-uart/silex-uart.sh start > $HOME/filesystem.out 2> $HOME/filesystem.err hciconfig hci0 up +if [ $? -eq 0 ]; then + echo $POSTMSG_BLUETOOTH >> $POSTLOG +fi # setup wifi Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -1,4 +1,4 @@ -/*! + /*! * \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 @@ -21,6 +21,7 @@ // Project #include "Logger.h" +#include "types.h" // namespace using namespace Bluetooth; @@ -95,12 +96,6 @@ void BluetoothInterface::initConnections() { // 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 , @@ -160,9 +155,10 @@ // ~~~~~~~~~~~ Local #define NOTIFY_LOCAL_INIT notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Init , \ _local->address().toString() , \ - _local->name() )); + _local->name(),0,1 )); + #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 notifyStateChange(MBluetooth(MBluetooth::eIS_Local_Error )); #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 )); @@ -175,51 +171,77 @@ #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 ); + vInfo.address().toString() , \ + vInfo.name(), "" , \ + _local->pairingStatus(vInfo.address()) , \ + 0 , \ + vInfo.isValid() , \ + vInfo.deviceUuid().toString() )); +#define NOTIFY_SCAN_FOUND notifyStateChange(MBluetooth(MBluetooth::eIS_Scan_Found , \ + _temp.address().toString() , \ + _temp.name(), "" , \ + _local->pairingStatus(_temp.address()) , \ + 0 , \ + _temp.isValid() , \ + _temp.deviceUuid().toString() )); #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() )); + _device->remoteAddress().toString() , \ + _device->remoteName() )); #define NOTIFY_DEVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Start , \ - _info.address().toString() , \ - _info.name() )); + _device->remoteAddress().toString() , \ + _device->remoteName() )); #define NOTIFY_DEVICE_CONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Connect , \ - _info.address().toString() , \ - _info.name() )); + _device->remoteAddress().toString() , \ + _device->remoteName() )); #define NOTIFY_DEVICE_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Done , \ - _info.address().toString() , \ - _info.name() )); + _device->remoteAddress().toString() , \ + _device->remoteName() )); #define NOTIFY_DEVICE_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Error , \ - _info.address().toString() , \ - _info.name() , \ - "",0, vError, false )); + _device->remoteAddress().toString() , \ + _device->remoteName() , \ + "",0, vError, false )); #define NOTIFY_DEVICE_DISCONNECT notifyStateChange(MBluetooth(MBluetooth::eIS_Device_Disconnect , \ - _info.address().toString() , \ - _info.name() )); + _device->remoteAddress().toString() , \ + _device->remoteName() )); #define NOTIFY_SERVICE_START notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Start )); +#define NOTIFY_SERVICE_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Discover )); +#define NOTIFY_SERVICE_DETAILS(vS) notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail , \ + _device->remoteAddress().toString() , \ + _device->remoteName(), "" , \ + _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(), "" , \ + _local->pairingStatus(_device->remoteAddress()), vError, 0 , \ + service->serviceUuid().toString() , \ + service->serviceName() )); +#define NOTIFY_SERVICE_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Done )); + +#define NOTIFY_DETAILS_ERROR notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Error , \ + _device->remoteAddress().toString() , \ + _device->remoteName(), "" , \ + _local->pairingStatus(_device->remoteAddress()), vState, 0 , \ + service->serviceUuid().toString() , \ + service->serviceName() )); +#define NOTIFY_DETAILS_INVALID notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Invalid )); +#define NOTIFY_SERVICE_DETAILS_DONE notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Detail_Done , \ + _device->remoteAddress().toString() , \ + _device->remoteName(), "" , \ + _local->pairingStatus(_device->remoteAddress()), vState, 0 , \ + service->serviceUuid().toString() , \ + service->serviceName() )); + + /* #define NOTIFY_SERVICE_DISCOVER notifyStateChange(MBluetooth(MBluetooth::eIS_Service_Discover , \ _service->serviceUuid().toString() , \ @@ -237,13 +259,8 @@ void BluetoothInterface::onstart() { _local->powerOn(); - if (! _local->isValid() ) { - NOTIFY_LOCAL_ERROR_INVALID - return; - } - - resetDevice(); - + if ( ! isLocalValid() ) return; + quitDevice(); _agent->setLowEnergyDiscoveryTimeout(5000); NOTIFY_LOCAL_INIT NOTIFY_IDLE @@ -288,50 +305,13 @@ } /*! - * \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 -} - -/*! - * \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 -} - -/*! - * \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(); +void BluetoothInterface::onLocalError ( QBluetoothLocalDevice::Error /*vError*/ ) { + NOTIFY_LOCAL_ERROR + quitDevice(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -350,7 +330,7 @@ NOTIFY_SCAN_DISCOVER if (vInfo.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { if ( isDeviceSupported( vInfo.name() ) ) { - _info = QBluetoothDeviceInfo(vInfo.address(), vInfo.name(), QBluetoothDeviceInfo::HealthBloodPressureMonitor); + _temp = QBluetoothDeviceInfo(vInfo.address(), vInfo.name(), QBluetoothDeviceInfo::HealthBloodPressureMonitor); NOTIFY_SCAN_FOUND if (_agent->isActive()) _agent->stop(); @@ -400,8 +380,9 @@ * \brief BluetoothInterface::connectToDevice * \return false if * the local Bluetooth device _local is not valid - * the device info _info 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::connectToDevice() { @@ -415,103 +396,250 @@ return true; } +/*! + * \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() +{ + 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() { NOTIFY_DEVICE_CONNECT - _device->discoverServices(); - NOTIFY_SERVICE_START + discoverServices(); } +/*! + * \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. + */ void BluetoothInterface::onDeviceDisconnect() { NOTIFY_DEVICE_DISCONNECT } -void BluetoothInterface::onDeviceError(QLowEnergyController::Error vError) +void BluetoothInterface::onDeviceDiscoverService(const QBluetoothUuid &vService) { - NOTIFY_DEVICE_ERROR + initServices(vService); } -void BluetoothInterface::onDeviceStateChanged(QLowEnergyController::ControllerState vState) +void BluetoothInterface::onDeviceDiscoverFinish() { - // qDebug() << "Device State Changed" << vState; + NOTIFY_SERVICE_DISCOVER + discoverServicesDetails(); } -void BluetoothInterface::onDeviceConnectionUpdated(const QLowEnergyConnectionParameters &/*vParameters*/) +void BluetoothInterface::discoverServicesDetails() { - // qDebug() << "Device Connection Changed"; + 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(); + } } -bool BluetoothInterface::initDevice() +/*! + * \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 ( _device ) { - _device->disconnectFromDevice(); - delete _device; - _device = nullptr; + NOTIFY_DEVICE_ERROR +} + +void BluetoothInterface::onServiceCharacteristicChanged(const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { + qDebug() << " ..... Service Charc C:" << vCharacteristic.name() << vValue; + if (vCharacteristic.uuid() == QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)) + { + parseMeasurement(vValue); } - _device = QLowEnergyController::createCentral(_info, this); - if ( _device ) NOTIFY_DEVICE_INIT - else { NOTIFY_DEVICE_INIT_ERROR - return false; - } +} +void BluetoothInterface::parseMeasurement(const QByteArray &byteArray) +{ + MeasurementData measurement; +// const uint8_t *d = reinterpret_cast(byteArray.constData()); + const uchar *d = reinterpret_cast(byteArray.constData()); + + measurement.flags = *d; + measurement.systolic = d[1]; + measurement.diastolic = d[3]; + measurement.mean_arterial_pressure_value= d[5]; + measurement.year = d[7]; + measurement.month = d[9]; + measurement.day = d[10]; + measurement.hour = d[11]; + measurement.minute = d[12]; + measurement.second = d[13]; + measurement.pulse_rate = d[14]; + measurement.user_id = d[16]; + measurement.measurement_status = d[17]; + + qDebug() << measurement.flags + << measurement.systolic + << measurement.diastolic + << measurement.mean_arterial_pressure_value + << measurement.year + << measurement.month + << measurement.day + << measurement.hour + << measurement.minute + << measurement.second + << measurement.pulse_rate + << measurement.user_id + << measurement.measurement_status ; + // emit didReceiveBPMeasurement(measurement); +} + +/*! + * \brief BluetoothInterface::initConnectionsDevice + * \details sets up the remote Bluetooth device _device connections. + */ +void BluetoothInterface::initConnectionsDevice() { // 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; + connect( _device, SIGNAL(serviceDiscovered (const QBluetoothUuid &)), + this , SLOT(onDeviceDiscoverService(const QBluetoothUuid &))); + connect( _device, SIGNAL(discoveryFinished ()), + this , SLOT(onDeviceDiscoverFinish ())); +} + +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) { + QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_SERVICE_ERROR +} + +void BluetoothInterface::onServiceStateChanged(QLowEnergyService::ServiceState vState) { + QLowEnergyService *service = reinterpret_cast(sender()); + qDebug() << "Service State:" << service->serviceUuid() << service->serviceName() << vState; + switch (vState) { + case QLowEnergyService::InvalidService : + NOTIFY_DETAILS_ERROR + break; + + case QLowEnergyService::ServiceDiscovered : + NOTIFY_SERVICE_DETAILS_DONE + for ( auto const &detail: service->characteristics()) { + qDebug() << " ~~~~~ " << detail.name() << detail.uuid() << detail.value(); } - if (vService == QBluetoothUuid (QBluetoothUuid::CurrentTimeService )) { - if ( _serviceCurrentTime ) - delete _serviceCurrentTime ; - _serviceCurrentTime = _device->createServiceObject(vService, this); - qDebug() << " ~~~~~ TDt Service Found" << vService; - return; + if ( service->serviceUuid() == QBluetoothUuid (QBluetoothUuid::BloodPressure)) { + // blood pressure measurements + const QLowEnergyCharacteristic detailBPMeas = service->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)); + QLowEnergyDescriptor configBPMeas = detailBPMeas.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + if (configBPMeas.isValid()) service->writeDescriptor(configBPMeas, QByteArray::fromHex("0100")); + + // blood pressure feature + const QLowEnergyCharacteristic detailBPFeat = service->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureFeature)); + if (!detailBPFeat.isValid()) { + qDebug() << "Blood pressure feature not found."; + return; + } + service->readCharacteristic(detailBPFeat); + _connectionActive = true; } - 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; - } - }); - connect(_device, &QLowEnergyController::discoveryFinished, [=](){ - // _serviceInformation->discoverDetails(); - NOTIFY_DEVICE_DONE - _device->disconnectFromDevice(); - }); + break; + + default: + break; + + } +} +/*! + * \brief BluetoothInterface::initDevice + * \return Initializes the device by making a new device and initializes its connections + */ +bool BluetoothInterface::initDevice() +{ + if ( ! makeDevice() ) return false; + initConnectionsDevice(); return true; } /*! + * \brief BluetoothInterface::makeDevice + * \details Makes a device by disconnect and delete the old one and create a new one, and + * validates if the device was created successfully, and + * notifies the observers (view: VBluetooth) that the state is + * MBluetooth::eIS_Device_Init if succeeded, or the state is + * MBluetooth::eIS_Device_Error_Init if failed. + * \return returns true if the remote Bluetooth device _device is created successfully, false otherwise. + */ +bool BluetoothInterface::makeDevice() +{ + quitDevice(); + _device = QLowEnergyController::createCentral(_temp, this); + _temp = QBluetoothDeviceInfo(); + if ( _device ) NOTIFY_DEVICE_INIT + else { NOTIFY_DEVICE_INIT_ERROR + return false; + } + return true; +} + +/*! * \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); } @@ -522,7 +650,10 @@ */ void BluetoothInterface::timerEvent(QTimerEvent *) { - if ( _bpRead ) { } + if ( _connectionActive ) { + if ( _device ) + _device->connectToDevice(); + } } /*! @@ -553,15 +684,15 @@ /*! * \brief BluetoothInterface::isInfoValid - * \details checks if the device info _info is valid. + * \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 _info is set to a default QBluetoothDeviceInfo which is invalid by default, + * \note the device info _temp 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() ) { + if ( ! _temp.isValid() ) { NOTIFY_SCAN_NOTFOUND // not a valid device found return false; } @@ -581,15 +712,92 @@ 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) +{ + if ( ! vDetail.isValid() ) { + NOTIFY_DETAILS_INVALID + return false; + } + return true; +} + /*! - * \brief BluetoothInterface::resetDevice - * \details resets the remote device _device and the device info _info. + * \brief BluetoothInterface::quitDevice + * \details quits and deletes the old remote device _device and the device info _temp. */ -void BluetoothInterface::resetDevice() { - _info = QBluetoothDeviceInfo(); // reset the found info +void BluetoothInterface::quitDevice() { + _connectionActive = false; if ( _device ) { + NOTIFY_DEVICE_DONE + quitServices(); // it seems safe to delete all the services when the device is deleted because the current discovered service may not apply to the next device. _device->disconnectFromDevice(); delete _device; _device = nullptr; } } + +/*! + * \brief BluetoothInterface::initService + * \details + */ +void BluetoothInterface::initServices(const QBluetoothUuid &vService) +{ + makeServices(vService); +} + +void BluetoothInterface::makeServices(const QBluetoothUuid &vService) +{ + if (vService == QBluetoothUuid (QBluetoothUuid::DeviceInformation )) { + _serviceDeviceInformation = _device->createServiceObject(vService, this); + initConnectionsService (_serviceDeviceInformation ); + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::CurrentTimeService )) { + _serviceCurrentTime = _device->createServiceObject(vService, this); + initConnectionsService (_serviceCurrentTime ); + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::BloodPressure )) { + _serviceBloodPressure = _device->createServiceObject(vService, this); + initConnectionsService (_serviceBloodPressure ); + return; + } + if (vService == QBluetoothUuid (QBluetoothUuid::BatteryService )) { + _serviceBattery = _device->createServiceObject(vService, this); + initConnectionsService (_serviceBattery ); + return; + } +} + +/*! + * \brief BluetoothInterface::quitServices + * \details quits and deletes the old remote services. + */ +void BluetoothInterface::quitServices() { + NOTIFY_SERVICE_DONE + if ( _serviceDeviceInformation ) { + delete _serviceDeviceInformation ; + _serviceDeviceInformation = nullptr; + } + if ( _serviceCurrentTime ) { + delete _serviceCurrentTime ; + _serviceCurrentTime = nullptr; + } + if ( _serviceBloodPressure ) { + delete _serviceBloodPressure ; + _serviceBloodPressure = nullptr; + } + if ( _serviceBattery ) { + delete _serviceBattery ; + _serviceBattery = nullptr; + } +} Index: sources/bluetooth/BluetoothInterface.h =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ sources/bluetooth/BluetoothInterface.h (.../BluetoothInterface.h) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -58,17 +58,34 @@ QBluetoothDeviceDiscoveryAgent *_agent = nullptr ; QLowEnergyController *_device = nullptr ; + // QList _services ; + QLowEnergyService *_serviceDeviceInformation = nullptr ; QLowEnergyService *_serviceCurrentTime = nullptr ; QLowEnergyService *_serviceBloodPressure = nullptr ; QLowEnergyService *_serviceBattery = nullptr ; - QBluetoothDeviceInfo _info ; - MBluetooth _model ; - MBluetooth::InterfaceStates _state ; + QBluetoothDeviceInfo _temp ; - bool _bpRead = false ; + bool _connectionActive = false ; const quint16 _interval = 1000 ; // the interface timer base interval in mSec +public: + // 19 total bytes + struct MeasurementData { + uint8_t flags; // 1 byte + uint16_t systolic; // 2 bytes + uint16_t diastolic; // 2 bytes + uint16_t mean_arterial_pressure_value; // 2 bytes + uint16_t year; // 2 bytes + uint8_t month; // 1 byte + uint8_t day; // 1 byte + uint8_t hour; // 1 byte + uint8_t minute; // 1 byte + uint8_t second; // 1 byte + uint16_t pulse_rate; // 2 bytes + uint8_t user_id; // 1 byte + uint16_t measurement_status; // 2 bytes + }; protected: void timerEvent(QTimerEvent *event) override; @@ -81,9 +98,6 @@ void quit(); // 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 ); @@ -97,32 +111,49 @@ // Device Slots void onDeviceConnect ( ); void onDeviceDisconnect ( ); + void onDeviceDiscoverService (const QBluetoothUuid &vService); + void onDeviceDiscoverFinish ( ); void onDeviceError ( QLowEnergyController::Error vError ); - void onDeviceStateChanged ( QLowEnergyController::ControllerState vState ); - void onDeviceConnectionUpdated (const QLowEnergyConnectionParameters & vParameters ); + + void onServiceCharacteristicChanged (const QLowEnergyCharacteristic &vCharacteristic , const QByteArray &vValue ); + void onServiceCharacteristicRead (const QLowEnergyCharacteristic &vCharacteristic , const QByteArray &vValue ) { qDebug() << " ..... Service Charc R:" << vCharacteristic .name() << vValue; } + void onServiceCharacteristicWritten (const QLowEnergyCharacteristic &vCharacteristic , const QByteArray &vValue ) { qDebug() << " ..... Service Charc W:" << vCharacteristic .name() << vValue; } + void onServiceDescriptorRead (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue ) { qDebug() << " ..... Service Descr R:" << vDescriptor .name() << vValue; } + void onServiceDescriptorWritten (const QLowEnergyDescriptor &vDescriptor , const QByteArray &vValue ) { qDebug() << " ..... Service Descr W:" << vDescriptor .name() << vValue; } + + void onServiceError ( QLowEnergyService::ServiceError vError ); + void onServiceStateChanged ( QLowEnergyService::ServiceState vState ); + private: - void initConnections(); + void initConnections (); + void initConnectionsDevice (); + void initConnectionsService (QLowEnergyService *vService); void initThread(QThread &vThread); void quitThread(); - bool discoverStart (); - bool discoverFinish (); + bool initDevice (); + bool makeDevice (); + void quitDevice (); - bool isLocalValid (); - bool isInfoValid (); - bool isDeviceValid (); - bool isDeviceSupported( const QString &vName ); + void initServices (const QBluetoothUuid &vService); + void makeServices (const QBluetoothUuid &vService); + void quitServices (); - bool initDevice (); - void resetDevice (); + bool isLocalValid (); + bool isInfoValid (); + bool isDeviceValid (); + // bool isServiceValid (QLowEnergyService *vService); + bool isDetailValid (const QLowEnergyCharacteristic &vDetail); + bool isDeviceSupported ( const QString &vName ); - bool connectToDevice(); - bool discoverServices(); + bool connectToDevice (); + void discoverServices (); + void discoverServicesDetails(); - void notifyStateChange(const BluetoothData &vData); + void parseMeasurement (const QByteArray &byteArray); signals: void didStateChange(const BluetoothData &vData); Index: sources/model/settings/MBluetooth.cpp =================================================================== diff -u -r2dd767833cf0cf706c457951c2d78e7e20aff768 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- sources/model/settings/MBluetooth.cpp (.../MBluetooth.cpp) (revision 2dd767833cf0cf706c457951c2d78e7e20aff768) +++ sources/model/settings/MBluetooth.cpp (.../MBluetooth.cpp) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -18,21 +18,36 @@ 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 ) -{} + InterfaceStates vState , + QString vDeviceAddr , + QString vDeviceName , + QString vDevicePin , + quint8 vDevicePair , + qint16 vError , + bool vValid , + QString vServiceAddr , + QString vServiceName ): + state (vState ), + deviceAddr (vDeviceAddr ), + deviceName (vDeviceName ), + devicePin (vDevicePin ), + devicePair (vDevicePair ), + error (vError ), + valid (vValid ), + serviceAddr (vServiceAddr ), + serviceName (vServiceName ){ +} +MBluetooth::MBluetooth( + InterfaceStates vState , + QString vLocalAddr , + QString vLocalName , + qint16 vError , + bool vValid ): + state (vState ), + localAddr (vLocalAddr ), + localName (vLocalName ), + error (vError ), + valid (vValid ){ +} + Index: sources/model/settings/MBluetooth.h =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ sources/model/settings/MBluetooth.h (.../MBluetooth.h) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -30,71 +30,82 @@ public: enum InterfaceStates { - eIS_Idle , + eIS_Idle , - eIS_Local_Init , - eIS_Local_Connect , - eIS_Local_Error_Invalid , - eIS_Local_Error_Off , - eIS_Local_Error_IO , - eIS_Local_Error_Unknown , - eIS_Local_Disconnect , + eIS_Local_Init , + eIS_Local_Connect , + eIS_Local_Error_Invalid , + eIS_Local_Error_Off , + eIS_Local_Error_IO , + eIS_Local_Error , + 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_Scan_Start , + eIS_Scan_Reject , + eIS_Scan_NotFound , + eIS_Scan_Discover , + eIS_Scan_Found , + eIS_Scan_Stop , + eIS_Scan_Done , - eIS_Pair_Start , - eIS_Pair_Error , - eIS_Pair_PinCode , - eIS_Pair_Confirm , - eIS_Pair_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_State , - // eIS_Device_Update , - eIS_Device_Done , - eIS_Device_Disconnect , + eIS_Device_Init , + eIS_Device_Start , + eIS_Device_Connect , + eIS_Device_Error_Init , + eIS_Device_Error , + eIS_Device_Done , + eIS_Device_Disconnect , - eIS_Service_Start , - eIS_Service_Error , - eIS_Service_Discover , - eIS_Service_Done , + eIS_Service_Start , + eIS_Service_Error , + eIS_Service_Discover , + eIS_Service_Detail , + eIS_Service_Detail_Invalid , + eIS_Service_Detail_Error , + eIS_Service_Detail_Done , + eIS_Service_Done , - eIS_Close , + eIS_Close , }; Q_ENUM(InterfaceStates) - InterfaceStates state ; - QString localAddr ; - QString localName ; - QString deviceAddr ; - QString deviceName ; - QString devicePin ; - quint8 devicePair ; - qint16 error ; - bool valid ; - QString uuid ; + InterfaceStates state ; + QString localAddr = ""; + QString localName = ""; + QString deviceAddr = ""; + QString deviceName = ""; + QString devicePin = ""; + quint8 devicePair = 0; + qint16 error = 0; + bool valid = 1; + QString serviceAddr = ""; + QString serviceName = ""; MBluetooth( - InterfaceStates vState = eIS_Idle, - QString vDeviceAddr = "", - QString vDeviceName = "", - QString vDevicePin = "", - quint8 vDevicePair = 0, - qint16 vError = 0, - bool vValid = true, - QString vUUID = "" + InterfaceStates vState = eIS_Idle, + QString vDeviceAddr = "", + QString vDeviceName = "", + QString vDevicePin = "", + quint8 vDevicePair = 0, + qint16 vError = 0, + bool vValid = 1, + QString vServiceAddr = "", + QString vServiceName = "" ); + MBluetooth( + InterfaceStates vState , + QString vLocalAddr , + QString vLocalName , + qint16 vError , + bool vValid + ); + }; } Index: sources/view/settings/VBluetooth.cpp =================================================================== diff -u -r028cb1403e8fcb2d2e9ab2aa1562f660124015b1 -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 --- sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 028cb1403e8fcb2d2e9ab2aa1562f660124015b1) +++ sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) @@ -79,13 +79,13 @@ case MBluetooth::eIS_Close : message = tr("BluetoothInterface Closed" ); break; // Used BluetoothInterface to be consistent with the - case MBluetooth::eIS_Local_Init : message = tr("The Bluetooth Adapter Is Ready" ); break; + case MBluetooth::eIS_Local_Init : message = tr("The Bluetooth Adapter Is Ready %1" ).arg(_localAddr ); 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_Local_Error : 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; @@ -94,7 +94,6 @@ 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("Device Initializing ..." ); break; case MBluetooth::eIS_Device_Error_Init : message = tr("Device Initialization Error" ); break; @@ -105,8 +104,12 @@ 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 Scanning Error" ); break; + case MBluetooth::eIS_Service_Error : message = tr("Service Error: %1" ).arg(_error ); 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 Scanning Finished" ); break; case MBluetooth::eIS_Pair_Start : message = tr("Pairing ..." ); break; @@ -121,7 +124,7 @@ notification(message); // Console Log - message = QString::number(_error) + " " + _deviceAddr + " " + QString::number(_devicePair) + " " + message + " " + _deviceName; + message = _deviceAddr + " " + message; message = message.trimmed().simplified(); qDebug().noquote().nospace() << message;