Index: sources/view/settings/VBluetooth.cpp =================================================================== diff -u -r93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7 -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 --- sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 93cb2e56782aa64aafb2b69ec526a5e49ffdf1c7) +++ sources/view/settings/VBluetooth.cpp (.../VBluetooth.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) @@ -1,138 +1,325 @@ /*! * - * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. * \copyright * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * \file VBluetooth.cpp - * \author (last) Behrouz NematiPour - * \date (last) 8/23/2021 + * \author (last) Vy + * \date (last) 05-Sep-2023 * \author (original) Behrouz NematiPour - * \date (original) 8/23/2021 + * \date (original) 24-Aug-2021 * */ #include "VBluetooth.h" // Qt // Project +#include "ApplicationController.h" #include "GuiController.h" -#include "MBluetooth.h" +#include "BluetoothInterface.h" -VIEW_DEF_CLASS(VBluetooth) - using namespace Bluetooth; using namespace Model; +View::VBluetooth::VBluetooth(QObject *parent) : QAbstractListModel(parent) { + initConnections(); +} + /*! * \brief VBluetooth::initConnections * Makes the necessary connections. Called inside VIEW_DEF_CLASS */ void View::VBluetooth::initConnections() { - ACTION_VIEW_CONNECTION(AdjustSerialNumberHDResponseData); - connect(&_BluetoothInterface, &BluetoothInterface::didStateChange, - this , &VBluetooth::onStateChange ); + connect(&_BluetoothInterface, SIGNAL(didStateChange (BluetoothData )), + this , SLOT( onStateChange (BluetoothData ))); + connect(&_BluetoothInterface, SIGNAL(didDeviceChange(BluetoothDeviceData)), + this , SLOT( onDeviceChange(BluetoothDeviceData))); + connect(this , SIGNAL(didDeviceSelect(QString, QString )), + this , SLOT( onDeviceSelect(QString, QString ))); } -void View::VBluetooth::onActionReceive(const AdjustSerialNumberHDResponseData &vData) +/*! + * \brief View::VBluetooth::rowCount + * \details QAbstractItemModel::rowCount override + * \return Returns the number of rows under the given parent. When the parent is valid it means that rowCount is returning the number of children of parent. + */ +int View::VBluetooth::rowCount(const QModelIndex &) const { + return _devices.count(); +} + +/*! + * \brief View::VBluetooth::data + * \details QAbstractItemModel::data override + * \param index - the row index + * \param role - the row role + * \return Returns the data stored under the given role for the item referred to by the index. + */ +QVariant View::VBluetooth::data(const QModelIndex &index, int role) const { - LOG_EVENT( QString() + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + vData.mSerialNumber); - _BluetoothInterface.doScan(); + if (index.row() < rowCount()) + switch (role) { + case ToStringRole : return _devices.at(index.row()).toString(); + case AddrRole : return _devices.at(index.row()).addr; + case NameRole : return _devices.at(index.row()).name; + case PairRole : return _devices.at(index.row()).pair; + default: return QVariant(); + } + return QVariant(); } -void View::VBluetooth::onStateChange(const Model::MBluetooth &vData) +/*! + * \brief View::VBluetooth::roleNames + * \details QAbstractItemModel::roleNames override + * \return Returns the model's role names. + */ +QHash View::VBluetooth::roleNames() const { - scanInProgress( ! ( vData.state == MBluetooth::eIS_Idle || - vData.state == MBluetooth::eIS_Device_Disconnect || - vData.state == MBluetooth::eIS_Device_Error || - vData.state == MBluetooth::eIS_Device_Error_Init || - vData.state == MBluetooth::eIS_Scan_NotFound || - vData.state == MBluetooth::eIS_Local_Disconnect )); + static const QHash roles { + { ToStringRole, "toString" }, + { AddrRole, "addr" }, + { NameRole, "name" }, + { PairRole, "pair" } + }; + return roles; +} - switch (vData.state) { +/*! + * \brief View::VBluetooth::reset + * \details Clears the list of the devices. + */ +void View::VBluetooth::reset() +{ + beginResetModel(); + _devices.clear(); + endResetModel(); +} + +/*! + * \brief View::VBluetooth::onStateChange + * \details Updates the View when the Bluetooth Interface state change signal is received. + * \param vData - The Bluetooth Interface information data. + */ +void View::VBluetooth::onStateChange(const BluetoothData &vData) +{ + Model::MBluetooth::InterfaceStates state = vData.state; + if ( state == MBluetooth::eIS_Local_Error_POST ) { + isInvalid( true ); + notify( state ); + return; + } + + // TODO: re-evaluate the states for the scan button enable/disable. + // scanEnabled(state == MBluetooth::eIS_Idle + // || state == MBluetooth::eIS_Scan_Done + // || state == MBluetooth::eIS_Scan_NotFound + // || state == MBluetooth::eIS_Device_Error + // || state == MBluetooth::eIS_Device_Waiting + // ); + + switch (state) { // The device name is not always available and the interface may be in investigation. - case MBluetooth::eIS_Scan_Found : - case MBluetooth::eIS_Scan_NotFound : - case MBluetooth::eIS_Scan_Discover : - deviceAddr (vData.deviceAddr ); - deviceName (vData.deviceName ); - devicePair (vData.devicePair ); + case MBluetooth::eIS_Local_Init : + localAddr (vData.localAddr ); + localName (vData.localName ); break; - case MBluetooth::eIS_Local_Init : - localAddr (vData.localAddr ); - localName (vData.localName ); + case MBluetooth::eIS_Scan_Start : + pairedAddr(""); + // DEBUG: LOG_APPED_UI(tr("Bluetooth unpaired." )); // pairedAddr == "" implies unpaired + scanEnabled(false); // disable the scan button while the device is scanning + reset(); break; - default: + case MBluetooth::eIS_Scan_Done : + if (! _devices.count()) state = MBluetooth::eIS_Scan_NotFound; + scanEnabled(true); // enable the scan button when scanning is not running break; + + case MBluetooth::eIS_Device_Waiting : // Selected device connected and is in waiting mode for read. + pairedAddr(vData.deviceAddr); + pairedBatt(vData.deviceBatt); + scanEnabled(true); + break; + + case MBluetooth::eIS_Device_Connect : + if ( vData.devicePair != QBluetoothLocalDevice::Unpaired ) LOG_APPED_UI(tr("Bluetooth reconnected." )); + else LOG_APPED_UI(tr("Bluetooth paired and connected." )); + break; + + case MBluetooth::eIS_Device_Disconnect : + LOG_APPED_UI(tr("Bluetooth paired and disconnected." )); + break; + + case MBluetooth::eIS_Idle : + case MBluetooth::eIS_Local_Connect : + case MBluetooth::eIS_Local_Error_Invalid : + case MBluetooth::eIS_Local_Error_POST : + case MBluetooth::eIS_Local_Error_Off : + case MBluetooth::eIS_Local_Error_IO : + case MBluetooth::eIS_Local_Error : + case MBluetooth::eIS_Local_Disconnect : + + case MBluetooth::eIS_Scan_Reject : + case MBluetooth::eIS_Scan_NotFound : + case MBluetooth::eIS_Scan_Discover : + case MBluetooth::eIS_Scan_Found : + case MBluetooth::eIS_Scan_Stop : + + case MBluetooth::eIS_Device_Init : + case MBluetooth::eIS_Device_Start : + case MBluetooth::eIS_Device_Error_Init : + case MBluetooth::eIS_Device_Error : + case MBluetooth::eIS_Device_Done : + + case MBluetooth::eIS_Service_Start : + case MBluetooth::eIS_Service_Invalid : + case MBluetooth::eIS_Service_Error : + case MBluetooth::eIS_Service_Discover : + case MBluetooth::eIS_Service_Detail : + case MBluetooth::eIS_Service_Detail_Error : + case MBluetooth::eIS_Service_Detail_Done : + case MBluetooth::eIS_Service_Done : + + case MBluetooth::eIS_Detail_Change : + case MBluetooth::eIS_Detail_Read : + case MBluetooth::eIS_Detail_Write : + case MBluetooth::eIS_Config_Read : + case MBluetooth::eIS_Config_Write : + + case MBluetooth::eIS_Close : + break; } error (vData.error ); - devicePin (vData.devicePin ); + notify( state ); + + //DEBUG: qDebug()<< "bt state : " << state << " currently paired to addr: "<< _pairedAddr; +} + +/*! + * \brief View::VBluetooth::onDeviceChange + * \details updates the list of devices when a device data has been received. Used with Discovery Agent to populate list of discovered devices to the QML/UI. + * \param vDevice - The device information + */ +void View::VBluetooth::onDeviceChange(const BluetoothDeviceData &vDevice) +{ + int row = 0; + while (row < _devices.count()) ++row; + beginInsertRows(QModelIndex(), row, row); + _devices.insert(row, vDevice); + endInsertRows(); + + /* DEBUG: Found BCuff devices debug + qDebug() << _devices.count(); + for (auto device: _devices) { + qDebug() << device.addr << device.name << device.pair; + } + */ + +} + +/*! + * \brief View::VBluetooth::onDeviceSelect + * \details The signal handler of the device selection by user on the Bluetooth Cuff setting screen + * \param vAddr - The selected device address + * \param vName - The selected device name + */ +void View::VBluetooth::onDeviceSelect(const QString &vAddr, const QString &vName) +{ + BluetoothDeviceData data; + data.addr = vAddr; + data.name = vName; + emit _BluetoothInterface.didDeviceSelect(data); +} + +/*! + * \brief View::VBluetooth::toText + * \details Maps the BluetoothInterface state vState to its corresponding text message. + * \param vState - current state. + * \return corresponding message text mapped from the state cState. + */ +QString View::VBluetooth::toText(MBluetooth::InterfaceStates vState) const +{ QString message; - switch (vData.state) { + switch (vState) { case MBluetooth::eIS_Idle : message = "" ; break; case MBluetooth::eIS_Close : message = tr("BluetoothInterface Closed" ); break; // Used BluetoothInterface to be consistent with the - case MBluetooth::eIS_Local_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_POST : message = tr("The Bluetooth Adapter POST Failed" ); 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 : message = tr("The Bluetooth Adapter Unknown Error" ); break; case MBluetooth::eIS_Scan_NotFound : message = tr("No Valid device found" ); break; case MBluetooth::eIS_Scan_Start : message = tr("Scanning ..." ); break; case MBluetooth::eIS_Scan_Reject : message = tr("Scanning Rejected" ); break; - case MBluetooth::eIS_Scan_Discover : message = tr("Device Discovered" ); break; + case MBluetooth::eIS_Scan_Discover : message = tr("Device Discovering ..." ); break; case MBluetooth::eIS_Scan_Found : message = tr("Blood Pressure Device Found" ); break; case MBluetooth::eIS_Scan_Stop : message = tr("Scanning Stopped" ); break; case MBluetooth::eIS_Scan_Done : message = tr("Scanning Finished" ); break; case MBluetooth::eIS_Device_Init : message = tr("Device Initializing ..." ); break; case MBluetooth::eIS_Device_Error_Init : message = tr("Device Initialization Error" ); break; case MBluetooth::eIS_Device_Start : message = tr("Device Connecting ..." ); break; + case MBluetooth::eIS_Device_Waiting : message = tr("Device Waiting For Measurement ..." ); break; // received feedback and changed the "Waiting" to this to avoid user confusion. case MBluetooth::eIS_Device_Error : message = tr("Device Connection Error" ); break; case MBluetooth::eIS_Device_Connect : message = tr("Device Connected" ); break; - case MBluetooth::eIS_Device_Done : message = tr("Device Connection Done" ); break; - case MBluetooth::eIS_Device_Disconnect : message = tr("Device Disconnected" ); break; + case MBluetooth::eIS_Device_Done : message = tr("Device Clean Up" ); break; + case MBluetooth::eIS_Device_Disconnect : message = tr("Device In Power Saving Mode" ); break; // received feedback and changed the "Disconnected" to this to avoid user confusion. case MBluetooth::eIS_Service_Start : message = tr("Service Scanning ..." ); break; case MBluetooth::eIS_Service_Error : message = tr("Service Error: %1" ).arg(_error ); break; + case MBluetooth::eIS_Service_Invalid : message = tr("Service Invalid" ); 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_Service_Done : message = tr("Service Clean Up" ); break; - case MBluetooth::eIS_Pair_Start : message = tr("Pairing ..." ); break; - case MBluetooth::eIS_Pair_Error : message = tr("Pairing Error" ); break; - case MBluetooth::eIS_Pair_PinCode : message = tr("Pairing PinCode" ); break; - case MBluetooth::eIS_Pair_Confirm : message = tr("Pairing Confirm" ); break; - case MBluetooth::eIS_Pair_Done : message = tr("Pairing Done" ); break; - + case MBluetooth::eIS_Detail_Change : message = tr("Service Characteristic Changed" ); break; + case MBluetooth::eIS_Detail_Read : message = tr("Service Characteristic Read" ); break; + case MBluetooth::eIS_Detail_Write : message = tr("Service Characteristic Write" ); break; + case MBluetooth::eIS_Config_Read : message = tr("Service Descriptor Read" ); break; + case MBluetooth::eIS_Config_Write : message = tr("Service Descriptor Write" ); break; // IMPORTANT: Do not use the "default:" to let compiler check for all the enumeration which are not handled. } + return message; +} +/*! + * \brief View::VBluetooth::notify + * \details Notifies the QML/UI about the state change and sends its test mapping to the QML/UI observers. + * \param vState - The current state + */ +void View::VBluetooth::notify(MBluetooth::InterfaceStates vState) +{ + QString message = toText(vState); notification(message); // Console Log - message = _deviceAddr + " " + message; - message = message.trimmed().simplified(); - qDebug().noquote().nospace() << message; + // DEBUG: message = _deviceAddr + " " + message + " " + _detailName + " " + _detailValue; + // message = message.trimmed().simplified(); + // qDebug().noquote().nospace() << message; // Service Log - LOG_DEBUG(message); + if ( vState != MBluetooth::eIS_Device_Start ) { // this is the "Device Connecting ..." state and has the interval of 1s and will fill up the service log fast, so removed from log. + LOG_DEBUG(message); + } } -void View::VBluetooth::doScan() -{ +/*! + * \brief View::VBluetooth::doScan + * \details calls the Bluetooth Interface scan to start discovering the Bluetooth devices. + */ +void View::VBluetooth::doScan() { _BluetoothInterface.doScan(); }