Index: firmware/App/Controllers/DrainPump.c =================================================================== diff -u -rccf1219089b835ab2f9d401c0be0d2000be9010a -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision ccf1219089b835ab2f9d401c0be0d2000be9010a) +++ firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -440,7 +440,16 @@ *************************************************************************/ static DRAIN_PUMP_STATE_T handleDrainPumpOpenLoopState( void ) { - return DRAIN_PUMP_OPEN_LOOP_STATE; + DRAIN_PUMP_STATE_T state = DRAIN_PUMP_OPEN_LOOP_STATE; + + // Check if the RPM is 0, and if it is turn off the pump + if ( getTargetDrainPumpRPM() == 0 ) + { + state = DRAIN_PUMP_OFF_STATE; + signalDrainPumpHardStop(); + } + + return state; } /*********************************************************************//** @@ -573,11 +582,7 @@ if ( TRUE == isTestingActivated() ) { - // Check for the RPM to be in range - if ( value >= MIN_DRAIN_PUMP_RPM && value <= MAX_DRAIN_PUMP_RPM ) - { - result = setDrainPumpTargetRPM( value ); - } + result = setDrainPumpTargetRPM( value ); } return result; Index: firmware/App/Controllers/Fans.c =================================================================== diff -u -rf68e01a2daee6cb88bb54816aee56668d662bcd4 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/Fans.c (.../Fans.c) (revision f68e01a2daee6cb88bb54816aee56668d662bcd4) +++ firmware/App/Controllers/Fans.c (.../Fans.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -111,8 +111,7 @@ fansMonitorCounter = 0; // Initialize a persistent alarm for fans RPM out of range - initPersistentAlarm( PERSISTENT_ALARM_FANS_RPM_OUT_RANGE, ALARM_ID_DG_FAN_RPM_OUT_OF_RANGE, - TRUE, FANS_MAX_ALLOWED_RPM_OUT_OF_RANGE_INTERVAL, FANS_MAX_ALLOWED_RPM_OUT_OF_RANGE_INTERVAL ); + initPersistentAlarm( ALARM_ID_DG_FAN_RPM_OUT_OF_RANGE, FANS_MAX_ALLOWED_RPM_OUT_OF_RANGE_INTERVAL, FANS_MAX_ALLOWED_RPM_OUT_OF_RANGE_INTERVAL ); } /*********************************************************************//** @@ -482,15 +481,8 @@ /*for ( fan = FAN_INLET_1; fan < NUM_OF_FANS_NAMES; fan++ ) { - // Call persistent alarm if a fan's RPM is out of range - if ( fansStatus.rpm[ fan ] >= FANS_MAX_ALLOWED_RPM ) - { - checkPersistentAlarm( PERSISTENT_ALARM_FANS_RPM_OUT_RANGE, TRUE, fansStatus.rpm[ fan ], FANS_MAX_ALLOWED_RPM ); - } - else if ( fansStatus.rpm[ fan ] <= FANS_MIN_ALLOWED_RPM ) - { - checkPersistentAlarm( PERSISTENT_ALARM_FANS_RPM_OUT_RANGE, TRUE, fansStatus.rpm[ fan ], FANS_MIN_ALLOWED_RPM ); - } + BOOL const fanRpmOutOfRange = ( fansStatus.rpm[ fan ] >= FANS_MAX_ALLOWED_RPM ) && ( fansStatus.rpm[ fan ] <= FANS_MIN_ALLOWED_RPM ); + checkPersistentAlarm( ALARM_ID_DG_FAN_RPM_OUT_OF_RANGE, fanRpmOutOfRange, fansStatus.rpm[ fan ], FANS_MAX_ALLOWED_RPM ); }*/ fansMonitorCounter = 0; Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -ra21818c35ee6d2db460e2713a003274ac41f1c47 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision a21818c35ee6d2db460e2713a003274ac41f1c47) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -20,6 +20,7 @@ #include "etpwm.h" #include "AlarmMgmt.h" +#include "DGDefs.h" #include "Heaters.h" #include "ROPump.h" #include "PIControllers.h" @@ -277,10 +278,50 @@ /*********************************************************************//** * @brief - * The execHeatersMonitor function turns off the heaters when RO pump is - * not on. - * @details Inputs: none TODO update the doxygen header function - * @details Outputs: none + * The handleTrimmerHeaterCmd handles a start trimmer heater command from the HD. + * It resets the trimmer heater's state and sets the duty cycle of the trimmer heater. + * @details Inputs: none + * @details Outputs: process command and send back response + * @param heaterCmdPtr pointer to heater command data record + * @return status + *************************************************************************/ +void handleTrimmerHeaterCmd( TRIMMER_HEATER_CMD_T *heaterCmdPtr ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_START_TRIMMER_HEATER; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + if ( TRUE == heaterCmdPtr->startHeater ) + { + if ( ( MINIMUM_TARGET_TEMPERATURE <= heaterCmdPtr->targetTemp ) && ( heaterCmdPtr->targetTemp <= MAXIMUM_TARGET_TEMPERATURE ) ) + { + cmdResponse.rejected = FALSE; + #ifndef DISABLE_HEATERS_AND_TEMPS + trimmerHeaterTargetTemperature = heaterCmdPtr->targetTemp; + hasStartTrimmerHeaterRequested = TRUE; + #endif + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; + } + } + else + { + cmdResponse.rejected = FALSE; + stopTrimmerHeater(); + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The execHeatersMonitor function turns off the heaters when RO pump is not on. + * @details Inputs: none + * @details Outputs: Turns off the heaters when RO pump is not on * @return none *************************************************************************/ void execHeatersMonitor( void ) @@ -712,9 +753,9 @@ { HEATERS_DATA_T data; - data.mainPrimaryDutyCyclePct = mainPrimaryHeaterDutyCycle * 100; - data.smallPrimaryDutyCyclePct = smallPrimaryHeaterDutyCycle * 100; - data.trimmerDutyCyclePct = trimmerHeaterDutyCycle * 100; + //data.mainPrimaryDutyCyclePct = mainPrimaryHeaterDutyCycle * 100; + //data.smallPrimaryDutyCyclePct = smallPrimaryHeaterDutyCycle * 100; + //data.trimmerDutyCyclePct = trimmerHeaterDutyCycle * 100; broadcastHeatersData( &data ); Index: firmware/App/Controllers/Heaters.h =================================================================== diff -u -re0265b8fad80add7a5d54db11ecc72fd6b1665a8 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision e0265b8fad80add7a5d54db11ecc72fd6b1665a8) +++ firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -32,17 +32,31 @@ * @{ */ -// ********** public definitions ********** +#pragma pack(push,1) -/// Heaters data publish struct +/// Target temperature data structure. typedef struct { - F32 mainPrimaryDutyCyclePct; ///< Main primary heater duty cycle in percent. - F32 smallPrimaryDutyCyclePct; ///< Small primary heater duty cycle in percent. - F32 trimmerDutyCyclePct; ///< Trimmer heater duty cycle in percent. + F32 targetPrimaryHeaterTemp; ///< Primary heater set temperature target + F32 targetTrimmerHeaterTemp; ///< Trimmer heater set temperature target +} TARGET_TEMPS_PAYLOAD_T; + +/// Trimmer heater command data structure. +typedef struct +{ + BOOL startHeater; ///< Flag indicates start or stop heater + F32 targetTemp; ///< Target temperature for heater +} TRIMMER_HEATER_CMD_T; + +/// Heaters data struct. +typedef struct +{ + U32 mainPrimayHeaterDC; ///< Main primary heater DC + U32 smallPrimaryHeaterDC; ///< Small primary heater DC + U32 trimmerHeaterDC; ///< Trimmer heater DC } HEATERS_DATA_T; -// ********** public function prototypes ********** +#pragma pack(pop) void initHeaters( void ); @@ -55,6 +69,8 @@ void stopPrimaryHeater( void ); void stopTrimmerHeater( void ); +void handleTrimmerHeaterCmd( TRIMMER_HEATER_CMD_T *heaterCmdPtr ); // handle trimmer heater control command from HD + void execHeatersMonitor( void ); SELF_TEST_STATUS_T execHeatersSelfTest( void ); Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r0c1f66a170a3a0a4324fa1a3c3bfb4c7f77139b5 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 0c1f66a170a3a0a4324fa1a3c3bfb4c7f77139b5) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -53,25 +53,24 @@ #define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. #define ROP_RAMP_UP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump pressure control. -#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump pressure control. +#define ROP_P_COEFFICIENT 0.25 ///< P term for RO pump pressure control. +#define ROP_I_COEFFICIENT 0.25 ///< I term for RO pump pressure control. -#define ROP_RAMP_UP_P_COEFFICIENT 0.0 ///< P term for RO pump flow control. -#define ROP_RAMP_UP_I_COEFFICIENT 0.1 ///< I term for RO pump flow control. #define ROP_FLOW_TARGET_TOLERANCE 0.03 ///< Tolerance in between the target flow rate and the actual flow rate in percentage. +#define ROP_RAMP_DOWN_DUTY_CYCLE_RATIO 0.01 ///< Pump ramp down duty cycle ratio when the pressure higher than max defined. #define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). #define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. #define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. /// The time in counts to check the flow and make sure it is in range. -#define FLOW_VERIFICATION_COUNTER_TARGET ( 2 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +#define FLOW_VERIFICATION_COUNTER_TARGET ( 2 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) //TODO remove #define RO_FLOW_ADC_TO_LPM_FACTOR 5555 ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). -#define ROP_FLOW_TO_PWM_SLOPE 0.5 ///< Slope of flow to PWM line equation. -#define ROP_FLOW_TO_PWM_INTERCEPT 0.28 ///< Intercept of flow to PWM line equation. +#define ROP_FLOW_TO_PWM_SLOPE 0.1 ///< Slope of flow to PWM line equation. +#define ROP_FLOW_TO_PWM_INTERCEPT 0.0 ///< Intercept of flow to PWM line equation. /// Initial conversion factor from target flow rate to PWM duty cycle estimate. #define ROP_FLOW_TO_PWM_DC(flow) ( ROP_FLOW_TO_PWM_SLOPE * flow + ROP_FLOW_TO_PWM_INTERCEPT ) @@ -88,16 +87,17 @@ #define MAX_ALLOWED_RAMP_UP_TIME ( 10 * MS_PER_SECOND ) ///< Maximum allowed ramp up time to a flow rate in ms. #define ROP_PSI_TO_PWM_DC(p) ( 0.2 + ( (F32)((p) - 100) * 0.01 ) ) ///< Conversion factor from target PSI to PWM duty cycle estimate. #define SAFETY_SHUTDOWN_TIMEOUT ( 3 * MS_PER_SECOND ) ///< RO pump safety shutdown activation timeout in ms. -#define ROP_FLOW_STABILIZE_TIME ( 3 * MS_PER_SECOND ) ///< Time required for RO flow to stabilize. +#define ROP_FLOW_STABILIZE_TIME ( 3 * MS_PER_SECOND ) ///< Time required for RO flow to stabilize. TODO remove #define ROP_MAX_RAMP_UP_RETRY 5 ///< Maximum ramp up retires before alarm. +// ************ New defines for pump control ****************// + + /// Enumeration of RO pump states. typedef enum ROPump_States { RO_PUMP_OFF_STATE = 0, ///< RO pump off state - RO_PUMP_CONTROL_SETUP_STATE, ///< RO pump control setup state RO_PUMP_RAMP_UP_STATE, ///< RO pump ramp up to target flow rate state - RO_PUMP_VERIFY_FLOW_STATE, ///< RO pump maintain the flow rate for a set period of time RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state RO_PUMP_OPEN_LOOP_STATE, ///< RO pump open loop state NUM_OF_RO_PUMP_STATES ///< Number of RO pump states @@ -130,11 +130,8 @@ 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus. static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< measured RO flow rate (in L/min). -static U32 flowVerificationCounter = 0; ///< Counter to verify the flow is in range. static U32 roControlTimerCounter = 0; ///< determines when to perform control on RO pump. static F32 roPumpOpenLoopTargetDutyCycle = 0; ///< Target RO pump open loop PWM. -static F32 roPumpFlowRateRunningSum = 0; ///< RO pump flow rate running sum. -static F32 roPumpPressureRunningSum = 0; ///< RO pump pressure running sum. /* TODO These variables are used for POST. POST has not been implemented yet static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current RO pump self test state. @@ -143,24 +140,20 @@ static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. static U32 flowFilterCounter = 0; ///< Flow filtering counter. -static U32 roPumpOnStartTime = 0; ///< Start time when RO pump turned on. -static BOOL setupROPumpControl = 0; ///< Flag to indicate if we need to setup RO pump control. static U32 rampUpRetryCount = 0; ///< Number of ramp up retries. // ********** private function prototypes ********** static RO_PUMP_STATE_T handleROPumpOffState( void ); -static RO_PUMP_STATE_T handleROPumpControlSetupState( void ); static RO_PUMP_STATE_T handleROPumpRampUpState( void ); -static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ); static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); static void setROPumpTargetDutyCycle( F32 duty ); static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); static void stopROPump( void ); static void publishROPumpData( void ); -static U32 getPublishROPumpDataInterval( void ); +static U32 getPublishROPumpDataInterval( void ); /*********************************************************************//** * @brief @@ -180,31 +173,29 @@ initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE, ROP_P_COEFFICIENT, ROP_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); - // Initialize the I controller during ramp up - initializePIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_DUTY_CYCLE, ROP_RAMP_UP_P_COEFFICIENT, ROP_RAMP_UP_I_COEFFICIENT, - MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); - // Initialize the persistent alarm for flow out of upper and lower range - initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); - initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + /*initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_UPPER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, TRUE, + FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_LOWER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, TRUE, + FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + // Initialize the persistent alarm for max allowed pressure out of range - initPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_PRESSURE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, TRUE, + MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); // Initialize the persistent alarm for ramp up to target flow timeout - initPersistentAlarm( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, MAX_ALLOWED_RAMP_UP_TIME, MAX_ALLOWED_RAMP_UP_TIME ); + initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_RAMP_UP_TO_TARGET_FLOW_TIMEOUT, ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, TRUE, + MAX_ALLOWED_RAMP_UP_TIME, MAX_ALLOWED_RAMP_UP_TIME ); // Initialize the persistent alarm for not turning off the pump - initPersistentAlarm( ALARM_ID_RO_PUMP_OFF_FAULT, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); + initPersistentAlarm( PERSISTEMT_ALARM_RO_PUMP_OFF_ERROR, ALARM_ID_RO_PUMP_OFF_FAULT, TRUE, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT );*/ // Initialize the variables roControlTimerCounter = 0; roPumpOpenLoopTargetDutyCycle = 0; - roPumpFlowRateRunningSum = 0; - roPumpPressureRunningSum = 0; measuredFlowReadingsSum = 0; flowFilterCounter = 0; - flowVerificationCounter = 0; roPumpDataPublicationTimerCounter = 0; rampUpRetryCount = 0; roPumpState = RO_PUMP_OFF_STATE; @@ -242,7 +233,6 @@ roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; // Get the initial guess of the duty cycle roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); - setupROPumpControl = TRUE; result = TRUE; } // Requested max pressure is out of range @@ -280,7 +270,6 @@ roPumpPWMDutyCyclePct = 0.0; roPumpOpenLoopTargetDutyCycle = 0.0; roControlTimerCounter = 0; - flowVerificationCounter = 0; isROPumpOn = FALSE; targetROPumpPressure = 0; resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE ); @@ -378,18 +367,10 @@ roPumpState = handleROPumpOffState(); break; - case RO_PUMP_CONTROL_SETUP_STATE: - roPumpState = handleROPumpControlSetupState(); - break; - case RO_PUMP_RAMP_UP_STATE: roPumpState = handleROPumpRampUpState(); break; - case RO_PUMP_VERIFY_FLOW_STATE: - roPumpState = handleROPumpVerifyFlowState(); - break; - case RO_PUMP_CONTROL_TO_TARGET_STATE: roPumpState = handleROPumpControlToTargetState(); break; @@ -439,7 +420,8 @@ * @brief * The handleROPumpOffState function handles the RO pump off state of the * controller state machine. - * @details Inputs: roPumpControlMode, roPumpPWMDutyCyclePctSet, roPumpOpenLoopTargetDutyCycle + * @details Inputs: roPumpControlMode, roPumpPWMDutyCyclePctSet, + * roPumpOpenLoopTargetDutyCycle * @details Outputs: roPumpPWMDutyCyclePct, setupROPumpControl, isROPumpOn * @return next state of the controller state machine *************************************************************************/ @@ -450,10 +432,12 @@ // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow if ( getTargetROPumpFlowRate() > 0 && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) { + roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; // Set pump to on isROPumpOn = TRUE; - result = RO_PUMP_CONTROL_SETUP_STATE; - setupROPumpControl = TRUE; + roPumpDutyCyclePctSet = ROP_FLOW_TO_PWM_DC( getTargetROPumpFlowRate() ); + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + result = RO_PUMP_RAMP_UP_STATE; } // If the target duty cycle is greater than zero (minimum is 10%) and the mode has been set to open // loop, set the duty cycle @@ -469,39 +453,6 @@ /*********************************************************************//** * @brief - * The handleROPumpControlSetupState function handles the RO pump control - * setup state of the controller state machine. - * @details Inputs: setupROPumpControl, roPumpPWMDutyCyclePct - * @details Outputs: setup RO pump PI controller and wait for flow stabilize - * @return next state of the controller state machine - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpControlSetupState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_CONTROL_SETUP_STATE; - - if ( TRUE == setupROPumpControl ) - { - roPumpControlModeSet = roPumpControlMode; - // Set initial PWM duty cycle - roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; - setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - // Reset controller - resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, roPumpDutyCyclePctSet ); - setupROPumpControl = FALSE; - roPumpOnStartTime = getMSTimerCount(); - } - - if ( TRUE == didTimeout( roPumpOnStartTime, ROP_FLOW_STABILIZE_TIME ) ) - { - rampUpRetryCount = 0; - result = RO_PUMP_RAMP_UP_STATE; - } - - return result; -} - -/*********************************************************************//** - * @brief * The handleROPumpRampUpState function handles the RO pump ramp up state * of the controller state machine. * @details Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, @@ -523,14 +474,15 @@ BOOL isFlowOutOfRange = flowRateDeviation > ROP_FLOW_TARGET_TOLERANCE; // If the ramp up persistent alarm is active, turn off the pump and go to off state - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, isFlowOutOfRange ) ) + /*if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, isFlowOutOfRange ) ) { stopROPump(); result = RO_PUMP_OFF_STATE; SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT, actualFlowRate, MAX_ALLOWED_RAMP_UP_TIME ); - } + }*/ // Control at set interval - else if ( ++roControlTimerCounter >= ROP_RAMP_UP_CONTROL_INTERVAL ) + //else if ( ++roControlTimerCounter >= ROP_RAMP_UP_CONTROL_INTERVAL ) + if ( ++roControlTimerCounter >= ROP_RAMP_UP_CONTROL_INTERVAL ) { F32 targetPressure = getTargetROPumpPressure(); @@ -540,98 +492,37 @@ // be reset to the corresponding pressure of the target flow rate. if ( ( actualPressure > targetPressure ) || ( ( targetPressure - actualPressure ) < MAX_PRESSURE_TARGET_TOLERANCE ) ) { + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); result = RO_PUMP_CONTROL_TO_TARGET_STATE; } - // If the actual flow is still far from target flow, update the duty cycle using the I controller and stay in this state + // else if ( TRUE == isFlowOutOfRange ) { - roPumpDutyCyclePctSet = runPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, targetFlowRate, actualFlowRate ); + roPumpDutyCyclePctSet += ( targetFlowRate - actualFlowRate ) * 0.5; + //roPumpDutyCyclePctSet = ROP_FLOW_TO_PWM_DC( getTargetROPumpFlowRate() ); setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); } // Reached to the target flow go to the next state else { - // Reset all the variables to prepare for transition - flowVerificationCounter = 0; - roPumpFlowRateRunningSum = 0; - roPumpPressureRunningSum = 0; - result = RO_PUMP_VERIFY_FLOW_STATE; + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); + result = RO_PUMP_CONTROL_TO_TARGET_STATE; } roControlTimerCounter = 0; } - if ( TRUE == setupROPumpControl ) + /*if ( TRUE == setupROPumpControl ) { - resetPersistentAlarmTimer( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT ); + //resetPersistentAlarmTimer( ALARM_ID_RO_PUMP_RAMP_UP_TO_FLOW_TIMEOUT ); result = RO_PUMP_CONTROL_SETUP_STATE; - } + }*/ return result; } /*********************************************************************//** * @brief - * The handleROPumpVerifyFlowState function handles the RO pump verify - * flow state of the RO pump controller state machine. - * @details Inputs: flowVerificationCounter, targetROPumpPressure, - * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum - * @details Outputs: flowVerificationCounter, targetROPumpPressure, - * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum - * @return next state of the controller state machine - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_VERIFY_FLOW_STATE; - - // Calculate the running sum of the flow rate and RO pump outlet pressure - roPumpFlowRateRunningSum = roPumpFlowRateRunningSum + (F32)getMeasuredROFlowRate(); - roPumpPressureRunningSum = roPumpPressureRunningSum + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); - - // Check if the time for flow verification has elapsed - if ( ++flowVerificationCounter >= FLOW_VERIFICATION_COUNTER_TARGET ) - { - - // Calculate the average pressure and flow rate - F32 const targetFlowRate = getTargetROPumpFlowRate(); - F32 const avgFlowRate = roPumpFlowRateRunningSum / flowVerificationCounter; - F32 const flowRateDeviation = fabs( targetFlowRate - avgFlowRate ) / targetFlowRate; - - if ( flowRateDeviation < ROP_FLOW_TARGET_TOLERANCE ) - { - F32 const avgPressure = roPumpPressureRunningSum / flowVerificationCounter; - // If the flow has been achieved without reaching the maximum pressure, set the new pressure - // otherwise, stay with the maximum allowed pressure as target pressure - if ( avgPressure < getTargetROPumpPressure() ) - { - targetROPumpPressure = avgPressure; - } - - // Set initial PWM duty cycle and reset controller - setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); - result = RO_PUMP_CONTROL_TO_TARGET_STATE; - } - else - { - if ( ++rampUpRetryCount > ROP_MAX_RAMP_UP_RETRY ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_RO_PUMP_TOO_MANY_RAMP_UP_RETRY, rampUpRetryCount, ROP_MAX_RAMP_UP_RETRY ); - } - result = RO_PUMP_RAMP_UP_STATE; - } - } - - if ( TRUE == setupROPumpControl ) - { - result = RO_PUMP_CONTROL_SETUP_STATE; - } - - return result; -} - -/*********************************************************************//** - * @brief * The handleROPumpControlToTargetState function handles the control to * target state of the RO pump controller state machine. * @details Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter, @@ -648,17 +539,25 @@ { // Get the pressure to use it for setting the control F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + if ( actualPressure >= targetROPumpPressure ) + { + roPumpDutyCyclePctSet -= ROP_RAMP_DOWN_DUTY_CYCLE_RATIO; + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); + } + else + { + roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP, getTargetROPumpFlowRate(), getMeasuredROFlowRate() ); + } - roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP, getTargetROPumpPressure(), actualPressure ); setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); roControlTimerCounter = 0; } - if ( TRUE == setupROPumpControl ) + /*if ( TRUE == setupROPumpControl ) { result = RO_PUMP_CONTROL_SETUP_STATE; - } + }*/ return result; } @@ -834,8 +733,8 @@ if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; - roPumpDataPublishInterval.ovData = intvl; - roPumpDataPublishInterval.override = OVERRIDE_KEY; + roPumpDataPublishInterval.ovData = intvl; + roPumpDataPublishInterval.override = OVERRIDE_KEY; result = TRUE; } Index: firmware/App/Controllers/Thermistors.c =================================================================== diff -u -r2fea76e972a450a97c74b2a9f627095032a3b586 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Controllers/Thermistors.c (.../Thermistors.c) (revision 2fea76e972a450a97c74b2a9f627095032a3b586) +++ firmware/App/Controllers/Thermistors.c (.../Thermistors.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -102,7 +102,8 @@ thermistorsStatus[ THERMISTOR_POWER_SUPPLY_2 ].betaValue = POWER_SUPPLY_THERMISTOR_BETA_VALUE; // Initialize a persistent alarm for thermistors temeprature out of range - initPersistentAlarm( ALARM_ID_DG_THERMISTORS_TEMPERATURE_OUT_OF_RANGE, MAX_ALLOWED_TEMP_OUT_OF_RANGE_PERIOD, MAX_ALLOWED_TEMP_OUT_OF_RANGE_PERIOD ); + //initPersistentAlarm( PERSISTENT_ALARM_THERMISTOR_TEMPERATURE_OUT_OF_RANGE, ALARM_ID_DG_THERMISOTRS_TEMPERATURE_OUT_OF_RANGE, + // TRUE, MAX_ALLOWED_TEMP_OUT_OF_RANGE_PERIOD, MAX_ALLOWED_TEMP_OUT_OF_RANGE_PERIOD ); } /*********************************************************************//** Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -15,9 +15,21 @@ * ***************************************************************************/ +#include "ConductivitySensors.h" +#include "DrainPump.h" +#include "Heaters.h" +#include "LoadCell.h" #include "ModeHeatDisinfect.h" #include "OperationModes.h" #include "Pressures.h" +#include "Reservoirs.h" +#include "ROPump.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TemperatureSensors.h" +#include "Timers.h" +#include "UVReactors.h" +#include "Valves.h" /** * @addtogroup DGHeatDisinfectMode @@ -26,29 +38,156 @@ // ********** 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. + +// 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. + +// Drain R1 & R2 states defines +#define DRAIN_PUMP_TARGET_RPM 1800 ///< Drain pump target RPM during drain. +#define RSRVRS_INITIAL_DRAIN_TIME_OUT_MS ( 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 initial drain time out in milliseconds. +#define RSRVRS_EMPTY_VOL_ML 50.0 ///< Reservoirs 1 & 2 empty volume in mL. //TODO Change this value to actual value +#define DRAIN_WEIGH_UNCHANGE_TIMEOUT ( 2 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. + +// Flush drain path state defines +#define FLUSH_DRAIN_WAIT_TIME_MS ( 60 * MS_PER_SECOND ) ///< Flush Drain path wait time in milliseconds. +#define MIN_INLET_TEMPERATURE_C 25.0 ///< Minimum water inlet temperature in C. +#define MIN_INLET_CONDUCTIVITY_US_PER_CM 0.0 ///< Minimum water inlet conductivity in uS/cm +#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. +#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. +#define MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C 3.0 ///< Maximum flush circulation temperature difference tolerance in C. + +// Flush and drain R1 and R2 +#define RSRVRS_FULL_VOL_ML 2200.0 ///< Reservoirs 1 & 2 full volume in mL. +#define RSRVRS_PARTIAL_FILL_VOL_ML 500.0 ///< Reservoirs 1 & 2 partial volume in mL. +#define RSRVRS_FILL_UP_TIMEOUT_MS ( 5 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 full fill up timeout in ms. +#define RSRVRS_500ML_FILL_UP_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 partial fill up timeout in ms. +#define RSRVRS_DRAIN_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 drain timeout in ms. + +// Fill and heat water +#define HEAT_DISINFECT_TARGET_TEMPERATURE_C 88.0 ///< Heat disinfect target water temperature in C. + +// R1 to R2 & R2 to R1 heat disinfect circulation +#define HEAT_DISINFECT_TARGET_RO_FLOW_LPM 0.2 ///< 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_START_TEMPERATURE_C 81.0 ///< Heat disinfect minimum acceptable temperature in C. +#define HEAT_DISINFECT_TIME_MS ( 10 * 60 * MS_PER_SECOND ) ///< Heat disinfect time for each section in milliseconds. +#define HEAT_DISINFECT_START_TEMP_TIMOUT_MS ( 30 * 60 * MS_PER_SECOND ) ///< Heat disinfect reaching to minimum temperature timeout in milliseconds. +#define RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ( 2 * 60 * MS_PER_SECOND ) ///< Reservoirs 1 & 2 maximum volume out of range timeout during heat disnfect. +#define RSRVRS_MAX_TARGET_VOL_CHANGE_ML 100.0 ///< Reservoirs 1 & 2 maximum allowed volume change when full during heat disinfect. +#define POST_HEAT_DISINFECT_WAIT_TIME_MS ( 1 * 60 * MS_PER_SECOND ) ///< Heat disinfect final wait time before flushing the system in milliseconds. + +// 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. + +/// Name of reservoirs +typedef enum rsrvrs +{ + R1 = 0, ///< Reservoir 1 + R2, ///< Reservoir 2 + NUM_OF_RSRVRS ///< Number of reservoirs +} RSRVRS_T; //TODO remove + +/// TODO remove? +typedef enum rsvrs_status +{ + RSRVR_EMPTY = 0, + RSRVR_PARTIALLY_FULL, + RSVR_FULL, + NUM_OF_RSRVRS_STATUS +} RSRVRS_STATUS_T; + // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state. +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect 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. +/// 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 BOOL isR1Full = FALSE; ///< Reservoir 1 full/empty flag. +static BOOL isR2Full = FALSE; ///< Reservoir 2 full/empty flag. +static U32 R1HeatDisinfectVol = 0; ///< Reservoir 1 full volume during heat disinfect. +static U32 R2HeatDisinfectVol = 0; ///< Reservoir 2 full volume during heat disinfect. +static U32 heatDisinfectTimer = 0; ///< Heat disinfect timer. +static BOOL hasHeatDisinfectStarted = FALSE; ///< Heat disinfect start/not start 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 BOOL hasPostHeatDisinfectWaitStarted = FALSE; ///< Final delay at the end of heat disinfect and before flush flag. +static U32 dataPublishCounter = 0; ///< Heat Disinfect data publish counter. // ********** private function prototypes ********** +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushCirculationState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushR1AndR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushR2AndDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR1ToR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillR2WithHotWater( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR2State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR1ToR2( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR2ToR1AndDrainR1State( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseCirculationState( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeBasicPath( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeColdWaterPath( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectCancelModeHotWaterPath( void ); + +static void resetActuators( void ); +static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T state ); +static BOOL isRsrvrFull( RSRVRS_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T state ); +static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T failedState ); +static BOOL isStateHeatDisinfectComplete( DG_HEAT_DISINFECT_STATE_T state ); +static void publishHeatDisinfectData( void ); + /*********************************************************************//** * @brief - * The initHeatDisinfectMode function initializes the heat disinfect mode module. + * The initHeatDisinfectMode function initializes the heat disinfect mode + * module. * @details Inputs: none - * @details Outputs: Initialized heat disinfect mode module + * @details Outputs: heatDisinfectState, stateTimer, isThisLastDrain, + * stateTrialCounter, areTempSensorsInRange, isR1Full, isR2Full, + * R1HeatDisinfectVol, R2HeatDisinfectVol, hasPostHeatDisinfectWaitStarted, + * overallHeatDisinfectTimer TODO fill up as we go * @return none *************************************************************************/ void initHeatDisinfectMode( void ) { - heatState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; + stateTimer = 0; + isThisLastDrain = FALSE; + stateTrialCounter = 0; + areTempSensorsInRange = FALSE; + isR1Full = FALSE; + isR2Full = FALSE; + R1HeatDisinfectVol = 0; + R2HeatDisinfectVol = 0; + hasPostHeatDisinfectWaitStarted = FALSE; + overallHeatDisinfectTimer = getMSTimerCount(); } /*********************************************************************//** * @brief - * The transitionToHeatDisinfectMode function prepares for transition to heat disinfect mode. + * The transitionToHeatDisinfectMode function prepares for transition to + * heat disinfect mode. * @details Inputs: none - * @details Outputs: Prepare for transition to heat disinfect mode + * @details Outputs: none * @return none *************************************************************************/ void transitionToHeatDisinfectMode( void ) @@ -58,41 +197,1089 @@ /*********************************************************************//** * @brief - * The execHeatDisinfectMode function executes the heat disinfect mode state machine. - * @details Inputs: none - * @details Outputs: Heat disinfect mode state machine executed + * The execHeatDisinfectMode function executes the heat disinfect mode + * state machine. + * @details Inputs: heatDisinfectState + * @details Outputs: heatDisinfectState * @return current state *************************************************************************/ U32 execHeatDisinfectMode( void ) { - checkInletPressureFault(); + checkInletPressureFault(); // TODO what is this? - // execute current heat disinfect state - switch ( heatState ) + switch ( heatDisinfectState ) { case DG_HEAT_DISINFECT_STATE_START: + heatDisinfectState = handleHeatDisinfectStartState(); break; + case DG_HEAT_DISINFECT_STATE_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_DRAIN_R2: + heatDisinfectState = handleHeatDisinfectDrainR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN: + heatDisinfectState = handleHeatDisinfectFlushDrainState(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION: + heatDisinfectState = handleHeatDisinfectFlushCirculationState(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_R1_AND_R2: + heatDisinfectState = handleHeatDisinfectFlushR1AndR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectFlushR2AndDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R2: + heatDisinfectState = handleHeatDisinfectFlushDrainR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectFlushDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER: + heatDisinfectState = handleHeatDisinfectFillWithWaterState(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2: + heatDisinfectState = handleHeatDisinfectDisinfectR1ToR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER: + heatDisinfectState = handleHeatDisinfectFillR2WithHotWater(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1: + heatDisinfectState = handleHeatDisinfectDisinfectR2ToR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectMixDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R2: + heatDisinfectState = handleHeatDisinfectMixDrainR2State(); + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2: + heatDisinfectState = handleHeatDisinfectRinseR1ToR2(); + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1: + heatDisinfectState = handleHeatDisinfectRinseR2ToR1AndDrainR1State(); + break; + + case DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION: + heatDisinfectState = handleHeatDisinfectRinseCirculationState(); + break; + + case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_BASIC_PATH: + break; + + case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_COLD_WATER_PATH: + break; + + case DG_HEAT_DISINFECT_STATE_CANCEL_MODE_HOT_WATER_PATH: + break; + + case DG_HEAT_DISINFECT_STATE_COMPLETE: + // Done with heat disinfect cycle, complete or not + break; + default: - // TODO - s/w fault - heatState = DG_HEAT_DISINFECT_STATE_START; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_HEAT_DISINFECT_INVALID_EXEC_STATE, heatDisinfectState ) + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; break; } - return heatState; + publishHeatDisinfectData(); + + return heatDisinfectState; } /*********************************************************************//** * @brief - * The getCurrentHeatDisinfectState function returns the current state of the - * heat disinfect mode. - * @details Inputs: heatState + * The getCurrentHeatDisinfectState function returns the current state of + * the heat disinfect mode. + * @details Inputs: heatDisinfectState * @details Outputs: none * @return the current state of heat disinfect mode. *************************************************************************/ DG_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ) { - return heatState; + return heatDisinfectState; } +/*********************************************************************//** + * @brief + * The stopDGHeatDisinfect function stops heat disinfect mode. + * @details Inputs: heatDisinfectionState + * @details Outputs: heatDisinfectionState + * @return none + *************************************************************************/ +void stopDGHeatDisinfect( void ) +{ + heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; + resetActuators(); + + requestNewOperationMode( DG_MODE_STAN ); +} + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectStartState function handles the heat disinfect + * start state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStartState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + + // Set all the actuators to reset and deenergized state + resetActuators(); + + F32 ppiPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); + F32 TDiTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TRoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); + + // If the inlet pressure is less than the threshold or TDi and TRo difference is greater than 1 C, the cycle + // should be canceled + if ( ppiPressure < MIN_INLET_PRESSURE_PSI && fabs( TDiTemp - TRoTemp ) > MAX_START_STATE_TEMP_SENSORS_DIFF_C ) + { + setModeToFailed( state ); + } + else + { + // Close VPi to prevent wasting water + setValveState( VPI, VALVE_STATE_CLOSED ); + + // Set the actuators to drain R1 + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + stateTimer = getMSTimerCount(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDrainR1State function handles the heat disinfect + * drain R1 state. + * @details Inputs: stateTimer, isR1Full, isThisLastDrain + * @details Outputs: stateTimer, isR1Full + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + isR1Full = FALSE; + + if ( isThisLastDrain ) + { + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + + //TODO turn on the concentrate pumps + + // TODO discuss the cooling process for proper flow rate and pressure set + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + + // Done with final rinsing + isThisLastDrain = FALSE; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; + } + else + { + // Set the actuators to drain R2. + // NOTE: Drain pump is already on and VDr is already on drain state + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDrainR2State function handles the heat disinfect + * drain R2 state. + * @details Inputs: stateTimer, isR2Full, isThisLastDrain + * @details Outputs: stateTimer, isR2Full + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + isR2Full = FALSE; + + if ( isThisLastDrain ) + { + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + state = DG_HEAT_DISINFECT_STATE_DRAIN_R1; + } + else + { + stateTrialCounter = 0; + setValveState( VPI, VALVE_STATE_OPEN ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushDrainState function handles the heat disinfect + * flush drain state. + * @details Inputs: stateTimer, stateTrialCounter + * @details Outputs: stateTimer, stateTrialCounter + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN; + + // Check if flush time has elapsed + if ( didTimeout( stateTimer, FLUSH_DRAIN_WAIT_TIME_MS ) ) + { + // If the inlet temperature and conductivity are in range, move onto the next state + if ( getTemperatureValue( TEMPSENSORS_INLET_PRIMARY_HEATER ) > MIN_INLET_TEMPERATURE_C /*&& + getConductivityValue( CONDUCTIVITYSENSORS_CPI_SENSOR ) > MIN_INLET_CONDUCTIVITY_US_PER_CM*/ ) + { + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NC ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLUSH_FILL_FLOW_RATE_LPM, MAX_RO_PUMP_FLUSH_FILL_PRESSURE_PSI ); + stateTimer = getMSTimerCount(); + stateTrialCounter = 0; + state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; + } + // If the failure is still in range, reset the timer and start over + else if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) + { + stateTimer = getMSTimerCount(); + } + // Couldn't get a good water sample after a couple of trials and the disinfection cycle failed + else + { + setModeToFailed( state ); + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushCirculationState function handles the heat + * disinfect flush circulation state. + * @details Inputs: stateTimer, stateTrialCounter + * @details Outputs: stateTimer, stateTrialCounter + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushCirculationState( void ) +{ + 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 ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) && FALSE == areTempSensorsInRange ) + { + // TODO add TPm later. This is the new temp sensor of the coldest spot. It is temporarily TDi. + F32 TPmTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TD1Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_1 ); + F32 TD2Temp = getTemperatureValue( TEMPSENSORS_CONDUCTIVITY_SENSOR_2 ); + F32 avgTemp = ( TPmTemp + TPoTemp + TD1Temp + TD2Temp ) / 4.0; + + BOOL isTPmOut = fabs( TPmTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + BOOL isTPoOut = fabs( TPoTemp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + BOOL isTD1Out = fabs( TD1Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + BOOL isTD2Out = fabs( TD2Temp - avgTemp ) > MAX_FLUSH_CIRC_TEMP_SENSOR_DIFF_C; + + // Check if any of the temperature sensors are out of tolerance + if( isTPmOut || isTPoOut || isTD1Out || isTD2Out ) + { + // Check if we have exceeded the number of trials. If not, try another time + if ( ++stateTrialCounter < MAX_ALLOWED_STATE_TRIALS ) + { + stateTimer = getMSTimerCount(); + } + // State failed. Cancel heat disinfect mode + else + { + setModeToFailed( state ); + } + } + else + { + areTempSensorsInRange = TRUE; + stateTimer = getMSTimerCount(); + // TODO Turn on the concentrate pumps and wait for 30 seconds + } + } + + // Only start the concentrate pumps if the temperature sensors are in range + if ( areTempSensorsInRange ) + { + // TODO: enable the timeout once the concentrate pumps are available. + //if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) + if ( TRUE ) + { + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_R1_AND_R2; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushR1AndR2State function handles the heat + * disinfect flush reservoir 1 and reservoir 2 state. + * @details Inputs: stateTimer, isR1Full, isR2Full + * @details Outputs: stateTimer, isR1Full, isR2Full + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushR1AndR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; + + // If R1 is not full, keep monitoring for R1 level and timeout + if ( FALSE == isR1Full ) + { + isR1Full = isRsrvrFull( R1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + } + // Once R1 is full, keep monitoring for R2 level and timeout + if( isR1Full ) + { + isR2Full = isRsrvrFull( R2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + + // Once R2 is full (to 500mL in this case), transition to the next state + if ( isR2Full ) + { + // Set the actuators to flush R2 and drain R1 state + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_R2_AND_DRAIN_R1; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushR2AndDrainR1State function handles the heat + * disinfect flush reservoir 2 and drain reservoir 1 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushR2AndDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_CIRCULATION; + + // If reservoir 1 is empty, turn off the drain pump + if ( FALSE == isR1Full ) + { + isR1Full = isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ); + + // Done with draining R1 + signalDrainPumpHardStop(); + } + + // First reservoir 2 must be completely full + if ( FALSE == isR2Full ) + { + isR2Full = isRsrvrFull( R2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + } + // Once R2 is full, R1 must be partially full + else + { + isR1Full = isRsrvrFull( R1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + + // Once R1 is partially full, transition to the next state + if ( isR1Full ) + { + // Done with filing turn off the RO pump + signalROPumpHardStop(); + + // Set the valves to drain R2 and no fill + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R2; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushDrainR2State function handles the heat + * disinfect flush drain reservoir 2 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R2; + + // If reservoir 2 is empty, set the drain valve to drain R1 + if (isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFlushDrainR1State function handles the heat + * disinfect flush drain reservoir 1 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFlushDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FLUSH_DRAIN_R1; + + // If reservoir 1 is empty, set the state to fill water state + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + + // 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 + setPrimaryHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE_C ); + startPrimaryHeater(); + + // Start the timer for drain timeout + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFillWithWaterState function handles the heat + * disinfect fill with water state. + * @details Inputs: stateTimer, isR1Full, isR2Full + * @details Outputs: stateTimer, isR1Full, isR2Full + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + + // First reservoir 1 must be full + if ( FALSE == isR1Full ) + { + isR1Full = isRsrvrFull( R1, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + } + // Once reservoir 1 is full, check the status of reservoir 2 since the water overflows to reservoir 2 + else + { + isR2Full = isRsrvrFull( R2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + + // Once reservoir 2 is full, set the actuators for recirculation + if ( isR2Full ) + { + // Set the valves to drain R2 and no fill + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + setValveState( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + + // Set the RO flow to maximum pressure of 25psi 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 ); + + //TODO add the new control api for the drain pump + + // Start the trimmer heater since we are recirculating water + 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 = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + R2HeatDisinfectVol = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + + stateTimer = getMSTimerCount(); + rsrvrsVolMonitorTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDisinfectR1ToR2State function handles the heat + * disinfect R1 to R2 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR1ToR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + + if ( isStateHeatDisinfectComplete( state ) ) + { + //TODO turn off CP1 and CP2 + + // Set the valves to transfer hot water from R1 to R2 and fill up R2. + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFillR2WithHotWater function handles fill R2 + * with water state. + * @details Inputs: R1HeatDisinfectVol, R2HeatDisinfectVol + * @details Outputs: R1HeatDisinfectVol, R2HeatDisinfectVol + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillR2WithHotWater( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + + // In this state, R2 is fully filled up and R1 is partially filled up with hot water + // So waiting for R1 to get to the level of defined partially full + BOOL isR1PartiallyFull = fabs( getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - RSRVRS_PARTIAL_FILL_VOL_ML ) < RSRVRS_MAX_TARGET_VOL_CHANGE_ML; + + if ( isRsrvrFull( R2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ) && isR1PartiallyFull ) + { + // Get the current volumes to be monitored during R2 to R1 heat disinfect state + R1HeatDisinfectVol = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + R2HeatDisinfectVol = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + + //TODO turn on CP1 and CP2 + + state = DG_HEAT_DISINFECT_STATE_DISINFECT_R2_TO_R1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDisinfectR2ToR1State function handles the heat + * disinfect R2 to R1 state. + * @details Inputs: hasPostHeatDisinfectWaitStarted, stateTimer + * @details Outputs: hasPostHeatDisinfectWaitStarted, stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDisinfectR2ToR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_R2_WITH_HOT_WATER; + + // Keep monitoring for the end of heat disinfect and while the port delay has not started + if ( isStateHeatDisinfectComplete( state ) && FALSE == hasPostHeatDisinfectWaitStarted ) + { + // Turn off the pumps and heaters + //TODO turn off CP1 and CP2 + stopPrimaryHeater(); + stopTrimmerHeater(); + + hasPostHeatDisinfectWaitStarted = TRUE; + stateTimer = getMSTimerCount(); + } + else if ( hasPostHeatDisinfectWaitStarted && didTimeout( stateTimer, POST_HEAT_DISINFECT_WAIT_TIME_MS ) ) + { + // Stop the drain pump to exit the closed loop + signalDrainPumpHardStop(); + + // Deenergize all the valves that are not in the path anymore and set the other + // valves to drain the hot water + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + // Turn on the drain pump to drain the reservoirs in open loop mode + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimer = getMSTimerCount(); + hasPostHeatDisinfectWaitStarted = FALSE; + state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectMixDrainR1State function handles the heat + * disinfect mix drain R1 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R1; + + if ( isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + isR1Full = FALSE; + + // Set the drain valve to reservoir 2 + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R2; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectMixDrainR2State function handles the heat + * disinfect mix drain R2 state. + * @details Inputs: stateTimer + * @details Outputs: stateTimer + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectMixDrainR2State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_MIX_DRAIN_R2; + + if ( isRsrvrEmpty( DG_RESERVOIR_2, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ) ) + { + isR2Full = FALSE; + + // Done with draining the reservoirs + signalDrainPumpHardStop(); + + // Set the valves to fill up R1 and overflow to R2 + // The RO pump is still running at low pressure until the coldest + // spot temperature is less than 45 C. + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectRinseR1ToR2 function handles the heat + * disinfect rinse R1 to R2 state. + * @details Inputs: stateTimer, isR1Full, isR2Full + * @details Outputs: stateTimer, isR1Full, isR2Full + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR1ToR2( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_RINSE_R1_TO_R2; + + if ( FALSE == isR1Full ) + { + // Since reservoir 1 is being filled up at a lower flow rate, the timeout is twice as long as a normal fill up + isR1Full = isRsrvrFull( R1, RSRVRS_FULL_VOL_ML, 2 * RSRVRS_FILL_UP_TIMEOUT_MS, state ); + } + else + { + // Since reservoir 2 is being filled up at a lower flow rate, the timeout is longer than a normal fill up + isR2Full = isRsrvrFull( R2, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + + if ( isR2Full ) + { + // Set the valves to rinses R2 to R1 and drain R1 + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectRinseR2ToR1AndDrainR1State function handles the + * heat disinfect rinse R2 to R1 and drain R1 state. + * @details Inputs: stateTimer, isR1Full, isR2Full, isThisLastDrain + * @details Outputs: stateTimer, isR1Full, isR2Full, isThisLastDrain + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseR2ToR1AndDrainR1State( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_RINSE_R2_TO_R1_AND_DRAIN_R1; + + if ( isR1Full ) + { + // Since reservoir 1 is being filled up at a lower flow rate, the timeout is twice as long as a normal fill up + isR1Full = isRsrvrEmpty( DG_RESERVOIR_1, DRAIN_WEIGH_UNCHANGE_TIMEOUT, RSRVRS_INITIAL_DRAIN_TIME_OUT_MS, state ); + + // Done with draining R1 + signalDrainPumpHardStop(); + } + else if ( FALSE == isR1Full ) + { + if ( FALSE == isR2Full ) + { + isR2Full = isRsrvrFull( R2, RSRVRS_FULL_VOL_ML, RSRVRS_FILL_UP_TIMEOUT_MS, state ); + } + else + { + isR1Full = isRsrvrFull( R1, RSRVRS_PARTIAL_FILL_VOL_ML, RSRVRS_500ML_FILL_UP_TIMEOUT_MS, state ); + + if ( isR1Full ) + { + // Done with filling, turn off the RO pump + signalROPumpHardStop(); + + // Deenergize all the valves and set the VDr to drain R2 + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_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 ); + + // Turn on the drain pump to drain R2 + setDrainPumpTargetRPM( DRAIN_PUMP_TARGET_RPM ); + + // This is the last drain of heat disinfect cycle + isThisLastDrain = TRUE; + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DRAIN_R2; + } + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectRinseCirculationState function handles the + * heat disinfect rinse RO circulation and conectrate pumps state. + * @details Inputs: none + * @details Outputs: none + * @return next state of the heat disinfect state machine + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRinseCirculationState( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_RINSE_CIRCULATION; + + if ( didTimeout( stateTimer, FLUSH_CICRCULATION_WAIT_TIME_MS ) ) + { + // Done with heat disinfect cycle + resetActuators(); + + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The resetActuators function sets all the actuators to reset and + * deenergized 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 ); + + // Deenergize all the valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( 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 setModeToFailed function sets the heat disinfect mode to failed + * by changing the state to complete. + * @details Inputs: heatDisinfectState + * @details Outputs: heatDisinfectState + * @param failedStated which is the state heat disinfect mode failed + * @return none + *************************************************************************/ +static void setModeToFailed( DG_HEAT_DISINFECT_STATE_T failedState ) +{ + heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; + + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_HEAT_DISINFECT_CYCLE_FAILED, failedState ) +} + +/*********************************************************************//** + * @brief + * The isRsrvrFull function checks whether the target reservoir is full or + * not. If the fill times out, it sets the state machine to complete and + * exits the heat disinfect mode. + * @details Inputs: none + * @details Outputs: none + * @param r is either R1 or R2 + * @param targetVol is the target fill volume + * @param timeout is the fill up timeout + * @param state is the state that called this function + * @return none + *************************************************************************/ +static BOOL isRsrvrFull( RSRVRS_T r, F32 targetVol, U32 timeout, DG_HEAT_DISINFECT_STATE_T state ) +{ + BOOL rsrvrStatus = FALSE; + F32 volume = 0.0; + + if ( r == R1 ) + { + volume = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ); + } + else if ( r == R2 ) + { + volume = getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_2_PRIMARY ); + } + + // Check the volume of the reservoir against the target volume + if ( volume >= targetVol ) + { + rsrvrStatus = TRUE; + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + else if ( didTimeout( stateTimer, timeout ) ) + { + // Fill timed out + setModeToFailed( state ); + } + + return rsrvrStatus; +} + +/*********************************************************************//** + * @brief + * The isRsrvrEmpty function checks whether the target reservoir is empty + * or not. If the fill times out, it sets the state machine to complete and + * exits the heat disinfect mode. + * @details Inputs: none + * @details Outputs: none + * @param r is R1 or R2 + * @param state is the state that called this function + * @return none + *************************************************************************/ +static BOOL isRsrvrEmpty( DG_RESERVOIR_ID_T r, U32 drainSteadyStateTimeout, U32 timeout, DG_HEAT_DISINFECT_STATE_T failedState ) +{ + BOOL isDrainComplete = FALSE; + + isDrainComplete = hasTargetDrainVolumeBeenReached( r, drainSteadyStateTimeout); + + if ( TRUE == isDrainComplete ) + { + // Set the state timer in case it needs to be used for another timeout check + stateTimer = getMSTimerCount(); + } + else if ( didTimeout( stateTimer, RSRVRS_DRAIN_TIMEOUT_MS ) ) + { + setModeToFailed( failedState ); + } + + return isDrainComplete; +} + +/*********************************************************************//** + * @brief + * The isStateHeatDisinfectComplete function monitors and runs the current + * stage of heat disinfect cycle. + * @details Inputs: areRsrvrsLeaking, areRsrvrsLeaking + * @details Outputs: areRsrvrsLeaking, areRsrvrsLeaking + * @param state is the state that called this function + * @return TRUE if this stage of heat disinfect cycle is done + *************************************************************************/ +static BOOL isStateHeatDisinfectComplete( DG_HEAT_DISINFECT_STATE_T state ) +{ + BOOL heatDisinfectStatus = FALSE; + + F32 TPoTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TPmTemp = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); //TODO change this to actual TPm sensor later + + BOOL isR1OutOfRange = fabs( getLoadCellFilteredWeight( LOAD_CELL_RESERVOIR_1_PRIMARY ) - R1HeatDisinfectVol ) > RSRVRS_MAX_TARGET_VOL_CHANGE_ML; + BOOL isR2OutOfRange = fabs( getLoadCellFilteredWeight( 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 the leak is the first time after a while, set the flag and start the timer + if ( FALSE == areRsrvrsLeaking ) + { + areRsrvrsLeaking = TRUE; + rsrvrsVolMonitorTimer = getMSTimerCount(); + } + // If the volume is out of range and it has timed out, exit + else if ( didTimeout( rsrvrsVolMonitorTimer, RSRVRS_TARGET_VOL_OUT_TIMEOUT_MS ) ) + { + areRsrvrsLeaking = FALSE; + setModeToFailed( state ); + } + } + // We are in range + else + { + areRsrvrsLeaking = FALSE; + } + + // If the coldest spot which is TPm is less than minimum heat disinfect temperature, + // reset the heat disinfect timers and check whether heating up has timed out + if ( TPmTemp < HEAT_DISINFECT_START_TEMPERATURE_C ) + { + hasHeatDisinfectStarted = FALSE; + + if ( didTimeout( stateTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + { + // Heating up to minimum temperature for heat disinfect failed + setModeToFailed( state ); + } + } + else + { + // The temperature of the coldest spot is in range start. Start the timer for heat disinfect cycle + heatDisinfectTimer = getMSTimerCount(); + hasHeatDisinfectStarted = TRUE; + } + + // If the flag is TRUE, check if this stage of heat disinfect is done + if ( hasHeatDisinfectStarted ) + { + if ( didTimeout( heatDisinfectTimer, HEAT_DISINFECT_START_TEMP_TIMOUT_MS ) ) + { + // Done with this stage of heat disnfect. Reset the variables + heatDisinfectStatus = TRUE; + hasHeatDisinfectStarted = FALSE; + } + } + + return heatDisinfectStatus; +} + +/*********************************************************************//** + * @brief + * The publishHeatDisinfectData function publishes heat disinfect data at + * the set interval. + * @details Inputs: dataPublishCounter + * @details Outputs: dataPublishCounter + * @return: none + *************************************************************************/ +static void publishHeatDisinfectData( void ) +{ + if ( ++dataPublishCounter > HEAT_DISINFECT_DATA_PUB_INTERVAL ) + { + MODE_HEAT_DISINFECT_DATA_T data; + + data.heatDisinfectState = (U32)heatDisinfectState; + // Get the time elapsed so far and convert them to minutes TODO remove the timings? + data.overallElapsedTime = calcTimeSince( overallHeatDisinfectTimer ) / ( 60 * MS_PER_SECOND ); + data.heatDisinfectElapsedTime = calcTimeSince( stateTimer ) / ( 60 * MS_PER_SECOND ); + + broadcastHeatDisinfectData( &data ); + + dataPublishCounter = 0; + } +} + /**@}*/ Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r55425a4c5370a6fa1faad61dc24fcd76b854d3ed -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 55425a4c5370a6fa1faad61dc24fcd76b854d3ed) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -87,7 +87,8 @@ 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 ); + setROPumpTargetFlowRate( TARGET_RO_FLOW_RATE_L, 50 /*TARGET_RO_PRESSURE_PSI*/ ); + signalDrainPumpHardStop(); startPrimaryHeater(); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1 ); Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r5fc16235c1752c993b3f1285f3a2b9738372af7a -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 5fc16235c1752c993b3f1285f3a2b9738372af7a) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -89,8 +89,8 @@ requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2 ); // UV off - resetReservoirLoadCellsOffset( RESERVOIR_1 ); - resetReservoirLoadCellsOffset( RESERVOIR_2 ); + resetReservoirLoadCellsOffset( DG_RESERVOIR_1 ); + resetReservoirLoadCellsOffset( DG_RESERVOIR_2 ); } /*********************************************************************//** Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -r5fc16235c1752c993b3f1285f3a2b9738372af7a -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 5fc16235c1752c993b3f1285f3a2b9738372af7a) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -163,7 +163,8 @@ SW_FAULT_ID_DRAIN_PUMP_INVALID_DELTA_PRESSURE_SELECTED, SW_FAULT_ID_INVALID_TEMPERATURE_SENSOR_SELECTED, SW_FAULT_ID_DRAIN_PUMP_INVALID_RPM_SELECTED, - SW_FAULT_ID_HEAT_DISINFECT_INVALID_EXEC_STATE, + SW_FAULT_ID_ALARM_MGMT_INVALID_ALARM_ID, + SW_FAULT_ID_HEAT_DISINFECT_INVALID_EXEC_STATE, // 75 NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; @@ -175,8 +176,11 @@ void activateAlarmNoData( ALARM_ID_T alarm ); void activateAlarm1Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData ); void activateAlarm2Data( ALARM_ID_T alarm, ALARM_DATA_T alarmData1, ALARM_DATA_T alarmData2 ); -void clearAlarm( ALARM_ID_T alarm ); -BOOL isAlarmActive( ALARM_ID_T alarm ); +void clearAlarm( ALARM_ID_T alarm ); +void clearAlarmCondition( ALARM_ID_T alarm ); +BOOL isAlarmActive( ALARM_ID_T alarm ); + +void checkPersistentAlarm( ALARM_ID_T alarm, BOOL const isErrorOccured, F32 const data, F32 const limit ); BOOL testSetAlarmStateOverride( U32 alarmID, BOOL value ); BOOL testResetAlarmStateOverride( U32 alarmID ); Index: firmware/App/Services/MessagePayloads.h =================================================================== diff -u -re0265b8fad80add7a5d54db11ecc72fd6b1665a8 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/MessagePayloads.h (.../MessagePayloads.h) (revision e0265b8fad80add7a5d54db11ecc72fd6b1665a8) +++ firmware/App/Services/MessagePayloads.h (.../MessagePayloads.h) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -84,13 +84,6 @@ U32 drainToVolumeMl; ///< Volume target to drain to } RESERVOIR_DATA_T; -/// Target temperature payload struct. -typedef struct -{ - F32 targetPrimaryHeaterTemp; ///< Primary heater set temperature target - F32 targetTrimmerHeaterTemp; ///< Trimmer heater set temperature target -} TARGET_TEMPS_PAYLOAD_T; - #pragma pack(pop) /**@}*/ Index: firmware/App/Services/PIControllers.c =================================================================== diff -u -r64b37cc2955d04bbc77ea41940b1b1b30c06651b -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 64b37cc2955d04bbc77ea41940b1b1b30c06651b) +++ firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -61,11 +61,10 @@ /// PI Controllers - initial configurations. static PI_CONTROLLER_T piControllers[ NUM_OF_PI_CONTROLLERS_IDS ] = { // Kp Ki uMax uMin ref meas err esw esum ctrl - { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_RO_PUMP - { 0.0, 0.0, 3000, 300, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, CONTROLLER_BIDIRECTIONAL }, // PI_CONTROLLER_ID_DRAIN_PUMP - { 0.0, 0.0, 1.39, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_PRIMARY_HEATER - { 0.0, 0.0, 0.50, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_TRIMMER_HEATER - { 0.0, 0.0, 0.99, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, CONTROLLER_UNIDIRECTIONAL }, // I_CONTROLLER_ID_RO_PUMP_RAMP_UP + { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_RO_PUMP + { 0.0, 0.0, 3000, 300, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_BIDIRECTIONAL }, // PI_CONTROLLER_ID_DRAIN_PUMP + { 0.0, 0.0, 1.39, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_PRIMARY_HEATER + { 0.0, 0.0, 0.50, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_TRIMMER_HEATER }; /*********************************************************************//** Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r484b185f0cf4b2ea0ba9de331573952b1b5124b4 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 484b185f0cf4b2ea0ba9de331573952b1b5124b4) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -77,12 +77,8 @@ * @return none *************************************************************************/ void initReservoirs( void ) -{ - activeReservoir.data = DG_RESERVOIR_2; - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); +{ + setActiveReservoirCmd( DG_RESERVOIR_1 ); fillVolumeTargetMl.data = DEFAULT_FILL_VOLUME_ML; drainVolumeTargetMl.data = DEFAULT_DRAIN_VOLUME_ML; } Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r6145c5d1a645646587fb077df3c61eef2354f744 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 6145c5d1a645646587fb077df3c61eef2354f744) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -1039,6 +1039,11 @@ handleTesterLogInRequest( message ); break; + case MSG_ID_DG_START_STOP_HEAT_DISINFECT: + handleStartStopDGHeatDisinfect( message ); + break; + + default: // unrecognized message ID received - ok, ignore - may be a test message handled below break; @@ -1141,10 +1146,6 @@ handleTestDGAccelBroadcastIntervalOverrideRequest( message ); break; - case MSG_ID_DG_ACCEL_SET_CALIBRATION: - handleSetAccelCalibration( message ); - break; - case MSG_ID_DRAIN_PUMP_SET_DELTA_PRESSURE_OVERRIDE: handleSetDrainPumpDeltaPressureOverrideRequest( message ); break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r9f403b860d7767f4fb07e13692ccdc9852a42105 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 9f403b860d7767f4fb07e13692ccdc9852a42105) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -260,7 +260,7 @@ * @param alarm ID of alarm cleared * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ -BOOL broadcastAlarmCleared( U16 alarm ) +BOOL broadcastAlarmCleared( U32 alarm ) { BOOL result; MESSAGE_T msg; @@ -269,9 +269,9 @@ // create a message record blankMessage( &msg ); msg.hdr.msgID = MSG_ID_ALARM_CLEARED; - msg.hdr.payloadLen = sizeof( U16 ); + msg.hdr.payloadLen = sizeof( U32 ); - memcpy( payloadPtr, &alarm, sizeof( U16 ) ); + memcpy( payloadPtr, &alarm, sizeof( U32 ) ); // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_ALARM, ACK_REQUIRED ); @@ -281,6 +281,35 @@ /*********************************************************************//** * @brief + * The broadcastAlarmConditionCleared function constructs an alarm condition + * cleared msg to be broadcast and queues the msg for transmit on the + * appropriate CAN channel. + * @details Inputs: none + * @details Outputs: alarm condition cleared msg constructed and queued. + * @param alarm ID of alarm which alarm condition is cleared + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastAlarmConditionCleared( U32 alarm ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_ALARM_CONDITION_CLEARED; + msg.hdr.payloadLen = sizeof( U32 ); + + memcpy( payloadPtr, &alarm, sizeof( U32 ) ); + + // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_ALARM, ACK_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief * The broadcastAccelData function constructs an accelerometer data msg to * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details Inputs: none @@ -875,6 +904,29 @@ return result; } +/*********************************************************************//** + * The sendCommandResponseMsg function constructs a command response to HD + * and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: Command response msg constructed and queued. + * @param cmdResponsePtr pointer to command response data record + * @return none + *************************************************************************/ +void sendCommandResponseMsg( DG_CMD_RESPONSE_T *cmdResponsePtr ) +{ + MESSAGE_T msg; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_COMMAND_RESPONSE; + msg.hdr.payloadLen = sizeof( DG_CMD_RESPONSE_T ); + + memcpy( msg.payload, cmdResponsePtr, sizeof( DG_CMD_RESPONSE_T ) ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_2_HD, ACK_REQUIRED ); +} + // *********************************************************************** // **************** Message Handling Helper Functions ******************** // *********************************************************************** @@ -894,20 +946,46 @@ if ( message->hdr.payloadLen == sizeof( U32 ) ) { - RESERVOIR_ID_T reservoirID; + DG_RESERVOIR_ID_T reservoirID; U32 resID; result = TRUE; memcpy( &resID, message->payload, sizeof( U32 ) ); - reservoirID = (RESERVOIR_ID_T)resID; + reservoirID = (DG_RESERVOIR_ID_T)resID; setActiveReservoirCmd( reservoirID ); } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); } + /*********************************************************************//** * @brief + * The handleChangeValveSettingCmd function handles a switch reservoirs command + * from the HD. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleChangeValveSettingCmd( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof( U32 ) ) + { + DG_VALVE_SETTING_ID_T valveSettingID; + + result = TRUE; + memcpy( &valveSettingID, message->payload, sizeof( U32 ) ); + changeValveSettingCmd( valveSettingID ); + } + + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); +} + +/*********************************************************************//** + * @brief * The handleFillCmd function handles a fill command from the HD. * @details Inputs: none * @details Outputs: message handled @@ -1000,20 +1078,13 @@ { BOOL result = FALSE; - if ( message->hdr.payloadLen == sizeof( U32 ) ) + if ( message->hdr.payloadLen == sizeof( TRIMMER_HEATER_CMD_T ) ) { - BOOL startingHeater; + TRIMMER_HEATER_CMD_T heaterCmd; - memcpy( &startingHeater, message->payload, sizeof( U32 ) ); - - if ( TRUE == startingHeater ) - { - result = startTrimmerHeaterCmd(); - } - else - { - result = stopTrimmerHeaterCmd(); - } + result = TRUE; + memcpy( &heaterCmd, message->payload, sizeof( TRIMMER_HEATER_CMD_T ) ); + handleTrimmerHeaterCmd( &heaterCmd ); } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -re0265b8fad80add7a5d54db11ecc72fd6b1665a8 -r9ce06772b2f651c57144327e6cbf886e2bc22dee --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision e0265b8fad80add7a5d54db11ecc72fd6b1665a8) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 9ce06772b2f651c57144327e6cbf886e2bc22dee) @@ -24,6 +24,7 @@ #include "Heaters.h" #include "ModeHeatDisinfect.h" #include "MsgQueues.h" +#include "Reservoirs.h" #include "ROPump.h" #include "Thermistors.h" #include "UVReactors.h" @@ -47,8 +48,11 @@ BOOL broadcastAlarmTriggered( U32 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); // MSG_ID_ALARM_CLEARED -BOOL broadcastAlarmCleared( U16 alarm ); +BOOL broadcastAlarmCleared( U32 alarm ); +// MSG_ID_ALARM_CONDITION_CLEARED +BOOL broadcastAlarmConditionCleared( U32 alarm ); + // MSG_ID_DG_ACCELEROMETER_DATA BOOL broadcastAccelData( F32 x, F32 y, F32 z, F32 xm, F32 ym, F32 zm, F32 xt, F32 yt, F32 zt ); @@ -94,6 +98,12 @@ // MSG_ID_DG_FANS_DATA BOOL broadcastFansData( FANS_DATA_T * fansData ); +// MSG_ID_DG_UV_REACTORS_DATA +BOOL broadcastUVReactorsData( UV_REACTORS_DATA_T *uvReactorsData ); + +// MSG_ID_DG_COMMAND_RESPONSE +void sendCommandResponseMsg( DG_CMD_RESPONSE_T *cmdResponsePtr ); + // MSG_ID_POWER_OFF_WARNING void handlePowerOffWarning( MESSAGE_T *message ); @@ -103,13 +113,16 @@ // MSG_ID_REQUEST_FW_VERSIONS void handleFWVersionCmd( MESSAGE_T *message ); -// MSG_ID_DG_SWITCH_RESERVOIR +// MSG_ID_DG_SWITCH_RESERVOIR_CMD void handleSwitchReservoirCmd( MESSAGE_T *message ); -// MSG_ID_DG_FILL +// MSG_ID_DG_CHANGE_VALVE_SETTING_CMD +void handleChangeValveSettingCmd( MESSAGE_T *message ); + +// MSG_ID_DG_FILL_CMD void handleFillCmd( MESSAGE_T *message ); -// MSG_ID_DG_DRAIN +// MSG_ID_DG_DRAIN_CMD void handleDrainCmd( MESSAGE_T *message ); // MSG_ID_STARTING_STOPPING_TREATMENT