Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r2bb447181c2519690441d81f83563d17e0882ef2 -ra3d8f8dafc488730c316ae0a64d05cb69ec8bcc9 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 2bb447181c2519690441d81f83563d17e0882ef2) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision a3d8f8dafc488730c316ae0a64d05cb69ec8bcc9) @@ -1,298 +1,580 @@ -/************************************************************************** - * - * Copyright (c) 2019-2019 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 BloodFlow.c - * - * @date 05-Nov-2019 - * @author S. Nash - * - * @brief Monitor/Controller for blood pump and flow sensor. - * - **************************************************************************/ +/************************************************************************** +* +* Copyright (c) 2019-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 BloodFlow.c +* +* @author (last) Sean Nash +* @date (last) 15-Jul-2022 +* +* @author (original) Sean Nash +* @date (original) 07-Nov-2019 +* +***************************************************************************/ -#ifndef _VECTORCAST_ - #include -#endif +#include // Used for fabs() and pow() functions #include "can.h" #include "etpwm.h" -#include "Common.h" +#include "BloodFlow.h" #include "FPGA.h" -#include "InternalADC.h" +#include "InternalADC.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 "BloodFlow.h" +#include "Timers.h" +#include "Utilities.h" +/** + * @addtogroup BloodFlow + * @{ + */ + // ********** private definitions ********** + +/// Interval (ms/task time) at which the blood flow data is published on the CAN bus. +#define BLOOD_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) -#define BLOOD_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) // interval (ms/task time) at which the blood flow data is published on the CAN bus +#define MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE 0.008F ///< Max duty cycle change when ramping up ~ 100 mL/min/s. +#define MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE 0.016F ///< Max duty cycle change when ramping down ~ 200 mL/min/s. +#define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.89F ///< Controller will error if PWM duty cycle > 90%, so set max to 89% +#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.10F ///< Controller will error if PWM duty cycle < 10%, so set min to 10% + +#define BP_CONTROL_INTERVAL_SEC 10 ///< Blood pump control interval (in seconds). + +/// Interval (ms/task time) at which the blood pump is controlled. +static const U32 BP_CONTROL_INTERVAL = ( BP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); -#define MAX_BLOOD_FLOW_RATE 500 // mL/min -#define MIN_BLOOD_FLOW_RATE 100 // mL/min +#define BP_P_COEFFICIENT 0.0001F ///< P term for blood pump control +#define BP_I_COEFFICIENT 0.00075F ///< I term for blood pump control -#define MAX_BLOOD_PUMP_PWM_STEP_CHANGE 0.005 // max duty cycle change when ramping -#define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.88 // controller will error if PWM duty cycle > 90%, so set max to 88% -#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.12 // controller will error if PWM duty cycle < 10%, so set min to 12% +#define BP_HOME_RATE 100 ///< Target pump speed (in estimate mL/min) for homing. +#define BP_HOME_TIMEOUT_MS 10000 ///< Maximum time (in ms) allowed for homing to complete. +#define BP_MAX_ROTOR_HALL_INTERVAL_MS 20000 ///< Maximum time (in ms) allowed between rotor hall sensor detects (50 mL/min worst case). -#define BP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) // interval (ms/task time) at which the blood pump is controlled -#define BP_P_COEFFICIENT 0.0002 // P term for blood pump control -#define BP_I_COEFFICIENT 0.00002 // I term for blood pump control -#define BP_MAX_ERROR_SUM 10.0 // for anti-wind-up in I term -#define BP_MIN_ERROR_SUM -10.0 -#define BP_MAX_PWM_DC_DELTA 0.01 // prevents large steps in PWM duty cycle while controlling -#define BP_MIN_PWM_DC_DELTA -0.01 +/// Interval (ms/task time) at which the blood pump speed is calculated (every 40 ms). +#define BP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) -#define BP_MAX_CURR_WHEN_STOPPED_MA 150.0 // motor controller current should not exceed this when pump should be stopped -#define BP_MIN_CURR_WHEN_RUNNING_MA 150.0 // motor controller current should always exceed this when pump should be running -#define BP_MAX_CURR_WHEN_RUNNING_MA 1000.0 // motor controller current should not exceed this when pump should be running -#define BP_MAX_CURR_ERROR_DURATION_MS 2000 // motor controller current errors persisting beyond this duration will trigger an alarm +/// Number of hall sensor counts kept in buffer to hold last 1 second of count data. +#define BP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) + +#define BP_MAX_ROTOR_SPEED_RPM 100.0F ///< Maximum rotor speed allowed for blood pump. + +#define BP_MAX_FLOW_RATE 1320.0F ///< Maximum measured BP flow rate allowed. +#define BP_MIN_FLOW_RATE -1320.0F ///< Minimum measured BP flow rate allowed. +#define BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0F ///< Maximum motor speed (RPM) while motor is commanded off. +#define BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0F ///< Maximum difference in speed between motor and rotor (in rotor RPM). +#define BP_MAX_MOTOR_SPEED_ERROR_RPM 300.0F ///< Maximum difference in speed between measured and commanded RPM. + +/// Persist time (in ms) for motor off error condition. +static const U32 BP_OFF_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (in ms) motor speed error condition. +static const U32 BP_MOTOR_SPEED_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (in ms) rotor speed error condition. +static const U32 BP_ROTOR_SPEED_ERROR_PERSIST = ( 22 * MS_PER_SECOND ); +/// Persist time (in ms) pump direction error condition. +static const U32 BP_DIRECTION_ERROR_PERSIST = ( 250 ); +/// Persist time period (in ms) blood pump rotor speed too fast error condition. +static const U32 BP_MAX_ROTOR_SPEED_ERROR_PERSIST = ( 1 * MS_PER_SECOND ); +/// Persist time (in ms) blood flow rate out of range error condition. +static const U32 BP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST = (1 * MS_PER_SECOND); -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.375 // conversion factor from ADC counts to RPM for blood pump motor -#define BP_CURRENT_ADC_TO_MA_FACTOR 2.65 // conversion factor from ADC counts to mA for blood pump motor +#define BP_MAX_CURR_WHEN_STOPPED_MA 150.0F ///< Motor controller current should not exceed this when pump should be stopped. +#define BP_MAX_CURR_WHEN_RUNNING_MA 2000.0F ///< Motor controller current should not exceed this when pump should be running. +#define BP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. + +#define BLOODPUMP_ADC_FULL_SCALE_V 3.0F ///< BP analog signals are 0-3V (while int. ADC ref may be different). +#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. + +/// Macro converts 12 bit ADC value to signed 16-bit value. +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) + +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752F ///< Conversion factor from ADC counts to RPM for blood pump motor (3500 RPM/1998 counts). +#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238F ///< ~42 BP motor RPM = 1% PWM duty cycle. +#define BP_CURRENT_ADC_TO_MA_FACTOR 3.002F ///< Conversion factor from ADC counts to mA for blood pump motor. -#define BP_REV_PER_LITER 124.0 // rotor revolutions per liter -#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) -#define BP_GEAR_RATIO 32.0 // blood pump motor to blood pump gear ratio -#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000369 //717 // ~27 BP motor RPM = 1% PWM duty cycle -#define BP_PWM_ZERO_OFFSET 0.1 // 10% PWM duty cycle = zero speed -#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) +#define BP_REV_PER_LITER 146.84F ///< Rotor revolutions per liter. +#define BP_ML_PER_ROTOR_REV 6.81F ///< Milliliters per rotor revolusion. +#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to motor RPM. +#define BP_GEAR_RATIO 32.0F ///< Blood pump motor to blood pump gear ratio. +#define BP_PWM_ZERO_OFFSET 0.1F ///< 10 pct PWM duty cycle = zero speed. -#define BLOODPUMP_ADC_FULL_SCALE_V 3.0 // BP analog signals are 0-3V (while int. ADC ref V is 3.3V) -#define BLOODPUMP_ADC_MID_PT_BITS ( (F32)( INT_ADC_FULL_SCALE_BITS >> 1 ) * ( BLOODPUMP_ADC_FULL_SCALE_V / INT_ADC_REF_V ) ) -#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_MID_PT_BITS ) +/// Conversion macro from mL/min to estimated PWM duty cycle %. +#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) +/// Conversion from PWM duty cycle % to commanded pump motor speed. +#define BP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - BP_PWM_ZERO_OFFSET) * 4000.0F ) -#define BLOOD_FLOW_SAMPLE_FREQ ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) -#define SIZE_OF_ROLLING_AVG (U32)( (F32)BLOOD_FLOW_SAMPLE_FREQ * 0.8 ) // measured blood flow is filtered w/ moving average -#define MAX_FLOW_FILTER_INTERVAL 5 // slowest sample interval for filter is every 5th sample +/// Measured blood flow is filtered w/ moving average. +#define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 1 ) + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define BP_MIN_DIR_CHECK_SPEED_RPM 10.0F ///< Minimum motor speed before we check pump direction. +#define BP_COMMUTATION_ERROR_MAX_CNT 3 ///< Maximum number of commutation errors within time window before alarm triggered. +#define BP_COMMUTATION_ERROR_TIME_WIN_MS (15 * MS_PER_SECOND) ///< Time window for BP commutation error. + +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.1970F ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.000000029F ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.00055F ///< B term used for wear portion of alpha flow coefficient. +#define BP_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define DATA_PUBLISH_COUNTER_START_COUNT 20 ///< Data publish counter start count. +/// Enumeration of blood pump controller states. typedef enum BloodPump_States { - BLOOD_PUMP_OFF_STATE = 0, - BLOOD_PUMP_RAMPING_UP_STATE, - BLOOD_PUMP_RAMPING_DOWN_STATE, - BLOOD_PUMP_CONTROL_TO_TARGET_STATE, - NUM_OF_BLOOD_PUMP_STATES + BLOOD_PUMP_OFF_STATE = 0, ///< Blood pump off state + BLOOD_PUMP_RAMPING_UP_STATE, ///< Blood pump ramping up state + BLOOD_PUMP_RAMPING_DOWN_STATE, ///< Blood pump ramping down state + BLOOD_PUMP_CONTROL_TO_TARGET_STATE, ///< Blood pump controlling to target state + NUM_OF_BLOOD_PUMP_STATES ///< Number of blood pump states } BLOOD_PUMP_STATE_T; +/// Enumeration of blood pump self-test states. typedef enum BloodFlow_Self_Test_States { - BLOOD_FLOW_SELF_TEST_STATE_START = 0, - BLOOD_FLOW_TEST_STATE_IN_PROGRESS, - BLOOD_FLOW_TEST_STATE_COMPLETE, - NUM_OF_BLOOD_FLOW_SELF_TEST_STATES + BLOOD_FLOW_SELF_TEST_STATE_START = 0, ///< Blood pump self-test start state + BLOOD_FLOW_TEST_STATE_IN_PROGRESS, ///< Blood pump self-test in progress state + BLOOD_FLOW_TEST_STATE_COMPLETE, ///< Blood pump self-test completed state + NUM_OF_BLOOD_FLOW_SELF_TEST_STATES ///< Number of blood pump self-test states } BLOOD_FLOW_SELF_TEST_STATE_T; -// pin assignments for pump stop and direction outputs +// Pin assignments for pump stop and direction outputs #define STOP_CAN3_PORT_MASK 0x00000002 // (Tx - re-purposed as output GPIO for blood pump stop signal) #define DIR_CAN3_PORT_MASK 0x00000002 // (Rx - re-purposed as output GPIO for blood pump direction signal) -// blood pump stop and direction macros -#define SET_BP_DIR() {canREG3->RIOC |= DIR_CAN3_PORT_MASK;} -#define SET_BP_STOP() {canREG3->TIOC |= STOP_CAN3_PORT_MASK;} -#define CLR_BP_DIR() {canREG3->RIOC &= ~DIR_CAN3_PORT_MASK;} -#define CLR_BP_STOP() {canREG3->TIOC &= ~STOP_CAN3_PORT_MASK;} +// Blood pump stop and direction macros +#define SET_BP_DIR() {canREG3->RIOC |= DIR_CAN3_PORT_MASK;} // Macro to set blood pump direction signal high. +#define CLR_BP_DIR() {canREG3->RIOC &= ~DIR_CAN3_PORT_MASK;} // Macro to set blood pump direction signal low. +#define SET_BP_STOP() {canREG3->TIOC &= ~STOP_CAN3_PORT_MASK;} // Macro to set blood pump stop signal (active low). +#define CLR_BP_STOP() {canREG3->TIOC |= STOP_CAN3_PORT_MASK;} // Macro to clear blood pump stop signal (active low). // ********** private data ********** -static BLOOD_PUMP_STATE_T bloodPumpState = BLOOD_PUMP_OFF_STATE; // current state of blood flow controller state machine -static U32 bloodFlowDataPublicationTimerCounter = 0; // used to schedule blood flow data publication to CAN bus -static BOOL isBloodPumpOn = FALSE; // blood pump is currently running -static F32 bloodPumpPWMDutyCyclePct = 0.0; // initial blood pump PWM duty cycle -static F32 bloodPumpPWMDutyCyclePctSet = 0.0; // currently set blood pump PWM duty cycle -static MOTOR_DIR_T bloodPumpDirection = MOTOR_DIR_FORWARD; // requested blood flow direction -static MOTOR_DIR_T bloodPumpDirectionSet = MOTOR_DIR_FORWARD; // currently set blood flow direction +static BLOOD_PUMP_STATE_T bloodPumpState = BLOOD_PUMP_OFF_STATE; ///< Current state of blood flow controller state machine +static U32 bloodFlowDataPublicationTimerCounter; ///< Used to schedule blood flow data publication to CAN bus +static BOOL isBloodPumpOn = FALSE; ///< Blood pump is currently running +static F32 bloodPumpPWMDutyCyclePct = 0.0; ///< Initial blood pump PWM duty cycle +static F32 bloodPumpPWMDutyCyclePctSet = 0.0; ///< Currently set blood pump PWM duty cycle +static MOTOR_DIR_T bloodPumpDirection = MOTOR_DIR_FORWARD; ///< Requested blood flow direction +static MOTOR_DIR_T bloodPumpDirectionSet = MOTOR_DIR_FORWARD; ///< Currently set blood flow direction +static PUMP_CONTROL_MODE_T bloodPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested blood pump control mode. +static PUMP_CONTROL_MODE_T bloodPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set blood pump control mode. -DATA_DECL( U32, BloodFlowDataPub, bloodFlowDataPublishInterval, BLOOD_FLOW_DATA_PUB_INTERVAL, BLOOD_FLOW_DATA_PUB_INTERVAL ); // interval (in ms) at which to publish blood flow data to CAN bus -DATA_DECL( S32, TargetBloodFlowRate, targetBloodFlowRate, 0, 0 ); // requested blood flow rate -DATA_DECL( F32, MeasuredBloodFlowRate, measuredBloodFlowRate, 0.0, 0.0 ); // measured blood flow rate -DATA_DECL( F32, MeasuredBloodPumpRotorSpeed, bloodPumpRotorSpeedRPM, 0.0, 0.0 );// measured blood pump rotor speed -DATA_DECL( F32, MeasuredBloodPumpSpeed, bloodPumpSpeedRPM, 0.0, 0.0 ); // measured blood pump motor speed -DATA_DECL( F32, MeasuredBloodPumpMCSpeed, adcBloodPumpMCSpeedRPM, 0.0, 0.0 ); // measured blood pump motor controller speed -DATA_DECL( F32, MeasuredBloodPumpMCCurrent, adcBloodPumpMCCurrentmA, 0.0, 0.0 );// measured blood pump motor controller current +/// Interval (in task intervals) at which to publish blood flow data to CAN bus. +static OVERRIDE_U32_T bloodFlowDataPublishInterval = { BLOOD_FLOW_DATA_PUB_INTERVAL, BLOOD_FLOW_DATA_PUB_INTERVAL, BLOOD_FLOW_DATA_PUB_INTERVAL, 0 }; +static S32 targetBloodFlowRate = 0; ///< Requested blood flow rate. +static OVERRIDE_F32_T measuredBloodFlowRate = { 0.0, 0.0, 0.0, 0 }; ///< Measured (calculated now) blood flow rate. +static OVERRIDE_F32_T bloodPumpRotorSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump rotor speed. +static OVERRIDE_F32_T bloodPumpSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor speed. +static OVERRIDE_F32_T adcBloodPumpMCSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor controller speed. +static OVERRIDE_F32_T adcBloodPumpMCCurrentmA = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor controller current. -static F32 bpFlowError = 0.0; // blood flow error -static F32 bpFlowErrorSum = 0.0; // blood flow error sum -static U32 bpControlTimerCounter = 0; // determines when to perform control on blood flow +static U08 lastBloodPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA. -static F32 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 F32 flowReadingsTotal = 0.0; // rolling total - used to calc average -static U32 flowReadingsCount = 0; // # of samples in flow rolling average buffer -static U32 flowReadingsTmrCtr = 0; // determines when to add samples to filter +static F32 rpmReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds RPM samples for a rolling average. +static U32 rpmReadingsIdx = 0; ///< Index for next sample in rolling average array. +static F32 rpmReadingsTotal = 0.0; ///< Rolling total - used to calc average. +static U32 rpmReadingsCount = 0; ///< Number of samples in RPM rolling average buffer. +static F32 filteredBloodPumpSpeed = 0.0; ///< Filtered blood pump speed used in blood flow estimation. + +static U32 bpControlTimerCounter = 0; ///< Determines when to perform control on blood flow -static U32 bpCurrErrorDurationCtr = 0; // used for tracking persistence of bp current errors +static U32 bpRotorRevStartTime = 0; ///< Blood pump rotor rotation start time (in ms) +static OVERRIDE_U32_T bloodPumpRotorCounter = { 0, 0, 0, 0 }; ///< Running counter for blood pump rotor revolutions +static BOOL bpStopAtHomePosition = FALSE; ///< Stop blood pump at next home position +static U32 bpHomeStartTime = 0; ///< When did blood pump home command begin? (in ms) -static BLOOD_FLOW_SELF_TEST_STATE_T bloodPumpSelfTestState = BLOOD_FLOW_SELF_TEST_STATE_START; // current blood pump self test state -static U32 bloodPumpSelfTestTimerCount = 0; // timer counter for blood pump self test +static U32 bloodPumpMotorEdgeCount = 0; ///< Running counter for blood pump motor revolutions +static U16 bpLastMotorHallSensorCounts[ BP_SPEED_CALC_BUFFER_LEN ]; ///< Last hall sensor readings for the blood pump motor +static U32 bpMotorSpeedCalcIdx = 0; ///< Index into 1 second buffer of motor speed hall sensor counts +static U32 bpMotorSpeedCalcTimerCtr = 0; ///< Counter determines interval for calculating blood pump motor speed from hall sensor count. +static HD_PUMPS_CAL_RECORD_T bloodPumpCalRecord; ///< Blood pump calibration record. // ********** private function prototypes ********** static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ); static BLOOD_PUMP_STATE_T handleBloodPumpRampingUpState( void ); static BLOOD_PUMP_STATE_T handleBloodPumpRampingDownState( void ); static BLOOD_PUMP_STATE_T handleBloodPumpControlToTargetState( void ); +static void setBloodPumpControlSignalPWM( F32 newPWM ); static void stopBloodPump( void ); static void releaseBloodPumpStop( void ); static void setBloodPumpDirection( MOTOR_DIR_T dir ); static void publishBloodFlowData( void ); -static void resetBloodFlowMovingAverage( void ); -static void filterBloodFlowReadings( F32 flow ); +static void updateBloodPumpSpeedAndDirectionFromHallSensors( void ); +static void checkBloodPumpRotor( void ); static void checkBloodPumpDirection( void ); -static void checkBloodPumpMCCurrent( void ); -static DATA_GET_PROTOTYPE( U32, getPublishBloodFlowDataInterval ); - -/************************************************************************* - * @brief initBloodFlow +static void checkBloodPumpSpeeds( void ); +static void checkBloodPumpMCCurrent( void ); +static void checkBloodPumpFlowRate( void ); + +static F32 calcBloodFlow( void ); +static void resetBloodPumpRPMMovingAverage( void ); +static void filterBloodPumpRPMReadings( F32 rpm ); + +/*********************************************************************//** + * @brief * The initBloodFlow function initializes the BloodFlow module. - * @details - * Inputs : none - * Outputs : BloodFlow module initialized. - * @param none + * @details Inputs: none + * @details Outputs: bloodFlowDataPublicationTimerCounter * @return none *************************************************************************/ void initBloodFlow( void ) -{ - stopBloodPump(); +{ + U32 i; + + bloodFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + signalBloodPumpHardStop(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); - // zero rolling flow average buffer - resetBloodFlowMovingAverage(); + // Zero rolling pump speed average buffer + resetBloodPumpRPMMovingAverage(); + + // Zero motor hall sensors counts buffer + bpMotorSpeedCalcIdx = 0; + for ( i = 0; i < BP_SPEED_CALC_BUFFER_LEN; i++ ) + { + bpLastMotorHallSensorCounts[ i ] = getFPGABloodPumpHallSensorCount(); + } + resetBloodPumpRotorCount(); + + // Initialize blood flow PI controller + initializePIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, + BP_P_COEFFICIENT, BP_I_COEFFICIENT, + MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); + + // Initialize persistent alarm for flow sensor + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_OFF_CHECK, 0, BP_OFF_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, 0, BP_MOTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, 0, BP_ROTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, 0, BP_DIRECTION_ERROR_PERSIST ); + initTimeWindowedCount( TIME_WINDOWED_COUNT_BP_COMMUTATION_ERROR, BP_COMMUTATION_ERROR_MAX_CNT, BP_COMMUTATION_ERROR_TIME_WIN_MS ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, 0, BP_MAX_ROTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, 0, BP_MAX_CURR_ERROR_DURATION_MS ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, 0, BP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST ); } -/************************************************************************* - * @brief setBloodPumpTargetFlowRate +/*********************************************************************//** + * @brief * The setBloodPumpTargetFlowRate function sets a new target flow rate and * pump direction. - * @details - * Inputs : isBloodPumpOn, bloodPumpDirectionSet - * Outputs : targetBloodFlowRate, bloodPumpdirection, bloodPumpPWMDutyCyclePct - * @param flowRate : new target blood flow rate - * @param dir : new blood flow direction + * @details Inputs: isBloodPumpOn, bloodPumpDirectionSet + * @details Outputs: targetBloodFlowRate, bloodPumpdirection, bloodPumpPWMDutyCyclePct + * @param flowRate new target blood flow rate + * @param dir new blood flow direction + * @param mode new control mode * @return TRUE if new flow rate & dir are set, FALSE if not *************************************************************************/ -BOOL setBloodPumpTargetFlowRate( U32 flowRate, MOTOR_DIR_T dir ) +BOOL setBloodPumpTargetFlowRate( 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 == isBloodPumpOn ) || ( 0 == flowRate ) || ( dir == bloodPumpDirectionSet ) ) - { - // verify flow rate - if ( flowRate <= MAX_BLOOD_FLOW_RATE ) - { - resetBloodFlowMovingAverage(); - targetBloodFlowRate.data = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); - bloodPumpDirection = dir; - // 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 - bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) - // reset flow control stats - bpFlowError = 0.0; - bpFlowErrorSum = 0.0; - - switch ( bloodPumpState ) + { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) + { + BOOL isFlowInrange = ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ? TRUE : FALSE ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + isFlowInrange = TRUE; + } +#endif + // Verify flow rate of if the bypass flow limit has been enabled + if ( TRUE == isFlowInrange ) { - case BLOOD_PUMP_RAMPING_UP_STATE: // see if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - break; - case BLOOD_PUMP_RAMPING_DOWN_STATE: // see if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; - case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // start ramp to new target in appropriate direction - if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - else - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; - default: - // ok - not all states need to be handled here - break; + resetBloodPumpRPMMovingAverage(); + targetBloodFlowRate = dirFlowRate; + bloodPumpDirection = dir; + bloodPumpControlMode = 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 + bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) + + switch ( bloodPumpState ) + { + case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + break; + + case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; + + case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + else + { + bloodPumpState = BLOOD_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_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) + } + } } - else // requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) - } } return result; } -/************************************************************************* - * @brief signalBloodPumpHardStop +/*********************************************************************//** + * @brief + * The calcBloodFlow function calculates an estimated blood flow rate from + * blood pump speed, arterial pressure and tubing wear (measured from count + * of rotor revolutions since cartridge install). + * @details Inputs: bloodPumpRotorCounter, arterial pressure + * @details Outputs: none + * @return calculated blood flow rate (mL/min) + *************************************************************************/ +static F32 calcBloodFlow( void ) +{ + F32 artPres = getLongFilteredArterialPressure(); + F32 rotSpd = filteredBloodPumpSpeed / BP_GEAR_RATIO; + U32 r = getBloodPumpRotorCount(); + U32 rotCnt = CAP( r, BP_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wear = BP_FLOW_WEAR_A_TERM * (F32)rotCnt + BP_FLOW_WEAR_B_TERM; + F32 alpha = wear * artPres + BP_FLOW_ALPHA_Y_INTERCEPT; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; + + return flow; +} + +/*********************************************************************//** + * @brief * The signalBloodPumpHardStop function stops the blood pump immediately. - * @details - * Inputs : none - * Outputs : Blood pump stopped, set point reset, state changed to off - * @param none + * @details Inputs: none + * @details Outputs: Blood pump stopped, set point reset, state changed to off * @return none *************************************************************************/ void signalBloodPumpHardStop( void ) { - targetBloodFlowRate.data = 0; + targetBloodFlowRate = 0; stopBloodPump(); bloodPumpState = BLOOD_PUMP_OFF_STATE; - bloodPumpPWMDutyCyclePct = 0.0; - bpFlowError = 0.0; - bpFlowErrorSum = 0.0; + bloodPumpPWMDutyCyclePct = BP_PWM_ZERO_OFFSET; bpControlTimerCounter = 0; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE ); } -/************************************************************************* - * @brief execBloodFlowMonitor +/*********************************************************************//** + * @brief + * The signalBloodPumpRotorHallSensor function handles the blood pump rotor + * hall sensor detection. Calculates rotor speed (in RPM). Stops pump if + * there is a pending request to home the pump. + * @details Inputs: bpRotorRevStartTime, bpStopAtHomePosition + * @details Outputs: bpRotorRevStartTime, bloodPumpRotorSpeedRPM, bloodPumpRotorCounter + * @return none + *************************************************************************/ +void signalBloodPumpRotorHallSensor( void ) +{ + U32 rotTime = getMSTimerCount(); + U32 deltaTime = calcTimeBetween( bpRotorRevStartTime, rotTime ); + + // Increment rotor counter + bloodPumpRotorCounter.data++; + + // Calculate rotor speed (in RPM) + bloodPumpRotorSpeedRPM.data = ( 1.0 / (F32)deltaTime ) * (F32)MS_PER_SECOND * (F32)SEC_PER_MIN; + bpRotorRevStartTime = rotTime; + + // If we are supposed to stop pump at home position, stop pump now. + if ( TRUE == bpStopAtHomePosition ) + { + signalBloodPumpHardStop(); + bpStopAtHomePosition = FALSE; + } +} + +/*********************************************************************//** + * @brief + * The homeBloodPump function initiates a blood pump home operation. + * @details Inputs: bloodPumpState + * @details Outputs: bpStopAtHomePosition, bpHomeStartTime, blood pump started (slow) + * @return none + *************************************************************************/ +BOOL homeBloodPump( void ) +{ + BOOL result = FALSE; + + if ( BLOOD_PUMP_OFF_STATE == bloodPumpState ) + { + bpStopAtHomePosition = TRUE; + bpHomeStartTime = getMSTimerCount(); + result = setBloodPumpTargetFlowRate( BP_HOME_RATE, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpMotorCount function returns the current count for the + * blood pump motor revolution counter. + * @details Inputs: bloodPumpMotorCount + * @details Outputs: none + * @return bloodPumpMotorCount + *************************************************************************/ +U32 getBloodPumpMotorCount( void ) +{ + return bloodPumpMotorEdgeCount; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpRotorCount function returns the current count for the + * blood pump rotor revolution counter. + * @details Inputs: bloodPumpRotorCounter + * @details Outputs: none + * @return bloodPumpRotorCounter + *************************************************************************/ +U32 getBloodPumpRotorCount( void ) +{ + U32 result = bloodPumpRotorCounter.data; + + if ( OVERRIDE_KEY == bloodPumpRotorCounter.override ) + { + result = bloodPumpRotorCounter.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isBloodPumpRunning function returns whether the blood pump is currently + * running or not. + * @details Inputs: isBloodPumpOn + * @details Outputs: none + * @return isBloodPumpOn + *************************************************************************/ +BOOL isBloodPumpRunning( void ) +{ + return isBloodPumpOn; +} + +/*********************************************************************//** + * @brief + * The isBloodPumpRampComplete function returns whether the blood pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: bloodPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isBloodPumpRampComplete( void ) +{ + BOOL result = ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ? TRUE : FALSE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The resetBloodPumpRotorCount function resets the blood pump rotor counter + * that is a proxy for cartridge wear. Call this function after a new cartridge + * has been installed. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @return none + *************************************************************************/ +void resetBloodPumpRotorCount( void ) +{ +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_WORN_OUT_CARTRIDGE ) != SW_CONFIG_ENABLE_VALUE ) + { + bloodPumpRotorCounter.data = 0; + } + else +#endif + { + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; + } +} + +/*********************************************************************//** + * @brief * The execBloodFlowMonitor function executes the blood flow monitor. - * @details - * Inputs : none - * Outputs : measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, adcBloodPumpMCCurrentmA - * @param none + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, + * adcBloodPumpMCCurrentmA * @return none *************************************************************************/ void execBloodFlowMonitor( void ) -{ +{ + HD_OP_MODE_T opMode = getCurrentOperationMode(); U16 bpRPM = getIntADCReading( INT_ADC_BLOOD_PUMP_SPEED ); - U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); - F32 bpFlow = getFPGABloodFlow(); - + U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); + adcBloodPumpMCSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpRPM)) * BP_SPEED_ADC_TO_RPM_FACTOR; - adcBloodPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * BP_CURRENT_ADC_TO_MA_FACTOR; + adcBloodPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * BP_CURRENT_ADC_TO_MA_FACTOR; - filterBloodFlowReadings( bpFlow ); + filterBloodPumpRPMReadings( getMeasuredBloodPumpMCSpeed() ); + measuredBloodFlowRate.data = calcBloodFlow(); // Pressure and rotor speed already filtered as inputs to calc, so no need to filter flow any further - // don't start enforcing checks until out of init/POST mode - if ( getCurrentOperationMode() != MODE_INIT ) + // Calculate blood pump motor speed/direction from hall sensor count + updateBloodPumpSpeedAndDirectionFromHallSensors(); + + // Do not start enforcing checks until out of init/POST mode + if ( opMode != MODE_INIT ) { + // Check pump direction checkBloodPumpDirection(); + // Check pump controller current checkBloodPumpMCCurrent(); - } + // Check pump speeds and flow + checkBloodPumpSpeeds(); + checkBloodPumpFlowRate(); + // Check for home position, zero/low speed + checkBloodPumpRotor(); + } + else + { + lastBloodPumpDirectionCount = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + } - // publish blood flow data on interval + // Publish blood flow data on interval publishBloodFlowData(); } -/************************************************************************* - * @brief execBloodFlowController +/*********************************************************************//** + * @brief * The execBloodFlowController function executes the blood flow controller. - * @details - * Inputs : bloodPumpState - * Outputs : bloodPumpState - * @param none + * @details Inputs: bloodPumpState + * @details Outputs: bloodPumpState * @return none *************************************************************************/ void execBloodFlowController( void ) @@ -316,204 +598,198 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_STATE, bloodPumpState ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_STATE, bloodPumpState ) break; } } -/************************************************************************* - * @brief handleBloodPumpOffState - * The handleBloodPumpOffState function handles the blood pump off state \n +/*********************************************************************//** + * @brief + * The handleBloodPumpOffState function handles the blood pump off state * of the blood pump controller state machine. - * @details - * Inputs : targetBloodFlowRate, bloodPumpDirection - * Outputs : bloodPumpPWMDutyCyclePctSet, bloodPumpDirectionSet, isBloodPumpOn - * @param none + * @details Inputs: targetBloodFlowRate, bloodPumpDirection + * @details Outputs: bloodPumpPWMDutyCyclePctSet, bloodPumpDirectionSet, isBloodPumpOn * @return next state *************************************************************************/ static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ) { BLOOD_PUMP_STATE_T result = BLOOD_PUMP_OFF_STATE; - // if we've been given a flow rate, setup ramp up and transition to ramp up state - if ( getTargetBloodFlowRate() != 0 ) + // If we have been given a flow rate, setup ramp up and transition to ramp up state + if ( targetBloodFlowRate != 0 ) { - // set initial PWM duty cycle - bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET + MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)FLOAT_TO_INT_WITH_ROUND( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) ); - // allow blood pump to run in requested direction + // Set initial PWM duty cycle + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET + MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + // Allow blood pump to run in requested direction setBloodPumpDirection( bloodPumpDirection ); releaseBloodPumpStop(); - // start PWM for blood pump - etpwmStartTBCLK(); isBloodPumpOn = TRUE; result = BLOOD_PUMP_RAMPING_UP_STATE; } return result; } -/************************************************************************* - * @brief handleBloodPumpRampingUpState - * The handleBloodPumpRampingUpState function handles the ramp up state \n +/*********************************************************************//** + * @brief + * The handleBloodPumpRampingUpState function handles the ramp up state * of the blood pump controller state machine. - * @details - * Inputs : bloodPumpPWMDutyCyclePctSet - * Outputs : bloodPumpPWMDutyCyclePctSet - * @param none + * @details Inputs: bloodPumpPWMDutyCyclePctSet + * @details Outputs: bloodPumpPWMDutyCyclePctSet * @return next state *************************************************************************/ static BLOOD_PUMP_STATE_T handleBloodPumpRampingUpState( void ) { BLOOD_PUMP_STATE_T result = BLOOD_PUMP_RAMPING_UP_STATE; - // have we been asked to stop the blood pump? - if ( 0 == getTargetBloodFlowRate() ) + // Have we been asked to stop the blood pump? + if ( 0 == targetBloodFlowRate ) { - // start ramp down to stop - bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)FLOAT_TO_INT_WITH_ROUND( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) ); + // Start ramp down to stop + bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); result = BLOOD_PUMP_RAMPING_DOWN_STATE; } - // have we reached end of ramp up? + // Have we reached end of ramp up? else if ( bloodPumpPWMDutyCyclePctSet >= bloodPumpPWMDutyCyclePct ) { - resetBloodFlowMovingAverage(); + resetBloodPumpRPMMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); + bloodPumpControlModeSet = bloodPumpControlMode; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } - // continue ramp up + // Continue ramp up else { - bloodPumpPWMDutyCyclePctSet += MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)FLOAT_TO_INT_WITH_ROUND( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) ); + bloodPumpPWMDutyCyclePctSet += MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); } return result; } -/************************************************************************* - * @brief handleBloodPumpRampingDownState - * The handleBloodPumpRampingDownState function handles the ramp down state \n +/*********************************************************************//** + * @brief + * The handleBloodPumpRampingDownState function handles the ramp down state * of the blood pump controller state machine. - * @details - * Inputs : bloodPumpPWMDutyCyclePctSet - * Outputs : bloodPumpPWMDutyCyclePctSet - * @param none + * @details Inputs: bloodPumpPWMDutyCyclePctSet + * @details Outputs: bloodPumpPWMDutyCyclePctSet * @return next state *************************************************************************/ static BLOOD_PUMP_STATE_T handleBloodPumpRampingDownState( void ) { BLOOD_PUMP_STATE_T result = BLOOD_PUMP_RAMPING_DOWN_STATE; - // have we essentially reached zero speed - if ( bloodPumpPWMDutyCyclePctSet < (MAX_BLOOD_PUMP_PWM_STEP_CHANGE + BP_PWM_ZERO_OFFSET) ) + // Have we essentially reached zero speed? + if ( bloodPumpPWMDutyCyclePctSet < (MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE + BP_PWM_ZERO_OFFSET) ) { - stopBloodPump(); + signalBloodPumpHardStop(); result = BLOOD_PUMP_OFF_STATE; } - // have we reached end of ramp down? + // Have we reached end of ramp down? else if ( bloodPumpPWMDutyCyclePctSet <= bloodPumpPWMDutyCyclePct ) { - resetBloodFlowMovingAverage(); + resetBloodPumpRPMMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); + bloodPumpControlModeSet = bloodPumpControlMode; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } - // continue ramp down + // Continue ramp down else { - bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_CHANGE; - etpwmSetCmpA( etpwmREG1, (U32)FLOAT_TO_INT_WITH_ROUND( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) ); + bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); } return result; } -/************************************************************************* - * @brief handleBloodPumpControlToTargetState - * The handleBloodPumpControlToTargetState function handles the "control to \n +/*********************************************************************//** + * @brief + * The handleBloodPumpControlToTargetState function handles the "control to * target" state of the blood pump controller state machine. - * @details - * Inputs : none - * Outputs : bloodPumpState - * @param none + * @details Inputs: none + * @details Outputs: bloodPumpState * @return next state *************************************************************************/ static BLOOD_PUMP_STATE_T handleBloodPumpControlToTargetState( void ) { BLOOD_PUMP_STATE_T result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; - F32 tgtFlow = (F32)getTargetBloodFlowRate(); - F32 actFlow = getMeasuredBloodFlowRate(); - F32 pTerm, iTerm; - F32 newPWM; - // control at set interval + // Control at set interval if ( ++bpControlTimerCounter >= BP_CONTROL_INTERVAL ) { - // compute P term - if ( MOTOR_DIR_FORWARD == bloodPumpDirectionSet ) + if ( bloodPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) { - bpFlowError = tgtFlow - actFlow; + F32 tgtFlow = (F32)targetBloodFlowRate; + F32 actFlow = getMeasuredBloodFlowRate(); + F32 newPWM; + + newPWM = runPIController( PI_CONTROLLER_ID_BLOOD_FLOW, tgtFlow, actFlow ); + bloodPumpPWMDutyCyclePctSet = newPWM; + setBloodPumpControlSignalPWM( newPWM ); } - else - { - bpFlowError = (tgtFlow * -1.0) - (actFlow * -1.0); - } - pTerm = bpFlowError * BP_P_COEFFICIENT; - pTerm = RANGE( pTerm, BP_MIN_PWM_DC_DELTA, BP_MAX_PWM_DC_DELTA ); - // compute I term - bpFlowErrorSum += bpFlowError; - iTerm = RANGE( bpFlowErrorSum, BP_MIN_ERROR_SUM, BP_MAX_ERROR_SUM ); - iTerm *= BP_I_COEFFICIENT; - // compute new PWM duty cycle % for blood pump motor - newPWM = bloodPumpPWMDutyCyclePctSet + pTerm + iTerm; - newPWM = RANGE( newPWM, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); - bloodPumpPWMDutyCyclePctSet = newPWM; - etpwmSetCmpA( etpwmREG1, (U32)FLOAT_TO_INT_WITH_ROUND( bloodPumpPWMDutyCyclePctSet * (F32)(etpwmREG1->TBPRD) ) ); bpControlTimerCounter = 0; } return result; } -/************************************************************************* - * @brief stopBloodPump +/*********************************************************************//** + * @brief + * The setBloodPumpControlSignalPWM function sets the PWM duty cycle for + * the blood pump to a given %. + * @details Inputs: none + * @details Outputs: blood pump stop signal activated, PWM duty cycle zeroed + * @param newPWM new duty cycle % to apply to PWM + * @return none + *************************************************************************/ +static void setBloodPumpControlSignalPWM( F32 newPWM ) +{ + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( newPWM * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief * The stopBloodPump function sets the blood pump stop signal. - * @details - * Inputs : none - * Outputs : blood pump stop signal activated, PWM duty cycle zeroed - * @param none + * @details Inputs: none + * @details Outputs: blood pump stop signal activated, PWM duty cycle zeroed * @return none *************************************************************************/ static void stopBloodPump( void ) { isBloodPumpOn = FALSE; - bloodPumpPWMDutyCyclePctSet = 0.0; + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET; etpwmSetCmpA( etpwmREG1, 0 ); - etpwmStopTBCLK(); SET_BP_STOP(); } -/************************************************************************* - * @brief releaseBloodPumpStop +/*********************************************************************//** + * @brief * The releaseBloodPumpStop function clears the blood pump stop signal. - * @details - * Inputs : none - * Outputs : blood pump stop signal - * @param none + * @details Inputs: none + * @details Outputs: blood pump stop signal * @return none *************************************************************************/ static void releaseBloodPumpStop( void ) { CLR_BP_STOP(); } -/************************************************************************* - * @brief setBloodPumpDirection - * The setBloodPumpDirection function sets the set blood pump direction to \n +/*********************************************************************//** + * @brief + * The setBloodPumpDirection function sets the set blood pump direction to * the given direction. - * @details - * Inputs : bloodPumpState - * Outputs : bloodPumpState - * @param dir : blood pump direction to set + * @details Inputs: bloodPumpState + * @details Outputs: bloodPumpState + * @param dir blood pump direction to set * @return none *************************************************************************/ static void setBloodPumpDirection( MOTOR_DIR_T dir ) @@ -531,313 +807,472 @@ break; default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_DIRECTION, dir ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_DIRECTION, dir ) break; } +} + +/*********************************************************************//** + * @brief + * The getTargetBloodFlowRate function gets the target blood flow rate. + * @details Inputs: targetBloodFlowRate + * @details Outputs: none + * @return the current target blood flow rate (in mL/min). + *************************************************************************/ +S32 getTargetBloodFlowRate( void ) +{ + return targetBloodFlowRate; } -/************************************************************************* - * @brief getPublishBloodFlowDataInterval - * The getPublishBloodFlowDataInterval function gets the blood flow data \n - * publication interval. - * @details - * Inputs : bloodFlowDataPublishInterval - * Outputs : none - * @param none - * @return the current blood flow data publication interval (in ms). - *************************************************************************/ -DATA_GET( U32, getPublishBloodFlowDataInterval, bloodFlowDataPublishInterval ) - -/************************************************************************* - * @brief getTargetBloodFlowRate - * The getTargetBloodFlowRate function gets the current target blood flow \n +/*********************************************************************//** + * @brief + * The getMeasuredBloodFlowRate function gets the measured blood flow * rate. - * @details - * Inputs : targetBloodFlowRate - * Outputs : none - * @param none - * @return the current target blood flow rate (in mL/min). - *************************************************************************/ -DATA_GET( S32, getTargetBloodFlowRate, targetBloodFlowRate ) - -/************************************************************************* - * @brief getMeasuredBloodFlowRate - * The getMeasuredBloodFlowRate function gets the measured blood flow \n - * rate. - * @details - * Inputs : measuredBloodFlowRate - * Outputs : none - * @param none + * @details Inputs: measuredBloodFlowRate + * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodFlowRate, measuredBloodFlowRate ) +F32 getMeasuredBloodFlowRate( void ) +{ + F32 result = measuredBloodFlowRate.data; -/************************************************************************* - * @brief getMeasuredBloodPumpRotorSpeed - * The getMeasuredBloodPumpRotorSpeed function gets the measured blood flow \n + if ( OVERRIDE_KEY == measuredBloodFlowRate.override ) + { + result = measuredBloodFlowRate.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpRotorSpeed function gets the measured blood flow * rate. - * @details - * Inputs : bloodPumpRotorSpeedRPM - * Outputs : none - * @param none + * @details Inputs: bloodPumpRotorSpeedRPM + * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodPumpRotorSpeed, bloodPumpRotorSpeedRPM ) +F32 getMeasuredBloodPumpRotorSpeed( void ) +{ + F32 result = bloodPumpRotorSpeedRPM.data; -/************************************************************************* - * @brief getMeasuredBloodPumpSpeed - * The getMeasuredBloodPumpSpeed function gets the measured blood flow \n + if ( OVERRIDE_KEY == bloodPumpRotorSpeedRPM.override ) + { + result = bloodPumpRotorSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpSpeed function gets the measured blood flow * rate. - * @details - * Inputs : bloodPumpSpeedRPM - * Outputs : none - * @param none + * @details Inputs: bloodPumpSpeedRPM + * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodPumpSpeed, bloodPumpSpeedRPM ) +F32 getMeasuredBloodPumpSpeed( void ) +{ + F32 result = bloodPumpSpeedRPM.data; -/************************************************************************* - * @brief getMeasuredBloodPumpMCSpeed - * The getMeasuredBloodPumpMCSpeed function gets the measured blood pump \n + if ( OVERRIDE_KEY == bloodPumpSpeedRPM.override ) + { + result = bloodPumpSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpMCSpeed function gets the measured blood pump * speed. - * @details - * Inputs : adcBloodPumpMCSpeedRPM - * Outputs : none - * @param none + * @details Inputs: adcBloodPumpMCSpeedRPM + * @details Outputs: none * @return the current blood pump speed (in RPM). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodPumpMCSpeed, adcBloodPumpMCSpeedRPM ) +F32 getMeasuredBloodPumpMCSpeed( void ) +{ + F32 result = adcBloodPumpMCSpeedRPM.data; -/************************************************************************* - * @brief getMeasuredBloodPumpMCCurrent - * The getMeasuredBloodPumpMCCurrent function gets the measured blood pump \n + if ( OVERRIDE_KEY == adcBloodPumpMCSpeedRPM.override ) + { + result = adcBloodPumpMCSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpMCCurrent function gets the measured blood pump * current. - * @details - * Inputs : adcBloodPumpMCCurrentmA - * Outputs : none - * @param none + * @details Inputs: adcBloodPumpMCCurrentmA + * @details Outputs: none * @return the current blood pump current (in mA). *************************************************************************/ -DATA_GET( F32, getMeasuredBloodPumpMCCurrent, adcBloodPumpMCCurrentmA ) +F32 getMeasuredBloodPumpMCCurrent( void ) +{ + F32 result = adcBloodPumpMCCurrentmA.data; -/************************************************************************* - * @brief publishBloodFlowData - * The publishBloodFlowData function publishes blood flow data at the set \n + if ( OVERRIDE_KEY == adcBloodPumpMCCurrentmA.override ) + { + result = adcBloodPumpMCCurrentmA.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishBloodFlowData function publishes blood flow data at the set * interval. - * @details - * Inputs : target flow rate, measured flow rate, measured MC speed, \n + * @details Inputs: target flow rate, measured flow rate, measured MC speed, * measured MC current - * Outputs : Blood flow data is published to CAN bus. - * @param none + * @details Outputs: Blood flow data is published to CAN bus. * @return none *************************************************************************/ static void publishBloodFlowData( void ) { - // publish blood flow data on interval - if ( ++bloodFlowDataPublicationTimerCounter > getPublishBloodFlowDataInterval() ) - { - S32 flowStPt = (S32)getTargetBloodFlowRate(); - F32 measFlow = getMeasuredBloodFlowRate(); - F32 measRotSpd = getMeasuredBloodPumpRotorSpeed(); - F32 measSpd = getMeasuredBloodPumpSpeed(); - F32 measMCSpd = getMeasuredBloodPumpMCSpeed(); - F32 measMCCurr = getMeasuredBloodPumpMCCurrent(); -#ifdef DEBUG_ENABLED - // TODO - temporary debug code - remove later - S32 pwm = (S32)( 100.0 * bloodPumpPWMDutyCyclePctSet ); - char debugFlowStr[ 256 ]; - - sprintf( debugFlowStr, "Target Flow:%5d, Meas. Flow:%5d, Speed:%5d RPM, Current:%5d mA, PWM:%5d \n", flowStPt, (S32)measFlow, (S32)measMCSpd, (S32)measMCCurr, pwm ); - sendDebugData( (U08*)debugFlowStr, strlen(debugFlowStr) ); -#endif - broadcastBloodFlowData( flowStPt, measFlow, measRotSpd, measSpd, measMCSpd, measMCCurr ); - //broadcastBloodFlowData( 500, 501.0, 100.0, 1000.0, -1001.25, 750.0 ); + // Publish blood flow data on interval + if ( ++bloodFlowDataPublicationTimerCounter >= getU32OverrideValue( &bloodFlowDataPublishInterval ) ) + { + BLOOD_PUMP_STATUS_PAYLOAD_T payload; + + payload.setPoint = targetBloodFlowRate; + payload.measFlow = getMeasuredBloodFlowRate(); + payload.measRotorSpd = getMeasuredBloodPumpRotorSpeed(); + payload.measPumpSpd = getMeasuredBloodPumpSpeed(); + payload.measMCSpd = getMeasuredBloodPumpMCSpeed(); + payload.measMCCurr = getMeasuredBloodPumpMCCurrent(); + payload.pwmDC = bloodPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + payload.rotorCount = getBloodPumpRotorCount(); + broadcastData( MSG_ID_BLOOD_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( BLOOD_PUMP_STATUS_PAYLOAD_T ) ); bloodFlowDataPublicationTimerCounter = 0; } } -/************************************************************************* - * @brief resetBloodFlowMovingAverage - * The resetBloodFlowMovingAverage function re-sizes and re-initializes the \n - * blood flow moving average sample buffer. - * @details - * Inputs : none - * Outputs : flowReadingsTotal, flowReadingsIdx, flowReadingsCount all set to zero. - * @param initFlow : the new blood flow set pt. - * @param flowDir : the new set direction +/*********************************************************************//** + * @brief + * The resetBloodPumpRPMMovingAverage function re-initializes the pump speed + * moving average sample buffer. + * @details Inputs: none + * @details Outputs: rpmReadingsTotal, rpmReadingsIdx, rpmReadingsCount all set to zero. + * @return none + *************************************************************************/ +static void resetBloodPumpRPMMovingAverage( void ) +{ + rpmReadingsIdx = 0; + rpmReadingsCount = 0; + rpmReadingsTotal = 0.0; + filteredBloodPumpSpeed = 0.0; +} + +/*********************************************************************//** + * @brief + * The filterBloodPumpRPMReadings function adds a new pump speed sample to + * the filter. + * @details Inputs: none + * @details Outputs: rpmReadings[], rpmReadingsIdx, rpmReadingsCount, rpmReadingsTotal + * @param rpm newest blood pump speed (in RPM) sample to add to filter + * @return none + *************************************************************************/ +static void filterBloodPumpRPMReadings( F32 rpm ) +{ + if ( rpmReadingsCount >= SIZE_OF_ROLLING_AVG ) + { + rpmReadingsTotal -= rpmReadings[ rpmReadingsIdx ]; + } + rpmReadings[ rpmReadingsIdx ] = rpm; + rpmReadingsTotal += rpm; + rpmReadingsIdx = INC_WRAP( rpmReadingsIdx, 0, SIZE_OF_ROLLING_AVG - 1 ); + rpmReadingsCount = INC_CAP( rpmReadingsCount, SIZE_OF_ROLLING_AVG ); + filteredBloodPumpSpeed = rpmReadingsTotal / (F32)rpmReadingsCount; +} + +/*********************************************************************//** + * @brief + * The updateBloodPumpSpeedAndDirectionFromHallSensors function calculates + * the blood pump motor speed and direction from hall sensor counter on + * a 1 second interval. + * @details Inputs: bpLastMotorHallSensorCount, bpMotorSpeedCalcTimerCtr, current count from FPGA + * @details Outputs: bpMotorDirectionFromHallSensors, bloodPumpSpeedRPM * @return none *************************************************************************/ -static void resetBloodFlowMovingAverage( void ) +static void updateBloodPumpSpeedAndDirectionFromHallSensors( void ) { - flowReadingsTotal = 0.0; - flowReadingsIdx = 0; - flowReadingsCount = 0; - bpControlTimerCounter = 0; + if ( ++bpMotorSpeedCalcTimerCtr >= BP_SPEED_CALC_INTERVAL ) + { + U16 bpMotorHallSensorCount = getFPGABloodPumpHallSensorCount(); + U16 last = bpLastMotorHallSensorCounts[ bpMotorSpeedCalcIdx ]; + U32 nextIdx = INC_WRAP( bpMotorSpeedCalcIdx, 0, BP_SPEED_CALC_BUFFER_LEN - 1 ); + U16 incDelta = u16DiffWithWrap( bpLastMotorHallSensorCounts[ nextIdx ], bpMotorHallSensorCount ); + U16 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); + U16 spdDelta; + S16 delta; + + // Determine blood pump speed/direction from delta hall sensor count since last interval + if ( incDelta < decDelta ) + { + spdDelta = incDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; + } + else + { + spdDelta = decDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN * -1.0; + } + + // Keep a running 32-bit edge count used for safety check on volume in some functions + delta = u16BiDiffWithWrap( last, bpMotorHallSensorCount ); + bloodPumpMotorEdgeCount += ( delta >= 0 ? (U16)delta : 0 ); + + // Update last count for next time + bpLastMotorHallSensorCounts[ nextIdx ] = bpMotorHallSensorCount; + bpMotorSpeedCalcIdx = nextIdx; + bpMotorSpeedCalcTimerCtr = 0; + } } -/************************************************************************* - * @brief filterBloodFlowReadings - * The filterBloodFlowReadings function adds a new flow sample to the filter \n - * if decimation rate for current set point calls for it. - * @details - * Inputs : none - * Outputs : flowReadings[], flowReadingsIdx, flowReadingsCount - * @param flow : newest blood flow sample +/*********************************************************************//** + * @brief + * The checkBloodPumpRotor function checks the rotor for the blood + * 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: bpStopAtHomePosition, bpHomeStartTime, bpRotorRevStartTime + * @details Outputs: pump may be stopped if homing, bloodPumpRotorSpeedRPM may be set to zero. * @return none *************************************************************************/ -static void filterBloodFlowReadings( F32 flow ) +static void checkBloodPumpRotor( void ) { - BOOL addSampleToFilter = FALSE; + F32 rotorSpeed = getMeasuredBloodPumpRotorSpeed(); - if ( ( targetBloodFlowRate.data < MIN_BLOOD_FLOW_RATE ) || ( targetBloodFlowRate.data >= MAX_BLOOD_FLOW_RATE ) ) + // If homing, check timeout + if ( ( TRUE == bpStopAtHomePosition ) && ( TRUE == didTimeout( bpHomeStartTime, BP_HOME_TIMEOUT_MS ) ) ) { - addSampleToFilter = TRUE; + signalBloodPumpHardStop(); + bpStopAtHomePosition = FALSE; + // TODO - alarm??? } - else - { - switch ( flowReadingsTmrCtr ) - { - case 0: - addSampleToFilter = TRUE; - break; - case 1: - addSampleToFilter = FALSE; - break; - - case 2: - if ( targetBloodFlowRate.data >= 400 ) - { - addSampleToFilter = TRUE; - } - break; - - case 3: - if ( targetBloodFlowRate.data >= 200 ) - { - addSampleToFilter = TRUE; - } - break; - - case 4: - if ( targetBloodFlowRate.data >= 300 ) - { - addSampleToFilter = TRUE; - } - break; - - default: - // TODO - s/w fault? - break; - } + // Ensure rotor speed below maximum + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed > BP_MAX_ROTOR_SPEED_RPM ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed ) } - if ( TRUE == addSampleToFilter ) + // If pump is stopped or running very slowly, set rotor speed to zero + if ( TRUE == didTimeout( bpRotorRevStartTime, BP_MAX_ROTOR_HALL_INTERVAL_MS ) ) { - 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 ); - measuredBloodFlowRate.data = flowReadingsTotal / (F32)flowReadingsCount; + bloodPumpRotorSpeedRPM.data = 0.0; } - - flowReadingsTmrCtr = INC_WRAP( flowReadingsTmrCtr, 0, MAX_FLOW_FILTER_INTERVAL - 1 ); } -/************************************************************************* - * @brief checkBloodPumpDirection - * The checkBloodPumpDirection function checks the set direction vs. \n +/*********************************************************************//** + * @brief + * The checkBloodPumpDirection function checks the set direction vs. * the direction implied by the sign of the measured MC speed. - * @details - * Inputs : - * Outputs : - * @param none + * @details Inputs: + * @details Outputs: * @return none *************************************************************************/ static void checkBloodPumpDirection( void ) { - MOTOR_DIR_T bpMCDir; - if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) { - // check set direction vs. direction from sign of motor controller speed - bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); - if ( bloodPumpDirectionSet != bpMCDir ) - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpMCDir ) - } - } + MOTOR_DIR_T bpMCDir, bpDir; + BOOL isDirIncorrect; + U08 dirErrorCnt = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + F32 measMCSpeed = getMeasuredBloodPumpMCSpeed(); + BOOL minDirSpeed = ( measMCSpeed >= BP_MIN_DIR_CHECK_SPEED_RPM ? TRUE : FALSE ); + BOOL isHallSensorFailed = ( TRUE == minDirSpeed && lastBloodPumpDirectionCount != dirErrorCnt ? TRUE : FALSE ); + + // Check pump direction error count + if ( ( TRUE == isHallSensorFailed ) && ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BP_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_BLOOD_PUMP ) + } + } + lastBloodPumpDirectionCount = dirErrorCnt; + + bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + bpDir = ( getMeasuredBloodPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + + // Check set direction vs. direction from hall sensors vs. direction from sign of motor controller speed + isDirIncorrect = ( ( ( bloodPumpDirectionSet != bpDir ) || ( bloodPumpDirectionSet != bpMCDir ) ) && ( TRUE == minDirSpeed ) ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + if ( bloodPumpDirectionSet != bpDir ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpDir ) + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpMCDir ) + } + } + } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK ); + } } -/************************************************************************* - * @brief checkBloodPumpMCCurrent - * The checkBloodPumpMCCurrent function checks the measured MC current vs. \n - * the set state of the blood pump (stopped or running). - * @details - * Inputs : - * Outputs : - * @param none +/*********************************************************************//** + * @brief + * The checkBloodPumpSpeeds function checks several aspects of the blood 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 commanded 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: targetBloodFlowRate, bloodPumpSpeedRPM, bloodPumpRotorSpeedRPM + * @details Outputs: alarm(s) may be triggered * @return none *************************************************************************/ -static void checkBloodPumpMCCurrent( void ) +static void checkBloodPumpSpeeds( void ) { - F32 bpCurr; + F32 measMotorSpeed = fabs( getMeasuredBloodPumpSpeed() ); + F32 measMCMotorSpeed = fabs( getMeasuredBloodPumpMCSpeed() ); - // blood pump should be off - if ( BLOOD_PUMP_OFF_STATE == bloodPumpState ) - { - bpCurr = fabs( getMeasuredBloodPumpMCCurrent() ); - if ( bpCurr > BP_MAX_CURR_WHEN_STOPPED_MA ) - { - bpCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( bpCurrErrorDurationCtr > BP_MAX_CURR_ERROR_DURATION_MS ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, getMeasuredBloodPumpMCCurrent() ); - } + // Check for pump running while commanded off + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, + ( 0 == targetBloodFlowRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); + activateSafetyShutdown(); } - else - { - bpCurrErrorDurationCtr = 0; - } } - // blood pump should be running - else + + // Checks that only occur when pump is running (and beyond ramp). + if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) { - bpCurr = fabs( getMeasuredBloodPumpMCCurrent() ); - if ( ( bpCurr < BP_MIN_CURR_WHEN_RUNNING_MA ) || ( bpCurr > BP_MAX_CURR_WHEN_RUNNING_MA ) ) - { - bpCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( bpCurrErrorDurationCtr > BP_MAX_CURR_ERROR_DURATION_MS ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, getMeasuredBloodPumpMCCurrent() ); - } + F32 cmdMotorSpeed = BP_PWM_TO_MOTOR_SPEED_RPM( bloodPumpPWMDutyCyclePctSet ); + F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); + F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); + F32 measRotorSpeed = getMeasuredBloodPumpRotorSpeed(); + F32 measMotorSpeedInRotorRPM = measMotorSpeed / BP_GEAR_RATIO; + F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); + + // Check measured motor speed vs. commanded motor speed while controlling to target + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, + ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); + } } - else - { - bpCurrErrorDurationCtr = 0; + + // Check measured rotor speed vs. measured motor speed while controlling to target + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); + } } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK ); + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK ); } } -/************************************************************************* - * @brief execBloodFlowTest - * The execBloodFlowTest function executes the state machine for the \n - * BloodFlow self test. - * @details - * Inputs : none - * Outputs : none - * @param none - * @return the current state of the BloodFlow self test. +/*********************************************************************//** + * @brief + * The checkBloodPumpMCCurrent function checks the measured MC current vs. + * the set state of the blood pump (stopped or running). + * @details Inputs: BP motor controller measured current. + * @details Outputs: Alarm triggered it current too high. + * @return none *************************************************************************/ -SELF_TEST_STATUS_T execBloodFlowTest( void ) +static void checkBloodPumpMCCurrent( void ) { - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; + F32 const bpCurr = fabs( getMeasuredBloodPumpMCCurrent() ); + // Check blood pump current during off state + BOOL const isOffMCCurrentBad = ( ( BLOOD_PUMP_OFF_STATE == bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_STOPPED_MA ) ? TRUE : FALSE ); + // Check blood pump current during running state + BOOL const isRunningMCCurrentBad = ( ( BLOOD_PUMP_OFF_STATE != bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_RUNNING_MA ) ? TRUE : FALSE ); + + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) && + ( FALSE == isAlarmActive( ALARM_ID_HD_AC_POWER_LOST ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, bpCurr ); + } + } +} + +/*********************************************************************//** + * @brief + * The checkBloodPumpFlowRate function checks the measured blood flow rate + * is in range. + * @details Inputs: measuredBloodFlowRate + * @details Outputs: alarm may be triggered + * @return none + *************************************************************************/ +static void checkBloodPumpFlowRate( void ) +{ +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + F32 flow = getMeasuredBloodFlowRate(); + + // Range check on measure BP flow rate. + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, ( flow > BP_MAX_FLOW_RATE ) || ( flow < BP_MIN_FLOW_RATE ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); + } + } +} - // TODO - implement self test(s) +/*********************************************************************//** + * @brief + * The execBloodFlowTest function executes the state machine for the + * BloodFlow self-test. + * @details Inputs: bloodPumpCalRecord + * @details Outputs: none + * @return the current state of the BloodFlow self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execBloodFlowTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&bloodPumpCalRecord, 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; } @@ -846,16 +1281,15 @@ /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ - - -/************************************************************************* - * @brief testSetBloodFlowDataPublishIntervalOverride - * The testSetBloodFlowDataPublishIntervalOverride function overrides the \n + + +/*********************************************************************//** + * @brief + * The testSetBloodFlowDataPublishIntervalOverride function overrides the * blood flow data publish interval. - * @details - * Inputs : none - * Outputs : bloodFlowDataPublishInterval - * @param value : override blood flow data publish interval with (in ms) + * @details Inputs: none + * @details Outputs: bloodFlowDataPublishInterval + * @param value override blood flow data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodFlowDataPublishIntervalOverride( U32 value ) @@ -874,13 +1308,12 @@ return result; } -/************************************************************************* - * @brief testResetBloodFlowDataPublishIntervalOverride - * The testResetBloodFlowDataPublishIntervalOverride function resets the override \n +/*********************************************************************//** + * @brief + * The testResetBloodFlowDataPublishIntervalOverride function resets the override * of the blood flow data publish interval. - * @details - * Inputs : none - * Outputs : bloodFlowDataPublishInterval + * @details Inputs: none + * @details Outputs: bloodFlowDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodFlowDataPublishIntervalOverride( void ) @@ -897,88 +1330,309 @@ return result; } -/************************************************************************* - * @brief testSetTargetBloodFlowRateOverride and testResetTargetBloodFlowRateOverride - * The testSetTargetBloodFlowRateOverride function overrides the target \n - * blood flow rate. \n - * The testResetTargetBloodFlowRateOverride function resets the override of the \n - * target blood flow rate. - * @details - * Inputs : none - * Outputs : targetBloodFlowRate - * @param value : override target blood flow rate (in mL/min) +/*********************************************************************//** + * @brief + * The testSetTargetBloodFlowRateOverride function overrides the target + * blood flow rate. + * @details Inputs: none + * @details Outputs: targetBloodFlowRate + * @param value override target blood 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 *************************************************************************/ -DATA_OVERRIDE_FUNC( S32, testSetTargetBloodFlowRateOverride, testResetTargetBloodFlowRateOverride, targetBloodFlowRate ) +BOOL testSetTargetBloodFlowRateOverride( S32 value, U32 ctrlMode ) +{ + BOOL result = FALSE; -/************************************************************************* - * @brief testSetMeasuredBloodFlowRateOverride and testResetMeasuredBloodFlowRateOverride - * The testResetMeasuredBloodFlowRateOverride function overrides the measured \n - * blood flow rate. \n - * The testResetOffButtonStateOverride function resets the override of the \n + if ( TRUE == isTestingActivated() ) + { + MOTOR_DIR_T dir; + + if ( value < 0 ) + { + dir = MOTOR_DIR_REVERSE; + } + else + { + dir = MOTOR_DIR_FORWARD; + } + if ( ctrlMode < NUM_OF_PUMP_CONTROL_MODES ) + { + result = setBloodPumpTargetFlowRate( abs(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodFlowRateOverride function overrides the measured + * blood flow rate. + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate + * @param value override measured blood flow rate (in mL/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodFlowRateOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + measuredBloodFlowRate.ovData = value; + measuredBloodFlowRate.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodFlowRateOverride function resets the override of the * measured blood flow rate. - * @details - * Inputs : none - * Outputs : measuredBloodFlowRate - * @param value : override measured blood flow rate (in mL/min) + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodFlowRateOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + measuredBloodFlowRate.override = OVERRIDE_RESET; + measuredBloodFlowRate.ovData = measuredBloodFlowRate.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpRotorSpeedOverride function overrides the measured + * blood pump rotor speed. + * @details Inputs: none + * @details Outputs: bloodPumpRotorSpeedRPM + * @param value override measured blood pump rotor speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ -DATA_OVERRIDE_FUNC( F32, testSetMeasuredBloodFlowRateOverride, testResetMeasuredBloodFlowRateOverride, measuredBloodFlowRate ) +BOOL testSetMeasuredBloodPumpRotorSpeedOverride( F32 value ) +{ + BOOL result = FALSE; -/************************************************************************* - * @brief testSetMeasuredBloodPumpRotorSpeedOverride and testResetMeasuredBloodPumpRotorSpeedOverride - * The testSetMeasuredBloodPumpRotorSpeedOverride function overrides the measured \n - * blood pump rotor speed. \n - * The testResetMeasuredBloodPumpRotorSpeedOverride function resets the override of the \n + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorSpeedRPM.ovData = value; + bloodPumpRotorSpeedRPM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpRotorSpeedOverride function resets the override of the * measured blood pump rotor speed. - * @details - * Inputs : none - * Outputs : bloodPumpRotorSpeedRPM - * @param value : override measured blood pump rotor speed (in RPM) + * @details Inputs: none + * @details Outputs: bloodPumpRotorSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpRotorSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorSpeedRPM.override = OVERRIDE_RESET; + bloodPumpRotorSpeedRPM.ovData = bloodPumpRotorSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpSpeedOverride function overrides the measured + * blood pump motor speed. + * @details Inputs: none + * @details Outputs: bloodPumpSpeedRPM + * @param value override measured blood pump motor speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ -DATA_OVERRIDE_FUNC( F32, testSetMeasuredBloodPumpRotorSpeedOverride, testResetMeasuredBloodPumpRotorSpeedOverride, bloodPumpRotorSpeedRPM ) +BOOL testSetMeasuredBloodPumpSpeedOverride( F32 value ) +{ + BOOL result = FALSE; -/************************************************************************* - * @brief testSetMeasuredBloodPumpSpeedOverride and testResetMeasuredBloodPumpSpeedOverride - * The testSetMeasuredBloodPumpSpeedOverride function overrides the measured \n - * blood pump motor speed. \n - * The testResetMeasuredBloodPumpSpeedOverride function resets the override of the \n + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpSpeedRPM.ovData = value; + bloodPumpSpeedRPM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpSpeedOverride function resets the override of the * measured blood pump motor speed. - * @details - * Inputs : none - * Outputs : bloodPumpSpeedRPM - * @param value : override measured blood pump motor speed (in RPM) + * @details Inputs: none + * @details Outputs: bloodPumpSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpSpeedRPM.override = OVERRIDE_RESET; + bloodPumpSpeedRPM.ovData = bloodPumpSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpMCSpeedOverride function overrides the measured + * blood pump motor speed. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCSpeedRPM + * @param value override measured blood pump speed (in RPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ -DATA_OVERRIDE_FUNC( F32, testSetMeasuredBloodPumpSpeedOverride, testResetMeasuredBloodPumpSpeedOverride, bloodPumpSpeedRPM ) +BOOL testSetMeasuredBloodPumpMCSpeedOverride( F32 value ) +{ + BOOL result = FALSE; -/************************************************************************* - * @brief testSetMeasuredBloodPumpMCSpeedOverride and testResetMeasuredBloodPumpMCSpeedOverride - * The testSetMeasuredBloodPumpMCSpeedOverride function overrides the measured \n - * blood pump motor speed. \n - * The testResetMeasuredBloodPumpMCSpeedOverride function resets the override of the \n + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCSpeedRPM.ovData = value; + adcBloodPumpMCSpeedRPM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpMCSpeedOverride function resets the override of the * measured blood pump motor speed. - * @details - * Inputs : none - * Outputs : adcBloodPumpMCSpeedRPM - * @param value : override measured blood pump speed (in RPM) + * @details Inputs: none + * @details Outputs: adcBloodPumpMCSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpMCSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCSpeedRPM.override = OVERRIDE_RESET; + adcBloodPumpMCSpeedRPM.ovData = adcBloodPumpMCSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpMCCurrentOverride function overrides the measured + * blood pump motor current. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCCurrentmA + * @param value override measured blood pump current (in mA) * @return TRUE if override successful, FALSE if not *************************************************************************/ -DATA_OVERRIDE_FUNC( F32, testSetMeasuredBloodPumpMCSpeedOverride, testResetMeasuredBloodPumpMCSpeedOverride, adcBloodPumpMCSpeedRPM ) +BOOL testSetMeasuredBloodPumpMCCurrentOverride( F32 value ) +{ + BOOL result = FALSE; -/************************************************************************* - * @brief testSetMeasuredBloodPumpMCCurrentOverride and testResetMeasuredBloodPumpMCCurrentOverride - * The testSetMeasuredBloodPumpMCCurrentOverride function overrides the measured \n - * blood pump motor current. \n - * The testResetMeasuredBloodPumpMCCurrentOverride function resets the override of the \n + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCCurrentmA.ovData = value; + adcBloodPumpMCCurrentmA.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpMCCurrentOverride function resets the override of the * measured blood pump motor current. - * @details - * Inputs : none - * Outputs : adcBloodPumpMCCurrentmA - * @param value : override measured blood pump current (in mA) - * @return TRUE if override successful, FALSE if not + * @details Inputs: none + * @details Outputs: adcBloodPumpMCCurrentmA + * @return TRUE if reset successful, FALSE if not *************************************************************************/ -DATA_OVERRIDE_FUNC( F32, testSetMeasuredBloodPumpMCCurrentOverride, testResetMeasuredBloodPumpMCCurrentOverride, adcBloodPumpMCCurrentmA ) +BOOL testResetMeasuredBloodPumpMCCurrentOverride( void ) +{ + BOOL result = FALSE; + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCCurrentmA.override = OVERRIDE_RESET; + adcBloodPumpMCCurrentmA.ovData = adcBloodPumpMCCurrentmA.ovInitData; + } + return result; +} + +/*********************************************************************//** + * @brief + * The testSetBloodPumpRotorCountOverride function overrides the blood pump + * rotor counter value. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @param value override blood pump rotor counter value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetBloodPumpRotorCountOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorCounter.ovData = value; + bloodPumpRotorCounter.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBloodPumpRotorCountOverride function resets the override + * of the blood pump rotor counter. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetBloodPumpRotorCountOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorCounter.override = OVERRIDE_RESET; + bloodPumpRotorCounter.ovData = bloodPumpRotorCounter.ovInitData; + } + + return result; +} + +/**@}*/