Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -r4af713cb53b909ba87893dc814d39af89fb8e8d2 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 4af713cb53b909ba87893dc814d39af89fb8e8d2) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -34,13 +34,19 @@ #define ADC2GRAM (0.0894 * 1.1338) ///< Conversion factor from ADC counts to grams. #define LOAD_CELL_ZERO_OFFSET -1215.0 ///< Zero offset (in grams). TODO - right now, this is empty reservoir weight. +/// Load cell data structure +typedef struct +{ + U32 measuredReadingSum; ///< Raw load cell sums for averaging + OVERRIDE_F32_T filteredWeight; ///< Latest filtered load cell weights + F32 autoCalOffset; ///< Load cell auto-calibration offset +} LOADCELL_T; + // ********** private data ********** static OVERRIDE_U32_T loadCellDataPublishInterval = { LOAD_CELL_REPORT_PERIOD, LOAD_CELL_REPORT_PERIOD, 0, 0 }; ///< Broadcast load cell data publish interval. -static U32 measuredLoadCellReadingsSum[ NUM_OF_LOAD_CELLS ]; ///< Raw load cell sums for averaging. -static OVERRIDE_F32_T filteredLoadCellWeights[ NUM_OF_LOAD_CELLS ]; ///< Latest filtered load cell weights. -static F32 autoCalOffset[ NUM_OF_LOAD_CELLS ]; ///< Auto calibration offset for load cell. +static LOADCELL_T loadcells[ NUM_OF_LOAD_CELLS ]; ///< Load cell data structures. static U32 loadCellFilterTimerCount = 0; ///< Load cell filtering timer count. static U32 loadCellDataPublicationTimerCounter = 0; ///< Load cell data publication timer counter to CAN bus. @@ -61,14 +67,13 @@ for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { - filteredLoadCellWeights[ i ].data = 0.0; - filteredLoadCellWeights[ i ].ovData = 0.0; - filteredLoadCellWeights[ i ].ovInitData = 0.0; - filteredLoadCellWeights[ i ].override = OVERRIDE_RESET; + loadcells[ i ].filteredWeight.data = 0.0; + loadcells[ i ].filteredWeight.ovData = 0.0; + loadcells[ i ].filteredWeight.ovInitData = 0.0; + loadcells[ i ].filteredWeight.override = OVERRIDE_RESET; - measuredLoadCellReadingsSum[ i ] = 0; - - autoCalOffset[ i ] = 0.0; + loadcells[ i ].measuredReadingSum = 0; + loadcells[ i ].autoCalOffset = 0.0; } } @@ -82,32 +87,28 @@ *************************************************************************/ void execLoadCell( void ) { + U32 ii; + // update sums for load cell average calculations - measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] += getFPGALoadCellA1(); - measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] += getFPGALoadCellA2(); - measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] += getFPGALoadCellB1(); - measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] += getFPGALoadCellB2(); + loadcells[ LOAD_CELL_A1 ].measuredReadingSum += getFPGALoadCellA1(); + loadcells[ LOAD_CELL_A2 ].measuredReadingSum += getFPGALoadCellA2(); + loadcells[ LOAD_CELL_B1 ].measuredReadingSum += getFPGALoadCellB1(); + loadcells[ LOAD_CELL_B2 ].measuredReadingSum += getFPGALoadCellB2(); // filter every 100ms if ( ++loadCellFilterTimerCount >= LOAD_CELL_SAMPLES_TO_AVERAGE ) { - loadCellFilterTimerCount = 0; + for ( ii = 0; ii < NUM_OF_LOAD_CELLS; ++ii ) + { + // calculate load cell average weights + loadcells[ ii ].filteredWeight.data = (F32)loadcells[ ii ].measuredReadingSum * LOAD_CELL_AVERAGE_MULTIPLIER * + ADC2GRAM + LOAD_CELL_ZERO_OFFSET - loadcells[ ii ].autoCalOffset; - // calculate load cell average weights - filteredLoadCellWeights[ LOAD_CELL_A1 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET - autoCalOffset[ LOAD_CELL_A1 ]; - filteredLoadCellWeights[ LOAD_CELL_A2 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET - autoCalOffset[ LOAD_CELL_A2 ]; - filteredLoadCellWeights[ LOAD_CELL_B1 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET - autoCalOffset[ LOAD_CELL_B1 ]; - filteredLoadCellWeights[ LOAD_CELL_B2 ].data = (F32)measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] * - LOAD_CELL_AVERAGE_MULTIPLIER * ADC2GRAM + LOAD_CELL_ZERO_OFFSET - autoCalOffset[ LOAD_CELL_B2 ]; + // reset sums for next averaging + loadcells[ ii ].measuredReadingSum = 0; + } - // reset sums for next averaging - measuredLoadCellReadingsSum[ LOAD_CELL_A1 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_A2 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_B1 ] = 0; - measuredLoadCellReadingsSum[ LOAD_CELL_B2 ] = 0; + loadCellFilterTimerCount = 0; } // broadcast load cell data if we are at scheduled interval. @@ -123,23 +124,35 @@ /*********************************************************************//** * @brief - * The setLoadCellAutoCal function sets the load cell auto calibration offset + * The tareLoadCell function sets the load cell auto calibration offset * for a given load cell ID. * @details Inputs: none - * @details Outputs: autoCalibrationOffset[] + * @details Outputs: load cell autoCalOffset * @param loadCellID ID of load cell to set calibration offset for - * @param calOffset auto calibration offset value *************************************************************************/ -void setLoadCellAutoCal( LOAD_CELL_ID_T loadCellID, F32 calOffset ) +void tareLoadCell( LOAD_CELL_ID_T loadCellID ) { - autoCalOffset[ loadCellID ] = calOffset; + loadcells[ loadCellID ].autoCalOffset = loadcells[ loadCellID ].filteredWeight.data; } /*********************************************************************//** * @brief + * The resetLoadCellOffset function resets the load cell auto calibration offset + * to zero for a given load cell ID. + * @details Inputs: none + * @details Outputs: load cell autoCalOffset + * @param loadCellID ID of load cell to set calibration offset for + *************************************************************************/ +void resetLoadCellOffset( LOAD_CELL_ID_T loadCellID ) +{ + loadcells[ loadCellID ].autoCalOffset = 0.0; +} + +/*********************************************************************//** + * @brief * The getLoadCellFilteredWeight function gets the measured filtered load cell * weight for a given load cell ID. - * @details Inputs: filteredLoadCellWeights[] + * @details Inputs: load cell filtered weight * @details Outputs: none * @param loadCellID ID of load cell to get filtered weight for * @return the filtered load cell weight for the given load cell ID. @@ -150,13 +163,13 @@ if ( loadCellID < NUM_OF_LOAD_CELLS ) { - if ( OVERRIDE_KEY == filteredLoadCellWeights[ loadCellID ].override ) + if ( OVERRIDE_KEY == loadcells[ loadCellID ].filteredWeight.override ) { - result = filteredLoadCellWeights[ loadCellID ].ovData; + result = loadcells[ loadCellID ].filteredWeight.ovData; } else { - result = filteredLoadCellWeights[ loadCellID ].data; + result = loadcells[ loadCellID ].filteredWeight.data; } } else @@ -196,7 +209,7 @@ * @brief * The testSetLoadCellOverride function overrides the measured load cell data. * @details Inputs: none - * @details Outputs: filteredLoadCellWeights[] + * @details Outputs: load cell filtered weight * @param loadCellID ID of the load cell to override * @param value override filtered load cell weight * @return TRUE if override successful, FALSE if not @@ -210,8 +223,8 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - filteredLoadCellWeights[ loadCellID ].ovData = value; - filteredLoadCellWeights[ loadCellID ].override = OVERRIDE_KEY; + loadcells[ loadCellID ].filteredWeight.ovData = value; + loadcells[ loadCellID ].filteredWeight.override = OVERRIDE_KEY; } } @@ -222,7 +235,7 @@ * @brief * The testResetLoadCellOverride function resets the override of the load cell. * @details Inputs: none - * @details Outputs: filteredLoadCellWeights[] + * @details Outputs: load cell filtered weight * @param loadCellID ID of the load cell to override * @return TRUE if reset successful, FALSE if not *************************************************************************/ @@ -235,8 +248,8 @@ if ( TRUE == isTestingActivated() ) { result = TRUE; - filteredLoadCellWeights[ loadCellID ].override = OVERRIDE_RESET; - filteredLoadCellWeights[ loadCellID ].ovData = filteredLoadCellWeights[ loadCellID ].ovInitData; + loadcells[ loadCellID ].filteredWeight.override = OVERRIDE_RESET; + loadcells[ loadCellID ].filteredWeight.ovData = loadcells[ loadCellID ].filteredWeight.ovInitData; } } Index: firmware/App/Controllers/LoadCell.h =================================================================== diff -u -r4af713cb53b909ba87893dc814d39af89fb8e8d2 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Controllers/LoadCell.h (.../LoadCell.h) (revision 4af713cb53b909ba87893dc814d39af89fb8e8d2) +++ firmware/App/Controllers/LoadCell.h (.../LoadCell.h) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -45,7 +45,8 @@ void initLoadCell( void ); // Initialize the LoadCell module. void execLoadCell( void ); // Execute the LoadCell monitor. -void setLoadCellAutoCal( LOAD_CELL_ID_T loadCellID, F32 calOffset ); +void tareLoadCell( LOAD_CELL_ID_T loadCellID ); +void resetLoadCellOffset( LOAD_CELL_ID_T loadCellID ); F32 getLoadCellFilteredWeight( LOAD_CELL_ID_T loadCellID ); BOOL testSetLoadCellOverride( U32 loadCellID, F32 value ); Index: firmware/App/Modes/ModeDrain.c =================================================================== diff -u -r4af713cb53b909ba87893dc814d39af89fb8e8d2 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Modes/ModeDrain.c (.../ModeDrain.c) (revision 4af713cb53b909ba87893dc814d39af89fb8e8d2) +++ firmware/App/Modes/ModeDrain.c (.../ModeDrain.c) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -17,7 +17,6 @@ #include "ConductivitySensors.h" #include "DrainPump.h" -#include "LoadCell.h" #include "ModeDrain.h" #include "OperationModes.h" #include "Pressures.h" @@ -34,14 +33,11 @@ // ********** private definitions ********** #define TARGET_DRAIN_PUMP_RPM 2800 ///< Target drain pump speed (in RPM). -#define DRAIN_WEIGHT_CHANGE_TOLERANCE 0.1 ///< Weight changes during draining tolerance. -#define DRAIN_WEIGH_UNCHANGE_TIMEOUT ( 10 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Time period of unchanged weight during draining before timeout. +#define DRAIN_WEIGH_UNCHANGE_TIMEOUT ( 10 * MS_PER_SECOND ) ///< Time period of unchanged weight during draining before timeout. // ********** private data ********** static DG_DRAIN_STATE_T drainState = DG_DRAIN_STATE_START; ///< Currently active drain state. -static F32 previousWeight; ///< Previous weight of the reservoir draining. -static U32 weightNotDroppingTimerCounter; ///< Timer counter for the period weight not dropping. // ********** private function prototypes ********** @@ -57,8 +53,6 @@ void initDrainMode( void ) { drainState = DG_DRAIN_STATE_START; - previousWeight = 0.0; - weightNotDroppingTimerCounter = 0; } /*********************************************************************//** @@ -123,33 +117,11 @@ static DG_DRAIN_STATE_T handleDrainState( void ) { DG_DRAIN_STATE_T result = DG_DRAIN_STATE_DRAIN; - LOAD_CELL_ID_T drainWeightLoadCell = LOAD_CELL_A1; - F32 currentFilteredWeight; - U32 const targetWeight = getReservoirDrainVolumeTargetMl(); + RESERVOIR_ID_T inactiveReservoir = getInactiveReservoir(); - // determine which load cell to use for drain volume - we want weight of inactive reservoir - if ( RESERVOIR_1 == getActiveReservoir() ) + // if we've reached our target drain to volume (by weight) or cannot drain anymore, we're done draining - go back to re-circ mode + if ( hasTargetDrainVolumeReached( inactiveReservoir, DRAIN_WEIGH_UNCHANGE_TIMEOUT ) ) { - drainWeightLoadCell = LOAD_CELL_B1; - } - - currentFilteredWeight = getLoadCellFilteredWeight( drainWeightLoadCell ); - - // if weight stays the same for 10 seconds, timeout and auto calibration - if ( fabs( previousWeight - currentFilteredWeight ) < DRAIN_WEIGHT_CHANGE_TOLERANCE ) - { - previousWeight = currentFilteredWeight; - - if ( ++weightNotDroppingTimerCounter >= DRAIN_WEIGH_UNCHANGE_TIMEOUT ) - { - weightNotDroppingTimerCounter = 0; - setLoadCellAutoCal( drainWeightLoadCell, currentFilteredWeight - targetWeight ); - } - } - - // if we've reached our target drain to volume (by weight), we're done draining - go back to re-circ mode - if ( targetWeight >= currentFilteredWeight ) - { setDrainPumpTargetSpeed( 0 ); requestNewOperationMode( DG_MODE_CIRC ); } Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -19,6 +19,7 @@ #include "DrainPump.h" #include "Heaters.h" #include "OperationModes.h" +#include "Reservoirs.h" #include "ROPump.h" #include "SystemComm.h" #include "Timers.h" @@ -85,6 +86,9 @@ stopTrimmerHeater(); // conc. pumps off // UV off + + resetReservoirLoadCellsOffset( RESERVOIR_1 ); + resetReservoirLoadCellsOffset( RESERVOIR_2 ); } /*********************************************************************//** Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -16,14 +16,16 @@ ***************************************************************************/ #include // for memcpy() - + +#include "Heaters.h" +#include "LoadCell.h" #include "ModeRecirculate.h" #include "OperationModes.h" +#include "Reservoirs.h" #include "SystemCommMessages.h" -#include "TaskGeneral.h" +#include "TaskGeneral.h" +#include "Timers.h" #include "Valves.h" -#include "Reservoirs.h" -#include "Heaters.h" /** * @addtogroup Reservoirs @@ -32,26 +34,37 @@ // ********** private definitions ********** -#define MIN_RESERVOIR_VOLUME_ML 0 ///< Minimum reservoir volume in mL. -#define MAX_RESERVOIR_VOLUME_ML 2000 ///< Maximum reservoir volume in mL. -#define DEFAULT_FILL_VOLUME_ML 1700 ///< Default fill volume for treatment in mL. -#define DISINFECT_FILL_VOLUME_ML 2400 ///> Fill volume for disinfection in mL. -#define MAX_FILL_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///> Maximum fill volume in mL. -#define DEFAULT_DRAIN_VOLUME_ML 100 ///> Default drain volume in mL. -#define MAX_DRAIN_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///> Maximum drain volume in mL. -#define MIN_DRAIN_VOLUME_ML 100 ///> Minimum drain volume in mL. +#define MIN_RESERVOIR_VOLUME_ML 0 ///< Minimum reservoir volume in mL. +#define MAX_RESERVOIR_VOLUME_ML 2000 ///< Maximum reservoir volume in mL. +#define DEFAULT_FILL_VOLUME_ML 1700 ///< Default fill volume for treatment in mL. +#define DISINFECT_FILL_VOLUME_ML 2400 ///> Fill volume for disinfection in mL. +#define MAX_FILL_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///> Maximum fill volume in mL. +#define DEFAULT_DRAIN_VOLUME_ML 100 ///> Default drain volume in mL. +#define MAX_DRAIN_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///> Maximum drain volume in mL. +#define MIN_DRAIN_VOLUME_ML 100 ///> Minimum drain volume in mL. -#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 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. + // ********** private data ********** -static U32 reservoirDataPublicationTimerCounter = 0; ///< used to schedule reservoir data publication to CAN bus. +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. -static OVERRIDE_U32_T fillVolumeTargetMl = { 0, 0, 0, 0 }; ///< The target reservoir fill volume (in mL). -static OVERRIDE_U32_T drainVolumeTargetMl = { 0, 0, 0, 0 }; ///< The target reservoir drain volume (in mL). +static OVERRIDE_U32_T activeReservoir = { 0, 0, 0, 0 }; ///< The active reservoir that the DG is filling/draining/etc. +static OVERRIDE_U32_T fillVolumeTargetMl = { 0, 0, 0, 0 }; ///< The target reservoir fill volume (in mL). +static OVERRIDE_U32_T drainVolumeTargetMl = { 0, 0, 0, 0 }; ///< The target reservoir drain volume (in mL). + +static LOAD_CELL_ID_T associateLoadCell[ NUM_OF_RESERVOIRS ] = { LOAD_CELL_A1, + LOAD_CELL_B1 }; ///< The reservoirs' associate load cell. +static LOAD_CELL_ID_T redundantLoadCell[ NUM_OF_RESERVOIRS ] = { LOAD_CELL_A2, + LOAD_CELL_B2 }; ///< The reservoirs' associate redundant load cell. + +static F32 reservoirLowestWeight[ NUM_OF_RESERVOIRS ] = { MAX_RESERVOIR_VOLUME_ML, + MAX_RESERVOIR_VOLUME_ML }; ///< The reservoirs' lowest weight during draining. +static U32 reservoirWeightUnchangeStartTime[ NUM_OF_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. -// ********** private function prototypes ********** +// ********** private function prototypes ********** +static U32 getReservoirDrainVolumeTargetMl( void ); /*********************************************************************//** * @brief @@ -194,17 +207,18 @@ * @param drainToVolMl Target volume (in mL) to drain reservoir to * @return TRUE if drain command successful, FALSE if not. *************************************************************************/ -BOOL startDrainCmd( U32 drainToVolMl ) +BOOL startDrainCmd( DRAIN_CMD_T drainCmd ) { BOOL result = FALSE; // drain command only valid in re-circulate mode if ( DG_MODE_CIRC == getCurrentOperationMode() ) { // validate parameters - if ( ( drainToVolMl >= MIN_DRAIN_VOLUME_ML ) && ( drainToVolMl <= MAX_DRAIN_VOLUME_ML ) ) + if ( ( drainCmd.targetVolume >= MIN_DRAIN_VOLUME_ML ) && ( drainCmd.targetVolume <= MAX_DRAIN_VOLUME_ML ) ) { - drainVolumeTargetMl.data = drainToVolMl; + drainVolumeTargetMl.data = drainCmd.targetVolume; + tareLoadCellRequest = drainCmd.tareLoadCell; requestNewOperationMode( DG_MODE_DRAI ); result = TRUE; } @@ -287,6 +301,25 @@ return result; } + +/*********************************************************************//** + * @brief + * The getInactiveReservoir function gets the inactive reservoir. + * @details Inputs: activeReservoir + * @details Outputs: none + * @return the currently inactive reservoir. + *************************************************************************/ +RESERVOIR_ID_T getInactiveReservoir( void ) +{ + RESERVOIR_ID_T inactiveReservoir = RESERVOIR_1; + + if ( RESERVOIR_1 == getActiveReservoir() ) + { + inactiveReservoir = RESERVOIR_2; + } + + return inactiveReservoir; +} /*********************************************************************//** * @brief @@ -305,28 +338,85 @@ } return result; -} - -/*********************************************************************//** - * @brief - * The getReservoirDrainVolumeTargetMl function gets the reservoir drain volume (in mL). - * @details Inputs: drainVolumeTargetMl - * @details Outputs: none - * @return the current target reservoir drain volume (in mL). - *************************************************************************/ -U32 getReservoirDrainVolumeTargetMl( void ) -{ - U32 result = drainVolumeTargetMl.data; - - if ( OVERRIDE_KEY == drainVolumeTargetMl.override ) - { - result = drainVolumeTargetMl.ovData; - } - - return result; -} +} - +/*********************************************************************//** + * @brief + * The resetReservoirLoadCellsOffset function sets the reservoir's load cells + * offset to zero. + * @details Inputs: associateLoadCell[], redundantLoadCell[] + * @details Outputs: reset reservoir's associate load cells auto calibration offset + * @param reservoirId reservoir id + * @return none + *************************************************************************/ +void resetReservoirLoadCellsOffset( RESERVOIR_ID_T reservoirId ) +{ + resetLoadCellOffset( associateLoadCell[ reservoirId ] ); + resetLoadCellOffset( redundantLoadCell[ reservoirId ] ); +} + +/*********************************************************************//** + * @brief + * The hasTargetDrainVolumeReached function checks if the target drain volume + * for specific reservoir has been reached or exceed time limit. + * @details Inputs: drainVolumeTargetMl + * @details Outputs: none + * @param reservoirId reservoir id + * @param timeout timeout period when weight remains the same + * @return TRUE if target drain volume has been reached or exceeds time limit, FALSE if not. + *************************************************************************/ +BOOL hasTargetDrainVolumeReached( RESERVOIR_ID_T reservoirId, U32 timeout ) +{ + BOOL result = FALSE; + F32 const loadcellWeight = getLoadCellFilteredWeight( associateLoadCell[ reservoirId ] ); + F32 const redundantLoadcellWeight = getLoadCellFilteredWeight( redundantLoadCell[ reservoirId ] ); + U32 const targetDrainVolume = getReservoirDrainVolumeTargetMl(); + + if ( ( loadcellWeight < reservoirLowestWeight[ reservoirId ] ) || ( redundantLoadcellWeight < reservoirLowestWeight[ reservoirId ] ) ) + { + reservoirLowestWeight[ reservoirId ] = loadcellWeight < redundantLoadcellWeight ? loadcellWeight : redundantLoadcellWeight; + reservoirWeightUnchangeStartTime[ reservoirId ] = getMSTimerCount(); + } + + BOOL const hasTimeOut = didTimeout( reservoirWeightUnchangeStartTime[ reservoirId ], timeout ); + BOOL const hasTargetReached = ( targetDrainVolume >= loadcellWeight ) || ( targetDrainVolume >= redundantLoadcellWeight ); + + if ( hasTimeOut || hasTargetReached ) + { + result = TRUE; + reservoirLowestWeight[ reservoirId ] = MAX_RESERVOIR_VOLUME_ML; + + if ( tareLoadCellRequest ) + { + tareLoadCellRequest = FALSE; + tareLoadCell( associateLoadCell[ reservoirId ] ); + tareLoadCell( redundantLoadCell[ reservoirId ] ); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getReservoirDrainVolumeTargetMl function gets the reservoir drain volume (in mL). + * @details Inputs: drainVolumeTargetMl + * @details Outputs: none + * @return the current target reservoir drain volume (in mL). + *************************************************************************/ +static U32 getReservoirDrainVolumeTargetMl( void ) +{ + U32 result = drainVolumeTargetMl.data; + + if ( OVERRIDE_KEY == drainVolumeTargetMl.override ) + { + result = drainVolumeTargetMl.ovData; + } + + return result; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Services/Reservoirs.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/Reservoirs.h (.../Reservoirs.h) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -36,7 +36,16 @@ RESERVOIR_1 = 0, ///< Reservoir number 1 RESERVOIR_2, ///< Reservoir number 2 NUM_OF_RESERVOIRS ///< Number of reservoirs -} RESERVOIR_ID_T; +} RESERVOIR_ID_T; + +#pragma pack(push,1) +/// Enumeration of drain command. +typedef struct +{ + U32 targetVolume; ///< Target volume to drain to (in mL) + BOOL tareLoadCell; ///< Flag to tare load call +} DRAIN_CMD_T; +#pragma pack(pop) // ********** public function prototypes ********** @@ -46,14 +55,17 @@ BOOL setActiveReservoirCmd( RESERVOIR_ID_T resID ); // handle switch reservoirs command from HD BOOL startFillCmd( U32 fillToVolMl ); // handle fill command from HD BOOL stopFillCmd( void ); // handle stop fill command from HD -BOOL startDrainCmd( U32 drainToVolMl ); // handle drain command from HD +BOOL startDrainCmd( DRAIN_CMD_T drainCmd ); // handle drain command from HD BOOL stopDrainCmd( void ); // handle stop drain command from HD BOOL startTrimmerHeaterCmd( void ); // handle start trimmer heater control command from HD BOOL stopTrimmerHeaterCmd( void ); // handle stop trimmer heater control command from HD -RESERVOIR_ID_T getActiveReservoir( void ); +RESERVOIR_ID_T getActiveReservoir( void ); +RESERVOIR_ID_T getInactiveReservoir( void ); U32 getReservoirFillVolumeTargetMl( void ); -U32 getReservoirDrainVolumeTargetMl( void ); + +void resetReservoirLoadCellsOffset( RESERVOIR_ID_T reservoirId ); +BOOL hasTargetDrainVolumeReached( RESERVOIR_ID_T reservoirId , U32 timeout ); BOOL testSetDGActiveReservoirOverride( RESERVOIR_ID_T value ); BOOL testResetDGActiveReservoirOverride( void ); Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r87a22cbaa87daab0d7cedabc67452cead83d8630 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 87a22cbaa87daab0d7cedabc67452cead83d8630) @@ -817,12 +817,12 @@ { BOOL result = FALSE; - if ( message->hdr.payloadLen == sizeof(U32) ) + if ( message->hdr.payloadLen == sizeof( DRAIN_CMD_T ) ) { - U32 drainToVolMl; + DRAIN_CMD_T drainToVolMl; result = TRUE; - memcpy( &drainToVolMl, message->payload, sizeof(U32) ); + memcpy( &drainToVolMl, message->payload, sizeof( DRAIN_CMD_T ) ); startDrainCmd( drainToVolMl ); }