/************************************************************************** * * Copyright (c) 2020-2024 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) Sean Nash * @date (last) 12-Nov-2024 * * @author (original) Sean Nash * @date (original) 12-Nov-2024 * ***************************************************************************/ #include // for log() #include "Flow.h" //#include "NVDataMgmt.h" #include "Messaging.h" #include "MessageSupport.h" #include "PersistentAlarm.h" #include "PIControllers.h" #include "Pressure.h" #include "ROPump.h" #include "SafetyShutdown.h" #include "TaskGeneral.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup ROPump * @{ */ // ********** private definitions ********** #define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. #define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. #define ROP_FLOW_CONTROL_P_COEFFICIENT 0.000065F ///< P term for RO pump flow control. #define ROP_FLOW_CONTROL_I_COEFFICIENT 0.00022F ///< I term for RO pump flow control. #define ROP_MIN_FLOW_TO_CONTROL_PCT 0.75F #define ROP_PRESSURE_CONTROL_P_COEFFICIENT 0.15F ///< P term for RO pump pressure control. #define ROP_PRESSURE_CONTROL_I_COEFFICIENT 0.65F ///< I term for RO pump pressure control. #define ROP_FLOW_TO_PWM_SLOPE 155.31F ///< Slope of flow to PWM line equation. #define ROP_FLOW_TO_PWM_INTERCEPT -699.99F ///< Intercept of flow to PWM line equation. #define ROP_PRESSURE_TO_PWM_SLOPE 0.5F ///< Slope of pressure to PWM line equation. #define ROP_PRESSURE_TO_PWM_INTERCEPT 0.0F ///< Intercept of pressure to PWM line equation. #define DATA_PUBLISH_COUNTER_START_COUNT 10 ///< Data publish counter start count. #define ROP_PRESSURE_TO_PWM_PCT(pres) ( ( ROP_PRESSURE_TO_PWM_SLOPE * pres + ROP_PRESSURE_TO_PWM_INTERCEPT ) / MAX_FLUID_PUMP_PWM_DUTY_CYCLE ) ///< PWM line equation for pressure. converted to percentage. #define ROP_FLOW_TO_PWM_PCT(flow) ( ( ROP_FLOW_TO_PWM_SLOPE * log(flow) + ROP_FLOW_TO_PWM_INTERCEPT ) / MAX_FLUID_PUMP_PWM_DUTY_CYCLE ) ///< PWM line equation for flow converted to percentage. #define ROP_FLOW_TO_PWM(flow) ( ROP_FLOW_TO_PWM_SLOPE * log(flow) + ROP_FLOW_TO_PWM_INTERCEPT ) ///< PWM line equation for flow converted to percentage. // ********** private data ********** static RO_PUMP_STATE_T roPumpState; ///< Current state of pump controller state machine. static BOOL isROPumpOn; ///< Flag indicating whether pump is currently running. static BOOL stopPumpRequest; ///< Flag indicating pump stop is requested. static U32 roPumpDataPublicationTimerCounter; ///< Used to schedule RO pump data publication to CAN bus. static OVERRIDE_U32_T roPumpDataPublishInterval; ///< Interval (in ms) at which to publish boost pump data to CAN bus. static U32 roControlTimerCounter; ///< Determines when to perform control on RO pump. static OVERRIDE_U32_T targetROPumpFlowRate; ///< Target RO flow rate (in L/min). static OVERRIDE_F32_T targetROPumpPressure; ///< Target RO max allowed pressure (in PSI). static F32 roPumpDutyCyclePctSet; ///< Currently set RO pump PWM duty cycle. static OVERRIDE_F32_T roPumpOpenLoopTargetDutyCycle; ///< Target RO pump open loop PWM. static BOOL roPumpStartControl; ///< boolean to determine when closed loop flow control starts // ********** private function prototypes ********** static RO_PUMP_STATE_T handleROPumpOffState( void ); static RO_PUMP_STATE_T handleROPumpControlToTargetFlowState( void ); static RO_PUMP_STATE_T handleROPumpControlToTargetPressureState( void ); static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); static F32 roPumpPresToPWM( F32 targetPressure ); static F32 roPumpFlowToPWM( U32 targetFlow ); static void stopROPump( void ); static void publishROPumpData( void ); /*********************************************************************//** * @brief * The initROPump function initializes the RO Pump module. * @details \b Inputs: roPumpState, roPumpControlMode, isROPumpOn, stopPumpRequest, * roControlTimerCounter, roPumpDutyCyclePctSet, roPumpOpenLoopTargetDutyCycle, roPumpDataPublicationTimerCounter, * roPumpDataPublishInterval, targetROPumpFlowRate, targetROPumpPressure * @details \b Outputs: RO Pump controller unit initialized * @return none *************************************************************************/ void initROPump( void ) { initFluidPump(); // Initialize RO pump PI controller to flow initializePIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, MIN_RO_FLOWRATE_MLPM, ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_FLOWRATE_MLPM, MAX_RO_FLOWRATE_MLPM, FALSE, 0 ); // Initialize RO pump PI controller to target pressure initializePIController( PI_CONTROLLER_ID_RO_PUMP_PRES, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, ROP_PRESSURE_CONTROL_P_COEFFICIENT, ROP_PRESSURE_CONTROL_I_COEFFICIENT, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, MAX_FLUID_PUMP_DUTY_CYCLE_PCT, FALSE, 0 ); roPumpState = RO_PUMP_OFF_STATE; isROPumpOn = FALSE; stopPumpRequest = FALSE; roControlTimerCounter = 0; roPumpDutyCyclePctSet = 0.0F; roPumpStartControl = FALSE; roPumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; roPumpDataPublishInterval.data = RO_PUMP_DATA_PUB_INTERVAL; roPumpDataPublishInterval.ovData = RO_PUMP_DATA_PUB_INTERVAL; roPumpDataPublishInterval.ovInitData = 0; roPumpDataPublishInterval.override = OVERRIDE_RESET; targetROPumpFlowRate.data = 0; targetROPumpFlowRate.ovData = 0; targetROPumpFlowRate.ovInitData = 0; targetROPumpFlowRate.override = OVERRIDE_RESET; targetROPumpPressure.data = 0.0F; targetROPumpPressure.ovData = 0.0F; targetROPumpPressure.ovInitData = 0.0F; targetROPumpPressure.override = OVERRIDE_RESET; roPumpOpenLoopTargetDutyCycle.data = 0.0; roPumpOpenLoopTargetDutyCycle.ovData = 0.0; roPumpOpenLoopTargetDutyCycle.ovInitData = 0.0; roPumpOpenLoopTargetDutyCycle.override = OVERRIDE_RESET; stopROPump(); } /*********************************************************************//** * @brief * The execROPumpController function executes the RO pump controller. * @details \b Alarm: ALARM_ID_FP_SOFTWARE_FAULT if pump is in an invalid state * @details \b Inputs: roPumpState * @details \b Outputs: roPumpState * @return none *************************************************************************/ void execROPumpController( void ) { // Update RO pump feedback from FPGA readFluidPumps(); switch ( roPumpState ) { case RO_PUMP_OFF_STATE: roPumpState = handleROPumpOffState(); break; case RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE: roPumpState = handleROPumpControlToTargetFlowState(); break; case RO_PUMP_CONTROL_TO_TARGET_PRESSURE_STATE: roPumpState = handleROPumpControlToTargetPressureState(); break; case RO_PUMP_OPEN_LOOP_STATE: roPumpState = handleROPumpOpenLoopState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, roPumpState ) roPumpState = RO_PUMP_OFF_STATE; break; } // Publish RO pump data on interval publishROPumpData(); } /*********************************************************************//** * @brief * The handleROPumpOffState function handles the off state of the RO pump * state machine. * @details \b Inputs: isROPumpOn, roPumpControlMode, roPumpOpenLoopTargetDutyCycle * @details \b Outputs: isROPumpOn, roPumpDutyCyclePctSet * @return next state *************************************************************************/ static RO_PUMP_STATE_T handleROPumpOffState( void ) { RO_PUMP_STATE_T state = RO_PUMP_OFF_STATE; isROPumpOn = FALSE; // If there is a target flow set, transition to the PI controller and control to flow if ( getTargetROPumpFlowRateMLPM() > 0 ) { // Set pump to on isROPumpOn = TRUE; roPumpDutyCyclePctSet = roPumpFlowToPWM( getTargetROPumpFlowRateMLPM() ); resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPumpDutyCyclePctSet, 0.0F ); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); roPumpStartControl = FALSE; state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; } // If there is a target pressure set, transition to the PI controller and control to pressure. else if ( getTargetROPumpPressure() > 0.0F ) { // Set pump to on isROPumpOn = TRUE; roPumpDutyCyclePctSet = roPumpPresToPWM( getTargetROPumpPressure() ); resetPIController( PI_CONTROLLER_ID_RO_PUMP_PRES, roPumpDutyCyclePctSet, 0.0F ); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); state = RO_PUMP_CONTROL_TO_TARGET_PRESSURE_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 else if ( getTargetROPumpDutyCyclePCT() > 0.0F ) { roPumpDutyCyclePctSet = getTargetROPumpDutyCyclePCT(); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); isROPumpOn = TRUE; state = RO_PUMP_OPEN_LOOP_STATE; } return state; } /*********************************************************************//** * @brief * The handleROPumpOpenLoopState function handles the open loop control * state of the RO pump state machine. * @details \b Inputs: stopPumpRequest, roPumpControlMode, * roPumpDutyCyclePctSet * @details \b Outputs: roPumpState, stopPumpRequest * @return next state *************************************************************************/ static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ) { RO_PUMP_STATE_T state = RO_PUMP_OPEN_LOOP_STATE; if ( TRUE == stopPumpRequest ) { stopPumpRequest = FALSE; signalROPumpHardStop(); } // If there is a target flow set, transition to the PI controller and control to flow if ( getTargetROPumpFlowRateMLPM() > 0 ) { ///transition to closed loop resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, getTargetROPumpDutyCyclePCT(), 0 ); state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; } // If there is a target pressure set, transition to the PI controller and control to pressure. else if ( getTargetROPumpPressure() > 0.0F ) { //transition to closed loop resetPIController( PI_CONTROLLER_ID_RO_PUMP_PRES, getTargetROPumpPressure(), 0 ); state = RO_PUMP_CONTROL_TO_TARGET_PRESSURE_STATE; } else if ( (F32)getTargetROPumpDutyCyclePCT() == 0.0F ) { signalROPumpHardStop(); } return state; } /*********************************************************************//** * @brief * The handleROPumpControlToTargetFlowState function handles the control to * target flow state of the RO pump controller state machine. * @details \b Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter, roPumpControlMode * @details \b 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; F32 nexttgtflow = 0.0; // Check if need to switch control modes if ( getTargetROPumpPressure() > 0.0F ) { // Transition to target pressure resetPIController( PI_CONTROLLER_ID_RO_PUMP_PRES, getTargetROPumpPressure(), 0 ); state = RO_PUMP_CONTROL_TO_TARGET_PRESSURE_STATE; } else if ( getTargetROPumpDutyCyclePCT() > 0.0F ) { roPumpDutyCyclePctSet = getTargetROPumpDutyCyclePCT(); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); state = RO_PUMP_OPEN_LOOP_STATE; } // Control at set interval or shut off else if ( (F32)getTargetROPumpFlowRateMLPM() == 0.0F ) { signalROPumpHardStop(); roPumpStartControl = FALSE; } else if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) { // P16 flow seems to lag in current Leahi HW. We will wait till we hit a % of target flow before we start changing control. if( ( TRUE == roPumpStartControl ) || ( getFilteredFlow( P16_FLOW ) >= ( (F32)getTargetROPumpFlowRateMLPM() * ROP_MIN_FLOW_TO_CONTROL_PCT ) ) ) { roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, (F32)getTargetROPumpFlowRateMLPM(), getFilteredFlow( P16_FLOW ) ); roPumpDutyCyclePctSet = MIN( roPumpDutyCyclePctSet, ( MAX_FLUID_PUMP_PWM_DUTY_CYCLE * MAX_FLUID_PUMP_DUTY_CYCLE_PCT ) ); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); if ( FALSE == roPumpStartControl ) { roPumpStartControl = TRUE; } } roControlTimerCounter = 0; } return state; } /*********************************************************************//** * @brief * The handleROPumpControlToTargetPressureState function handles the control * to target pressure state of the RO pump controller state machine. * @details \b Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter, roPumpControlMode * @details \b Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpControlToTargetPressureState( void ) { RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_PRESSURE_STATE; // Check if we are changing control if ( getTargetROPumpFlowRateMLPM() > 0 ) { resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, getTargetROPumpFlowRateMLPM(), 0 ); state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; } else if ( getTargetROPumpDutyCyclePCT() > 0.0F ) { setFluidPumpPctToPWMDutyCycle( P12_PUMP, getTargetROPumpDutyCyclePCT() ); roPumpDutyCyclePctSet = getTargetROPumpDutyCyclePCT(); state = RO_PUMP_OPEN_LOOP_STATE; } // Control at set interval or shut off else if ( getTargetROPumpPressure() == 0.0F ) { signalROPumpHardStop(); } else if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) { roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP_PRES, getTargetROPumpPressure(), getFilteredPressure( P17_PRES ) ); setFluidPumpPctToPWMDutyCycle( P12_PUMP, roPumpDutyCyclePctSet ); roControlTimerCounter = 0; } return state; } /*********************************************************************//** * @brief * The setROPumpTargetFlowRateMLPM function sets a new target flow rate for the * RO pump. * @details \b Inputs: roPumpOpenLoopTargetDutyCycle * @details \b Outputs: targetROPumpFlowRate, roPumpControlMode, roPumpDutyCyclePctSet, * roControlTimerCounter, isROPumpOn * @param roFlowRate which is target RO flow rate in mL/min * @param firmwareCall indicates whether the call initiated by firmware * internally or by dialin * @return TRUE if new target flow rate is set successfully, FALSE if not *************************************************************************/ BOOL setROPumpTargetFlowRateMLPM( U32 roFlowRate, BOOL firmwareCall ) { BOOL result = FALSE; BOOL skipSet = FALSE; // First of all, the flow rate must be in range if ( roFlowRate <= MAX_RO_FLOWRATE_MLPM ) { if ( firmwareCall == TRUE ) // firmware call { // set the target flow and pressure to zero if there are no active override if ( ( targetROPumpFlowRate.override == OVERRIDE_RESET ) && ( targetROPumpPressure.override == OVERRIDE_RESET ) && ( roPumpOpenLoopTargetDutyCycle.override == OVERRIDE_RESET ) ) { targetROPumpPressure.data = 0; roPumpOpenLoopTargetDutyCycle.data = 0.0F; } // skip the firmware set call if any override is active else { result = TRUE; skipSet = TRUE; } } if ( skipSet != TRUE ) { targetROPumpFlowRate.data = roFlowRate; // Get the initial guess of the duty cycle roPumpDutyCyclePctSet = roPumpFlowToPWM( getTargetROPumpFlowRateMLPM() ); roControlTimerCounter = 0; isROPumpOn = TRUE; result = TRUE; } } // Requested flow rate is out of range else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_FLOW_RATE_SET, roFlowRate ) } return result; } /*********************************************************************//** * @brief * The setROPumpTargetPressure function sets a new target pressure for the * RO pump. * @details \b Inputs: roPumpOpenLoopTargetDutyCycle, targetROPumpFlowRate * @details \b Outputs: roPumpOpenLoopTargetDutyCycle, targetROPumpFlowRate, isROPumpOn, * roControlTimerCounter, roPumpDutyCyclePctSet, roPumpControlMode, targetROPumpPressure * @param roPressure which is target RO pressure * @param firmwareCall indicates whether the call initiated by firmware * internally or by dialin * @return TRUE if new target flow rate is set successfully, FALSE if not *************************************************************************/ BOOL setROPumpTargetPressure( F32 roPressure, BOOL firmwareCall ) { BOOL result = FALSE; BOOL skipSet = FALSE; // First of all, the pressure must be in range if ( ( roPressure <= MAX_RO_PRESSURE_PSI ) && ( roPressure >= MIN_RO_PRESSURE_PSI ) ) { if ( firmwareCall == TRUE ) // firmware call { // set the target flow and pressure to zero if there are no active override if ( ( targetROPumpFlowRate.override == OVERRIDE_RESET ) && ( targetROPumpPressure.override == OVERRIDE_RESET ) && ( roPumpOpenLoopTargetDutyCycle.override == OVERRIDE_RESET ) ) { targetROPumpFlowRate.data = 0; roPumpOpenLoopTargetDutyCycle.data = 0.0F; } // skip the firmware set call if any override is active else { result = TRUE; skipSet = TRUE; } } if ( skipSet != TRUE ) { targetROPumpPressure.data = roPressure; // Get the initial guess of the duty cycle roPumpDutyCyclePctSet = roPumpPresToPWM( getTargetROPumpPressure() ); roControlTimerCounter = 0; isROPumpOn = TRUE; result = TRUE; } } // Requested flow rate is out of range else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_PUMP_INVALID_PRESSURE_SELECTED, roPressure ) } return result; } /*********************************************************************//** * @brief * The setROPumpTargetDutyCycle function sets the duty cycle that the * pump should run. * @details \b Inputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, * targetROPumpPressure, targetROPumpFlowRate * @details \b Outputs: roPumpOpenLoopTargetDutyCycle * roPumpControlMode, targetROPumpFlowRate, targetROPumpPressure * @param duty which is the duty cycle * @param firmwareCall indicates whether the call initiated by firmware * internally or by dialin * @return none *************************************************************************/ BOOL setROPumpTargetDutyCycle( F32 dutyCycle, BOOL firmwareCall ) { BOOL result = FALSE; BOOL skipSet = FALSE; if ( ( dutyCycle >= MIN_FLUID_PUMP_DUTY_CYCLE_PCT ) && ( dutyCycle <= MAX_FLUID_PUMP_DUTY_CYCLE_PCT ) ) { if ( firmwareCall == TRUE ) // firmware call { // set the target flow and pressure to zero if there are no active override if ( ( targetROPumpFlowRate.override == OVERRIDE_RESET ) && ( targetROPumpPressure.override == OVERRIDE_RESET ) && ( roPumpOpenLoopTargetDutyCycle.override == OVERRIDE_RESET ) ) { targetROPumpFlowRate.data = 0; targetROPumpPressure.data = 0.0F; } // skip the firmware set call if any override is active else { result = TRUE; skipSet = TRUE; } } if ( skipSet != TRUE ) { // Set the new duty cycle of the pump roPumpOpenLoopTargetDutyCycle.data = dutyCycle; result = TRUE; // stop RO Pump if duty cycle is set to zero if ( dutyCycle == 0.0F ) { if ( ( targetROPumpFlowRate.data == 0 ) && ( targetROPumpPressure.data == 0.0F ) ) { signalROPumpHardStop(); } } else { setFluidPumpPctToPWMDutyCycle( P12_PUMP, getTargetROPumpDutyCyclePCT() ); } } } else { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_FP_INVALID_PUMP_DUTY_CYCLE_SELECTED, dutyCycle ) } return result; } /*********************************************************************//** * @brief * The getTargetRODutyCyclePCT function gets the target RO pump * pwm. * @details \b Inputs: roPumpOpenLoopTargetDutyCycle * @details \b Outputs: none * @return the current target RO pwm between 0 and 0.99 *************************************************************************/ F32 getTargetROPumpDutyCyclePCT( void ) { F32 dutyCycle = getF32OverrideValue( &roPumpOpenLoopTargetDutyCycle ); return dutyCycle; } /*********************************************************************//** * @brief * The getCurrentRODutyCyclePCT function gets the current RO pump * pwm. * @details \b Inputs: none * @details \b Outputs: none * @return the current feedback RO pwm between 0 and 0.99 *************************************************************************/ F32 getCurrentROPumpDutyCyclePCT( void ) { F32 dutyCyclePct = convertDutyCycleCntToPct( getFluidPumpReadPWMDutyCycle( P12_PUMP ) ); return dutyCyclePct; } /*********************************************************************//** * @brief * The getTargetROPumpPressure function gets the current target RO pump * pressure. * @details \b Inputs: targetROPumpPressure * @details \b Outputs: none * @return the current target RO pressure in PSI *************************************************************************/ F32 getTargetROPumpPressure( void ) { F32 pressure = getF32OverrideValue( &targetROPumpPressure ); return pressure; } /*********************************************************************//** * @brief * The getTargetROPumpFlowRateMLPM function gets the current target RO pump * flow rate. * @details \b Inputs: targetROPumpFlowRate * @details \b Outputs: none * @return the current target RO flow rate (in mL/min). *************************************************************************/ U32 getTargetROPumpFlowRateMLPM( void ) { U32 flowRate = getU32OverrideValue( &targetROPumpFlowRate ); return flowRate; } /*********************************************************************//** * @brief * The roPumpPresToPWM function calculates the duty cycle for the given target * pressure. * @details \b Inputs: none * @details \b Outputs: dutyCyclePct * @param targetPressure target pressure value to control in PSI * @return the current target RO pump PWM in a percentage. *************************************************************************/ static F32 roPumpPresToPWM( F32 targetPressure ) { F32 dutyCyclePct = ROP_PRESSURE_TO_PWM_PCT( targetPressure ); return dutyCyclePct; } /*********************************************************************//** * @brief * The roPumpFlowToPWM function calculates the duty cycle for the given target * flow rate. * @details \b Inputs: none * @details \b Outputs: dutyCyclePct * @param targetFlow target flow value to control in in mL/min * @return the current target RO pump PWM in a percentage. *************************************************************************/ static F32 roPumpFlowToPWM( U32 targetFlow ) { F32 dutyCyclePct = ROP_FLOW_TO_PWM_PCT( targetFlow ); return dutyCyclePct; } /*********************************************************************//** * @brief * The signalROPumpStop function stops the P12 pump immediately and * resets all the variables associated with the P12 pump run. * @details \b Inputs: roPumpState[] * @details \b Outputs: stopPumpRequest[] * @return none *************************************************************************/ void signalROPumpHardStop( void ) { if( targetROPumpFlowRate.data > 0 ) { targetROPumpFlowRate.data = 0; resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, 0.0F ); } if( targetROPumpPressure.data > 0.0F ) { targetROPumpPressure.data = 0.0F; resetPIController( PI_CONTROLLER_ID_RO_PUMP_PRES, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, 0.0F ); } roPumpState = RO_PUMP_OFF_STATE; roPumpDutyCyclePctSet = 0.0F; roControlTimerCounter = 0; roPumpOpenLoopTargetDutyCycle.data = 0.0F; stopROPump(); } /*********************************************************************//** * @brief * The stopROPump function sets the P12 pump duty cycle to zero. * @details \b Inputs: none * @details \b Outputs: isROPumpOn, roPumpPWMDutyCyclePctSet * @return none *************************************************************************/ static void stopROPump( void ) { isROPumpOn = FALSE; // Set the new duty cycle of the pump setFluidPumpPWMDutyCycle( P12_PUMP, 0 ); } /*********************************************************************//** * @brief * The isROPumpRunning function returns the on/off status of P12 pump. * @details \b Inputs: isROPumpOn * @details \b 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 publishROPumpData function publishes p12 pump data at the set interval. * @details \b Message \b Sent: MSG_ID_FP_RO_PUMP_DATA * @details \b Inputs: roPumpDataPublicationTimerCounter * @details \b Outputs: roPumpDataPublicationTimerCounter * @return none *************************************************************************/ static void publishROPumpData( void ) { // publish RO pump data on interval if ( ++roPumpDataPublicationTimerCounter >= getU32OverrideValue( &roPumpDataPublishInterval ) ) { RO_PUMP_DATA_T pumpData; pumpData.p12PumpState = (U32)roPumpState; pumpData.p12PumpDutyCycle = (U32)getFluidPumpPWMDutyCycle( P12_PUMP ); pumpData.p12PumpFBDutyCycle = (U32)getFluidPumpReadPWMDutyCycle( P12_PUMP ); pumpData.p12PumpSpeed = getFluidPumpRPM( P12_PUMP ); pumpData.p12TargetPressure = getTargetROPumpPressure(); pumpData.p12TargetFlow = getTargetROPumpFlowRateMLPM(); pumpData.p12TargetDutyCycle = getTargetROPumpDutyCyclePCT(); pumpData.p12PumpDutyCyclePct = convertDutyCycleCntToPct( (U32)getFluidPumpPWMDutyCycle( P12_PUMP ) ); pumpData.p12PumpFBDutyCyclePct = convertDutyCycleCntToPct( (U32)getFluidPumpReadPWMDutyCycle( P12_PUMP ) ); broadcastData( MSG_ID_FP_RO_PUMP_DATA, COMM_BUFFER_OUT_CAN_FP_BROADCAST, (U08*)&pumpData, sizeof( RO_PUMP_DATA_T ) ); roPumpDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testROPumpDataPublishIntervalOverride function overrides the RO pump * data publish interval. * @details \b Inputs: roPumpDataPublishInterval * @details \b Outputs: roPumpDataPublishInterval * @param message Override message from Dialin which includes the value * that override ro pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROPumpDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &roPumpDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testROPumpTargetPressureOverride function overrides the RO pump * data publish interval. * @details \b Inputs: targetROPumpPressure * @details \b Outputs: targetROPumpPressure * @param message Override message from Dialin which includes the value * of the target pressure * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROPumpTargetPressureOverride( MESSAGE_T *message ) { TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); BOOL result = FALSE; // reset target pressure override if ( ( ovType == OVERRIDE_RESET_OVERRIDE ) && ( targetROPumpPressure.override != OVERRIDE_RESET ) ) { // Restore previous flow, duty cycle and pressure values targetROPumpPressure.data = targetROPumpPressure.ovInitData; targetROPumpPressure.ovInitData = 0.0F; targetROPumpPressure.ovData = targetROPumpPressure.ovInitData; targetROPumpPressure.override = OVERRIDE_RESET; if ( targetROPumpFlowRate.override == OVERRIDE_RESET && targetROPumpFlowRate.ovInitData != 0 ) { targetROPumpFlowRate.data = targetROPumpFlowRate.ovInitData; } if ( roPumpOpenLoopTargetDutyCycle.override == OVERRIDE_RESET && roPumpOpenLoopTargetDutyCycle.ovInitData != 0.0F ) { roPumpOpenLoopTargetDutyCycle.data = roPumpOpenLoopTargetDutyCycle.ovInitData; } } // set target pressure override else if ( ovType == OVERRIDE_OVERRIDE ) { targetROPumpPressure.ovData = payload.state.f32; targetROPumpPressure.override = OVERRIDE_KEY; if ( targetROPumpPressure.ovInitData == 0.0F ) { targetROPumpPressure.ovInitData = targetROPumpPressure.data; } handleFluidPumpF32Data( &roPumpOpenLoopTargetDutyCycle ); handleFluidPumpU32Data( &targetROPumpFlowRate ); } result = setROPumpTargetPressure(getTargetROPumpPressure(), FALSE); return result; } /*********************************************************************//** * @brief * The testROPumpTargetFlowOverride function overrides the RO pump * data publish interval. * @details \b Inputs: targetROPumpFlowRate * @details \b Outputs: targetROPumpFlowRate * @param message Override message from Dialin which includes the value * of the target flow * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROPumpTargetFlowOverride( MESSAGE_T *message ) { TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); BOOL result = FALSE; // reset target flow rate override if ( ( ovType == OVERRIDE_RESET_OVERRIDE ) && ( targetROPumpFlowRate.override != OVERRIDE_RESET ) ) { // Restore previous flow, duty cycle and pressure values targetROPumpFlowRate.data = targetROPumpFlowRate.ovInitData; targetROPumpFlowRate.ovInitData = 0; targetROPumpFlowRate.ovData = targetROPumpFlowRate.ovInitData; targetROPumpFlowRate.override = OVERRIDE_RESET; if ( roPumpOpenLoopTargetDutyCycle.override == OVERRIDE_RESET && roPumpOpenLoopTargetDutyCycle.ovInitData != 0.0F ) { roPumpOpenLoopTargetDutyCycle.data = roPumpOpenLoopTargetDutyCycle.ovInitData; } if ( targetROPumpPressure.override == OVERRIDE_RESET && targetROPumpPressure.ovInitData != 0.0F ) { targetROPumpPressure.data = targetROPumpPressure.ovInitData; } } // set target flow rate override else if ( ovType == OVERRIDE_OVERRIDE ) { targetROPumpFlowRate.ovData = payload.state.u32; targetROPumpFlowRate.override = OVERRIDE_KEY; if ( targetROPumpFlowRate.ovInitData == 0 ) { targetROPumpFlowRate.ovInitData = targetROPumpFlowRate.data; } handleFluidPumpF32Data( &roPumpOpenLoopTargetDutyCycle ); handleFluidPumpF32Data( &targetROPumpPressure ); } result = setROPumpTargetFlowRateMLPM(getTargetROPumpFlowRateMLPM(), FALSE); return result; } /*********************************************************************//** * @brief * The testROPumpTargetDutyCycleOverride function overrides the RO pump * duty cycle. * @details \b Inputs: roPumpOpenLoopTargetDutyCycle * @details \b Outputs: roPumpOpenLoopTargetDutyCycle * @param message Override message from Dialin which includes the value * of the target flow * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROPumpTargetDutyCycleOverride( MESSAGE_T *message ) { TEST_OVERRIDE_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); BOOL result = FALSE; // reset target duty cycle override if ( ( ovType == OVERRIDE_RESET_OVERRIDE ) && ( roPumpOpenLoopTargetDutyCycle.override != OVERRIDE_RESET ) ) { // Restore previous flow, duty cycle and pressure values roPumpOpenLoopTargetDutyCycle.data = roPumpOpenLoopTargetDutyCycle.ovInitData; roPumpOpenLoopTargetDutyCycle.ovInitData = 0.0F; roPumpOpenLoopTargetDutyCycle.ovData = roPumpOpenLoopTargetDutyCycle.ovInitData; roPumpOpenLoopTargetDutyCycle.override = OVERRIDE_RESET; if ( targetROPumpFlowRate.override == OVERRIDE_RESET && targetROPumpFlowRate.ovInitData != 0 ) { targetROPumpFlowRate.data = targetROPumpFlowRate.ovInitData; } if ( targetROPumpPressure.override == OVERRIDE_RESET && targetROPumpPressure.ovInitData != 0 ) { targetROPumpPressure.data = targetROPumpPressure.ovInitData; } } // set target duty cycle override else if ( ovType == OVERRIDE_OVERRIDE ) { roPumpOpenLoopTargetDutyCycle.ovData = payload.state.f32; roPumpOpenLoopTargetDutyCycle.override = OVERRIDE_KEY; if ( roPumpOpenLoopTargetDutyCycle.ovInitData == 0.0F ) { roPumpOpenLoopTargetDutyCycle.ovInitData = roPumpOpenLoopTargetDutyCycle.data; } handleFluidPumpU32Data( &targetROPumpFlowRate ); handleFluidPumpF32Data( &targetROPumpPressure ); } result = setROPumpTargetDutyCycle(getTargetROPumpDutyCyclePCT(), FALSE); return result; } /*********************************************************************//** * @brief * The testBoostPumpHardStopOverride function stops the RO pump. * @details \b Inputs: boostPumpOpenLoopTargetDutyCycle * @details \b Outputs: boostPumpOpenLoopTargetDutyCycle * @param message Override message from Dialin which includes the value * of the target flow * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testROPumpHardStop( MESSAGE_T *message ) { BOOL result = TRUE; signalROPumpHardStop(); return result; } /**@}*/