Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r19a8bf98a7154e24c35da25225d4b55bf70ddd09 -r14d9389c9db66c265e17d975e30ed73c66dcc21b --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 19a8bf98a7154e24c35da25225d4b55bf70ddd09) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 14d9389c9db66c265e17d975e30ed73c66dcc21b) @@ -8,7 +8,7 @@ * @file DialInFlow.c * * @author (last) Dara Navaei -* @date (last) 03-Apr-2022 +* @date (last) 18-Oct-2022 * * @author (original) Sean * @date (original) 16-Dec-2019 @@ -50,7 +50,7 @@ #define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.89F ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. #define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.10F ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. -#define DIP_CONTROL_INTERVAL_SEC 10 ///< Dialysate inlet pump control interval (in seconds). +#define DIP_CONTROL_INTERVAL_SEC 4 ///< Dialysate inlet pump control interval (in seconds). /// Interval (ms/task time) at which the dialIn pump is controlled. static const U32 DIP_CONTROL_INTERVAL = ( DIP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); #define DIP_P_COEFFICIENT 0.0001F ///< P term for dialIn pump control. @@ -66,7 +66,7 @@ #define DIP_MAX_FLOW_RATE 1320.0F ///< Maximum measured BP flow rate allowed. #define DIP_MIN_FLOW_RATE -1320.0F ///< Minimum measured BP flow rate allowed. -#define DIP_MAX_FLOW_VS_SPEED_DIFF_RPM 200.0F ///< Maximum difference between measured motor speed and speed implied by measured flow. +#define DIP_MAX_FLOW_VS_SPEED_DIFF_RPM 350.0F ///< Maximum difference between measured motor speed and speed implied by measured flow. #define DIP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0F ///< Maximum motor speed (RPM) while motor is commanded off. #define DIP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0F ///< Maximum difference in speed between motor and rotor (in rotor RPM). #define DIP_MAX_MOTOR_SPEED_ERROR_RPM 300.0F ///< Maximum difference in speed between measured and commanded RPM. @@ -77,8 +77,8 @@ static const U32 DIP_OFF_ERROR_PERSIST = ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) motor speed error condition. static const U32 DIP_MOTOR_SPEED_ERROR_PERSIST = ((5 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); -/// Persist time (task intervals) rotor speed error condition. -static const U32 DIP_ROTOR_SPEED_ERROR_PERSIST = ((12 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); +/// Rotor speed persist time test needs a minimum number of rotations. +static const U32 DIP_ROTOR_ERROR_PERSIST_ROTATION_MIN = 3; /// Persist time (task intervals) pump direction error condition. static const U32 DIP_DIRECTION_ERROR_PERSIST = (250 / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) dialysate flow rate out of range error condition. @@ -106,19 +106,39 @@ #define DIP_GEAR_RATIO 32.0F ///< DialIn pump motor to dialIn pump gear ratio. #define DIP_PWM_ZERO_OFFSET 0.1F ///< 10% PWM duty cycle = zero speed. -/// Macro converts flow rate to estimate PWM needed to achieve it. -#define DIP_PWM_FROM_ML_PER_MIN(rate) ( ( ((rate)*(rate)) * 0.000001 ) + ( (rate) * 0.0005 ) + 0.126 + DIP_PWM_ZERO_OFFSET ) -//#define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) -/// Conversion from PWM duty cycle % to commanded pump motor speed. +/// Macro converts flow rate to estimate PWM needed to achieve it. +#define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) +/// Conversion from PWM duty cycle % to commanded pump motor speed. PWM range is 10% to 90%. RPM range is 0 to 3200. 3200 / 0.8 = 4000. #define DIP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DIP_PWM_ZERO_OFFSET) * 4000.0F ) +/// Conversion from pump motor speed to PWM duty cycle. +#define DIP_MOTOR_SPEED_RPM_TO_PWM(rpm) ( ( rpm / 4000.0F ) + 0.1 ) +// Macro converts PWM to estimate flow rate needed to achieve it. +#define DIP_ML_PER_MIN_FROM_PWM(pwm) ( (( pwm - DIP_PWM_ZERO_OFFSET) * 684.73F ) + 49.121F ) + /// Measured dialIn flow is filtered w/ moving average. -#define SIZE_OF_ROLLING_AVG 10 +#define SIZE_OF_ROLLING_AVG 4 #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define DIP_MIN_DIR_CHECK_SPEED_RPM 10.0F ///< Minimum motor speed before we check pump direction. +#define DIP_COMMUTATION_ERROR_MAX_CNT 3 ///< Maximum number of commutation errors within time window before alarm triggered. +#define DIP_COMMUTATION_ERROR_TIME_WIN_MS (15 * MS_PER_SECOND) ///< Time window for DPi commutation error. #define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. +//Hybrid flow rate algorithm parameters +#define DIAL_IN_FLOW_A_ZERO 1.267F ///< Y intercept used for alpha flow coefficient calculation. +#define DIAL_IN_FLOW_WEAR_A_TERM 0.000000003551F ///< A term used for wear portion of alpha flow coefficient (m'). +#define DIAL_IN_FLOW_WEAR_B_TERM 0.002244F ///< B term used for wear portion of alpha flow coefficient (m0). +#define DIAL_IN_FLOW_QHIGHTRANSITION 400.0F ///< High flow rate transition for blended algorithm +#define DIAL_IN_FLOW_QLOWTRANSITION 300.0F ///< Low flow rate transition for blended algorithm +#define DIAL_IN_FLOW_PEST_A_TERM -0.000491F ///< a (2nd order) term in polynomial fit for pressure estimation +#define DIAL_IN_FLOW_PEST_B_TERM -0.04672F ///< b (first order) term in polynomial fit for pressure estimation +#define DIAL_IN_FLOW_PEST_C_TERM 18.648F ///< c (zero order) term in polynomial fit for pressure estimation +#define DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define DIAL_IN_STROKE_VOLUME 3.405 ///< Stroke volume (SV) used for Flow Estimation ALgorithm +#define DIAL_IN_GEAR_RATIO 32 ///< Gear ratio used for Flow Estimation ALgorithm + /// Enumeration of dialysate inlet pump states. typedef enum DialInPump_States { @@ -193,8 +213,11 @@ static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer. static U32 dipCurrErrorDurationCtr = 0; ///< Used for tracking persistence of dip current errors. -static HD_PUMPS_CAL_RECORD_T dialInPumpCalRecord; ///< Dialysate inlet calibration record. +static HD_PUMPS_CAL_RECORD_T dialInPumpCalRecord; ///< Dialysate inlet calibration record. +static OVERRIDE_U32_T dialysateInPumpRotorCounter = { 0, 0, 0, 0 }; ///< Running counter for dialin pump rotor revolutions +static F32 filteredDialInFlowMeterReading = 0.0; ///< Storage for current filtered flow meter reading + // ********** private function prototypes ********** static DIAL_IN_PUMP_STATE_T handleDialInPumpOffState( void ); @@ -214,6 +237,8 @@ static void checkDialInPumpSpeeds( void ); static void checkDialInPumpMCCurrent( void ); static void checkDialInPumpFlowRate( void ); +static F32 calcDialInFlow( void ); +static F32 dialysateInPumpPWMFromTargetFlowRate( F32 QdTarget ); /*********************************************************************//** * @brief @@ -232,7 +257,9 @@ setDialInPumpDirection( MOTOR_DIR_FORWARD ); // Zero rolling flow average buffer - resetDialInFlowMovingAverage(); + resetDialInFlowMovingAverage(); + // Zero pump rotor count + resetDialInPumpRotorCount(); // Zero motor hall sensors counts buffer dipMotorSpeedCalcIdx = 0; @@ -248,6 +275,7 @@ // Initialize persistent alarm for flow sensor signal strength too low initPersistentAlarm( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, 0, DIP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST ); + initTimeWindowedCount( TIME_WINDOWED_COUNT_DIP_COMMUTATION_ERROR, DIP_COMMUTATION_ERROR_MAX_CNT, DIP_COMMUTATION_ERROR_TIME_WIN_MS ); } /*********************************************************************//** @@ -273,24 +301,24 @@ // Don't interrupt pump control unless rate or mode is changing if ( ( dirFlowRate != targetDialInFlowRate ) || ( mode != dialInPumpControlMode ) ) { - BOOL byPassFlowLimit = FALSE; + BOOL isFlowRateInRange = ( flowRate <= MAX_DIAL_IN_FLOW_RATE ? TRUE : FALSE ); #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) { - byPassFlowLimit = TRUE; + isFlowRateInRange = TRUE; } #endif // Verify flow rate - if ( ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) + if ( TRUE == isFlowRateInRange ) { resetDialInFlowMovingAverage(); targetDialInFlowRate = dirFlowRate; dialInPumpDirection = dir; dialInPumpControlMode = 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 - dialInPumpPWMDutyCyclePct = ( 0 == flowRate ? DIP_PWM_ZERO_OFFSET : DIP_PWM_FROM_ML_PER_MIN( (F32)flowRate ) ); + // 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 + dialInPumpPWMDutyCyclePct = ( 0 == flowRate ? DIP_PWM_ZERO_OFFSET : dialysateInPumpPWMFromTargetFlowRate( (F32)flowRate ) ); switch ( dialInPumpState ) { @@ -365,7 +393,7 @@ * hall sensor detection. Calculates rotor speed (in RPM). Stops pump if * there is a pending request to home the pump. * @details Inputs: dipRotorRevStartTime, dipStopAtHomePosition - * @details Outputs: dipRotorRevStartTime, dialInPumpRotorSpeedRPM + * @details Outputs: dipRotorRevStartTime, dialInPumpRotorSpeedRPM, dialysateInPumpRotorCounter, dipStopAtHomePosition * @return none *************************************************************************/ void signalDialInPumpRotorHallSensor( void ) @@ -376,6 +404,7 @@ // Calculate rotor speed (in RPM) dialInPumpRotorSpeedRPM.data = ( 1.0 / (F32)deltaTime ) * (F32)MS_PER_SECOND * (F32)SEC_PER_MIN; dipRotorRevStartTime = rotTime; + dialysateInPumpRotorCounter.data++; // If we are supposed to stop pump at home position, stop pump now. if ( TRUE == dipStopAtHomePosition ) @@ -453,6 +482,7 @@ { dipFlow = getDGDialysateFlowRateLMin() * (F64)ML_PER_LITER; // convert rate to mL/min filterDialInFlowReadings( dipFlow ); // process the fresh dialysate flow data + measuredDialInFlowRate.data = calcDialInFlow(); // calculate the measured flow rate using blended algorithm dialysateFlowDataFreshStatusCounter = 0; } else @@ -491,6 +521,10 @@ // Check for home position, zero/low speed checkDialInPumpRotor(); } + else + { + lastDialInPumpDirectionCount = getFPGADialInPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + } // Publish dialIn flow data on interval publishDialInFlowData(); @@ -738,6 +772,104 @@ break; } } + +/*********************************************************************//** + * @brief + * The calcDialInFlow function calculates an estimated dialysate flow rate from + * a blended algorithm based on flow meter data and dialin pump speed and tubing wear + * (measured from count of rotor revolutions since cartridge install). + * @details Inputs: DialInPumpRotorCounter, targetDialInFlowRate, dialInPumpRotorSpeedRPM + * @details Outputs: measuredDialInFlowRate (ml/min) + * @return none + *************************************************************************/ +static F32 calcDialInFlow( void ) +{ + F32 estimatedFlow; + F32 QdTarget = getTargetDialInFlowRate(); + F32 deltaFlow; + + if ( QdTarget >= DIAL_IN_FLOW_QHIGHTRANSITION ) + { + //At higher flow rates, use the flow meter value. Assume target flow rate has already checked for out of bounds on high end. + estimatedFlow = filteredDialInFlowMeterReading; + } + else + { //Use blended or calculated flow rate + F32 motorRPM = getMeasuredDialInPumpMCSpeed(); + U32 r = getDialInPumpRotorCount(); + U32 rotCount = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wearFactor = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCount + DIAL_IN_FLOW_WEAR_B_TERM; + F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * ( QdTarget * QdTarget ) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; + F32 alphaTerm = wearFactor * Pest + DIAL_IN_FLOW_A_ZERO; + + F32 calculatedFlow = ( motorRPM * 2 * DIAL_IN_STROKE_VOLUME/DIAL_IN_GEAR_RATIO ) * alphaTerm; + + if ( ( QdTarget < DIAL_IN_FLOW_QHIGHTRANSITION ) && ( QdTarget > DIAL_IN_FLOW_QLOWTRANSITION ) ) + { // use blended flow rate calculation + estimatedFlow = ( ( QdTarget - DIAL_IN_FLOW_QLOWTRANSITION ) / ( DIAL_IN_FLOW_QHIGHTRANSITION - DIAL_IN_FLOW_QLOWTRANSITION ) ) * calculatedFlow + + ( ( DIAL_IN_FLOW_QHIGHTRANSITION - QdTarget ) / ( DIAL_IN_FLOW_QHIGHTRANSITION - DIAL_IN_FLOW_QLOWTRANSITION ) ) * filteredDialInFlowMeterReading; + } + else + { // use calculated flow rate. Assume target flow rate has already checked for out of bounds on low end. + estimatedFlow = calculatedFlow; + } + } + + // Check the measured flow against estimated flow - / + deltaFlow = 0.5 * estimatedFlow; // 50% estimated flow + if ( deltaFlow < fabs( estimatedFlow - filteredDialInFlowMeterReading ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_DIAL_IN_FLOW_CHECK_FAILURE, filteredDialInFlowMeterReading, estimatedFlow ); + } + + return estimatedFlow; +} + + +/*********************************************************************//** + * @brief + * The dialysateInPumpPWMFromTargetFlowRate function calculates a motor PWM setting + * from the estimator based on target flow rate and tubing wear. + * @details Inputs: dialInPumpRotorCounter + * @details Outputs: none + * @param QdTarget target dialysate flow rate + * @return Motor PWM value for given target flow rate + *************************************************************************/ +static F32 dialysateInPumpPWMFromTargetFlowRate( F32 QdTarget ) +{ + U32 r = getDialInPumpRotorCount(); + U32 rotCount = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wearFactor = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCount + DIAL_IN_FLOW_WEAR_B_TERM; + F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * ( QdTarget * QdTarget ) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; + F32 alphaTerm = wearFactor * Pest + DIAL_IN_FLOW_A_ZERO; + F32 rpmTgt = QdTarget * DIAL_IN_GEAR_RATIO / ( 2 * DIAL_IN_STROKE_VOLUME * alphaTerm ); + F32 pwmDC = DIP_MOTOR_SPEED_RPM_TO_PWM( rpmTgt ); + + return pwmDC; +} + +/*********************************************************************//** + * @brief + * The resetDialInPumpRotorCount function resets the dialin 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: dialInPumpRotorCounter is reset to 0 + * @return none + *************************************************************************/ +void resetDialInPumpRotorCount( void ) +{ +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_WORN_OUT_CARTRIDGE ) ) + { + dialysateInPumpRotorCounter.data = DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR; + } + else +#endif + { + dialysateInPumpRotorCounter.data = 0; + } +} /*********************************************************************//** * @brief @@ -872,7 +1004,49 @@ return result; } + +/*********************************************************************//** + * @brief + * The getDialInPumpRotorCount function returns the current count for the + * dialin pump rotor revolution counter. + * @details Inputs: dialInPumpRotorCounter + * @details Outputs: none + * @return dialInPumpRotorCounter + *************************************************************************/ +U32 getDialInPumpRotorCount( void ) +{ + U32 result = dialysateInPumpRotorCounter.data; + + if ( OVERRIDE_KEY == dialysateInPumpRotorCounter.override ) + { + result = dialysateInPumpRotorCounter.ovData; + } + + return result; +} +/*********************************************************************//** + * @brief + * The getPumpRotorErrorPersistTime function calculates the Rotor error persist time. + * @details Inputs: none + * @details Outputs: none + * @param mtr_rpm, RPM of the motor. + * gear_ratio, Gear ratio of motor vs motor + * @return Persistent error test time in (ms) + *************************************************************************/ +U32 getPumpRotorErrorPersistTime( F32 mtr_rpm, F32 gear_ratio ) +{ + U32 err_persist_time = HEX_32_BIT_FULL_SCALE; // 49 days + + if ( mtr_rpm > 0 ) + { + /// Calculate persist time for rotor speed error condition. + err_persist_time = ( ( DIP_ROTOR_ERROR_PERSIST_ROTATION_MIN / ( mtr_rpm / gear_ratio / SEC_PER_MIN ) ) * MS_PER_SECOND ); + } + + return err_persist_time; +} + /*********************************************************************//** * @brief * The publishDialInFlowData function publishes dialIn flow data at the set @@ -896,7 +1070,7 @@ payload.measMCSpd = getMeasuredDialInPumpMCSpeed(); payload.measMCCurr = getMeasuredDialInPumpMCCurrent(); payload.pwmDC = dialInPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; - payload.flowSigStrength = 0.0; + payload.rotorCount = getDialInPumpRotorCount(); broadcastData( MSG_ID_DIALYSATE_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( DIALIN_PUMP_STATUS_PAYLOAD_T ) ); dialInFlowDataPublicationTimerCounter = 0; } @@ -934,8 +1108,8 @@ flowReadings[ flowReadingsIdx ] = flow; flowReadingsTotal += flow; flowReadingsIdx = INC_WRAP( flowReadingsIdx, 0, SIZE_OF_ROLLING_AVG - 1 ); - flowReadingsCount = INC_CAP( flowReadingsCount, SIZE_OF_ROLLING_AVG ); - measuredDialInFlowRate.data = (F32)( flowReadingsTotal / (F64)flowReadingsCount ); + flowReadingsCount = INC_CAP( flowReadingsCount, SIZE_OF_ROLLING_AVG ); + filteredDialInFlowMeterReading = (F32)( flowReadingsTotal / (F64)flowReadingsCount ); } /*********************************************************************//** @@ -1018,24 +1192,27 @@ { MOTOR_DIR_T dipMCDir, dipDir; U08 dirErrorCnt = getFPGADialInPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + F32 measMCSpeed = getMeasuredDialInPumpMCSpeed(); + BOOL minDirSpeed = ( measMCSpeed >= DIP_MIN_DIR_CHECK_SPEED_RPM ? TRUE : FALSE ); + BOOL isHallSensorFailed = ( TRUE == minDirSpeed && lastDialInPumpDirectionCount != dirErrorCnt ? TRUE : FALSE ); // Check pump direction error count - if ( lastDialInPumpDirectionCount != dirErrorCnt ) + if ( ( TRUE == isHallSensorFailed ) && ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_DIP_COMMUTATION_ERROR ) ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif { - lastDialInPumpDirectionCount = dirErrorCnt; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_INLET_PUMP ) } } + lastDialInPumpDirectionCount = dirErrorCnt; dipMCDir = ( getMeasuredDialInPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); dipDir = ( getMeasuredDialInPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); // Check set direction vs. direction from hall sensors - if ( dialInPumpDirectionSet != dipDir ) + if ( ( dialInPumpDirectionSet != dipDir ) && ( TRUE == minDirSpeed ) ) { if ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) { @@ -1048,7 +1225,7 @@ } } // Check set direction vs. direction from sign of motor controller speed - else if ( dialInPumpDirectionSet != dipMCDir ) + else if ( ( dialInPumpDirectionSet != dipMCDir ) && ( TRUE == minDirSpeed ) ) { if ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) { @@ -1120,7 +1297,7 @@ F32 cmdMotorSpeed = DIP_PWM_TO_MOTOR_SPEED_RPM( dialInPumpPWMDutyCyclePctSet ); F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); - F32 measRotorSpeed = getMeasuredDialInPumpRotorSpeed(); + F32 measRotorSpeed = fabs( getMeasuredDialInPumpRotorSpeed() ); F32 measMotorSpeedInRotorRPM = measMotorSpeed / DIP_GEAR_RATIO; F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); @@ -1145,7 +1322,7 @@ // Check measured rotor speed vs. measured motor speed while controlling to target if ( deltaRotorSpeed > DIP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) { - if ( ++errorDialInRotorSpeedPersistTimerCtr >= DIP_ROTOR_SPEED_ERROR_PERSIST ) + if ( ++errorDialInRotorSpeedPersistTimerCtr >= ( getPumpRotorErrorPersistTime( measMotorSpeed, DIP_GEAR_RATIO ) / TASK_PRIORITY_INTERVAL ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) @@ -1196,9 +1373,9 @@ { F32 flow = (F32)targetDialInFlowRate; F32 speed = getMeasuredDialInPumpSpeed(); - F32 impliedSpeed = DIP_PWM_TO_MOTOR_SPEED_RPM( DIP_PWM_FROM_ML_PER_MIN( flow ) ); + F32 impliedSpeed = ( flow * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO ); F32 delta = fabs( speed - impliedSpeed ); - + if ( delta > DIP_MAX_FLOW_VS_SPEED_DIFF_RPM ) { if ( ++errorDialInFlowVsMotorSpeedPersistTimerCtr >= DIP_FLOW_VS_SPEED_PERSIST ) @@ -1233,50 +1410,53 @@ static void checkDialInPumpMCCurrent( void ) { F32 dipCurr; - - // DialIn pump should be off - if ( DIAL_IN_PUMP_OFF_STATE == dialInPumpState ) + + if ( FALSE == isAlarmActive( ALARM_ID_HD_AC_POWER_LOST ) ) { - dipCurr = fabs( getMeasuredDialInPumpMCCurrent() ); - if ( dipCurr > DIP_MAX_CURR_WHEN_STOPPED_MA ) + // DialIn pump should be off + if ( DIAL_IN_PUMP_OFF_STATE == dialInPumpState ) { - dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) - { + dipCurr = fabs( getMeasuredDialInPumpMCCurrent() ); + if ( dipCurr > DIP_MAX_CURR_WHEN_STOPPED_MA ) + { + dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; + if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) + { #ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); + } } } + else + { + dipCurrErrorDurationCtr = 0; + } } + // DialIn pump should be running else { - dipCurrErrorDurationCtr = 0; - } - } - // DialIn pump should be running - else - { - dipCurr = fabs( getMeasuredDialInPumpMCCurrent() ); - if ( dipCurr > DIP_MAX_CURR_WHEN_RUNNING_MA ) - { - dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) - { -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); + dipCurr = fabs( getMeasuredDialInPumpMCCurrent() ); + if ( dipCurr > DIP_MAX_CURR_WHEN_RUNNING_MA ) + { + dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; + if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) + { + #ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + #endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); + } } } - } - else - { - dipCurrErrorDurationCtr = 0; - } + else + { + dipCurrErrorDurationCtr = 0; + } + } } } @@ -1625,6 +1805,73 @@ } return result; -} +} +/*********************************************************************//** + * @brief + * The testSetDialInPumpTargetDutyCycle function sets the duty cycle of the + * dialysate inlet pump by calling setDialInPumpTargetFlowRate. + * @details Inputs: none + * @details Outputs: none + * @param value duty cycle of the dialysate inlet pump (as a percentage). + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testSetDialInPumpTargetDutyCycle( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + setDialInPumpTargetFlowRate( (U32)DIP_ML_PER_MIN_FROM_PWM(value), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetDialysateInPumpRotorCountOverride function overrides the dialin pump + * rotor counter value. + * @details Inputs: none + * @details Outputs: dialInPumpRotorCounter + * @param value override dialin pump rotor counter value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetDialysateInPumpRotorCountOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + dialysateInPumpRotorCounter.ovData = value; + dialysateInPumpRotorCounter.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetDialInPumpRotorCountOverride function resets the override + * of the dialin pump rotor counter. + * @details Inputs: none + * @details Outputs: dialysateInPumpRotorCounter + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetDialysateInPumpRotorCountOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + dialysateInPumpRotorCounter.override = OVERRIDE_RESET; + dialysateInPumpRotorCounter.ovData = dialysateInPumpRotorCounter.ovInitData; + } + + return result; +} + /**@}*/