Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -rebbb1f85550a1f9b8f946655f7b2b63f76fbf67d -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision ebbb1f85550a1f9b8f946655f7b2b63f76fbf67d) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -20,6 +20,7 @@ #include "FPGA.h" #include "LoadCell.h" #include "NVDataMgmt.h" +#include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "TaskPriority.h" @@ -33,29 +34,33 @@ // TODO check the maximum weight on the load cells in tare. There was 1500 grams limit // but it has been removed. Check the load cells data sheet. -#define LOAD_CELL_REPORT_PERIOD (100 / TASK_PRIORITY_INTERVAL) ///< Broadcast load cell values message every 100 ms. +#define LOAD_CELL_REPORT_PERIOD (100 / TASK_PRIORITY_INTERVAL) ///< Broadcast load cell values message every 100 ms. /// Conversion factor from ADC counts to grams. -static const F32 ADC2GRAM = (0.0894 * 1.1338); -#define LOAD_CELL_ZERO_OFFSET -1500.0 ///< Zero offset (in grams). TODO - right now, this is empty reservoir weight. -#define LOAD_CELL_FILTER_ALPHA 0.05 ///< Alpha factor for the alpha filter used on load cell readings. +static const F32 ADC2GRAM = (0.0894 * 1.1338); +#define LOAD_CELL_FILTER_ALPHA 0.05 ///< Alpha factor for the alpha filter used on load cell readings. -#define SIZE_OF_SMALL_LOAD_CELL_AVG 100 ///< Small load cell moving average has 100 raw samples @ 10ms intervals (1-second). -#define SIZE_OF_LARGE_LOAD_CELL_AVG 40 ///< Large load cell moving average has 40 samples from small filter @ 100ms intervals (4-second). +#define SIZE_OF_SMALL_LOAD_CELL_AVG 100 ///< Small load cell moving average has 100 raw samples @ 10ms intervals (1-second). +#define SIZE_OF_LARGE_LOAD_CELL_AVG 40 ///< Large load cell moving average has 40 samples from small filter @ 100ms intervals (4-second). +#define LOAD_CELL_ADC_ERROR_PERSISTENCE 500 ///< Alarm persistence period (in ms) for load cell ADC errors. +#define EMPTY_RESERVOIR_WEIGHT_GRAMS 1600 ///< Reservoirs empty weight in grams. +#define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS 300 ///< Max allowed extra weight before tare in grams. + /// Load cell data structure. typedef struct { U32 rawReading; ///< Latest raw load cell reading OVERRIDE_F32_T 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 - F32 smallFilterTotal; ///< Small filter rolling total - used to calc small load cell moving average - F32 smallFilteredWeight; ///< Load cell small filtered (100 100Hz raw sample) weight + F32 smallFilterReadings[ SIZE_OF_SMALL_LOAD_CELL_AVG ]; ///< Load cell samples for small load cell moving average. + F32 smallFilterTotal; ///< Small filter rolling total - used to calc small load cell moving average. + F32 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 - F32 largeFilterTotal; ///< Large filter rolling total - used to calc small load cell moving average - F32 largeFilteredWeight; ///< Load cell large filtered (40 10Hz filtered sample) weight + F32 largeFilterReadings[ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Load cell samples for large load cell moving average. + F32 largeFilterTotal; ///< Large filter rolling total - used to calc small load cell moving average. + F32 largeFilteredWeight; ///< Load cell large filtered (40 10Hz filtered sample) weight. } LOADCELL_T; // ********** private data ********** @@ -70,8 +75,6 @@ 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. -// TODO - gain and offset for load cells should be read from NV Data calibration record. - // ********** private function prototypes ********** static U32 getLoadCellDataPublishInterval( void ); @@ -119,6 +122,8 @@ { loadcells[ i ].largeFilterReadings[ j ] = 0.0; } + + loadcells[ i ].loadCellVelocity_g_min = 0.0; } // Set all the load cells' calibration values to benign values @@ -131,6 +136,9 @@ loadCellsCalRecord.loadCells[ cell ].gain = 1.0; loadCellsCalRecord.loadCells[ cell ].offset = 0.0; } + + // Initialize persistent alarm(s) + initPersistentAlarm( ALARM_ID_DG_LOAD_CELL_ADC_ERROR, 0, LOAD_CELL_ADC_ERROR_PERSISTENCE ); } /*********************************************************************//** @@ -144,17 +152,53 @@ void execLoadCell( void ) { U32 ii; + U32 a1 = getFPGALoadCellA1(); + U32 a2 = getFPGALoadCellA2(); + U32 b1 = getFPGALoadCellB1(); + U32 b2 = getFPGALoadCellB2(); // update sums for load cell average calculations - loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].rawReading = getFPGALoadCellA1(); - loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].rawReading = getFPGALoadCellA2(); - loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].rawReading = getFPGALoadCellB1(); - loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].rawReading = getFPGALoadCellB2(); + loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].rawReading = a1 & MASK_OFF_U32_MSB; + loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].rawReading = a2 & MASK_OFF_U32_MSB; + loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].rawReading = b1 & MASK_OFF_U32_MSB; + loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].rawReading = b2 & MASK_OFF_U32_MSB; + // Check error bits from new readings + a1 = ( a1 >> 31 ) << SHIFT_24_BITS; + a2 = ( a2 >> 31 ) << SHIFT_16_BITS_FOR_WORD_SHIFT; + b1 = ( b1 >> 31 ) << SHIFT_8_BITS_FOR_BYTE_SHIFT; + b2 = ( b2 >> 31 ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DG_LOAD_CELL_ADC_ERROR, ( ( a1 > 0 ) || ( a2 > 0 ) || ( b1 > 0 ) || ( b2 > 0 ) ) ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_LOAD_CELL_ADC_ERROR, ( a1 | a2 | b1 | b2 ) ) + } + + // Check if a new calibration is available + if ( isNewCalibrationRecordAvailable() == TRUE ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + + // Zero the current tare values when new calibration data is available + loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].autoCalOffset = 0.0; + loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].autoCalOffset = 0.0; + loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].autoCalOffset = 0.0; + loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].autoCalOffset = 0.0; + } + // Rolling average of last 100 raw samples in small filter for ( ii = 0; ii < NUM_OF_LOAD_CELLS; ++ii ) { - loadcells[ ii ].weight.data = (F32)loadcells[ ii ].rawReading * ADC2GRAM + LOAD_CELL_ZERO_OFFSET - loadcells[ ii ].autoCalOffset; + loadcells[ ii ].weight.data = (F32)loadcells[ ii ].rawReading * ADC2GRAM; + // 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(loadcells[ ii ].weight.data, 4) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].fourthOrderCoeff + + pow(loadcells[ ii ].weight.data, 3) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].thirdOrderCoeff + + pow(loadcells[ ii ].weight.data, 2) * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].secondOrderCoeff + + loadcells[ ii ].weight.data * loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].gain + + loadCellsCalRecord.loadCells[ (CAL_DATA_DG_LOAD_CELLS_T)ii ].offset; + loadcells[ ii ].weight.data = loadcells[ ii ].weight.data - loadcells[ ii ].autoCalOffset; + loadcells[ ii ].loadCellVelocity_g_min = ( getLoadCellWeight( (LOAD_CELL_ID_T)ii ) - loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ] ) * (F32)SEC_PER_MIN; // Update small filter with new weight sample loadcells[ ii ].smallFilterTotal -= loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ]; @@ -231,8 +275,18 @@ *************************************************************************/ void tareLoadCell( LOAD_CELL_ID_T loadCellID ) { - // Add old auto calibration offset to get back to actual weight value - loadcells[ loadCellID ].autoCalOffset = ( loadcells[ loadCellID ].smallFilteredWeight + loadcells[ loadCellID ].autoCalOffset ); + F32 weight = getLoadCellSmallFilteredWeight( loadCellID ); + BOOL isWeightOutOfRange = ( weight > ( EMPTY_RESERVOIR_WEIGHT_GRAMS + MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS ) ? TRUE : FALSE ); + + if ( FALSE == isWeightOutOfRange ) + { + // Add old auto calibration offset to get back to actual weight value + loadcells[ loadCellID ].autoCalOffset = ( loadcells[ loadCellID ].smallFilteredWeight + loadcells[ loadCellID ].autoCalOffset ); + } + else + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_LOAD_CELLS_TARE_WEIGHT_OUT_OF_RANGE, weight ) + } } /*********************************************************************//** @@ -274,7 +328,7 @@ } else { - activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LOAD_CELL_ID, (U32)loadCellID ) } return result; @@ -299,7 +353,7 @@ } else { - activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LOAD_CELL_ID, (U32)loadCellID ) } return result; @@ -316,22 +370,47 @@ *************************************************************************/ F32 getLoadCellLargeFilteredWeight( LOAD_CELL_ID_T loadCellID ) { - F32 result = 0; + F32 result = 0.0; if ( loadCellID < NUM_OF_LOAD_CELLS ) { result = loadcells[ loadCellID ].largeFilteredWeight; } else { - activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LOAD_CELL_ID, (U32)loadCellID ) } return result; } /*********************************************************************//** * @brief + * The getLoadCellVelocity function gets the current velocity (in g/min) + * for the given load cell. + * @details Inputs: loadcells[] + * @details Outputs: none + * @param loadCellID ID of load cell to get velocity + * @return the velocity (in g/min) for the given load cell ID. + *************************************************************************/ +F32 getLoadCellVelocity( LOAD_CELL_ID_T loadCellID ) +{ + F32 result = 0.0; + + if ( loadCellID < NUM_OF_LOAD_CELLS ) + { + result = loadcells[ loadCellID ].loadCellVelocity_g_min; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LOAD_CELL_ID, (U32)loadCellID ) + } + + return result; +} + +/*********************************************************************//** + * @brief * The getLoadCellDataPublishInterval function gets the load cell data publish interval. * @details Inputs: loadCellDataPublishInterval * @details Outputs: none Index: firmware/App/DGCommon.h =================================================================== diff -u -r654c5598765bb862c00a0175bdac95604c6c9b24 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 654c5598765bb862c00a0175bdac95604c6c9b24) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -56,6 +56,7 @@ #define DISABLE_WATER_QUALITY_CHECK 1 #define DISABLE_RTC_CONFIG 1 //#define V_2_SYSTEM 1 + #define SKIP_RECIRC 1 #include #include #endif Index: firmware/App/Modes/ModeChemicalDisinfect.c =================================================================== diff -u -r654c5598765bb862c00a0175bdac95604c6c9b24 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision 654c5598765bb862c00a0175bdac95604c6c9b24) +++ firmware/App/Modes/ModeChemicalDisinfect.c (.../ModeChemicalDisinfect.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -77,15 +77,18 @@ #define CHEM_DISINFECT_TARGET_RO_FLOW_LPM 0.9 ///< Chemical disinfect target RO flow rate in L/min. TODO original value was 0.8 #define CHEM_DISINFECT_MAX_RO_PRESSURE_PSI 130 ///< Chemical disinfect maximum RO pressure in psi. #define CHEM_DISINFECT_TARGET_DRAIN_PRES_PSI 10.0 ///< Chemical disinfect target drain outlet pressure in psi. -#define CHEM_DISINFECT_TIME_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 10 minutes +#define CHEM_DISINFECT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect time for each section in milliseconds. TODO original time was 10 minutes #define CHEM_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect reaching to minimum temperature timeout in milliseconds. TODO figure out this timeout #define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 0.5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during chemical disinfect. TODO change this to 5 seconds #define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 600.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during chemical disinfect. TODO original value is 100 mL #define POST_CHEM_DISINFECT_WAIT_TIME_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< Chemical disinfect final wait time before flushing the system in milliseconds. -// Fill and heat up +// Fill heat up #define CHEM_DISINFECT_TARGET_TEMPERATURE_C 21.0 ///< Chemical disinfect target water temperature in C. +// Post disinfect rinses +#define NUM_OF_POST_DISINFECT_RINSES 1 ///< Number of rinses after a chemical disinfect. + /// Cancellation paths typedef enum Cancellation_modes { @@ -128,6 +131,7 @@ static CANCELLATION_MODE_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. static ALARM_ID_T alarmDetectedPendingTrigger; ///< Chemical disinfect alarm to raise. +static U32 numberOfPostDisinfectRinses = NUM_OF_POST_DISINFECT_RINSES; ///< Number of times to rinse the fluid path after chemical disinfect. // ********** private function prototypes ********** @@ -170,7 +174,7 @@ * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1ChemDisinfectVol, R2ChemDisinfectVol, overallChemDisinfectTimer, * cancellationMode, rsrvrFillStableTimeCounter, prevChemDisinfectState - * isPartialDisinfectInProgress + * isPartialDisinfectInProgress, numberOfPostDisinfectRinses * @return none *************************************************************************/ void initChemicalDisinfectMode( void ) @@ -189,6 +193,7 @@ cancellationMode = CANCELLATION_MODE_NONE; rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; + numberOfPostDisinfectRinses = NUM_OF_POST_DISINFECT_RINSES; } /*********************************************************************//** @@ -1196,20 +1201,24 @@ signalDrainPumpHardStop(); signalROPumpHardStop(); - // De-energize all the valves that are not in the path anymore - // and wait for the RO membrane to be cooled down. - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_CLOSED ); + if ( 0 == getTargetDrainPumpRPM() ) + { + // De-energize all the valves that are not in the path anymore + // and wait for the RO membrane to be cooled down. + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); #ifndef V_2_SYSTEM - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_OPEN ); #else - setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); #endif - setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - stateTimer = getMSTimerCount(); - state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1; + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + stateTimer = getMSTimerCount(); + state = DG_CHEM_DISINFECT_STATE_DISINFECTANT_DRAIN_R1; + } } return state; @@ -1342,7 +1351,7 @@ { prevChemDisinfectState = state; alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; - state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + state = DG_CHEM_DISINFECT_STATE_CANCEL_WATER_PATH; } } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) @@ -1355,7 +1364,7 @@ setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); #ifndef V_2_SYSTEM - setValveState( VRD1, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRD1, VALVE_STATE_OPEN ); #else setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); #endif @@ -1448,30 +1457,23 @@ // Done with filling, turn off the RO pump signalROPumpHardStop(); - // De-energize all the valves and set the VDr to drain R2 - setValveState( VPI, VALVE_STATE_CLOSED ); + // Set the valves to rinse R2 to R1 and drain R1 #ifndef V_2_SYSTEM - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NC ); -#else - setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); -#endif - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); -#ifndef V_2_SYSTEM setValveState( VRD2, VALVE_STATE_OPEN ); #else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); #endif - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); // Turn on the drain pump to drain R2 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); - stateTimer = getMSTimerCount(); // Set the reservoir status rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; + stateTimer = getMSTimerCount(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -1487,6 +1489,22 @@ return state; } + +/*********************************************************************//** + * @brief + * The handleChemicalDisinfectRinseR1ToR2AndDrainR2State function handles + * the chemical disinfect rinse R1 to R2 and drain R2 state. The state + * rinses reservoir 1 and drains reservoir 2 at the same time. If the drain + * process times out, it transitions to basic cancellation state, and + * if the rinse times out, it transitions to water cancellation state. + * If the drain and rinse are completed within the define time, it + * transitions to the next state. + * @details Inputs: rsrvr1Status, rsrvr2Status, numberOfPostDisinfectRinses + * @details Outputs: stateTimer, rsrvr1Status, rsrvr2Status, + * prevChemDisinfectState, alarmDetectedPendingTrigger, isThisLastDrain + * numberOfPostDisinfectRinses + * @return next state of the chemical disinfect state machine + *************************************************************************/ static DG_CHEM_DISINFECT_STATE_T handleChemicalDisinfectRinseR1ToR2AndDrainR2State( void ) { DG_CHEM_DISINFECT_STATE_T state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; @@ -1544,14 +1562,27 @@ #else setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); #endif - // Turn on the drain pump to drain R2 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + // If the number of post chemical disinfect rinses have finished, + // transition to drain R1 state. Otherwise, start the next rinse. + if ( ++numberOfPostDisinfectRinses > NUM_OF_POST_DISINFECT_RINSES ) + { + // Set the reservoir status + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + // This is last drain + isThisLastDrain = TRUE; + state = DG_CHEM_DISINFECT_STATE_DRAIN_R1; + } + else + { + // Set the reservoir status + rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; + state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; + } + stateTimer = getMSTimerCount(); - // Set the reservoir status - rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; - state = DG_CHEM_DISINFECT_STATE_RINSE_R1_TO_R2_AND_DRAIN_R2; } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { @@ -1784,7 +1815,8 @@ data.R2FillLevel = R2ChemDisinfectVol; // If the mode is in the actual chemical disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion - if ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState || DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) + if ( ( DG_CHEM_DISINFECT_STATE_DISINFECT_R1_TO_R2 == chemDisinfectState ) || + ( DG_CHEM_DISINFECT_STATE_DISINFECT_R2_TO_R1 == chemDisinfectState ) ) { data.chemDisinfectElapsedTime = calcTimeSince( chemDisinfectTimer ); } @@ -1793,6 +1825,9 @@ data.chemDisinfectElapsedTime = 0; } + data.postDisinfectTargetRinseCount = NUM_OF_POST_DISINFECT_RINSES; + data.postDisinfectCurrentRinseCount = numberOfPostDisinfectRinses; + broadcastChemicalDisinfectData( &data ); dataPublishCounter = 0; Index: firmware/App/Modes/ModeChemicalDisinfect.h =================================================================== diff -u -r86eec09ab556fbd970ddcae9dc622727928ee757 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Modes/ModeChemicalDisinfect.h (.../ModeChemicalDisinfect.h) (revision 86eec09ab556fbd970ddcae9dc622727928ee757) +++ firmware/App/Modes/ModeChemicalDisinfect.h (.../ModeChemicalDisinfect.h) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -34,13 +34,15 @@ /// Chemical disinfect data typedef struct { - U32 chemDisinfectState; ///< Chemical disinfect state. - U32 overallElapsedTime; ///< Overall elapsed time in chemical disinfect mode. - U32 stateElapsedTime; ///< Current chemical disinfect elapsed time. - U32 chemDisinfectElapsedTime; ///< Elapsed time in just chemical disinfecting. - U32 cancellationMode; ///< Chemical disinfect cancellation mode. - F32 R1FillLevel; ///< Reservoir 1 level upon starting the chemical disinfect. - F32 R2FillLevel; ///< Reservoir 2 level upon starting the chemical disinfect. + U32 chemDisinfectState; ///< Chemical disinfect state. + U32 overallElapsedTime; ///< Overall elapsed time in chemical disinfect mode. + U32 stateElapsedTime; ///< Current chemical disinfect elapsed time. + U32 chemDisinfectElapsedTime; ///< Elapsed time in just chemical disinfecting. + U32 cancellationMode; ///< Chemical disinfect cancellation mode. + F32 R1FillLevel; ///< Reservoir 1 level upon starting the chemical disinfect. + F32 R2FillLevel; ///< Reservoir 2 level upon starting the chemical disinfect. + U32 postDisinfectTargetRinseCount; ///< Target post disinfect rinse count. + U32 postDisinfectCurrentRinseCount; ///< Current post disinfect rinse count. }MODE_CHEMICAL_DISINFECT_DATA_T; // ********** public function prototypes ********** Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r379f78f1fad668d741b3ccf1e78c69f3fccc45b5 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 379f78f1fad668d741b3ccf1e78c69f3fccc45b5) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -173,7 +173,9 @@ // when enough water volume has flowed to flush the lines, transition to re-circ state if ( flushLinesVolumeL >= FLUSH_LINES_VOLUME_L ) { +#ifndef SKIP_RECIRC setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); +#endif setROPumpTargetFlowRate( TARGET_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); result = DG_RECIRCULATE_MODE_STATE_RECIRC_WATER; } Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r654c5598765bb862c00a0175bdac95604c6c9b24 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 654c5598765bb862c00a0175bdac95604c6c9b24) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -436,7 +436,7 @@ // If DG is in standby mode and the standby mode is in Idle, request chemical disinfect // Chemical disinfect cannot be run in solo mode because the user has to confirm that the acid is inserted or removed - if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) + //if ( ( DG_MODE_STAN == getCurrentOperationMode() ) && ( DG_STANDBY_MODE_STATE_IDLE == standbyState ) ) TODO un-comment this line. This is commented to be able to run chemical without HD for development { requestNewOperationMode( DG_MODE_CHEM ); status = TRUE; Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -r86eec09ab556fbd970ddcae9dc622727928ee757 -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 86eec09ab556fbd970ddcae9dc622727928ee757) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -162,6 +162,9 @@ SW_FAULT_ID_FILL_MODE_INVALID_EXEC_STATE, SW_FAULT_ID_PRESSURE_INVALID_EXEC_STATE, SW_FAULT_ID_INVALID_NVDATAMGMT_EXEC_CAL_STATE, + SW_FAULT_ID_INVALID_VOLTAGE_MONITOR_STATE, + SW_FAULT_ID_INVALID_MONITORED_VOLTAGE_ID, // 85 + SW_FAULT_ID_INVALID_LOAD_CELL_ID, SW_FAULT_ID_DG_CHEM_DISINFECT_INVALID_EXEC_STATE, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/FPGA.c =================================================================== diff -u -rebbb1f85550a1f9b8f946655f7b2b63f76fbf67d -rc0700a4503f28288f16070634bb87f4eccb2568c --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision ebbb1f85550a1f9b8f946655f7b2b63f76fbf67d) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision c0700a4503f28288f16070634bb87f4eccb2568c) @@ -727,7 +727,7 @@ else { result = SELF_TEST_STATUS_FAILED; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaId ) } return result;