Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r5f929b475f0143cd3597547e3c20a77a5abb6d9c -r37a9fd8f15e413db5337371a7d1a1cb65567af7c --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 5f929b475f0143cd3597547e3c20a77a5abb6d9c) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 37a9fd8f15e413db5337371a7d1a1cb65567af7c) @@ -7,8 +7,8 @@ * * @file BloodFlow.c * -* @author (last) Hung Nguyen -* @date (last) 04-Jan-2022 +* @author (last) Darren Cox +* @date (last) 10-Mar-2022 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -107,7 +107,7 @@ #define BP_ML_PER_ROTOR_REV 6.81 ///< 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.0 ///< Blood pump motor to blood pump gear ratio. -#define BP_PWM_ZERO_OFFSET 0.1 ///< 10 pct PWM duty cycle = zero speed. +#define BP_PWM_ZERO_OFFSET 0.1F ///< 10 pct PWM duty cycle = zero speed. /// 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 ) @@ -119,11 +119,11 @@ #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. -#define BP_FLOW_ALPHA_Y_INTERCEPT 1.2163 ///< Y intercept used for alpha flow coefficient calculation. -#define BP_FLOW_WEAR_A_TERM 0.000000005665 ///< A term used for wear portion of alpha flow coefficient. -#define BP_FLOW_WEAR_B_TERM 0.0006125 ///< B term used for wear portion of alpha flow coefficient. +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.1050 ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.000000001 ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.00055 ///< 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 BP_FLOW_CORRECTION_FACTOR 0.9 // TODO - why do we need this +#define DATA_PUBLISH_COUNTER_START_COUNT 20 ///< Data publish counter start count. /// Enumeration of blood pump controller states. typedef enum BloodPump_States @@ -156,7 +156,7 @@ // ********** 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 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 @@ -193,6 +193,7 @@ 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 ********** @@ -220,12 +221,14 @@ * @brief * The initBloodFlow function initializes the BloodFlow module. * @details Inputs: none - * @details Outputs: BloodFlow module initialized. + * @details Outputs: bloodFlowDataPublicationTimerCounter * @return none *************************************************************************/ void initBloodFlow( void ) { U32 i; + + bloodFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; signalBloodPumpHardStop(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); @@ -237,7 +240,7 @@ bpMotorSpeedCalcIdx = 0; for ( i = 0; i < BP_SPEED_CALC_BUFFER_LEN; i++ ) { - bpLastMotorHallSensorCounts[ i ] = 0; + bpLastMotorHallSensorCounts[ i ] = getFPGABloodPumpHallSensorCount(); } resetBloodPumpRotorCount(); @@ -278,11 +281,17 @@ // Don't interrupt pump control unless rate or mode is changing if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) - { -#ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) + { + BOOL byPassFlowLimit = FALSE; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + byPassFlowLimit = TRUE; + } #endif + // Verify flow rate of if the bypass flow limit has been enabled + if ( ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) { resetBloodPumpRPMMovingAverage(); targetBloodFlowRate = dirFlowRate; @@ -324,12 +333,16 @@ } result = TRUE; } -#ifndef NO_PUMP_FLOW_LIMITS + else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) - } + { +#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 ) + } + } } } @@ -358,7 +371,7 @@ 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 * BP_FLOW_CORRECTION_FACTOR; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; return flow; } @@ -478,6 +491,21 @@ /*********************************************************************//** * @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. @@ -487,11 +515,14 @@ *************************************************************************/ void resetBloodPumpRotorCount( void ) { -#ifndef WORN_OUT_CARTRIDGE - bloodPumpRotorCounter.data = 0; -#else - bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_WORN_OUT_CARTRIDGE ) != SW_CONFIG_ENABLE_VALUE ) + { + bloodPumpRotorCounter.data = 0; + } + else + { + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; + } } /*********************************************************************//** @@ -973,7 +1004,7 @@ 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 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); U16 spdDelta; S16 delta; @@ -1050,31 +1081,29 @@ BOOL isDirIncorrect; U08 dirErrorCnt = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; -#ifndef DISABLE_PUMP_DIRECTION_CHECKS // Check pump direction error count - if ( lastBloodPumpDirectionCount != dirErrorCnt ) + if ( ( lastBloodPumpDirectionCount != dirErrorCnt ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { lastBloodPumpDirectionCount = dirErrorCnt; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) } -#endif 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 ); - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS - if ( bloodPumpDirectionSet != bpDir ) + 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 } } else @@ -1101,12 +1130,12 @@ F32 measMCMotorSpeed = fabs( getMeasuredBloodPumpMCSpeed() ); // 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 ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, + ( 0 == targetBloodFlowRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); -#endif } // Checks that only occur when pump is running (and beyond ramp). @@ -1120,20 +1149,18 @@ 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 ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, + ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); -#endif } // 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 ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); -#endif } } else @@ -1159,11 +1186,10 @@ // 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_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, bpCurr ); -#endif } } @@ -1177,30 +1203,41 @@ *************************************************************************/ static void checkBloodPumpFlowRate( void ) { -#ifndef DISABLE_PUMP_FLOW_CHECKS - 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 ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); + 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 ); + } } -#endif } /*********************************************************************//** * @brief * The execBloodFlowTest function executes the state machine for the * BloodFlow self-test. - * @details Inputs: none + * @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; - // TODO - anything to test here? + 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; }