Index: firmware/App/Controllers/SubstitutionPump.c =================================================================== diff -u --- firmware/App/Controllers/SubstitutionPump.c (revision 0) +++ firmware/App/Controllers/SubstitutionPump.c (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -0,0 +1,554 @@ +/************************************************************************** +* +* Copyright (c) 2024-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 SubstitutionPumps.c +* +* @author (last) Jashwant Gantyada +* @date (last) 02-Apr-2026 +* +* @author (original) Vinayakam Mani +* @date (original) 19-Sep-2024 +* +***************************************************************************/ +#include "SubstitutionPump.h" +#include "FpgaDD.h" +#include "MessageSupport.h" +#include "Messaging.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" +#include "TaskGeneral.h" +#include "Utilities.h" + +/** + * @addtogroup SubstitutionPumps + * @{ + */ + +// ********** private definitions ********** +#define SUBSTITUTION_PUMP_DATA_PUBLISH_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the Substitution pump is monitored. +#define SUBSTITUTION_PUMP_CONTROL_INTERVAL ( 100 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the Substitution pump is controlled. +#define SUBSTITUTION_PUMP_DATA_PUBLISH_COUNTER_START_COUNT 6 ///< Data publish counter start count. + +#define SUBSTITUTION_PUMP_VOLUME_PER_REV 1.25F ///< Volume output every revolution (mL). +#define SUBSTITUTION_PUMP_ZERO_REVOLUTION_COUNT 0 ///< Revolution count reached to Zero. +#define SUBSTITUTION_PUMP_ZERO_FLOW_RATE 0xFFFFFFFF ///< Pulse width value when zero flow rate or pump is off +#define SUBSTITUTION_PUMP_STEP_PER_REV 200.0F ///< Number of steps for every revolution. +#define SUBSTITUTION_PUMP_MICRO_STEPS_PER_STEP 64.0F ///< Number of micro-steps ( fractions of step) per step. +#define SUBSTITUTION_PUMP_VOLUME_TO_REVOLUTION ( ( 1.0F / SUBSTITUTION_PUMP_VOLUME_PER_REV ) * \ + ( SUBSTITUTION_PUMP_STEP_PER_REV * \ + SUBSTITUTION_PUMP_MICRO_STEPS_PER_STEP ) ) ///< Convert volume in to number of revolutions needed. +#define SUBSTITUTION_PUMP_STEP_PERIOD_RESOLUTION ( 0.50F / ( US_PER_SECOND * SEC_PER_MIN ) ) ///< Convert step period resolution (0.50 us) to minute. + +#define SUBSTITUTION_PUMP_FORWARD_DIR 0x1 ///< Concentrate pump forward direction configuration. +#define SUBSTITUTION_PUMP_REVERSE_DIR 0x0 ///< Concentrate pump reverse direction configuration. +#define SUBSTITUTION_PUMP_CONTROL_EIGHTH_STEP 0x04 ///< Substitution pump control 1/8th step. +#define SUBSTITUTION_PUMP_CONTROL_REVERSE_DIR 0x00 ///< Substitution pump control reverse direction. +#define SUBSTITUTION_PUMP_CONTROL_FORWARD_DIR 0x08 ///< Substitution pump control forward direction. +#define SUBSTITUTION_PUMP_CONTROL_ENABLE 0x00 ///< Substitution pump control enable pump. +#define SUBSTITUTION_PUMP_CONTROL_DISABLE 0x10 ///< Substitution pump control disable pump. +#define SUBSTITUTION_PUMP_CONTROL_NOT_RESET 0x20 ///< Substitution pump control not reset. +#define SUBSTITUTION_PUMP_CONTROL_SLEEP_OFF 0x40 ///< Substitution pump control sleep off. + +#define SUBSTITUTION_PUMP_TRANS_TO_RAMP_SPEED_THRESHOLD_MLPM 10.0F ///< Substitution pump transition to ramp to target speed threshold in mL/min. +#define SUBSTITUTION_PUMP_RAMP_SPEED_INCREMENT 5.0F ///< Speed increase (mL/min) when controlling Substitution pump to target step speed. + + +static const U32 SUBSTITUTION_PUMP_CONTROL_FORWARD = SUBSTITUTION_PUMP_CONTROL_SLEEP_OFF | + SUBSTITUTION_PUMP_CONTROL_NOT_RESET | + SUBSTITUTION_PUMP_CONTROL_ENABLE | + SUBSTITUTION_PUMP_CONTROL_FORWARD_DIR | + SUBSTITUTION_PUMP_CONTROL_EIGHTH_STEP; + +static const U32 SUBSTITUTION_PUMP_CONTROL_STOP = SUBSTITUTION_PUMP_CONTROL_SLEEP_OFF | + SUBSTITUTION_PUMP_CONTROL_NOT_RESET | + SUBSTITUTION_PUMP_CONTROL_DISABLE | + SUBSTITUTION_PUMP_CONTROL_FORWARD_DIR | + SUBSTITUTION_PUMP_CONTROL_EIGHTH_STEP; + + +/// Enumeration of Substitution pump states. +typedef enum SubstituionPumpState +{ + SUBSTITUTION_PUMP_OFF_STATE = 0, ///< Substitution pump off state. + SUBSTITUTION_PUMP_RAMP_TO_TARGET_SPEED_STATE, ///< Substitution pump ramp to target state. + SUBSTITUTION_PUMP_CONTROL_TARGET_SPEED_STATE, ///< Substitution pump on state. + NUM_OF_SUBSTITUTION_PUMP_STATES ///< Number of Substitution pump states. +} SUBSTITUTION_PUMP_STATE_T; + +/// Substitution pump data structure +typedef struct +{ + U32 controlTimerCounter; ///< Timer counter to perform control on Substitution pump. + SUBSTITUTION_PUMP_STATE_T execState; ///< Concentrate pump execute current state. + BOOL hasTurnOnPumpsBeenRequested; ///< Flag indicates a request to turn Substitution pumps on. + F32 currentPumpSpeed; ///< Current controlled Substitution pumps' speed (mL/min). + U32 togglePeriodCount; ///< Converted pump speed (mL/min) to toggle period counts (0.5 uS increment counts per step). + U08 direction; ///< Substitution pump motor direction. + U08 controlSet; ///< Substitution pump control set. (Used in DVT). +} SUBSTITUTION_PUMP_T; + +/// Payload record structure for Substitution pump start/stop request +typedef struct +{ + U32 pumpID; ///< Substitution pump ID + U32 startStop; ///< Substitution pump start:1,stop :0. + F32 speed; ///< Speed in ml/min + F32 volume; ///< Target volume in ml +} SUB_PUMP_START_STOP_CMD_PAYLOAD_T; + +// ********** private data ********** + +static OVERRIDE_U32_T substitutionPumpDataPublishInterval; ///< Substitution pump data publish interval. +static SUBSTITUTION_PUMP_T substitutionPumps[ NUM_OF_SUB_PUMPS ]; ///< Array of Substitution pumps' data structure. +static OVERRIDE_F32_T pumpTargetSpeed[ NUM_OF_SUB_PUMPS ]; ///< Target concentrate pumps' speed (mL/min). + + +// ********** private function prototypes ********** + +static void stopSubstitutionPump( SUBSTITUTION_PUMPS_T pumpId ); +static SUBSTITUTION_PUMP_STATE_T handleSubstitutionPumpOffState( SUBSTITUTION_PUMPS_T pumpId ); +static SUBSTITUTION_PUMP_STATE_T handleSubstitutionPumpControlTargetSpeedState( SUBSTITUTION_PUMPS_T pumpId ); +static BOOL stepSubstitutionPumpToTargetSpeed( SUBSTITUTION_PUMPS_T pumpId ); +static void checkSubstitutionPumpControlSet( SUBSTITUTION_PUMPS_T pumpId ); +static void publishSubstitutionPumpData( void ); + +/*********************************************************************//** + * @brief + * The initSubstitutionPump function initializes the SubstitutionPumps unit. + * @details \b Inputs: none + * @details \b Outputs: SubstitutionPumps unit variables initialized + * @return none + *************************************************************************/ +void initSubstitutionPump( void ) +{ + SUBSTITUTION_PUMPS_T pumpId; + + for ( pumpId = SUBPUMPS_FIRST; pumpId < NUM_OF_SUB_PUMPS; pumpId++ ) + { + substitutionPumps[ pumpId ].controlTimerCounter = 0; + substitutionPumps[ pumpId ].execState = SUBSTITUTION_PUMP_OFF_STATE; + substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; + substitutionPumps[ pumpId ].direction = SUBSTITUTION_PUMP_FORWARD_DIR; + substitutionPumps[ pumpId ].controlSet = SUBSTITUTION_PUMP_CONTROL_FORWARD_DIR; + } + setFPGAD92PumpRevolutionCount( SUBSTITUTION_PUMP_ZERO_FLOW_RATE ); + setFPGAD92PumpControl( SUBSTITUTION_PUMP_CONTROL_STOP ); + + substitutionPumpDataPublishInterval.data = SUBSTITUTION_PUMP_DATA_PUBLISH_INTERVAL; + substitutionPumpDataPublishInterval.ovInitData = SUBSTITUTION_PUMP_DATA_PUBLISH_INTERVAL; + substitutionPumpDataPublishInterval.ovData = 0; + substitutionPumpDataPublishInterval.override = OVERRIDE_RESET; +} + +/*********************************************************************//** + * @brief + * The execSubstitutionPumpController function executes the substitution 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 execSubstitutionPumpController( void ) +{ + SUBSTITUTION_PUMPS_T pumpId; + + for ( pumpId = SUBPUMPS_FIRST; pumpId < NUM_OF_SUB_PUMPS; pumpId++ ) + { + switch ( substitutionPumps[ pumpId ].execState ) + { + case SUBSTITUTION_PUMP_OFF_STATE: + substitutionPumps[ pumpId ].execState = handleSubstitutionPumpOffState( pumpId ); + break; + + case SUBSTITUTION_PUMP_CONTROL_TARGET_SPEED_STATE: + substitutionPumps[ pumpId ].execState = handleSubstitutionPumpControlTargetSpeedState( pumpId ); + break; + + // 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 ) + substitutionPumps[ pumpId ].execState = SUBSTITUTION_PUMP_OFF_STATE; + break; + } + } +} + +/*********************************************************************//** + * @brief + * The handleSubstitutionPumpOffState function turns on a given substitution + * pumps and switch to on state upon request. + * @details \b Inputs: none + * @details \b Outputs: pump turned on + * @param pumpId ID of the substitution pump + * @return state + *************************************************************************/ +static SUBSTITUTION_PUMP_STATE_T handleSubstitutionPumpOffState( SUBSTITUTION_PUMPS_T pumpId ) +{ + SUBSTITUTION_PUMP_STATE_T state = SUBSTITUTION_PUMP_OFF_STATE; + + + if ( TRUE == substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested ) + { + U08 controlSet = substitutionPumps[ pumpId ].controlSet; + + setFPGAD92PumpRevolutionCount( SUBSTITUTION_PUMP_ZERO_FLOW_RATE ); + setFPGAD92PumpControl( controlSet ); + state = SUBSTITUTION_PUMP_CONTROL_TARGET_SPEED_STATE; + } + else + { + setFPGAD92PumpRevolutionCount( SUBSTITUTION_PUMP_ZERO_FLOW_RATE ); + setFPGAD92PumpControl( SUBSTITUTION_PUMP_CONTROL_STOP ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleSubstitutionPumpControlTargetSpeedState function turns off given + * substitution pumps switch to off state upon request. While in on state, + * the function controls substitution pumps to a target step speed. + * @details \b Inputs: currentPumpSpeed[] + * @details \b Outputs: control given substitution pumps to target step speed + * @param pumpId ID of the substitution pump + * @return state + *************************************************************************/ +static SUBSTITUTION_PUMP_STATE_T handleSubstitutionPumpControlTargetSpeedState( SUBSTITUTION_PUMPS_T pumpId ) +{ + SUBSTITUTION_PUMP_STATE_T state = SUBSTITUTION_PUMP_CONTROL_TARGET_SPEED_STATE; + F32 targetToCurreSpeedDiffMLPM = fabs( getSubstitutionPumpTargetSpeed( pumpId ) - substitutionPumps[ pumpId ].currentPumpSpeed ); + + if ( ++substitutionPumps[ pumpId ].controlTimerCounter >= SUBSTITUTION_PUMP_CONTROL_INTERVAL ) + { + substitutionPumps[ pumpId ].controlTimerCounter = 0; + stepSubstitutionPumpToTargetSpeed( pumpId ); + } + + if ( targetToCurreSpeedDiffMLPM >= SUBSTITUTION_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 + stepSubstitutionPumpToTargetSpeed( pumpId ); + state = SUBSTITUTION_PUMP_RAMP_TO_TARGET_SPEED_STATE; + } + + //Stop the pump if measured rev count reaches zero + if ( FALSE == substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested ) + { + state = SUBSTITUTION_PUMP_OFF_STATE; + stopSubstitutionPump( pumpId ); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The stopSubstitutionPump function sets the given substitution pump step speed + * to zero and turns off substitution pump. Also parks the pump if requested. + * @details \b Inputs: none + * @details \b Outputs: substitutionPumps + * @param pumpId ID of the substitution pump + * @return none + *************************************************************************/ +static void stopSubstitutionPump( SUBSTITUTION_PUMPS_T pumpId ) +{ + substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; // Just to make sure pump is in Off state. + substitutionPumps[ pumpId ].currentPumpSpeed = 0.0F; // set target rate to zero + + // Disable the motor when stopping, to take next revolution count + // Send zero rate command to stop the pump + setFPGAD92PumpControl( SUBSTITUTION_PUMP_CONTROL_STOP ); + setFPGAD92PumpSetStepSpeed( SUBSTITUTION_PUMP_ZERO_FLOW_RATE ); +} + +/*********************************************************************//** + * @brief + * The stepSubstitutionPumpToTargetSpeed 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 stepSubstitutionPumpToTargetSpeed( SUBSTITUTION_PUMPS_T pumpId ) +{ + F32 speedIncrease; + BOOL hasTgtBeenReached = FALSE; + F32 currentToTargetDiff = fabs( getSubstitutionPumpTargetSpeed( pumpId ) - substitutionPumps[ pumpId ].currentPumpSpeed ); + + if ( currentToTargetDiff > NEARLY_ZERO ) + { + if ( currentToTargetDiff > SUBSTITUTION_PUMP_RAMP_SPEED_INCREMENT ) + { + speedIncrease = SUBSTITUTION_PUMP_RAMP_SPEED_INCREMENT; + } + else + { + speedIncrease = currentToTargetDiff; + hasTgtBeenReached = TRUE; + } + + // Subtract current speed when target speed is smaller + if ( getSubstitutionPumpTargetSpeed( pumpId ) < substitutionPumps[ pumpId ].currentPumpSpeed ) + { + speedIncrease *= -1.0F; + } + + substitutionPumps[ pumpId ].currentPumpSpeed += speedIncrease; + + // If the pump's target speed is set to be 0, do not ramp down set it to zero immediately + if ( getSubstitutionPumpTargetSpeed( pumpId ) < NEARLY_ZERO ) + { + substitutionPumps[ pumpId ].currentPumpSpeed = 0.0F; + } + } + + if ( substitutionPumps[ pumpId ].currentPumpSpeed > NEARLY_ZERO ) + { + F32 timePerStep; + F32 stepPeriodCounts; + + timePerStep = SUBSTITUTION_PUMP_VOLUME_PER_REV / ( substitutionPumps[ pumpId ].currentPumpSpeed * SUBSTITUTION_PUMP_STEP_PER_REV ); + stepPeriodCounts = timePerStep / ( SUBSTITUTION_PUMP_STEP_PERIOD_RESOLUTION * SUBSTITUTION_PUMP_MICRO_STEPS_PER_STEP ); + substitutionPumps[ pumpId ].togglePeriodCount = (U32)( stepPeriodCounts + FLOAT_TO_INT_ROUNDUP_OFFSET ); + } + else + { + substitutionPumps[ pumpId ].togglePeriodCount = SUBSTITUTION_PUMP_ZERO_FLOW_RATE; + } + + // Check if the control set bit is set as desired and if not, correct it + checkSubstitutionPumpControlSet( pumpId ); + setFPGAD92PumpSetStepSpeed( substitutionPumps[ pumpId ].togglePeriodCount ); + + return hasTgtBeenReached; +} + +/*********************************************************************//** + * @brief + * The checkSubstitutionPumpControlSet function monitors the status of the + * given substitution pumps control set bit and if they are different from the + * required set bit, they are set again. + * @details \b Inputs: substitutionPumps + * @details \b Outputs: none + * @param pumpId pump id to check its control set bit + * @return none + *************************************************************************/ +static void checkSubstitutionPumpControlSet( SUBSTITUTION_PUMPS_T pumpId ) +{ + U08 controlSetBits = getFPGAD92PumpControlStatus(); + + if ( controlSetBits != substitutionPumps[ pumpId ].controlSet ) + { + setFPGAD92PumpControl( substitutionPumps[ pumpId ].controlSet ); + } +} + +/*********************************************************************//** + * @brief + * The getSubstitutionPumpTargetSpeed function gets the current target speed for the given + * substituion 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 substitution pump id to get the current target speed + * @return the current target speed for the given concentrate pump. + *************************************************************************/ +F32 getSubstitutionPumpTargetSpeed( SUBSTITUTION_PUMPS_T pumpId ) +{ + F32 speed = 0.0F; + + if ( pumpId < NUM_OF_SUB_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 requestSubstitutionPumpOn function requests the module to turn on + * the concentrate pumps. + * @details \b Inputs: none + * @details \b Outputs: concentratePumps[],acidConcentratePumpParkPersistenceClear, + * bicarbConcentratePumpParkPersistenceClear, ufPumpParkPersistenceClear + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. + * @param pumpId concentrate pump id + * @return none + *************************************************************************/ +void requestSubstitutionPumpOn( SUBSTITUTION_PUMPS_T pumpId ) +{ + if ( pumpId < NUM_OF_SUB_PUMPS ) + { + substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested = TRUE; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); + } +} + +/*********************************************************************//** + * @brief + * The requestSubstitutionPumpOff 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 requestSubstitutionPumpOff( SUBSTITUTION_PUMPS_T pumpId ) +{ + if ( pumpId < NUM_OF_SUB_PUMPS ) + { + substitutionPumps[ pumpId ].hasTurnOnPumpsBeenRequested = FALSE; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); + } +} + +/*********************************************************************//** + * @brief + * The setSubstitutionPumpTargetSpeed 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 + * @param targetVolume_ml dosing volume to be delivered in ml. + * @return none + *************************************************************************/ +void setSubstitutionPumpTargetSpeed( SUBSTITUTION_PUMPS_T pumpId, F32 targetSpeed_ml_min, F32 Vol ) +{ + if ( pumpId < NUM_OF_SUB_PUMPS ) + { + if ( targetSpeed_ml_min >= 0.0 ) + { + substitutionPumps[ pumpId ].direction = SUBSTITUTION_PUMP_FORWARD_DIR; + substitutionPumps[ pumpId ].controlSet = SUBSTITUTION_PUMP_CONTROL_FORWARD; + } + else + { + substitutionPumps[ pumpId ].direction = SUBSTITUTION_PUMP_REVERSE_DIR; + substitutionPumps[ pumpId ].controlSet = SUBSTITUTION_PUMP_CONTROL_FORWARD; + targetSpeed_ml_min *= -1.0; + } + + /* + * If 0.0 <= speed <= 200 set it + * If speed < 0.0 set to 0 + * else speed > 200 set to 200 + */ + pumpTargetSpeed[ pumpId ].data = targetSpeed_ml_min; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, pumpId ); + } +} + + +/************************************************************************* + * 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 testSubstitutionPumpDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &substitutionPumpDataPublishInterval, 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 testSubstituionPumpTargetSpeedOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &pumpTargetSpeed[ 0 ], NUM_OF_SUB_PUMPS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testSubstitutionPumpStartStopOverride function starts a given substituion pump + * at mentioned speed/flowrate ( ml/min) or stops the substituion pump. + * @details \b Inputs: tester logged in + * @details \b Outputs: substituionPumps[] + * @param message set message from Dialin which includes the substituion pump to set + * and the state to set the substituion pump to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testSubstitutionPumpStartStopOverride( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with DD + if ( TRUE == isTestingActivated() ) + { + // Verify payload length is valid + if ( sizeof( SUB_PUMP_START_STOP_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) + { + SUB_PUMP_START_STOP_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(SUB_PUMP_START_STOP_CMD_PAYLOAD_T) ); + + if ( (SUBSTITUTION_PUMPS_T)payload.pumpID < NUM_OF_SUB_PUMPS ) + { + // Handle start command + if ( ( TRUE == payload.startStop ) && ( payload.volume > 0.0 ) ) + { + setSubstitutionPumpTargetSpeed( (SUBSTITUTION_PUMPS_T)payload.pumpID, payload.speed, payload.volume ); + requestSubstitutionPumpOn ( (SUBSTITUTION_PUMPS_T)payload.pumpID ); + result = TRUE; + } + + //Handle stop command + if ( FALSE == payload.startStop ) + { + requestSubstitutionPumpOff( (SUBSTITUTION_PUMPS_T)payload.pumpID ); + result = TRUE; + } + } + } + } + + return result; +} + +/**@}*/ Index: firmware/App/Controllers/SubstitutionPump.h =================================================================== diff -u --- firmware/App/Controllers/SubstitutionPump.h (revision 0) +++ firmware/App/Controllers/SubstitutionPump.h (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -0,0 +1,73 @@ +/************************************************************************** +* +* Copyright (c) 2024-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 SubstitutionPump.h +* +* @author (last) Sameer Kalliadan Poyil +* @date (last) 15-Apr-2026 +* +* @author (original) Vinayakam Mani +* @date (original) 19-Sep-2024 +* +***************************************************************************/ + +#ifndef __SUBSTITUTION_PUMPS_H__ +#define __SUBSTITUTION_PUMPS_H__ + +#include "DDCommon.h" +//#include "NVDataMgmt.h" + +/** + * @defgroup SubstitutionPumps SubstitutionPumps + * @brief Substitution pumps monitor and control unit. Monitors and control Substitution pump with an closed loop approach. + * + * @addtogroup SubstitutionPumps + * @{ + */ + +// ********** public definitions ********** + +#define SUB_PUMP_CONT_VOLUME 0xFFFFFFFF ///< Volume set to 0xFFFFFFFF enables continuous delivery based on the speed set. + +#define PARK_CONC_PUMPS TRUE ///< For park parameter to requestConcentratePumpOff(). +#define NO_PARK_CONC_PUMPS FALSE ///< For park parameter to requestConcentratePumpOff(). + +/// Enumeration of substitution pumps. +typedef enum SubstitutionPumps +{ + D92_PUMP = 0, ///< HDF pump + SUBPUMPS_FIRST = D92_PUMP, ///< First substitution pump in list + NUM_OF_SUB_PUMPS ///< Number of substitution pumps +} SUBSTITUTION_PUMPS_T; + +/// Substitution pump data struct. +typedef struct +{ + F32 d92_PumpTargetSpeed; ///< substitution pump D92_Pump target speed + F32 d92_PumpCurrentSetSpeed; ///< substitution pump D92_Pump current set speed + U32 d92_PumpTargetRevCount; ///< substitution pump D92_Pump target revolution count + U32 d92_PumpState; ///< substitution pump D92_Pump current state +} SUBSTITUTION_PUMP_DATA_T; + +// ********** public function prototypes ********** + +void initSubstitutionPump( void ); +void execSubstitutionPumpMonitor( void ); +void execSubstitutionPumpController( void ); + +void requestSubstitutionPumpOn( SUBSTITUTION_PUMPS_T pumpId ); +void requestSubstitutionPumpOff( SUBSTITUTION_PUMPS_T pumpId ); +F32 getSubstitutionPumpTargetSpeed( SUBSTITUTION_PUMPS_T pumpId ); + +BOOL testSubstitutionPumpDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testSubstitutionPumpTargetSpeedOverride( MESSAGE_T *message ); + +BOOL testSubstitutionPumpStartStopOverride( MESSAGE_T *message ); // Concentrate pump start/stop request + +/**@}*/ + +#endif Index: firmware/App/Drivers/ConductivitySensors.c =================================================================== diff -u -r336f6c49e05f515ca1250e0fd9ea97e5f5b5f11c -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Drivers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 336f6c49e05f515ca1250e0fd9ea97e5f5b5f11c) +++ firmware/App/Drivers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -52,7 +52,7 @@ #define MAX_CONDUCTIVITY_SENSOR_FAILURES 2 ///< Number of failures before alarming in timed window count. #define MAX_CONDUCTIVITY_SENSOR_FAILURE_WINDOW_MS ( 60 * MS_PER_SECOND ) ///< Set time for timed window count. -#define MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ( 500 / TASK_PRIORITY_INTERVAL ) ///< New reading every 333ms, expect to get valid new reading in 500ms. +#define MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ( 800 / TASK_PRIORITY_INTERVAL ) ///< New reading every 333ms, expect to get valid new reading in 500ms. #define COND_SENSORS_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Conductivity sensors FPGA error timeout in milliseconds. #define COND_SENSORS_READ_ERR_MAX_CNT 255 ///< Conductivity sensors read and error count max value. Index: firmware/App/Monitors/Conductivity.c =================================================================== diff -u -rfd897db8177752330ad08d877e0a13620513dbdc -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Monitors/Conductivity.c (.../Conductivity.c) (revision fd897db8177752330ad08d877e0a13620513dbdc) +++ firmware/App/Monitors/Conductivity.c (.../Conductivity.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -84,10 +84,6 @@ static U32 roRRCount; ///< RO rejection ratio Number of samples in average buffer. static F32 roRRTankFillAvg; ///< Average RO rejection ratio during permeate tank fill state. static U32 roRRSampleIntervalCounter; ///< RO rejection ratio sample collection timer counter. -static U32 condtempDataCollectionTimeInterval; ///< Conductivity Temperature data collection time interval in task counts. -static U32 condtempSampleIntervalCounter; ///< Conductivity Temperature sensor sample collection timer counter. -static U32 condDataCollectionTimeInterval; ///< Conductivity data collection time interval in task counts. -static U32 condSampleIntervalCounter; ///< Conductivity sensor sample collection timer counter. // ********** private function prototypes ********** @@ -126,8 +122,6 @@ roRRAvg.ovInitData = 0.0F; roRRAvg.override = OVERRIDE_RESET; roRRSampleIntervalCounter = 0; - condtempDataCollectionTimeInterval= COND_SENSOR_UPDATE_INTERVAL; - condtempSampleIntervalCounter = 0; memset( &roRRSamples, 0, sizeof( roRRSamples ) ); Index: firmware/App/Services/FpgaDD.c =================================================================== diff -u -rfd897db8177752330ad08d877e0a13620513dbdc -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Services/FpgaDD.c (.../FpgaDD.c) (revision fd897db8177752330ad08d877e0a13620513dbdc) +++ firmware/App/Services/FpgaDD.c (.../FpgaDD.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -615,10 +615,12 @@ U08 fpgaConSensD43Control; ///< Reg 118. Conductivity/Temperature Sensors D43 Control registers U16 fpgaConSensD43_Addrs; ///< Reg 119. D43 Initialization Address register U32 fpgaConSensD43_Data_In; ///< Reg 121. D43 Initialization data register - U08 unusedRegister3; ///< Reg 125. Unused register 3 + U08 fpgaD92PumpControl; ///< Reg 125. D92 HDF Pump Control U32 fpgaD11PumpSpeed; ///< Reg 126. Acid Concentrate Pump Speed/RPM Control U32 fpgaD10PumpSpeed; ///< Reg 130. BiCarb Concentrate Pump Speed/RPM Control U32 fpgaD76PumpSpeed; ///< Reg 134. UF Pump Speed/RPM Control + U32 fpgaD92PumpSpeed; ///< Reg 138. HDF Pump Speed/RPM Control + U32 fpgaD92PumpRevCount; ///< Reg 142. HDF pump revolution count } FPGA_ACTUATORS_T; #pragma pack(pop) @@ -1107,6 +1109,7 @@ SET_FPGA_ACTUATOR_FIELD( fpgaD12PumpSpeed, currentSpeed ); } + /*********************************************************************//** * @brief * The setFPGAD48PumpControl function sets the controls for @@ -1193,6 +1196,23 @@ /*********************************************************************//** * @brief + * The setFPGAD92PumpSetStepSpeed function sets the step speed period for + * HDF D92_Pump. + * @details \b Inputs: none + * @details \b Outputs: fpgaD92PumpSpeed + * @param stepSpeed The HDF pump step speed period + * @return none + *************************************************************************/ +void setFPGAD92PumpSetStepSpeed( U32 stepSpeed ) +{ + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) == TRUE ) + { + fpgaActuatorSetPoints.fpgaD92PumpSpeed = stepSpeed; + } +} + +/*********************************************************************//** + * @brief * The setFPGAD11PumpControl function sets the DVT concentrate pump 1 * (acid pump) control mode. * bit 7: Park (set in different function) @@ -1256,6 +1276,29 @@ /*********************************************************************//** * @brief + * The setFPGAD92PumpControl function sets the UF pump + * (D76 pump) control mode. + * bit 7: Park (set in different function) + * bit 6: nSleep + * bit 5: nReset + * bit 4: nEnable + * bit 3: Direction (1=Fwd, 0=Rev) + * bit 0-2: Microstepping resolution + * @details \b Inputs: none + * @details \b Outputs: fpgaD76PumpControl + * @param control UF pump control set + * @return none + *************************************************************************/ +void setFPGAD92PumpControl( U08 control ) +{ + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) == TRUE ) + { + fpgaActuatorSetPoints.fpgaD92PumpControl &= 0x80; // preserve msb (park command bit) + fpgaActuatorSetPoints.fpgaD92PumpControl |= control; + } +} +/*********************************************************************//** + * @brief * The setFPGAD11PumpParkCmd function sets the DVT concentrate pump 1 * (acid pump) park command bit. * bit 7: Park command bit @@ -1374,6 +1417,22 @@ /*********************************************************************//** * @brief + * The setFPGAD92PumpRevolutionCount function sets the HDF + * pump revolution count. + * @details \b Inputs: none + * @details \b Outputs: fpgaD92PumpRevCount + * @param count the number of revolution to be rotated for the pump. + * @return none + *************************************************************************/ +void setFPGAD92PumpRevolutionCount( U32 count ) +{ + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) == TRUE ) + { + fpgaActuatorSetPoints.fpgaD92PumpRevCount = count; + } +} +/*********************************************************************//** + * @brief * The setFPGAD5HeaterOnOffControl function sets the primary heater * On/Off control. * @details \b Inputs: none @@ -1672,6 +1731,36 @@ /*********************************************************************//** * @brief + * The getFPGAD76PumpControlStatus function gets the Ultrafilteration pump + * (D76 pump) control mode. + * bit 7: Park (set in different function) + * bit 6: nSleep + * bit 5: nReset + * bit 4: nEnable + * bit 3: Direction (1=Fwd, 0=Rev) + * bit 0-2: Microstepping resolution + * @details \b Inputs: none + * @details \b Outputs: fpgaD76PumpControl + * @return UF pump control status bit + *************************************************************************/ +U08 getFPGAD92PumpControlStatus( void ) +{ + U08 result; + + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) == TRUE ) + { + result = fpgaActuatorSetPoints.fpgaD92PumpControl; + } + else + { + result = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief * The getFPGAUFPumpFault function gets UF pumps fault * reported by FGPA. * @details \b Inputs: fpgaD76PumpFault @@ -3932,4 +4021,5 @@ { return fpgaSensorReadings.fpgaP18CalMemCounter; } + /**@}*/ Index: firmware/App/Services/FpgaDD.h =================================================================== diff -u -rb04db69f541f245e543df343257bcbdb73fbbc3d -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Services/FpgaDD.h (.../FpgaDD.h) (revision b04db69f541f245e543df343257bcbdb73fbbc3d) +++ firmware/App/Services/FpgaDD.h (.../FpgaDD.h) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -131,19 +131,23 @@ void setFPGAD11PumpSetStepSpeed( U32 stepSpeed ); void setFPGAD10PumpSetStepSpeed( U32 stepSpeed ); void setFPGAD76PumpSetStepSpeed( U32 stepSpeed ); +void setFPGAD92PumpSetStepSpeed( U32 stepSpeed ); void setFPGAD11PumpControl( U08 control ); void setFPGAD10PumpControl( U08 control ); void setFPGAD76PumpControl( U08 control ); +void setFPGAD92PumpControl( U08 control ); void setFPGAD11PumpParkCmd( void ); void setFPGAD10PumpParkCmd( void ); void setFPGAD76PumpParkCmd( void ); void setFPGAD11PumpRevolutionCount( U32 count ); void setFPGAD10PumpRevolutionCount( U32 count ); void setFPGAD76PumpRevolutionCount( U32 count ); +void setFPGAD92PumpRevolutionCount( U32 count ); U08 getFPGAD11PumpControlStatus( void ); U08 getFPGAD10PumpControlStatus( void ); U08 getFPGAD76PumpControlStatus( void ); +U08 getFPGAD92PumpControlStatus( void ); U08 getFPGAUFPumpFault( void ); BOOL getFPGAD76PumpParkFault( void ); BOOL getFPGAD76PumpIsParked( void ); Index: firmware/App/Services/Messaging.c =================================================================== diff -u -r2d295ca85f19e95da42476a57ca6b4496baf980a -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision 2d295ca85f19e95da42476a57ca6b4496baf980a) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -59,6 +59,7 @@ #include "StateFlushFilterDefeatured.h" #include "StateFlushPermeate.h" #include "StateInletPressureCheck.h" +#include "SubstitutionPump.h" #include "SystemCommDD.h" #include "Temperature.h" #include "TestSupport.h" @@ -289,6 +290,7 @@ { MSG_ID_FP_CONDUCTIVITY_SENSOR_VERSION_REQUEST, &testHandleConductivitySensorVersionRequest }, { MSG_ID_DD_TEMPERATURE_SENSOR_FILTERED_TEMP_OVERRIDE_REQUEST, &testDDTemperatureSensorFilteredReadingsOverride }, { MSG_ID_FP_SET_RECOVERY_VALVES_REQUEST, &testIOFPSetValveRecoveryConfig }, + { MSG_ID_DD_SUBSTITUION_PUMP_START_STOP_OVERRIDE_REQUEST, &testSubstitutionPumpStartStopOverride }, }; /// Calculation for number of entries in the incoming message function handler look-up table. Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r6d0bd19fb192dcd272fa773e8833862cc8a8f750 -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 6d0bd19fb192dcd272fa773e8833862cc8a8f750) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -30,6 +30,7 @@ #include "PermeateTank.h" #include "RinsePump.h" #include "ROPump.h" +#include "SubstitutionPump.h" #include "SystemCommDD.h" #include "TaskGeneral.h" #include "WatchdogMgmt.h" @@ -104,6 +105,9 @@ execDryBicart(); } + // Control Substitution pump + execSubstitutionPumpController(); + // Control RO pump execROPumpController(); Index: firmware/source/sys_main.c =================================================================== diff -u -r89c8709e3b27648926fbb20f25c9a67cbeb99adc -r11fcfaffab49f00f358124c8c285a821632eba24 --- firmware/source/sys_main.c (.../sys_main.c) (revision 89c8709e3b27648926fbb20f25c9a67cbeb99adc) +++ firmware/source/sys_main.c (.../sys_main.c) (revision 11fcfaffab49f00f358124c8c285a821632eba24) @@ -98,6 +98,7 @@ #include "StateFlushFilterDefeatured.h" #include "StateFlushPermeate.h" #include "StateInletPressureCheck.h" +#include "SubstitutionPump.h" #include "SystemCommDD.h" #include "TaskBG.h" #include "TDInterface.h" @@ -208,6 +209,7 @@ initUltrafiltration(); initRinsePump(); initDryBiCart(); + initSubstitutionPump(); // FP Modules