Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r7d293e18ea5ac0fce443c68525100e44df80b4fd -r353d01d31bc69d4d1901ff09097ee610bb1c9dbc --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 7d293e18ea5ac0fce443c68525100e44df80b4fd) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 353d01d31bc69d4d1901ff09097ee610bb1c9dbc) @@ -20,6 +20,7 @@ #include "LoadCell.h" #include "MessageSupport.h" #include "ModeDrain.h" +#include "ModeFill.h" #include "ModeGenIdle.h" #include "OperationModes.h" #include "Pressures.h" @@ -37,7 +38,7 @@ // ********** private definitions ********** #define MIN_RESERVOIR_VOLUME_ML 0 ///< Minimum reservoir volume in mL. -#define DEFAULT_FILL_VOLUME_ML 1700 ///< Default fill volume for treatment in mL. +#define DEFAULT_FILL_VOLUME_ML 1500 ///< Default fill volume for treatment in mL. #define MAX_FILL_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///< Maximum fill volume in mL. #define DEFAULT_DRAIN_VOLUME_ML 0 ///< Default drain volume in mL. #define MAX_DRAIN_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///< Maximum drain volume in mL. @@ -48,10 +49,29 @@ #define RESERVOIR_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the reservoir data is published on the CAN bus. -#define MAX_REDUNDANT_LOAD_CELL_DIFF 50.0 ///< Maximum difference in redundant load cells when determing if fill completed. +#define MAX_REDUNDANT_LOAD_CELL_DIFF 50.0 ///< Maximum difference in redundant load cells when determing if fill completed. -// ********** private data ********** - + +// TODO add doxygen comments +#define RESERVOIR_TEMPERATURE_TAU_C_PER_MIN -0.512 ///< Reservoir temperature time constant C/min. +#define ULTRAFILTER_TEMPERATURE_TAU_C_PER_MIN -0.512 ///< Ultrafilter temperature time constant C/min. +#define ULTRAFILTER_VOLUME_ML 700 + + +// ********** private data ********** + +// TODO yes we should add all the doxygen comments soon +// TODO add doxygen comments +typedef struct +{ + U32 timeReservoirCycleMS; + F32 timeUFDecayMS; + F32 tempUFFill; + F32 tempRerservoirStartFill; + +} HEATERS_TEMPERATURE_CALC_DATA_T; + +static HEATERS_TEMPERATURE_CALC_DATA_T heatersTempCalc; static U32 reservoirDataPublicationTimerCounter = 0; ///< used to schedule reservoir data publication to CAN bus. static OVERRIDE_U32_T activeReservoir = { 0, 0, 0, 0 }; ///< The active reservoir that the DG is filling/draining/etc. @@ -69,11 +89,16 @@ static U32 reservoirWeightUnchangeStartTime[ NUM_OF_DG_RESERVOIRS ] = { 0, 0 }; ///< The reservoirs' weight start time when weight stop decreasing. static BOOL tareLoadCellRequest; ///< Flag indicates if load cell tare has been requested by HD. static DG_RESERVOIR_VOLUME_RECORD_T reservoirsCalRecord; ///< DG reservoirs non-volatile record. -static F32 targetFillFlowRateLPM; +static F32 targetFillFlowRateLPM; ///< Target fill flow rate in L/min. +static const F32 ULTRAFILTER_TAU_C_PER_MS = ULTRAFILTER_TEMPERATURE_TAU_C_PER_MIN * SEC_PER_MIN * MS_PER_SECOND; +static const F32 RESERVOIR_TAU_C_PER_MS = RESERVOIR_TEMPERATURE_TAU_C_PER_MIN * SEC_PER_MIN * MS_PER_SECOND; + // ********** private function prototypes ********** -static BOOL processCalibrationData( void ); +static BOOL processCalibrationData( void ); +static F32 getPrimaryHeaterTargetTemperature( void ); +static F32 getTrimmerHeaterTargetTemperature( void ); /*********************************************************************//** * @brief @@ -88,7 +113,7 @@ activeReservoir.data = (U32)DG_RESERVOIR_1; fillVolumeTargetMl.data = DEFAULT_FILL_VOLUME_ML; drainVolumeTargetMl.data = DEFAULT_DRAIN_VOLUME_ML; - targetFillFlowRateLPM = 0.0; + targetFillFlowRateLPM = 0.0; } /*********************************************************************//** @@ -270,9 +295,9 @@ if ( fillToVolMl < MAX_FILL_VOLUME_ML ) { fillVolumeTargetMl.data = fillToVolMl; + cmdResponse.rejected = FALSE; requestNewOperationMode( DG_MODE_FILL ); - cmdResponse.rejected = FALSE; } else { @@ -284,6 +309,7 @@ cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; } + // Set the fill flow rate targetFillFlowRateLPM = fillTargetLPM; sendCommandResponseMsg( &cmdResponse ); @@ -451,19 +477,53 @@ /*********************************************************************//** * @brief + * The getTargetFillVolumeML function returns the target fill volume in mL. + * @details Inputs: none + * @details Outputs: none + * @return target fill volume in mL + *************************************************************************/ +U32 getTargetFillVolumeML( void ) +{ + U32 targetFill = fillVolumeTargetMl.data; + + if ( OVERRIDE_KEY == fillVolumeTargetMl.override ) + { + targetFill = fillVolumeTargetMl.ovData; + } + + return targetFill; +} + +/*********************************************************************//** + * @brief * The getTargetFillFlowRateLPM function returns the target fill flow rate * in L/min. * @details Inputs: none * @details Outputs: none * @return target fill flow rate in L/min *************************************************************************/ -F32 getTargetFillFlowRateLPM( void ) +F32 getTargetFillFlowRateLPM( void ) { return targetFillFlowRateLPM; } /*********************************************************************//** * @brief + * The setActiveReservoirCycleTime function sets the active reservoir cycle + * time in milliseconds. + * @details Inputs: none + * @details Outputs: heatersTemperatureCalcData + * @return none + *************************************************************************/ +void setHeatersTargetTemperature( TARGET_TEMPS_AND_TIME_PAYLOAD_T targets ) +{ + heatersTempCalc.timeReservoirCycleMS = targets.activeReservoirCycleTimeMS; + + setHeaterTargetTemperature( DG_PRIMARY_HEATER, getPrimaryHeaterTargetTemperature() ); +} + +/*********************************************************************//** + * @brief * The getReservoirsCalRecord function returns the reservoirs' calibration * record. * @details Inputs: reservoirsCalRecord @@ -617,7 +677,42 @@ return status; } +/*********************************************************************//** + * @brief + * The getPrimaryHeaterTargetTemperature function calculates the primary + * heater target temperature and returns target temperature value. + * @details Inputs: none + * @details Outputs: heatersTempCalc + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static F32 getPrimaryHeaterTargetTemperature( void ) +{ + F32 targetTemp = 0.0; + F32 targetFillVolML = getTargetFillVolumeML(); + F32 timeFillMS = ( getTargetFillFlowRateLPM() * ML_PER_LITER ) / targetFillVolML; // TODO target flow can come from RO pump too + heatersTempCalc.timeUFDecayMS = (F32)heatersTempCalc.timeReservoirCycleMS - timeFillMS; + heatersTempCalc.tempUFFill = getLastFillTemperature() + ( heatersTempCalc.timeUFDecayMS * ULTRAFILTER_TAU_C_PER_MS ); + + F32 ultrafilterPart = ( ULTRAFILTER_VOLUME_ML / targetFillVolML ) * heatersTempCalc.tempUFFill; + F32 fillPart = ( ( ( targetFillVolML - ULTRAFILTER_VOLUME_ML ) / targetFillVolML ) * getAvgFillTemperature() ); + + heatersTempCalc.tempRerservoirStartFill = ultrafilterPart + fillPart; + + return targetTemp; +} + +static F32 getTrimmerHeaterTargetTemperature( void ) +{ + F32 targetTemp = 0.0; + F32 targetFillVolML = getTargetFillVolumeML(); + F32 timeHalfFillMS = ( getTargetFillFlowRateLPM() * ML_PER_LITER * 0.5 ) / targetFillVolML; // TODO target flow can come from RO pump + + + return targetTemp; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -681,8 +776,8 @@ if ( TRUE == isTestingActivated() ) { - result = TRUE; - fillVolumeTargetMl.ovData = value; + result = TRUE; + fillVolumeTargetMl.ovData = value; fillVolumeTargetMl.override = OVERRIDE_KEY; } @@ -703,9 +798,9 @@ if ( TRUE == isTestingActivated() ) { - result = TRUE; + result = TRUE; fillVolumeTargetMl.override = OVERRIDE_RESET; - fillVolumeTargetMl.ovData = fillVolumeTargetMl.ovInitData; + fillVolumeTargetMl.ovData = fillVolumeTargetMl.ovInitData; } return result;