#include #include "StateController.h" #include "ApplicationController.h" #include "types.h" float StateController::getBloodPrimeRampStepML() { qint32 setBPRateMLPM = _treatmentParams.bloodFlowRateMLPM - BLOOD_PRIME_START_FLOW_MLPM; float rampRateS = ((BLOOD_PRIME_VOLUME_ML / (setBPRateMLPM + BLOOD_PRIME_VOLUME_ML) / BLOOD_PRIME_START_FLOW_MLPM) / 2.0) * SECONDS_PER_MINUTE; // qDebug() << "Step cal" << _treatmentParams.bloodFlowRateMLPM << setBPRateMLPM << rampRateS; rampRateS = (rampRateS < SECONDS_PER_MINUTE ? SECONDS_PER_MINUTE : rampRateS); float rampStepML = setBPRateMLPM / rampRateS; return rampStepML; } void StateController::handleBloodPrimePauseResume(bool &resume) { if (_treatmentRcvdMessages[ID_UI_BLOOD_PRIME_CMD_RQST].isNull()) { return; } handleUIResponseMessage(ID_TD_BLOOD_PRIME_CMD_RESP, ACCEPT_VALUE); quint32 resumeStatus = extractU32DataFromReceivedMessage(ID_UI_BLOOD_PRIME_CMD_RQST, 0); resume = (resumeStatus == BLOOD_PRIME_RESUME ? true : false); _treatmentSubStates.bloodPrimeState = (resumeStatus == BLOOD_PRIME_RESUME ? BLOOD_PRIME_RUN_STATE : BLOOD_PRIME_PAUSED_STATE); // Send the results immediately handleTreatmentStatesBroadcastData(BC_IMMEDIATELY); _treatmentRcvdMessages[ID_UI_BLOOD_PRIME_CMD_RQST].clear(); } void StateController::handleBloodPrimeVolML(const bool resume, const float rampStepML, const bool hasFlowChanged, quint32 &currBloodFlowMLPM, float &accumBloodVolML) { static quint32 primeTimeoutS = 0; static quint32 pauseCountDownS = 0; static quint32 elapsedTimeSincePauseS = 0; static quint32 controlCounter = 0; // Assume the blood pump is running unless the pause button has been resumed _treatmentStatus.isBloodPumpRunning = true; if (!resume) { // If the user has pressed pause, then do the countdown and broadcast // TODO should we exit is the timeout has happened? elapsedTimeSincePauseS += (QOBJECT_TIMER_TIMEOUT_MS); primeTimeoutS = BLOOD_PRIME_PAUSE_TIMEOUT_S; pauseCountDownS = ( elapsedTimeSincePauseS / MILLISECONDS_PER_SECOND < BLOOD_PRIME_PAUSE_TIMEOUT_S ? BLOOD_PRIME_PAUSE_TIMEOUT_S - elapsedTimeSincePauseS / MILLISECONDS_PER_SECOND : pauseCountDownS ); handleBloodPrimeBroadcastData(accumBloodVolML, primeTimeoutS, pauseCountDownS, BC_DELAYED); // Blood prime has been paused so the blood pump is not running _treatmentStatus.isBloodPumpRunning = false; return; } accumBloodVolML += (currBloodFlowMLPM * BLOOD_PRIME_FLOW_INTEGRATOR); if (++controlCounter % NUM_OF_COUNTS_TIMER_2_CONTROL != 0) { return; } if (!hasFlowChanged) { // If the user has changed the flow then do not control (ramp) the steps currBloodFlowMLPM += rampStepML; // qDebug() << "Flow calc" << currBloodFlowMLPM; if (rampStepML < 0){ // If the ramp is negative, check the current flow not be less than target and if it is, set it to min // e.g. current flow calculated = 30 mL/min, treatment params = 50 mL/min, Set it to 50 mL/min currBloodFlowMLPM = (currBloodFlowMLPM < _treatmentParams.bloodFlowRateMLPM ? _treatmentParams.bloodFlowRateMLPM : currBloodFlowMLPM); } else { currBloodFlowMLPM = (currBloodFlowMLPM > _treatmentParams.bloodFlowRateMLPM ? _treatmentParams.bloodFlowRateMLPM : currBloodFlowMLPM); } } primeTimeoutS = 0; pauseCountDownS = 0; elapsedTimeSincePauseS = 0; handleBloodPrimeBroadcastData(accumBloodVolML, primeTimeoutS, pauseCountDownS, BC_IMMEDIATELY); //qDebug() << "Current" << currBloodFlowMLPM << _treatmentParams.bloodFlowRateMLPM << controlCounter << accumBloodVolML; } void StateController::setTreatmentParametersToDefault() { // TODO complete the list as we go _treatmentParams.finalConfirmation = true; _treatmentParams.treatmentModality = 0; // TODO set the actual enum value _treatmentParams.bloodFlowRateMLPM = DEF_TX_PARAM_BLOOD_FLOW_RATE_MLPM; _treatmentParams.dialysateFlowRateMLPM = DEF_TX_PARAM_DIAL_FLOW_RATE_MLPM; _treatmentParams.treatmentDurationMin = DEF_TX_PARAM_PRESCRIBED_DUR_MIN; _treatmentParams.dialysateTemperatureC = DEF_TX_PARAM_DIA_TEMPERATURE_C; _treatmentParams.fluidBlousVolumeML = DEF_TX_PARAM_SALINE_BOLUS_VOL_ML; _treatmentParams.ufVolumeL = DEF_TX_PARAM_UF_VOLUME_L; _treatmentParams.rinsebackVolumeML = DEF_TX_PARAM_RINSEBACK_VOLUME_ML; } void StateController::initializeTreatmentTimeAndUltrafiltration() { if (_treatmentStatus.hasTxParamsBeenInitialized) { _treatmentStatus.treatmentElapsedTimeMS = 0; } _treatmentStatus.presUFRateMLPM = (_treatmentParams.ufVolumeL * MILLILITERS_PER_LITER) / (static_cast(_treatmentParams.treatmentDurationMin)); float presUFVolL = _treatmentParams.ufVolumeL; float presUFRateLHR = presUFVolL / (static_cast(_treatmentParams.treatmentDurationMin) / static_cast(MINUTES_PER_HOUR)); float UFVolLMS = presUFRateLHR / (static_cast(MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND)); _treatmentStatus.ufVolDeliveredL = UFVolLMS * _treatmentStatus.treatmentElapsedTimeMS; qDebug() << "UF Init" << presUFRateLHR << UFVolLMS << _treatmentStatus.ufVolDeliveredL; } void StateController::handleFluidBolusRequestMessage() { if (! _treatmentRcvdMessages[ID_UI_FLUID_BOLUS_RQST].isNull()){ quint32 fluidBolusCmd = extractU32DataFromReceivedMessage(ID_UI_FLUID_BOLUS_RQST, 0); // Assume the fluid bolus is not in progress _treatmentSubStates.fluidBolusState = FLUID_BOLUS_IDLE_STATE; if (fluidBolusCmd == FLUID_BOLUS_START_CMD){ _treatmentSubStates.fluidBolusState = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; _treatmentSubStates.dialysisSubState = DIALYSIS_UF_FLUID_BOLUS_STATE; } else { _treatmentStatus.totalFluidBolusDeliveredML += _treatmentStatus.accumFluidBolusDeliveredML; } _treatmentRcvdMessages[ID_UI_FLUID_BOLUS_RQST].clear(); handleUIResponseMessage(ID_TD_FLUID_BOLUS_RESP, ACCEPT_VALUE, {static_cast(REQUEST_REJECT_REASON_NONE), _treatmentParams.fluidBlousVolumeML}); } if (! _treatmentRcvdMessages[ID_UI_BOLUS_VOLUME_CHANGE_RQST].isNull()){ quint32 fluidBolusVolML = extractU32DataFromReceivedMessage(ID_UI_BOLUS_VOLUME_CHANGE_RQST, 0); // TODO Check the range of the requested bolus volume _treatmentParams.fluidBlousVolumeML = fluidBolusVolML; _treatmentRcvdMessages[ID_UI_BOLUS_VOLUME_CHANGE_RQST].clear(); handleUIResponseMessage(ID_TD_BOLUS_VOLUME_CHANGE_RESP, ACCEPT_VALUE); } } void StateController::handleFluidBolusFluidDelivery(const quint32 bloodFlowMLPM) { if (_treatmentSubStates.fluidBolusState != FLUID_BOLUS_SALINE_IN_PROGRESS_STATE) { return; } float timeSinceLastTimeMin = static_cast(QOBJECT_TIMER_TIMEOUT_MS) / static_cast(MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE); _treatmentStatus.accumFluidBolusDeliveredML += static_cast(bloodFlowMLPM) * timeSinceLastTimeMin; if (_treatmentStatus.accumFluidBolusDeliveredML >= _treatmentParams.fluidBlousVolumeML) { _treatmentSubStates.fluidBolusState = FLUID_BOLUS_IDLE_STATE; _treatmentSubStates.dialysisSubState = DIALYSIS_UF_STATE; _treatmentStatus.totalFluidBolusDeliveredML += _treatmentStatus.accumFluidBolusDeliveredML; _treatmentStatus.accumFluidBolusDeliveredML = 0.0; // Immediately broadcast the results to be updated handleFluidBolusBroadcastData(BC_IMMEDIATELY); } //qDebug() << "Bolus" << _treatmentStatus.accumFluidBolusDeliveredML << _treatmentStatus.totalFluidBolusDeliveredML; } void StateController::handleTreatmentPrescriptionEditRequestMessage() { if (_treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINTS_CHANGE_RQST].isNull()) { return; } // TODO range check the parameters QVariantList resp; resp.append(static_cast(ID_TD_TREATMENT_SET_POINTS_CHANGE_RESP)); resp.append(Can_Id::eChlid_TD_UI); resp.append(ACCEPT_VALUE); QVariant payload = _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINTS_CHANGE_RQST]; qint32 index = 0; Types::U32 u32Var; Types::F32 f32Var; GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.bloodFlowRateMLPM = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.dialysateFlowRateMLPM = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, f32Var); _treatmentParams.dialysateTemperatureC = f32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); if (_treatmentParams.acidConcentrate != u32Var.value) { triggerAnAlarm(ALARM_ID_TD_REPLACE_ACID_JUG); } _treatmentParams.acidConcentrate = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, f32Var); _treatmentParams.acidKConcentrateConversionFactor = f32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.bicarbobateMEQL = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.treatmentModality = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.hepatitisBStatus = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.sodiumMEQL = u32Var.value; resp.append(0); GetValue(payload.toByteArray(), index, u32Var); _treatmentParams.bicarbobateMEQL = u32Var.value; resp.append(0); _isSendListReady = false; _sendMessages.append(resp); _isSendListReady = true; _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINTS_CHANGE_RQST].clear(); } void StateController::handleSetPointBloodFlowChange(quint32 &bloodFlowMLPM, bool &hasBloodFlowChanged) { if (_treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST].isNull()) { return; } // TODO do we need to check the range bloodFlowMLPM = extractU32DataFromReceivedMessage(ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST, 0); handleUIResponseMessage(ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESP, ACCEPT_VALUE); hasBloodFlowChanged = true; handleTreatmentSetpointsBroadcastData(bloodFlowMLPM, _treatmentParams.dialysateFlowRateMLPM, _treatmentParams.dialysateTemperatureC, BC_IMMEDIATELY); _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST].clear(); } void StateController::handleSetPointDialysateFlowChange() { if (_treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RQST].isNull()) { return; } // TODO do we need to check the range _treatmentParams.dialysateFlowRateMLPM = extractU32DataFromReceivedMessage(ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RQST, 0); handleUIResponseMessage(ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESP, ACCEPT_VALUE); handleTreatmentSetpointsBroadcastData(_treatmentParams.bloodFlowRateMLPM, _treatmentParams.dialysateFlowRateMLPM, _treatmentParams.dialysateTemperatureC, BC_IMMEDIATELY); _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RQST].clear(); } void StateController::handleSetPointDialysateTemperatureChange() { if (_treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RQST].isNull()){ return; } // TODO range check _treatmentParams.dialysateTemperatureC = extractF32DataFromReceivedMessage(ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RQST, 0); handleUIResponseMessage(ID_TD_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RESP, ACCEPT_VALUE); handleTreatmentSetpointsBroadcastData(_treatmentParams.bloodFlowRateMLPM, _treatmentParams.dialysateFlowRateMLPM, _treatmentParams.dialysateTemperatureC, BC_IMMEDIATELY); _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RQST].clear(); } void StateController::handleUltrafiltrationPauseResume() { if (_treatmentRcvdMessages[ID_UI_UF_PAUSE_RESUME_RQST].isNull()){ return; } quint32 cmd = extractU32DataFromReceivedMessage(ID_UI_UF_PAUSE_RESUME_RQST, 0); quint32 acceptReject = REJECT_VALUE; QVariantList reason; if (_treatmentSubStates.txState == TREAT_DIALYSIS_STATE) { // Assume the default state is UF state _treatmentSubStates.dialysisSubState = DIALYSIS_UF_STATE; _treatmentSubStates.dialysisSubState = (cmd == 0 ? DIALYSIS_UF_PAUSED_STATE : _treatmentSubStates.dialysisSubState); acceptReject = ACCEPT_VALUE; qDebug() << "UF Pa" << _treatmentSubStates.dialysisSubState; } else if (_treatmentSubStates.txState != TREAT_DIALYSIS_STATE) { reason.append(REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE); } else { quint32 r = (cmd == 0 ? REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS : REQUEST_REJECT_REASON_UF_NOT_PAUSED); reason.append(r); } handleUIResponseMessage(ID_TD_UF_PAUSE_RESUME_RESP, acceptReject, reason); _treatmentRcvdMessages[ID_UI_UF_PAUSE_RESUME_RQST].clear(); } void StateController::handleUltrafiltrationVolumeChangeValidation() { if (_treatmentRcvdMessages[ID_UI_TREATMENT_UF_VOLUME_VALIDATE_RQST].isNull()) { return; } QVariantList reason = {REQUEST_REJECT_REASON_NONE, 0.0, 0.0}; quint32 rejReasIndex = 0; quint32 ufGoalIndex = 1; quint32 ufRateIndex = 2; quint32 acceptReject = REJECT_VALUE; float elapsedTimeMin = _treatmentStatus.treatmentElapsedTimeMS / static_cast(SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND); float measuredUFVolML = _treatmentStatus.ufVolDeliveredL * static_cast(MILLILITERS_PER_LITER); float treatmentDurMin = static_cast(_treatmentParams.treatmentDurationMin); float requestedUFVolL = extractF32DataFromReceivedMessage(ID_UI_TREATMENT_UF_VOLUME_VALIDATE_RQST, 0); float requestedUFVolML = requestedUFVolL * static_cast(MILLILITERS_PER_LITER); reason[ufGoalIndex] = requestedUFVolL; qDebug() << "UF CLAC" << elapsedTimeMin << measuredUFVolML << treatmentDurMin << requestedUFVolL << requestedUFVolML; if ((requestedUFVolL >= MIN_UF_VOL_L) && (requestedUFVolL <= MAX_UF_VOL_L)) { if (requestedUFVolML > measuredUFVolML) { if (treatmentDurMin > elapsedTimeMin) { float remainingUFVolML = requestedUFVolML - measuredUFVolML; float remainingTreatmentTimeMin = treatmentDurMin - elapsedTimeMin; float newUFRatMLPM = remainingUFVolML / remainingTreatmentTimeMin; reason[ufRateIndex] = (newUFRatMLPM * static_cast(MINUTES_PER_HOUR)) / (static_cast(MILLILITERS_PER_LITER)); qDebug() << "UF" << remainingUFVolML << remainingTreatmentTimeMin << newUFRatMLPM << reason[ufRateIndex]; if (newUFRatMLPM <= MAX_UF_RATE_MLPM) { acceptReject = ACCEPT_VALUE; _treatmentStatus.validateUFVolReceived = true; _treatmentStatus.validateUFVolGoalL = requestedUFVolL; _treatmentStatus.validateUFRateLHR = (newUFRatMLPM * static_cast(MINUTES_PER_HOUR)) / (static_cast(MILLILITERS_PER_LITER)); } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; } } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; } } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; } } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE; } handleUIResponseMessage(ID_TD_TREATMENT_UF_VOLUME_VALIDATE_RESP, acceptReject, reason); _treatmentRcvdMessages[ID_UI_TREATMENT_UF_VOLUME_VALIDATE_RQST].clear(); } void StateController::handleUltrafiltrationVolumeChangeConfirm() { if (_treatmentRcvdMessages[ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST].isNull()) { return; } QVariantList reason; quint32 acceptReject = REJECT_VALUE; float roundedUFRateLHR = qRound(_treatmentStatus.validateUFRateLHR * 100.0) / 100.0; float requestedUFVolL = extractF32DataFromReceivedMessage(ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST, 0); float requestedUFRateLHR = extractF32DataFromReceivedMessage(ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST, 4); bool isUFVolInRange = (qAbs(requestedUFVolL - _treatmentStatus.validateUFVolGoalL) < NEARLY_ZERO ? true : false); bool isUFRateInRange = (qAbs(requestedUFRateLHR - roundedUFRateLHR) < NEARLY_ZERO ? true : false); qDebug() << "UF CONFI" << roundedUFRateLHR << requestedUFVolL << requestedUFRateLHR << isUFVolInRange << isUFRateInRange << qAbs(requestedUFRateLHR - roundedUFRateLHR); if (_treatmentStatus.validateUFVolReceived && isUFVolInRange && isUFRateInRange) { _treatmentParams.ufVolumeL = _treatmentStatus.validateUFVolGoalL; // Calcuate the new UF rate after the volume change _treatmentStatus.presUFRateMLPM = (_treatmentStatus.validateUFRateLHR * static_cast(MILLILITERS_PER_LITER)) / (static_cast(MINUTES_PER_HOUR)); _treatmentStatus.validateUFRateLHR = 0.0; _treatmentStatus.validateUFVolGoalL = 0.0; _treatmentStatus.validateUFVolReceived = false; acceptReject = ACCEPT_VALUE; } else if (!_treatmentStatus.validateUFVolReceived) { reason.append(REQUEST_REJECT_REASON_CONFIRMATION_NOT_EXPECTED); } else { reason.append(REQUEST_REJECT_REASON_CONFIRMATION_MISMATCH); } handleUIResponseMessage(ID_TD_ULTRAFILTRATION_CHANGE_CONFIRM_RESP, acceptReject, reason); _treatmentRcvdMessages[ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST].clear(); } void StateController::handleTreatmentTimeChangeValidation() { if (_treatmentRcvdMessages[ID_UI_DURATION_VALIDATE_RQST].isNull()) { return; } QVariantList reason = {REQUEST_REJECT_REASON_NONE, 0, 0, 0.0, 0.0}; quint32 acceptReject = REJECT_VALUE; quint32 rejReasIndex = 0; quint32 txDurMinsIndex = 1; quint32 hepDurMinsIndex = 2; quint32 ufGoalIndex = 3; quint32 ufRateIndex = 4; float prescribedUFVolML = _treatmentParams.ufVolumeL * static_cast(MILLILITERS_PER_LITER); float elapsedTxTimeMin = _treatmentStatus.treatmentElapsedTimeMS / static_cast(MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE); float measUFVolML = _treatmentStatus.ufVolDeliveredL * static_cast(MILLILITERS_PER_LITER); float remainingUFVolML = prescribedUFVolML - measUFVolML; quint32 requestedTxDurMin = extractU32DataFromReceivedMessage(ID_UI_DURATION_VALIDATE_RQST, 0); quint32 txHepDiffMin = 0; qDebug() << "Tx Dur1" << prescribedUFVolML << elapsedTxTimeMin << measUFVolML << remainingUFVolML << requestedTxDurMin; reason[txDurMinsIndex] = requestedTxDurMin; if ((requestedTxDurMin >= MIN_TX_TIME_MINS) && (requestedTxDurMin <= MAX_TX_TIME_MINS)) { if (static_cast(requestedTxDurMin) > elapsedTxTimeMin) { if (remainingUFVolML < 0.0) { remainingUFVolML = 0.0; } float remainingTxTimeMin = static_cast(requestedTxDurMin) - elapsedTxTimeMin; float newUFRateMLPM = remainingUFVolML / remainingTxTimeMin; reason[ufGoalIndex] = prescribedUFVolML / static_cast(MILLILITERS_PER_LITER); reason[ufRateIndex] = (newUFRateMLPM * static_cast(MINUTES_PER_HOUR)) / static_cast(MILLILITERS_PER_LITER); if (newUFRateMLPM <= MAX_UF_RATE_MLPM) { if (_treatmentParams.treatmentDurationMin > _treatmentParams.heparinDeliveryDurationMin) { txHepDiffMin = _treatmentParams.treatmentDurationMin - _treatmentParams.heparinDeliveryDurationMin; qDebug() << "Here" << _treatmentParams.treatmentDurationMin << _treatmentParams.heparinDeliveryDurationMin; } if (requestedTxDurMin > txHepDiffMin) { _treatmentStatus.validateHepDurMin = requestedTxDurMin - txHepDiffMin; } else { _treatmentStatus.validateHepDurMin = 0; } reason[hepDurMinsIndex] = _treatmentStatus.validateHepDurMin; acceptReject = ACCEPT_VALUE; qDebug() << "Hep time" << txHepDiffMin << requestedTxDurMin << _treatmentParams.heparinDeliveryDurationMin; qDebug() << "Tx Dur2" << remainingTxTimeMin << newUFRateMLPM << reason[ufGoalIndex] << reason[ufRateIndex] << reason[ufRateIndex]; _treatmentStatus.validateTxDurReceived = true; _treatmentStatus.validateTxDurMin = requestedTxDurMin; _treatmentStatus.validateUFRateLHR = (newUFRateMLPM * static_cast(MINUTES_PER_HOUR)) / static_cast(MILLILITERS_PER_LITER); _treatmentStatus.validateHepDurMin = _treatmentStatus.validateHepDurMin; } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE; } } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT; } } else { reason[rejReasIndex] = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } handleUIResponseMessage(ID_TD_DURATION_VALIDATE_RESP, acceptReject, reason); _treatmentRcvdMessages[ID_UI_DURATION_VALIDATE_RQST].clear(); } void StateController::handleTreatmentTimeChangeConfirm() { if (_treatmentRcvdMessages[ID_UI_DURATION_CONFIRM_RQST].isNull()) { return; } QVariantList reason; quint32 acceptReject = REJECT_VALUE; float roundedUFRateLHR = qRound(_treatmentStatus.validateUFRateLHR * 100.0) / 100.0; quint32 requestedTxDurMin = extractU32DataFromReceivedMessage(ID_UI_DURATION_CONFIRM_RQST, 0); quint32 requestedHepDurMin = extractU32DataFromReceivedMessage(ID_UI_DURATION_CONFIRM_RQST, 4); float requestedUFRateLHR = extractF32DataFromReceivedMessage(ID_UI_DURATION_CONFIRM_RQST, 8); bool isUFRateInRage = (qAbs(requestedUFRateLHR - roundedUFRateLHR) < NEARLY_ZERO ? true : false); qDebug() << "Tx Dur Confirm" << roundedUFRateLHR << requestedTxDurMin << requestedHepDurMin << requestedUFRateLHR << isUFRateInRage; if ((_treatmentStatus.validateTxDurReceived) && (requestedTxDurMin == _treatmentStatus.validateTxDurMin) && (isUFRateInRage) && (requestedHepDurMin == _treatmentStatus.validateHepDurMin)) { _treatmentParams.treatmentDurationMin = _treatmentStatus.validateTxDurMin; _treatmentParams.heparinDeliveryDurationMin = _treatmentStatus.validateHepDurMin; _treatmentStatus.presUFRateMLPM = (_treatmentStatus.validateUFRateLHR * MILLILITERS_PER_LITER) / (static_cast(MINUTES_PER_HOUR)); acceptReject = ACCEPT_VALUE; // Reset the validation values _treatmentStatus.validateTxDurReceived = false; _treatmentStatus.validateHepDurMin = 0; _treatmentStatus.validateTxDurMin = 0; _treatmentStatus.validateUFRateLHR = 0.0; } else if (!_treatmentStatus.validateTxDurReceived) { reason.append(REQUEST_REJECT_REASON_CONFIRMATION_NOT_EXPECTED); } else { reason.append(REQUEST_REJECT_REASON_CONFIRMATION_MISMATCH); } handleUIResponseMessage(ID_TD_DURATION_CONFIRM_RESP, acceptReject, reason); _treatmentRcvdMessages[ID_UI_DURATION_CONFIRM_RQST].clear(); } void StateController::handlePressureLimitState() { switch (_pressureVars.presLimitState) { case PRESSURE_LIMITS_STATE_OFF: if ((_treatmentSubStates.txState > TREAT_START_STATE) && (_treatmentSubStates.txState != TREAT_RECIRC_STATE)) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_IDLE; } break; case PRESSURE_LIMITS_STATE_IDLE: // TODO do we want to show the blood prime ramp? _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_WIDE; break; case PRESSURE_LIMITS_STATE_WIDE: if (!_treatmentStatus.isBloodPumpRunning) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_IDLE; } else if ((_treatmentSubStates.txState == TREAT_DIALYSIS_STATE) || (_treatmentSubStates.txState == TREAT_PAUSED_STATE)) { _pressureVars.presStabilizationTimerCtr = 0; _pressureVars.presStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_STABILIZATION; } else if (_treatmentSubStates.txState == TREAT_RECIRC_STATE) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_OFF; } break; case PRESSURE_LIMITS_STATE_STABILIZATION: // Assume the stabilization timeout is normal timeout _pressureVars.presStabilizeTimeoutMS = PRES_LIMIT_STABE_TIME_MS; _pressureVars.presStabilizationTimerCtr++; if (_pressureVars.presLimitState == PRESSURE_LIMITS_STATE_STABILIZATION) { _pressureVars.presStabilizeTimeoutMS = PRES_LIMIT_SHORT_STABE_TIME_MS; } if (!_treatmentStatus.isBloodPumpRunning) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_IDLE; } else if ((_treatmentSubStates.txState != TREAT_DIALYSIS_STATE) && (_treatmentSubStates.txState != TREAT_PAUSED_STATE)) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_WIDE; } else if ((_pressureVars.presStabilizationTimerCtr * QOBJECT_TIMER_TIMEOUT_MS) >= _pressureVars.presStabilizeTimeoutMS) { handleUpdatePressureLimitWindows(); _pressureVars.presStabilizationTimerCtr = 0; _pressureVars.presStabilizeTime = USE_NORMAL_STABILIZATION_PERIOD; _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_STABLE; } break; case PRESSURE_LIMITS_STATE_STABLE: _pressureVars.presStabilizationTimerCtr++; if (!_treatmentStatus.isBloodPumpRunning) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_IDLE; } else if ((_treatmentSubStates.txState != TREAT_DIALYSIS_STATE) && (_treatmentSubStates.txState != TREAT_PAUSED_STATE)) { _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_WIDE; qDebug() << "WIDEW" << _pressureVars.presLimitState; } else if ((_pressureVars.presStabilizationTimerCtr * QOBJECT_TIMER_TIMEOUT_MS) >= PRES_LIMIT_RESTABILIZE_TIME_MS) { handleUpdatePressureLimitWindows(); _pressureVars.presStabilizationTimerCtr = 0; _pressureVars.presStabilizeTime = STABILIZATION_PERIOD_OFF; _pressureVars.presLimitState = PRESSURE_LIMITS_STATE_STABILIZATION; } break; default: // Do nothing break; } qDebug() << "Pres Steat" << _pressureVars.presLimitState << _treatmentStatus.isBloodPumpRunning << _pressureVars.presStabilizeTimeoutMS << _pressureVars.presStabilizationTimerCtr * QOBJECT_TIMER_TIMEOUT_MS << _treatmentSubStates.txState ; } void StateController::handleUpdatePressureLimitWindows() { float artMMHG; float venMMHG; float tmpMMHG; if (_pressureVars.presStabilizeTime == USE_SHORT_STABILIZATION_PERIOD) { artMMHG = _pressureVars.arterialFilteredMMHG; venMMHG = _pressureVars.venousFilteredMMHG; tmpMMHG = _pressureVars.tmpFilteredMMHG; } else { // TODO need to do the long filtered? artMMHG = _pressureVars.arterialFilteredMMHG; venMMHG = _pressureVars.venousFilteredMMHG; tmpMMHG = _pressureVars.tmpFilteredMMHG; } _pressureVars.arterialStableMMHG = (artMMHG < 0.0 ? static_cast(artMMHG - 0.5) : static_cast(artMMHG + 0.5)); _pressureVars.venousStableMMHG = (venMMHG < 0.0 ? static_cast(venMMHG - 0.5) : static_cast(venMMHG + 0.5)); _pressureVars.tmpStableMMHG = (tmpMMHG < 0.0 ? static_cast(tmpMMHG - 0.5) : static_cast(tmpMMHG + 0.5)); } void StateController::handleDeterminePressureLimits() { if (_pressureVars.presLimitState == PRESSURE_LIMITS_STATE_STABLE) { qint32 artOffsetMMHG = static_cast(ART_PRES_LIMIT_WINDOW_MMHG) / 2; qint32 venMinOffsetMMHG = static_cast(VEN_PRES_LIMIT_ASYMM_MMHG); qint32 venMaxOffsetMMHG = static_cast(VEN_PRES_LIMIT_WINDOW_MMHG) - venMinOffsetMMHG; qint32 tmpOffsetMMHG = static_cast(TMP_PRES_LIMIT_WINDOW_MMHG) / 2; _pressureVars.arterialMinLimitMMHG = _pressureVars.arterialStableMMHG - artOffsetMMHG; _pressureVars.arterialMinLimitMMHG = qMax(_pressureVars.arterialMinLimitMMHG, static_cast(MIN_ART_PRES_LIMIT_MMHG)); _pressureVars.arterialMaxLimitMMHG = _pressureVars.arterialStableMMHG + artOffsetMMHG; _pressureVars.arterialMaxLimitMMHG = qMin(_pressureVars.arterialMaxLimitMMHG, static_cast(MAX_ART_PRES_LIMIT_MMHG)); _pressureVars.venousMinLimitMMHG = _pressureVars.venousStableMMHG - venMinOffsetMMHG; _pressureVars.venousMinLimitMMHG = qMax(_pressureVars.venousMinLimitMMHG, static_cast(MIN_VEN_PRES_LIMIT_MMHG)); _pressureVars.venousMaxLimitMMHG = _pressureVars.venousStableMMHG + venMaxOffsetMMHG; _pressureVars.venousMaxLimitMMHG = qMin(_pressureVars.venousMaxLimitMMHG, static_cast(MAX_VEN_PRES_LIMIT_MMHG)); _pressureVars.tmpMinLimitMMHG = _pressureVars.tmpStableMMHG - tmpOffsetMMHG; _pressureVars.tmpMinLimitMMHG = qMax(_pressureVars.tmpMinLimitMMHG, static_cast(MIN_TMP_PRES_LIMIT_MMHG)); _pressureVars.tmpMaxLimitMMHG = _pressureVars.tmpStableMMHG + tmpOffsetMMHG; _pressureVars.tmpMaxLimitMMHG = qMin(_pressureVars.tmpMaxLimitMMHG, static_cast(MAX_TMP_PRES_LIMIT_MMHG)); } else { _pressureVars.arterialMinLimitMMHG = MIN_ART_PRES_LIMIT_MMHG; _pressureVars.arterialMaxLimitMMHG = MAX_ART_PRES_LIMIT_MMHG; _pressureVars.venousMinLimitMMHG = MIN_VEN_PRES_LIMIT_MMHG; _pressureVars.venousMaxLimitMMHG = MAX_VEN_PRES_LIMIT_MMHG; _pressureVars.tmpMinLimitMMHG = MIN_TMP_PRES_LIMIT_MMHG; _pressureVars.tmpMaxLimitMMHG = MAX_TMP_PRES_LIMIT_MMHG; } } void StateController::handleWidenPressureLimitsMessage() { if (! _treatmentRcvdMessages[ID_UI_PRESSURE_LIMIT_WIDEN_RQST].isNull()){ _treatmentRcvdMessages[ID_UI_PRESSURE_LIMIT_WIDEN_RQST].clear(); // TODo address the increase per request handleUIResponseMessage(ID_TD_PRESSURE_LIMIT_WIDEN_RESP, ACCEPT_VALUE); } }