Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r8467f8ff09e382e0991f14d02683080dc811e24e -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 8467f8ff09e382e0991f14d02683080dc811e24e) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -40,12 +40,22 @@ // ********** private definitions ********** +#ifndef V_2_SYSTEM +#define MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE 1.00 ///< Main primary heater (heater A) max duty cycle (100%). +#define SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE 1.00 ///< Small Primary heater (heater B) max duty cycle (100%). +#define TRIMMER_HEATER_MAX_DUTY_CYCLE 1.00 ///< Trimmer heater max duty cycle (100%). +#else #define MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE 0.89 ///< Main primary heater (heater A) max duty cycle (89%). #define SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE 0.50 ///< Small Primary heater (heater B) max duty cycle (50%). #define TRIMMER_HEATER_MAX_DUTY_CYCLE 0.50 ///< Trimmer heater max duty cycle (50%). +#endif #define HEATERS_MIN_DUTY_CYCLE 0.00 ///< Primary and trimmer heaters minimum duty cycle (0.00%). +#define PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ( MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE + \ + SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ) ///< Primary heaters cumulative duty cycle. +#define PRIMARY_HEATER_INITIAL_DUTY_CYCLE_ESTIMATE_DIVISOR 2.0 ///< Primary heaters initial duty cycle estimation divisor. +#define MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR 2.0 ///< Main and small primary heater duty cycle divisor -#define PRIMARY_HEATERS_P_COEFFICIENT 0.02 ///< Primary heaters proportional coefficient. +#define PRIMARY_HEATERS_P_COEFFICIENT 0.15 ///< Primary heaters proportional coefficient. #define PRIMARY_HEATERS_I_COEFFICIENT 0.001 ///< Primary heaters integral coefficient. #define TRIMMER_HEATER_P_COEFFICIENT 0.02 ///< Trimmer heater proportional coefficient. @@ -56,29 +66,14 @@ #define HEATERS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. -#define SMALL_PRIMARY_AND_TRIMMER_HEATERS_POST_TARGET_TEMPERATURE 40U ///< Small primary and trimmer heaters target temperature during POST. -#define MAIN_PRIMARY_HEATER_POST_TARGET_TEMPERATURE 35U ///< Main primary heater target temperature during POST. -#define HEATERS_POST_HEAT_UP_TIME_SECONDS 50U ///< The time that the heaters are heated up to reach to the target temperature during POST. -#define HEATERS_POST_TEMPERATURE_TOLERANCE 1U ///< Tolerance of the sensors to the target temperature during POST. +#define MINIMUM_TARGET_TEMPERATURE 10.0 ///< Minimum allowed target temperature for the heaters. +#define MAXIMUM_TARGET_TEMPERATURE 90.0 ///< Maximum allowed target temperature for the heaters. -#define MINIMUM_TARGET_TEMPERATURE 10U ///< Minimum allowed target temperature for the heaters. -#define MAXIMUM_TARGET_TEMPERATURE 90U ///< Maximum allowed target temperature for the heaters. - #define HEATERS_ON_WITH_NO_FLOW_TIMEOUT_COUNT ( ( 3 * MS_PER_SECOND ) / TASK_PRIORITY_INTERVAL ) ///< Heaters are on but there is no sufficient flow timeout in counts. -#define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C 120.0 ///< Heaters max allowed internal temperature in degrees C. TODO figure out the max temperature value +#define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C 190.0 ///< Heaters max allowed internal temperature in degrees C. TODO figure out the max temperature value #define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heaters max allowed internal temperature timeout in milliseconds. #define HEATERS_ON_NO_FLOW_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heaters on with no flow time out in milliseconds. -/// Heaters self-test enums -typedef enum heaters_self_test_states -{ - HEATERS_SELF_TEST_START = 0, ///< Heaters self-test start state - HEATERS_SELF_TEST_SMALL_PRIMARY_AND_TRIMMER_HEATERS, ///< Heaters self-test small primary and trimmer heaters state - HEATERS_SELF_TEST_MAIN_PRIMARY_HEATER, ///< Heaters self-test start main primary state - HEATERS_SELF_TEST_COMPLETE, ///< Heaters self-test complete state - NUM_OF_HEATERS_SELF_TEST_STATES ///< Number of heaters self-test states -} HEATERS_SELF_TEST_STATES_T ; - /// Primary heaters exec states typedef enum primary_heaters_exec_states { @@ -105,8 +100,6 @@ // ********** private data ********** -static SELF_TEST_STATUS_T heatersSelfTestResult; ///< Heaters self-test results. -static HEATERS_SELF_TEST_STATES_T heatersSelfTestState; ///< Heaters self-test state. static PRIMARY_HEATERS_EXEC_STATES_T primaryHeatersExecState; ///< Primary heaters exec state. static TRIMMER_HEATER_EXEC_STATES_T trimmerHeaterExecState; ///< Trimmer heater exec state. @@ -124,20 +117,19 @@ static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. -static U32 selfTestElapsedTime; ///< Self-test elapsed time variable. static BOOL hasStartPrimaryHeaterRequested; ///< Start primary heater request flag. static BOOL hasStartTrimmerHeaterRequested; ///< Start trimmer heater request flag. static U32 heatersOnWithNoFlowTimer; ///< Heaters are on but there is no sufficient flow. static TEMPERATURE_SENSORS_T primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_PRIMARY_HEATER; ///< Primary heaters feedback temperature sensors. -static TEMPERATURE_SENSORS_T trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; ///< Trimmer heater feedback temperature sensors. +static TEMPERATURE_SENSORS_T trimmerHeaterFeedbackTempSensor = TEMPSENSORS_INLET_DIALYSATE; ///< Trimmer heater feedback temperature sensors. +static U32 primaryHeatersInternalTempOutTimer = 0; ///< Primary heaters internal temperature out of range timer. +static U32 trimmerHeaterInternalTempOutTimer = 0; ///< Trimmer heater internal temperature out of range timer. +static BOOL isPrimaryHeatersTempOutOfRange = FALSE; ///< Boolean flag to indicate if the primary heaters internal temperature out of range. +static BOOL isTrimmerHeaterTempOutOfRange = FALSE; ///< Boolean flag to indicate if the trimmer heater internal temperature out of range. static BOOL isFlowBelowMin = FALSE; ///< Boolean flag to indicate if the flow is below the minimum. // ********** private function prototypes ********** -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestStart( void ); -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestSmallPrimaryAndTrimmerHeaters( void ); -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestMainPrimaryHeater( void ); - static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateOff( void ); static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateControlToTarget( void ); @@ -161,7 +153,6 @@ *************************************************************************/ void initHeaters( void ) { - heatersSelfTestState = HEATERS_SELF_TEST_START; primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_OFF; trimmerHeaterExecState = TRIMMER_HEATER_EXEC_STATE_OFF; primaryHeaterTargetTemperature = 0.0; @@ -171,14 +162,17 @@ dataPublicationTimerCounter = 0; isPrimaryHeaterOn = FALSE; isTrimmerHeaterOn = FALSE; - selfTestElapsedTime = 0; primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_PRIMARY_HEATER; - trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; + trimmerHeaterFeedbackTempSensor = TEMPSENSORS_INLET_DIALYSATE; + primaryHeatersInternalTempOutTimer = 0; + trimmerHeaterInternalTempOutTimer = 0; + isPrimaryHeatersTempOutOfRange = FALSE; + isTrimmerHeaterTempOutOfRange = FALSE; isFlowBelowMin = FALSE; // Initialize the PI controller for the primary heaters initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATERS_P_COEFFICIENT, PRIMARY_HEATERS_I_COEFFICIENT, - HEATERS_MIN_DUTY_CYCLE, MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE + SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ); + HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ); // Initialize the PI controller for the trimmer heater initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, @@ -231,9 +225,7 @@ if ( ( primaryHeaterTargetTemperature >= MINIMUM_TARGET_TEMPERATURE ) && ( primaryHeaterTargetTemperature <= MAXIMUM_TARGET_TEMPERATURE ) ) { -//#ifndef DISABLE_HEATERS_AND_TEMPS hasStartPrimaryHeaterRequested = TRUE; -//#endif status = TRUE; } @@ -254,9 +246,7 @@ if ( ( trimmerHeaterTargetTemperature >= MINIMUM_TARGET_TEMPERATURE ) && ( trimmerHeaterTargetTemperature <= MAXIMUM_TARGET_TEMPERATURE ) ) { -#ifndef DISABLE_HEATERS_AND_TEMPS hasStartTrimmerHeaterRequested = TRUE; -#endif status = TRUE; } @@ -341,7 +331,6 @@ *************************************************************************/ void execHeatersMonitor( void ) { - // TODO check for the heaters' fault flags and fault if any of them are at fault it should alarm #ifndef IGNORE_HEATERS_MONITOR F32 primaryHeatersInternalTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_INTERNAL ); F32 trimmerHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_INTERNAL ); @@ -370,8 +359,11 @@ * If the flow is below minimum for more than the defined time, stop the heaters and raise the alarm * If the flow is in range, reset the variables * This is to make sure that any of the heaters do not stay on while there is no flow + * In the monitor, trimmer heater is only monitored if heat disinfect mode is active. Trimmer heater is usually + * controlled by HD so checking the DG flow rate to decide whether it should be on or off is not appropriate */ - BOOL isHeaterOn = ( TRUE == isPrimaryHeaterOn ) || ( TRUE == isTrimmerHeaterOn ); + BOOL isModeHeat = ( DG_MODE_HEAT == getCurrentOperationMode() ) && ( TRUE == isTrimmerHeaterOn ); + BOOL isHeaterOn = ( TRUE == isPrimaryHeaterOn ) || ( TRUE == isModeHeat ); BOOL isPWMNonZero = ( mainPrimaryHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ) || ( smallPrimaryHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ) || ( trimmerHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ); @@ -409,42 +401,6 @@ /*********************************************************************//** * @brief - * The execHeatersSelfTest function executes the heaters' self-test state machine. - * @details Inputs: heatersSelfTestState - * @details Outputs: heatersSelfTestState - * @return heatersSelfTestState - *************************************************************************/ -SELF_TEST_STATUS_T execHeatersSelfTest( void ) -{ - switch ( heatersSelfTestState ) - { - case HEATERS_SELF_TEST_START: - heatersSelfTestState = handleHeatersSelfTestStart(); - break; - - case HEATERS_SELF_TEST_SMALL_PRIMARY_AND_TRIMMER_HEATERS: - heatersSelfTestState = handleHeatersSelfTestSmallPrimaryAndTrimmerHeaters(); - break; - - case HEATERS_SELF_TEST_MAIN_PRIMARY_HEATER: - heatersSelfTestState = handleHeatersSelfTestMainPrimaryHeater(); - break; - - case HEATERS_SELF_TEST_COMPLETE: - // POST is done. Do nothing - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_SELF_TEST_INVALID_STATE, heatersSelfTestState ); - heatersSelfTestState = HEATERS_SELF_TEST_COMPLETE; - break; - } - - return heatersSelfTestResult; -} - -/*********************************************************************//** - * @brief * The execPrimaryHeaters function executes the primary heaters' state machine. * @details Inputs: primaryHeatersExecState * @details Outputs: primaryHeatersExecState @@ -497,106 +453,6 @@ /*********************************************************************//** * @brief - * The handleHeatersSelfTestStart function starts the small primary and - * the trimmer heaters for self-test. - * @details Inputs: heatersSelfTestResult, selfTestElapsedTime - * @details Outputs: heatersSelfTestResult, selfTestElapsedTime - * @return state (HEATERS_SELF_TEST_STATES_T) - *************************************************************************/ -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestStart( void ) -{ - // Code temporarily disabled since POST is not tested yet - // TODO once POST is tested and implemented, remove #ifndef -#ifndef _VECTORCAST_ - heatersSelfTestResult = SELF_TEST_STATUS_PASSED; - return HEATERS_SELF_TEST_COMPLETE; -#else - heatersSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; - setSmallPrimaryHeaterPWM( SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ); - setTrimmerHeaterPWM( TRIMMER_HEATER_MAX_DUTY_CYCLE ); - selfTestElapsedTime = getMSTimerCount(); - - return HEATERS_SELF_TEST_SMALL_PRIMARY_AND_TRIMMER_HEATERS; -#endif -} - -/*********************************************************************//** - * @brief - * The handleHeatersSelfTestSmallPrimaryAndTrimmerHeaters function checks if - * the time on the small primary and trimmer heaters has elapsed. If time has - * elapsed, it checks the thermocouple temperature shared among the two - * heaters. If they are in range, it sets the main primary heater and transitions - * to the next state. If it fails, it sets an alarm and fails the test. - * @details Inputs: heatersSelfTestResult, selfTestElapsedTime - * @details Outputs: heatersSelfTestResult, selfTestElapsedTime - * @return state (HEATERS_SELF_TEST_STATES_T) - *************************************************************************/ -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestSmallPrimaryAndTrimmerHeaters( void ) -{ - HEATERS_SELF_TEST_STATES_T state = HEATERS_SELF_TEST_SMALL_PRIMARY_AND_TRIMMER_HEATERS; - - if ( TRUE == didTimeout( selfTestElapsedTime, HEATERS_POST_HEAT_UP_TIME_SECONDS ) ) - { - setSmallPrimaryHeaterPWM( 0 ); - setTrimmerHeaterPWM( 0 ); - - F32 convertedTemperature = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_INTERNAL ); - - if ( fabs( convertedTemperature - SMALL_PRIMARY_AND_TRIMMER_HEATERS_POST_TARGET_TEMPERATURE ) > HEATERS_POST_TEMPERATURE_TOLERANCE ) - { - heatersSelfTestResult = SELF_TEST_STATUS_FAILED; - state = HEATERS_SELF_TEST_COMPLETE; - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_HEATERS_SELF_TEST_FAILURE, TEMPSENSORS_TRIMMER_HEATER_INTERNAL, convertedTemperature ) - } - else - { - setMainPrimaryHeaterPWM( MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ); - selfTestElapsedTime = getMSTimerCount(); - state = HEATERS_SELF_TEST_MAIN_PRIMARY_HEATER; - } - } - - return state; -} - -/*********************************************************************//** - * @brief - * The handleHeatersSelfTestMainPrimaryHeater function checks if the time - * on the main primary heater has elapsed. When the time has elapsed, it - * checks to ensure the thermocouple temperature is within the tolerance - * of the target temperature. It then transitions to the complete state. - * @details Inputs: heatersSelfTestResult - * @details Outputs: heatersSelfTestResult - * @return state (HEATERS_SELF_TEST_STATES_T) - *************************************************************************/ -static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestMainPrimaryHeater( void ) -{ - HEATERS_SELF_TEST_STATES_T state = HEATERS_SELF_TEST_MAIN_PRIMARY_HEATER; - - if ( TRUE == didTimeout( selfTestElapsedTime, HEATERS_POST_HEAT_UP_TIME_SECONDS ) ) - { - setMainPrimaryHeaterPWM( 0 ); - - F32 convertedTemperature = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_INTERNAL ); - - if ( fabs( convertedTemperature - MAIN_PRIMARY_HEATER_POST_TARGET_TEMPERATURE ) > HEATERS_POST_TEMPERATURE_TOLERANCE ) - { - heatersSelfTestResult = SELF_TEST_STATUS_FAILED; - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_HEATERS_SELF_TEST_FAILURE, TEMPSENSORS_PRIMARY_HEATER_INTERNAL, convertedTemperature ) - } - else - { - heatersSelfTestResult = SELF_TEST_STATUS_PASSED; - } - - state = HEATERS_SELF_TEST_COMPLETE; - } - - return state; -} - -/*********************************************************************//** - * @brief * The handlePrimaryHeaterStateOff function handles the primary heaters at * off state. * @details Inputs: hasStartPrimaryHeaterRequested, isPrimaryHeaterOn @@ -610,16 +466,24 @@ if ( TRUE == hasStartPrimaryHeaterRequested ) { resetHeaterState( PRIMARY_HEATER ); + // Once the primary heaters duty cycle is set, it is divided into 2 + // so both heaters will start and both elements are heated up setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); + setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); isPrimaryHeaterOn = TRUE; hasStartPrimaryHeaterRequested = FALSE; // Check if the operation mode is heat disinfect. If the mode is // heat disinfect, the feedback sensor will be Thd if ( DG_MODE_HEAT == getCurrentOperationMode() ) { +#ifdef THD_USING_TRO_CONNECTOR // Set the feedback temperature sensor - primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; //TODO change this to Thd sensors once it is installed + // THd uses TRo in V3 + primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; +#else + primaryHeatersFeedbackTempSensor = TEMPSENSORS_HEAT_DISINFECT; +#endif } state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; @@ -649,25 +513,25 @@ // If the flow is within range, run the PI controller to control the heaters normally if ( FALSE == isFlowBelowMin ) { - F32 outletTemp = getTemperatureValue( primaryHeatersFeedbackTempSensor ); - mainPrimaryHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); - - if ( mainPrimaryHeaterDutyCycle >= MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ) + // If the primary heater is running and another start primary heater request + // is set, reset the primary heater again + if ( TRUE == hasStartPrimaryHeaterRequested ) { - // The duty cycle from the PI controller was greater than max duty cycle of the main primary - // heater. So subtract the remaining from the max main primary heater duty cycle and set - // the rest to the small primary heater - smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle - MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; - mainPrimaryHeaterDutyCycle = MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; - setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); - setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + resetHeaterState( PRIMARY_HEATER ); + hasStartPrimaryHeaterRequested = FALSE; } else { - setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); - smallPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; - setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + F32 outletTemp = getTemperatureValue( primaryHeatersFeedbackTempSensor ); + mainPrimaryHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); + + // Once the primary heaters duty cycle is set, it is divided into 2 so both heaters will start and both elements are heated up + smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; + mainPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; } + + setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); + setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); } // Flow is below the minimum required flow to run the primary heaters else @@ -679,7 +543,7 @@ primaryHeaterTimerCounter = 0; } - if ( isPrimaryHeaterOn != TRUE ) + if ( FALSE == isPrimaryHeaterOn ) { // Switch to off state. Set the duty cycles to 0 mainPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; @@ -708,15 +572,6 @@ isTrimmerHeaterOn = TRUE; hasStartTrimmerHeaterRequested = FALSE; setTrimmerHeaterPWM( trimmerHeaterDutyCycle ); - - // Check if the operation mode is heat disinfect. If the mode is - // heat disinfect, the feedback sensor will be Thd - if ( DG_MODE_HEAT == getCurrentOperationMode() ) - { - // Set the feedback temperature sensor - trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; //TODO change this to Thd sensors once it is installed - } - state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; } @@ -755,7 +610,7 @@ trimmerHeaterTimerCounter = 0; } - if ( isTrimmerHeaterOn != TRUE ) + if ( FALSE == isTrimmerHeaterOn ) { // Set the duty cycle to 0 and switch to off state trimmerHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; @@ -816,8 +671,31 @@ { if ( PRIMARY_HEATER == heater ) { - mainPrimaryHeaterDutyCycle = MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; - resetPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ); + // Calculate the delta temperature from the inlet primary heater to target temperature + F32 inletPrimaryHeaterTemp = getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ); + F32 deltaTemp = primaryHeaterTargetTemperature - inletPrimaryHeaterTemp; + + // If the delta temperature (target temperature - inlet primary heater temperature) + // Is 0 or negative, the duty cycle is 0.0 + if ( deltaTemp <= 0.0 ) + { + mainPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; + smallPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; + } + else + { + // The formula for the initial guess is: (delta temperature * target flow) / 2.0 + F32 targetFlow = getTargetROPumpFlowRate(); + F32 duty = ( targetFlow * deltaTemp ) / PRIMARY_HEATER_INITIAL_DUTY_CYCLE_ESTIMATE_DIVISOR; + // If the duty cycle is greater 200% on the primary and small primary heaters, set it to 200%, otherwise set it to the + // estimated duty cycles + duty = ( duty > PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ? PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE : duty ); + mainPrimaryHeaterDutyCycle = duty / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; + smallPrimaryHeaterDutyCycle = duty / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; + } + + // The PI controller of the primary heater consists of main and small primary heaters duty cycles + resetPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, mainPrimaryHeaterDutyCycle + smallPrimaryHeaterDutyCycle ); } else if ( TRIMMER_HEATER == heater ) { Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -r5a36a768d11cc597a36b894c1fb3a5e5590130f1 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 5a36a768d11cc597a36b894c1fb3a5e5590130f1) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -34,32 +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); +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 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. -#define LOAD_CELL_ADC_ERROR_PERSISTENCE 500 ///< Alarm persistence period (in ms) for load cell ADC errors. - /// 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. + 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. + 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. - 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. + F64 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 ********** @@ -197,13 +198,14 @@ 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 ]; loadcells[ ii ].smallFilterReadings[ smallReadingsIdx ] = getLoadCellWeight( (LOAD_CELL_ID_T)ii ); loadcells[ ii ].smallFilterTotal += getLoadCellWeight( (LOAD_CELL_ID_T)ii ); - loadcells[ ii ].smallFilteredWeight = loadcells[ ii ].smallFilterTotal / (F32)SIZE_OF_SMALL_LOAD_CELL_AVG; + loadcells[ ii ].smallFilteredWeight = (F32)( loadcells[ ii ].smallFilterTotal / (F64)SIZE_OF_SMALL_LOAD_CELL_AVG ); } smallReadingsIdx = INC_WRAP( smallReadingsIdx, 0, SIZE_OF_SMALL_LOAD_CELL_AVG - 1 ); @@ -217,7 +219,7 @@ loadcells[ ii ].largeFilterTotal -= loadcells[ ii ].largeFilterReadings[ largeReadingsIdx ]; loadcells[ ii ].largeFilterReadings[ largeReadingsIdx ] = loadcells[ ii ].smallFilteredWeight; loadcells[ ii ].largeFilterTotal += loadcells[ ii ].smallFilteredWeight; - loadcells[ ii ].largeFilteredWeight = loadcells[ ii ].largeFilterTotal / (F32)SIZE_OF_LARGE_LOAD_CELL_AVG; + loadcells[ ii ].largeFilteredWeight = (F32)( loadcells[ ii ].largeFilterTotal / (F64)SIZE_OF_LARGE_LOAD_CELL_AVG ); } loadCellFilterTimerCount = 0; @@ -274,8 +276,32 @@ *************************************************************************/ 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 ); + BOOL isWeightOutOfRange = FALSE; + + F32 weight = getLoadCellSmallFilteredWeight( loadCellID ); + + // Check if the load cell is being tared for the first time + if ( fabs(loadcells[ loadCellID ].autoCalOffset) < NEARLY_ZERO ) + { + // 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 + F32 deltaWeight = fabs( weight - EMPTY_RESERVOIR_WEIGHT_GRAMS ); + isWeightOutOfRange = ( deltaWeight > MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS ? TRUE : FALSE ); + } + else + { + isWeightOutOfRange = ( fabs(weight) > 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 ) + } } /*********************************************************************//** Index: firmware/App/Controllers/UVReactors.c =================================================================== diff -u -ra8bb1da29825b5d666333629fda871652d16229a -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Controllers/UVReactors.c (.../UVReactors.c) (revision a8bb1da29825b5d666333629fda871652d16229a) +++ firmware/App/Controllers/UVReactors.c (.../UVReactors.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -19,7 +19,7 @@ #define INLET_UV_REACTOR_ENABLE_PIN 0 ///< Inlet UV reactor GPIO pin number (enable pin). #define OUTLET_UV_REACTOR_ENABLE_PIN 1 ///< Outlet UV reactor GPIO pin number (enable Pin). -#define INLET_UV_REACTOR_INDICATION_PIN 0x1A ///< Inlet UV reactor N2HET1 pin number (health check). +#define INLET_UV_REACTOR_INDICATION_PIN 0x18 ///< Inlet UV reactor N2HET1 pin number (health check). #define OUTLET_UV_REACTOR_INDICATION_PIN 0x0B ///< Outlet UV reactor N2HET1 pin number (health check). #define UV_REACTORS_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< UV reactors data publication time interval. /// Self test wait time after enabling the reactors and before checking for their health in ms. @@ -75,7 +75,7 @@ static UV_REACTOR_STATE_T handleUVReactorStateOn( UV_REACTORS_T reactor ); // Support functions -static BOOL isReactorHealthy( UV_REACTORS_T reactor ); +static U32 getReactorHealth( UV_REACTORS_T reactor ); static void setReactorEnableStatus( UV_REACTORS_T reactor, PIN_SIGNAL_STATE_T state ); static void publishUVReactorsData( void ); static U32 getPublishUVReactorsDataInterval( void ); @@ -93,7 +93,7 @@ { UV_REACTORS_T reactor; - uvReactorsSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; + uvReactorsSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; uvReactorsSelfTestStates = UV_REACTORS_SELF_TEST_OFF; dataPublishCounter = 0; @@ -108,9 +108,9 @@ // Initialize the common values in the UV reactors for( reactor = INLET_UV_REACTOR; reactor < NUM_OF_UV_REACTORS; reactor++ ) { - reactorsStatus[ reactor ].pinSignalState = PIN_SIGNAL_LOW; - reactorsStatus[ reactor ].execState = UV_REACTOR_STATE_OFF; - reactorsStatus[ reactor ].switchState = TURN_OFF; + reactorsStatus[ reactor ].pinSignalState = PIN_SIGNAL_LOW; + reactorsStatus[ reactor ].execState = UV_REACTOR_STATE_OFF; + reactorsStatus[ reactor ].switchState = TURN_OFF; } initPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); @@ -186,27 +186,28 @@ /*********************************************************************//** * @brief - * The getUVReactorHealth function returns the health status of a UV reactor. + * The getUVReactorHealth function returns the health status of a UV + * reactor. * @details Inputs: reactorsStatus * @details Outputs: none * @param reactor to return its health - * @return returns the health of the requested UV reactor + * @return returns the health of the requested UV reactor as an enum *************************************************************************/ -BOOL getUVReactorHealth( UV_REACTORS_T reactor ) +UV_REACTORS_HEALTH_STATUS_T getUVReactorHealth( UV_REACTORS_T reactor ) { - BOOL health = FALSE; + UV_REACTORS_HEALTH_STATUS_T health = UV_REACTOR_OFF; // Check if the reactor selected is in range if ( reactor < NUM_OF_UV_REACTORS ) { // Check if the health is in override or not if ( reactorsStatus[ reactor ].healthStatus.override == OVERRIDE_KEY ) { - health = reactorsStatus[ reactor ].healthStatus.ovData; + health = (UV_REACTORS_HEALTH_STATUS_T)reactorsStatus[ reactor ].healthStatus.ovData; } else { - health = reactorsStatus[ reactor ].healthStatus.data; + health = (UV_REACTORS_HEALTH_STATUS_T)reactorsStatus[ reactor ].healthStatus.data; } } else @@ -306,11 +307,11 @@ if ( TRUE == didTimeout( selfTestElapsedTime, SELF_TEST_DELAY_TIME ) ) { // Get the health status of the reactors - BOOL isInletHealthy = isReactorHealthy( INLET_UV_REACTOR ); - BOOL isOutletHealthy = isReactorHealthy( OUTLET_UV_REACTOR ); + BOOL isInletHealthy = (BOOL)getReactorHealth( INLET_UV_REACTOR ); + BOOL isOutletHealthy = (BOOL)getReactorHealth( OUTLET_UV_REACTOR ); // Check if both of them are healthy and if not, raise an alarm - if ( TRUE == isInletHealthy && TRUE == isOutletHealthy ) + if ( ( TRUE == isInletHealthy ) &&( TRUE == isOutletHealthy ) ) { uvReactorsSelfTestResult = SELF_TEST_STATUS_PASSED; } @@ -351,6 +352,10 @@ { UV_REACTOR_STATE_T state = UV_REACTOR_STATE_OFF; + // Set the health status to be off. When the reactor is off, it does not report + // its health status + reactorsStatus[reactor].healthStatus.data = (U32)UV_REACTOR_OFF; + // If the a reactor is requested to be on and it is off, turn it on // and change the state if ( TURN_ON == reactorsStatus[ reactor ].switchState ) @@ -375,11 +380,13 @@ { UV_REACTOR_STATE_T state = UV_REACTOR_STATE_ON; - reactorsStatus[ reactor ].healthStatus.data = (U32)isReactorHealthy( reactor ); + // Update the UV reactor's health. It should be either healthy (1) or not healthy (0) + reactorsStatus[ reactor ].healthStatus.data = getReactorHealth( reactor ); - BOOL isReactorHealthy = getUVReactorHealth( reactor ); + // Get the health of the reactor (override or non-override) and decide the status + BOOL isReactorUnhealthy = ( UV_REACTOR_HEALTHY == getUVReactorHealth( reactor ) ? FALSE : TRUE ); - checkPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, !isReactorHealthy, (U32)reactor, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); + checkPersistentAlarm( ALARM_ID_UV_REACTOR_NOT_HEALTHY, isReactorUnhealthy, (U32)reactor, MAX_ALLOWED_UNHEALTHY_REACTOR_PERIOD ); // Check if the alarm has been active if ( TRUE == isAlarmActive( ALARM_ID_UV_REACTOR_NOT_HEALTHY ) ) @@ -411,23 +418,23 @@ static void setReactorEnableStatus( UV_REACTORS_T reactor, PIN_SIGNAL_STATE_T state ) { // Set the GIO pin to enable or disable - gioSetBit( gioPORTA, reactorsStatus[ reactor ].reactorEnablePin, state ); + gioSetBit( gioPORTA, reactorsStatus[ reactor ].reactorEnablePin, (U32)state ); // Update the pin signal state reactorsStatus[ reactor ].pinSignalState = state; } /*********************************************************************//** * @brief - * The isReactorHealthy function checks the health status of a reactor. + * The getReactorHealth function checks the health status of a reactor. * @details Inputs: reactorsStatus * @details Outputs: none * @param reactor to check its health - * @return returns TRUE if the reactor is healthy otherwise a FALSE + * @return returns 1 if the reactor is healthy otherwise a 0 *************************************************************************/ -static BOOL isReactorHealthy( UV_REACTORS_T reactor ) +static U32 getReactorHealth( UV_REACTORS_T reactor ) { - return (BOOL)gioGetBit( hetPORT1, reactorsStatus[ reactor ].reactorHealthStatusPin ); + return gioGetBit( hetPORT1, reactorsStatus[ reactor ].reactorHealthStatusPin ); } /*********************************************************************//** @@ -462,17 +469,18 @@ { UV_REACTORS_DATA_T uvReactorsData; // Publish the reactors health status - uvReactorsData.inletUVReactorHealthStatus = reactorsStatus[ INLET_UV_REACTOR ].reactorHealthStatusPin; - uvReactorsData.outletUVReactorHealthStatus = reactorsStatus[ OUTLET_UV_REACTOR ].reactorHealthStatusPin; - uvReactorsData.inletUVReactorState = reactorsStatus[ INLET_UV_REACTOR ].execState; - uvReactorsData.outletUVReactorHealthStatus = reactorsStatus[ OUTLET_UV_REACTOR ].execState; + uvReactorsData.inletUVReactorHealthStatus = (U32)getUVReactorHealth( INLET_UV_REACTOR ); + uvReactorsData.outletUVReactorHealthStatus = (U32)getUVReactorHealth( OUTLET_UV_REACTOR ); + uvReactorsData.inletUVReactorState = (U32)reactorsStatus[ INLET_UV_REACTOR ].execState; + uvReactorsData.outletUVReactorState = (U32)reactorsStatus[ OUTLET_UV_REACTOR ].execState; broadcastUVReactorsData( &uvReactorsData ); dataPublishCounter = 0; } } + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -535,15 +543,15 @@ * @param health which is high for healthy on and low for not healthy * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetUVReactorHealthOverride( U32 reactor, BOOL health ) +BOOL testSetUVReactorHealthOverride( U32 reactor, U32 health ) { BOOL result = FALSE; - if ( TRUE == isTestingActivated() && (UV_REACTORS_T)reactor < NUM_OF_UV_REACTORS ) + if ( ( TRUE == isTestingActivated() ) && ( (UV_REACTORS_T)reactor < NUM_OF_UV_REACTORS ) ) { reactorsStatus[ (UV_REACTORS_T)reactor ].healthStatus.ovInitData = reactorsStatus[ (UV_REACTORS_T)reactor ].healthStatus.data; reactorsStatus[ (UV_REACTORS_T)reactor ].healthStatus.override = OVERRIDE_KEY; - reactorsStatus[ (UV_REACTORS_T)reactor ].healthStatus.ovData = (U32)health; + reactorsStatus[ (UV_REACTORS_T)reactor ].healthStatus.ovData = health; result = TRUE; } Index: firmware/App/DGCommon.h =================================================================== diff -u -r5a36a768d11cc597a36b894c1fb3a5e5590130f1 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 5a36a768d11cc597a36b894c1fb3a5e5590130f1) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -46,14 +46,18 @@ // #define HEATERS_DEBUG 1 // #define PRESSURES_DEBUG 1 #define DISABLE_DIALYSATE_CHECK 1 - #define IGNORE_DRAIN_PUMP_MONITOR 1 - #define IGNORE_HEATERS_MONITOR 1 +// #define IGNORE_DRAIN_PUMP_MONITOR 1 +// #define IGNORE_HEATERS_MONITOR 1 #define IGNORE_RO_PUMP_MONITOR 1 - #define IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT 1 // #define DISABLE_RO_RATIO_CHECK 1 #define DISABLE_COND_SENSOR_CHECK 1 #define DISABLE_MIXING 1 // #define DISABLE_WATER_QUALITY_CHECK 1 + #define DISABLE_RTC_CONFIG 1 + //#define V_2_SYSTEM 1 + //#define SKIP_RECIRC 1 + #define THD_USING_TRO_CONNECTOR 1 + #define IGNORE_CONC_PUMP_IN_HEAT_DISINFECT 1 #include #include #endif Index: firmware/App/Modes/ModeFault.c =================================================================== diff -u -r1a5efe97f5f39594b45797fded52cafce92afe80 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 1a5efe97f5f39594b45797fded52cafce92afe80) +++ firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -59,6 +59,8 @@ *************************************************************************/ void transitionToFaultMode( void ) { + deenergizeActuators(); + // Publish POST failure status to UI if fault triggered in Init/POST mode if ( DG_MODE_INIT == getPreviousOperationMode() ) { Index: firmware/App/Modes/ModeFlush.c =================================================================== diff -u -r654c5598765bb862c00a0175bdac95604c6c9b24 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 654c5598765bb862c00a0175bdac95604c6c9b24) +++ firmware/App/Modes/ModeFlush.c (.../ModeFlush.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -642,7 +642,7 @@ } } // Once reservoir 2 is full, reservoir 1 must be partially full - else if( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_PARTIAL_FILL_TIMEOUT_MS ); @@ -669,7 +669,7 @@ } } // Check if reservoir 2 fill time out - else if( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) + else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { state = DG_FLUSH_STATE_CANCEL_WATER_PATH; } Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r5a36a768d11cc597a36b894c1fb3a5e5590130f1 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 5a36a768d11cc597a36b894c1fb3a5e5590130f1) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -15,6 +15,7 @@ * ***************************************************************************/ +#include "ConcentratePumps.h" #include "ConductivitySensors.h" #include "DrainPump.h" #include "Heaters.h" @@ -40,107 +41,118 @@ // ********** private definitions ********** // General defines -#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. -#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode Heat Disinfect data publish interval in counts. +#define MAX_ALLOWED_STATE_TRIALS 1 ///< Max allowed trials on a state. This is general among all the states. +#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Mode heat disinfect data publish interval in counts. // Start state defines -#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. -#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 1.0 ///< Max start state TDi and TRo difference tolerance in C. +#define MIN_INLET_PRESSURE_PSI 30.0 ///< Minimum water inlet pressure in psi. +#define MAX_START_STATE_TEMP_SENSORS_DIFF_C 3.0 ///< Max start state TDi and TRo difference tolerance in C. // Drain R1 & R2 states defines -#define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. -#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 2* SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. -#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. +#define DRAIN_PUMP_TARGET_RPM 2200 ///< Drain pump target RPM during drain. +#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 6 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // Flush drain path state defines -#define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. TODo original time was 60 seconds -#define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C -#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm +#define FLUSH_DRAIN_WAIT_TIME_MS ( SEC_PER_MIN * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +#define MIN_INLET_TEMPERATURE_C 15.0 ///< Minimum water inlet temperature in C. TODO original temperature was 25 C +#define MAX_INLET_CONDUCTIVITY_US_PER_CM 2000.0 ///< Maximum water inlet conductivity in us/cm // Flush circulation path state defines -#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. TODO original flow was 0.8 -#define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. -#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds -#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 50.0 ///< Maximum flush circulation temperature difference tolerance in C. TODO original difference was 3.0 degrees -#define NUM_OF_TEMP_SENSORS_TO_AVG 4.0 ///< Number of temperature sensors to average to check the difference. +#define RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM 0.8 ///< RO pump target flow rate during flush/fill in L/min. +#define MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI 130 ///< Maximum RO pump pressure during flush/fill states in psi. +#define FLUSH_CICRCULATION_WAIT_TIME_MS ( 30 * MS_PER_SECOND ) ///< Flush/rinse circulation path wait time in milliseconds. TODO original time was 30 seconds +#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 50.0 ///< Maximum flush circulation temperature difference tolerance in C. TODO original difference was 3.0 degrees +#define NUM_OF_TEMP_SENSORS_TO_AVG 4.0 ///< Number of temperature sensors to average to check the difference. +#define CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN -30.0 ///< Concentrate pumps reverse speed in mL/min. // Flush and drain R1 and R2 -#define RSRVRS_FULL_VOL_ML 1680.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 -#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. -#define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. -#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. TODO original value was 5 mins -#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. -#define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. +#define RSRVRS_FULL_VOL_ML 1750.0 ///< Reservoirs 1 & 2 full volume in mL. TODo original value was 1900 +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. +#define RSRVRS_FULL_STABLE_TIME_COUNT ( ( 4 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Reservoirs 1 & 2 full stable time in counts. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. TODO original value was 5 mins +#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. // Fill and heat water -#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 85.0 ///< Heat disinfect target water temperature in C. TODO original temperature was 85.0 -#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. TODO original temperature was 81.0 +#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 83.0 ///< Heat disinfect target water temperature in C. +#define HEAT_DISINFECT_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. // R1 to R2 & R2 to R1 heat disinfect circulation -#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 0.9 ///< Heat disinfect target RO flow rate in L/min. TODO original value was 0.8 -#define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. -#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 10.0 ///< Heat disinfect target drain outlet pressure in psi. -#define HEAT_DISINFECT_TIME_MS ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. TODO original time was 10 minutes -#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. TODO figure out this timeout +#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 1.3 ///< Heat disinfect target RO flow rate in L/min. +#define HEAT_DISINFECT_MAX_RO_PRESSURE_PSI 30 ///< Heat disinfect maximum RO pressure in psi. +#define HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI 12.0 ///< Heat disinfect target drain outlet pressure in psi. +#define HEAT_DISINFECT_TIME_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. +#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 4 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. #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 heat 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 heat disinfect. TODO original value is 100 mL +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 600.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. TODO original value is 100 mL #define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. +// Cool down RO filter +#define THD_REACH_BELOW_45_AFTER_CIRC_TIME_MS ( 5 * MS_PER_SECOND ) ///< Number of circulations that are needed to make the RO filter is below 45 C. +#define ROF_COOL_DOWN_TARGET_FLOW_LPM 0.3 ///< RO filter cool down target flow in L/min. +#define ROF_COOL_DOWN_CIRCULATION_TIME_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< RO filter cool down circulation timer in milliseconds. +#define TARGET_THD_SENSOR_FOR_RINSING_C 44.0 ///< Target THd temperature sensor value before rinsing in C. + // Mix drain R1 and R2 #define RSRVRS_MIX_DRAIN_TIMEOUT_MS ( 20 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoirs 1 & 2 mix drain timeout in ms. #define DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ( 5 * MS_PER_SECOND ) ///< Time to start the drain pump at mix drain after directing the flow to drain in ms. -#define DRAIN_PUMP_RPM_IN_MIX_DRAIN 600 ///< The RPM that the drain pump should be run during mix drain. +#define DRAIN_PUMP_RPM_IN_MIX_DRAIN 600 ///< The RPM that the drain pump should be run during mix drain. #define MIX_DRAIN_WEIGHT_UNCHANGE_TIMEOUT ( 15 * MS_PER_SECOND ) ///< Time period of unchanged weight during mix draining before timeout. // Rinse R1 to R2 -#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. TODO the actual value is 45.0 +#define ROF_MIN_LOW_PRESSURE_TEMPERATURE_C 45.0 ///< RO filter minimum temperature that the pressure must be no more than 30psi in C. -// Cancellation paths -#define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0 ///< Temperature threshold for performing mix drain or normal drain. +#define MIX_DRAIN_TEMPERATURE_THRESHOLD_C 60.0 ///< Temperature threshold for performing mix drain or normal drain. /// Cancellation paths typedef enum Cancellation_modes { - CANCELLATION_MODE_NONE = 0, ///< Cancellation mode none. - CANCELLATION_MODE_BASIC, ///< Cancellation mode basic. - CANCELLATION_MODE_HOT, ///< Cancellation mode hot. - CANCELLATION_MODE_COLD, ///< Cancellation mode cold. - NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. -} CANCELLATION_MODES_T; + CANCELLATION_MODE_NONE = 0, ///< Cancellation mode none. + CANCELLATION_MODE_BASIC, ///< Cancellation mode basic. + CANCELLATION_MODE_HOT, ///< Cancellation mode hot. + CANCELLATION_MODE_COLD, ///< Cancellation mode cold. + NUM_OF_CANCELLATION_MODES ///< Number of cancellation modes. +} CANCELLATION_MODE_T; /// Heat disinfect status typedef enum Heat_disinfect_status { - HEAT_DISINFECT_IN_PROGRESS = 0, ///< Heat disinfect in progress. - HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT, ///< Heat disinfect reservoirs leak timeout. - HEAT_DISINFECT_HEAT_UP_TIMEOUT, ///< Heat disinfect heat up timeout. - HEAT_DISINFECT_COMPLETE, ///< Heat disinfect complete. - NUM_OF_HEAT_DISINFECT_STATUS ///< Number of heat disinfect status. + HEAT_DISINFECT_IN_PROGRESS = 0, ///< Heat disinfect in progress. + HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT, ///< Heat disinfect reservoirs leak timeout. + HEAT_DISINFECT_HEAT_UP_TIMEOUT, ///< Heat disinfect heat up timeout. + HEAT_DISINFECT_COMPLETE, ///< Heat disinfect complete. + NUM_OF_HEAT_DISINFECT_STATUS ///< Number of heat disinfect status. } HEAT_DISINFECT_STATUS_T; // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Current active heat disinfect state. -static DG_HEAT_DISINFECT_STATE_T prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Previous active heat disinfect state before alarm. -static U32 overallHeatDisinfectTimer = 0; ///< Heat disinfect cycle total timer. -static U32 stateTimer = 0; ///< Heat disinfect state timer to be used in different states. -static U32 stateTrialCounter = 0; ///< Heat disinfect state trial counter to be used for retries in different states. -static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Current active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T prevHeatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Previous active heat disinfect state before alarm. +static DG_HEAT_DISINFECT_UI_STATE_T heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_NOT_RUNNING; ///< Current active heat disinfect UI state. +static U32 overallHeatDisinfectTimer = 0; ///< Heat disinfect cycle total timer. +static U32 stateTimer = 0; ///< Heat disinfect state timer to be used in different states. +static U32 stateTrialCounter = 0; ///< Heat disinfect state trial counter to be used for retries in different states. +static BOOL areTempSensorsInRange = FALSE; ///< Heat disinfect temperature sensors in/out range flag. +static U32 concentratePumpsPrimeTimer = 0; ///< Concentrate pumps prime timer. /// Boolean flag to check whether draining R1 and R2 is at the end of the heat disinfect cycle or in the beginning. So the drain states can be reused. static BOOL isThisLastDrain = FALSE; -static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. -static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. -static F32 R1HeatDisinfectVol = 0.0; ///< Reservoir 1 full volume during heat disinfect. -static F32 R2HeatDisinfectVol = 0.0; ///< Reservoir 2 full volume during heat disinfect. -static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. -static BOOL isPartialDisinfectInProgress = FALSE; ///< Heat disinfect partial complete/in progess flag. -static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. -static BOOL areRsrvrsLeaking = FALSE; ///< Reservoir 1 & 2 leak check flag during heat disinfect. -static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. -static CANCELLATION_MODES_T cancellationMode = CANCELLATION_MODE_NONE; ///< Cancellation mode. -static U32 rsrvrFillStableTimeCounter = 0; ///< Reservoirs fill stable time counter. -static ALARM_ID_T alarmDetectedPendingTrigger; ///< Heat disinfect alarm to raise. -static BOOL isDrainPumpInMixDrainOn = FALSE; ///< Flag to show the drain pump is on during mix drain. +static DG_RESERVOIR_STATUS_T rsrvr1Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 1 status. +static DG_RESERVOIR_STATUS_T rsrvr2Status = NUM_OF_DG_RESERVOIR_STATUS; ///< Reservoir 2 status. +static F32 R1HeatDisinfectVol = 0.0; ///< Reservoir 1 full volume during heat disinfect. +static F32 R2HeatDisinfectVol = 0.0; ///< Reservoir 2 full volume during heat disinfect. +static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. +static BOOL isPartialDisinfectInProgress = FALSE; ///< Heat disinfect partial complete/in progess flag. +static U32 rsrvrsVolMonitorTimer = 0; ///< Reservoir 1 & 2 volume monitor timers during heat disinfect. +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 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. // ********** private function prototypes ********** @@ -182,14 +194,17 @@ * @details Outputs: heatDisinfectState, stateTimer, isThisLastDrain, * stateTrialCounter, areTempSensorsInRange, rsrvr1Status, rsrvr2Status, * R1HeatDisinfectVol, R2HeatDisinfectVol, overallHeatDisinfectTimer, - * cancellationMode, rsrvrFillStableTimeCounter, isPartialDisinfectInProgress, - * isDrainPumpOnInMixDrain + * cancellationMode, rsrvrFillStableTimeCounter, prevHeatDisinfectState + * isPartialDisinfectInProgress, isDrainPumpOnInMixDrain, + * hasROFCirculationBeenStarted, ROFCirculationTimer, + * ROFCirculationCoolingCounter, concentratePumpsPrimeTimer * @return none *************************************************************************/ 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; @@ -203,6 +218,10 @@ rsrvrFillStableTimeCounter = 0; isPartialDisinfectInProgress = FALSE; isDrainPumpInMixDrainOn = FALSE; + ROFCirculationTimer = 0; + ROFCoolingTimer = 0; + hasROFCirculationBeenStarted = FALSE; + concentratePumpsPrimeTimer = 0; } /*********************************************************************//** @@ -403,10 +422,10 @@ resetReservoirsLowestWeight(); F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); - F32 TDiTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODo change to TDi + F32 TDiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - // If the inlet pressure is less than the threshold and TDi and TRo difference is greater than 1 C, the cycle + // If the inlet pressure is less than the threshold and 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 ) ) { @@ -416,6 +435,9 @@ } else { + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_FLUSH_BEFORE_DISINFECT; + // Close VPi to prevent wasting water setValveState( VPI, VALVE_STATE_CLOSED ); // Request a tare for reservoir 1 @@ -490,6 +512,7 @@ rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // Request a tare for reservoir 2 tareReservoir(); + #ifndef V_2_SYSTEM // Done with draining R1, close it setValveState( VRD1, VALVE_STATE_CLOSED ); @@ -551,6 +574,7 @@ else { signalDrainPumpHardStop(); + #ifndef V_2_SYSTEM // Done with draining R2, close it setValveState( VRD2, VALVE_STATE_CLOSED ); @@ -574,7 +598,7 @@ * @brief * The handleHeatDisinfectFlushDrainState function handles the heat disinfect * flush drain state. The state flushes the drain line for a period of time - * and then measure the temperature and conductivity of water. If they are + * and then measures the temperature and conductivity of water. If they are * not within the range, it transitions to basic cancellation path, otherwise * it transitions to the next state. * @details Inputs: stateTimer, stateTrialCounter, alarm, @@ -640,9 +664,9 @@ DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; // Check if the flush circulation time has elapsed and the temperature sensors are not in range yet - if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && ( FALSE == areTempSensorsInRange ) ) + if ( ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) && ( FALSE == areTempSensorsInRange ) ) { - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // TODO add THd later. This is the new temp sensor of the coldest spot. + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); F32 TD1Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_1 ); F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); @@ -674,21 +698,31 @@ else { areTempSensorsInRange = TRUE; - stateTimer = getMSTimerCount(); - // TODO Turn on the concentrate pumps and wait for 30 seconds +#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + + // Turn on the concentrate pumps + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); +#endif + concentratePumpsPrimeTimer = getMSTimerCount(); } } // Only start the concentrate pumps if the temperature sensors are in range if ( TRUE == areTempSensorsInRange ) { - // TODO: enable the timeout once the concentrate pumps are available. - //if ( TRUE == didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) - if ( TRUE ) + if ( TRUE == didTimeout( concentratePumpsPrimeTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) { rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; + // Done with priming the concentrate pumps line + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); @@ -721,7 +755,7 @@ { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); - // Keep monitoring the status of reservoir 2 as the same time + // 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 ); // 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 @@ -964,7 +998,7 @@ // Turn on the RO pump setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); - // Start heating the water while we are filling up the rsrvrs + // Start heating the water while we are filling up the reservoirs setPrimaryHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); startPrimaryHeater(); @@ -1002,6 +1036,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; + // First reservoir 1 must be full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1029,17 +1066,17 @@ // Set the drain pump to control mode setDrainPumpTargetOutletPressure( HEAT_DISINFECT_TARGET_DRAIN_PRES_PSI ); - // Set the RO flow to maximum pressure of 25psi since it is the maximum pressure on the RO filter + // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter // at inlet temperature > 45 C setROPumpTargetFlowRate( HEAT_DISINFECT_TARGET_RO_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); - // Start the trimmer heater since we are recirculating water - //setTrimmerHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); - //startTrimmerHeater(); TODO turn the trimmer heater on when THD is implemented + // Start the trimmer heater since we are recirculating water and there is flow in the shunt line + setTrimmerHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startTrimmerHeater(); // Get the current volumes of R1 & R2. These values will be used to make sure the reservoirs' // volume does not change more than a certain amount during the actual heat disinfect cycle - R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change this back to primary + R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); stateTimer = getMSTimerCount(); @@ -1087,7 +1124,8 @@ case HEAT_DISINFECT_COMPLETE: - //TODO turn off CP1 and CP2 + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); // Set the valves to transfer hot water from R1 to R2 and fill up R2. setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); #ifndef V_2_SYSTEM @@ -1103,9 +1141,11 @@ rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; rsrvr1Status = DG_RESERVOIR_BELOW_TARGET; stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; break; + case HEAT_DISINFECT_IN_PROGRESS: default: // Do nothing, heat disinfect is in progress break; @@ -1131,6 +1171,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_TRANSITION_HOT_WATER; + // First reservoir 1 must be partially full if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { @@ -1146,25 +1189,19 @@ R1HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); R2HeatDisinfectVol = getLoadCellLargeFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); - //TODO turn on CP1 and CP2 - state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif } -#ifdef IGNORE_HEAT_DISINFECT_RSRVR_TIMEOUT else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; } -#endif return state; } @@ -1176,8 +1213,8 @@ * temperature within a certain period of time, it transitions to water * cancellation state. If heat disinfect reservoir 1 to reservoir 2 is * completed, it transitions to the next state. - * @details Inputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status - * @details Outputs: hasPostHeatDisinfectWaitStarted, stateTimer, rsrvr1Status + * @details Inputs: stateTimer, rsrvr1Status + * @details Outputs: stateTimer, rsrvr1Status * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ) @@ -1193,13 +1230,17 @@ break; case HEAT_DISINFECT_COMPLETE: - // Turn off the pumps and heaters - // TODO turn off CP1 and CP2 + // Turn off the heaters stopPrimaryHeater(); stopTrimmerHeater(); stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; break; + + case HEAT_DISINFECT_IN_PROGRESS: + default: + // Do nothing heat disinfect is in progress. + break; } return state; @@ -1218,6 +1259,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_HEATERS; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COOL_DOWN_DEVICE; + if ( TRUE == didTimeout( stateTimer, POST_HEAT_DISINFECT_WAIT_TIME_MS ) ) { // Stop the drain pump and the RO pump to exit the closed loop @@ -1226,18 +1270,19 @@ // De-energize all the valves that are not in the path anymore // and wait for the RO membrane to be cooled down. - // In this state, VPi and VPd must still be kept energized to make sure fresh - // water does not enter the circulation path the membrane is cooling down + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPI, VALVE_STATE_CLOSED ); setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); #ifndef V_2_SYSTEM setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VRD1, VALVE_STATE_CLOSED ); #else setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); - #endif + ROFCoolingTimer = getMSTimerCount(); stateTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_RO_FILTER; } @@ -1250,32 +1295,66 @@ * The handleHeatDisinfectCoolDownROFilterState function handles the heat * disinfect cool down RO filter state. The state monitors the temperature * at THd and if it is less than 45 C, it transitions to the next state. - * @details Inputs: stateTimer, rsrvr1Status - * @details Outputs: stateTimer, rsrvr1Status + * @details Inputs: stateTimer, rsrvr1Status, hasROFCirculationBeenStarted, + * ROFCirculationCoolingCounter + * @details Outputs: stateTimer, rsrvr1Status, hasROFCirculationBeenStarted, + * ROFCirculationCoolingCounter * @return next state of the heat disinfect state machine *************************************************************************/ static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCoolDownROFilterState( void ) { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COOL_DOWN_RO_FILTER; - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual THd sensor later + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COOL_DOWN_DEVICE; - // Check if the coldest spot temperature is less than 45 C so the RO filter - // can safely run fluid through - if ( ThdTemp < ROF_MIN_LOW_PRESSURE_TEMPERATURE_C ) + // THd is the closet sensor to the RO filter and this temperature is monitored + // until it is dropped below 45 C to be able to run fluid through the RO filter + F32 THdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); + + // Check if the coldest spot temperature is less than 45 C so the RO filter can safely run + if ( ( FALSE == isROPumpRunning() ) && ( THdTemp < TARGET_THD_SENSOR_FOR_RINSING_C ) ) { - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + U32 time = calcTimeSince( ROFCoolingTimer ); - rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; - stateTimer = getMSTimerCount(); - state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + if ( time <= THD_REACH_BELOW_45_AFTER_CIRC_TIME_MS ) + { + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + rsrvr1Status = DG_RESERVOIR_ABOVE_TARGET; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + } + else + { + // Set the valves to circulation. VBf is opened because the fluid in the RO filter might still be hot + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + + // Set the RO flow to maximum pressure of 30psi since it is the maximum pressure on the RO filter + // at inlet temperature > 45 C + setROPumpTargetFlowRate( ROF_COOL_DOWN_TARGET_FLOW_LPM, HEAT_DISINFECT_MAX_RO_PRESSURE_PSI ); + + hasROFCirculationBeenStarted = TRUE; + ROFCirculationTimer = getMSTimerCount(); + } } + // If the RO filter water circulation is in progress and the time for it has elapsed, stop the pump + else if ( ( TRUE == hasROFCirculationBeenStarted ) && ( TRUE == didTimeout( ROFCirculationTimer, ROF_COOL_DOWN_CIRCULATION_TIME_MS ) ) ) + { + hasROFCirculationBeenStarted = FALSE; + ROFCoolingTimer = getMSTimerCount(); + signalROPumpHardStop(); + } return state; } @@ -1296,13 +1375,16 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; - if ( ( TRUE == didTimeout( stateTimer, DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ) ) && ( isDrainPumpInMixDrainOn == FALSE ) ) + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT; + + if ( ( TRUE == didTimeout( stateTimer, DRAIN_PUMP_START_TIME_IN_MIX_DRAIN_MS ) ) && ( FALSE == isDrainPumpInMixDrainOn ) ) { isDrainPumpInMixDrainOn = TRUE; + #ifndef V_2_SYSTEM setValveState( VRD1, VALVE_STATE_OPEN ); #endif - // Turn on the drain pump to drain the reservoirs in open loop mode setDrainPumpTargetRPM( DRAIN_PUMP_RPM_IN_MIX_DRAIN ); } @@ -1410,6 +1492,18 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr1Status ) { rsrvr1Status = getRsrvrFillStatus( DG_RESERVOIR_1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + // 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 ); + // 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. + if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { @@ -1421,7 +1515,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 @@ -1487,6 +1581,21 @@ if ( DG_RESERVOIR_BELOW_TARGET == rsrvr2Status ) { rsrvr2Status = getRsrvrFillStatus( DG_RESERVOIR_2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS ); + + U32 drainPumpRPM = getTargetDrainPumpRPM(); + // Keep monitoring the status of reservoir 1 as the same time + F32 volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + // Reservoir 1 cannot be filled before reservoir 2 is filled and is overflowing to reservoir 1. If reservoir 1 has already + // reached to target volume, it means reservoir 2's load cell might be reading incorrect values. This situation might continue + // 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 ) ) + { + prevHeatDisinfectState = state; + alarmDetectedPendingTrigger = ALARM_ID_DG_INVALID_LOAD_CELL_VALUE; + state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + } } // Once reservoir 2 is completely full, monitor reservoir 1 else if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) @@ -1517,7 +1626,16 @@ // Turn on the drain pump to drain R2 setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); +#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + // Turn on the concentrate pumps + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); +#endif + // This is the last drain of heat disinfect cycle isThisLastDrain = TRUE; stateTimer = getMSTimerCount(); @@ -1576,6 +1694,9 @@ // Go to state complete, we are done DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_CANCEL_DISINFECT; + // Set the cancellation mode cancellationMode = CANCELLATION_MODE_BASIC; @@ -1601,6 +1722,9 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_CANCEL_WATER_PATH; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_CANCEL_DISINFECT; + if ( CANCELLATION_MODE_NONE == cancellationMode ) { U32 targetRPM = 0; @@ -1609,7 +1733,7 @@ deenergizeActuators(); // Check inlet dialysate and redundant outlet temperature sensors - F32 TDi = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change to TDi + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); F32 TRo = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); // The two sensors must be less than a threshold to decide if mix drain is needed to normal drain @@ -1636,6 +1760,8 @@ rsrvr2Status = DG_RESERVOIR_ABOVE_TARGET; // The drain is set to start from reservoir 2 since all the actuators have been de-energized + // Set the drain valve to reservoir 2 + setValveState( VRD2, VALVE_STATE_OPEN ); // Start the drain pump setDrainPumpTargetRPM( targetRPM ); @@ -1652,8 +1778,9 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr2Status ) { #ifndef V_2_SYSTEM - // Set the drain valve to reservoir 1 + // Set the drain valve to reservoir 1 and close reservoir 2 setValveState( VRD1, VALVE_STATE_OPEN ); + setValveState( VRD2, VALVE_STATE_CLOSED ); #else // Set the drain valve to reservoir 1 setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); @@ -1662,6 +1789,11 @@ } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { + // Stop the actuators that are running before going to basic cancellation path + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } @@ -1674,10 +1806,18 @@ if ( DG_RESERVOIR_REACHED_TARGET == rsrvr1Status ) { + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + failHeatDisinfect(); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr1Status ) { + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + signalDrainPumpHardStop(); + prevHeatDisinfectState = state; state = DG_HEAT_DISINFECT_STATE_CANCEL_BASIC_PATH; } @@ -1699,55 +1839,19 @@ { DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_COMPLETE; + // Set the heat disinfect UI state + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_COMPLETE; + stopDGHeatDisinfect(); return state; } /*********************************************************************//** * @brief - * The resetActuators function sets all the actuators to reset and - * de-energized state. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -static void resetActuators( void ) -{ - // UV reactors will not be used in the heat disinfection since their operating temperature - // range is below 85C and they might be damaged by the high temperature. - turnOffUVReactor( INLET_UV_REACTOR ); - turnOffUVReactor( OUTLET_UV_REACTOR ); - - // De-energize all the valves - setValveState( VPI, VALVE_STATE_CLOSED ); - setValveState( VBF, VALVE_STATE_CLOSED ); - setValveState( VSP, VALVE_STATE_CLOSED ); -#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( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); - setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - - //TODO add the composition pumps - signalROPumpHardStop(); - signalDrainPumpHardStop(); - stopPrimaryHeater(); - stopTrimmerHeater(); -} - -/*********************************************************************//** - * @brief * The failHeatDisinfect function sets the alarm that failed the heat * disinfect mode. - * @details Inputs: alarm, prevHeatDisinfectState + * @details Inputs: alarmDetectedPendingTrigger, prevHeatDisinfectState * @details Outputs: none * @return none *************************************************************************/ @@ -1775,7 +1879,7 @@ if ( r == DG_RESERVOIR_1 ) { - volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); //TODO change back to primary + volume = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); } else if ( r == DG_RESERVOIR_2 ) { @@ -1814,8 +1918,7 @@ * reservoir. * @details Inputs: stateTimer, prevHeatDisinfectState, heatDisinfectState, * alarm - * @details Outputs: stateTimer, heatDisinfectState heatDisinfectState, - * alarm + * @details Outputs: stateTimer, heatDisinfectState, alarm * @param r is DG_RESERVOIR_1 or DG_RESERVOIR_2 * @param drainSteadyStateTimeout which is the time the reservoir's level * does not change and is steady state @@ -1856,21 +1959,21 @@ * If the heat disinfect has started or has elapsed, it set the status of * heat disinfect accordingly. * @details Inputs: areRsrvrsLeaking, areRsrvrsLeaking - * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking + * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking, heatDisinfectState * @return status of the heat disinfect (i.e in progress, complete) *************************************************************************/ static HEAT_DISINFECT_STATUS_T getHeatDisinfectStatus( void ) { HEAT_DISINFECT_STATUS_T status = HEAT_DISINFECT_IN_PROGRESS; F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 ThdTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); //TODO change this to actual TPm sensor later + F32 ThdTemp = getTemperatureValue( TEMPSENSORS_HEAT_DISINFECT ); - BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; //TODo change this to primary when the stupid load cell was fixed + BOOL isR1OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; BOOL isR2OutOfRange = fabs( getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ) - R2HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; // Check if either reservoir 1 or reservoir 2 are losing volume more than allowed volume - if ( isR1OutOfRange || isR2OutOfRange ) + if ( ( TRUE == isR1OutOfRange ) || ( TRUE == isR2OutOfRange ) ) { // If the leak is the first time after a while, set the flag and start the timer if ( FALSE == areRsrvrsLeaking ) @@ -1882,7 +1985,7 @@ else if ( TRUE == didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) { areRsrvrsLeaking = FALSE; - alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; + alarmDetectedPendingTrigger = ALARM_ID_DG_RESERVOIR_LEAK_TIMEOUT; status = HEAT_DISINFECT_RSRVRS_LEAK_TIMEOUT; } } @@ -1892,18 +1995,19 @@ areRsrvrsLeaking = FALSE; } - // If the coldest spot which is TPm is less than minimum heat disinfect temperature, + // If the coldest spot which is THd is less than minimum heat disinfect temperature, // reset the heat disinfect timers and check whether heating up has timed out if ( ThdTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) { // Keep reseting the disinfect timer so the elapsed time is always 0 until disinfect truly starts heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = FALSE; + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_HEAT_UP_WATER; if ( TRUE == didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) { // Heating up to minimum temperature for heat disinfect failed - alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; + alarmDetectedPendingTrigger = ALARM_ID_DG_HEAT_DISINFECT_TARGET_TEMP_TIMEOUT; status = HEAT_DISINFECT_HEAT_UP_TIMEOUT; } } @@ -1912,6 +2016,25 @@ // The temperature of the coldest spot is in range to start the disinfect timer heatDisinfectTimer = getMSTimerCount(); isPartialDisinfectInProgress = TRUE; + + // Set the heat disinfect UI state + if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) + { + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_1; +#ifndef IGNORE_CONC_PUMP_IN_HEAT_DISINFECT + // Turn the pumps on in reverse + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONC_PUMPS_REVERSE_SPEED_ML_PER_MIN ); + + // During R1 to R2 disinfect, the concentrate pumps turn on + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); +#endif + } + else + { + heatDisinfectUIState = HEAT_DISINFECT_UI_STATE_DISINFECT_RESERVOIR_2; + } } // If heat disinfect temperature has been reached, check if this stage of heat disinfect is done @@ -1938,26 +2061,36 @@ if ( ++dataPublishCounter > HEAT_DISINFECT_DATA_PUB_INTERVAL ) { MODE_HEAT_DISINFECT_DATA_T data; + MODE_HEAT_DISINFECT_UI_DATA_T uiData; - data.heatDisinfectState = (U32)heatDisinfectState; - data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); - data.stateElapsedTime = calcTimeSince( stateTimer ); - data.cancellationMode = (U32)cancellationMode; - data.R1FillLevel = R1HeatDisinfectVol; - data.R2FillLevel = R2HeatDisinfectVol; + data.heatDisinfectState = (U32)heatDisinfectState; + data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ); + data.stateElapsedTime = calcTimeSince( stateTimer ); + data.cancellationMode = (U32)cancellationMode; + data.heatDisinfectUIState = (U32)heatDisinfectUIState; // If the mode is in the actual heat disinfect states, publish the elapsed time, otherwise publish 0 to avoid confusion - if ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState || DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) + if ( ( DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2 == heatDisinfectState ) || + ( DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1 == heatDisinfectState ) ) { - data.heatDisinfectElapsedTime = calcTimeSince( heatDisinfectTimer ); + uiData.heatDisinfectTargetTime = HEAT_DISINFECT_TIME_MS; + uiData.heatDisinfectCountdownTime = HEAT_DISINFECT_TIME_MS - calcTimeSince( heatDisinfectTimer ); + data.R1FillLevel = R1HeatDisinfectVol; + data.R2FillLevel = R2HeatDisinfectVol; } else { - data.heatDisinfectElapsedTime = 0; + uiData.heatDisinfectTargetTime = 0; + uiData.heatDisinfectCountdownTime = 0; + data.R1FillLevel = 0.0; + data.R2FillLevel = 0.0; } broadcastHeatDisinfectData( &data ); + // Publish data to UI + broadcastHeatDisinfectData2UI( &uiData ); + dataPublishCounter = 0; } } Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r1a5efe97f5f39594b45797fded52cafce92afe80 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 1a5efe97f5f39594b45797fded52cafce92afe80) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -20,6 +20,7 @@ #include "DrainPump.h" #include "Fans.h" #include "FPGA.h" +#include "Integrity.h" #include "LoadCell.h" #include "ModeInitPOST.h" #include "NVDataMgmt.h" @@ -108,6 +109,11 @@ postState = handlePOSTStatus( testStatus ); break; + case DG_POST_STATE_FW_INTEGRITY: + testStatus = execIntegrityTest(); + postState = handlePOSTStatus( testStatus ); + break; + case DG_POST_STATE_FPGA: testStatus = execFPGATest(); postState = handlePOSTStatus( testStatus ); @@ -208,7 +214,7 @@ break; default: - // TODO - s/w fault + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_MODE_INIT_POST_INVALID_POST_STATE, postState ) postState = DG_POST_STATE_FAILED; break; } Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r5a36a768d11cc597a36b894c1fb3a5e5590130f1 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 5a36a768d11cc597a36b894c1fb3a5e5590130f1) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -44,7 +44,7 @@ #define TARGET_RO_FLOW_RATE_L 0.3 ///< Target flow rate for RO pump. #define TARGET_FLUSH_LINES_RO_FLOW_RATE_L 0.6 ///< Target flow rate for RO pump. -#define FLUSH_LINES_VOLUME_L 0.1 ///< Water volume (in Liters) to flush when starting re-circulate mode. +#define FLUSH_LINES_VOLUME_L 0.01 ///< Water volume (in Liters) to flush when starting re-circulate mode. // ********** private data ********** @@ -91,16 +91,28 @@ setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setROPumpTargetFlowRate( TARGET_FLUSH_LINES_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); signalDrainPumpHardStop(); - stopPrimaryHeater(); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); - // UV on + // UV reactors on turnOnUVReactor( INLET_UV_REACTOR ); turnOnUVReactor( OUTLET_UV_REACTOR ); + + // NOTE: The target flow rate should be set prior to setting the start primary heater + // because the initial guess in the heaters driver needs the target flow to calculate + // the new PWMs for the main and small primary heaters + setROPumpTargetFlowRate( TARGET_FLUSH_LINES_RO_FLOW_RATE_L, TARGET_RO_PRESSURE_PSI ); + startPrimaryHeater(); + +#ifndef _VECTORCAST_ + { // TODO - test code to start the fan since we're turning the heater on + F32 fanPWM = 0.25; + etpwmSetCmpA( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); + etpwmSetCmpB( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); + } +#endif } /*********************************************************************//** @@ -166,7 +178,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 -r3d131237935eb36e56e0d057a713430e31dc6405 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 3d131237935eb36e56e0d057a713430e31dc6405) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -22,6 +22,7 @@ #include "ModeFault.h" #include "ModeStandby.h" #include "OperationModes.h" +#include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" #include "SystemComm.h" @@ -54,13 +55,16 @@ static U32 waterSampleStartTime = 0; ///< Time stamp for start of water sample state. static U32 filterFlushStartTime = 0; ///< Time stamp for start of filter flush state. static U32 filterFlushPublishTimerCounter = 0; ///< Filter flush data publish timer counter. +/// Filter flush time period in ms. +static OVERRIDE_U32_T filterFlushTimePeriod = { FILTER_FLUSH_TIME_MS, FILTER_FLUSH_TIME_MS, 0, 0 }; // ********** private function prototypes ********** static DG_STANDBY_MODE_STATE_T handleStandbyIdleState( void ); static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterState( void ); static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterIdleState( void ); static DG_STANDBY_MODE_STATE_T handleStandbySampleWaterState( void ); +static U32 getFilterFlushTimePeriod( void ); /*********************************************************************//** * @brief @@ -189,15 +193,18 @@ static DG_STANDBY_MODE_STATE_T handleStandbyFlushFilterState( void ) { DG_STANDBY_MODE_STATE_T state = DG_STANDBY_MODE_STATE_FLUSH_FILTER; + U32 const filterFlushTimePeriod_ms = getFilterFlushTimePeriod(); - if ( TRUE == didTimeout( filterFlushStartTime, FILTER_FLUSH_TIME_MS ) ) + checkInletPressure(); + + if ( TRUE == didTimeout( filterFlushStartTime, filterFlushTimePeriod_ms ) ) { state = DG_STANDBY_MODE_STATE_FLUSH_FILTER_IDLE; } if ( FILTER_FLUSH_DATA_PUBLISH_INTERVAL <= filterFlushPublishTimerCounter++ ) { - U32 const timeout = FILTER_FLUSH_TIME_MS / MS_PER_SECOND; + U32 const timeout = filterFlushTimePeriod_ms / MS_PER_SECOND; U32 const countdown = timeout - ( calcTimeSince( filterFlushStartTime ) / MS_PER_SECOND ); filterFlushPublishTimerCounter = 0; @@ -430,4 +437,74 @@ return standbyState; } +/*********************************************************************//** + * @brief + * The getFilterFlushTimePeriod function gets the filter flush time period. + * @details Inputs: filterFlushTimePeriod + * @details Outputs: none + * @return the current filter flush time period (in ms). + *************************************************************************/ +static U32 getFilterFlushTimePeriod( void ) +{ + U32 result = filterFlushTimePeriod.data; + + if ( OVERRIDE_KEY == filterFlushTimePeriod.override ) + { + result = filterFlushTimePeriod.ovData; + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetFilterFlushTimePeriodOverride function overrides the filter + * flush time period. + * @details Inputs: none + * @details Outputs: filterFlushTimePeriod + * @param value override concentrate pump data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetFilterFlushTimePeriodOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + filterFlushTimePeriod.override = OVERRIDE_KEY; + filterFlushTimePeriod.ovData = value; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetFilterFlushTimePeriodOverride function resets the + * override of the filter flush time period. + * @details Inputs: none + * @details Outputs: filterFlushTimePeriod + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetFilterFlushTimePeriodOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + filterFlushTimePeriod.override = OVERRIDE_RESET; + filterFlushTimePeriod.ovData = filterFlushTimePeriod.ovInitData; + } + + return result; +} + /**@}*/ Index: firmware/App/Modes/ModeStandby.h =================================================================== diff -u -r86eec09ab556fbd970ddcae9dc622727928ee757 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Modes/ModeStandby.h (.../ModeStandby.h) (revision 86eec09ab556fbd970ddcae9dc622727928ee757) +++ firmware/App/Modes/ModeStandby.h (.../ModeStandby.h) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -37,15 +37,17 @@ void transitionToStandbyMode( void ); // prepares for transition to standby mode U32 execStandbyMode( void ); // execute the standby mode state machine (call from OperationModes) -DG_STANDBY_MODE_STATE_T getCurrentStandbyState( void ); // get the current state of the standby mode. - void waterSampleCommandHandler( SAMPLE_WATER_CMD_T sampleWaterCmd ); BOOL requestDGStart( void ); // HD requests DG start (go to re-circulate mode) BOOL startDGFlush( void ); // HD start flush mode BOOL startDGHeatDisinfect( void ); // HD start heat disinfect mode +DG_STANDBY_MODE_STATE_T getCurrentStandbyState( void ); // get the current state of the standby mode. +BOOL testSetFilterFlushTimePeriodOverride( U32 value ); +BOOL testResetFilterFlushTimePeriodOverride( void ); + BOOL startDGChemicalDisinfect( void ); // HD start chemical disinfect mode /**@}*/ Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r3d131237935eb36e56e0d057a713430e31dc6405 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 3d131237935eb36e56e0d057a713430e31dc6405) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -567,13 +567,12 @@ else { signalCANXmitsCompleted(); - // TODO - shouldn't get here, but let's see if we do - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)mBox ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_CAN_TX_FAULT, (U32)mBox ) } } else - { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_CAN_MESSAGE_SIZE, (U32)dataSize ) } } @@ -839,9 +838,7 @@ if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) { hdIsCommunicating = FALSE; -#ifndef DEBUG_ENABLED - activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm if we're in middle of a treatment? or if in a mode that comm loss would impact badly? -#endif + activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); } } @@ -1275,6 +1272,10 @@ handleSetFluidLeakStateDetectorOverrideRequest( message ); break; + case MSG_ID_FILTER_FLUSH_TIME_PERIOD_OVERRIDE: + handleFilterFlushTimePeriodOverride(message); + break; + default: // TODO - unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r3d131237935eb36e56e0d057a713430e31dc6405 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 3d131237935eb36e56e0d057a713430e31dc6405) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -772,13 +772,17 @@ *************************************************************************/ void handleAlarmClear( MESSAGE_T *message ) { + BOOL result = FALSE; + if ( message->hdr.payloadLen == sizeof( U32 ) ) { U32 alarmId; + result = TRUE; memcpy(&alarmId, message->payload, sizeof( U32 ) ); clearAlarm( (ALARM_ID_T)alarmId ); } + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } /*********************************************************************//** @@ -3362,6 +3366,38 @@ } /*********************************************************************//** + * @brief + * The handleFilterFlushTimePeriodOverride function handles a request + * to override the filter flush time period value. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleFilterFlushTimePeriodOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetFilterFlushTimePeriodOverride( payload.state.u32 ); + } + else + { + result = testResetFilterFlushTimePeriodOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** * @brief * The handleStartStopDGChemicalDisinfect function handles a request to start * or stop DG chemical disinfect mode. Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r1a5efe97f5f39594b45797fded52cafce92afe80 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 1a5efe97f5f39594b45797fded52cafce92afe80) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -107,6 +107,9 @@ // MSG_ID_DG_UV_REACTORS_DATA BOOL broadcastUVReactorsData( UV_REACTORS_DATA_T *uvReactorsData ); +// MSG_ID_DG_HEAT_DISINFECT_DATA +BOOL broadcastHeatDisinfectData( MODE_HEAT_DISINFECT_DATA_T *heatDisinfectData ); + // MSG_ID_DG_FILTER_FLUSH_PROGRESS BOOL broadcastFilterFlushData( U32 timeout, U32 countdown ); @@ -167,12 +170,6 @@ // MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD void handleStartStopTrimmerHeaterCmd( MESSAGE_T *message ); -// MSG_ID_DG_UV_REACTORS_DATA -BOOL broadcastUVReactorsData( UV_REACTORS_DATA_T *uvReactorsData ); - -// MSG_ID_DG_HEAT_DISINFECT_DATA -BOOL broadcastHeatDisinfectData( MODE_HEAT_DISINFECT_DATA_T *heatDisinfectData ); - // MSG_ID_DG_SEND_CALIBRATION_DATA BOOL sendDGCalibrationRecord( U32 payloadCurrNum, U32 payloadTotalNum, U32 length, U08* calRcrdAddress ); @@ -367,6 +364,9 @@ // MSG_ID_DG_START_STOP_CHEM_DSINFECT BOOL handleStartStopDGChemicalDisinfect( MESSAGE_T *message ); +// MSG_ID_FILTER_FLUSH_TIME_PERIOD_OVERRIDE +void handleFilterFlushTimePeriodOverride( MESSAGE_T *message ); + /**@}*/ #endif Index: firmware/source/sys_main.c =================================================================== diff -u -r1a5efe97f5f39594b45797fded52cafce92afe80 -r2fff37fa585181917705645494549b5fd4a4d522 --- firmware/source/sys_main.c (.../sys_main.c) (revision 1a5efe97f5f39594b45797fded52cafce92afe80) +++ firmware/source/sys_main.c (.../sys_main.c) (revision 2fff37fa585181917705645494549b5fd4a4d522) @@ -73,6 +73,7 @@ #include "FluidLeak.h" #include "FPGA.h" #include "Heaters.h" +#include "Integrity.h" #include "InternalADC.h" #include "Interrupts.h" #include "LoadCell.h" @@ -197,6 +198,7 @@ initReservoirs(); initFluidLeak(); initOperationModes(); + initIntegrity(); } /*************************************************************************