Index: firmware/App/Modes/ModeROPermeateSample.c =================================================================== diff -u -re41df6b9a323e27c7d779f602579bbcf457ffa6d -ra12e1212c1cf49011ed8d65beaf9416ca18ffe98 --- firmware/App/Modes/ModeROPermeateSample.c (.../ModeROPermeateSample.c) (revision e41df6b9a323e27c7d779f602579bbcf457ffa6d) +++ firmware/App/Modes/ModeROPermeateSample.c (.../ModeROPermeateSample.c) (revision a12e1212c1cf49011ed8d65beaf9416ca18ffe98) @@ -3,6 +3,7 @@ #include "ConductivitySensors.h" #include "CPLD.h" #include "DrainPump.h" +#include "FlowSensors.h" #include "Heaters.h" #include "LoadCell.h" #include "MessageSupport.h" @@ -33,59 +34,106 @@ #define ACID_PUMP_SPEED_ML_PER_MIN 30.6F ///< Acid concentrate pump speed in mL/min. // The acid pump is 2% faster than the acid pump to create a flow from acid to bicarb line during sampling #define BICARB_PUMP_SPEED_ML_PER_MIN -30.0F ///< Bicarb concentrate pump speed in mL/min. +#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.8F ///< RO pump target flow rate during flush/fill in L/min. +#define RO_PUMP_MAX_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define FLUSH_DRAIN_WAIT_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +#define FLUSH_DIALYSATE_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush dialysate wait time in milliseconds. +#define FLUSH_CONCENTRATE_STRAWS_TIME_MS ( 3 * 60 * MS_PER_SECOND ) ///< Flush concentrate straws wait time in milliseconds. + #define RSRVR_FILL_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir fill timeout in milliseconds. #define RSRVR_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir drain timeout in milliseconds. #define RSRVR_DRAIN_STEADY_TIMEOUT_MS ( 6 * MS_PER_SECOND ) ///< Reservoir drain steady timeout in milliseconds. #define RSRVR_DRAIN_TARGET_RPM 2400 ///< Reservoir drain target RPM. #define RSRVR_MIX_DRAIN_TIMEOUT_MS ( 4 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. +#define RSRVR_FILL_TARGET_FILL_ML 1850.0F ///< Reservoir fill target in mL. +#define RSRVR_DRAIN_BEFORE_SAMPLE_COLLECTION_MS ( 4.25F * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir drain before collection samples in milliseconds. +#define RO_PUMP_TARGET_DISPENSE_FLOW_RATE_LPM 0.6F ///< RO pump target flow rate during dispensing in L/min. +#define TARGET_DISPENSE_VOLUME_ML 100.0F ///< Target dispense volume in milliliters. +/// Collection sample substates enum +typedef enum Sample_Collection_Substates +{ + COLLECT_SAMPLE_INITIALIZE = 0, ///< Collect sample initialize. + COLLECT_SAMPLE_DISPENSE, ///< Collect sample dispense. + COLLECT_SAMPLE_STOP, ///< Collect sample stop. + NUM_OF_COLLECT_SAMPLE_STATES ///< Number of collect sample states. +} COLLECT_SAMPLE_STATES_T; + +/// Dispense request message status structure +typedef struct +{ + BOOL hasMessageBeenReceived; ///< Dispense message request flag to indicate message has been received. + BOOL signalContinueDispensing; ///< Dispense message request flag to indicate whether continue dispensing or not. +} DISPENSE_RQST_MSG_STATUS_T; + static DG_RO_PERM_STATE_T roPermeateSampleState; ///< Mode RO permeate sample state. static DG_RO_PERM_STATE_T roPermeateSamplePrevState; ///< Mode RO permeate sample previous state. static U32 stateStartTimeMS; ///< Mode RO permeate sample state timer in milliseconds. static U32 dataPublishCounter; ///< Mode RO permeate sample data publish counter. static U32 overallROPermeateSampleTimer; ///< Mode RO permeate sample over mode timer. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Mode RO permeate sample pending alarm trigger. static DIS_RSRVR_STATUS_T rsrvrsStatus; ///< Mode RO permeate sample reservoirs status. +static F32 roPermeateSampledispensedVolumeML; ///< Mode RO permeate sample dispensed volume in milliliters. +static BOOL isReservoirFull; ///< Mode RO permeate sample flag to indicate reservoir 2 is filled. +static COLLECT_SAMPLE_STATES_T collectSampleSubState; ///< Mode RO permeate sample collect sample substate. +static DISPENSE_RQST_MSG_STATUS_T dispenseMessageStatus; ///< Mode RO permeate sample dispense message status. // ********** private function prototypes ********** +static DG_RO_PERM_STATE_T handleROPermeateSampleStartState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleDrainR1State( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleDrainR2State( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushDrainState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushDialysateState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushConcenrateStrawsState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushR2ToR1AndDrainR1State( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleCollectSampleState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleCancelBasicPathState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleCancelWaterPathState( void ); +static DG_RO_PERM_STATE_T handleROPermeateSampleCompleteState( void ); + static void failROPermeateSample( void ); static void publishROPermeateSampleData( void ); static void monitorROPermeateSample( void ); -static void setROPermeateSampleActuators( DG_RO_PERM_STATE_T state ); +static void setROPermeateSampleStateTransition( DG_RO_PERM_STATE_T state ); static DG_RO_PERM_STATE_T checkRsrvrMgmtTimeoutStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ); -static DG_RO_PERM_STATE_T checkRsrvrPartialFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ); -static DG_RO_PERM_STATE_T checkRsrvrMixDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ); -static DG_RO_PERM_STATE_T checkRsrvrFillStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ); static DG_RO_PERM_STATE_T checkRsrvrDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ); /*********************************************************************//** * @brief * The initROPermeateSampleMode function initializes the RO permeate sample * mode module. * @details Inputs: none - * @details Outputs: TODO + * @details Outputs: roPermeateSampleState, roPermeateSamplePrevState, + * stateStartTimeMS, dataPublishCounter, overallROPermeateSampleTimer, + * alarmDetectedPendingTrigger, rsrvrsStatus, roPermeateSampledispensedVolumeML, + * isReservoirFull, collectSampleSubState, dispenseMessageStatus * @return none *************************************************************************/ void initROPermeateSampleMode( void ) { - roPermeateSampleState = DG_RO_PERM_SAMPLE_STATE_START; - roPermeateSamplePrevState = DG_RO_PERM_SAMPLE_STATE_START; - stateStartTimeMS = getMSTimerCount(); - dataPublishCounter = 0; - overallROPermeateSampleTimer = getMSTimerCount(); - alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; + roPermeateSampleState = DG_RO_PERM_SAMPLE_STATE_START; + roPermeateSamplePrevState = DG_RO_PERM_SAMPLE_STATE_START; + stateStartTimeMS = getMSTimerCount(); + dataPublishCounter = 0; + overallROPermeateSampleTimer = getMSTimerCount(); + alarmDetectedPendingTrigger = ALARM_ID_NO_ALARM; + roPermeateSampledispensedVolumeML = 0.0F; + isReservoirFull = FALSE; + collectSampleSubState = COLLECT_SAMPLE_INITIALIZE; + dispenseMessageStatus.hasMessageBeenReceived = FALSE; + dispenseMessageStatus.signalContinueDispensing = FALSE; // Initialize the reservoirs rsrvrsStatus.rsrvrFillStableTime = 0; rsrvrsStatus.rsrvrFillStableTimeoutMS = RSRVRS_FULL_STABLE_TIME_COUNT; rsrvrsStatus.isThisInitialDrain = TRUE; rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].drainInit = FALSE; rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].loadCell = LOAD_CELL_RESERVOIR_1_PRIMARY; - rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = NUM_OF_DG_RESERVOIR_STATUS; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].drainInit = FALSE; rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].loadCell = LOAD_CELL_RESERVOIR_2_PRIMARY; - rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = NUM_OF_DG_RESERVOIR_STATUS; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; } /*********************************************************************//** @@ -102,6 +150,7 @@ initROPermeateSampleMode(); setCurrentSubState( NO_SUB_STATE ); + setCPLDCleanLEDColor( CPLD_CLEAN_LED_OFF ); return roPermeateSampleState; } @@ -115,39 +164,63 @@ *************************************************************************/ U32 execROPermeateSampleMode( void ) { + // The inlet pressure shall be checked all the time as long as VPi is open + checkInletWaterPressure(); + + if ( roPermeateSampleState != DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN ) + { + // Do not check on the inlet water temperature and conductivity until the inlet filters have been flushed + // The initial states are drain reservoirs but in those states VPi is closed so these alarms are not checked + checkInletWaterTemperature(); + checkInletWaterConductivity(); + } + + monitorROPermeateSample(); + switch ( roPermeateSampleState ) { case DG_RO_PERM_SAMPLE_STATE_START: + roPermeateSampleState = handleROPermeateSampleStartState(); break; case DG_RO_PERM_SAMPLE_STATE_DRAIN_R1: + roPermeateSampleState = handleROPermeateSampleDrainR1State(); break; case DG_RO_PERM_SAMPLE_STATE_DRAIN_R2: + roPermeateSampleState = handleROPermeateSampleDrainR2State(); break; case DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN: + roPermeateSampleState = handleROPermeateSampleFlushDrainState(); break; case DG_RO_PERM_SAMPLE_STATE_FLUSH_DIALYSATE: + roPermeateSampleState = handleROPermeateSampleFlushDialysateState(); break; case DG_RO_PERM_SAMPLE_STATE_FLUSH_CONCENTRATE_STRAWS: + roPermeateSampleState = handleROPermeateSampleFlushConcenrateStrawsState(); break; case DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1: + roPermeateSampleState = handleROPermeateSampleFlushR2ToR1AndDrainR1State(); break; - case DG_RO_PERM_SAMPLE_STATE_SAMPLE_COLLECTION: + case DG_RO_PERM_SAMPLE_STATE_COLLECT_SAMPLE: + roPermeateSampleState = handleROPermeateSampleCollectSampleState(); break; case DG_RO_PERM_SAMPLE_STATE_CANCEL_BASIC_PATH: + roPermeateSampleState = handleROPermeateSampleCancelBasicPathState(); break; case DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH: + roPermeateSampleState = handleROPermeateSampleCancelWaterPathState(); break; case DG_RO_PERM_SAMPLE_STATE_COMPLETE: + roPermeateSampleState = handleROPermeateSampleCompleteState(); break; default: @@ -156,6 +229,8 @@ break; } + publishROPermeateSampleData(); + return roPermeateSampleState; } @@ -198,4 +273,626 @@ return status; } +// ********** private functions ********** + +static DG_RO_PERM_STATE_T handleROPermeateSampleStartState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_DRAIN_R1; + + setROPermeateSampleStateTransition( state ); + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleDrainR1State( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_DRAIN_R1; + + state = checkRsrvrDrainStatus( DG_RESERVOIR_1, state ); + + return state; +} +static DG_RO_PERM_STATE_T handleROPermeateSampleDrainR2State( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_DRAIN_R2; + + state = checkRsrvrDrainStatus( DG_RESERVOIR_2, state ); + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushDrainState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN; + + if ( TRUE == didTimeout( stateStartTimeMS, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + state = DG_RO_PERM_SAMPLE_STATE_FLUSH_DIALYSATE; + setROPermeateSampleStateTransition( state ); + } + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushDialysateState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_FLUSH_DIALYSATE; + + if ( TRUE == didTimeout( stateStartTimeMS, FLUSH_DIALYSATE_WAIT_TIME_MS ) ) + { + state = DG_RO_PERM_SAMPLE_STATE_FLUSH_CONCENTRATE_STRAWS; + setROPermeateSampleStateTransition( state ); + } + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushConcenrateStrawsState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_FLUSH_CONCENTRATE_STRAWS; + + if ( TRUE == didTimeout( stateStartTimeMS, FLUSH_CONCENTRATE_STRAWS_TIME_MS ) ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_BELOW_TARGET; + state = DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1; + setROPermeateSampleStateTransition( state ); + } + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleFlushR2ToR1AndDrainR1State( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1; + + if ( DG_RESERVOIR_BELOW_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = getDisinfectRsrvrFillStatus( DG_RESERVOIR_2, &rsrvrsStatus, RSRVR_FILL_TARGET_FILL_ML, + RSRVR_FILL_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + if ( FALSE == isReservoirFull ) + { + isReservoirFull = TRUE; + stateStartTimeMS = getMSTimerCount(); + } + + if ( TRUE == didTimeout( stateStartTimeMS, RSRVR_DRAIN_BEFORE_SAMPLE_COLLECTION_MS ) ) + { + stateStartTimeMS = getMSTimerCount(); + state = DG_RO_PERM_SAMPLE_STATE_COLLECT_SAMPLE; + setROPermeateSampleStateTransition( state ); + } + } + + state = checkRsrvrMgmtTimeoutStatus( DG_RESERVOIR_2, state ); + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleCollectSampleState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_COLLECT_SAMPLE; + + if ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ) + { + clearAlarm( ALARM_ID_DG_RO_PERMEATE_SAMPLE_REMOVE_DIA_CAP ); + + if ( ( FALSE == dispenseMessageStatus.hasMessageBeenReceived ) && ( FALSE == dispenseMessageStatus.signalContinueDispensing ) ) + { + // Check alarm active is not needed + if ( ( FALSE == isAlarmActive( ALARM_ID_DG_RO_PERMEATE_SAMPLE_REMOVE_DIA_CAP ) ) && ( COLLECT_SAMPLE_INITIALIZE == collectSampleSubState ) ) + { + collectSampleSubState = COLLECT_SAMPLE_DISPENSE; + setROPermeateSampleStateTransition( state ); + } + } + else if ( TRUE == dispenseMessageStatus.hasMessageBeenReceived ) + { + if ( ( TRUE == dispenseMessageStatus.signalContinueDispensing ) && ( FALSE == isROPumpRunning() ) ) + { + collectSampleSubState = COLLECT_SAMPLE_DISPENSE; + setROPermeateSampleStateTransition( state ); + } + else if ( FALSE == dispenseMessageStatus.signalContinueDispensing ) + { + collectSampleSubState = COLLECT_SAMPLE_STOP; + setROPermeateSampleStateTransition( state ); + } + } + + if ( TRUE == isROPumpRunning() ) + { + if ( roPermeateSampledispensedVolumeML < TARGET_DISPENSE_VOLUME_ML ) + { + roPermeateSampledispensedVolumeML += ( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) * ML_PER_LITER * TASK_GENERAL_INTERVAL ) / + ( SEC_PER_MIN * MS_PER_SECOND ); + } + else + { + collectSampleSubState = COLLECT_SAMPLE_STOP; + setROPermeateSampleStateTransition( state ); + } + } + } + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleCancelBasicPathState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_CANCEL_BASIC_PATH; + + failROPermeateSample(); + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleCancelWaterPathState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH; + + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) + { + // If the cancellation water path cannot be done, go to basic cancellation path + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = getDisinfectRsrvrDrainStatus( DG_RESERVOIR_2, &rsrvrsStatus, RSRVR_DRAIN_STEADY_TIMEOUT_MS, + RSRVR_DRAIN_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) && + ( DG_RESERVOIR_BELOW_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) ) + { + // Reset the state timer for the next reservoir to drain + stateStartTimeMS = getMSTimerCount(); + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + // Set the drain valve to reservoir 1 and close reservoir 2 + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + } + else if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) && + ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) ) + { + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = getDisinfectRsrvrDrainStatus( DG_RESERVOIR_1, &rsrvrsStatus, RSRVR_DRAIN_STEADY_TIMEOUT_MS, + RSRVR_DRAIN_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) && + ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) ) + { + failROPermeateSample(); + } + else if ( ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus ) || + ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus ) ) + { + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + state = DG_RO_PERM_SAMPLE_STATE_CANCEL_BASIC_PATH; + } + + return state; +} + +static DG_RO_PERM_STATE_T handleROPermeateSampleCompleteState( void ) +{ + DG_RO_PERM_STATE_T state = DG_RO_PERM_SAMPLE_STATE_COMPLETE; + + stopDGROPermeateSample(); + + return state; +} + + +/*********************************************************************//** + * @brief + * The failROPermeateSample function sets the alarm that failed the RO + * permeate sample mode. + * @details Inputs: alarmDetectedPendingTrigger, prevHeatDisinfectState + * @details Outputs: none + * @return none + *************************************************************************/ +static void failROPermeateSample( void ) +{ + // In the cleaning modes the alarms are triggered but the mode is not transitioned to fault automatically + // so transition to fault mode is done here + if ( alarmDetectedPendingTrigger != ALARM_ID_NO_ALARM ) + { + SET_ALARM_WITH_1_U32_DATA( alarmDetectedPendingTrigger, roPermeateSamplePrevState ) + } + requestNewOperationMode( DG_MODE_STAN ); +} + +/*********************************************************************//** + * @brief + * The publishROPermeateSampleData function broadcasts RO permeate sample + * data at the set interval. + * @details Inputs: dataPublishCounter + * @details Outputs: dataPublishCounter + * @return: none + *************************************************************************/ +static void publishROPermeateSampleData( void ) +{ + if ( ++dataPublishCounter >= RO_PERMEATE_SAMPLE_DATA_PUB_INTERVAL ) + { + MODE_RO_PERMEATE_SAMPLE_DATA_T data; + + data.roPermeateSampleState = (U32)roPermeateSampleState; + data.overallElapsedTimeMS = calcTimeSince( overallROPermeateSampleTimer ); + data.stateElapsedTimeMS = calcTimeSince( stateStartTimeMS ); + data.roPermeateSampleDispensedVolML = roPermeateSampledispensedVolumeML; + + broadcastData( MSG_ID_DG_RO_PERMEATE_SAMPLE_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( MODE_RO_PERMEATE_SAMPLE_DATA_T ) ); + + dataPublishCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The monitorROPermeateSample function monitors the status of the caps and + * sets the state of the state machine to water cancellation path if the caps + * are not closed during the run. + * @details Inputs: none + * @details Outputs: roPermeateSamplePrevState, roPermeateSampleState, + * alarmDetectedPendingTrigger + * @return: none + *************************************************************************/ +static void monitorROPermeateSample( void ) +{ +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAPS_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + BOOL isDialysateCapOpen = ( STATE_OPEN == getSwitchStatus( DIALYSATE_CAP ) ? TRUE : FALSE ); + BOOL isConcentrateCapOpen = ( STATE_OPEN == getSwitchStatus( CONCENTRATE_CAP ) ? TRUE : FALSE ); + + switch ( roPermeateSampleState ) + { + case DG_RO_PERM_SAMPLE_STATE_START: + case DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN: + case DG_RO_PERM_SAMPLE_STATE_FLUSH_DIALYSATE: + case DG_RO_PERM_SAMPLE_STATE_FLUSH_CONCENTRATE_STRAWS: + case DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1: + if ( ( TRUE == isDialysateCapOpen ) || ( TRUE == isConcentrateCapOpen ) ) + { + roPermeateSamplePrevState = roPermeateSampleState; + roPermeateSampleState = DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH; + alarmDetectedPendingTrigger = ( TRUE == isDialysateCapOpen ? ALARM_ID_DG_DIALYSATE_CAP_NOT_IN_PROPER_POSITION : + ALARM_ID_DG_CONCENTRATE_CAP_NOT_IN_PROPER_POSITION ); + } + break; + } + } + + if ( ( TRUE == isDGFaultAlarmActive() ) && ( roPermeateSampleState != DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH ) ) + { + // If there is any fault alarm and we are not already in the cancel water path state, set it to cancel water path state + roPermeateSamplePrevState = roPermeateSampleState; + roPermeateSampleState = DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH; + } +} + +static void setROPermeateSampleStateTransition( DG_RO_PERM_STATE_T state ) +{ + switch( state ) + { + case DG_RO_PERM_SAMPLE_STATE_DRAIN_R1: + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_DRAIN_R2: + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + signalDrainPumpHardStop(); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_FLUSH_DIALYSATE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + // Drain pump + signalDrainPumpHardStop(); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_FLUSH_CONCENTRATE_STRAWS: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Set the concentrate pumps speed + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + // Turn on the concentrate pumps + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + // Drain pump + signalDrainPumpHardStop(); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + stateStartTimeMS = getMSTimerCount(); + break; + + case DG_RO_PERM_SAMPLE_STATE_COLLECT_SAMPLE: + switch( collectSampleSubState ) + { + case COLLECT_SAMPLE_INITIALIZE: + deenergizeActuators( NO_PARK_CONC_PUMPS ); + activateAlarmNoData( ALARM_ID_DG_RO_PERMEATE_SAMPLE_REMOVE_DIA_CAP ); + stateStartTimeMS = getMSTimerCount(); + roPermeateSampledispensedVolumeML = 0.0F; + break; + + case COLLECT_SAMPLE_DISPENSE: + // Valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOnUVReactor( INLET_UV_REACTOR ); + turnOnUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + setROPumpTargetFlowRateLPM( RO_PUMP_TARGET_DISPENSE_FLOW_RATE_LPM, RO_PUMP_MAX_PRESSURE_PSI ); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + roPermeateSampledispensedVolumeML = 0.0F; + break; + + case COLLECT_SAMPLE_STOP: + deenergizeActuators( NO_PARK_CONC_PUMPS ); + break; + } + break; + + case DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH: + // Prepare to start draining reservoir 2 first + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_OPEN ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); + // RO pump + signalROPumpHardStop(); + // Drain pump + setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); + stateStartTimeMS = getMSTimerCount(); + rsrvrsStatus.rsrvr[ DG_RESERVOIR_1 ].rStatus = DG_RESERVOIR_BELOW_TARGET; + rsrvrsStatus.rsrvr[ DG_RESERVOIR_2 ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + break; + + case DG_RO_PERM_SAMPLE_STATE_COMPLETE: + deenergizeActuators( NO_PARK_CONC_PUMPS ); + break; + } +} + +/*********************************************************************//** + * @brief + * The checkRsrvrMgmtTimeoutStatus function checks and manages the status + * of reservoir management timeout status + * @details Inputs: rsrvrsStatus + * @details Outputs: alarmDetectedPendingTrigger, roPermeateSamplePrevState + * @param rsrvrID the reservoir ID to check the status of the timeout + * @param state the state of the RO permeate sample mode + * @return: state of the RO permeate sample mode + *************************************************************************/ +static DG_RO_PERM_STATE_T checkRsrvrMgmtTimeoutStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ) +{ + if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + switch ( state ) + { + case DG_RO_PERM_SAMPLE_STATE_FLUSH_R2_TO_R1_AND_DRAIN_R1: + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_FILL_TIMEOUT; + break; + + case DG_RO_PERM_SAMPLE_STATE_DRAIN_R1: + case DG_RO_PERM_SAMPLE_STATE_DRAIN_R2: + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + break; + + default: + // Do nothing + break; + } + + roPermeateSamplePrevState = state; + state = DG_RO_PERM_SAMPLE_STATE_CANCEL_WATER_PATH; + setROPermeateSampleStateTransition( state ); + } + + return state; +} + +static DG_RO_PERM_STATE_T checkRsrvrDrainStatus( DG_RESERVOIR_ID_T rsrvrID, DG_RO_PERM_STATE_T state ) +{ + if ( DG_RESERVOIR_ABOVE_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + rsrvrsStatus.rsrvr[ rsrvrID ].rStatus = getDisinfectRsrvrDrainStatus( rsrvrID, &rsrvrsStatus, RSRVR_DRAIN_STEADY_TIMEOUT_MS, + RSRVR_DRAIN_TIMEOUT_MS, stateStartTimeMS ); + } + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvrsStatus.rsrvr[ rsrvrID ].rStatus ) + { + if ( TRUE == rsrvrsStatus.isThisInitialDrain ) + { + LOAD_CELL_ID_T backUp = ( LOAD_CELL_RESERVOIR_1_PRIMARY == rsrvrsStatus.rsrvr[ rsrvrID ].loadCell ? + LOAD_CELL_RESERVOIR_1_BACKUP : LOAD_CELL_RESERVOIR_2_BACKUP ); + tareLoadCell( rsrvrsStatus.rsrvr[ rsrvrID ].loadCell ); + tareLoadCell( backUp ); + } + + if ( DG_RO_PERM_SAMPLE_STATE_DRAIN_R1 == state ) + { + DG_RESERVOIR_ID_T switchRsrvrID = ( DG_RESERVOIR_1 == rsrvrID ? DG_RESERVOIR_2 : DG_RESERVOIR_1 ); + + rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_ABOVE_TARGET; + state = DG_RO_PERM_SAMPLE_STATE_DRAIN_R2; + } + else if ( DG_RO_PERM_SAMPLE_STATE_DRAIN_R2 == state ) + { + state = ( TRUE == rsrvrsStatus.isThisInitialDrain ? DG_RO_PERM_SAMPLE_STATE_FLUSH_DRAIN : + DG_RO_PERM_SAMPLE_STATE_COMPLETE ); + rsrvrsStatus.isThisInitialDrain = FALSE; + } + + stateStartTimeMS = getMSTimerCount(); + setROPermeateSampleStateTransition( state ); + } + + state = checkRsrvrMgmtTimeoutStatus( rsrvrID, state ); + + return state; +} + /**@}*/