/************************************************************************** * * Copyright (c) 2025-2026 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 RinsePump.c * * @author (last) “Raghu * @date (last) 04-Feb-2026 * * @author (original) Vinayakam Mani * @date (original) 02-Oct-2025 * ***************************************************************************/ #include "AlarmMgmtDD.h" #include "FpgaDD.h" #include "Messaging.h" #include "OperationModes.h" #include "RinsePump.h" #include "TaskGeneral.h" #include "Timers.h" #include "Valves.h" /** * @addtogroup RinsePump * @{ */ // ********** private definitions ********** #define RINSE_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Rinse pump data publish interval. #define DATA_PUBLISH_COUNTER_START_COUNT 13 ///< Rinse pump data publish start counter. #define RINSE_PUMP_OFF_COUNT 0U ///< Rinse Pump OFF value in count #define RINSE_PUMP_DEFAULT_PWM_PERCENT 45.0F ///< Initial Rinse pump PWM percentage #define RINSE_PUMP_MAX_PWM_PERCENT 100.0F ///< Max Rinse pump PWM percentage #define RINSE_PUMP_PWM_IN_COUNT_MAX 250.0F ///< Rinse pump max count (100% PWM = 250) #define RINSE_PUMP_PWM_PULSE_RESOLUTION_US 10 ///< Rinse pump PWM pulse resolution in 10us // TODO remove once PMW control is implemented #define RINSE_PUMP_TURN_OFF_CONTROL_BIT 0xFE ///< Rinse pump turn off control bit. #define RINSE_PUMP_TURN_ON_CONTROL_BIT 0xFF ///< Rinse pump turn on control bit. #define RINSE_PUMP_PULSE_WIDTH_INVALID_MIN 0U ///< Invalid pulse width minimum (no rotation). #define RINSE_PUMP_PULSE_WIDTH_INVALID_MAX 0xFFFFU ///< Invalid pulse width maximum (sensor fault). #define RINSE_PUMP_SPD_OUT_OF_RANGE_TOL_PCT 0.10F ///< Rinse pump commanded vs measured speed tolerance (10%). #define RINSE_PUMP_MAX_RPM_ESTIMATE 3000U ///< Estimated max rinse pump RPM (for PWM-to-target conversion). // ********** private data ********** static RINSE_PUMP_STATE_T currentRinsePumpState; ///< Current rinse pump control state. static U32 rinsePumpDataPublicationTimerCounter; ///< Rinse pump data broadcast timer counter. static U32 rinsePumpMeasuredSpeed; ///< Rinse pump measured speed (RPM) static U32 rinsePumpTargetSpeedRPM; ///< Rinse pump commanded target speed (RPM) for monitor static OVERRIDE_F32_T rinsePumpPwmPercentage; ///< Rinse pump PWM percentage. static OVERRIDE_U32_T rinsePumpDataPublishInterval; ///< Rinse pump data broadcast interval (in ms). // ********** private function prototypes ********** static RINSE_PUMP_STATE_T handleRinsePumpStartState( void ); static RINSE_PUMP_STATE_T handleRinsePumpOffState( void ); static RINSE_PUMP_STATE_T handleRinsePumpOnState ( void ); static void publishRinsePumpData( void ); static void setRinsePumpPwmCount( RINSE_PUMP_ID_T pumpId, U32 pwmCount ); /*********************************************************************//** * @brief * The initRinsePump function initializes the rinse pump driver. * @details \b Inputs: none * @details \b Outputs: Rinse pump driver unit initialized * @return none *************************************************************************/ void initRinsePump(void) { // Initialize controller variables rinsePumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; currentRinsePumpState = RINSE_PUMP_STATE_INIT; rinsePumpDataPublishInterval.data = RINSE_PUMP_DATA_PUB_INTERVAL; rinsePumpDataPublishInterval.ovData = RINSE_PUMP_DATA_PUB_INTERVAL; rinsePumpDataPublishInterval.ovInitData = RINSE_PUMP_DATA_PUB_INTERVAL; rinsePumpDataPublishInterval.override = OVERRIDE_RESET; rinsePumpPwmPercentage.data = RINSE_PUMP_DEFAULT_PWM_PERCENT; rinsePumpPwmPercentage.ovData = RINSE_PUMP_DEFAULT_PWM_PERCENT; rinsePumpPwmPercentage.ovInitData = RINSE_PUMP_DEFAULT_PWM_PERCENT; rinsePumpPwmPercentage.override = OVERRIDE_RESET; rinsePumpMeasuredSpeed = 0U; rinsePumpTargetSpeedRPM = 0U; } /*********************************************************************//** * @brief * The setRinsePumpState function sets the current rinse pump state machine state. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if invalid state given. * @details \b Inputs: currentRinsePumpState * @details \b Outputs: currentRinsePumpState * @param state Rinse pump state to set * @return none *************************************************************************/ void setRinsePumpState( RINSE_PUMP_STATE_T state ) { if ( state < NUM_OF_RINSE_PUMP_STATES ) { currentRinsePumpState = state; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_RINSE_PUMP_INVALID_STATE1, (U32)state ) } } /*********************************************************************//** * @brief * The getRinsePumpState function returns the current rinse pump state machine. * @details \b Inputs: currentRinsePumpState * @details \b Outputs: none * @return current state of the rinse pump state machine. *************************************************************************/ RINSE_PUMP_STATE_T getRinsePumpState( void ) { return currentRinsePumpState; } /*********************************************************************//** * @brief * The getRinsePumpMeasuredSpeed function returns the rinse pump measured * speed from FPGA feedback. * @details \b Inputs: rinsePumpMeasuredSpeed * @details \b Outputs: none * @return Measured rinse pump speed in RPM *************************************************************************/ U32 getRinsePumpMeasuredSpeed( void ) { return rinsePumpMeasuredSpeed; } /*********************************************************************//** * @brief * The getRinsePumpTargetSpeedRPM function returns the rinse pump commanded * target speed for monitor tolerance checking. * @details \b Inputs: rinsePumpTargetSpeedRPM * @details \b Outputs: none * @return Target rinse pump speed in RPM *************************************************************************/ U32 getRinsePumpTargetSpeedRPM( void ) { return rinsePumpTargetSpeedRPM; } /*********************************************************************//** * @brief * The calculateRinsePumpSpeed function calculate rinse pump speed based * on FPGA report pulse width value. * @details \b Inputs: fpgaD79PumpSpeed * @details \b Outputs: rinsePumpMeasuredSpeed * @return none. *************************************************************************/ void calculateRinsePumpSpeed( void ) { // Pulse width in 10us resolution U16 pumpPulseWidth = getFPGAD79RinsePumpPulseWidth(); U32 pumpSpeedPerSec = 0U; if ( ( RINSE_PUMP_PULSE_WIDTH_INVALID_MIN != pumpPulseWidth ) && ( RINSE_PUMP_PULSE_WIDTH_INVALID_MAX != pumpPulseWidth ) ) { pumpSpeedPerSec = US_PER_SECOND / ( pumpPulseWidth * RINSE_PUMP_PWM_PULSE_RESOLUTION_US ); // Speed in RPM rinsePumpMeasuredSpeed = pumpSpeedPerSec * SEC_PER_MIN; } else { rinsePumpMeasuredSpeed = 0U; } } /*********************************************************************//** * @brief * The execRinsePumpMonitor function executes the rinse pump monitor. * @details \b Inputs: none * @details \b Outputs: publish rinse pump data * @details \b Alarm: ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE when * commanded vs measured speed deviates beyond tolerance. Data1=measured RPM, Data2=target RPM. * @return none *************************************************************************/ void execRinsePumpMonitor( void ) { U08 fpgaConcPumpsFault = getFPGAConcentratePumpsFault(); BOOL isConcPumpFault = ( fpgaConcPumpsFault > 0 ? TRUE : FALSE ); // Check if a new calibration is available // if ( TRUE == isNewCalibrationRecordAvailable() ) // { // // Get the calibration values of acid and bicarb // getNVRecord2Driver( GET_CAL_ACID_CONCENTREATES, (U08*)&acidConcentrateCalRecord, sizeof( acidConcentrateCalRecord ), // NUMBER_OF_ACID_AND_BICARB_NV_DATA_TO_CHECK, ALARM_ID_DD_ACID_CONCENTRATE_INVALID_CAL_RECORD ); // getNVRecord2Driver( GET_CAL_BICARB_CONCENTRATES, (U08*)&bicarbConcentrateCalRecord, sizeof( bicarbConcentrateCalRecord ), // NUMBER_OF_ACID_AND_BICARB_NV_DATA_TO_CHECK, ALARM_ID_DD_BICARB_CONCENTRATE_INVALID_CAL_RECORD ); // } // Calculate rinse pump speed calculateRinsePumpSpeed(); // Monitor pump speed (commanded vs measured tolerance, triggers ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE) monitorRinsePumpSpeed(); //Publish rinse pump data // TODO should be done in monitor or controller? // publishRinsePumpData(); } /*********************************************************************//** * @brief * The execRinsePumpController function executes the rinse pump state machine. * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if the current state is invalid. * @details \b Inputs: currentRinsePumpState * @details \b Outputs: currentRinsePumpState * @return none *************************************************************************/ void execRinsePumpController( void ) { switch( currentRinsePumpState ) { case RINSE_PUMP_STATE_INIT: currentRinsePumpState = handleRinsePumpStartState(); break; case RINSE_PUMP_STATE_OFF: currentRinsePumpState = handleRinsePumpOffState(); break; case RINSE_PUMP_STATE_ON: currentRinsePumpState = handleRinsePumpOnState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_RINSE_PUMP_INVALID_EXEC_STATE, (U32)currentRinsePumpState ) break; } publishRinsePumpData(); } /*********************************************************************//** * @brief * The monitorRinsePumpSpeed function monitors the rinse pump speed and * triggers the alarms if they are out of range. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ static void monitorRinsePumpSpeed( void ) { F32 rpTargetSpeed = (F32)rinsePumpTargetSpeedRPM; F32 rpMeasSpeed = (F32)rinsePumpMeasuredSpeed; F32 rpError = 0.0F; BOOL isRpSpeedOut = FALSE; F32 tolerance = RINSE_PUMP_SPD_OUT_OF_RANGE_TOL_PCT; if ( RINSE_PUMP_STATE_ON == currentRinsePumpState ) { rpError = fabs( rpMeasSpeed - rpTargetSpeed ); if ( rpTargetSpeed > 0.0F ) { rpError = rpError / rpTargetSpeed; } isRpSpeedOut = ( rpError > tolerance ? TRUE : FALSE ); } if ( TRUE == isRpSpeedOut ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE, rinsePumpMeasuredSpeed, rinsePumpTargetSpeedRPM ); } else { clearAlarmConditionDD( ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE ); } } /*********************************************************************//** * @brief * The handleRinsePumpStartState function starts the rinse pump state machine. * @details \b Inputs: none * @details \b Outputs: none * @return next state of the rinse pump state machine *************************************************************************/ static RINSE_PUMP_STATE_T handleRinsePumpStartState( void ) { RINSE_PUMP_STATE_T state = RINSE_PUMP_STATE_OFF; return state; } /*********************************************************************//** * @brief * The handleRinsePumpOffState function stops the rinse pump * @details \b Inputs: none * @details \b Outputs: Rinse pump motor turned off * @return next state of the rinse pump state machine *************************************************************************/ static RINSE_PUMP_STATE_T handleRinsePumpOffState( void ) { RINSE_PUMP_STATE_T state = RINSE_PUMP_STATE_OFF; rinsePumpTargetSpeedRPM = 0U; if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) ) { // Set PWM count zero to stop the logical rinse pump setRinsePumpPwmCount( D79_RINSE_PUMP, RINSE_PUMP_OFF_COUNT ); } else { setValveState( D88_79_VALV, VALVE_STATE_CLOSED ); } return state; } /*********************************************************************//** * @brief * The handleRinsePumpOnState function starts the rinse pump * @details \b Inputs: none * @details \b Outputs: Rinse pump motor turned on. * @return next state of the rinse pump state machine *************************************************************************/ static RINSE_PUMP_STATE_T handleRinsePumpOnState( void ) { RINSE_PUMP_STATE_T state = RINSE_PUMP_STATE_ON; if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) ) { F32 pwmPercent = getF32OverrideValue( &rinsePumpPwmPercentage ); // TODO should this conversion happen in setPWMCount function? U08 pwmInCount = (U08)( ( pwmPercent / RINSE_PUMP_MAX_PWM_PERCENT ) * RINSE_PUMP_PWM_IN_COUNT_MAX ); rinsePumpTargetSpeedRPM = (U32)( ( (F32)pwmInCount / RINSE_PUMP_PWM_IN_COUNT_MAX ) * (F32)RINSE_PUMP_MAX_RPM_ESTIMATE ); // Turn on logical rinse pump with given PWM value setRinsePumpPwmCount( D79_RINSE_PUMP, (U32)pwmInCount ); } else { setValveState( D88_79_VALV, VALVE_STATE_OPEN ); } return state; } /*********************************************************************//** * @brief * The setRinsePumpPwmCount function maps a logical rinse pump ID to the * underlying FPGA control and applies the requested PWM count. * @details \b Inputs: pumpId, pwmCount * @details \b Outputs: FPGA rinse pump control register * @param pumpId Logical rinse pump identifier * @param pwmCount PWM magnitude (0..RINSE_PUMP_PWM_IN_COUNT_MAX) * @return none *************************************************************************/ static void setRinsePumpPwmCount( RINSE_PUMP_ID_T pumpId, U32 pwmCount ) { switch ( pumpId ) { case D79_RINSE_PUMP: setFPGAD79RinsePumpPWMControl( (U08)pwmCount ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_RINSE_PUMP, pumpId ); break; } } /*********************************************************************//** * @brief * The publishRinsePumpData function constructs and sends the rinse pump data * broadcast message. * @details \b Message \b Sent: MSG_ID_DD_RINSE_PUMP_DATA * @details \b Inputs: rinsePumpDataPublicationTimerCounter, currentRinsePumpState * @details \b Outputs: rinsePumpDataPublicationTimerCounter * @return none *************************************************************************/ static void publishRinsePumpData( void ) { if ( ++rinsePumpDataPublicationTimerCounter >= getU32OverrideValue( &rinsePumpDataPublishInterval ) ) { RINSE_PUMP_PAYLOAD_T data; data.d79State = getRinsePumpState(); data.d79PumpPWM = getF32OverrideValue( &rinsePumpPwmPercentage ); data.d79PumpRPM = rinsePumpMeasuredSpeed; broadcastData( MSG_ID_DD_RINSE_PUMP_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( RINSE_PUMP_PAYLOAD_T ) ); rinsePumpDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testRinsePumpDataPublishIntervalOverride function overrides the interval * at which the DD rinse pump data is published. * @details \b Inputs: none * @details \b Outputs: rinsePumpDataPublishInterval * @param message Override message from Dialin which includes the interval * (in ms) to override the rinse pump broadcast interval to. * @return TRUE if override request is successful, FALSE if not *************************************************************************/ BOOL testRinsePumpDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &rinsePumpDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testRinsePumpPWMPercentOverride function sets the override value * of the rinse pump PWM percentage. * @details Inputs: rinsePumpPwmPercentage (0 to 100%) * @details Outputs: rinsePumpPwmPercentage * @param message Override message from Dialin which includes the override * value of the rinse pump PWM percentage. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testRinsePumpPWMPercentOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &rinsePumpPwmPercentage ); return result; } /*********************************************************************//** * @brief * The testRinsePumpTurnOnOffRequest function sets the rinse pump status to * On or Off. * @details Inputs: none * @details Outputs: none * @param message Override message from Dialin which includes the rinse pump * value of being 0 (Off) or 1 (On) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testRinsePumpTurnOnOffRequest( MESSAGE_T *message ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { if ( message->hdr.payloadLen == sizeof( U32 ) ) { U32 rinsePumpOnOff; RINSE_PUMP_STATE_T rinsePumpState; U08* payloadPtr = message->payload; memcpy( &rinsePumpOnOff, payloadPtr, sizeof( U32 ) ); if ( ( OFF == rinsePumpOnOff ) || ( ON == rinsePumpOnOff ) ) { // Only On or Off requests are accepted rinsePumpState = ( OFF == rinsePumpOnOff ? RINSE_PUMP_STATE_OFF : RINSE_PUMP_STATE_ON ); setRinsePumpState( rinsePumpState ); result = TRUE; } } } return result; } /**@}*/