Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r95c81a7d81fa3e6534bcf2e35e1d9b1eba26e372 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 95c81a7d81fa3e6534bcf2e35e1d9b1eba26e372) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -29,6 +29,7 @@ #include "OperationModes.h" #include "Pressures.h" #include "StateTxBloodPrime.h" +#include "TreatmentEnd.h" #include "StateTxDialysis.h" #include "StateTxPaused.h" #include "StateTxRecirc.h" @@ -105,6 +106,8 @@ static U32 treatmentStartTimeStamp; ///< Treatment start timestamp for logging purpose. static U32 treatmentEndTimeStamp; ///< Treatment end timestamp for logging purpose. +static BOOL treatmentEndToRinsebackRequest; ///< Flag indicates treatment end sub-mode has requested transition to Rinseback. + // ********** private function prototypes ********** static void broadcastTreatmentSettingsRanges( void ); @@ -193,15 +196,10 @@ initBloodPrime(); initDialysis(); initTreatmentPaused(); -<<<<<<< HEAD -// initRinseback(); -// initTreatmentRecirc(); - initTreatmentEnd(); -======= + initRinseback(); initTreatmentRecirc(); -// initTreatmentEnd(); ->>>>>>> staging + initTreatmentEnd(); initFluidBolus(); // Started the treatment - set the start time in epoch @@ -525,7 +523,7 @@ resumeBlockedByAlarm = TRUE; } - // Check dialysate temperature during treatment mode (except end state where treatment is over, dialyzer is bypassed and temp is no longer an issue) +// Check dialysate temperature during treatment mode (except end state where treatment is over, dialyzer is bypassed and temp is no longer an issue) // if ( currentTreatmentState != TREATMENT_END_STATE ) // { // checkDialysateTemperature(); @@ -756,10 +754,16 @@ treatmentCompleted = TRUE; // sendLastTreatmentPeriodicData = TRUE; // treatmentEndTimeStamp = getRTCTimestamp(); - pauseDialysis(); - //requestNewOperationMode( MODE_STAN ); // TODO +// pauseDialysis(); + + /// CKOE + // stopDialysis(); transitionToTreatmentEnd(); + + //CKOE Do we need data to broadd cast here //SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_END_OF_TREATMENT_WARNING, presTreatmentTimeSecs ); + // Trigger the low-priority End of Treatment alarm + activateAlarmNoData( ALARM_ID_TD_END_OF_TREATMENT ); result = TREATMENT_END_STATE; } // Otherwise, execute state machine for treatment dialysis sub-mode @@ -932,39 +936,34 @@ * @details \b 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(); -// } -// // End treatment state does not allow resume -// -// // 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 ); -// } +// // 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 ) + { + //sendLastTreatmentPeriodicData = TRUE; TODO + requestNewOperationMode( MODE_POST ); + } + // End treatment state does not allow resume + // Execute treatment end sub-mode + execTreatmentEnd(); + if ( TRUE == treatmentEndToRinsebackRequest ) + { + transitionToRinseback(); + result = TREATMENT_RINSEBACK_STATE; + } return result; } - /*********************************************************************//** * @brief * The broadcastTreatmentTimeAndState function broadcasts treatment time and @@ -1027,7 +1026,7 @@ payload.txPausedState = getCurrentTreatmentPausedState(); payload.rinsebackState = getCurrentRinsebackState(); payload.txRecircState = getCurrentTreatmentRecircState(); - payload.txEndState = 0; // getCurrentTreatmentEndState(); + payload.txEndState = getCurrentTreatmentEndState(); payload.txFluidBolusState = getCurrentFluidBolusState(); payload.txHepState = 0; // broadcastData( MSG_ID_TD_TREATMENT_STATE_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)(&payload), sizeof( TREATMENT_STATE_DATA_T ) ); @@ -1213,7 +1212,7 @@ endTreatmentRequest = FALSE; rinsebackToRecircRequest = FALSE; bloodPrimeToDialysisRequest = FALSE; -// treatmentEndToRinsebackRequest = FALSE; // TODO: Declare & uncomment when end treat is implemented. + treatmentEndToRinsebackRequest = FALSE; recirculateToBloodPrimeRequest = FALSE; } @@ -1234,6 +1233,18 @@ /*********************************************************************//** * @brief + * The signalTreatmentEndToRinseback function signals that treatment end + * sub-mode wants to transition to the rinseback sub-mode. + * @details Inputs: none + * @details Outputs: treatmentEndToRinsebackRequest + * @return none + *************************************************************************/ +void signalTreatmentEndToRinseback( void ) +{ + treatmentEndToRinsebackRequest = TRUE; +} +/*********************************************************************//** + * @brief * The publishUltrafiltrationData function publishes the ultrafiltration data * at the set time interval. * @details \b Inputs: none Index: firmware/App/Modes/ModeTreatment.h =================================================================== diff -u -ra1f14a4e422f94b6bc25d1b91839761e7e1196d7 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision a1f14a4e422f94b6bc25d1b91839761e7e1196d7) +++ firmware/App/Modes/ModeTreatment.h (.../ModeTreatment.h) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -133,7 +133,9 @@ // MSG_ID_TD_PRESSURE_LIMITS_CHANGE_RESPONSE BOOL sendPressureLimitsChangeResponse( PRESSURE_LIMIT_CHANGE_RESPONSE_T *data ); +void signalTreatmentEndToRinseback( void ); + /**@}*/ #endif Index: firmware/App/Modes/StateTxDialysis.c =================================================================== diff -u -r95c81a7d81fa3e6534bcf2e35e1d9b1eba26e372 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision 95c81a7d81fa3e6534bcf2e35e1d9b1eba26e372) +++ firmware/App/Modes/StateTxDialysis.c (.../StateTxDialysis.c) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -248,7 +248,7 @@ // Make rate changes in real time if currently performing dialysis. if ( (TREATMENT_END_STATE == getTreatmentState() )) { - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); } } @@ -385,6 +385,25 @@ /*********************************************************************//** * @brief + * The stopDialysis function stops dialysis. This function will be called + * by Treatment Mode when an alarm occurs or the user pressed the stop button. + * Dialysis may be resumed later. + * @details Inputs: none + * @details Outputs: Blood and dialysate pumps stopped. Heparin pump stopped. + * @return none + *************************************************************************/ +void stopDialysis( void ) +{ + // Stop pumps + signalBloodPumpHardStop(); + stopSyringePump(); + + // CKOE whta command used for trimmer heater to stop + // Tell DG to stop heating dialysate + //cmdStopDGTrimmerHeater(); +} +/*********************************************************************//** + * @brief * The execDialysis function executes the Dialysis sub-mode state machine. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if state is invalid * @details \b Message \b Sent: TD_EVENT_SUB_STATE_CHANGE when state changes Index: firmware/App/Modes/TreatmentEnd.c =================================================================== diff -u -r9d80274d4f31715890d519f5f9fbe445c4614046 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Modes/TreatmentEnd.c (.../TreatmentEnd.c) (revision 9d80274d4f31715890d519f5f9fbe445c4614046) +++ firmware/App/Modes/TreatmentEnd.c (.../TreatmentEnd.c) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -5,7 +5,7 @@ * Author: fw */ #include "DDInterface.h" - +#include "string.h" #include "AirTrap.h" #include "BloodFlow.h" #include "ModeTreatment.h" @@ -22,200 +22,184 @@ #include "Bubbles.h" #include "Switches.h" #include "Common.h" +#include "Messaging.h" +#include "TDDefs.h" +#include "StateTxPaused.h" /** * @addtogroup TreatmentEnd * @{ */ // ********** private definitions *********** -/// Placeholder End of Treatment blood pump flow rate (mL/min). -// TODO CONFIRM #6: reuse TREATMENT_PARAM_BLOOD_FLOW via getTreatmentParameterU32(), or a -// dedicated End-of-Treatment rate param — not yet located in this codebase. Using a local -// placeholder constant here in the meantime so the file compiles. -#define TX_END_BP_FLOW_RATE_ML_MIN 150 - -/// Interval at which treatment end progress is to be published to UI. -#define TREATMENT_END_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) - /// Time before escalating the low-priority End of Treatment alarm to high priority. static const U32 TX_END_ESCALATION_TIMEOUT_MS = ( ( 10 * 60 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ); -typedef enum ENDTREATMENT_STATES_T -{ - TX_END_WAIT_FOR_RINSEBACK_STATE, - TX_END_FLUID_BOLUS_STATE, - TX_END_PAUSED_STATE, - NO_OF_TX_END_STATES -} ENDTREATMENT_STATES_T; - // ********** private data ********** -static ENDTREATMENT_STATES_T treatmentEndState; ///< Current substate of Treatment End. +static TREATMENT_END_STATE_T treatmentEndState; ///< Current substate of Treatment End. +static U32 txEndTimerCtr; ///< Timer counter (GP task intervals) tracking time in Wait for Rinseback, drives low->high alarm escalation. +static U32 bloodSittingTimerCtr; ///< blood sitting timer counter +static BOOL txEndAlarmRinsebackRequested; ///< User requested rinseback via alarm action / UI message. +static BOOL txEndBolusRequested; ///< User requested a fluid bolus while in End of Treatment. +static BOOL txEndEscalated; ///< Tracks whether the high-priority alarm has already been raised, to avoid re-triggering every cycle. +static TREATMENT_END_STATE_T txEndPriorStateBeforeBolus; -static U32 txEndTimerCtr; ///< Timer counter (GP task intervals) tracking time in Wait for Rinseback, drives low->high alarm escalation. -static U32 treatmentEndPublishTimerCtr; ///< Timer counter for UI publish interval. - -static BOOL txEndAlarmRinsebackRequested; ///< User requested rinseback via alarm action / UI message. -static BOOL txEndAlarmEndTreatmentOnlyRequested; ///< User requested "End Treatment Only" via alarm action / UI message. -static BOOL txEndBolusRequested; ///< User requested a fluid bolus while in End of Treatment. -static BOOL txEndEscalated; ///< Tracks whether the high-priority alarm has already been raised, to avoid re-triggering every cycle. -static ENDTREATMENT_STATES_T txEndPriorStateBeforeBolus; - // ********** private function prototypes ********** -static void setupForTxEndWait4RinsebackState( void ); -static void setupForTxEndPausedState( void ); +static TREATMENT_END_STATE_T handleTxEndWaitForRinsebackState( void ); +static TREATMENT_END_STATE_T handleTxEndFluidBolusState( void ); +static TREATMENT_END_STATE_T handleTxEndPausedState( void ); static void resetTreatmentEndFlags( void ); -static void publishTreatmentEndData( void ); +static void setupForTreatmentEndSubState( TREATMENT_END_STATE_T newState ); +static void handleTreatmentEndBloodSittingTimer( void ); +static BOOL handleTxEndRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); -static ENDTREATMENT_STATES_T handleTxEndWait4RinsebackState( void ); -static ENDTREATMENT_STATES_T handleTxEndFluidBolusState( void ); -static ENDTREATMENT_STATES_T handleTxEndPausedState( void ); - /*********************************************************************//** * @brief * The initTreatmentEnd function initializes the Treatment End sub-mode. * @details \b Inputs: none - * @details \b Outputs: treatmentEndState, txEndTimerCtr, treatmentEndPublishTimerCtr, - * txEndEscalated, txEndAlarmRinsebackRequested, txEndAlarmEndTreatmentOnlyRequested, - * txEndBolusRequested + * @details \b Outputs: treatmentEndState, txEndTimerCtr, txEndEscalated, + * bloodSittingTimerCtr * @return none *************************************************************************/ void initTreatmentEnd( void ) { - treatmentEndState = TX_END_WAIT_FOR_RINSEBACK_STATE; + treatmentEndState = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; txEndTimerCtr = 0; - treatmentEndPublishTimerCtr = 0; txEndEscalated = FALSE; + bloodSittingTimerCtr = 0; resetTreatmentEndFlags(); } /*********************************************************************//** * @brief - * The transitionToTreatmentEnd function prepares for transition to treatment - * end sub-mode: stops heparin delivery, bypasses the dialyzer, branches DD - * dialysate generation based on priming fluid type, sets up Wait for Rinseback - * actuator states, and triggers the low-priority End of Treatment alarm. + * The transitionToTreatmentEnd function prepares for transition to + * Treatment End sub-mode. * @details \b Inputs: treatmentEndState - * @details \b Outputs: treatmentEndState (via initTreatmentEnd), DD dialysate - * delivery command set (via cmdBypassDialyzer/cmdStopGenerateDialysate/ - * cmdChangeQd/cmdSubstitutionRate — owned by DDInterface.c, not local to this - * module) + * @details \b Outputs: none * @return none *************************************************************************/ void transitionToTreatmentEnd( void ) { initTreatmentEnd(); cmdBypassDialyzer( TRUE ); stopSyringePump(); - // Set user alarm recovery actions allowed in this state + setAlarmUserActionEnabled( ALARM_USER_ACTION_RESUME, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_RINSEBACK, TRUE ); setAlarmUserActionEnabled( ALARM_USER_ACTION_END_TREATMENT, TRUE ); - // Require BP door to be closed during this state - doorClosedRequired( TRUE ); if ( FLUID_TYPE_SALINE == getFluidType() ) { - cmdStopGenerateDialysate(); // saline branch — DD stops + cmdStopGenerateDialysate(); } else { - // Direct DD to bypass dialysate and set substitution to universal flow rate - cmdChangeQd( (U32)getTreatmentParameterU32( TREATMENT_PARAM_RINSEBACK_FLOW_RATE ) ); // substitution branch — DD keeps running, Qdt=Qb + ///CKOE by passing the value manually suppose give 100 for substitution and check once + //CKOE write a print for get function + cmdSubstitutionRate((F32) getSysConfigTreatmentParameterU32DefaultValue( TREATMENT_PARAM_RINSEBACK_FLOW_RATE )); } - // Substitution flow Off — confirmed real call (DDInterface.c). Modality scope (all vs - // HDF-only) still needs confirmation before this is unconditional. - // TODO CONFIRM #10: modality scope check before calling. - cmdSubstitutionRate( 0.0F ); - setCurrentSubState( (U32)treatmentEndState ); + setupForTreatmentEndSubState(TREATMENT_END_WAIT_FOR_RINSEBACK_STATE); - setupForTxEndWait4RinsebackState(); - - // Venous bubble detection stays enabled always — confirmed real call, same pattern - // used in ModeTreatment.c's transitionToTreatmentMode(). -#ifndef TEST_UI_ONLY setVenousBubbleDetectionEnabled( H18_BBLD, TRUE ); -#endif - // Trigger the low-priority End of Treatment alarm — this IS the notification (no UI dialog). - activateAlarmNoData( ALARM_ID_TD_END_OF_TREATMENT ); +// // Trigger the low-priority End of Treatment alarm +// activateAlarmNoData( ALARM_ID_TD_END_OF_TREATMENT ); } /*********************************************************************//** * @brief - * Sets actuators for Wait for Rinseback substate entry: requires the door - * closed, opens the arterial and venous pinch valves, commands the blood - * pump to the End of Treatment flow rate, and continues air trap level control. - * @details \b Inputs: none - * @details \b Outputs: door-closed-required state, H1_VALV/H19_VALV position, - * blood pump target rate, air trap controller start request + * Tracks how long blood has been sitting (not recirculating) while in + * Treatment End Paused substate, raising warning/max-timeout alarms as + * thresholds are exceeded. + * @details \b Alarm: ALARM_ID_TD_BLOOD_SITTING_WARNING / + * ALARM_ID_TD_BLOOD_SITTING_TOO_LONG as thresholds are exceeded. + * @details \b Inputs: bloodSittingTimerCtr + * @details \b Outputs: bloodSittingTimerCtr * @return none *************************************************************************/ -static void setupForTxEndWait4RinsebackState( void ) +static void handleTreatmentEndBloodSittingTimer( void ) { - // Confirmed real calls/signatures from StatePreTxRecirculate.c. - doorClosedRequired( TRUE ); + // Ensure we do not sit in stopped state for too long (if blood in line) + bloodSittingTimerCtr++; - setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); - setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); - - // TODO CONFIRM #6: TX_END_BP_FLOW_RATE_ML_MIN is a placeholder value (150) — confirm - // whether End of Treatment reuses TREATMENT_PARAM_BLOOD_FLOW directly (no rate change) - // or commands a dedicated slower End-of-Treatment rate, per PRS-810 ("keep blood flowhb - // rate at the set rate"). If PRS-810 is authoritative, replace with: - // getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) - setBloodPumpTargetFlowRate( TX_END_BP_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - - // Continue air trap level control — confirmed real call (AirTrap.c). Air trap - // controller runs continuously once started; this just (re)requests control if - // not already controlling. No stop/start toggling needed beyond entry/pause. - startAirTrapControl(); + if ( FALSE == doesAlarmStatusIndicateEndTxOnly() ) // Alarms appropriate only if we are not already at an alarm stop, end Tx only + { + if ( bloodSittingTimerCtr > WARN_TIME_BLOOD_SITTING ) + { + activateAlarmNoData( ALARM_ID_TD_BLOOD_SITTING_WARNING ); + } + if ( bloodSittingTimerCtr > MAX_TIME_BLOOD_SITTING ) + { + // Activate the alarm + activateAlarmNoData( ALARM_ID_TD_BLOOD_SITTING_TOO_LONG ); + } + } } - /*********************************************************************//** * @brief - * Sets actuators for Paused substate entry (alarm requires pump stop): - * stops the blood pump and stops air trap level control. + * Applies actuator/config setup for the Treatment End substate being entered. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if newState is invalid. * @details \b Inputs: none - * @details \b Outputs: blood pump state (via signalBloodPumpHardStop), air trap - * controller stop request + * @details \b Outputs: bloodSittingTimerCtr + * @param newState substate being entered * @return none *************************************************************************/ -static void setupForTxEndPausedState( void ) + +static void setupForTreatmentEndSubState( TREATMENT_END_STATE_T newState ) { - // Confirmed real call (StatePreTxRecirculate.c: handlePreTxRecirculateState() calls - // this identically when doesAlarmStatusIndicateStop() is TRUE). - signalBloodPumpHardStop(); + switch ( newState ) + { + case TREATMENT_END_WAIT_FOR_RINSEBACK_STATE: + doorClosedRequired( TRUE ); + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), + MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + startAirTrapControl(); + break; - // Stop air trap level control — confirmed real call (AirTrap.c). Note: - // endAirTrapControl() also internally calls signalLowVenousPressureCheck() to - // keep venous pressure checking active even after auto air trap control ends. - endAirTrapControl(); + case TREATMENT_END_PAUSED_STATE: + bloodSittingTimerCtr = 0; + signalBloodPumpHardStop(); + endAirTrapControl(); + setValvePosition( H1_VALV, VALVE_POSITION_C_CLOSE ); + setValvePosition( H19_VALV, VALVE_POSITION_C_CLOSE ); + break; - // Confirmed: doorClosedRequired() stays TRUE for every Treatment End substate — - // no release call needed here. Set once at Wait for Rinseback entry and left as-is. + case TREATMENT_END_FLUID_BOLUS_STATE: + doorClosedRequired( TRUE ); + setValvePosition( H1_VALV, VALVE_POSITION_B_OPEN ); + setValvePosition( H19_VALV, VALVE_POSITION_B_OPEN ); + setBloodPumpTargetFlowRate( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ), + MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + startAirTrapControl(); + signalStartFluidBolus( getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ) ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_END_INVALID_STATE, (U32)newState ); + break; + } } + /*********************************************************************//** * @brief * The execTreatmentEnd function executes the Treatment End sub-mode * state machine. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if the current Treatment End - * substate is invalid. - * @details \b Inputs: treatmentEndState, txEndTimerCtr, txEndEscalated, - * txEndAlarmRinsebackRequested, txEndAlarmEndTreatmentOnlyRequested, - * txEndBolusRequested - * @details \b Outputs: treatmentEndState, txEndTimerCtr, txEndEscalated, - * treatmentEndPublishTimerCtr, (flags reset via resetTreatmentEndFlags) + * substate is invalid; ALARM_ID_TD_END_OF_TREATMENT_TIMEOUT on escalation timeout. + * @details \b Inputs: treatmentEndState, txEndTimerCtr, txEndEscalated + * @details \b Outputs: treatmentEndState, txEndTimerCtr, txEndEscalated * @return none *************************************************************************/ void execTreatmentEnd( void ) { - ENDTREATMENT_STATES_T priorSubState = treatmentEndState; + TREATMENT_END_STATE_T priorSubState = treatmentEndState; // Escalate low -> high alarm after confirmed 10-minute timeout, once only. if ( ( ++txEndTimerCtr > TX_END_ESCALATION_TIMEOUT_MS ) && ( FALSE == txEndEscalated ) ) @@ -226,74 +210,60 @@ switch ( treatmentEndState ) { - case TX_END_WAIT_FOR_RINSEBACK_STATE: - treatmentEndState = handleTxEndWait4RinsebackState(); + case TREATMENT_END_WAIT_FOR_RINSEBACK_STATE: + treatmentEndState = handleTxEndWaitForRinsebackState(); break; - case TX_END_FLUID_BOLUS_STATE: + case TREATMENT_END_FLUID_BOLUS_STATE: treatmentEndState = handleTxEndFluidBolusState(); break; - case TX_END_PAUSED_STATE: + case TREATMENT_END_PAUSED_STATE: + handleTreatmentEndBloodSittingTimer(); treatmentEndState = handleTxEndPausedState(); break; default: - // Confirmed real macro/pattern (StatePreTxRecirculate.c: identical structure - // with SW_FAULT_ID_PRE_TX_RECIRC_INVALID_STATE). Fault ID name below follows - // the same naming convention but is not itself a confirmed enum value — - // confirm SW_FAULT_ID_TREATMENT_END_INVALID_STATE exists before building. SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TREATMENT_END_INVALID_STATE, (U32)treatmentEndState ); break; } if ( priorSubState != treatmentEndState ) { - // Confirmed real pattern (StatePreTxRecirculate.c: execPreTxRecirculate()). + setupForTreatmentEndSubState( treatmentEndState ); setCurrentSubState( (U32)treatmentEndState ); SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_SUB_STATE_CHANGE, priorSubState, treatmentEndState ); } - - publishTreatmentEndData(); - // Flags should be handled by now — reset in case not handled by current state. resetTreatmentEndFlags(); } /*********************************************************************//** * @brief - * Wait for Rinseback substate — all three user options available immediately, - * no escalation-gating. Also handles transition to Paused if an alarm - * requires blood pump stop. - * @details \b Inputs: txEndAlarmRinsebackRequested, txEndAlarmEndTreatmentOnlyRequested, - * txEndBolusRequested - * @details \b Outputs: none (transitions reported via return value) + * Wait for Rinseback substate — rinseback and fluid bolus requests are + * available immediately, no escalation-gating. Also handles transition + * to Paused if an alarm requires blood pump stop. + * @details \b Inputs: txEndAlarmRinsebackRequested, txEndBolusRequested + * @details \b Outputs: none * @return next Treatment End substate *************************************************************************/ -static ENDTREATMENT_STATES_T handleTxEndWait4RinsebackState( void ) + +static TREATMENT_END_STATE_T handleTxEndWaitForRinsebackState( void ) { - ENDTREATMENT_STATES_T result = TX_END_WAIT_FOR_RINSEBACK_STATE; + TREATMENT_END_STATE_T result = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; - // Confirmed real call (StatePreTxRecirculate.c: handlePreTxRecirculateState()). if ( TRUE == doesAlarmStatusIndicateStop() ) { - setupForTxEndPausedState(); - result = TX_END_PAUSED_STATE; + result = TREATMENT_END_PAUSED_STATE; } else if ( TRUE == txEndAlarmRinsebackRequested ) { - // Set via signalTreatmentEndRinsebackRequest(), called by the UI message handler - // when the Rinseback / "Return Blood & End Treatment" option is selected. - // PENDING: you're checking whether an existing enable/gating flag controls this - // path before wiring the real call — hold here until confirmed. Once resolved, - // this branch calls the real rinseback transition function (name still TBD). + signalTreatmentEndToRinseback(); } - else if ( TRUE == txEndBolusRequested ) { - txEndPriorStateBeforeBolus = TX_END_WAIT_FOR_RINSEBACK_STATE; - result = TX_END_FLUID_BOLUS_STATE; - signalStartFluidBolus( TX_END_BP_FLOW_RATE_ML_MIN ); + txEndPriorStateBeforeBolus = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; + result = TREATMENT_END_FLUID_BOLUS_STATE; } return result; @@ -303,24 +273,23 @@ * @brief * Fluid Bolus substate — delegates to existing fluid bolus service. * @details \b Inputs: none - * @details \b Outputs: none (transitions reported via return value) + * @details \b Outputs: none * @return next Treatment End substate *************************************************************************/ -static ENDTREATMENT_STATES_T handleTxEndFluidBolusState( void ) + +static TREATMENT_END_STATE_T handleTxEndFluidBolusState( void ) { - ENDTREATMENT_STATES_T result = TX_END_FLUID_BOLUS_STATE; + TREATMENT_END_STATE_T result = TREATMENT_END_FLUID_BOLUS_STATE; if ( FALSE == isFluidBolusActive() ) { - result = txEndPriorStateBeforeBolus; - - if ( TX_END_PAUSED_STATE == txEndPriorStateBeforeBolus ) + if ( TRUE == doesAlarmStatusIndicateStop() ) { - setupForTxEndPausedState(); + result= TREATMENT_END_PAUSED_STATE; } else { - setupForTxEndWait4RinsebackState(); + result= TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; } } @@ -330,113 +299,178 @@ /*********************************************************************//** * @brief * Paused substate — entered only if an alarm requires blood pump stop. - * Offers Rinseback and End Treatment Only directly, same as Wait for Rinseback. - * @details \b Inputs: txEndAlarmRinsebackRequested, txEndAlarmEndTreatmentOnlyRequested - * @details \b Outputs: none (transitions reported via return value) + * @details \b Inputs: none + * @details \b Outputs: none * @return next Treatment End substate *************************************************************************/ -static ENDTREATMENT_STATES_T handleTxEndPausedState( void ) + +static TREATMENT_END_STATE_T handleTxEndPausedState( void ) { - ENDTREATMENT_STATES_T result = TX_END_PAUSED_STATE; + TREATMENT_END_STATE_T result = TREATMENT_END_PAUSED_STATE; - if ( TRUE == txEndAlarmRinsebackRequested ) - { - // PENDING: same rinseback call as Wait for Rinseback. - } - else if ( TRUE == txEndAlarmEndTreatmentOnlyRequested ) - { - // PENDING: same operation-mode-change call as Wait for Rinseback. - } - else if ( TRUE == txEndBolusRequested ) - { - txEndPriorStateBeforeBolus = TX_END_PAUSED_STATE; - result = TX_END_FLUID_BOLUS_STATE; - signalStartFluidBolus( TX_END_BP_FLOW_RATE_ML_MIN ); - } - else if ( FALSE == isBloodRecircBlocked() ) - { - setupForTxEndWait4RinsebackState(); - result = TX_END_WAIT_FOR_RINSEBACK_STATE; - } + if ( FALSE == isBloodRecircBlocked() ) + { + result = TREATMENT_END_WAIT_FOR_RINSEBACK_STATE; + } +// else if ( TRUE == txEndAlarmRinsebackRequested ) +// { +// signalTreatmentEndToRinseback(); +// } +// +// else if ( TRUE == txEndBolusRequested ) +// { +// bloodSittingTimerCtr = 0; +// txEndPriorStateBeforeBolus = TREATMENT_END_PAUSED_STATE; +// result = TREATMENT_END_FLUID_BOLUS_STATE; +// } + return result; } /*********************************************************************//** * @brief * Resets all Treatment End request flags. * @details \b Inputs: none - * @details \b Outputs: txEndAlarmRinsebackRequested, txEndAlarmEndTreatmentOnlyRequested, - * txEndBolusRequested + * @details \b Outputs: txEndAlarmRinsebackRequested, txEndBolusRequested * @return none *************************************************************************/ + static void resetTreatmentEndFlags( void ) { txEndAlarmRinsebackRequested = FALSE; - txEndAlarmEndTreatmentOnlyRequested = FALSE; txEndBolusRequested = FALSE; } /*********************************************************************//** * @brief - * Publishes Treatment End progress to UI at set interval. - * @details \b Inputs: treatmentEndPublishTimerCtr - * @details \b Outputs: treatmentEndPublishTimerCtr - * @return none + * The signalTreatmentEndFluidBolusRequest function signals a user request + * for a fluid bolus while in Treatment End. + * @details \b Inputs: treatmentEndState + * @details \b Outputs: txEndBolusRequested + * @return TRUE if request accepted, FALSE if rejected *************************************************************************/ -static void publishTreatmentEndData( void ) +BOOL signalTreatmentEndFluidBolusRequest( void ) { - if ( ++treatmentEndPublishTimerCtr >= TREATMENT_END_DATA_PUBLISH_INTERVAL ) + BOOL result = FALSE; +// TODO REMOVE PAUSED STATE IF W CANT ABLE TO MOVE TO RINSEBACK UPON ANY ALARMS + if ( ( TREATMENT_END_WAIT_FOR_RINSEBACK_STATE == treatmentEndState ) || + ( TREATMENT_END_PAUSED_STATE == treatmentEndState ) ) { - treatmentEndPublishTimerCtr = 0; - // TODO: confirm payload contents/message ID for Treatment End status broadcast to UI. - // You're updating this yourself once decided. + txEndBolusRequested = TRUE; + result = TRUE; } + + return result; } +/*********************************************************************//** + * @brief + * The getCurrentTreatmentEndState function returns the current substate of + * the Treatment End sub-mode. + * @details \b Inputs: treatmentEndState + * @details \b Outputs: none + * @return current Treatment End substate + *************************************************************************/ +U32 getCurrentTreatmentEndState( void ) +{ + return (U32)treatmentEndState; +} + /*********************************************************************//** * @brief - * Signal functions called externally (e.g. from message handlers, or from - * ModeTreatment.c's handleTreatmentEndState() translating alarm action flags) - * when the corresponding user action / confirmation is received. Rinseback - * and End Treatment Only are both expected to arrive as UI messages via the - * firmware message handler, not as locally-detected conditions. + * The signalTreatmentEndAlarmRinsebackUserAction function is called by + * ModeTreatment.c when the user has requested rinseback via an alarm + * recovery action while in Treatment End. * @details \b Inputs: none - * @details \b Outputs: txEndAlarmRinsebackRequested / txEndAlarmEndTreatmentOnlyRequested / - * txEndBolusRequested (one each, respectively) + * @details \b Outputs: txEndAlarmRinsebackRequested * @return none *************************************************************************/ -void signalTreatmentEndRinsebackRequest( void ) +void signalTreatmentEndAlarmRinsebackUserAction( void ) { txEndAlarmRinsebackRequested = TRUE; } +/*********************************************************************//** + * @brief + * The handleTxEndRinsebackUserAction function handles an end treatment + * rinseback user action request. + * @details \b Inputs: treatmentEndState + * @details \b Outputs: txEndAlarmRinsebackRequested + * @param rejReason Code indicating reason for rejection + * @return TRUE if user action accepted, FALSE if not + *************************************************************************/ -BOOL signalTreatmentEndFluidBolusRequest( void ) +static BOOL handleTxEndRinsebackUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ) { BOOL result = FALSE; - if ( ( TX_END_WAIT_FOR_RINSEBACK_STATE == treatmentEndState ) || - ( TX_END_PAUSED_STATE == treatmentEndState ) ) + if ( TREATMENT_END_WAIT_FOR_RINSEBACK_STATE == treatmentEndState ) { - txEndBolusRequested = TRUE; result = TRUE; + txEndAlarmRinsebackRequested = TRUE; } + else + { + *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; + } return result; } + /*********************************************************************//** * @brief - * The getCurrentTreatmentEndState function returns the current substate of - * the Treatment End sub-mode. Referenced by TreatmentEnd.h and expected by - * ModeTreatment.c's broadcastTreatmentTimeAndState() (payload.txEndState). - * @details \b Inputs: treatmentEndState + * The handleTreatmentEndUserAction function handles a UI Treatment End + * command request message. + * @details \b Inputs: none * @details \b Outputs: none - * @return current Treatment End substate + * @param message Incoming UI message containing the requested action. + * @return TRUE if request is accepted, FALSE if rejected. *************************************************************************/ -U32 getCurrentTreatmentEndState( void ) + +BOOL handleTreatmentEndUserAction( MESSAGE_T *message ) { - return (U32)treatmentEndState; + BOOL result = FALSE; + U32 cmd = 0; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; + UI_RESPONSE_PAYLOAD_T response; + + if ( sizeof(U32) == message->hdr.payloadLen ) + { + memcpy( &cmd, message->payload, sizeof(U32) ); + + // Reject if any alarm active — user must clear alarm first. + if ( FALSE == isAnyAlarmActive() ) + { + switch ( (REQUESTED_TREATMENT_END_USER_ACTIONS_T)cmd ) + { + case REQUESTED_USER_ACTION_TX_END_RINSEBACK_START: + result = handleTxEndRinsebackUserAction( &rejReason ); + break; + + default: + rejReason = REQUEST_REJECT_REASON_INVALID_COMMAND; + break; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_ALARM_IS_ACTIVE; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + response.accepted = result; + response.rejectionReason = rejReason; + sendMessage( MSG_ID_TD_END_TREATMENT_RESPONSE, + COMM_BUFFER_OUT_CAN_TD_2_UI, + (U08*)&response, + sizeof( UI_RESPONSE_PAYLOAD_T ) ); + + return result; } /**@}*/ Index: firmware/App/Modes/TreatmentEnd.h =================================================================== diff -u -r9d80274d4f31715890d519f5f9fbe445c4614046 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Modes/TreatmentEnd.h (.../TreatmentEnd.h) (revision 9d80274d4f31715890d519f5f9fbe445c4614046) +++ firmware/App/Modes/TreatmentEnd.h (.../TreatmentEnd.h) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -37,9 +37,10 @@ void transitionToTreatmentEnd( void ); void execTreatmentEnd( void ); U32 getCurrentTreatmentEndState( void ); -void signalTreatmentEndRinsebackRequest( void ); void signalTreatmentEndOnlyRequest( void ); BOOL signalTreatmentEndFluidBolusRequest( void ); +BOOL handleTreatmentEndUserAction( MESSAGE_T *message ); +void signalTreatmentEndAlarmRinsebackUserAction( void ); /**@}*/ Index: firmware/App/Services/Messaging.c =================================================================== diff -u -ra1f14a4e422f94b6bc25d1b91839761e7e1196d7 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision a1f14a4e422f94b6bc25d1b91839761e7e1196d7) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -27,6 +27,7 @@ #include "Compatible.h" #include "CpldInterface.h" #include "DDInterface.h" +#include "TreatmentEnd.h" #include "Ejector.h" #include "FluidBolus.h" #include "FpgaTD.h" @@ -233,6 +234,7 @@ { MSG_ID_TD_GET_ALARM_PROPERTIES_REQUEST, &testGetAlarmPropertiesRequest }, { MSG_ID_TD_RINSEBACK_VOLUME_OVERRIDE, &testRinsebackVolumeOverride }, { MSG_ID_TD_RINSEBACK_PUBLISH_INTERVAL_OVERRIDE_REQUEST, &testRinsebackPublishIntervalOverride }, + { MSG_ID_TD_END_TREATMENT_REQUEST, &handleTreatmentEndUserAction }, }; /// Number of entries in the message handling function lookup table. Index: firmware/App/Services/Messaging.h =================================================================== diff -u -ra1f14a4e422f94b6bc25d1b91839761e7e1196d7 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Services/Messaging.h (.../Messaging.h) (revision a1f14a4e422f94b6bc25d1b91839761e7e1196d7) +++ firmware/App/Services/Messaging.h (.../Messaging.h) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -34,6 +34,7 @@ // ********** public definitions ********** +#define SIMULATION_TEST_RINSEBACK TRUE #define ACK_REQUIRED TRUE ///< Macro for functions that want to know if an outgoing message requires acknowledgement from receiver. #define ACK_NOT_REQUIRED FALSE ///< Macro for functions that want to know if an outgoing message requires acknowledgement from receiver. Index: firmware/App/Services/TxParams.c =================================================================== diff -u -ra1f14a4e422f94b6bc25d1b91839761e7e1196d7 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/App/Services/TxParams.c (.../TxParams.c) (revision a1f14a4e422f94b6bc25d1b91839761e7e1196d7) +++ firmware/App/Services/TxParams.c (.../TxParams.c) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -114,7 +114,12 @@ { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=2}, {.uInt=0} }, // TREATMENT_PARAM_HDF_DILUTION { CRITICAL_DATA_TYPE_U32, {.uInt=50}, {.uInt=500}, {.uInt=50} }, // TREATMENT_PARAM_BLOOD_FLOW { CRITICAL_DATA_TYPE_U32, {.uInt=50}, {.uInt=600}, {.uInt=50} }, // TREATMENT_PARAM_DIALYSATE_FLOW + +#if SIMULATION_TEST_RINSEBACK + { CRITICAL_DATA_TYPE_U32, {.uInt=5}, {.uInt=480}, {.uInt=60} }, // TREATMENT_PARAM_TREATMENT_DURATION +#else { CRITICAL_DATA_TYPE_U32, {.uInt=60}, {.uInt=480}, {.uInt=60} }, // TREATMENT_PARAM_TREATMENT_DURATION +#endif { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=480}, {.uInt=0} }, // TREATMENT_PARAM_HEPARIN_DELIVERY_DURATION { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=0}, {.uInt=0} }, // TREATMENT_PARAM_HEPARIN_TYPE { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=5}, {.uInt=0} }, // TREATMENT_PARAM_DRY_BICARB_CART_SIZE @@ -2215,7 +2220,14 @@ if ( TRUE == isTreatmentParamInRange( TREATMENT_PARAM_BLOOD_FLOW, requestedValue ) ) { setTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW, request.flowRate ); - setDialysisBloodPumpFlowRate( request.flowRate ); + if(TREATMENT_DIALYSIS_STATE == getTreatmentState() ) + { + setDialysisBloodPumpFlowRate( request.flowRate ); + } + else if( TREATMENT_END_STATE ==getTreatmentState() ) + { + setDialysisBloodPumpFlowRateEndTx( request.flowRate ); + } response.accepted = TRUE; response.rejectionReason = REQUEST_REJECT_REASON_NONE; Index: firmware/targetConfigs/RM46L852.ccxml =================================================================== diff -u -r73d8423edc56daed591bc0b3f7baee5540aea423 -r28d515e25f5f3b2c0bbff55abd68641927b6659c --- firmware/targetConfigs/RM46L852.ccxml (.../RM46L852.ccxml) (revision 73d8423edc56daed591bc0b3f7baee5540aea423) +++ firmware/targetConfigs/RM46L852.ccxml (.../RM46L852.ccxml) (revision 28d515e25f5f3b2c0bbff55abd68641927b6659c) @@ -6,6 +6,11 @@ + + + + +