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; } /**@}*/