#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::handleBloodPrimeBroadcastData(const float accumulatedVolML, const quint32 primeTimeOutS, const quint32 pauseCountDownS, const Broadcast_Type BCType) { static quint32 broadcastCounter = 0; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } // Broadcast QVariantList msg; msg.append(static_cast(ID_TD_BLOOD_PRIME_PROGRESS_DATA)); msg.append(Can_Id::eChlid_TD_Sync); msg.append(BLOOD_PRIME_VOLUME_ML); msg.append(accumulatedVolML); msg.append(primeTimeOutS); msg.append(pauseCountDownS); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } 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; 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); 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.treatmentDurationMin = DEF_TX_PARAM_PRESCRIBED_DUR_MIN; _treatmentParams.fluidBlousVolumeML = DEF_TX_PARAM_SALINE_BOLUS_VOL_ML; } void StateController::handleTreatmentSetpointsBroadcastData(const quint32 bloodFlowMLPM, const quint32 dialFlowMLPM, const float dialTempC, const Broadcast_Type BCType) { static quint32 broadcastCounter = 3; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } QVariantList msg; msg.append(static_cast(ID_TD_TREATMENT_SET_POINTS)); msg.append(Can_Id::eChlid_TD_Sync); msg.append(bloodFlowMLPM); msg.append(dialFlowMLPM); msg.append(dialTempC); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } void StateController::handleTreatmentStatesBroadcastData(const QList &txStates, const Broadcast_Type BCType) { static quint32 broadcastCounter = 0; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } QVariantList msg; msg.append(static_cast(ID_TD_TREATMENT_STATE_DATA)); msg.append(Can_Id::eChlid_TD_Sync); for (auto item: txStates) { msg.append(item); } _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } 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 _treatmentStatus.fluidBolusState = FLUID_BOLUS_IDLE_STATE; if (fluidBolusCmd == FLUID_BOLUS_START_CMD){ _treatmentStatus.fluidBolusState = FLUID_BOLUS_SALINE_IN_PROGRESS_STATE; } else { _treatmentStatus.totalFluidBolusDeliveredML += _treatmentStatus.accumFluidBolusDeliveredML; } _treatmentRcvdMessages[ID_UI_FLUID_BOLUS_RQST].clear(); handleUIResponseMessage(ID_TD_FLUID_BOLUS_RESP, ACCEPT_VALUE); } } void StateController::handleFluidBolusFluidDelivery(const quint32 bloodFlowMLPM) { float timeSinceLastTimeMin = static_cast(QOBJECT_TIMER_TIMEOUT_MS) / static_cast(MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE); _treatmentStatus.accumFluidBolusDeliveredML += static_cast(bloodFlowMLPM) * timeSinceLastTimeMin; float deliveredFluidML = qAbs(_treatmentStatus.totalFluidBolusDeliveredML - _treatmentStatus.accumFluidBolusDeliveredML); if (deliveredFluidML >= _treatmentParams.fluidBlousVolumeML) { _treatmentStatus.fluidBolusState = FLUID_BOLUS_IDLE_STATE; _treatmentStatus.totalFluidBolusDeliveredML += _treatmentStatus.accumFluidBolusDeliveredML; } qDebug() << "Bolus" << deliveredFluidML << _treatmentStatus.accumFluidBolusDeliveredML << _treatmentStatus.totalFluidBolusDeliveredML; } void StateController::handleFluidBolusBroadcastData(const Broadcast_Type BCType) { static quint32 broadcastCounter = 5; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } QVariantList msg; msg.append(static_cast(ID_TD_FLUID_BOLUS_DATA)); msg.append(Can_Id::eChlid_TD_Sync); msg.append(_treatmentParams.fluidBlousVolumeML); msg.append(_treatmentStatus.accumFluidBolusDeliveredML); msg.append(_treatmentStatus.totalFluidBolusDeliveredML); msg.append(0); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } void StateController::handleTDPressureProcessAndBroadcastData(const Broadcast_Type BCType) { static quint32 broadcastCounter = 10; 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); } // TODO update the pressures float h2ArtPresMMHG = 12.2; float h14VenPresMMHG = 80.1; quint32 presLimitState = 1; qint32 h2ArtMinLimitMMHG = MIN_ART_PRES_LIMIT_MMHG; qint32 h2ArtMaxLimitMMHG = MAX_ART_PRES_LIMIT_MMHG; qint32 h14VenMinLimitMMGH = MIN_VEN_PRES_LIMIT_MMHG; qint32 h14VenMaxLimitMMHG = MAX_VEN_PRES_LIMIT_MMHG; float h2ArtLongFilterPresMMHG = -23.0; float h14VenLongFilterPresMMHG = 67.5; float tmpPresMMHG = 45.03; float tmpLongFilter = 45.5; float tmpMinLimitMMHG = MIN_TMP_PRES_LIMIT_MMHG; float tmpMaxLimitMMHG = MAX_TMP_PRES_LIMIT_MMHG; float h23BaroPresPSI = 14.2l; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } QVariantList msg; msg.append(static_cast(ID_TD_PRESSURE_DATA)); msg.append(Can_Id::eChlid_TD_Sync); msg.append(h2ArtPresMMHG); msg.append(h14VenPresMMHG); msg.append(presLimitState); msg.append(h2ArtMinLimitMMHG); msg.append(h2ArtMaxLimitMMHG); msg.append(h14VenMinLimitMMGH); msg.append(h14VenMaxLimitMMHG); msg.append(h2ArtLongFilterPresMMHG); msg.append(h14VenLongFilterPresMMHG); msg.append(tmpPresMMHG); msg.append(tmpLongFilter); msg.append(tmpMinLimitMMHG); msg.append(tmpMaxLimitMMHG); msg.append(h23BaroPresPSI); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } void StateController::handleTreatmentTimeProcessAndBroadcastData(const Broadcast_Type BCType) { static quint32 broadcastCounter = 12; if (_treatmentStatus.fluidBolusState == FLUID_BOLUS_IDLE_STATE) { _treatmentStatus.treatmentElapsedTimeMS += QOBJECT_TIMER_TIMEOUT_MS; } if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } quint32 prescribedTimeS = _treatmentParams.treatmentDurationMin * SECONDS_PER_MINUTE; quint32 elapsedTimeS = _treatmentStatus.treatmentElapsedTimeMS / MILLISECONDS_PER_SECOND; quint32 remainingTimeS = prescribedTimeS - elapsedTimeS; //qDebug() << "Times" << prescribedTimeS << elapsedTimeS << remainingTimeS; QVariantList msg; msg.append(static_cast(ID_TD_TREATMENT_TIME_DATA)); msg.append(Can_Id::eChlid_TD_Sync); msg.append(prescribedTimeS); msg.append(elapsedTimeS); msg.append(remainingTimeS); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } void StateController::handleTreatmentPrescriptionEditRequestMessage() { if (! _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINTS_CHANGE_RQST].isNull()){ // 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); _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()){ // 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::handleDDGenDialysateModeBroadcastData(const Broadcast_Type BCType) { static quint32 broadcastCounter = 15; if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } quint32 dummyData = 1; float dummyFloat = 150.2; QVariantList msg; msg.append(static_cast(ID_DD_GEN_DIALYSATE_MODE_DATA)); msg.append(Can_Id::eChlid_DD_Sync); msg.append(dummyData); msg.append(dummyData); msg.append(ALLOW_DIALYSATE_DELIVER); msg.append(dummyFloat); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; } void StateController::handleSetPointDialysateFlowChange() { if (! _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RQST].isNull()){ // 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_TD_TREATMENT_SET_POINT_DIALYSATE_FLOW_CHANGE_RESP].clear(); } }