Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r140ae221faea91628aabbc24c453f86078e94918 -r526e890e4e35fac0a622af538bf611ea15a30609 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 140ae221faea91628aabbc24c453f86078e94918) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 526e890e4e35fac0a622af538bf611ea15a30609) @@ -7,8 +7,8 @@ * * @file DGInterface.c * -* @author (last) Sean Nash -* @date (last) 08-Mar-2023 +* @author (last) Dara Navaei +* @date (last) 10-Aug-2023 * * @author (original) Sean * @date (original) 08-Apr-2020 @@ -43,13 +43,18 @@ #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. -#define DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C 2.0F ///< Dialysate temperature out of target tolerance C. -#define DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ( 300 * MS_PER_SECOND ) ///< Dialysate temperature out of target timeout in milliseconds. -#define DIALYSATE_TEMP_HIGH_SAFETY_LIMIT_C 46.0F ///< Dialysate high safety temperature limit in C. -#define DIALYSATE_TEMP_HIGH_SAFETY_TIMEOUT_MS ( 1 * MS_PER_SECOND ) ///< Dialysate temperature high safety timeout in milliseconds. -#define DIALYSATE_TEMP_LOW_SAFETY_LIMIT_C 42.0F ///< Dialysate low safety temperature limit in C. -#define DIALYSATE_TEMP_LOW_SAFETY_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Dialysate temperature low safety timeout in milliseconds. -#define DG_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< DG data freshness timeout (in ms). +#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 ( 300 * 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 ********** @@ -66,6 +71,8 @@ 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 ]; @@ -89,8 +96,8 @@ static BOOL dgOpModeDataFreshFlag = FALSE; ///< Flag to signal the handleDGOpMode() to process fresh dg op mode data // Reservoir data -static DG_RESERVOIR_ID_T dgActiveReservoir = DG_RESERVOIR_2; ///< Latest active reservoir reported by the DG. -static DG_RESERVOIR_ID_T dgActiveReservoirSet = DG_RESERVOIR_2; ///< Active reservoir commanded. +static DG_RESERVOIR_ID_T dgActiveReservoir; ///< Latest active reservoir reported by the DG. +static DG_RESERVOIR_ID_T dgActiveReservoirSet; ///< Active reservoir commanded. static U32 dgReservoirFillVolumeTarget = 0; ///< Latest fill-to volume reported by the DG. static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. @@ -122,11 +129,13 @@ { 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; - dgActiveReservoirSet = DG_RESERVOIR_2; - dgActiveReservoir = DG_RESERVOIR_2; + dgTrimmerTempSet = 0.0F; + dgTrimmerTempCheckTimerCtr = 0; + dgActiveReservoirSet = DG_RESERVOIR_1; + dgActiveReservoir = DG_RESERVOIR_1; dgReservoirFillVolumeTargetSet = 0; dgReservoirDrainVolumeTargetSet = 0; dgDialysateTemp = 0.0F; @@ -172,16 +181,15 @@ lgLoadCellBackupReadingsTotal[ DG_RESERVOIR_1 ] = 0.0F; lgLoadCellBackupReadingsTotal[ DG_RESERVOIR_2 ] = 0.0F; - initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_OUT_OF_HIGH_SAFETY_RANGE, DIALYSATE_TEMP_HIGH_SAFETY_TIMEOUT_MS, DIALYSATE_TEMP_HIGH_SAFETY_TIMEOUT_MS ); - initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_OUT_OF_LOW_SAFETY_RANGE, DIALYSATE_TEMP_LOW_SAFETY_TIMEOUT_MS, DIALYSATE_TEMP_LOW_SAFETY_TIMEOUT_MS ); + 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_DIALYSATE_TEMP_BELOW_TARGET_TEMP, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS ); - initPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, DIALYSATE_TEMP_OUT_OF_TARGET_TIMEOUT_MS, DIALYSATE_TEMP_OUT_OF_TARGET_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_TEMPERATURE_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_NEW_DG_OPERATION_MODE_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 ); } /**********************************************************************//** @@ -232,19 +240,28 @@ 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_TEMPERATURE_DATA_MESSAGE_NOT_RECEIVE, &dgDialysateTemperatureDataFreshFlag ); + 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_NEW_DG_OPERATION_MODE_MESSAGE_NOT_RECEIVE, &dgOpModeDataFreshFlag ); + 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 - checkDGTrimmerHeaterStatus(); + if ( ++dgTrimmerTempCheckTimerCtr >= DG_TRIMMER_HTR_CHECK_INTERVAL ) + { + dgTrimmerTempCheckTimerCtr = 0; + checkDGTrimmerHeaterStatus(); + } } } @@ -474,6 +491,19 @@ /*********************************************************************//** * @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: none * @details Outputs: none @@ -526,6 +556,12 @@ { 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; } @@ -1025,17 +1061,17 @@ /*********************************************************************//** * @brief - * The cmdStartDGChememicalFlushDisinfect function sends a start chemical disinfect + * 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 cmdStartDGChememicalFlushDisinfect( void ) +void cmdStartDGChemicalFlushDisinfect( void ) { BOOL start = TRUE; dgCmdResp[ DG_CMD_START_CHEM_DISINFECT_FLUSH ].commandID = DG_CMD_NONE; - sendDGStartChemicalDisinfectFlushModeCommand( start ); + sendDGStartStopChemicalDisinfectFlushModeCommand( start ); } /*********************************************************************//** @@ -1050,11 +1086,57 @@ { BOOL start = FALSE; dgCmdResp[ DG_CMD_STOP_CHEM_DISINFECT_FLUSH ].commandID = DG_CMD_NONE; - sendDGStartChemicalDisinfectFlushModeCommand( start ); + 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 @@ -1107,7 +1189,7 @@ switch ( dgCmdRespPtr->rejectCode ) { case DG_CMD_REQUEST_REJECT_REASON_INVALID_PARAMETER: - activateAlarmNoData( ALARM_ID_DG_COMMAND_INVALID_PARAMETER_FAULT ); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DG_COMMAND_INVALID_PARAMETER_FAULT, dgCmdRespPtr->commandID ); break; case DG_CMD_REQUEST_REJECT_REASON_NONE: @@ -1152,23 +1234,38 @@ *************************************************************************/ void checkDialysateTemperature( void ) { - BOOL isTDiTempAboveHighSafety = ( dgDialysateTemp >= DIALYSATE_TEMP_HIGH_SAFETY_LIMIT_C ? TRUE : FALSE ); - BOOL isTDiTempAboveLowSafety = ( dgDialysateTemp >= DIALYSATE_TEMP_LOW_SAFETY_LIMIT_C ? TRUE : FALSE ); + 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 = ( TDiHigh >= dgDialysateTemp ? TRUE : FALSE ); + BOOL isTDiTempAboveDialysateTarget = ( dgDialysateTemp >= TDiHigh ? TRUE : FALSE ); F32 TDiLow = dgTrimmerTempSet - DIALYSATE_TEMP_OUT_OF_TARGET_TOL_C; - BOOL isTDiTempBelowDialysateTarget = ( TDiLow >= dgDialysateTemp ? TRUE : FALSE ); + BOOL isTDiTempBelowDialysateTarget = ( dgDialysateTemp <= TDiLow ? TRUE : FALSE ); + BOOL isTempBelowTrigger = (BOOL)( isTDITempBelowLowSafety || isTDiTempBelowDialysateTarget ); + BOOL isTempAboveTrigger = (BOOL)( isTDiTempAboveLowSafety || isTDiTempAboveDialysateTarget ); #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DIALYSATE_TEMP_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { - // Per PRS 377, PRS 124 - checkPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_OUT_OF_HIGH_SAFETY_RANGE, isTDiTempAboveHighSafety, dgDialysateTemp, DIALYSATE_TEMP_HIGH_SAFETY_LIMIT_C ); - checkPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_OUT_OF_LOW_SAFETY_RANGE, isTDiTempAboveLowSafety, dgDialysateTemp, DIALYSATE_TEMP_LOW_SAFETY_LIMIT_C ); + // 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 ); - checkPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_ABOVE_TARGET_TEMP, isTDiTempAboveDialysateTarget, dgDialysateTemp, TDiHigh ); - checkPersistentAlarm( ALARM_ID_HD_DIALYSATE_TEMP_BELOW_TARGET_TEMP, isTDiTempBelowDialysateTarget, dgDialysateTemp, TDiLow ); + 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 ); } } @@ -1178,8 +1275,8 @@ * @brief * The checkDGRestart function checks to see if DG has restarted after started * by HD and triggers appropriate alarm. - * @details Inputs: dgStarted - * @details Outputs: triggers a fault alarm if DG restarted + * @details Inputs: dgStartCommandSent, dgStarted, dgCurrentOpMode + * @details Outputs: dgStartCommandSent, dgStarted, triggers a fault alarm if DG restarted * @return none *************************************************************************/ static void checkDGRestart( void ) @@ -1195,7 +1292,8 @@ if ( ( DG_MODE_FAUL != dgCurrentOpMode ) && ( DG_MODE_GENE != dgCurrentOpMode ) && ( DG_MODE_FILL != dgCurrentOpMode ) && ( DG_MODE_DRAI != dgCurrentOpMode ) ) { - activateAlarmNoData( ALARM_ID_DG_RESTARTED_FAULT ); + activateAlarmNoData( ALARM_ID_HD_DG_RESTARTED_FAULT ); + dgStarted = FALSE; // do not want to re-trigger alarm after alarm is cleared } } }