Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r3eba74d2fda81310a66fb2c92dea220013730246 -rf1d120886e090e82cef5b31d371db9ac294d3479 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 3eba74d2fda81310a66fb2c92dea220013730246) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision f1d120886e090e82cef5b31d371db9ac294d3479) @@ -8,7 +8,7 @@ * @file ModeStandby.c * * @author (last) Dara Navaei -* @date (last) 22-Sep-2022 +* @date (last) 18-Oct-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -30,6 +30,7 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "RTC.h" #include "Switches.h" #include "SyringePump.h" #include "SystemComm.h" @@ -46,7 +47,7 @@ // ********** private definitions ********** #define DISINFECTS_DATA_PUB_INTERVAL ( 1 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Disinfects data publish interval in counts. -#define SERVICE_TIME_INTERVAL_MS ( 6 * 30 * SECONDS_IN_A_DAY * MS_PER_SECOND ) ///< HD/DG 6-month service interval in milliseconds. +#define DISINFECTS_TIME_INTERVAL_S ( 2 * SECONDS_IN_A_DAY ) ///< HD/DG 2-day service interval in seconds. // ********** private data ********** @@ -56,16 +57,19 @@ static BOOL flushStartReqReceived; ///< Flag indicates user has requested initiation of flush mode. static BOOL heatDisinfectStartReqReceived; ///< Flag indicates user has requested initiation of heat disinfect mode. static BOOL chemDisinfectStartReqReceived; ///< Flag indicates user has requested initiation of chemical disinfect mode. +static GENERIC_CONFIRM_ID_T disinfectCancelReqID; ///< ID of requested cancel disinfect mode. static DG_DISINFECT_STATE_T dgDisinfectState; ///< DG disinfect state to be boadcast to UI. static U32 dataPublishCounter = 0; ///< Disinfects data publish counter. /// Interval (in task intervals) at which to publish standby mode data to CAN bus. static OVERRIDE_U32_T standbyModePublishInterval = { DISINFECTS_DATA_PUB_INTERVAL, DISINFECTS_DATA_PUB_INTERVAL, DISINFECTS_DATA_PUB_INTERVAL, 0 }; -static BOOL homingInitiated; ///< Flag indicates actuator homing has been initiated from standby mode. +static const U32 SERVICE_TIME_INTERVAL_S = (U32)( 365 * 0.5 * SECONDS_IN_A_DAY ); ///< HD/DG 6-month service interval in seconds. // ********** private function prototypes ********** +static void handleDisinfectCancel( BOOL stop ); + static HD_STANDBY_STATE_T handleStandbyModeStartState( void ); static HD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ); static HD_STANDBY_STATE_T handleStandbyModeWaitForDisinfectState( void ); @@ -82,6 +86,8 @@ static HD_STANDBY_STATE_T handleStandbyModeWaitForDGChemDisinfectStartState( void ); static HD_STANDBY_STATE_T handleStandbyModeDGChemDisininfectInProgressState( void ); +static BOOL isDGDisinfectValid( void ); +static BOOL haveHDDGServicesBeenExpired( REQUEST_REJECT_REASON_CODE_T* rejReason ); static void publishDisinfectData( void ); /*********************************************************************//** @@ -101,7 +107,7 @@ dataPublishCounter = 0; heatDisinfectStartReqReceived = FALSE; chemDisinfectStartReqReceived = FALSE; - homingInitiated = FALSE; + disinfectCancelReqID = GENERIC_CONFIRM_ID_NONE; dgDisinfectState = DG_DISINFECT_NOT_RUNNING_STATE; } @@ -148,6 +154,9 @@ { currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; } + // Request DG service record and usage information from DG + sendDGServiceRequestToDG(); + sendDGUsageInfoRequestToDG(); return currentStandbyState; } @@ -163,12 +172,14 @@ { BOOL stop = isStopButtonPressed(); + handleDisinfectCancel( stop ); + #ifndef RUN_WITHOUT_DG // State machine to get DG to prep a reservoir so we can start a treatment switch ( currentStandbyState ) { case STANDBY_START_STATE: - currentStandbyState = handleStandbyModeStartState();; + currentStandbyState = handleStandbyModeStartState(); break; case STANDBY_WAIT_FOR_TREATMENT_STATE: @@ -283,9 +294,22 @@ rejReason = REQUEST_REJECT_REASON_BATTERY_IS_NOT_CHARGED; } +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SERVICE_AND_DISINFECT_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // This function checks both HD and DG service records and if any of them has failed, it fills the provided reject reason buffer + haveHDDGServicesBeenExpired( &rejReason ); + + if ( FALSE == isDGDisinfectValid() ) + { + rejReason = REQUEST_REJECT_REASON_DG_DISINFECT_HAS_BEEN_EXPIRED; + } + } + if ( REQUEST_REJECT_REASON_NONE == rejReason ) { - result = TRUE; + result = TRUE; treatStartReqReceived = TRUE; } @@ -473,6 +497,87 @@ /*********************************************************************//** * @brief + * The handleDisinfectCancel function handles + * DG disinfect cancel UI interaction. + * @details Inputs: none + * @details Outputs: none + * @param stop button status + * @return none + *************************************************************************/ +static void handleDisinfectCancel( BOOL stop ) +{ + CONFIRMATION_REQUEST_STATUS_T confirm_status; + GENERIC_CONFIRM_ID_T confirm_id; + + if ( ( STANDBY_DG_FLUSH_IN_PROGRESS_STATE == currentStandbyState ) || + ( STANDBY_DG_HEAT_DISINFECT_IN_PROGRESS_STATE == currentStandbyState ) || + ( STANDBY_DG_CHEM_DISINFECT_IN_PROGRESS_STATE == currentStandbyState ) ) + { + if ( ( TRUE == stop ) && ( GENERIC_CONFIRM_ID_NONE == disinfectCancelReqID ) ) + { + if ( STANDBY_DG_FLUSH_IN_PROGRESS_STATE == currentStandbyState ) + { + confirm_id = GENERIC_CONFIRM_ID_DISINFECT_STOP_WATERFLUSH; + } + else if ( STANDBY_DG_HEAT_DISINFECT_IN_PROGRESS_STATE == currentStandbyState ) + { + confirm_id = GENERIC_CONFIRM_ID_DISINFECT_STOP_HEAT; + } + else if ( STANDBY_DG_CHEM_DISINFECT_IN_PROGRESS_STATE == currentStandbyState ) + { + confirm_id = GENERIC_CONFIRM_ID_DISINFECT_STOP_CHEMICAL; + } + // Send message to UI to indicate user request to cancel disinfect + disinfectCancelReqID = addConfirmationRequest( confirm_id, GENERIC_CONFIRM_CMD_REQUEST_OPEN, 0 ); + } + else if ( GENERIC_CONFIRM_ID_NONE != disinfectCancelReqID ) + { + // Get the confirmation request. It consumes the request if completed and responds to UI. + confirm_status = getConfirmationRequestStatus( disinfectCancelReqID ); + switch ( confirm_status ) + { + case CONFIRMATION_REQUEST_STATUS_ACCEPTED : + // Clear request active status + disinfectCancelReqID = GENERIC_CONFIRM_ID_NONE; + + switch ( currentStandbyState ) + { + case STANDBY_DG_FLUSH_IN_PROGRESS_STATE: + cmdStopDGFlush(); + break; + + case STANDBY_DG_HEAT_DISINFECT_IN_PROGRESS_STATE: + cmdStopDGHeatDisinfect(); + break; + + case STANDBY_DG_CHEM_DISINFECT_IN_PROGRESS_STATE: + cmdStopDGChemicalDisinfect(); + break; + + default: + // UI Confirm already closed. Nothing to do. + break; + } + break; + + case CONFIRMATION_REQUEST_STATUS_TIMEOUT : + case CONFIRMATION_REQUEST_STATUS_REJECTED : + // Clear request active status + disinfectCancelReqID = GENERIC_CONFIRM_ID_NONE; + break; + + case CONFIRMATION_REQUEST_STATUS_PENDING: + case CONFIRMATION_REQUEST_STATUS_UNUSED: + default : + // Nothing to do + break; + } + } + } +} + +/*********************************************************************//** + * @brief * The handleStandbyModeStartState function handles the standby start state. * This state waits for the door to be closed and then initiates homing of * pumps and valves and transitions to the wait for treatment state. @@ -534,7 +639,7 @@ *************************************************************************/ static HD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ) { - HD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; + HD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; DG_OP_MODE_T dgOperationMode = getDGOpMode(); // If DG is filling while we are in standby mode, abort the fill @@ -549,17 +654,22 @@ cmdStopDG(); } - // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). TODO - check required conditions before allowing treatment start, reject if necessary. + // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). if ( TRUE == treatStartReqReceived ) { - // Initialize treatment modes before starting a new treatment - initTreatParamsMode(); - initPreTreatmentMode(); - initTreatmentMode(); - initPostTreatmentMode(); - // Start treatment workflow with treatment parameters mode - requestNewOperationMode( MODE_TPAR ); - treatStartReqReceived = FALSE; + BOOL startTreatment = TRUE; + + if ( TRUE == startTreatment ) + { + // Initialize treatment modes before starting a new treatment + initTreatParamsMode(); + initPreTreatmentMode(); + initTreatmentMode(); + initPostTreatmentMode(); + // Start treatment workflow with treatment parameters mode + requestNewOperationMode( MODE_TPAR ); + treatStartReqReceived = FALSE; + } } return state; @@ -837,6 +947,85 @@ /*********************************************************************//** * @brief + * The isDGDisinfectValid function checks whether the DG disinfects is + * acceptable to start another treatment. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if the disinfect is valid otherwise, FALSE + ***********************************************************************/ +static BOOL isDGDisinfectValid( void ) +{ + DG_SERVICE_AND_USAGE_DATA_T data; + BOOL status = TRUE; + + getHDVersionDGServiceAndUsageData( &data ); + + if ( TRUE == data.isDGUsageInfoAviable ) + { + if ( TRUE == data.dgUsageInfo.isDisinfected ) + { + U32 chemDisElapsedTimeS = getRTCTimestamp() - data.dgUsageInfo.lastChemicalDisDateEpoch; + BOOL hasChemDisBeenExpired = ( chemDisElapsedTimeS > DISINFECTS_TIME_INTERVAL_S ? TRUE : FALSE ); + U32 heatDisElapsedTimeS = getRTCTimestamp() - data.dgUsageInfo.lastHeatDisDateEpoch; + BOOL hasHeatDisBeenExpired = ( heatDisElapsedTimeS > DISINFECTS_TIME_INTERVAL_S ? TRUE : FALSE ); + + if ( ( TRUE == hasChemDisBeenExpired ) && ( TRUE == hasHeatDisBeenExpired ) ) + { + status = FALSE; + } + } + else + { + status = FALSE; + } + } + + return status; +} + +/*********************************************************************//** + * @brief + * The haveHDDGServicesBeenExpired function checks whether the last DG/HD + * service time is still within the interval or not. + * @details Inputs: none + * @details Outputs: none + * @param rejReason pointer to the provided reject reason buffer to be send to UI + * @return TRUE if the service time is still valid otherwise, FALSE + ***********************************************************************/ +static BOOL haveHDDGServicesBeenExpired( REQUEST_REJECT_REASON_CODE_T* rejReason ) +{ + BOOL status = TRUE; + DG_SERVICE_AND_USAGE_DATA_T dgData; + HD_SERVICE_RECORD_T hdServiceRecord; + + getHDVersionDGServiceAndUsageData( &dgData ); + getNVRecord2Driver( GET_SRV_RECORD, (U08*)&hdServiceRecord, sizeof( HD_SERVICE_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + + if ( TRUE == dgData.isDGServiceRecordAvailable ) + { + U32 dgSrvcElapsedTimeS = getRTCTimestamp() - dgData.dgServiceRecord.lastServiceDateEpoch; + BOOL hasDGSrvcBeenExpired = ( dgSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); + U32 hdSrvcElapsedTimeS = getRTCTimestamp() - hdServiceRecord.lastServiceEpochDate; + BOOL hasHDSrvcBeenExpied = ( hdSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); + + if ( TRUE == hasDGSrvcBeenExpired ) + { + status = FALSE; + *rejReason = REQUEST_REJECT_REASON_DG_SERVICE_IS_DUE; + } + + if ( TRUE == hasHDSrvcBeenExpied ) + { + status = FALSE; + *rejReason = REQUEST_REJECT_REASON_HD_SERVICE_IS_DUE; + } + } + + return status; +} + +/*********************************************************************//** + * @brief * The publishDisinfectData function publishes disinfects data at * the set interval. * @details Inputs: dataPublishCounter