Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -raa1f3f772497ece7928affb06214269d93d036e0 -rc7ed4f90b600fe684097654f150e4972646ffec9 --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision aa1f3f772497ece7928affb06214269d93d036e0) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision c7ed4f90b600fe684097654f150e4972646ffec9) @@ -7,8 +7,8 @@ * * @file ModeFill.c * -* @author (last) Michael Garthwaite -* @date (last) 10-Mar-2022 +* @author (last) Dara Navaei +* @date (last) 05-Jan-2022 * * @author (original) Leonardo Baloa * @date (original) 19-Nov-2019 @@ -23,6 +23,7 @@ #include "Heaters.h" #include "LoadCell.h" #include "ModeFill.h" +#include "ModeGenIdle.h" #include "NVDataMgmtDGRecords.h" #include "NVDataMgmt.h" #include "OperationModes.h" @@ -31,6 +32,7 @@ #include "Reservoirs.h" #include "ROPump.h" #include "SystemComm.h" +#include "SystemCommMessages.h" #include "TaskGeneral.h" #include "TemperatureSensors.h" #include "Timers.h" @@ -45,30 +47,49 @@ // ********** private definitions ********** #define TARGET_RO_PRESSURE_PSI 130 ///< Target pressure for RO pump. +#define RO_PUMP_400_ML_PER_MIN 400.0 ///< RO pump speed of 400.0 mL/minute. +#define RO_PUMP_800_ML_PER_MIN 800.0 ///< RO pump speed of 800.0 mL/minute. +#define MILLILITERS_PER_LITER 1000.0 ///< One liter is 1000 milliliters +#define ACID_PUMP_20_ML_PER_MIN 20.0 ///< Acid pump speed of 20.0 mL/minute. +#define BICARB_PUMP_40_ML_PER_MIN 40.0 ///< Bicarb pump speed of 40.0 mL/minute. +#define CONCENTRATE_PUMP_40_ML_PER_MIN 40.0 ///< Concentrate pump speed of 40.0 mL/minute. +#define FILL_MODE_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the fill mode data is published on the CAN bus. #define DIALYSATE_FILL_TIME_OUT ( 5 * SEC_PER_MIN * MS_PER_SECOND ) ///< Time out period when reservoir is not filled with correct dialysate. -#define EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ( 5 * MS_PER_SECOND ) ///< Persistent period for empty bottle detect. +#define EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ( 1 * MS_PER_SECOND ) ///< Persistent period for empty bottle detect. #define CONCENTRATE_PUMP_PRIME_INTERVAL ( 3 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Persistent time interval for concentrate pumps prime. -#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 FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE 0.1F ///< Flow integrated volume has 10% tolerance compare to load cell reading. +#define ACID_TEST_CD1_TCD 12252.1 ///< Used for testing CD1 acid theoretical conductivity. +#define ACID_TEST_CD2_TCD ACID_TEST_CD1_TCD ///< Used for testing CD2 acid theoretical conductivity. +#define BICARB_TEST_CD2_TCD 6820.91 ///< Used for testing CD2 bicarb theoretical conductivity. +#define FIVE_PERCENT_FACTOR 0.05 ///< 5.0 / 100.0 used to calculate conductivity within range of -/+ 5%. +#define RO_PUMP_LOOKUP_TABLE_SIZE 4 ///< Size of array used as RO pump speed lookup table. #define CONCENTRATE_PUMP_PRIME_EXTRA_SPEED_ML_MIN 5.0 ///< Concentrate pump additional speed during priming in mL/min. -#define CONCENTRATE_TEST_TIME_OUT_MS ( 45 * 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 CONCENTRATE_TEST_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Concentrate test time out period in ms. +#define WATER_QUALITY_TEST_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Inlet water quality test time out period in ms. +#define PRIME_CONCENTRATE_LINES_TIME_OUT_MS ( 95 * MS_PER_SECOND ) ///< Time required to prime the concentrate lines. +#define FLUSH_BUBBLES_PUMP_TIME_OUT_MS ( 2 * MS_PER_SECOND ) ///< RO pump on during flush bubble interval in ms. #define DIALYSATE_TEMPERATURE_TOLERANCE_C 2.0 ///< Dialysate temperature tolerance in degree C. #define DIALYSATE_TEMPERATURE_SENSORS_MAX_DRIFT_C 2.0 ///< Dialysate temperature sensors maximum allowed drift in C. #define DIALYSATE_TEMPERATURE_SENSORS_DRIFT_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Dialysate temperature sensors drift timeout in milliseconds. -#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. +#define ACID_CONCENTRATION_BOTTLE_VOLUME_ML 3430.0 ///< Bottle volume of acid concentration in mL. +#define BICARB_CONCENTRATION_BOTTLE_VOLUME_ML 3780.0 ///< Bottle volume of bicarb concentration in mL. +#define CONCENTRATION_BOTTLE_LOW_VOLUME_ML 100.0 ///< Concentration bottle low volume in mL. +#define DATA_PUBLISH_COUNTER_START_COUNT 63 ///< Data publish counter start count. + /// Multiplier to convert flow (mL/min) into volume (mL) for period of general task interval. static const F32 FLOW_INTEGRATOR = ( (F32)TASK_GENERAL_INTERVAL / (F32)( SEC_PER_MIN * MS_PER_SECOND ) ); +static const F32 RO_PUMP_FLUSH_BUBBLES_FLOWS[ RO_PUMP_LOOKUP_TABLE_SIZE ] = { RO_PUMP_400_ML_PER_MIN, + RO_PUMP_800_ML_PER_MIN, + RO_PUMP_400_ML_PER_MIN, + RO_PUMP_800_ML_PER_MIN }; ///< Lookup table to determine the desired RO speed in mL/min when flushing bubbles. + // ********** private data ********** /// Fill conditions status @@ -81,64 +102,95 @@ F32 fillFlowRateAverage; ///< Fill flow average value. F32 fillLastTemperature; ///< Fill last temperature value. BOOL isThisFirstFill; ///< Fill flag to indicate whether it is the first fill or not. + BOOL fillEmptyAcidBottleDetected; ///< Fill acid bottle empty detected. + BOOL fillEmptyBicarbBottleDetected; ///< Fill bicarb bottle empty detected. } FILL_CONDITION_STATUS_T; +static U32 dataPublishCounter; ///< Used to schedule dialysate fill data publication to CAN bus. 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 FILL_CONDITION_STATUS_T fillStatus; ///< Fill condition status. -static U32 waterQualityCheckStartTime; ///< Starting time for inlet water quality check. +static U32 waterQualityTestStartTime; ///< Starting time for inlet water quality test. static U32 concentrateTestStartTime; ///< Starting time for concentrate test. +static U32 concentratePrimingStartTime; ///< Starting time for concentrate priming. +static U32 flushBubblesStartTime; ///< Starting time for flush bubbles. static U32 concentratePumpPrimeCount; ///< Interval count for concentrate pump prime. static F32 totalROFlowRateMLPM; ///< 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 F32 bicarbConductivityTotal; ///< Total of bicarb conductivity during fill. static U32 conductivitySampleCount; ///< Sample count of conductivity during fill. -static OVERRIDE_F32_T usedAcidVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated acid concentration volume has been used in ml. -static OVERRIDE_F32_T usedBicarbVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated bicarb concentration volume has been used in ml. +static F32 averageBicarbConductivity; ///< Average bicarb conductivity over 30 seconds. +static F32 averageAcidConductivity; ///< Average acid conductivity over 30 seconds. +static F32 pctDiffInConductivity; ///< Percent difference in conductivity between CD1 (acid) and CD2 (bicarb). +static U32 bicarbConductivitySampleCount; ///< Sample count of bicarb conductivity over 30 seconds. +static U32 acidConductivitySampleCount; ///< Sample count of acid conductivity over 30 seconds. + +static F32 totalBicarbConductivity; ///< Total bicarb conductivity over 30 seconds. +static F32 totalAcidConductivity; ///< Total acid conductivity over 30 seconds. + +static U32 pumpSpeedIndex; ///< Index used to access the desired pump speed in roPumpFlushBubblesSpeed table. + +static OVERRIDE_F32_T usedAcidVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated acid concentration volume has been used in mL. +static OVERRIDE_F32_T usedBicarbVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated bicarb concentration volume has been used in mL. +static OVERRIDE_U32_T fillModeDataPublishInterval = { FILL_MODE_DATA_PUB_INTERVAL, + FILL_MODE_DATA_PUB_INTERVAL, + 0, 0 }; ///< Interval (in ms) at which to publish fill mode data to CAN bus. + // ********** private function prototypes ********** -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 handleTestInletWaterState( void ); +static DG_FILL_MODE_STATE_T handlePrimeConcentrateLinesState( void ); +static DG_FILL_MODE_STATE_T handleFlushBubblesState( void ); +static DG_FILL_MODE_STATE_T handleTestBicarbConductivityState( void ); +static DG_FILL_MODE_STATE_T handleTestAcidConductivityState( void ); +static DG_FILL_MODE_STATE_T handleProduceDialysateState( void ); static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ); static DG_FILL_MODE_STATE_T handlePausedState( void ); -static BOOL isWaterQualityGood( void ); static void checkDialysateTemperatureSensorsDrift( void ); -static BOOL checkDialysateTemperature( void ); static void handleDialysateMixing( F32 measuredROFlowRate_mL_min ); static void setFillInfoToRTCRAM( void ); +static BOOL isValueWithinPercentRange( F32 testValue, F32 baseValue, F32 percentFactor ); +static void publishFillModeData( void ); /*********************************************************************//** * @brief * The initFillMode function initializes the fill mode module. * @details Inputs: none * @details Outputs: fillState, dialysateFillStartTime, reservoirBaseWeight, * totalROFlowRateMLPM, concentrateTestStartTime, acidConductivityTotal, - * dialysateConductivityTotal, conductivitySampleCount, + * bicarbConductivityTotal, conductivitySampleCount, * concentratePumpPrimeCount * @return none *************************************************************************/ void initFillMode( void ) { - fillState = DG_FILL_MODE_STATE_START; - dialysateFillStartTime = 0; - reservoirBaseWeight = 0.0; - totalROFlowRateMLPM = 0.0; - concentrateTestStartTime = 0; - acidConductivityTotal = 0.0; - dialysateConductivityTotal = 0.0; - conductivitySampleCount = 0; - concentratePumpPrimeCount = 0; + fillState = DG_FILL_MODE_STATE_START; + dialysateFillStartTime = 0; + dataPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; + reservoirBaseWeight = 0.0; + totalROFlowRateMLPM = 0.0; + concentrateTestStartTime = 0; + acidConductivityTotal = 0.0; + bicarbConductivityTotal = 0.0; + conductivitySampleCount = 0; + concentratePumpPrimeCount = 0; + pumpSpeedIndex = 0; + averageBicarbConductivity = 0.0; + averageAcidConductivity = 0.0; + pctDiffInConductivity = 0.0; + bicarbConductivitySampleCount = 0; + acidConductivitySampleCount = 0; + totalBicarbConductivity = 0.0; + totalAcidConductivity = 0.0; - 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 ); + initPersistentAlarm( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME, 0, EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ); + initPersistentAlarm( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME, 0, EMPTY_BOTTLE_DETECT_PERSISTENT_PERIOD_MS ); initPersistentAlarm( ALARM_ID_DG_DIALYSATE_TEMPERATURE_SENSORS_DRIFT_TIMEOUT, 0, DIALYSATE_TEMPERATURE_SENSORS_DRIFT_TIMEOUT_MS ); } @@ -191,6 +243,7 @@ checkInletPressure(); checkRORejectionRatio(); checkDialysateTemperatureSensorsDrift(); + publishFillModeData(); // TODO: Check for open straw door status and alarm if closed // Check if run out of time to fill the reservoir @@ -204,26 +257,34 @@ switch ( fillState ) { case DG_FILL_MODE_STATE_START: - waterQualityCheckStartTime = getMSTimerCount(); - fillState = DG_FILL_MODE_STATE_CHECK_INLET_WATER; + waterQualityTestStartTime = getMSTimerCount(); + fillState = DG_FILL_MODE_STATE_TEST_INLET_WATER; break; - case DG_FILL_MODE_STATE_CHECK_INLET_WATER: - fillState = handleCheckInletWaterState(); + case DG_FILL_MODE_STATE_TEST_INLET_WATER: + fillState = handleTestInletWaterState(); break; - case DG_FILL_MODE_STATE_BICARB_PUMP_CHECK: - fillState = handleBicarbPumpCheckState(); + case DG_FILL_MODE_STATE_PRIME_CONCENTRATE_LINES: + fillState = handlePrimeConcentrateLinesState(); break; - case DG_FILL_MODE_STATE_ACID_PUMP_CHECK: - fillState = handleAcidPumpCheckState(); + case DG_FILL_MODE_STATE_FLUSH_BUBBLES: + fillState = handleFlushBubblesState(); break; - case DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION: - fillState = handleDialysateProductionState(); + case DG_FILL_MODE_STATE_TEST_BICARB_CONDUCTIVITY: + fillState = handleTestBicarbConductivityState(); break; + case DG_FILL_MODE_STATE_TEST_ACID_CONDUCTIVITY: + fillState = handleTestAcidConductivityState(); + break; + + case DG_FILL_MODE_STATE_PRODUCE_DIALYSATE: + fillState = handleProduceDialysateState(); + break; + case DG_FILL_MODE_STATE_DELIVER_DIALYSATE: fillState = handleDeliverDialysateState(); break; @@ -302,9 +363,11 @@ fillStatus.fillTemperatureRunningSum = 0.0; // At the beginning the last and average temperatures are considered as the trimmer heater target temperature which // is the dialysate temperature - fillStatus.fillTemperatureAverage = getHeaterTargetTemperature( DG_TRIMMER_HEATER ); - fillStatus.fillLastTemperature = getHeaterTargetTemperature( DG_TRIMMER_HEATER ) + RESERVOIR_EXTRA_TEMPERATURE; - fillStatus.isThisFirstFill = TRUE; + fillStatus.fillTemperatureAverage = getHeaterTargetTemperature( DG_TRIMMER_HEATER ); + fillStatus.fillLastTemperature = getHeaterTargetTemperature( DG_TRIMMER_HEATER ) + RESERVOIR_EXTRA_TEMPERATURE; + fillStatus.isThisFirstFill = TRUE; + fillStatus.fillEmptyAcidBottleDetected = FALSE; + fillStatus.fillEmptyBicarbBottleDetected = FALSE; } /*********************************************************************//** @@ -322,194 +385,291 @@ /*********************************************************************//** * @brief - * The handleCheckInletWaterState function checks for inlet water quality - * before jumping to dialysate production state. - * @details Inputs: Temperature and conductivity alarms - * @details Outputs: request concentrate pump on and set RO pump flow rate + * The isEmptyAcidBottle function returns the boolean flag that indicates + * whether the acid bottle is empty. + * @details Inputs: none + * @details Outputs: none + * @return fillStatus.fillEmtyAcidBottleDetected + *************************************************************************/ +BOOL isEmptyAcidBottle( void ) +{ + return fillStatus.fillEmptyAcidBottleDetected; +} + +/*********************************************************************//** + * @brief + * The isEmptyBicarbBottle function returns the boolean flag that indicates + * whether the bicarb bottle is empty. + * @details Inputs: none + * @details Outputs: none + * @return fillStatus.fillEmtyBicarbBottleDetected + *************************************************************************/ +BOOL isEmptyBicarbBottle( void ) +{ + return fillStatus.fillEmptyBicarbBottleDetected; +} + +/*********************************************************************//** + * @brief + * The setThisFisrtFillFlag function sets the boolean flag that indicates + * the acid and bicarb bottle need priming. + * @details Inputs: none + * @details Outputs: none + * @param flag to TRUE if prime is needed otherwise FALSE + *************************************************************************/ +void setThisFisrtFillFlag( BOOL flag ) +{ + fillStatus.isThisFirstFill = flag; +} + +/*********************************************************************//** + * @brief + * The handleTestInletWaterState function tests for inlet water quality + * and if this is the first fill of a treatment, prime the acid and bicarb + * lines before jumping to dialysate production state. + * @details Inputs: Temperature, pressure, and conductivity alarms + * @details Outputs: request acid and bicarb pumps on * @return the next state *************************************************************************/ -static DG_FILL_MODE_STATE_T handleCheckInletWaterState( void ) +static DG_FILL_MODE_STATE_T handleTestInletWaterState( void ) { - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_TEST_INLET_WATER; + // If this is the first fill of a treatment, prime acid and bicarb lines, otherwise transition + // to dialysate production directly + if ( TRUE == isThisTheFirstFill() ) + { + // Prepare the acid and bicarb pumps to prime the concentrate lines + setROPumpTargetFlowRateLPM( RO_PUMP_800_ML_PER_MIN / MILLILITERS_PER_LITER, TARGET_RO_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONCENTRATE_PUMP_MAX_SPEED ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONCENTRATE_PUMP_MAX_SPEED ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); // TODO if + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + + concentratePrimingStartTime = getMSTimerCount(); + result = DG_FILL_MODE_STATE_PRIME_CONCENTRATE_LINES; + } + else + { + result = DG_FILL_MODE_STATE_PRODUCE_DIALYSATE; + } + + // TODO get back to this #ifndef DISABLE_DIALYSATE_CHECK - if ( TRUE == isWaterQualityGood() ) + if ( TRUE == didTimeout( waterQualityTestStartTime, WATER_QUALITY_TEST_TIME_OUT_MS ) ) + { + activateAlarmNoData( ALARM_ID_DG_BAD_INLET_WATER_QUALITY ); // alarm is recoverable should go to fill paused state + result = DG_FILL_MODE_STATE_PAUSED; // paused state should go back to DG_FILL_MODE_STATE_TEST_INLET_WATER + } // when alarm acknowledged #endif + + return result; +} + +/*********************************************************************//** + * @brief + * The handlePrimeConcentrateLinesState function primes the acid and bicarb + * lines. + * @details Inputs: None + * @details Outputs: None + * @return the next state + *************************************************************************/ +static DG_FILL_MODE_STATE_T handlePrimeConcentrateLinesState( void ) +{ + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_PRIME_CONCENTRATE_LINES; + + if ( TRUE == didTimeout( concentratePrimingStartTime, PRIME_CONCENTRATE_LINES_TIME_OUT_MS ) ) { - // If this is the first fill of a treatment, prime and acid and bicarb lines, otherwise transition - // to dialysate production directly - if ( TRUE == isThisTheFirstFill() ) - { - concentrateTestStartTime = getMSTimerCount(); - #ifndef DISABLE_MIXING + requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, CONCENTRATE_PUMP_MAX_SPEED ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); - #endif - result = DG_FILL_MODE_STATE_BICARB_PUMP_CHECK; + // Set the RO pump flow rate in according to the roPumpFlushBubblesSpeed table to flush bubbles + pumpSpeedIndex = 0; + setROPumpTargetFlowRateLPM( RO_PUMP_FLUSH_BUBBLES_FLOWS[ pumpSpeedIndex ] / MILLILITERS_PER_LITER, TARGET_RO_PRESSURE_PSI ); + + flushBubblesStartTime = getMSTimerCount(); + result = DG_FILL_MODE_STATE_FLUSH_BUBBLES; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleFlushBubblesState function removes the bubbles in the RO lines by + * running the RP pump at 400 mL/minute for 2 seconds 0 + * then 800 mL/minute for 2 seconds 1 + * then 400 mL/minute for 2 seconds 2 + * then 800 mL/minute for 2 seconds 3 + * @details Inputs: None + * @details Outputs: request RO pump flow rate in mL/minute + * @return the next state + *************************************************************************/ +static DG_FILL_MODE_STATE_T handleFlushBubblesState( void ) +{ + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_FLUSH_BUBBLES; + + if ( TRUE == didTimeout( flushBubblesStartTime, FLUSH_BUBBLES_PUMP_TIME_OUT_MS ) ) + { + if ( pumpSpeedIndex < RO_PUMP_LOOKUP_TABLE_SIZE ) + { + setROPumpTargetFlowRateLPM( RO_PUMP_FLUSH_BUBBLES_FLOWS[ pumpSpeedIndex++ ] / MILLILITERS_PER_LITER, TARGET_RO_PRESSURE_PSI ); + flushBubblesStartTime = getMSTimerCount(); } else { - result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + // Initialization + totalBicarbConductivity = 0.0; + averageBicarbConductivity = 0.0; + bicarbConductivitySampleCount = 0; + + // Set pumps flow rate to prepare for bicarb conductivity testing + setROPumpTargetFlowRateLPM( RO_PUMP_400_ML_PER_MIN / MILLILITERS_PER_LITER, TARGET_RO_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_40_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + + // State transition + concentrateTestStartTime = getMSTimerCount(); + result = DG_FILL_MODE_STATE_TEST_BICARB_CONDUCTIVITY; } } - if ( TRUE == didTimeout( waterQualityCheckStartTime, WATER_QUALITY_CHECK_TIME_OUT_MS ) ) - { - activateAlarmNoData( ALARM_ID_DG_BAD_INLET_WATER_QUALITY ); - requestNewOperationMode( DG_MODE_GENE ); - } - return result; } /*********************************************************************//** * @brief - * The handleBicarbPumpCheckState function checks conductivity value for + * The handleTestBicarbConductivityState function tests conductivity value for * bicarbonate concentrate. * @details Inputs: Bicarbonate conductivity sensor value * @details Outputs: Verified bicarbonate conductivity value * @return the next state *************************************************************************/ -static DG_FILL_MODE_STATE_T handleBicarbPumpCheckState( void ) +static DG_FILL_MODE_STATE_T handleTestBicarbConductivityState( void ) { - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_BICARB_PUMP_CHECK; + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_TEST_BICARB_CONDUCTIVITY; + F32 bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - DG_BICARB_CONCENTRATES_RECORD_T bicarb = getBicarbConcentrateCalRecord(); - F32 measuredROFlowRateMLPM = getMeasuredROFlowRateLPM() * ML_PER_LITER; - F32 bicarbPumpFlowRateMLPM = measuredROFlowRateMLPM * bicarb.bicarbConcentrate[ CAL_DATA_BICARB_CONCENTRATE_1 ].bicarbConcMixRatio - + CONCENTRATE_PUMP_PRIME_EXTRA_SPEED_ML_MIN; +#ifndef DISABLE_BICARB_CONDUCTIVITY_TEST + totalBicarbConductivity += bicarbConductivity; + bicarbConductivitySampleCount++; -#ifndef DISABLE_DIALYSATE_CHECK - F32 bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); -#else - F32 bicarbConductivity = MAX_BICARB_CONCENTRATE_CONDUCTIVITY; -#endif - - bicarbPumpFlowRateMLPM = MIN( bicarbPumpFlowRateMLPM, CONCENTRATE_PUMP_MAX_SPEED ); - - if ( bicarbConductivity >= MIN_BICARB_CONCENTRATE_CONDUCTIVITY ) + if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) { - // Reduce acid pump speed after reaching minimum conductivity - // This prevents conductivity value to go out of sensor's range - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, bicarbPumpFlowRateMLPM ); + averageBicarbConductivity = totalBicarbConductivity / bicarbConductivitySampleCount; - if ( concentratePumpPrimeCount++ > CONCENTRATE_PUMP_PRIME_INTERVAL ) + if ( TRUE == isValueWithinPercentRange( averageBicarbConductivity, BICARB_TEST_CD2_TCD, FIVE_PERCENT_FACTOR ) ) { - concentratePumpPrimeCount = 0; - concentrateTestStartTime = getMSTimerCount(); -#ifndef DISABLE_MIXING - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, CONCENTRATE_PUMP_MAX_SPEED ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + // Initialization requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); + totalBicarbConductivity = 0.0; + totalAcidConductivity = 0.0; + bicarbConductivitySampleCount = 0; + acidConductivitySampleCount = 0; #endif - result = DG_FILL_MODE_STATE_ACID_PUMP_CHECK; + // Set pumps flow rate to prepare for acid conductivity testing + setROPumpTargetFlowRateLPM( RO_PUMP_800_ML_PER_MIN / MILLILITERS_PER_LITER, TARGET_RO_PRESSURE_PSI ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_20_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + // State transition + concentrateTestStartTime = getMSTimerCount(); + result = DG_FILL_MODE_STATE_TEST_ACID_CONDUCTIVITY; + +#ifndef DISABLE_BICARB_CONDUCTIVITY_TEST } + else + { + // Bicarb test failed, go to fault + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, averageBicarbConductivity ); + } } - else - { - concentratePumpPrimeCount = 0; - } +#endif - if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, bicarbConductivity ); - requestNewOperationMode( DG_MODE_GENE ); - } - return result; } /*********************************************************************//** * @brief - * The handleAcidPumpCheckState function checks conductivity value for + * The handleTestAcidConductivityState function validates that the average + * conductivity of the acid and bicarb concentrate are within 5% of the + * theoretical conductivity over 30 seconds sampling period. * acid concentrate. - * @details Inputs: Acid conductivity sensor value - * @details Outputs: Verified acid conductivity value + * @details Inputs: Acid and bicarb conductivity sensor values + * @details Outputs: Verified acid, bicarb, acid & bicarb conductivity values * @return the next state *************************************************************************/ -static DG_FILL_MODE_STATE_T handleAcidPumpCheckState( void ) +static DG_FILL_MODE_STATE_T handleTestAcidConductivityState( void ) { - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_ACID_PUMP_CHECK; + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_TEST_ACID_CONDUCTIVITY; + F32 acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + F32 bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - DG_ACID_CONCENTRATES_RECORD_T acid = getAcidConcentrateCalRecord(); - F32 measuredROFlowRateMLPM = getMeasuredROFlowRateLPM() * ML_PER_LITER; - F32 acidPumpFlowRateMLPM = measuredROFlowRateMLPM * acid.acidConcentrate[ CAL_DATA_ACID_CONCENTRATE_1 ].acidConcMixRatio + - CONCENTRATE_PUMP_PRIME_EXTRA_SPEED_ML_MIN; +#ifndef DISABLE_ACID_CONDUCTIVITY_TEST + totalBicarbConductivity += bicarbConductivity; + bicarbConductivitySampleCount++; -#ifndef DISABLE_DIALYSATE_CHECK - F32 acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); -#else - F32 acidConductivity = MAX_ACID_CONCENTRATE_CONDUCTIVITY; -#endif + totalAcidConductivity += acidConductivity; + acidConductivitySampleCount++; - acidPumpFlowRateMLPM = MIN( acidPumpFlowRateMLPM, CONCENTRATE_PUMP_MAX_SPEED ); - - if ( acidConductivity >= MIN_ACID_CONCENTRATE_CONDUCTIVITY ) + if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) { - // Reduce acid pump speed after reaching minimum conductivity - // This prevents conductivity value to go out of sensor's range - setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, acidPumpFlowRateMLPM ); + averageBicarbConductivity = totalBicarbConductivity / bicarbConductivitySampleCount; + averageAcidConductivity = totalAcidConductivity / acidConductivitySampleCount; + pctDiffInConductivity = fabs( 2.0 * ( averageAcidConductivity - averageBicarbConductivity ) / + ( averageAcidConductivity + averageBicarbConductivity ) ); - if ( concentratePumpPrimeCount++ > CONCENTRATE_PUMP_PRIME_INTERVAL ) + if ( ( TRUE == isValueWithinPercentRange( averageAcidConductivity, ACID_TEST_CD2_TCD, FIVE_PERCENT_FACTOR ) ) && + ( pctDiffInConductivity < FIVE_PERCENT_FACTOR ) ) { - concentratePumpPrimeCount = 0; +#endif + setROPumpTargetFlowRateLPM( getTargetFillFlowRateLPM(), TARGET_RO_PRESSURE_PSI ); + + handleDialysateMixing( getMeasuredROFlowRateLPM() * ML_PER_LITER ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + + // Do the necessary setup here before transition to Produce Dialysate State fillStatus.isThisFirstFill = FALSE; - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + result = DG_FILL_MODE_STATE_PRODUCE_DIALYSATE; + +#ifndef DISABLE_ACID_CONDUCTIVITY_TEST } + else + { + // Acid conductivity did not pass, fault + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, averageAcidConductivity ); + } } - else - { - concentratePumpPrimeCount = 0; - } - if ( TRUE == didTimeout( concentrateTestStartTime, CONCENTRATE_TEST_TIME_OUT_MS ) ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, acidConductivity ); - requestNewOperationMode( DG_MODE_GENE ); - } +#endif return result; } /*********************************************************************//** * @brief - * The handleDialysateProductionState function executes the dialysate production + * The handleProduceDialysateState function executes the dialysate production * state of the fill mode state machine. * @details Inputs: inlet water quality and dialysate temperature * @details Outputs: none * @return the next state *************************************************************************/ -static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ) +static DG_FILL_MODE_STATE_T handleProduceDialysateState( void ) { - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; - F32 measuredROFlowRateMLPM = getMeasuredROFlowRateLPM() * ML_PER_LITER; + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_PRODUCE_DIALYSATE; -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( TRUE == isWaterQualityGood() ) && ( TRUE == checkDialysateTemperature() ) ) -#else - if ( TRUE ) -#endif - { - // Prime mixing before deliver result to reservoir - handleDialysateMixing( measuredROFlowRateMLPM ); + // Prime mixing before deliver result to reservoir + handleDialysateMixing( getMeasuredROFlowRateLPM() * ML_PER_LITER ); + #ifndef DISABLE_MIXING - requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + + if ( concentratePumpPrimeCount++ > CONCENTRATE_PUMP_PRIME_INTERVAL ) #endif + { + fillStatus.isThisFirstFill = FALSE; setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; } - else - { - concentratePumpPrimeCount = 0; - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - } return result; } @@ -524,96 +684,91 @@ *************************************************************************/ static DG_FILL_MODE_STATE_T handleDeliverDialysateState( void ) { - F32 integratedVolumeML; + F32 integratedVolumeML; - F32 measuredROFlowRateMLPM = getMeasuredROFlowRateLPM() * ML_PER_LITER; - F32 acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); - F32 dialysateConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - BOOL isAcidConductivityOutOfRange = ( acidConductivity <= MIN_ACID_CONCENTRATE_CONDUCTIVITY ) || - ( acidConductivity >= MAX_ACID_CONCENTRATE_CONDUCTIVITY ) ? TRUE : FALSE; - BOOL isDialysateConductivityOutOfRange = ( dialysateConductivity <= MIN_DIALYSATE_CONDUCTIVITY ) || - ( dialysateConductivity >= MAX_DIALYSATE_CONDUCTIVITY ) ? TRUE : FALSE; - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DELIVER_DIALYSATE; DG_RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); + F32 acidConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD1_SENSOR ); + F32 bicarbConductivity = getConductivityValue( CONDUCTIVITYSENSORS_CD2_SENSOR ); - // Set concentrate pumps speed based off RO pump flow rate - handleDialysateMixing( measuredROFlowRateMLPM ); + // Set concentrate pumps speed based on the RO pump flow rate + handleDialysateMixing( getMeasuredROFlowRateLPM() * ML_PER_LITER ); - totalROFlowRateMLPM += measuredROFlowRateMLPM; - integratedVolumeML = totalROFlowRateMLPM * FLOW_INTEGRATOR * ACID_BICARB_CONCENTRATE_ADDITION_MULTIPLER; - usedAcidVolumeML.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ) * FLOW_INTEGRATOR; - usedBicarbVolumeML.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ) * FLOW_INTEGRATOR; + totalROFlowRateMLPM += getMeasuredROFlowRateWithConcPumpsLPM() * ML_PER_LITER; + integratedVolumeML = totalROFlowRateMLPM * FLOW_INTEGRATOR; + usedAcidVolumeML.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ) * FLOW_INTEGRATOR; + usedBicarbVolumeML.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP2_BICARB ) * FLOW_INTEGRATOR; - acidConductivityTotal += acidConductivity; - dialysateConductivityTotal += dialysateConductivity; + acidConductivityTotal += acidConductivity; + bicarbConductivityTotal += bicarbConductivity; conductivitySampleCount++; // DG is delivering dialysate keep collecting the sample counter and the measured flow fillStatus.fillSampleCounter += 1; fillStatus.fillFlowRateRunningSum += getMeasuredROFlowRateLPM(); fillStatus.fillTemperatureRunningSum += getTemperatureValue( (U32)TEMPSENSORS_OUTLET_PRIMARY_HEATER ); -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( isWaterQualityGood() != TRUE ) || ( checkDialysateTemperature() != TRUE ) ) - { - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; - } +#ifndef DISABLE_MIXING + // If you start the fill you should be finished. - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ACID_CONDUCTIVITY_OUT_OF_RANGE, isAcidConductivityOutOfRange ) ) + // Detect empty bottles using integrated volumes // TODO: empty bottles detection using conductivity sensors + if ( ( ( ACID_CONCENTRATION_BOTTLE_VOLUME_ML - getF32OverrideValue( &usedAcidVolumeML ) ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) ) // || // SRSDG 437 { usedAcidVolumeML.data = 0.0; requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - result = DG_FILL_MODE_STATE_PAUSED; + fillStatus.isThisFirstFill = TRUE; // empty bottles need replaced, set isThisFirstFill to FALSE so that prime, flush, acid & bicarb test are needed + fillStatus.fillEmptyAcidBottleDetected = TRUE; // set this variable to FALSE when user presses OK on the alarm to confirm bottle has been replaced and resume } - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BICARB_CONDUCTIVITY_OUT_OF_RANGE, isDialysateConductivityOutOfRange ) ) + if ( ( ( BICARB_CONCENTRATION_BOTTLE_VOLUME_ML - getF32OverrideValue( &usedBicarbVolumeML ) ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) ) // || // SRSDG 438 { usedBicarbVolumeML.data = 0.0; requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID ); requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - result = DG_FILL_MODE_STATE_PAUSED; + fillStatus.isThisFirstFill = TRUE; + fillStatus.fillEmptyBicarbBottleDetected = TRUE; } #endif -#ifndef DISABLE_MIXING - if ( ( ACID_CONCENTRATION_BOTTLE_VOLUME_ML - getF32OverrideValue( &usedAcidVolumeML ) ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) - { - activateAlarmNoData( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME ); - } - if ( ( BICARB_CONCENTRATION_BOTTLE_VOLUME_ML - getF32OverrideValue( &usedBicarbVolumeML ) ) <= CONCENTRATION_BOTTLE_LOW_VOLUME_ML ) - { - activateAlarmNoData( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME ); - } -#endif - // If we've reached our target fill to volume (by weight), we're done filling - go back to generation idle mode + setBadAvgConductivityDetectedFlag( FALSE ); + + // If we've reached our target fill to volume (by weight), we're done filling - go back to generation idle mode // SRSDG 398 if ( TRUE == hasTargetFillVolumeBeenReached( inactiveReservoir ) ) { F32 filledVolumeML = getReservoirWeight( inactiveReservoir ) - reservoirBaseWeight; - F32 integratedVolumeToLoadCellReadingPercent = fabs( 1 - ( filledVolumeML / integratedVolumeML ) ); - F32 avgAcidConductivity = acidConductivityTotal / conductivitySampleCount; // TODO - should we be checking this below? - F32 avgDialysateConductivity = dialysateConductivityTotal / conductivitySampleCount; + F32 integratedVolumeToLoadCellReadingPercent = fabs( 1.0F - ( filledVolumeML / integratedVolumeML ) ); + F32 avgAcidConductivity = acidConductivityTotal / conductivitySampleCount; + F32 avgBicarbConductivity = bicarbConductivityTotal / conductivitySampleCount; - if ( integratedVolumeToLoadCellReadingPercent > FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE ) - { #ifndef DISABLE_FLOW_CHECK_IN_FILL + if ( integratedVolumeToLoadCellReadingPercent > FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE ) // SRSDG 439 + { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_FLOW_METER_CHECK_FAILURE, filledVolumeML, integratedVolumeML ); + } #endif + +#ifndef DISABLE_DIALYSATE_CHECK // SRSDG 400 + if ( FALSE == isValueWithinPercentRange( avgBicarbConductivity, BICARB_NORMAL_CONDUCTIVITY, FIVE_PERCENT_FACTOR ) ) + { + fillStatus.isThisFirstFill = TRUE; + setBadAvgConductivityDetectedFlag( TRUE ); // signal idle bad avg conductivity detected + setThisFisrtFillFlag( TRUE ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FILL_CONDUCTIVITY_OUT_OF_RANGE, avgBicarbConductivity, BICARB_NORMAL_CONDUCTIVITY ); // trigger replace bottles alarm #1 + activateAlarmNoData ( ALARM_ID_CREATING_DIALYSATE_PLEASE_WAIT ); } -#ifndef DISABLE_DIALYSATE_CHECK - if ( ( avgDialysateConductivity < MIN_DIALYSATE_CONDUCTIVITY ) || ( avgDialysateConductivity > MAX_DIALYSATE_CONDUCTIVITY ) ) + if ( FALSE == isValueWithinPercentRange( avgAcidConductivity, ACID_NORMAL_CONDUCTIVITY, FIVE_PERCENT_FACTOR ) ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_CONDUCTIVITY_FAULT, avgAcidConductivity, avgDialysateConductivity ); + fillStatus.isThisFirstFill = TRUE; + setBadAvgConductivityDetectedFlag( TRUE ); // signal idle bad avg conductivity detected + setThisFisrtFillFlag( TRUE ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_FILL_CONDUCTIVITY_OUT_OF_RANGE, avgAcidConductivity, ACID_NORMAL_CONDUCTIVITY ); // trigger replace bottles alarm #1 then + activateAlarmNoData ( ALARM_ID_CREATING_DIALYSATE_PLEASE_WAIT ); } #endif - // Done with this fill. Calculate the average fill flow rate and average temperature // Reset the variables for the next fill // Get the last fill temperature before leaving to Generation Idle @@ -626,7 +781,7 @@ // Write the latest fill data into the RTC RAM for heaters control // TODO test this and make sure it is writing it correctly - setFillInfoToRTCRAM(); + setFillInfoToRTCRAM(); // SRSDG ??? requestNewOperationMode( DG_MODE_GENE ); } @@ -646,38 +801,16 @@ { 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 ) ) ) + if ( FALSE == isAlarmActive( ALARM_ID_DG_BAD_INLET_WATER_QUALITY ) ) { - result = DG_FILL_MODE_STATE_CHECK_INLET_WATER; + result = DG_FILL_MODE_STATE_TEST_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 isInletPressureGood = ( FALSE == isAlarmActive( ALARM_ID_INLET_WATER_LOW_PRESSURE ) ? FALSE : TRUE ); - - BOOL isWaterTemperatureGood = ( ( FALSE == isAlarmActive( ALARM_ID_INLET_WATER_HIGH_TEMPERATURE ) && - FALSE == isAlarmActive( ALARM_ID_INLET_WATER_LOW_TEMPERATURE ) ) ? FALSE : TRUE ); - - BOOL isWaterConductivityGood = ( ( FALSE == isAlarmActive( ALARM_ID_INLET_WATER_HIGH_CONDUCTIVITY ) && - FALSE == isAlarmActive( ALARM_ID_INLET_WATER_LOW_CONDUCTIVITY ) && - FALSE == isAlarmActive( ALARM_ID_RO_REJECTION_RATIO_OUT_OF_RANGE ) ) ? FALSE : TRUE ); - - return ( ( isInletPressureGood && isWaterTemperatureGood && isWaterConductivityGood ) ); -} - -/*********************************************************************//** - * @brief * The checkDialysateTemperatureSensorsDrift function checks whether the * dialysate temperature sensors have drifted. If they are drifted, it raises * an alarm. @@ -701,18 +834,27 @@ /*********************************************************************//** * @brief - * The checkDialysateTemperature function checks dialysate temperature after - * it gets heated up by primary heater. - * @details Inputs: TPo temperature value + * The isValueWithinPercentRange function validates if the test value + * is within the percentage range specified by the baseValue and + * percentFactor. + * @details Inputs: None * @details Outputs: None - * @return TRUE if dialysate temperature is in range, otherwise FALSE + * @param: testValue, baseValue, percentFactor + * @return TRUE if testValue is within range. Otherwise, return FALSE *************************************************************************/ -static BOOL checkDialysateTemperature( void ) +static BOOL isValueWithinPercentRange( F32 testValue, F32 baseValue, F32 percentFactor ) { - F32 dialysateTemp = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); - F32 targetTemp = getHeaterTargetTemperature( DG_PRIMARY_HEATER ); + BOOL testFlag = FALSE; + F32 percentValue = baseValue * percentFactor; + F32 valueMax = baseValue + percentValue; + F32 valueMin = baseValue - percentValue; - return ( ( fabs( dialysateTemp - targetTemp ) <= DIALYSATE_TEMPERATURE_TOLERANCE_C ) ? TRUE : FALSE ); + if ( ( testValue >= valueMin ) && ( testValue <= valueMax ) ) + { + testFlag = TRUE; + } + + return testFlag; } /*********************************************************************//** @@ -762,4 +904,181 @@ setHeatersInfoRecord( (U08*)&record, sizeof( DG_HEATERS_RECORD_T ) ); } +/*********************************************************************//** + * @brief + * The publishFillModeData function publishes fill mode data + * at the set interval. + * @details Inputs: fillModeDataPublicationTimerCounter + * @details Outputs: fillModeDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishFillModeData( void ) +{ + // publish Drain pump data on interval + if ( ++dataPublishCounter >= getU32OverrideValue( &fillModeDataPublishInterval ) ) + { + DG_FILL_MODE_DATA_T fillModeData; + + // Populate the data structure for publication + fillModeData.averageAcidConductivity = averageAcidConductivity; + fillModeData.averageBicarbConductivity = averageBicarbConductivity; + fillModeData.isThisTheFirstFill = isThisTheFirstFill(); + fillModeData.pctDiffInConductivity = pctDiffInConductivity; + fillModeData.usedAcidVolumeML = usedAcidVolumeML.data; + fillModeData.usedBicarbVolumeML = usedBicarbVolumeML.data; + fillModeData.totalIntegratedVolumeML = totalROFlowRateMLPM; + + broadcastData( MSG_ID_DG_FILL_MODE_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&fillModeData, sizeof( DG_FILL_MODE_DATA_T ) ); + + dataPublishCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + +/*********************************************************************//** + * @brief + * The testSetUsedAcidVolumeMLOverride function overrides the + * acid volume. + * @details Inputs: used acid volume + * @details Outputs: used acid volume + * @param: value : override used acid volume in mL + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetUsedAcidVolumeMLOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + usedAcidVolumeML.ovInitData = usedAcidVolumeML.data; + usedAcidVolumeML.ovData = value; + usedAcidVolumeML.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetUsedAcidVolumeMLOverride function resets the override + * of the used acid volume. + * @details Inputs: used acid volume + * @details Outputs: used acid volume + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetUsedAcidVolumeMLOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + usedAcidVolumeML.data = usedAcidVolumeML.ovInitData; + usedAcidVolumeML.override = OVERRIDE_RESET; + usedAcidVolumeML.ovInitData = 0.0; + usedAcidVolumeML.ovData = 0.0; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetUsedBicarbVolumeMLOverride function overrides the + * bicarb volume. + * @details Inputs: used bicarb volume + * @details Outputs: used bicarb volume + * @param: value : override used bicarb volume in mL + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetUsedBicarbVolumeMLOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + usedBicarbVolumeML.ovInitData = usedBicarbVolumeML.data; + usedBicarbVolumeML.ovData = value; + usedBicarbVolumeML.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetUsedBicarbVolumeMLOverride function resets the override + * of the used bicarb volume. + * @details Inputs: used bicarb volume + * @details Outputs: used bicarb volume + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetUsedBicarbVolumeMLOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + usedBicarbVolumeML.data = usedBicarbVolumeML.ovInitData; + usedBicarbVolumeML.override = OVERRIDE_RESET; + usedBicarbVolumeML.ovInitData = 0.0; + usedBicarbVolumeML.ovData = 0.0; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetFillModeDataPublishIntervalOverride function overrides the + * fill mode data publish interval. + * @details Inputs: FillModeDataPublishInterval + * @details Outputs: FillModeDataPublishInterval + * @param: value override fill mode data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetFillModeDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_GENERAL_INTERVAL; + fillModeDataPublishInterval.ovData = intvl; + fillModeDataPublishInterval.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetFillModeDataPublishIntervalOverride function resets the + * override of the fill mode data publish interval. + * @details Inputs: FillModeDataPublishInterval + * @details Outputs: FillModeDataPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetFillModeDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + fillModeDataPublishInterval.override = OVERRIDE_RESET; + fillModeDataPublishInterval.ovData = fillModeDataPublishInterval.ovInitData; + result = TRUE; + } + + return result; +} + /**@}*/