/************************************************************************** * * Copyright (c) 2019-2021 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 DialOutFlow.c * * @author (last) Sean Nash * @date (last) 12-Nov-2021 * * @author (original) Sean * @date (original) 24-Jan-2020 * ***************************************************************************/ #include // Using fabs() function #include "etpwm.h" #include "gio.h" #include "mibspi.h" #include "DialOutFlow.h" #include "FPGA.h" #include "InternalADC.h" #include "ModeTreatment.h" #include "OperationModes.h" #include "PIControllers.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup DialysateOutlet * @{ */ // ********** private definitions ********** /// Interval (ms/task time) at which the dialysate outlet pump data is published on the CAN bus. #define DIAL_OUT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) /// Interval (ms/task time) at which the dialysate outlet flow is filtered. #define DIAL_OUT_FILTER_INTERVAL ( 100 / TASK_PRIORITY_INTERVAL ) #define MAX_DIAL_OUT_FLOW_RATE 650 ///< Maximum dialysate outlet pump flow rate in mL/min. #define MIN_DIAL_OUT_FLOW_RATE 100 ///< Minimum dialysate outlet pump flow rate in mL/min. #define MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE 0.0133 ///< Maximum duty cycle change when ramping up ~ 200 mL/min/s. #define MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE 0.02 ///< Maximum duty cycle change when ramping down ~ 300 mL/min/s. #define MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. #define MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. #define MAX_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL 0.4 ///< Maximum PWM offset (added to DPi PWM duty cycle). #define MIN_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL -0.4 ///< Minimum PWM offset (added to DPi PWM duty cycle). #define P_VOL 0.001 ///< P term for volume error feedback into dialysate outlet pump control. #define P_UF 0.001 ///< P term for UF rate error feedback into dialysate outlet pump control. #define P_CORR 0.1666 ///< P term for volume error feedback into dialysate outlet pump flow estimate correction offset. #define RPM_2_ML_MIN_CONVERSION 0.215964 ///< Conversion factor for estimating flow rate from pump motor RPM. #define SIZE_OF_ROLLING_AVG 100 ///< Number of samples in DPo flow estimation moving average. #define DOP_HOME_RATE 100 ///< Target pump speed (in estimate mL/min) for homing. #define DOP_HOME_TIMEOUT_MS 10000 ///< Maximum time allowed for homing to complete (in ms). /// Interval (ms/task time) at which the blood pump speed is calculated (every 40 ms). #define DOP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) /// Number of hall sensor counts kept in buffer to hold last 1 second of count data. #define DOP_SPEED_CALC_BUFFER__LEN ( 1000 / DOP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define DOP_HALL_EDGE_COUNTS_PER_REV 48 ///< Number of hall sensor edge counts per motor revolution. #define DOP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0 ///< Maximum motor speed (RPM) while motor is commanded off. #define DOP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0 ///< Maximum difference in speed between motor and rotor (in rotor RPM). #define DOP_MAX_MOTOR_SPEED_ERROR_RPM 300.0 ///< Maximum difference in speed between measured and commanded RPM. /// Persist time (task intervals) for motor off error condition. static const U32 DOP_OFF_ERROR_PERSIST = ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) motor speed error condition. static const U32 DOP_MOTOR_SPEED_ERROR_PERSIST = ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) rotor speed error condition. static const U32 DOP_ROTOR_SPEED_ERROR_PERSIST = ((12 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) pump direction error condition. static const U32 DOP_DIRECTION_ERROR_PERSIST = (250 / TASK_PRIORITY_INTERVAL); #define DOP_MAX_CURR_WHEN_STOPPED_MA 150.0 ///< Motor controller current should not exceed this when pump should be stopped. #define DOP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DOP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. #define DOP_ADC_FULL_SCALE_V 3.0 ///< DPo analog signals are 0-3V (while int. ADC ref V may be different). #define DOP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. #define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DOP_ADC_ZERO ) ///< Macro converts a 12-bit ADC reading to a signed 16-bit value. #define DOP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor (3500 RPM/1998 counts). #define DOP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 BP motor RPM = 1% PWM duty cycle #define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. #define DOP_REV_PER_LITER 146.84 ///< Rotor revolutions per liter. #define DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DOP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to pump motor RPM. #define DOP_GEAR_RATIO 32.0 ///< Pump motor to pump gear ratio. #define DOP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. /// Macro converts a flow rate to an estimated PWM duty cycle %. #define DOP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DOP_GEAR_RATIO * DOP_MOTOR_RPM_TO_PWM_DC_FACTOR + DOP_PWM_ZERO_OFFSET ) /// Conversion from PWM duty cycle % to commanded pump motor speed. #define DOP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DOP_PWM_ZERO_OFFSET) * 4000.0 ) #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. /// Enumeration of dialysate outlet pump controller states. typedef enum DialOutPump_States { DIAL_OUT_PUMP_OFF_STATE = 0, ///< Off state of the dialysate outlet pump state machine. DIAL_OUT_PUMP_RAMPING_UP_STATE, ///< Ramping up state of the dialysate outlet pump state machine. DIAL_OUT_PUMP_RAMPING_DOWN_STATE, ///< Ramping down state of the dialysate outlet pump state machine. DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE, ///< Control state of the dialysate outlet pump state machine. NUM_OF_DIAL_OUT_PUMP_STATES ///< Number of dialysate outlet pump control states. } DIAL_OUT_PUMP_STATE_T; /// Enumeration of dialysate outlet pump self-test states. typedef enum DialOut_Pump_Self_Test_States { DIAL_OUT_PUMP_SELF_TEST_STATE_START = 0, ///< Start state of the dialysate outlet pump self-test state machine. DIAL_OUT_PUMP_TEST_STATE_IN_PROGRESS, ///< In progress state of the dialysate outlet pump self-test state machine. DIAL_OUT_PUMP_TEST_STATE_COMPLETE, ///< Completed state of the dialysate outlet pump self-test state machine. NUM_OF_DIAL_OUT_PUMP_SELF_TEST_STATES ///< Number of dialysate outlet pump self-test states. } DIAL_OUT_PUMP_SELF_TEST_STATE_T; // Pin assignments and macros for pump stop and direction outputs #define STOP_DO_PUMP_MIBSPI1_PORT_MASK 0x00000400 ///< MIBSPI1 SIMO[0] - re-purposed as GPIOoutput for pump controller run/stop pin. #define SET_DOP_STOP() {mibspiREG1->PC3 &= ~STOP_DO_PUMP_MIBSPI1_PORT_MASK;} ///< Macro sets pump controller run/stop signal to stop. #define CLR_DOP_STOP() {mibspiREG1->PC3 |= STOP_DO_PUMP_MIBSPI1_PORT_MASK;} ///< Macro sets pump controller run/stop signal to run. #define STOP_DO_PUMP_GIO_PORT_PIN 6U ///< GIO port A pin used for pump controller direction pin. #define SET_DOP_DIR() gioSetBit( gioPORTA, STOP_DO_PUMP_GIO_PORT_PIN, PIN_SIGNAL_HIGH ) ///< Macro sets pump controller direction to forward direction. #define CLR_DOP_DIR() gioSetBit( gioPORTA, STOP_DO_PUMP_GIO_PORT_PIN, PIN_SIGNAL_LOW ) ///< Macro sets pump controller direction to reverse direction. // ********** private data ********** static DIAL_OUT_PUMP_STATE_T dialOutPumpState = DIAL_OUT_PUMP_OFF_STATE; ///< Current state of the dialysate outlet pump controller state machine. static U32 dialOutFlowDataPublicationTimerCounter = 6; ///< Timer counter controlling when to publish dialysate outlet data. Set non-zero to phase data publication to CAN bus. static BOOL isDialOutPumpOn = FALSE; ///< Flag set to TRUE when dialysate outlet pump is running. static U32 lastGivenRate = 0; ///< Remembers the last given set point rate for the dialysate outlet pump. static F32 dialOutPumpPWMDutyCyclePct = 0.0; ///< Requested PWM duty cycle for dialysate outlet pump (based on given rate). static F32 dialOutPumpPWMDutyCyclePctSet = 0.0; ///< Currently set PWM duty cycle for dialysate outlet pump. static MOTOR_DIR_T dialOutPumpDirection = MOTOR_DIR_FORWARD; ///< Requested direction for dialysate outlet pump. static MOTOR_DIR_T dialOutPumpDirectionSet = MOTOR_DIR_FORWARD; ///< Currently set direction for dialysate outlet pump. static PUMP_CONTROL_MODE_T dialOutPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested control mode for dialysate outlet pump (open or closed loop). static PUMP_CONTROL_MODE_T dialOutPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set control mode for dialysate outlet pump. static OVERRIDE_U32_T dialOutDataPublishInterval = { DIAL_OUT_DATA_PUB_INTERVAL, DIAL_OUT_DATA_PUB_INTERVAL, DIAL_OUT_DATA_PUB_INTERVAL, 0 }; ///< Interval (in ms) at which to publish dialysate outlet data to CAN bus. static OVERRIDE_F32_T referenceUFVolumeInMl = { 0.0, 0.0, 0.0, 0 }; ///< Target ultrafiltration volume (in mL). static OVERRIDE_F32_T totalMeasuredUFVolumeInMl = { 0.0, 0.0, 0.0, 0 }; ///< Total measured ultrafiltration volume (in mL). static OVERRIDE_F32_T dialOutPumpMCSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump motor controller speed. static OVERRIDE_F32_T dialOutPumpMCCurrentmA = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump motor controller current. static OVERRIDE_F32_T dialOutPumpRotorSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump rotor speed. static OVERRIDE_F32_T dialOutPumpSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured dialysate outlet pump motor speed. static F32 offsetPWMDutyCyclePct = 0.0; ///< PWM duty cycle percentage offset to add to inlet pump duty cycle for UF control. static F32 dopMeasuredRate = 0.0; ///< Estimated flow rate for dialysate outlet pump. static F32 ufMeasuredRate = 0.0; ///< Calculated UF flow rate from measured dialysate flow rate subtracted from estimated dialysate outlet flow rate. static F32 dopRateCorrectionOffset = 0.0; ///< Correction offset for estimated flow rate for dialysate outlet pump. static U32 flowFilterTimerCtr = 0; ///< Timer counter for determining when to add a new sample to the moving average. static F64 flowReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds flow samples for a rolling average. static U32 flowReadingsIdx = 0; ///< Index for next sample in rolling average array. static F64 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average. static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer. static BOOL dopControlSignal = FALSE; ///< Control signal for syncing UF control to follow control interval of dialysate inlet pump. static U32 dopCurrErrorDurationCtr = 0; ///< Timer counter for motor current error persistence. static U32 dopRotorRevStartTime = 0; ///< Dialysate outlet pump rotor rotation start time (in ms) static BOOL dopStopAtHomePosition = FALSE; ///< Stop dialysate outlet pump at next home position static U32 dopHomeStartTime = 0; ///< When did dialysate outlet pump home command begin? (in ms) static U16 dopLastMotorHallSensorCounts[ DOP_SPEED_CALC_BUFFER__LEN ]; ///< Last hall sensor count for the dialysate outlet pump motor static U32 dopMotorSpeedCalcIdx = 0; ///< Index into 1 second buffer of motor speed hall sensor counts static U32 dopMotorSpeedCalcTimerCtr = 0; ///< Counter determines interval for calculating dialysate outlet pump motor speed from hall sensor count. static U32 errorDialOutMotorOffPersistTimerCtr = 0; ///< Persistence timer counter for motor off check error condition. static U32 errorDialOutMotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for motor speed error condition. static U32 errorDialOutRotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for rotor speed error condition. static U32 errorDialOutPumpDirectionPersistTimerCtr = 0; ///< Persistence timer counter for pump direction error condition. static U08 lastDialOutPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA // ********** private function prototypes ********** static DIAL_OUT_PUMP_STATE_T handleDialOutPumpOffState( void ); static DIAL_OUT_PUMP_STATE_T handleDialOutPumpRampingUpState( void ); static DIAL_OUT_PUMP_STATE_T handleDialOutPumpRampingDownState( void ); static DIAL_OUT_PUMP_STATE_T handleDialOutPumpControlToTargetState( void ); static void setDialOutPumpControlSignalPWM( F32 newPWM ); static void stopDialOutPump( void ); static void releaseDialOutPumpStop( void ); static void setDialOutPumpDirection( MOTOR_DIR_T dir ); static void publishDialOutFlowData( void ); static void updateDialOutPumpSpeedAndDirectionFromHallSensors( void ); static void checkDialOutPumpRotor( void ); static void checkDialOutPumpDirection( void ); static void checkDialOutPumpSpeeds( void ); static void checkDialOutPumpMCCurrent( void ); static void resetDialOutFlowMovingAverage( void ); static void filterDialOutFlowReadings( F64 flow ); /*********************************************************************//** * @brief * The initDialOutFlow function initializes the DialOutFlow module. * @details Inputs: none * @details Outputs: DialOutFlow module initialized. * @return none *************************************************************************/ void initDialOutFlow( void ) { U32 i; stopDialOutPump(); setDialOutPumpDirection( MOTOR_DIR_FORWARD ); // Zero motor hall sensors counts buffer dopMotorSpeedCalcIdx = 0; for ( i = 0; i < DOP_SPEED_CALC_BUFFER__LEN; i++ ) { dopLastMotorHallSensorCounts[ i ] = 0; } dopMeasuredRate = 0.0; ufMeasuredRate = 0.0; dopRateCorrectionOffset = 40.0; // TODO - set to 0.0 when we have a better dop flow estimate. resetDialOutFlowMovingAverage(); } /*********************************************************************//** * @brief * The setDialOutPumpTargetRate function sets a new target flow rate, pump * direction, and control mode. * @details Inputs: isDialOutPumpOn, dialOutPumpDirectionSet * @details Outputs: targetDialOutFlowRate, dialOutPumpdirection, dialOutPumpPWMDutyCyclePct * @param flowRate new target dialysate outlet flow rate * @param dir new dialysate outlet flow direction * @param mode new control mode * @return TRUE if new flow rate & dir are set, FALSE if not *************************************************************************/ BOOL setDialOutPumpTargetRate( U32 flowRate, MOTOR_DIR_T dir, PUMP_CONTROL_MODE_T mode ) { BOOL result = FALSE; // Direction change while pump is running is not allowed if ( ( FALSE == isDialOutPumpOn ) || ( 0 == flowRate ) || ( dir == dialOutPumpDirectionSet ) ) { F32 pwmDC = DOP_PWM_FROM_ML_PER_MIN( (F32)flowRate ); // Don't interrupt pump control unless rate or mode is changing if ( ( fabs( pwmDC - dialOutPumpPWMDutyCyclePct ) > NEARLY_ZERO ) || ( mode != dialOutPumpControlMode ) ) { #ifndef NO_PUMP_FLOW_LIMITS // Verify flow rate if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) #endif { resetDialOutFlowMovingAverage(); dopControlSignal = FALSE; lastGivenRate = flowRate; dialOutPumpDirection = dir; dialOutPumpControlMode = mode; // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed dialOutPumpPWMDutyCyclePct = pwmDC; dialOutPumpPWMDutyCyclePct = MIN( dialOutPumpPWMDutyCyclePct, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); switch ( dialOutPumpState ) { case DIAL_OUT_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp if ( dialOutPumpPWMDutyCyclePct < dialOutPumpPWMDutyCyclePctSet ) { dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; } break; case DIAL_OUT_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp if ( dialOutPumpPWMDutyCyclePct > dialOutPumpPWMDutyCyclePctSet ) { dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; } break; case DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction if ( dialOutPumpPWMDutyCyclePctSet > dialOutPumpPWMDutyCyclePct ) { dialOutPumpState = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; } else { dialOutPumpState = DIAL_OUT_PUMP_RAMPING_UP_STATE; } break; default: // Ok - not all states need to be handled here break; } result = TRUE; } #ifndef NO_PUMP_FLOW_LIMITS else // Requested flow rate too high { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) } #endif } } return result; } /*********************************************************************//** * @brief * The setDialOutUFVolumes function sets the ultrafiltration reference and * measured total volumes (in mL). * @details Inputs: none * @details Outputs: referenceUFVolumeInMl and totalMeasuredUFVolumeInMl * @param refVol New ultrafiltration reference volume (in mL) * @param totVol New ultrafiltration total volume (in mL) * @return none *************************************************************************/ void setDialOutUFVolumes( F32 refVol, F32 totVol ) { referenceUFVolumeInMl.data = refVol; totalMeasuredUFVolumeInMl.data = totVol; } /*********************************************************************//** * @brief * The signalDialOutPumpHardStop function stops the dialysate outlet pump * immediately. * @details Inputs: none * @details Outputs: Dialysate outlet pump stopped, set point reset, state changed to off * @return none *************************************************************************/ void signalDialOutPumpHardStop( void ) { lastGivenRate = 0; stopDialOutPump(); dialOutPumpState = DIAL_OUT_PUMP_OFF_STATE; dialOutPumpPWMDutyCyclePct = 0.0; resetDialOutFlowMovingAverage(); } /*********************************************************************//** * @brief * The signalDialOutPumpRotorHallSensor function handles the dialysate outlet * pump rotor hall sensor detection. Calculates rotor speed (in RPM). * Stops pump if there is a pending request to home the pump. * @details Inputs: dopRotorRevStartTime, dopStopAtHomePosition * @details Outputs: dopRotorRevStartTime, dialOutPumpRotorSpeedRPM * @return none *************************************************************************/ void signalDialOutPumpRotorHallSensor( void ) { U32 rotTime = getMSTimerCount(); U32 deltaTime = calcTimeBetween( dopRotorRevStartTime, rotTime ); // Calculate rotor speed (in RPM) dialOutPumpRotorSpeedRPM.data = ( 1.0 / (F32)deltaTime ) * (F32)MS_PER_SECOND * (F32)SEC_PER_MIN; dopRotorRevStartTime = rotTime; // If we are supposed to stop pump at home position, stop pump now. if ( TRUE == dopStopAtHomePosition ) { signalDialOutPumpHardStop(); dopStopAtHomePosition = FALSE; } } /*********************************************************************//** * @brief * The signalDialOutControl function signals the dialysate outlet pump to * perform a control. Call this function when dialysate inlet pump control * has completed. * @details Inputs: none * @details Outputs: dopControlSignal * @return none *************************************************************************/ void signalDialOutControl( void ) { dopControlSignal = TRUE; } /*********************************************************************//** * @brief * The resetDialOutFlowMovingAverage function resets the properties of the * dialysate outlet flow moving average sample buffer. * @details Inputs: none * @details Outputs: flowReadingsTotal, flowReadingsIdx, flowReadingsCount all set to zero. * @return none *************************************************************************/ static void resetDialOutFlowMovingAverage( void ) { flowReadingsIdx = 0; flowReadingsCount = 0; flowReadingsTotal = 0.0; offsetPWMDutyCyclePct = 0.0; } /*********************************************************************//** * @brief * The filterDialOutFlowReadings function adds a new flow sample to the filter. * @details Inputs: none * @details Outputs: flowReadings[], flowReadingsIdx, flowReadingsCount, flowReadingsTotal * @return none *************************************************************************/ static void filterDialOutFlowReadings( F64 flow ) { if ( flowReadingsCount >= SIZE_OF_ROLLING_AVG ) { flowReadingsTotal -= flowReadings[ flowReadingsIdx ]; } flowReadings[ flowReadingsIdx ] = flow; flowReadingsTotal += flow; flowReadingsIdx = INC_WRAP( flowReadingsIdx, 0, SIZE_OF_ROLLING_AVG - 1 ); flowReadingsCount = INC_CAP( flowReadingsCount, SIZE_OF_ROLLING_AVG ); dopMeasuredRate = (F32)( flowReadingsTotal / (F64)flowReadingsCount ) + dopRateCorrectionOffset; } /*********************************************************************//** * @brief * The homeDialOutPump function initiates a dialysate outlet pump home operation. * @details Inputs: dialOutPumpState * @details Outputs: dopStopAtHomePosition, dopHomeStartTime, dialysate outlet pump started (slow) * @return none *************************************************************************/ BOOL homeDialOutPump( void ) { BOOL result = FALSE; if ( DIAL_OUT_PUMP_OFF_STATE == dialOutPumpState ) { dopStopAtHomePosition = TRUE; dopHomeStartTime = getMSTimerCount(); result = setDialOutPumpTargetRate( DOP_HOME_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); } return result; } /*********************************************************************//** * @brief * The isDialOutPumpRunning function returns whether the dialysate outlet * pump is currently running or not. * @details Inputs: isDialOutPumpOn * @details Outputs: none * @return isDialOutPumpOn *************************************************************************/ BOOL isDialOutPumpRunning( void ) { return isDialOutPumpOn; } /*********************************************************************//** * @brief * The execDialOutFlowMonitor function executes the dialysate outlet pump * and load cell sensor monitor. Checks are performed. Data is published * at appropriate interval. * @details Inputs: latest sensor data * @details Outputs: dialOutPumpMCSpeedRPM, dialOutPumpMCCurrentmA * @return none *************************************************************************/ void execDialOutFlowMonitor( void ) { U16 bpRPM = getIntADCReading( INT_ADC_DIAL_OUT_PUMP_SPEED ); U16 bpmA = getIntADCReading( INT_ADC_DIAL_OUT_PUMP_MOTOR_CURRENT ); dialOutPumpMCSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpRPM)) * DOP_SPEED_ADC_TO_RPM_FACTOR; dialOutPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * DOP_CURRENT_ADC_TO_MA_FACTOR; // Calculate dialysate outlet pump motor speed/direction from hall sensor count updateDialOutPumpSpeedAndDirectionFromHallSensors(); // Filter estimated dialysate out flow rate and calculate UF rate if ( ++flowFilterTimerCtr >= DIAL_OUT_FILTER_INTERVAL ) { flowFilterTimerCtr = 0; // Calculate DPo flow in mL/min filterDialOutFlowReadings( getMeasuredDialOutPumpMCSpeed() * RPM_2_ML_MIN_CONVERSION ); // Calculate UF flow in mL/min ufMeasuredRate = dopMeasuredRate - getMeasuredDialInFlowRate(); } // Do not start enforcing checks until out of init/POST mode if ( getCurrentOperationMode() != MODE_INIT ) { // Check pump direction checkDialOutPumpDirection(); // Check pump controller current checkDialOutPumpMCCurrent(); // Check pump speeds checkDialOutPumpSpeeds(); // Check for home position, zero/low speed checkDialOutPumpRotor(); } publishDialOutFlowData(); } /*********************************************************************//** * @brief * The execDialOutFlowController function executes the dialysate outlet pump * ultrafiltration controller state machine. * @details Inputs: dialOutPumpState * @details Outputs: dialOutPumpState * @return none *************************************************************************/ void execDialOutFlowController( void ) { switch ( dialOutPumpState ) { case DIAL_OUT_PUMP_OFF_STATE: dialOutPumpState = handleDialOutPumpOffState(); break; case DIAL_OUT_PUMP_RAMPING_UP_STATE: dialOutPumpState = handleDialOutPumpRampingUpState(); break; case DIAL_OUT_PUMP_RAMPING_DOWN_STATE: dialOutPumpState = handleDialOutPumpRampingDownState(); break; case DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE: dialOutPumpState = handleDialOutPumpControlToTargetState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_STATE, dialOutPumpState ); break; } } /*********************************************************************//** * @brief * The handleDialOutPumpOffState function handles the dialOut pump off state * of the dialOut pump controller state machine. * @details Inputs: targetDialOutFlowRate, dialOutPumpDirection * @details Outputs: dialOutPumpPWMDutyCyclePctSet, dialOutPumpDirectionSet, isDialOutPumpOn * @return next state *************************************************************************/ static DIAL_OUT_PUMP_STATE_T handleDialOutPumpOffState( void ) { DIAL_OUT_PUMP_STATE_T result = DIAL_OUT_PUMP_OFF_STATE; // If we have been given a flow rate, setup ramp up and transition to ramp up state if ( lastGivenRate > 0 ) { // Set initial PWM duty cycle dialOutPumpPWMDutyCyclePctSet = DOP_PWM_ZERO_OFFSET + MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); // Allow dialOut pump to run in requested direction setDialOutPumpDirection( dialOutPumpDirection ); releaseDialOutPumpStop(); isDialOutPumpOn = TRUE; result = DIAL_OUT_PUMP_RAMPING_UP_STATE; } else { dialOutPumpPWMDutyCyclePct = 0.0; } return result; } /*********************************************************************//** * @brief * The handleDialOutPumpRampingUpState function handles the ramp up state * of the dialOut pump controller state machine. * @details Inputs: dialOutPumpPWMDutyCyclePctSet * @details Outputs: dialOutPumpPWMDutyCyclePctSet * @return next state *************************************************************************/ static DIAL_OUT_PUMP_STATE_T handleDialOutPumpRampingUpState( void ) { DIAL_OUT_PUMP_STATE_T result = DIAL_OUT_PUMP_RAMPING_UP_STATE; // Have we been asked to stop the dialOut pump? if ( dialOutPumpPWMDutyCyclePct < (MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE + DOP_PWM_ZERO_OFFSET) ) { // Start ramp down to stop dialOutPumpPWMDutyCyclePctSet -= MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); result = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; } // Have we reached end of ramp up? else if ( dialOutPumpPWMDutyCyclePctSet >= dialOutPumpPWMDutyCyclePct ) { dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; dialOutPumpControlModeSet = dialOutPumpControlMode; resetDialOutFlowMovingAverage(); setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp up else { dialOutPumpPWMDutyCyclePctSet += MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } return result; } /*********************************************************************//** * @brief * The handleDialOutPumpRampingDownState function handles the ramp down state * of the dialOut pump controller state machine. * @details Inputs: dialOutPumpPWMDutyCyclePctSet * @details Outputs: dialOutPumpPWMDutyCyclePctSet * @return next state *************************************************************************/ static DIAL_OUT_PUMP_STATE_T handleDialOutPumpRampingDownState( void ) { DIAL_OUT_PUMP_STATE_T result = DIAL_OUT_PUMP_RAMPING_DOWN_STATE; // Have we essentially reached zero speed? if ( dialOutPumpPWMDutyCyclePctSet < (MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE + DOP_PWM_ZERO_OFFSET) ) { stopDialOutPump(); result = DIAL_OUT_PUMP_OFF_STATE; } // Have we reached end of ramp down? else if ( dialOutPumpPWMDutyCyclePctSet <= dialOutPumpPWMDutyCyclePct ) { dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; dialOutPumpControlModeSet = dialOutPumpControlMode; resetDialOutFlowMovingAverage(); setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp down else { dialOutPumpPWMDutyCyclePctSet -= MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } return result; } /*********************************************************************//** * @brief * The handleDialOutPumpControlToTargetState function handles the "control to * target" state of the dialOut pump controller state machine. * @details Inputs: dopControlTimerCounter, dialOutPumpControlModeSet, volumes. * @details Outputs: dopControlTimerCounter, pump controlled. * @return next state *************************************************************************/ static DIAL_OUT_PUMP_STATE_T handleDialOutPumpControlToTargetState( void ) { DIAL_OUT_PUMP_STATE_T result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; // Control when signalled (sync'd with dialysate inlet pump control - we want this control to follow inlet pump) if ( TRUE == dopControlSignal ) { if ( dialOutPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) { F32 refVol = getTotalTargetDialOutUFVolumeInMl(); F32 totVol = getTotalMeasuredUFVolumeInMl(); F32 volErr = refVol - totVol; F32 ufrErr = getCurrentUFSetRate() - ufMeasuredRate; dopControlSignal = FALSE; dopRateCorrectionOffset += ( ( totVol - refVol ) * P_CORR ); offsetPWMDutyCyclePct += volErr * P_VOL; offsetPWMDutyCyclePct += ( ufrErr * P_UF ); // Add PWM offset to DPi PWM mirror for our new DPo PWM dialOutPumpPWMDutyCyclePctSet = getDialInPumpPWMDutyCyclePct( FALSE ) + offsetPWMDutyCyclePct; // Limit PWM range dialOutPumpPWMDutyCyclePctSet = MIN( dialOutPumpPWMDutyCyclePctSet, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); dialOutPumpPWMDutyCyclePctSet = MAX( dialOutPumpPWMDutyCyclePctSet, MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); // Apply new PWM to DPo pump setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } } return result; } /*********************************************************************//** * @brief * The setDialOutPumpControlSignalPWM function set the PWM duty cycle of * the dialysate outlet pump to a given %. * @details Inputs: none * @details Outputs: dialysis outlet pump PWM duty cycle is set. * @param newPWM A percentage duty cycle between 0.0 and 1.0 * @return none *************************************************************************/ static void setDialOutPumpControlSignalPWM( F32 newPWM ) { etpwmSetCmpA( etpwmREG3, (U32)( (S32)( ( newPWM * (F32)(etpwmREG3->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } /*********************************************************************//** * @brief * The stopDialOutPump function sets the dialout flow stop signal and PWM * duty cycle to 0.0. * @details Inputs: none * @details Outputs: dialOut pump stop signal activated, PWM duty cycle zeroed * @return none *************************************************************************/ static void stopDialOutPump( void ) { dialOutPumpPWMDutyCyclePctSet = DOP_PWM_ZERO_OFFSET; setDialOutPumpControlSignalPWM( 0 ); SET_DOP_STOP(); isDialOutPumpOn = FALSE; } /*********************************************************************//** * @brief * The releaseDialOutPumpStop function clears the dialysate outlet pump stop signal. * @details Inputs: none * @details Outputs: dialysate outlet pump stop signal is cleared. * @return none *************************************************************************/ static void releaseDialOutPumpStop( void ) { CLR_DOP_STOP(); } /*********************************************************************//** * @brief * The setDialOutPumpDirection function sets the set dialOut pump direction to * the given direction. * @details Inputs: none * @details Outputs: dialOutPumpDirectionSet, pump direction signal set to match given direction. * @param dir dialysate outlet pump direction to set * @return none *************************************************************************/ static void setDialOutPumpDirection( MOTOR_DIR_T dir ) { switch ( dir ) { case MOTOR_DIR_FORWARD: dialOutPumpDirectionSet = dir; SET_DOP_DIR(); break; case MOTOR_DIR_REVERSE: dialOutPumpDirectionSet = dir; CLR_DOP_DIR(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_DIRECTION, dir ); break; } } /*********************************************************************//** * @brief * The publishDialOutFlowData function publishes dialysate outlet data at * the set interval. * @details Inputs: Dialysate outlet pump data * @details Outputs: Dialysate outlet pump data is published to CAN bus. * @return none *************************************************************************/ static void publishDialOutFlowData( void ) { // Publish dialysate outlet pump and UF volume data on interval if ( ++dialOutFlowDataPublicationTimerCounter >= getU32OverrideValue( &dialOutDataPublishInterval ) ) { DIAL_OUT_FLOW_DATA_T dialOutBroadCastVariables; dialOutBroadCastVariables.refUFVolMl = getTotalTargetDialOutUFVolumeInMl(); dialOutBroadCastVariables.measUFVolMl = getTotalMeasuredUFVolumeInMl(); dialOutBroadCastVariables.measRotSpdRPM = getMeasuredDialOutPumpRotorSpeed(); #if 1 // TODO - remove test code dialOutBroadCastVariables.measSpdRPM = ufMeasuredRate; #else dialOutBroadCastVariables.measSpdRPM = getMeasuredDialOutPumpSpeed(); #endif dialOutBroadCastVariables.measMCSpdRPM = getMeasuredDialOutPumpMCSpeed(); dialOutBroadCastVariables.measMCCurrmA = getMeasuredDialOutPumpMCCurrent(); dialOutBroadCastVariables.setPWMpct = dialOutPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; broadcastData( MSG_ID_DIALYSATE_OUT_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&dialOutBroadCastVariables, sizeof( DIAL_OUT_FLOW_DATA_T ) ); dialOutFlowDataPublicationTimerCounter = 0; } } /*********************************************************************//** * @brief * The updateDialOutPumpSpeedAndDirectionFromHallSensors function calculates * the dialysate outlet pump motor speed and direction from hall sensor counter on * a 1 second interval. * @details Inputs: dopLastMotorHallSensorCount, dopMotorSpeedCalcTimerCtr, current count from FPGA * @details Outputs: dopMotorDirectionFromHallSensors, dialOutPumpSpeedRPM * @return none *************************************************************************/ static void updateDialOutPumpSpeedAndDirectionFromHallSensors( void ) { if ( ++dopMotorSpeedCalcTimerCtr >= DOP_SPEED_CALC_INTERVAL ) { U16 dopMotorHallSensorCount = getFPGADialOutPumpHallSensorCount(); U32 nextIdx = INC_WRAP( dopMotorSpeedCalcIdx, 0, DOP_SPEED_CALC_BUFFER__LEN - 1 ); U16 incDelta = ( dopMotorHallSensorCount >= dopLastMotorHallSensorCounts[ nextIdx ] ? \ dopMotorHallSensorCount - dopLastMotorHallSensorCounts[ nextIdx ] : \ ( HEX_64_K - dopLastMotorHallSensorCounts[ nextIdx ] ) + dopMotorHallSensorCount ); U16 decDelta = HEX_64_K - incDelta; U16 delta; // Determine dialysate outlet pump speed/direction from delta hall sensor count since last interval if ( incDelta < decDelta ) { delta = incDelta; dialOutPumpSpeedRPM.data = ( (F32)delta / (F32)DOP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; } else { delta = decDelta; dialOutPumpSpeedRPM.data = ( (F32)delta / (F32)DOP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN * -1.0; } // Update last count for next time dopLastMotorHallSensorCounts[ nextIdx ] = dopMotorHallSensorCount; dopMotorSpeedCalcIdx = nextIdx; dopMotorSpeedCalcTimerCtr = 0; } } /*********************************************************************//** * @brief * The checkDialOutPumpRotor function checks the rotor for the dialysate outlet * pump. If homing, this function will stop when hall sensor detected. If pump * is off or running very slowly, rotor speed will be set to zero. * @details Inputs: dopStopAtHomePosition, dopHomeStartTime, dopRotorRevStartTime * @details Outputs: pump may be stopped if homing, dialOutPumpRotorSpeedRPM may be set to zero. * @return none *************************************************************************/ static void checkDialOutPumpRotor( void ) { // If homing, check timeout if ( ( TRUE == dopStopAtHomePosition ) && ( TRUE == didTimeout( dopHomeStartTime, DOP_HOME_TIMEOUT_MS ) ) ) { signalDialOutPumpHardStop(); dopStopAtHomePosition = FALSE; // TODO - alarm??? } // If pump is stopped or running very slowly, set rotor speed to zero if ( TRUE == didTimeout( dopRotorRevStartTime, DOP_HOME_TIMEOUT_MS ) ) { dialOutPumpRotorSpeedRPM.data = 0.0; } } /*********************************************************************//** * @brief * The checkDialOutPumpDirection function checks the set direction vs. * the direction implied by the sign of the measured MC speed. * @details Inputs: adcDialOutPumpMCSpeedRPM, dialOutPumpDirectionSet, dialOutPumpState * @details Outputs: none * @return none *************************************************************************/ static void checkDialOutPumpDirection( void ) { if ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ) { MOTOR_DIR_T dopMCDir, dopDir; U08 dirErrorCnt = getFPGADialOutPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; // Check pump direction error count if ( lastDialOutPumpDirectionCount != dirErrorCnt ) { lastDialOutPumpDirectionCount = dirErrorCnt; #ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_OUTLET_PUMP ) #endif } dopMCDir = ( getMeasuredDialOutPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); dopDir = ( getMeasuredDialOutPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); // Check set direction vs. direction from hall sensors if ( dialOutPumpDirectionSet != dopDir ) { if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopDir ) #endif } } // Check set direction vs. direction from sign of motor controller speed else if ( dialOutPumpDirectionSet != dopMCDir ) { if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopMCDir ) #endif } } else { errorDialOutPumpDirectionPersistTimerCtr = 0; } } else { errorDialOutPumpDirectionPersistTimerCtr = 0; } } /*********************************************************************//** * @brief * The checkDialOutPumpSpeeds function checks several aspects of the dialysate * outlet pump speed. * 1. while pump is commanded off, measured motor speed should be < limit. * 2. while pump is controlling, measured motor speed should be within allowed range of measured motor controller speed. * 3. measured motor speed should be within allowed range of measured rotor speed. * All 3 checks have a persistence time that must be met before an alarm is triggered. * @details Inputs: targetDialOutFlowRate, dialOutPumpSpeedRPM, dialOutPumpRotorSpeedRPM * @details Outputs: alarm(s) may be triggered * @return none *************************************************************************/ static void checkDialOutPumpSpeeds( void ) { F32 measMotorSpeed = getMeasuredDialOutPumpSpeed(); F32 measMCMotorSpeed = fabs( getMeasuredDialOutPumpMCSpeed() ); // Check for pump running while commanded off if ( dialOutPumpPWMDutyCyclePctSet <= DOP_PWM_ZERO_OFFSET ) { if ( measMotorSpeed > DOP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) { if ( ++errorDialOutMotorOffPersistTimerCtr >= DOP_OFF_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); #endif } } else { errorDialOutMotorOffPersistTimerCtr = 0; } } else { errorDialOutMotorOffPersistTimerCtr = 0; } if ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ) { F32 cmdMotorSpeed = DOP_PWM_TO_MOTOR_SPEED_RPM( dialOutPumpPWMDutyCyclePctSet ); F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); F32 measRotorSpeed = getMeasuredDialOutPumpRotorSpeed(); F32 measMotorSpeedInRotorRPM = measMotorSpeed / DOP_GEAR_RATIO; F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); // Check measured motor speed vs. commanded motor speed while controlling to target if ( ( deltaMotorSpeed > DOP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > DOP_MAX_MOTOR_SPEED_ERROR_RPM ) ) { if ( ++errorDialOutMotorSpeedPersistTimerCtr >= DOP_MOTOR_SPEED_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); #endif } } else { errorDialOutMotorSpeedPersistTimerCtr = 0; } // Check measured rotor speed vs. measured motor speed while controlling to target if ( deltaRotorSpeed > DOP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) { if ( ++errorDialOutRotorSpeedPersistTimerCtr >= DOP_ROTOR_SPEED_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); #endif } } else { errorDialOutRotorSpeedPersistTimerCtr = 0; } } else { errorDialOutMotorSpeedPersistTimerCtr = 0; errorDialOutRotorSpeedPersistTimerCtr = 0; } } /*********************************************************************//** * @brief * The checkDialOutPumpMCCurrent function checks the measured MC current vs. * the set state of the dialOut pump (stopped or running). * @details Inputs: dialOutPumpState, dopCurrErrorDurationCtr, adcDialOutPumpMCCurrentmA * @details Outputs: none * @return none *************************************************************************/ static void checkDialOutPumpMCCurrent( void ) { F32 dopCurr; // DialOut pump should be off if ( DIAL_OUT_PUMP_OFF_STATE == dialOutPumpState ) { dopCurr = fabs( getMeasuredDialOutPumpMCCurrent() ); if ( dopCurr > DOP_MAX_CURR_WHEN_STOPPED_MA ) { dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) { #ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); #endif } } else { dopCurrErrorDurationCtr = 0; } } // DialOut pump should be running else { dopCurr = fabs( getMeasuredDialOutPumpMCCurrent() ); if ( dopCurr > DOP_MAX_CURR_WHEN_RUNNING_MA ) { dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) { #ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); #endif } } else { dopCurrErrorDurationCtr = 0; } } } /************************************************************************* * GET SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The getTotalTargetDialOutUFVolumeInMl function gets the target UF volume. * @details Inputs: referenceUFVolumeInMl * @details Outputs: none * @return the current target UF volume in mL. *************************************************************************/ F32 getTotalTargetDialOutUFVolumeInMl( void ) { F32 result = referenceUFVolumeInMl.data; if ( OVERRIDE_KEY == referenceUFVolumeInMl.override ) { result = referenceUFVolumeInMl.ovData; } return result; } /*********************************************************************//** * @brief * The getTotalMeasuredUFVolumeInMl function gets the measured UF volume. * @details Inputs: totalMeasuredUFVolumeInMl * @details Outputs: none * @return the current UF volume (in mL). *************************************************************************/ F32 getTotalMeasuredUFVolumeInMl( void ) { F32 result = totalMeasuredUFVolumeInMl.data; if ( OVERRIDE_KEY == totalMeasuredUFVolumeInMl.override ) { result = totalMeasuredUFVolumeInMl.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialOutPumpRotorSpeed function gets the measured dialysate * outlet pump rotor speed. * @details Inputs: dialOutPumpRotorSpeedRPM * @details Outputs: none * @return the current dialysate outlet pump rotor speed (in RPM). *************************************************************************/ F32 getMeasuredDialOutPumpRotorSpeed( void ) { F32 result = dialOutPumpRotorSpeedRPM.data; if ( OVERRIDE_KEY == dialOutPumpRotorSpeedRPM.override ) { result = dialOutPumpRotorSpeedRPM.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialOutPumpSpeed function gets the measured dialysate outlet * pump motor speed. * @details Inputs: dialOutPumpSpeedRPM * @details Outputs: none * @return the current dialysate outlet pump motor speed (in RPM). *************************************************************************/ F32 getMeasuredDialOutPumpSpeed( void ) { F32 result = dialOutPumpSpeedRPM.data; if ( OVERRIDE_KEY == dialOutPumpSpeedRPM.override ) { result = dialOutPumpSpeedRPM.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialOutPumpMCSpeed function gets the measured dialOut pump * speed. * @details Inputs: dialOutPumpMCSpeedRPM * @details Outputs: none * @return the current dialOut pump speed (in RPM). *************************************************************************/ F32 getMeasuredDialOutPumpMCSpeed( void ) { F32 result = dialOutPumpMCSpeedRPM.data; if ( OVERRIDE_KEY == dialOutPumpMCSpeedRPM.override ) { result = dialOutPumpMCSpeedRPM.ovData; } return result; } /*********************************************************************//** * @brief * The getMeasuredDialOutPumpMCCurrent function gets the measured dialOut pump * current. * @details Inputs: dialOutPumpMCCurrentmA * @details Outputs: none * @return the current dialOut pump current (in mA). *************************************************************************/ F32 getMeasuredDialOutPumpMCCurrent( void ) { F32 result = dialOutPumpMCCurrentmA.data; if ( OVERRIDE_KEY == dialOutPumpMCCurrentmA.override ) { result = dialOutPumpMCCurrentmA.ovData; } return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetDialOutPumpAndLoadCellDataPublishIntervalOverride function overrides the * dialout data publish interval. * @details Inputs: none * @details Outputs: dialOutDataPublishInterval * @param value override dialout data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialOutPumpAndLoadCellDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; dialOutDataPublishInterval.ovData = intvl; dialOutDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetDialOutPumpAndLoadCellDataPublishIntervalOverride function resets the override * of the dialout data publish interval. * @details Inputs: none * @details Outputs: dialOutDataPublishInterval * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutPumpAndLoadCellDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutDataPublishInterval.override = OVERRIDE_RESET; dialOutDataPublishInterval.ovData = dialOutDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetTargetDialOutFlowRateOverride function overrides the target * dialysate outlet flow rate. * @details Inputs: none * @details Outputs: pump started w/ set target rate and control mode * @param value override target dialysate outlet flow rate (in mL/min) * @param ctrlMode override pump control mode to this mode (0 = closed loop, 1 = open loop) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetTargetDialOutFlowRateOverride( S32 value, U32 ctrlMode ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { MOTOR_DIR_T dir; if ( value < 0 ) { dir = MOTOR_DIR_REVERSE; } else { dir = MOTOR_DIR_FORWARD; } if ( ctrlMode < NUM_OF_PUMP_CONTROL_MODES ) { result = setDialOutPumpTargetRate( abs(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); } } return result; } /*********************************************************************//** * @brief * The testSetDialOutUFRefVolumeOverride function overrides the target * dialout vol rate. * @details Inputs: referenceUFVolumeInMl * @details Outputs: referenceUFVolumeInMl * @param value override target dialout vol rate (in mL/min) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialOutUFRefVolumeOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; referenceUFVolumeInMl.ovData = value; referenceUFVolumeInMl.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetDialOutUFRefVolumeOverride function resets the override of the * target dialout vol rate. * @details Inputs: referenceUFVolumeInMl * @details Outputs: referenceUFVolumeInMl * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFRefVolumeOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; referenceUFVolumeInMl.override = OVERRIDE_RESET; referenceUFVolumeInMl.ovData = referenceUFVolumeInMl.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetDialOutUFTotVolumeOverride function overrides the measured * dialout vol rate. * @details Inputs: totalMeasuredUFVolumeInMl * @details Outputs: totalMeasuredUFVolumeInMl * @param value override measured dialout vol rate (in mL/min) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialOutUFTotVolumeOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; totalMeasuredUFVolumeInMl.ovData = value; totalMeasuredUFVolumeInMl.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetDialOutUFTotVolumeOverride function resets the override of the * measured dialout vol rate. * @details Inputs: totalMeasuredUFVolumeInMl * @details Outputs: totalMeasuredUFVolumeInMl * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFTotVolumeOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; totalMeasuredUFVolumeInMl.override = OVERRIDE_RESET; totalMeasuredUFVolumeInMl.ovData = totalMeasuredUFVolumeInMl.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetMeasuredDialOutPumpRotorSpeedOverride function overrides the measured * dialOut pump rotor speed. * @details Inputs: DialOutPumpRotorSpeedRPM * @details Outputs: DialOutPumpRotorSpeedRPM * @param value override measured dialOut pump rotor speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetMeasuredDialOutPumpRotorSpeedOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpRotorSpeedRPM.ovData = value; dialOutPumpRotorSpeedRPM.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetMeasuredDialOutPumpRotorSpeedOverride function resets the override of the * measured dialOut pump rotor speed. * @details Inputs: DialOutPumpRotorSpeedRPM * @details Outputs: DialOutPumpRotorSpeedRPM * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpRotorSpeedOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpRotorSpeedRPM.override = OVERRIDE_RESET; dialOutPumpRotorSpeedRPM.ovData = dialOutPumpRotorSpeedRPM.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetMeasuredDialOutPumpSpeedOverride function overrides the measured * dialOut pump motor speed. * @details Inputs: dialOutPumpSpeedRPM * @details Outputs: dialOutPumpSpeedRPM * @param value override measured dialOut pump motor speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetMeasuredDialOutPumpSpeedOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpSpeedRPM.ovData = value; dialOutPumpSpeedRPM.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetMeasuredDialOutPumpSpeedOverride function resets the override of the * measured dialOut pump motor speed. * @details Inputs: dialOutPumpSpeedRPM * @details Outputs: dialOutPumpSpeedRPM * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpSpeedOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpSpeedRPM.override = OVERRIDE_RESET; dialOutPumpSpeedRPM.ovData = dialOutPumpSpeedRPM.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetMeasuredDialOutPumpMCSpeedOverride function overrides the measured * dialOut pump motor speed. * @details Inputs: dialOutPumpMCSpeedRPM * @details Outputs: dialOutPumpMCSpeedRPM * @param value override measured dialOut pump speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetMeasuredDialOutPumpMCSpeedOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpMCSpeedRPM.ovData = value; dialOutPumpMCSpeedRPM.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetMeasuredDialOutPumpMCSpeedOverride function resets the override of the * measured dialOut pump motor speed. * @details Inputs: dialOutPumpMCSpeedRPM * @details Outputs: dialOutPumpMCSpeedRPM * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpMCSpeedOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpMCSpeedRPM.override = OVERRIDE_RESET; dialOutPumpMCSpeedRPM.ovData = dialOutPumpMCSpeedRPM.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetMeasuredDialOutPumpMCCurrentOverride function overrides the measured * dialOut pump motor current. * @details Inputs: dialOutPumpMCCurrentmA * @details Outputs: dialOutPumpMCCurrentmA * @param value override measured dialOut pump current (in mA) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetMeasuredDialOutPumpMCCurrentOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpMCCurrentmA.ovData = value; dialOutPumpMCCurrentmA.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetMeasuredDialOutPumpMCCurrentOverride function resets the override of the * measured dialOut pump motor current. * @details Inputs: dialOutPumpMCCurrentmA * @details Outputs: dialOutPumpMCCurrentmA * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpMCCurrentOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; dialOutPumpMCCurrentmA.override = OVERRIDE_RESET; dialOutPumpMCCurrentmA.ovData = dialOutPumpMCCurrentmA.ovInitData; } return result; } /**@}*/