Index: firmware/App/Controllers/DialOutFlow.c =================================================================== diff -u -rc84daa1f07003427fc5cdde8f5651434478f7313 -rb1492eff71eab83d55456ad3520ccfd6cda06a77 --- firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision c84daa1f07003427fc5cdde8f5651434478f7313) +++ firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision b1492eff71eab83d55456ad3520ccfd6cda06a77) @@ -1,37 +1,39 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* 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 +* @file DialOutFlow.c * -* @author (last) Sean Nash -* @date (last) 19-Jun-2020 +* @author (last) Dara Navaei +* @date (last) 15-Jun-2022 * -* @author (original) Sean -* @date (original) 24-Jan-2020 +* @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 @@ -40,53 +42,79 @@ // ********** 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 DPO_FLOW_ADJ_DUE_TO_HIGHER_INLET_PRES 0.875 ///< Adjustment factor to account for higher pump inlet pressure (than DPi pump inlet). -#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.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_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). -#define DOP_SPEED_CALC_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< interval (ms/task time) at which the dialysate outlet pump speed is calculated. -#define DOP_HALL_EDGE_COUNTS_PER_REV 48 ///< number of hall sensor edge counts per motor revolution. +#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_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. -#define DOP_OFF_ERROR_PERSIST ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< persist time (task intervals) for motor off error condition. -#define DOP_MOTOR_SPEED_ERROR_PERSIST ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< persist time (task intervals) motor speed error condition. -#define DOP_ROTOR_SPEED_ERROR_PERSIST ((12 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< persist time (task intervals) rotor speed error condition. +#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). -#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. +/// 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_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.00028 ///< ~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 DOP_MIN_DIR_CHECK_SPEED_RPM 10.0F ///< Minimum motor speed before we check pump direction. +#define DOP_COMMUTATION_ERROR_MAX_CNT 3 ///< Maximum number of commutation errors within time window before alarm triggered. +#define DOP_COMMUTATION_ERROR_TIME_WIN_MS (15 * MS_PER_SECOND) ///< Time window for DPo commutation error. +#define DATA_PUBLISH_COUNTER_START_COUNT 40 ///< Data publish counter start count. + /// Enumeration of dialysate outlet pump controller states. typedef enum DialOutPump_States { @@ -97,42 +125,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 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). @@ -141,27 +163,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 U32 dopCurrErrorDurationCtr = 0; ///< Timer counter for motor current error persistence. +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 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 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 U16 dopLastMotorHallSensorCount = 0; ///< last hall sensor count for the dialysate outlet pump motor -static MOTOR_DIR_T dopMotorDirectionFromHallSensors = MOTOR_DIR_FORWARD; ///< pump direction according to hall sensor count -static U32 dopMotorSpeedCalcTimerCtr = 0; ///< counter determines interval for calculating dialysate outlet pump motor speed from hall sensor count. +static BOOL dopControlSignal = FALSE; ///< Control signal for syncing UF control to follow control interval of dialysate inlet pump. -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 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 ); @@ -182,124 +214,140 @@ 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; - dopLastMotorHallSensorCount = getFPGADialOutPumpHallSensorCount(); + dialOutFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; - stopDialOutPump(); + 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; + dopMeasuredRate = 0.0; + ufMeasuredRate = 0.0; + dopRateCorrectionOffset = 0.0; + resetDialOutFlowMovingAverage(); - // 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 ); + initTimeWindowedCount( TIME_WINDOWED_COUNT_DOP_COMMUTATION_ERROR, DOP_COMMUTATION_ERROR_MAX_CNT, DOP_COMMUTATION_ERROR_TIME_WIN_MS ); } /*********************************************************************//** * @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 ) ) { - F32 adjFlow = (F32)flowRate * DPO_FLOW_ADJ_DUE_TO_HIGHER_INLET_PRES; +#ifndef _RELEASE_ + BOOL byPassFlowLimit = 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'll control to flow when ramp completed - dialOutPumpPWMDutyCyclePct = DOP_PWM_FROM_ML_PER_MIN(adjFlow); + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + byPassFlowLimit = TRUE; + } +#endif - switch ( dialOutPumpState ) + // Verify flow rate +#ifdef _RELEASE_ + if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) +#else + if ( ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) +#endif { - 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; + 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; } - 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_HD_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 ) @@ -310,43 +358,40 @@ /*********************************************************************//** * @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 signalDialOutPumpRotorHallSensor function handles the dialysate outlet \n - * pump rotor hall sensor detection. Calculates rotor speed (in RPM). \n + * 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 - * Outputs : dopRotorRevStartTime, dialOutPumpRotorSpeedRPM + * @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) + // Calculate rotor speed (in RPM) dialOutPumpRotorSpeedRPM.data = ( 1.0 / (F32)deltaTime ) * (F32)MS_PER_SECOND * (F32)SEC_PER_MIN; dopRotorRevStartTime = rotTime; - // if we're supposed to stop pump at home position, stop pump now. + // If we are supposed to stop pump at home position, stop pump now. if ( TRUE == dopStopAtHomePosition ) { signalDialOutPumpHardStop(); @@ -356,10 +401,59 @@ /*********************************************************************//** * @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 - * Outputs : dopStopAtHomePosition, dopHomeStartTime, dialysate outlet pump started (slow) + * @details Inputs: dialOutPumpState + * @details Outputs: dopStopAtHomePosition, dopHomeStartTime, dialysate outlet pump started (slow) * @return none *************************************************************************/ BOOL homeDialOutPump( void ) @@ -378,37 +472,66 @@ /*********************************************************************//** * @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 isDialOutPumpRunning function returns whether the dialysate outlet + * pump is currently running or not. + * @details Inputs: isDialOutPumpOn + * @details Outputs: none + * @return isDialOutPumpOn *************************************************************************/ -BOOL setNewLoadCellReadings( F32 res1Primary, F32 res1Backup, F32 res2Primary, F32 res2Backup ) +BOOL isDialOutPumpRunning( void ) { - BOOL result = TRUE; + return isDialOutPumpOn; +} - 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; +/*********************************************************************//** + * @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 execDialOutFlowMonitor - * The execDialOutFlowMonitor function executes the dialysate outlet pump \n - * and load cell sensor monitor. Checks are performed. Data is published \n + * @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 ) @@ -419,32 +542,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; - // calculate dialysate outlet pump motor speed/direction from hall sensor count + // Calculate dialysate outlet pump motor speed/direction from hall sensor count updateDialOutPumpSpeedAndDirectionFromHallSensors(); - // don't start enforcing checks until out of init/POST mode + // 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 + // Check pump direction checkDialOutPumpDirection(); - // check pump controller current + // Check pump controller current checkDialOutPumpMCCurrent(); - // check pump speeds + // Check pump speeds checkDialOutPumpSpeeds(); - // check for home position, zero/low speed + // 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 ) @@ -474,25 +610,24 @@ } /*********************************************************************//** - * @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 + // 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; @@ -507,40 +642,35 @@ } /*********************************************************************//** - * @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 + // 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_UP_CHANGE; @@ -551,38 +681,33 @@ } /*********************************************************************//** - * @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_UP_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_DN_CHANGE; @@ -593,54 +718,54 @@ } /*********************************************************************//** - * @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_UP_CHANGE ) - { - newPWM = ( deltaPWM < 0.0 ? dialOutPumpPWMDutyCyclePctSet - MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE : dialOutPumpPWMDutyCyclePctSet + MAX_DIAL_OUT_PUMP_PWM_STEP_UP_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 ) @@ -649,17 +774,16 @@ } /*********************************************************************//** - * @brief stopDialOutPump - * The stopDialOutPump function sets the dialout flow stop signal and PWM \n + * @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; @@ -668,9 +792,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 ) @@ -680,12 +803,11 @@ /*********************************************************************//** * @brief - * The setDialOutPumpDirection function sets the set dialOut pump direction to \n + * 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 ) @@ -710,91 +832,95 @@ /*********************************************************************//** * @brief - * The publishDialOutFlowData function publishes dialysate outlet data at \n + * 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(); dialOutBroadCastVariables.measRotSpdRPM = getMeasuredDialOutPumpRotorSpeed(); 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 updateDialOutPumpSpeedAndDirectionFromHallSensors function calculates \n - * the dialysate outlet pump motor speed and direction from hall sensor counter on \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 - * Outputs : dopMotorDirectionFromHallSensors, dialOutPumpSpeedRPM + * @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(); - U16 incDelta = ( dopMotorHallSensorCount >= dopLastMotorHallSensorCount ? dopMotorHallSensorCount - dopLastMotorHallSensorCount : ( HEX_64_K - dopLastMotorHallSensorCount ) + dopMotorHallSensorCount ); - U16 decDelta = HEX_64_K - incDelta; + 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 + // Determine dialysate outlet pump speed/direction from delta hall sensor count since last interval if ( incDelta < decDelta ) { - dopMotorDirectionFromHallSensors = MOTOR_DIR_FORWARD; delta = incDelta; dialOutPumpSpeedRPM.data = ( (F32)delta / (F32)DOP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; } else { - dopMotorDirectionFromHallSensors = MOTOR_DIR_REVERSE; 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 - dopLastMotorHallSensorCount = dopMotorHallSensorCount; + // Update last count for next time + dopLastMotorHallSensorCounts[ nextIdx ] = dopMotorHallSensorCount; + dopMotorSpeedCalcIdx = nextIdx; dopMotorSpeedCalcTimerCtr = 0; } } /*********************************************************************//** * @brief - * The checkDialOutPumpRotor function checks the rotor for the dialysate outlet \n - * pump. If homing, this function will stop when hall sensor detected. If pump \n + * 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 - * Outputs : pump may be stopped if homing, dialOutPumpRotorSpeedRPM may 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 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 pump is stopped or running very slowly, set rotor speed to zero if ( TRUE == didTimeout( dopRotorRevStartTime, DOP_HOME_TIMEOUT_MS ) ) { dialOutPumpRotorSpeedRPM.data = 0.0; @@ -803,57 +929,105 @@ /*********************************************************************//** * @brief - * The checkDialOutPumpDirection function checks the set direction vs. \n + * 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 + * @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 hall sensors or sign of motor controller speed + MOTOR_DIR_T dopMCDir, dopDir; + U08 dirErrorCnt = getFPGADialOutPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + F32 measMCSpeed = getMeasuredDialOutPumpMCSpeed(); + BOOL minDirSpeed = ( measMCSpeed >= DOP_MIN_DIR_CHECK_SPEED_RPM ? TRUE : FALSE ); + BOOL isHallSensorFailed = ( TRUE == minDirSpeed && lastDialOutPumpDirectionCount != dirErrorCnt ? TRUE : FALSE ); + + // Check pump direction error count + if ( ( TRUE == isHallSensorFailed ) && ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_DOP_COMMUTATION_ERROR ) ) ) + { +#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 ) || ( dialOutPumpDirectionSet != dopMotorDirectionFromHallSensors ) ) + dopDir = ( getMeasuredDialOutPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + + // Check set direction vs. direction from hall sensors + if ( ( dialOutPumpDirectionSet != dopDir ) && ( TRUE == minDirSpeed ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopMotorDirectionFromHallSensors ) + 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 ) && ( TRUE == minDirSpeed ) ) + { + 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 checkDialOutPumpSpeeds function checks several aspects of the dialysate \n - * outlet pump speed. \n - * 1. while pump is commanded off, measured motor speed should be < limit. \n - * 2. while pump is controlling, measured motor speed should be within allowed range of measured motor controller speed. \n - * 3. measured motor speed should be within allowed range of measured rotor speed. \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 - * Outputs : alarm(s) may be 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 ( FALSE == isDialOutPumpOn ) + // 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 ); +#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 @@ -868,42 +1042,48 @@ if ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ) { - F32 controllerMotorSpeed = getMeasuredDialOutPumpMCSpeed(); - F32 deltaMotorSpeed = FABS( measMotorSpeed - controllerMotorSpeed ); + 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 ); + 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 ) + // 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, controllerMotorSpeed, measMotorSpeed ); +#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 + // 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 ); +#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 { @@ -914,18 +1094,17 @@ /*********************************************************************//** * @brief - * The checkDialOutPumpMCCurrent function checks the measured MC current vs. \n + * 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 + * @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() ); @@ -934,28 +1113,34 @@ 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() ); +#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_CHECKS - 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 @@ -970,65 +1155,12 @@ * 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_HD_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 ) @@ -1046,9 +1178,8 @@ /*********************************************************************//** * @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 ) @@ -1065,11 +1196,10 @@ /*********************************************************************//** * @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 ) @@ -1086,11 +1216,10 @@ /*********************************************************************//** * @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 ) @@ -1107,11 +1236,10 @@ /*********************************************************************//** * @brief - * The getMeasuredDialOutPumpMCSpeed function gets the measured dialOut pump \n + * The getMeasuredDialOutPumpMCSpeed function gets the measured dialOut pump * speed. - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : none + * @details Inputs: dialOutPumpMCSpeedRPM + * @details Outputs: none * @return the current dialOut pump speed (in RPM). *************************************************************************/ F32 getMeasuredDialOutPumpMCSpeed( void ) @@ -1128,11 +1256,10 @@ /*********************************************************************//** * @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 ) @@ -1155,12 +1282,11 @@ /*********************************************************************//** * @brief - * The testSetDialOutPumpAndLoadCellDataPublishIntervalOverride function overrides the \n + * The testSetDialOutPumpAndLoadCellDataPublishIntervalOverride function overrides the * dialout data publish interval. - * @details - * Inputs : none - * Outputs : dialOutDataPublishInterval - * @param value : override dialout data publish interval with (in ms) + * @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 ) @@ -1181,12 +1307,11 @@ /*********************************************************************//** * @brief - * The testResetDialOutPumpAndLoadCellDataPublishIntervalOverride function resets the override \n + * The testResetDialOutPumpAndLoadCellDataPublishIntervalOverride function resets the override * of the dialout data publish interval. - * @details - * Inputs : none - * Outputs : dialOutDataPublishInterval - * @return TRUE if reset reset successful, FALSE if not + * @details Inputs: none + * @details Outputs: dialOutDataPublishInterval + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutPumpAndLoadCellDataPublishIntervalOverride( void ) { @@ -1204,13 +1329,12 @@ /*********************************************************************//** * @brief - * The testSetTargetDialOutFlowRateOverride function overrides the target \n + * The testSetTargetDialOutFlowRateOverride function overrides the target * dialysate outlet flow rate. - * @details - * Inputs : none - * 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) + * @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 ) @@ -1231,7 +1355,15 @@ } if ( ctrlMode < NUM_OF_PUMP_CONTROL_MODES ) { - result = setDialOutPumpTargetRate( ABS(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); + if ( 0 == value ) + { + signalDialOutPumpHardStop(); + result = TRUE; + } + else + { + result = setDialOutPumpTargetRate( abs(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); + } } } @@ -1240,33 +1372,11 @@ /*********************************************************************//** * @brief - * The testResetTargetDialOutFlowRateOverride function resets the override of the \n - * target dialysate outlet flow rate. - * @details - * Inputs : none - * Outputs : pump stopped - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetTargetDialOutFlowRateOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = setDialOutPumpTargetRate( 0, dialOutPumpDirection, dialOutPumpControlMode ); - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetDialOutUFRefVolumeOverride function overrides the target \n + * The testSetDialOutUFRefVolumeOverride function overrides the target * dialout vol rate. - * @details - * Inputs : referenceUFVolumeInMl - * Outputs : referenceUFVolumeInMl - * @param value : override target dialout vol rate (in mL/min) + * @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 ) @@ -1285,12 +1395,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 reset reset successful, FALSE if not + * @details Inputs: referenceUFVolumeInMl + * @details Outputs: referenceUFVolumeInMl + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFRefVolumeOverride( void ) { @@ -1308,12 +1417,11 @@ /*********************************************************************//** * @brief - * The testSetDialOutUFTotVolumeOverride function overrides the measured \n + * The testSetDialOutUFTotVolumeOverride function overrides the measured * dialout vol rate. - * @details - * Inputs : totalMeasuredUFVolumeInMl - * Outputs : totalMeasuredUFVolumeInMl - * @param value : override measured dialout vol rate (in mL/min) + * @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 ) @@ -1332,12 +1440,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 reset reset successful, FALSE if not + * @details Inputs: totalMeasuredUFVolumeInMl + * @details Outputs: totalMeasuredUFVolumeInMl + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetDialOutUFTotVolumeOverride( void ) { @@ -1355,12 +1462,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpRotorSpeedOverride function overrides the measured \n + * The testSetMeasuredDialOutPumpRotorSpeedOverride function overrides the measured * dialOut pump rotor speed. - * @details - * Inputs : DialOutPumpRotorSpeedRPM - * Outputs : DialOutPumpRotorSpeedRPM - * @param value : override measured dialOut pump rotor speed (in RPM) + * @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 ) @@ -1379,12 +1485,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpRotorSpeedOverride function resets the override of the \n + * The testResetMeasuredDialOutPumpRotorSpeedOverride function resets the override of the * measured dialOut pump rotor speed. - * @details - * Inputs : DialOutPumpRotorSpeedRPM - * Outputs : DialOutPumpRotorSpeedRPM - * @return TRUE if reset reset successful, FALSE if not + * @details Inputs: DialOutPumpRotorSpeedRPM + * @details Outputs: DialOutPumpRotorSpeedRPM + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpRotorSpeedOverride( void ) { @@ -1402,12 +1507,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpSpeedOverride function overrides the measured \n + * The testSetMeasuredDialOutPumpSpeedOverride function overrides the measured * dialOut pump motor speed. - * @details - * Inputs : dialOutPumpSpeedRPM - * Outputs : dialOutPumpSpeedRPM - * @param value : override measured dialOut pump motor speed (in RPM) + * @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 ) @@ -1426,12 +1530,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpSpeedOverride function resets the override of the \n + * The testResetMeasuredDialOutPumpSpeedOverride function resets the override of the * measured dialOut pump motor speed. - * @details - * Inputs : dialOutPumpSpeedRPM - * Outputs : dialOutPumpSpeedRPM - * @return TRUE if reset reset successful, FALSE if not + * @details Inputs: dialOutPumpSpeedRPM + * @details Outputs: dialOutPumpSpeedRPM + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpSpeedOverride( void ) { @@ -1449,12 +1552,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpMCSpeedOverride function overrides the measured \n + * The testSetMeasuredDialOutPumpMCSpeedOverride function overrides the measured * dialOut pump motor speed. - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : dialOutPumpMCSpeedRPM - * @param value : override measured dialOut pump speed (in RPM) + * @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 ) @@ -1473,12 +1575,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpMCSpeedOverride function resets the override of the \n + * The testResetMeasuredDialOutPumpMCSpeedOverride function resets the override of the * measured dialOut pump motor speed. - * @details - * Inputs : dialOutPumpMCSpeedRPM - * Outputs : dialOutPumpMCSpeedRPM - * @return TRUE if reset reset successful, FALSE if not + * @details Inputs: dialOutPumpMCSpeedRPM + * @details Outputs: dialOutPumpMCSpeedRPM + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpMCSpeedOverride( void ) { @@ -1496,12 +1597,11 @@ /*********************************************************************//** * @brief - * The testSetMeasuredDialOutPumpMCCurrentOverride function overrides the measured \n + * The testSetMeasuredDialOutPumpMCCurrentOverride function overrides the measured * dialOut pump motor current. - * @details - * Inputs : dialOutPumpMCCurrentmA - * Outputs : dialOutPumpMCCurrentmA - * @param value : override measured dialOut pump current (in mA) + * @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 ) @@ -1520,12 +1620,11 @@ /*********************************************************************//** * @brief - * The testResetMeasuredDialOutPumpMCCurrentOverride function resets the override of the \n + * The testResetMeasuredDialOutPumpMCCurrentOverride function resets the override of the * measured dialOut pump motor current. - * @details - * Inputs : dialOutPumpMCCurrentmA - * Outputs : dialOutPumpMCCurrentmA - * @return TRUE if reset reset successful, FALSE if not + * @details Inputs: dialOutPumpMCCurrentmA + * @details Outputs: dialOutPumpMCCurrentmA + * @return TRUE if reset override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredDialOutPumpMCCurrentOverride( void ) { @@ -1541,59 +1640,4 @@ return result; } -/*********************************************************************//** - * @brief - * The testSetDialOutLoadCellWeightOverride function overrides the value of the \n - * load cell sensor with a given weight (in grams). - * @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 reset 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; -} - /**@}*/