Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r30b1f6126c37f7b99cf699f63b4bcee9d1a1745f -rabbad386f4cc94f315300dffef321fe8c03fbd52 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 30b1f6126c37f7b99cf699f63b4bcee9d1a1745f) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision abbad386f4cc94f315300dffef321fe8c03fbd52) @@ -20,10 +20,6 @@ #include "can.h" #include "etpwm.h" -// TODO - Test includes - remove later -#include "DialInFlow.h" -#include "PresOccl.h" - #include "BloodFlow.h" #include "FPGA.h" #include "InternalADC.h" @@ -35,7 +31,8 @@ #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TaskPriority.h" -#include "Timers.h" +#include "Timers.h" +#include "Utilities.h" /** * @addtogroup BloodFlow @@ -49,11 +46,11 @@ #define MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE 0.008 ///< Max duty cycle change when ramping up ~ 100 mL/min/s. #define MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE 0.016 ///< Max duty cycle change when ramping down ~ 200 mL/min/s. -#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 MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89% +#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10% /// Interval (ms/task time) at which the blood pump is controlled. -#define BP_CONTROL_INTERVAL ( 10000 / TASK_GENERAL_INTERVAL ) +static const U32 BP_CONTROL_INTERVAL = ( 10000 / TASK_GENERAL_INTERVAL ); #define BP_P_COEFFICIENT 0.00035 ///< P term for blood pump control #define BP_I_COEFFICIENT 0.00035 ///< I term for blood pump control @@ -62,33 +59,42 @@ /// Interval (ms/task time) at which the blood pump speed is calculated (every 40 ms). #define BP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) /// Number of hall sensor counts kept in buffer to hold last 1 second of count data. -#define BP_SPEED_CALC_BUFFER_LEN ( 1000 / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) -#define BP_HALL_EDGE_COUNTS_PER_REV 48 ///< Number of hall sensor edge counts per motor revolution. +#define BP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define BP_MAX_ROTOR_SPEED_RPM 100.0 ///< Maximum rotor speed allowed for blood pump. #define BP_MAX_FLOW_VS_SPEED_DIFF_RPM 200.0 ///< Maximum difference between measured speed and speed implied by measured flow. #define BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0 ///< Maximum motor speed (RPM) while motor is commanded off. #define BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0 ///< Maximum difference in speed between motor and rotor (in rotor RPM). -#define BP_MAX_MOTOR_SPEED_ERROR_RPM 300.0 ///< Maximum difference in speed between measured and commanded RPM. -#define BP_FLOW_VS_SPEED_PERSIST ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) for flow vs. motor speed error condition. -#define BP_OFF_ERROR_PERSIST ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) for motor off error condition. -#define BP_MOTOR_SPEED_ERROR_PERSIST ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) motor speed error condition. -#define BP_ROTOR_SPEED_ERROR_PERSIST ((12 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) rotor speed error condition. -#define BP_DIRECTION_ERROR_PERSIST (250 / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) pump direction error condition. -#define BP_MAX_ROTOR_SPEED_ERROR_PERSIST ((1 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL) ///< Persist time (task intervals) blood pump rotor speed too fast error condition. +#define BP_MAX_MOTOR_SPEED_ERROR_RPM 300.0 ///< Maximum difference in speed between measured and commanded RPM. +/// Persist time (task intervals) for flow vs. motor speed error condition. +static const U32 BP_FLOW_VS_SPEED_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (task intervals) for motor off error condition. +static const U32 BP_OFF_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (task intervals) motor speed error condition. +static const U32 BP_MOTOR_SPEED_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (task intervals) rotor speed error condition. +static const U32 BP_ROTOR_SPEED_ERROR_PERSIST = ( 12 * MS_PER_SECOND ); +/// Persist time (task intervals) pump direction error condition. +static const U32 BP_DIRECTION_ERROR_PERSIST = ( 250 ); +/// Persist time period blood pump rotor speed too fast error condition. +static const U32 BP_MAX_ROTOR_SPEED_ERROR_PERSIST = ( 1 * MS_PER_SECOND ); #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 2000.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 - -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + +#ifndef V2_0_SYSTEM + #define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle +#else + #define BP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle +#endif #define BP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for blood pump motor #define BP_REV_PER_LITER 150.0 ///< Rotor revolutions per liter #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.0 ///< Blood pump motor to blood pump gear ratio -#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00028 ///< ~28 BP motor RPM = 1% PWM duty cycle #define BP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed /// Conversion factor 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 ) @@ -104,25 +110,35 @@ #define FLOW_SIG_STRGTH_ALARM_PERSIST ( 5 * MS_PER_SECOND ) #define MIN_FLOW_SIG_STRENGTH 0.9 ///< Minimum flow sensor signal strength (90%). -#define BFM_SENSOR_PARAM_CORRUPT_STATUS 0x7 ///< Blood flow meter NVM parameter status. +/// Blood flow fast read timeout alarm persistence. +#define BLOOD_FLOW_FAST_READ_TO_PERSIST 100 +/// Blood flow slow read timeout alarm persistence. +#define BLOOD_FLOW_SLOW_READ_TO_PERSIST ( MS_PER_SECOND * 3 ) +/// Blood flow comm error persistence. +#define BLOOD_FLOW_COMM_ERROR_PERSIST MS_PER_SECOND + +#define BFM_SENSOR_CONNECTED_STATUS 0x00 ///< Blood flow meter connected status. +#define BFM_SENSOR_PARAM_CORRUPT_STATUS 0x07 ///< Blood flow meter NVM parameter status. + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. /// Enumeration of blood pump controller states. typedef enum BloodPump_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_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 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_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 @@ -145,8 +161,6 @@ 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. -static F32 bloodFlowCalGain = 1.0; ///< Blood flow calibration gain. -static F32 bloodFlowCalOffset = 0.0; ///< Blood flow calibration offset. /// 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 }; @@ -170,20 +184,17 @@ 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 U32 errorBloodFlowVsMotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for flow vs. motor speed error condition. -static U32 errorBloodMotorOffPersistTimerCtr = 0; ///< Persistence timer counter for motor off check error condition. -static U32 errorBloodMotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for motor speed error condition. -static U32 errorBloodRotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for rotor speed error condition. -static U32 errorBloodPumpDirectionPersistTimerCtr = 0; ///< Persistence timer counter for pump direction error condition. -static U32 errorBloodPumpRotorTooFastPersistTimerCtr = 0; ///< Persistence timer counter for pump rotor too fast error condition. +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; ///< Number of samples in flow rolling average buffer. -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; ///< Number of samples in flow rolling average buffer +static U08 lastBloodFlowFastPacketReadCtr = 0; ///< Previous read counter for the blood flow fast packets. +static U08 lastBloodFlowSlowPacketReadCtr = 0; ///< Previous read counter for the blood flow slow packets. +static U08 lastBloodPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA. +static U08 lastBloodFlowCommErrorCount = 0; ///< Previous BP flow sensor comm error count. +static HD_FLOW_SENSORS_CAL_RECORD_T bloodFlowCalRecord; ///< Blood flow sensor calibration record. -static U32 bpCurrErrorDurationCtr = 0; ///< Used for tracking persistence of bp current errors - // ********** private function prototypes ********** static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ); @@ -203,7 +214,8 @@ static void checkBloodPumpSpeeds( void ); static void checkBloodPumpFlowAgainstSpeed( void ); static void checkBloodPumpMCCurrent( void ); -static void checkBloodFlowSensorSignalStrength( void ); +static void checkBloodFlowSensorSignalStrength( void ); +static BOOL processCalibrationData( void ); static U32 getPublishBloodFlowDataInterval( void ); /*********************************************************************//** @@ -235,8 +247,18 @@ BP_P_COEFFICIENT, BP_I_COEFFICIENT, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); - // Initialize persistent alarm for flow sensor signal strength too low - initPersistentAlarm( ALARM_ID_BLOOD_FLOW_SIGNAL_STRENGTH_TOO_LOW, FLOW_SIG_STRGTH_ALARM_PERSIST, FLOW_SIG_STRGTH_ALARM_PERSIST ); + // Initialize persistent alarm for flow sensor + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, 0, BP_FLOW_VS_SPEED_PERSIST ); + 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 ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, 0, BP_MAX_ROTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_FLOW_SIGNAL_STRENGTH_TOO_LOW, 0, FLOW_SIG_STRGTH_ALARM_PERSIST ); + initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, 0, BP_MAX_CURR_ERROR_DURATION_MS ); + initPersistentAlarm( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR, 0, BLOOD_FLOW_FAST_READ_TO_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR, 0, BLOOD_FLOW_SLOW_READ_TO_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR, 0, BLOOD_FLOW_COMM_ERROR_PERSIST ); } /*********************************************************************//** @@ -383,7 +405,7 @@ *************************************************************************/ U32 getBloodPumpMotorCount( void ) { - return bloodPumpMotorEdgeCount / BP_HALL_EDGE_COUNTS_PER_REV; + return bloodPumpMotorEdgeCount; } /*********************************************************************//** @@ -416,21 +438,62 @@ * @brief * The execBloodFlowMonitor function executes the blood flow monitor. * @details Inputs: none - * @details Outputs: measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, adcBloodPumpMCCurrentmA + * @details Outputs: measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, + * adcBloodPumpMCCurrentmA * @return none *************************************************************************/ void execBloodFlowMonitor( void ) { + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + HD_OP_MODE_T opMode = getCurrentOperationMode(); U16 bpRPM = getIntADCReading( INT_ADC_BLOOD_PUMP_SPEED ); U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); + U08 fpReadCtr = getFPGABloodFlowFastPacketReadCounter(); + U08 spReadCtr = getFPGABloodFlowSlowPacketReadCounter(); + U08 flowErrorCtr = getFPGABloodFlowErrorCounter(); + U08 flowStatus = getFPGABloodFlowMeterStatus(); -#ifndef V1_5_SYSTEM - F32 bpFlow = ( getFPGABloodFlow() * bloodFlowCalGain ) + bloodFlowCalOffset; -#else - F32 bpFlow = ( ( getFPGABloodFlow() * -1.0 ) * bloodFlowCalGain ) + bloodFlowCalOffset; // Blood flow sensor installed backwards on HD + F32 fpgaBloodFlow = getFPGABloodFlow(); + F32 bpFlow = pow(fpgaBloodFlow, 4) * bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].fourthOrderCoeff + + pow(fpgaBloodFlow, 3) * bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].thirdOrderCoeff + + pow(fpgaBloodFlow, 2) * bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].secondOrderCoeff + + fpgaBloodFlow * bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].gain + + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].offset; + +#ifndef DISABLE_PUMP_FLOW_CHECKS + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR, ( flowErrorCtr != lastBloodFlowCommErrorCount ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR ); + } + if ( flowStatus != BFM_SENSOR_CONNECTED_STATUS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BLOOD_FLOW_STATUS_SELF_TEST_FAILURE, (U32)flowStatus ); + } + lastBloodFlowCommErrorCount = flowErrorCtr; #endif - + +#ifndef DISABLE_FPGA_COUNTER_CHECKS + // Check for stale flow reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR, ( fpReadCtr == lastBloodFlowFastPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR ); + } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR, ( spReadCtr == lastBloodFlowSlowPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR ); + } +#endif + + // Record flow read counters for next time around + lastBloodFlowFastPacketReadCtr = fpReadCtr; + lastBloodFlowSlowPacketReadCtr = spReadCtr; + 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; bloodFlowSignalStrength.data = getFPGABloodFlowSignalStrength(); @@ -716,7 +779,7 @@ * @details Outputs: none * @return the current blood flow data publication interval (in task intervals). *************************************************************************/ -U32 getPublishBloodFlowDataInterval( void ) +U32 getPublishBloodFlowDataInterval( void ) { U32 result = bloodFlowDataPublishInterval.data; @@ -932,25 +995,28 @@ if ( ++bpMotorSpeedCalcTimerCtr >= BP_SPEED_CALC_INTERVAL ) { U16 bpMotorHallSensorCount = getFPGABloodPumpHallSensorCount(); - U32 nextIdx = INC_WRAP( bpMotorSpeedCalcIdx, 0, BP_SPEED_CALC_BUFFER_LEN - 1 ); - U16 incDelta = ( bpMotorHallSensorCount >= bpLastMotorHallSensorCounts[ nextIdx ] ? \ - bpMotorHallSensorCount - bpLastMotorHallSensorCounts[ nextIdx ] : \ - ( HEX_64_K - bpLastMotorHallSensorCounts[ nextIdx ] ) + bpMotorHallSensorCount ); + U16 last = bpLastMotorHallSensorCounts[ bpMotorSpeedCalcIdx ]; + U32 nextIdx = INC_WRAP( bpMotorSpeedCalcIdx, 0, BP_SPEED_CALC_BUFFER_LEN - 1 ); + U16 incDelta = u16DiffWithWrap( bpLastMotorHallSensorCounts[ nextIdx ], bpMotorHallSensorCount ); U16 decDelta = HEX_64_K - incDelta; - U16 delta; - + U16 spdDelta; + S16 delta; + // Determine blood pump speed/direction from delta hall sensor count since last interval if ( incDelta < decDelta ) { - delta = incDelta; - bloodPumpSpeedRPM.data = ( (F32)delta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; + spdDelta = incDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; } else { - delta = decDelta; - bloodPumpSpeedRPM.data = ( (F32)delta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN * -1.0; + spdDelta = decDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN * -1.0; } - bloodPumpMotorEdgeCount += delta; + + // Keep a running 32-bit edge count used for safety check on volume in some functions + delta = u16BiDiffWithWrap( last, bpMotorHallSensorCount ); + bloodPumpMotorEdgeCount += (U16)delta; // Update last count for next time bpLastMotorHallSensorCounts[ nextIdx ] = bpMotorHallSensorCount; @@ -980,17 +1046,10 @@ // TODO - alarm??? } - // Ensure rotor speed below maximum - if ( rotorSpeed > BP_MAX_ROTOR_SPEED_RPM ) - { - if ( ++errorBloodPumpRotorTooFastPersistTimerCtr >= BP_MAX_ROTOR_SPEED_ERROR_PERSIST ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed ) - } - } - else + // Ensure rotor speed below maximum + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed > BP_MAX_ROTOR_SPEED_RPM ) ) { - errorBloodPumpRotorTooFastPersistTimerCtr = 0; + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed ) } // If pump is stopped or running very slowly, set rotor speed to zero @@ -1013,39 +1072,39 @@ if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) { MOTOR_DIR_T bpMCDir, bpDir; + BOOL isDirIncorrect; + U08 dirErrorCnt = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + // Check pump direction error count + if ( lastBloodPumpDirectionCount != dirErrorCnt ) + { + lastBloodPumpDirectionCount = dirErrorCnt; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) + } + 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 - if ( bloodPumpDirectionSet != bpDir ) - { - if ( ++errorBloodPumpDirectionPersistTimerCtr >= BP_DIRECTION_ERROR_PERSIST ) - { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpDir ) -#endif - } - } - // Check set direction vs. direction from sign of motor controller speed - else if ( bloodPumpDirectionSet != bpMCDir ) + // Check set direction vs. direction from hall sensors vs. direction from sign of motor controller speed + isDirIncorrect = ( bloodPumpDirectionSet != bpDir ) || ( bloodPumpDirectionSet != bpMCDir ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) { - if ( ++errorBloodPumpDirectionPersistTimerCtr >= BP_DIRECTION_ERROR_PERSIST ) - { #ifndef DISABLE_PUMP_DIRECTION_CHECKS + 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 ) -#endif } +#endif } - else - { - errorBloodPumpDirectionPersistTimerCtr = 0; - } } else { - errorBloodPumpDirectionPersistTimerCtr = 0; - } + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK ); + } } /*********************************************************************//** @@ -1066,27 +1125,13 @@ S32 cmdRate = targetBloodFlowRate; // Check for pump running while commanded off - if ( 0 == cmdRate ) - { - if ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) - { - if ( ++errorBloodMotorOffPersistTimerCtr >= BP_OFF_ERROR_PERSIST ) - { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, ( 0 == cmdRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) + { #ifndef DISABLE_PUMP_SPEED_CHECKS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); - activateSafetyShutdown(); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); + activateSafetyShutdown(); #endif - } - } - else - { - errorBloodMotorOffPersistTimerCtr = 0; - } } - else - { - errorBloodMotorOffPersistTimerCtr = 0; - } if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) { @@ -1096,41 +1141,27 @@ F32 measMotorSpeedInRotorRPM = measMotorSpeed / BP_GEAR_RATIO; F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); - // Check measured motor speed vs. commanded motor speed while controlling to target - if ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) - { - if ( ++errorBloodMotorSpeedPersistTimerCtr >= BP_MOTOR_SPEED_ERROR_PERSIST ) - { -#ifndef DISABLE_PUMP_SPEED_CHECKS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, (F32)cmdRate, measMotorSpeed ); + // 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 ) ) + { +#ifndef DISABLE_PUMP_SPEED_CHECKS + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, (F32)cmdRate, measMotorSpeed ); #endif - } } - else - { - errorBloodMotorSpeedPersistTimerCtr = 0; - } - // Check measured rotor speed vs. measured motor speed while controlling to target - if ( deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) - { - if ( ++errorBloodRotorSpeedPersistTimerCtr >= BP_ROTOR_SPEED_ERROR_PERSIST ) - { -#ifndef DISABLE_PUMP_SPEED_CHECKS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); + // 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 DISABLE_PUMP_SPEED_CHECKS + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); #endif - } } - else - { - errorBloodRotorSpeedPersistTimerCtr = 0; - } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK ); + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK ); } - else - { - errorBloodMotorSpeedPersistTimerCtr = 0; - errorBloodRotorSpeedPersistTimerCtr = 0; - } } /*********************************************************************//** @@ -1139,38 +1170,31 @@ * against the implied flow of the measured pump speed when in treatment mode * and controlling to target flow. If a sufficient difference persists, a * flow vs. motor speed check error is triggered. - * @details Inputs: measuredBloodFlowRate, bloodPumpSpeedRPM, errorBloodFlowVsMotorSpeedPersistTimerCtr + * @details Inputs: measuredBloodFlowRate, bloodPumpSpeedRPM * @details Outputs: alarm may be triggered * @return none *************************************************************************/ static void checkBloodPumpFlowAgainstSpeed( void ) { - // Check only performed while in treatment mode and while we are in control to target state + // Check only performed while in treatment mode and while we are in control to target state if ( ( MODE_TREA == getCurrentOperationMode() ) && ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) ) { F32 flow = getMeasuredBloodFlowRate(); F32 speed = getMeasuredBloodPumpSpeed(); F32 impliedSpeed = ( flow / (F32)ML_PER_LITER ) * BP_REV_PER_LITER * BP_GEAR_RATIO; F32 delta = fabs( speed - impliedSpeed ); - - if ( delta > BP_MAX_FLOW_VS_SPEED_DIFF_RPM ) - { - if ( ++errorBloodFlowVsMotorSpeedPersistTimerCtr >= BP_FLOW_VS_SPEED_PERSIST ) - { -#ifndef DISABLE_PUMP_FLOW_CHECKS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, flow, speed ); -#endif - } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, delta > BP_MAX_FLOW_VS_SPEED_DIFF_RPM ) ) + { +#ifndef DISABLE_PUMP_SPEED_CHECKS + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, flow, speed ); +#endif } - else - { - errorBloodFlowVsMotorSpeedPersistTimerCtr = 0; - } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK ); } - else - { - errorBloodFlowVsMotorSpeedPersistTimerCtr = 0; - } } /*********************************************************************//** @@ -1183,46 +1207,18 @@ *************************************************************************/ static void checkBloodPumpMCCurrent( void ) { - F32 bpCurr; - - // 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 ) - { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, getMeasuredBloodPumpMCCurrent() ); -#endif - } - } - else - { - bpCurrErrorDurationCtr = 0; - } + 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 ); + // Check blood pump current during running state + BOOL const isRunningMCCurrentBad = ( BLOOD_PUMP_OFF_STATE != bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_RUNNING_MA ); + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) + { +#ifndef DISABLE_MOTOR_CURRENT_CHECKS + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, bpCurr ); +#endif } - // Blood pump should be running - else - { - 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 ) - { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, getMeasuredBloodPumpMCCurrent() ); -#endif - } - } - else - { - bpCurrErrorDurationCtr = 0; - } - } } /*********************************************************************//** @@ -1250,6 +1246,52 @@ } } #endif +} + +/*********************************************************************//** + * @brief + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: bloodFlowCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static BOOL processCalibrationData( void ) +{ + BOOL status = TRUE; + + // Get the calibration record from NVDataMgmt + HD_FLOW_SENSORS_CAL_RECORD_T calData = getHDFlowSensorsCalibrationRecord(); + + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the blood flow sensors data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].calibrationTime ) + { +#ifndef SKIP_CAL_CHECK + activateAlarmNoData( ALARM_ID_HD_BLOOD_FLOW_INVALID_CAL_RECORD ); + status = FALSE; +#endif + } + + // The calibration data was valid, update the local copy + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].fourthOrderCoeff = + calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].fourthOrderCoeff; + + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].thirdOrderCoeff = + calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].thirdOrderCoeff; + + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].secondOrderCoeff = + calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].secondOrderCoeff; + + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].gain = + calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].gain; + + bloodFlowCalRecord.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].offset = + calData.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].offset; + + return status; } /*********************************************************************//** @@ -1262,16 +1304,27 @@ *************************************************************************/ SELF_TEST_STATUS_T execBloodFlowTest( void ) { - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - CALIBRATION_DATA_T cal; + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; + U08 const bfmStatus = getFPGABloodFlowMeterStatus(); // Retrieve blood flow sensor calibration data and check for sensor connected status - if ( ( TRUE == getCalibrationData( &cal ) ) && ( BFM_SENSOR_PARAM_CORRUPT_STATUS != getFPGABloodFlowMeterStatus() ) ) + if ( BFM_SENSOR_PARAM_CORRUPT_STATUS != bfmStatus ) { - bloodFlowCalGain = cal.bloodFlowGain; - bloodFlowCalOffset = cal.bloodFlowOffset_mL_min; - result = SELF_TEST_STATUS_PASSED; + BOOL calStatus = processCalibrationData(); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } } + else + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BLOOD_FLOW_STATUS_SELF_TEST_FAILURE, (U32)bfmStatus ); + } return result; } @@ -1280,58 +1333,7 @@ /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ - - -/*********************************************************************//** - * @brief - * The setBloodFlowCalibration function sets the blood flow calibration - * factors and has them stored in non-volatile memory. - * @details Inputs: none - * @details Outputs: bloodFlowCalGain, bloodFlowCalOffset - * @param gain gain calibration factor for blood flow sensor - * @param offset offset calibration factor for blood flow sensor - * @return TRUE if calibration factors successfully set/stored, FALSE if not - *************************************************************************/ -BOOL setBloodFlowCalibration( F32 gain, F32 offset ) -{ - BOOL result = FALSE; - if ( TRUE == isTestingActivated() ) - { - CALIBRATION_DATA_T cal; - - getCalibrationData( &cal ); - // Keep locally and apply immediately - bloodFlowCalGain = gain; - bloodFlowCalOffset = offset; - // Also update calibration record in non-volatile memory - cal.bloodFlowGain = gain; - cal.bloodFlowOffset_mL_min = offset; - if ( TRUE == setCalibrationData( cal ) ) - { - result = TRUE; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getBloodFlowCalibration function retrieves the current blood flow - * calibration factors. - * @details Inputs: bloodFlowCalGain, bloodFlowCalOffset - * @details Outputs: none - * @param gain value to populate with gain calibration factor for blood flow sensor - * @param offset value to populate with offset calibration factor for blood flow sensor - * @return none - *************************************************************************/ -void getBloodFlowCalibration( F32 *gain, F32 *offset ) -{ - *gain = bloodFlowCalGain; - *offset = bloodFlowCalOffset; -} - /*********************************************************************//** * @brief * The testSetBloodFlowDataPublishIntervalOverride function overrides the @@ -1440,7 +1442,7 @@ /*********************************************************************//** * @brief - * The testResetOffButtonStateOverride function resets the override of the + * The testResetMeasuredBloodFlowRateOverride function resets the override of the * measured blood flow rate. * @details Inputs: none * @details Outputs: measuredBloodFlowRate