/************************************************************************** * * Copyright (c) 2020-2023 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file ROPump.c * * @author (last) Dara Navaei * @date (last) 21-Dec-2022 * * @author (original) Sean * @date (original) 04-Apr-2020 * ***************************************************************************/ #include #include "etpwm.h" #include "mibspi.h" #include "ConcentratePumps.h" #include "FlowSensors.h" #include "FPGA.h" #include "InternalADC.h" #include "NVDataMgmt.h" #include "MessageSupport.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "PIControllers.h" #include "Pressures.h" #include "ROPump.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" #include "Utilities.h" #include "Valves.h" /** * @addtogroup ROPump * @{ */ // ********** private definitions ********** #define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. #define MAX_RO_PUMP_DUTY_CYCLE 0.99F ///< Max duty cycle. #define MIN_RO_PUMP_DUTY_CYCLE 0.0F ///< Min duty cycle. #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_RAMP_UP_P_COEFFICIENT 0.22F ///< P term for RO pump ramp up to flow control. #define ROP_FLOW_CONTROL_P_COEFFICIENT 0.15F ///< P term for RO pump flow control. #define ROP_FLOW_CONTROL_I_COEFFICIENT 0.65F ///< I term for RO pump flow control. #define ROP_MAX_PRESSURE_P_COEFFICIENT 0.01F ///< P term for RO pump max pressure control. #define ROP_MAX_PRESSURE_I_COEFFICIENT 0.01F ///< I term for RO pump max pressure control. #define ROP_PWM_STEP_LIMIT 0.50F ///< Current maximum PWM step limit used in RO Profiles. #define ROP_FLOW_TARGET_TOLERANCE 0.03F ///< Tolerance in between the target flow rate and the actual flow rate in percentage. #define ROP_RAMP_DOWN_DUTY_CYCLE_RATIO 0.03F ///< 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_AVERAGE_MULTIPLIER ( 1.0F / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. // The ADC to LPM factor is calculated using the following steps: // 0.1 to 2 LPM range // 110000 pulses/liter // For 2 LPM => 2LPM x 110000 pulses/liter * 1 edges/pulse * 1 min/60 seconds = 3666.66 counts/sec => 272.72 microseconds => for 1 LPM = 136.36 counts #define RO_FLOW_ADC_TO_LPM_FACTOR 272.72F ///< 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.5F ///< Slope of flow to PWM line equation. #define ROP_FLOW_TO_PWM_INTERCEPT 0.0F ///< 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 ) #define MAX_ALLOWED_FLOW_DEVIATION 0.1F ///< Max allowed deviation from target flow. #define FLOW_OUT_OF_RANGE_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Flow out of range time out in counts. // TODO - changed to prevent alarms (initial value 12) #define MAX_PRESSURE_TARGET_TOLERANCE 5 ///< Pressure tolerance from maximum set pressure by user in psi. #define MAX_ALLOWED_PRESSURE_PSI 130 ///< Maximum allowed pressure that the RO pump can go to. #define MIN_ALLOWED_PRESSURE_PSI 10 ///< Minimum allowed pressure that the RO pump can go to. #define MAX_ALLOWED_MEASURED_PRESSURE_PSI 135 ///< Maximum allowed pressure that the sensor measures. RO pump shut off pressure is 140psi. #define MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL MS_PER_SECOND ///< Maximum allowed time that the pressure can be very high. #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.2F + ( (F32)((p) - 100) * 0.01F ) ) ///< 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_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE 2.51F ///< RO pump 0% duty cycle feedback voltage. #define ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE 0.05F ///< RO pump duty cycle out of range tolerance. #define DATA_PUBLISH_COUNTER_START_COUNT 50 ///< Data publish counter start count. /// Enumeration of RO pump states. typedef enum ROPump_States { RO_PUMP_OFF_STATE = 0, ///< RO pump off state. RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE, ///< RO pump ramp up to target flow rate state. RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE, ///< RO pump control to target flow state. RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE, ///< RO pump control to max pressure state. RO_PUMP_OPEN_LOOP_STATE, ///< RO pump open loop state. NUM_OF_RO_PUMP_STATES ///< Number of RO pump states. } RO_PUMP_STATE_T; /// Enumeration of RO pump self-test states. typedef enum ROPump_Self_Test_States { RO_PUMP_SELF_TEST_STATE_START = 0, ///< RO pump self-test start state. RO_PUMP_TEST_STATE_IN_PROGRESS, ///< RO pump self-tests in progress state. RO_PUMP_TEST_STATE_COMPLETE, ///< RO pump self-tests completed state. NUM_OF_RO_PUMP_SELF_TEST_STATES ///< Number of RO pump self-test states. } RO_PUMP_SELF_TEST_STATE_T; // ********** private data ********** static RO_PUMP_STATE_T roPumpState; ///< Current state of RO pump controller state machine. static U32 roPumpDataPublicationTimerCounter; ///< Used to schedule RO pump data publication to CAN bus. static BOOL isROPumpOn; ///< RO pump is currently running. static F32 roPumpPWMDutyCyclePct; ///< Initial RO pump PWM duty cycle. static F32 roPumpDutyCyclePctSet; ///< Currently set RO pump PWM duty cycle. static OVERRIDE_F32_T roPumpFeedbackDutyCyclePct = { 0, 0, 0, 0 }; ///< RO pump feedback duty cycle in percent. static PUMP_CONTROL_MODE_T roPumpControlMode; ///< Requested RO pump control mode. static F32 pendingROPumpCmdMaxPressure; ///< Delayed (pending) RO pump max pressure (in PSI) setting. static F32 pendingROPumpCmdTargetFlow; ///< Delayed (pending) RO pump target flow rate (in mL/min) setting. static U32 pendingROPumpCmdCountDown; ///< Delayed (pending) RO pump command count down timer (in task intervals). static F32 targetROPumpFlowRateLPM; ///< Target RO flow rate (in L/min). static F32 targetROPumpMaxPressure; ///< Target RO max allowed pressure (in PSI). static OVERRIDE_U32_T roPumpDataPublishInterval = { RO_PUMP_DATA_PUB_INTERVAL, RO_PUMP_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus. static U32 roControlTimerCounter; ///< Determines when to perform control on RO pump. static F32 roPumpOpenLoopTargetDutyCycle; ///< Target RO pump open loop PWM. static F32 roVolumeL; ///< RO water generated in liters. static U32 roPumpControlInterval; ///< RO pump Control interval. static RO_PI_FLOW_PROFILES_T currentROPumpProfile; ///< RO Pump flow profile table. ///< Most values are currently the same until future efforts into tuning op modes. ///< TODO: Fine tune each op mode. static PI_CONTROLLER_PROFILE_DATA_T roPIFlowProfiles[ NUM_OF_RO_PI_FLOW_PROFILES ] = { // Kp Ki uMin uMax maxErrorSumStep Control Interval { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FLUSH { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_GEN_IDLE { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FILL { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_DRAIN { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_HEAT { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_OPEN_LOOP };// Kp Ki uMin uMax maxErrorSumStep Control Interval // ********** private function prototypes ********** static RO_PUMP_STATE_T handleROPumpOffState( void ); static RO_PUMP_STATE_T handleROPumpRampUpToTargetFlowState( void ); static RO_PUMP_STATE_T handleROPumpControlToTargetFlowState( void ); static RO_PUMP_STATE_T handleROPumpControlToMaxPressureState( void ); static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); static F32 roPumpFlowToPWM( RO_PI_FLOW_PROFILES_T profileID, F32 targetFlow ); static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); static void stopROPump( void ); static void publishROPumpData( void ); static F32 getROFeedbackDutyCycle( void ); /*********************************************************************//** * @brief * The initROPump function initializes the RO Pump module. * @details Inputs: roControlTimerCounter,roPumpOpenLoopTargetDutyCycle, * roPumpPressureRunningSum, flowFilterCounter, flowVerificationCounter, * roPumpState, roPumpControlMode, roPumpDataPublicationTimerCounter, rawFlowLP, * roPumpPWMDutyCyclePct, roPumpDutyCyclePctSet, pendingROPumpCmdMaxPressure, * pendingROPumpCmdTargetFlow, pendingROPumpCmdCountDown, targetROPumpMaxPressure, * @details Outputs: none * @return none *************************************************************************/ void initROPump( void ) { stopROPump(); // Initialize RO pump PI controller to flow initializePIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, MIN_RO_PUMP_DUTY_CYCLE, ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); // Initialize RO pump PI controller t maximum pressure initializePIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, MIN_RO_PUMP_DUTY_CYCLE, ROP_MAX_PRESSURE_P_COEFFICIENT, ROP_MAX_PRESSURE_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_TIME_OUT_MS, FLOW_OUT_OF_RANGE_TIME_OUT_MS ); initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FLOW_OUT_OF_RANGE_TIME_OUT_MS, FLOW_OUT_OF_RANGE_TIME_OUT_MS ); // 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 ); // Initialize the persistent alarm for not turning off the pump initPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); // Initialize the variables roControlTimerCounter = 0; roPumpOpenLoopTargetDutyCycle = 0; roPumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; roPumpState = RO_PUMP_OFF_STATE; roPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; isROPumpOn = FALSE; roPumpFeedbackDutyCyclePct.data = 0.0F; roVolumeL = 0.0F; targetROPumpFlowRateLPM = 0.0F; roPumpPWMDutyCyclePct = 0.0F; roPumpDutyCyclePctSet = 0.0F; pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; pendingROPumpCmdCountDown = 0; targetROPumpMaxPressure = 0.0F; roPumpControlInterval = ROP_CONTROL_INTERVAL; currentROPumpProfile = RO_PI_FLOW_PROFILE_GEN_IDLE; } /*********************************************************************//** * @brief * The setROPumpTargetFlowRate function sets a new target flow rate for the * RO pump. * @details Inputs: targetROPumpPressure, targetROPumpFlowRate, * roPumpControlMode, rampUp2FlowTimeoutCounter, currentROPumpProfile * @details Outputs: targetROPumpPressure, targetROPumpFlowRate, * roPumpControlMode, rampUp2FlowTimeoutCounter, roPumpPWMDutyCyclePct * @param roFlowRate which is target RO flow rate * @param maxPressure which is the maximum allowed pressure that the RO pump * can reach * @return TRUE if new target flow rate is set successfully, FALSE if not *************************************************************************/ BOOL setROPumpTargetFlowRateLPM( F32 roFlowRate, U32 maxPressure ) { BOOL result = FALSE; // First of all, the flow rate must be in range if ( ( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) { // Then the max pressure that we are allowed to reach must be in range if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) { // For now maximum allowed pressure is inserted into the target pressure override // if the target flow rate exceeded the max pressure, it will set the maximum pressure targetROPumpMaxPressure = maxPressure; targetROPumpFlowRateLPM = roFlowRate; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; // Get the initial guess of the duty cycle roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; isROPumpOn = TRUE; result = TRUE; } // Requested max pressure is out of range else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, maxPressure ) } } // Requested flow rate is out of range else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, roFlowRate ) } return result; } /*********************************************************************//** * @brief * The setROPumpTargetFlowRateDelayed function sets a new target flow rate for the * RO pump to be set after given delay. * @details Inputs: none * @details Outputs: pendingROPumpCmdMaxPressure, pendingROPumpCmdTargetFlow, * pendingROPumpCmdCountDown * @param roFlowRate which is target RO flow rate * @param maxPressure which is the maximum allowed pressure that the RO pump * can reach * @param delayMs delay duration (in ms) before RO pump started * @return TRUE if new target flow rate is set successfully, FALSE if not *************************************************************************/ BOOL setROPumpTargetFlowRateDelayed( F32 roFlowRate, U32 maxPressure, U32 delayMs ) { BOOL result = FALSE; // First of all, the flow rate must be in range if ( ( roFlowRate <= MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) { // Then the max pressure that we are allowed to reach must be in range if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) { pendingROPumpCmdMaxPressure = (F32)maxPressure; pendingROPumpCmdTargetFlow = roFlowRate; pendingROPumpCmdCountDown = delayMs / TASK_GENERAL_INTERVAL; result = TRUE; } // Requested max pressure is out of range else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, maxPressure ) } } // Requested flow rate is out of range else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, roFlowRate ) } return result; } /*********************************************************************//** * @brief * The setROPumpTargetDutyCycle function sets the duty cycle that the * pump should run. * @details Inputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, * roPumpPWMDutyCyclePctSet, roPumpControlMode * @details Outputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, * roPumpPWMDutyCyclePctSet, roPumpControlMode * @param: duty which is the duty cycle * @return none *************************************************************************/ BOOL setROPumpTargetDutyCycle( F32 duty ) { BOOL status = FALSE; if ( ( duty >= MIN_RO_PUMP_DUTY_CYCLE ) && ( duty <= MAX_RO_PUMP_DUTY_CYCLE ) ) { roPumpOpenLoopTargetDutyCycle = duty; roPumpPWMDutyCyclePct = roPumpOpenLoopTargetDutyCycle; roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; roPumpControlMode = PUMP_CONTROL_MODE_OPEN_LOOP; status = TRUE; // Set the new duty cycle of the pump setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_DG_INVALID_RO_PUMP_DUTY_CYCLE_SELECTED, duty ) } return status; } /*********************************************************************//** * @brief * The signalROPumpHardStop function stops the RO pump immediately and * resets all the variables associated with the RO pump run. * @details Inputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, flowVerificationCounter, * flowVerificationCounter, rampUp2FlowTimeoutCounter * @details Outputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter * @return none *************************************************************************/ void signalROPumpHardStop( void ) { stopROPump(); targetROPumpFlowRateLPM = 0.0F; roPumpState = RO_PUMP_OFF_STATE; roPumpPWMDutyCyclePct = 0.0F; roPumpOpenLoopTargetDutyCycle = 0.0F; roControlTimerCounter = 0; targetROPumpMaxPressure = 0; pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; pendingROPumpCmdCountDown = 0; resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, MIN_RO_PUMP_DUTY_CYCLE ); } /*********************************************************************//** * @brief * The execROPumpMonitor function executes the RO pump monitor. The RO flow * sensor is read, filtered, converted to L/min and calibrated. * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, * measuredROFlowRateLPM, roPumpState, roPumpFeedbackDutyCyclePct, * flowOutOfRangeCounter, roPumpControlMode, Ppo * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, * measuredROFlowRateLPM, roVolumeL, roPumpFeedbackDutyCyclePct * @return none *************************************************************************/ void execROPumpMonitor( void ) { U32 roFlowReading = (U32)getFPGAROPumpFlowRate(); F32 roFeedbackVoltage = getIntADCVoltageConverted( INT_ADC_RO_PUMP_FEEDBACK_DUTY_CYCLE ); // Read the pressure at the sensor. The pump cannot be more that the maximum allowed pressure // to make sure the hardware (especially the ROF) is not damaged. If it is the case, we need to stop immediately F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); BOOL isPressureMax = ( actualPressure >= MAX_ALLOWED_MEASURED_PRESSURE_PSI ? TRUE : FALSE ); BOOL isDutyCylceOutOfRange = FALSE; checkPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure, MAX_ALLOWED_MEASURED_PRESSURE_PSI ); if ( ( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) > NEARLY_ZERO ) && ( VALVE_STATE_CLOSED == getValveStateName( VBF ) ) ) { // If the RO pump's flow is greater than zero, and the VBf valve is not open (like heat disinfect) it means RO water is being generated // Add that water to the variable roVolumeL += ( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) / ( SEC_PER_MIN * MS_PER_SECOND ) ) * TASK_PRIORITY_INTERVAL; } #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RO_PUMP_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) #endif { // To monitor the flow, the control mode must be in closed loop mode and the pump should be control to flow state // If the pump is controlled to the maximum pressure, the flow might be different from the target flow for more than 10% // but the pump is not able to achieve the flow. if ( ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) && ( RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE == roPumpState ) ) { F32 currentFlow = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); F32 targetFlow = getTargetROPumpFlowRateLPM(); // The flow cannot be out of range for than 10% of the target flow BOOL isFlowOutOfRange = ( fabs( 1.0F - ( currentFlow / targetFlow ) ) > MAX_ALLOWED_FLOW_DEVIATION ? TRUE : FALSE ); // Figure out whether flow is out of range from which side BOOL isFlowOutOfUpperRange = ( isFlowOutOfRange && ( currentFlow > targetFlow ) ? TRUE : FALSE ); BOOL isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlow < targetFlow ) ? TRUE : FALSE ); checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, isFlowOutOfUpperRange, currentFlow, targetFlow ); checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, isFlowOutOfLowerRange, currentFlow, targetFlow ); } else { checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, FALSE, 0.0F, 0.0F ); checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FALSE, 0.0F, 0.0F ); } #ifndef _RELEASE_ if ( getHardwareConfigStatus() != HW_CONFIG_BETA ) #endif { // The feedback voltage is on the 0V line so when the duty cycle is 0, the feedback is 2.5V // The duty cycle is calculated by getting the 1 - (ratio of feedback / to the voltage at 0 percent duty cycle). roPumpFeedbackDutyCyclePct.data = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); isDutyCylceOutOfRange = ( fabs( getROFeedbackDutyCycle() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, getROFeedbackDutyCycle(), roPumpDutyCyclePctSet ); // Check if it the alarm has timed out and if the pump is supposed to be off but it is still on, activate the safety shutdown if ( ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) && ( FALSE == isROPumpOn ) ) { activateSafetyShutdown(); } } } // Publish RO pump data on interval publishROPumpData(); } /*********************************************************************//** * @brief * The execROPumpController function executes the RO pump controller. * @details Inputs: roPumpState * @details Outputs: roPumpState * @return none *************************************************************************/ void execROPumpController( void ) { // Handle pending delayed RO pump command if ( pendingROPumpCmdCountDown > 0 ) { pendingROPumpCmdCountDown--; if ( 0 == pendingROPumpCmdCountDown ) { targetROPumpMaxPressure = pendingROPumpCmdMaxPressure; targetROPumpFlowRateLPM = pendingROPumpCmdTargetFlow; pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; // Get the initial guess of the duty cycle roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; isROPumpOn = TRUE; } } // Execute RO pump control state machine switch ( roPumpState ) { case RO_PUMP_OFF_STATE: roPumpState = handleROPumpOffState(); break; case RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE: roPumpState = handleROPumpRampUpToTargetFlowState(); break; case RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE: roPumpState = handleROPumpControlToTargetFlowState(); break; case RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE: roPumpState = handleROPumpControlToMaxPressureState(); break; case RO_PUMP_OPEN_LOOP_STATE: roPumpState = handleROPumpOpenLoopState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_EXEC_STATE, roPumpState ) roPumpState = RO_PUMP_OFF_STATE; break; } } /*********************************************************************//** * @brief * The execROPumpSelfTest function executes the RO pump's self-test. * @details Inputs: none * @details Outputs: none * @return PressuresSelfTestResult (SELF_TEST_STATUS_T) *************************************************************************/ SELF_TEST_STATUS_T execROPumpSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; // TODO is there anything else needed in POST for the RO pump? return result; } /*********************************************************************//** * @brief * The isROPumpRunning function returns the on/off status of RO pump. * @details Inputs: isROPumpOn * @details Outputs: none * @return isROPumpOn the boolean flag that is TRUE if the pump is on and * FALSE if it is off *************************************************************************/ BOOL isROPumpRunning( void ) { return isROPumpOn; } /*********************************************************************//** * @brief * The getTargetROPumpFlowRateLPM function gets the current target RO pump * flow rate. * @details Inputs: targetROPumpFlowRateLPM * @details Outputs: none * @return the current target RO flow rate (in L/min). *************************************************************************/ F32 getTargetROPumpFlowRateLPM( void ) { return targetROPumpFlowRateLPM; } /*********************************************************************//** * @brief * The getTargetROPumpPressurePSI function gets the current target RO pump * pressure. * @details Inputs: none * @details Outputs: targetROPumpMaxPressure * @return the current target RO pump pressure in psi. *************************************************************************/ F32 getTargetROPumpPressurePSI( void ) { return targetROPumpMaxPressure; } /*********************************************************************//** * @brief * The getROGeneratedVolumeL function returns the RO generated volume in liters. * @details Inputs: none * @details Outputs: roVolumeL * @return the RO generated volume in liters *************************************************************************/ F32 getROGeneratedVolumeL( void ) { return roVolumeL; } /*********************************************************************//** * @brief * The getROFeedbackDutyCyle function returns the RO pump feedback * duty cycle. * @details Inputs: roPumpFeedbackDutyCyclePct * @details Outputs: none * @return ro pump feedback duty cycle *************************************************************************/ static F32 getROFeedbackDutyCycle( void ) { F32 feedbackdutyCycle = getF32OverrideValue( &roPumpFeedbackDutyCyclePct ); return feedbackdutyCycle; } /*********************************************************************//** * @brief * The resetROGenerateVolumeL function resets the RO generated volume in liters. * @details Inputs: none * @details Outputs: roVolumeL * @return none *************************************************************************/ void resetROGenerateVolumeL( void ) { roVolumeL = 0.0F; } /*********************************************************************//** * @brief * The handleROPumpOffState function handles the RO pump off state of the * controller state machine. * @details Inputs: roPumpControlMode, roPumpPWMDutyCyclePctSet, * roPumpOpenLoopTargetDutyCycle * @details Outputs: roPumpPWMDutyCyclePct, setupROPumpControl, isROPumpOn * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpOffState( void ) { RO_PUMP_STATE_T state = RO_PUMP_OFF_STATE; isROPumpOn = FALSE; // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow if ( ( getTargetROPumpFlowRateLPM() > 0.0F ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Set pump to on isROPumpOn = TRUE; roPumpDutyCyclePctSet = roPumpFlowToPWM( currentROPumpProfile, getTargetROPumpFlowRateLPM() ); setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); state = RO_PUMP_CONTROL_TO_TARGET_FLOW_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 if ( ( roPumpOpenLoopTargetDutyCycle > 0.0F ) && ( PUMP_CONTROL_MODE_OPEN_LOOP == roPumpControlMode ) ) { setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); isROPumpOn = TRUE; state = RO_PUMP_OPEN_LOOP_STATE; } return state; } /*********************************************************************//** * @brief * The handleROPumpRampUpToTargetFlowState function handles the RO pump * ramp up to flow state of the controller state machine. * @details Inputs: none * @details Outputs: none * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpRampUpToTargetFlowState( void ) { RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; // TODO - remove function and state - obsolete return state; } /*********************************************************************//** * @brief * The handleROPumpControlToTargetFlowState function handles the control to * target flow state of the RO pump controller state machine. * @details Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @details Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpControlToTargetFlowState( void ) { RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; // Control at set interval if ( ( ++roControlTimerCounter >= roPumpControlInterval ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Get the pressure to use it for setting the control F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); if ( actualPressure >= targetROPumpMaxPressure ) { resetPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, roPumpDutyCyclePctSet ); state = RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE; } else { roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, getTargetROPumpFlowRateLPM(), getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) ); } setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); roControlTimerCounter = 0; } return state; } /*********************************************************************//** * @brief * The handleROPumpControlToMaxPressureState function handles the control * to max pressure state of the RO pump controller state machine. * @details Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @details Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpControlToMaxPressureState( void ) { RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE; // Get the pressure to use it for setting the control F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); // Control at set interval if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) { if ( actualPressure > targetROPumpMaxPressure ) { roPumpDutyCyclePctSet -= ROP_RAMP_DOWN_DUTY_CYCLE_RATIO; resetPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, roPumpDutyCyclePctSet ); } else { roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, getTargetROPumpFlowRateLPM(), getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) ); } setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); roControlTimerCounter = 0; } // Check if the actual pressure is out of tolerance from max pressure. // If it is out, go back to ramp up state and to try to reach to target flow again if ( ( targetROPumpMaxPressure - actualPressure ) > MAX_PRESSURE_TARGET_TOLERANCE ) { resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPumpDutyCyclePctSet ); state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; roControlTimerCounter = 0; } return state; } /*********************************************************************//** * @brief * The handleROPumpOpenLoopState function handles the open loop state of * the RO pump controller state machine. * @details Inputs: none * @details Outputs: none * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ) { return RO_PUMP_OPEN_LOOP_STATE; } /*********************************************************************//** * @brief * The setROPumpControlSignalDutyCycle function sets the duty cycle for the * RO pump to a given duty cycle. * @details Inputs: none * @details Outputs: none * @param dutyCycle which is the duty cycle * @return none *************************************************************************/ static void setROPumpControlSignalDutyCycle( F32 dutyCycle ) { etpwmSetCmpB( etpwmREG2, (U32)( (S32)( ( dutyCycle * (F32)(etpwmREG2->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } /*********************************************************************//** * @brief * The stopROPump function sets the RO pump duty cycle to zero. * @details Inputs: isROPumpOn, roPumpPWMDutyCyclePctSet * @details Outputs: isROPumpOn, roPumpPWMDutyCyclePctSet * @return none *************************************************************************/ static void stopROPump( void ) { isROPumpOn = FALSE; roPumpDutyCyclePctSet = 0.0; etpwmSetCmpB( etpwmREG2, 0 ); } /*********************************************************************//** * @brief * The publishROPumpData function publishes RO pump data at the set interval. * @details Inputs: roPumpDataPublicationTimerCounter * @details Outputs: roPumpDataPublicationTimerCounter * @return none *************************************************************************/ static void publishROPumpData( void ) { // publish RO pump data on interval if ( ++roPumpDataPublicationTimerCounter >= getU32OverrideValue( &roPumpDataPublishInterval ) ) { RO_PUMP_DATA_T pumpData; pumpData.roPumpTgtFlowRateLPM = getTargetROPumpFlowRateLPM(); pumpData.roPumpTgtPressurePSI = getTargetROPumpPressurePSI(); pumpData.roPumpDutyCycle = roPumpDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; pumpData.roMeasFlowRateLPM = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); pumpData.roPumpState = (U32)roPumpState; pumpData.roPumpFBDutyCycle = getROFeedbackDutyCycle() * FRACTION_TO_PERCENT_FACTOR; broadcastData( MSG_ID_RO_PUMP_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&pumpData, sizeof( RO_PUMP_DATA_T ) ); roPumpDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The setROPIFlowProfile function sets the RO flow PI controller to new coefficients * and calculates the initial duty cycle. * @details Inputs: targetROPumpFlowRateLPM * @details Outputs: roPumpControlInterval, currentROPumpProfile * @param profileID the ID for which flow profile to be used * @return none *************************************************************************/ void setROPIFlowProfile( RO_PI_FLOW_PROFILES_T profileID ) { F32 initialControlDutyCycle; if ( profileID < NUM_OF_RO_PI_FLOW_PROFILES ) { roPumpControlInterval = roPIFlowProfiles[ profileID ].controlInterval; initialControlDutyCycle = roPumpFlowToPWM( profileID, (getTargetROPumpFlowRateLPM()) ); initializePIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, initialControlDutyCycle, roPIFlowProfiles[ profileID ].Kp, roPIFlowProfiles[ profileID ].Ki, roPIFlowProfiles[ profileID ].uMin, roPIFlowProfiles[ profileID ].uMax ); setPIControllerStepLimit( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPIFlowProfiles[ profileID ].maxErrorSumStep ); currentROPumpProfile = profileID; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_PI_PROFILE_SELECTED, profileID ) } } /*********************************************************************//** * @brief * The roPumpFlowToPWM function calculates the duty cycle for the given target * flow in relation to which PI profile has been selected. * @details Inputs: none * @details Outputs: dutyCyclePct * @param profileID the ID for which flow profile to be used * targetFlow the flow as a parameter for the conversion calculation * @return dutyCyclePct, the duty cycle for the given flow *************************************************************************/ static F32 roPumpFlowToPWM( RO_PI_FLOW_PROFILES_T profileID, F32 targetFlow ) { F32 dutyCyclePct = 0; if ( profileID < NUM_OF_RO_PI_FLOW_PROFILES ) { switch( profileID ) { case RO_PI_FLOW_PROFILE_FLUSH: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; case RO_PI_FLOW_PROFILE_GEN_IDLE: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; case RO_PI_FLOW_PROFILE_FILL: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; case RO_PI_FLOW_PROFILE_DRAIN: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; case RO_PI_FLOW_PROFILE_HEAT: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; default: dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); break; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_PI_PROFILE_SELECTED, profileID ) } return dutyCyclePct; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetROPumpDataPublishIntervalOverride function overrides the * RO pump data publish interval. * @details Inputs: roPumpDataPublishInterval * @details Outputs: roPumpDataPublishInterval * @param: value : override RO pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; roPumpDataPublishInterval.ovData = intvl; roPumpDataPublishInterval.override = OVERRIDE_KEY; result = TRUE; } return result; } /*********************************************************************//** * @brief * The testResetROPumpDataPublishIntervalOverride function resets the * override of the RO pump data publish interval. * @details Inputs: roPumpDataPublishInterval * @details Outputs: roPumpDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetROPumpDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { roPumpDataPublishInterval.override = OVERRIDE_RESET; roPumpDataPublishInterval.ovData = roPumpDataPublishInterval.ovInitData; result = TRUE; } return result; } /*********************************************************************//** * @brief * The testSetTargetROPumpFlow function overrides the target flow rate. * @details Inputs: none * @details Outputs: none * @param value which is override target RO flow rate (in L/min) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetTargetROPumpFlow( F32 flow ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // The flow rate and pressure must be in range if ( ( flow <= MAX_RO_FLOWRATE_LPM ) && ( flow >= MIN_RO_FLOWRATE_LPM ) ) { result = setROPumpTargetFlowRateLPM( flow, MAX_ALLOWED_PRESSURE_PSI ); } // If the flow is less than a very small number, it means 0 LPM flow rate has been requested // and this is coming from Dialin so the user requested the pump to stop if ( fabs( flow ) < NEARLY_ZERO ) { signalROPumpHardStop(); result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetTargetROPumpPressureOverride function overrides the target * RO pressure. * @details Inputs: targetROPumpPressure * @details Outputs: targetROPumpPressure * @param value override target RO pressure (in psi) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetTargetROPumpPressure( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // Make sure the requested pressure is in range if ( value >= MIN_ALLOWED_PRESSURE_PSI && value <= MAX_ALLOWED_PRESSURE_PSI ) { targetROPumpMaxPressure = value; result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetTargetDutyCycleOverride function overrides the target duty * cycle of the RO pump. * @details Inputs: none * @details Outputs: none * @param value which is the duty cycle to be set * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetTargetDutyCycle( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // Check if duty cycle is within range if ( ( value >= MIN_RO_PUMP_DUTY_CYCLE ) && ( value <= MAX_RO_PUMP_DUTY_CYCLE ) ) { setROPumpTargetDutyCycle( value ); result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetROPumpMeasuredFeedbackDutyCycleOverride function overrides the * feedback duty cycle. * @details Inputs: none * @details Outputs: roPumpFeedbackDutyCyclePct * @param value override feedback duty cycle. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetROPumpMeasuredFeedbackDutyCycleOverride( F32 value ) { BOOL status = FALSE; // Check if the requested drain pump RPM is within range if ( ( value >= MIN_RO_PUMP_DUTY_CYCLE ) && ( value <= MAX_RO_PUMP_DUTY_CYCLE ) ) { // Check if the user is logged in if ( TRUE == isTestingActivated() ) { roPumpFeedbackDutyCyclePct.ovData = value; roPumpFeedbackDutyCyclePct.override = OVERRIDE_KEY; status = TRUE; } } return status; } /*********************************************************************//** * @brief * The testResetROPumpMeasuredFeedbackDutyCycleOverride function resets the * feedback duty cycle. * @details Inputs: none * @details Outputs: roPumpFeedbackDutyCyclePct * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetROPumpMeasuredFeedbackDutyCycleOverride( void ) { BOOL status = FALSE; // Check if the user is logged in if ( TRUE == isTestingActivated() ) { roPumpFeedbackDutyCyclePct.ovData = roPumpFeedbackDutyCyclePct.ovInitData; roPumpFeedbackDutyCyclePct.override = OVERRIDE_RESET; status = TRUE; } return status; } /**@}*/