Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -rdd7fad816b77aee7febdc79785eb74102b844370 -rfba89d67dd2bef913e85a13563e2aa49f0e2e2f5 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision dd7fad816b77aee7febdc79785eb74102b844370) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision fba89d67dd2bef913e85a13563e2aa49f0e2e2f5) @@ -17,7 +17,6 @@ #include // for memcpy() -#include "Heaters.h" #include "LoadCell.h" #include "ModeRecirculate.h" #include "OperationModes.h" @@ -37,13 +36,12 @@ #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 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 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 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. @@ -55,19 +53,19 @@ 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 associatedLoadCell[ 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. +/// 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 }; -static F32 reservoirLowestWeight[ NUM_OF_RESERVOIRS ] = { MAX_RESERVOIR_WEIGHT, - MAX_RESERVOIR_WEIGHT }; ///< The reservoirs' lowest weight during draining. -static U32 reservoirWeightUnchangeStartTime[ NUM_OF_RESERVOIRS ] = { 0, 0 }; ///< The reservoirs' weight start time when weight stop decreasing. +/// 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. // ********** private function prototypes ********** -static RESERVOIR_ID_T getActiveReservoir( void ); +static DG_RESERVOIR_ID_T getActiveReservoir( void ); static U32 getReservoirFillVolumeTargetMl( void ); static U32 getReservoirDrainVolumeTargetMl( void ); @@ -79,12 +77,8 @@ * @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 ); +{ + setActiveReservoirCmd( DG_RESERVOIR_1 ); fillVolumeTargetMl.data = DEFAULT_FILL_VOLUME_ML; drainVolumeTargetMl.data = DEFAULT_DRAIN_VOLUME_ML; } @@ -111,60 +105,121 @@ /*********************************************************************//** * @brief - * The setActiveReservoir function sets the given reservoir as active + * The setActiveReservoirCmd function sets the given reservoir as active * (meaning HD will be drawing from this reservoir). * @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; +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 re-circulate mode if ( DG_MODE_CIRC == getCurrentOperationMode() ) { switch ( resID ) { - case RESERVOIR_1: - activeReservoir.data = (U32)resID; - result = TRUE; + 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. + case DG_RESERVOIR_2: + activeReservoir.data = (U32)resID; + cmdResponse.rejected = FALSE; + 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 ); break; default: - // invalid reservoir given - cmd will be NAK'd w/ false 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; } - - return result; + + 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 re-circulate mode + if ( DG_MODE_CIRC == 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 startFill function handles a fill command from the HD. + * 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 TRUE if fill command successful, FALSE if not. + * @return none *************************************************************************/ -BOOL startFillCmd( U32 fillToVolMl ) +void startFillCmd( U32 fillToVolMl ) { - BOOL result = FALSE; + 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 re-circulate mode if ( ( DG_MODE_CIRC == getCurrentOperationMode() ) && @@ -175,150 +230,192 @@ { fillVolumeTargetMl.data = fillToVolMl; requestNewOperationMode( DG_MODE_FILL ); - result = TRUE; + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; } - - return result; + + sendCommandResponseMsg( &cmdResponse ); } /*********************************************************************//** * @brief - * The stopFill function handles a stop fill command from the HD. + * The stopFillCmd function handles a stop fill command from the HD. * @details Inputs: none - * @details Outputs: move to standby mode - * @return TRUE if stop fill command successful, FALSE if not. + * @details Outputs: move to re-circulate mode + * @return none *************************************************************************/ -BOOL stopFillCmd( void ) +void stopFillCmd( void ) { - BOOL result = FALSE; + 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_CIRC ); - result = TRUE; + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; } - return result; + sendCommandResponseMsg( &cmdResponse ); } /*********************************************************************//** * @brief - * The startDrain function handles a drain command from the HD. + * The startDrainCmd function handles a drain command from the HD. * @details Inputs: none * @details Outputs: Start draining in re-circulate mode - * @param drainToVolMl Target volume (in mL) to drain reservoir to - * @return TRUE if drain command successful, FALSE if not. + * @param drainCmd drain command data record + * @return none *************************************************************************/ -BOOL startDrainCmd( DRAIN_CMD_T drainCmd ) +void startDrainCmd( DRAIN_CMD_T drainCmd ) { - BOOL result = FALSE; + 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 re-circulate mode if ( DG_MODE_CIRC == getCurrentOperationMode() ) { // validate parameters - if ( ( drainCmd.targetVolume >= MIN_DRAIN_VOLUME_ML ) && ( drainCmd.targetVolume <= MAX_DRAIN_VOLUME_ML ) ) + if ( drainCmd.targetVolume <= MAX_DRAIN_VOLUME_ML ) { drainVolumeTargetMl.data = drainCmd.targetVolume; tareLoadCellRequest = drainCmd.tareLoadCell; requestNewOperationMode( DG_MODE_DRAI ); - result = TRUE; + cmdResponse.rejected = FALSE; + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER; } + } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; } - return result; + sendCommandResponseMsg( &cmdResponse ); } /*********************************************************************//** * @brief - * The stopDrain function handles a stop drain command from the HD. + * The stopDrainCmd function handles a stop drain command from the HD. * @details Inputs: none - * @details Outputs: move to standby mode - * @return TRUE if stop drain command successful, FALSE if not. + * @details Outputs: move to re-circulate mode + * @return none *************************************************************************/ -BOOL stopDrainCmd( void ) +void stopDrainCmd( void ) { - BOOL result = FALSE; + 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_CIRC ); - result = TRUE; + cmdResponse.rejected = FALSE; } + else + { + cmdResponse.rejectCode = DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE; + } - return result; -} - -/*********************************************************************//** - * @brief - * The startTrimmerHeater function handles a start trimmer heater command - * from the HD. - * @details Inputs: none - * @details 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 - * from the HD. - * @details Inputs: none - * @details Outputs: stop trimmer heater - * @return TRUE if stop drain command successful, FALSE if not. - *************************************************************************/ -BOOL stopTrimmerHeaterCmd( void ) -{ - BOOL result = TRUE; - - stopTrimmerHeater(); - - return result; -} + 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. *************************************************************************/ -RESERVOIR_ID_T getInactiveReservoir( void ) +DG_RESERVOIR_ID_T getInactiveReservoir( void ) { - RESERVOIR_ID_T inactiveReservoir = RESERVOIR_1; + DG_RESERVOIR_ID_T inactiveReservoir = DG_RESERVOIR_1; - if ( RESERVOIR_1 == getActiveReservoir() ) + if ( DG_RESERVOIR_1 == getActiveReservoir() ) { - inactiveReservoir = RESERVOIR_2; + inactiveReservoir = DG_RESERVOIR_2; } return inactiveReservoir; } /*********************************************************************//** * @brief + * The getReservoirWeight function returns the large 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 large filtered weight + *************************************************************************/ +F32 getReservoirWeight( DG_RESERVOIR_ID_T reservoirId ) +{ + return getLoadCellLargeFilteredWeight( associatedLoadCell[ reservoirId ] ); +} + +/*********************************************************************//** + * @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( RESERVOIR_ID_T reservoirId ) +BOOL hasTargetFillVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId ) { - F32 const loadcellWeight = getLoadCellFilteredWeight( associatedLoadCell[ reservoirId ] ); + F32 const loadcellWeight = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); U32 const targetFillVolume = getReservoirFillVolumeTargetMl(); BOOL const hasTargetReached = ( loadcellWeight >= targetFillVolume ); @@ -335,10 +432,24 @@ * @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( RESERVOIR_ID_T reservoirId, U32 timeout ) +BOOL hasTargetDrainVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId, U32 timeout ) { BOOL result = FALSE; - F32 const loadcellWeight = getLoadCellFilteredWeight( associatedLoadCell[ reservoirId ] ); + + F32 loadcellWeight = 0.0; + + // TODO remove this code once the load cell is repaired + if ( DG_RESERVOIR_1 == reservoirId ) + { + loadcellWeight = getLoadCellSmallFilteredWeight( LOAD_CELL_RESERVOIR_1_BACKUP ); + } + else + { + loadcellWeight = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); + } + // TODO remove the above code the load cell is repaired + + //F32 const loadcellWeight = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); U32 const targetDrainVolume = getReservoirDrainVolumeTargetMl(); if ( loadcellWeight < reservoirLowestWeight[ reservoirId ] ) @@ -368,33 +479,18 @@ /*********************************************************************//** * @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( associatedLoadCell[ reservoirId ] ); - resetLoadCellOffset( redundantLoadCell[ reservoirId ] ); -} - -/*********************************************************************//** - * @brief * The getActiveReservoir function gets the active reservoir. * @details Inputs: activeReservoir * @details Outputs: none * @return the currently active reservoir. *************************************************************************/ -static RESERVOIR_ID_T getActiveReservoir( void ) +static DG_RESERVOIR_ID_T getActiveReservoir( void ) { - RESERVOIR_ID_T result = (RESERVOIR_ID_T)activeReservoir.data; + DG_RESERVOIR_ID_T result = (DG_RESERVOIR_ID_T)activeReservoir.data; if ( OVERRIDE_KEY == activeReservoir.override ) { - result = (RESERVOIR_ID_T)activeReservoir.ovData; + result = (DG_RESERVOIR_ID_T)activeReservoir.ovData; } return result; @@ -452,7 +548,7 @@ * @param value override active reservoir ID * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetDGActiveReservoirOverride( RESERVOIR_ID_T value ) +BOOL testSetDGActiveReservoirOverride( DG_RESERVOIR_ID_T value ) { BOOL result = FALSE;