Index: denali.pro =================================================================== diff -u -ra51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1 -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- denali.pro (.../denali.pro) (revision a51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1) +++ denali.pro (.../denali.pro) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -1,4 +1,4 @@ -QT += widgets qml quick serialbus concurrent +QT += widgets qml quick serialbus concurrent bluetooth CONFIG += c++17 warn_on QMAKE_CXXFLAGS += -Wall -Werror -Wimplicit-fallthrough # -save-temps # see .ii and .s files @@ -33,6 +33,7 @@ sources/storage \ sources/gui \ sources/canbus \ + sources/bluetooth \ sources/utility \ sources/abstract \ sources/model \ @@ -52,6 +53,7 @@ common/HDDefs.h \ common/MsgDefs.h \ \ # Main + sources/bluetooth/BLEScanner.h \ sources/VTreatmentBegin.h \ sources/main.h \ sources/model/MEndTreatmentResponse.h \ @@ -112,11 +114,14 @@ sources/canbus/messagebuilder.h \ sources/canbus/messageinterpreter.h \ sources/canbus/messagedispatcher.h \ + \ # Bluetooth \ # Gui sources/gui/guiglobals.h \ sources/gui/guiview.h \ sources/gui/guicontroller.h \ \ # ---------- Views ---------- + sources/view/VBluetooth.h \ + sources/view/VBluetoothDeviceInfo.h \ sources/view/VTreatmentCreate.h \ sources/view/VEventSpy.h \ sources/view/hd/data/VHDTreatmentStatesData.h \ @@ -168,6 +173,7 @@ \ # common \ # Main main.cpp \ + sources/bluetooth/BLEScanner.cpp \ sources/VTreatmentBegin.cpp \ sources/model/MEndTreatmentResponse.cpp \ sources/model/MStartTreatmentResponse.cpp \ @@ -224,11 +230,14 @@ sources/canbus/messagebuilder.cpp \ sources/canbus/messagedispatcher.cpp \ sources/canbus/messageinterpreter.cpp \ + \ # Bluetooth \ # Gui sources/gui/guiglobals.cpp \ sources/gui/guiview.cpp \ sources/gui/guicontroller.cpp \ \ # ---------- Views ---------- + sources/view/VBluetooth.cpp \ + sources/view/VBluetoothDeviceInfo.cpp \ sources/view/VTreatmentCreate.cpp \ sources/view/VEventSpy.cpp \ sources/view/hd/data/VHDTreatmentStatesData.cpp \ Index: denali.pro.user =================================================================== diff -u -ra51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1 -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- denali.pro.user (.../denali.pro.user) (revision a51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1) +++ denali.pro.user (.../denali.pro.user) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -1,6 +1,6 @@ - + EnvironmentId @@ -89,7 +89,7 @@ Desktop Qt 5.12.5 GCC 64bit Desktop Qt 5.12.5 GCC 64bit qt.qt5.5125.gcc_64_kit - 1 + 0 0 0 Index: denali.qrc =================================================================== diff -u -r846a9ebc350e33be4affab3cc4c136248900015d -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- denali.qrc (.../denali.qrc) (revision 846a9ebc350e33be4affab3cc4c136248900015d) +++ denali.qrc (.../denali.qrc) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -5,6 +5,7 @@ sources/gui/qml/pages/SettingsHome.qml sources/gui/qml/pages/Diagnostics.qml sources/gui/qml/pages/ManagerHome.qml + sources/gui/qml/pages/SettingsBluetooth.qml sources/gui/qml/dialogs/PowerOff.qml Index: main.cpp =================================================================== diff -u -r56e378f7504701b9e9a9dccaf205aef2fd52c58e -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- main.cpp (.../main.cpp) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) +++ main.cpp (.../main.cpp) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -41,6 +41,7 @@ #include "logger.h" #include "DriveWatcher.h" #include "threads.h" +#include "BLEScanner.h" // kernel #include @@ -290,6 +291,9 @@ _MessageDispatcher.enableConsoleOut(gConsoleoutFrameInterface); } + //! - Initializing BLE Interface + _BLEScanner.init(); + //! - Initializing Application Controller _ApplicationController.init(Threads::_Application_Thread); Fisheye: Tag 0470ff6f209ff0c5089f8f0849b6da04f60f8f41 refers to a dead (removed) revision in file `resources/images/alarm.svg'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0470ff6f209ff0c5089f8f0849b6da04f60f8f41 refers to a dead (removed) revision in file `resources/images/bell-off.svg'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 0470ff6f209ff0c5089f8f0849b6da04f60f8f41 refers to a dead (removed) revision in file `resources/images/bell.svg'. Fisheye: No comparison available. Pass `N' to diff? Index: sources/bluetooth/BLEScanner.cpp =================================================================== diff -u --- sources/bluetooth/BLEScanner.cpp (revision 0) +++ sources/bluetooth/BLEScanner.cpp (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,461 @@ +#include "BLEScanner.h" + +// Qt +#include +#include +#include + +// Project +#include "main.h" +#include "logger.h" + + + +BLEScanner::BLEScanner(QObject *parent) : QObject(parent) +{ + discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this); + macAddress = "EC:21:E5:F4:BC:C9"; // for testing only +} + +void BLEScanner::initConnections() +{ + + // discovery agent + connect(discoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)), + this, SLOT(onDeviceDiscovered(const QBluetoothDeviceInfo&))); + connect(discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(onDiscoveryAgentError(QBluetoothDeviceDiscoveryAgent::Error))); + connect(discoveryAgent, SIGNAL(finished()), this, SLOT(onScanFinished())); + +} + +/*! + * \brief BLEScanner::init + * \details Initializes the class by setting the connections + * \return true on first initialization, false if it has already been initialized + */ +bool BLEScanner::init() +{ + if (_init) + return false; + + _init = true; + + initConnections(); + + LOG_EVENT("UI," + tr("%1 Initialized").arg(metaObject()->className())); + + return true; +} + + +/*! + * \brief BLEScanner::quit + * Called when the application is exiting. + */ +void BLEScanner::quit() +{ + quitThread(); // verified + +} + + +/*! + * \brief BLEScanner::quitThread + * \details Moves this object to main thread to be handled by QApplicaiton + * It will also be destroyed there. + */ +void BLEScanner::quitThread() +{ + if (!_thread ) + return; + + moveToThread(qApp->thread()); +} + + +/*! + * \brief BLEScanner::setMacAddress + * Sets the BLE mac address to pair with + * \param mac - (QString) The mac address to pair to (e.g. "EC:21:E5:F4:BC:C9") + */ +void BLEScanner::setMacAddress(const QString &mac) +{ + macAddress = mac; +} + +/*! + * \brief BLEScanner::onSelectedDevice + * \param addr - The mac address of the device to connect to + */ +void BLEScanner::onSelectedDevice(const QString &addr) +{ + setMacAddress(addr); + for (const QBluetoothDeviceInfo &deviceInfo : devices) { + if (deviceInfo.address().toString() == addr) { + connectToDevice(deviceInfo); + return; + } + } +} + +/*! + * \brief BLEScanner::onDeviceDiscovered + * When a new mac address was discovered + * \param deviceInfo - The discovered device's information + */ +void BLEScanner::onDeviceDiscovered(const QBluetoothDeviceInfo& deviceInfo) +{ + qDebug() << __FUNCTION__ << deviceInfo.address(); + devices.append(deviceInfo); + emit deviceDiscovered(deviceInfo); +} + +/*! + * \brief BLEScanner::onDiscoveryAgentError + * Called when the discovery agent encounters an error + * \param error - the error enum + */ +void BLEScanner::onDiscoveryAgentError(QBluetoothDeviceDiscoveryAgent::Error error) +{ + qDebug() << __FUNCTION__ << error; + emit scanForDevicesError(error); +} + +/*! + * \brief BLEScanner::onScanFinished + * Called when the scan has completed + */ +void BLEScanner::onScanFinished() +{ + emit scanFinished(); +} + +/*! + * \brief BLEScanner::scanForDevices + * Tells the discovery agent to start scanning for devices + */ +void BLEScanner::scanForDevices() +{ + discoveryAgent->start(); +} + +/*! + * \brief BLEScanner::onServiceDiscovered + * Called when a new service is discovered on the paired BLE device. + * \param uuid - the QBluetoothUuid of the discovered service + */ +void BLEScanner::onServiceDiscovered(const QBluetoothUuid &uuid) +{ + + QLowEnergyService* service = lowEnergyController->createServiceObject(uuid, this); + + services.append(service); + + if (uuid.toString() == omronUnknownServiceName) { + omronUnknownService = service; + + } + else if (uuid.toString() == omronBloodPressureServiceName) { + omronBloodPressureService = service; + } + else if (uuid.toString() == omronCurrentTimeServiceName) { + omronCurrentTimeService = service; + } + else if (uuid.toString() == omronBatteryLevelServiceName) { + omronBatteryLevelService = service; + } + + service->discoverDetails(); + + qDebug() << "Service " << service->serviceName() << "UUID: " << uuid << " state: " << service->state(); + + foreach (const QLowEnergyCharacteristic &c, service->characteristics()) { + qDebug() << "----> Characteristic: " << c.name() + << " uuid: " << c.uuid(); + + } + + +} + +/*! + * \brief BLEScanner::requestBPMeasurement + * Requests BP Measurement data. + * Must already be connected to the BLE device + * The BLE device must be in the correct mode and it + * must support indicate / notify for the blood pressure measurement characteristic (0x2A35). + */ +void BLEScanner::requestBPMeasurement() +{ + if (omronBloodPressureService == nullptr) + { + qDebug() << "Blood pressure service is null. Cannot request BP Measurement"; + return; + } + + // blood pressure measurements + const QLowEnergyCharacteristic bpCharacteristic = omronBloodPressureService->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)); + if (!bpCharacteristic.isValid()) { + qDebug() << "Blood pressure service not found."; + return; + } + + notificationDesc = bpCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + if (notificationDesc.isValid()) + omronBloodPressureService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100")); + + // blood pressure feature + const QLowEnergyCharacteristic c = omronBloodPressureService->characteristic(QBluetoothUuid(QBluetoothUuid::BloodPressureFeature)); + if (!c.isValid()) { + qDebug() << "Blood pressure feature not found."; + return; + } + + omronBloodPressureService->readCharacteristic(c); +} + +/*! + * \brief BLEScanner::serviceStateChanged + * Called when the BLE service state has changed + * Requests blood pressure measurement data + * \param serviceState - the new state of the service + */ +void BLEScanner::serviceStateChanged(const QLowEnergyService::ServiceState &serviceState) +{ + + switch (serviceState) { + + case QLowEnergyService::ServiceDiscovered: + { + requestBPMeasurement(); + break; + } + case QLowEnergyService::InvalidService: + { + qDebug() << "Invalid Service"; + break; + } + case QLowEnergyService::DiscoveryRequired: + { + qDebug() << "Discovery Required"; + break; + } + case QLowEnergyService::DiscoveringServices: + { + qDebug() << "Discovering Services."; + break; + } + case QLowEnergyService::LocalService: + { + qDebug() << "Invalid service state."; + break; + } + default: + { + qDebug() << "Invalid service state"; + break; + } + + } + + +} + +/*! + * \brief BLEScanner::onCharacteristicChanged + * Called when we received data for a particular characteristic + * BP and HR data is received here + * \param c - the characteristic we received data for + * \param byteArray - the data received + */ +void BLEScanner::onCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &byteArray) +{ + + qDebug() << "@@@@@@@@ Data Read @@@@@@@@@@: " << c.name() << byteArray; + + if (c.uuid() != QBluetoothUuid(QBluetoothUuid::BloodPressureMeasurement)) + { + qDebug() << "Ignoring data read for " << c.uuid(); + return; + } + + parseMeasurement(byteArray); + +} + +/*! + * \brief BLEScanner::parseMeasurement + * Parses the BP and Pulse Rate measurement data + * \param byteArray - the data to be parsed + */ +void BLEScanner::parseMeasurement(const QByteArray &byteArray) +{ + bp_measurement_t measurement; + + // for debugging + /* + const char *data = "\x16t\x00M\x00Z\x00\xE4\x07\t\x04\n\x05""8@\x00\x00\x00"; + + QByteArray byteArray = QByteArray::fromRawData(data, sizeof(bp_measurement)); + */ + const uint8_t *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() << "flags: " << measurement.flags; + qDebug() << "systolic: " << measurement.systolic; + qDebug() << "diastolic: " << measurement.diastolic; + qDebug() << "mean arterial pressure: " << measurement.mean_arterial_pressure_value; + qDebug() << "year: " << measurement.year; + qDebug() << "month: " << measurement.month; + qDebug() << "day: " << measurement.day; + qDebug() << "hour: " << measurement.hour; + qDebug() << "minute: " << measurement.minute; + qDebug() << "second: " << measurement.second; + qDebug() << "pulse_rate: " << measurement.pulse_rate; + qDebug() << "user_id: " << measurement.user_id; + qDebug() << "measurement_status: " << measurement.measurement_status; + + emit receivedBPMeasurement(measurement); + +} + +/*! + * \brief BLEScanner::confirmedDescriptorWrite + * When we received confirmation that the descriptor was written to + * \param desc - the descriptor that was written to + * \param byteArray - data confirming a descriptor disconnect or connection + */ +void BLEScanner::confirmedDescriptorWrite(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; + } + +} + +/*! + * \brief BLEScanner::serviceCharacteristicsRead + * Called when the provided characteristic has been read + * \param c - the BLE characteristic that was read + * \param byteArray - the data read from the BLE characteristic + */ +void BLEScanner::serviceCharacteristicsRead(const QLowEnergyCharacteristic &c,const QByteArray &byteArray) +{ + qDebug() << __FUNCTION__ << c.name() << " data: " << byteArray; + +} + +/*! + * \brief BLEScanner::onServiceScanDone + * Called when we have finished scanning the services provided by BLE device + */ +void BLEScanner::onServiceScanDone() +{ + + qDebug() << "##############################"; + qDebug() << "##############################"; + qDebug() << "######## Scan Finished #######"; + qDebug() << "##############################"; + qDebug() << "##############################"; + + foreach (QLowEnergyService* service, services) { + + connect(service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), + this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState))); + + connect(service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic, QByteArray)), + this, SLOT(onCharacteristicChanged(QLowEnergyCharacteristic,QByteArray))); + + connect(service, SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)), + this, SLOT(serviceCharacteristicsRead(QLowEnergyCharacteristic,QByteArray))); + + connect(service, SIGNAL(descriptorWritten(QLowEnergyDescriptor, QByteArray)), + this, SLOT(confirmedDescriptorWrite(QLowEnergyDescriptor, QByteArray))); + } + +} + +/*! + * \brief BLEScanner::onControllerError + * Called when the BLE Controller encounters an error + * \param error - the error enum + */ +void BLEScanner::onControllerError(const QLowEnergyController::Error &error) +{ + qDebug() << __FUNCTION__ << "LE controller error: " << error; + +} + +/*! + * \brief BLEScanner::onDeviceConnected + * Called when we successfully connect to a device. + * Starts the scan for services on the device + */ +void BLEScanner::onDeviceConnected() +{ + qDebug() << __FUNCTION__; + + lowEnergyController->discoverServices(); + +} + +/*! + * \brief BLEScanner::onDeviceDisconnected + * Called when we become disconnected from a device. + */ +void BLEScanner::onDeviceDisconnected() +{ + qDebug() << __FUNCTION__; + +} + +/*! + * \brief BLEScanner::connectToDevice + * Creates the low energy controller object + * Configures the low energy controller signals + * Connects to the desired device + * \param deviceInfo - The QBluetoothDeviceInfo object to connect to + */ +void BLEScanner::connectToDevice(const QBluetoothDeviceInfo& deviceInfo) +{ + + lowEnergyController = QLowEnergyController::createCentral(deviceInfo); + + // low energy controller + connect(lowEnergyController, SIGNAL(serviceDiscovered(QBluetoothUuid)), + this, SLOT(onServiceDiscovered(QBluetoothUuid))); + + connect(lowEnergyController, SIGNAL(discoveryFinished()), + this, SLOT(onServiceScanDone())); + + connect(lowEnergyController, SIGNAL(error(QLowEnergyController::Error)), + this, SLOT(onControllerError(QLowEnergyController::Error))); + + connect(lowEnergyController, SIGNAL(connected()), + this, SLOT(onDeviceConnected())); + + connect(lowEnergyController, SIGNAL(disconnected()), + this, SLOT(onDeviceDisconnected())); + + lowEnergyController->connectToDevice(); +} Index: sources/bluetooth/BLEScanner.h =================================================================== diff -u --- sources/bluetooth/BLEScanner.h (revision 0) +++ sources/bluetooth/BLEScanner.h (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,118 @@ +#ifndef BLESCANNER_H +#define BLESCANNER_H + +// Qt +#include +#include +#include +#include +#include +#include +#include + +// Project +#include "main.h" +#include "VBluetoothDeviceInfo.h" + +// define +#define _BLEScanner BLEScanner::I() + +using namespace View; + +class BLEScanner : public QObject +{ + Q_OBJECT + + QThread *_thread = nullptr; + bool _init = false; + +// Singleton +SINGLETON(BLEScanner) + +public: + + // 19 total bytes + struct bp_measurement { + 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 + + }; + typedef bp_measurement bp_measurement_t; + + void scanForDevices(); + void parseMeasurement(const QByteArray &byteArray); + void requestBPMeasurement(); + +private: + + QList devices; + QString macAddress = ""; + QBluetoothDeviceDiscoveryAgent *discoveryAgent; + QLowEnergyController *lowEnergyController; + + QList services; + QLowEnergyService* omronUnknownService = nullptr; + QLowEnergyService* omronCurrentTimeService = nullptr; + QLowEnergyService* omronBatteryLevelService = nullptr; + QLowEnergyService* omronBloodPressureService = nullptr; + QLowEnergyDescriptor notificationDesc; + QLowEnergyDescriptor readDesc; + + 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}"); + + QStringList characteristicsToAcquireNotify; + + void initConnections(); + void quitThread(); + void connectToDevice(const QBluetoothDeviceInfo& deviceInfo); + void setMacAddress(const QString &mac); + +signals: + void receivedBPMeasurement(bp_measurement_t); + void connectedToBloodPressureService(); + void scanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error error); + void scanFinished(); + void deviceDiscovered(const QBluetoothDeviceInfo &device); + +public slots: + bool init(); + +private slots: + + // discovery agent + void onDeviceDiscovered(const QBluetoothDeviceInfo& deviceInfo); + void onDiscoveryAgentError(QBluetoothDeviceDiscoveryAgent::Error error); + void onScanFinished(); + + // low energy controller + void onServiceDiscovered(const QBluetoothUuid &uuid); + void onServiceScanDone(); + void onControllerError(const QLowEnergyController::Error &error); + void onDeviceConnected(); + void onDeviceDisconnected(); + + // service slots + void serviceStateChanged(const QLowEnergyService::ServiceState &serviceState); + void onCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &byteArray); + void confirmedDescriptorWrite(const QLowEnergyDescriptor &desc, const QByteArray &byteArray); + void serviceCharacteristicsRead(const QLowEnergyCharacteristic &c,const QByteArray &byteArray); + + void quit(); + void onSelectedDevice(const QString &addr); +}; + +#endif // BLESCANNER_H Index: sources/gui/guiglobals.cpp =================================================================== diff -u -r846a9ebc350e33be4affab3cc4c136248900015d -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 846a9ebc350e33be4affab3cc4c136248900015d) +++ sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -55,6 +55,8 @@ #include "vtreatmentadjustmentultrafiltrationedit.h" #include "vtreatmentadjustmentultrafiltrationconfirm.h" #include "VTreatmentCreate.h" +#include "VBluetooth.h" +#include "VBluetoothDeviceInfo.h" #include "VPriming.h" #include "VTreatmentBegin.h" #include "VTreatmentAdjustmentSaline.h" Index: sources/gui/qml/components/ScreenItem.qml =================================================================== diff -u -r56e378f7504701b9e9a9dccaf205aef2fd52c58e -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/qml/components/ScreenItem.qml (.../ScreenItem.qml) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) +++ sources/gui/qml/components/ScreenItem.qml (.../ScreenItem.qml) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -30,8 +30,14 @@ width : Variables.applicationWidth height : Variables.applicationHeight + BackButton { id : _backButton + onClicked: pop() + } + Rectangle { id: _backgroundRect anchors.fill: parent color: Colors.backgroundMain } + + } Index: sources/gui/qml/components/SettingsItem.qml =================================================================== diff -u -r56e378f7504701b9e9a9dccaf205aef2fd52c58e -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/qml/components/SettingsItem.qml (.../SettingsItem.qml) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) +++ sources/gui/qml/components/SettingsItem.qml (.../SettingsItem.qml) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -46,18 +46,33 @@ } - Image { id: _arrowImage - visible: true + // chevron + Line { + color: "#4290ec" + height: 18 + width: 3 anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - width : Variables.largeArrowWidth - height: Variables.largeArrowHeight - source: "qrc:/images/iArrow" + anchors.bottom: parent.verticalCenter + anchors.rightMargin: 20 + anchors.bottomMargin: -3 + rotation: 135 } Line { + color: "#4290ec" + height: 18 + width: 3 + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.top: parent.verticalCenter + anchors.topMargin: -3 + rotation: 45 + } + + + Line { width: parent.width - color: "gray" + color: "#475f75" anchors.left: parent.left; anchors.bottom: parent.bottom; } Index: sources/gui/qml/globals/Variables.qml =================================================================== diff -u -r846a9ebc350e33be4affab3cc4c136248900015d -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision 846a9ebc350e33be4affab3cc4c136248900015d) +++ sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -106,8 +106,11 @@ readonly property int notificationBarIconWidth : 30 readonly property int settingsOptionWidth : 550 - readonly property int settingsOptionHeight : 50 + readonly property int settingsOptionHeight : 100 + readonly property int settingsBLEButtonWidth : 300 + readonly property int settingsBLEButtonHeight : 75 + // ---------- < PRS > Related Section ---------- // Min/Max readonly property int bloodFlowMin : 100 Index: sources/gui/qml/main.qml =================================================================== diff -u -rd8004655ec64da6c8806b9a074a0cb07d799ddf9 -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/qml/main.qml (.../main.qml) (revision d8004655ec64da6c8806b9a074a0cb07d799ddf9) +++ sources/gui/qml/main.qml (.../main.qml) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -39,6 +39,7 @@ import VTreatmentAdjustmentUltrafiltrationConfirm 0.1; import VTreatmentCreate 0.1; +import VBluetooth 0.1; import VDGDrainPump 0.1; import VDGHeaters 0.1; import VDGLoadCellReadings 0.1; @@ -108,6 +109,7 @@ VTreatmentAdjustmentUltrafiltrationEdit { id: vTreatmentAdjustmentUltrafiltrationEdit } VTreatmentAdjustmentUltrafiltrationConfirm { id: vTreatmentAdjustmentUltrafiltrationConfirm } VTreatmentCreate { id: vTreatmentCreate } + VBluetooth { id: vBluetooth } VPriming { id: vPriming } VTreatmentBegin { id: vTreatmentBegin } Index: sources/gui/qml/pages/SettingsBluetooth.qml =================================================================== diff -u --- sources/gui/qml/pages/SettingsBluetooth.qml (revision 0) +++ sources/gui/qml/pages/SettingsBluetooth.qml (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,115 @@ +/*! + * + * 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 SettingsBluetooth.qml + * \author (last) Peter Lucia + * \date (last) 23-Sept-2020 + * \author (original) Peter Lucia + * \date (original) 23-Sept-2020 + * + */ + +// Qt +import QtQuick 2.12 + +// Project +import Gui.Actions 0.1; + +// Qml imports +import "qrc:/globals" +import "qrc:/components" + +/*! + * \brief SettingsHome is the screen + * which is the default screen in the "Settings" stack + */ +ScreenItem { id: _root + + signal clickedBack() + + BackButton { id : _backButton + onClicked: _root.clickedBack() + } + + TouchRect { + id: _scan_for_devices + anchors.horizontalCenter: _root.horizontalCenter + anchors.top: _root.top + anchors.topMargin: 75 + height: Variables.settingsBLEButtonHeight + width: Variables.settingsBLEButtonWidth + text.text: "Scan for devices" + animated: true + onClicked: vBluetooth.onScanForDevices() + } + + Rectangle { + id: _status + anchors.left: _scan_for_devices.right + anchors.top: _root.top + anchors.topMargin: 75 + color: "transparent" + height: Variables.settingsBLEButtonHeight + width: Variables.settingsBLEButtonWidth + Text { + id: _status_text + anchors.centerIn: parent + text: vBluetooth.status + color: Colors.textMain + font.pixelSize: Fonts.fontPixelDialogText + } + } + + ListView { + id: _devices + model: vBluetooth.devices + anchors.top: _scan_for_devices.bottom + anchors.topMargin: 10 + anchors.bottom: _root.bottom + width: Variables.settingsBLEButtonWidth + anchors.horizontalCenter: _root.horizontalCenter + clip: true + spacing: 10 + + delegate: TouchRect { + id: _devices_rect + anchors.horizontalCenter: parent.horizontalCenter + height: 85 + width: parent.width + color: Colors.backgroundMain + border.color: Colors.borderButton + radius: 5 + animated: true + + Text { + id: device + anchors.bottom: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + text: modelData.name + color: Colors.textMain + } + + Text { + id: deviceAddress + anchors.top: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + text: modelData.address + color: Colors.textMain + } + + onClicked: { + vBluetooth.onSelectedDevice(modelData.address) + } + } + } + + Connections { target: vBluetooth + onScanFinished: { + console.debug("Scan Finished."); + } + } +} Index: sources/gui/qml/pages/SettingsHome.qml =================================================================== diff -u -r56e378f7504701b9e9a9dccaf205aef2fd52c58e -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/gui/qml/pages/SettingsHome.qml (.../SettingsHome.qml) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) +++ sources/gui/qml/pages/SettingsHome.qml (.../SettingsHome.qml) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -28,6 +28,7 @@ * which is the default screen in the "Settings" stack */ ScreenItem { id: _root + backgroundRect.color: Colors.backgroundMenu USBButton { id: _usbButton anchors { top : parent.top @@ -63,9 +64,9 @@ _GuiView.doActionTransmit(GuiActions.ID_PowerOff, GuiActions.NoData) } } -} -/* + + TitleText { id: _titleText anchors.horizontalCenter: parent.horizontalCenter; anchors.top: parent.top @@ -77,21 +78,30 @@ } + /* Diagnostics { id: _diagnostics onBackClicked: pop() } + */ + SettingsBluetooth { + id: _bluetooth + onClickedBack: pop() + + } + Column { anchors.centerIn: parent; // add each settings page here. - SettingsItem { id: _item_diagnostics - title : qsTr("Diagnostics") - onClicked: push(_diagnostics); + SettingsItem { id: _item_bluetooth + title : qsTr("Bluetooth") + onClicked: push(_bluetooth); + } } -*/ +} Index: sources/threads.cpp =================================================================== diff -u -r56e378f7504701b9e9a9dccaf205aef2fd52c58e -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/threads.cpp (.../threads.cpp) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) +++ sources/threads.cpp (.../threads.cpp) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -35,6 +35,7 @@ QThread _DriveWatcher_Thread ; QThread _Logger_Thread ; QThread _Application_Thread ; + QThread _BLEScanner_Thread ; /*! * \brief registerTypes Index: sources/view/VBluetooth.cpp =================================================================== diff -u --- sources/view/VBluetooth.cpp (revision 0) +++ sources/view/VBluetooth.cpp (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,102 @@ +#include "VBluetooth.h" +#include "BLEScanner.h" + +// Qt + +// Project + +using namespace View; + +VBluetooth::VBluetooth(QObject *parent) : QObject(parent) +{ + connect(&_BLEScanner, SIGNAL(scanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error))); + + connect(&_BLEScanner, SIGNAL(scanFinished()), + this, SLOT(onScanForDevicesFinished())); + + connect(&_BLEScanner, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo)), + this, SLOT(onDeviceDiscovered(const QBluetoothDeviceInfo))); + + connect(this, SIGNAL(selectedDevice(const QString)), + &_BLEScanner, SLOT(onSelectedDevice(const QString))); +} + +/*! + * \brief VBluetooth::onScanForDevices + * Slot for when the user starts scanning for devices. + * Updates the status and emits a signal to the BLEScanner to + * begin a new scan. + */ +void VBluetooth::onScanForDevices() +{ + bleDevices.clear(); + emit devicesChanged(); + _BLEScanner.scanForDevices(); + status = "Scanning..."; + emit statusChanged(); +} + +/*! + * \brief VBluetooth::onScanForDevicesError + * Slot called when the BLEScanner enounters an error + * while scanning for devices + * \param error + */ +void VBluetooth::onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error error) +{ + switch (error) { + case QBluetoothDeviceDiscoveryAgent::PoweredOffError: + status = tr("Error: The bluetooth module is powered off."); + break; + default: + status = tr("Error: Scan for devices error."); + break; + } + emit statusChanged(); +} + +/*! + * \brief VBluetooth::onDeviceDiscovered + * Slot for when a device is discovered by the BLEScanner. + * \param device - the BLE Device info of the discovered device + */ +void VBluetooth::onDeviceDiscovered(const QBluetoothDeviceInfo &device) +{ + VBluetoothDeviceInfo *info = new VBluetoothDeviceInfo(device); + bleDevices.append(info); + qDebug() << "VBluetooth: Discovered " << device.address(); + emit devicesChanged(); +} + +/*! + * \brief VBluetooth::onScanForDevicesFinished + * Slot called when the scan is finished. Updates the scanning status. + */ +void VBluetooth::onScanForDevicesFinished() +{ + emit scanFinished(); + status = "Scan Finished."; + emit statusChanged(); +} + +/*! + * \brief VBluetooth::getDevices + * Gets the BLE modelData for QML + * \return QVariant - the modelData + */ +QVariant VBluetooth::getDevices() +{ + return QVariant::fromValue(bleDevices); +} + +/*! + * \brief VBluetooth::onSelectedDevice + * Emits a signal that the device was selected + * \param addr - the selected BLE mac address + */ +void VBluetooth::onSelectedDevice(const QString &addr) +{ + emit selectedDevice(addr); +} + Index: sources/view/VBluetooth.h =================================================================== diff -u --- sources/view/VBluetooth.h (revision 0) +++ sources/view/VBluetooth.h (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,50 @@ +#ifndef VBLUETOOTH_H +#define VBLUETOOTH_H + +// Qt +#include +#include + +// Project +#include "VBluetoothDeviceInfo.h" +#include "guicontroller.h" + +using namespace Gui; + +// forward diclations +class tst_views; + +namespace View { +class VBluetooth : public QObject +{ + Q_OBJECT +public: + explicit VBluetooth(QObject *parent = nullptr); + +protected: + Q_PROPERTY(QVariant devices READ getDevices NOTIFY devicesChanged) + Q_PROPERTY(QVariant status READ getStatus NOTIFY statusChanged) + +public slots: + void onScanForDevices(); + QVariant getDevices(); + void onSelectedDevice(const QString &addr); + +signals: + void devicesChanged(); + void selectedDevice(const QString &addr); + void scanFinished(); + void statusChanged(); + +private: + QList bleDevices; + QString status; + + QString getStatus() { return status; } +private slots: + void onScanForDevicesError(QBluetoothDeviceDiscoveryAgent::Error error); + void onScanForDevicesFinished(); + void onDeviceDiscovered(const QBluetoothDeviceInfo &device); +}; +} +#endif // VBLUETOOTH_H Index: sources/view/VBluetoothDeviceInfo.cpp =================================================================== diff -u --- sources/view/VBluetoothDeviceInfo.cpp (revision 0) +++ sources/view/VBluetoothDeviceInfo.cpp (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,60 @@ +#include "VBluetoothDeviceInfo.h" + +// Qt +#include +#include + +// Project + +using namespace View; + +/*! + * \brief VBluetoothDeviceInfo::VBluetoothDeviceInfo + * Constructor for the VBluetoothDeviceInfo class + * \param info - the device information + */ +VBluetoothDeviceInfo::VBluetoothDeviceInfo(const QBluetoothDeviceInfo &info) +{ + device = info; +} + +/*! + * \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 + */ +QString VBluetoothDeviceInfo::getName() const +{ + return device.name(); +} + +/*! + * \brief VBluetoothDeviceInfo::getAddress + * Gets the bluetooth address + * \return QString - the bluetooth address + */ +QString VBluetoothDeviceInfo::getAddress() const +{ + return device.address().toString(); +} + +/*! + * \brief VBluetoothDeviceInfo::setDevice + * Sets the QBluetoothDeviceInfo object to a new object + * \param device - the new QbluetoothDeviceInfo device + */ +void VBluetoothDeviceInfo::setDevice(const QBluetoothDeviceInfo &device) +{ + this->device = device; + emit deviceChanged(); +} Index: sources/view/VBluetoothDeviceInfo.h =================================================================== diff -u --- sources/view/VBluetoothDeviceInfo.h (revision 0) +++ sources/view/VBluetoothDeviceInfo.h (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -0,0 +1,36 @@ +#ifndef VBLUETOOTHDEVICEINFO_H +#define VBLUETOOTHDEVICEINFO_H + +// Qt +#include +#include +#include + +// Project + +namespace View { + +class VBluetoothDeviceInfo: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ getName NOTIFY deviceChanged) + Q_PROPERTY(QString address READ getAddress NOTIFY deviceChanged) + +public: + VBluetoothDeviceInfo(const QBluetoothDeviceInfo &device); + + void setDevice(const QBluetoothDeviceInfo &device); + QString getName() const; + QString getAddress() const; + QBluetoothDeviceInfo getDevice() const; + +signals: + void deviceChanged(); + +private: + QBluetoothDeviceInfo device; +}; + +} + +#endif // VBLUETOOTHDEVICEINFO_H Index: sources/view/vview.h =================================================================== diff -u -ra51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1 -r0470ff6f209ff0c5089f8f0849b6da04f60f8f41 --- sources/view/vview.h (.../vview.h) (revision a51b1ec80d65c7cf9f7f3b86f45a637a6d42efc1) +++ sources/view/vview.h (.../vview.h) (revision 0470ff6f209ff0c5089f8f0849b6da04f60f8f41) @@ -122,6 +122,7 @@ REGISTER_TYPE( VTreatmentAdjustmentUltrafiltrationEdit ) \ REGISTER_TYPE( VTreatmentAdjustmentUltrafiltrationConfirm ) \ REGISTER_TYPE( VTreatmentCreate ) \ + REGISTER_TYPE( VBluetooth ) \ REGISTER_TYPE( VPriming ) \ REGISTER_TYPE( VTreatmentBegin ) \ REGISTER_TYPE( VTreatmentAdjustmentSaline )