Index: sources/storage/TreatmentLog.cpp =================================================================== diff -u -rc2ed4667b513c51c5ee31566c15d2cf5a042ed61 -r3b323bd6a1a03429c2321a889049de1c3b11302f --- sources/storage/TreatmentLog.cpp (.../TreatmentLog.cpp) (revision c2ed4667b513c51c5ee31566c15d2cf5a042ed61) +++ sources/storage/TreatmentLog.cpp (.../TreatmentLog.cpp) (revision 3b323bd6a1a03429c2321a889049de1c3b11302f) @@ -1,13 +1,13 @@ /*! * - * Copyright (c) 2021-2023 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 TreatmentLog.cpp * \author (last) Behrouz NematiPour - * \date (last) 14-Sep-2023 + * \date (last) 13-Mar-2024 * \author (original) Behrouz NematiPour * \date (original) 04-May-2021 * @@ -22,20 +22,21 @@ #include "FileHandler.h" #include "ApplicationController.h" #include "Logger.h" -// #include "MSettings.h" #include "Settings.h" #include "CloudSyncController.h" -#include "GuiGlobals.h" -#include "MAlarmStatusData.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"; +#define ADDTOLOG( vINDEX ) index = vINDEX; logContent += title(index) + _sep + value(index) + _sep + unit(index) + "\n"; +#define ADDTOLOG_MT(vINDEX, vVALUE ) \ + index = vINDEX; \ + logContent += title(index) + _sep + \ + ( value(index).trimmed().isEmpty() ? vVALUE : value(index) ) + _sep + \ + unit(index) + "\n"; /*! * \brief TreatmentLog::TreatmentLog @@ -64,7 +65,7 @@ QOverload< const AdjustSerialNumberHDResponseData & >::of( &ApplicationController::didActionReceive ), [ this ] ( const AdjustSerialNumberHDResponseData &vData ) { - // The serial number is going to be recieved from HD + // The serial number is going to be received from HD // on POST or on request // and will be used for the device ID // which we designed initially to be different. @@ -183,13 +184,14 @@ * Initializing the model for the constant values. * \param vData - the response model data. */ -void TreatmentLog::initModel(const AdjustTreatmentLogResponseData &vData, const QString &vPatientID, bool vIsHeparinOff) +void TreatmentLog::initModel(const AdjustTreatmentLogResponseData &vData, const QString &vPatientID, bool vHeparinBolusVolumeOff, bool vHeparinDispensingRateOff) { // Formatted values QString mStrText = "%1"; // DEBUG: qDebug() << _Settings.groups(); // SRSUI910 : PRS178 : Clinical - Data - Order + bool isHeparinOff = vHeparinBolusVolumeOff && vHeparinDispensingRateOff; QString mTreatmentDurationFmt = QTime (0, 0).addSecs(int(vData.mTreatmentDuration )).toString(_timeFormat); QString mActualTreatmentDurationFmt = QTime (0, 0).addSecs(int(vData.mActualTreatmentDuration )).toString(_timeFormat); @@ -210,53 +212,41 @@ // init/fill/clear the _values - _valuesLog.clear(); - for (int i = 0; i < eTreatmentLogIndexCount; i++) _valuesLog << ""; + clearModel(); - _valuesLog[ePatientID ] = vPatientID.trimmed() ; - _valuesLog[eBloodFlowRate ] = mStrText.arg(vData.mBloodFlowRate ); - _valuesLog[eDialysateFlowRate ] = mStrText.arg(vData.mDialysateFlowRate ); - _valuesLog[eTreatmentDuration ] = mTreatmentDuration ; - _valuesLog[eActualTreatmentDuration ] = mActualTreatmentDuration ; - _valuesLog[eAcidConcentrateType ] = mAcidConcentrateType ; - _valuesLog[eBicarbonateConcentrateType ] = mBicarbonateConcentrateType ; - _valuesLog[ePotassiumConcentration ] = mStrText.arg(vData.mPotassiumConcentration ); - _valuesLog[eCalciumConcentration ] = mStrText.arg(vData.mCalciumConcentration ); - _valuesLog[eBicarbonateConcentration ] = mStrText.arg(vData.mBicarbonateConcentration ); - _valuesLog[eSodiumConcentration ] = mStrText.arg(vData.mSodiumConcentration ); - _valuesLog[eDialysateTemperature ] = mStrText.arg(vData.mDialysateTemperature ,FLOAT3 ); - _valuesLog[eDialyzerType ] = mDialyzerType ; - _valuesLog[eHeparinType ] = mHeparinType ; - _valuesLog[eHeparinConcentration ] = mStrText.arg(vData.mHeparinConcentration ); - _valuesLog[eHeparinBolusVolume ] = mStrText.arg(vData.mHeparinBolusVolume ,FLOAT3 ); - _valuesLog[eHeparinDispenseRate ] = mStrText.arg(vData.mHeparinDispenseRate ,FLOAT3 ); - _valuesLog[eHeparinStop ] = mStrText.arg(vData.mHeparinStop ); - _valuesLog[eHeparinDeliveredVolume ] = mStrText.arg(vData.mHeparinDeliveredVolume ,FLOAT3 ); - _valuesLog[eTreatmentStartDateTime ] = mTreatmentStartDateTime ; - _valuesLog[eTreatmentEndDateTime ] = mTreatmentEndDateTime ; - _valuesLog[eWaterSampleTestResult ] = mWaterSampleTestResult ; - _valuesLog[eDialysateVolumeUsed ] = mStrText.arg(vData.mDialysateVolumeUsed ,FLOAT3 ); - _valuesLog[eOriginUFVolume ] = mStrText.arg(vData.mOriginUFVolume ,FLOAT3 ); - _valuesLog[eTargetUFVolume ] = mStrText.arg(vData.mTargetUFVolume ,FLOAT3 ); - _valuesLog[eActualUFVolume ] = mStrText.arg(vData.mActualUFVolume ,FLOAT3 ); - _valuesLog[eOriginUFRate ] = mStrText.arg(vData.mOriginUFRate ,FLOAT3 ); - _valuesLog[eTargetUFRate ] = mStrText.arg(vData.mTargetUFRate ,FLOAT3 ); - _valuesLog[eActualUFRate ] = mStrText.arg(vData.mActualUFRate ,FLOAT3 ); - _valuesLog[eSalineBolusVolume ] = mStrText.arg(vData.mSalineBolusVolume ); + _values[ePatientID ] = vPatientID.trimmed() ; + _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[eTreatmentStartDateTime ] = mTreatmentStartDateTime ; + _values[eTreatmentEndDateTime ] = mTreatmentEndDateTime ; + _values[eWaterSampleTestResult ] = mWaterSampleTestResult ; + _values[eDialysateVolumeUsed ] = mStrText.arg(vData.mDialysateVolumeUsed ,FLOAT3 ); + _values[eOriginUFVolume ] = mStrText.arg(vData.mOriginUFVolume ,FLOAT3 ); + _values[eTargetUFVolume ] = mStrText.arg(vData.mTargetUFVolume ,FLOAT3 ); + _values[eActualUFVolume ] = mStrText.arg(vData.mActualUFVolume ,FLOAT3 ); + _values[eOriginUFRate ] = mStrText.arg(vData.mOriginUFRate ,FLOAT3 ); + _values[eTargetUFRate ] = mStrText.arg(vData.mTargetUFRate ,FLOAT3 ); + _values[eActualUFRate ] = mStrText.arg(vData.mActualUFRate ,FLOAT3 ); + _values[eSalineBolusVolume ] = mStrText.arg(vData.mSalineBolusVolume ); - //https://diality.atlassian.net/browse/DEN-15911 - _valuesGui = _valuesLog; - if ( ! vIsHeparinOff ) goto lOut; + _values[eHeparinType ] = isHeparinOff ? tr("NONE") : mHeparinType ; + _values[eHeparinConcentration ] = isHeparinOff ? tr("NONE") : mStrText.arg(vData.mHeparinConcentration ); + _values[eHeparinBolusVolume ] = vHeparinBolusVolumeOff ? tr("OFF" ) : mStrText.arg(vData.mHeparinBolusVolume ,FLOAT3 ); + _values[eHeparinDispenseRate ] = vHeparinDispensingRateOff ? tr("OFF" ) : mStrText.arg(vData.mHeparinDispenseRate ,FLOAT3 ); + _values[eHeparinStop ] = vHeparinDispensingRateOff ? tr("OFF" ) : mStrText.arg(vData.mHeparinStop ); + _values[eHeparinDeliveredVolume ] = isHeparinOff ? tr("OFF" ) : mStrText.arg(vData.mHeparinDeliveredVolume ,FLOAT3 ); - _valuesGui[eHeparinType ] = tr("NONE"); - _valuesGui[eHeparinConcentration ] = tr("NONE"); - _valuesGui[eHeparinBolusVolume ] = tr("NONE"); - _valuesGui[eHeparinDispenseRate ] = tr("NONE"); - _valuesGui[eHeparinStop ] = tr("NONE"); - _valuesGui[eHeparinDeliveredVolume ] = tr("NONE"); - -lOut: - emit didTxCodeReceive("..."); /* put ... just to notify user about the wait for data */ + emit didTxCodeReceive(""); } /*! @@ -333,18 +323,20 @@ bool TreatmentLog::saveLog() { _lastTxInfo.clear(); - bool ok = (unsigned)_valuesLog.count() >= eTreatmentLogIndexCount; + bool ok = (unsigned)_values.count() >= eTreatmentLogIndexCount; if (!ok) return false; - QString logContent ; - QString sep = "," ; - QString csv = "%1" + sep; - QString end = "%1" ; - uint index = 0 ; + QString logContent ; + QString csv = "%1" + _sep ; + QString end = "%1" ; + uint index = 0 ; + QString txCode = "%1,%2," ; - // ADDTITLE("Title"); // will be added with Tx Code when gets out of pending, by receiving the Tx Code from CloudSync - ADDTOLOG( ePatientID ); + ADDTITLE("Title"); + ADDALINE(txCode + .arg(_txCodeKey).arg(_gTxCode) ); + ADDTOLOG_MT( ePatientID, _emptyPatinetID ); ADDTITLE("Treatment Parameters" ); ADDTOLOG( eTreatmentDuration ); @@ -421,13 +413,13 @@ } ADDALINE(""); - _lastTxInfo.mDateTime = _valuesLog[eTreatmentStartDateTime]; + _lastTxInfo.mDateTime = _values[eTreatmentStartDateTime]; _lastTxInfo.mDateTime.replace("/", "" ); // remove date separator _lastTxInfo.mDateTime.replace(":", "" ); // remove time separator _lastTxInfo.mDateTime.replace(" ", "_"); // replace spaces _lastTxInfo.mDeviceID = _deviceID; - _lastTxInfo.mPatientID = _valuesLog[ePatientID]; + _lastTxInfo.mPatientID = _values[ePatientID]; _lastTxInfo.mFileName = QString("%1%2_%3.%4") .arg(_treatmentLogPath) .arg(_lastTxInfo.mDateTime) @@ -551,59 +543,72 @@ */ void TreatmentLog::onTxCodeReceive(const QString &vTxCode) { - _txCode = vTxCode; + _rTxCode = vTxCode; // This has to be checked before the addTxCode, // because that function will change the _lastTxInfo.mFilename after it is moved from pending. - bool isLastTxInfo = ! _lastTxInfo.mFileName.isEmpty() && _pendingTx == _lastTxInfo.mFileName; + bool isLastTxInfo = ! _lastTxInfo.mFileName.isEmpty() && _pendingTxr == _lastTxInfo.mFileName; // getting the Tx out of pending and add the received Tx in the file - addTxCode(); + checkTxCode(); if ( isLastTxInfo ) { // avoid updating the screen with another pending Tx in queue - emit didTxCodeReceive(_txCode); + emit didTxCodeReceive(_rTxCode); } } /*! - * \brief TreatmentLog::addTxCode - * \details Adds the [Title] and Tx Code to the file and moves it from pending. + * \brief TreatmentLog::checkTxCode + * \details Compares the received TxCode with the generated and if matches renames Txr from pending. * \return true on success, false on any case of read, write, remove. */ -bool TreatmentLog::addTxCode() +bool TreatmentLog::checkTxCode() { bool ok = true; - QString src = _pendingTx; + QString src = _pendingTxr; QString dst = QString("%1%2.%3") .arg(_treatmentLogPath) .arg(QFileInfo(src).baseName()) .arg(_treatmentLogExtUploaded); - QString logContent; - ADDTITLE("Title"); - ADDALINE(QString("Tx Code,%1,").arg(_txCode)); - ok = FileHandler::read (src, logContent, true ); // reads the file and appends the content to logContent + ok = _gTxCode == _rTxCode; if ( ! ok ) { - LOG_DEBUG(QString("Couldn't read pending treatment log file '%1'").arg(src)); + LOG_DEBUG(QString("Generated '%1' TxCode and Received TxCode '%2' does not match").arg(_gTxCode).arg(_rTxCode)); return ok; } - ok = FileHandler::write (dst, logContent ); + ok = QFile::rename(src, dst); if ( ! ok ) { - LOG_DEBUG(QString("Couldn't settle pending treatment log file '%1'").arg(src)); + LOG_DEBUG(QString("Couldn't change the state of pending treatment log file '%1'").arg(src)); return ok; } - - QFile::remove(src); - if ( ! ok ) { - LOG_DEBUG(QString("Couldn't remove pending treatment log file '%1'").arg(src)); - return ok; - } _lastTxInfo.mFileName = dst; // Update the last Tx file to the new location [ export ] sendPending(); // start looking for the next pending, instead of waiting to timeout return ok; } +bool TreatmentLog::findTxCode() +{ + bool ok = false; + QString content = ""; + FileHandler::read(_pendingTxr, content); + QStringList lines = content.split('\n'); + for ( const QString &line : lines ) { + if ( line.contains(_txCodeKey) ) { + QStringList fields = line.split(','); + if ( fields.count() >= Role::eCount ) { + if ( fields[Role::eTitle] == _txCodeKey ) { + if ( fields[Role::eValue].length() ) { + _gTxCode = fields[Role::eValue]; + ok = true; + } + } + } + } + } + return ok; +} + /*! * \brief TreatmentLog::sendPending * \details Resets the pending counter to immediately/ASAP as for the pending and won't waits for the timeout. @@ -615,14 +620,14 @@ /*! * \brief TreatmentLog::testPendingTxReports - * \details this function count downs for the _pendingInterval + * \details this function counts downs for the _pendingInterval * when the _pendingCounter reaches 0 will search for the files - * in the _TreatmentLog.logPathPending() * and if there is any will get the recent file in the list - * and asks for the TxCode by emitting the didTxPending signal + * and asks for the TxCode by emitting the didPendingTxr signal */ void TreatmentLog::testPendingTxReports() { + static QString pendingTxr = ""; if ( _pendingCounter ) { _pendingCounter -- ; return; @@ -640,7 +645,14 @@ // the process repeats until there is no file in pending if ( pendingFiles.count() ) { // the most recent/first Tx file, to first ask for the current treatment which has just saved as pending on screen - _pendingTx = pendingFiles.first().absoluteFilePath(); - emit didTxPending( _pendingTx ); + _pendingTxr = pendingFiles.first().absoluteFilePath(); + // DEBUG qDebug() << _pendingTxr; + if (pendingTxr != _pendingTxr ) { + pendingTxr = _pendingTxr; + findTxCode(); + } + QString message = pendingTxr + " , " + _pendingTxr + " , " + _gTxCode; + LOG_DEBUG(message); + emit didPendingTxr( _pendingTxr ); } }