/**********************************************************************//** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file DGInterface.c * * @date 08-Apr-2020 * @author S. Nash * * @brief Interfaces with and monitors the DG sub-system. * **************************************************************************/ #include "DialInFlow.h" #include "ModeTreatment.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "DGInterface.h" /** * @addtogroup DGInterface * @{ */ // ********** private definitions ********** #define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. #define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. #define DRAIN_RESERVOIR_TO_VOLUME_ML 200 //100 ///< Drain reservoir to this volume (in mL) during treatment. #define FILL_RESERVOIR_TO_VOLUME_ML 1500 ///< Fill reservoir to this volume (in mL) during treatment. #define RESERVOIR_SETTLE_TIME_MS 3000 ///< Time (in ms) allotted for reservoir to settle (after fill, before drain). /// States of the treatment reservoir management state machine. typedef enum TreatmentReservoirMgmt_States { TREATMENT_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE, ///< Wait for drain to complete. TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE, ///< Wait to fill inactive reservoir (if appropriate) - then start filling inactive reservoir. TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE, ///< Wait for fill to complete. TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE, ///< Wait a bit for filled reservoir to settle before getting baseline weight (volume). TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE, ///< Wait for active reservoir to be consumed and switch cmd given - then back to flush DG lines state. TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Wait for inactive reservoir to settle before getting final weight (volume) before starting to drain. NUM_OF_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of treatment reservoir mgmt. states. } TREATMENT_RESERVOIR_MGMT_STATE_T; // ********** private data ********** // DG status static DG_OP_MODE_T dgCurrentOpMode = DG_MODE_INIT; ///< Current DG operation mode. static U32 dgSubMode = 0; ///< Current state (sub-mode) of current DG operation mode. static BOOL dgStarted = FALSE; ///< Flag indicates whether we've commanded the DG to start or stop. static BOOL dgTrimmerHeaterOn = FALSE; ///< Flag indicates whether we've commanded the DG to start or stop the trimmer heater. static BOOL dgWaterSampled = FALSE; ///< Flag indicates whether we've commanded the DG to sample water. // state machine states static TREATMENT_RESERVOIR_MGMT_STATE_T currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; ///< Current state of treatment mode reservoir management. static U32 resMgmtTimer = 0; ///< used for keeping state time. // DG sensor data static F32 dgPressures[ NUM_OF_DG_PRESSURE_SENSORS ]; ///< Latest pressures reported by the DG. static F32 dgPrimaryTempSet = 0.0; ///< Primary heater target temperature commanded. static F32 dgPrimaryTemp = 0.0; ///< Latest RO water temperature reported by the DG. static F32 dgTrimmerTempSet = 0.0; ///< Trimmer heater target temperature commanded. static F32 dgTrimmerTemp = 0.0; ///< Latest dialysate temperature reported by the DG. // DG pumps data static F32 dgROPumpFlowRateMlMin = 0.0; ///< Latest RO water flow rate reported by the DG. static U32 dgROPumpPressureSetPtPSI = 0; ///< Latest RO pump target pressure reported by the DG. static U32 dgDrainPumpSpeedSetPtRPM = 0; ///< Latest Drain pump target speed reported by the DG. // reservoir data static DG_RESERVOIR_ID_T dgActiveReservoir = DG_RESERVOIR_2; ///< Latest active reservoir reported by the DG. static DG_RESERVOIR_ID_T dgActiveReservoirSet = DG_RESERVOIR_2; ///< Active reservoir commanded. static U32 dgReservoirFillVolumeTarget = 0; ///< Latest fill-to volume reported by the DG. static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. static U32 dgReservoirDrainVolumeTarget = 0; ///< Latest drain-to volume reported by the DG. static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. static U32 resUseTimer = 0; ///< used to track time pumping from active reservoir (for volume used calculation). static F32 resUseVolumeMl = 0.0; ///< Accumulated volume used from active reservoir. // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initDGInterface function initializes the DGInterface module. * @details * Inputs : none * Outputs : DGInterface module initialized. * @return none *************************************************************************/ void initDGInterface( void ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; } /*********************************************************************//** * @brief * The execTreatmentReservoirMgmt function executes the state machine for the \n * reservoir management during treatment mode. * @details * Inputs : none * Outputs : DG reservoirs (drains & fills) managed. * @return none *************************************************************************/ void execTreatmentReservoirMgmt( void ) { DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); U32 msSinceLastVolumeCalc = calcTimeSince( resUseTimer ); F32 flowRateMlPerMs = getMeasuredDialInFlowRate() / (F32)( MS_PER_SECOND * SEC_PER_MIN ); // calculate volume used from active reservoir resUseVolumeMl += ( flowRateMlPerMs * msSinceLastVolumeCalc ); // TODO - should this calc be done and kept by Dialysis sub-mode? // treatment reservoir mgmt. state machine switch ( currentTrtResMgmtState ) { case TREATMENT_RESERVOIR_MGMT_START_STATE: resUseTimer = getMSTimerCount(); resUseVolumeMl = 0.0; currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; break; case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: if ( DG_MODE_CIRC == dgOpMode ) { if ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) { cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML ); } } else if ( DG_MODE_DRAI == dgOpMode ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; } else { // TODO - ??? } break; case TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE: if ( DG_MODE_CIRC == dgOpMode ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; } break; case TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE: // delay fill start if we've paused treatment? if ( getTreatmentState() == TREATMENT_DIALYSIS_STATE ) { if ( DG_MODE_CIRC == dgOpMode ) { if ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) { cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML ); } } else { // TODO - ??? } } if ( DG_MODE_FILL == dgOpMode ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; } break; case TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE: if ( DG_MODE_CIRC == dgOpMode ) { resMgmtTimer = getMSTimerCount(); currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE; } break; case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE: if ( TRUE == didTimeout( resMgmtTimer, RESERVOIR_SETTLE_TIME_MS ) ) { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE; } break; case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE: // reservoir switch during treatment should only occur in this state (i.e. when DG is ready). // switch reservoirs when active reservoir is spent (i.e. we've pumped fill volume through dialyzer) and DG ready if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) && ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) ) { DG_RESERVOIR_ID_T activeRes = dgActiveReservoirSet; DG_RESERVOIR_ID_T inactiveRes = ( activeRes == DG_RESERVOIR_1 ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); // signal dialysis sub-mode to capture baseline volume for next reservoir. setStartReservoirVolume(); // command DG to switch reservoirs cmdSetDGActiveReservoir( inactiveRes ); // signal dialysis sub-mode to switch reservoirs signalReservoirsSwitched(); // wait for used reservoir to settle resMgmtTimer = getMSTimerCount(); currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; } break; case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE: if ( TRUE == didTimeout( resMgmtTimer, RESERVOIR_SETTLE_TIME_MS ) ) { // signal dialysis sub-mode to capture final volume of prior reservoir after settling. setFinalReservoirVolume(); // reset to start state to restart drain, fill, switch process. currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; } break; default: // TODO - s/w fault currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; break; } } /*********************************************************************//** * @brief * The getDGOpMode function gets the current DG operating mode. * @details * Inputs : dgCurrentOpMode * Outputs : none * @return Current DG operating mode. *************************************************************************/ DG_OP_MODE_T getDGOpMode( void ) { return dgCurrentOpMode; } /*********************************************************************//** * @brief * The getDGSubMode function gets the current DG operating sub-mode. * @details * Inputs : dgSubMode * Outputs : none * @return Current DG operating sub-mode. *************************************************************************/ U32 getDGSubMode( void ) { return dgSubMode; } /*********************************************************************//** * @brief * The getDGActiveReservoir function gets the current active reservoir. * @details * Inputs : dgActiveReservoirSet * Outputs : none * @return Currently commanded active reservoir. *************************************************************************/ DG_RESERVOIR_ID_T getDGActiveReservoir( void ) { return dgActiveReservoirSet; } /*********************************************************************//** * @brief * The getDGPressure function gets the latest pressure reported by the DG \n * for a given pressure sensor. * @details * Inputs : dgPressures[] * Outputs : none * @param sensorID : pressure sensor we are getting reading for. * @return Latest pressure reading reported by DG for the given sensor. *************************************************************************/ F32 getDGPressure( DG_PRESSURE_SENSORS_T sensorID ) { F32 result = 0.0; if ( sensorID < NUM_OF_DG_PRESSURE_SENSORS ) { result = dgPressures[ sensorID ]; } else { // TODO - s/w fault } return result; } /*********************************************************************//** * @brief * The getDGROPumpPressureSetPt function gets the latest RO pump \n * pressure set point reported by the DG. * @details * Inputs : dgROPumpPressureSetPtPSI * Outputs : none * @return Latest RO pump pressure set point reported by DG. *************************************************************************/ U32 getDGROPumpPressureSetPt( void ) { U32 result = dgROPumpPressureSetPtPSI; return result; } /*********************************************************************//** * @brief * The getDGROPumpFlowRateMlMin function gets the latest RO pump flow \n * rate reported by the DG. * @details * Inputs : dgROPumpFlowRateMlMin * Outputs : none * @return Latest RO pump flow rate reported by DG. *************************************************************************/ F32 getDGROPumpFlowRateMlMin( void ) { F32 result = dgROPumpFlowRateMlMin; return result; } /*********************************************************************//** * @brief * The getDGDrainPumpRPMSetPt function gets the latest drain pump RPM \n * set point reported by the DG. * @details * Inputs : dgDrainPumpSpeedSetPtRPM * Outputs : none * @return Latest drain pump RPM set point reported by DG. *************************************************************************/ U32 getDGDrainPumpRPMSetPt( void ) { U32 result = dgDrainPumpSpeedSetPtRPM; return result; } /*********************************************************************//** * @brief * The setDGOpMode function sets the latest DG operating mode reported by \n * the DG. * @details * Inputs : none * Outputs : dgCurrentOpMode * @param opMode : operating mode reported by DG. * @param subMode : sub-mode (current state) of operating mode reported by DG. * @return none *************************************************************************/ void setDGOpMode( U32 opMode, U32 subMode ) { if ( opMode < NUM_OF_DG_MODES ) { dgCurrentOpMode = (DG_OP_MODE_T)opMode; dgSubMode = subMode; } } /*********************************************************************//** * @brief * The setDGDialysateTemperatures function sets the latest temperature data \n * reported by the DG. * @details * Inputs : none * Outputs : dgPrimaryTemp, dgTrimmerTemp * @param primaryHtrTemp : Primary heater temperature reported by DG. * @param trimmerHtrTemp : Trimmer heater temperature reported by DG. * @return none *************************************************************************/ void setDGDialysateTemperatures( F32 primaryHtrTemp, F32 trimmerHtrTemp ) { dgPrimaryTemp = primaryHtrTemp; dgTrimmerTemp = trimmerHtrTemp; } /*********************************************************************//** * @brief * The setDGReservoirsData function sets the latest reservoir data \n * reported by the DG. * @details * Inputs : none * Outputs : dgActiveReservoir, dgReservoirFillVolumeTarget, dgReservoirDrainVolumeTarget * @param resID : ID of active reservoir. * @param fillVol : Reservoir fill to volume reported by DG. * @param drainVol : Reservoir drain to volume reported by DG. * @return none *************************************************************************/ void setDGReservoirsData( DG_RESERVOIR_ID_T resID, U32 fillVol, U32 drainVol ) { if ( resID < NUM_OF_DG_RESERVOIRS ) { dgActiveReservoir = resID; dgReservoirFillVolumeTarget = fillVol; dgReservoirDrainVolumeTarget = drainVol; } } /*********************************************************************//** * @brief * The setDGPressures function sets the latest pressures reported by the DG. * @details * Inputs : none * Outputs : dgPressures[] * @param roIn : latest RO pump inlet pressure reported by DG. * @param roOut : latest RO pump outlet pressure reported by DG. * @param drainIn : latest drain pump inlet pressure reported by DG. * @param drainOut : latest drain pump outlet pressure reported by DG. * @return none *************************************************************************/ void setDGPressures( F32 roIn, F32 roOut, F32 drainIn, F32 drainOut ) { dgPressures[ DG_PRESSURE_SENSOR_RO_PUMP_INLET ] = roIn; dgPressures[ DG_PRESSURE_SENSOR_RO_PUMP_OUTLET ] = roOut; dgPressures[ DG_PRESSURE_SENSOR_DRAIN_PUMP_INLET ] = drainIn; dgPressures[ DG_PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ] = drainOut; } /*********************************************************************//** * @brief * The setDGROPumpData function sets the latest RO pump data reported by the DG. * @details * Inputs : none * Outputs : dgROPumpPressureSetPtPSI, dgROPumpFlowRateMlMin * @param presSetPt : latest RO pump pressure set point reported by DG. * @param flowRate : latest RO pump flow rate reported by DG. * @return none *************************************************************************/ void setDGROPumpData( U32 presSetPt, F32 flowRate ) { dgROPumpPressureSetPtPSI = presSetPt; dgROPumpFlowRateMlMin = flowRate; } /*********************************************************************//** * @brief * The setDGDrainPumpData function sets the latest drain pump data reported by the DG. * @details * Inputs : none * Outputs : dgDrainPumpSpeedSetPtRPM * @param rpmSetPt : latest drain pump RPM set point reported by DG. * @return none *************************************************************************/ void setDGDrainPumpData( U32 rpmSetPt ) { dgDrainPumpSpeedSetPtRPM = rpmSetPt; } /*********************************************************************//** * @brief * The cmdSetDGDialysateTargetTemps function sends a target dialysate \n * temperature command message to the DG. * @details * Inputs : none * Outputs : dgPrimaryTempSet, dgTrimmerTempSet * @param primaryHtrTemp : commanded target dialysate temperature for the primary heater. * @param trimmerHtrTemp : commanded target dialysate temperature for the trimmer heater. * @return none *************************************************************************/ void cmdSetDGDialysateTargetTemps( F32 primaryHtrTemp, F32 trimmerHtrTemp ) { dgPrimaryTempSet = primaryHtrTemp; dgTrimmerTempSet = trimmerHtrTemp; sendDialysateTempTargetsToDG( primaryHtrTemp, trimmerHtrTemp ); } /*********************************************************************//** * @brief * The cmdStartDG function sends a start command to the DG. DG will transition \n * from standby to re-circulate mode and start producing warm, pure water. * @details * Inputs : none * Outputs : start DG command sent * @return none *************************************************************************/ void cmdStartDG( void ) { dgStarted = TRUE; sendDGStartStopCommand( START_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStopDG function sends a stop command to the DG. DG will transition \n * from re-circulate mode to standby mode. Pumps and heater go off. * @details * Inputs : none * Outputs : stop DG command sent * @return none *************************************************************************/ void cmdStopDG( void ) { dgStarted = FALSE; sendDGStartStopCommand( STOP_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStartDGTrimmerHeater function sends a start trimmer heater command \n * to the DG. * @details * Inputs : none * Outputs : start DG trimmer heater command sent * @return none *************************************************************************/ void cmdStartDGTrimmerHeater( void ) { dgTrimmerHeaterOn = TRUE; sendDGStartStopTrimmerHeaterCommand( START_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStopDGTrimmerHeater function sends a stop trimmer heater command \n * to the DG. * @details * Inputs : none * Outputs : stop DG trimmer heater command sent * @return none *************************************************************************/ void cmdStopDGTrimmerHeater( void ) { dgTrimmerHeaterOn = FALSE; sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD ); } /*********************************************************************//** * @brief * The cmdSetDGActiveReservoir function sends a set active reservoir command \n * message to the DG. * @details * Inputs : none * Outputs : set active reservoir command sent to DG. * @param resID : ID of reservoir to set as active (reservoir for HD to draw from). * @return none *************************************************************************/ void cmdSetDGActiveReservoir( DG_RESERVOIR_ID_T resID ) { if ( resID < NUM_OF_DG_RESERVOIRS ) { dgActiveReservoirSet = resID; sendDGSwitchReservoirCommand( resID ); // reset treatment reservoir mgmt. state machine on reservoir switch currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; } else { // TODO - s/w fault } } /*********************************************************************//** * @brief * The cmdStartDGFill function sends a fill command message to the DG. * @details * Inputs : none * Outputs : fill command sent to DG. * @param fillToVolMl : volume (in mL) to fill inactive reservoir to. * @return none *************************************************************************/ void cmdStartDGFill( U32 fillToVolMl ) { dgReservoirFillVolumeTargetSet = fillToVolMl; sendDGFillCommand( fillToVolMl ); } /*********************************************************************//** * @brief * The cmdStartDGDrain function sends a drain command message to the DG. * @details * Inputs : none * Outputs : drain command sent to DG. * @param drainToVolMl : volume (in mL) to drain inactive reservoir to. * @return none *************************************************************************/ void cmdStartDGDrain( U32 drainToVolMl ) { dgReservoirDrainVolumeTargetSet = drainToVolMl; sendDGDrainCommand( drainToVolMl ); } /*********************************************************************//** * @brief * The cmdDGSampleWater function sends a sample water command message to the DG. * @details * Inputs : none * Outputs : sample water command sent to DG. * @return none *************************************************************************/ void cmdDGSampleWater( void ) { dgWaterSampled = TRUE; sendDGSampleWaterCommand(); } /**@}*/