Index: sources/drydemo/StateController.cpp =================================================================== diff -u -r61e26e538aae580369385eb78a966e74240d79c4 -r756496932decbaae7bb3c9f694afc0402eeb1349 --- sources/drydemo/StateController.cpp (.../StateController.cpp) (revision 61e26e538aae580369385eb78a966e74240d79c4) +++ sources/drydemo/StateController.cpp (.../StateController.cpp) (revision 756496932decbaae7bb3c9f694afc0402eeb1349) @@ -15,38 +15,18 @@ connect(&_ApplicationController, SIGNAL(didUnhandledMsgAppController(const QVariantList &)), this , SLOT(doStateControllerUnhandledMsgReceived(const QVariantList &))); - _dryDemo.connectToState("Standby" , this, &StateController::onStandbyStateChange ); - _dryDemo.connectToState("Pre_Tx" , this, &StateController::onPretreatmentStateChange ); - _dryDemo.connectToState("Blood_Prime" , this, &StateController::onBloodPrimeStateChange ); - _dryDemo.connectToState("Treatment" , this, &StateController::onTreatmentStateChange ); - //_dryDemo.connectToState("Disposables" , this, &StateController::onDisposablesStateChange ); - //_dryDemo.connectToState("System_Prime" , this, &StateController::onSystemPrimeStateChange ); - //_dryDemo.connectToState("BP_HR" , this, &StateController::onBPHRStateChange ); - //_dryDemo.connectToState("Ultrafiltraion" , this, &StateController::onUltrafiltrationStateChange ); - //_dryDemo.connectToState("Connection" , this, &StateController::onConnectionStateChange ); + _dryDemo.connectToState("Standby" , this, &StateController::onStandbyStateChange ); + _dryDemo.connectToState("Pre_Tx" , this, &StateController::onPretreatmentStateChange ); + _dryDemo.connectToState("Blood_Prime" , this, &StateController::onBloodPrimeStateChange ); + _dryDemo.connectToState("Treatment" , this, &StateController::onTreatmentStateChange ); - //_dryDemo.connectToState("Start_Tx" , this, &StateController::onStartTreatmentStateChange ); - //_dryDemo.connectToState("Blood_Prime" , this, &StateController::onTreatmentBloodPrimeStateChange); - //_dryDemo.connectToState("Treatment" , this, &StateController::onTreatmentTreatmentStateChange ); - //_dryDemo.connectToState("End_Tx" , this, &StateController::onEndTreatmentStateChange ); - //_dryDemo.connectToState("Post_Tx" , this, &StateController::onPostTreatmentStateChange ); - //_dryDemo.connectToState("Disinfect" , this, &StateController::onDisinfectStateChange ); - _transitionEventsFromStandby.clear(); - _transitionEventsFromStandby[CMD_PRE_TX ] = "T_SB_2_Pretx"; - _transitionEventsFromStandby[CMD_BLOOD_PRIME ] = "T_SB_2_BP"; - _transitionEventsFromStandby[CMD_MAIN_TX ] = "T_SB_2_Tx"; - //_transitionEventsFromStandby[CMD_CONSUMABLES ] = "Transition_2_Consumables"; - //_transitionEventsFromStandby[CMD_DISPOSABLES ] = "Transition_2_Disposables"; - //_transitionEventsFromStandby[CMD_SYSTEM_PRIME ] = "Transition_2_Sys_Prime"; - //_transitionEventsFromStandby[CMD_BP_HR ] = "Transition_2_BP_HR"; - //_transitionEventsFromStandby[CMD_ULTRAFILTRATION] = "Transition_2_Ultrafiltraion"; - //_transitionEventsFromStandby[CMD_CONNECTION ] = "Transition_2_Patient_Connection"; - //_transitionEventsFromStandby[CMD_START_TX ] = "Transition_2_Start_Tx"; - //_transitionEventsFromStandby[CMD_END_TX ] = "Transition_2_End_Tx"; - //_transitionEventsFromStandby[CMD_DISINFECTION ] = "Transition_2_Disinfect"; + _transitionEventsFromStandby[CMD_PRE_TX ] = {"T_SB_2_Pretx", static_cast(MODE_PRET)}; + _transitionEventsFromStandby[CMD_BLOOD_PRIME ] = {"T_SB_2_BP" , static_cast(MODE_TREA)}; + _transitionEventsFromStandby[CMD_MAIN_TX ] = {"T_SB_2_Tx" , static_cast(MODE_TREA)}; + //connect(&_dryDemo, &QScxmlStateMachine::runningChanged, this, &StateController::onBackToStanbyEvent); // TODO remove } void StateController::quit() @@ -56,7 +36,7 @@ void StateController::doStateControllerUnhandledMsgReceived(const QVariantList &msg) { - MessageID receivedMsgID = static_cast(msg[0].toUInt()); + MessageID receivedMsgID = static_cast(msg[0].toUInt()); // TODO check the length before reading the index switch(receivedMsgID) { @@ -65,28 +45,13 @@ case ID_UI_BLOOD_PRIME_CMD_RQST: case ID_UI_CONFIRMATION_RESULT_RESP: case ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST: - //case ID_UI_TX_PARAMS_RQST: - //case ID_UI_CONFIRM_RESP: - //case ID_UI_RINSEBACK_CMD_RQST: - //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: - //case ID_UI_SALINE_BOLUS_RQST: - //case ID_UI_PRESSURE_LIMITS_CHANGE_RQST: - //case ID_UI_ALARM_USER_ACTION_RQST: - //case ID_USER_BLOOD_DIAL_RATE_CHANGE_RQST: - //case ID_UI_HEPARIN_PAUSE_RESUME_RQST: _treatmentRcvdMessages[receivedMsgID] = msg[1]; break; //// These messages do not have a payload in from UI so a fake payload is added to be consumed //// and processed case ID_UI_ADJUST_DISPOSABLES_CONFIRM_RQST: case ID_UI_ADJUST_START_TREATMENT_RQST: - //case ID_UI_TREATMENT_LOG_RQST: - //case ID_UI_POST_TREATMNET_NEXT_RQST: - //case ID_UI_DISPOSABLE_REMOVAL_CONFIRM_RQST: _treatmentRcvdMessages[receivedMsgID] = 0; break; @@ -119,25 +84,26 @@ void StateController::timerEvent(QTimerEvent *) { - if (!_dryDemo.isRunning()) { - _dryDemo.start(); + if (!_dryDemo.isRunning()){ + _dryDemo.start(); } _dryDemo.submitEvent("TimeoutEvent"); - if (_isBroadcastListReady) { - sendMessages(true); + if (_isBroadcastListReady){ + sendMessages(true); } - if (_isSendListReady) { - sendMessages(false); + if (_isSendListReady){ + sendMessages(false); } - if (! _treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].isNull()){ - // Check for the user request message from the dry-deme menu - handleDryDemoMenuRequestMessage(); - _dryDemo.submitEvent(_back2StandbyEvent); - } + //if (! _treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].isNull()){ + // // Check for the user request message from the dry-deme menu + // handleDryDemoMenuRequestMessage(); + //} + + //qDebug() << "Active State" << _dryDemo.activeStateNames(); } // ---------------------- Private methods ------------------ // @@ -160,274 +126,265 @@ void StateController::handleDryDemoMenuRequestMessage() { - qint32 IDIndex = 0; - Types::U32 param; - GetValue(_treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].toByteArray(), IDIndex, param); - if (param.value != UI_MSG_BB_PAYLOAD_ID) { return; } + quint32 msgPayload = extractU32DataFromReceivedMessage(ID_UI_CONFIRMATION_RESULT_RESP, 0); + if (msgPayload != UI_MSG_BB_PAYLOAD_ID) { return; } - IDIndex = UI_MSG_BB_STATUS_INDEX; - GetValue(_treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].toByteArray(), IDIndex, param); - _treatmentStatus.userCmd = static_cast(param.value); + msgPayload = extractU32DataFromReceivedMessage(ID_UI_CONFIRMATION_RESULT_RESP, UI_MSG_BB_STATUS_INDEX); + _treatmentStatus.userCmd = static_cast(msgPayload); _treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].clear(); } void StateController::handleBackToStandbyEvent(State_Status &status) { - _dryDemo.connectToEvent(_back2StandbyEvent, [&status](const QScxmlEvent &event) { - qDebug() << "Event invoked:" << event.name(); - status = STATE_ON_EXIT; - }); + //_dryDemo.connectToEvent(_back2StandbyEvent, [&status](const QScxmlEvent &event) { + // qDebug() << "Event invoked:" << event.name(); + // status = STATE_ON_ENTRY; + //}, Qt::UniqueConnection); + if (! _treatmentRcvdMessages[ID_UI_CONFIRMATION_RESULT_RESP].isNull()){ + // Check for the user request message from the dry-demo menu + handleDryDemoMenuRequestMessage(); + _treatmentStatus.stateTransitionEvent = "T_Back_2_SB"; + status = STATE_ON_EXIT; + } +} +void StateController::onBackToStanbyEvent() +{ + // TODO remove + qDebug() << "Active State" << _dryDemo.activeStateNames(); } - - // ----------- State transition methods ---------------- // void StateController::onStandbyStateChange(bool active) { static State_Status status = STATE_ON_ENTRY; - auto inEntry = [=](){ - handleTDOpModeTransitionBroadcastData(MODE_STAN, 0); + auto onEntry = [=](){ + handleTDOpModeTransitionBroadcastData(MODE_STAN, 0, BC_IMMEDIATELY); setTreatmentParametersToDefault(); resetDryDemoVariables(); status = STATE_ON_ACTION; - qDebug() << "Standby on entry"; }; - auto inAction = [=](){ + auto onAction = [=](){ status = STATE_ON_ACTION; if (! _treatmentRcvdMessages[ID_INITIATE_TREATMENT].isNull()){ _treatmentRcvdMessages[ID_INITIATE_TREATMENT].clear(); - QVariantList resp; - resp.append(static_cast(ID_TD_RESP_INITIATE_TREATMENT)); - resp.append(Can_Id::eChlid_TD_UI); - resp.append(1); - resp.append(0); - _isSendListReady = false; - _sendMessages.append(resp); - _isSendListReady = true; - _dryDemo.submitEvent(_transitionEventsFromStandby[CMD_PRE_TX]); + _treatmentStatus.stateTransitionEvent = _transitionEventsFromStandby[CMD_PRE_TX][0].toString(); + + handleUIResponseMessage(ID_TD_RESP_INITIATE_TREATMENT, ACCEPT_VALUE); status = STATE_ON_EXIT; } if (_treatmentStatus.userCmd != CMD_NONE){ if ((_treatmentStatus.userCmd > CMD_STAND_BY) && (_treatmentStatus.userCmd <= CMD_DISINFECTION)) { - qDebug() << "Submit event" << _transitionEventsFromStandby[_treatmentStatus.userCmd]; - _dryDemo.submitEvent(_transitionEventsFromStandby[_treatmentStatus.userCmd]); + _treatmentStatus.stateTransitionEvent = _transitionEventsFromStandby[_treatmentStatus.userCmd][0].toString(); + TD_OP_MODE opMode = static_cast(_transitionEventsFromStandby[_treatmentStatus.userCmd][1].toUInt()); + qDebug() << "Submit event" << _treatmentStatus.stateTransitionEvent << opMode; + handleTDOpModeTransitionBroadcastData(opMode, 0, BC_IMMEDIATELY); _treatmentStatus.userCmd = CMD_NONE; status = STATE_ON_EXIT; } } + handleTDOpModeTransitionBroadcastData(MODE_STAN, 0, BC_DELAYED); + handleBackToStandbyEvent(status); }; - auto inExit = [=](){ + auto onExit = [=](){ qDebug() << "Standby in exit"; - status = STATE_ON_ENTRY; + _dryDemo.submitEvent(_treatmentStatus.stateTransitionEvent); + status = STATE_ON_ENTRY; }; switch (status) { // TODO macro it later - case STATE_ON_ENTRY : if (active) inEntry (); break; - case STATE_ON_ACTION: if (active) inAction(); break; - case STATE_ON_EXIT : if (active) inExit (); break; + case STATE_ON_ENTRY : if (active) onEntry (); break; + case STATE_ON_ACTION: if (active) onAction(); break; + case STATE_ON_EXIT : if (active) onExit (); break; } } void StateController::onPretreatmentStateChange(bool active) { static State_Status status = STATE_ON_ENTRY; - auto inEntry = [=](){ - handleTDOpModeTransitionBroadcastData(MODE_PRET, 0); - + auto onEntry = [=](){ + handleTDOpModeTransitionBroadcastData(MODE_PRET, 0, BC_IMMEDIATELY); status = STATE_ON_ACTION; - qDebug() << "PreTx on entry"; }; - auto inAction = [=](){ + auto onAction = [=](){ + status = STATE_ON_ACTION; if (! _treatmentRcvdMessages[ID_UI_ADJUST_DISPOSABLES_CONFIRM_RQST].isNull()){ _treatmentRcvdMessages[ID_UI_ADJUST_DISPOSABLES_CONFIRM_RQST].clear(); - - QVariantList resp; - resp.append(static_cast(ID_TD_ADJUST_DISPOSSABLES_CONFIRM_RESP)); - resp.append(Can_Id::eChlid_TD_UI); - resp.append(1); - resp.append(0); - _isSendListReady = false; - _sendMessages.append(resp); - _isSendListReady = true; + handleUIResponseMessage(ID_TD_ADJUST_DISPOSSABLES_CONFIRM_RESP, ACCEPT_VALUE); } if (! _treatmentRcvdMessages[ID_UI_TREATMENT_PARAMS_TO_VALIDATE].isNull()){ setTreatmentParametersFromUI(_treatmentRcvdMessages[ID_UI_TREATMENT_PARAMS_TO_VALIDATE]); _treatmentRcvdMessages[ID_UI_TREATMENT_PARAMS_TO_VALIDATE].clear(); } - status = STATE_ON_ACTION; - if (! _treatmentRcvdMessages[ID_UI_ADJUST_START_TREATMENT_RQST].isNull()){ _treatmentRcvdMessages[ID_UI_ADJUST_START_TREATMENT_RQST].clear(); - sendStartTxResponse(); - status = STATE_ON_EXIT; - _dryDemo.submitEvent("T_Pretx_2_BP"); + handleUIResponseMessage(ID_TD_ADJUST_START_TREATMENT_RESP, ACCEPT_VALUE); + status = STATE_ON_EXIT; + _treatmentStatus.stateTransitionEvent = "T_Pretx_2_BP"; } + handleBackToStandbyEvent(status); }; - auto inExit = [=](){ + auto onExit = [=](){ qDebug() << "PreTx in exit"; + _dryDemo.submitEvent(_treatmentStatus.stateTransitionEvent); status = STATE_ON_ENTRY; }; switch (status) { // TODO macro it later - case STATE_ON_ENTRY : if (active) inEntry (); break; - case STATE_ON_ACTION: if (active) inAction(); break; - case STATE_ON_EXIT : if (active) inExit (); break; + case STATE_ON_ENTRY : if (active) onEntry (); break; + case STATE_ON_ACTION: if (active) onAction(); break; + case STATE_ON_EXIT : if (active) onExit (); break; } } void StateController::onBloodPrimeStateChange(bool active) { - static State_Status status = STATE_ON_ENTRY; - static float accumBloodVolML = 0.0; - static quint32 currBloodFlowMLPM = BLOOD_PRIME_START_FLOW_MLPM; - static bool resume = true; + static State_Status status = STATE_ON_ENTRY; + static float accumBloodVolML = 0.0; + static quint32 currBloodFlowMLPM = BLOOD_PRIME_START_FLOW_MLPM; + static bool resume = true; + static quint32 bloodPrimeResume = 1; + static quint32 bloodPrimePause = 2; + static float rampStepML = 0.0; + static bool hasFlowChngeRequested = false; - auto inEntry = [=](){ - handleTDOpModeTransitionBroadcastData(MODE_TREA, 0); - handleBloodPrimeBroadcastData(0.0, 0, 0, true); - accumBloodVolML = 0.0; - currBloodFlowMLPM = BLOOD_PRIME_START_FLOW_MLPM; - resume = true; + auto onEntry = [=](){ + handleTDOpModeTransitionBroadcastData(MODE_TREA, 0, BC_IMMEDIATELY); + // Clear the blood prime data immediately to prevent residual accumulated volume from a previous run + handleBloodPrimeBroadcastData(0.0, 0, 0, BC_IMMEDIATELY); + accumBloodVolML = 0.0; + currBloodFlowMLPM = BLOOD_PRIME_START_FLOW_MLPM; + resume = true; + hasFlowChngeRequested = false; quint32 bloodPrimeStateRamp = 1; QList txStates = {TREAT_BLOOD_PRIME_STATE, bloodPrimeStateRamp, 0, 0, 0, 0, 0, 0, 0, 0}; - handleTreatmentStatesBroadcastData(txStates); + handleTreatmentStatesBroadcastData(txStates, BC_IMMEDIATELY); + + rampStepML = getBloodPrimeRampStepML(); + qDebug() << "Rmpa" << rampStepML; + status = STATE_ON_ACTION; qDebug() << "Blood prime on entry"; }; - auto inAction = [=](){ + auto onAction = [=](){ + status = STATE_ON_ACTION; if (! _treatmentRcvdMessages[ID_UI_BLOOD_PRIME_CMD_RQST].isNull()){ - QVariantList resp; - qint32 index = 0; - Types::U32 u32Var; - resp.append(static_cast(ID_TD_BLOOD_PRIME_CMD_RESP)); - resp.append(Can_Id::eChlid_TD_UI); - resp.append(ACCEPT_VALUE); - resp.append(0); - _isSendListReady = false; - _sendMessages.append(resp); - _isSendListReady = true; - GetValue(_treatmentRcvdMessages[ID_UI_BLOOD_PRIME_CMD_RQST].toByteArray(), index, u32Var); - resume = (u32Var.value == 1 ? true : false); - quint32 state = (u32Var.value == 1 ? 1 : 2); + handleUIResponseMessage(ID_TD_BLOOD_PRIME_CMD_RESP, ACCEPT_VALUE); - QVariantList msg; - msg.append(static_cast(ID_TD_TREATMENT_STATE_DATA)); - msg.append(Can_Id::eChlid_TD_Sync); - msg.append(1); msg.append(state); msg.append(0); msg.append(0); msg.append(0); msg.append(0); msg.append(0); msg.append(0); - msg.append(0); msg.append(0); - _isBroadcastListReady = false; - _broadcastMessages.append(msg); - _isBroadcastListReady = true; + quint32 resumeStatus = extractU32DataFromReceivedMessage(ID_UI_BLOOD_PRIME_CMD_RQST, 0); + resume = (resumeStatus == bloodPrimeResume ? true : false); + quint32 state = (resumeStatus == bloodPrimeResume ? bloodPrimeResume : bloodPrimePause); + + QList txStates = {TREAT_BLOOD_PRIME_STATE, state, 0, 0, 0, 0, 0, 0, 0, 0}; + handleTreatmentStatesBroadcastData(txStates, BC_IMMEDIATELY); _treatmentRcvdMessages[ID_UI_BLOOD_PRIME_CMD_RQST].clear(); } if (! _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST].isNull()){ - qint32 index = 0; - Types::U32 u32Var; - GetValue(_treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST].toByteArray(), index, u32Var); - quint32 var = u32Var.value; - handleBloodPrimeFlowChangeRequest(var, currBloodFlowMLPM); - //qDebug() << "FLow" << currBloodFlowMLPM; + // TODO do we need to check the range + currBloodFlowMLPM = extractU32DataFromReceivedMessage(ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST, 0); + handleUIResponseMessage(ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESP, ACCEPT_VALUE); + hasFlowChngeRequested = true; + qDebug() << "FLow" << currBloodFlowMLPM; _treatmentRcvdMessages[ID_UI_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RQST].clear(); } - //_dryDemo.connectToEvent("T_Back_2_SB", [](const QScxmlEvent &event) { - // qDebug() << "Event invoked:" << event.name(); - // status = STATE_ON_EXIT; - //}); - handleBackToStandbyEvent(status); + handleBloodPrimeVolML(resume, rampStepML, hasFlowChngeRequested, currBloodFlowMLPM, accumBloodVolML); + handleTreatmentSetpointsBroadcastData(currBloodFlowMLPM, _treatmentParams.dialysateFlowRateMLPM, + _treatmentParams.dialysateTemperatureC); - handleBloodPrimeVolML(resume, currBloodFlowMLPM, accumBloodVolML); - handleTreatmentSetpointsBroadcastData(currBloodFlowMLPM, _treatmentParams.dialysateFlowRateMLPM, _treatmentParams.dialysateTemperatureC); - - status = STATE_ON_ACTION; - - if (accumBloodVolML > BLOOD_PRIME_VOLUME_ML) { - status = STATE_ON_EXIT; + _treatmentStatus.stateTransitionEvent = "T_BP_2_Tx"; + status = STATE_ON_EXIT; + // Send the final volume value prior to trnasiotining to treatment + handleBloodPrimeBroadcastData(accumBloodVolML, 0, 0, BC_IMMEDIATELY); qDebug() << "VOL" << accumBloodVolML; - _dryDemo.submitEvent("T_BP_2_Tx"); } + + handleBackToStandbyEvent(status); + + //qDebug() << "Blood state" << status; }; - auto inExit = [=](){ + auto onExit = [=](){ //qDebug() << "Blood prime on exit"; + _dryDemo.submitEvent(_treatmentStatus.stateTransitionEvent); status = STATE_ON_ENTRY; }; switch (status) { // TODO macro it later - case STATE_ON_ENTRY : if (active) inEntry (); break; - case STATE_ON_ACTION: if (active) inAction(); break; - case STATE_ON_EXIT : if (active) inExit (); break; + case STATE_ON_ENTRY : if (active) onEntry (); break; + case STATE_ON_ACTION: if (active) onAction(); break; + case STATE_ON_EXIT : if (active) onExit (); break; } } void StateController::onTreatmentStateChange(bool active) { static State_Status status = STATE_ON_ENTRY; - auto inEntry = [=](){ - handleTDOpModeTransitionBroadcastData(MODE_TREA, 0); - QVariantList msg; - msg.append(static_cast(ID_TD_TREATMENT_STATE_DATA)); - msg.append(Can_Id::eChlid_TD_Sync); - msg.append(2); msg.append(0); msg.append(0); msg.append(0); msg.append(0); msg.append(0); msg.append(0); msg.append(0); - msg.append(0); msg.append(0); - _isBroadcastListReady = false; - _broadcastMessages.append(msg); - _isBroadcastListReady = true; + auto onEntry = [=](){ + handleTDOpModeTransitionBroadcastData(MODE_TREA, 0, BC_IMMEDIATELY); + QList txStates = {TREAT_START_STATE, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + handleTreatmentStatesBroadcastData(txStates, BC_IMMEDIATELY); + txStates = {TREAT_DIALYSIS_STATE, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + handleTreatmentStatesBroadcastData(txStates, BC_IMMEDIATELY); status = STATE_ON_ACTION; qDebug() << "Tx on entry"; }; - auto inAction = [=](){ + auto onAction = [=](){ status = STATE_ON_ACTION; - - + handleTDOpModeTransitionBroadcastData(MODE_TREA, 0, BC_DELAYED); + QList txStates = {TREAT_DIALYSIS_STATE, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + handleTreatmentStatesBroadcastData(txStates, BC_DELAYED); handleBackToStandbyEvent(status); - }; - auto inExit = [=](){ + auto onExit = [=](){ qDebug() << "Tx in exit"; - status = STATE_ON_ENTRY; + _dryDemo.submitEvent(_treatmentStatus.stateTransitionEvent); + status = STATE_ON_ENTRY; }; switch (status) { // TODO macro it later - case STATE_ON_ENTRY : if (active) inEntry (); break; - case STATE_ON_ACTION: if (active) inAction(); break; - case STATE_ON_EXIT : if (active) inExit (); break; + case STATE_ON_ENTRY : if (active) onEntry (); break; + case STATE_ON_ACTION: if (active) onAction(); break; + case STATE_ON_EXIT : if (active) onExit (); break; } } +// ************* Hepler functions ************* // - -void StateController::handleTDOpModeTransitionBroadcastData(Can::TD_OP_MODE mode, quint32 subMode) +void StateController::handleTDOpModeTransitionBroadcastData(const TD_OP_MODE mode, const quint32 subMode, 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_OP_MODE_DATA)); msg.append(Can_Id::eChlid_TD_Sync); @@ -556,12 +513,12 @@ _isSendListReady = true; } -void StateController::sendStartTxResponse() +void StateController::handleUIResponseMessage(const Can::Message_ID_Enum msgID, const quint32 acceptReject) { QVariantList resp; - resp.append(static_cast(ID_TD_ADJUST_START_TREATMENT_RESP)); + resp.append(static_cast(msgID)); resp.append(Can_Id::eChlid_TD_UI); - resp.append(ACCEPT_VALUE); + resp.append(acceptReject); resp.append(0); _isSendListReady = false; _sendMessages.append(resp); @@ -573,4 +530,13 @@ _treatmentStatus.hasTxParamsBeenInitialized = false; _treatmentStatus.treatmentElapsedTimeS = DEF_TX_ELAPSED_TIME_S; _treatmentStatus.remainingTreatmentTimeS = DEF_TX_PARAM_PRESCRIBED_DUR_S - _treatmentStatus.treatmentElapsedTimeS; + _treatmentStatus.stateTransitionEvent = ""; } + +quint32 StateController::extractU32DataFromReceivedMessage(const Message_ID_Enum msgID, qint32 index) +{ + Types::U32 u32Var; + GetValue(_treatmentRcvdMessages[msgID].toByteArray(), index, u32Var); + + return u32Var.value; +} Index: sources/drydemo/StateController.h =================================================================== diff -u -r61e26e538aae580369385eb78a966e74240d79c4 -r756496932decbaae7bb3c9f694afc0402eeb1349 --- sources/drydemo/StateController.h (.../StateController.h) (revision 61e26e538aae580369385eb78a966e74240d79c4) +++ sources/drydemo/StateController.h (.../StateController.h) (revision 756496932decbaae7bb3c9f694afc0402eeb1349) @@ -50,6 +50,7 @@ #define QOBJECT_TIMER_TIMEOUT_MS 100 #define PROGRESS_TIME_BC_INTERVAL_MS 1000 #define NUM_OF_COUNTS_TIMER_BC_EMIT (PROGRESS_TIME_BC_INTERVAL_MS / QOBJECT_TIMER_TIMEOUT_MS) + #define NUM_OF_COUNTS_TIMER_2_CONTROL (PROGRESS_TIME_BC_INTERVAL_MS / QOBJECT_TIMER_TIMEOUT_MS) #define NUM_OF_COUNTS_TO_BC_MSG 3 // Treatment params @@ -93,7 +94,6 @@ // Treatment defines #define BLOOD_PRIME_VOLUME_ML (106.6 + 40) #define BLOOD_PRIME_START_FLOW_MLPM 250 - #define BLOOD_PRIME_FLOW_CHNG_MLPM 25 #define FLOW_INTEGRATOR (1.0 / (SECONDS_PER_MINUTE * (MILLISECONDS_PER_SECOND / QOBJECT_TIMER_TIMEOUT_MS))) #define MAX_DIALYSATE_VOLUME_ML 150000 #define BLOOD_PRIME_PAUSE_TIMEOUT_S (5 * SECONDS_PER_MINUTE) @@ -167,12 +167,18 @@ STATE_ON_EXIT, }; + enum Broadcast_Type { + BC_DELAYED = 0, + BC_IMMEDIATELY, + }; + struct Treatment_Status_Vars { bool hasTxParamsBeenInitialized; quint32 treatmentElapsedTimeS; quint32 remainingTreatmentTimeS; quint32 prescribedTreatmentTimeS; User_Command_ID userCmd; + QString stateTransitionEvent; }; struct Treatment_Params { @@ -203,8 +209,7 @@ float ufVolumeL; }; - QString _back2StandbyEvent = "T_Back_2_SB"; - QHash_transitionEventsFromStandby; + QHash_transitionEventsFromStandby; QList _broadcastMessages; QList _sendMessages; QHash _treatmentRcvdMessages; @@ -221,25 +226,28 @@ void handleDryDemoMenuRequestMessage(); // State handlers + void onBackToStanbyEvent(); // TODO remove + void onStandbyStateChange(bool active); void onPretreatmentStateChange(bool active); void onBloodPrimeStateChange(bool active); void onTreatmentStateChange(bool active); // Helper functions - void handleTDOpModeTransitionBroadcastData(Can::TD_OP_MODE mode, quint32 subMode); + void handleTDOpModeTransitionBroadcastData(const Can::TD_OP_MODE mode, const quint32 subMode, const Broadcast_Type BCType); void setTreatmentParametersFromUI(const QVariant &payload); // TODO move the implementation to pretx cpp - void sendStartTxResponse(); + void handleUIResponseMessage(const Can::Message_ID_Enum msgID, const quint32 acceptReject); void resetDryDemoVariables(); void handleBackToStandbyEvent(State_Status &status); + quint32 extractU32DataFromReceivedMessage(const Can::Message_ID_Enum msgID, qint32 index); // Blood prime methods - void handleBloodPrimeBroadcastData(float accumulatedVolML, quint32 primeTimeOutS, quint32 pauseCountDownS, bool initBC); - void handleBloodPrimeVolML(bool resume, quint32 &currBlodFlowMLPM, float &accumBloodVolML); - void handleBloodPrimeFlowChangeRequest(quint32 requestedFlowMLPM, quint32 &currBloodFlowMLPM); + float getBloodPrimeRampStepML(); + void handleBloodPrimeBroadcastData(const float accumulatedVolML, const quint32 primeTimeOutS, const quint32 pauseCountDownS, const Broadcast_Type BCType); + void handleBloodPrimeVolML(const bool resume, const float rampStepML, const bool hasFlowChanged, quint32 &currBlodFlowMLPM, float &accumBloodVolML); // Treatment methods void setTreatmentParametersToDefault(); - void handleTreatmentSetpointsBroadcastData(quint32 bloodFlowMLPM, quint32 dialFlowMLPM, float dialTempC); - void handleTreatmentStatesBroadcastData(const QList &txStates); + void handleTreatmentSetpointsBroadcastData(const quint32 bloodFlowMLPM, const quint32 dialFlowMLPM, const float dialTempC); + void handleTreatmentStatesBroadcastData(const QList &txStates, const Broadcast_Type BCType); }; Index: sources/drydemo/StateControllerTreatment.cpp =================================================================== diff -u -r61e26e538aae580369385eb78a966e74240d79c4 -r756496932decbaae7bb3c9f694afc0402eeb1349 --- sources/drydemo/StateControllerTreatment.cpp (.../StateControllerTreatment.cpp) (revision 61e26e538aae580369385eb78a966e74240d79c4) +++ sources/drydemo/StateControllerTreatment.cpp (.../StateControllerTreatment.cpp) (revision 756496932decbaae7bb3c9f694afc0402eeb1349) @@ -3,11 +3,23 @@ #include "ApplicationController.h" #include "types.h" -void StateController::handleBloodPrimeBroadcastData(float accumulatedVolML, quint32 primeTimeOutS, quint32 pauseCountDownS, bool initBC) +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) && (!initBC)) { return; } + if ((++broadcastCounter % NUM_OF_COUNTS_TIMER_BC_EMIT != 0) && (BCType == BC_DELAYED)) { return; } // Broadcast QVariantList msg; @@ -22,68 +34,51 @@ _isBroadcastListReady = true; } - -void StateController::handleBloodPrimeVolML(bool resume, quint32 &currBloodFlowMLPM, float &accumBloodVolML) +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, false); - qDebug() << "Count" << primeTimeoutS << pauseCountDownS << elapsedTimeSincePauseS; + 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; } - //prepareOcclusionBroadcastData(); - //prepareTreatmentParamsRangesBroadcastData(true); // Reset the params and get ready for a new treatment + accumBloodVolML += (currBloodFlowMLPM * FLOW_INTEGRATOR); - if (currBloodFlowMLPM < _treatmentParams.bloodFlowRateMLPM) { - // If interim blood flow is less than the target blood flow, keep adding - // to the blood flow ramp - currBloodFlowMLPM += BLOOD_PRIME_FLOW_CHNG_MLPM; - } + if (++controlCounter % NUM_OF_COUNTS_TIMER_2_CONTROL != 0) { return; } - if (currBloodFlowMLPM >= _treatmentParams.bloodFlowRateMLPM) { - // If the interim blood flow is >= target blood flow: - // If target blood flow is less than 250 which is the starting flow in blood prime, - // then keep subtracting the target (e.g. target 110 and we start from 250 mL/min) - // If the target blood flow is > than 250 mL/min set the interim flow to target blood flow - if (_treatmentParams.bloodFlowRateMLPM < BLOOD_PRIME_START_FLOW_MLPM) { - currBloodFlowMLPM -= BLOOD_PRIME_FLOW_CHNG_MLPM; + if (!hasFlowChanged) { + // If the user has changed the flow then do not control (ramp) the steps + currBloodFlowMLPM += rampStepML; - if (currBloodFlowMLPM <= _treatmentParams.bloodFlowRateMLPM) { currBloodFlowMLPM = _treatmentParams.bloodFlowRateMLPM; } + 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 = _treatmentParams.bloodFlowRateMLPM; } + else { + currBloodFlowMLPM = (currBloodFlowMLPM > _treatmentParams.bloodFlowRateMLPM ? _treatmentParams.bloodFlowRateMLPM : currBloodFlowMLPM); + } } - accumBloodVolML += (currBloodFlowMLPM * FLOW_INTEGRATOR); - - primeTimeoutS = 0; - pauseCountDownS = 0; + primeTimeoutS = 0; + pauseCountDownS = 0; elapsedTimeSincePauseS = 0; - handleBloodPrimeBroadcastData(accumBloodVolML, primeTimeoutS, pauseCountDownS, false); - //qDebug() << "Current" << currBloodFlowMLPM << _treatmentParams.bloodFlowRateMLPM; + handleBloodPrimeBroadcastData(accumBloodVolML, primeTimeoutS, pauseCountDownS, BC_IMMEDIATELY); + qDebug() << "Current" << currBloodFlowMLPM << _treatmentParams.bloodFlowRateMLPM << controlCounter << accumBloodVolML; } -void StateController::handleBloodPrimeFlowChangeRequest(quint32 requestedFlowMLPM, quint32 &currBloodFlowMLPM) -{ - currBloodFlowMLPM = requestedFlowMLPM; - - QVariantList resp; - resp.append(static_cast(ID_TD_TREATMENT_SET_POINT_BLOOD_FLOW_CHANGE_RESP)); - resp.append(Can_Id::eChlid_TD_UI); - resp.append(ACCEPT_VALUE); - resp.append(0); - _isSendListReady = false; - _sendMessages.append(resp); - _isSendListReady = true; - -} - void StateController::setTreatmentParametersToDefault() { // TODO complete the list as we go @@ -96,7 +91,7 @@ _treatmentParams.treatmentDurationMin = DEF_TX_PARAM_PRESCRIBED_DUR_MIN; } -void StateController::handleTreatmentSetpointsBroadcastData(quint32 bloodFlowMLPM, quint32 dialFlowMLPM, float dialTempC) +void StateController::handleTreatmentSetpointsBroadcastData(const quint32 bloodFlowMLPM, const quint32 dialFlowMLPM, const float dialTempC) { static quint32 broadcastCounter = 0; @@ -111,14 +106,18 @@ _isBroadcastListReady = true; } -void StateController::handleTreatmentStatesBroadcastData(const QList &txStates) +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); + msg.append(item); } _isBroadcastListReady = false; _broadcastMessages.append(msg);