Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r8abde9a00d09d1e687be6fe88592e66706c1a81d -r99ec83eff4683ad69a249f935d74cb9226984d21 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 8abde9a00d09d1e687be6fe88592e66706c1a81d) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 99ec83eff4683ad69a249f935d74cb9226984d21) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2019-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2023 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 ModeStandby.c * -* @author (last) Dara Navaei -* @date (last) 11-Nov-2022 +* @author (last) Sean Nash +* @date (last) 13-Mar-2023 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -20,6 +20,7 @@ #include "Battery.h" #include "BloodFlow.h" #include "Buttons.h" +#include "Compatible.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" @@ -48,6 +49,8 @@ #define DISINFECTS_DATA_PUB_INTERVAL ( 1 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Disinfects data publish interval in counts. #define DISINFECTS_TIME_INTERVAL_S ( 2 * SECONDS_IN_A_DAY ) ///< HD/DG 2-day service interval in seconds. +#define FLUSH_TIME_INTERVAL_S ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Flush time interval in seconds. +#define MAX_ALLOWED_RO_FILTER_TEMP_FOR_TX_C 44.0F ///< Maximum allowed temperature to start a treatment in C. // ********** private data ********** @@ -131,10 +134,8 @@ resetAirTrap(); resetBloodPumpRotorCount(); resetDialInPumpRotorCount(); + resetPreLoadStatus(); - doorClosedRequired( FALSE, FALSE ); - syringeDetectionRequired( FALSE ); - // Set user alarm recovery actions allowed in this mode setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, FALSE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, FALSE ); @@ -156,8 +157,15 @@ // If we just exited Post Treatment Mode, goto disinfect sub state. if ( MODE_POST == previousOpMode ) { + doorClosedRequired( FALSE, FALSE ); // door no longer required to be closed in standby mode currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; } + else + { + doorClosedRequired( TRUE, FALSE ); + } + syringeDetectionRequired( FALSE ); + // Request DG service record and usage information from DG sendDGServiceRequestToDG(); sendDGUsageInfoRequestToDG(); @@ -178,7 +186,6 @@ handleDisinfectCancel( stop ); -#ifndef RUN_WITHOUT_DG // State machine to get DG to prep a reservoir so we can start a treatment switch ( currentStandbyState ) { @@ -235,33 +242,7 @@ currentStandbyState = STANDBY_START_STATE; break; } -#else - // State machine to get DG to prep a reservoir so we can start a treatment - switch ( currentStandbyState ) - { - case STANDBY_START_STATE: - currentStandbyState = STANDBY_WAIT_FOR_TREATMENT_STATE; - // Temporary test code - TODO - remove later - homeBloodPump(); - homeDialInPump(); - homeDialOutPump(); - break; - case STANDBY_WAIT_FOR_TREATMENT_STATE: - if ( TRUE == treatStartReqReceived ) - { - requestNewOperationMode( MODE_TPAR ); - treatStartReqReceived = FALSE; - } - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_STANDBY_INVALID_STATE, currentStandbyState ); - currentStandbyState = STANDBY_START_STATE; - break; - } -#endif - return currentStandbyState; } @@ -276,47 +257,63 @@ BOOL signalUserInitiateTreatment( void ) { BOOL result = FALSE; + DG_VERSIONS_T dgVersion = getDGVersion(); REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; + // Verify HD is in standby mode waiting for treatment start request if ( ( MODE_STAN != getCurrentOperationMode() ) || ( STANDBY_WAIT_FOR_TREATMENT_STATE != currentStandbyState ) ) { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; } - - if ( TRUE != isDGCommunicating() ) + // Verify DG is communicating with HD + else if ( TRUE != isDGCommunicating() ) { rejReason = REQUEST_REJECT_REASON_DG_COMM_LOST; } - - if ( ( DG_MODE_STAN != getDGOpMode() ) || ( DG_STANDBY_MODE_STATE_IDLE != getDGSubMode() ) ) + // Verify DG software is compatible with HD software + else if ( dgVersion.compatibilityRev != SW_COMPATIBILITY_REV ) { + rejReason = REQUEST_REJECT_REASON_DG_INCOMPATIBLE; + } + // Verify DG is not busy + else if ( ( DG_MODE_STAN != getDGOpMode() ) || ( DG_STANDBY_MODE_STATE_IDLE != getDGSubMode() ) ) + { rejReason = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; } - - if ( FALSE == isBatteryCharged() ) + // Verify HD battery has sufficient charge to hold up logic/sensors for at least 10 minutes + else if ( FALSE == isBatteryCharged() ) { rejReason = REQUEST_REJECT_REASON_BATTERY_IS_NOT_CHARGED; } - -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SERVICE_AND_DISINFECT_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#ifdef _RELEASE_ + else +#else + else 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() ) + // Verify HD and DG are not over due for service + if ( haveHDDGServicesBeenExpired( &rejReason ) != TRUE ) { - rejReason = REQUEST_REJECT_REASON_DG_DISINFECT_HAS_BEEN_EXPIRED; + // Verify DG is disinfected + if ( FALSE == isDGDisinfectValid() ) + { + rejReason = REQUEST_REJECT_REASON_DG_DISINFECT_HAS_BEEN_EXPIRED; + } + else if ( getHeatDisinfectTemperatureSensorValue() > MAX_ALLOWED_RO_FILTER_TEMP_FOR_TX_C ) + { + rejReason = REQUEST_REJECT_REASON_DG_RO_FILTER_TEMPERATURE_OUT_OF_RANGE; + } } } + // If no reason to reject request to start treatment, set flag to initiate treatment workflow if ( REQUEST_REJECT_REASON_NONE == rejReason ) { result = TRUE; treatStartReqReceived = TRUE; } + // Respond to request to start treatment sendInitiateTreatmentResponseMsg( result, rejReason ); return result; @@ -628,16 +625,12 @@ { syringePumpVerifyForceSensorDACCalibration(); homingInitiated = FALSE; // reset for next time + doorClosedRequired( FALSE, FALSE ); // door no longer required to be closed in standby mode state = STANDBY_WAIT_FOR_TREATMENT_STATE; // Go to wait for treatment state after above check } } } } - else - { - // Trigger door open alarm to prompt user to close the door - activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); - } return state; } @@ -667,24 +660,30 @@ cmdStopDG(); } - // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). - if ( TRUE == treatStartReqReceived ) + // If DG is communicating and we don't yet have DG version info, request it + if ( TRUE == isDGCommunicating() ) { - BOOL startTreatment = TRUE; + DG_VERSIONS_T dgVersion = getDGVersion(); - if ( TRUE == startTreatment ) + if ( 0 == dgVersion.compatibilityRev ) { - // Initialize treatment modes before starting a new treatment - initTreatParamsMode(); - initPreTreatmentMode(); - initTreatmentMode(); - initPostTreatmentMode(); - // Start treatment workflow with treatment parameters mode - requestNewOperationMode( MODE_TPAR ); - treatStartReqReceived = FALSE; + sendFWVersionRequest(); } } + // 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; + } + return state; } @@ -969,27 +968,44 @@ static BOOL isDGDisinfectValid( void ) { DG_SERVICE_AND_USAGE_DATA_T data; - BOOL status = TRUE; + BOOL status = FALSE; getHDVersionDGServiceAndUsageData( &data ); - if ( TRUE == data.isDGUsageInfoAviable ) + if ( TRUE == data.isDGUsageInfoAvailable ) { - 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 ); + HD_USAGE_INFO_RECORD_T usageRecord; + getNVRecord2Driver( GET_USAGE_RECORD, (U08*)&usageRecord, sizeof( HD_USAGE_INFO_RECORD_T ), 0, ALARM_ID_NO_ALARM ); - if ( ( TRUE == hasChemDisBeenExpired ) && ( TRUE == hasHeatDisBeenExpired ) ) - { - status = FALSE; - } - } - else + U32 lastChemCompleteDate = data.dgUsageInfo.lastChemDisCompleteDateEpoch; + U32 lastChemFlushCompleteDate = data.dgUsageInfo.lastChemDisFlushCompleteDateEpoch; + U32 lastHeatCompleteDate = data.dgUsageInfo.lastHeatDisCompleteDateEpoch; + U32 lastFlushCompleteDate = data.dgUsageInfo.lastBasicFlushCompleteDateEpoch; + U32 lastStartTxTimeDate = usageRecord.txLastStartTimeEpoch; + + // Last Treatment Start < Last Heat Disinfect Complete or Last Treatment Start < Last Chem Disinfect Complete so it means at least a heat disinfect + // or a chemical disinfect has been done since the last treatment + BOOL hasDisBeenDone = ( ( ( lastStartTxTimeDate < lastChemCompleteDate ) || ( lastStartTxTimeDate < lastHeatCompleteDate ) ) ? TRUE : FALSE ); + + // Last Chem Disinfect Complete < Current Time – Chem Disinfect Interval, so the chemical disinfect that has been done has not been expired + BOOL isChemDisValid = ( lastChemCompleteDate < ( getRTCTimestamp() - DISINFECTS_TIME_INTERVAL_S ) ? TRUE : FALSE ); + + // Last Heat Disinfect Complete < Current Time – Heat Disinfect Interval, so the heat disinfect that has been done has not been expired + BOOL isHeatDisValid = ( lastHeatCompleteDate < ( getRTCTimestamp() - DISINFECTS_TIME_INTERVAL_S ) ? TRUE : FALSE ); + + // Last Chem Flush Complete < Last Chem Disinfect Start, so after running a chemical disinfect, a chemical disinfect flush has been done + BOOL isChemFlushComplete = ( lastChemFlushCompleteDate > lastChemCompleteDate ? TRUE : FALSE ); + + // If either of the basic flush, heat disinfect, or chemical disinfect flush have been done within the interval, it means the filters have been flushed + BOOL isBasicFlushValid = ( lastFlushCompleteDate < ( getRTCTimestamp() - FLUSH_TIME_INTERVAL_S ) ? TRUE : TRUE ); + BOOL isHeatDisFlushValid = ( lastHeatCompleteDate < ( getRTCTimestamp() - FLUSH_TIME_INTERVAL_S ) ? TRUE : TRUE ); + BOOL isChemFlushValid = ( lastChemFlushCompleteDate < ( getRTCTimestamp() - FLUSH_TIME_INTERVAL_S ) ? TRUE : TRUE ); + BOOL isFlushValid = ( isBasicFlushValid || isHeatDisFlushValid || isChemFlushValid ); + + // If all of the above conditions are true, it means we can start a treatment + if ( ( TRUE == hasDisBeenDone ) && ( TRUE == isChemDisValid ) && ( TRUE == isHeatDisValid ) && ( TRUE == isChemFlushComplete ) && ( TRUE == isFlushValid ) ) { - status = FALSE; + status = TRUE; } } @@ -1003,11 +1019,11 @@ * @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 + * @return TRUE if the service for HD or DG has expired otherwise FALSE ***********************************************************************/ static BOOL haveHDDGServicesBeenExpired( REQUEST_REJECT_REASON_CODE_T* rejReason ) { - BOOL status = TRUE; + BOOL status = FALSE; DG_SERVICE_AND_USAGE_DATA_T dgData; HD_SERVICE_RECORD_T hdServiceRecord; @@ -1016,20 +1032,20 @@ if ( TRUE == dgData.isDGServiceRecordAvailable ) { - U32 dgSrvcElapsedTimeS = getRTCTimestamp() - dgData.dgServiceRecord.lastServiceDateEpoch; - BOOL hasDGSrvcBeenExpired = ( dgSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); + U32 dgSrvcElapsedTimeS = getRTCTimestamp() - dgData.dgServiceRecord.lastServiceEpochDate; U32 hdSrvcElapsedTimeS = getRTCTimestamp() - hdServiceRecord.lastServiceEpochDate; + BOOL hasDGSrvcBeenExpired = ( dgSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); BOOL hasHDSrvcBeenExpied = ( hdSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); if ( TRUE == hasDGSrvcBeenExpired ) { - status = FALSE; + status = TRUE; *rejReason = REQUEST_REJECT_REASON_DG_SERVICE_IS_DUE; } if ( TRUE == hasHDSrvcBeenExpied ) { - status = FALSE; + status = TRUE; *rejReason = REQUEST_REJECT_REASON_HD_SERVICE_IS_DUE; } } @@ -1047,7 +1063,7 @@ *************************************************************************/ static void publishDisinfectData( void ) { - if ( ++dataPublishCounter > DISINFECTS_DATA_PUB_INTERVAL ) + if ( ++dataPublishCounter >= DISINFECTS_DATA_PUB_INTERVAL ) { DG_DISINFECT_UI_STATES_T state = getDGDisinfectsStates(); DISINFECTS_DATA_T data;