/************************************************************************** * * Copyright (c) 2024-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 ConcentratePumps.c * * @author (last) Vinayakam Mani * @date (last) 18-Sep-2024 * * @author (original) Vinayakam Mani * @date (original) 18-Sep-2024 * ***************************************************************************/ #include #include "ConcentratePumps.h" #include "FpgaDD.h" #include "MessageSupport.h" #include "Messaging.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "TaskGeneral.h" #include "Utilities.h" /** * @addtogroup ConcentratePumps * @{ */ // ********** private definitions ********** //TODO : The definitions of pump direction is differ from HDD, need to revisit. #define CONCENTRATE_PUMP_FORWARD_DIR 0x1 ///< Concentrate pump forward direction configuration. #define CONCENTRATE_PUMP_REVERSE_DIR 0x0 ///< Concentrate pump reverse direction configuration. #define CONCENTRATE_PUMP_SPEED_INCREMENT 10.0F ///< Speed increase (mL/min) when controlling concentrate pump to target step speed. #define CONCENTRATE_PUMP_MIN_SPEED 3.0F ///< Minimum speed for concentrate pump in mL per min. #define CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_ON_PCT 0.02F ///< Concentrate pump speed out of range tolerance when on in percentage. #define CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_SLOW_MLPM 1.0F ///< Concentrate pump speed out of range tolerance when slow in mL/min. #define CONCENTRATE_PUMP_LOW_SPEED_THRESHOLD_MLPM 10.0F ///< Concentrate pump low speed threshold in mL/min. #define CONCENTRATE_PUMP_ZERO_FLOW_RATE 0xFFFF ///< Pulse width value when zero flow rate or pump is off. #define CONCENTRATE_PUMP_VOLUME_PER_REV 0.1F ///< Volume output every revolution (mL). #define CONCENTRATE_PUMP_PULSE_PER_REV 2.0F ///< Number of pulses generate for every revolution. #define CONCENTRATE_PUMP_STEP_PER_REV 200.0F ///< Number of steps for every revolution. #define CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION 100.0F ///< Hall sense period resolution in microseconds. #define CONCENTRATE_PUMP_MIN_ALLOWED_HALL_SENSOR_COUNT 1000 ///< Hall sensors minimum allowed value. #define CONCENTRATE_PUMP_HALL_SENSORS_OUT_OF_RANGE_TIME_MS ( 5 * MS_PER_SECOND ) ///< Hall sensors out of range time in milliseconds. #define CONCENTRATE_PUMP_MICRO_STEPS_PER_STEP 8.0F ///< Number of micro-steps ( fractions of step) per step. #define CONCENTRATE_PUMP_VOLUME_TO_REVOLUTION ( ( 1 / CONCENTRATE_PUMP_VOLUME_PER_REV ) * \ ( CONCENTRATE_PUMP_STEP_PER_REV * \ CONCENTRATE_PUMP_MICRO_STEPS_PER_STEP ) ) ///< Convert volume in to number of revolutions needed. #define CONCENTRATE_PUMP_STEP_PERIOD_RESOLUTION ( 0.50F / ( US_PER_SECOND * SEC_PER_MIN ) ) ///< Convert step period resolution (0.50 us) to minute. /// Volume output per pulse. #define CONCENTRATE_PUMP_VOLUME_PER_PULSE ( CONCENTRATE_PUMP_VOLUME_PER_REV / CONCENTRATE_PUMP_PULSE_PER_REV ) #define CONCENTRATE_PUMP_DATA_PUBLISH_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the concentrate pump is monitored. #define CONCENTRATE_PUMP_CONTROL_INTERVAL ( 1 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the concentrate pump is controlled. #define CONCENTRATE_PUMP_SPEED_OUT_OF_RANGE_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Concentrate pumps speed out of range timeout in milliseconds. #define NUMBER_OF_ACID_AND_BICARB_NV_DATA_TO_CHECK 1 ///< Number of acid and bicarb non-volatile data to check. #define DATA_PUBLISH_COUNTER_START_COUNT 0 ///< Data publish counter start count. #define CONCENTRATE_PUMP_FAULT_PERSISTENCE_PERIOD 500 ///< Concentrate pump fault persistence period in milliseconds. #define CONCENTRATE_PUMP_TRANS_TO_RAMP_SPEED_THRESHOLD_MLPM 20.0F ///< Concentrate pump transition to ramp to target speed threshold in mL/min. #define CONCENTRATE_PUMP_CONTROL_EIGHTH_STEP 0x07 ///< Concentrate pump control 1/8th step. #define CONCENTRATE_PUMP_CONTROL_REVERSE_DIR 0x00 ///< Concentrate pump control reverse direction. #define CONCENTRATE_PUMP_CONTROL_FORWARD_DIR 0x08 ///< Concentrate pump control forward direction. #define CONCENTRATE_PUMP_CONTROL_ENABLE 0x00 ///< Concentrate pump control enable pump. #define CONCENTRATE_PUMP_CONTROL_DISABLE 0x01 ///< Concentrate pump control disable pump. #define CONCENTRATE_PUMP_CONTROL_NOT_RESET 0x20 ///< Concentrate pump control not reset. #define CONCENTRATE_PUMP_CONTROL_SLEEP_OFF 0x40 ///< Concentrate pump control sleep off. #define CONCENTRATE_PUMP_CONTROL_ENABLE_MASK 0x10 ///< Concentrate pump control enable bit mask. static const U32 CONCENTRATE_PUMP_CONTROL_FORWARD = CONCENTRATE_PUMP_CONTROL_SLEEP_OFF | CONCENTRATE_PUMP_CONTROL_NOT_RESET | CONCENTRATE_PUMP_CONTROL_ENABLE | CONCENTRATE_PUMP_CONTROL_FORWARD_DIR | CONCENTRATE_PUMP_CONTROL_EIGHTH_STEP; ///< Concentrate pump control forward. static const U32 CONCENTRATE_PUMP_CONTROL_REVERSE = CONCENTRATE_PUMP_CONTROL_SLEEP_OFF | CONCENTRATE_PUMP_CONTROL_NOT_RESET | CONCENTRATE_PUMP_CONTROL_ENABLE | CONCENTRATE_PUMP_CONTROL_REVERSE_DIR | CONCENTRATE_PUMP_CONTROL_EIGHTH_STEP; ///< Concentrate pump control reverse. /// Enumeration of concentrate pump states. typedef enum ConcentratePumpState { CONCENTRATE_PUMP_OFF_STATE = 0, ///< Concentrate pump off state. CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE, ///< Concentrate pump ramp to target state. CONCENTRATE_PUMP_CONTROL_TARGET_SPEED_STATE, ///< Concentrate pump on state. NUM_OF_CONCENTRATE_PUMP_STATES ///< Number of concentrate pump states. } CONCENTRATE_PUMP_STATE_T; /// Concentrate pump data structure typedef struct { U32 controlTimerCounter; ///< Timer counter to perform control on concentrate pump. CONCENTRATE_PUMP_STATE_T execState; ///< Concentrate pump execute current state. BOOL hasTurnOnPumpsBeenRequested; ///< Flag indicates a request to turn concentrate pumps on. F32 currentPumpSpeed; ///< Current controlled concentrate pumps' speed (mL/min). U16 togglePeriodCount; ///< Converted pump speed (mL/min) to toggle period counts (0.5 uS increment counts per step). U08 direction; ///< Concentrate pump motor direction. U08 controlSet; ///< Concentrate pump control set. (Used in DVT) F32 pulseWidthUS; ///< Concentrate pump pulse width in microseconds. BOOL isConcPumpParkInProgress; ///< Concentrate pump park progress boolean flag (T/F). } CONCENTRATE_PUMP_T; /// Payload record structure for concentrate pump start/stop request typedef struct { U32 pumpID; ///< Concentrate pump ID (0:Acid ,1:Bicarb) U32 startStop; ///< Concentrate pump start:1,stop :0. F32 speed; ///< Speed range from 0.1 ml/min to 48.0 ml/min. F32 volume; ///< Target volume in ml } CONC_PUMP_START_STOP_CMD_PAYLOAD_T; // ********** private data ********** static U32 concentratePumpMonitorTimerCounter; ///< Timer counter to perform monitor on concentrate pump. static BOOL acidConcentratePumpParkPersistenceClear; ///< Boolean acid park persistence clearing. static BOOL bicarbConcentratePumpParkPersistenceClear; ///< Boolean for bicard park persistence clearing. /// Concentrate pump data publish interval. static OVERRIDE_U32_T concentratePumpDataPublishInterval = { CONCENTRATE_PUMP_DATA_PUBLISH_INTERVAL, CONCENTRATE_PUMP_DATA_PUBLISH_INTERVAL, 0, 0 }; static CONCENTRATE_PUMP_T concentratePumps[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Array of concentrate pumps' data structure. static OVERRIDE_U32_T hasParkBeenRequested[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Flag indicates a request to park the pump. static OVERRIDE_F32_T pumpTargetSpeed[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Target concentrate pumps' speed (mL/min). static OVERRIDE_U32_T pumpTargetRevCnt[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Target concentrate pump revolution count static OVERRIDE_U32_T pumpMesauredRevCnt[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Current measured concentrate pump revolution count static OVERRIDE_F32_T measuredPumpSpeed[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Measured concentrate pump speed (mL/min). static OVERRIDE_U32_T parked[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Concentrate pump is currently parked (T/F). static OVERRIDE_U32_T parkFaulted[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Concentrate pump park command has faulted (T/F). //static DD_ACID_CONCENTRATES_RECORD_T acidConcentrateCalRecord; ///< Acid concentrate calibration record. //static DD_BICARB_CONCENTRATES_RECORD_T bicarbConcentrateCalRecord; ///< Bicarb concentrate calibration record. //static DD_CONC_PUMPS_CAL_RECORD_T concentratePumpsCalRecord; ///< Concentrate pumps calibration record. // ********** private function prototypes ********** static void stopConcentratePump( CONCENTRATE_PUMPS_T pumpId ); static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOffState( CONCENTRATE_PUMPS_T pumpId ); static CONCENTRATE_PUMP_STATE_T handleConcentratePumpRampToTargetSpeedState( CONCENTRATE_PUMPS_T pumpId ); static CONCENTRATE_PUMP_STATE_T handleConcentratePumpControlTargetSpeedState( CONCENTRATE_PUMPS_T pumpId ); static BOOL stepConcentratePumpToTargetSpeed( CONCENTRATE_PUMPS_T pumpId ); static void calcMeasuredPumpsSpeed( void ); static void monitorPumpSpeed( CONCENTRATE_PUMPS_T pumpId, ALARM_ID_T alarm ); static void checkConcentratePumpControlSet( CONCENTRATE_PUMPS_T pumpId ); static void publishConcentratePumpData( void ); /*********************************************************************//** * @brief * The initConcentratePump function initializes the ConcentratePumps unit. * @details \b Inputs: none * @details \b Outputs: ConcentratePumps unit variables initialized * @return none *************************************************************************/ void initConcentratePump( void ) { CONCENTRATE_PUMPS_T pumpId; concentratePumpMonitorTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; acidConcentratePumpParkPersistenceClear = FALSE; bicarbConcentratePumpParkPersistenceClear = FALSE; for ( pumpId = CONCENTRATEPUMPS_CP1_ACID; pumpId < NUM_OF_CONCENTRATE_PUMPS; pumpId++ ) { concentratePumps[ pumpId ].controlTimerCounter = 0; concentratePumps[ pumpId ].execState = CONCENTRATE_PUMP_OFF_STATE; measuredPumpSpeed[ pumpId ].data = 0.0F; measuredPumpSpeed[ pumpId ].ovInitData = 0.0F; measuredPumpSpeed[ pumpId ].ovData = 0.0F; measuredPumpSpeed[ pumpId ].override = OVERRIDE_RESET; concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; hasParkBeenRequested[ pumpId ].data = FALSE; hasParkBeenRequested[ pumpId ].ovInitData = FALSE; hasParkBeenRequested[ pumpId ].ovData = FALSE; hasParkBeenRequested[ pumpId ].override = OVERRIDE_RESET; parked[ pumpId ].data = FALSE; parked[ pumpId ].ovInitData = FALSE; parked[ pumpId ].ovData = FALSE; parked[ pumpId ].override = OVERRIDE_RESET; parkFaulted[ pumpId ].data = FALSE; parkFaulted[ pumpId ].ovInitData = FALSE; parkFaulted[ pumpId ].ovData = FALSE; parkFaulted[ pumpId ].override = OVERRIDE_RESET; pumpTargetSpeed[ pumpId ].data = 0.0F; pumpTargetSpeed[ pumpId ].ovInitData = 0.0F; pumpTargetSpeed[ pumpId ].ovData = 0.0F; pumpTargetSpeed[ pumpId ].override = OVERRIDE_RESET; pumpTargetRevCnt[ pumpId ].data = 0; pumpTargetRevCnt[ pumpId ].ovInitData = 0; pumpTargetRevCnt[ pumpId ].ovData = 0; pumpTargetRevCnt[ pumpId ].override = OVERRIDE_RESET; pumpMesauredRevCnt[ pumpId ].data = 0; pumpMesauredRevCnt[ pumpId ].ovInitData = 0; pumpMesauredRevCnt[ pumpId ].ovData = 0; pumpMesauredRevCnt[ pumpId ].override = OVERRIDE_RESET; concentratePumps[ pumpId ].direction = CONCENTRATE_PUMP_FORWARD_DIR; concentratePumps[ pumpId ].controlSet = CONCENTRATE_PUMP_CONTROL_FORWARD; concentratePumps[ pumpId ].isConcPumpParkInProgress = FALSE; stopConcentratePump( pumpId ); } initPersistentAlarm( ALARM_ID_DD_CP1_SPEED_CONTROL_ERROR, 0, CONCENTRATE_PUMP_SPEED_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_DD_CP2_SPEED_CONTROL_ERROR, 0, CONCENTRATE_PUMP_SPEED_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_DD_CONC_PUMP_HALL_SENSOR_OUT_OF_RANGE, CONCENTRATE_PUMP_HALL_SENSORS_OUT_OF_RANGE_TIME_MS, CONCENTRATE_PUMP_HALL_SENSORS_OUT_OF_RANGE_TIME_MS ); initPersistentAlarm( ALARM_ID_DD_CONCENTRATE_PUMP_FAULT, CONCENTRATE_PUMP_FAULT_PERSISTENCE_PERIOD, CONCENTRATE_PUMP_FAULT_PERSISTENCE_PERIOD ); } /*********************************************************************//** * @brief * The execConcentratePumpMonitor function executes the concentrate pump monitor. * @details \b Inputs: none * @details \b Outputs: publish concentrate pump data * @details \b Alarm: ALARM_ID_DD_CONCENTRATE_PUMP_FAULT when FPGA reports any * pump fault. * @return none *************************************************************************/ void execConcentratePumpMonitor( 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 pump speed for each defined pump calcMeasuredPumpsSpeed(); parked[ CONCENTRATEPUMPS_CP1_ACID ].data = (U32)getFPGAAcidPumpIsParked(); parked[ CONCENTRATEPUMPS_CP2_BICARB ].data = (U32)getFPGABicarbPumpIsParked(); parkFaulted[ CONCENTRATEPUMPS_CP1_ACID ].data = (U32)getFPGAAcidPumpParkFault(); parkFaulted[ CONCENTRATEPUMPS_CP2_BICARB ].data = (U32)getFPGABicarbPumpParkFault(); pumpMesauredRevCnt[ CONCENTRATEPUMPS_CP1_ACID ].data = (U32)getFPGACPARevolutionCountStatus(); pumpMesauredRevCnt[ CONCENTRATEPUMPS_CP2_BICARB ].data = (U32)getFPGACPBRevolutionCountStatus(); if ( ( TRUE == getConcPumpIsParked( CONCENTRATEPUMPS_CP1_ACID ) ) || ( TRUE == getConcPumpParkIsFaulted( CONCENTRATEPUMPS_CP1_ACID ) ) ) { // If the pump has parked or faulted during the park, then it is not in progress concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].isConcPumpParkInProgress = FALSE; } if ( ( TRUE == getConcPumpIsParked( CONCENTRATEPUMPS_CP2_BICARB ) ) || ( TRUE == getConcPumpParkIsFaulted( CONCENTRATEPUMPS_CP2_BICARB ) ) ) { concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].isConcPumpParkInProgress = FALSE; } // Don't monitor persistence for cp speed alarms if we are parked. if ( TRUE == acidConcentratePumpParkPersistenceClear ) { // Clear flag and resume persistence checking once park bit is set. if ( TRUE == getConcPumpIsParked( CONCENTRATEPUMPS_CP1_ACID ) ) { acidConcentratePumpParkPersistenceClear = FALSE; } else { resetPersistentAlarmTimer( ALARM_ID_DD_CP1_SPEED_CONTROL_ERROR ); } } if ( TRUE == bicarbConcentratePumpParkPersistenceClear ) { // Clear flag and resume persistence checking once park bit is set. if ( TRUE == getConcPumpIsParked( CONCENTRATEPUMPS_CP2_BICARB ) ) { bicarbConcentratePumpParkPersistenceClear = FALSE; } else { resetPersistentAlarmTimer( ALARM_ID_DD_CP2_SPEED_CONTROL_ERROR ); } } monitorPumpSpeed( CONCENTRATEPUMPS_CP1_ACID, ALARM_ID_DD_CP1_SPEED_CONTROL_ERROR ); monitorPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB, ALARM_ID_DD_CP2_SPEED_CONTROL_ERROR ); checkPersistentAlarm( ALARM_ID_DD_CONCENTRATE_PUMP_FAULT, isConcPumpFault, fpgaConcPumpsFault, CONCENTRATE_PUMP_FAULT_PERSISTENCE_PERIOD ); //Publish concentrate pump data publishConcentratePumpData(); } /*********************************************************************//** * @brief * The execConcentratePumpController function executes the concentrate pump controller. * @details \b Inputs: execState * @details \b Outputs: execState * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump state is seen. * @return none *************************************************************************/ void execConcentratePumpController( void ) { CONCENTRATE_PUMPS_T pumpId; for ( pumpId = CONCENTRATEPUMPS_FIRST; pumpId < NUM_OF_CONCENTRATE_PUMPS; pumpId++ ) { switch ( concentratePumps[ pumpId ].execState ) { case CONCENTRATE_PUMP_OFF_STATE: concentratePumps[ pumpId ].execState = handleConcentratePumpOffState( pumpId ); break; case CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE: concentratePumps[ pumpId ].execState = handleConcentratePumpRampToTargetSpeedState( pumpId ); break; case CONCENTRATE_PUMP_CONTROL_TARGET_SPEED_STATE: concentratePumps[ pumpId ].execState = handleConcentratePumpControlTargetSpeedState( pumpId ); break; #ifndef _VECTORCAST_ // The switch case is in a for loop so the default case cannot be covered in VectorCAST default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_EXEC_INVALID_STATE, pumpId ) concentratePumps[ pumpId ].execState = CONCENTRATE_PUMP_OFF_STATE; break; #endif } } } /*********************************************************************//** * @brief * The execConcenratePumpsSelfTest function executes the concentrate pumps * self-test. * @details \b Inputs: calibration * @details \b Outputs: none * @return ConcentratepumpSelfTestResult (SELF_TEST_STATUS_T) *************************************************************************/ SELF_TEST_STATUS_T execConcenratePumpsSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; // BOOL calStatus = FALSE; // calStatus |= getNVRecord2Driver( GET_CAL_ACID_CONCENTREATES, (U08*)&acidConcentrateCalRecord, sizeof( DD_ACID_CONCENTRATES_RECORD_T ), // NUMBER_OF_ACID_AND_BICARB_NV_DATA_TO_CHECK, ALARM_ID_DD_ACID_CONCENTRATE_INVALID_CAL_RECORD ); // // calStatus |= getNVRecord2Driver( GET_CAL_BICARB_CONCENTRATES, (U08*)&bicarbConcentrateCalRecord, sizeof( DD_BICARB_CONCENTRATES_RECORD_T ), // NUMBER_OF_ACID_AND_BICARB_NV_DATA_TO_CHECK, ALARM_ID_DD_BICARB_CONCENTRATE_INVALID_CAL_RECORD ); // // calStatus |= getNVRecord2Driver( GET_CAL_CONCENTRATE_PUMPS_RECORD, (U08*)&concentratePumpsCalRecord, sizeof( DD_CONC_PUMPS_CAL_RECORD_T ), // NUM_OF_CAL_DATA_DD_CONC_PUMPS, ALARM_ID_NO_ALARM ); // // result = ( TRUE == calStatus ? SELF_TEST_STATUS_PASSED : SELF_TEST_STATUS_FAILED ); return result; } /*********************************************************************//** * @brief * The requestConcentratePumpOn function requests the module to turn on * the concentrate pumps. * @details \b Inputs: none * @details \b Outputs: concentratePumps[],acidConcentratePumpParkPersistenceClear, * bicarbConcentratePumpParkPersistenceClear * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id * @return none *************************************************************************/ void requestConcentratePumpOn( CONCENTRATE_PUMPS_T pumpId ) { if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested = TRUE; acidConcentratePumpParkPersistenceClear = FALSE; bicarbConcentratePumpParkPersistenceClear = FALSE; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } } /*********************************************************************//** * @brief * The handleConcentratePumpParkRequest function accepts/rejects the park * concentrate pumps request. * @details \b Inputs: Pump state and DD operating mode * @details \b Outputs: concentratePumps[] * @return result as true if park is accomplished. *************************************************************************/ BOOL handleConcentratePumpParkRequest( void ) { BOOL result = FALSE; DD_OP_MODE_T opMode = getCurrentOperationMode(); // pumps should be not ON and DD operation mode is not in fault mode if ( ( concentratePumps[CONCENTRATEPUMPS_CP1_ACID].execState == CONCENTRATE_PUMP_OFF_STATE ) && ( concentratePumps[CONCENTRATEPUMPS_CP2_BICARB].execState == CONCENTRATE_PUMP_OFF_STATE ) && //( DD_MODE_FILL != opMode ) && ( DD_MODE_FAUL != opMode ) ) { // Park concentrate pump requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, PARK_CONC_PUMPS ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, PARK_CONC_PUMPS ); result = TRUE; } return result; } /*********************************************************************//** * @brief * The isConcPumpParkInProgress function requests whether the concentrate * pump park is in progress or not. * @details \b Inputs: concentratePumps[] * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id * @return TRUE if the concentrate pump park is in progress otherwise, FALSE *************************************************************************/ BOOL isConcPumpParkInProgress( CONCENTRATE_PUMPS_T pumpId ) { BOOL status = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { status = concentratePumps[ pumpId ].isConcPumpParkInProgress; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return status; } /*********************************************************************//** * @brief * The requestConcentratePumpOff function requests the module to turn off * the concentrate pumps. * @details \b Inputs: none * @details \b Outputs: concentratePumps[] * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId ID of concentrate pump * @param park TRUE if pump should be parked, FALSE if not * @return none *************************************************************************/ void requestConcentratePumpOff( CONCENTRATE_PUMPS_T pumpId, BOOL park ) { if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; hasParkBeenRequested[ pumpId ].data = park; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } } /*********************************************************************//** * @brief * The setConcentratePumpTargetSpeed function sets the target step speed based on * given speed in mL/min to specified concentrate pump. * @details \b Inputs: none * @details \b Outputs: concentratePumps[] * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId pump id to set step speed * @param targetSpeed_ml_min target speed in mL/min * @return none *************************************************************************/ void setConcentratePumpTargetSpeed( CONCENTRATE_PUMPS_T pumpId, F32 targetSpeed_ml_min, F32 targetVolume_ml ) { if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { if ( targetSpeed_ml_min >= 0.0 ) { concentratePumps[ pumpId ].direction = CONCENTRATE_PUMP_FORWARD_DIR; concentratePumps[ pumpId ].controlSet = CONCENTRATE_PUMP_CONTROL_FORWARD; } else { concentratePumps[ pumpId ].direction = CONCENTRATE_PUMP_REVERSE_DIR; concentratePumps[ pumpId ].controlSet = CONCENTRATE_PUMP_CONTROL_REVERSE; targetSpeed_ml_min *= -1.0; } //Update target revolution count if ( targetVolume_ml > 0.0 ) { pumpTargetRevCnt[ pumpId ].data = (U32)( targetVolume_ml * CONCENTRATE_PUMP_VOLUME_TO_REVOLUTION ); if ( CONCENTRATEPUMPS_CP1_ACID == pumpId ) { setFPGACPARevolutionCount( getConcPumpTargetRevolutionCount( pumpId ) ); } else { setFPGACPBRevolutionCount( getConcPumpTargetRevolutionCount( pumpId ) ); } } /* * If 3.0 <= speed <= 48 set it * If speed < 3.0 set to 0 * else speed > 48 set to 48 */ if ( ( CONCENTRATE_PUMP_MIN_SPEED <= targetSpeed_ml_min ) && ( targetSpeed_ml_min <= CONCENTRATE_PUMP_MAX_SPEED ) ) { pumpTargetSpeed[ pumpId ].data = targetSpeed_ml_min; } else if ( targetSpeed_ml_min < CONCENTRATE_PUMP_MIN_SPEED ) { pumpTargetSpeed[ pumpId ].data = 0.0; } else { pumpTargetSpeed[ pumpId ].data = CONCENTRATE_PUMP_MAX_SPEED; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } } /*********************************************************************//** * @brief * The getConcentratePumpTargetFlowMLPM function returns the target flow rate * for a given concentrate pump. * @details \b Inputs: concentratePumps * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get its target flow * @return the current target flow rate (in mL/min) for the given conecntrate pump. *************************************************************************/ F32 getConcentratePumpTargetFlowMLPM( CONCENTRATE_PUMPS_T pumpId ) { F32 flow = 0.0; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { flow = getPumpTargetSpeed( pumpId ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return flow; } /*********************************************************************//** * @brief * The getPumpTargetSpeed function gets the current target spped for the given * concentrate pump. * @details \b Inputs: pumpTargetSpeed * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get the current target speed * @return the current target spped for the given concentrate pump. *************************************************************************/ F32 getPumpTargetSpeed( CONCENTRATE_PUMPS_T pumpId ) { F32 speed = 0.0F; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { speed = getF32OverrideValue( &pumpTargetSpeed[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return speed; } /*********************************************************************//** * @brief * The getMeasuredPumpSpeedMLPM function gets the measured flow rate * for a given concentrate pump. * @details \b Inputs: measuredPumpSpeed * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to increase current step speed * @Note Pump speed is referred as flow rate as they are directly related across * the concentrate pump unit. * @return the current measured flow rate (in mL/min) for the given concentrate * pump. *************************************************************************/ F32 getMeasuredPumpSpeedMLPM( CONCENTRATE_PUMPS_T pumpId ) { F32 speed = 0.0F; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { speed = getF32OverrideValue( &measuredPumpSpeed[ pumpId ] ); speed = ( CONCENTRATE_PUMP_REVERSE_DIR == concentratePumps[ pumpId ].direction ? speed * -1.0F : speed ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return speed; } /*********************************************************************//** * @brief * The getConcPumpParkRequest function gets the current park request state for a * given pump. * @details \b Inputs: hasParkBeenRequested * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get park request state for * @return TRUE if a park request is pending for the given concentrate pump, * FALSE if not *************************************************************************/ BOOL getConcPumpParkRequest( CONCENTRATE_PUMPS_T pumpId ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { result = (BOOL)getU32OverrideValue( &hasParkBeenRequested[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return result; } /*********************************************************************//** * @brief * The getConcPumpTargetRevolutionCount function gets the concentrate pump * target revolution count. * @details \b Inputs: pumpTargetRevCnt * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get target revolution count * @return the target revolution count for the given concentrate pump *************************************************************************/ U16 getConcPumpTargetRevolutionCount( CONCENTRATE_PUMPS_T pumpId ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { result = (U16)getU32OverrideValue( &pumpTargetRevCnt[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return result; } /*********************************************************************//** * @brief * The getConcPumpCurrentMeasuredRevolutionCount function gets the concentrate pump * current measured revolution count. * @details \b Inputs: pumpMesauredRevCnt * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get current measured revolution count * @return the current revolution count for the given concentrate pump *************************************************************************/ U16 getConcPumpCurrentMeasuredRevolutionCount( CONCENTRATE_PUMPS_T pumpId ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { result = (U16)getU32OverrideValue( &pumpMesauredRevCnt[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return result; } /*********************************************************************//** * @brief * The getConcPumpIsParked function gets the current parked state for a * given pump. * @details \b Inputs: parked * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get parked state for * @return TRUE if the given concentrate pump is currently parked, FALSE if not. *************************************************************************/ BOOL getConcPumpIsParked( CONCENTRATE_PUMPS_T pumpId ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { result = (BOOL)getU32OverrideValue( &parked[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return result; } /*********************************************************************//** * @brief * The getConcPumpParkIsFaulted function gets the current park command * fault state for a given pump. * @details \b Inputs: parkFaulted * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId concentrate pump id to get park faulted state for * @return TRUE if the given concentrate pump has failed a park command.. *************************************************************************/ BOOL getConcPumpParkIsFaulted( CONCENTRATE_PUMPS_T pumpId ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { result = (BOOL)getU32OverrideValue( &parkFaulted[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } return result; } /*********************************************************************//** * @brief * The stopConcentratePump function sets the given concentrate pump step speed * to zero and turns off concentrate pump. Also parks the pump if requested. * @details \b Inputs: none * @details \b Outputs: concentratePumps * @param pumpId ID of the concentrate pump * @return none *************************************************************************/ static void stopConcentratePump( CONCENTRATE_PUMPS_T pumpId ) { BOOL parkPump = getConcPumpParkRequest( pumpId ); hasParkBeenRequested[ pumpId ].data = FALSE; // reset park request for next time concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; // Just to make sure pump is in Off state. concentratePumps[ pumpId ].currentPumpSpeed = 0.0F; // set target rate to zero pumpTargetSpeed[ pumpId ].data = 0.0F; pumpTargetRevCnt[ pumpId ].data = 0; // Disable the motor when stopping, to take next revolution count // Send zero rate command to stop the pump if ( CONCENTRATEPUMPS_CP1_ACID == pumpId ) { setFPGAAcidPumpSetStepSpeed( CONCENTRATE_PUMP_ZERO_FLOW_RATE ); //concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].controlSet |= CONCENTRATE_PUMP_CONTROL_ENABLE_MASK; //setFPGAAcidPumpControl( concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].controlSet ); } else { setFPGABicarbSetStepSpeed( CONCENTRATE_PUMP_ZERO_FLOW_RATE ); //concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].controlSet |= CONCENTRATE_PUMP_CONTROL_ENABLE_MASK; //setFPGABicarbPumpControl( concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].controlSet ); } // Park concentrate pump too if requested if ( TRUE == parkPump ) { if ( CONCENTRATEPUMPS_CP1_ACID == pumpId ) { setFPGAAcidPumpParkCmd(); acidConcentratePumpParkPersistenceClear = TRUE; } else { setFPGABicarbPumpParkCmd(); bicarbConcentratePumpParkPersistenceClear = TRUE; } concentratePumps[ pumpId ].isConcPumpParkInProgress = TRUE; } } /*********************************************************************//** * @brief * The handleConcentratePumpOffState function turns on a given concentrate * pumps and switch to on state upon request. * @details \b Inputs: none * @details \b Outputs: pump turned on * @param pumpId ID of the concentrate pump * @return state *************************************************************************/ static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOffState( CONCENTRATE_PUMPS_T pumpId ) { CONCENTRATE_PUMP_STATE_T state = CONCENTRATE_PUMP_OFF_STATE; if ( TRUE == concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested ) { U08 controlSet = concentratePumps[ pumpId ].controlSet; if ( CONCENTRATEPUMPS_CP1_ACID == pumpId ) { setFPGAAcidPumpControl( controlSet ); } else { setFPGABicarbPumpControl( controlSet ); } state = CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE; } // In case we are in a mode that the concentrate pumps are off but they still need to be parked, then the stop function // is called to park the pumps if ( TRUE == getConcPumpParkRequest( pumpId ) ) { stopConcentratePump( pumpId ); } return state; } /*********************************************************************//** * @brief * The handleConcentratePumpRampToTargetSpeedState function executes the * given concentrate pump ramp up to target speed state. Once the speed is close * to target the state is transitioned to control target state. * @details \b Inputs: none * @details \b Outputs: none * @param pumpId ID of the concentrate pump to ramp. * @return next state of the state machine *************************************************************************/ static CONCENTRATE_PUMP_STATE_T handleConcentratePumpRampToTargetSpeedState( CONCENTRATE_PUMPS_T pumpId ) { CONCENTRATE_PUMP_STATE_T state = CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE; //U16 currentMeasuredRev = getConcPumpCurrentMeasuredRevolutionCount( pumpId ); if ( TRUE == stepConcentratePumpToTargetSpeed( pumpId ) ) { state = CONCENTRATE_PUMP_CONTROL_TARGET_SPEED_STATE; } //Stop the pump if measured rev count reaches zero if ( FALSE == concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested ) { state = CONCENTRATE_PUMP_OFF_STATE; stopConcentratePump( pumpId ); } return state; } /*********************************************************************//** * @brief * The handleConcentratePumpControlTargetSpeedState function turns off given * concentrate pumps switch to off state upon request. While in on state, * the function controls concentrate pumps to a target step speed. * @details \b Inputs: currentPumpSpeed[] * @details \b Outputs: control given concentrate pumps to target step speed * @param pumpId ID of the concentrate pump * @return state *************************************************************************/ static CONCENTRATE_PUMP_STATE_T handleConcentratePumpControlTargetSpeedState( CONCENTRATE_PUMPS_T pumpId ) { CONCENTRATE_PUMP_STATE_T state = CONCENTRATE_PUMP_CONTROL_TARGET_SPEED_STATE; //U16 currentMeasuredRev = getConcPumpCurrentMeasuredRevolutionCount( pumpId ); F32 targetToCurreSpeedDiffMLPM = fabs( getPumpTargetSpeed( pumpId ) - concentratePumps[ pumpId ].currentPumpSpeed ); if ( ++concentratePumps[ pumpId ].controlTimerCounter >= CONCENTRATE_PUMP_CONTROL_INTERVAL ) { concentratePumps[ pumpId ].controlTimerCounter = 0; stepConcentratePumpToTargetSpeed( pumpId ); } if ( targetToCurreSpeedDiffMLPM >= CONCENTRATE_PUMP_TRANS_TO_RAMP_SPEED_THRESHOLD_MLPM ) { // If the requested target speed is greater than the threshold, transition back to ramp state regardless of the status of the // control interval stepConcentratePumpToTargetSpeed( pumpId ); state = CONCENTRATE_PUMP_RAMP_TO_TARGET_SPEED_STATE; } //Stop the pump if measured rev count reaches zero if ( FALSE == concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested ) { state = CONCENTRATE_PUMP_OFF_STATE; stopConcentratePump( pumpId ); } return state; } /*********************************************************************//** * @brief * The stepConcentratePumpToTargetSpeed function steps current step speed * toward target speed for the given concentrate pump,with predefined step increase. * @details \b Inputs: none * @details \b Outputs: currentPumpSpeed[] * @param pumpId concentrate pump id to increase current step speed * @return TRUE if the pump has reached to target otherwise, FALSE *************************************************************************/ static BOOL stepConcentratePumpToTargetSpeed( CONCENTRATE_PUMPS_T pumpId ) { F32 speedIncrease; BOOL hasTgtBeenReached = FALSE; F32 currentToTargetDiff = fabs( getPumpTargetSpeed( pumpId ) - concentratePumps[ pumpId ].currentPumpSpeed ); if ( currentToTargetDiff > NEARLY_ZERO ) { if ( currentToTargetDiff > CONCENTRATE_PUMP_SPEED_INCREMENT ) { speedIncrease = CONCENTRATE_PUMP_SPEED_INCREMENT; } else { speedIncrease = currentToTargetDiff; hasTgtBeenReached = TRUE; } // Subtract current speed when target speed is smaller if ( getPumpTargetSpeed( pumpId ) < concentratePumps[ pumpId ].currentPumpSpeed ) { speedIncrease *= -1.0F; } concentratePumps[ pumpId ].currentPumpSpeed += speedIncrease; // If the pump's target speed is set to be 0, do not ramp down set it to zero immediately if ( getPumpTargetSpeed( pumpId ) < NEARLY_ZERO ) { concentratePumps[ pumpId ].currentPumpSpeed = 0.0F; } } if ( concentratePumps[ pumpId ].currentPumpSpeed > NEARLY_ZERO ) { F32 timePerStep = CONCENTRATE_PUMP_VOLUME_PER_REV / ( concentratePumps[ pumpId ].currentPumpSpeed * CONCENTRATE_PUMP_STEP_PER_REV ); F32 stepPeriodCounts = timePerStep / ( CONCENTRATE_PUMP_STEP_PERIOD_RESOLUTION * CONCENTRATE_PUMP_MICRO_STEPS_PER_STEP ); concentratePumps[ pumpId ].togglePeriodCount = (U16)( stepPeriodCounts + FLOAT_TO_INT_ROUNDUP_OFFSET ); } else { concentratePumps[ pumpId ].togglePeriodCount = CONCENTRATE_PUMP_ZERO_FLOW_RATE; } // Check if the control set bit is set as desired and if not, correct it checkConcentratePumpControlSet( pumpId ); if ( CONCENTRATEPUMPS_CP1_ACID == pumpId ) { setFPGAAcidPumpSetStepSpeed( concentratePumps[ pumpId ].togglePeriodCount ); } else { setFPGABicarbSetStepSpeed( concentratePumps[ pumpId ].togglePeriodCount ); } return hasTgtBeenReached; } /*********************************************************************//** * @brief * The calcMeasuredPumpsSpeed function iterates through the concentrate * pumps and calculates the concentrate pump flow. It also checks that * the hall sensor pulse width count for the concentrate pump is valid. * @details \b Inputs: Hall sensor reading from FPGA * @details \b Outputs: measuredPumpSpeed * @details \b Alarms: ALARM_ID_DD_CONC_PUMP_HALL_SENSOR_OUT_OF_RANGE when * hall sensor pulse width is out of range. * @return none *************************************************************************/ static void calcMeasuredPumpsSpeed( void ) { CONCENTRATE_PUMPS_T pumpId; U16 pulseWidthCount = 0; F32 pulseWidthInMicroSeconds = 0.0F; BOOL isPulseWidthOut = FALSE; CONCENTRATE_PUMPS_T pumpInAlarm = CONCENTRATEPUMPS_FIRST; F32 pumpInAlarmPulseWidthInMicroSeconds = 0.0F; BOOL isPumpPulseWidthOut = FALSE; for ( pumpId = CONCENTRATEPUMPS_FIRST; pumpId < NUM_OF_CONCENTRATE_PUMPS; pumpId++ ) { switch ( pumpId ) { case CONCENTRATEPUMPS_CP1_ACID: pulseWidthCount = getFPGACPAHallSensePulseWidth(); break; case CONCENTRATEPUMPS_CP2_BICARB: pulseWidthCount = getFPGACPBHallSensePulseWidth(); break; #ifndef _VECTORCAST_ // Disabled in VectorCAST since it cannot be reached in VectorCAST because the switch case is in a for loop default: // Loop only allows for valid concentrate pump Ids. break; #endif } pulseWidthInMicroSeconds = pulseWidthCount * CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION; concentratePumps[ pumpId ].pulseWidthUS = pulseWidthInMicroSeconds; isPumpPulseWidthOut = ( pulseWidthInMicroSeconds <= (F32)CONCENTRATE_PUMP_MIN_ALLOWED_HALL_SENSOR_COUNT ? TRUE : FALSE ); // Determine measured speed for the pump if ( CONCENTRATE_PUMP_ZERO_FLOW_RATE == pulseWidthCount ) { measuredPumpSpeed[ pumpId ].data = 0.0F; } else if ( FALSE == isPumpPulseWidthOut ) { measuredPumpSpeed[ pumpId ].data = ( US_PER_SECOND / pulseWidthInMicroSeconds ) * CONCENTRATE_PUMP_VOLUME_PER_PULSE * SEC_PER_MIN; } // If pulse width is out of range capture pump out of range, pumpId and pulse width if ( TRUE == isPumpPulseWidthOut ) { // Pulse width for this concentrate pump is out of range isPulseWidthOut = TRUE; pumpInAlarm = pumpId; pumpInAlarmPulseWidthInMicroSeconds = pulseWidthInMicroSeconds; } } checkPersistentAlarm( ALARM_ID_DD_CONC_PUMP_HALL_SENSOR_OUT_OF_RANGE, isPulseWidthOut, pumpInAlarm, pumpInAlarmPulseWidthInMicroSeconds ); } /*********************************************************************//** * @brief * The monitorPumpSpeed function monitors the given concentrate pumps speed and * triggers the alarms if they are out of range. * @details \b Inputs: concentratePumps * @details \b Outputs: none * @details \b Alarm: ALARM_ID_DD_CP1_SPEED_CONTROL_ERROR when the speed difference * between requested and measured is not in range. * @details \b Alarm: ALARM_ID_DD_CP2_SPEED_CONTROL_ERROR when the speed difference * between requested and measured is not in range. * @param pumpId pump id to check the difference between requested and measured speed * @param alarm which the corresponding alarm of the concentrate pump * @return none *************************************************************************/ static void monitorPumpSpeed( CONCENTRATE_PUMPS_T pumpId, ALARM_ID_T alarm ) { F32 cpTargetSpeed = concentratePumps[ pumpId ].currentPumpSpeed; F32 cpError = fabs( fabs( getMeasuredPumpSpeedMLPM( pumpId ) ) - cpTargetSpeed ); BOOL isCpSpeedOut = FALSE; F32 tolerance = CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_SLOW_MLPM; if ( cpTargetSpeed > CONCENTRATE_PUMP_LOW_SPEED_THRESHOLD_MLPM ) { // Check if the pump is not in the off state and if it is not and greater than the minimum threshold, divide the error // to target speed. If the pump is off the target speed is 0 so the speed check is done differently cpError = cpError / cpTargetSpeed; tolerance = CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_ON_PCT; } isCpSpeedOut = ( cpError > tolerance ? TRUE : FALSE ); checkPersistentAlarm( alarm, isCpSpeedOut, cpError, tolerance ); } /*********************************************************************//** * @brief * The checkConcentratePumpControlSet function monitors the status of the * given concentrate pumps control set bit and if they are different from the * required set bit, they are set again. * @details \b Inputs: concentratePumps * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId pump id to check its control set bit * @return none *************************************************************************/ static void checkConcentratePumpControlSet( CONCENTRATE_PUMPS_T pumpId ) { U08 controlSetBits; switch ( pumpId ) { case CONCENTRATEPUMPS_CP1_ACID: controlSetBits = getFPGAAcidPumpControlStatus(); if ( controlSetBits != concentratePumps[ pumpId ].controlSet ) { setFPGAAcidPumpControl( concentratePumps[ pumpId ].controlSet ); } break; case CONCENTRATEPUMPS_CP2_BICARB: controlSetBits = getFPGABicarbPumpControlStatus(); if ( controlSetBits != concentratePumps[ pumpId ].controlSet ) { setFPGABicarbPumpControl( concentratePumps[ pumpId ].controlSet ); } break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); break; } } /*********************************************************************//** * @brief * The publishConcentratePumpData function publishes Concentrate pump states * at the set interval. * @details \b Inputs: concentratePumpMonitorTimerCounter * @details \b Outputs: concentratePumpMonitorTimerCounter * @details \b Message \Sent: MSG_ID_DD_CONCENTRATE_PUMP_DATA to publish concentrate pump states. * @return none *************************************************************************/ static void publishConcentratePumpData( void ) { if ( ++concentratePumpMonitorTimerCounter >= getU32OverrideValue( &concentratePumpDataPublishInterval ) ) { CONCENTRATE_PUMP_DATA_T data; U08 cp1Direction = concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].direction; F32 cp1SetSpeed = concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].currentPumpSpeed; F32 cp1TgtSpeed = getPumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID ); U08 cp2Direction = concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].direction; F32 cp2SetSpeed = concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].currentPumpSpeed; F32 cp2TgtSpeed = getPumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB ); // Use the above values to prepare the broadcast data data.cp1CurrentSetSpeed = ( CONCENTRATE_PUMP_REVERSE_DIR == cp1Direction ? cp1SetSpeed * -1.0F : cp1SetSpeed ); data.cp1MeasuredSpeed = getMeasuredPumpSpeedMLPM( CONCENTRATEPUMPS_CP1_ACID ); data.cp1TargetSpeed = ( CONCENTRATE_PUMP_REVERSE_DIR == cp1Direction ? cp1TgtSpeed * -1.0F : cp1TgtSpeed ); data.cp2CurrentSetSpeed = ( CONCENTRATE_PUMP_REVERSE_DIR == cp2Direction ? cp2SetSpeed * -1.0F : cp2SetSpeed ); data.cp2MeasuredSpeed = getMeasuredPumpSpeedMLPM( CONCENTRATEPUMPS_CP2_BICARB ); data.cp2TargetSpeed = ( CONCENTRATE_PUMP_REVERSE_DIR == cp2Direction ? cp2TgtSpeed * -1.0F : cp2TgtSpeed ); data.cp1TargetRevCount = (U32)getConcPumpTargetRevolutionCount( CONCENTRATEPUMPS_CP1_ACID ); data.cp1MeasuredRevCount= getFPGACPARevolutionCountStatus(); data.cp2TargetRevCount = (U32)getConcPumpTargetRevolutionCount( CONCENTRATEPUMPS_CP2_BICARB ); data.cp1MeasuredRevCount= getFPGACPBRevolutionCountStatus(); data.cp1State = concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].execState; data.cp2State = concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].execState; data.cp1PulseUS = concentratePumps[ CONCENTRATEPUMPS_CP1_ACID ].pulseWidthUS; data.cp2PulseUS = concentratePumps[ CONCENTRATEPUMPS_CP2_BICARB ].pulseWidthUS; data.cp1Parked = getConcPumpIsParked( CONCENTRATEPUMPS_CP1_ACID ); data.cp2Parked = getConcPumpIsParked( CONCENTRATEPUMPS_CP2_BICARB ); data.cp1ParkFault = getConcPumpParkIsFaulted( CONCENTRATEPUMPS_CP1_ACID ); data.cp2ParkFault = getConcPumpParkIsFaulted( CONCENTRATEPUMPS_CP2_BICARB ); concentratePumpMonitorTimerCounter = 0; broadcastData( MSG_ID_DD_CONCENTRATE_PUMP_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( CONCENTRATE_PUMP_DATA_T ) ); } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testConcentratePumpDataPublishIntervalOverride function overrides the * concentrate pump data publish interval. * @details \b Inputs: none * @details \b Outputs: concentratePumpDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the concentrate pump data broadcast interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &concentratePumpDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpTargetSpeedOverride function overrides the target * speed value of given concentrate pump id. * @details \b Inputs: none * @details \b Outputs: pumpTargetSpeed * @param message Override message from Dialin which includes an ID of * the pump to override and the state to override the pump to. * @return TRUE if override successful, FALSE if not * @note pump traget speed range should be between 3.0F and 45.0F. *************************************************************************/ BOOL testConcentratePumpTargetSpeedOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &pumpTargetSpeed[ 0 ], NUM_OF_CONCENTRATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpMeasuredSpeedOverride function overrides the * measured speed value of given concentrate pump id. * @details \b Inputs: none * @details \b Outputs: measuredPumpSpeed * @param message Override message from Dialin which includes an ID of * the pump to override and the state to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpMeasuredSpeedOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &measuredPumpSpeed[ 0 ], NUM_OF_CONCENTRATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpParkedOverride function overrides the parked * status of given concentrate pump id. * @details \b Inputs: none * @details \b Outputs: parked * @param message Override message from Dialin which includes an ID of * the pump to override and the state to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpParkedOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &parked[ 0 ], NUM_OF_CONCENTRATE_PUMPS - 1, FALSE, TRUE ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpTargetRevCountOverride function overrides the * target revolution count of given concentrate pump id. * @details \b Inputs: none * @details \b Outputs: pumpTargetRevCnt * @param message Override message from Dialin which includes an ID of * the pump to override and the target revolution count of the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpTargetRevCountOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &pumpTargetRevCnt[ 0 ], NUM_OF_CONCENTRATE_PUMPS - 1, 0, 65535 ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpParkCmdFaultedOverride function overrides the * park command fault status of given concentrate pump id. * @details \b Inputs: none * @details \b Outputs: parkFaulted * @param message Override message from Dialin which includes an ID of * the pump to override and the state to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpParkCmdFaultedOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &parkFaulted[ 0 ], NUM_OF_CONCENTRATE_PUMPS - 1, FALSE, TRUE ); return result; } /*********************************************************************//** * @brief * The testConcentratePumpStartStopOverride function starts a given concentrate pump * at mentioned speed/flowrate ( ml/min) or stops the concentrate pump. * @details \b Inputs: tester logged in * @details \b Outputs: concentratePumps[] * @param message set message from Dialin which includes the concentrate pump to set * and the state to set the concentratet pump to. * @return TRUE if set request is successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpStartStopOverride( MESSAGE_T *message ) { BOOL result = FALSE; // Verify tester has logged in with TD if ( TRUE == isTestingActivated() ) { // Verify payload length is valid if ( sizeof( CONC_PUMP_START_STOP_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { CONC_PUMP_START_STOP_CMD_PAYLOAD_T payload; memcpy( &payload, message->payload, sizeof(CONC_PUMP_START_STOP_CMD_PAYLOAD_T) ); if ( (CONCENTRATE_PUMPS_T)payload.pumpID < NUM_OF_CONCENTRATE_PUMPS ) { // Handle start command if ( ( TRUE == payload.startStop ) && ( ( payload.speed >= CONCENTRATE_PUMP_MIN_SPEED ) && ( payload.speed <= CONCENTRATE_PUMP_MAX_SPEED ) ) && ( payload.volume > 0.0 ) ) { setConcentratePumpTargetSpeed( (CONCENTRATE_PUMPS_T)payload.pumpID, payload.speed, payload.volume ); requestConcentratePumpOn ( (CONCENTRATE_PUMPS_T)payload.pumpID ); result = TRUE; } //Handle stop command if ( FALSE == payload.startStop ) { requestConcentratePumpOff( (CONCENTRATE_PUMPS_T)payload.pumpID, FALSE ); result = TRUE; } } } } return result; } /*********************************************************************//** * @brief * The testConcentratePumpParkRequestOverride function overrides the given pump * to park request. * @details \b Inputs: concentratePumps * @details \b Outputs: concentratePumps * @param message Override message from Dialin which includes an ID of * the pump to override and the state to override the pump to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testConcentratePumpParkRequestOverride( MESSAGE_T *message ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T override; OVERRIDE_TYPE_T ovType = getOverrideArrayPayloadFromMessage( message, &override ); // Verify tester has logged in with DD and override type is valid if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { U32 pumpId = override.index; // Verify concentrate pump index of override if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { if ( OVERRIDE_OVERRIDE == ovType ) { U32 value = override.state.u32; hasParkBeenRequested[ pumpId ].ovData = value; hasParkBeenRequested[ pumpId ].override = OVERRIDE_KEY; if ( TRUE == hasParkBeenRequested[ pumpId ].ovData ) { // If pump is running, stop it w/ park option if ( TRUE == concentratePumps[ pumpId ].hasTurnOnPumpsBeenRequested ) { requestConcentratePumpOff( (CONCENTRATE_PUMPS_T)pumpId, TRUE ); } // If pump is already stopped, just send park command else { stopConcentratePump( (CONCENTRATE_PUMPS_T)pumpId ); } } } else { hasParkBeenRequested[ pumpId ].override = OVERRIDE_RESET; hasParkBeenRequested[ pumpId ].ovData = hasParkBeenRequested[ pumpId ].ovInitData; } result = TRUE; } } return result; } /**@}*/