Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r1c478c1aff953528127767db1f4f747a7f7089c8 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 1c478c1aff953528127767db1f4f747a7f7089c8) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -45,13 +45,11 @@ #define BAL_CHAMBER_FILL_PRES_DROP_MS ( 200 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber filling started and corrosponding valves opened. #define BAL_CHAMBER_FILL_COMPLETE_MS ( 300 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber fill completed and pressure is within range #define SPENT_FILL_COMPLETE_PRES 25.0F ///< Spent fill complete pressure (PSI) for Diener 2000 pump. -#define SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG 15.0F ///< Spent fill complete pressure (PSI) when Diener 1000 and 200 < Qd <= 400. +#define SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG 10.0F ///< Spent fill complete pressure (PSI) when Diener 1000 and 200 < Qd <= 400. #define SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG 20.0F ///< Spent fill complete pressure (PSI) when Diener 1000 and Qd > 400. #define SPENT_FILL_COMPLETE_QD_SLOPE_MAX_MLPM 300.0F ///< For Qd <= 300 mL/min, spent fill completion uses pressure-rise slope detection. -#define SPENT_FILL_COMPLETE_QD_TWO_HIT_MAX_MLPM 150.0F ///< For Qd <= 150 mL/min, require two rise detections; above this and <=300, one rise detection is enough. #define SPENT_FILL_COMPLETE_DP_RISE_PSIG 0.5F ///< Minimum 100 ms spent pressure rise (current minus n-2) to count as a rise hit at low Qd. #define SPENT_FILL_SLOPE_SPENT_PRESSURE_HIGH_PSIG 2.0F ///< Above this absolute spent pressure, only one rise hit is required. -#define SPENT_FILL_SLOPE_SPENT_PRESSURE_LOW_PSIG 0.5F ///< Below this absolute spent pressure, use Qd-based required rise hit count. #define SPENT_FILL_SLOPE_MAX_RISE_HITS 2 ///< Rise hits required when Qd <= 150 in the low spent-pressure band. #define SPENT_FILL_DETECT_COUNT_TOL_PCT 1.0F ///< Allowed detection timing tolerance as a fraction of expected BC switching count. #define QD_THRESHOLD_HIGH_MLPM 400.0F ///< Qd threshold (mL/min) below which mid pressure limit applies. @@ -60,7 +58,7 @@ #define D48_SPEED_RANGE_LIMIT 0.25F ///< D48 speed adjustment range check limit ( D48 speed can vary +/-25% of initial calculated speed) #define BICARB_CHAMBER_PERIODIC_FILL_TIME ( 1 * SEC_PER_MIN * \ ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ) ///< Periodic bicarb chamber fill request 60 sec x 20 = 1200 -#define BAL_CHAMBER_FILL_TIMEOUT_FACTOR 2.5F ///< Balancing Chamber fill timeout factor (250% of observed fill count) +#define BAL_CHAMBER_FILL_TIMEOUT_FACTOR 3.0F ///< Balancing Chamber fill timeout factor (300% of observed fill count) /// Payload record structure for balancing chamber switch only request typedef struct @@ -104,6 +102,9 @@ static BOOL isBalChamberSwitchingActive; ///< Flag indicating balancing chamber switching is active or not. static BOOL isBalChamberSwitchingOnRequested; ///< Flag indicating that a request was made to activate balancing chamber switching. static BOOL isBalChamberSwitchingOffRequested; ///< Flag indicating that a request was made to deactivate balancing chamber switching. +static F32 pendingTdDialysateFlowrate; ///< Pending TD dialysate flow rate; applied at FillEnd after a BC switch completes. +static BOOL isBalChamberSwitchingPeriodUpdatePending; ///< BC switching period update pending apply at fill end. +static U32 bcSwitchingBasedOnClosedPeriodCounter; ///< Valve-close segments remaining before first-cycle relaxations clear after Qd timing apply. //TODO: remove later once level sensor working static U32 bicarbChamberPeriodicFillCounter; @@ -122,6 +123,9 @@ static U32 getBalChamberDataPublishInterval( void ); static void checkSpentFillComplete( F32 spentDialPressure ); static BOOL isSpentFillCompleteByPressure( F32 spentDialPressure, F32 qdMlpm, F32 spentFillCompletePresPsig ); +static void applyBalChamberSwitchingPeriod( F32 tdDialysateFlowrate ); +static BOOL isBalChamberTimeBasedSwitching( void ); +static void scheduleFirstCycleRelaxAfterQdApply( void ); /*********************************************************************//** * @brief @@ -177,6 +181,9 @@ isBalChamberSwitchingActive = FALSE; isBalChamberSwitchingOnRequested = FALSE; isBalChamberSwitchingOffRequested = FALSE; + pendingTdDialysateFlowrate = 0.0F; + isBalChamberSwitchingPeriodUpdatePending = FALSE; + bcSwitchingBasedOnClosedPeriodCounter = 0; //TODO:remove once level sensor working bicarbChamberPeriodicFillCounter = 0; } @@ -209,6 +216,42 @@ if ( lastTdDialysateFlowrate != tdDialysateFlowrate ) { + // Defer Qd timing update to FillEnd at end of the current BC switch + if ( ( TRUE == isBalChamberSwitchingActive ) && ( BAL_CHAMBER_STATE_IDLE != balChamberExecState ) ) + { + pendingTdDialysateFlowrate = tdDialysateFlowrate; + isBalChamberSwitchingPeriodUpdatePending = TRUE; + } + // Apply immediately when BC is inactive or still idle + else + { + pendingTdDialysateFlowrate = tdDialysateFlowrate; + isBalChamberSwitchingPeriodUpdatePending = TRUE; + applyBalChamberSwitchingPeriod( pendingTdDialysateFlowrate ); + scheduleFirstCycleRelaxAfterQdApply(); + } + } + else + { + pendingTdDialysateFlowrate = 0.0F; + isBalChamberSwitchingPeriodUpdatePending = FALSE; + } +} + +/*********************************************************************//** + * @brief + * The applyBalChamberSwitchingPeriod function applies the active balancing + * chamber switching time based on the provided dialysis flow rate. + * @details \b Inputs: Dialysis flow rate. + * @details \b Outputs: balChamberSwitchingFreq,balChamberSwitchingPeriod + * @return none + *************************************************************************/ +static void applyBalChamberSwitchingPeriod( F32 tdDialysateFlowrate ) +{ + if ( TRUE == isBalChamberSwitchingPeriodUpdatePending ) + { + U32 initialPumpSpeed = 0; + // update the balancing chamber switching frequency balChamberSwitchingFreq.data = tdDialysateFlowrate / BAL_CHAMBER_FILL_VOLUME_ML; @@ -221,7 +264,7 @@ //Update last td dialysate flow rate lastTdDialysateFlowrate = tdDialysateFlowrate; - // Update fill timeout count based on the switching period (e.g. 250% of period) + // Update fill timeout count based on the switching period (e.g. 300% of period) balChamberFillTimeoutCount = (U32)( (F32)balChamberSwitchingPeriod * BAL_CHAMBER_FILL_TIMEOUT_FACTOR ); //Reset the BC switching flag for new Qd. @@ -242,11 +285,48 @@ spentDialPressure = getFilteredPressure( D51_PRES ); lastPrevSpentDialPressure = spentDialPressure; prevSpentDialPressure = spentDialPressure; + + initialPumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + setD48PumpSpeedForBCFill( initialPumpSpeed ); + setDialysatePumpTargetRPM( D48_PUMP, initialPumpSpeed, TRUE ); + + pendingTdDialysateFlowrate = 0.0F; + isBalChamberSwitchingPeriodUpdatePending = FALSE; } } /*********************************************************************//** * @brief + * The scheduleFirstCycleRelaxAfterQdApply function configures how many BC + * switches still use first-cycle relaxations after a Qd timing update. + * @details One full BC cycle is two switches require two + * valve-close segments under the new timing before clearing relaxations. + * @return none + *************************************************************************/ +static void scheduleFirstCycleRelaxAfterQdApply( void ) +{ + bcSwitchingBasedOnClosedPeriodCounter = 2; +} + +/*********************************************************************//** + * @brief + * The isBalChamberTimeBasedSwitching function checks whether the nominal + * (pre-clamp) D48 starting speed should use fixed-speed, time-based balancing + * chamber switching. + * @details \b Inputs: nominal ceiled D48 speed + * @details \b Outputs: none + * @return TRUE if time-based switching should be used; otherwise FALSE. + *************************************************************************/ +static BOOL isBalChamberTimeBasedSwitching( void ) +{ + BOOL state = FALSE; + state = ( getD48PumpSpeed() <= BAL_CHAMBER_TIME_BASED_D48_SPEED_RPM ) ? TRUE : FALSE; + + return state; +} + +/*********************************************************************//** + * @brief * The execBalancingChamberControl function executes the balancing chamber state machine. * @details \b Inputs: balChamberExecState * @details \b Outputs: balChamberExecState @@ -526,7 +606,6 @@ BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_FILL_START; balChamberSWState = BAL_CHAMBER_SW_STATE1; - // Preserve the Qd-based timeout so a stuck fill can fault. isBalChamberFillInProgress = FALSE; isPressureStabilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; @@ -640,7 +719,6 @@ ( TRUE == isConcentratePumpDosingCompleted( D10_PUMP ) ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) { - if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { // Low-Qd spent slope: baseline = spent pressure on last dosing tick (this task period) before VALVES_CLOSE. @@ -671,14 +749,12 @@ BOOL isBothFillsComplete = FALSE; BOOL isFirstCycleNotDone = FALSE; BOOL isFillCompleteOrFirstCycle = FALSE; - BOOL isFillTimeoutEnabled = ( ( TRUE == isFirstCycleBCSwitchingCompleted ) && - ( FALSE == getBalChamberSwitchingOnlyStatus() ) ) ? TRUE : FALSE; freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); // After the first BC cycle, fault if fill never completes at the Qd-based timeout. - if ( ( TRUE == isFillTimeoutEnabled ) && ( balChamberFillTimeoutCount > 0 ) && ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) ) + if ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BC_FILL_TIMEOUT_FAULT, currentBalChamberFillCounter, balChamberFillTimeoutCount ); @@ -696,7 +772,6 @@ } } - // Spent side of balancing chamber fill is complete or not checkSpentFillComplete( spentDialPressure ); // Check both spent and fresh side fill is complete @@ -719,6 +794,16 @@ setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); } + if ( bcSwitchingBasedOnClosedPeriodCounter > 0 ) + { + bcSwitchingBasedOnClosedPeriodCounter -= 1; + } + + if ( 0 == bcSwitchingBasedOnClosedPeriodCounter ) + { + isFirstCycleBCSwitchingCompleted = TRUE; + } + // Transition to next state state = BAL_CHAMBER_STATE1_FILL_END; } @@ -750,6 +835,12 @@ if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { + if ( TRUE == isBalChamberSwitchingPeriodUpdatePending ) + { + applyBalChamberSwitchingPeriod( pendingTdDialysateFlowrate ); + scheduleFirstCycleRelaxAfterQdApply(); + } + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) @@ -760,7 +851,7 @@ // Move to the idle state state = BAL_CHAMBER_STATE_IDLE; } - else if ( TRUE != isPressureStabilizedDuringFill ) + else if ( ( TRUE != isPressureStabilizedDuringFill ) && ( TRUE != isSpentFillComplete ) ) { // Alarm when switching time expired, but still pressure not in range which indicates fill is not yet completed. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); @@ -924,8 +1015,6 @@ BOOL isBothFillsComplete = FALSE; BOOL isFirstCycleNotDone = FALSE; BOOL isFillCompleteOrFirstCycle = FALSE; - BOOL isFillTimeoutEnabled = ( ( TRUE == isFirstCycleBCSwitchingCompleted ) && - ( FALSE == getBalChamberSwitchingOnlyStatus() ) ) ? TRUE : FALSE; freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); @@ -941,15 +1030,24 @@ } // After the first BC cycle, fault if fill never completes at the Qd-based timeout. - if ( ( TRUE == isFillTimeoutEnabled ) && ( balChamberFillTimeoutCount > 0 ) && ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) ) + if ( currentBalChamberFillCounter > balChamberFillTimeoutCount ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_BC_FILL_TIMEOUT_FAULT, currentBalChamberFillCounter, balChamberFillTimeoutCount ); // Move to the idle state state = BAL_CHAMBER_STATE_IDLE; } - // Spent side of balancing chamber fill is complete or not + // Check fresh dialysate pressure back in range to indicate fill complete. + if ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) + { + if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) + { + // stabilized pressure indicating fresh side fill is complete + isPressureStabilizedDuringFill = TRUE; + } + } + checkSpentFillComplete( spentDialPressure ); // Check switching cycle time or pressure check for valve closure @@ -972,6 +1070,16 @@ setDialysatePumpTargetRPM( D48_PUMP, getD48PumpSpeedForBCFill(), TRUE ); } + if ( bcSwitchingBasedOnClosedPeriodCounter > 0 ) + { + bcSwitchingBasedOnClosedPeriodCounter -= 1; + } + + if ( 0 == bcSwitchingBasedOnClosedPeriodCounter ) + { + isFirstCycleBCSwitchingCompleted = TRUE; + } + //Transition to next state state = BAL_CHAMBER_STATE2_FILL_END; } @@ -1001,53 +1109,51 @@ balChamberFillPressureDropCounter = 0; balChamberFillCompleteStablePressureCounter = 0; - // Pressure alarm check - if ( TRUE != getBalChamberSwitchingOnlyStatus() ) + if ( TRUE != getBalChamberSwitchingOnlyStatus() ) + { + if ( TRUE == isBalChamberSwitchingPeriodUpdatePending ) { - if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + applyBalChamberSwitchingPeriod( pendingTdDialysateFlowrate ); + scheduleFirstCycleRelaxAfterQdApply(); + } + + if ( getTestConfigStatus( TEST_CONFIG_DD_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) + { + if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) { - if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) - { - // When fill initiated, pressure is not dropped to the expected range, possible valve failures. - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + // When fill initiated, pressure is not dropped to the expected range, possible valve failures. + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); - // Move to the idle state - state = BAL_CHAMBER_STATE_IDLE; - } - else if ( TRUE != isPressureStabilizedDuringFill ) - { - // Alarm when switching time expired, but still pressure not in range which indicates fill is not completed. - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; + } + else if ( ( TRUE != isPressureStabilizedDuringFill ) && ( TRUE != isSpentFillComplete ) ) + { + // Alarm when switching time expired, but still pressure not in range which indicates fill is not completed. + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); - // Move to the idle state - state = BAL_CHAMBER_STATE_IDLE; - } - else - { - // Move to next state when pressure is in range. - state = BAL_CHAMBER_STATE1_FILL_START; - } + // Move to the idle state + state = BAL_CHAMBER_STATE_IDLE; } else { - // Allow to proceed next state even though pressure is not stabilized. + // Move to next state when pressure is in range. state = BAL_CHAMBER_STATE1_FILL_START; } } else { - // For Balancing Chamber Switch Only command, change state as per the switching period - if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) - { - state = BAL_CHAMBER_STATE1_FILL_START; - } + // Allow to proceed next state even though pressure is not stabilized. + state = BAL_CHAMBER_STATE1_FILL_START; } - - // Trigger pressure drop alarm after first cycle of balancing chamber switching complete - if ( FALSE == isFirstCycleBCSwitchingCompleted ) + } + else + { // For Balancing Chamber Switch Only command, change state as per the switching period + if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) { - isFirstCycleBCSwitchingCompleted = TRUE; + state = BAL_CHAMBER_STATE1_FILL_START; } + } // Clear the switching only on request flag. balanceChamberSwitchingOnlyOnRequested = FALSE; @@ -1170,10 +1276,6 @@ { requiredRiseCount = 1U; } - else if ( riseDeltaPsi < SPENT_FILL_SLOPE_SPENT_PRESSURE_LOW_PSIG ) - { - requiredRiseCount = ( qdMlpm <= SPENT_FILL_COMPLETE_QD_TWO_HIT_MAX_MLPM ) ? SPENT_FILL_SLOPE_MAX_RISE_HITS : 1U; - } else { requiredRiseCount = 2U; @@ -1231,69 +1333,81 @@ U32 minD48Speed = initialD48PumpSpeed - ( initialD48PumpSpeed * D48_SPEED_RANGE_LIMIT ); U32 maxD48Speed = initialD48PumpSpeed + ( initialD48PumpSpeed * D48_SPEED_RANGE_LIMIT ); U32 d48SpeedPostRangeCheck = 0; - F32 qdMlpm = getTDDialysateFlowrate(); + F32 qdMlpm = getBalChamberActiveDialysateFlowrate(); BOOL result = FALSE; F32 spentFillCompletePresPsig; BOOL isSpentFillCompleteDetected = FALSE; - // Diener 2000 pump: spent fill complete pressure use legacy 25 PSI. Other pump: depends on Qd. - if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) + if ( TRUE == isBalChamberTimeBasedSwitching() ) { - spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES; + if ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) + { + isSpentFillComplete = TRUE; + } } else { - if ( qdMlpm <= QD_THRESHOLD_HIGH_MLPM ) + // Diener 2000 pump: spent fill complete pressure use legacy 25 PSI. Other pump: depends on Qd. + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) { - spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG; + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES; } else { - spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG; + if ( qdMlpm <= QD_THRESHOLD_HIGH_MLPM ) + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_MID_PSIG; + } + else + { + spentFillCompletePresPsig = SPENT_FILL_COMPLETE_PRES_QD_HIGH_PSIG; + } } - } - isSpentFillCompleteDetected = isSpentFillCompleteByPressure( spentDialPressure, qdMlpm, spentFillCompletePresPsig ); + isSpentFillCompleteDetected = isSpentFillCompleteByPressure( spentDialPressure, qdMlpm, spentFillCompletePresPsig ); - if ( ( TRUE == isSpentFillCompleteDetected ) && ( isSpentFillComplete != TRUE ) ) - { - // Check spent fill time against the balancing chamber closing period - if ( balChamberValveClosePeriod > 0 ) + if ( ( TRUE == isSpentFillCompleteDetected ) && ( isSpentFillComplete != TRUE ) ) { - diffSpentFillCompleteCount = balChamberValveClosePeriod - currentBalChamberFillCounter; - absDiffSpentFillCount = abs(diffSpentFillCompleteCount); - adjustedSpeed = ( ( (F32)absDiffSpentFillCount / (F32)balChamberValveClosePeriod ) * spentDialPumpSpeed ) * D48_SPEED_ADJUST_FACTOR; + // Check spent fill time against the balancing chamber closing period + if ( balChamberValveClosePeriod > 0 ) + { + diffSpentFillCompleteCount = balChamberValveClosePeriod - currentBalChamberFillCounter; + absDiffSpentFillCount = abs(diffSpentFillCompleteCount); + adjustedSpeed = ( ( (F32)absDiffSpentFillCount / (F32)balChamberValveClosePeriod ) * spentDialPumpSpeed ) * D48_SPEED_ADJUST_FACTOR; - // Skip D48 trim in deadband: diff 0..-2 counts (0..100 ms at 50 ms/task); positive band only (larger negative may mean under-fill). - result = ( ( diffSpentFillCompleteCount <= 0 ) && ( diffSpentFillCompleteCount >= -2 ) ) ? TRUE : FALSE; + // Skip D48 trim in deadband: diff 0..-2 counts (0..100 ms at 50 ms/task); positive band only (larger negative may mean under-fill). + result = ( ( diffSpentFillCompleteCount <= 0 ) && ( diffSpentFillCompleteCount >= -2 ) ) ? TRUE : FALSE; - if ( FALSE == result ) - { - if ( diffSpentFillCompleteCount < SPENT_DIFF_COUNT_ZERO ) + if ( FALSE == result ) { - // Increase the D48 pump speed - spentDialPumpSpeed += adjustedSpeed; - } - else - { - //Decrease the D48 pump speed - spentDialPumpSpeed -= adjustedSpeed; - } + if ( diffSpentFillCompleteCount < SPENT_DIFF_COUNT_ZERO ) + { + // Increase the D48 pump speed + spentDialPumpSpeed += adjustedSpeed; + } + else + { + //Decrease the D48 pump speed + spentDialPumpSpeed -= adjustedSpeed; + } - d48SpeedPostRangeCheck = RANGE( spentDialPumpSpeed, minD48Speed, maxD48Speed ); + d48SpeedPostRangeCheck = RANGE( spentDialPumpSpeed, minD48Speed, maxD48Speed ); - - // Do not turn on the pump if the switching only is enabled in the standby mode. - if ( FALSE == getBalChamberSwitchingOnlyStatus() ) - { - // Update the D48 pump speed - setD48PumpSpeedForBCFill( d48SpeedPostRangeCheck ); + // Do not turn on the pump if the switching only is enabled in the standby mode. + if ( FALSE == getBalChamberSwitchingOnlyStatus() ) + { + // Update the D48 pump speed + setD48PumpSpeedForBCFill( d48SpeedPostRangeCheck ); + } } } - } - //Update spent fill is complete - isSpentFillComplete = TRUE; + //Update spent fill is complete + if ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) + { + isSpentFillComplete = TRUE; + } + } } } @@ -1345,6 +1459,19 @@ /*********************************************************************//** * @brief + * The getBalChamberActiveDialysateFlowrate function gets the Qd currently + * applied to balancing chamber timing. + * @details \b Inputs: lastTdDialysateFlowrate + * @details \b Outputs: none + * @return active balancing chamber dialysate flow rate + *************************************************************************/ +F32 getBalChamberActiveDialysateFlowrate( void ) +{ + return lastTdDialysateFlowrate; +} + +/*********************************************************************//** + * @brief * The setBalChamberSwitchingOnlyStatus function sets the balancing chamber * switching only On/Off status. * @details \b Inputs: balanceChamberSwitchingOnly Index: firmware/App/Controllers/ConcentratePumps.c =================================================================== diff -u -r9ac050d6099effbdd62070173d14dd5e225d5310 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Controllers/ConcentratePumps.c (.../ConcentratePumps.c) (revision 9ac050d6099effbdd62070173d14dd5e225d5310) +++ firmware/App/Controllers/ConcentratePumps.c (.../ConcentratePumps.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -266,6 +266,7 @@ //Monitor Pump Park status monitorPumpParkStatus(); + //TODO: Uncomment once done. // Temporarily disable concentrate pump speed mismatch alarms // monitorPumpSpeed( D11_PUMP, ALARM_ID_DD_D11_PUMP_SPEED_CONTROL_ERROR ); // monitorPumpSpeed( D10_PUMP, ALARM_ID_DD_D10_PUMP_SPEED_CONTROL_ERROR ); @@ -851,6 +852,8 @@ concentratePumps[ pumpId ].currentPumpSpeed = 0.0F; // set target rate to zero pumpTargetSpeed[ pumpId ].data = 0.0F; pumpTargetRevCnt[ pumpId ].data = 0; + measuredPumpSpeed[ pumpId ].data = 0.0F; + concentratePumps[ pumpId ].pulseWidthUS = 0.0F; isDosingCompleted [ pumpId ] = TRUE; // Disable the motor when stopping, to take next revolution count @@ -1116,16 +1119,26 @@ pulseWidthInMicroSeconds = pulseWidthCount * CONCENTRATE_PUMP_HALL_SENSE_PERIOD_RESOLUTION; concentratePumps[ pumpId ].pulseWidthUS = pulseWidthInMicroSeconds; - isPumpPulseWidthOut = ( pulseWidthInMicroSeconds <= (F32)CONCENTRATE_PUMP_MIN_ALLOWED_HALL_SENSOR_COUNT ? TRUE : FALSE ); + isPumpPulseWidthOut = FALSE; // Determine measured speed for the pump - if ( CONCENTRATE_PUMP_ZERO_FLOW_RATE == pulseWidthCount ) + if ( ( concentratePumps[ pumpId ].currentPumpSpeed <= NEARLY_ZERO ) || + ( CONCENTRATE_PUMP_ZERO_FLOW_RATE == pulseWidthCount ) ) { measuredPumpSpeed[ pumpId ].data = 0.0F; } - else if ( FALSE == isPumpPulseWidthOut ) + else { - measuredPumpSpeed[ pumpId ].data = ( US_PER_SECOND / pulseWidthInMicroSeconds ) * CONCENTRATE_PUMP_VOLUME_PER_PULSE_DIENER * SEC_PER_MIN; + isPumpPulseWidthOut = ( pulseWidthInMicroSeconds <= (F32)CONCENTRATE_PUMP_MIN_ALLOWED_HALL_SENSOR_COUNT ? TRUE : FALSE ); + + if ( FALSE == isPumpPulseWidthOut ) + { + measuredPumpSpeed[ pumpId ].data = ( US_PER_SECOND / pulseWidthInMicroSeconds ) * CONCENTRATE_PUMP_VOLUME_PER_PULSE_DIENER * SEC_PER_MIN; + } + else + { + measuredPumpSpeed[ pumpId ].data = 0.0F; + } } // If pulse width is out of range capture pump out of range, pumpId and pulse width Index: firmware/App/Controllers/RinsePump.c =================================================================== diff -u -ra7af93efacb700dc80504906356851e9991ba3b1 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Controllers/RinsePump.c (.../RinsePump.c) (revision a7af93efacb700dc80504906356851e9991ba3b1) +++ firmware/App/Controllers/RinsePump.c (.../RinsePump.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -48,7 +48,7 @@ #define RINSE_PUMP_PULSE_WIDTH_INVALID_MAX 0xFFFFU ///< Invalid pulse width maximum (sensor fault). //TODO: to be tested once the Beta 2 units are out #define RINSE_PUMP_SPD_OUT_OF_RANGE_TOL_PCT 0.10F ///< Rinse pump commanded vs measured speed tolerance (10%). -#define RINSE_PUMP_SPEED_OUT_PERSISTENCE_MS 500 ///< Persistence time (ms) before declaring speed-out-of-range alarm. +#define RINSE_PUMP_SPEED_OUT_PERSISTENCE_MS 3000 ///< Persistence time (ms) before declaring speed-out-of-range alarm. #define RINSE_PUMP_MAX_RPM_ESTIMATE 3000U ///< Estimated max rinse pump RPM (for PWM-to-target conversion). // ********** private data ********** @@ -258,7 +258,8 @@ } //TODO: to be tested once the Beta 2 units are out - checkPersistentAlarm( ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE, isRpSpeedOut, (F32)rinsePumpMeasuredSpeed, (F32)rinsePumpTargetSpeedRPM ); + //TODO: Needs more understanding/characterization from EE team, so uncomment after understanding. + //checkPersistentAlarm( ALARM_ID_DD_D79_RINSE_PUMP_SPEED_OUT_OF_RANGE, isRpSpeedOut, (F32)rinsePumpMeasuredSpeed, (F32)rinsePumpTargetSpeedRPM ); } /*********************************************************************//** Index: firmware/App/DDCommon.h =================================================================== diff -u -r21970bc9eb9d4411d3061c3a2c8fad629bf5465e -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/DDCommon.h (.../DDCommon.h) (revision 21970bc9eb9d4411d3061c3a2c8fad629bf5465e) +++ firmware/App/DDCommon.h (.../DDCommon.h) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -57,16 +57,22 @@ //Uncomment below if D1 placement is used for Temp control at dialyzer //#define __USE_D1_TEMP_ 1 +//Uncomment below to disable revised heater model +#define __REVISED_HEATER_MODEL__ 1 + // comment below to disable bicarb multi level sensor for time based chamber F fill #define CONDUCTIVE_LEVEL_SENSOR_ENABLED 1 //Uncomment below to enable d30 heater alarm(as all units are not equipped with d30 temp sensor) //#define ENABLE_ALARM_3 -//Define to enable the DD too-many-bad-message-CRCs alarm. -//#define __BAD_MSG_CRC_ALARM_ENABLED__ 1 +//Comment below to disable the DD too-many-bad-message-CRCs alarm. +#define __BAD_MSG_CRC_ALARM_ENABLED__ 1 +//Comment below to disable the conductivity sensor alarms +#define ENABLE_ALARM_4 + #include #include #endif Index: firmware/App/Drivers/ConductivitySensors.c =================================================================== diff -u -r1c478c1aff953528127767db1f4f747a7f7089c8 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Drivers/ConductivitySensors.c (.../ConductivitySensors.c) (revision 1c478c1aff953528127767db1f4f747a7f7089c8) +++ firmware/App/Drivers/ConductivitySensors.c (.../ConductivitySensors.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -553,7 +553,10 @@ { if ( ++conductivitySensorStatus[ sensorId ].interalCondErrorCount > MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ) { -// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) + //TODO: restore once conductivity sensor are calibrated and working +#ifndef ENABLE_ALARM_4 + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) +#endif } } @@ -566,15 +569,21 @@ { if ( ++conductivitySensorStatus[ sensorId ].interalTempErrorCount > MAX_ALLOWED_UNCHANGED_CONDUCTIVITY_READS ) { -// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) + //TODO: restore once conductivity sensor are calibrated and working +#ifndef ENABLE_ALARM_4 + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) +#endif } } } else { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_CONDUCTIVITY_SENSOR_ERROR ) ) { -// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) + //TODO: restore once conductivity sensor are calibrated and working +#ifndef ENABLE_ALARM_4 + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId ) +#endif } } } @@ -691,7 +700,10 @@ // Alarm if any data is out of range. if ( FALSE == result ) { -// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId, ( U32 )idx ) + //TODO: restore once conductivity sensor are calibrated and working +#ifndef ENABLE_ALARM_4 + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, sensorId, ( U32 )idx ) +#endif } return result; Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -r87ee9712a928c58e3fe8b456bce567df0c6a2038 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 87ee9712a928c58e3fe8b456bce567df0c6a2038) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -656,15 +656,14 @@ /*********************************************************************//** * @brief - * The getCalculatedD48PumpSpeedForBCFill function returns the D48 pump speed - * calculated from dialysate flow rate (Qd) for continuous delivery. - * @details \b Inputs: Qd from TD, test config TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP. + * The getD48PumpSpeed function returns the ceiled D48 pump speed. + * @details \b Inputs: Active flow rate(Qd), pump test config. * @details \b Outputs: none - * @return Calculated D48 pump speed in RPM (Diener 1000 or 2000 formula per test config). + * @return Ceiled D48 pump speed in RPM . *************************************************************************/ -U32 getCalculatedD48PumpSpeedForBCFill( void ) +U32 getD48PumpSpeed( void ) { - F32 dialFlowrate = getTDDialysateFlowrate(); + F32 dialFlowrate = getBalChamberActiveDialysateFlowrate(); F32 slope; F32 intercept; F32 calculatedSpeed; @@ -681,10 +680,8 @@ intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_1000; } - // Calculate nominal speed from Qd. calculatedSpeed = ( slope * dialFlowrate ) + intercept; - // Prevent negative before converting to unsigned and round up using ceilf. if ( calculatedSpeed < 0.0F ) { calculatedSpeed = 0.0F; @@ -697,6 +694,30 @@ /*********************************************************************//** * @brief + * The getCalculatedD48PumpSpeedForBCFill function returns the D48 pump speed + * for balancing chamber fill after applying the low-speed clamp. + * @details \b Inputs: Active BC Qd (or TD Qd before BC period init), pump test config. + * @details \b Outputs: none + * @return D48 pump speed in RPM for BC fill (Diener formula with low-speed floor). + *************************************************************************/ +U32 getCalculatedD48PumpSpeedForBCFill( void ) +{ + U32 rpm; + U32 nominalRpm; + + nominalRpm = getD48PumpSpeed(); + rpm = nominalRpm; + + if ( nominalRpm <= BAL_CHAMBER_TIME_BASED_D48_SPEED_RPM ) + { + rpm = BAL_CHAMBER_TIME_BASED_D48_SPEED_RPM; + } + + return rpm; +} + +/*********************************************************************//** + * @brief * The handleGenDDialysateIsolatedUFState function performs the * Isolated ultrafiltration operations. * @details \b Inputs: none. Index: firmware/App/Monitors/Level.c =================================================================== diff -u -raab669a4ba33505d3a5d6b0e8fa8613933a1e490 -ra2ea8edd918761b403cbe2c00e1bfe2fc69be5ea --- firmware/App/Monitors/Level.c (.../Level.c) (revision aab669a4ba33505d3a5d6b0e8fa8613933a1e490) +++ firmware/App/Monitors/Level.c (.../Level.c) (revision a2ea8edd918761b403cbe2c00e1bfe2fc69be5ea) @@ -608,7 +608,7 @@ /*********************************************************************//** * @brief - * The testFloaterLevelStatusOverride function sets the override status + * The testDDFloaterLevelStateOverride function sets the override status * for a specific floater level sensor. * @details \b Inputs: none * @details \b Outputs: status