Index: denali.pro.user =================================================================== diff -u -rc3a1e077ddeba65709084f9af5dd756741db8b4f -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- denali.pro.user (.../denali.pro.user) (revision c3a1e077ddeba65709084f9af5dd756741db8b4f) +++ denali.pro.user (.../denali.pro.user) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -1,6 +1,6 @@ - + EnvironmentId Index: sources/bluetooth/BLEScanner.cpp =================================================================== diff -u -r7249125bb71e6fab4139590ee777c64ece9cf3be -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/bluetooth/BLEScanner.cpp (.../BLEScanner.cpp) (revision 7249125bb71e6fab4139590ee777c64ece9cf3be) +++ sources/bluetooth/BLEScanner.cpp (.../BLEScanner.cpp) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -12,7 +12,9 @@ BLEScanner::BLEScanner(QObject *parent) : QObject(parent) { discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this); - macAddress = "EC:21:E5:F4:BC:C9"; // for testing only + + timer = new QTimer(this); + timer->setInterval(1000); // SRSUI 6 } void BLEScanner::onInitConnections() @@ -172,6 +174,9 @@ else if (uuid.toString() == omronBatteryLevelServiceName) { omronBatteryLevelService = service; } + else if (uuid.toString() == omronDeviceInformationServiceName) { + omronDeviceInformationService = service; + } service->discoverDetails(); @@ -180,12 +185,41 @@ foreach (const QLowEnergyCharacteristic &c, service->characteristics()) { qDebug() << "----> Characteristic: " << c.name() << " uuid: " << c.uuid(); + } +} +/*! + * \brief BLEScanner::onRequestDeviceSerialNumber + * Sends a request for the device's serial number + */ +void BLEScanner::onRequestDeviceSerialNumber() +{ + // read device serial number + const QLowEnergyCharacteristic c = omronDeviceInformationService->characteristic( + QBluetoothUuid(QBluetoothUuid::SerialNumberString) + ); + if (!c.isValid()) { + qDebug() << "Cannot read device information."; + disconnect(timer, SIGNAL(timeout()), + this, SLOT(onRequestDeviceInformation())); + connect(timer, SIGNAL(timeout()), + this, SLOT(onRetryConnectToDevice())); + return; } + omronDeviceInformationService->readCharacteristic(c); +} - +/*! + * \brief BLEScanner::onRequestDeviceInformation + * Requests BP monitor device information + */ +void BLEScanner::onRequestDeviceInformation() +{ + qDebug() << __FUNCTION__; +// onRequestDeviceInformation(); } + /*! * \brief BLEScanner::requestBPMeasurement * Requests BP Measurement data. @@ -343,13 +377,15 @@ void BLEScanner::onConfirmedDescriptorWrite(const QLowEnergyDescriptor &desc, const QByteArray &byteArray) { qDebug() << "Confirmed descriptor write: " << byteArray; + if (desc.isValid() && desc == desc && byteArray == QByteArray::fromHex("0000")) { //disabled notifications -> assume disconnect qDebug() << "deleting omron blood pressure service"; lowEnergyController->disconnectFromDevice(); delete omronBloodPressureService; omronBloodPressureService = nullptr; } + emit didConnectToDevice(selectedDeviceInfo); } @@ -414,6 +450,14 @@ qDebug() << __FUNCTION__; lowEnergyController->discoverServices(); + + disconnect(timer, SIGNAL(timeout()), + this, SLOT(onRetryConnectToDevice())); + connect(timer, SIGNAL(timeout()), + this, SLOT(onRequestDeviceInformation())); + + if (!timer->isActive()) + timer->start(); } /*! @@ -423,9 +467,33 @@ void BLEScanner::onDeviceDisconnected() { qDebug() << __FUNCTION__; + emit didDisconnectFromDevice(selectedDeviceInfo); } /*! + * \brief BLEScanner::onControllerStateChanged + * Slot called when the low energy controller state changes + * \param state - the new state of the low energy controller + */ +void BLEScanner::onControllerStateChanged(const QLowEnergyController::ControllerState &state) +{ + qDebug() << __FUNCTION__ << state; + switch (state) { + case (QLowEnergyController::ClosingState): + emit didDisconnectFromDevice(selectedDeviceInfo); + break; + case (QLowEnergyController::UnconnectedState): + case (QLowEnergyController::ConnectingState): + case (QLowEnergyController::ConnectedState): + case (QLowEnergyController::DiscoveringState): + case (QLowEnergyController::DiscoveredState): + case (QLowEnergyController::AdvertisingState): + default: + break; + } +} + +/*! * \brief BLEScanner::connectToDevice * Creates the low energy controller object * Configures the low energy controller signals @@ -453,6 +521,15 @@ connect(lowEnergyController, SIGNAL(disconnected()), this, SLOT(onDeviceDisconnected())); + connect(lowEnergyController, SIGNAL(stateChanged(QLowEnergyController::ControllerState)), + this, SLOT(onControllerStateChanged(QLowEnergyController::ControllerState))); + emit didStartConnectingToDevice(); lowEnergyController->connectToDevice(); } + +void BLEScanner::onRetryConnectToDevice() +{ + qDebug() << __FUNCTION__ << "Retrying to connect to device..."; + lowEnergyController->connectToDevice(); +} Index: sources/bluetooth/BLEScanner.h =================================================================== diff -u -r7249125bb71e6fab4139590ee777c64ece9cf3be -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/bluetooth/BLEScanner.h (.../BLEScanner.h) (revision 7249125bb71e6fab4139590ee777c64ece9cf3be) +++ sources/bluetooth/BLEScanner.h (.../BLEScanner.h) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -59,18 +59,22 @@ QLowEnergyController *lowEnergyController; QList services; - QLowEnergyService* omronUnknownService = nullptr; - QLowEnergyService* omronCurrentTimeService = nullptr; - QLowEnergyService* omronBatteryLevelService = nullptr; - QLowEnergyService* omronBloodPressureService = nullptr; + QLowEnergyService *omronUnknownService = nullptr; + QLowEnergyService *omronCurrentTimeService = nullptr; + QLowEnergyService *omronBatteryLevelService = nullptr; + QLowEnergyService *omronBloodPressureService = nullptr; + QLowEnergyService *omronDeviceInformationService = nullptr; + QLowEnergyDescriptor notificationDesc; QLowEnergyDescriptor readDesc; + QTimer *timer; - const QString omronCurrentTimeServiceName = QString("{00002a2b-0000-1000-8000-00805f9b34fb}"); - const QString omronBatteryLevelServiceName = QString("{0000180f-0000-1000-8000-00805f9b34fb}"); - const QString omronUnknownServiceName = QString("{ecbe3980-c9a2-11e1-b1bd-0002a5d5c51b}"); - const QString omronBloodPressureServiceName = QString("{00001810-0000-1000-8000-00805f9b34fb}"); - const QStringList omronDeviceNamesPrefixes = {"BP7000", "BLEsmart"}; + const QString omronCurrentTimeServiceName = QString("{00002a2b-0000-1000-8000-00805f9b34fb}"); + const QString omronBatteryLevelServiceName = QString("{0000180f-0000-1000-8000-00805f9b34fb}"); + const QString omronUnknownServiceName = QString("{ecbe3980-c9a2-11e1-b1bd-0002a5d5c51b}"); + const QString omronBloodPressureServiceName = QString("{00001810-0000-1000-8000-00805f9b34fb}"); + const QString omronDeviceInformationServiceName = QString("{0000180a-0000-1000-8000-00805f9b34fb}"); + const QStringList omronDeviceNamesPrefixes = {"BP7000", "BLEsmart"}; QStringList characteristicsToAcquireNotify; @@ -87,7 +91,9 @@ void didStartConnectingToDevice(); void didReceiveControllerError(const QLowEnergyController::Error &error); void didConnectToDevice(const QBluetoothDeviceInfo &deviceInfo); + void didDisconnectFromDevice(const QBluetoothDeviceInfo &deviceInfo); + public slots: bool doInit(); void doSelectDevice(const QString &addr); @@ -108,6 +114,7 @@ void onControllerError(const QLowEnergyController::Error &error); void onDeviceConnected(); void onDeviceDisconnected(); + void onControllerStateChanged(const QLowEnergyController::ControllerState &state); // service slots void onServiceStateChanged(const QLowEnergyService::ServiceState &serviceState); @@ -116,6 +123,9 @@ void onServiceCharacteristicsRead(const QLowEnergyCharacteristic &c,const QByteArray &byteArray); void onQuit(); + void onRequestDeviceInformation(); + void onRequestDeviceSerialNumber(); + void onRetryConnectToDevice(); }; #endif // BLESCANNER_H Index: sources/gui/qml/globals/Fonts.qml =================================================================== diff -u -r7249125bb71e6fab4139590ee777c64ece9cf3be -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/gui/qml/globals/Fonts.qml (.../Fonts.qml) (revision 7249125bb71e6fab4139590ee777c64ece9cf3be) +++ sources/gui/qml/globals/Fonts.qml (.../Fonts.qml) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -68,4 +68,5 @@ readonly property int crTreatmentFontSize : 30 readonly property int crTreatmentTableFontSize : 24 readonly property int bleTitleFontSize : 30 + readonly property int bleConnectedFontSize : 16 } Index: sources/gui/qml/pages/SettingsBluetooth.qml =================================================================== diff -u -r7249125bb71e6fab4139590ee777c64ece9cf3be -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/gui/qml/pages/SettingsBluetooth.qml (.../SettingsBluetooth.qml) (revision 7249125bb71e6fab4139590ee777c64ece9cf3be) +++ sources/gui/qml/pages/SettingsBluetooth.qml (.../SettingsBluetooth.qml) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -81,7 +81,7 @@ text: qsTr("My Devices") } - ListView { id: _paired_devices + ListView { id: _pairedDevices model: vBluetooth.pairedDevices anchors.top: _pairedDevicesLabel.bottom anchors.topMargin: Variables.settingsBLEListViewMargin @@ -103,7 +103,7 @@ animated: true Text { - id: _pairedDevice + id: _pairedDeviceName anchors.bottom: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter text: modelData.name @@ -118,6 +118,17 @@ color: Colors.textMain } + Text { + id: _isConnected + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.horizontalCenter: parent.horizontalCenter + anchors.leftMargin: 5 + text: modelData.connected ? "Paired, Connected" : "Paired, Not Connected" + color: Colors.textMain + font.pixelSize: Fonts.bleConnectedFontSize + } + onClicked: { vBluetooth.doSelectDevice(modelData.address) } @@ -132,7 +143,7 @@ font.pixelSize: Fonts.bleTitleFontSize color: Colors.textMain - text: qsTr("Devices") + text: qsTr("Other Devices") } ListView { id: _devices Index: sources/view/VBluetooth.cpp =================================================================== diff -u -rc3a1e077ddeba65709084f9af5dd756741db8b4f -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/view/VBluetooth.cpp (.../VBluetooth.cpp) (revision c3a1e077ddeba65709084f9af5dd756741db8b4f) +++ sources/view/VBluetooth.cpp (.../VBluetooth.cpp) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -28,6 +28,9 @@ connect(&_BLEScanner, SIGNAL(didConnectToDevice(QBluetoothDeviceInfo)), this, SLOT(onConnectedToDevice(QBluetoothDeviceInfo))); + connect(&_BLEScanner, SIGNAL(didDisconnectFromDevice(QBluetoothDeviceInfo)), + this, SLOT(onDisconnectedFromDevice(QBluetoothDeviceInfo))); + // outgoing connect(this, SIGNAL(didSelectDevice(const QString)), &_BLEScanner, SLOT(doSelectDevice(const QString))); @@ -158,7 +161,7 @@ return tr("No Error."); break; case QLowEnergyController::UnknownError: - return tr("Unknown Error."); + return tr("Unknown Error. Is device turned off?"); break; case QLowEnergyController::UnknownRemoteDeviceError: return tr("Unknown Remote Device Error."); @@ -205,20 +208,19 @@ */ bool VBluetooth::isDeviceAlreadyPaired(const QBluetoothDeviceInfo &deviceInfo) { - bool alreadyPaired = false; for (QObject *device : pairedDevices) { VBluetoothDeviceInfo *pairedDevice = static_cast(device); if (pairedDevice->getAddress() == deviceInfo.address().toString()) - alreadyPaired = true; + return true; } - return alreadyPaired; + return false; } /*! * \brief VBluetooth::removeFromDevices * Removes a device from the non-paired bluetooth devices list * Adds that devices to the non-paired bluetooth devices blacklist - * \param info - the bluetooth device info object to remove + * \param info - (VBluetoothDeviceInfo*) the bluetooth device info object to remove */ void VBluetooth::removeFromDevices(const VBluetoothDeviceInfo *info) { @@ -241,18 +243,58 @@ * \brief VBluetooth::onConnectedToDevice * Slot called when BLEScanner connects to a device. Moves a device * from the devices list to the my devices list - * \param deviceInfo - the device connected to + * \param deviceInfo - (QBluetoothDeviceInfo) the device connected to */ void VBluetooth::onConnectedToDevice(const QBluetoothDeviceInfo &deviceInfo) { VBluetoothDeviceInfo *info = new VBluetoothDeviceInfo(deviceInfo); + info->setConnected(true); bool alreadyPaired = isDeviceAlreadyPaired(deviceInfo); - if (!alreadyPaired) - { + if (alreadyPaired) { + setDeviceConnected(deviceInfo, true); + } else { pairedDevices.append(info); emit didPairedDevicesChanged(); removeFromDevices(info); } - onUpdateStatus(tr("Connected.")); + onUpdateStatus(tr("Paired, Connected.")); } + +/*! + * \brief VBluetooth::setDeviceConnected + * Ensures the device displays as connected + * \param deviceInfo - (QBluetoothDeviceInfo) contains the device information + * \param connected - (bool) true to set connected, false to set not connected + */ +void VBluetooth::setDeviceConnected(const QBluetoothDeviceInfo &deviceInfo, const bool &connected) +{ + if (isDeviceAlreadyPaired(deviceInfo)) { + for (QList::iterator iter = pairedDevices.begin(); iter != pairedDevices.end(); ++iter) + { + if (deviceInfo.address().toString() == ((VBluetoothDeviceInfo*)(*iter))->getAddress()) + ((VBluetoothDeviceInfo*)(*iter))->setConnected(connected); + } + emit didPairedDevicesChanged(); + } else { + for (QList::iterator iter = bleDevices.begin(); iter != bleDevices.end(); ++iter) + { + if (deviceInfo.address().toString() == ((VBluetoothDeviceInfo*)(*iter))->getAddress()) + ((VBluetoothDeviceInfo*)(*iter))->setConnected(connected); + } + emit didDevicesChanged(); + } +} + +/*! + * \brief VBluetooth::onDisconnectedFromDevice + * Slot called when the BLEScanner detects that a device disconnected. Updates + * the status of the device to Not Connected if is has already been paired + * \param deviceInfo - (QBluetoothDeviceInfo) contains the device information + */ +void VBluetooth::onDisconnectedFromDevice(const QBluetoothDeviceInfo &deviceInfo) +{ + setDeviceConnected(deviceInfo, false); + emit didPairedDevicesChanged(); + onUpdateStatus(tr("Paired, Not Connected.")); +} Index: sources/view/VBluetooth.h =================================================================== diff -u -r7249125bb71e6fab4139590ee777c64ece9cf3be -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/view/VBluetooth.h (.../VBluetooth.h) (revision 7249125bb71e6fab4139590ee777c64ece9cf3be) +++ sources/view/VBluetooth.h (.../VBluetooth.h) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -50,6 +50,7 @@ QString controllerErrorToString(QLowEnergyController::Error error); bool isDeviceAlreadyPaired(const QBluetoothDeviceInfo &deviceInfo); void removeFromDevices(const VBluetoothDeviceInfo *info); + void setDeviceConnected(const QBluetoothDeviceInfo &deviceInfo, const bool &connected); private slots: void onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error error); @@ -59,6 +60,7 @@ void onUpdateStatus(const QString &message); void onControllerError(QLowEnergyController::Error error); void onConnectedToDevice(const QBluetoothDeviceInfo &deviceInfo); + void onDisconnectedFromDevice(const QBluetoothDeviceInfo &deviceInfo); }; } #endif // VBLUETOOTH_H Index: sources/view/VBluetoothDeviceInfo.cpp =================================================================== diff -u -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/view/VBluetoothDeviceInfo.cpp (.../VBluetoothDeviceInfo.cpp) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) +++ sources/view/VBluetoothDeviceInfo.cpp (.../VBluetoothDeviceInfo.cpp) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -13,22 +13,9 @@ * Constructor for the VBluetoothDeviceInfo class * \param info - the device information */ -VBluetoothDeviceInfo::VBluetoothDeviceInfo(const QBluetoothDeviceInfo &info) -{ - device = info; -} +VBluetoothDeviceInfo::VBluetoothDeviceInfo(const QBluetoothDeviceInfo &info) : device(info), connected(false) {} /*! - * \brief VBluetoothDeviceInfo::getDevice - * Gets the QBluetoothDeviceInfo this class describes - * \return The QBluetoothDeviceInfo object - */ -QBluetoothDeviceInfo VBluetoothDeviceInfo::getDevice() const -{ - return device; -} - -/*! * \brief VBluetoothDeviceInfo::getName * Gets the name of the device * \return QString - the name of the device @@ -49,12 +36,24 @@ } /*! - * \brief VBluetoothDeviceInfo::setDevice - * Sets the QBluetoothDeviceInfo object to a new object - * \param device - the new QbluetoothDeviceInfo device + * \brief VBluetoothDeviceInfo::setConnected + * Sets the bluetooth connection state */ -void VBluetoothDeviceInfo::setDevice(const QBluetoothDeviceInfo &device) +void VBluetoothDeviceInfo::setConnected(const bool &conn) { - this->device = device; - emit deviceChanged(); + if (conn != connected) + { + connected = conn; + emit deviceChanged(); + } } + +/*! + * \brief VBluetoothDeviceInfo::isConnected + * Gets the bluetooth connection state + * \return bool - true if connected, false otherwise + */ +bool VBluetoothDeviceInfo::isConnected() const +{ + return connected; +} Index: sources/view/VBluetoothDeviceInfo.h =================================================================== diff -u -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 -r5696b8db4628ee3143d93952c5dbdf511fa985b1 --- sources/view/VBluetoothDeviceInfo.h (.../VBluetoothDeviceInfo.h) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) +++ sources/view/VBluetoothDeviceInfo.h (.../VBluetoothDeviceInfo.h) (revision 5696b8db4628ee3143d93952c5dbdf511fa985b1) @@ -15,22 +15,29 @@ Q_OBJECT Q_PROPERTY(QString name READ getName NOTIFY deviceChanged) Q_PROPERTY(QString address READ getAddress NOTIFY deviceChanged) + Q_PROPERTY(bool connected READ isConnected NOTIFY deviceChanged) public: VBluetoothDeviceInfo(const QBluetoothDeviceInfo &device); - - void setDevice(const QBluetoothDeviceInfo &device); QString getName() const; QString getAddress() const; - QBluetoothDeviceInfo getDevice() const; + bool isConnected() const; + void setConnected(const bool &conn); signals: void deviceChanged(); private: + + bool operator==(const VBluetoothDeviceInfo &d1) { + if (getAddress() != d1.getAddress()) + return false; + return true; + } + QBluetoothDeviceInfo device; + bool connected; }; - } #endif // VBLUETOOTHDEVICEINFO_H