Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -ra19a676d1e67bb3e1aca9e9bba49727f9d5f8b38 -r7c8ec681f8c5dc44674893b5c3924a6203f2c8d0 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision a19a676d1e67bb3e1aca9e9bba49727f9d5f8b38) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 7c8ec681f8c5dc44674893b5c3924a6203f2c8d0) @@ -14,9 +14,11 @@ * **************************************************************************/ -#include "AlarmMgmt.h" +#include "DialInFlow.h" +#include "ModeTreatment.h" #include "OperationModes.h" #include "SystemCommMessages.h" +#include "Timers.h" #include "DGInterface.h" /** @@ -26,37 +28,61 @@ // ********** private definitions ********** -#define START_DG_CMD TRUE -#define STOP_DG_CMD FALSE +#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 RESERVOIR_SETTLE_TIME_MS 5000 ///< 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; -static BOOL dgStarted = FALSE; -static BOOL dgStartetSet = FALSE; -static BOOL dgWaterSampled = FALSE; -static BOOL dgWaterSampledSet = FALSE; +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 ]; -static F32 dgPrimaryTempSet = 0.0; -static F32 dgPrimaryTemp = 0.0; -static F32 dgTrimmerTempSet = 0.0; -static F32 dgTrimmerTemp = 0.0; +static F32 dgPressures[ NUM_OF_DG_PRESSURE_SENSORS ]; ///< Latest pressures reported by the DG. +static F32 dgDialysateTemp = 0.0; ///< Dialysate temperature reported by the DG. +static F32 dgRedundantDialysateTemp = 0.0; ///< Redundant dialysate temperature 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; -static U32 dgROPumpPressureSetPtPSI = 0; -static U32 dgDrainPumpSpeedSetPtRPM = 0; +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; -static DG_RESERVOIR_ID_T dgActiveReservoirSet = DG_RESERVOIR_2; -static U32 dgReservoirFillVolumeTarget = 0; -static U32 dgReservoirFillVolumeTargetSet = 0; -static U32 dgReservoirDrainVolumeTarget = 0; -static U32 dgReservoirDrainVolumeTargetSet = 0; +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 ********** @@ -71,11 +97,163 @@ *************************************************************************/ void initDGInterface( void ) { - // TODO - anything to initialize? + dgStarted = FALSE; + dgTrimmerHeaterOn = FALSE; + dgWaterSampled = FALSE; + dgPrimaryTempSet = 0.0; + dgTrimmerTempSet = 0.0; + dgActiveReservoirSet = DG_RESERVOIR_2; + dgReservoirFillVolumeTargetSet = 0; + dgReservoirDrainVolumeTargetSet = 0; } /*********************************************************************//** * @brief + * The initTreatmentReservoirMgmt function initializes the treatment reservoir \n + * management state machine. + * @details + * Inputs : none + * Outputs : treatment reservoir management state machine initialized. + * @return none + *************************************************************************/ +void initTreatmentReservoirMgmt( void ) +{ + currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; + resMgmtTimer = 0; + resUseTimer = getMSTimerCount(); + resUseVolumeMl = 0.0; +} + +/*********************************************************************//** + * @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 = (F32)getTargetDialInFlowRate() / (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? + resUseTimer = getMSTimerCount(); + + // treatment reservoir mgmt. state machine + switch ( currentTrtResMgmtState ) + { + case TREATMENT_RESERVOIR_MGMT_START_STATE: + 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 ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) ) + { + 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(); + resUseVolumeMl = 0.0; + // 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 @@ -84,13 +262,37 @@ *************************************************************************/ DG_OP_MODE_T getDGOpMode( void ) { - DG_OP_MODE_T result = dgCurrentOpMode; + return dgCurrentOpMode; +} - return result; +/*********************************************************************//** + * @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 @@ -109,7 +311,7 @@ } else { - // TODO - s/w fault + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_PRESSURE_ID, sensorID ) } return result; @@ -171,18 +373,41 @@ * 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 ) +void setDGOpMode( U32 opMode, U32 subMode ) { if ( opMode < NUM_OF_DG_MODES ) { dgCurrentOpMode = (DG_OP_MODE_T)opMode; + dgSubMode = subMode; } + else + { + // TODO + } } /*********************************************************************//** * @brief + * The setDialysateTemperatureReadings function sets the latest dialysate \n + * temperatures reported by the DG. + * @details + * Inputs : none + * Outputs : dgDialysateTemp, dgRedundantDialysateTemp + * @param temp1 : dialysate temperature reported by DG. + * @param temp2 : redundant dialysate temperature reported by DG. + * @return none + *************************************************************************/ +void setDialysateTemperatureReadings( F32 temp1, F32 temp2 ) +{ + dgDialysateTemp = temp1; + dgRedundantDialysateTemp = temp2; +} + +/*********************************************************************//** + * @brief * The setDGDialysateTemperatures function sets the latest temperature data \n * reported by the DG. * @details @@ -218,6 +443,10 @@ dgReservoirFillVolumeTarget = fillVol; dgReservoirDrainVolumeTarget = drainVol; } + else + { + // TODO + } } /*********************************************************************//** @@ -247,13 +476,13 @@ * 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. + * @param flowRate : latest RO pump flow rate (LPM) reported by DG. * @return none *************************************************************************/ void setDGROPumpData( U32 presSetPt, F32 flowRate ) { dgROPumpPressureSetPtPSI = presSetPt; - dgROPumpFlowRateMlMin = flowRate; + dgROPumpFlowRateMlMin = flowRate * ML_PER_LITER; } /*********************************************************************//** @@ -320,6 +549,36 @@ /*********************************************************************//** * @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 @@ -333,7 +592,7 @@ if ( resID < NUM_OF_DG_RESERVOIRS ) { dgActiveReservoirSet = resID; - sendDGSwitchReservoirCommand( resID ); + sendDGSwitchReservoirCommand( (U32)resID ); } else {