Index: firmware/App/Controllers/DialOutFlow.c =================================================================== diff -u -r94895e32fe18e78b98fe3bb7786838cf00afdbfa -r45627442c3b93ec57ed18cd0943eed2662fb2dbc --- firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 94895e32fe18e78b98fe3bb7786838cf00afdbfa) +++ firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 45627442c3b93ec57ed18cd0943eed2662fb2dbc) @@ -1,36 +1,39 @@ -/**********************************************************************//** - * - * Copyright (c) 2020-2020 Diality Inc. - All Rights Reserved. - * - * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN - * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. - * - * @file DialOutFlow.c - * - * @date 22-Jan-2020 - * @author S. Nash - * - * @brief Monitor/Controller for dialysate outlet pump and load cell sensor. - * - **************************************************************************/ +/************************************************************************** +* +* Copyright (c) 2020-2022 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) Dara Navaei +* @date (last) 15-Jun-2022 +* +* @author (original) Sean +* @date (original) 24-Jan-2020 +* +***************************************************************************/ -#ifndef _VECTORCAST_ - #include -#endif +#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 "NVDataMgmt.h" #include "OperationModes.h" +#include "PersistentAlarm.h" #include "PIControllers.h" +#include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" -#include "DialOutFlow.h" /** * @addtogroup DialysateOutlet @@ -39,39 +42,76 @@ // ********** private definitions ********** -#define DIAL_OUT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the dialysate outlet pump data is published on the CAN bus. +/// 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_CHANGE 0.01 ///< Maximum duty cycle change when ramping. -#define MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.88 ///< Controller will error if PWM duty cycle > 90%, so set max to 88%. -#define MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.12 ///< Controller will error if PWM duty cycle < 10%, so set min to 12%. +#define MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE 0.0133F ///< Maximum duty cycle change when ramping up ~ 200 mL/min/s. +#define MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE 0.02F ///< Maximum duty cycle change when ramping down ~ 300 mL/min/s. +#define MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.89F ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. +#define MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.10F ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. +#define MAX_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL 0.4F ///< Maximum PWM offset (added to DPi PWM duty cycle). +#define MIN_DIAL_OUT_PUMP_PWM_OFFSET_CONTROL -0.4F ///< Minimum PWM offset (added to DPi PWM duty cycle). -#define DOP_CONTROL_INTERVAL ( 1000 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the dialysate outlet pump is controlled. -#define DOP_P_COEFFICIENT 0.0050 ///< P term for dialysate outlet pump control. -#define DOP_I_COEFFICIENT 0.0001 ///< I term for dialysate outlet pump control. +#define P_VOL 0.001F ///< P term for volume error feedback into dialysate outlet pump control. +#define P_UF 0.001F ///< P term for UF rate error feedback into dialysate outlet pump control. +#define P_CORR 0.1666F ///< P term for volume error feedback into dialysate outlet pump flow estimate correction offset. -#define DOP_MAX_CURR_WHEN_STOPPED_MA 150.0 ///< Motor controller current should not exceed this when pump should be stopped. -#define DOP_MIN_CURR_WHEN_RUNNING_MA 150.0 ///< Motor controller current should always exceed this when pump should be running. -#define DOP_MAX_CURR_WHEN_RUNNING_MA 1000.0 ///< Motor controller current should not exceed this when pump should be running. +#define RPM_2_ML_MIN_CONVERSION 0.215964F ///< 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.0F ///< Maximum motor speed (RPM) while motor is commanded off. +#define DOP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0F ///< Maximum difference in speed between motor and rotor (in rotor RPM). +#define DOP_MAX_MOTOR_SPEED_ERROR_RPM 300.0F ///< 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.0F ///< Motor controller current should not exceed this when pump should be stopped. +#define DOP_MAX_CURR_WHEN_RUNNING_MA 2000.0F ///< 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_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor. -#define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. -#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 ( (F32)( INT_ADC_ZERO ) * ( DOP_ADC_FULL_SCALE_V / INT_ADC_REF_V ) ) ///< Mid-point (zero) for ADC readings. +#define DOP_ADC_FULL_SCALE_V 3.0F ///< 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.000238F ///< ~42 BP motor RPM = 1% PWM duty cycle +#define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002F ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. -/*** setDialOutFlowRxTotalVolumeAndRxTime ***/ -#define DOP_REV_PER_LITER 150.24 ///< Rotor revolutions per liter. +#define DOP_REV_PER_LITER 146.84F ///< 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_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00035 ///< ~28 DPo motor RPM = 1% PWM duty cycle. -#define DOP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. -#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 ) ///< Macro converts a flow rate to an estimated PWM duty cycle %. +#define DOP_GEAR_RATIO 32.0F ///< Pump motor to pump gear ratio. +#define DOP_PWM_ZERO_OFFSET 0.1F ///< 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) * 0.0009 ) + 0.0972 + 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.0F ) + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define DATA_PUBLISH_COUNTER_START_COUNT 40 ///< Data publish counter start count. + /// Enumeration of dialysate outlet pump controller states. typedef enum DialOutPump_States { @@ -82,42 +122,36 @@ 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. +/// 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 pumpt 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 +// 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. -#ifndef BREADBOARD_TARGET - #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. -#else - #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. -#endif -#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. +#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 U32 dialOutFlowDataPublicationTimerCounter; ///< 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.0; ///< Remembers the last given set point rate for the dialysate outlet pump. +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_F32_T loadCellWeightInGrams[ NUM_OF_LOAD_CELLS ]; ///< Measured weight from load cells. 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). @@ -126,15 +160,37 @@ 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 U32 dopControlTimerCounter = 0; ///< Timer counter to determine when to control dialysate outlet pump. +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 DIAL_OUT_PUMP_SELF_TEST_STATE_T dialOutPumpSelfTestState = DIAL_OUT_PUMP_SELF_TEST_STATE_START; ///< Current state of the dialysate outlet pump self test state machine. -static U32 dialOutPumpSelfTestTimerCount = 0; ///< Timer counter for time reference during self test. +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) -// Broadcasting record -DIAL_OUT_FLOW_DATA_T dialOutBroadCastVariables; ///< Record containing latest dialysate outlet data for broadcasting. +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. +static HD_PUMPS_CAL_RECORD_T dialOutPumpCalRecord; ///< Dialysate outlet calibration record. + // ********** private function prototypes ********** static DIAL_OUT_PUMP_STATE_T handleDialOutPumpOffState( void ); @@ -149,123 +205,144 @@ 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 DATA_GET_PROTOTYPE( U32, getPublishDialOutDataInterval ); +static void resetDialOutFlowMovingAverage( void ); +static void filterDialOutFlowReadings( F64 flow ); /*********************************************************************//** * @brief * The initDialOutFlow function initializes the DialOutFlow module. - * @details - * Inputs : none - * Outputs : DialOutFlow module initialized. + * @details Inputs: none + * @details Outputs: dialOutFlowDataPublicationTimerCounter * @return none *************************************************************************/ void initDialOutFlow( void ) { U32 i; - stopDialOutPump(); + dialOutFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + signalDialOutPumpHardStop(); setDialOutPumpDirection( MOTOR_DIR_FORWARD ); - // initialize load cell weights - for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) + // Zero motor hall sensors counts buffer + dopMotorSpeedCalcIdx = 0; + for ( i = 0; i < DOP_SPEED_CALC_BUFFER__LEN; i++ ) { - loadCellWeightInGrams[ i ].data = 0.0; + dopLastMotorHallSensorCounts[ i ] = getFPGADialOutPumpHallSensorCount(); } - // initialize broadcast data - dialOutBroadCastVariables.refUFVolMl = 0.0; - dialOutBroadCastVariables.measUFVolMl = 0.0; - dialOutBroadCastVariables.measRotSpdRPM = 0.0; - dialOutBroadCastVariables.measSpdRPM = 0.0; - dialOutBroadCastVariables.measMCSpdRPM = 0.0; - dialOutBroadCastVariables.measMCCurrmA = 0.0; - dialOutBroadCastVariables.setPWMpct = 0.0; - - // initialize dialysate outlet flow PI controller - initializePIController( PI_CONTROLLER_ID_ULTRAFILTRATION, MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE, - DOP_P_COEFFICIENT, DOP_I_COEFFICIENT, - MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); + dopMeasuredRate = 0.0; + ufMeasuredRate = 0.0; + dopRateCorrectionOffset = 0.0; + resetDialOutFlowMovingAverage(); } /*********************************************************************//** * @brief - * The setDialOutPumpTargetRate function sets a new target flow rate, pump \n + * The setDialOutPumpTargetRate function sets a new target flow rate, pump * direction, and control mode. - * @details - * Inputs : isDialOutPumpOn, dialOutPumpDirectionSet - * Outputs : targetDialOutFlowRate, dialOutPumpdirection, dialOutPumpPWMDutyCyclePct - * @param flowRate : new target dialysate outlet flow rate - * @param dir : new dialysate outlet flow direction - * @param mode : new 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 + // Direction change while pump is running is not allowed if ( ( FALSE == isDialOutPumpOn ) || ( 0 == flowRate ) || ( dir == dialOutPumpDirectionSet ) ) { - // verify flow rate - if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) + F32 pwmDC = ( 0 == flowRate ? DOP_PWM_ZERO_OFFSET : 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 ) ) { - 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'll control to flow when ramp completed - dialOutPumpPWMDutyCyclePct = DOP_PWM_FROM_ML_PER_MIN((F32)flowRate); +#ifndef _RELEASE_ + BOOL byPassFlowLimit = FALSE; - switch ( dialOutPumpState ) + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) { - 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; + byPassFlowLimit = TRUE; } - result = TRUE; +#endif + + // Verify flow rate +#ifdef _RELEASE_ + if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) +#else + if ( ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) +#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; + + 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; + } + else // Requested flow rate too high + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) + } + } } - else // requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) - } } return result; } /*********************************************************************//** * @brief - * The setDialOutUFVolumes function sets the ultrafiltration reference and \n + * The setDialOutUFVolumes function sets the ultrafiltration reference and * measured total volumes (in mL). - * @details - * Inputs : none - * Outputs : referenceUFVolumeInMl and totalMeasuredUFVolumeInMl - * @param refVol : New ultrafiltration reference volume (in mL). - * @param totVol : New ultrafiltration total volume (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 ) @@ -276,56 +353,180 @@ /*********************************************************************//** * @brief - * The signalDialOutPumpHardStop function stops the dialysate outlet pump \n + * The signalDialOutPumpHardStop function stops the dialysate outlet pump * immediately. - * @details - * Inputs : none - * Outputs : Dialysate outlet pump stopped, set point reset, state changed to off + * @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; - dopControlTimerCounter = 0; - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); + dialOutPumpPWMDutyCyclePct = DOP_PWM_ZERO_OFFSET; + resetDialOutFlowMovingAverage(); } /*********************************************************************//** * @brief - * The setDialOutUFVolumes function sets the ultrafiltration reference and \n - * measured total volumes (in mL). - * @details - * Inputs : none - * Outputs : loadCellWeightInGrams[] - * @param res1Primary : New weight from primary load cell of reservoir 1. - * @param res1Backup : New weight from backup load cell of reservoir 1. - * @param res2Primary : New weight from primary load cell of reservoir 2. - * @param res2Backup : New weight from backup load cell of reservoir 2. - * @return TRUE if successful, FALSE if not + * 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 *************************************************************************/ -BOOL setNewLoadCellReadings( F32 res1Primary, F32 res1Backup, F32 res2Primary, F32 res2Backup ) +void signalDialOutPumpRotorHallSensor( void ) { - BOOL result = TRUE; + U32 rotTime = getMSTimerCount(); + U32 deltaTime = calcTimeBetween( dopRotorRevStartTime, rotTime ); - loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_PRIMARY ].data = res1Primary; - loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_BACKUP ].data = res1Backup; - loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_PRIMARY ].data = res2Primary; - loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_BACKUP ].data = res2Backup; + // 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 execDialOutFlowMonitor - * The execDialOutFlowMonitor function executes the dialysate outlet pump \n - * and load cell sensor monitor. Checks are performed. Data is published \n + * @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 isDialOutPumpRampComplete function returns whether the dialysate outlet pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: dialOutPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isDialOutPumpRampComplete( void ) +{ + BOOL result = ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ? TRUE : FALSE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The execDialOutFlowTest function executes the state machine for the + * DialOutFlow self-test. + * @details Inputs: none + * @details Outputs: dialOutPumpCalRecord + * @return the current state of the DialOutFlow self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execDialOutFlowTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&dialOutPumpCalRecord, sizeof( HD_PUMPS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PUMPS, ALARM_ID_NO_ALARM ); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; +} + +/*********************************************************************//** + * @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 - * Outputs : dialOutPumpMCSpeedRPM, dialOutPumpMCCurrentmA + * @details Inputs: latest sensor data + * @details Outputs: dialOutPumpMCSpeedRPM, dialOutPumpMCCurrentmA * @return none *************************************************************************/ void execDialOutFlowMonitor( void ) @@ -336,23 +537,45 @@ 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; - // don't start enforcing checks until out of init/POST mode + // 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(); } + else + { + lastDialOutPumpDirectionCount = getFPGADialOutPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + } publishDialOutFlowData(); } /*********************************************************************//** - * @brief execDialOutFlowController - * The execDialOutFlowController function executes the dialysate outlet pump \n + * @brief + * The execDialOutFlowController function executes the dialysate outlet pump * ultrafiltration controller state machine. - * @details - * Inputs : dialOutPumpState - * Outputs : dialOutPumpState + * @details Inputs: dialOutPumpState + * @details Outputs: dialOutPumpState * @return none *************************************************************************/ void execDialOutFlowController( void ) @@ -376,31 +599,30 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_STATE, dialOutPumpState ); + 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 handleDialOutPumpOffState - * The handleDialOutPumpOffState function handles the dialOut pump off state \n + * @brief + * The handleDialOutPumpOffState function handles the dialOut pump off state * of the dialOut pump controller state machine. - * @details - * Inputs : targetDialOutFlowRate, dialOutPumpDirection - * Outputs : dialOutPumpPWMDutyCyclePctSet, dialOutPumpDirectionSet, isDialOutPumpOn + * @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've been given a flow rate, setup ramp up and transition to ramp up 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_CHANGE; + // 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 + // Allow dialOut pump to run in requested direction setDialOutPumpDirection( dialOutPumpDirection ); releaseDialOutPumpStop(); isDialOutPumpOn = TRUE; @@ -415,140 +637,130 @@ } /*********************************************************************//** - * @brief handleDialOutPumpRampingUpState - * The handleDialOutPumpRampingUpState function handles the ramp up state \n + * @brief + * The handleDialOutPumpRampingUpState function handles the ramp up state * of the dialOut pump controller state machine. - * @details - * Inputs : dialOutPumpPWMDutyCyclePctSet - * Outputs : dialOutPumpPWMDutyCyclePctSet + * @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 < NEARLY_ZERO ) + // 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_CHANGE; + // 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? + // Have we reached end of ramp up? else if ( dialOutPumpPWMDutyCyclePctSet >= dialOutPumpPWMDutyCyclePct ) { - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet ); + dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; dialOutPumpControlModeSet = dialOutPumpControlMode; - // if open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( dialOutPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; - setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePct ); - } + resetDialOutFlowMovingAverage(); + setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } - // continue ramp up + // Continue ramp up else { - dialOutPumpPWMDutyCyclePctSet += MAX_DIAL_OUT_PUMP_PWM_STEP_CHANGE; + dialOutPumpPWMDutyCyclePctSet += MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } return result; } /*********************************************************************//** - * @brief handleDialOutPumpRampingDownState - * The handleDialOutPumpRampingDownState function handles the ramp down state \n + * @brief + * The handleDialOutPumpRampingDownState function handles the ramp down state * of the dialOut pump controller state machine. - * @details - * Inputs : dialOutPumpPWMDutyCyclePctSet - * Outputs : dialOutPumpPWMDutyCyclePctSet + * @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_CHANGE + DOP_PWM_ZERO_OFFSET) ) + // 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? + // Have we reached end of ramp down? else if ( dialOutPumpPWMDutyCyclePctSet <= dialOutPumpPWMDutyCyclePct ) { - resetPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, dialOutPumpPWMDutyCyclePctSet ); + dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; dialOutPumpControlModeSet = dialOutPumpControlMode; - // if open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( dialOutPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - dialOutPumpPWMDutyCyclePctSet = dialOutPumpPWMDutyCyclePct; - setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePct ); - } + resetDialOutFlowMovingAverage(); + setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); result = DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE; } - // continue ramp down + // Continue ramp down else { - dialOutPumpPWMDutyCyclePctSet -= MAX_DIAL_OUT_PUMP_PWM_STEP_CHANGE; + dialOutPumpPWMDutyCyclePctSet -= MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE; setDialOutPumpControlSignalPWM( dialOutPumpPWMDutyCyclePctSet ); } return result; } /*********************************************************************//** - * @brief handleDialOutPumpControlToTargetState - * The handleDialOutPumpControlToTargetState function handles the "control to \n + * @brief + * The handleDialOutPumpControlToTargetState function handles the "control to * target" state of the dialOut pump controller state machine. - * @details - * Inputs : dopControlTimerCounter, dialOutPumpControlModeSet, volumes. - * Outputs : dopControlTimerCounter, pump controlled. + * @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 at set interval - if ( ++dopControlTimerCounter >= DOP_CONTROL_INTERVAL ) + // 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 newPWM; - F32 deltaPWM; + F32 volErr = refVol - totVol; + F32 ufrErr = getCurrentUFSetRate() - ufMeasuredRate; - // get new PWM from PI controller - newPWM = runPIController( PI_CONTROLLER_ID_ULTRAFILTRATION, refVol, totVol ); - // limit PWM change to max - deltaPWM = newPWM - dialOutPumpPWMDutyCyclePctSet; - if ( FABS( deltaPWM ) > MAX_DIAL_OUT_PUMP_PWM_STEP_CHANGE ) - { - newPWM = ( deltaPWM < 0.0 ? dialOutPumpPWMDutyCyclePctSet - MAX_DIAL_OUT_PUMP_PWM_STEP_CHANGE : dialOutPumpPWMDutyCyclePctSet + MAX_DIAL_OUT_PUMP_PWM_STEP_CHANGE ); - } - // set new PWM - dialOutPumpPWMDutyCyclePctSet = newPWM; - setDialOutPumpControlSignalPWM( newPWM ); + 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 ); } - dopControlTimerCounter = 0; } return result; } /*********************************************************************//** * @brief - * The setDialOutPumpControlSignalPWM function set the PWM duty cycle of \n + * The setDialOutPumpControlSignalPWM function set the PWM duty cycle of * the dialysate outlet pump to a given %. - * @details - * Inputs : none - * Outputs : dialysis outlet pump PWM duty cycle is set. - * @param newPWM : A percentage duty cycle between 0.0 and 1.0. + * @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 ) @@ -557,17 +769,16 @@ } /*********************************************************************//** - * @brief stopDialOutPump + * @brief * The stopDialOutPump function sets the dialout flow stop signal and PWM * duty cycle to 0.0. - * @details - * Inputs : none - * Outputs : dialOut pump stop signal activated, PWM duty cycle zeroed + * @details Inputs: none + * @details Outputs: dialOut pump stop signal activated, PWM duty cycle zeroed * @return none *************************************************************************/ static void stopDialOutPump( void ) { - dialOutPumpPWMDutyCyclePctSet = 0.0; + dialOutPumpPWMDutyCyclePctSet = DOP_PWM_ZERO_OFFSET; setDialOutPumpControlSignalPWM( 0 ); SET_DOP_STOP(); isDialOutPumpOn = FALSE; @@ -576,9 +787,8 @@ /*********************************************************************//** * @brief * The releaseDialOutPumpStop function clears the dialysate outlet pump stop signal. - * @details - * Inputs : none - * Outputs : dialysate outlet pump stop signal is cleared. + * @details Inputs: none + * @details Outputs: dialysate outlet pump stop signal is cleared. * @return none *************************************************************************/ static void releaseDialOutPumpStop( void ) @@ -587,13 +797,12 @@ } /*********************************************************************//** - * @brief setDialOutPumpDirection - * The setDialOutPumpDirection function sets the set dialIn pump direction to \n + * @brief + * The setDialOutPumpDirection function sets the set dialOut pump direction to * the given direction. - * @details - * Inputs : none - * Outputs : dialOutPumpDirectionSet, pump direction signal set to match given direction. - * @param dir : dialysate outlet pump direction to set + * @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 ) @@ -611,82 +820,284 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_INVALID_DIAL_OUT_PUMP_DIRECTION, dir ); + 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 publishDialOutFlowData - * The publishDialOutFlowData function publishes dialysate outlet data at \n + * @brief + * The publishDialOutFlowData function publishes dialysate outlet data at * the set interval. - * @details - * Inputs : Dialysate outlet pump data - * Outputs : Dialysate outlet pump data is published to CAN bus. + * @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 >= getPublishDialOutDataInterval() ) + // 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(); -#ifndef SHOW_LOAD_CELL_IN_ROTOR_RPM dialOutBroadCastVariables.measRotSpdRPM = getMeasuredDialOutPumpRotorSpeed(); -#else - dialOutBroadCastVariables.measRotSpdRPM = getLoadCellWeightInGrams( LOAD_CELL_RESERVOIR_1_PRIMARY ); -#endif dialOutBroadCastVariables.measSpdRPM = getMeasuredDialOutPumpSpeed(); dialOutBroadCastVariables.measMCSpdRPM = getMeasuredDialOutPumpMCSpeed(); dialOutBroadCastVariables.measMCCurrmA = getMeasuredDialOutPumpMCCurrent(); dialOutBroadCastVariables.setPWMpct = dialOutPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + dialOutBroadCastVariables.dopCorrOffset = dopRateCorrectionOffset; + dialOutBroadCastVariables.dopCalcRate = dopMeasuredRate; + dialOutBroadCastVariables.ufCalcRate = ufMeasuredRate; - broadcastDialOutFlowData( &dialOutBroadCastVariables); + 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 checkDialOutPumpDirection function checks the set direction vs. \n + * 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 = ( 0 == incDelta ? 0xFFFF : 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 - * Outputs : none - * @param none + * @details Inputs: adcDialOutPumpMCSpeedRPM, dialOutPumpDirectionSet, dialOutPumpState + * @details Outputs: none * @return none *************************************************************************/ static void checkDialOutPumpDirection( void ) { - MOTOR_DIR_T dopMCDir; - if ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ) { - // check set direction vs. direction from sign of motor controller speed + MOTOR_DIR_T dopMCDir, dopDir; + U08 dirErrorCnt = getFPGADialOutPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + BOOL isHallSensorFailed = ( lastDialOutPumpDirectionCount != dirErrorCnt ? TRUE : FALSE ); + + // Check pump direction error count + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, isHallSensorFailed ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_OUTLET_PUMP ) + } + } + lastDialOutPumpDirectionCount = dirErrorCnt; + dopMCDir = ( getMeasuredDialOutPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); - if ( dialOutPumpDirectionSet != dopMCDir ) + dopDir = ( getMeasuredDialOutPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + + // Check set direction vs. direction from hall sensors + if ( dialOutPumpDirectionSet != dopDir ) { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopMCDir ) + if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopDir ) + } + } } + // Check set direction vs. direction from sign of motor controller speed + else if ( dialOutPumpDirectionSet != dopMCDir ) + { + if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopMCDir ) + } + } + } + else + { + errorDialOutPumpDirectionPersistTimerCtr = 0; + } } + else + { + errorDialOutPumpDirectionPersistTimerCtr = 0; + } } -/************************************************************************* +/*********************************************************************//** * @brief - * The checkDialOutPumpMCCurrent function checks the measured MC current vs. \n + * 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 _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_OFF_CHECK, measMotorSpeed ); + activateSafetyShutdown(); + } + } + } + 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 _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); + } + } + } + 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 _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); + } + } + } + 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 - * Outputs : none - * @param none + * @details Inputs: dialOutPumpState, dopCurrErrorDurationCtr, adcDialOutPumpMCCurrentmA + * @details Outputs: none * @return none *************************************************************************/ static void checkDialOutPumpMCCurrent( void ) { F32 dopCurr; - // dialOut pump should be off + // DialOut pump should be off if ( DIAL_OUT_PUMP_OFF_STATE == dialOutPumpState ) { dopCurr = fabs( getMeasuredDialOutPumpMCCurrent() ); @@ -695,28 +1106,34 @@ dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) { -#ifndef DISABLE_MOTOR_CURRENT_ERRORS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); + } } } else { dopCurrErrorDurationCtr = 0; } } - // dialOut pump should be running + // DialOut pump should be running else { dopCurr = fabs( getMeasuredDialOutPumpMCCurrent() ); - if ( ( dopCurr < DOP_MIN_CURR_WHEN_RUNNING_MA ) || ( dopCurr > DOP_MAX_CURR_WHEN_RUNNING_MA ) ) + if ( dopCurr > DOP_MAX_CURR_WHEN_RUNNING_MA ) { dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) { -#ifndef DISABLE_MOTOR_CURRENT_ERRORS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); + } } } else @@ -731,187 +1148,138 @@ * GET SUPPORT FUNCTIONS *************************************************************************/ -/*********************************************************************//** - * @brief - * The getPublishDialOutFlowDataInterval function gets the dialysate out flow \n - * data publication interval. - * @details - * Inputs : dialOutDataPublishInterval - * Outputs : none - * @return the current dialysate out flow data publication interval (in ms). - *************************************************************************/ -static U32 getPublishDialOutDataInterval( void ) -{ - U32 result = dialOutDataPublishInterval.data; - if ( OVERRIDE_KEY == dialOutDataPublishInterval.override ) - { - result = dialOutDataPublishInterval.ovData; - } - - return result; -} - /*********************************************************************//** * @brief - * The getLoadCellWeightInGrams function gets the load cell weight. - * @details - * Inputs : loadCellWeightInGrams - * Outputs : none - * @param loadCellID : ID of load cell to get - * @return the current load cell weight in grams - *************************************************************************/ -F32 getLoadCellWeightInGrams( U32 loadCellID ) -{ - F32 result = 0.0; - if ( loadCellID <= NUM_OF_LOAD_CELLS - 1 ) - { - if ( OVERRIDE_KEY == loadCellWeightInGrams[ loadCellID ].override ) - { - result = loadCellWeightInGrams[ loadCellID ].ovData; - } - else - { - result = loadCellWeightInGrams[ loadCellID ].data; - } - } - else - { - activateAlarmNoData( ALARM_ID_SOFTWARE_FAULT ); - } - return result; -} - -/*********************************************************************//** - * @brief * The getTotalTargetDialOutUFVolumeInMl function gets the target UF volume. - * @details - * Inputs : referenceUFVolumeInMl - * Outputs : none + * @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 - * Outputs : none + * @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 \n + * The getMeasuredDialOutPumpRotorSpeed function gets the measured dialysate * outlet pump rotor speed. - * @details - * Inputs : dialOutPumpRotorSpeedRPM - * Outputs : none + * @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 \n + * The getMeasuredDialOutPumpSpeed function gets the measured dialysate outlet * pump motor speed. - * @details - * Inputs : dialOutPumpSpeedRPM - * Outputs : none + * @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 \n + * The getMeasuredDialOutPumpMCSpeed function gets the measured dialOut pump * speed. - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : none -* @param none + * @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 \n + * The getMeasuredDialOutPumpMCCurrent function gets the measured dialOut pump * current. - * @details - * Inputs : dialOutPumpMCCurrentmA - * Outputs : none + * @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 \n - * dialout vol data publish interval. - * @details - * Inputs : none - * Outputs : dialOutDataPublishInterval - * @param value : override dialout vol data publish interval with (in ms) + * 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 ) @@ -932,12 +1300,11 @@ /*********************************************************************//** * @brief - * The testResetDialOutPumpAndLoadCellDataPublishIntervalOverride function resets the override \n - * of the dialout vol data publish interval. - * @details - * Inputs : none - * Outputs : dialOutDataPublishInterval - * @return TRUE if override reset successful, FALSE if not + * 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 ) { @@ -955,14 +1322,56 @@ /*********************************************************************//** * @brief - * The testSetDialOutUFRefVolumeOverride function overrides the target \n - * dialout vol rate. \n - * @details - * Inputs : referenceUFVolumeInMl - * Outputs : referenceUFVolumeInMl - * @param value : override target dialout vol rate (in mL/min) + * 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 ) + { + if ( 0 == value ) + { + signalDialOutPumpHardStop(); + result = TRUE; + } + else + { + 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; @@ -979,12 +1388,11 @@ /*********************************************************************//** * @brief - * The testResetDialOutUFRefVolumeOverride function resets the override of the \n + * The testResetDialOutUFRefVolumeOverride function resets the override of the * target dialout vol rate. - * @details - * Inputs : referenceUFVolumeInMl - * Outputs : referenceUFVolumeInMl - * @return TRUE if override reset successful, FALSE if not + * @details Inputs: referenceUFVolumeInMl + * @details Outputs: referenceUFVolumeInMl + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFRefVolumeOverride( void ) { @@ -1002,12 +1410,11 @@ /*********************************************************************//** * @brief - * The testSetDialOutUFTotVolumeOverride function overrides the measured \n - * dialout vol rate. \n - * @details - * Inputs : totalMeasuredUFVolumeInMl - * Outputs : totalMeasuredUFVolumeInMl - * @param value : override measured dialout vol rate (in mL/min) + * 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 ) @@ -1026,12 +1433,11 @@ /*********************************************************************//** * @brief - * The testResetDialOutUFTotVolumeOverride function resets the override of the \n + * The testResetDialOutUFTotVolumeOverride function resets the override of the * measured dialout vol rate. - * @details - * Inputs : totalMeasuredUFVolumeInMl - * Outputs : totalMeasuredUFVolumeInMl - * @return TRUE if override reset successful, FALSE if not + * @details Inputs: totalMeasuredUFVolumeInMl + * @details Outputs: totalMeasuredUFVolumeInMl + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFTotVolumeOverride( void ) { @@ -1049,12 +1455,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpRotorSpeedOverride function overrides the measured \n - * dialIn pump rotor speed. \n - * @details - * Inputs : DialOutPumpRotorSpeedRPM - * Outputs : DialOutPumpRotorSpeedRPM - * @param value : override measured dialIn pump rotor speed (in RPM) + * 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 ) @@ -1073,12 +1478,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpRotorSpeedOverride function resets the override of the \n - * measured dialIn pump rotor speed. - * @details - * Inputs : DialOutPumpRotorSpeedRPM - * Outputs : DialOutPumpRotorSpeedRPM - * @return TRUE if override reset successful, FALSE if not + * 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 ) { @@ -1096,12 +1500,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpSpeedOverride function overrides the measured \n - * dialIn pump motor speed. \n - * @details - * Inputs : dialOutPumpSpeedRPM - * Outputs : dialOutPumpSpeedRPM - * @param value : override measured dialIn pump motor speed (in RPM) + * 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 ) @@ -1120,12 +1523,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpSpeedOverride function resets the override of the \n - * measured dialIn pump motor speed. - * @details - * Inputs : dialOutPumpSpeedRPM - * Outputs : dialOutPumpSpeedRPM - * @return TRUE if override reset successful, FALSE if not + * 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 ) { @@ -1143,12 +1545,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpMCSpeedOverride function overrides the measured \n - * dialIn pump motor speed. \n - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : dialOutPumpMCSpeedRPM - * @param value : override measured dialIn pump speed (in RPM) + * 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 ) @@ -1167,12 +1568,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpMCSpeedOverride function resets the override of the \n - * measured dialIn pump motor speed. - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : dialOutPumpMCSpeedRPM - * @return TRUE if override reset successful, FALSE if not + * 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 ) { @@ -1190,12 +1590,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpMCCurrentOverride function overrides the measured \n - * dialIn pump motor current. \n - * @details - * Inputs : dialOutPumpMCCurrentmA - * Outputs : dialOutPumpMCCurrentmA - * @param value : override measured dialIn pump current (in mA) + * 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 ) @@ -1214,12 +1613,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpMCCurrentOverride function resets the override of the \n - * measured dialIn pump motor current. - * @details - * Inputs : dialOutPumpMCCurrentmA - * Outputs : dialOutPumpMCCurrentmA - * @return TRUE if override reset successful, FALSE if not + * 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 ) { @@ -1235,59 +1633,4 @@ return result; } -/*********************************************************************//** - * @brief - * The testSetDialOutLoadCellWeightOverride function overrides the value of the \n - * load cell sensor with a given weight (in grams). \n - * @details - * Inputs : loadCellWeightInGrams[] - * Outputs : loadCellWeightInGrams[] - * @param sensor : ID of load cell sensor to override weight for - * @param value : override weight (in grams) for the given sensor - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetDialOutLoadCellWeightOverride( U32 sensor, F32 value ) -{ - BOOL result = FALSE; - - if ( sensor < NUM_OF_LOAD_CELLS ) - { - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - loadCellWeightInGrams[ sensor ].ovData = value; - loadCellWeightInGrams[ sensor ].override = OVERRIDE_KEY; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetDialOutLoadCellWeightOverride function resets the override of the \n - * load cell sensor. - * @details - * Inputs : loadCellWeightInGrams[] - * Outputs : loadCellWeightInGrams[] - * @param sensor : ID of load cell sensor to override weight for - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testResetDialOutLoadCellWeightOverride( U32 sensor ) -{ - BOOL result = FALSE; - - if ( sensor < NUM_OF_LOAD_CELLS ) - { - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - loadCellWeightInGrams[ sensor ].override = OVERRIDE_RESET; - loadCellWeightInGrams[ sensor ].ovData = loadCellWeightInGrams[ sensor ].ovInitData; - } - } - - return result; -} - - +/**@}*/