Index: sources/StateController.cpp =================================================================== diff -u -rad35b27c3ec3ea357b6173df5ab8793c3378af6e -r3b740846dabcba2ed00f2e48824a6ff155e78d26 --- sources/StateController.cpp (.../StateController.cpp) (revision ad35b27c3ec3ea357b6173df5ab8793c3378af6e) +++ sources/StateController.cpp (.../StateController.cpp) (revision 3b740846dabcba2ed00f2e48824a6ff155e78d26) @@ -53,6 +53,7 @@ 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: _treatmentRcvdMessages[receivedMsgID] = msg[1]; break; @@ -62,10 +63,12 @@ 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_HD_ALARM_STATUS_BC: case ID_HD_BLOOD_FLOW_DATA_BC: case ID_HD_DIALYSATE_FLOW_DATA_BC: case ID_PRESSURE_OCCLUSION_DATA_BC: @@ -88,6 +91,7 @@ case ID_HD_RINSEBACK_CMD_RESP: case ID_HD_RINSEBACK_DATA_BC: case ID_HD_SALINE_BOLUS_BC: + case ID_HD_PRESSURE_LIMITS_CHANGE_RESP: // Do nothing break; } @@ -244,25 +248,38 @@ // so the UF volume is set to default as well. _treatmentVars.txParamsUFVolL = DEF_TX_PARAM_UF_VOLUME_L; } + + // Update the default arterial and venous pressure limits + _treatmentVars.minArtPresLimitMMHG = static_cast(MIN_ART_PRES_LIMIT_MMHG); + _treatmentVars.maxArtPresLimitMMHG = static_cast(MAX_ART_PRES_LIMIT_MMHG); + _treatmentVars.minVenPresLimitMMHG = static_cast(MIN_VEN_PRES_LIMIT_MMHG); + _treatmentVars.maxVenPresLimitMMHG = static_cast(MAX_VEN_PRES_LIMIT_MMHG); } void StateController::prepareOcclusionBroadcastData() { - float artUpperFloatWindowMMHG = static_cast(200); - float artLowerFloatWindowMMHG = static_cast(_treatmentParams.areterialPresLimitWindowMMHG); + //qint32 minArtMMHG = static_cast(MIN_ART_PRES_LIMIT_MMHG); + //qint32 maxArtMMHG = static_cast(MAX_ART_PRES_LIMIT_MMHG); - float venUpperFloatWindowMMHG = static_cast(200); - float venLowerFloatWindowMMHG = static_cast(_treatmentParams.venousPresLimitWindowMMHG); + //float artWinMaxMMHGFloat = static_cast(_treatmentParams.areterialPresLimitWindowMMHG) + 20.0; + //float artWinMinMMHGFloat = static_cast(_treatmentParams.areterialPresLimitWindowMMHG) - 20.0; - float artRandomMMHG = _randNumGenerator.generateDouble() * (artUpperFloatWindowMMHG - artLowerFloatWindowMMHG) + artLowerFloatWindowMMHG; - float venRandomMMHG = _randNumGenerator.generateDouble() * (venUpperFloatWindowMMHG - venLowerFloatWindowMMHG) + venLowerFloatWindowMMHG; + //float venUpperFloatWindowMMHG = static_cast(0); + //float venLowerFloatWindowMMHG = static_cast(400); + //float artRandomMMHG = _randNumGenerator.generateDouble() * (maxArtMMHG - minArtMMHG) + minArtMMHG; + //float venRandomMMHG = _randNumGenerator.generateDouble() * (venUpperFloatWindowMMHG - venLowerFloatWindowMMHG) + venLowerFloatWindowMMHG; + QVariantList msg; msg.append(static_cast(ID_PRESSURE_OCCLUSION_DATA_BC)); msg.append(Can_Id::eChlid_HD_Sync); - msg.append(artRandomMMHG); msg.append(venRandomMMHG); 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); msg.append(0); + msg.append(_treatmentVars.curArtPresMMHG); msg.append(_treatmentVars.curVenPresMMHG); msg.append(0); msg.append(0); + msg.append(_treatmentVars.minArtPresLimitMMHG); + msg.append(_treatmentVars.maxArtPresLimitMMHG); + msg.append(_treatmentVars.minVenPresLimitMMHG); + msg.append(_treatmentVars.maxVenPresLimitMMHG); + msg.append(0); msg.append(0); + msg.append(0); msg.append(0); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; @@ -327,7 +344,8 @@ msg.append(_treatmentVars.measUFVolumeML); msg.append(0.0); msg.append(0.0); msg.append(0.0); msg.append(0.0); msg.append(0.0); msg.append(0.0); msg.append(0.0); msg.append(0.0); - msg.append(0); msg.append(0.0); msg.append(0); + msg.append(0); msg.append(_treatmentVars.prescribedUFRate); + msg.append(0); _isBroadcastListReady = false; _broadcastMessages.append(msg); _isBroadcastListReady = true; @@ -703,13 +721,170 @@ return status; } +void StateController::handleAlarmStatus(bool trigger, User_Command_ID cmd = CMD_HIGH_PRIO_ALARM) +{ + enum Alarm_Priority { + NONE = 0, + LOW = 1, + MEDIUM = 2, + HIGH = 3 + }; + + enum Alarm_ID { + ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE = 68, + ALARM_ID_HD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE = 70, + ALARM_ID_HD_VENOUS_PRESSURE_SELF_TEST_FAILURE = 71 + }; + + quint32 alarmID = 0; + quint32 alarmPriority = static_cast(NONE); + quint16 alarmFlags = 0; + + QVariantList msg; + msg.append(static_cast(ID_HD_ALARM_STATUS_BC)); + msg.append(Can_Id::eChlid_HD_Alarm); + + if (trigger) { + if (cmd == CMD_HIGH_PRIO_ALARM) { + alarmPriority = static_cast(HIGH); + alarmID = static_cast(ALARM_ID_HD_VENOUS_PRESSURE_SELF_TEST_FAILURE); + alarmFlags = 86; + } + else if (cmd == CMD_MEDIUM_PRIO_ALARM) { + alarmPriority = static_cast(MEDIUM); + alarmID = static_cast(ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE); + alarmFlags = 2; + } + else if (cmd == CMD_LOW_PRIO_ALARM) { + alarmPriority = static_cast(LOW); + alarmID = static_cast(ALARM_ID_HD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE); + alarmFlags = 18; + } + } + + msg.append(alarmPriority); + msg.append(alarmID); + msg.append(0); + msg.append(0); + msg.append(alarmFlags); + + _isSendListReady = false; + _sendMessages.append(msg); + _isSendListReady = true; +} + +void StateController::generateOcclusionPresureValues(bool initArray, quint32 stableCount) +{ + static const quint32 arraySize = MILLISECONDS_PER_SECOND/QOBJECT_TIMER_TIMEOUT_MS; + static float artRandArrayGenMMHG[arraySize]; + static float artRunningSumMMHG; + static quint32 artArrayIndex; + static quint32 artReadingCount; + + static float venRandArrayGenMMHG[arraySize]; + static float venRunningSumMMHG; + static quint32 venArrayIndex; + static quint32 venReadingCount; + + if (initArray) { + artRunningSumMMHG = 0.0; + artArrayIndex = 0; + artReadingCount = 0; + for (quint32 i = 0; i < arraySize; i++) { + artRandArrayGenMMHG[i] = 0.0; + } + + venRunningSumMMHG = 0; + venArrayIndex = 0; + venReadingCount = 0; + for (quint32 i = 0; i < arraySize; i++) { + venRandArrayGenMMHG[i] = 0.0; + } + } + + if (stableCount >= OCCLUSION_STABLE_TIME_COUNT) { + qint32 artTxParamsMMHG = _treatmentParams.areterialPresLimitWindowMMHG / 2; + _treatmentVars.minArtPresLimitMMHG = _treatmentVars.curArtPresMMHG - artTxParamsMMHG; + _treatmentVars.minArtPresLimitMMHG = qMax(_treatmentVars.minArtPresLimitMMHG, static_cast(MIN_ART_PRES_LIMIT_MMHG)); + + _treatmentVars.maxArtPresLimitMMHG = _treatmentVars.curArtPresMMHG + artTxParamsMMHG; + _treatmentVars.maxArtPresLimitMMHG = qMin(_treatmentVars.maxArtPresLimitMMHG, static_cast(MAX_ART_PRES_LIMIT_MMHG)); + } + + float artRandomMMHG = _randNumGenerator.generateDouble() * + (_treatmentVars.maxArtPresLimitMMHG - _treatmentVars.minArtPresLimitMMHG) + _treatmentVars.minArtPresLimitMMHG; + + if (artReadingCount >= arraySize) { + artRunningSumMMHG -= artRandArrayGenMMHG[artArrayIndex]; + } + + artRandArrayGenMMHG[artArrayIndex] = artRandomMMHG; + artRunningSumMMHG += artRandomMMHG; + artArrayIndex = (artArrayIndex >= arraySize - 1 ? 0 : artArrayIndex + 1); + artReadingCount = (artReadingCount >= arraySize + 1 ? arraySize + 1 : artReadingCount + 1); + _treatmentVars.curArtPresMMHG = artRunningSumMMHG / artReadingCount; + + if (stableCount >= OCCLUSION_STABLE_TIME_COUNT) { + qint32 venMinOffsetMMHG = _treatmentParams.venousPresLimitAsymWindowMMHG; + qint32 venMaxOffsetMMHG = _treatmentParams.venousPresLimitWindowMMHG - venMinOffsetMMHG; + _treatmentVars.minVenPresLimitMMHG = _treatmentVars.curVenPresMMHG - venMinOffsetMMHG; + _treatmentVars.minVenPresLimitMMHG = qMax(_treatmentVars.minVenPresLimitMMHG, static_cast(MIN_VEN_PRES_LIMIT_MMHG)); + + _treatmentVars.maxVenPresLimitMMHG = _treatmentVars.curVenPresMMHG + venMaxOffsetMMHG; + _treatmentVars.maxVenPresLimitMMHG = qMin(_treatmentVars.maxVenPresLimitMMHG, static_cast(MAX_VEN_PRES_LIMIT_MMHG)); + } + + float venRandomMMHG = _randNumGenerator.generateDouble() * + (_treatmentVars.maxVenPresLimitMMHG - _treatmentVars.minVenPresLimitMMHG) + _treatmentVars.minVenPresLimitMMHG; + + if (venReadingCount >= arraySize) { + venRunningSumMMHG -= venRandArrayGenMMHG[artArrayIndex]; + } + + venRandArrayGenMMHG[artArrayIndex] = venRandomMMHG; + venRunningSumMMHG += venRandomMMHG; + venArrayIndex = (venArrayIndex >= arraySize - 1 ? 0 : venArrayIndex + 1); + venReadingCount = (venReadingCount >= arraySize + 1 ? arraySize + 1 : venReadingCount + 1); + _treatmentVars.curVenPresMMHG = venRunningSumMMHG / venReadingCount; + + qDebug() << "Pressure" << _treatmentParams.areterialPresLimitWindowMMHG << + _treatmentParams.venousPresLimitWindowMMHG << + _treatmentParams.venousPresLimitAsymWindowMMHG ; +} + +void StateController::handlePressureChangeReqeust(const QVariant &payload) +{ + QVariantList msg; + msg.append(static_cast(ID_HD_PRESSURE_LIMITS_CHANGE_RESP)); + msg.append(Can_Id::eChlid_HD_UI); + msg.append(ACCEPT_VALUE); + msg.append(0); + + qint32 presIndex = 0; + Types::S32 pressure; + GetValue(payload.toByteArray(), presIndex, pressure); + _treatmentParams.areterialPresLimitWindowMMHG = pressure.value; + msg.append(pressure.value); + GetValue(payload.toByteArray(), presIndex, pressure); + _treatmentParams.venousPresLimitWindowMMHG = pressure.value; + msg.append(pressure.value); + GetValue(payload.toByteArray(), presIndex, pressure); + _treatmentParams.venousPresLimitAsymWindowMMHG = pressure.value; + msg.append(pressure.value); + + _isSendListReady = false; + _sendMessages.append(msg); + _isSendListReady = true; +} + // ----------- State transition methods ---------------- // void StateController::onIdleStateChange(bool active) { static State_Status status = STATE_ON_ENTRY; auto inEntry = [=](){ _treatmentVars.broadcastIntervalCount = 0; + _hasUserConfirmedToProceed = false; prepareHDModeTransitionBroadcastData(MODE_STAN, 0); @@ -749,7 +924,12 @@ // Keep sending the default status once a second if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { - prepareHDModeTransitionBroadcastData(MODE_STAN, 0); + if (_hasUserConfirmedToProceed) { + prepareHDModeTransitionBroadcastData(MODE_SERV, 0); + } + else { + prepareHDModeTransitionBroadcastData(MODE_STAN, 0); + } // Send the pre treatment states to reset so it starts from the right state QList preTxStates({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); prepareStatesBroadcastData(ID_PRE_TX_STATES_BC, preTxStates); @@ -764,35 +944,47 @@ bool isMsgBBRequested = false; if (!_treatmentRcvdMessages[ID_UI_CONFIRM_RESP].isNull()) { - qint32 cmd = handleMsgBBPayload(_treatmentRcvdMessages[ID_UI_CONFIRM_RESP]); + qint32 cmd = handleMsgBBPayload(_treatmentRcvdMessages[ID_UI_CONFIRM_RESP]); User_Command_ID cmdIDEnum = static_cast(cmd); + handleAlarmStatus(false, cmdIDEnum); + _treatmentRcvdMessages[ID_UI_CONFIRM_RESP].clear(); - // TODO SEND MESSAGE 0XBA BACK TO UI - if ((cmdIDEnum > CMD_STAND_BY) && (cmdIDEnum < NUM_OF_USER_CMDS)) { + if ((cmdIDEnum > CMD_STAND_BY) && (cmdIDEnum <= CMD_DISINFECTION)) { qDebug() << "Submit event" << _transitionEventsFromIdle[cmdIDEnum]; _dryDemo.submitEvent(_transitionEventsFromIdle[cmdIDEnum]); isMsgBBRequested = true; status = STATE_ON_EXIT; } + else if ((cmdIDEnum >= CMD_HIGH_PRIO_ALARM) && (cmdIDEnum < NUM_OF_USER_CMDS)) { + handleAlarmStatus(true, cmdIDEnum); + } qDebug() << "Idle in action" << cmdIDEnum; } // If the use has requested message 0xBB then ignore create treatment button if ((!_treatmentRcvdMessages[ID_UI_RQST_TX].isNull()) && (!isMsgBBRequested)) { - if (isTreatmenStartRequested(_treatmentRcvdMessages[ID_UI_RQST_TX])) { + // clear the alarms in case they have been triggered + handleAlarmStatus(false, CMD_HIGH_PRIO_ALARM); _dryDemo.submitEvent(_transitionEventsFromIdle[CMD_TX_PARAMS]); status = STATE_ON_EXIT; qDebug() << "Idle starting Tx"; } _treatmentRcvdMessages[ID_UI_RQST_TX].clear(); } + + if (!_treatmentRcvdMessages[ID_UI_SERVICE_MODE_RQST].isNull()) { + _hasUserConfirmedToProceed = true; + qDebug() << "Service mode requested" << _treatmentRcvdMessages[ID_UI_SERVICE_MODE_RQST]; + _treatmentRcvdMessages[ID_UI_SERVICE_MODE_RQST].clear(); + } }; auto inExit = [=](){ qDebug() << "Idle in exit"; - status = STATE_ON_ENTRY; + _hasUserConfirmedToProceed = false; + status = STATE_ON_ENTRY; }; switch (status) { // TODO macro it later @@ -1347,12 +1539,15 @@ _treatmentVars.broadcastIntervalCount = 0; prepareBloodFlowBroadcastData(_treatmentParams.bloodFlowRateMLPM); prepareBloodPrimeBroadcastData(accumBloodVolML); + generateOcclusionPresureValues(true, 0); }; auto inAction = [=](){ _treatmentVars.broadcastIntervalCount++; accumBloodVolML += (_treatmentParams.bloodFlowRateMLPM * FLOW_INTEGRATOR); + generateOcclusionPresureValues(false, 0); + if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { prepareBloodFlowBroadcastData(_treatmentParams.bloodFlowRateMLPM); prepareBloodPrimeBroadcastData(accumBloodVolML); @@ -1393,6 +1588,8 @@ static float bolSalineVolML = 0.0; auto inEntry = [=](){ + _treatmentVars.broadcastIntervalCount = 0; + _treatmentVars.prescribedTreatmentTimeS = _treatmentParams.txDurationMins * SECONDS_PER_MINUTE; _treatmentVars.treatmentElapsedTimeS = (_treatmentVars.prescribedTreatmentTimeS < DEF_TX_ELAPSED_TIME_S ? 0 : DEF_TX_ELAPSED_TIME_S); _treatmentVars.remainingTreatmentTimeS = _treatmentVars.prescribedTreatmentTimeS - _treatmentVars.treatmentElapsedTimeS; @@ -1460,11 +1657,8 @@ bolSalineVolML = 0.0; isSalineBolRqstd= false; } - - qDebug() << "Saline" << bloodFlowMLPM << bolSalineVolML << cumSalineVolML; } - if (!_treatmentRcvdMessages[ID_USER_TX_TIME_CHANGES_RQST].isNull()) { handleTreatmentTimeChangeRequest(_treatmentRcvdMessages[ID_USER_TX_TIME_CHANGES_RQST]); _treatmentRcvdMessages[ID_USER_TX_TIME_CHANGES_RQST].clear(); @@ -1474,6 +1668,13 @@ status = STATE_ON_EXIT; } + if (!_treatmentRcvdMessages[ID_UI_PRESSURE_LIMITS_CHANGE_RQST].isNull()) { + handlePressureChangeReqeust(_treatmentRcvdMessages[ID_UI_PRESSURE_LIMITS_CHANGE_RQST]); + _treatmentRcvdMessages[ID_UI_PRESSURE_LIMITS_CHANGE_RQST].clear(); + } + + generateOcclusionPresureValues(false, _treatmentVars.broadcastIntervalCount); + if (_treatmentVars.broadcastIntervalCount % NUM_OF_COUNTS_TIMER_BC_EMIT == 0) { QList txStates({DIALYSIS_SUB_STATE, ufSubState, salineSubState, 0, 0, 0, 0, 0, 0, 0, 0}); prepareStatesBroadcastData(ID_HD_TX_STATES_BC, txStates);