Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r19d00df76fc906db9e514b10f259c39958ff25bb -rf38051e1882be3e774f10ba924343a6ce1334890 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 19d00df76fc906db9e514b10f259c39958ff25bb) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision f38051e1882be3e774f10ba924343a6ce1334890) @@ -25,6 +25,7 @@ #include "Heaters.h" #include "InternalADC.h" #include "MessageSupport.h" +#include "ModeFill.h" #include "OperationModes.h" #include "PIControllers.h" #include "ROPump.h" @@ -81,7 +82,7 @@ typedef enum Heaters_Exec_States { - HEATER_EXEC_STATE_NOT_RUNNING = 0, ///< Heater exec state not running. + HEATER_EXEC_STATE_OFF = 0, ///< Heater exec state off. HEATER_EXEC_STATE_RAMP_TO_TARGET, ///< Heater exec state ramp to target. HEATER_EXEC_STATE_CONTROL_TO_TARGET, ///< Heater exec state control to target. NUM_OF_HEATERS_STATE, ///< Number of heaters state. @@ -90,8 +91,8 @@ /// Heaters data structure typedef struct { - F32 targetTemp; ///< Heater target temperature. - F32 originalTargetTemp; ///< Heater original target temperature set by user. + F32 targetTemp; // TODO do we need this anymore? ///< Heater target temperature. + F32 originalTargetTemp; ///< Heater original target temperature set by user. HEATERS_STATE_T state; ///< Heater state. TEMPERATURE_SENSORS_T feedbackSensor; ///< Heater feedback sensor for controlling. U32 controlTimerCounter; // TODO remove? Maybe use in heat disinfect ///< Heater control timer counter. @@ -102,9 +103,7 @@ U32 heaterOnWithNoFlowTimer; // TODO remove ///< Heater on with no flow timer. BOOL isFlowBelowMin; ///< Heater flow below minimum flag indicator. BOOL hasTargetTempChanged; ///< Heater target temperature change flag indicator. - BOOL isThisFirstFill; ///< Heater the first fill flag indicator. - PI_CONTROLLER_ID_T controllerID; ///< Heater PI controller ID TODO remove this? U32 tempOutOfRangeTimer; ///< Heater temperature out of range timer TODO remove once the mechanical thermal cutoff was implemented BOOL isHeaterTempOutOfRange; ///< Heater temperature out of range flag indicator TODO remove once the mechanical thermal cutoff was implemented @@ -118,7 +117,7 @@ // ********** private function prototypes ********** -static HEATERS_STATE_T handleHeaterStateNotRunning( DG_HEATERS_T heater ); +static HEATERS_STATE_T handleHeaterStateOff( DG_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateRampToTarget( DG_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToTarget( DG_HEATERS_T heater ); @@ -159,14 +158,13 @@ heatersStatus[ heater ].startHeaterSignal = FALSE; heatersStatus[ heater ].tempOutOfRangeTimer = 0; heatersStatus[ heater ].isHeaterTempOutOfRange = FALSE; - heatersStatus[ heater ].state = HEATER_EXEC_STATE_NOT_RUNNING; + heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; heatersStatus[ heater ].targetTemp = 0.0; heatersStatus[ heater ].originalTargetTemp = 0.0; heatersStatus[ heater ].dutycycle = 0.0; heatersStatus[ heater ].targetROFlow = 0.0; heatersStatus[ heater ].controllerID = ( DG_PRIMARY_HEATER == heater ? 4 : PI_CONTROLLER_ID_TRIMMER_HEATER ); // TODO remove or refactor? heatersStatus[ heater ].hasTargetTempChanged = FALSE; - heatersStatus[ heater ].isThisFirstFill = TRUE; } // Initialize the PI controller for the trimmer heater @@ -282,8 +280,8 @@ switch( state ) { - case HEATER_EXEC_STATE_NOT_RUNNING: - heatersStatus[ heater ].state = handleHeaterStateNotRunning( heater ); + case HEATER_EXEC_STATE_OFF: + heatersStatus[ heater ].state = handleHeaterStateOff( heater ); break; case HEATER_EXEC_STATE_RAMP_TO_TARGET: @@ -297,7 +295,7 @@ default: // The heater is in an unknown state. Turn it off and switch to not running state stopHeater( heater ); - heatersStatus[ heater ].state = HEATER_EXEC_STATE_NOT_RUNNING; + heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_INVALID_EXEC_STATE, heater ); break; } @@ -411,46 +409,21 @@ /*********************************************************************//** * @brief - * The handleHeaterStateNotRunning function handles the heater not running state. + * The handleHeaterStateOff function handles the heater not running state. * @details Inputs: heaterStatus * @details Outputs: heaterStatus * @param heater: The heater Id that its not running state is handled * @return next state of the state machine *************************************************************************/ -static HEATERS_STATE_T handleHeaterStateNotRunning( DG_HEATERS_T heater ) +static HEATERS_STATE_T handleHeaterStateOff( DG_HEATERS_T heater ) { - HEATERS_STATE_T state = HEATER_EXEC_STATE_NOT_RUNNING; + HEATERS_STATE_T state = HEATER_EXEC_STATE_OFF; if ( TRUE == heatersStatus[ heater ].startHeaterSignal ) { heatersStatus[ heater ].isHeaterOn = TRUE; heatersStatus[ heater ].startHeaterSignal = FALSE; - heatersStatus[ heater ].targetROFlow = getTargetROPumpFlowRate(); - /*f ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) - { - heatersStatus[ heater ].targetTemp = MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE; - } - else - { - // Heaters control work with target temperature internally. Original target temperature is set by the user using the APIs - heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - } - - // If the operation mode is heat disinfect and the heater is primary heater, change the feedback sensor to THd - if ( ( DG_MODE_HEAT == getCurrentOperationMode() ) && ( DG_PRIMARY_HEATER == heater ) ) - { - heatersStatus[ heater ].feedbackSensor = TEMPSENSORS_HEAT_DISINFECT; // TODO do we need this? - } - - TEMPERATURE_SENSORS_T sensor = heatersStatus[ heater ].feedbackSensor; - F32 feedbackTemperature = getTemperatureValue( (U32)sensor ); - F32 targetTemperature = heatersStatus[ heater ].targetTemp; - - // If the target temperature is greater than the feedback temperature the duty cycle is 100% otherwise, 0% - F32 duty = ( targetTemperature > feedbackTemperature ? HEATERS_MAX_DUTY_CYCLE : HEATERS_MIN_DUTY_CYCLE ); - setHeaterDutyCycle( heater, duty );*/ - // Turn on the heater state = HEATER_EXEC_STATE_RAMP_TO_TARGET; } @@ -469,34 +442,29 @@ *************************************************************************/ static HEATERS_STATE_T handleHeaterStateRampToTarget( DG_HEATERS_T heater ) { - F32 dutyCycle = 0.0; - HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; + F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + F32 targetFlow = 0.0; + F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; + F32 dutyCycle = 0.0; - F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); - F32 feedbackTemperature = getTemperatureValue( (U32)heatersStatus[ heater ].feedbackSensor ); - F32 targetFlow = getTargetROPumpFlowRate(); - BOOL isItHandOffTime = FALSE; - if ( DG_MODE_FILL == getCurrentOperationMode() ) { - F32 flow; - F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; + // Get the previous fill's average flow rate + targetFlow = getAverageFillFlowRate(); + dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); + } + else if ( ( DG_MODE_GENE == getCurrentOperationMode() ) || ( DG_MODE_DRAI == getCurrentOperationMode() ) ) + { + targetFlow = getTargetROPumpFlowRate(); + } - if ( TRUE == heatersStatus[ heater ].isThisFirstFill ) - { - flow = targetFlow; - heatersStatus[ heater ].isThisFirstFill = FALSE; - } - //dutyCycle = calculatePrimaryHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); - //heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - } + // TODO For testing only remove //dutyCycle = calculatePrimaryHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); //heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; // TODO for testing only remove - isItHandOffTime = TRUE; /*if ( heatersStatus[ heater ].initialDutyCycle - 0.0 < NEARLY_ZERO ) @@ -590,7 +558,7 @@ } }*/ - if ( TRUE == isItHandOffTime ) + if ( TRUE /*== isItHandOffTime*/ ) { setHeaterDutyCycle( heater, dutyCycle ); @@ -602,7 +570,7 @@ if ( FALSE == heatersStatus[ heater ].isHeaterOn ) { setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); - state = HEATER_EXEC_STATE_NOT_RUNNING; + state = HEATER_EXEC_STATE_OFF; } return state; @@ -662,7 +630,7 @@ if ( FALSE == heatersStatus[ heater ].isHeaterOn ) { setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); - state = HEATER_EXEC_STATE_NOT_RUNNING; + state = HEATER_EXEC_STATE_OFF; } return state; Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r373b25b7e3229e9203f4af6bfa491def69e2ce83 -rf38051e1882be3e774f10ba924343a6ce1334890 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 373b25b7e3229e9203f4af6bfa491def69e2ce83) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision f38051e1882be3e774f10ba924343a6ce1334890) @@ -64,12 +64,13 @@ #define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. #define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. -//#define RO_FLOW_ADC_TO_LPM_FACTOR 5555 ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). - +#ifdef USE_SMALL_FLOW_SENSOR_K_FACTOR // TODO new flow sensor k factor for testing only -#define RO_FLOW_ADC_TO_LPM_FACTOR 300 ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). +#define RO_FLOW_ADC_TO_LPM_FACTOR 300 ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). +#else +#define RO_FLOW_ADC_TO_LPM_FACTOR 5555 ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). +#endif - #define ROP_FLOW_TO_PWM_SLOPE 0.1 ///< Slope of flow to PWM line equation. #define ROP_FLOW_TO_PWM_INTERCEPT 0.0 ///< Intercept of flow to PWM line equation. @@ -183,7 +184,7 @@ MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); // Initialize the persistent alarm for not turning off the pump - initPersistentAlarm( ALARM_ID_RO_PUMP_OFF_FAULT, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); + initPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); // Initialize the variables roControlTimerCounter = 0; @@ -390,10 +391,10 @@ F32 pressureInlet = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_INLET ); BOOL isPumpRunning = ( pressureInlet + MAX_PRESSURE_TARGET_TOLERANCE ) < actualPressure; - checkPersistentAlarm( ALARM_ID_RO_PUMP_OFF_FAULT, isPumpRunning, pressureInlet, ( pressureInlet + MAX_PRESSURE_TARGET_TOLERANCE ) ); + checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isPumpRunning, pressureInlet, ( pressureInlet + MAX_PRESSURE_TARGET_TOLERANCE ) ); // Check if it has timed out - if ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_OFF_FAULT ) ) + if ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) { activateSafetyShutdown(); } Index: firmware/App/DGCommon.h =================================================================== diff -u -r45891ce485a2f527a6278ee1b0cb49c1345fc2f2 -rf38051e1882be3e774f10ba924343a6ce1334890 --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 45891ce485a2f527a6278ee1b0cb49c1345fc2f2) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision f38051e1882be3e774f10ba924343a6ce1334890) @@ -56,6 +56,7 @@ // Turn these flags on to disable dialysate mixing #define DISABLE_DIALYSATE_CHECK 1 #define DISABLE_MIXING 1 + #define USE_SMALL_FLOW_SENSOR_K_FACTOR 1 #include #include Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r2c4dfa08ac8ead07939b4f6aba3b0073e0997706 -rf38051e1882be3e774f10ba924343a6ce1334890 --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 2c4dfa08ac8ead07939b4f6aba3b0073e0997706) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision f38051e1882be3e774f10ba924343a6ce1334890) @@ -61,17 +61,22 @@ #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 FLOW_MOVING_AVG_TIME_INTERVAL ( 1 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Fill flow moving average time interval. -#define NUMBER_OF_FLOW_SAMPLES_FOR_MOVING_AVG 10.0 ///< Number of flow samples to collect for moving average. - /// 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 ) ); // ********** private data ********** +typedef struct +{ + F32 fillFlowRunningSum; ///< Fill flow running sum. + U32 fillFlowSampleCounter; ///< Fill flow sample counter. + F32 fillFlowAverage; ///< Fill flow average value. +} FILL_FLOW_RATE_STATUS_T; + 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_FLOW_RATE_STATUS_T fillFlowRate; ///< Fill flow rate status. static U32 waterQualityCheckStartTime; ///< Starting time for inlet water quality check. static U32 concentrateTestStartTime; ///< Starting time for concentrate test. @@ -97,6 +102,7 @@ static BOOL isWaterQualityGood( void ); static BOOL checkDialysateTemperature( void ); static void handleDialysateMixing( F32 measuredROFlowRate_mL_min ); +static void calculateFillAverage( void ); /*********************************************************************//** * @brief @@ -107,15 +113,18 @@ *************************************************************************/ void initFillMode( void ) { - fillState = DG_FILL_MODE_STATE_START; - dialysateFillStartTime = 0; - reservoirBaseWeight = 0.0; - totalROFlowRate_mL_min = 0.0; - concentrateTestStartTime = 0; - acidConductivityTotal = 0.0; - dialysateConductivityTotal = 0.0; - conductivitySampleCount = 0; - concentratePumpPrimeCount = 0; + fillState = DG_FILL_MODE_STATE_START; + dialysateFillStartTime = 0; + reservoirBaseWeight = 0.0; + totalROFlowRate_mL_min = 0.0; + concentrateTestStartTime = 0; + acidConductivityTotal = 0.0; + dialysateConductivityTotal = 0.0; + conductivitySampleCount = 0; + concentratePumpPrimeCount = 0; + fillFlowRate.fillFlowAverage = 0.79; // TODO get this value from NV RAM at the beginning of the fill + fillFlowRate.fillFlowRunningSum = 0.0; + fillFlowRate.fillFlowSampleCounter = 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 ); @@ -216,6 +225,19 @@ /*********************************************************************//** * @brief + * The getAverageFillFlowRate function returns the moving average fill + * flow rate. + * @details Inputs: none + * @details Outputs: averageFillFlowRate + * @return the moving average of the fill flow rate + *************************************************************************/ +F32 getAverageFillFlowRate( void ) +{ + return fillFlowRate.fillFlowAverage; +} + +/*********************************************************************//** + * @brief * The handleCheckInletWaterState function checks for inlet water quality * before jumping to dialysate production state. * @details Inputs: Temperature and conductivity alarms @@ -315,8 +337,8 @@ { DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_ACID_PUMP_CHECK; DG_ACID_CONCENTRATES_RECORD_T acid = getAcidConcentrateCalRecord(); - F32 const measuredROFlowRate_mL_min = getMeasuredROFlowRate() * ML_PER_LITER; - F32 const acidPumpFlowRate_mL_min = measuredROFlowRate_mL_min * acid.acidConcentrate[ CAL_DATA_ACID_CONCENTRATE_1 ].acidConcMixRatio + + F32 measuredROFlowRate_mL_min = getMeasuredROFlowRate() * ML_PER_LITER; + F32 acidPumpFlowRate_mL_min = measuredROFlowRate_mL_min * acid.acidConcentrate[ CAL_DATA_ACID_CONCENTRATE_1 ].acidConcMixRatio + CONCENTRATE_PUMP_PRIME_EXTRA_SPEED_ML_MIN; #ifndef DISABLE_DIALYSATE_CHECK @@ -363,8 +385,8 @@ *************************************************************************/ static DG_FILL_MODE_STATE_T handleDialysateProductionState( void ) { - DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; - F32 const measuredROFlowRate_mL_min = getMeasuredROFlowRate() * ML_PER_LITER; + DG_FILL_MODE_STATE_T result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; + F32 measuredROFlowRate_mL_min = getMeasuredROFlowRate() * ML_PER_LITER; #ifndef DISABLE_DIALYSATE_CHECK if ( ( TRUE == isWaterQualityGood() ) && ( TRUE == checkDialysateTemperature() ) ) @@ -425,6 +447,10 @@ dialysateConductivityTotal += dialysateConductivity; conductivitySampleCount++; + // DG is delivering dialysate keep collecting the sample counter and the measured flow + fillFlowRate.fillFlowSampleCounter += 1; + fillFlowRate.fillFlowRunningSum += getMeasuredROFlowRate(); + #ifndef DISABLE_DIALYSATE_CHECK if ( ( isWaterQualityGood() != TRUE ) || ( checkDialysateTemperature() != TRUE ) ) { @@ -485,6 +511,12 @@ } #endif + // Done with this fill. Calculate the average fill flow rate + fillFlowRate.fillFlowAverage = fillFlowRate.fillFlowRunningSum / (F32)fillFlowRate.fillFlowSampleCounter; + // Reset the variables for the next fill + fillFlowRate.fillFlowRunningSum = 0.0; + fillFlowRate.fillFlowSampleCounter = 0; + requestNewOperationMode( DG_MODE_GENE ); } @@ -570,7 +602,12 @@ #endif } +static void calculateFillAverage( void ) +{ +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Modes/ModeFill.h =================================================================== diff -u -rb1dc3df084a8517ca1575bdbf741fecd96d56a12 -rf38051e1882be3e774f10ba924343a6ce1334890 --- firmware/App/Modes/ModeFill.h (.../ModeFill.h) (revision b1dc3df084a8517ca1575bdbf741fecd96d56a12) +++ firmware/App/Modes/ModeFill.h (.../ModeFill.h) (revision f38051e1882be3e774f10ba924343a6ce1334890) @@ -37,6 +37,8 @@ void transitionToFillMode( void ); // prepares for transition to fill mode U32 execFillMode( void ); // execute the fill mode state machine (call from OperationModes) +F32 getAverageFillFlowRate( void ); + /**@}*/ #endif