/************************************************************************** * * Copyright (c) 2020-2024 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 DGInterface.c * * @author (last) Darren Cox * @date (last) 31-Jan-2024 * * @author (original) Sean * @date (original) 08-Apr-2020 * ***************************************************************************/ #include // To check for NaN #include "CPLD.h" #include "DialInFlow.h" #include "Dialysis.h" #include "DGDefs.h" #include "DGInterface.h" #include "ModeInitPOST.h" #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemComm.h" #include "SystemCommMessages.h" #include "Timers.h" /** * @addtogroup DGInterface * @{ */ // ********** private definitions ********** #define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. #define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. #define DIALYSATE_TEMP_OUT_OF_TARGET_CLEAR_TOL_C 2.0F ///< Dialysate temperature clear alarm tolerance C #define DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C 4.0F ///< Dialysate temperature out of target tolerance C. #define DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ( 90 * MS_PER_SECOND ) ///< Dialysate temperature out of target timeout in milliseconds. #define DIALYSATE_TEMP_UPPER_MAX_SAFETY_LIMIT_C 46.0F ///< Dialysate upper bound maximum temperature limit in C. #define DIALYSATE_TEMP_UPPER_MAX_SAFETY_TIMEOUT_MS ( 1 * MS_PER_SECOND ) ///< Dialysate temperature upper bound maximum safety timeout in milliseconds. #define DIALYSATE_TEMP_UPPER_SAFETY_LIMIT_C 42.0F ///< Dialysate upper bound safety temperature limit in C. #define DIALYSATE_TEMP_UPPER_SAFETY_TIMEOUT_MS ( 300 * MS_PER_SECOND ) ///< Dialysate temperature upper bound timeout in milliseconds. #define DIALYSATE_TEMP_LOWER_SAFETY_LIMIT_C 33.0F ///< Dialysate lower bound safety temperature limit in C. #define DIALYSATE_TEMP_LOWER_SAFETY_TIMEOUT_MS ( 300 * MS_PER_SECOND ) ///< Dialysate temperature lower bound timeout in milliseconds. #define DIALYSATE_TEMP_CLEAR_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Dialysate temperature clear persistence timeout. #define DG_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< DG data freshness timeout (in ms). #define DG_TRIMMER_HTR_CHECK_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL + 2 ) ///< DG trimmer heater check interval in general task execution time counts. // ********** private data ********** // DG status static DG_OP_MODE_T dgCurrentOpMode; ///< Current DG operation mode. static U32 dgSubMode; ///< Current state (sub-mode) of current DG operation mode. static BOOL dgStartCommandSent; ///< Flag indicates command to start DG has been sent. static BOOL dgStarted; ///< Flag indicates whether we have commanded the DG to start or stop. static BOOL dgTrimmerHeaterOn; ///< Flag indicates whether we have commanded the DG to start or stop the trimmer heater. // DG sensor data static F32 dgDialysateTemp; ///< Dialysate temperature reported by the DG. static F32 dgRedundantDialysateTemp; ///< Redundant dialysate temperature reported by the DG. static F32 dgHeatDisinfectTemp; ///< Heat disinfect temperature reported by the DG. static F32 dgTrimmerTempSet; ///< Trimmer heater target temperature commanded. static U32 dgTrimmerTempCheckTimerCtr; ///< Trimmer heater temp check interval timer counter. /// Measured weight from load cells. static OVERRIDE_F32_T loadCellWeightInGrams[ NUM_OF_LOAD_CELLS ]; static F32 lgFilteredReservoirWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; ///< Filtered (32 sample) weight of reservoirs from primary load cells. static F32 lgFilteredReservoirBackupWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; ///< Filtered (32 sample) weight of reservoirs from redundant load cells. // Load cell filtering data static F32 lgLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Holds load cell samples for large load cell moving average. static U32 lgLoadCellReadingsIdx = 0; ///< Index for next sample in large load cell rolling average sample array. static F32 lgLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. static F32 lgLoadCellBackupReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Holds load cell samples for large load cell moving average. static F32 lgLoadCellBackupReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. // DG Dialysate flow rate static F32 dgDialysateFlowRateLMin; ///< Latest dialysate flow rate (in L/min) reported by the DG. static F32 dgDialysateFlowRateRawLMin; ///< Latest raw dialysate flow rate (in L/min) reported by the DG. static BOOL dgDialysateFlowDataFreshFlag = FALSE; ///< Flag to signal the execDialInFlowMonitor() to process fresh flow rate data static BOOL dgLoadCellDataFreshFlag = FALSE; ///< Flag to signal the handleLoadCellReadingsFromDG() to process fresh load cell data static BOOL dgDialysateTemperatureDataFreshFlag = FALSE; ///< Flag to signal the handleTemperatureReadingsFromDG() to process fresh temperature data static BOOL dgReservoirsDataFreshFlag = FALSE; ///< Flag to signal the handleDGReservoirData() to process fresh reservoirs data static BOOL dgOpModeDataFreshFlag = FALSE; ///< Flag to signal the handleDGOpMode() to process fresh dg op mode data // Reservoir data static DG_RESERVOIR_ID_T dgActiveReservoir; ///< Latest active reservoir reported by the DG. static DG_RESERVOIR_ID_T dgActiveReservoirSet; ///< Active reservoir commanded. static DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. static DG_MIXING_RATIOS_T dgMixingRatios; ///< DG mixing ratios. static HEATERS_DATA_T dgHeatersData; ///< DG heaters data. static DG_SERVICE_AND_USAGE_DATA_T dgServiceAndUsageData; ///< DG service and usage data. // DG command response static DG_CMD_RESPONSE_T dgCmdResp[ NUM_OF_DG_COMMANDS ]; ///< Keep the latest DG command response for each command. // ********** private function prototypes ********** static void checkDGRestart( void ); static void checkDGTrimmerHeaterStatus( void ); static void checkDGDataFreshness( ALARM_ID_T alarmID, BOOL *dgFreshDataFlag ); /*********************************************************************//** * @brief * The initDGInterface function initializes the DGInterface module. * @details Inputs: none * @details Outputs: DGInterface module initialized. * @return none *************************************************************************/ void initDGInterface( void ) { U32 i, j; // NOTE: the active reservoir is set to reservoir 1 since DG will send active reservoir 1 as active on power up dgStarted = FALSE; dgTrimmerHeaterOn = FALSE; dgTrimmerTempSet = 0.0F; dgTrimmerTempCheckTimerCtr = 0; dgActiveReservoirSet = DG_RESERVOIR_2; dgActiveReservoir = DG_RESERVOIR_2; dgDialysateTemp = 0.0F; dgCurrentOpMode = DG_MODE_INIT; dgSubMode = 0; dgStartCommandSent = FALSE; dgDialysateFlowRateLMin = 0.0F; dgDialysateFlowRateRawLMin = 0.0F; dgDialysateFlowDataFreshFlag = FALSE; dgHeatDisinfectTemp = 0.0F; // initialize load cell weights for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { loadCellWeightInGrams[ i ].data = 0.0F; loadCellWeightInGrams[ i ].ovInitData = 0.0F; loadCellWeightInGrams[ i ].ovData = 0.0F; loadCellWeightInGrams[ i ].override = 0; } // initialize reservoirs weights for ( i = 0; i < NUM_OF_DG_RESERVOIRS; i++ ) { lgFilteredReservoirWeightInGrams[ i ] = 0.0F; for ( j = 0; j < SIZE_OF_LARGE_LOAD_CELL_AVG; j++ ) { lgLoadCellReadings[ i ][ j ] = 0.0F; lgLoadCellBackupReadings[ i ][ j ] = 0.0F; } } // initialize DG command response for ( i = 0; i < NUM_OF_DG_COMMANDS; i++ ) { dgCmdResp[ i ].commandID = DG_CMD_NONE; dgCmdResp[ i ].rejected = TRUE; dgCmdResp[ i ].rejectCode = DG_CMD_REQUEST_REJECT_REASON_NONE; } lgLoadCellReadingsIdx = 0; lgLoadCellReadingsTotal[ DG_RESERVOIR_1 ] = 0.0F; lgLoadCellReadingsTotal[ DG_RESERVOIR_2 ] = 0.0F; lgLoadCellBackupReadingsTotal[ DG_RESERVOIR_1 ] = 0.0F; lgLoadCellBackupReadingsTotal[ DG_RESERVOIR_2 ] = 0.0F; initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, DIALYSATE_TEMP_CLEAR_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP, DIALYSATE_TEMP_CLEAR_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_SAFETY_TEMP, DIALYSATE_TEMP_CLEAR_TIMEOUT_MS, DIALYSATE_TEMP_UPPER_MAX_SAFETY_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_NEW_LOAD_CELL_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_NEW_DIALYSATE_TEMP_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_NEW_RESERVOIRS_DATA_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_HD_DG_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE, DG_DATA_FRESHNESS_TIMEOUT_MS, DG_DATA_FRESHNESS_TIMEOUT_MS ); } /**********************************************************************//** * @brief * The checkDGDataFreshness function checks the condition * for triggering an alarm if the DG fresh data is not received for 2 seconds. * @details Inputs: none * @details Outputs: an alarm is triggered or an alarm condition is cleared * @param alarm ID of alarm to check * @param flag to signal the fresh data processing * @return None *************************************************************************/ static void checkDGDataFreshness( ALARM_ID_T alarmID, BOOL *dgFreshDataFlag ) { if ( TRUE == *dgFreshDataFlag ) { *dgFreshDataFlag = FALSE; checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } else { // Alarm if not receiving DG fresh data message in timely manner if ( TRUE == isDGCommunicating() ) { checkPersistentAlarm( alarmID, TRUE, 0.0, 0.0 ); } else { checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } } } /*********************************************************************//** * @brief * The execDGInterfaceMonitor function executes the DG Interface monitoring * function. Ensures DG is sending fresh data in a timely manner. * @details Inputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag * @details Outputs: dgLoadCellDataFreshFlag, dgDialysateTemperatureDataFreshFlag, * dgReservoirsDataFreshFlag, dgOpModeDataFreshFlag * @return none *************************************************************************/ void execDGInterfaceMonitor( void ) { if ( getCPLDACPowerLossDetected() != TRUE ) { // Trigger alarm if not receiving new load cell data message in timely manner checkDGDataFreshness( ALARM_ID_HD_NEW_LOAD_CELL_DATA_MESSAGE_NOT_RECEIVE, &dgLoadCellDataFreshFlag ); // Trigger alarm if not receiving new dialysate temperature data message in timely manner checkDGDataFreshness( ALARM_ID_HD_NEW_DIALYSATE_TEMP_DATA_MESSAGE_NOT_RECEIVE, &dgDialysateTemperatureDataFreshFlag ); // Trigger alarm if not receiving new reservoirs data message in timely manner checkDGDataFreshness( ALARM_ID_HD_NEW_RESERVOIRS_DATA_MESSAGE_NOT_RECEIVE, &dgReservoirsDataFreshFlag ); // Trigger alarm if not receiving new DG op mode message in timely manner checkDGDataFreshness( ALARM_ID_HD_DG_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE, &dgOpModeDataFreshFlag ); if ( TRUE == isAlarmActive( ALARM_ID_HD_DG_NEW_OPERATION_MODE_MESSAGE_NOT_RECEIVE ) ) { // we don't want to keep thinking DG is in a useful mode - set it to fault mode until DG is able to report its' true mode status setDGOpMode( DG_MODE_FAUL, 0 ); } // Check to see if DG has restarted checkDGRestart(); // Check the status of the trimmer heater if ( ++dgTrimmerTempCheckTimerCtr >= DG_TRIMMER_HTR_CHECK_INTERVAL ) { dgTrimmerTempCheckTimerCtr = 0; checkDGTrimmerHeaterStatus(); } } } /*********************************************************************//** * @brief * The getDGOpMode function gets the current DG operating mode. * @details Inputs: dgCurrentOpMode * @details Outputs: none * @return Current DG operating mode. *************************************************************************/ DG_OP_MODE_T getDGOpMode( void ) { return dgCurrentOpMode; } /*********************************************************************//** * @brief * The getDGSubMode function gets the current DG operating sub-mode. * @details Inputs: dgSubMode * @details Outputs: none * @return Current DG operating sub-mode. *************************************************************************/ U32 getDGSubMode( void ) { return dgSubMode; } /*********************************************************************//** * @brief * The getDGActiveReservoir function gets the current active reservoir. * @details Inputs: dgActiveReservoirSet * @details Outputs: none * @return Currently commanded active reservoir. *************************************************************************/ DG_RESERVOIR_ID_T getDGActiveReservoir( void ) { return dgActiveReservoirSet; } /*********************************************************************//** * @brief * The getDGInactiveReservoir function gets the currently inactive reservoir. * @details Inputs: dgActiveReservoirSet * @details Outputs: none * @return Currently commanded inactive reservoir. *************************************************************************/ DG_RESERVOIR_ID_T getDGInactiveReservoir( void ) { DG_RESERVOIR_ID_T inactiveRes = ( DG_RESERVOIR_2 == dgActiveReservoirSet ? DG_RESERVOIR_1 : DG_RESERVOIR_2 ); return inactiveRes; } /*********************************************************************//** * @brief * The hasDGCompletedReservoirSwitch function checks if DG has completed a * switch reservoir command. * @details Inputs: dgActiveReservoir, dgActiveReservoirSet * @details Outputs: none * @return TRUE if reported active reservoir is the same as set id, otherwise FALSE *************************************************************************/ BOOL hasDGCompletedReservoirSwitch( void ) { return ( dgActiveReservoir == dgActiveReservoirSet ); } /*********************************************************************//** * @brief * The getDGDialysateFlowRateLMin function gets the latest dialysate flow * rate reported by the DG. * @details Inputs: dgDialysateFlowRateLMin * @details Outputs: none * @return Latest dialysate flow rate (in L/min) reported by DG. *************************************************************************/ F32 getDGDialysateFlowRateLMin( void ) { F32 result = dgDialysateFlowRateLMin; return result; } /*********************************************************************//** * @brief * The getDGRawDialysateFlowRateLMin function gets the latest raw dialysate flow * rate reported by the DG. * @details Inputs: dgDialysateFlowRateRawLMin * @details Outputs: none * @return Latest dialysate flow rate (in L/min) reported by DG. *************************************************************************/ F32 getDGRawDialysateFlowRateLMin( void ) { F32 result = dgDialysateFlowRateRawLMin; return result; } /*********************************************************************//** * @brief * The getDialysateFlowDataFreshFlag function returns a flag to indicate * if the dialysate flow rate data reported by the DG is fresh or stale data. * @details Inputs: dgDialysateFlowDataFreshFlag * @details Outputs: dgDialysateFlowDataFreshFlag * @return T/F flag to indicate fresh/stale status of dialysate flow data. *************************************************************************/ BOOL getDialysateFlowDataFreshFlag( void ) { BOOL result = dgDialysateFlowDataFreshFlag; dgDialysateFlowDataFreshFlag = FALSE; return result; } /*********************************************************************//** * @brief * The getLoadCellWeight function gets the current load cell weight. * @details Inputs: loadCellWeightInGrams * @details Outputs: none * @param loadCellID ID of load cell to get * @return the current load cell weight in grams *************************************************************************/ F32 getLoadCellWeight( LOAD_CELL_ID_T loadCellID ) { F32 result = 0.0; if ( loadCellID < NUM_OF_LOAD_CELLS ) { if ( OVERRIDE_KEY == loadCellWeightInGrams[ loadCellID ].override ) { result = loadCellWeightInGrams[ loadCellID ].ovData; } else { result = loadCellWeightInGrams[ loadCellID ].data; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LOAD_CELL_ID, loadCellID ); } return result; } /*********************************************************************//** * @brief * The getReservoirWeightLargeFilter function gets the load cell weight * of the given reservoir after large (32 sample) filter applied. * @details Inputs: lgFilteredReservoirWeightInGrams[] * @details Outputs: none * @param resID ID of reservoir to get filtered weight for * @return the current filtered weight of the given reservoir in grams *************************************************************************/ F32 getReservoirWeightLargeFilter( DG_RESERVOIR_ID_T resID ) { F32 result = 0.0; if ( resID < NUM_OF_DG_RESERVOIRS ) { result = lgFilteredReservoirWeightInGrams[ resID ]; } return result; } /*********************************************************************//** * @brief * The getReservoirWeight function gets the load cell weight of a given reservoir. * @details Inputs: loadCellWeightInGrams[] * @details Outputs: none * @param resID ID of reservoir to get weight for * @return the current weight of the given reservoir in grams *************************************************************************/ F32 getReservoirWeight( DG_RESERVOIR_ID_T resID ) { LOAD_CELL_ID_T lc = ( DG_RESERVOIR_1 == resID ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); F32 wt = getLoadCellWeight( lc ); return wt; } /*********************************************************************//** * @brief * The getReservoirBackupWeightLargeFilter function gets the backup load cell weight * of the given reservoir after large (32 sample) filter applied. * @details Inputs: lgFilteredReservoirWeightInGrams[] * @details Outputs: none * @param resID ID of reservoir to get filtered weight for * @return the current filtered weight of the given reservoir in grams *************************************************************************/ F32 getReservoirBackupWeightLargeFilter( DG_RESERVOIR_ID_T resID ) { F32 result = 0.0; if ( resID < NUM_OF_DG_RESERVOIRS ) { result = lgFilteredReservoirBackupWeightInGrams[ resID ]; } return result; } /*********************************************************************//** * @brief * The getDialysateTemperature function gets the latest dialysate temperature. * @details Inputs: dgDialysateTemp * @details Outputs: none * @return the latest dialysate temperature *************************************************************************/ F32 getDialysateTemperature( void ) { return dgDialysateTemp; } /*********************************************************************//** * @brief * The getRedundantDialysateTemperature function gets the latest redundant * dialysate temperature. * @details Inputs: dgRedundantDialysateTemp * @details Outputs: none * @return the latest redundant dialysate temperature *************************************************************************/ F32 getRedundantDialysateTemperature( void ) { return dgRedundantDialysateTemp; } /*********************************************************************//** * @brief * The getHeatDisinfectTemperatureSensorValue function gets the latest * heat disinfect temperature sensor value. * @details Inputs: dgDialysateTemp * @details Outputs: none * @return the current heat disinfect temperature sensor value *************************************************************************/ F32 getHeatDisinfectTemperatureSensorValue( void ) { return dgHeatDisinfectTemp; } /*********************************************************************//** * @brief * The getTrimmerHeaterCommandedOn function gets the latest on/off commanded * status of the trimmer heater. * @details Inputs: dgTrimmerHeaterOn * @details Outputs: none * @return dgTrimmerHeaterOn *************************************************************************/ BOOL getTrimmerHeaterCommandedOn( void ) { return dgTrimmerHeaterOn; } /*********************************************************************//** * @brief * The getDGDisinfectsStates function returns the DG disinfects readings. * @details Inputs: disinfectsStatus * @details Outputs: none * @return the current DG disinfects readings *************************************************************************/ DG_DISINFECT_UI_STATES_T getDGDisinfectsStates( void ) { return disinfectsStatus; } /*********************************************************************//** * @brief * The getDGMixingRatios function returns the DG mixing ratios and the fill * prep time. * @details Inputs: dgMixingRatios * @details Outputs: none * @return getDGMixingRatios which is the DG mixing ratios *************************************************************************/ DG_MIXING_RATIOS_T getDGMixingRatios( void ) { return dgMixingRatios; } /*********************************************************************//** * @brief * The getHDVersionDGServiceAndUsageData function copies the HD version of * the DG service and usage data into the provided buffer. * @details Inputs: dgServiceAndUsageData * @details Outputs: none * @param data which is a pointer of type DG_SERVICE_AND_USAGE_DATA_T that * is the provided buffer * @return none *************************************************************************/ void getHDVersionDGServiceAndUsageData( DG_SERVICE_AND_USAGE_DATA_T* data ) { memcpy( data, &dgServiceAndUsageData, sizeof( DG_SERVICE_AND_USAGE_DATA_T ) ); } /*********************************************************************//** * @brief * The setDGOpMode function sets the latest DG operating mode reported by * the DG. * @details Inputs: none * @details Outputs: dgCurrentOpMode, dgSubMode, dgOpModeDataFreshFlag * @param opMode operating mode reported by DG * @param subMode sub-mode (current state) of operating mode reported by DG * @return none *************************************************************************/ void setDGOpMode( U32 opMode, U32 subMode ) { if ( opMode < NUM_OF_DG_MODES ) { // reset POST passed flag if DG restarted or faulted or went to service mode if ( ( opMode < DG_MODE_STAN ) && ( dgCurrentOpMode >= DG_MODE_STAN ) ) { signalDGPOSTFinalResult( FALSE ); } // update DG op mode and sub-mode dgCurrentOpMode = (DG_OP_MODE_T)opMode; dgSubMode = subMode; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_DG_OPERATING_MODE, opMode ); } dgOpModeDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setDialysateTemperatureReadings function sets the latest dialysate * temperatures reported by the DG. * @details Inputs: none * @details Outputs: dgDialysateTemp, dgRedundantDialysateTemp, * dgDialysateTemperatureDataFreshFlag * @param tdi dialysate temperature reported by DG * @param tro redundant dialysate temperature reported by DG * @param thd heat disinfect temperature sensor reported by DG * @return none *************************************************************************/ void setDialysateTemperatureReadings( F32 tdi, F32 tro, F32 thd ) { dgDialysateTemp = tdi; dgRedundantDialysateTemp = tro; dgHeatDisinfectTemp = thd; dgDialysateTemperatureDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setDGReservoirsData function sets the latest reservoir data * reported by the DG. * @details Inputs: none * @details Outputs: dgActiveReservoir, dgReservoirsDataFreshFlag * @param resID ID of active reservoir * @param fillVol Reservoir fill to volume reported by DG * @param drainVol Reservoir drain to volume reported by DG * @return none *************************************************************************/ void setDGReservoirsData( DG_RESERVOIR_ID_T resID, U32 fillVol, U32 drainVol ) { if ( resID < NUM_OF_DG_RESERVOIRS ) { dgActiveReservoir = resID; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, resID ); } dgReservoirsDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setDialysateFlowData function sets the latest dialysate flow rate * and its freshness status. The dialysate flow data is reported by the DG. * @details Inputs: none * @details Outputs: dgDialysateFlowRateLMin, dgDialysateFlowRateRawLMin, * dgDialysateFlowDataFreshFlag * @param flowRates latest DG flow rates (mL/min) reported by DG * @return none *************************************************************************/ void setDialysateFlowData( FLOW_SENSORS_DATA_T flowRates ) { // Check if the sent value by DG is a NaN if ( isnan( flowRates.dialysateFlowRateLPM ) ) { flowRates.dialysateFlowRateLPM = 0.0F; } if ( isnan( flowRates.dialysateRawFlowRateLPM ) ) { flowRates.dialysateRawFlowRateLPM = 0.0F; } dgDialysateFlowRateLMin = flowRates.dialysateFlowRateLPM; dgDialysateFlowRateRawLMin = flowRates.dialysateRawFlowRateLPM; dgDialysateFlowDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setNewLoadCellReadings function sets the latest DG reservoir load cell * readings sent by the DG (in g or mL). New readings are expected once * every 100 ms. * @details Inputs: none * @details Outputs: loadCellWeightInGrams[], smFilteredReservoirWeightInGrams[], * lgFilteredReservoirWeightInGrams[], lgLoadCellReadingsTotal[], * lgLoadCellBackupReadingsTotal[], lgLoadCellReadingsIdx, dgLoadCellDataFreshFlag * @param res1Primary New weight from primary load cell of reservoir 1 * @param res1Backup New weight from backup load cell of reservoir 1 * @param res2Primary New weight from primary load cell of reservoir 2 * @param res2Backup New weight from backup load cell of reservoir 2 * @return none *************************************************************************/ void setNewLoadCellReadings( F32 res1Primary, F32 res1Backup, F32 res2Primary, F32 res2Backup ) { DG_RESERVOIR_ID_T res; DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); BOOL inTreatment = ( MODE_TREA == getCurrentOperationMode() ? TRUE : FALSE ); loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_PRIMARY ].data = res1Primary; loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_1_BACKUP ].data = res1Backup; loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_PRIMARY ].data = res2Primary; loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_BACKUP ].data = res2Backup; // Feed new weight samples into filters and update moving averages for ( res = DG_RESERVOIR_1; res < NUM_OF_DG_RESERVOIRS; res++ ) { F32 wt = ( res == DG_RESERVOIR_1 ? res1Primary : res2Primary ); lgLoadCellReadingsTotal[ res ] -= lgLoadCellReadings[ res ][ lgLoadCellReadingsIdx ]; lgLoadCellReadings[ res ][ lgLoadCellReadingsIdx ] = wt; lgLoadCellReadingsTotal[ res ] += wt; lgFilteredReservoirWeightInGrams[ res ] = lgLoadCellReadingsTotal[ res ] / (F32)SIZE_OF_LARGE_LOAD_CELL_AVG; wt = ( res == DG_RESERVOIR_1 ? res1Backup : res2Backup ); lgLoadCellBackupReadingsTotal[ res ] -= lgLoadCellBackupReadings[ res ][ lgLoadCellReadingsIdx ]; lgLoadCellBackupReadings[ res ][ lgLoadCellReadingsIdx ] = wt; lgLoadCellBackupReadingsTotal[ res ] += wt; lgFilteredReservoirBackupWeightInGrams[ res ] = lgLoadCellBackupReadingsTotal[ res ] / (F32)SIZE_OF_LARGE_LOAD_CELL_AVG; } lgLoadCellReadingsIdx = INC_WRAP( lgLoadCellReadingsIdx, 0, SIZE_OF_LARGE_LOAD_CELL_AVG - 1 ); // Update Dialysis sub-mode with new reservoir volumes updateReservoirVolumes( res1Primary, res2Primary ); dgLoadCellDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setDGDisinfectsStates function sets the latest disinfects states * from DG. * @details Inputs: none * @details Outputs: disinfectsStatus * @param states latest DG disinfects state readings * @return none *************************************************************************/ void setDGDisinfectsStates( DG_DISINFECT_UI_STATES_T states ) { memcpy( &disinfectsStatus, &states, sizeof(DG_DISINFECT_UI_STATES_T) ); } /*********************************************************************//** * @brief * The setDGMixingRatios function sets the mixing ratios as well as the fill * prep time upon a request from DG. * @details Inputs: none * @details Outputs: dgMixingRatios * @param ratios the mixing ratios from DG * @return none *************************************************************************/ void setDGMixingRatios( DG_MIXING_RATIOS_T ratios ) { memcpy( &dgMixingRatios, &ratios, sizeof( DG_MIXING_RATIOS_T ) ); } /*********************************************************************//** * @brief * The setDGHeatersData function sets heaters data that has been read from DG. * @details Inputs: none * @details Outputs: dgHeatersData * @param data which is a pointer to the received heaters data * @return none *************************************************************************/ void setDGHeatersData( HEATERS_DATA_T *data ) { memcpy( &dgHeatersData, data, sizeof( HEATERS_DATA_T ) ); } /*********************************************************************//** * @brief * The setHDVersionDGServiceRecord function sets the HD version of the DG * service record. * @details Inputs: none * @details Outputs: dgServiceAndUsageData * @param data which is a pointer to the received HD version of the DG service * record * @return none *************************************************************************/ void setHDVersionDGServiceRecord( DG_SERVICE_RECORD_T* data ) { dgServiceAndUsageData.isDGServiceRecordAvailable = TRUE; memcpy( &dgServiceAndUsageData.dgServiceRecord, data, sizeof( DG_SERVICE_RECORD_T ) ); } /*********************************************************************//** * @brief * The setHDVersionDGUsageInfo function sets the HD version of the DG * usage information. * @details Inputs: none * @details Outputs: dgServiceAndUsageData * @param data which is a pointer to the received HD version of the DG usage * info * @return none *************************************************************************/ void setHDVersionDGUsageInfo( DG_USAGE_INFO_RECORD_T* data ) { dgServiceAndUsageData.isDGUsageInfoAvailable = TRUE; memcpy( &dgServiceAndUsageData.dgUsageInfo, data, sizeof( DG_USAGE_INFO_RECORD_T ) ); } /*********************************************************************//** * @brief * The cmdSetDGDialysateHeatingParams function sends the dialysate heating * parameters to DG. * @details Inputs: none * @details Outputs: dgTrimmerTempSet * @param heatingParams Dialysate heating parameters to be sent to DG * @return none *************************************************************************/ void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ) { dgTrimmerTempSet = heatingParams.trimmerTargetTemperature; // TODO what should we do with the BOOL return of this function? sendDialysateHeatingParamsToDG( &heatingParams ); } /*********************************************************************//** * @brief * The cmdStartDG function sends a start command to the DG. DG will transition * from standby to recirculate mode and start producing warm, pure water. * @details Inputs: none * @details Outputs: start DG command sent * @return none *************************************************************************/ void cmdStartDG( void ) { dgStartCommandSent = TRUE; sendDGStartStopCommand( (BOOL)START_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStopDG function sends a stop command to the DG. DG will transition * from recirculate mode to standby mode. Pumps and heater go off. * @details Inputs: none * @details Outputs: stop DG command sent * @return none *************************************************************************/ void cmdStopDG( void ) { dgStarted = FALSE; sendDGStartStopCommand( (BOOL)STOP_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStartDGTrimmerHeater function sends a start trimmer heater command * to the DG. * @details Inputs: none * @details Outputs: start DG trimmer heater command sent * @return none *************************************************************************/ void cmdStartDGTrimmerHeater( void ) { dgTrimmerHeaterOn = TRUE; dgCmdResp[ DG_CMD_START_TRIMMER_HEATER ].commandID = DG_CMD_NONE; sendDGStartStopTrimmerHeaterCommand( START_DG_CMD ); } /*********************************************************************//** * @brief * The cmdStopDGTrimmerHeater function sends a stop trimmer heater command * to the DG. * @details Inputs: none * @details Outputs: stop DG trimmer heater command sent * @return none *************************************************************************/ void cmdStopDGTrimmerHeater( void ) { dgTrimmerHeaterOn = FALSE; dgCmdResp[ DG_CMD_STOP_TRIMMER_HEATER ].commandID = DG_CMD_NONE; sendDGStartStopTrimmerHeaterCommand( STOP_DG_CMD ); } /*********************************************************************//** * @brief * The cmdSetDGActiveReservoir function sends a set active reservoir command * message to the DG. * @details Inputs: none * @details Outputs: set active reservoir command sent to DG. * @param resID ID of reservoir to set as active (reservoir for HD to draw from) * @return none *************************************************************************/ void cmdSetDGActiveReservoir( DG_SWITCH_RSRVRS_CMD_T *cmd ) { DG_RESERVOIR_ID_T resID = (DG_RESERVOIR_ID_T)cmd->reservoirID; if ( resID < NUM_OF_DG_RESERVOIRS ) { dgActiveReservoirSet = resID; dgCmdResp[ DG_CMD_SWITCH_RESERVOIR ].commandID = DG_CMD_NONE; sendDGSwitchReservoirCommand( cmd ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_RESERVOIR_ID, (U32)resID ); } } /*********************************************************************//** * @brief * The cmdChangeDGValveSetting function sends a change valve setting command * message to the DG. * @details Inputs: none * @details Outputs: change valve setting command sent to DG. * @param valveSettingID ID of valve setting to change to * @return none *************************************************************************/ void cmdChangeDGValveSetting( DG_VALVE_SETTING_ID_T valveSettingID ) { if ( valveSettingID < NUM_OF_DG_VALVE_SETTTINGS ) { dgCmdResp[ DG_CMD_VALVE_SETTING ].commandID = DG_CMD_NONE; sendDGChangeValveSettingCommand( (U32)valveSettingID ); } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_VALVE_SETTING_ID, (U32)valveSettingID ); } } /*********************************************************************//** * @brief * The cmdStartDGFill function sends a fill command message to the DG. * @details Inputs: none * @details Outputs: fill command sent to DG. * @param fillToVolMl volume (in mL) to fill inactive reservoir to * @param targetFlowLPM target flow rate in L/min * @return none *************************************************************************/ void cmdStartDGFill( U32 fillToVolMl, F32 targetFlowLPM ) { dgCmdResp[ DG_CMD_START_FILL ].commandID = DG_CMD_NONE; if ( ( FALSE == isAlarmActive( ALARM_ID_DG_ACID_BOTTLE_LOW_VOLUME ) ) && ( FALSE == isAlarmActive( ALARM_ID_DG_BICARB_BOTTLE_LOW_VOLUME ) ) ) { // The empty bottle alarms should not be active. If they are, the user shall insert the new bottle first and then hit Ok/Resume and // then the fill can go. This is to make sure the next fill is done the full bottles sendDGFillCommand( DG_CMD_START, fillToVolMl, targetFlowLPM ); } } /*********************************************************************//** * @brief * The cmdStopDGFill function sends a fill command with stop parameter message to the DG. * @details Inputs: none * @details Outputs: fill command with stop parameter sent to DG. * @return none *************************************************************************/ void cmdStopDGFill( void ) { dgCmdResp[ DG_CMD_STOP_FILL ].commandID = DG_CMD_NONE; sendDGFillCommand( DG_CMD_STOP, 0, 0 ); } /*********************************************************************//** * @brief * The cmdStartDGDrain function sends a drain command message to the DG. * @details Inputs: none * @details Outputs: drain command sent to DG. * @param drainToVolMl volume (in mL) to drain inactive reservoir to * @param tareLoadCell flag to tell DG tare load cell or not * @param start flag to tell DG to start or stop the drain mode * @return none *************************************************************************/ void cmdStartDGDrain( U32 drainToVolMl, BOOL tareLoadCell, BOOL rinse, BOOL start ) { DRAIN_RESERVOIR_CMD_PAYLOAD_T payload; dgCmdResp[ DG_CMD_START_DRAIN ].commandID = DG_CMD_NONE; payload.drainToVolumeML = drainToVolMl; payload.tareLoadCells = tareLoadCell; payload.rinseConcentrateLines = rinse; payload.cmd = start; sendDGDrainCommand( &payload ); } /*********************************************************************//** * @brief * The cmdDGSampleWater function sends a sample water command message to the DG. * @details Inputs: none * @details Outputs: sample water command sent to DG. * @return none *************************************************************************/ void cmdDGSampleWater( SAMPLE_WATER_CMD_T cmd ) { sendDGSampleWaterCommand( cmd ); } /*********************************************************************//** * @brief * The cmdDGParkConcentratePumps function sends a park concentrate pumps command * message to the DG. * @details Inputs: none * @details Outputs: park concentrate pumps command sent to DG. * @return none *************************************************************************/ void cmdDGParkConcentratePumps( void ) { dgCmdResp[ DG_CMD_PARK_CONCENTRATE_PUMPS ].commandID = DG_CMD_NONE; sendDGParkConcentratePumpsCommand( ); } /*********************************************************************//** * @brief * The cmdStartDGFlush function sends a start flush command message to * the DG. * @details Inputs: none * @details Outputs: start flush mode command sent to DG. * @return none *************************************************************************/ void cmdStartDGFlush( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_FLUSH ].commandID = DG_CMD_NONE; sendDGStartFlushModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGFlush function sends a stop flush command message to * the DG. * @details Inputs: none * @details Outputs: stop flush mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGFlush( void ) { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_FLUSH ].commandID = DG_CMD_NONE; sendDGStartFlushModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStartDGHeatDisinfect function sends a start heat disinfect * command message to the DG. * @details Inputs: none * @details Outputs: start heat disinfect mode command sent to DG. * @return none *************************************************************************/ void cmdStartDGHeatDisinfect( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_HEAT_DISINFECT ].commandID = DG_CMD_NONE; sendDGStartHeatDisinfectModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGHeatDisinfect function sends a stop heat disinfect * command message to the DG. * @details Inputs: none * @details Outputs: stop heat disinfect mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGHeatDisinfect( void ) { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_HEAT_DISINFECT ].commandID = DG_CMD_NONE; sendDGStartHeatDisinfectModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStartDGChemicalDisinfect function sends a start chemical disinfect * command message to the DG. * @details Inputs: none * @details Outputs: start chemical disinfect mode command sent to DG. * @return none *************************************************************************/ void cmdStartDGChemicalDisinfect( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_CHEM_DISINFECT ].commandID = DG_CMD_NONE; sendDGStartChemicalDisinfectModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGChemicalDisinfect function sends a stop chemical disinfect * command message to the DG. * @details Inputs: none * @details Outputs: stop chemical disinfect mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGChemicalDisinfect( void ) { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_CHEM_DISINFECT ].commandID = DG_CMD_NONE; sendDGStartChemicalDisinfectModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStartDGChemicalFlushDisinfect function sends a start chemical disinfect * flush command message to the DG. * @details Inputs: none * @details Outputs: start chemical disinfect flush mode command sent to DG. * @return none *************************************************************************/ void cmdStartDGChemicalFlushDisinfect( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_CHEM_DISINFECT_FLUSH ].commandID = DG_CMD_NONE; sendDGStartStopChemicalDisinfectFlushModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGChemFlushDisinfect function sends a stop chemical disinfect * flush command message to the DG. * @details Inputs: none * @details Outputs: stop chemical disinfect flush mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGChemFlushDisinfect( void ) { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_CHEM_DISINFECT_FLUSH ].commandID = DG_CMD_NONE; sendDGStartStopChemicalDisinfectFlushModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGActiveCool function sends a stop active cool command * message to the DG. * @details Inputs: none * @details Outputs: stop active cool mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGActiveCool( void ) { dgCmdResp[ DG_CMD_STOP_ACTIVE_COOL ].commandID = DG_CMD_NONE; sendDGStopActiveCoolModeCommand(); } /*********************************************************************//** * @brief * The cmdStartDGROPermeateSampleMode function sends an RO permeate sample * start command message to the DG. * @details Inputs: none * @details Outputs: start RO permeate sample mode command sent to DG. * @return none *************************************************************************/ void cmdStartDGROPermeateSampleMode( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_RO_PERMEATE_SAMPLE ].commandID = DG_CMD_NONE; sendDGStartStopDGROPermeateSampleModeCommand( start ); } /*********************************************************************//** * @brief * The cmdStopDGROPermeateSampleMode function sends an RO permeate sample * stop command message to the DG. * @details Inputs: none * @details Outputs: stop RO permeate sample mode command sent to DG. * @return none *************************************************************************/ void cmdStopDGROPermeateSampleMode( void ) { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_RO_PERMEATE_SAMPLE ].commandID = DG_CMD_NONE; sendDGStartStopDGROPermeateSampleModeCommand( start ); } /*********************************************************************//** * @brief * The cmdRequestDGConcentrateRatios function sends a request to DG to receive * the concentrate ratios. * @details Inputs: none * @details Outputs: none * @return none *************************************************************************/ void cmdRequestDGMixingRatios( void ) { dgCmdResp[ DG_CMD_REQUEST_CONC_MIXING_RATIOS ].commandID = DG_CMD_NONE; sendDGConcentrateMixingRatiosRequest(); } /*********************************************************************//** * @brief * The cmdSetDGToServiceMode function sends a request to DG to transition * to service mode. * @details Inputs: none * @details Outputs: none * @return none *************************************************************************/ void cmdSetDGToServiceMode( void ) { sendDGServiceModeRequest(); } /*********************************************************************//** * @brief * The handleDGCommandResponse function processes the latest DG command response. * @details Inputs: none * @details Outputs: process command response from DG * @param dgCmdRespPtr pointer to DG command response data record * @return none *************************************************************************/ void handleDGCommandResponse( DG_CMD_RESPONSE_T *dgCmdRespPtr ) { if ( dgCmdRespPtr->commandID < NUM_OF_DG_COMMANDS ) { if ( DG_CMD_NONE != dgCmdRespPtr->commandID ) { memcpy( &dgCmdResp[ dgCmdRespPtr->commandID ], dgCmdRespPtr, sizeof( DG_CMD_RESPONSE_T ) ); } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_COMMAND_RESPONSE_ID, dgCmdRespPtr->commandID ); } if ( TRUE == dgCmdRespPtr->rejected ) { switch ( dgCmdRespPtr->rejectCode ) { case DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER: SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DG_COMMAND_INVALID_PARAMETER_FAULT, dgCmdRespPtr->commandID ); break; case DG_CMD_REQUEST_REJECT_REASON_NONE: case DG_CMD_REQUEST_REJECT_REASON_INVALID_MODE: default: // Our state machines will detect and handle DG mode out of sync // TODO Consider a generic handler for all state machine break; } } } /*********************************************************************//** * @brief * The getDGCommandResponse function gets the latest command response from DG. * @details Inputs: dgCmdResp * @details Outputs: none * @param commandID id of specific interested command response * @param cmdRespPtr pointer to data record to copy DG command response to * @return TRUE if a specific command response has been received, otherwise FALSE *************************************************************************/ BOOL getDGCommandResponse( U32 commandID, DG_CMD_RESPONSE_T *cmdRespPtr ) { BOOL hasCommandResp = FALSE; if ( commandID == dgCmdResp[ commandID ].commandID ) { hasCommandResp = TRUE; memcpy( cmdRespPtr, &dgCmdResp[ commandID ], sizeof( DG_CMD_RESPONSE_T ) ); } return hasCommandResp; } /*********************************************************************//** * @brief * The checkDialysateTemperature function checks the dialysate temperature * reported by DG and alarm if temperature is out of range. * @details Inputs: dgTrimmerTempSet, dgDialysateTemp * @details Outputs: none * @return none *************************************************************************/ void checkDialysateTemperature( void ) { BOOL isTDiTempAboveHighSafety = ( dgDialysateTemp >= DIALYSATE_TEMP_UPPER_MAX_SAFETY_LIMIT_C ? TRUE : FALSE ); BOOL isTDiTempAboveLowSafety = ( dgDialysateTemp > DIALYSATE_TEMP_UPPER_SAFETY_LIMIT_C ? TRUE : FALSE ); BOOL isTDITempBelowLowSafety = ( dgDialysateTemp < DIALYSATE_TEMP_LOWER_SAFETY_LIMIT_C ? TRUE : FALSE ); F32 TDiHigh = dgTrimmerTempSet + DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C; BOOL isTDiTempAboveDialysateTarget = ( dgDialysateTemp >= TDiHigh ? TRUE : FALSE ); F32 TDiLow = dgTrimmerTempSet - DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C; BOOL isTDiTempBelowDialysateTarget = ( dgDialysateTemp <= TDiLow ? TRUE : FALSE ); BOOL isTempBelowTrigger = (BOOL)( isTDITempBelowLowSafety || isTDiTempBelowDialysateTarget ); BOOL isTempAboveTrigger = (BOOL)( isTDiTempAboveLowSafety || isTDiTempAboveDialysateTarget ); if ( getTargetDialInFlowRate() > 0 ) { // check clear condition first if ( TRUE == isAlarmActive( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_SAFETY_TEMP ) ) { isTDiTempAboveHighSafety = ( dgDialysateTemp <= ( dgTrimmerTempSet + DIALYSATE_TEMP_OUT_OF_TARGET_CLEAR_TOL_C ) ? FALSE : TRUE ); } checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_SAFETY_TEMP, isTDiTempAboveHighSafety, dgDialysateTemp, dgTrimmerTempSet ); if ( TRUE == isAlarmActive( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP ) ) { isTempAboveTrigger = ( dgDialysateTemp <= ( dgTrimmerTempSet + DIALYSATE_TEMP_OUT_OF_TARGET_CLEAR_TOL_C ) ? FALSE : TRUE ); } checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, isTempAboveTrigger, dgDialysateTemp, dgTrimmerTempSet ); if ( TRUE == isAlarmActive( ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP ) ) { isTempBelowTrigger = ( dgDialysateTemp >= ( dgTrimmerTempSet - DIALYSATE_TEMP_OUT_OF_TARGET_CLEAR_TOL_C ) ? FALSE : TRUE ); } checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP, isTempBelowTrigger, dgDialysateTemp, dgTrimmerTempSet ); } else { checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_SAFETY_TEMP, FALSE, dgDialysateTemp, dgTrimmerTempSet ); checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, FALSE, dgDialysateTemp, dgTrimmerTempSet ); checkPersistentAlarm(ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP, FALSE, dgDialysateTemp, dgTrimmerTempSet ); } } // ********** private functions ********** /*********************************************************************//** * @brief * The checkDGRestart function checks to see if DG has restarted after started * by HD and triggers appropriate alarm. * @details Inputs: dgStartCommandSent, dgStarted, dgCurrentOpMode * @details Outputs: dgStartCommandSent, dgStarted, triggers a fault alarm if DG restarted * @return none *************************************************************************/ static void checkDGRestart( void ) { if ( ( dgStartCommandSent == TRUE ) && ( DG_MODE_GENE == dgCurrentOpMode ) ) { dgStartCommandSent = FALSE; dgStarted = TRUE; } if ( TRUE == dgStarted ) { if ( ( DG_MODE_FAUL != dgCurrentOpMode ) && ( DG_MODE_GENE != dgCurrentOpMode ) && ( DG_MODE_FILL != dgCurrentOpMode ) && ( DG_MODE_DRAI != dgCurrentOpMode ) ) { activateAlarmNoData( ALARM_ID_HD_DG_RESTARTED_FAULT ); dgStarted = FALSE; // do not want to re-trigger alarm after alarm is cleared } } } /*********************************************************************//** * @brief * The checkDGTrimmerHeaterStatus function checks to see the status of the * trimmer heater and set them according to the status of the trimmer heater flag. * @details Inputs: dgTrimmerHeaterOn, dgHeatersData * @details Outputs: none * @return none *************************************************************************/ static void checkDGTrimmerHeaterStatus( void ) { U32 trimmerState = dgHeatersData.trimmerHeaterState; DG_OP_MODE_T dgOp = getDGOpMode(); if ( getCPLDACPowerLossDetected() != TRUE ) { if ( ( DG_MODE_GENE == dgOp ) || ( DG_MODE_FILL == dgOp ) || ( DG_MODE_DRAI == dgOp ) ) { // In heat disinfect and chemical disinfect, the trimmer heater is controlled by the DG itself so no commands from HD should be sent // regarding the trimmer heater. if ( ( TRUE == dgTrimmerHeaterOn ) && ( HEATER_EXEC_STATE_OFF == trimmerState ) ) { cmdStartDGTrimmerHeater(); } else if ( ( FALSE == dgTrimmerHeaterOn ) && ( trimmerState != HEATER_EXEC_STATE_OFF ) ) { cmdStopDGTrimmerHeater(); } } } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetDialOutLoadCellWeightOverride function overrides the value of the * load cell sensor with a given weight (in grams). * @details Inputs: loadCellWeightInGrams[] * @details Outputs: loadCellWeightInGrams[] * @param sensor ID of load cell sensor to override weight for * @param value override weight (in grams) for the given sensor * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDialOutLoadCellWeightOverride( U32 sensor, F32 value ) { BOOL result = FALSE; if ( sensor < NUM_OF_LOAD_CELLS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; loadCellWeightInGrams[ sensor ].ovData = value; loadCellWeightInGrams[ sensor ].override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetDialOutLoadCellWeightOverride function resets the override of the * load cell sensor. * @details Inputs: loadCellWeightInGrams[] * @details Outputs: loadCellWeightInGrams[] * @param sensor ID of load cell sensor to override weight for * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetDialOutLoadCellWeightOverride( U32 sensor ) { BOOL result = FALSE; if ( sensor < NUM_OF_LOAD_CELLS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; loadCellWeightInGrams[ sensor ].override = OVERRIDE_RESET; loadCellWeightInGrams[ sensor ].ovData = loadCellWeightInGrams[ sensor ].ovInitData; } } return result; } /**@}*/