/************************************************************************** * * 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 DialysatePumps.c * * @author (last) Vinayakam Mani * @date (last) 02-Oct-2024 * * @author (original) Vinayakam Mani * @date (original) 02-Oct-2024 * ***************************************************************************/ #include #include "BalancingChamber.h" #include "DialysatePumps.h" #include "FpgaDD.h" #include "MessageSupport.h" #include "Messaging.h" //#include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "PIControllers.h" #include "Pressure.h" #include "SafetyShutdown.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup DialysatePumps * @{ */ // ********** private definitions ********** #define DIALYSATE_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the dialysate pump data is published on the CAN bus. #define DATA_PUBLISH_COUNTER_START_COUNT 60 ///< Data publish counter start count. #define DP_CONTROL_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the dialysate pump is controlled. #define DIALYSATE_PUMP_CONTROL_RUN 0x01 ///< Dialysate pump control run pump. #define DIALYSATE_PUMP_CONTROL_STOP 0x00 ///< Dialysate pump control stop pump. #define DIALYSATE_PUMP_FORWARD_DIR 1 ///< Dialysate pump forward direction. reverse direction is not allowed. #define DIALYSATE_PUMP_RAMP_SPEED_INCREMENT 10.0F ///< Speed increase when controlling dialysate pump ramp to target step speed. #define ZERO_SPEED 0.0F ///< Zero speed/RPM value. #define DIALYSATE_PUMP_MAX_CURRENT_WHEN_OFF_A 0.1F ///< Dialysate pump maximum current when the pump is off in amps. #define DIALYSATE_PUMP_MAX_CURRENT_A 2.2F ///< Dialysate pump maximum current in amps. #define DIALYSATE_PUMP_CURRENT_OUT_OF_RANGE_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Dialysate pump current out of range timeout in milliseconds. #define DIALYSATE_PUMP_DIR_OF_RANGE_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Dialysate pump direction out of range timeout in milliseconds. #define DIALYSATE_PUMP_DIR_BIT_MASK 0x80 ///< Dialysate pump direction bit clear mask. #define DIALYSATE_PUMP_DIR_ERROR_CNT_BIT_MASK 0x3F ///< Dialysate pump direction error count bit mask. #define DIALYSATE_PUMP_MIN_RPM_FOR_DIR_CHECK 100 ///< Dialysate pump minimum RPM for direction check. #define MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_WINDOW_MS ( 1 * SEC_PER_MIN * MS_PER_SECOND ) ///< FPGA dialysate pump direction fault window #define MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_FAILURES 10 ///< FPGA dialysate pump direction fault failures per MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_WINDOW_MS #define FRESH_DIALYSATE_TARGET_PRESSURE_PSI 25.0F ///< Fresh dialysate pump recommended pressure(D18) in psi. #define FRESH_DIALYSATE_MAX_PRESSURE_PSI 26.0F ///< Fresh dialysate pump maximum allowed (D18) pressure in psi. #define SPENT_DIALYSATE_TARGET_PRESSURE_PSI 29.0F ///< Spent dialysate pump recommended pressure(PDs) in psi. #define SPENT_DIALYSATE_MAX_PRESSURE_PSI 30.0F ///< Spent dialysate pump maximum allowed (PDs) pressure in psi. #define FRESH_DIAL_OPEN_LOOP_SPEED_RPM 2000.0F ///< fresh dialysate pump open loop speed to meet target pressure. #define SPENT_DIAL_OPEN_LOOP_SPEED_RPM 2500.0F ///< spent dialysate pump open loop speed to meet target pressure. #define DIALYSATE_PUMP_SPEED_ZERO_RPM 0 ///< Dialysate pump zero RPM speed. #define SPEED_COUNT_ZERO 0 ///< Measured speed count zero check. #define SPEED_CONV_FACTOR 1500000 ///< Measured speed count conversion to RPM #define D12_PUMP_P_COEFFICIENT 20.0F ///< P term for fresh dialysate pump delta pressure control. #define D12_PUMP_I_COEFFICIENT 60.0F ///< I term for fresh dialysate pump delta pressure control. #define D48_PUMP_P_COEFFICIENT 20.0F ///< P term for spent dialysate pump delta pressure control. #define D48_PUMP_I_COEFFICIENT 60.0F ///< I term for spent dialysate pump delta pressure control. #define MAX_ALLOWED_RPM_OUT_OF_RANGE 300 ///< Maximum allowed RPM out of range from target RPM in open loop. #define PUMP_TRANS_TO_RAMP_SPEED_THRESHOLD 20.0F ///< Speed change that alters the state to ramp during control state. #define RPM_OUT_OF_RANGE_TIME_OUT ( 10 * MS_PER_SECOND ) ///< Open loop RPM out of range time out in ms. #define SAFETY_SHUTDOWN_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Dialysate pump safety shutdown activation timeout. /// Enumeration of dialysate pump states. typedef enum DialysatePump_States { DIALYSATE_PUMP_OFF_STATE = 0, ///< Dialysate pump off state DIALYSATE_PUMP_RAMP_UP_STATE, ///< Dialysate pump ramp up state DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE, ///< Dialysate pump control to target state NUM_OF_DIALYSATE_PUMP_STATES ///< Number of dialysate pump states } DIALYSATE_PUMP_STATE_T; /// Enumeration of dialysate pump self-test states. typedef enum DialysatePump_Self_Test_States { DIALYSATE_PUMP_SELF_TEST_STATE_START = 0, ///< Dialysate pump self-test start state DIALYSATE_PUMP_TEST_STATE_IN_PROGRESS, ///< Dialysate pump self-test in progress state DIALYSATE_PUMP_TEST_STATE_COMPLETE, ///< Dialysate pump self-test completed state NUM_OF_DIALYSATE_PUMP_SELF_TEST_STATES ///< Number of dialysate pump self-test states } DIALYSATE_PUMP_SELF_TEST_STATE_T; /// Dialysate pump data structure typedef struct { U32 controlTimerCounter; ///< Timer counter to perform control on dialysate pump. DIALYSATE_PUMP_STATE_T dialysatePumpState; ///< Current state of dialysate pump controller state machine. BOOL isDialPumpOn; ///< Flag indicates dialysate pump On or Off state F32 prevPumpTargetSpeed; ///< Previous target dialysate pumps' speed (mL/min). F32 currentPumpSpeed; ///< Current controlled dialysate pumps' speed (mL/min). U32 directionErrorCount; ///< dialysate pump direction error count from power up. U32 lastDirectionErrorCount; ///< last dialysate pump direction error count from power up. U08 control; ///< Dialysate pump control } DIALYSATE_PUMP_DATA_T; /// Payload record structure for dialysate pump start/stop request typedef struct { U32 pumpID; ///< Pump ID Fresh(DGP) : 0, Spent ( SDP) : 1 U32 startStop; ///< Stop : 0, Start : 1 U32 rpm; ///< Speed range from 300 to 4500 RPM range } DIAL_PUMP_START_STOP_CMD_PAYLOAD_T; // ********** private data ********** static U32 dialysatePumpDataPublicationTimerCounter; ///< Used to schedule dialysate pump data publication to CAN bus. static OVERRIDE_U32_T dialysatePumpDataPublishInterval = { DIALYSATE_PUMP_DATA_PUB_INTERVAL, DIALYSATE_PUMP_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish dialysate pump data to CAN bus. //static DD_DIALYSATE_PUMP_CAL_RECORD_T dialysatePumpCalRecord; ///< Dialysate pump calibration record. static DIALYSATE_PUMP_DATA_T dialysatePumps[ NUM_OF_DIALYSATE_PUMPS ]; ///< Array of dialysate pumps data structure. static OVERRIDE_F32_T pumpTargetSpeed[ NUM_OF_DIALYSATE_PUMPS ]; ///< Target dialysate pumps' speed (mL/min).forward direction only, hence positive speed. static OVERRIDE_F32_T measuredPumpSpeed[ NUM_OF_DIALYSATE_PUMPS ]; ///< Measured dialysate pump speed (mL/min). static OVERRIDE_F32_T dialysatePumpMeasuredCurrentA[ NUM_OF_DIALYSATE_PUMPS ]; ///< Measured dialysate pump current feedback. static OVERRIDE_U32_T measuredDirection[ NUM_OF_DIALYSATE_PUMPS ]; ///< Measured dialysate pump direction. static OVERRIDE_F32_T pumpTargetPressure[ NUM_OF_DIALYSATE_PUMPS ]; ///< Target dialysate pumps' pressure (PSI). static BOOL dialPumpsReadyToControl; ///< Flag use to indicate the minimum control interval is met for pump control //For testing #ifdef __PITEST__ static F32 pIControlSignal[ NUM_OF_CONTROLLER_SIGNAL ]; #endif static const F32 CURRENT_CONVERSION_COEFF = (F32)( 2.5F / ( BITS_12_FULL_SCALE - 1.0F ) ); // ********** private function prototypes ********** static void publishDialysatePumpsData( void ); static DIALYSATE_PUMP_STATE_T handleDialysatePumpControlToTargetState( DIALYSATE_PUMPS_T pumpId ); static BOOL stepDialysatePumpToTargetSpeed( DIALYSATE_PUMPS_T pumpId ); static DIALYSATE_PUMP_STATE_T handleDialysatePumpRampToTargetState( DIALYSATE_PUMPS_T pumpId ); static DIALYSATE_PUMP_STATE_T handleDialysatePumpOffState( DIALYSATE_PUMPS_T pumpId ); static void monitorPumpDirectionErrorCount( DIALYSATE_PUMPS_T pumpId ); /*********************************************************************//** * @brief * The initDialysatePump function initializes the DialysatePumps unit. * @details \b Inputs: none * @details \b Outputs: Dialysate pump unit variables initialized. * @return none *************************************************************************/ void initDialysatePump( void ) { DIALYSATE_PUMPS_T pumpId; #ifdef __PITEST__ U32 i; #endif dialysatePumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; for ( pumpId = DIALYSATE_PUMPS_FIRST; pumpId < NUM_OF_DIALYSATE_PUMPS; pumpId++ ) { dialysatePumps[ pumpId ].controlTimerCounter = 0; dialysatePumps[ pumpId ].dialysatePumpState = DIALYSATE_PUMP_OFF_STATE; dialysatePumps[ pumpId ].isDialPumpOn = FALSE; measuredPumpSpeed[ pumpId ].data = 0.0F; measuredPumpSpeed[ pumpId ].ovInitData = 0.0F; measuredPumpSpeed[ pumpId ].override = OVERRIDE_RESET; measuredPumpSpeed[ pumpId ].ovData = 0.0F; pumpTargetSpeed[ pumpId ].data = 0.0F; pumpTargetSpeed[ pumpId ].ovInitData = 0.0F; pumpTargetSpeed[ pumpId ].override = OVERRIDE_RESET; pumpTargetSpeed[ pumpId ].ovData = 0.0F; measuredDirection[ pumpId ].data = DIALYSATE_PUMP_FORWARD_DIR; measuredDirection[ pumpId ].ovInitData = DIALYSATE_PUMP_FORWARD_DIR; measuredDirection[ pumpId ].ovData = DIALYSATE_PUMP_FORWARD_DIR; measuredDirection[ pumpId ].override = OVERRIDE_RESET; dialysatePumpMeasuredCurrentA[ pumpId ].data = 0.0F; dialysatePumpMeasuredCurrentA[ pumpId ].ovInitData = 0.0F; dialysatePumpMeasuredCurrentA[ pumpId ].ovData = 0.0F; dialysatePumpMeasuredCurrentA[ pumpId ].override = OVERRIDE_RESET; dialysatePumps[ pumpId ].currentPumpSpeed = MIN_DIALYSATE_PUMP_RPM; dialysatePumps[ pumpId ].prevPumpTargetSpeed = 0.0F; dialysatePumps[ pumpId ].control = DIALYSATE_PUMP_CONTROL_STOP; dialysatePumps[ pumpId ].directionErrorCount = 0; dialysatePumps[ pumpId ].lastDirectionErrorCount = 0; dialPumpsReadyToControl = FALSE; signalDialysatePumpHardStop( pumpId ); } pumpTargetPressure[D12_PUMP].data = FRESH_DIALYSATE_TARGET_PRESSURE_PSI; pumpTargetPressure[D12_PUMP].ovInitData = FRESH_DIALYSATE_TARGET_PRESSURE_PSI; pumpTargetPressure[D12_PUMP].ovData = 0.0F; pumpTargetPressure[D12_PUMP].override = OVERRIDE_RESET; pumpTargetPressure[D48_PUMP].data = SPENT_DIALYSATE_TARGET_PRESSURE_PSI; pumpTargetPressure[D48_PUMP].ovInitData = SPENT_DIALYSATE_TARGET_PRESSURE_PSI; pumpTargetPressure[D48_PUMP].ovData = 0.0F; pumpTargetPressure[D48_PUMP].override = OVERRIDE_RESET; // Initialize the fresh dialysate pump PI controller initializePIController( PI_CONTROLLER_ID_D12_PUMP, FRESH_DIAL_OPEN_LOOP_SPEED_RPM, D12_PUMP_P_COEFFICIENT, D12_PUMP_I_COEFFICIENT, MIN_DIALYSATE_PUMP_RPM, MAX_DIALYSATE_PUMP_RPM ); // Initialize spent dialysate pump PI controller initializePIController( PI_CONTROLLER_ID_D48_PUMP, SPENT_DIAL_OPEN_LOOP_SPEED_RPM, D48_PUMP_P_COEFFICIENT, D48_PUMP_I_COEFFICIENT, MIN_DIALYSATE_PUMP_RPM, MAX_DIALYSATE_PUMP_RPM ); // Init the dialysate pump with valid PWM while motor is disabled. // when enable triggers, we dont want invlid RPM set that triggers alarm in motor controller. setFPGAD12PumpSpeed( MIN_DIALYSATE_PUMP_RPM ); setFPGAD48PumpSpeed( MIN_DIALYSATE_PUMP_RPM ); #ifdef __PITEST__ for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) { pIControlSignal[ i ] = 0.0F; } #endif // Initialize the persistent alarms for fresh dialysate pump initPersistentAlarm( ALARM_ID_DD_D12_PUMP_RPM_OUT_OF_RANGE, RPM_OUT_OF_RANGE_TIME_OUT, RPM_OUT_OF_RANGE_TIME_OUT ); initPersistentAlarm( ALARM_ID_DD_D12_PUMP_OFF_FAULT, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); initPersistentAlarm( ALARM_ID_DD_D12_PUMP_CURRENT_OUT_OF_RANGE, DIALYSATE_PUMP_CURRENT_OUT_OF_RANGE_TIMEOUT_MS, DIALYSATE_PUMP_CURRENT_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_DD_D12_PUMP_DIRECTION_INVALID, DIALYSATE_PUMP_DIR_OF_RANGE_TIMEOUT_MS, DIALYSATE_PUMP_DIR_OF_RANGE_TIMEOUT_MS ); //Initialize the persistent alarms for spent dialysate pump initPersistentAlarm( ALARM_ID_DD_D48_PUMP_RPM_OUT_OF_RANGE, RPM_OUT_OF_RANGE_TIME_OUT, RPM_OUT_OF_RANGE_TIME_OUT ); initPersistentAlarm( ALARM_ID_DD_D48_PUMP_OFF_FAULT, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); initPersistentAlarm( ALARM_ID_DD_D48_PUMP_CURRENT_OUT_OF_RANGE, DIALYSATE_PUMP_CURRENT_OUT_OF_RANGE_TIMEOUT_MS, DIALYSATE_PUMP_CURRENT_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_DD_D48_PUMP_DIRECTION_INVALID, DIALYSATE_PUMP_DIR_OF_RANGE_TIMEOUT_MS, DIALYSATE_PUMP_DIR_OF_RANGE_TIMEOUT_MS ); // initialize FPGA dialysate pump hall sensor error initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_D12_PUMP_HALL_SENSOR_ERROR, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_FAILURES, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_WINDOW_MS ); initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_D48_PUMP_HALL_SENSOR_ERROR, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_FAILURES, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_WINDOW_MS ); } /*********************************************************************//** * @brief * The setDialysatePumpTargetSpeed function sets a new target RPM for the * dialysate pump. * @details \b Inputs: none * @details \b Outputs: pumpTargetSpeed. * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump id supplied. * @param pumpId pump id to set the new speed. * @param rpm new dialysate pump target RPM * @return TRUE if new target RPM is set, FALSE if not *************************************************************************/ BOOL setDialysatePumpTargetRPM( DIALYSATE_PUMPS_T pumpId, U32 rpm ) { BOOL result = FALSE; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { if ( ( MIN_DIALYSATE_PUMP_RPM <= rpm ) && ( rpm <= MAX_DIALYSATE_PUMP_RPM ) ) { pumpTargetSpeed[ pumpId ].data = rpm; } else if ( rpm < MIN_DIALYSATE_PUMP_RPM ) { // Lets assign minimum speed to make sure, driver is not getting into fault mode pumpTargetSpeed[ pumpId ].data = MIN_DIALYSATE_PUMP_RPM; } else { pumpTargetSpeed[ pumpId ].data = MAX_DIALYSATE_PUMP_RPM; } //handle target speed update when pump is running if ( DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE == dialysatePumps[ pumpId ].dialysatePumpState ) { F32 diffSpeed = fabs( getDialysatePumpTargetSpeed( pumpId ) - dialysatePumps[ pumpId ].prevPumpTargetSpeed ); if ( diffSpeed > PUMP_TRANS_TO_RAMP_SPEED_THRESHOLD ) { // change to ramp state dialysatePumps[ pumpId ].dialysatePumpState = DIALYSATE_PUMP_RAMP_UP_STATE; } } dialysatePumps[ pumpId ].prevPumpTargetSpeed = getDialysatePumpTargetSpeed( pumpId ); result = TRUE; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ) } return result; } /*********************************************************************//** * @brief * The signalDialysatePumpHardStop function stops the Dialysate pump immediately. * @details \b Inputs: none * @details \b Outputs: control,currentPumpSpeed,pumpTargetSpeed,dialysatePumpState, * controlTimerCounter,isDialPumpOn. * @param pumpId pump id to stop the given dialysate pump * @return none *************************************************************************/ void signalDialysatePumpHardStop( DIALYSATE_PUMPS_T pumpId ) { //Update control to stop the dialysate pump if ( D12_PUMP == pumpId ) { // dialysate pump control run enable dialysatePumps[ pumpId ].control = DIALYSATE_PUMP_CONTROL_STOP; setFPGAD12PumpControl( dialysatePumps[ pumpId ].control ); setFPGAD12PumpSpeed( MIN_DIALYSATE_PUMP_RPM ); } else { dialysatePumps[ pumpId ].control = DIALYSATE_PUMP_CONTROL_STOP; setFPGAD48PumpControl( dialysatePumps[ pumpId ].control ); setFPGAD48PumpSpeed( MIN_DIALYSATE_PUMP_RPM ); } // Reset all the variables to stop mode dialysatePumps[ pumpId ].currentPumpSpeed = MIN_DIALYSATE_PUMP_RPM; pumpTargetSpeed[ pumpId ].data = 0.0F; dialysatePumps[ pumpId ].dialysatePumpState = DIALYSATE_PUMP_OFF_STATE; dialysatePumps[ pumpId ].controlTimerCounter = 0; dialysatePumps[ pumpId ].isDialPumpOn = FALSE; //Reset PI Controller if ( D12_PUMP == pumpId ) { resetPIController( PI_CONTROLLER_ID_D12_PUMP, FRESH_DIAL_OPEN_LOOP_SPEED_RPM ); } else { resetPIController( PI_CONTROLLER_ID_D48_PUMP, SPENT_DIAL_OPEN_LOOP_SPEED_RPM ); } } /*********************************************************************//** * @brief * The monitorPumpDirectionErrorCount function monitors the given dialysate pumps * direction error count and triggers the alarms if they are incrementing for * certain count with in defined time. * @details \b Inputs: directionErrorCount,lastDirectionErrorCount * @details \b Outputs: lastDirectionErrorCount * @details \b Alarm: ALARM_ID_DD_D12_PUMP_DIRECTION_FPGA_FAULT when * the direction error count increments for certian count with in defined time. * @details \b Alarm: ALARM_ID_DD_D48_PUMP_DIRECTION_FPGA_FAULT when * the direction error count increments for certian count with in defined time. * @param pumpId pump id to check the direction error count for the given dialysate * pump * @return none *************************************************************************/ static void monitorPumpDirectionErrorCount( DIALYSATE_PUMPS_T pumpId ) { if ( dialysatePumps[ pumpId ].directionErrorCount != dialysatePumps[ pumpId ].lastDirectionErrorCount ) { if ( D12_PUMP == pumpId ) { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_D12_PUMP_HALL_SENSOR_ERROR ) ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_D12_PUMP_DIRECTION_FPGA_FAULT, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_FAILURES, dialysatePumps[ pumpId ].directionErrorCount ) } } else { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_D48_PUMP_HALL_SENSOR_ERROR ) ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_D48_PUMP_DIRECTION_FPGA_FAULT, MAX_FPGA_DIALYSATE_PUMP_DIRECTION_FAULT_FAILURES, dialysatePumps[ pumpId ].directionErrorCount ) } } dialysatePumps[ pumpId ].lastDirectionErrorCount = dialysatePumps[ pumpId ].directionErrorCount; } } /*********************************************************************//** * @brief * The execDialysatePumpMonitor function executes the dialysate pump monitor. * @details \b Inputs: dialysate pumps speed, current and direction reported * by FPGA * @details \b Outputs: measuredPumpSpeed,dialysatePumpMeasuredCurrentA, * measuredDirection,directionErrorCount * @detail \b Alarms: ALARM_ID_DD_D12_PUMP_RPM_OUT_OF_RANGE, * ALARM_ID_DD_D48_PUMP_RPM_OUT_OF_RANGE when speed mismatch * occurs between set and measured speed. * @detail \b Alarms: ALARM_ID_DD_D12_PUMP_OFF_FAULT, * ALARM_ID_DD_D48_PUMP_OFF_FAULT when dialysate pump runs at * certain speed when not commanded to run. * @detail \b Alarms: ALARM_ID_DD_D12_PUMP_DIRECTION_INVALID, * ALARM_ID_DD_D48_PUMP_DIRECTION_INVALID when dialysate pump is * not running in forward direction. * @detail \b Alarms:ALARM_ID_DD_D12_PUMP_CURRENT_OUT_OF_RANGE, * ALARM_ID_DD_D48_PUMP_CURRENT_OUT_OF_RANGE when dialysate pump * is drawing more current than expected. * @return none *************************************************************************/ void execDialysatePumpMonitor( void ) { U16 d12Current = getFPGAD12PumpCurrentFeedback(); U16 d48Current = getFPGAD48PumpCurrentFeedback(); U16 d12SpeedCnt = getFPGAD12PumpSpeed(); U16 d48SpeedCnt = getFPGAD48PumpSpeed(); BOOL isOffCurrentOut = FALSE; BOOL isCurrentOutOfRange = FALSE; DIALYSATE_PUMPS_T pumpId; // Update the paramerters dialysatePumpMeasuredCurrentA[ D12_PUMP ].data = (F32)d12Current * CURRENT_CONVERSION_COEFF; dialysatePumpMeasuredCurrentA[ D48_PUMP ].data = (F32)d48Current * CURRENT_CONVERSION_COEFF; measuredDirection[ D12_PUMP ].data = (U32)( ( getFPGAD12PumpHallDirectionStatus() & DIALYSATE_PUMP_DIR_BIT_MASK ) >> SHIFT_BITS_BY_7 ); measuredDirection[ D48_PUMP ].data = (U32)( ( getFPGAD48PumpHallDirectionStatus() & DIALYSATE_PUMP_DIR_BIT_MASK ) >> SHIFT_BITS_BY_7 ); dialysatePumps[ D12_PUMP ].directionErrorCount = (U32)( getFPGAD12PumpHallDirectionStatus() & DIALYSATE_PUMP_DIR_ERROR_CNT_BIT_MASK ); dialysatePumps[ D48_PUMP ].directionErrorCount = (U32)( getFPGAD48PumpHallDirectionStatus() & DIALYSATE_PUMP_DIR_ERROR_CNT_BIT_MASK ); if ( d12SpeedCnt > SPEED_COUNT_ZERO ) { measuredPumpSpeed[ D12_PUMP ].data = SPEED_CONV_FACTOR / d12SpeedCnt; } if ( d48SpeedCnt > SPEED_COUNT_ZERO ) { measuredPumpSpeed[ D48_PUMP ].data = SPEED_CONV_FACTOR / d48SpeedCnt; } // Monitor dialysate pumps for ( pumpId = DIALYSATE_PUMPS_FIRST; pumpId < NUM_OF_DIALYSATE_PUMPS; pumpId++ ) { switch ( dialysatePumps[ pumpId ].dialysatePumpState ) { case DIALYSATE_PUMP_OFF_STATE: { BOOL isRPMTooHigh = FALSE; isOffCurrentOut = ( getDialysatePumpMeasuredCurrentA( pumpId ) > DIALYSATE_PUMP_MAX_CURRENT_WHEN_OFF_A ? TRUE : FALSE ); isRPMTooHigh = ( getDialysatePumpMeasuredSpeed( pumpId ) > MIN_DIALYSATE_PUMP_RPM ? TRUE : FALSE ); //TODO : Enable the code later for alarm testing #if 0 if ( D12_PUMP == pumpId ) { checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_RPM_OUT_OF_RANGE, FALSE, getDialysatePumpMeasuredSpeed( pumpId ), MAX_ALLOWED_RPM_OUT_OF_RANGE ); checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_OFF_FAULT, isRPMTooHigh, getDialysatePumpMeasuredSpeed( pumpId ), MIN_DIALYSATE_PUMP_RPM ); checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_DIRECTION_INVALID, FALSE, getDialysatePumpMeasuredDirection( pumpId ), DIALYSATE_PUMP_FORWARD_DIR ); } else { checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_RPM_OUT_OF_RANGE, FALSE, getDialysatePumpMeasuredSpeed( pumpId ), MAX_ALLOWED_RPM_OUT_OF_RANGE ); checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_OFF_FAULT, isRPMTooHigh, getDialysatePumpMeasuredSpeed( pumpId ), MIN_DIALYSATE_PUMP_RPM ); checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_DIRECTION_INVALID, FALSE, getDialysatePumpMeasuredDirection( pumpId ), DIALYSATE_PUMP_FORWARD_DIR ); } // If the direction off fault alarm has become active, trigger the safety shutdown if ( ( TRUE == isAlarmActive( ALARM_ID_DD_D12_PUMP_OFF_FAULT ) ) || ( TRUE == isAlarmActive( ALARM_ID_DD_D12_PUMP_OFF_FAULT ) ) ) { //activateSafetyShutdown(); } #endif } break; case DIALYSATE_PUMP_RAMP_UP_STATE: case DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE: { U32 direction = getDialysatePumpMeasuredDirection( pumpId ); U32 rpm = getDialysatePumpMeasuredSpeed( pumpId ); BOOL isRPMOutOfRange = FALSE; U32 rpmDiff = abs( getDialysatePumpTargetSpeed( pumpId ) - rpm ); BOOL isDirInvalid = ( ( direction != DIALYSATE_PUMP_FORWARD_DIR ) && ( rpm > DIALYSATE_PUMP_MIN_RPM_FOR_DIR_CHECK ) ? TRUE : FALSE ); isRPMOutOfRange = ( rpmDiff > MAX_ALLOWED_RPM_OUT_OF_RANGE ? TRUE : FALSE ); //TODO : Enable the code later for alarm testing #if 0 if ( D12_PUMP == pumpId ) { checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_RPM_OUT_OF_RANGE, isRPMOutOfRange, rpm, MAX_ALLOWED_RPM_OUT_OF_RANGE ); checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_OFF_FAULT, FALSE, getDialysatePumpMeasuredSpeed( pumpId ), MIN_DIALYSATE_PUMP_RPM ); checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_DIRECTION_INVALID, isDirInvalid, (F32)direction, DIALYSATE_PUMP_FORWARD_DIR ); } else { checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_RPM_OUT_OF_RANGE, isRPMOutOfRange, rpm, MAX_ALLOWED_RPM_OUT_OF_RANGE ); checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_OFF_FAULT, FALSE, getDialysatePumpMeasuredSpeed( pumpId ), MIN_DIALYSATE_PUMP_RPM ); checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_DIRECTION_INVALID, isDirInvalid, (F32)direction, DIALYSATE_PUMP_FORWARD_DIR ); } #endif } break; default: // do nothing break; } //Monitor Direction error count monitorPumpDirectionErrorCount( pumpId ); // Check the persistent alarm for the maximum dialysate pump current F32 currentA = getDialysatePumpMeasuredCurrentA( pumpId ); isCurrentOutOfRange = ( currentA > DIALYSATE_PUMP_MAX_CURRENT_A ? TRUE : FALSE ) | isOffCurrentOut; //TODO : Enable the code later for alarm testing #if 0 if ( D12_PUMP == pumpId ) { checkPersistentAlarm( ALARM_ID_DD_D12_PUMP_CURRENT_OUT_OF_RANGE, isCurrentOutOfRange, currentA, DIALYSATE_PUMP_MAX_CURRENT_A ); } else { checkPersistentAlarm( ALARM_ID_DD_D48_PUMP_CURRENT_OUT_OF_RANGE, isCurrentOutOfRange, currentA, DIALYSATE_PUMP_MAX_CURRENT_A ); } #endif } // Publish dialysate pumps data on interval publishDialysatePumpsData(); } /*********************************************************************//** * @brief * The execDialysatePumpController function executes the dialysate pumps controller. * @details \b Inputs: dialysatePumpState * @details \b Outputs: dialysatePumpState * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid dialysate pump * state machine found. * @return none *************************************************************************/ void execDialysatePumpController( void ) { DIALYSATE_PUMPS_T pumpId; // Check if a new calibration is available // if ( TRUE == isNewCalibrationRecordAvailable() ) // { // get updated record //getNVRecord2Driver( GET_CAL_DIALYSATE_PUMP_RECORD, (U08*)&dialysatePumpCalRecord, sizeof( DD_DIALYSATE_PUMP_CAL_RECORD_T ), 0, // ALARM_ID_DD_D12_PUMP_INVALID_CAL_RECORD ); // } for ( pumpId = DIALYSATE_PUMPS_FIRST; pumpId < NUM_OF_DIALYSATE_PUMPS; pumpId++ ) { switch ( dialysatePumps[ pumpId ].dialysatePumpState ) { case DIALYSATE_PUMP_OFF_STATE: dialysatePumps[ pumpId ].dialysatePumpState = handleDialysatePumpOffState( pumpId ); break; case DIALYSATE_PUMP_RAMP_UP_STATE: dialysatePumps[ pumpId ].dialysatePumpState = handleDialysatePumpRampToTargetState( pumpId ); break; case DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE: dialysatePumps[ pumpId ].dialysatePumpState = handleDialysatePumpControlToTargetState( pumpId ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_EXEC_INVALID_STATE, pumpId ) dialysatePumps[ pumpId ].dialysatePumpState = DIALYSATE_PUMP_OFF_STATE; break; } } } /*********************************************************************//** * @brief * The execDialysatePumpSelfTest function executes the dialysate pump's self-test. * @details \b Inputs: Non volatile records. * @details \b Outputs: none * @return DialysatePumps SelfTest Result (SELF_TEST_STATUS_T) *************************************************************************/ SELF_TEST_STATUS_T execDialysatePumpSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; BOOL calStatus = TRUE; // TODO:initialize to false when calibration records avialble // This is only one record the number of items to check is 0 since the get NV data function does not do a for loop to check the calibration time // calStatus |= getNVRecord2Driver( GET_CAL_D12_PUMP_RECORD, (U08*)&freshDialysatePumpRecord, sizeof( DD_D12_PUMP_RECORD_T ), 0, // ALARM_ID_DD_D12_PUMP_INVALID_CAL_RECORD ); // calStatus |= getNVRecord2Driver( GET_CAL_D48_PUMP_RECORD, (U08*)&spentDialysatePumpRecord, sizeof( DD_D48_PUMP_RECORD_T ), 0, // ALARM_ID_DD_D48_PUMP_INVALID_CAL_RECORD ); // // calStatus |= getNVRecord2Driver( GET_CAL_DIALYSATE_PUMP_RECORD, (U08*)&dialysatePumpCalRecord, sizeof( DD_DIALYSATE_PUMP_CAL_RECORD_T ), 0, // ALARM_ID_NO_ALARM ); if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; } return result; } /*********************************************************************//** * @brief * The isDialysatePumpOn function determines whether the dialysate pump is on * or Off state. * @details \b Inputs: dialysatePumps[] * @details \b Outputs: none * @param pumpId dialysate pump id to return status of dialysate pump running state * @return TRUE if dialysate pump is on, FALSE if not. *************************************************************************/ BOOL isDialysatePumpOn( DIALYSATE_PUMPS_T pumpId ) { return ( dialysatePumps[ pumpId ].isDialPumpOn ); } /*********************************************************************//** * @brief * The handleDialysatePumpOffState function handles the dialysate pump off state of * the dialysate pump controller state machine. * @details \b Inputs: pumpTargetSpeed * @details \b Outputs: dialysatePumps[].control,isDialPumpOn * @param pumpId dialysate pump id to run the dialysate pump * @return next state for the controller state machine *************************************************************************/ static DIALYSATE_PUMP_STATE_T handleDialysatePumpOffState( DIALYSATE_PUMPS_T pumpId ) { DIALYSATE_PUMP_STATE_T result = DIALYSATE_PUMP_OFF_STATE; F32 targetSpeed = getDialysatePumpTargetSpeed( pumpId ); if ( targetSpeed >= MIN_DIALYSATE_PUMP_RPM ) { if ( D12_PUMP == pumpId ) { // dialysate pump control run enable, forward run only. dialysatePumps[ pumpId ].control = DIALYSATE_PUMP_CONTROL_RUN; setFPGAD12PumpControl( dialysatePumps[ pumpId ].control ); } else { dialysatePumps[ pumpId ].control = DIALYSATE_PUMP_CONTROL_RUN; setFPGAD48PumpControl( dialysatePumps[ pumpId ].control ); } dialysatePumps[ pumpId ].isDialPumpOn = TRUE; result = DIALYSATE_PUMP_RAMP_UP_STATE; } else { dialysatePumps[ pumpId ].isDialPumpOn = FALSE; } return result; } /*********************************************************************//** * @brief * The handleDialysatePumpRampToTargetState function handles the dialysate pump * ramp to target state of the dialysate pump controller state machine. * @details \b Inputs: pumpTargetSpeed * @details \b Outputs: currentPumpSpeed * @param pumpId dialysate pump id to increase current step speed * @return next state for the controller state machine *************************************************************************/ static DIALYSATE_PUMP_STATE_T handleDialysatePumpRampToTargetState( DIALYSATE_PUMPS_T pumpId ) { DIALYSATE_PUMP_STATE_T state = DIALYSATE_PUMP_RAMP_UP_STATE; if ( TRUE == stepDialysatePumpToTargetSpeed( pumpId ) ) { if ( D12_PUMP == pumpId ) { resetPIController( PI_CONTROLLER_ID_D12_PUMP, FRESH_DIAL_OPEN_LOOP_SPEED_RPM ); } else { resetPIController( PI_CONTROLLER_ID_D48_PUMP, SPENT_DIAL_OPEN_LOOP_SPEED_RPM ); } state = DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE; } return state; } /*********************************************************************//** * @brief * The stepDialysatePumpToTargetSpeed function steps current step speed * toward target speed for the given dialysate pump,with predefined step increase. * @details \b Inputs: pumpTargetSpeed * @details \b Outputs: currentPumpSpeed * @param pumpId dialysate pump id to increase current step speed * @return TRUE if the pump has reached to target otherwise, FALSE *************************************************************************/ static BOOL stepDialysatePumpToTargetSpeed( DIALYSATE_PUMPS_T pumpId ) { F32 speedIncrease = 0.0F; BOOL hasTgtBeenReached = FALSE; F32 currentToTargetDiff = fabs( getDialysatePumpTargetSpeed( pumpId ) - dialysatePumps[ pumpId ].currentPumpSpeed ); if ( currentToTargetDiff > ZERO_SPEED ) { if ( currentToTargetDiff > DIALYSATE_PUMP_RAMP_SPEED_INCREMENT ) { speedIncrease = DIALYSATE_PUMP_RAMP_SPEED_INCREMENT; } else { speedIncrease = currentToTargetDiff; hasTgtBeenReached = TRUE; } // Subtract current speed when target speed is smaller if ( getDialysatePumpTargetSpeed( pumpId ) < dialysatePumps[ pumpId ].currentPumpSpeed ) { speedIncrease *= -1.0F; } dialysatePumps[ pumpId ].currentPumpSpeed += speedIncrease; // If the pump's target speed is set to be 0, do not ramp down set it to zero immediately // if ( getDialysatePumpTargetSpeed( pumpId ) < MIN_DIALYSATE_PUMP_RPM ) // { // dialysatePumps[ pumpId ].currentPumpSpeed = MIN_DIALYSATE_PUMP_RPM; // } } if ( dialysatePumps[ pumpId ].currentPumpSpeed >= MIN_DIALYSATE_PUMP_RPM ) { if ( D12_PUMP == pumpId ) { // Set fresh dialyate pump speed setFPGAD12PumpSpeed( (U16)dialysatePumps[ pumpId ].currentPumpSpeed ); } else { // Set spent dialyate pump speed setFPGAD48PumpSpeed( (U16)dialysatePumps[ pumpId ].currentPumpSpeed ); } } return hasTgtBeenReached; } /*********************************************************************//** * @brief * The handleDialysatePumpControlToTargetState function handles the control to * target state of the dialysate pump controller state machine. * @details \b Inputs: controlTimerCounter * @details \b Outputs: currentPumpSpeed, controlTimerCounter * @return next state of the controller state machine *************************************************************************/ static DIALYSATE_PUMP_STATE_T handleDialysatePumpControlToTargetState( DIALYSATE_PUMPS_T pumpId ) { DIALYSATE_PUMP_STATE_T state = DIALYSATE_PUMP_CONTROL_TO_TARGET_STATE; // control at set minimum interval or interval is expired and balance chamber fill is complete if ( ( ++dialysatePumps[ pumpId ].controlTimerCounter >= DP_CONTROL_INTERVAL ) || ( TRUE == dialPumpsReadyToControl ) ) { dialysatePumps[ pumpId ].controlTimerCounter = 0; dialPumpsReadyToControl = TRUE; // Control happen only when balancing chamber fill is complete. if ( FALSE == getBalancingChamberFillinProgressStatus() ) { dialPumpsReadyToControl = FALSE; // Control based on the measured and target pressure if ( D12_PUMP == pumpId ) { F32 measuredPressure = getFilteredPressure( D18_PRES ); F32 targetPressure = getDialysatePumpTargetPressure( pumpId ); F32 control = runPIController( PI_CONTROLLER_ID_D12_PUMP, targetPressure, measuredPressure ); #ifdef __PITEST__ U32 i; for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) { pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D12_PUMP, (PI_CONTROLLER_SIGNALS_ID)i ); } #endif dialysatePumps[ pumpId ].currentPumpSpeed = control; //Set fresh dialyate pump speed setFPGAD12PumpSpeed( (U16)dialysatePumps[ pumpId ].currentPumpSpeed ); } else { F32 measuredPressure = getFilteredPressure( D51_PRES ); F32 targetPressure = getDialysatePumpTargetPressure( pumpId ); F32 control = runPIController( PI_CONTROLLER_ID_D48_PUMP, targetPressure, measuredPressure ); #ifdef __PITEST__ U32 i; for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) { pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D48_PUMP, (PI_CONTROLLER_SIGNALS_ID)i ); } #endif dialysatePumps[ pumpId ].currentPumpSpeed = control; //Set spent dialyate pump speed setFPGAD48PumpSpeed( (U16)dialysatePumps[ pumpId ].currentPumpSpeed ); } } } return state; } /*********************************************************************//** * @brief * The getDialysatePumpTargetSpeed function gets the current target speed for the given * dialysate 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 dialysate pump id to get the current target speed * @return the current target speed for the given dialysate pump. *************************************************************************/ F32 getDialysatePumpTargetSpeed( DIALYSATE_PUMPS_T pumpId ) { F32 speed = 0.0F; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { speed = getF32OverrideValue( &pumpTargetSpeed[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ); } return speed; } /*********************************************************************//** * @brief * The getDialysatePumpMeasuredSpeed function gets the measured speed for the given * dialysate 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 dialysate pump id to get the measured speed * @return the measured speed for the given dialysate pump. *************************************************************************/ F32 getDialysatePumpMeasuredSpeed( DIALYSATE_PUMPS_T pumpId ) { F32 speed = 0.0F; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { speed = getF32OverrideValue( &measuredPumpSpeed[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ); } return speed; } /*********************************************************************//** * @brief * The getDialysatePumpTargetPressure function gets the target pressure for * the given dialysate pump. * @details \b Inputs: pumpTargetPressure * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @param pumpId dialysate pump id to get the target pressure * @return the target pressure for the given dialysate pump. *************************************************************************/ F32 getDialysatePumpTargetPressure( DIALYSATE_PUMPS_T pumpId ) { F32 pressure = 0.0F; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { pressure = getF32OverrideValue( &pumpTargetPressure[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ); } return pressure; } /*********************************************************************//** * @brief * The getDialysatePumpMeasuredCurrentA function returns the given dialysate * pump current feedback. * @details \b Inputs: dialysatePumpMeasuredCurrentA * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @return the given dialysate pump current feedback *************************************************************************/ F32 getDialysatePumpMeasuredCurrentA( DIALYSATE_PUMPS_T pumpId ) { F32 current = 0.0F; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { current = getF32OverrideValue( &dialysatePumpMeasuredCurrentA[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ); } return current; } /*********************************************************************//** * @brief * The getDialysatePumpMeasuredDirection function returns the given dialysate pump * direction. * @details \b Inputs: measuredDirection * @details \b Outputs: none * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid pump ID is seen. * @return the given dialysate pump direction *************************************************************************/ U32 getDialysatePumpMeasuredDirection( DIALYSATE_PUMPS_T pumpId ) { U32 direction = 0; if ( pumpId < NUM_OF_DIALYSATE_PUMPS ) { direction = getU32OverrideValue( &measuredDirection[ pumpId ] ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSATE_PUMP_INVALID_PUMP_ID, pumpId ); } return direction; } /*********************************************************************//** * @brief * The publishDialysatePumpsData function publishes dialysate pumps data at the set * interval. * @details \b Inputs: dialysatePumpDataPublicationTimerCounter,dialysatePumps * @details \b Outputs: dialPump * @details \b Message \Sent: MSG_ID_DIALYSATE_PUMPS_DATA to pusblish dialysate * pumps data. * @return none *************************************************************************/ static void publishDialysatePumpsData( void ) { // publish Dialysate pump data on interval if ( ++dialysatePumpDataPublicationTimerCounter >= getU32OverrideValue( &dialysatePumpDataPublishInterval ) ) { DIALYSATE_PUMPS_PUBLISH_DATA_T dialPump; // Populate the data structure for publication #ifndef __PITEST__ dialPump.d12PumpTargetRPM = getDialysatePumpTargetSpeed( D12_PUMP ); dialPump.d48PumpTargetRPM = getDialysatePumpTargetSpeed( D48_PUMP ); #else dialPump.d12PumpTargetRPM = pIControlSignal[ 0 ]; dialPump.d48PumpTargetRPM = pIControlSignal[ 1 ]; #endif dialPump.d12PumpMeasuredSpeed = getDialysatePumpMeasuredSpeed( D12_PUMP ); dialPump.d48PumpMeasuredSpeed = getDialysatePumpMeasuredSpeed( D48_PUMP ); dialPump.d12PumpCurrentSpeed = dialysatePumps[ D12_PUMP ].currentPumpSpeed; dialPump.d48PumpCurrentSpeed = dialysatePumps[ D48_PUMP ].currentPumpSpeed; dialPump.d12PumpState = (U32)dialysatePumps[ D12_PUMP ].dialysatePumpState; dialPump.d48PumpState = (U32)dialysatePumps[ D48_PUMP ].dialysatePumpState; #ifndef __PITEST__ dialPump.d12PumpTargetPressure = getDialysatePumpTargetPressure( D12_PUMP ); dialPump.d48PumpTargetPressure = getDialysatePumpTargetPressure( D48_PUMP ); dialPump.d12PumpMeasuredPressure = getFilteredPressure( D18_PRES ); dialPump.d48PumpMeasuredPressure = getFilteredPressure( D51_PRES ); dialPump.d12PumpMeasuredCurrent = getDialysatePumpMeasuredCurrentA( D12_PUMP ); dialPump.d48PumpMeasuredCurrent = getDialysatePumpMeasuredCurrentA( D48_PUMP ); #else dialPump.d12PumpTargetPressure = pIControlSignal[ 2 ]; dialPump.d48PumpTargetPressure = pIControlSignal[ 3 ]; dialPump.d12PumpMeasuredPressure = pIControlSignal[ 4 ]; dialPump.d48PumpMeasuredPressure = pIControlSignal[ 5 ]; dialPump.d12PumpMeasuredCurrent = pIControlSignal[ 6 ]; dialPump.d48PumpMeasuredCurrent = pIControlSignal[ 7 ]; #endif dialPump.d12PumpControl = (U32)dialysatePumps[ D12_PUMP ].control; dialPump.d48PumpControl = (U32)dialysatePumps[ D48_PUMP ].control; dialPump.d12PumpDirErrCnt = dialysatePumps[ D12_PUMP ].directionErrorCount; dialPump.d48PumpDirErrCnt = dialysatePumps[ D48_PUMP ].directionErrorCount; dialPump.d12PumpMeasuredDir = getDialysatePumpMeasuredDirection( D12_PUMP ); dialPump.d48PumpMeasuredDir = getDialysatePumpMeasuredDirection( D48_PUMP ); broadcastData( MSG_ID_DIALYSATE_PUMPS_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&dialPump, sizeof( DIALYSATE_PUMPS_PUBLISH_DATA_T ) ); dialysatePumpDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testDialysatePumpsDataPublishIntervalOverride function overrides the * dialysate pump data publish interval. * @details \b Inputs: dialysatePumpDataPublishInterval * @details \b Outputs: dialysatePumpDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the dialysate pump data broadcast interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testDialysatePumpsDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &dialysatePumpDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpTargetSpeedOverride function overrides the target * speed value of given dialysate 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 *************************************************************************/ BOOL testDialysatePumpTargetSpeedOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &pumpTargetSpeed[ 0 ], NUM_OF_DIALYSATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpMeasuredSpeedOverride function overrides the measured * speed value of given dialysate 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 testDialysatePumpMeasuredSpeedOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &measuredPumpSpeed[ 0 ], NUM_OF_DIALYSATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpTargetPressureOverride function overrides the target * pressure value of given dialysate pump id. * @details \b Inputs: none * @details \b Outputs: pumpTargetPressure * @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 testDialysatePumpTargetPressureOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &pumpTargetPressure[ 0 ], NUM_OF_DIALYSATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpMeasuredCurrentOverride function overrides the measured * current value of given dialysate pump id. * @details \b Inputs: none * @details \b Outputs: dialysatePumpMeasuredCurrentA * @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 testDialysatePumpMeasuredCurrentOverride( MESSAGE_T *message ) { BOOL result = f32ArrayOverride( message, &dialysatePumpMeasuredCurrentA[ 0 ], NUM_OF_DIALYSATE_PUMPS - 1 ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpMeasuredDirectionOverride function overrides the measured * direction value of given dialysate pump id. * @details \b Inputs: none * @details \b Outputs: measuredDirection * @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 testDialysatePumpMeasuredDirectionOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &measuredDirection[ 0 ], NUM_OF_DIALYSATE_PUMPS - 1, 0, DIALYSATE_PUMP_FORWARD_DIR ); return result; } /*********************************************************************//** * @brief * The testDialysatePumpStartStopOverride function starts a given dialysate pump * at mentioned RPM. * @details \b Inputs: tester logged in * @details \b Outputs: dialysatePumps[] * @param message set message from Dialin which includes the dialysate pump to set * and the state to set the dialysate pump to. * @return TRUE if set request is successful, FALSE if not *************************************************************************/ BOOL testDialysatePumpStartStopOverride( MESSAGE_T *message ) { BOOL result = FALSE; // Verify tester has logged in with DD if ( TRUE == isTestingActivated() ) { // Verify payload length is valid if ( sizeof( DIAL_PUMP_START_STOP_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { DIAL_PUMP_START_STOP_CMD_PAYLOAD_T payload; memcpy( &payload, message->payload, sizeof(DIAL_PUMP_START_STOP_CMD_PAYLOAD_T) ); if ( (DIALYSATE_PUMPS_T)payload.pumpID < NUM_OF_DIALYSATE_PUMPS ) { // Handle start command if ( ( TRUE == payload.startStop ) && ( ( payload.rpm >= MIN_DIALYSATE_PUMP_RPM ) && ( payload.rpm <= MAX_DIALYSATE_PUMP_RPM ) ) ) { setDialysatePumpTargetRPM( (DIALYSATE_PUMPS_T)payload.pumpID, payload.rpm ); result = TRUE; } //Handle stop command if ( FALSE == payload.startStop ) { signalDialysatePumpHardStop( (DIALYSATE_PUMPS_T)payload.pumpID ); result = TRUE; } } } } return result; } /**@}*/