/************************************************************************** * * Copyright (c) 2025-2025 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 FluidPump.c * * @author (last) Michael Garthwaite * @date (last) 08-Sep-2025 * * @author (original) Michael Garthwaite * @date (original) 08-Sep-2025 * ***************************************************************************/ #include "FluidPump.h" #include "FpgaDD.h" #include "Messaging.h" #include "MessageSupport.h" #include "PersistentAlarm.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup FluidPump * @{ */ // ********** private definitions ********** #define FLUID_PUMP_COUNTS_2_RPM_NUMERATOR 1500000.0F ///< Numerator in counts to RPM conversion. #define FLUID_PUMP_COUNTS_FOR_STOPPED_PUMP 0xFFFF ///< FPGA will report FFFF counts when pump is stopped. /// Payload record structure for fluid pump set PWM request typedef struct { U32 pumpID; ///< Pump ID U32 pwm; ///< Pump PWM magnitude (0..500). } FLUID_PUMP_CMD_PAYLOAD_T; // ********** private data ********** static U16 fluidPumpCmdDutyCycle[ NUM_OF_PUMPS ]; ///< Commanded duty cycles for fluid pumps. static OVERRIDE_U32_T fluidPumpReadDutyCycle[ NUM_OF_PUMPS ]; ///< Fluid pump duty cycles read back from FPGA. static OVERRIDE_F32_T fluidPumpMeasRPM[ NUM_OF_PUMPS ]; ///< Fluid pump measured speeds (RPM). // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initFluidPump function initializes the Fluid Pump driver unit. * @details \b Inputs: none * @details \b Outputs: Fluid pump unit initialized. * @return none *************************************************************************/ void initFluidPump( void ) { U32 pump; // initialize duty cycles and measured speeds for ( pump = 0; pump < NUM_OF_PUMPS; pump++ ) { fluidPumpCmdDutyCycle[ pump ] = 0; fluidPumpReadDutyCycle[ pump ].data = 0; fluidPumpReadDutyCycle[ pump ].ovData = 0; fluidPumpReadDutyCycle[ pump ].ovInitData = 0; fluidPumpReadDutyCycle[ pump ].override = OVERRIDE_RESET; fluidPumpMeasRPM[ pump ].data = 0.0F; fluidPumpMeasRPM[ pump ].ovData = 0.0F; fluidPumpMeasRPM[ pump ].ovInitData = 0.0F; fluidPumpMeasRPM[ pump ].override = OVERRIDE_RESET; } // set RO pump to stop setFPGAP12PumpPWM( 0 ); // TODO set fluid pump to stop } /*********************************************************************//** * @brief * The readFluidPumps function reads the PWM and tach counts for each fluid pump. * @details \b Inputs: none * @details \b Outputs: fluidPumpReadDutyCycle[], fluidPumpMeasRPM[] * @return none *************************************************************************/ void readFluidPumps( void ) { U32 tach; U32 pump; for ( pump = 0; pump < NUM_OF_PUMPS; pump++ ) { // get latest fluid pump duty cycle read back from FPGA // and get latest fluid pump tachometer count from FPGA and convert to RPM if ( P12_PUMP == pump ) { fluidPumpReadDutyCycle[ pump ].data = getFPGAP12PumpPWM(); tach = (U32)getFPGAP12PumpTachCount(); } else { fluidPumpReadDutyCycle[ pump ].data = getFPGAP40PumpPWM(); tach = (U32)getFPGAP40PumpTachCount(); } if ( ( tach != 0 ) && ( tach < FLUID_PUMP_COUNTS_FOR_STOPPED_PUMP ) ) { fluidPumpMeasRPM[ pump ].data = FLUID_PUMP_COUNTS_2_RPM_NUMERATOR / (F32)tach; } else { fluidPumpMeasRPM[ pump ].data = 0.0F; } } } /*********************************************************************//** * @brief * The setFluidPumpPctToPWMDutyCycle function sets the commanded PWM percentage * for the given fluid pump. * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if invalid fluid pump ID given. * @details \b Inputs: none * @details \b Outputs: none * @param pumpID ID of fluid pump to set commanded PWM magnitude for. * @param dutyCyclePct Value (0..0.99) indicating magnitude of PWM duty cycle to set * @return TRUE if duty cycle set successfully, FALSE if not *************************************************************************/ BOOL setFluidPumpPctToPWMDutyCycle( FP_FLUID_PUMP_T pumpID, F32 dutyCyclePct) { BOOL result = FALSE; U16 pwmCnt = 0; if ( pumpID < NUM_OF_PUMPS ) { pwmCnt = convertDutyCyclePctToCnt( dutyCyclePct ); result = setFluidPumpPWMDutyCycle(pumpID, pwmCnt); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_INVALID_FLUID_PUMP_ID1, (U32)pumpID ) } return result; } /*********************************************************************//** * @brief * The setFluidPumpPWMDutyCycle function sets the commanded PWM magnitude (0..500) * for the given fluid pump. * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if invalid fluid pump ID given. * @details \b Inputs: none * @details \b Outputs: fluidPumpCmdDutyCycle[] * @param pumpID ID of fluid pump to set commanded PWM magnitude for. * @param pwm Value (0..500) indicating magnitude of PWM duty cycle to set * @return TRUE if duty cycle set successfully, FALSE if not *************************************************************************/ BOOL setFluidPumpPWMDutyCycle( FP_FLUID_PUMP_T pumpID, U16 pwm ) { BOOL result = FALSE; if ( pumpID < NUM_OF_PUMPS ) { // enable/disable pump per given PWM if ( P12_PUMP == pumpID ) { if ( 0 == pwm ) { setFPGAP12PumpEnable( FALSE ); } else { setFPGAP12PumpEnable( TRUE ); } } else { if ( 0 == pwm ) { setFPGAP40PumpEnable( FALSE ); } else { setFPGAP40PumpEnable( TRUE ); } } // constrain given pwm magnitude to valid range pwm = MIN( pwm, MAX_FLUID_PUMP_PWM_DUTY_CYCLE ); // set commanded duty cycle for given fluid pump to given pwm magnitude fluidPumpCmdDutyCycle[ pumpID ] = pwm; if ( P12_PUMP == pumpID ) { setFPGAP12PumpPWM( pwm ); } else { setFPGAP12PumpPWM( pwm ); } result = TRUE; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_INVALID_FLUID_PUMP_ID1, (U32)pumpID ) } return result; } /*********************************************************************//** * @brief * The getFluidPumpPWMDutyCycle function gets the commanded PWM magnitude (0..500) * for the given fluid pump. * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if invalid fluid pump ID given. * @details \b Inputs: fluidPumpCmdDutyCycle[] * @details \b Outputs: none * @param pumpID ID of fluid pump to get commanded PWM magnitude for. * @return Value (0..500) indicating magnitude of PWM duty cycle *************************************************************************/ U16 getFluidPumpPWMDutyCycle( FP_FLUID_PUMP_T pumpID ) { U16 result = 0; if ( pumpID < NUM_OF_PUMPS ) { result = fluidPumpCmdDutyCycle[ pumpID ]; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_INVALID_FLUID_PUMP_ID2, (U32)pumpID ) } return result; } /*********************************************************************//** * @brief * The getFluidPumpReadPWMDutyCycle function gets the PWM magnitude (0..500) * read back from FPGA for the given fluid pump. * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if invalid fluid pump ID given. * @details \b Inputs: fluidPumpReadDutyCycle[] * @details \b Outputs: none * @param pumpID ID of fluid pump to get read back PWM magnitude for. * @return Value (0..500) indicating magnitude of PWM duty cycle *************************************************************************/ U16 getFluidPumpReadPWMDutyCycle( FP_FLUID_PUMP_T pumpID ) { U16 result = 0; if ( pumpID < NUM_OF_PUMPS ) { result = (U16)getU32OverrideValue( &fluidPumpReadDutyCycle[ pumpID ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_INVALID_FLUID_PUMP_ID3, (U32)pumpID ) } return result; } /*********************************************************************//** * @brief * The getFluidPumpRPM function gets the measured speed (RPM) for the given * fluid pump. * @details \b Alarm: ALARM_ID_RO_SOFTWARE_FAULT if invalid fluid pump ID given. * @details \b Inputs: fluidPumpMeasRPM[] * @details \b Outputs: none * @param pumpID ID of fluid pump to get measured speed for. * @return measured pump speed (RPM) for the given pump *************************************************************************/ F32 getFluidPumpRPM( FP_FLUID_PUMP_T pumpID ) { F32 result = 0.0F; if ( pumpID < NUM_OF_PUMPS ) { result = (U16)getF32OverrideValue( &fluidPumpMeasRPM[ pumpID ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_SOFTWARE_FAULT, FP_FAULT_ID_INVALID_FLUID_PUMP_ID4, (U32)pumpID ) } return result; } /*********************************************************************//** * @brief * The convertDutyCyclePctToCnt function converts a duty cycle percentage * into counts to set the PWM magnitude. * @details Inputs: none * @details Outputs: none * @param dutyCyclePct duty cycle percentage to be converted. * @return Value (0..500) indicating magnitude of PWM duty cycle. *************************************************************************/ U16 convertDutyCyclePctToCnt( F32 dutyCyclePct ) { U16 pwmCnt = (U16)MAX( (MAX_FLUID_PUMP_PWM_DUTY_CYCLE * dutyCyclePct) , MIN_FLUID_PUMP_PWM_DUTY_CYCLE ); return pwmCnt; } /*********************************************************************//** * @brief * The convertDutyCycleCntToPct function converts a duty cycle counts * into percentage to read the PWM magnitude. * @details Inputs: none * @details Outputs: none * @param dutyCyclePct duty cycle count to be converted. * @return Value (0..0.99) indicating magnitude of PWM duty cycle as a percentage. *************************************************************************/ F32 convertDutyCycleCntToPct( U32 dutyCycleCnt ) { F32 pwmCnt = MAX( ( (F32)dutyCycleCnt / (F32)MAX_FLUID_PUMP_PWM_DUTY_CYCLE ) , (F32)MIN_FLUID_PUMP_PWM_DUTY_CYCLE ); return pwmCnt; } /*********************************************************************//** * @brief * The handleFluidPumpU32Data function checks the OVERRIDE_U32_T and sets * the current data to 0 and resets the override if it is active. * @details \b Inputs: None * @details \b Outputs: None * @param ovU32 pointer to an unsigned integer override record * @return none *************************************************************************/ void handleFluidPumpU32Data( OVERRIDE_U32_T *ovU32) { if ( ovU32->data > 0 ) { if ( ovU32->override != OVERRIDE_RESET ) { ovU32->ovData = 0; ovU32->override = OVERRIDE_RESET; ovU32->data = 0; } else if ( ovU32->ovInitData == 0 ) { ovU32->ovInitData = ovU32->data; ovU32->data = 0; } } } /*********************************************************************//** * @brief * The handleFluidPumpF32Data function checks the OVERRIDE_F32_T and sets * the current data to 0 and resets the override if it is active. * @details \b Inputs: None * @details \b Outputs: None * @param ovF32 pointer to an floating point override record * @return none *************************************************************************/ void handleFluidPumpF32Data( OVERRIDE_F32_T *ovF32) { if ( ovF32->data > 0.0F ) { if ( ovF32->override != OVERRIDE_RESET ) { ovF32->ovData = 0.0F; ovF32->override = OVERRIDE_RESET; ovF32->data = 0.0F; } else if ( ovF32->ovInitData == 0.0F ) { ovF32->ovInitData = ovF32->data; ovF32->data = 0.0F; } } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetFluidPumpPWM function sets a given fluid pump to a given PWM * value. * @details \b Inputs: none * @details \b Outputs: fluidPumpCmdDutyCycle[] * @param message Override message from Dialin which includes an ID of * the pump to override and the PWM to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetFluidPumpPWM( MESSAGE_T *message ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { if ( sizeof( FLUID_PUMP_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { FLUID_PUMP_CMD_PAYLOAD_T payload; memcpy( &payload, &message->payload[0], sizeof( FLUID_PUMP_CMD_PAYLOAD_T ) ); result = setFluidPumpPWMDutyCycle( (FP_FLUID_PUMP_T)payload.pumpID, (U16)payload.pwm ); } } return result; } /*********************************************************************//** * @brief * The testFluidPumpPWMOverride function overrides the measured PWM of the * given fluid pump. * @details \b Inputs: none * @details \b Outputs: fluidPumpReadDutyCycle[] * @param message Override message from Dialin which includes an ID of * the fluid pump to override PWM for and the PWM to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testFluidPumpPWMOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &fluidPumpReadDutyCycle[0], NUM_OF_PUMPS - 1, 0, MAX_FLUID_PUMP_PWM_DUTY_CYCLE ); return result; } /*********************************************************************//** * @brief * The testFluidPumpRPMOverride function overrides the measured speed (RPM) * of the given fluid pump. * @details \b Inputs: none * @details \b Outputs: fluidPumpMeasRPM[] * @param message Override message from Dialin which includes an ID of * the fluid pump to override speed for and the speed to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testFluidPumpRPMOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &fluidPumpMeasRPM[0], NUM_OF_PUMPS - 1 ); return result; } /**@}*/