Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r0a313ac4ec34865255e72089fded191b951b62de -r5d82009d1baa2b52122065934481745bf4de223b --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 0a313ac4ec34865255e72089fded191b951b62de) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 5d82009d1baa2b52122065934481745bf4de223b) @@ -26,6 +26,7 @@ #include "Pressures.h" #include "Reservoirs.h" #include "ROPump.h" +#include "SystemComm.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" #include "Timers.h" @@ -46,53 +47,60 @@ #define DIALYSATE_BICARB_CONCENTRATE_RATIO ( 4.06812 / FRACTION_TO_PERCENT_FACTOR ) ///< Ratio between RO water and bicarbonate concentrate. #define DIALYSATE_FILL_TIME_OUT ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time out period when reservoir is not filled with correct dialysate. -///< Persistent time interval for concentrate pumps test. -#define CONCENTRATE_PUMP_TEST_PERSISTENT_INTERVAL ( 2 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) +#define EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ( 3 * MS_PER_SECOND ) ///< Persistent period for empty bottle detect. ///< Persistent time interval for concentrate pumps prime. #define CONCENTRATE_PUMP_PRIME_INTERVAL ( 3 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) #define ACID_BICARB_CONCENTRATE_ADDITION_MULTIPLER 1.06 ///< Acid and bicarbonate concentrates make up around 6% to total volume. #define FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE 0.1 ///< Flow integrated volume has 10% tolerance compare to load cell reading. +#define CONCENTRATE_PUMP_PRIME_SPEED_ML_MIN 40.0 ///< Concentrate pump speed during priming in mL/min. #define CONCENTRATE_TEST_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Concentrate test time out period in ms. #define WATER_QUALITY_CHECK_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Inlet water quality check time out period in ms. -#define CONDUCTIVITY_ERROR_PERSISTENCE_PERIOD_MS ( 15 * MS_PER_SECOND ) ///< Persistence period for conductivity error. -#define CONDUCTIVITY_CLEAR_PERSISTENCE_PERIOD_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity error. - #define DIALYSATE_TEMPERATURE_TOLERANCE_C 2.0 ///< Dialysate temperature tolerance in degree C. -#define ONE_LITER_WEIGHT_GRAMS ( ML_PER_LITER ) ///< One liter weight in grams. +#define ACID_CONCENTRATION_BOTTLE_VOLUME_ML 3000.0 ///< Volume of acid concentration in ml. +#define BICARB_CONCENTRATION_BOTTLE_VOLUME_ML 3000.0 ///< Volume of bicarb concentration in ml. +#define CONCENTRATION_BOTTLE_LOW_VOLUME_ML 100.0 ///< Concentration bottle low volume in ml. /// Multiplier to convert flow (L/min) into volume (mL) for period of general task interval. static const F32 RO_FLOW_INTEGRATOR = ( ( ML_PER_LITER * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); +/// Multiplier to convert flow (mL/min) into volume (mL) for period of general task interval. +static const F32 CONCENTRATE_PUMP_FLOW_INTEGRATOR = ( TASK_GENERAL_INTERVAL / ( SEC_PER_MIN * MS_PER_SECOND ) ); // ********** private data ********** -static DG_FILL_MODE_STATE_T fillState; ///< Currently active fill state. -static U32 dialysateFillStartTime; ///< Current time when starting to fill dialysate. -static F32 reservoirBaseWeight; ///< Fill reservoir base weight. -static F32 totalROFlowRate_LPM; ///< Total RO flow rate over period of time. -static U32 concentrateTestStartTime; ///< Starting time for concentrate test. -static U32 waterQualityCheckStartTime; ///< Starting time for inlet water quality check. -static F32 dialysateConductivityTotal; ///< Total of dialysate conductivity during fill. -static U32 dialysateConductivitySampleCount; ///< Sample count of dialysate conductivity during fill. -static U32 concentratePumpTestPersistentCount; ///< Persistent count for concentrate pump testing. -static U32 concentratePumpPrimeCount; +static DG_FILL_MODE_STATE_T fillState; ///< Currently active fill state. +static U32 dialysateFillStartTime; ///< Current time when starting to fill dialysate. +static F32 reservoirBaseWeight; ///< Fill reservoir base weight. +static U32 waterQualityCheckStartTime; ///< Starting time for inlet water quality check. +static U32 concentrateTestStartTime; ///< Starting time for concentrate test. +static U32 concentratePumpPrimeCount; ///< Interval count for concentrate pump prime. + +static F32 totalROFlowRate_LPM; ///< Total RO flow rate over period of time. +static F32 acidConductivityTotal; ///< Total of acid conductivity during fill. +static F32 dialysateConductivityTotal; ///< Total of dialysate conductivity during fill. +static U32 conductivitySampleCount; ///< Sample count of conductivity during fill. + +static OVERRIDE_F32_T usedAcidVolume_mL = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated acid concentration volume has been used in ml. +static OVERRIDE_F32_T usedBicarbVolume_mL = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated bicarb concentration volume has been used in ml. + // ********** private function prototypes ********** -static BOOL isWaterQualityGood( void ); -static BOOL checkDialysateConductivity( void ); -static BOOL checkDialysateTemperature( void ); static DG_FILL_MODE_STATE_T handleCheckInletWaterState( void ); static DG_FILL_MODE_STATE_T handleBicarbPumpCheckState( void ); static DG_FILL_MODE_STATE_T handleAcidPumpCheckState( void ); static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ); static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ); static DG_FILL_MODE_STATE_T handlePausedState( void ); -static void handleDialysateMixing( void ); +static BOOL isWaterQualityGood( void ); +static BOOL checkDialysateTemperature( void ); +static void handleDialysateMixing( F32 measuredROFlowRate ); +static F32 getUsedAcidVolume( void ); +static F32 getUsedBicarbVolume( void ); /*********************************************************************//** * @brief @@ -108,12 +116,13 @@ reservoirBaseWeight = 0.0; totalROFlowRate_LPM = 0.0; concentrateTestStartTime = 0; + acidConductivityTotal = 0.0; dialysateConductivityTotal = 0.0; - dialysateConductivitySampleCount = 0; - concentratePumpTestPersistentCount = 0; + conductivitySampleCount = 0; concentratePumpPrimeCount = 0; - initPersistentAlarm( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE, CONDUCTIVITY_CLEAR_PERSISTENCE_PERIOD_MS, CONDUCTIVITY_ERROR_PERSISTENCE_PERIOD_MS ); + initPersistentAlarm( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, 0, EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ); + initPersistentAlarm( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, 0, EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ); } /*********************************************************************//** @@ -129,7 +138,7 @@ dialysateFillStartTime = getMSTimerCount(); - // set initial actuator states + // Set initial actuator states setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); @@ -152,27 +161,27 @@ *************************************************************************/ U32 execFillMode( void ) { - // check inlet water conductivity, temperature, pressure, and RO rejection ratio + // Check inlet water conductivity, temperature, pressure, and RO rejection ratio checkInletWaterConductivity(); checkInletWaterTemperature(); checkInletPressure(); checkRORejectionRatio(); // TODO: Check for open straw door status and alarm if closed - - // check if run out of time to fill the reservoir + // Check if run out of time to fill the reservoir if ( TRUE == didTimeout( dialysateFillStartTime, DIALYSATE_FILL_TIME_OUT ) ) { activateAlarmNoData( ALARM_ID_DG_DIALYSATE_FILL_OUT_OF_TIME ); requestNewOperationMode( DG_MODE_CIRC ); } + // Transition to re-circ mode when HD is not communicating if ( FALSE == isHDCommunicating() ) { requestNewOperationMode( DG_MODE_CIRC ); } - // execute current Fill state + // Execute current Fill state switch ( fillState ) { case DG_FILL_MODE_STATE_START: @@ -215,76 +224,6 @@ /*********************************************************************//** * @brief - * The isWaterQualityGood function checks for inlet water quality. - * @details Inputs: Temperature and conductivity alarms - * @details Outputs: none - * @return TRUE if water quality is good, otherwise FALSE - *************************************************************************/ -static BOOL isWaterQualityGood( void ) -{ - BOOL const isInletPressureGood = !isAlarmActive( ALARM_ID_INLET_WATER_LOW_PRESSURE ); - BOOL const isWaterTemperatureGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_TEMPERATURE ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_TEMPERATURE ); - BOOL const isWaterConductivityGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY ) && - !isAlarmActive( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE ); - - return ( isInletPressureGood && isWaterTemperatureGood && isWaterConductivityGood ); -} - -/*********************************************************************//** - * @brief - * The checkDialysateConductivity function checks dialysate conductivity - * after adding acid and bicarbonate and triggers an alarm when conductivity - * is out of range. - * @details Inputs: CD1 and CD2 sensor conductivity - * @details Outputs: Trigger alarms when dialysate conductivity is out of allowed range - * @return TRUE if dialysate conductivity is good, otherwise FALSE - *************************************************************************/ -static BOOL checkDialysateConductivity( void ) -{ - BOOL const isDialysateConductivityGood = isDialysateConductivityInRange(); - F32 const acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); - - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE, !isDialysateConductivityGood ) ) - { -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( MIN_ACID_CONCENTRATE_CONDUCTIVITY <= acidConductivity ) && ( acidConductivity <= MAX_ACID_CONCENTRATE_CONDUCTIVITY ) ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ) ); - } - else - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE, getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ) ); - } -#endif - } - - if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE, !isDialysateConductivityGood ) ) - { - clearAlarmCondition( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE ); - clearAlarmCondition( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE ); - } - - return ( isDialysateConductivityGood && isWaterQualityGood() ); -} - -/*********************************************************************//** - * @brief - * The checkDialysateTemperature function checks dialysate temperature after - * it gets heated up by primary heater. - * @details Inputs: TPo temperature value - * @details Outputs: None - * @return TRUE if dialysate temperature is in range, otherwise FALSE - *************************************************************************/ -static BOOL checkDialysateTemperature( void ) -{ - F32 const dialysateTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 const targetTemp = getPrimaryHeaterTargetTemperature(); - - return ( ( fabs( dialysateTemp - targetTemp ) <= DIALYSATE_TEMPERATURE_TOLERANCE_C ) ? TRUE : FALSE ); -} - -/*********************************************************************//** - * @brief * The handleCheckInletWaterState function checks for inlet water quality * before jumping to dialysate production state. * @details Inputs: Temperature and conductivity alarms @@ -294,17 +233,17 @@ static DG_FILL_MODE_STATE_T handleCheckInletWaterState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; - DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); #ifndef DISABLE_DIALYSATE_CHECK if ( TRUE == isWaterQualityGood() ) #endif { - reservoirBaseWeight = getReservoirWeight( inactiveReservoir ); concentrateTestStartTime = getMSTimerCount(); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, 40.0 ); +#ifndef DISABLE_MIXING + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONCENTRATE_PUMP_PRIME_SPEED_ML_MIN ); +#endif result = DG_FILL_MODE_STATE_BICARB_PUMP_CHECK; } @@ -328,48 +267,34 @@ static DG_FILL_MODE_STATE_T handleBicarbPumpCheckState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_BICARB_PUMP_CHECK; +#ifndef DISABLE_DIALYSATE_CHECK F32 const bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); +#else + F32 const bicarbConductivity = MIN_BICARB_CONCENTRATE_CONDUCTIVITY; +#endif if ( MIN_BICARB_CONCENTRATE_CONDUCTIVITY <= bicarbConductivity ) { if ( concentratePumpPrimeCount++ > CONCENTRATE_PUMP_PRIME_INTERVAL ) { - F32 const measuredROFlowRate = getMeasuredROFlowRate(); - F32 const bicarbCP2PumpFlowRate = DIALYSATE_BICARB_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; - - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, bicarbCP2PumpFlowRate ); - } - } - else - { - concentratePumpPrimeCount = 0; - } - -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( MIN_BICARB_CONCENTRATE_CONDUCTIVITY <= bicarbConductivity ) && ( bicarbConductivity <= MAX_BICARB_CONCENTRATE_CONDUCTIVITY ) ) -#else - if ( TRUE ) -#endif - { - if ( concentratePumpTestPersistentCount++ > CONCENTRATE_PUMP_TEST_PERSISTENT_INTERVAL ) - { - concentratePumpTestPersistentCount = 0; concentratePumpPrimeCount = 0; concentrateTestStartTime = getMSTimerCount(); requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, 40.0 ); +#ifndef DISABLE_MIXING + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONCENTRATE_PUMP_PRIME_SPEED_ML_MIN ); +#endif result = DG_FILL_MODE_STATE_ACID_PUMP_CHECK; } } else { - concentratePumpTestPersistentCount = 0; + concentratePumpPrimeCount = 0; } if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ) ); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, bicarbConductivity ); requestNewOperationMode( DG_MODE_CIRC ); } @@ -387,45 +312,30 @@ static DG_FILL_MODE_STATE_T handleAcidPumpCheckState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_ACID_PUMP_CHECK; +#ifndef DISABLE_DIALYSATE_CHECK F32 const acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); +#else + F32 const acidConductivity = MIN_ACID_CONCENTRATE_CONDUCTIVITY; +#endif if ( MIN_ACID_CONCENTRATE_CONDUCTIVITY <= acidConductivity ) { if ( concentratePumpPrimeCount++ > CONCENTRATE_PUMP_PRIME_INTERVAL ) { - F32 const measuredROFlowRate = getMeasuredROFlowRate(); - F32 const acidCP1PumpFlowRate = DIALYSATE_ACID_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; - - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, acidCP1PumpFlowRate ); + concentratePumpPrimeCount = 0; + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; } } else { concentratePumpPrimeCount = 0; } -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( MIN_ACID_CONCENTRATE_CONDUCTIVITY <= acidConductivity ) && ( acidConductivity <= MAX_ACID_CONCENTRATE_CONDUCTIVITY ) ) -#else - if ( TRUE ) -#endif - { - if ( concentratePumpTestPersistentCount++ > CONCENTRATE_PUMP_TEST_PERSISTENT_INTERVAL ) - { - concentratePumpTestPersistentCount = 0; - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); - result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; - } - } - else - { - concentratePumpTestPersistentCount = 0; - } - if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ) ); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, acidConductivity ); requestNewOperationMode( DG_MODE_CIRC ); } @@ -436,112 +346,108 @@ * @brief * The handleDialysateProductionState function executes the dialysate production * state of the fill mode state machine. - * @details Inputs: Dialysate conditions + * @details Inputs: inlet water quality and dialysate temperature * @details Outputs: none * @return the next state *************************************************************************/ static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ) { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; - BOOL const isDialysateGood = checkDialysateConductivity(); + DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); - handleDialysateMixing(); - #ifndef DISABLE_DIALYSATE_CHECK - if ( ( TRUE == isDialysateGood ) && ( TRUE == checkDialysateTemperature() ) ) + if ( ( TRUE == isWaterQualityGood() ) && ( TRUE == checkDialysateTemperature() ) ) #else if ( TRUE ) #endif { + reservoirBaseWeight = getReservoirWeight( inactiveReservoir ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2_BICARB ); setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; } - else if ( isDialysateGood != TRUE ) - { - if ( ( TRUE == isAlarmActive( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE ) ) || - ( TRUE == isAlarmActive( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE ) ) ) - { - result = DG_FILL_MODE_STATE_PAUSED; - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); - } - } return result; } /*********************************************************************//** * @brief - * The handlePausedState function executes the paused state of the fill - * mode state machine. - * @details Inputs: Dialysate conditions - * @details Outputs: none - * @return the next state - *************************************************************************/ -static DG_FILL_MODE_STATE_T handlePausedState( void ) -{ - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_PAUSED; - - if ( TRUE == checkDialysateConductivity() ) - { - if ( ( isAlarmActive( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE ) != TRUE ) && - ( isAlarmActive( ALARM_ID_DIALYSATE_CONDUCTIVITY_OUT_OF_RANGE ) ) != TRUE ) - { - result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; - } - } - - return result; -} - -/*********************************************************************//** - * @brief * The handleDeliverDialysateState function executes the deliver dialysate * state of the fill mode state machine. - * @details Inputs: Dialysate conditions - * @details Outputs: Deliver dialysate + * @details Inputs: inlet water quality and dialysate temperature + * @details Outputs: Deliver dialysate to inactive reservoir * @return the next state *************************************************************************/ static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ) { - F32 avgDialysateConductivity; - F32 integratedVolume_mL; + F32 const measuredROFlowRate = getMeasuredROFlowRate(); + F32 const acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + F32 const dialysateConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); + BOOL const isAcidConductivityOutOfRange = ( acidConductivity <= MIN_ACID_CONCENTRATE_CONDUCTIVITY ) && ( MAX_ACID_CONCENTRATE_CONDUCTIVITY >= acidConductivity ); + BOOL const isDialysateConductivityOutOfRange = ( dialysateConductivity <= MIN_DIALYSATE_CONDUCTIVITY ) && ( MAX_DIALYSATE_CONDUCTIVITY >= dialysateConductivity ); + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + F32 integratedVolume_mL; - totalROFlowRate_LPM += getMeasuredROFlowRate(); + // Set concentrate pumps speed based off RO pump flow rate + handleDialysateMixing( measuredROFlowRate ); + + totalROFlowRate_LPM += measuredROFlowRate; integratedVolume_mL = totalROFlowRate_LPM * RO_FLOW_INTEGRATOR * ACID_BICARB_CONCENTRATE_ADDITION_MULTIPLER; - dialysateConductivityTotal += getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - dialysateConductivitySampleCount++; + usedAcidVolume_mL.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ) * CONCENTRATE_PUMP_FLOW_INTEGRATOR; + usedBicarbVolume_mL.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ) * CONCENTRATE_PUMP_FLOW_INTEGRATOR; - handleDialysateMixing(); + acidConductivityTotal += acidConductivity; + dialysateConductivityTotal += dialysateConductivity; + conductivitySampleCount++; - if ( ( checkDialysateConductivity() != TRUE ) || ( checkDialysateTemperature() != TRUE ) ) - { #ifndef DISABLE_DIALYSATE_CHECK + if ( ( isWaterQualityGood() != TRUE ) || ( checkDialysateTemperature() != TRUE ) ) + { + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + } #endif + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, isAcidConductivityOutOfRange ) ) + { + usedAcidVolume_mL.data = 0.0; + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + result = DG_FILL_MODE_STATE_PAUSED; } - if ( ( getReservoirWeight( inactiveReservoir ) - reservoirBaseWeight ) >= ONE_LITER_WEIGHT_GRAMS ) + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, isDialysateConductivityOutOfRange ) ) { - avgDialysateConductivity = dialysateConductivityTotal / dialysateConductivitySampleCount; + usedBicarbVolume_mL.data = 0.0; + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpsOff( CONCENTRATEPUMPS_CP2_BICARB ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + result = DG_FILL_MODE_STATE_PAUSED; + } - if ( ( avgDialysateConductivity < MIN_DIALYSATE_CONDUCTIVITY ) || ( avgDialysateConductivity > MAX_DIALYSATE_CONDUCTIVITY ) ) - { -#ifndef DISABLE_DIALYSATE_CHECK - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIALYSATE_CONDUCTIVITY_FAULT, avgDialysateConductivity ); - requestNewOperationMode( DG_MODE_CIRC ); -#endif - } + if ( ( ACID_CONCENTRATION_BOTTLE_VOLUME_ML - getUsedAcidVolume() ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) + { + activateAlarmNoData( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME ); } + if ( ( BICARB_CONCENTRATION_BOTTLE_VOLUME_ML - getUsedBicarbVolume() ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) + { + activateAlarmNoData( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME ); + } + // if we've reached our target fill to volume (by weight), we're done filling - go back to re-circ mode if ( ( TRUE == hasTargetFillVolumeBeenReached( inactiveReservoir ) ) || ( ( integratedVolume_mL - reservoirBaseWeight ) >= MAX_RESERVOIR_VOLUME_ML ) ) { F32 const filledVolume_mL = getReservoirWeight( inactiveReservoir ) - reservoirBaseWeight; F32 const integratedVolumeToLoadCellReadingPercent = fabs( 1 - ( filledVolume_mL / integratedVolume_mL ) ); + F32 const avgAcidConductivity = acidConductivityTotal / conductivitySampleCount; + F32 const avgDialysateConductivity = dialysateConductivityTotal / conductivitySampleCount; if ( integratedVolumeToLoadCellReadingPercent > FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE ) { @@ -550,6 +456,14 @@ #endif } +#ifndef DISABLE_DIALYSATE_CHECK + if ( ( avgAcidConductivity < MIN_ACID_CONCENTRATE_CONDUCTIVITY ) || ( avgAcidConductivity > MAX_ACID_CONCENTRATE_CONDUCTIVITY ) || + ( avgDialysateConductivity < MIN_DIALYSATE_CONDUCTIVITY ) || ( avgDialysateConductivity > MAX_DIALYSATE_CONDUCTIVITY ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_CONDUCTIVITY_FAULT, avgAcidConductivity, avgDialysateConductivity ); + } +#endif + requestNewOperationMode( DG_MODE_CIRC ); } @@ -558,17 +472,71 @@ /*********************************************************************//** * @brief + * The handlePausedState function executes the paused state of the fill + * mode state machine. + * @details Inputs: Empty bottle alarm active + * @details Outputs: none + * @return the next state + *************************************************************************/ +static DG_FILL_MODE_STATE_T handlePausedState( void ) +{ + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_PAUSED; + + if ( ( FALSE == isAlarmActive( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE ) ) && + ( FALSE == isAlarmActive( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE ) ) ) + { + result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isWaterQualityGood function checks for inlet water quality. + * @details Inputs: Temperature and conductivity alarms + * @details Outputs: none + * @return TRUE if water quality is good, otherwise FALSE + *************************************************************************/ +static BOOL isWaterQualityGood( void ) +{ + BOOL const isInletPressureGood = !isAlarmActive( ALARM_ID_INLET_WATER_LOW_PRESSURE ); + BOOL const isWaterTemperatureGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_TEMPERATURE ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_TEMPERATURE ); + BOOL const isWaterConductivityGood = !isAlarmActive( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY ) && !isAlarmActive( ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY ) && + !isAlarmActive( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE ); + + return ( isInletPressureGood && isWaterTemperatureGood && isWaterConductivityGood ); +} + +/*********************************************************************//** + * @brief + * The checkDialysateTemperature function checks dialysate temperature after + * it gets heated up by primary heater. + * @details Inputs: TPo temperature value + * @details Outputs: None + * @return TRUE if dialysate temperature is in range, otherwise FALSE + *************************************************************************/ +static BOOL checkDialysateTemperature( void ) +{ + F32 const dialysateTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 const targetTemp = getPrimaryHeaterTargetTemperature(); + + return ( ( fabs( dialysateTemp - targetTemp ) <= DIALYSATE_TEMPERATURE_TOLERANCE_C ) ? TRUE : FALSE ); +} + +/*********************************************************************//** + * @brief * The handleDialysateMixing function handles the dialysate mixing by setting * the concentrate pump speed relative to the RO pump flow rate. * @details Inputs: none * @details Outputs: Set concentrate pump speed relative to RO pump flow rate + * @param measuredROFlowRate measured RO flow rate * @return none *************************************************************************/ -static void handleDialysateMixing( void ) +static void handleDialysateMixing( F32 measuredROFlowRate ) { #ifndef DISABLE_MIXING // Set concentrate pumps speed based off RO pump flow rate - F32 const measuredROFlowRate = getMeasuredROFlowRate(); F32 const acidCP1PumpFlowRate = DIALYSATE_ACID_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; F32 const bicarbCP2PumpFlowRate = DIALYSATE_BICARB_CONCENTRATE_RATIO * measuredROFlowRate * ML_PER_LITER; @@ -577,4 +545,49 @@ #endif } +/*********************************************************************//** + * @brief + * The getUsedAcidVolume function returns the used volume of acid concentration. + * @details Inputs: usedAcidVolume_mL + * @details Outputs: none + * @return used acid concentration volume + *************************************************************************/ +static F32 getUsedAcidVolume( void ) +{ + F32 result = usedAcidVolume_mL.data; + + if ( OVERRIDE_KEY == usedAcidVolume_mL.override ) + { + result = usedAcidVolume_mL.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getUsedBicarbVolume function returns the used volume of bicarbonate concentration. + * @details Inputs: usedBicarbVolume_mL + * @details Outputs: none + * @return used bicarbonate concentration volume + *************************************************************************/ +static F32 getUsedBicarbVolume( void ) +{ + F32 result = usedBicarbVolume_mL.data; + + if ( OVERRIDE_KEY == usedBicarbVolume_mL.override ) + { + result = usedBicarbVolume_mL.ovData; + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + + /**@}*/