/************************************************************************** * * Copyright (c) 2019-2020 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) Quang Nguyen * @date (last) 30-Sep-2020 * * @author (original) Quang Nguyen * @date (original) 30-Sep-2020 * ***************************************************************************/ #include #include "ConcentratePumps.h" #include "FPGA.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" /** * @addtogroup ConcentratePumps * @{ */ // ********** private definitions ********** #define CONCENTRATE_PUMP_ON_CONTROL 0x1A ///< Configuration to turn on concentrate pump with 8 microsteps. #define CONCENTRATE_PUMP_OFF_CONTROL 0x3A ///< Configuration to turn off concentrate pump. #define CONCENTRATE_PUMP_SPEED_INCREMENT 8.0 ///< Speed increase (mL/min) when controlling concentrate pump to target step speed. #define CONCENTRATE_PUMP_MIN_SPEED 3.0 ///< Minimum speed for concentrate pump in mL per min. #define CONCENTRATE_PUMP_MAX_SPEED 49.0 ///< Maximum speed for concentrate pump in mL per min. #define CONCENTRATE_PUMP_VOLUME_PER_REV 0.15 ///< Volume output every revolution (mL). #define CONCENTRATE_PUMP_PULSE_PER_REV 4.0 ///< Number of pulses generate for every revolution. #define CONCENTRATE_PUMP_STEP_PER_REV 200.0 ///< Number of steps for every revolution. #define CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION 100.0 ///< Hall sense period resolution in microseconds. #define CONCENTRATE_PUMP_MICRO_STEPS_PER_STEP 8.0 ///< Number of micro-steps ( fractions of step) per step. #define CONCENTRATE_PUMP_STEP_PERIOD_RESOLUTION ( 0.5 / ( US_PER_SECOND * SEC_PER_MIN ) ) ///< Convert one step period (0.5 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 ( 500 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the concentrate pump is monitored. #define CONCENTRATE_PUMP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the concentrate pump is controlled. /// Enumeration of concentrate pump states. typedef enum ConcentratePumpState { CONCENTRATE_PUMP_OFF_STATE = 0, ///< Concentrate pump off state CONCENTRATE_PUMP_ON_STATE, ///< Concentrate pump on state NUM_OF_CONCENTRATE_PUMP_STATES ///< Number of concentrate pump states } CONCENTRATE_PUMP_STATE_T; // ********** private data ********** static CONCENTRATE_PUMP_STATE_T concentratePumpState; ///< Concentrate pump module current state. static BOOL isPumpOnRequested; ///< Flag indicates a request to turn concentrate pumps on. static BOOL isPumpOffRequested; ///< Flag indicates a request to turn concentrate pumps off. static U32 concentratePumpControlTimerCounter; ///< Timer counter to perform control on concentrate pump. static U32 concentratePumpMonitorTimerCounter; ///< Timer counter to perform monitor on concentrate pump. /// Concentrate pump data publish interval. static OVERRIDE_U32_T concentratePumpDataPublishInterval = { CONCENTRATE_PUMP_DATA_PUBLISH_INTERVAL, CONCENTRATE_PUMP_DATA_PUBLISH_INTERVAL, 0, 0 }; static F32 pumpTargetSpeed[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Target concentrate pumps' speed (mL/min). static F32 currentPumpSpeed[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Current controlled concentrate pumps' speed (mL/min). static U16 convertedStepSpeedPeriod[ NUM_OF_CONCENTRATE_PUMPS ]; ///< Converted pump speed (mL/min) to step speed period. // ********** private function prototypes ********** static void stopConcentratePump( void ); static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOffState( void ); static void stepConcentratePumpToTargetSpeed( CONCENTRATE_PUMPS_T pumpId ); static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOnState( void ); static U32 getPublishConcentratePumpDataInterval( void ); /*********************************************************************//** * @brief * The initConcentratePump function initializes the ConcentratePumps module. * @details Inputs: none * @details Outputs: ConcentratePumps module initialized * @return none *************************************************************************/ void initConcentratePump( void ) { concentratePumpState = CONCENTRATE_PUMP_OFF_STATE; isPumpOnRequested = FALSE; isPumpOffRequested = FALSE; concentratePumpControlTimerCounter = 0; concentratePumpMonitorTimerCounter = 0; stopConcentratePump(); } /*********************************************************************//** * @brief * The execConcentratePumpMonitor function executes the concentrate pump monitor. * @details Inputs: none * @details Outputs: publish concentrate pump data * @return none *************************************************************************/ void execConcentratePumpMonitor( void ) { if ( ++concentratePumpMonitorTimerCounter >= getPublishConcentratePumpDataInterval() ) { CONCENTRATE_PUMP_DATA_T data; concentratePumpMonitorTimerCounter = 0U; F32 const cp1PulseWidthInSecond = (F32)( getFPGACP1HallSensePulseWidth() * CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION ) / US_PER_SECOND; F32 const cp2PulseWidthInSecond = (F32)( getFPGACP2HallSensePulseWidth() * CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION ) / US_PER_SECOND; F32 const cp1SpeedMlPerMin = ( 1 / cp1PulseWidthInSecond ) * CONCENTRATE_PUMP_VOLUME_PER_PULSE * SEC_PER_MIN; F32 const cp2SpeedMlPerMin = ( 1 / cp2PulseWidthInSecond ) * CONCENTRATE_PUMP_VOLUME_PER_PULSE * SEC_PER_MIN; data.cp1TargetSpeed = pumpTargetSpeed[ CONCENTRATEPUMPS_CP1 ]; data.cp1MeasuredSpeed = cp1SpeedMlPerMin; data.cp2TargetSpeed = pumpTargetSpeed[ CONCENTRATEPUMPS_CP2 ]; data.cp2MeasuredSpeed = cp2SpeedMlPerMin; broadcastConcentratePumpData( &data ); } } /*********************************************************************//** * @brief * The execConcentratePumpController function executes the concentrate pump controller. * @details Inputs: concentratePumpState * @details Outputs: concentratePumpState * @return none *************************************************************************/ void execConcentratePumpController( void ) { switch ( concentratePumpState ) { case CONCENTRATE_PUMP_OFF_STATE: concentratePumpState = handleConcentratePumpOffState(); break; case CONCENTRATE_PUMP_ON_STATE: concentratePumpState = handleConcentratePumpOnState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_EXEC_INVALID_STATE, concentratePumpState ) concentratePumpState = CONCENTRATE_PUMP_OFF_STATE; break; } } /*********************************************************************//** * @brief * The requestConcentratePumpsOn function requests the module to turn on * the concentrate pumps. * @details Inputs: none * @details Outputs: set flag isPumpOnRequested to TRUE * @return none *************************************************************************/ void requestConcentratePumpsOn( void ) { isPumpOnRequested = TRUE; } /*********************************************************************//** * @brief * The requestConcentratePumpsOff function requests the module to turn off * the concentrate pumps. * @details Inputs: none * @details Outputs: set flag isPumpOffRequested to TRUE * @return none *************************************************************************/ void requestConcentratePumpsOff( void ) { isPumpOffRequested = TRUE; pumpTargetSpeed[ CONCENTRATEPUMPS_CP1 ] = 0.0; pumpTargetSpeed[ CONCENTRATEPUMPS_CP2 ] = 0.0; } /*********************************************************************//** * @brief * The setConcentratePumpTargetSpeed function sets the target step speed based on * given speed in mL/min to specified concentrate pump. * @details Inputs: none * @details Outputs: set target step speed for given pump * @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 ) { if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { if ( ( CONCENTRATE_PUMP_MIN_SPEED <= targetSpeed_ml_min ) && ( targetSpeed_ml_min <= CONCENTRATE_PUMP_MAX_SPEED ) ) { pumpTargetSpeed[ pumpId ] = targetSpeed_ml_min; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_SPEED_OUT_OF_RANGE, targetSpeed_ml_min ) } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); } } /*********************************************************************//** * @brief * The stopConcentratePump function sets the concentrate pump step speed to zero * and turns off concentrate pumps. * @details Inputs: none * @details Outputs: targetPumpSpeed[], currentPumpSpeed[], turn concentrate pumps off * @return none *************************************************************************/ static void stopConcentratePump( void ) { U32 ii; for ( ii = 0; ii < NUM_OF_CONCENTRATE_PUMPS; ii++ ) { pumpTargetSpeed[ ii ] = 0.0; currentPumpSpeed[ ii ] = 0.0; } setFPGACP1Control( CONCENTRATE_PUMP_OFF_CONTROL ); setFPGACP2Control( CONCENTRATE_PUMP_OFF_CONTROL ); setFPGACP1SetStepSpeed( currentPumpSpeed[ CONCENTRATEPUMPS_CP1 ] ); setFPGACP2SetStepSpeed( currentPumpSpeed[ CONCENTRATEPUMPS_CP2 ] ); } /*********************************************************************//** * @brief * The handleConcentratePumpOffState function turns on concentrate pumps and * switch to on state upon request. * @details Inputs: none * @details Outputs: concentrate pumps turn on * @return state *************************************************************************/ static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOffState( void ) { CONCENTRATE_PUMP_STATE_T state = CONCENTRATE_PUMP_OFF_STATE; if ( isPumpOnRequested ) { setFPGACP1Control( CONCENTRATE_PUMP_ON_CONTROL ); setFPGACP2Control( CONCENTRATE_PUMP_ON_CONTROL ); state = CONCENTRATE_PUMP_ON_STATE; isPumpOnRequested = FALSE; } return state; } /*********************************************************************//** * @brief * The stepConcentratePumpToTargetSpeed function steps current step speed * toward target speed with predefined step increase. * @details Inputs: none * @details Outputs: currentPumpSpeed[] * @param pumpId concentrate pump id to increase current step speed * @return none *************************************************************************/ static void stepConcentratePumpToTargetSpeed( CONCENTRATE_PUMPS_T pumpId ) { F32 const currentToTargetDiff = fabs( pumpTargetSpeed[ pumpId ] - currentPumpSpeed[ pumpId ] ); F32 speedIncrease; if ( currentToTargetDiff > NEARLY_ZERO ) { if ( currentToTargetDiff > CONCENTRATE_PUMP_SPEED_INCREMENT ) { speedIncrease = CONCENTRATE_PUMP_SPEED_INCREMENT; } else { speedIncrease = currentToTargetDiff; } // Subtract current speed when target speed is smaller if ( pumpTargetSpeed[ pumpId ] < currentPumpSpeed[ pumpId ] ) { speedIncrease *= -1.0; } currentPumpSpeed[ pumpId ] += speedIncrease; } F32 const timePerStep = CONCENTRATE_PUMP_VOLUME_PER_REV / ( currentPumpSpeed[ pumpId ] * CONCENTRATE_PUMP_STEP_PER_REV ) ; F32 const stepPeriod = timePerStep / ( CONCENTRATE_PUMP_STEP_PERIOD_RESOLUTION * CONCENTRATE_PUMP_MICRO_STEPS_PER_STEP ); convertedStepSpeedPeriod[ pumpId ] = (U16)( stepPeriod + 0.5 ); } /*********************************************************************//** * @brief * The handleConcentratePumpOnState function turns off concentrate pumps switch * to off state upon request. While in on state, the function controls concentrate * pumps to a target step speed. * @details Inputs: currentPumpSpeed[] * @details Outputs: control concentrate pumps to target step speed * @return state *************************************************************************/ static CONCENTRATE_PUMP_STATE_T handleConcentratePumpOnState( void ) { CONCENTRATE_PUMP_STATE_T state = CONCENTRATE_PUMP_ON_STATE; if ( ++concentratePumpControlTimerCounter >= CONCENTRATE_PUMP_CONTROL_INTERVAL ) { concentratePumpControlTimerCounter = 0; stepConcentratePumpToTargetSpeed( CONCENTRATEPUMPS_CP1 ); stepConcentratePumpToTargetSpeed( CONCENTRATEPUMPS_CP2 ); setFPGACP1SetStepSpeed( convertedStepSpeedPeriod[ CONCENTRATEPUMPS_CP1 ] ); setFPGACP2SetStepSpeed( convertedStepSpeedPeriod[ CONCENTRATEPUMPS_CP2 ] ); } if ( isPumpOffRequested ) { state = CONCENTRATE_PUMP_OFF_STATE; isPumpOffRequested = FALSE; stopConcentratePump(); } return state; } /*********************************************************************//** * @brief * The getConcentratePumpTargetSpeed function gets the concentrate pump * target speed for a given pump id. * @details Inputs: pumpTargetSpeed * @details Outputs: none * @param pumpId concentrate pump id to increase current step speed * @return the current concentrate pump target speed. *************************************************************************/ //static F32 getConcentratePumpTargetSpeed( CONCENTRATE_PUMPS_T pumpId ) //{ // F32 result = 0.0; // // if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) // { // if ( OVERRIDE_KEY == pumpTargetSpeed[ pumpId ].override ) // { // result = pumpTargetSpeed[ pumpId ].ovData; // } // else // { // result = pumpTargetSpeed[ pumpId ].data; // } // } // else // { // activateAlarmNoData( ALARM_ID_DG_SOFTWARE_FAULT ); // } // // return result; //} /*********************************************************************//** * @brief * The getPublishConcentratePumpDataInterval function gets the concentrate pump * data publication interval. * @details Inputs: concentratePumpDataPublishInterval * @details Outputs: none * @return the current concentrate pump data publication interval (in ms). *************************************************************************/ static U32 getPublishConcentratePumpDataInterval( void ) { U32 result = concentratePumpDataPublishInterval.data; if ( OVERRIDE_KEY == concentratePumpDataPublishInterval.override ) { result = concentratePumpDataPublishInterval.ovData; } return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetConcentratePumpDataPublishIntervalOverride function overrides the * concentrate pump data publish interval. * @details Inputs: none * @details Outputs: concentratePumpDataPublishInterval * @param value override concentrate pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetConcentratePumpDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_GENERAL_INTERVAL; result = TRUE; concentratePumpDataPublishInterval.ovData = intvl; concentratePumpDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetConcentratePumpDataPublishIntervalOverride function resets the * override of the concentrate pump data publish interval. * @details Inputs: none * @details Outputs: concentratePumpDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetConcentratePumpDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; concentratePumpDataPublishInterval.override = OVERRIDE_RESET; concentratePumpDataPublishInterval.ovData = concentratePumpDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetConcentratePumpTargetSpeedOverride function overrides the target * speed value of given concentrate pump id. * @details Inputs: none * @details Outputs: targetPumpSpeed[] * @param pumpId concentrate pump id * @param value override concentrate pump target speed * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetConcentratePumpTargetSpeedOverride( U32 pumpId, F32 value ) { BOOL result = FALSE; if ( pumpId < NUM_OF_CONCENTRATE_PUMPS && isTestingActivated() ) { if ( ( CONCENTRATE_PUMP_MIN_SPEED <= value ) && ( value <= CONCENTRATE_PUMP_MAX_SPEED ) ) { result = TRUE; setConcentratePumpTargetSpeed( (CONCENTRATE_PUMPS_T)pumpId, value ); } } return result; } /**@}*/