/*! * * 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 TreatmentLog.cpp * author (last) Behrouz NematiPour * date (last) 4/30/2021 * author (original) Behrouz NematiPour * date (original) 4/30/2021 * */ #include "TreatmentLog.h" // Qt #include // Project #include "StorageGlobals.h" #include "FileHandler.h" #include "Logger.h" #include "MSettings.h" using namespace Storage; #define NONE "N/A" #define FLOAT3 0,'f',3 #define ADDTITLE(vTITLE) logContent += QString("[%1]\n").arg(vTITLE) #define ADDALINE(vTEXT ) logContent += QString("%1\n" ).arg(vTEXT ) #define ADDTOLOG(vINDEX) index = vINDEX; logContent += title(index) + sep + value(index) + sep + unit(index) + "\n"; /*! * \brief TreatmentLog::TreatmentLog * The constructor to initial the Treatment Log * \param parent */ TreatmentLog::TreatmentLog(QObject *parent) : QObject(parent) { initConnections(); logPath(Logger::eLogTrtmt, _Logger.logPath(Logger::eLogTrtmt)); } /*! \brief Connection Initializer \details All the class signal/slot connections are defined here. */ void TreatmentLog::initConnections() { connect(&_Logger , SIGNAL(didLogPathSet(Logger::LogType, const QString &)), this , SLOT( onLogPathSet(Logger::LogType, const QString &))); connect(&_exportWatcher , SIGNAL(finished()), this , SLOT(onExport())); connect(&_saveWatcher , SIGNAL(finished()), this , SLOT(onSave ())); } /*! * \brief TreatmentLog::initModel * Initializing the model for the constant values. * \param vData - the response model data. */ void TreatmentLog::initModel(const AdjustTreatmentLogResponseData &vData, const QString &vPatientID) { // Formatted values QString mStrText = "%1"; // qDebug() << _Settings.groups(); // SRSUI910 : PRS178 : Clinical - Data - Order QString mTreatmentDurationFmt = QTime (0, 0).addSecs(vData.mTreatmentDuration ).toString(_timeFormat); QString mActualTreatmentDurationFmt = QTime (0, 0).addSecs(vData.mActualTreatmentDuration ).toString(_timeFormat); QString mTreatmentDuration = QString::number(vData.mTreatmentDuration / 60 ); // Converted seconds to minutes. QString mActualTreatmentDuration = QString::number(vData.mActualTreatmentDuration / 60 ); // Converted seconds to minutes. QString mTreatmentStartDateTime = Format::fromEpoch( vData.mTreatmentStartEpoch , _datetimeFormat); QString mTreatmentEndDateTime = Format::fromEpoch( vData.mTreatmentEndEpoch , _datetimeFormat); // TODO : The settings needs modification not only to define the category and groups in a common header but also the settings itself needs some mods. // - the category shall become as part of the group // - the structure of the settings should become horizontal which vertical now. QString mAcidConcentrateType = _Settings.key("Acid Concentrate" , vData.mAcidConcentrateType ); QString mBicarbonateConcentrateType = _Settings.key("Bicarbonate Concentrate" , vData.mBicarbonateConcentrateType ); QString mDialyzerType = _Settings.key("Dialyzer Type" , vData.mDialyzerType ); QString mHeparinType = _Settings.key("Heparin Type" , vData.mHeparinType ); QString mWaterSampleTestResult = _Settings.key("Water Sample Result" , vData.mWaterSampleTestResult ); // init/fill/clear the _values _values.clear(); for (int i = 0; i < eTreatmentLogIndexCount; i++) _values << ""; _values[ePatientID ] = vPatientID.trimmed() ; _values[eDeviceID ] = mStrText.arg(vData.mDeviceID ); _values[eBloodFlowRate ] = mStrText.arg(vData.mBloodFlowRate ); _values[eDialysateFlowRate ] = mStrText.arg(vData.mDialysateFlowRate ); _values[eTreatmentDuration ] = mTreatmentDuration ; _values[eActualTreatmentDuration ] = mActualTreatmentDuration ; _values[eAcidConcentrateType ] = mAcidConcentrateType ; _values[eBicarbonateConcentrateType ] = mBicarbonateConcentrateType ; _values[ePotassiumConcentration ] = mStrText.arg(vData.mPotassiumConcentration ); _values[eCalciumConcentration ] = mStrText.arg(vData.mCalciumConcentration ); _values[eBicarbonateConcentration ] = mStrText.arg(vData.mBicarbonateConcentration ); _values[eSodiumConcentration ] = mStrText.arg(vData.mSodiumConcentration ); _values[eDialysateTemperature ] = mStrText.arg(vData.mDialysateTemperature ,FLOAT3 ); _values[eDialyzerType ] = mDialyzerType ; _values[eHeparinType ] = mHeparinType ; _values[eHeparinConcentration ] = mStrText.arg(vData.mHeparinConcentration ); _values[eHeparinBolusVolume ] = mStrText.arg(vData.mHeparinBolusVolume ,FLOAT3 ); _values[eHeparinDispenseRate ] = mStrText.arg(vData.mHeparinDispenseRate ,FLOAT3 ); _values[eHeparinStop ] = mStrText.arg(vData.mHeparinStop ); _values[eHeparinDeliveredVolume ] = mStrText.arg(vData.mHeparinDeliveredVolume ,FLOAT3 ); _values[eTreatmentStartDateTime ] = mTreatmentStartDateTime ; _values[eTreatmentEndDateTime ] = mTreatmentEndDateTime ; _values[eWaterSampleTestResult ] = mWaterSampleTestResult ; _values[eDialysateVolumeUsed ] = mStrText.arg(vData.mDialysateVolumeUsed ,FLOAT3 ); _values[eTargetUFVolume ] = mStrText.arg(vData.mTargetUFVolume ,FLOAT3 ); _values[eActualUFVolume ] = mStrText.arg(vData.mActualUFVolume ,FLOAT3 ); _values[eTargetUFRate ] = mStrText.arg(vData.mTargetUFRate ,FLOAT3 ); _values[eActualUFRate ] = mStrText.arg(vData.mActualUFRate ,FLOAT3 ); _values[eSalineBolusVolume ] = mStrText.arg(vData.mSalineBolusVolume ); _values[eAverageBloodFlow ] = mStrText.arg(vData.mAverageBloodFlow ,FLOAT3 ); _values[eAverageDialysateFlow ] = mStrText.arg(vData.mAverageDialysateFlow ,FLOAT3 ); _values[eAverageDialysateTemp ] = mStrText.arg(vData.mAverageDialysateTemp ,FLOAT3 ); _values[eAverageArterialPressure ] = mStrText.arg(vData.mAverageArterialPressure ,FLOAT3 ); _values[eAverageVenousPressure ] = mStrText.arg(vData.mAverageVenousPressure ,FLOAT3 ); } /*! * \brief TreatmentLog::append * \param vData - the received data to be kept in the list to be appended at the end of the Treatment Log */ void TreatmentLog::append(const TreatmentLogAvrgeData &vData) { _treatmentLogAvrgeData.append(vData); } void TreatmentLog::append(const TreatmentLogAlarmData &vData) { _treatmentLogAlarmData.append(vData); } void TreatmentLog::append(const TreatmentLogEventData &vData) { _treatmentLogEventData.append(vData); } /*! * \brief TreatmentLog::onLogPathSet * \details sets the logging path * \param vLogType - The log type which in this should be eLogTrtmt * \param vLogPath - The full treatment log path */ void TreatmentLog::onLogPathSet(Logger::LogType vLogType, const QString &vLogPath) { logPath(vLogType, vLogPath); } /*! * \brief TreatmentLog::logPath * \details sets the treatment log path if the given type is treatment log, with the path, vLogPath. * If the given vLogPath is empty, the defaults in Storage will be used. * \sa Storage::SDCard_Base_Path_Name * \sa Storage::Treatment_Log_Folder * \param vLogType - The Log type of type Logger::LogType * \param vLogPath - the path to be set and used. */ void TreatmentLog::logPath(Logger::LogType vLogType, QString vLogPath) { if (vLogType == Logger::eLogTrtmt) { if ( vLogPath.trimmed().isEmpty() ) { _treatmentLogPath = QString("%1%2") .arg(Storage::SDCard_Base_Path_Name) .arg(Storage::Treatment_Log_Folder ); } else { _treatmentLogPath = vLogPath; } LOG_DEBUG(QString("Treatment log folder has been set to %1").arg(_treatmentLogPath)); } } // ----- Save /*! * \brief TreatmentLog::doSave * The save slot to be exposed to the UI to be able to request for save */ void TreatmentLog::doSave() { if (_saveWatcher.isRunning()) return; isIdle(false); saveLogConcurrent(); } /*! * \brief TreatmentLog::saveLogConcurrent * The treatment log save which is using a thread pool to run the save process. */ void TreatmentLog::saveLogConcurrent() { LOG_DEBUG("Save Treatment Log Started"); QFuture mFuture = QtConcurrent::run(this, &TreatmentLog::saveLog); _saveWatcher.setFuture(mFuture); } /*! * \brief TreatmentLog::saveLog * The actual treatment log save function which does the save into the treatment log * \return true on successful save and false otherwise. */ bool TreatmentLog::saveLog() { bool ok = (unsigned)_values.count() >= eTreatmentLogIndexCount; if (!ok) return false; QString logContent ; QString sep = "," ; QString csv = "%1" + sep; QString end = "%1" ; uint index = 0 ; ADDTITLE("Title"); ADDTOLOG( ePatientID ); ADDTOLOG( eDeviceID ); ADDTITLE("Treatment Prescription" ); ADDTOLOG( eTreatmentDuration ); ADDTOLOG( eBloodFlowRate ); ADDTOLOG( eDialysateFlowRate ); ADDTOLOG( eAcidConcentrateType ); ADDTOLOG( eBicarbonateConcentrateType ); ADDTOLOG( ePotassiumConcentration ); ADDTOLOG( eCalciumConcentration ); ADDTOLOG( eBicarbonateConcentration ); ADDTOLOG( eSodiumConcentration ); ADDTOLOG( eDialysateTemperature ); ADDTOLOG( eDialyzerType ); ADDTOLOG( eHeparinType ); ADDTOLOG( eHeparinConcentration ); ADDTOLOG( eHeparinBolusVolume ); ADDTOLOG( eHeparinDispenseRate ); ADDTOLOG( eHeparinStop ); ADDTITLE("Treatment Parameters" ); ADDTOLOG( eTreatmentStartDateTime ); ADDTOLOG( eTreatmentEndDateTime ); ADDTOLOG( eActualTreatmentDuration ); ADDTITLE("Post-Treatment Data" ); ADDTOLOG( eDialysateVolumeUsed ); ADDTOLOG( eTargetUFVolume ); ADDTOLOG( eActualUFVolume ); ADDTOLOG( eSalineBolusVolume ); ADDTOLOG( eHeparinDeliveredVolume ); ADDTITLE("Extra" ); ADDTOLOG( eWaterSampleTestResult ); ADDTOLOG( eTargetUFRate ); ADDTOLOG( eActualUFRate ); ADDTOLOG( eAverageBloodFlow ); ADDTOLOG( eAverageDialysateFlow ); ADDTOLOG( eAverageDialysateTemp ); ADDTOLOG( eAverageArterialPressure ); ADDTOLOG( eAverageVenousPressure ); ADDTITLE("Treatment Data" ); for ( const TreatmentLogAvrgeData &item : _treatmentLogAvrgeData ) { QString line; line += csv.arg(item.mTimeStamp ); line += csv.arg(NONE ); line += csv.arg(item.mBloodFlowRate ); line += csv.arg(item.mDialysateFlowRate ); line += csv.arg(item.mUFRate ,FLOAT3 ); line += csv.arg(item.mArterialPressure ,FLOAT3 ); line += csv.arg(item.mVenousPressure ,FLOAT3 ); line += csv.arg(item.mSystolic ); line += csv.arg(item.mDiastolic ); line += end.arg(item.mHeartRate ); ADDALINE(line); } ADDTITLE("Treatment Alarms" ); for ( const TreatmentLogAlarmData &item : _treatmentLogAlarmData ) { QString line; line += csv.arg(item.mTimeStamp ); line += csv.arg(item.mAlarmID ); line += csv.arg(item.mParam1 ); line += end.arg(item.mParam2 ); ADDALINE(line); } ADDTITLE("Treatment Events" ); for ( const TreatmentLogEventData &item : _treatmentLogEventData ) { QString line; line += csv.arg(item.mTimeStamp ); line += csv.arg(item.mEventID ); line += csv.arg(item.mOldValue ,FLOAT3 ); line += end.arg(item.mNewValue ,FLOAT3 ); ADDALINE(line); } ADDALINE(""); QString mDateTime = _values[eTreatmentStartDateTime]; mDateTime.replace("/", "" ); // remove date separator mDateTime.replace(":", "" ); // remove time separator mDateTime.replace(" ", "_"); // replace spaces QString mDeviceID = _values[eDeviceID]; QString mFileName = QString("%1_%2.log") .arg(mDateTime) .arg(mDeviceID); ok = Storage::FileHandler::makeFolder(_treatmentLogPath); if ( ! ok ) { LOG_DEBUG(QString("Cannot create folder %1").arg(_treatmentLogPath)); return ok; } ok = Storage::FileHandler::write(mFileName.prepend(_treatmentLogPath), logContent, false); if ( ! ok ) { LOG_DEBUG(QString("Cannot write to file %1").arg(mFileName )); return ok; } _treatmentLogAvrgeData.clear(); _treatmentLogAlarmData.clear(); _treatmentLogEventData.clear(); return ok; } /*! * \brief TreatmentLog::onSave * The private save slot which is called after the save process is finished saving. */ void TreatmentLog::onSave() { LOG_DEBUG(QString("Save Treatment Log Ended: %1").arg(_saveWatcher.result())); isIdle(true); } // ----- Export /*! * \brief TreatmentLog::doExport * The export treatment log slot to be exposed to the UI to be able to request for the export. */ void TreatmentLog::doExport() { if (_exportWatcher.isRunning()) return; isIdle(false); exportLogConcurrent(); } /*! * \brief TreatmentLog::exportLogConcurrent * The treatment log export which is using a thread pool to run the save process. */ void TreatmentLog::exportLogConcurrent() { LOG_DEBUG("Export Treatment Log Started"); QFuture mFuture = QtConcurrent::run(this, &TreatmentLog::exportLog); _exportWatcher.setFuture(mFuture); } /*! * \brief TreatmentLog::exportLog * The actual treatment log export function which does the export of the treatment log into the USB drive. * \return */ bool TreatmentLog::exportLog() { bool ok; QString exportPath = Storage::USB_Mount_Point; Storage::FileHandler::makeFolder(exportPath); ok = FileHandler::copyFolder(_treatmentLogPath , exportPath); return ok; } /*! * \brief TreatmentLog::onExport * The private export slot which is called after the export process is finished exporting. */ void TreatmentLog::onExport() { LOG_DEBUG(QString("Export Treatment Log Ended: %1").arg(_exportWatcher.result())); isIdle(true); }