Index: sources/MessageGlobals.h =================================================================== diff -u -r9edc9ba3995ca25a29bb74eeeae71f7d72965284 -r4533fba9bf69d25de21536b849b5d9cb09d959ee --- sources/MessageGlobals.h (.../MessageGlobals.h) (revision 9edc9ba3995ca25a29bb74eeeae71f7d72965284) +++ sources/MessageGlobals.h (.../MessageGlobals.h) (revision 4533fba9bf69d25de21536b849b5d9cb09d959ee) @@ -141,6 +141,7 @@ ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE = 0x4000, ID_UI_TREATMENT_UF_VOLUME_VALIDATE_RQST = 0x4100, ID_TD_TREATMENT_UF_VOLUME_VALIDATE_RESP = 0x4200, + ID_TD_TREATMENT_PARAM_RANGES_DATA = 0x4300, ID_INITIATE_TREATMENT = 0x4500, ID_TD_RESP_INITIATE_TREATMENT = 0x4600, ID_UI_UF_PAUSE_RESUME_RQST = 0x4700, @@ -151,6 +152,8 @@ ID_UI_BLOOD_PRESSURE_RQST = 0x6300, ID_TD_BLOOD_PRESSURE_READING_RESP = 0x6400, ID_TD_BLOOD_PRESSURE_DATA = 0x6500, + ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST = 0x6600, + ID_TD_ULTRAFILTRATION_CHANGE_CONFIRM_RESP = 0x6700, ID_UI_BOLUS_VOLUME_CHANGE_RQST = 0x7400, ID_TD_BOLUS_VOLUME_CHANGE_RESP = 0x7500, ID_UI_TREATMENT_SET_POINTS_CHANGE_RQST = 0x7A00, Index: sources/drydemo/DryDemoDefines.h =================================================================== diff -u -r9edc9ba3995ca25a29bb74eeeae71f7d72965284 -r4533fba9bf69d25de21536b849b5d9cb09d959ee --- sources/drydemo/DryDemoDefines.h (.../DryDemoDefines.h) (revision 9edc9ba3995ca25a29bb74eeeae71f7d72965284) +++ sources/drydemo/DryDemoDefines.h (.../DryDemoDefines.h) (revision 4533fba9bf69d25de21536b849b5d9cb09d959ee) @@ -10,6 +10,7 @@ #define MILLILITERS_PER_LITER 1000 #define ACCEPT_VALUE 1 #define REJECT_VALUE 0 +#define NEARLY_ZERO 0.00000001 #define CONFIRM_CMD_ACCEPT_CLOSE 3 // TODo remove #define PASS_RESULT 1 // TODO remove #define DEVICE_ID 1234 @@ -25,7 +26,7 @@ #define NUM_OF_COUNTS_TO_BC_MSG 3 // TODO remove // Treatment params -#define MIN_DIAL_RATE_MLPM 100 +#define MIN_DIAL_RATE_MLPM 50 #define MAX_DIAL_RATE_MLPM 600 #define MIN_BLOOD_RATE_MLPM 100 #define MAX_BLOOD_RATE_MLPM 500 @@ -161,7 +162,12 @@ enum Reject_Reasons { REQUEST_REJECT_REASON_NONE = 0, REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE = 4, + REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_CURRENT = 7, + REQUEST_REJECT_REASON_UF_VOLUME_OUT_OF_RANGE = 11, + REQUEST_REJECT_REASON_UF_RATE_OUT_OF_RANGE = 12, REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS = 14, REQUEST_REJECT_REASON_UF_NOT_PAUSED = 15, REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE = 17, + REQUEST_REJECT_REASON_CONFIRMATION_NOT_EXPECTED = 58, + REQUEST_REJECT_REASON_CONFIRMATION_MISMATCH = 59, }; Index: sources/drydemo/StateController.cpp =================================================================== diff -u -r9edc9ba3995ca25a29bb74eeeae71f7d72965284 -r4533fba9bf69d25de21536b849b5d9cb09d959ee --- sources/drydemo/StateController.cpp (.../StateController.cpp) (revision 9edc9ba3995ca25a29bb74eeeae71f7d72965284) +++ sources/drydemo/StateController.cpp (.../StateController.cpp) (revision 4533fba9bf69d25de21536b849b5d9cb09d959ee) @@ -54,6 +54,7 @@ case ID_UI_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RQST: case ID_UI_UF_PAUSE_RESUME_RQST: case ID_UI_TREATMENT_UF_VOLUME_VALIDATE_RQST: + case ID_UI_ULTRAFILTRATION_CHANGE_CONFIRM_RQST: _treatmentRcvdMessages[receivedMsgID] = msg[1]; break; @@ -64,16 +65,6 @@ _treatmentRcvdMessages[receivedMsgID] = 0; break; - //case ID_UI_TX_END_RQST: - //case ID_UI_CONSUMABLES_INSTALL: - //case ID_UI_INTALLATION_CONFIRM: - //case ID_UI_PATIENT_CONNECTION_RQST: - //case ID_UI_PATIENT_CONNECTION_CONF_RQST: - //case ID_UI_START_TX_RQST: - //case ID_UI_SERVICE_MODE_RQST: - // _hasUserConfirmedToProceed = true; - // break; - case ID_NONE: case ID_TD_OP_MODE_DATA: case ID_TD_TREATMENT_STATE_DATA: @@ -103,6 +94,8 @@ case ID_TD_TREATMENT_SET_POINT_DIALYSATE_TEMP_CHANGE_RESP: case ID_TD_UF_PAUSE_RESUME_RESP: case ID_TD_TREATMENT_UF_VOLUME_VALIDATE_RESP: + case ID_TD_TREATMENT_PARAM_RANGES_DATA: + case ID_TD_ULTRAFILTRATION_CHANGE_CONFIRM_RESP: // Do nothing break; } @@ -374,6 +367,7 @@ handleTreatmentTimeProcessAndBroadcastData(BC_IMMEDIATELY); handleDDGenDialysateModeBroadcastData(BC_IMMEDIATELY); initializeTreatmentTimeAndUltrafiltration(); + handleTreatmentSettingBroadcastData(BC_IMMEDIATELY); status = STATE_ON_ACTION; qDebug() << "Tx on entry"; }; @@ -399,6 +393,9 @@ handleSetPointDialysateTemperatureChange(); handleUltrafiltrationBroadcastData(BC_DELAYED); handleUltrafiltrationPauseResume(); + handleUltrafiltrationVolumeChangeValidation(); + handleTreatmentSettingBroadcastData(BC_DELAYED); + handleUltrafiltrationVolumeChangeConfirm(); if ((_treatmentStatus.treatmentElapsedTimeMS / MILLISECONDS_PER_SECOND) >= (_treatmentParams.treatmentDurationMin * SECONDS_PER_MINUTE)) { _treatmentStatus.stateTransitionEvent = "T_Tx_2_TE"; status = STATE_ON_EXIT; @@ -617,7 +614,7 @@ if (rejectReasons.isEmpty()) { // If the default reject reasons is empty, it means there were no reject reasons or extra payloads so assume none resp.append(static_cast(REQUEST_REJECT_REASON_NONE)); - qDebug() << "Empty" << rejectReasons; + qDebug() << "Empty"; } else { for (auto item: rejectReasons) { resp.append(item); } Index: sources/drydemo/StateController.h =================================================================== diff -u -r9edc9ba3995ca25a29bb74eeeae71f7d72965284 -r4533fba9bf69d25de21536b849b5d9cb09d959ee --- sources/drydemo/StateController.h (.../StateController.h) (revision 9edc9ba3995ca25a29bb74eeeae71f7d72965284) +++ sources/drydemo/StateController.h (.../StateController.h) (revision 4533fba9bf69d25de21536b849b5d9cb09d959ee) @@ -34,8 +34,8 @@ struct Treatment_Status_Vars { bool hasTxParamsBeenInitialized; quint32 treatmentElapsedTimeMS; - quint32 remainingTreatmentTimeS; - quint32 prescribedTreatmentTimeS; + quint32 remainingTreatmentTimeS; // TODO remove + quint32 prescribedTreatmentTimeS; // TODO remove User_Command_ID userCmd; QString stateTransitionEvent; float accumFluidBolusDeliveredML; @@ -45,6 +45,9 @@ Dialysis_States dialysisSubState; float presUFRateMLPM; float ufVolDeliveredL; + bool validateUFVolReceived; + float validateUFVolGoalL; + float validateUFRateLHR; }; struct Treatment_Params { @@ -134,7 +137,9 @@ void handleUltrafiltrationBroadcastData(const Broadcast_Type BCType); void handleSetPointDialysateTemperatureChange(); void handleUltrafiltrationPauseResume(); - void handleUltrafiltrationVolumeChangeRequest(); + void handleUltrafiltrationVolumeChangeValidation(); + void handleTreatmentSettingBroadcastData(const Broadcast_Type BCType); + void handleUltrafiltrationVolumeChangeConfirm(); // Treatment end methods Index: sources/drydemo/StateControllerTreatment.cpp =================================================================== diff -u -r9edc9ba3995ca25a29bb74eeeae71f7d72965284 -r4533fba9bf69d25de21536b849b5d9cb09d959ee --- sources/drydemo/StateControllerTreatment.cpp (.../StateControllerTreatment.cpp) (revision 9edc9ba3995ca25a29bb74eeeae71f7d72965284) +++ sources/drydemo/StateControllerTreatment.cpp (.../StateControllerTreatment.cpp) (revision 4533fba9bf69d25de21536b849b5d9cb09d959ee) @@ -99,7 +99,8 @@ { // The default elapsed time is 2 hours becasue the default tx duration is 4 hours. If the prescribed is less than 2 hours, 0 the elapsed if ((_treatmentParams.treatmentDurationMin * SECONDS_PER_MINUTE) < DEF_TX_ELAPSED_TIME_S){ _treatmentStatus.treatmentElapsedTimeMS = 0; } - _treatmentStatus.presUFRateMLPM = (_treatmentParams.ufVolumeL * MILLILITERS_PER_LITER) / (static_cast(_treatmentParams.treatmentDurationMin)); + _treatmentStatus.presUFRateMLPM = (_treatmentParams.ufVolumeL * MILLILITERS_PER_LITER) / (static_cast(_treatmentParams.treatmentDurationMin)); + _treatmentStatus.prescribedTreatmentTimeS = _treatmentParams.treatmentDurationMin / SECONDS_PER_MINUTE; float presUFVolL = _treatmentParams.ufVolumeL; float presUFRateLHR = presUFVolL / (static_cast(_treatmentParams.treatmentDurationMin) / static_cast(MINUTES_PER_HOUR)); @@ -488,9 +489,114 @@ _treatmentRcvdMessages[ID_UI_UF_PAUSE_RESUME_RQST].clear(); } -void StateController::handleUltrafiltrationVolumeChangeRequest() +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; + 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::handleTreatmentSettingBroadcastData(const Broadcast_Type BCType) +{ + static quint32 broadcastCounter = 38; + if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } + + quint32 elapsedTimeMin = _treatmentStatus.treatmentElapsedTimeMS / static_cast(SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND); + // NOTE: min tx time macro was converted to quint32 to prevent compilation error in qMax + quint32 minTxTimeMin = qMax(elapsedTimeMin + 2, static_cast(MIN_TX_TIME_MINS)); + // TOOD fix maxTime once firmware is done + quint32 maxTxTime1Min = minTxTimeMin; // TODO add the UF to it + quint32 maxTxTime2Min = MAX_TX_TIME_MINS; + quint32 maxTxTimeMin = qMax(maxTxTime1Min, maxTxTime2Min); + + float minUFVolML = 0.0; // TODO check with firmware for min + float maxUFVol1ML = minUFVolML + (static_cast(_treatmentParams.treatmentDurationMin - elapsedTimeMin) * MAX_UF_RATE_MLPM); + float maxUFVol2ML = (_treatmentStatus.presUFRateMLPM > 0.0 ? minUFVolML + static_cast(MAX_TX_TIME_MINS - elapsedTimeMin - 1) : minUFVolML); + float maxUFVolML = qMax(maxUFVol1ML, maxUFVol2ML); + //qDebug() << "TIME seetingt" << elapsedTimeMin << minTxTimeMin << maxTxTime1Min << maxTxTime2Min << maxTxTimeMin + // << maxUFVol1ML << maxUFVol2ML << maxUFVolML; + + QVariantList msg; + msg.append(static_cast(ID_TD_TREATMENT_PARAM_RANGES_DATA)); + msg.append(Can_Id::eChlid_TD_Sync); + msg.append(minTxTimeMin); + msg.append(maxTxTimeMin); + msg.append(minUFVolML); + msg.append(maxUFVolML); + msg.append(MIN_DIAL_RATE_MLPM); + msg.append(MAX_DIAL_RATE_MLPM); + _isBroadcastListReady = false; + _broadcastMessages.append(msg); + _isBroadcastListReady = true; +} + +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 = (_treatmentParams.ufVolumeL * MILLILITERS_PER_LITER) / (static_cast(_treatmentParams.treatmentDurationMin)); + _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(); +} +