Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r9f5e68247ff2f5214e8828a1b8152ea16941fe39 -r4b358e1af8512dd9a0e948ef7c534b6af393b611 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 9f5e68247ff2f5214e8828a1b8152ea16941fe39) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 4b358e1af8512dd9a0e948ef7c534b6af393b611) @@ -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,92 @@ /*********************************************************************//** * @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 getTreatmentTimeRemainingSecs function determines the number of seconds + * remaining in the treatment. + * @details Inputs: presTreatmentTimeSecs, treatmentTimeMS + * @details Outputs: none + * @return The number of seconds remaining in the treatment. + *************************************************************************/ +U32 getTreatmentTimeRemainingSecs( void ) +{ + U32 result = CALC_TREAT_TIME_REMAINING_IN_SECS(); return 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; +} + +/*********************************************************************//** + * @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,52 +311,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; - - 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: @@ -250,6 +338,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 @@ -271,6 +424,10 @@ currentTreatmentState = handleTreatmentStartState(); break; + case TREATMENT_BLOOD_PRIME_STATE: + currentTreatmentState = handleTreatmentBloodPrimeState(); + break; + case TREATMENT_DIALYSIS_STATE: currentTreatmentState = handleTreatmentDialysisState(); break; @@ -280,34 +437,32 @@ break; case TREATMENT_RINSEBACK_STATE: - // TODO - implement + currentTreatmentState = handleTreatmentRinsebackState(); break; case TREATMENT_RECIRC_STATE: - // TODO - implement + currentTreatmentState = handleTreatmentRecircState(); 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; @@ -316,14 +471,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; @@ -335,15 +491,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 @@ -367,29 +559,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; } @@ -406,39 +594,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 @@ -454,14 +751,14 @@ // 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; U32 dialVolume = presDialysateFlowRate * treatmentTime; // In mL // Always adjust UF volume to accommodate treatment time change (not UF rate) - uFVolume = ( (F32)( treatmentTime - CALC_ELAPSED_TREAT_TIME_IN_MIN() ) * presUFRate ) + getUltrafiltrationVolumeCollected(); + uFVolume = ( (F32)( treatmentTime - CALC_ELAPSED_TREAT_TIME_IN_MIN() ) * presUFRate ) + getUltrafiltrationReferenceVolume(); if ( ( treatmentTime <= MAX_TREATMENT_TIME_MINUTES ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) && ( uFVolume <= MAX_UF_VOLUME_ML ) ) @@ -494,7 +791,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; } @@ -541,7 +838,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 ) ) { @@ -600,7 +897,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; } @@ -844,25 +1141,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 = getHeparinState(); + + broadcastTreatmentState( payload ); + treatmentStateBroadcastTimerCtr = 0; + } } /*********************************************************************//** @@ -884,12 +1196,12 @@ 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 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 maxTimeRem = ( MAX_UF_VOLUME_ML - (U32)getUltrafiltrationReferenceVolume() ) / ( presUFRate > 0.0 ? (U32)presUFRate : 1 ); U32 maxTime1 = minTime + maxTimeRem; U32 maxTime2 = MAX_DIALYSATE_VOLUME_ML / presDialysateFlowRate; U32 maxTime = MAX( maxTime1, maxTime2 ); // Compute minimum UF volume - F32 minUFVol = getUltrafiltrationVolumeCollected() + presUFRate; + F32 minUFVol = getUltrafiltrationReferenceVolume() + presUFRate; // Compute maximum UF volume (considering from adjustment of UF rate and time perspectives) F32 maxUFVol1 = minUFVol + ( (F32)( presTime - elapseTime ) * MAX_UF_RATE_ML_MIN ); F32 maxUFVol2 = ( presUFRate > 0.0 ? minUFVol + ( (F32)( MAX_TREATMENT_TIME_MINUTES - elapseTime - 1 ) * presUFRate ) : minUFVol ); @@ -908,3 +1220,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; +} + +/**@}*/