Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r30f049651877229042e3f8700c8596e5b9a1e0f4 -re23087e0c17f6ea81d60641fdb52121a8dd5a099 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 30f049651877229042e3f8700c8596e5b9a1e0f4) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision e23087e0c17f6ea81d60641fdb52121a8dd5a099) @@ -26,9 +26,12 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "Rinseback.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" +#include "TreatmentEnd.h" +#include "TreatmentRecirc.h" #include "TreatmentStop.h" #include "Utilities.h" #include "Valves.h" @@ -49,9 +52,12 @@ #define USER_CONFIRM_CHANGE_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< Require user to confirm UF volume change within this time. #define PREVENT_UF_VOL_CHANGE_IF_NEARLY_DONE_SEC ( 10 * SEC_PER_MIN ) ///< Prevent UF volume change if treatment within this much time from end of treatment (in seconds). -#define TREATMENT_TIME_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the treatment time & state data is published on the CAN bus. +/// Interval (ms/task time) at which the treatment time data is published on the CAN bus. +static const U32 TREATMENT_TIME_DATA_PUB_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); +/// Interval (ms/task time) at which the treatment state data is published on the CAN bus. +static const U32 TREATMENT_STATE_DATA_PUB_INTERVAL = ( 250 / TASK_GENERAL_INTERVAL ); /// Interval (ms/task time) at which updated, valid treatment setting ranges are published on the CAN bus. -#define TREATMENT_SETTINGS_RANGES_PUB_INTERVAL ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) +static const U32 TREATMENT_SETTINGS_RANGES_PUB_INTERVAL = ( ( 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); #define CALC_ELAPSED_TREAT_TIME_IN_SECS() ( treatmentTimeMS / MS_PER_SECOND ) ///< Macro to calculate the elapsed treatment time in seconds. /// Macro to calculate the elapsed treatment time in minutes. @@ -63,6 +69,10 @@ static TREATMENT_STATE_T currentTreatmentState; ///< Current state (sub-mode) of treatment mode. +static BOOL bloodIsPrimed; ///< Flag indicates whether blood-side circuit has been primed with blood. Set FALSE at init and start of rinseback. Set TRUE at end of blood prime. +static BOOL rinsebackDone; ///< Flag indicates whether a rinseback has been completed. Set FALSE at start of blood prime. Set TRUE at init and end of rinseback. +static BOOL treatmentCompleted; ///< Flag indicates whether the treatment has completed. + static U32 presTreatmentTimeSecs; ///< Prescribed treatment time (in minutes). static U32 presBloodFlowRate; ///< Prescribed blood flow rate (in mL/min). static U32 presDialysateFlowRate; ///< Prescribed dialysate flow rate (in mL/min). @@ -71,12 +81,18 @@ static U32 treatmentTimeMS; ///< Elapsed treatment time (in ms). static U32 lastTreatmentTimeStamp; ///< Last time elapsed treatment time was recorded (a timestamp in ms). -static U32 treatmentTimeBroadcastTimerCtr; ///< Treatment data broadcast timer counter used to schedule when to transmit data. +static U32 treatmentTimeBroadcastTimerCtr; ///< Treatment time data broadcast timer counter used to schedule when to transmit data. +static U32 treatmentStateBroadcastTimerCtr; ///< Treatment state data broadcast timer counter used to schedule when to transmit data. static U32 treatmentParamsRangesBroadcastTimerCtr; ///< Treatment parameter ranges broadcast timer counter used to schedule when to transmit updated ranges. -// TODO - test code - remove later -static BUTTON_STATE_T lastOffButtonState = BUTTON_STATE_RELEASED; -static BOOL pendingUserEndTreatmentRequest; ///< Flag indicates user has requested treatment end. +static BOOL resumeTreatmentAlarmResponseRequest; ///< Flag indicates user has requested treatment resume. +static BOOL initiateRinsebackAlarmResponseRequest; ///< Flag indicates user has requested rinseback. +static BOOL endTreatmentAlarmResponseRequest; ///< Flag indicates user has requested treatment end. +static BOOL rinsebackToStoppedRequest; ///< Flag indicates user has requested return to treatment from rinseback workflow. +static BOOL endTreatmentRequest; ///< Flag indicates user has requested end of treatment from rinseback workflow. +static BOOL bloodPrimeToDialysisRequest; ///< Flag indicates blood prime has completed and time to start dialysis. +static BOOL rinsebackToRecircRequest; ///< Flag indicates user has requested to proceed to re-circulate sub-mode. +static BOOL treatmentEndToRinsebackRequest; ///< Flag indicates user has requested final rinseback. static U32 pendingParamChangesTimer; ///< User required to confirm UF volume change within 1 minute. static F32 pendingUFVolumeChange; ///< An ultrafiltration volume change (mL) is pending user confirmation. @@ -85,10 +101,16 @@ // ********** private function prototypes ********** +static void resetSignalFlags( void ); +static void resetAlarmSignalFlags( void ); static void broadcastTreatmentSettingsRanges( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); +static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ); static TREATMENT_STATE_T handleTreatmentDialysisState( void ); static TREATMENT_STATE_T handleTreatmentStopState( void ); +static TREATMENT_STATE_T handleTreatmentRinsebackState( void ); +static TREATMENT_STATE_T handleTreatmentRecircState( void ); +static TREATMENT_STATE_T handleTreatmentEndState( void ); /*********************************************************************//** * @brief @@ -101,18 +123,24 @@ { currentTreatmentState = TREATMENT_START_STATE; + bloodIsPrimed = FALSE; + treatmentCompleted = FALSE; + rinsebackDone = TRUE; + treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; - treatmentTimeBroadcastTimerCtr = 0; - treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // So we send ranges immediately + treatmentTimeBroadcastTimerCtr = TREATMENT_TIME_DATA_PUB_INTERVAL; // So we send time data immediately when we begin treatment mode + treatmentStateBroadcastTimerCtr = TREATMENT_STATE_DATA_PUB_INTERVAL; // So we send state data immediately when we begin treatment mode + treatmentParamsRangesBroadcastTimerCtr = TREATMENT_SETTINGS_RANGES_PUB_INTERVAL; // So we send ranges immediately when we begin treatment mode presTreatmentTimeSecs = 0; presBloodFlowRate = 0; presDialysateFlowRate = 0; presMaxUFVolumeML = 0.0; presUFRate = 0.0; - pendingUserEndTreatmentRequest = FALSE; + resetSignalFlags(); + resetAlarmSignalFlags(); pendingParamChangesTimer = 0; pendingUFVolumeChange = 0.0; @@ -122,6 +150,36 @@ /*********************************************************************//** * @brief + * The resetSignalFlags function resets all non-alarm signal flags. + * @details Inputs: none + * @details Outputs: non-alarm signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetSignalFlags( void ) +{ + rinsebackToStoppedRequest = FALSE; + endTreatmentRequest = FALSE; + rinsebackToRecircRequest = FALSE; + bloodPrimeToDialysisRequest = FALSE; + treatmentEndToRinsebackRequest = FALSE; +} + +/*********************************************************************//** + * @brief + * The resetAlarmSignalFlags function resets all alarm signal flags. + * @details Inputs: none + * @details Outputs: alarm signal flags set to FALSE + * @return none + *************************************************************************/ +static void resetAlarmSignalFlags( void ) +{ + resumeTreatmentAlarmResponseRequest = FALSE; + initiateRinsebackAlarmResponseRequest = FALSE; + endTreatmentAlarmResponseRequest = FALSE; +} + +/*********************************************************************//** + * @brief * The transitionToTreatmentMode function prepares for transition to treatment mode. * @details Inputs: none * @details Outputs: @@ -133,13 +191,12 @@ initTreatmentMode(); initTreatmentReservoirMgmt(); // Initialize treatment sub-modes each time we transition to treatment mode + initBloodPrime(); initDialysis(); initTreatmentStop(); - - // Set user alarm recovery actions allowed in this mode - setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); - setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); - setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); + initRinseback(); + initTreatmentRecirc(); + initTreatmentEnd(); } /*********************************************************************//** @@ -156,28 +213,77 @@ /*********************************************************************//** * @brief - * The userRequestEndTreatment function conveys a user request to end the - * treatment. - * @details Inputs: currentTreatmentState - * @details Outputs: response to user request sent - * @return TRUE if request accepted, FALSE if not + * The isTreatmentCompleted function determines whether the treatment has + * completed (indicating treatment duration has elapsed). + * @details Inputs: treatmentCompleted + * @details Outputs: none + * @return treatmentCompleted *************************************************************************/ -BOOL userRequestEndTreatment( void ) +BOOL isTreatmentCompleted( void ) { - BOOL result = FALSE; + return treatmentCompleted; +} - if ( TREATMENT_STOP_STATE == currentTreatmentState ) - { - pendingUserEndTreatmentRequest = TRUE; - result = TRUE; - } - sendTreatmentEndResponseMsg( result ); +/*********************************************************************//** + * @brief + * The getRinsebackCompleted function determines whether a rinseback has been + * completed (indicating blood-side circuit should be primarily saline). + * @details Inputs: rinsebackDone + * @details Outputs: none + * @return rinsebackDone + *************************************************************************/ +BOOL getRinsebackCompleted( void ) +{ + return rinsebackDone; +} - return result; +/*********************************************************************//** + * @brief + * The setRinsebackIsCompleted function sets that flag indicating whether a + * rinseback has been completed. Call this function with TRUE when rinseback + * operation is completed. Call this function with FALSE at start of blood + * prime operation. + * @details Inputs: none + * @details Outputs: rinsebackDone + * @param flag TRUE if rinseback has been completed, FALSE if not + * @return none + *************************************************************************/ +void setRinsebackIsCompleted( BOOL flag ) +{ + rinsebackDone = flag; } /*********************************************************************//** * @brief + * The getBloodIsPrimed function determines whether the blood-side circuit + * has been primed with blood (indicating blood-side circuit should be primarily blood). + * @details Inputs: bloodIsPrimed + * @details Outputs: none + * @return bloodIsPrimed + *************************************************************************/ +BOOL getBloodIsPrimed( void ) +{ + return bloodIsPrimed; +} + +/*********************************************************************//** + * @brief + * The setBloodIsPrimed function sets that flag indicating whether the + * blood-side circuit has been primed with blood. Call this function with + * TRUE when blood prime operation is completed. Call this function with + * FALSE at start of treatment or start of rinseback operation. + * @details Inputs: none + * @details Outputs: bloodIsPrimed + * @param flag TRUE if blood side circuit is primed with blood, FALSE if not + * @return none + *************************************************************************/ +void setBloodIsPrimed( BOOL flag ) +{ + bloodIsPrimed = flag; +} + +/*********************************************************************//** + * @brief * The signalAlarmActionToTreatmentMode function executes the given alarm action * as appropriate while in Treatment Mode. * @details Inputs: none @@ -190,60 +296,19 @@ switch( action ) { case ALARM_ACTION_STOP: - switch ( currentTreatmentState ) - { - case TREATMENT_START_STATE: - case TREATMENT_DIALYSIS_STATE: - stopDialysis(); - transitionToTreatmentStop(); - currentTreatmentState = TREATMENT_STOP_STATE; - break; - - case TREATMENT_RINSEBACK_STATE: - // TODO - implement - break; - - case TREATMENT_RECIRC_STATE: - // TODO - implement - break; - - default: - // Ignore - break; - } + // Stop signal actively polled by mode/sub-mode/state break; case ALARM_ACTION_RESUME: - switch ( currentTreatmentState ) - { - case TREATMENT_STOP_STATE: - lastTreatmentTimeStamp = getMSTimerCount(); - startDialysis(); - transitionToDialysis(); - currentTreatmentState = TREATMENT_DIALYSIS_STATE; - break; - - case TREATMENT_RINSEBACK_PAUSE_STATE: - // TODO - implement - break; - - case TREATMENT_RECIRC_PAUSE_STATE: - // TODO - implement - break; - - default: - // Ignore - break; - } + resumeTreatmentAlarmResponseRequest = TRUE; break; case ALARM_ACTION_RINSEBACK: - // TODO - implement + initiateRinsebackAlarmResponseRequest = TRUE; break; case ALARM_ACTION_END_TREATMENT: - // TODO - temporary code - implement - currentTreatmentState = TREATMENT_END_STATE; + endTreatmentAlarmResponseRequest = TRUE; break; case ALARM_ACTION_ACK: @@ -258,6 +323,71 @@ /*********************************************************************//** * @brief + * The signalRinsebackToTreatmentStopped function signals that user wants to return + * to treatment from rinseback workflow. + * @details Inputs: none + * @details Outputs: rinsebackToStoppedRequest + * @return none + *************************************************************************/ +void signalGoToTreatmentStopped( void ) +{ + rinsebackToStoppedRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The signalGoToRinseback function signals that user wants to perform + * a rinseback operation. + * @details Inputs: none + * @details Outputs: rinsebackRequested + * @return none + *************************************************************************/ +void signalGoToRinseback( void ) +{ + treatmentEndToRinsebackRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The signalRinsebackToTreatmentEnd function signals that user wants to end the + * treatment from rinseback workflow. + * @details Inputs: none + * @details Outputs: rinsebackToEndTreatmentRequest + * @return none + *************************************************************************/ +void signalEndTreatment( void ) +{ + endTreatmentRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The signalBloodPrimeToDialysis function signals that blood prime has + * completed and it is time to move on to dialysis. + * @details Inputs: none + * @details Outputs: bloodPrimeToDialysisRequest + * @return none + *************************************************************************/ +void signalBloodPrimeToDialysis( void ) +{ + bloodPrimeToDialysisRequest = TRUE; +} + +/*********************************************************************//** + * @brief + * The signalRinsebackToRecirc function signals that user wants to continue + * on to re-circulate portion of rinseback workflow. + * @details Inputs: none + * @details Outputs: rinsebackToRecircRequest + * @return none + *************************************************************************/ +void signalRinsebackToRecirc( void ) +{ + rinsebackToRecircRequest = TRUE; +} + +/*********************************************************************//** + * @brief * The execTreatmentMode function executes the Treatment Mode state machine. * @details Inputs: currentTreatmentState * @details Outputs: currentTreatmentState @@ -279,6 +409,10 @@ currentTreatmentState = handleTreatmentStartState(); break; + case TREATMENT_BLOOD_PRIME_STATE: + currentTreatmentState = handleTreatmentBloodPrimeState(); + break; + case TREATMENT_DIALYSIS_STATE: currentTreatmentState = handleTreatmentDialysisState(); break; @@ -288,50 +422,32 @@ break; case TREATMENT_RINSEBACK_STATE: - // TODO - implement + currentTreatmentState = handleTreatmentRinsebackState(); break; - case TREATMENT_RINSEBACK_PAUSE_STATE: - // TODO - implement - break; - - case TREATMENT_RECIRC_SETUP_STATE: - // TODO - implement - break; - case TREATMENT_RECIRC_STATE: - // TODO - implement + currentTreatmentState = handleTreatmentRecircState(); break; - case TREATMENT_RECIRC_PAUSE_STATE: - // TODO - implement - break; - - case TREATMENT_RECIRC_STOP_STATE: - // TODO - implement - break; - - case TREATMENT_DIALYSIS_END_STATE: - // TODO - implement - break; - case TREATMENT_END_STATE: - // TODO - implement - endAirTrapControl(); // TODO - move to appropriate place - requestNewOperationMode( MODE_POST ); // TODO - test code - remove later + currentTreatmentState = handleTreatmentEndState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_INVALID_STATE, currentTreatmentState ); - currentTreatmentState = TREATMENT_END_STATE; break; } + + // Alarm response request flags should be handled at this point, reset in case not handled in current state + resetAlarmSignalFlags(); + // clear signal flags from sub-modes before calling sub-mode executives + resetSignalFlags(); + // Broadcast treatment data broadcastTreatmentTimeAndState(); broadcastTreatmentSettingsRanges(); - // Call various execs for treatment mode - execTreatmentReservoirMgmt(); + // Manage air trap control execAirTrapMonitorTreatment(); return currentTreatmentState; @@ -340,14 +456,15 @@ /*********************************************************************//** * @brief * The handleTreatmentStartState function handles the Start state of - * the Treatment Mode state machine. + * the Treatment Mode state machine. Should only pass through this state + * once at very beginning of treatment. * @details Inputs: none * @details Outputs: treatmentTimeMS, lastTreatmentTimeStamp * @return next treatment mode state *************************************************************************/ static TREATMENT_STATE_T handleTreatmentStartState( void ) { - TREATMENT_STATE_T result = TREATMENT_DIALYSIS_STATE; + TREATMENT_STATE_T result = TREATMENT_BLOOD_PRIME_STATE; // Initialize treatment time treatmentTimeMS = 0; @@ -359,15 +476,51 @@ presMaxUFVolumeML = getTreatmentParameterF32( TREATMENT_PARAM_UF_VOLUME ) * (F32)ML_PER_LITER; presUFRate = presMaxUFVolumeML / (F32)getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); - // Kick dialysis sub-mode off - setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); - startDialysis(); + transitionToBloodPrime(); return result; } /*********************************************************************//** * @brief + * The handleTreatmentBloodPrimeState function handles the blood prime state of + * the Treatment Mode state machine. + * @details Inputs: none + * @details Outputs: none + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_BLOOD_PRIME_STATE; + + setRinsebackIsCompleted( FALSE ); + + // Handle alarm stoppage + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + transitionToTreatmentStop(); + result = TREATMENT_STOP_STATE; + } + else + { + execBloodPrime(); + + // Handle signals from blood prime sub-mode + if ( TRUE == bloodPrimeToDialysisRequest ) + { + lastTreatmentTimeStamp = getMSTimerCount(); + // Kick dialysis sub-mode off + setDialysisParams( presBloodFlowRate, presDialysateFlowRate, presMaxUFVolumeML, presUFRate ); + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The handleTreatmentDialysisState function handles the Dialysis state of * the Treatment Mode state machine. * @details Inputs: none @@ -391,29 +544,25 @@ // End treatment if treatment duration has been reached if ( CALC_ELAPSED_TREAT_TIME_IN_SECS() >= presTreatmentTimeSecs ) { + treatmentCompleted = TRUE; + stopDialysis(); + transitionToTreatmentEnd(); + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); result = TREATMENT_END_STATE; } // Otherwise, execute state machine for treatment dialysis sub-mode else { + execTreatmentReservoirMgmt(); execDialysis(); - } - - // TODO - test code - remove later - if ( getOffButtonState() == BUTTON_STATE_PRESSED ) - { - if ( lastOffButtonState == BUTTON_STATE_RELEASED ) + // Handle alarm stoppage + if ( TRUE == doesAlarmStatusIndicateStop() ) { - lastOffButtonState = BUTTON_STATE_PRESSED; stopDialysis(); transitionToTreatmentStop(); result = TREATMENT_STOP_STATE; } } - else - { - lastOffButtonState = BUTTON_STATE_RELEASED; - } return result; } @@ -430,39 +579,148 @@ { TREATMENT_STATE_T result = TREATMENT_STOP_STATE; + // If user requests resumption of treatment, resume treatment + if ( TRUE == resumeTreatmentAlarmResponseRequest ) + { + resumeTreatmentAlarmResponseRequest = FALSE; + if ( TRUE == getBloodIsPrimed() ) + { + lastTreatmentTimeStamp = getMSTimerCount(); + transitionToDialysis(); + result = TREATMENT_DIALYSIS_STATE; + } + else + { + transitionToBloodPrime(); + result = TREATMENT_BLOOD_PRIME_STATE; + } + } + // If user requests rinseback, go to rinseback + else if ( TRUE == initiateRinsebackAlarmResponseRequest ) + { + // TODO - should we block rinseback request if no blood in line (i.e. already did a rinseback)? + transitionToRinseback(); + result = TREATMENT_RINSEBACK_STATE; + } // If user requests treatment end, end treatment - if ( TRUE == pendingUserEndTreatmentRequest ) + else if ( TRUE == endTreatmentAlarmResponseRequest ) { - result = TREATMENT_END_STATE; + requestNewOperationMode( MODE_POST ); } + // Otherwise execute state machine for treatment stop sub-mode else { - // Execute state machine for treatment stop sub-mode execTreatmentStop(); } - // TODO - test code - remove later - if ( getOffButtonState() == BUTTON_STATE_PRESSED ) + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentRinsebackState function executes the rinseback state of the + * Treatment Mode state machine. + * @details Inputs: none + * @details Outputs: treatment rinseback sub-mode executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentRinsebackState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_RINSEBACK_STATE; + + // Execute treatment re-circ sub-mode + execRinseback(); + + // Handle signals from treatment end sub-mode + if ( TRUE == rinsebackToRecircRequest ) { - if ( lastOffButtonState == BUTTON_STATE_RELEASED ) - { - lastOffButtonState = BUTTON_STATE_PRESSED; - lastTreatmentTimeStamp = getMSTimerCount(); - startDialysis(); - transitionToDialysis(); - result = TREATMENT_DIALYSIS_STATE; - } + transitionToTreatmentRecirc(); + result = TREATMENT_RECIRC_STATE; } - else + else if ( TRUE == rinsebackToStoppedRequest ) { - lastOffButtonState = BUTTON_STATE_RELEASED; + transitionToTreatmentStop(); + result = TREATMENT_STOP_STATE; } + else if ( TRUE == endTreatmentRequest ) + { + requestNewOperationMode( MODE_POST ); + } return result; } /*********************************************************************//** * @brief + * The handleTreatmentRecircState function executes the re-circulate state of the + * Treatment Mode state machine. + * @details Inputs: none + * @details Outputs: treatment re-circulate sub-mode executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentRecircState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_RECIRC_STATE; + + // Execute treatment re-circ sub-mode + execTreatmentRecirc(); + + // Handle signals from treatment end sub-mode + if ( TRUE == rinsebackToStoppedRequest ) + { + transitionToTreatmentStop(); + result = TREATMENT_STOP_STATE; + } + else if ( TRUE == endTreatmentRequest ) + { + requestNewOperationMode( MODE_POST ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleTreatmentEndState function executes the end state of the + * Treatment Mode state machine. + * @details Inputs: none + * @details Outputs: treatment end sub-mode executed. + * @return next treatment mode state + *************************************************************************/ +static TREATMENT_STATE_T handleTreatmentEndState( void ) +{ + TREATMENT_STATE_T result = TREATMENT_END_STATE; + + // Handle final rinseback alarm response from user + if ( TRUE == initiateRinsebackAlarmResponseRequest ) + { + signalTreatmentEndAlarmRinsebackUserAction(); + } + // Handle alarm response from user to end treatment w/o rinseback + else if ( TRUE == endTreatmentAlarmResponseRequest ) + { + signalTreatmentEndAlarmEndTxUserAction(); + } + + // Execute treatment end sub-mode + execTreatmentEnd(); + + // Handle signals from treatment end sub-mode + if ( TRUE == treatmentEndToRinsebackRequest ) + { + transitionToRinseback(); + result = TREATMENT_RINSEBACK_STATE; + } + else if ( TRUE == endTreatmentRequest ) + { + requestNewOperationMode( MODE_POST ); + } + + return result; +} + +/*********************************************************************//** + * @brief * The verifyTreatmentDurationSettingChange function verifies and responds to * the user treatment duration setting change request. * @details Inputs: current operating mode, treatment states and parameters @@ -478,7 +736,7 @@ // Check if we are in an appropriate treatment state for settings adjustment if ( ( MODE_TREA == currMode ) && - ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) && + ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_END_STATE ) && ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= MIN_TREATMENT_TIME_MINUTES ) ) { F32 uFVolume; @@ -518,7 +776,7 @@ rejectReason = REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE; } else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || - ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) + ( currentTreatmentState >= TREATMENT_END_STATE ) ) { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } @@ -565,7 +823,7 @@ // Check if we are in an appropriate treatment state for settings adjustment if ( ( MODE_TREA == currMode ) && - ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_DIALYSIS_END_STATE ) && + ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_END_STATE ) && ( uFVolume <= MAX_UF_VOLUME_ML ) && ( CALC_TREAT_TIME_REMAINING_IN_SECS() >= PREVENT_UF_VOL_CHANGE_IF_NEARLY_DONE_SEC ) ) { @@ -624,7 +882,7 @@ rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_OUT_OF_RANGE; } else if ( ( currentTreatmentState <= TREATMENT_START_STATE ) || - ( currentTreatmentState >= TREATMENT_DIALYSIS_END_STATE ) ) + ( currentTreatmentState >= TREATMENT_END_STATE ) ) { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } @@ -868,25 +1126,40 @@ U32 elapsedTreatmentTimeInSecs; // Update treatment time stats and broadcast - end treatment if time - elapsedTreatmentTimeInSecs = treatmentTimeMS / MS_PER_SECOND; - if ( elapsedTreatmentTimeInSecs >= presTreatmentTimeSecs ) - { - stopDialysis(); - elapsedTreatmentTimeInSecs = presTreatmentTimeSecs; - currentTreatmentState = TREATMENT_DIALYSIS_END_STATE; - } - // Broadcast treatment time and state data at interval + elapsedTreatmentTimeInSecs = CALC_ELAPSED_TREAT_TIME_IN_SECS(); + // Broadcast treatment time data at interval if ( ++treatmentTimeBroadcastTimerCtr >= TREATMENT_TIME_DATA_PUB_INTERVAL ) { - U32 timeRemaining = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; - DIALYSIS_STATE_T dialysisState = getDialysisState(); - UF_STATE_T uFState = getUltrafiltrationState(); - SALINE_BOLUS_STATE_T salineBolusInProgress = getSalineBolusState(); + if ( isTreatmentCompleted() != TRUE ) + { + U32 timeRemaining = presTreatmentTimeSecs - elapsedTreatmentTimeInSecs; - broadcastTreatmentTime( presTreatmentTimeSecs, elapsedTreatmentTimeInSecs, timeRemaining ); - broadcastTreatmentState( currentTreatmentState, uFState, salineBolusInProgress ); + broadcastTreatmentTime( presTreatmentTimeSecs, elapsedTreatmentTimeInSecs, timeRemaining ); + } + else // If treatment is completed, send zeroes to UI + { + broadcastTreatmentTime( 0, 0, 0 ); + } treatmentTimeBroadcastTimerCtr = 0; } + // Broadcast treatment state data at interval + if ( ++treatmentStateBroadcastTimerCtr >= TREATMENT_STATE_DATA_PUB_INTERVAL ) + { + TREATMENT_STATE_DATA_T payload; + + payload.treatmentSubMode = (U32)currentTreatmentState; + payload.uFState = getUltrafiltrationState(); + payload.salineBolusState = getSalineBolusState(); + payload.txStopState = getCurrentTreatmentStopState(); + payload.bldPrimeState = getCurrentBloodPrimeState(); + payload.rinsebackState = getCurrentRinsebackState(); + payload.txStopState = getCurrentTreatmentRecircState(); + payload.txEndState = getCurrentTreatmentEndState(); + payload.heparinState = HEPARIN_STATE_OFF; // TODO - get Heparin state when implemented + + broadcastTreatmentState( payload ); + treatmentStateBroadcastTimerCtr = 0; + } } /*********************************************************************//** @@ -906,7 +1179,7 @@ // Compute minimum treatment duration U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); - U32 minTime = MAX( (elapseTime + 2), MIN_TREATMENT_TIME_MINUTES ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it's valid for next minute + U32 minTime = MAX( (elapseTime + 2), MIN_TREATMENT_TIME_MINUTES ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it is valid for next minute // Compute maximum treatment duration (from both UF and dialysate volume perspectives) U32 maxTimeRem = ( MAX_UF_VOLUME_ML - (U32)getUltrafiltrationVolumeCollected() ) / ( presUFRate > 0.0 ? (U32)presUFRate : 1 ); U32 maxTime1 = minTime + maxTimeRem; @@ -932,3 +1205,36 @@ treatmentParamsRangesBroadcastTimerCtr = 0; } } + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetTreatmentTimeRemainingOverride function overrides the + * treatment time remaining. + * @details Inputs: presTreatmentTimeSecs, currentTreatmentState + * @details Outputs: treatmentTimeMS + * @param value override treatment time remaining overridden to this (in sec) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTreatmentTimeRemainingOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( ( TRUE == isTestingActivated() ) && ( value < presTreatmentTimeSecs ) ) + { + if ( ( MODE_TREA == getCurrentOperationMode() ) && ( currentTreatmentState < TREATMENT_END_STATE ) ) + { + result = TRUE; + treatmentTimeMS = ( presTreatmentTimeSecs - value ) * MS_PER_SECOND; + } + } + + return result; +} + +/**@}*/