Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -rce247681f11b5e164e00992fb73ba5c595d349aa -r5ce7985577e93071cd4c361efe2342cdcd7004dd --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision ce247681f11b5e164e00992fb73ba5c595d349aa) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 5ce7985577e93071cd4c361efe2342cdcd7004dd) @@ -30,13 +30,14 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "RTC.h" +#include "Switches.h" +#include "SyringePump.h" #include "SystemComm.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" -#ifdef EMC_TEST_BUILD // TODO - test code -#include "FPGA.h" -#endif +#include "Valves.h" /** * @addtogroup HDStandbyMode @@ -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 ********** @@ -62,8 +63,11 @@ /// 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 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 HD_STANDBY_STATE_T handleStandbyModeStartState( void ); static HD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ); static HD_STANDBY_STATE_T handleStandbyModeWaitForDisinfectState( void ); @@ -79,6 +83,8 @@ static HD_STANDBY_STATE_T handleStandbyModeWaitForDGChemDisinfectStartState( void ); static HD_STANDBY_STATE_T handleStandbyModeDGChemDisininfectInProgressState( void ); +static BOOL isDGDisinfectValid( void ); +static BOOL haveHDDGServicesBeenExpired( void ); static void publishDisinfectData( void ); /*********************************************************************//** @@ -144,6 +150,9 @@ { currentStandbyState = STANDBY_WAIT_FOR_DISINFECT_STATE; } + // Request DG service record and usage information from DG + sendDGServiceRequestToDG(); + sendDGUsageInfoRequestToDG(); return currentStandbyState; } @@ -157,18 +166,14 @@ *************************************************************************/ U32 execStandbyMode( void ) { -#ifdef EMC_TEST_BUILD - static U32 toggle = 0; - static BOOL button_state = FALSE; -#endif BOOL stop = isStopButtonPressed(); #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 = STANDBY_WAIT_FOR_TREATMENT_STATE; + currentStandbyState = handleStandbyModeStartState(); break; case STANDBY_WAIT_FOR_TREATMENT_STATE: @@ -230,13 +235,6 @@ homeBloodPump(); homeDialInPump(); homeDialOutPump(); -#ifdef EMC_TEST_BUILD - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - startAirTrapControl(); -#endif break; case STANDBY_WAIT_FOR_TREATMENT_STATE: @@ -245,63 +243,6 @@ requestNewOperationMode( MODE_TPAR ); treatStartReqReceived = FALSE; } - // TODO - test code - if ( TRUE == stop ) - { -#ifndef EMC_TEST_BUILD - treatStartReqReceived = FALSE; - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - requestNewOperationMode( MODE_TPAR ); -#else - if ( stop != button_state ) - { - toggle = INC_WRAP( toggle, 0, 3 ); - switch ( toggle ) - { - case 0: // Pumps and valves off - setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - break; - - case 1: // Pumps off, valves in pos A - setValvePosition( VDI, VALVE_POSITION_A_INSERT_EJECT ); - setValvePosition( VDO, VALVE_POSITION_A_INSERT_EJECT ); - setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); - setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); - break; - - case 2: // Pumps on, valves in pos A - setBloodPumpTargetFlowRate( 500, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( 500, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialOutPumpTargetRate( 500, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - break; - - - default: // Should not get here, reset if we do - toggle = 0; - setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setValvePosition( VDI, VALVE_POSITION_C_CLOSE ); - setValvePosition( VDO, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBA, VALVE_POSITION_C_CLOSE ); - setValvePosition( VBV, VALVE_POSITION_C_CLOSE ); - break; - } - } -#endif - } -#ifdef EMC_TEST_BUILD - button_state = stop; -#endif break; default: @@ -342,12 +283,10 @@ rejReason = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; } -#ifndef DISABLE_BATT_COMM if ( FALSE == isBatteryCharged() ) { rejReason = REQUEST_REJECT_REASON_BATTERY_IS_NOT_CHARGED; } -#endif if ( REQUEST_REJECT_REASON_NONE == rejReason ) { @@ -539,6 +478,57 @@ /*********************************************************************//** * @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. + * @details Inputs: + * @details Outputs: + * @return next state of the standby mode state machine + *************************************************************************/ +static HD_STANDBY_STATE_T handleStandbyModeStartState( void ) +{ + static BOOL homingInitiated = FALSE; + HD_STANDBY_STATE_T state = STANDBY_START_STATE; + + // Wait for door to be closed so we can home actuators + if ( ( homingInitiated != TRUE ) && ( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ) ) + { + VALVE_T valve; + + // Home pumps and valves + for ( valve = VDI; valve < NUM_OF_VALVES; ++valve ) + { + homeValve( valve ); + } + homeBloodPump(); + homeDialInPump(); + homeDialOutPump(); + retractSyringePump(); + + homingInitiated = TRUE; + } + else + { + // Trigger door open alarm to prompt user to close the door + activateAlarmNoData( ALARM_ID_CARTRIDGE_DOOR_OPENED ); + homingInitiated = FALSE; + } + + // If homing has been initiated, wait for syringe pump to home and the verify force sensor calibration + if ( ( TRUE == homingInitiated ) && ( TRUE == isSyringePumpHome() ) ) + { + syringePumpVerifyForceSensorDACCalibration(); + homingInitiated = FALSE; // reset for next time + state = STANDBY_WAIT_FOR_TREATMENT_STATE; // Go to wait for treatment state after above check + } + + return state; +} +// Verify calibration + + +/*********************************************************************//** + * @brief * The handleStandbyModeWaitForTreatmentState function handles wait for * treatment state. * @details Inputs: treatStartReqReceived @@ -547,29 +537,45 @@ *************************************************************************/ 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 if ( DG_MODE_FILL == dgOperationMode ) { cmdStopDGFill(); } + // If DG is in idle generation state while we are in standby mode, transition DG to standby too if ( DG_MODE_GENE == dgOperationMode ) { cmdStopDG(); } + // 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; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SERVICE_AND_DISINFECT_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + startTreatment = isDGDisinfectValid(); + startTreatment = haveHDDGServicesBeenExpired(); + } + + 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; @@ -847,6 +853,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 ) +{ + BOOL status = TRUE; + DG_SERVICE_AND_USAGE_DATA_T data; + + 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; + activateAlarmNoData( ALARM_ID_DG_DISINFECT_HAS_BEEN_EXPIRED ); + } + } + else + { + status = FALSE; + activateAlarmNoData( ALARM_ID_DG_DISINFECT_HAS_BEEN_EXPIRED ); + } + } + + 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 + * @return TRUE if the service time is still valid otherwise, FALSE + ***********************************************************************/ +static BOOL haveHDDGServicesBeenExpired( void ) +{ + 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; + activateAlarmNoData( ALARM_ID_DG_SERIVCE_TIME_INTERVAL_HAS_ELAPSED ); + } + if ( TRUE == hasHDSrvcBeenExpied ) + { + status = FALSE; + activateAlarmNoData( ALARM_ID_HD_SERVICE_TIME_INTERVAL_HAS_ELAPSED ); + } + } + + return status; +} + +/*********************************************************************//** + * @brief * The publishDisinfectData function publishes disinfects data at * the set interval. * @details Inputs: dataPublishCounter