Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -184,6 +184,7 @@ if( heater < NUM_OF_DG_HEATERS ) { +#ifndef DISABLE_HEATERS_AND_TEMPS // Assume the target temperature has not changed heatersStatus[ heater ].hasTargetTempChanged = FALSE; @@ -194,6 +195,7 @@ heatersStatus[ heater ].hasTargetTempChanged = TRUE; result = TRUE; } +#endif } else { @@ -227,6 +229,7 @@ { BOOL status = FALSE; + if( heater < NUM_OF_DG_HEATERS ) { if ( HEATER_EXEC_STATE_OFF == heatersStatus[ heater ].state ) Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -48,23 +48,23 @@ #define LOAD_CELL_MIN_ALLOWED_WEIGHT_BEFORE_TARE_GRAMS 1600.0F ///< Load cell minimum allowed weight before tare in grams. #define LOAD_CELL_WEIGHT_OUT_RANGE_PERSISTENT_PERIOD_MS (5 * MS_PER_SECOND) ///< Load cell weight out of range persistent period in milliseconds. #define LOAD_CELL_PRIMARY_BACKUP_MAX_DRIFT_PERSISTENT_PERIOD_MS (5 * MS_PER_SECOND) ///< Load cell primary and backup maximum allowed weight drift persistent period in milliseconds. -#define EMPTY_RESERVOIR_WEIGHT_GRAMS 1600 ///< Reservoirs empty weight in grams. -#define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_FIRST_TARE_GRAMS 300 ///< Max allowed extra weight before first tare in grams. -#define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS 60 ///< Max allowed extra weight before tare in grams. +#define EMPTY_RESERVOIR_WEIGHT_GRAMS 1600.0F ///< Reservoirs empty weight in grams. +#define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_FIRST_TARE_GRAMS 300.0F ///< Max allowed extra weight before first tare in grams. +#define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS 60.0F ///< Max allowed extra weight before tare in grams. #define LOAD_CELL_PRIMARY_BACKUP_MAX_ALLOWED_DRIFT_GRAMS 60.0F ///< Load cell primary and backup maximum allowed weight drift in grams. #define DATA_PUBLISH_COUNTER_START_COUNT 0 ///< Data publish counter start count. /// Load cell data structure. typedef struct { U32 rawReading; ///< Latest raw load cell reading. - OVERRIDE_F32_T weight; ///< Latest load cell weight. + F32 weight; ///< Latest load cell weight. F32 autoCalOffset; ///< Load cell auto-calibration offset. F32 loadCellVelocity_g_min; ///< Velocity (in g/min) of load cell. F32 smallFilterReadings[ SIZE_OF_SMALL_LOAD_CELL_AVG ]; ///< Load cell samples for small load cell moving average. F64 smallFilterTotal; ///< Small filter rolling total - used to calc small load cell moving average. - F32 smallFilteredWeight; ///< Load cell small filtered (100 100Hz raw sample) weight. + OVERRIDE_F32_T smallFilteredWeight; ///< Load cell small filtered (100 100Hz raw sample) weight. F32 largeFilterReadings[ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Load cell samples for large load cell moving average. F64 largeFilterTotal; ///< Large filter rolling total - used to calc small load cell moving average. @@ -82,6 +82,7 @@ static U32 smallReadingsIdx; ///< Index for next sample in load cell small rolling average sample array. static U32 largeReadingsIdx; ///< Index for next sample in load cell large rolling average sample array. static DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< Load cells calibration record. +static BOOL hasLoadCellBeenTared[ NUM_OF_LOAD_CELLS ]; ///< Flags indicating whether loadcells have been tared yet. // ********** private function prototypes ********** @@ -95,7 +96,7 @@ * @details Outputs: LoadCell module initialized. * @return none *************************************************************************/ - void initLoadCell( void ) +void initLoadCell( void ) { U32 i; U32 j; @@ -105,21 +106,24 @@ loadCellDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; loadCellFilterTimerCount = 0; + // Initialize load cell filter data and set calibration data as benign until loaded from non-volatile memory for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { benignPolynomialCalRecord( &loadCellsCalRecord.loadCells[ i ] ); - loadcells[ i ].rawReading = 0; - loadcells[ i ].weight.data = 0.0; - loadcells[ i ].weight.ovData = 0.0; - loadcells[ i ].weight.ovInitData = 0.0; - loadcells[ i ].weight.override = OVERRIDE_RESET; - loadcells[ i ].autoCalOffset = 0.0; - loadcells[ i ].largeFilterTotal = 0.0; - loadcells[ i ].largeFilteredWeight = 0.0; - loadcells[ i ].smallFilterTotal = 0.0; - loadcells[ i ].smallFilteredWeight = 0.0; + hasLoadCellBeenTared[ i ] = FALSE; + loadcells[ i ].rawReading = 0; + loadcells[ i ].weight = 0.0; + loadcells[ i ].autoCalOffset = 0.0; + loadcells[ i ].largeFilterTotal = 0.0; + loadcells[ i ].largeFilteredWeight = 0.0; + loadcells[ i ].smallFilterTotal = 0.0; + loadcells[ i ].smallFilteredWeight.data = 0.0; + loadcells[ i ].smallFilteredWeight.ovData = 0.0; + loadcells[ i ].smallFilteredWeight.ovInitData = 0.0; + loadcells[ i ].smallFilteredWeight.override = OVERRIDE_RESET; + for ( j = 0; j < SIZE_OF_SMALL_LOAD_CELL_AVG; j++ ) { loadcells[ i ].smallFilterReadings[ j ] = 0.0; @@ -198,11 +202,11 @@ // Apply the calibration factors to the data. // load_cell_weight = fourth_order_coeff * (load_cell^4) + third_order_coeff * (load_cell^3) + second_order_coeff * (load_cell^2) + gain * load_cell + offset - loadcells[ ii ].weight.data = pow( loadCell, 4 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].fourthOrderCoeff + - pow( loadCell, 3 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].thirdOrderCoeff + - pow( loadCell, 2 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].secondOrderCoeff + - loadCell * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].gain + - loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].offset; + loadcells[ ii ].weight = pow( loadCell, 4 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].fourthOrderCoeff + + pow( loadCell, 3 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].thirdOrderCoeff + + pow( loadCell, 2 ) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].secondOrderCoeff + + loadCell * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].gain + + loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].offset; loadcells[ ii ].loadCellVelocity_g_min = ( getLoadCellWeight( (LOAD_CELL_ID_T)ii ) - loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ] ) * (F32)SEC_PER_MIN; @@ -213,13 +217,13 @@ loadcells[ ii ].smallFilterTotal += getLoadCellWeight( (LOAD_CELL_ID_T)ii ); // Calculate the load cell value before applying calibration to it - loadcells[ ii ].smallFilteredWeight = (F32)( loadcells[ ii ].smallFilterTotal / (F64)SIZE_OF_SMALL_LOAD_CELL_AVG ); + loadcells[ ii ].smallFilteredWeight.data = (F32)( loadcells[ ii ].smallFilterTotal / (F64)SIZE_OF_SMALL_LOAD_CELL_AVG ); // Monitor the load cells weight monitorLoadCellsWeightOutOfRange( (LOAD_CELL_ID_T)ii ); // Apply the tare offset. NOTE: tare must be applied after checking the weight out of range. - loadcells[ ii ].smallFilteredWeight -= loadcells[ ii ].autoCalOffset; + loadcells[ ii ].smallFilteredWeight.data -= loadcells[ ii ].autoCalOffset; } smallReadingsIdx = INC_WRAP( smallReadingsIdx, 0, SIZE_OF_SMALL_LOAD_CELL_AVG - 1 ); @@ -231,8 +235,8 @@ { // Update large filter with new small filter weight sample loadcells[ ii ].largeFilterTotal -= loadcells[ ii ].largeFilterReadings[ largeReadingsIdx ]; - loadcells[ ii ].largeFilterReadings[ largeReadingsIdx ] = loadcells[ ii ].smallFilteredWeight; - loadcells[ ii ].largeFilterTotal += loadcells[ ii ].smallFilteredWeight; + loadcells[ ii ].largeFilterReadings[ largeReadingsIdx ] = getLoadCellSmallFilteredWeight((LOAD_CELL_ID_T) ii); + loadcells[ ii ].largeFilterTotal += getLoadCellSmallFilteredWeight((LOAD_CELL_ID_T) ii); loadcells[ ii ].largeFilteredWeight = (F32)( loadcells[ ii ].largeFilterTotal / (F64)SIZE_OF_LARGE_LOAD_CELL_AVG ); } @@ -330,7 +334,7 @@ F32 weight = getLoadCellSmallFilteredWeight( loadCellID ); // Check if the load cell is being tared for the first time - if ( fabs( loadcells[ loadCellID ].autoCalOffset ) < NEARLY_ZERO ) + if ( hasLoadCellBeenTared[ loadCellID ] != TRUE ) { // For the first tare, the weight of the reservoir should be considered // The current weight of the load cell should not be greater than the weight of the reservoir + the extra weight @@ -345,7 +349,8 @@ if ( FALSE == isWeightOutOfRange ) { // Add old auto calibration offset to get back to actual weight value - loadcells[ loadCellID ].autoCalOffset = ( loadcells[ loadCellID ].smallFilteredWeight + loadcells[ loadCellID ].autoCalOffset ); + loadcells[ loadCellID ].autoCalOffset = ( loadcells[ loadCellID ].smallFilteredWeight.data + loadcells[ loadCellID ].autoCalOffset ); + hasLoadCellBeenTared[ loadCellID ] = TRUE; } else { @@ -378,14 +383,11 @@ *************************************************************************/ F32 getLoadCellWeight( LOAD_CELL_ID_T loadCellID ) { - F32 result = loadcells[ loadCellID ].weight.data; + F32 result = 0.0; if ( loadCellID < NUM_OF_LOAD_CELLS ) { - if ( OVERRIDE_KEY == loadcells[ loadCellID ].weight.override ) - { - result = loadcells[ loadCellID ].weight.ovData; - } + result = loadcells[ loadCellID ].weight; } else { @@ -410,7 +412,12 @@ if ( loadCellID < NUM_OF_LOAD_CELLS ) { - result = loadcells[ loadCellID ].smallFilteredWeight; + result = loadcells[ loadCellID ].smallFilteredWeight.data; + + if ( OVERRIDE_KEY == loadcells[ loadCellID ].smallFilteredWeight.override ) + { + result = loadcells[ loadCellID ].smallFilteredWeight.ovData; + } } else { @@ -556,8 +563,8 @@ { result = TRUE; // Add tare to given value so reported load will be what is requested when tare is subtracted later - loadcells[ loadCellID ].weight.ovData = value + loadcells[ loadCellID ].autoCalOffset; - loadcells[ loadCellID ].weight.override = OVERRIDE_KEY; + loadcells[ loadCellID ].smallFilteredWeight.ovData = value; + loadcells[ loadCellID ].smallFilteredWeight.override = OVERRIDE_KEY; } } @@ -581,8 +588,8 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - loadcells[ loadCellID ].weight.override = OVERRIDE_RESET; - loadcells[ loadCellID ].weight.ovData = loadcells[ loadCellID ].weight.ovInitData; + loadcells[ loadCellID ].smallFilteredWeight.override = OVERRIDE_RESET; + loadcells[ loadCellID ].smallFilteredWeight.ovData = loadcells[ loadCellID ].smallFilteredWeight.ovInitData; } } Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -226,15 +226,15 @@ BOOL result = FALSE; // First of all, the flow rate must be in range - if ( ( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) + if ( ( (roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM )) || 0 <= roFlowRate ) { // Then the max pressure that we are allowed to reach must be in range if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) { // For now maximum allowed pressure is inserted into the target pressure override // if the target flow rate exceeded the max pressure, it will set the maximum pressure targetROPumpMaxPressure = maxPressure; - targetROPumpFlowRateLPM = roFlowRate; + targetROPumpFlowRateLPM = roFlowRate; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; // Get the initial guess of the duty cycle @@ -276,7 +276,7 @@ BOOL result = FALSE; // First of all, the flow rate must be in range - if ( ( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) + if ( (( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM )) || 0 <= roFlowRate ) { // Then the max pressure that we are allowed to reach must be in range if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) @@ -376,12 +376,11 @@ measuredROFlowRateLPM.data = flow - ( getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ) / ML_PER_LITER ) - ( getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ) / ML_PER_LITER ); - // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that - // the flow is 0. - if ( FLOW_SENSOR_ZERO_READING == roFlowReading ) - { - measuredROFlowRateLPM.data = 0.0; - } + // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that the flow is 0. + if ( FLOW_SENSOR_ZERO_READING == roFlowReading ) + { + measuredROFlowRateLPM.data = 0.0; + } measuredFlowReadingsSum = 0; flowFilterCounter = 0; @@ -939,7 +938,7 @@ if ( TRUE == isTestingActivated() ) { // The flow rate and pressure must be in range - if ( ( flow <= MAX_RO_FLOWRATE_LPM ) && ( flow >= MIN_RO_FLOWRATE_LPM ) ) + if ( (( flow <= MAX_RO_FLOWRATE_LPM ) && ( flow >= MIN_RO_FLOWRATE_LPM ) ) || 0 <= flow ) { result = setROPumpTargetFlowRateLPM( flow, MAX_ALLOWED_PRESSURE_PSI ); } Index: firmware/App/Controllers/ROPump.h =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -32,7 +32,7 @@ // ********** public definitions ********** #define MAX_RO_FLOWRATE_LPM 1.8F ///< Maximum target RO flow rate in L/min. -#define MIN_RO_FLOWRATE_LPM 0.2F ///< Minimum target RO flow rate in L/min. +#define MIN_RO_FLOWRATE_LPM 0.3F ///< Minimum target RO flow rate in L/min. /// RO pump data struct. typedef struct Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -146,11 +146,11 @@ static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during chemical disinfect. static U32 dataPublishCounter = 0; ///< Chemical Disinfect data publish counter. static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. -static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. +static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. static U32 numberOfPostDisinfectRinses; ///< Number of times to rinse the fluid path after chemical disinfect. static U32 primeAcidSteadyStateCounter = 0; ///< Prime acid steady state counter. -static BOOL haveDrainParamsBeenInit; ///< Boolean flag to indicate whether the drain parameters have been reset or not. +static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. // ********** private function prototypes ********** @@ -181,8 +181,8 @@ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectCompleteState( void ); static void failChemicalDisinfect( void ); -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ); -static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, BOOL resetStateTimer ); +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, BOOL resetStateTimer ); static CHEM_DISINFECT_STATUS_T getChemicalDisinfectStatus( void ); static void publishChemicalDisinfectData( void ); static void monitorModeChemicalDisinfect( void ); @@ -202,24 +202,25 @@ *************************************************************************/ void initChemicalDisinfectMode( void ) { - chemDisinfectState = DG_CHEM_DISINFECT_STATE_START; - prevChemDisinfectState = DG_CHEM_DISINFECT_STATE_START; - stateTimer = 0; - isThisLastDrain = FALSE; - stateTrialCounter = 0; - areTempSensorsInRange = FALSE; - rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; - rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; - R1ChemDisinfectVol = 0.0; - R2ChemDisinfectVol = 0.0; - overallChemDisinfectTimer = 0; - cancellationMode = CANCELLATION_MODE_NONE; - rsrvrFillStableTimeCounter = 0; - isPartialDisinfectInProgress = FALSE; - numberOfPostDisinfectRinses = 0; - primeAcidSteadyStateCounter = 0; - chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; - haveDrainParamsBeenInit = FALSE; + chemDisinfectState = DG_CHEM_DISINFECT_STATE_START; + prevChemDisinfectState = DG_CHEM_DISINFECT_STATE_START; + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; + rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; + rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; + R1ChemDisinfectVol = 0.0; + R2ChemDisinfectVol = 0.0; + overallChemDisinfectTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; + rsrvrFillStableTimeCounter = 0; + isPartialDisinfectInProgress = FALSE; + numberOfPostDisinfectRinses = 0; + primeAcidSteadyStateCounter = 0; + chemDisinfectUIState = CHEM_DISINFECT_UI_STATE_NOT_RUNNING; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; } /*********************************************************************//** @@ -480,7 +481,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -553,7 +554,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -758,10 +759,10 @@ // If R1 is not full, keep monitoring for R1 level and timeout if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); // Keep monitoring the status of reservoir 2 at the same time - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue // until reservoir 2 is filled up and the tubing might expand or leak. @@ -775,7 +776,7 @@ // Once R1 is full, keep monitoring for R2 level and timeout else if( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Once R2 is full (to 500mL in this case), transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -829,7 +830,7 @@ // If reservoir 1 is empty, turn off the drain pump if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, FALSE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -847,7 +848,7 @@ // First reservoir 2 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, FALSE ); U32 drainPumpRPM = getDrainPumpTargetRPM(); // Keep monitoring the status of reservoir 1 as the same time @@ -857,7 +858,7 @@ // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevChemDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -867,7 +868,7 @@ // Once R2 is full, R1 must be partially full else if( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, FALSE ); // Once R1 is partially full, transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) @@ -921,7 +922,7 @@ // If reservoir 2 is empty, set the drain valve to drain R1 if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -960,7 +961,7 @@ // If reservoir 1 is empty, set the state to fill water state if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1091,12 +1092,12 @@ // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); } // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Once reservoir 2 is full, set the actuators for recirculation if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -1241,11 +1242,11 @@ // First reservoir 1 must be partially full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1368,7 +1369,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1407,7 +1408,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1457,10 +1458,10 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); // Keep monitoring the status of reservoir 2 at the same time - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue // until reservoir 2 is filled up and the tubing might expand or leak. @@ -1473,7 +1474,7 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1524,7 +1525,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1541,7 +1542,7 @@ // First reservoir 2 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); U32 drainPumpRPM = getDrainPumpTargetRPM(); // Keep monitoring the status of reservoir 1 as the same time @@ -1551,7 +1552,7 @@ // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevChemDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -1561,7 +1562,7 @@ // Once reservoir 2 is completely full, monitor reservoir 1 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1616,7 +1617,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1633,7 +1634,7 @@ // First reservoir 1 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); U32 drainPumpRPM = getDrainPumpTargetRPM(); // Keep monitoring the status of reservoir 2 as the same time @@ -1643,7 +1644,7 @@ // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevChemDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -1653,7 +1654,7 @@ // Once reservoir 1 is completely full, monitor reservoir 2 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1794,7 +1795,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { // If the cancellation water path cannot be done, got to basic cancellation path - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1814,7 +1815,7 @@ if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) { // If the cancellation water path cannot be done, got to basic cancellation path - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1877,7 +1878,7 @@ * @param timeout is the fill up timeout * @return the status of the reservoirs during filling *************************************************************************/ -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout ) +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T r, F32 targetVol, U32 timeout, BOOL resetStateTimer ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; F32 volume = 0.0; @@ -1902,8 +1903,11 @@ { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillStableTimeCounter = 0; - // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); + if (resetStateTimer) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } } } else if ( TRUE == didTimeout( stateTimer, timeout ) ) @@ -1931,33 +1935,36 @@ * then * @return the status of the reservoirs during draining *************************************************************************/ -static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, BOOL resetStateTimer ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; // If the drain parameters of the reservoir is not initialized, initialize them - if ( FALSE == haveDrainParamsBeenInit ) + if ( FALSE == haveDrainParamsBeenInit[ r ] ) { initDrainParameters( r ); - haveDrainParamsBeenInit = TRUE; + haveDrainParamsBeenInit[ r ] = TRUE; } BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); if ( TRUE == isDrainComplete ) { - // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); - haveDrainParamsBeenInit = FALSE; - status = DG_RESERVOIR_REACHED_TARGET; + if (resetStateTimer) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to drain on time. Update the previous chemical disinfect state and transition to basic cancellation - prevChemDisinfectState = chemDisinfectState; - haveDrainParamsBeenInit = FALSE; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + prevChemDisinfectState = chemDisinfectState; + haveDrainParamsBeenInit[ r ] = FALSE; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -162,14 +162,14 @@ static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. -static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. +static U32 rsrvrFillStableTimeCounter; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to indicate the drain pump is on during mix drain. static U32 ROFCirculationTimer = 0; ///< RO filter circulation timer. static U32 ROFCoolingTimer = 0; ///< RO filter cooling timer. static BOOL hasROFCirculationBeenStarted = FALSE; ///< Flag to indicate the water in RO filter has been recirculated. static U32 targetDisinfectTime = 0; ///< Target disinfect time. -static BOOL haveDrainParamsBeenInit; ///< Boolean flag to indicate whether the drain parameters have been reset or not. +static BOOL haveDrainParamsBeenInit[ NUM_OF_DG_RESERVOIRS ]; ///< Boolean flag to indicate whether the drain parameters have been reset or not. static U32 tempGradOutOfRangeTimer; ///< Temperature gradient out of range start timer. // ********** private function prototypes ********** @@ -199,8 +199,8 @@ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCompleteState( void ); static void failHeatDisinfect( void ); -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout ); -static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ); +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout, BOOL resetStateTimer ); +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, BOOL resetStateTimer ); static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ); static void publishHeatDisinfectData( void ); static void monitorModeHeatDisinfect( void ); @@ -222,29 +222,30 @@ *************************************************************************/ void initHeatDisinfectMode( void ) { - heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; - prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; - heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; - stateTimer = 0; - isThisLastDrain = FALSE; - stateTrialCounter = 0; - areTempSensorsInRange = FALSE; - rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; - rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; - R1HeatDisinfectVol = 0.0; - R2HeatDisinfectVol = 0.0; - overallHeatDisinfectTimer = 0; - cancellationMode = CANCELLATION_MODE_NONE; - rsrvrFillStableTimeCounter = 0; - isPartialDisinfectInProgress = FALSE; - isDrainPumpInMixDrainOn = FALSE; - ROFCirculationTimer = 0; - ROFCoolingTimer = 0; - hasROFCirculationBeenStarted = FALSE; - concentratePumpsPrimeTimer = 0; - targetDisinfectTime = 0; - haveDrainParamsBeenInit = FALSE; - tempGradOutOfRangeTimer = 0; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; + rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; + rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; + R1HeatDisinfectVol = 0.0; + R2HeatDisinfectVol = 0.0; + overallHeatDisinfectTimer = 0; + cancellationMode = CANCELLATION_MODE_NONE; + rsrvrFillStableTimeCounter = 0; + isPartialDisinfectInProgress = FALSE; + isDrainPumpInMixDrainOn = FALSE; + ROFCirculationTimer = 0; + ROFCoolingTimer = 0; + hasROFCirculationBeenStarted = FALSE; + concentratePumpsPrimeTimer = 0; + targetDisinfectTime = 0; + haveDrainParamsBeenInit[ DG_RESERVOIR_1 ] = FALSE; + haveDrainParamsBeenInit[ DG_RESERVOIR_2 ] = FALSE; + tempGradOutOfRangeTimer = 0; } /*********************************************************************//** @@ -450,9 +451,9 @@ // Set all the actuators to reset and de-energized state deenergizeActuators(); - // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 3 C, the cycle + // If the inlet pressure is less than or equal to the threshold or TDi and TRo difference is greater than 3 C, the cycle // should be canceled - if ( ( ppiPressure < MIN_INLET_PRESSURE_PSI ) && ( fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) + if ( ( ppiPressure <= MIN_INLET_PRESSURE_PSI ) || ( fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) ) { prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_INLET_PRES_AND_TEMP_SNSRS_OUT; @@ -465,6 +466,7 @@ // Close VPi to prevent wasting water setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); // Set the actuators to drain R1 setValveState( VRD1, VALVE_STATE_OPEN ); @@ -495,7 +497,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS , TRUE); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -508,7 +510,6 @@ setValveState( VPI, VALVE_STATE_OPEN ); setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); setValveState( VRD1, VALVE_STATE_CLOSED ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); @@ -537,6 +538,8 @@ state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; } + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); + // Start the timer stateTimer = getMSTimerCount(); } @@ -566,7 +569,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -591,6 +594,7 @@ stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; } + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -768,10 +772,10 @@ // If R1 is not full, keep monitoring for R1 level and timeout if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); // Keep monitoring the status of reservoir 2 at the same time - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue // until reservoir 2 is filled up and the tubing might expand or leak. @@ -785,7 +789,7 @@ // Once R1 is full, keep monitoring for R2 level and timeout else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Once R2 is full (to 500mL in this case), transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -838,7 +842,7 @@ // If reservoir 1 is empty, turn off the drain pump if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, FALSE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -856,7 +860,7 @@ // First reservoir 2 must be completely full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, FALSE ); U32 drainPumpRPM = getDrainPumpTargetRPM(); // Keep monitoring the status of reservoir 1 as the same time @@ -866,7 +870,7 @@ // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -876,7 +880,7 @@ // Once R2 is full, R1 must be partially full else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, FALSE ); // Once R1 is partially full, transition to the next state if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) @@ -929,7 +933,7 @@ // If reservoir 2 is empty, set the drain valve to drain R1 if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -967,7 +971,7 @@ // If reservoir 1 is empty, set the state to fill water state if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1031,12 +1035,12 @@ // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); } // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Once reservoir 2 is full, set the actuators for recirculation if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -1164,11 +1168,11 @@ // First reservoir 1 must be partially full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1379,7 +1383,7 @@ { if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_MIX_DRAIN_TIMEOUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_MIX_DRAIN_TIMEOUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1418,7 +1422,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_MIX_DRAIN_TIMEOUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_MIX_DRAIN_TIMEOUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1469,10 +1473,10 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); // Keep monitoring the status of reservoir 2 at the same time - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); // Reservoir 2 cannot be filled before reservoir 1 is filled and is overflowing to reservoir 2. If reservoir 2 has already // reached to target volume, it means reservoir 1's load cell might be reading incorrect values. This situation might continue // until reservoir 2 is filled up and the tubing might expand or leak. @@ -1485,7 +1489,7 @@ } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1535,7 +1539,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) { - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1555,7 +1559,7 @@ // Keep monitoring the status of reservoir 1 as the same time F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); - rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, TRUE ); U32 drainPumpRPM = getDrainPumpTargetRPM(); @@ -1564,7 +1568,7 @@ // until reservoir 1 is filled up and the tubing might expand or leak. // Before checking whether reservoir 1 is filled pre-maturely, we have to make sure reservoir 1 is drained completely to make // sure the extra volume that is read is not because of previous water that is being drained currently and it is above 500 mL - if ( ( volume > RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) + if ( ( volume >= RSRVRS_PARTIAL_FILL_VOL_ML ) && ( 0 == drainPumpRPM ) ) { prevHeatDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; @@ -1574,7 +1578,7 @@ // Once reservoir 2 is completely full, monitor reservoir 1 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { - rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS ); + rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1584,7 +1588,7 @@ // De-energize all the valves and set the VDr to drain R2 setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRD2, VALVE_STATE_OPEN ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); @@ -1732,7 +1736,7 @@ if ( DG_RESERVOIR_ABOVE_TARGET == rsrvr2Status ) { // If the cancellation water path cannot be done, got to basic cancellation path - rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr2Status = getRsrvrDrainStatus( DG_RESERVOIR_2, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { @@ -1756,7 +1760,7 @@ if ( ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) && ( DG_RESERVOIR_ABOVE_TARGET == rsrvr1Status ) ) { // If the cancellation water path cannot be done, got to basic cancellation path - rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ); + rsrvr1Status = getRsrvrDrainStatus( DG_RESERVOIR_1, DRAIN_WEIGHT_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, TRUE ); if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1826,7 +1830,7 @@ * @param timeout is the fill up timeout * @return the status of the reservoirs during filling *************************************************************************/ -static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout ) +static DG_RESERVOIR_STATUS_T getRsrvrFillStatus( DG_RESERVOIR_ID_T reservoir, F32 targetVol, U32 timeout, BOOL resetStateTimer ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_BELOW_TARGET; F32 volume = 0.0; @@ -1851,8 +1855,11 @@ { status = DG_RESERVOIR_REACHED_TARGET; rsrvrFillStableTimeCounter = 0; - // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); + if (resetStateTimer) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } } } else if ( TRUE == didTimeout( stateTimer, timeout ) ) @@ -1880,33 +1887,36 @@ * then * @return the status of the reservoirs during draining *************************************************************************/ -static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout ) +static DG_RESERVOIR_STATUS_T getRsrvrDrainStatus( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, BOOL resetStateTimer ) { DG_RESERVOIR_STATUS_T status = DG_RESERVOIR_ABOVE_TARGET; // If the drain parameters of the reservoir is not initialized, initialize them - if ( FALSE == haveDrainParamsBeenInit ) + if ( FALSE == haveDrainParamsBeenInit[ r ] ) { initDrainParameters( r ); - haveDrainParamsBeenInit = TRUE; + haveDrainParamsBeenInit[ r ] = TRUE; } BOOL isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout ); if ( TRUE == isDrainComplete ) { - // Set the state timer in case it needs to be used for another timeout check - stateTimer = getMSTimerCount(); - haveDrainParamsBeenInit = FALSE; - status = DG_RESERVOIR_REACHED_TARGET; + if (resetStateTimer) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_REACHED_TARGET; } else if ( TRUE == didTimeout( stateTimer, timeout ) ) { // Failed to drain on time. Update the previous heat disinfect state and transition to basic cancellation - prevHeatDisinfectState = heatDisinfectState; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; - haveDrainParamsBeenInit = FALSE; - status = DG_RESERVOIR_NOT_REACHED_TARGET; + prevHeatDisinfectState = heatDisinfectState; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_DRAIN_TIMEOUT; + haveDrainParamsBeenInit[ r ] = FALSE; + status = DG_RESERVOIR_NOT_REACHED_TARGET; } return status; Index: firmware/App/Modes/OperationModes.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -131,7 +131,6 @@ void execOperationModes( void ) { DG_OP_MODE_T newMode; - U32 priorSubMode = currentSubMode; priorSubMode = currentSubMode; @@ -150,7 +149,6 @@ if ( currentMode != newMode ) { // handle transition to new mode - priorSubMode = 0; lastMode = currentMode; transitionToNewOperationMode( newMode ); currentMode = newMode; @@ -416,6 +414,34 @@ /*********************************************************************//** * @brief + * The testSetOperationMode function will transition to a given operation + * mode if the transition is legal. + * @details Inputs: none + * @details Outputs: modeRequest[] + * @param newMode ID of requested mode to transition to + * @return TRUE if request successful, FALSE if not + *************************************************************************/ +BOOL testSetOperationMode( DG_OP_MODE_T newMode ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + DG_OP_MODE_T check = MODE_TRANSITION_TABLE[ currentMode ][ newMode ]; + + // Is mode transition legal? + if ( check == newMode ) + { + requestNewOperationMode( newMode ); + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The testSetDGOpModePublishIntervalOverride function overrides the * DG operation mode publish interval. * @details Inputs: none Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -1063,4 +1063,32 @@ return result; } +/*********************************************************************//** + * @brief + * The testTareReservoir function tares a given reservoir. It is assumed + * that the given reservoir has already been drained. + * @details Inputs: drainVolumeTargetMl + * @details Outputs: drainVolumeTargetMl + * @param value ID of reservoir to tare + * @return TRUE if tare successful, FALSE if not + *************************************************************************/ +BOOL testTareReservoir( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + if ( value < NUM_OF_DG_RESERVOIRS ) + { + result = TRUE; + tareLoadCellRequest = TRUE; + testSetReservoirDrainVolumeMlOverride( 0 ); + tareLoadCellsAtEmpty( (DG_RESERVOIR_ID_T)value ); + testResetReservoirDrainVolumeMlOverride(); + } + } + + return result; +} + /**@}*/ Index: firmware/App/Services/Reservoirs.h =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -141,7 +141,8 @@ BOOL testSetReservoirFillVolumeMlOverride( U32 value ); BOOL testResetReservoirFillVolumeMlOverride( void ); BOOL testSetReservoirDrainVolumeMlOverride( U32 value ); -BOOL testResetReservoirDrainVolumeMlOverride( void ); +BOOL testResetReservoirDrainVolumeMlOverride( void ); +BOOL testTareReservoir( U32 value ); /**@}*/ Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r98a1a2a624373a1d140daed0136522ab6e635237 -r752ec32e48ba27c3939d7e8ec56091cb917e3eef --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 98a1a2a624373a1d140daed0136522ab6e635237) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 752ec32e48ba27c3939d7e8ec56091cb917e3eef) @@ -23,7 +23,6 @@ #include "Compatible.h" #include "ConcentratePumps.h" #include "ConductivitySensors.h" -#include "Fans.h" #include "FPGA.h" #include "Heaters.h" #include "ModeFill.h" @@ -368,7 +367,6 @@ return result; } - // *********************************************************************** // **************** Message Handling Helper Functions ******************** // *********************************************************************** @@ -1368,6 +1366,56 @@ /*********************************************************************//** * @brief + * The handleTestSetOpModeRequest function handles a request to set the + * DG operation mode. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestSetOpModeRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof(U32) ) + { + U32 mode; + + memcpy( &mode, message->payload, sizeof(U32) ); + result = testSetOperationMode( (DG_OP_MODE_T)mode ); + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestTareReservoirRequest function handles a request to tare a + * given reservoir's weight. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestTareReservoirRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof(U32) ) + { + U32 res; + + memcpy( &res, message->payload, sizeof(U32) ); + result = testTareReservoir( res ); + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief * The handleSetHDOperationMode function receives the HD operation modes data * publish message. * @details Inputs: none @@ -3157,37 +3205,6 @@ } /*********************************************************************//** - * @brief - * The handleFansRPMOverride function handles a request to override a fans RPM value. - * @details Inputs: none - * @details Outputs: message handled - * @param message a pointer to the message to handle - * @return none - *************************************************************************/ -void handleFansRPMOverride( MESSAGE_T *message ) -{ - TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; - BOOL result = FALSE; - - // verify payload length - if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) - { - memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); - if ( FALSE == payload.reset ) - { - result = testSetFanRPMOverride( payload.index, payload.state.f32 ); - } - else - { - result = testResetFanRPMOverride( payload.index ); - } - } - - // respond to request - sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); -} - -/*********************************************************************//** * @brief * The handleStopDGRTCClock function handles a request to stop the RTC clock. * @details Inputs: none @@ -3326,10 +3343,41 @@ /*********************************************************************//** * @brief - * The handleTestFansRPMAlarmStartTimeOffsetRequest function handles a - * request to set the fans RPM alarm start time offset. + * The handleFansRPMOverride function handles a request to override a fans RPM value. * @details Inputs: none * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleFansRPMOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + if ( FALSE == payload.reset ) + { + result = testSetFanRPMOverride( payload.index, payload.state.f32 ); + } + else + { + result = testResetFanRPMOverride( payload.index ); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestFansRPMAlarmStartTimeOverrideRequest function handles a + * request to override the fan RPM alarm start time. + * @details Inputs: none + * @details Outputs: message handled * @param message : a pointer to the message to handle * @return none *************************************************************************/ @@ -3352,7 +3400,6 @@ } /*********************************************************************//** - * @brief * The handleTestUsedAcidVolumeMLOverrideRequest function handles a * request to override the acid volume. * @details Inputs: none @@ -3645,13 +3692,80 @@ /*********************************************************************//** * @brief -* The handleResendAllAlarmsCommand function handles a request to re-send -* all active DG alarms. +* The handleServiceModeRequest function handles a request to enter service +* mode. * @details Inputs: none * @details Outputs: message handled * @param message a pointer to the message to handle * @return none *************************************************************************/ +void handleServiceModeRequest( MESSAGE_T *message ) +{ + BOOL status = FALSE; + DG_OP_MODE_T currentMode = getCurrentOperationMode(); + REQUEST_REJECT_REASON_CODE_T reject; + + if ( 0 == message->hdr.payloadLen ) + { + if ( ( DG_MODE_STAN == currentMode ) || ( DG_MODE_FAUL == currentMode ) ) + { + status = TRUE; + requestNewOperationMode( DG_MODE_SERV ); + reject = REQUEST_REJECT_REASON_NONE; + } + else + { + reject = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; + } + } + else + { + reject = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, status ); + sendServiceModeResponse( status, (U32)reject ); +} + +/*********************************************************************//** + * @brief + * The sendServiceModeResponse function sends out the DG response to a + * UI request to go to service mode. + * @details Inputs: none + * @details Outputs: Service mode request response msg constructed and queued + * @param accepted TRUE if request was accepted, FALSE if not + * @param rejCode Reject reason code explaining why request was rejected + * @return none + *************************************************************************/ +void sendServiceModeResponse( BOOL accepted, U32 rejCode ) +{ + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_RESPONSE_SERVICE_MODE_REQUEST; + msg.hdr.payloadLen = sizeof( BOOL ) + sizeof( U32 ); + + memcpy( payloadPtr, &accepted, sizeof( BOOL ) ); + payloadPtr += sizeof( BOOL ); + memcpy( payloadPtr, &rejCode, sizeof( U32 ) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_2_HD, ACK_REQUIRED ); +} + +/*********************************************************************//** + * @brief + * The sendUIServiceModeResponse function sends out the DG response to a + * UI request to go to service mode. + * @details Inputs: none + * @details Outputs: Service mode request response msg constructed and queued + * @param accepted TRUE if request was accepted, FALSE if not + * @param rejCode Reject reason code explaining why request was rejected + * @return none + *************************************************************************/ void handleResendAllAlarmsCommand( MESSAGE_T *message ) { BOOL result = FALSE;