Index: sources/StateController.cpp =================================================================== diff -u -r4af87533b19d61512e7a368554042501eeea75f2 -r424c81d03f7d915d39ab962f652c0b565f465bf7 --- sources/StateController.cpp (.../StateController.cpp) (revision 4af87533b19d61512e7a368554042501eeea75f2) +++ sources/StateController.cpp (.../StateController.cpp) (revision 424c81d03f7d915d39ab962f652c0b565f465bf7) @@ -1,5 +1,6 @@ #include +#include #include "StateController.h" #include "ApplicationController.h" @@ -36,69 +37,32 @@ // TODo fill up } - void StateController::doStateControllerUnhandledMsgReceived(const QVariantList &msg) { MessageID receivedMsgID = static_cast(msg[0].toUInt()); switch(receivedMsgID) { case ID_UI_RQST_TX: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - case ID_UI_TX_PARAMS_RQST: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - case ID_UI_CONFIRM_RESP: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - - case ID_UI_CONFIRM_TX_PARAMS: - _hasUserConfirmedToProceed = true; - break; - case ID_UI_RINSEBACK_CMD_RQST: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - - case ID_UI_TX_END_RQST: - _hasUserConfirmedToProceed = true; - break; - case ID_SAMPLE_WATER_RESULT: + case ID_UI_SET_UF_VOLUME_RQST: + case ID_USER_TX_TIME_CHANGES_RQST: + case ID_UI_CONFIRM_TX_PARAMS: _treatmentRcvdMessages[receivedMsgID] = msg[1]; break; + case ID_UI_TX_END_RQST: case ID_UI_CONSUMABLES_INSTALL: - _hasUserConfirmedToProceed = true; - break; - case ID_UI_INTALLATION_CONFIRM: - _hasUserConfirmedToProceed = true; - break; - case ID_UI_PATIENT_CONNECTION_RQST: - _hasUserConfirmedToProceed = true; - break; - - case ID_UI_SET_UF_VOLUME_RQST: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - case ID_UI_PATIENT_CONNECTION_CONF_RQST: - _hasUserConfirmedToProceed = true; - break; - case ID_UI_START_TX_RQST: _hasUserConfirmedToProceed = true; break; - case ID_USER_TX_TIME_CHANGES_RQST: - _treatmentRcvdMessages[receivedMsgID] = msg[1]; - break; - case ID_NONE: case ID_HD_BLOOD_FLOW_DATA_BC: case ID_HD_DIALYSATE_FLOW_DATA_BC: @@ -252,7 +216,7 @@ else if (!_treatmentParams.hasTxParamsBeenInitialized) { _treatmentParams.bloodFlowRateMLPM = DEF_TX_PARAM_BLOOD_FLOW_RATE_MLPM; _treatmentParams.dialysateFlowRateMLPM = DEF_TX_PARAM_DIAL_FLOW_RATE_MLPM; - _treatmentParams.txDurationMins = DEF_TX_PARAM_PRESCRIBED_DUR_S / SECONDS_PER_MINUTE; + _treatmentParams.txDurationMins = DEF_TX_PARAM_PRESCRIBED_DUR_MIN; _treatmentParams.salineBolusVolML = DEF_TX_PARAM_SALINE_BOLUS_VOL_ML; _treatmentParams.acidConc = 0; _treatmentParams.bicarbConc = 0; @@ -271,8 +235,6 @@ // so the UF volume is set to default as well. _treatmentVars.txParamsUFVolL = DEF_TX_PARAM_UF_VOLUME_L; } - - qDebug() << "Treatment params" << _treatmentParams.hasTxParamsBeenInitialized; } void StateController::prepareOcclusionBroadcastData() @@ -455,6 +417,20 @@ _isBroadcastListReady = true; } +void StateController::prepareTreatmentTimeChangeResponse(quint32 accept, quint32 txDurS, float maxUFvolML) +{ + QVariantList resp; + resp.append(static_cast(ID_USER_TX_TIME_CHANGES_RESP)); + resp.append(Can_Id::eChlid_HD_UI); + resp.append(accept); + resp.append(0); + resp.append(txDurS/SECONDS_PER_MINUTE); + resp.append(maxUFvolML); + _isSendListReady = false; + _sendMessages.append(resp); + _isSendListReady = true; +} + void StateController::handleTreatmentTimeChangeRequest(const QVariant &payload) { quint32 accept = REJECT_VALUE; @@ -470,22 +446,26 @@ UFVolumeL /= MILLILITERS_PER_LITER; // Upper and lower range values are from #defines - quint32 dialVolume = _treatmentParams.dialysateFlowRateMLPM * txDurMin; + quint32 dialVolumeML = _treatmentParams.dialysateFlowRateMLPM * txDurMin; bool isMinTxTimeValid = (txDurMin >= MIN_TX_TIME_MINS ? true : false); bool isTxTimeValid = (txDurMin <= MAX_TX_TIME_MINS ? true : false); bool isMinUFVolValid = ((UFVolumeL >= MIN_UF_VOL_L) || (UFVolumeL <= 0.0) ? true : false); // TODO fix the UF Vol bool isUFVolValid = (UFVolumeL <= MAX_UF_VOL_L ? true : false); - qDebug() << "Test of tx" << _treatmentVars.prescribedUFRate << elapsedTimeMins << UFVolumeL << isUFVolValid; + qDebug() << "Test of tx" << _treatmentVars.prescribedUFRate << elapsedTimeMins << UFVolumeL << isUFVolValid << dialVolumeML; - if (isMinTxTimeValid && isTxTimeValid && isMinUFVolValid && isUFVolValid && (dialVolume <= MAX_DIALYSATE_VOLUME_ML)) { + if (isMinTxTimeValid && isTxTimeValid && isMinUFVolValid && isUFVolValid && (dialVolumeML <= MAX_DIALYSATE_VOLUME_ML)) { _treatmentVars.prescribedTreatmentTimeS = txDurMin * SECONDS_PER_MINUTE; _treatmentVars.prescribedMaxUFVolML = UFVolumeL * MILLILITERS_PER_LITER; accept = ACCEPT_VALUE; qDebug() << "New tx time" << txDurMin * SECONDS_PER_MINUTE << accept; } } + prepareTreatmentTimeChangeResponse(accept, + _treatmentVars.prescribedTreatmentTimeS, + _treatmentVars.prescribedMaxUFVolML); + /* QVariantList resp; resp.append(static_cast(ID_USER_TX_TIME_CHANGES_RESP)); resp.append(Can_Id::eChlid_HD_UI); @@ -496,6 +476,7 @@ _isSendListReady = false; _sendMessages.append(resp); _isSendListReady = true; +*/ } qint32 StateController::handleMsgBBPayload(const QVariant &payload) @@ -615,7 +596,7 @@ } void StateController::handleRinsebackSubstate(const QVariant &payload, float &accumVolML, - quint32 &txState, quint32 &rbState) + quint32 &txState, quint32 &rbState, quint32 &rbFlowMLPM) { qint32 cmdIndex = 0; Types::U32 param; @@ -628,6 +609,22 @@ rbState = RINSEBACK_RUN_STATE; break; + case RINSEBACK_ACCEL_FLOW: + if (rbFlowMLPM + RINSEBACK_ADJ_FLOW_RATE_MLPM <= RINSEBACK_MAX_RLOW_RATE_MLPM) { + if (rbState == RINSEBACK_RUN_STATE) { + rbFlowMLPM += RINSEBACK_ADJ_FLOW_RATE_MLPM; + } + } + break; + + case RINSEABCK_DECEL_FLOW: + if (rbFlowMLPM - RINSEBACK_ADJ_FLOW_RATE_MLPM >= RINSEBACK_MIN_FLOW_RATE_MLPM) { + if (rbState == RINSEBACK_RUN_STATE) { + rbFlowMLPM -= RINSEBACK_ADJ_FLOW_RATE_MLPM; + } + } + break; + case RINSEBACK_PAUSE_RB: rbState = RINSEBACK_PAUSE_STATE; break; @@ -782,17 +779,29 @@ }; auto inAction = [=]() { - //qDebug() << "In treatment params on action"; - if (!_treatmentRcvdMessages[ID_UI_TX_PARAMS_RQST].isNull()) { setTreatmentParams(true, _treatmentRcvdMessages[ID_UI_TX_PARAMS_RQST]); _treatmentRcvdMessages[ID_UI_TX_PARAMS_RQST].clear(); } - if ((_treatmentParams.hasTxParamsBeenInitialized) && (_hasUserConfirmedToProceed)) { + if (_treatmentParams.hasTxParamsBeenInitialized && _hasUserConfirmedToProceed) { status = STATE_ON_EXIT; } + if (!_treatmentRcvdMessages[ID_UI_CONFIRM_TX_PARAMS].isNull()) { + status = STATE_ON_ENTRY; + + qint32 index = 0; + Types::U32 u32Var; + GetValue(_treatmentRcvdMessages[ID_UI_CONFIRM_TX_PARAMS].toByteArray(), index, u32Var); + + if (u32Var.value == ACCEPT_VALUE) { + status = STATE_ON_EXIT; + qDebug() << "Tx params approved"; + } + _treatmentRcvdMessages[ID_UI_CONFIRM_TX_PARAMS].clear(); + } + if (!_treatmentRcvdMessages[ID_UI_RQST_TX].isNull()) { // If the user wants to go back in treatment params go back. if (!isTreatmenStartRequested(_treatmentRcvdMessages[ID_UI_RQST_TX])) { @@ -893,6 +902,7 @@ static State_Status status = STATE_ON_ENTRY; static quint32 state = 0; static quint32 stateIndex = 2; + static quint32 stateBCInt = 3; auto inEntry = [=](){ qDebug() << "Consumables on entry"; @@ -901,17 +911,23 @@ preTxStates[stateIndex] = state; prepareHDModeTransitionBroadcastData(MODE_PRET, 0); prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); - status = STATE_ON_ACTION; - _hasUserConfirmedToProceed = false; + status = STATE_ON_ACTION; + _hasUserConfirmedToProceed = false; + _treatmentVars.broadcastIntervalCount = 0; }; auto inAction = [=]() { + _treatmentVars.broadcastIntervalCount++; + if (_hasUserConfirmedToProceed) { - if (state < 4) { // TODO #define for this - state++; - QList preTxStates({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); - preTxStates[stateIndex] = state; - prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + if (state < 4 ) { // TODO #define for this + // Added broadcast delay to slow down the substate transitions + if (_treatmentVars.broadcastIntervalCount % stateBCInt == 0) { + state++; + QList preTxStates({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + preTxStates[stateIndex] = state; + prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + } } else { status = STATE_ON_EXIT; @@ -999,14 +1015,18 @@ void StateController::onSystemPrimeStateChange(bool active) { - static State_Status status = STATE_ON_ENTRY; - static quint32 timerCountDownS = DEFAULT_TIMEOUT_S; - static quint32 stateNum = 0; - static quint32 stateIndex = 5; - static bool hasPrimeCompleted = false; + static State_Status status = STATE_ON_ENTRY; + static quint32 timerCountDownS = DEFAULT_TIMEOUT_S; + static quint32 stateNum = 0; + static quint32 stateIndex = 5; + static bool hasPrimeCompleted = false; + static quint32 numOfPrimeStates = 15; + static quint32 primeStateBCInt = 0; + static quint32 numOfPrimingStates = 12; + static quint32 primingStateBCInt = 0; auto inEntry = [=](){ - qDebug() << "Prime on entry"; + qDebug() << "Prime on entry" << primeStateBCInt; stateNum = 0; stateIndex = 5; QList preTxStates({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); @@ -1018,6 +1038,20 @@ _treatmentVars.broadcastIntervalCount = 0; timerCountDownS = DEFAULT_TIMEOUT_S; hasPrimeCompleted = false; + + // For prime states + float divide = ((float)DEFAULT_TIMEOUT_S / (float)numOfPrimeStates) * MILLISECONDS_PER_SECOND; + quint32 ceilingValue = qCeil(divide); + quint32 modValue = ceilingValue % QOBJECT_TIMER_TIMEOUT_MS; + quint32 remaining = ceilingValue - modValue; + primeStateBCInt = remaining / QOBJECT_TIMER_TIMEOUT_MS; + + // For priming states + divide = ((float)DEFAULT_TIMEOUT_S / (float)numOfPrimingStates) * MILLISECONDS_PER_SECOND; + ceilingValue = qCeil(divide); + modValue = ceilingValue % QOBJECT_TIMER_TIMEOUT_MS; + remaining = ceilingValue - modValue; + primingStateBCInt = remaining / QOBJECT_TIMER_TIMEOUT_MS; }; auto inAction = [=](){ @@ -1029,11 +1063,13 @@ if (!hasPrimeCompleted) { hasTimeElapsed = hasPreTxTimerElapsed(ID_HD_DRY_SELF_TEST_TIME_BC, eChlid_HD_Sync, timerCountDownS, DEFAULT_TIMEOUT_S); - if (stateNum < 15) { - stateNum++; - QList preTxStates({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); - preTxStates[stateIndex] = stateNum; - prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + if (stateNum < numOfPrimeStates) { + if (_treatmentVars.broadcastIntervalCount % primeStateBCInt == 0) { + stateNum++; + QList preTxStates({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + preTxStates[stateIndex] = stateNum; + prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + } } else if (hasTimeElapsed) { hasPrimeCompleted = true; @@ -1047,12 +1083,14 @@ hasTimeElapsed = hasPreTxTimerElapsed(ID_HD_PRIMING_TIME_BC, eChlid_HD_Sync, timerCountDownS, DEFAULT_TIMEOUT_S); - if (stateNum < 12) { - stateNum++; - stateIndex = 6; - QList preTxStates({5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); - preTxStates[stateIndex] = stateNum; - prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + if (stateNum < numOfPrimingStates) { + if (_treatmentVars.broadcastIntervalCount % primingStateBCInt == 0) { + stateNum++; + stateIndex = 6; + QList preTxStates({5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + preTxStates[stateIndex] = stateNum; + prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); + } } else if (hasTimeElapsed) { QList preTxStates({6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); @@ -1097,12 +1135,15 @@ }; auto inAction = [=](){ - status = STATE_ON_EXIT; - if (!_treatmentRcvdMessages[ID_UI_CONFIRM_RESP].isNull()) { status = STATE_ON_ENTRY; _dryDemo.submitEvent("Transition_back_2_idle"); } + + // In BP/HR page in the UI there is a confirm button but it is not checked by + // the firmware so the dry demo state transitions to the UF page immediately because + // there is nothing else is left to be done here + status = STATE_ON_EXIT; }; auto inExit = [=](){ @@ -1124,6 +1165,7 @@ auto inEntry = [=](){ qDebug() << "UF on entry"; + prepareTreatmentParamsRangesBroadcastData(); QList preTxStates({7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); prepareHDModeTransitionBroadcastData(MODE_PRET, 0); prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); @@ -1173,7 +1215,6 @@ }; auto inAction = [=](){ - if(_hasUserConfirmedToProceed) { if (!isConnectionDone) { _hasUserConfirmedToProceed = false; @@ -1198,6 +1239,16 @@ status = STATE_ON_ENTRY; _dryDemo.submitEvent("Transition_back_2_idle"); } + + if (!_treatmentRcvdMessages[ID_UI_SET_UF_VOLUME_RQST].isNull()) { + // Firmware (and dry demo in this case) is not involved in going back and forth + // in between connection page and the UF page. So once the user hits back from + // connection, then the use has to hit confirm twice to be able to come back from + // UF to connection + _dryDemo.submitEvent("T_Con_2_UF"); + _treatmentRcvdMessages[ID_UI_SET_UF_VOLUME_RQST].clear(); + status = STATE_ON_ENTRY; + } }; auto inExit = [=](){ @@ -1257,15 +1308,16 @@ status = STATE_ON_ACTION; accumBloodVolML = 0.0; _treatmentVars.broadcastIntervalCount = 0; - + prepareBloodFlowBroadcastData(_treatmentParams.bloodFlowRateMLPM); prepareBloodPrimeBroadcastData(accumBloodVolML); }; auto inAction = [=](){ _treatmentVars.broadcastIntervalCount++; - accumBloodVolML += (DEF_TX_PARAM_BLOOD_FLOW_RATE_MLPM * FLOW_INTEGRATOR); + accumBloodVolML += (_treatmentParams.bloodFlowRateMLPM * FLOW_INTEGRATOR); if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { + prepareBloodFlowBroadcastData(_treatmentParams.bloodFlowRateMLPM); prepareBloodPrimeBroadcastData(accumBloodVolML); prepareOcclusionBroadcastData(); prepareTreatmentParamsRangesBroadcastData(); @@ -1302,14 +1354,24 @@ auto inEntry = [=](){ _treatmentVars.prescribedTreatmentTimeS = _treatmentParams.txDurationMins * SECONDS_PER_MINUTE; - _treatmentVars.treatmentElapsedTimeS = DEF_TX_ELAPSED_TIME_S; + _treatmentVars.treatmentElapsedTimeS = (_treatmentVars.prescribedTreatmentTimeS < DEF_TX_ELAPSED_TIME_S ? 0 : DEF_TX_ELAPSED_TIME_S); _treatmentVars.remainingTreatmentTimeS = _treatmentVars.prescribedTreatmentTimeS - _treatmentVars.treatmentElapsedTimeS; _treatmentVars.prescribedMaxUFVolML = _treatmentVars.txParamsUFVolL * MILLILITERS_PER_LITER; _treatmentVars.prescribedUFRate = _treatmentVars.prescribedMaxUFVolML / _treatmentParams.txDurationMins; _treatmentVars.refUFVolumeML = (_treatmentVars.treatmentElapsedTimeS / SECONDS_PER_MINUTE) * _treatmentVars.prescribedUFRate; - qDebug() << "Treatment Treatment state" << _treatmentVars.txParamsUFVolL << _treatmentParams.hasTxParamsBeenInitialized; + qDebug() << "Treatment UF start vals" << _treatmentVars.txParamsUFVolL + << _treatmentVars.prescribedUFRate + << _treatmentVars.prescribedMaxUFVolML + << _treatmentVars.refUFVolumeML; + // Send the treatment time range response at the beginning of the start treatment + // to update the UF ranges at the top right corner of the especially the max UF target + // that is set + prepareTreatmentTimeChangeResponse(ACCEPT_VALUE, + _treatmentVars.prescribedTreatmentTimeS, + _treatmentVars.prescribedMaxUFVolML); + status = STATE_ON_ACTION; }; @@ -1320,9 +1382,9 @@ _treatmentVars.refUFVolumeML += (timeSinceLastCallMS / SECONDS_PER_MINUTE) * _treatmentVars.prescribedUFRate; _treatmentVars.measUFVolumeML = _treatmentVars.refUFVolumeML; - //qDebug() << "UF Value" << QTime::currentTime() << _treatmentVars.refUFVolumeML << _treatmentVars.prescribedUFRate; + //qDebug() << "UF Value" << _treatmentVars.measUFVolumeML << _treatmentVars.refUFVolumeML << _treatmentVars.prescribedUFRate; if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { - QList txStates({DIALYSIS_SUB_STATE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + QList txStates({DIALYSIS_SUB_STATE, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}); prepareStatesBroadcastData(ID_HD_TX_STATES_BC, txStates); prepareOcclusionBroadcastData(); prepareTreatmentTimeBroadcastData(); @@ -1370,6 +1432,7 @@ // The default rinseback volume is 300 mL but the demo should be done in 10 seconds so it is recalculated here static float rbTargetVolML = 0.0; static float rbAcuumVolML = 0.0; + static quint32 rbFlowMLPM = _treatmentParams.rinsebackFlowRateMLPM; auto inEntry = [=](){ // Call the treatment params first in case the use just started from the end treatment @@ -1379,13 +1442,15 @@ // In order to jump to end treatment page, first the UI needs to be on another // treatment page, so on entry we first land on the dialysis page then we transition // to end treatment. + _treatmentVars.prescribedTreatmentTimeS = _treatmentParams.txDurationMins * SECONDS_PER_MINUTE; txSubState = DIALYSIS_SUB_STATE; rbSubState = 0; rbCountDownS = RINSEBACK_BACK_MAX_TIME_S; rbAcuumVolML = 0.0; - rbTargetVolML = (_treatmentParams.rinsebackFlowRateMLPM * DEFAULT_TIMEOUT_S) / SECONDS_PER_MINUTE; + rbFlowMLPM = _treatmentParams.rinsebackFlowRateMLPM; + rbTargetVolML = (rbFlowMLPM * DEFAULT_TIMEOUT_S) / SECONDS_PER_MINUTE; prepareHDModeTransitionBroadcastData(MODE_TREA, 0); - QList txStates({txSubState, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + QList txStates({txSubState, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}); prepareStatesBroadcastData(ID_HD_TX_STATES_BC, txStates); txSubState = TX_END_SUB_STATE; @@ -1405,8 +1470,7 @@ QList txStates({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); QList rinsebackVolsML({rbTargetVolML, rbAcuumVolML}); - QList rinsebackBC({_treatmentParams.rinsebackFlowRateMLPM, - RINSEBACK_BACK_MAX_TIME_S, rbCountDownS, 0}); + QList rinsebackBC({rbFlowMLPM, RINSEBACK_BACK_MAX_TIME_S, rbCountDownS, 0}); if (_hasUserConfirmedToProceed) { // Switching to the rinseback send the screen change quickly @@ -1419,7 +1483,7 @@ if (!_treatmentRcvdMessages[ID_UI_RINSEBACK_CMD_RQST].isNull()) { handleRinsebackSubstate(_treatmentRcvdMessages[ID_UI_RINSEBACK_CMD_RQST], - rbAcuumVolML, txSubState, rbSubState); + rbAcuumVolML, txSubState, rbSubState, rbFlowMLPM); txStates[0] = txSubState; txStates[4] = rbSubState; prepareStatesBroadcastData(ID_HD_TX_STATES_BC, txStates); @@ -1434,13 +1498,13 @@ } _treatmentRcvdMessages[ID_UI_RINSEBACK_CMD_RQST].clear(); } - if (rbSubState == RINSEBACK_RUN_STATE) { // Only accumulate the rinseback volume if we are in the run state - rbAcuumVolML += _treatmentParams.rinsebackFlowRateMLPM * FLOW_INTEGRATOR; + rbAcuumVolML += rbFlowMLPM * FLOW_INTEGRATOR; } if (rbAcuumVolML >= rbTargetVolML) { + qDebug() << "RB Vols" << rbAcuumVolML << rbTargetVolML; rbSubState = RINSEBACK_STOP_STATE; txStates[0] = txSubState; txStates[4] = rbSubState; @@ -1453,7 +1517,7 @@ } if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { - if (rbSubState != RINSEBACK_RUN_STATE) { + if ((rbSubState != RINSEBACK_RUN_STATE) && (rbCountDownS != 0)) { // If the rinseback is not in the run state, count down rinseback timer // TODO do we count down from the start rinseback button? rbCountDownS--; @@ -1462,6 +1526,7 @@ prepareStatesBroadcastData(ID_HD_TX_STATES_BC, txStates); prepareRinsebackBroadcastData(rinsebackVolsML, rinsebackBC); + prepareTreatmentTimeBroadcastData(); } };