Index: firmware/App/Controllers/LoadCell.c =================================================================== diff -u -r2c70c24f7c5ead2322ec56f740277f0654ad281a -r6abb2df716c69d47f6093d2c34a1f9c89f439528 --- firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 2c70c24f7c5ead2322ec56f740277f0654ad281a) +++ firmware/App/Controllers/LoadCell.c (.../LoadCell.c) (revision 6abb2df716c69d47f6093d2c34a1f9c89f439528) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2020-2023 Diality Inc. - All Rights Reserved. +* Copyright (c) 2020-2025 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file LoadCell.c * -* @author (last) Bill Bracken -* @date (last) 28-Mar-2023 +* @author (last) Dara Navaei +* @date (last) 12-Apr-2024 * * @author (original) Saeed Nejatali * @date (original) 25-Feb-2020 @@ -49,8 +49,8 @@ #define LOAD_CELL_MIN_ALLOWED_WEIGHT_BEFORE_TARE_GRAMS 1600.0F ///< Load cell minimum allowed weight before tare in grams. #define LOAD_CELL_WEIGHT_OUT_RANGE_PERSISTENT_PERIOD_MS (5 * MS_PER_SECOND) ///< Load cell weight out of range persistent period in milliseconds. #define LOAD_CELL_PRIMARY_BACKUP_MAX_DRIFT_PERSISTENT_PERIOD_MS (5 * MS_PER_SECOND) ///< Load cell primary and backup maximum allowed weight drift persistent period in milliseconds. -#define EMPTY_RESERVOIR_WEIGHT_GRAMS 1600.0F ///< Reservoirs empty weight in grams. #define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_FIRST_TARE_GRAMS 300.0F ///< Max allowed extra weight before first tare in grams. +#define HEAT_ACTIVE_COOL_MAX_ALLOWED_EXTRA_WEIGHT_TARE_GRAMS 200.0F ///< Heat disinfect active cool max allowed weight before tare in grams. #define MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS 60.0F ///< Max allowed extra weight before tare in grams. #define LOAD_CELL_PRIMARY_BACKUP_MAX_ALLOWED_DRIFT_GRAMS 80.0F ///< Load cell primary and backup maximum allowed weight drift in grams. #define LOAD_CELL_PRIMARY_BACKUP_MAX_HEAT_DRIFT_GRAMS 200.0F ///< Load cell primary and backup maximum allowed weight drift in grams for heat disinfect mode. @@ -87,7 +87,8 @@ static U32 smallReadingsIdx; ///< Index for next sample in load cell small rolling average sample array. static U32 largeReadingsIdx; ///< Index for next sample in load cell large rolling average sample array. static DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< Load cells calibration record. -static BOOL hasLoadCellBeenTared[ NUM_OF_LOAD_CELLS ]; ///< Flags indicating whether loadcells have been tared yet. +static DG_RESERVOIR_VOLUME_RECORD_T reservoirsCalRecord; ///< DG reservoirs non-volatile record. +static BOOL hasLoadCellBeenTared[ NUM_OF_LOAD_CELLS ]; ///< Flags indicating whether load cells have been tared yet. // ********** private function prototypes ********** @@ -121,7 +122,7 @@ loadcells[ i ].weight.ovData = 0.0F; loadcells[ i ].weight.ovInitData = 0.0F; loadcells[ i ].weight.override = OVERRIDE_RESET; - loadcells[ i ].autoCalOffset = 0.0F; + loadcells[ i ].autoCalOffset = EMPTY_RESERVOIR_WEIGHT_GRAMS; loadcells[ i ].largeFilterTotal = 0.0F; loadcells[ i ].largeFilteredWeight = 0.0F; loadcells[ i ].smallFilterTotal = 0.0F; @@ -201,14 +202,22 @@ // Check if a new calibration is available if ( TRUE == isNewCalibrationRecordAvailable() ) { + getNVRecord2Driver( GET_CAL_RSRVRS_VOL_RECORD, (U08*)&reservoirsCalRecord, sizeof( DG_RESERVOIR_VOLUME_RECORD_T ), + NUM_OF_CAL_DATA_RSRVRS, ALARM_ID_DG_RESERVOIRS_INVALID_CAL_RECORD ); + getNVRecord2Driver( GET_CAL_LOAD_CELL_SENSORS, (U08*)&loadCellsCalRecord, sizeof( DG_LOAD_CELLS_CAL_RECORD_T ), NUM_OF_CAL_DATA_LOAD_CELLS, ALARM_ID_DG_LOAD_CELLS_INVALID_CAL_RECORD ); - // Zero the current tare values when new calibration data is available - loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].autoCalOffset = 0.0F; - loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].autoCalOffset = 0.0F; - loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].autoCalOffset = 0.0F; - loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].autoCalOffset = 0.0F; + if ( getCurrentOperationMode() != DG_MODE_SERV ) + { + // In the service mode once the calibration values are set, the NV data management sends the signal to all the drivers and therefore the + // the offset values are set to what is in the calibration records. This is not wanted in the service mode + // Set the current tare values when the values are received from the cal record + loadcells[ LOAD_CELL_RESERVOIR_1_PRIMARY ].autoCalOffset = reservoirsCalRecord.reservoir[ CAL_DATA_RSRVR_1 ].rsrvrUnfilledWeight; + loadcells[ LOAD_CELL_RESERVOIR_1_BACKUP ].autoCalOffset = reservoirsCalRecord.reservoir[ CAL_DATA_RSRVR_1 ].rsrvrUnfilledWeight; + loadcells[ LOAD_CELL_RESERVOIR_2_PRIMARY ].autoCalOffset = reservoirsCalRecord.reservoir[ CAL_DATA_RSRVR_2 ].rsrvrUnfilledWeight; + loadcells[ LOAD_CELL_RESERVOIR_2_BACKUP ].autoCalOffset = reservoirsCalRecord.reservoir[ CAL_DATA_RSRVR_2 ].rsrvrUnfilledWeight; + } } // Rolling average of last 100 raw samples in small filter @@ -302,10 +311,14 @@ SELF_TEST_STATUS_T execLoadCellsSelfTest ( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; + BOOL calStatus = FALSE; - BOOL calStatus = getNVRecord2Driver( GET_CAL_LOAD_CELL_SENSORS, (U08*)&loadCellsCalRecord, sizeof( DG_LOAD_CELLS_CAL_RECORD_T ), - NUM_OF_CAL_DATA_LOAD_CELLS, ALARM_ID_DG_LOAD_CELLS_INVALID_CAL_RECORD ); + calStatus |= getNVRecord2Driver( GET_CAL_LOAD_CELL_SENSORS, (U08*)&loadCellsCalRecord, sizeof( DG_LOAD_CELLS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_LOAD_CELLS, ALARM_ID_DG_LOAD_CELLS_INVALID_CAL_RECORD ); + calStatus |= getNVRecord2Driver( GET_CAL_RSRVRS_VOL_RECORD, (U08*)&reservoirsCalRecord, sizeof( DG_RESERVOIR_VOLUME_RECORD_T ), + NUM_OF_CAL_DATA_RSRVRS, ALARM_ID_DG_RESERVOIRS_INVALID_CAL_RECORD ); + if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; @@ -354,17 +367,31 @@ BOOL isWeightOutOfRange = FALSE; F32 weight = getLoadCellSmallFilteredWeight( loadCellID ); + if ( ( DG_MODE_SERV == getCurrentOperationMode() ) && ( loadcells[ loadCellID ].autoCalOffset <= NEARLY_ZERO ) ) + { + // In service mode, some of the tests are done when the auto call offset is needed and some when is not needed. + // Once the tare command is issued, an auto cal value other than 0 is needed otherwise the tare will fail since the weight is at least 1700 grams + // which is the weight of the empty reservoirs. So for that matter, if the reservoirs have not been tared in the service mode meaning + // that the auto cal offset is zero, use the default values from the cal records. + CAL_DATA_DG_RESERVOIRS_T rsrvr = ( ( LOAD_CELL_RESERVOIR_1_PRIMARY == loadCellID ) || ( LOAD_CELL_RESERVOIR_1_BACKUP == loadCellID ) ? + CAL_DATA_RSRVR_1 : CAL_DATA_RSRVR_2 ); + + weight -= reservoirsCalRecord.reservoir[ rsrvr ].rsrvrUnfilledWeight; + } + // Check if the load cell is being tared for the first time if ( hasLoadCellBeenTared[ loadCellID ] != TRUE ) { - // For the first tare, the weight of the reservoir should be considered + // For the first tare, the weight of the reservoir should be considered so the weight tolerance is bigger // The current weight of the load cell should not be greater than the weight of the reservoir + the extra weight - F32 deltaWeight = fabs( weight - EMPTY_RESERVOIR_WEIGHT_GRAMS ); - isWeightOutOfRange = ( deltaWeight > MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_FIRST_TARE_GRAMS ? TRUE : FALSE ); + isWeightOutOfRange = ( fabs( weight ) > MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_FIRST_TARE_GRAMS ? TRUE : FALSE ); } else { - isWeightOutOfRange = ( fabs( weight ) > MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS ? TRUE : FALSE ); + DG_OP_MODE_T opMode = getCurrentOperationMode(); + F32 tareLimitG = ( DG_MODE_HCOL == opMode ? HEAT_ACTIVE_COOL_MAX_ALLOWED_EXTRA_WEIGHT_TARE_GRAMS : MAX_ALLOWED_EXTRA_WEIGHT_BEFORE_TARE_GRAMS ); + + isWeightOutOfRange = ( fabs( weight ) > tareLimitG ? TRUE : FALSE ); } if ( FALSE == isWeightOutOfRange ) @@ -675,4 +702,47 @@ return result; } +/*********************************************************************//** + * @brief + * The getLoadCellsTareValues function gets the load cells tare values + * @details Inputs: loadcells[] + * @details Outputs: none + * @param bufferAddress address to the buffer provided to get the load cells + * tare values + * @return none + *************************************************************************/ +void getLoadCellsTareValues( U08* bufferAddress ) +{ + LOAD_CELL_ID_T id; + + for ( id = LOAD_CELL_FIRST; id < NUM_OF_LOAD_CELLS; ++id ) + { + memcpy( bufferAddress, &loadcells[ id ].autoCalOffset, sizeof( F32 ) ); + bufferAddress += sizeof( F32 ); + } +} + +/*********************************************************************//** + * @brief + * The setLoadCellsTareValues function sets the load cells tare values + * @details Inputs: none + * @details Outputs: loadcells[] + * @param bufferAddress address to the buffer provided to set the load cells + * tare values + * @return none + *************************************************************************/ +void setLoadCellsTareValues( U08* bufferAddress ) +{ + LOAD_CELL_ID_T id; + + for ( id = LOAD_CELL_FIRST; id < NUM_OF_LOAD_CELLS; ++id ) + { + memcpy( &loadcells[ id ].autoCalOffset, bufferAddress, sizeof( F32 ) ); + bufferAddress += sizeof( F32 ); + + // Set the load cells have been tared already. + hasLoadCellBeenTared[ id ] = TRUE; + } +} + /**@}*/