Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r8e6488e189349e0f87f2fb21fa8176aced0b5a43 -r94a190522ce398399c7b93c59f788d7666ec0060 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 8e6488e189349e0f87f2fb21fa8176aced0b5a43) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 94a190522ce398399c7b93c59f788d7666ec0060) @@ -1,29 +1,31 @@ /************************************************************************** * -* Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2021 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 Reservoirs.c +* @file Reservoirs.c * -* @author (last) Sean Nash -* @date (last) 26-Jun-2020 +* @author (last) Dara Navaei +* @date (last) 11-Nov-2021 * -* @author (original) Sean -* @date (original) 18-Mar-2020 +* @author (original) Sean +* @date (original) 18-Mar-2020 * ***************************************************************************/ - -#include // for memcpy() - -#include "ModeRecirculate.h" -#include "OperationModes.h" -#include "SystemCommMessages.h" -#include "TaskGeneral.h" + +#include // for memcpy() + +#include "LoadCell.h" +#include "MessageSupport.h" +#include "ModeGenIdle.h" +#include "OperationModes.h" +#include "Reservoirs.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "Timers.h" #include "Valves.h" -#include "Reservoirs.h" -#include "Heaters.h" /** * @addtogroup Reservoirs @@ -32,463 +34,692 @@ // ********** 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 DEFAULT_FILL_VOLUME_ML 1700 ///< 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. + +#define MAX_RESERVOIR_WEIGHT 10000 ///< Maximum reservoir weight in grams. -#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). + +/// The reservoirs' associate load cell. +static LOAD_CELL_ID_T associatedLoadCell[ NUM_OF_DG_RESERVOIRS ] = { LOAD_CELL_RESERVOIR_1_PRIMARY, LOAD_CELL_RESERVOIR_2_PRIMARY }; +/// The reservoirs' associate redundant load cell. +static LOAD_CELL_ID_T redundantLoadCell[ NUM_OF_DG_RESERVOIRS ] = { LOAD_CELL_RESERVOIR_1_BACKUP, LOAD_CELL_RESERVOIR_2_BACKUP }; + +/// The reservoirs' lowest weight during draining. +static F32 reservoirLowestWeight[ NUM_OF_DG_RESERVOIRS ] = { MAX_RESERVOIR_WEIGHT, MAX_RESERVOIR_WEIGHT }; +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. + +// ********** private function prototypes ********** + +static BOOL processCalibrationData( void ); -// ********** private function prototypes ********** - /*********************************************************************//** * @brief * The initReservoirs function initializes the Reservoirs module. - * @details - * Inputs : none - * Outputs : Reservoirs module initialized. + * @details Inputs: none + * @details Outputs: Reservoirs module initialized * @return none *************************************************************************/ void initReservoirs( void ) -{ - activeReservoir.data = RESERVOIR_2; - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); - setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); - setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); +{ + activeReservoir.data = (U32)DG_RESERVOIR_1; fillVolumeTargetMl.data = DEFAULT_FILL_VOLUME_ML; drainVolumeTargetMl.data = DEFAULT_DRAIN_VOLUME_ML; } /*********************************************************************//** * @brief * The execReservoirs function manages periodic tasks for the Reservoirs module. - * @details - * Inputs : none - * Outputs : Reservoir data broadcast on interval. + * @details Inputs: reservoirDataPublicationTimerCounter + * @details Outputs: reservoirDataPublicationTimerCounter * @return none *************************************************************************/ void execReservoirs( void ) -{ +{ + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + // Get the new calibration data and check its validity + processCalibrationData(); + } + // publish active reservoir, fill/drain volume targets at 1 Hz. if ( ++reservoirDataPublicationTimerCounter >= RESERVOIR_DATA_PUB_INTERVAL ) - { - U32 actRes = getActiveReservoir(); - U32 filVol = getReservoirFillVolumeTargetMl(); - U32 drnVol = getReservoirDrainVolumeTargetMl(); - broadcastReservoirData( actRes, filVol, drnVol ); + { + RESERVOIR_DATA_T data; + + data.activeReservoir = getU32OverrideValue( &activeReservoir ); + data.fillToVolumeMl = getU32OverrideValue( &fillVolumeTargetMl ); + data.drainToVolumeMl = getU32OverrideValue( &drainVolumeTargetMl ); + + broadcastData( MSG_ID_DG_RESERVOIR_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( RESERVOIR_DATA_T ) ); reservoirDataPublicationTimerCounter = 0; } +} + +/*********************************************************************//** + * @brief + * The execDrainPumpSelfTest function executes the drain pump's self-test. + * @details Inputs: none + * @details Outputs: none + * @return PressuresSelfTestResult (SELF_TEST_STATUS_T) + *************************************************************************/ +SELF_TEST_STATUS_T execReservoirsSelfTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; + + BOOL calStatus = processCalibrationData(); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; } /*********************************************************************//** * @brief - * The setActiveReservoir function sets the given reservoir as active \n + * The setActiveReservoirCmd function sets the given reservoir as active * (meaning HD will be drawing from this reservoir). - * @details - * Inputs : none - * Outputs : Specified reservoir is set as active. + * @details Inputs: none + * @details Outputs: Specified reservoir is set as active. * @param resID ID of reservoir to set as active - * @return TRUE if set active reservoir command successful, FALSE if not. + * @return none *************************************************************************/ -BOOL setActiveReservoirCmd( RESERVOIR_ID_T resID ) -{ - BOOL result = FALSE; - - // switch reservoir command only valid in re-circulate mode - if ( DG_MODE_CIRC == getCurrentOperationMode() ) - { - switch ( resID ) - { - case RESERVOIR_1: - activeReservoir.data = (U32)resID; - result = TRUE; +void setActiveReservoirCmd( DG_RESERVOIR_ID_T resID ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_SWITCH_RESERVOIR; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // switch reservoir command only valid in generation idle mode + if ( DG_MODE_GENE == getCurrentOperationMode() ) + { + switch ( resID ) + { + case DG_RESERVOIR_1: + activeReservoir.data = (U32)resID; + cmdResponse.rejected = FALSE; setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); - setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); break; - case RESERVOIR_2: - activeReservoir.data = (U32)resID; - result = TRUE; - setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); // TODO - valve states are reversed for the two reservoirs for now - revert back when load cells are fixed. - setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + case DG_RESERVOIR_2: + activeReservoir.data = (U32)resID; + cmdResponse.rejected = FALSE; + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); break; default: - // invalid reservoir given - cmd will be NAK'd w/ false result. - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The startFill function handles a fill command from the HD. - * @details - * Inputs : none - * Outputs : move to fill mode - * @param fillToVolMl Target volume (in mL) to fill reservoir to - * @return TRUE if fill command successful, FALSE if not. - *************************************************************************/ -BOOL startFillCmd( U32 fillToVolMl ) -{ - BOOL result = FALSE; - - // fill command only valid in re-circulate mode - if ( ( DG_MODE_CIRC == getCurrentOperationMode() ) && - ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getCurrentRecirculateState() ) ) - { - // validate parameters - if ( fillToVolMl < MAX_FILL_VOLUME_ML ) - { - fillVolumeTargetMl.data = fillToVolMl; - requestNewOperationMode( DG_MODE_FILL ); - result = TRUE; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The stopFill function handles a stop fill command from the HD. - * @details - * Inputs : none - * Outputs : move to standby mode - * @return TRUE if stop fill command successful, FALSE if not. - *************************************************************************/ -BOOL stopFillCmd( void ) -{ - BOOL result = FALSE; - - // stop fill command only valid in fill mode - if ( DG_MODE_FILL == getCurrentOperationMode() ) - { - fillVolumeTargetMl.data = 0; - requestNewOperationMode( DG_MODE_CIRC ); - result = TRUE; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The startDrain function handles a fill command from the HD - * @details - * Inputs : none - * Outputs : - * @param drainToVolMl Target volume (in mL) to drain reservoir to - * @return TRUE if drain command successful, FALSE if not. - *************************************************************************/ -BOOL startDrainCmd( U32 drainToVolMl ) -{ - 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 ) ) - { - drainVolumeTargetMl.data = drainToVolMl; - requestNewOperationMode( DG_MODE_DRAI ); - result = TRUE; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The stopDrain function handles a stop drain command from the HD. - * @details - * Inputs : none - * Outputs : move to standby mode - * @return TRUE if stop drain command successful, FALSE if not. - *************************************************************************/ -BOOL stopDrainCmd( void ) -{ - BOOL result = FALSE; - - // stop drain command only valid in drain mode - if ( DG_MODE_DRAI == getCurrentOperationMode() ) - { - drainVolumeTargetMl.data = 0; - requestNewOperationMode( DG_MODE_CIRC ); - result = TRUE; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The startTrimmerHeater function handles a start trimmer heater command \n - * from the HD. - * @details - * Inputs : none - * Outputs : start trimmer heater - * @return TRUE if stop drain command successful, FALSE if not. - *************************************************************************/ -BOOL startTrimmerHeaterCmd( void ) -{ - BOOL result = FALSE; - - result = startTrimmerHeater(); - - return result; -} - -/*********************************************************************//** - * @brief - * The stopTrimmerHeater function handles a stop trimmer heater command \n - * from the HD. - * @details - * Inputs : none - * Outputs : stop trimmer heater - * @return TRUE if stop drain command successful, FALSE if not. - *************************************************************************/ -BOOL stopTrimmerHeaterCmd( void ) -{ - BOOL result = TRUE; - - stopTrimmerHeater(); - - return result; -} - -/************************************************************************* - * GET SUPPORT FUNCTIONS - *************************************************************************/ - -/*********************************************************************//** - * @brief - * The getActiveReservoir function gets the active reservoir. - * @details - * Inputs : activeReservoir - * Outputs : none - * @return the currently active reservoir. - *************************************************************************/ -RESERVOIR_ID_T getActiveReservoir( void ) -{ - RESERVOIR_ID_T result = (RESERVOIR_ID_T)activeReservoir.data; - - if ( OVERRIDE_KEY == activeReservoir.override ) - { - result = (RESERVOIR_ID_T)activeReservoir.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getReservoirFillVolumeTargetMl function gets the reservoir fill \n - * volume (in mL). - * @details - * Inputs : fillVolumeTargetMl - * Outputs : none - * @return the current target reservoir fill volume (in mL). - *************************************************************************/ -U32 getReservoirFillVolumeTargetMl( void ) -{ - U32 result = fillVolumeTargetMl.data; - - if ( OVERRIDE_KEY == fillVolumeTargetMl.override ) - { - result = fillVolumeTargetMl.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getReservoirDrainVolumeTargetMl function gets the reservoir drain \n - * volume (in mL). - * @details - * Inputs : drainVolumeTargetMl - * 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; -} - - -/************************************************************************* - * TEST SUPPORT FUNCTIONS - *************************************************************************/ - - -/*********************************************************************//** - * @brief - * The testSetDGActiveReservoirOverride function overrides the active \n - * reservoir. - * @details - * Inputs : activeReservoir - * Outputs : activeReservoir - * @param value override active reservoir ID - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetDGActiveReservoirOverride( RESERVOIR_ID_T value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - activeReservoir.ovData = value; - activeReservoir.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The activeReservoir function resets the override of the active \n - * reservoir. - * @details - * Inputs : activeReservoir - * Outputs : activeReservoir - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetDGActiveReservoirOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - activeReservoir.override = OVERRIDE_RESET; - activeReservoir.ovData = activeReservoir.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetReservoirFillVolumeMlOverride function overrides the target \n - * reservoir fill volume (in mL). - * @details - * Inputs : fillVolumeTargetMl - * Outputs : fillVolumeTargetMl - * @param value override target reservoir fill volume (in mL) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetReservoirFillVolumeMlOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - fillVolumeTargetMl.ovData = value; - fillVolumeTargetMl.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetReservoirFillVolumeMlOverride function resets the override of the \n - * target reservoir fill volume. - * @details - * Inputs : fillVolumeTargetMl - * Outputs : fillVolumeTargetMl - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetReservoirFillVolumeMlOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - fillVolumeTargetMl.override = OVERRIDE_RESET; - fillVolumeTargetMl.ovData = fillVolumeTargetMl.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetReservoirDrainVolumeMlOverride function overrides the target \n - * reservoir drain volume (in mL). - * @details - * Inputs : drainVolumeTargetMl - * Outputs : drainVolumeTargetMl - * @param value override target reservoir drain volume (in mL) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetReservoirDrainVolumeMlOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - drainVolumeTargetMl.ovData = value; - drainVolumeTargetMl.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetReservoirDrainVolumeMlOverride function resets the override of the \n - * target reservoir drain volume. - * @details - * Inputs : drainVolumeTargetMl - * Outputs : drainVolumeTargetMl - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetReservoirDrainVolumeMlOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - drainVolumeTargetMl.override = OVERRIDE_RESET; - drainVolumeTargetMl.ovData = drainVolumeTargetMl.ovInitData; - } - - return result; -} - -/**@}*/ + // invalid reservoir given - cmd will be NAK'd w/ false result. + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; + break; + } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The changeValveSettingCmd function changes valve settings according to + * the given setting ID. + * @details Inputs: none + * @details Outputs: Specified valve settings has been setup. + * @param valveSettingID ID of valve setting to change valves to + * @return none + *************************************************************************/ +void changeValveSettingCmd( DG_VALVE_SETTING_ID_T valveSettingID ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_VALVE_SETTING; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // valve setting command only valid in generation idle mode + if ( DG_MODE_GENE == getCurrentOperationMode() ) + { + switch ( valveSettingID ) + { + case DG_VALVE_SETTING_R1_TO_R2: + cmdResponse.rejected = FALSE; + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + break; + + case DG_VALVE_SETTING_R2_TO_R1: + cmdResponse.rejected = FALSE; + setValveState( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + break; + + default: + // invalid reservoir given - cmd will be NAK'd w/ false result. + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; + break; + } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The startFillCmd function handles a fill command from the HD. + * @details Inputs: none + * @details Outputs: move to fill mode + * @param fillToVolMl Target volume (in mL) to fill reservoir to + * @return none + *************************************************************************/ +void startFillCmd( U32 fillToVolMl ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_START_FILL; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // fill command only valid in generation idle mode + if ( ( DG_MODE_GENE == getCurrentOperationMode() ) && + ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == getCurrentGenIdleState() ) ) + { + // validate parameters + if ( fillToVolMl < MAX_FILL_VOLUME_ML ) + { + fillVolumeTargetMl.data = fillToVolMl; + requestNewOperationMode( DG_MODE_FILL ); + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; + } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The stopFillCmd function handles a stop fill command from the HD. + * @details Inputs: none + * @details Outputs: move to generation idle mode + * @return none + *************************************************************************/ +void stopFillCmd( void ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_STOP_FILL; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // stop fill command only valid in fill mode + if ( DG_MODE_FILL == getCurrentOperationMode() ) + { + fillVolumeTargetMl.data = 0; + requestNewOperationMode( DG_MODE_GENE ); + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The startDrainCmd function handles a drain command from the HD. + * @details Inputs: none + * @details Outputs: Start draining in generation idle mode + * @param drainCmd drain command data record + * @return none + *************************************************************************/ +void startDrainCmd( DRAIN_CMD_T drainCmd ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_START_DRAIN; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // drain command only valid in generation idle mode + if ( DG_MODE_GENE == getCurrentOperationMode() ) + { + // validate parameters + if ( drainCmd.targetVolume <= MAX_DRAIN_VOLUME_ML ) + { + drainVolumeTargetMl.data = drainCmd.targetVolume; + tareLoadCellRequest = drainCmd.tareLoadCell; + requestNewOperationMode( DG_MODE_DRAI ); + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; + } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The stopDrainCmd function handles a stop drain command from the HD. + * @details Inputs: none + * @details Outputs: move to generation idle mode + * @return none + *************************************************************************/ +void stopDrainCmd( void ) +{ + DG_CMD_RESPONSE_T cmdResponse; + + cmdResponse.commandID = DG_CMD_STOP_DRAIN; + cmdResponse.rejected = TRUE; + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; + + // stop drain command only valid in drain mode + if ( DG_MODE_DRAI == getCurrentOperationMode() ) + { + drainVolumeTargetMl.data = 0; + requestNewOperationMode( DG_MODE_GENE ); + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } + + sendCommandResponseMsg( &cmdResponse ); +} + +/*********************************************************************//** + * @brief + * The tareReservoir function sets the tare load cell variable to TRUE. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +void tareReservoir( void ) +{ + tareLoadCellRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The resetReservoirsLowestWeight function resets the lowest load cell + * weight of the reservoirs. + * @details Inputs: reservoirLowestWeight + * @details Outputs: reservoirLowestWeight + * @return none + *************************************************************************/ +void resetReservoirsLowestWeight( void ) +{ + reservoirLowestWeight[ DG_RESERVOIR_1 ] = MAX_RESERVOIR_WEIGHT; + reservoirLowestWeight[ DG_RESERVOIR_2 ] = MAX_RESERVOIR_WEIGHT; +} + +/*********************************************************************//** + * @brief + * The getInactiveReservoir function gets the inactive reservoir. + * @details Inputs: activeReservoir + * @details Outputs: none + * @return the currently inactive reservoir. + *************************************************************************/ +DG_RESERVOIR_ID_T getInactiveReservoir( void ) +{ + DG_RESERVOIR_ID_T inactiveReservoir = DG_RESERVOIR_1; + + if ( DG_RESERVOIR_1 == getU32OverrideValue( &activeReservoir ) ) + { + inactiveReservoir = DG_RESERVOIR_2; + } + + return inactiveReservoir; +} + +/*********************************************************************//** + * @brief + * The getReservoirWeight function returns the small filtered weight + * of the reservoir's associated load cell. + * @details Inputs: associatedLoadCell[] + * @details Outputs: none + * @param reservoirId id of reservoir to get weight from + * @return small filtered weight + *************************************************************************/ +F32 getReservoirWeight( DG_RESERVOIR_ID_T reservoirId ) +{ + return getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); +} + +/*********************************************************************//** + * @brief + * The getReservoirsCalRecord function returns the reservoirs' calibration + * record. + * @details Inputs: reservoirsCalRecord + * @details Outputs: none + * @return reservoirs' calibration record + *************************************************************************/ +DG_RESERVOIR_VOLUME_RECORD_T getReservoirsCalRecord( void ) +{ + return reservoirsCalRecord; +} + +/*********************************************************************//** + * @brief + * The hasTargetFillVolumeReached function checks if the target fill volume + * for specific reservoir has been reached. + * @details Inputs: fillVolumeTargetMl + * @details Outputs: none + * @param reservoirId reservoir id + * @return TRUE if target fill volume has been reached, FALSE if not. + *************************************************************************/ +BOOL hasTargetFillVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId ) +{ + F32 const loadcellWeight = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); + U32 const targetFillVolume = getU32OverrideValue( &fillVolumeTargetMl ); + BOOL const hasTargetReached = ( loadcellWeight >= targetFillVolume ); + + return hasTargetReached; +} + +/*********************************************************************//** + * @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 hasTargetDrainVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId, U32 timeout ) +{ + BOOL result = FALSE; + + F32 const loadcellWeight = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); + U32 const targetDrainVolume = getU32OverrideValue( &drainVolumeTargetMl ); + + if ( loadcellWeight < reservoirLowestWeight[ reservoirId ] ) + { + reservoirLowestWeight[ reservoirId ] = loadcellWeight; + reservoirWeightUnchangeStartTime[ reservoirId ] = getMSTimerCount(); + } + + BOOL const hasTimeOut = didTimeout( reservoirWeightUnchangeStartTime[ reservoirId ], timeout ); + BOOL const hasTargetReached = ( targetDrainVolume >= loadcellWeight ); + + // If the goal is to tare the load cell, then the target drain should be reached and timing out on the + // reservoir weight is not enough + if ( ( TRUE == hasTimeOut ) || ( ( TRUE == hasTargetReached ) && ( FALSE == tareLoadCellRequest ) ) ) + { + result = TRUE; + // Reset for next drain + reservoirLowestWeight[ reservoirId ] = MAX_RESERVOIR_WEIGHT; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The tareLoadCellsAtEmpty function tares the load cells for the given + * reservoir when empty and tare request is pending. + * @details Inputs: tareLoadCellRequest + * @details Outputs: tareLoadCellRequest + * @param reservoirId ID of reservoir to tare + * @return none + *************************************************************************/ +void tareLoadCellsAtEmpty( DG_RESERVOIR_ID_T reservoirId ) +{ + U32 const targetDrainVolume = getU32OverrideValue( &drainVolumeTargetMl ); + + if ( TRUE == tareLoadCellRequest ) + { + tareLoadCellRequest = FALSE; + + if ( MIN_RESERVOIR_VOLUME_ML == targetDrainVolume ) + { + tareLoadCell( associatedLoadCell[ reservoirId ] ); + tareLoadCell( redundantLoadCell[ reservoirId ] ); + } + } +} + +/*********************************************************************//** + * @brief + * The isReservoirTarePending function determines whether a reservoir tare + * request is currently pending. + * @details Inputs: tareLoadCellRequest + * @details Outputs: none + * @return tareLoadCellRequest + *************************************************************************/ +BOOL isReservoirTarePending( void ) +{ + return tareLoadCellRequest; +} + +/*********************************************************************//** + * @brief + * The processCalibrationData function gets the calibration data and makes + * sure it is valid by checking the calibration date. The calibration date + * should not be 0. + * @details Inputs: none + * @details Outputs: reservoirsCalRecord + * @return TRUE if the calibration record is valid, otherwise FALSE + *************************************************************************/ +static BOOL processCalibrationData( void ) +{ + BOOL status = TRUE; + U32 reservoir; + + // Get the calibration record from NVDataMgmt + DG_RESERVOIR_VOLUME_RECORD_T calData = getDGReservoirsVolumeRecord(); + + for ( reservoir = 0; reservoir < NUM_OF_CAL_DATA_RSRVRS; reservoir++ ) + { +#ifndef SKIP_CAL_CHECK + // Check if the calibration data that was received from NVDataMgmt is legitimate + // The calibration date item should not be zero. If the calibration date is 0, + // then the data is not stored in the NV memory or it was corrupted. + if ( 0 == calData.reservoir[ reservoir ].calibrationTime ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_RESERVOIRS_INVALID_CAL_RECORD, (U32)reservoir ); + status = FALSE; + } +#endif + + // The calibration data was valid, update the local copy + reservoirsCalRecord.reservoir[ reservoir ].maxResidualFluid = calData.reservoir[ reservoir ].maxResidualFluid; + reservoirsCalRecord.reservoir[ reservoir ].normalFillVolume = calData.reservoir[ reservoir ].normalFillVolume; + reservoirsCalRecord.reservoir[ reservoir ].rsrvrUnfilledWeight = calData.reservoir[ reservoir ].rsrvrUnfilledWeight; + reservoirsCalRecord.reservoir[ reservoir ].rsrvrVolume = calData.reservoir[ reservoir ].rsrvrVolume; + } + + return status; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetDGActiveReservoirOverride function overrides the active reservoir. + * @details Inputs: activeReservoir + * @details Outputs: activeReservoir + * @param value override active reservoir ID + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetDGActiveReservoirOverride( DG_RESERVOIR_ID_T value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + activeReservoir.ovData = value; + activeReservoir.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The activeReservoir function resets the override of the active reservoir. + * @details Inputs: activeReservoir + * @details Outputs: activeReservoir + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetDGActiveReservoirOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + activeReservoir.override = OVERRIDE_RESET; + activeReservoir.ovData = activeReservoir.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetReservoirFillVolumeMlOverride function overrides the target + * reservoir fill volume (in mL). + * @details Inputs: fillVolumeTargetMl + * @details Outputs: fillVolumeTargetMl + * @param value override target reservoir fill volume (in mL) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetReservoirFillVolumeMlOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + fillVolumeTargetMl.ovData = value; + fillVolumeTargetMl.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetReservoirFillVolumeMlOverride function resets the override of + * the target reservoir fill volume. + * @details Inputs: fillVolumeTargetMl + * @details Outputs: fillVolumeTargetMl + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetReservoirFillVolumeMlOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + fillVolumeTargetMl.override = OVERRIDE_RESET; + fillVolumeTargetMl.ovData = fillVolumeTargetMl.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetReservoirDrainVolumeMlOverride function overrides the target + * reservoir drain volume (in mL). + * @details Inputs: drainVolumeTargetMl + * @details Outputs: drainVolumeTargetMl + * @param value override target reservoir drain volume (in mL) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetReservoirDrainVolumeMlOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + drainVolumeTargetMl.ovData = value; + drainVolumeTargetMl.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetReservoirDrainVolumeMlOverride function resets the override of + * the target reservoir drain volume. + * @details Inputs: drainVolumeTargetMl + * @details Outputs: drainVolumeTargetMl + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetReservoirDrainVolumeMlOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + drainVolumeTargetMl.override = OVERRIDE_RESET; + drainVolumeTargetMl.ovData = drainVolumeTargetMl.ovInitData; + } + + return result; +} + +/**@}*/