/************************************************************************** * * Copyright (c) 2024-2025 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file SpentChamberFill.c * * @author (last) Vinayakam Mani * @date (last) 20-Aug-2025 * * @author (original) Vinayakam Mani * @date (original) 20-Aug-2025 * ***************************************************************************/ #include "BalancingChamber.h" #include "Conductivity.h" #include "ConcentratePumps.h" #include "DialysatePumps.h" #include "FpgaDD.h" #include "Heaters.h" #include "ModeGenDialysate.h" #include "Messaging.h" #include "OperationModes.h" #include "Pressure.h" #include "SpentChamberFill.h" #include "TaskGeneral.h" #include "Temperature.h" #include "TestSupport.h" #include "Valves.h" /** * @addtogroup SpentChamberFill * @{ */ // ********** private definitions ********** #define SPENT_CHAMBER_FILL_DATA_PUBLISH_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the balancing chamber data published. // ********** private data ********** static SPENT_CHAMBER_FILL_EXEC_STATE_T spentChamberFillExecState; ///< Current spent chamber fill executive state. static U32 spentChamberFillSwitchingPeriod; ///< Periodic spent chamber fill switching time in task interval count. static U32 currentSpentChamberFillSwitchingCounter; ///< Counter (in task interval) to monitor the timing spent during spent chamber fill operation. static U32 totalSpentChamberfillCounter; ///< Counter (in task interval) to monitor the total number of spent chamber fill operation. static U32 spentChamberFillDataPublicationTimerCounter; ///< Used to schedule spent chamber fill data publication to CAN bus. static OVERRIDE_U32_T spentChamberFillDataPublishInterval; ///< Spent chamber fill data publish interval. // ********** private function prototypes ********** static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState1FillStart( void ); static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState1FillEnd(void); static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState2FillStart( void ); static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState2FillEnd(void); static void publishSpentChamberFillData( void ); /*********************************************************************//** * @brief * The initSpentChamberFill function initializes the Spent chamber fill unit. * @details \b Inputs: none * @details \b Outputs: unit variables initialized * @return none *************************************************************************/ void initSpentChamberFill( void ) { spentChamberFillExecState = SPENT_CHAMBER_FILL_STATE_START; spentChamberFillDataPublishInterval.data = SPENT_CHAMBER_FILL_DATA_PUBLISH_INTERVAL; spentChamberFillDataPublishInterval.ovData = SPENT_CHAMBER_FILL_DATA_PUBLISH_INTERVAL; spentChamberFillDataPublishInterval.ovInitData = 0; spentChamberFillDataPublishInterval.override = OVERRIDE_RESET; spentChamberFillSwitchingPeriod = 0; currentSpentChamberFillSwitchingCounter = 0; spentChamberFillDataPublicationTimerCounter = 0; totalSpentChamberfillCounter = 0; } /*********************************************************************//** * @brief * The transitionToSpentChamberFill function prepares for transition to * spent chamber fill operations. * @details \b Inputs: balChamberSwitchingPeriod * @details \b Outputs: spentChamberFillSwitchingPeriod * @return none *************************************************************************/ void transitionToSpentChamberFill( void ) { initSpentChamberFill(); updateBalChamberSwitchingPeriod(); // Follow the same cycle for spent chamber fill spentChamberFillSwitchingPeriod = getBalChamberSwitchingPeriod(); } /*********************************************************************//** * @brief * The execSpentChamberFillControl function executes the spent chamber(H) fill * state machine. * @details \b Inputs: spentChamberFillExecState * @details \b Outputs: spentChamberFillExecState * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when wrong spent chamber fill * state invoked. * @return current spent chamber fill state. *************************************************************************/ U32 execSpentChamberFillControl( void ) { // Increment counter indicating fill is in progress. currentSpentChamberFillSwitchingCounter += 1; // execute current spent chamber fill exec state switch ( spentChamberFillExecState ) { case SPENT_CHAMBER_FILL_STATE_START: spentChamberFillExecState = SPENT_CHAMBER_FILL_STATE1_FILL_START; break; case SPENT_CHAMBER_FILL_STATE1_FILL_START: spentChamberFillExecState = handleSpentChamberFillState1FillStart(); break; case SPENT_CHAMBER_FILL_STATE1_FILL_END: spentChamberFillExecState = handleSpentChamberFillState1FillEnd(); break; case SPENT_CHAMBER_FILL_STATE2_FILL_START: spentChamberFillExecState = handleSpentChamberFillState2FillStart(); break; case SPENT_CHAMBER_FILL_STATE2_FILL_END: spentChamberFillExecState = handleSpentChamberFillState2FillEnd(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_SPENT_CHAMBER_FILL_INVALID_EXEC_STATE, spentChamberFillExecState ) spentChamberFillExecState = SPENT_CHAMBER_FILL_STATE_START; break; } //Publish spent chamber fill data publishSpentChamberFillData(); return spentChamberFillExecState; } /*********************************************************************//** * @brief * The valveControlForSCFillState1FillStart function actuates the valve combination * for state 1 fill process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForSCFillState1FillStart( void ) { // Close balancing chamber valves D24,D20,D26 and D21 setValveState( D20_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); setValveState( D21_VALV, VALVE_STATE_CLOSED ); //Open balancing chamber valves D19,D23, D22 and D25 setValveState( D19_VALV, VALVE_STATE_OPEN ); setValveState( D23_VALV, VALVE_STATE_OPEN ); setValveState( D25_VALV, VALVE_STATE_OPEN ); setValveState( D22_VALV, VALVE_STATE_OPEN ); } /*********************************************************************//** * @brief * The valveControlForSCFillState2FillStart function actuates the valve combination * for state 2 fill process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForSCFillState2FillStart( void ) { // Close balancing chamber valves D24,D22,D26,D19 setValveState( D19_VALV, VALVE_STATE_CLOSED ); setValveState( D22_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); //Open balancing chamber valves D21,D20,D23 and D25 setValveState( D21_VALV, VALVE_STATE_OPEN ); setValveState( D23_VALV, VALVE_STATE_OPEN ); setValveState( D25_VALV, VALVE_STATE_OPEN ); setValveState( D20_VALV, VALVE_STATE_OPEN ); } /*********************************************************************//** * @brief * The handleSpentChamberFillState1FillStart function handles the spent chamber * state 1 fill operations. * @details \b Inputs: fresh and spent dialysate pressure * @details \b Outputs: valve states,current spent chamber fill state * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_START_PRESSURE_OUT_OF_RANGE * when pressure is not in range during balacing chamber fill start. * @return next spent chamber fill state. *************************************************************************/ static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState1FillStart( void ) { SPENT_CHAMBER_FILL_EXEC_STATE_T state = SPENT_CHAMBER_FILL_STATE1_FILL_START; currentSpentChamberFillSwitchingCounter = 0; F32 freshDialPressure = getFilteredPressure( D18_PRES ); F32 spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure in range if ( ( ( freshDialPressure >= FRESH_DIAL_FILL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_FILL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_FILL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_FILL_PRESSURE_MAX_PSIG ) ) ) { //Valve control for state 1 spent chamber fill valveControlForSCFillState1FillStart(); state = SPENT_CHAMBER_FILL_STATE1_FILL_END; } else { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_SC_STATE1_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } return state; } /*********************************************************************//** * @brief * The handleSpentChamberFillState1FillEnd function check for the spent chamber * fill switching period and tranistion to next state. * @details \b Inputs: currentSpentChamberFillSwitchingCounter,spentChamberFillSwitchingPeriod * @details \b Outputs: currentSpentChamberFillSwitchingCounter, Valves state * @return next spent chamber fill state. *************************************************************************/ static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState1FillEnd( void ) { SPENT_CHAMBER_FILL_EXEC_STATE_T state = SPENT_CHAMBER_FILL_STATE1_FILL_END; // On completion of cycle time, transition to next state if ( currentSpentChamberFillSwitchingCounter >= spentChamberFillSwitchingPeriod ) { //Close all balancing chamber valves valveControlForBCClosedState(); totalSpentChamberfillCounter++; // Move to next state. state = SPENT_CHAMBER_FILL_STATE2_FILL_START; } return state; } /*********************************************************************//** * @brief * The handleSpentChamberFillState2FillStart function handles the spent chamber * state 2 fill operations. * @details \b Inputs: fresh and spent dialysate pressure * @details \b Outputs: balancing chamber valves state * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE * when pressure is not in range during balacing chamber state 2 fill start. * @return next spent chamber fill state. *************************************************************************/ static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState2FillStart( void ) { SPENT_CHAMBER_FILL_EXEC_STATE_T state = SPENT_CHAMBER_FILL_STATE2_FILL_START; currentSpentChamberFillSwitchingCounter = 0; F32 freshDialPressure = getFilteredPressure( D18_PRES ); F32 spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure in range if ( ( ( freshDialPressure >= FRESH_DIAL_FILL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_FILL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_FILL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_FILL_PRESSURE_MAX_PSIG ) ) ) { // Valve control for state 2 fill valveControlForSCFillState2FillStart(); state = SPENT_CHAMBER_FILL_STATE2_FILL_END; } else { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_SC_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } return state; } /*********************************************************************//** * @brief * The handleSpentChamberFillState2FillEnd function check for the spent chamber * switching period complete and transition to next state. * @details \b Inputs: currentSpentChamberFillSwitchingCounter,spentChamberFillSwitchingPeriod * @details \b Outputs: balancing chamber valves state * @return next balancing chamber state. *************************************************************************/ static SPENT_CHAMBER_FILL_EXEC_STATE_T handleSpentChamberFillState2FillEnd( void ) { SPENT_CHAMBER_FILL_EXEC_STATE_T state = SPENT_CHAMBER_FILL_STATE2_FILL_END; // On completion of cycle time, transition to next state if ( currentSpentChamberFillSwitchingCounter >= spentChamberFillSwitchingPeriod ) { //Close all balancing chamber valves valveControlForBCClosedState(); totalSpentChamberfillCounter++; // Move to next state state = SPENT_CHAMBER_FILL_STATE1_FILL_START; } return state; } /*********************************************************************//** * @brief * The totalSpentChamberfillCounter function returns the total number * of the Spent chamber fills. * @details \b Inputs: totalSpentChamberfillCounter * @details \b Outputs: none * @return the total number of spent chamber fills. *************************************************************************/ U32 getTotalSpentChamberFillCounts( void ) { return totalSpentChamberfillCounter; } /*********************************************************************//** * @brief * The getCurrentSpentChamberFillExecState function returns the current state * of the Spent chamber fill execution state. * @details \b Inputs: spentChamberFillExecState * @details \b Outputs: none * @return the current state of spent chamber fill states. *************************************************************************/ SPENT_CHAMBER_FILL_EXEC_STATE_T getCurrentSpentChamberFillExecState( void ) { return spentChamberFillExecState; } /*********************************************************************//** * @brief * The publishSpentChamberFillData function broadcasts the spent chamber * fill execution data at defined interval. * @details \b Inputs: spentChamberFillDataPublicationTimerCounter * @details \b Outputs: DD spent chamber fill data broadcast message sent * @details \b Message \Sent: MSG_ID_DD_SPENT_CHAMBER_FILL_DATA to publish the * Spent chamber fill data. * @return none *************************************************************************/ static void publishSpentChamberFillData( void ) { if ( ++spentChamberFillDataPublicationTimerCounter >= getU32OverrideValue( &spentChamberFillDataPublishInterval ) ) { SPENT_CHAMBER_FILL_DATA_T data; data.spentChamberFillExecState = (U32)spentChamberFillExecState; data.spentChamberFillSwPeriod = spentChamberFillSwitchingPeriod; data.totalSpentChamberfillCounter = totalSpentChamberfillCounter; broadcastData( MSG_ID_DD_SPENT_CHAMBER_FILL_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( SPENT_CHAMBER_FILL_DATA_T ) ); spentChamberFillDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testDDSpentChamberFillDataPublishIntervalOverride function overrides the * DD spent chamber fill data publish interval. * @details \b Inputs: spentChamberFillDataPublishInterval * @details \b Outputs: spentChamberFillDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the DD spent chamber fill data publish interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testDDSpentChamberFillDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &spentChamberFillDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /**@}*/