/************************************************************************** * * Copyright (c) 2025-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 BalancingChamber.c * * @author (last) Vinayakam Mani * @date (last) 03-Sep-2025 * * @author (original) Vinayakam Mani * @date (original) 28-Jan-2025 * ***************************************************************************/ #include "BalancingChamber.h" #include "Conductivity.h" #include "ConcentratePumps.h" #include "DialysatePumps.h" #include "FpgaDD.h" #include "Heaters.h" #include "ModeStandby.h" #include "Messaging.h" #include "OperationModes.h" #include "Pressure.h" #include "TaskGeneral.h" #include "TDInterface.h" #include "Temperature.h" #include "TestSupport.h" #include "Valves.h" /** * @addtogroup BalancingChamber * @{ */ // ********** private definitions ********** #define BAL_CHAMBER_DATA_PUBLISH_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the balancing chamber data published. #define BAL_CHAMBER_FILL_PRES_DROP_MS ( 200 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber filling started and corrosponding valves opened. #define BAL_CHAMBER_FILL_COMPLETE_MS ( 300 / TASK_GENERAL_INTERVAL ) ///< Time (ms/tasktime) to confirm the balancing chamber fill completed and pressure is within range /// Payload record structure for balancing chamber switch only request typedef struct { U32 startStop; ///< balancing chamber switching only start:1 and stop: 0 F32 flowrate; ///< dialysate flowrate in ml/min } BC_SWITCHING_ONLY_START_CMD_PAYLOAD_T; // ********** private data ********** static BAL_CHAMBER_EXEC_STATE_T balChamberExecState; ///< Current balancing chamber executive state. static OVERRIDE_F32_T balChamberSwitchingFreq; ///< Balancing chamber switching rate ( switches per min) based on the dialysate flow rate ( overrideable) static U32 balChamberSwitchingPeriod; ///< Periodic balancing chamber switching time in task interval count. static U32 balChamberValveClosePeriod; ///< Close balancing chamber valves with the defined time prior switching state. static U32 currentBalChamberSwitchingCounter; ///< Counter (in task interval) to monitor the timing spent during balancing chamber fill/drain operation. static BOOL isBalChamberFillInProgress; ///< Flag indicating balancing chamber fill/drain is in progress. static BOOL isPressureStalbilizedDuringFill; ///< Flag indicating that the pressure is stablized due to fill complete. static BAL_CHAMBER_SW_STATE_T balChamberSWState; ///< Current balancing chamber switching state ( state 1 or state 2). static U32 balChamberDataPublicationTimerCounter; ///< Used to schedule balancing chamber data publication to CAN bus. static U32 balChamberFillPressureDropCounter; ///< Counter to check balancing chamber valves opened and there by pressure drop is seen. static OVERRIDE_U32_T balChamberDataPublishInterval; ///< Balancing chamber data publish interval. static BOOL balanceChamberSwitchingOnly; ///< Balancing chamber switching without any pressure check and dosing delivery. static BOOL isPressureDroppedDuringFill; ///< Flag indicating that the pressure is dropped due to BC fill (state 1 or state 2) in progress condition. static BOOL isFirstCycleBCSwitchingCompleted; ///< Flag indicating that first time balancing chamber swithcing is done to trigger alarms from next cycle onwards. static U32 balChamberFillCompleteStablePressureCounter; ///< Counter to check balancing chamber fill complete and stable pressure is met. static OVERRIDE_F32_T acidDoseVolume; ///< Acid concentrate volume in ml ( overrideable). static OVERRIDE_F32_T bicarbDoseVolume; ///< Bicarb concentrate volume in ml ( overrideable). static F32 lastTdDialysateFlowrate; ///< Previous TD dialysate flow rate static F32 freshDialPressure; ///< Fresh side dialysate pressure static F32 spentDialPressure; ///< Spent side dialysate pressure // ********** private function prototypes ********** static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberConcentrateControl(void); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1ValvesClose( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillEnd(void); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillStart( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2ValvesClose( void ); static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillEnd(void); static void publishBalChamberData( void ); static U32 getBalChamberDataPublishInterval( void ); /*********************************************************************//** * @brief * The initBalanceChamber function initializes the balancing chamber unit. * @details \b Inputs: none * @details \b Outputs: unit variables initialized * @return none *************************************************************************/ void initBalanceChamber( void ) { balChamberExecState = BAL_CHAMBER_STATE_START; balChamberSWState = BAL_CHAMBER_SW_STATE1; balChamberSwitchingFreq.data = 0.0F; balChamberSwitchingFreq.ovData = 0.0F; balChamberSwitchingFreq.ovInitData = 0.0F; balChamberSwitchingFreq.override = OVERRIDE_RESET; balChamberDataPublishInterval.data = BAL_CHAMBER_DATA_PUBLISH_INTERVAL; balChamberDataPublishInterval.ovData = BAL_CHAMBER_DATA_PUBLISH_INTERVAL; balChamberDataPublishInterval.ovInitData = 0; balChamberDataPublishInterval.override = OVERRIDE_RESET; acidDoseVolume.data = DEFAULT_ACID_VOLUME_ML; acidDoseVolume.ovData = DEFAULT_ACID_VOLUME_ML; acidDoseVolume.ovInitData = 0.0F; acidDoseVolume.override = OVERRIDE_RESET; bicarbDoseVolume.data = DEFAULT_BICARB_VOLUME_ML; bicarbDoseVolume.ovData = DEFAULT_BICARB_VOLUME_ML; bicarbDoseVolume.ovInitData = 0.0F; bicarbDoseVolume.override = OVERRIDE_RESET; balanceChamberSwitchingOnly = FALSE; balChamberSwitchingPeriod = 0; balChamberValveClosePeriod = 0; isBalChamberFillInProgress = FALSE; currentBalChamberSwitchingCounter = 0; isPressureStalbilizedDuringFill = FALSE; lastTdDialysateFlowrate = 0.0F; balChamberDataPublicationTimerCounter = 0; balChamberFillPressureDropCounter = 0; balChamberFillCompleteStablePressureCounter = 0; isFirstCycleBCSwitchingCompleted = FALSE; isPressureDroppedDuringFill = FALSE; freshDialPressure = 0.0F; spentDialPressure = 0.0F; } /*********************************************************************//** * @brief * The transitionToBalChamberFill function prepares for transition to * balancing chamber fill/switching operations. * @details \b Inputs: none * @details \b Outputs: balChamberSwitchingFreq ,balChamberSwitchingPeriod * @return none *************************************************************************/ void transitionToBalChamberFill( void ) { initBalanceChamber(); updateBalChamberSwitchingPeriod(); } /*********************************************************************//** * @brief * The updateBalChamberSwitchingPeriod function updates the periodic * balancing chamber switching time based on the dialysis flow rate. * @details \b Inputs: Dialysis flow rate. * @details \b Outputs: balChamberSwitchingFreq,balChamberSwitchingPeriod * @return none *************************************************************************/ void updateBalChamberSwitchingPeriod( void ) { F32 tdDialysateFlowrate = getTDDialysateFlowrate(); if ( lastTdDialysateFlowrate != tdDialysateFlowrate ) { // update the balancing chamber switching frequency balChamberSwitchingFreq.data = tdDialysateFlowrate / BAL_CHAMBER_FILL_VOLUME_ML; //update the switching period in task interval for balancing chamber fill timeout check balChamberSwitchingPeriod = (U32)( (F32)SEC_PER_MIN / getBalChamberSwitchingFreq() * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); // finish the balancing chamber fill 50 ms prior completing the regular cycle time. balChamberSwitchingPeriod -= 1; //Update last td dialysate flow rate lastTdDialysateFlowrate = tdDialysateFlowrate; //Reset the BC switching flag for new Qd. isFirstCycleBCSwitchingCompleted = FALSE; //Update heater control on dialysate flow change signalHeaterControlOnQDUpdate( D5_HEAT ); //Testing balChamberValveClosePeriod = balChamberSwitchingPeriod; balChamberValveClosePeriod -= 1; // Close valves prior 50 msecond for testing } } /*********************************************************************//** * @brief * The execBalancingChamberControl function executes the balancing chamber state machine. * @details \b Inputs: balChamberExecState * @details \b Outputs: balChamberExecState * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when wrong balancing chamber state invoked. * @return current state. *************************************************************************/ U32 execBalancingChamberControl( void ) { // Increment counter indicating fill is in progress. currentBalChamberSwitchingCounter += 1; // execute current balancing chamber exec state switch ( balChamberExecState ) { case BAL_CHAMBER_STATE_START: balChamberExecState = BAL_CHAMBER_STATE1_FILL_START; break; case BAL_CHAMBER_STATE1_FILL_START: balChamberExecState = handleBalChamberState1FillStart(); break; case BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL: balChamberExecState = handleBalChamberConcentrateControl(); break; case BAL_CHAMBER_STATE1_VALVES_CLOSE: balChamberExecState = handleBalChamberState1ValvesClose(); break; case BAL_CHAMBER_STATE1_FILL_END: balChamberExecState = handleBalChamberState1FillEnd(); break; case BAL_CHAMBER_STATE2_FILL_START: balChamberExecState = handleBalChamberState2FillStart(); break; case BAL_CHAMBER_STATE2_BICARB_ACID_DOSING_CNTRL: balChamberExecState = handleBalChamberConcentrateControl(); break; case BAL_CHAMBER_STATE2_VALVES_CLOSE: balChamberExecState = handleBalChamberState2ValvesClose(); break; case BAL_CHAMBER_STATE2_FILL_END: balChamberExecState = handleBalChamberState2FillEnd(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BAL_CHAMBER_INVALID_EXEC_STATE, balChamberExecState ) balChamberExecState = BAL_CHAMBER_STATE_START; break; } //Publish balancing chamber data publishBalChamberData(); return balChamberExecState; } /*********************************************************************//** * @brief * The valveControlForBCState1FillStart function actuates the valve combination * for state 1 fill/drain process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForBCState1FillStart( void ) { // Close balancing chamber valve combinations D23,D20 and D21,D26 setValveState( D23_VALV, VALVE_STATE_CLOSED ); setValveState( D20_VALV, VALVE_STATE_CLOSED ); setValveState( D21_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); //Open balancing chamber valve combinations D19,D24 and D25,D22 setValveState( D19_VALV, VALVE_STATE_OPEN ); setValveState( D24_VALV, VALVE_STATE_OPEN ); setValveState( D25_VALV, VALVE_STATE_OPEN ); setValveState( D22_VALV, VALVE_STATE_OPEN ); } /*********************************************************************//** * @brief * The valveControlForBCState1FillEnd function closes the valve opened * for state 1 fill/drain process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForBCState1FillEnd( void ) { //Close balancing chamber valve combinations D19,D24 and D25,D22 setValveState( D19_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D25_VALV, VALVE_STATE_CLOSED ); setValveState( D22_VALV, VALVE_STATE_CLOSED ); } /*********************************************************************//** * @brief * The valveControlForBCState2FillStart function actuates the valve combination * for state 2 fill/drain process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForBCState2FillStart( void ) { //Close balancing chamber valve combinations D19,D24 and D25,D22 setValveState( D19_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D25_VALV, VALVE_STATE_CLOSED ); setValveState( D22_VALV, VALVE_STATE_CLOSED ); // Open balancing chamber valve combinations D23,D20 and D21,D26 setValveState( D23_VALV, VALVE_STATE_OPEN ); setValveState( D20_VALV, VALVE_STATE_OPEN ); setValveState( D21_VALV, VALVE_STATE_OPEN ); setValveState( D26_VALV, VALVE_STATE_OPEN ); } /*********************************************************************//** * @brief * The valveControlForBCState2FillEnd function closes the valve opened * for state 2 fill/drain process. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ static void valveControlForBCState2FillEnd( void ) { // Close balancing chamber valve combinations D23,D20 and D21,D26 setValveState( D23_VALV, VALVE_STATE_CLOSED ); setValveState( D20_VALV, VALVE_STATE_CLOSED ); setValveState( D21_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); } /*********************************************************************//** * @brief * The valveControlForBCClosedState function closes the all balancing * chamber valves. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ void valveControlForBCClosedState( void ) { // Close balancing chamber valve combinations D23,D20 and D21,D26 setValveState( D23_VALV, VALVE_STATE_CLOSED ); setValveState( D20_VALV, VALVE_STATE_CLOSED ); setValveState( D21_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); //Close balancing chamber valve combinations D19,D24 and D25,D22 setValveState( D19_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D25_VALV, VALVE_STATE_CLOSED ); setValveState( D22_VALV, VALVE_STATE_CLOSED ); } /*********************************************************************//** * @brief * The valveControlForBCOpenState function open the all balancing * chamber valves. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ void valveControlForBCOpenState( void ) { // Open balancing chamber valve combinations D23,D20 and D21,D26 setValveState( D23_VALV, VALVE_STATE_OPEN ); setValveState( D20_VALV, VALVE_STATE_OPEN ); setValveState( D21_VALV, VALVE_STATE_OPEN ); setValveState( D26_VALV, VALVE_STATE_OPEN ); //Open balancing chamber valve combinations D19,D24 and D25,D22 setValveState( D19_VALV, VALVE_STATE_OPEN ); setValveState( D24_VALV, VALVE_STATE_OPEN ); setValveState( D25_VALV, VALVE_STATE_OPEN ); setValveState( D22_VALV, VALVE_STATE_OPEN ); } /*********************************************************************//** * @brief * The valveControlForBCFreshSideOnlyOpenState function opens the fresh side * balancing chamber valves and closes the spent side valves. * @details \b Inputs: none * @details \b Outputs: valve states * @return none. *************************************************************************/ void valveControlForBCFreshSideOnlyOpenState( void ) { // Open fresh balancing chamber valves D19,D20,D21,D22 setValveState( D19_VALV, VALVE_STATE_OPEN ); setValveState( D20_VALV, VALVE_STATE_OPEN ); setValveState( D21_VALV, VALVE_STATE_OPEN ); setValveState( D22_VALV, VALVE_STATE_OPEN ); // Close spent side valves D23,D24,D25,D26 setValveState( D23_VALV, VALVE_STATE_CLOSED ); setValveState( D25_VALV, VALVE_STATE_CLOSED ); setValveState( D24_VALV, VALVE_STATE_CLOSED ); setValveState( D26_VALV, VALVE_STATE_CLOSED ); } /*********************************************************************//** * @brief * The handleBalChamberState1FillStart function handles the balancing chamber * state 1 fill and time to fill chamber counter being updated. * @details \b Inputs: Pressure * @details \b Outputs: valve states * @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 balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_FILL_START; currentBalChamberSwitchingCounter = 0; isBalChamberFillInProgress = FALSE; isPressureStalbilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; balChamberSWState = BAL_CHAMBER_SW_STATE1; F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure in range or BC switch only flag set if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) ) ) { //Valve control for state 1 fill valveControlForBCState1FillStart(); // Update fill status flag to true isBalChamberFillInProgress = TRUE; // Deliver dosing during generate dialysate mode if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { // start acid and bicarb pump with the expected quantity setConcentratePumpTargetSpeed( D11_PUMP, CONCENTRATE_PUMP_MAX_SPEED, acidVolume ); setConcentratePumpTargetSpeed( D10_PUMP, CONCENTRATE_PUMP_MAX_SPEED, bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); } state = BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL; } else { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } } return state; } /*********************************************************************//** * @brief * The handleBalChamberConcentrateControl function handles the Acid and Bicarb * concentrate doisng and checks the conductivity of the dialysate for the treatment. * @details \b Inputs: balChamberSWState , Concentrate volume * @details \b Outputs: isPressureDroppedDuringFill, state * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberConcentrateControl( void ) { BAL_CHAMBER_EXEC_STATE_T state; freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { state = BAL_CHAMBER_STATE1_BICARB_ACID_DOSING_CNTRL; } else { state = BAL_CHAMBER_STATE2_BICARB_ACID_DOSING_CNTRL; } // Pressure drop check during fill process helps to find if there is any issue with valves opening if ( ( freshDialPressure <= BC_FRESH_FILL_PRESSURE_PSIG ) && ( spentDialPressure <= BC_SPENT_FILL_PRESSURE_PSIG ) ) { if ( ++balChamberFillPressureDropCounter >= BAL_CHAMBER_FILL_PRES_DROP_MS ) { isPressureDroppedDuringFill = TRUE; } } // On dosing completion, transition to next state based on the current switching state if ( ( ( TRUE == isConcentratePumpDosingCompleted( D11_PUMP ) ) && ( TRUE == isConcentratePumpDosingCompleted( D10_PUMP ) ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) ) { if ( BAL_CHAMBER_SW_STATE1 == balChamberSWState ) { state = BAL_CHAMBER_STATE1_VALVES_CLOSE; } else { state = BAL_CHAMBER_STATE2_VALVES_CLOSE; } } return state; } /*********************************************************************//** * @brief * The handleBalChamberState1ValvesClose function check for the balancing chamber * fill complete and close the currently opened valves. * @details \b Inputs: currentBalChamberSwitchingCounter, spent and fresh dialysate pressure * @details \b Outputs: isPressureStalbilizedDuringFill,isBalChamberFillInProgress * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_VALVES_CLOSE; freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure back in range to indicate fill complete. if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) ) { if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { // stabilized pressure indicating fill is complete isPressureStalbilizedDuringFill = TRUE; } } } else { isPressureStalbilizedDuringFill = FALSE; } // Switching time met or pressure in range, close valves if ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) || ( TRUE == isPressureStalbilizedDuringFill ) ) { // close the state 1 opened valves valveControlForBCState1FillEnd(); isBalChamberFillInProgress = FALSE; //Transition to next state state = BAL_CHAMBER_STATE1_FILL_END; } return state; } /*********************************************************************//** * @brief * The handleBalChamberState1FillEnd function check for the balancing chamber * switching period and tranistion to next state switching. * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod * @details \b Outputs: balChamberFillPressureDropCounter,balChamberFillCompleteStablePressureCounter * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_PRESSURE_DROP_OUT_OF_RANGE * when pressure drop is not in range during balacing chamber fill in progress. * @details \b Alarm: ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE * when pressure is not in range during balacing chamber fill complete. * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillEnd( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE1_FILL_END; // On completion of cycle time, transition to next state if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) { balChamberFillPressureDropCounter = 0; balChamberFillCompleteStablePressureCounter = 0; if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) { // When fill initiated, pressure is not dropped to the expected range, possible valve failures. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } else if ( TRUE != isPressureStalbilizedDuringFill ) { // Alarm when switching time expired, but still pressure not in range which indicates fill is not yet completed. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE1_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } else { // Move to next state when pressure is in range. state = BAL_CHAMBER_STATE2_FILL_START; } } else { // Allow to proceed next state even though pressure is not stabilized. state = BAL_CHAMBER_STATE2_FILL_START; } } else { state = BAL_CHAMBER_STATE2_FILL_START; } } return state; } /*********************************************************************//** * @brief * The handleBalChamberState2FillStart function handles the balancing chamber * state 2 fill and time to fill chamber counter being updated. * @details \b Inputs: fresh and spent dialysate pressure * @details \b Outputs: valve states * @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 balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillStart( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_FILL_START; currentBalChamberSwitchingCounter = 0; isBalChamberFillInProgress = FALSE; isPressureStalbilizedDuringFill = FALSE; isPressureDroppedDuringFill = FALSE; balChamberSWState = BAL_CHAMBER_SW_STATE2; F32 acidVolume = getF32OverrideValue( &acidDoseVolume ); F32 bicarbVolume = getF32OverrideValue( &bicarbDoseVolume ); freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure in range if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) || ( TRUE == getBalChamberSwitchingOnlyStatus() ) || ( TRUE == getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) ) ) { // Valve control for state 2 fill valveControlForBCState2FillStart(); // Update fill status flag to true isBalChamberFillInProgress = TRUE; // Deliver dosing during generate dialysate mode if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { // start acid and bicarb pump with the expected quantity setConcentratePumpTargetSpeed( D11_PUMP, CONCENTRATE_PUMP_MAX_SPEED, acidVolume ); setConcentratePumpTargetSpeed( D10_PUMP, CONCENTRATE_PUMP_MAX_SPEED, bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); } state = BAL_CHAMBER_STATE2_BICARB_ACID_DOSING_CNTRL; } else { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { //Alarm when pressure is not in range SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_START_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } } return state; } /*********************************************************************//** * @brief * The handleBalChamberState2ValvesClose function check for the balancing chamber * fill complete and close the currently opened valves. * @details \b Inputs: currentBalChamberSwitchingCounter, spent and fresh dialysate pressure * @details \b Outputs: isPressureStalbilizedDuringFill,isBalChamberFillInProgress * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2ValvesClose( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_VALVES_CLOSE; freshDialPressure = getFilteredPressure( D18_PRES ); spentDialPressure = getFilteredPressure( D51_PRES ); // Check fresh and spent dialysate pressure back in range to indicate fill complete. if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( ( freshDialPressure >= FRESH_DIAL_PRESSURE_MIN_PSIG ) && ( freshDialPressure <= FRESH_DIAL_PRESSURE_MAX_PSIG ) ) && ( ( spentDialPressure >= SPENT_DIAL_PRESSURE_MIN_PSIG ) && ( spentDialPressure <= SPENT_DIAL_PRESSURE_MAX_PSIG ) ) ) { if ( ++balChamberFillCompleteStablePressureCounter >= BAL_CHAMBER_FILL_COMPLETE_MS ) { // stabilized pressure indicating fill is complete isPressureStalbilizedDuringFill = TRUE; } } } else { isPressureStalbilizedDuringFill = FALSE; } // Check switching cycle time or pressure check for valve closure if ( ( currentBalChamberSwitchingCounter >= balChamberValveClosePeriod ) || ( TRUE == isPressureStalbilizedDuringFill ) ) { // close the valves valveControlForBCState2FillEnd(); isBalChamberFillInProgress = FALSE; //Transition to next state state = BAL_CHAMBER_STATE2_FILL_END; } return state; } /*********************************************************************//** * @brief * The handleBalChamberState2FillEnd function check for the balancing chamber * switching period complete and transition to next state. * @details \b Inputs: currentBalChamberSwitchingCounter, balChamberSwitchingPeriod * @details \b Outputs: isPressureStalbilizedDuringFill,isBalChamberFillInProgress * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE * when pressure is not in range during balacing chamber state 2 fill in progress. * @details \b Alarm: ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE * when pressure is not in range during balacing chamber state 2 fill complete. * @return next balancing chamber state. *************************************************************************/ static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState2FillEnd( void ) { BAL_CHAMBER_EXEC_STATE_T state = BAL_CHAMBER_STATE2_FILL_END; // On completion of cycle time, transition to next state if ( currentBalChamberSwitchingCounter >= balChamberSwitchingPeriod ) { balChamberFillPressureDropCounter = 0; balChamberFillCompleteStablePressureCounter = 0; // Pressure alarm check if ( TRUE != getBalChamberSwitchingOnlyStatus() ) { if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BC_PRESSURE_ALARMS ) != TRUE ) { if ( ( TRUE != isPressureDroppedDuringFill ) && ( TRUE == isFirstCycleBCSwitchingCompleted ) ) { // When fill initiated, pressure is not dropped to the expected range, possible valve failures. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_PRESSURE_DROP_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } else if ( TRUE != isPressureStalbilizedDuringFill ) { // Alarm when switching time expired, but still pressure not in range which indicates fill is not completed. SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DD_BC_STATE2_FILL_END_PRESSURE_OUT_OF_RANGE, freshDialPressure, spentDialPressure ); } else { // Move to next state when pressure is in range. state = BAL_CHAMBER_STATE1_FILL_START; // Trigger pressure drop alarm after first cycle of balancing chamber switching complete if ( FALSE == isFirstCycleBCSwitchingCompleted ) { isFirstCycleBCSwitchingCompleted = TRUE; } } } else { // Allow to proceed next state even though pressure is not stabilized. state = BAL_CHAMBER_STATE1_FILL_START; } } else { state = BAL_CHAMBER_STATE1_FILL_START; } } return state; } /*********************************************************************//** * @brief * The getCurrentBalancingChamberExecState function returns the current state * of the balancing chamber. * @details \b Inputs: balChamberExecState * @details \b Outputs: none * @return the current state of balancing chamber states. *************************************************************************/ BAL_CHAMBER_EXEC_STATE_T getCurrentBalancingChamberExecState( void ) { return balChamberExecState; } /*********************************************************************//** * @brief * The getBalancingChamberFillinProgressStatus function returns the current * balancing chamber fill in progress status. * @details \b Inputs: isBalChamberFillInProgress * @details \b Outputs: none * @return the current balancing chamber fill in progress. *************************************************************************/ BOOL getBalancingChamberFillinProgressStatus( void ) { return isBalChamberFillInProgress; } /*********************************************************************//** * @brief * The getBalChamberSwitchingFreq function gets the balancing chamber switching * frequency value. * @details \b Inputs: balChamberSwitchingFreq * @details \b Outputs: none * @return balancing chamber switching frequency *************************************************************************/ F32 getBalChamberSwitchingFreq( void ) { F32 result = balChamberSwitchingFreq.data; if ( OVERRIDE_KEY == balChamberSwitchingFreq.override ) { result = balChamberSwitchingFreq.ovData; } return result; } /*********************************************************************//** * @brief * The setBalChamberSwitchingOnlyStatus function sets the balancing chamber * switching only On/Off status. * @details \b Inputs: balanceChamberSwitchingOnly * @details \b Outputs: none * @return none *************************************************************************/ void setBalChamberSwitchingOnlyStatus( BOOL OnOff ) { balanceChamberSwitchingOnly = OnOff; } /*********************************************************************//** * @brief * The getBalChamberSwitchingOnlyStatus function gets the balancing chamber * switching only status. * @details \b Inputs: balanceChamberSwitchingOnly * @details \b Outputs: none * @return balancing chamber switching only without any pressure validation * and dosing delivery *************************************************************************/ BOOL getBalChamberSwitchingOnlyStatus( void ) { return balanceChamberSwitchingOnly; } /*********************************************************************//** * @brief * The getBalChamberSwitchingPeriod function gets the balancing chamber * switching period. * @details \b Inputs: balChamberSwitchingPeriod * @details \b Outputs: none * @return balancing chamber switching period *************************************************************************/ U32 getBalChamberSwitchingPeriod( void ) { return balChamberSwitchingPeriod; } /*********************************************************************//** * @brief * The getBalChamberDataPublishInterval function gets the balancing chamber * data publish interval. * @details \b Inputs: balChamberDataPublishInterval * @details \b Outputs: none * @return the interval at balancing chamber data being published. *************************************************************************/ static U32 getBalChamberDataPublishInterval( void ) { U32 result = balChamberDataPublishInterval.data; if ( OVERRIDE_KEY == balChamberDataPublishInterval.override ) { result = balChamberDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @brief * The publishBalChamberData function broadcasts the balancing chamber * execution data at defined interval. * @details \b Inputs: balChamberDataPublicationTimerCounter * @details \b Outputs: DD balancing chamber data broadcast message sent * @details \b Message \Sent: MSG_ID_DD_BAL_CHAMBER_DATA to publish the balancing * chamber data. * @return none *************************************************************************/ static void publishBalChamberData( void ) { if ( ++balChamberDataPublicationTimerCounter >= getBalChamberDataPublishInterval() ) { BAL_CHAMBER_DATA_T data; data.balChamberExecState = (U32)balChamberExecState; data.balChamberSWState = (U32)balChamberSWState; data.balChamberSWFreq = getBalChamberSwitchingFreq(); data.balChamberSwPeriod = balChamberSwitchingPeriod; data.isBalChamberFillInProgress = isBalChamberFillInProgress; data.currentBalChamberSwitchingCounter = currentBalChamberSwitchingCounter; data.isPressureStalbilizedDuringFill = isPressureStalbilizedDuringFill; data.balChamberSWOnlyState = balanceChamberSwitchingOnly; broadcastData( MSG_ID_DD_BAL_CHAMBER_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( BAL_CHAMBER_DATA_T ) ); balChamberDataPublicationTimerCounter = 0; } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testDDBalChamberDataPublishIntervalOverride function overrides the * DD balancing chamber data publish interval. * @details \b Inputs: balChamberDataPublishInterval * @details \b Outputs: balChamberDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the DD balancing chamber data publish interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testDDBalChamberDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &balChamberDataPublishInterval, TASK_GENERAL_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testBalChamberSwFreqOverride function sets the override value * of the balancing chamber switching frequency. * @details Inputs: balChamberSwitchingFreq * @details Outputs: balChamberSwitchingFreq * @param message Override message from Dialin which includes the override * value to override the balancing chamber switching frequency. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBalChamberSwFreqOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &balChamberSwitchingFreq ); return result; } /*********************************************************************//** * @brief * The testAcidDoseVolumeOverride function sets the override value * of the acid concentrate dosing volume. * @details Inputs: acidDoseVolume * @details Outputs: acidDoseVolume * @param message Override message from Dialin which includes the override * value to override the acid concentrate dosing volume. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testAcidDoseVolumeOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &acidDoseVolume ); return result; } /*********************************************************************//** * @brief * The testBicarbDoseVolumeOverride function sets the override value * of the bicarb concentrate dosing volume. * @details Inputs: bicarbDoseVolume * @details Outputs: bicarbDoseVolume * @param message Override message from Dialin which includes the override * value to override the bicarb concentrate dosing volume. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBicarbDoseVolumeOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &bicarbDoseVolume ); return result; } /*********************************************************************//** * @brief * The testBCSwitchOnlyStartStopOverride function starts/stops balancing * chamber switching only without dosing delivery and pressure check condition. * @details \b Inputs: tester logged in * @details \b Outputs: tdDialysateFlowrate,balanceChamberSwitchingOnly * pendingBalanceChamberSwOnlyRequest * @param message set message from Dialin which includes the balancing chamber * to start/stop switching and update switching rate based on the flow rate. * @return TRUE if set request is successful, FALSE if not *************************************************************************/ BOOL testBCSwitchOnlyStartStopOverride( MESSAGE_T *message ) { BOOL result = FALSE; // Verify tester has logged in with TD if ( TRUE == isTestingActivated() ) { // Verify payload length is valid if ( sizeof( BC_SWITCHING_ONLY_START_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { BC_SWITCHING_ONLY_START_CMD_PAYLOAD_T payload; memcpy( &payload, message->payload, sizeof(BC_SWITCHING_ONLY_START_CMD_PAYLOAD_T) ); // Handle start command if ( ( TRUE == payload.startStop ) && ( ( payload.flowrate >= MIN_DIALYSATE_FLOW_RATE ) && ( payload.flowrate <= MAX_DIALYSATE_FLOW_RATE ) ) ) { // First set BC switching frequency based on the dialysate flow rate setTDDialysateFlowrate( payload.flowrate ); // update switching rate transitionToBalChamberFill(); // then set BC switching only flag to ignore pressure check and dosing. setBalChamberSwitchingOnlyStatus( TRUE ); // Now, if the current operating mode is standby mode idle state, execute the balancing chamber switching only control result = requestBCSwitchingOnlyStart(); } //Handle stop command if ( FALSE == payload.startStop ) { //Reset the flag setBalChamberSwitchingOnlyStatus( FALSE ); //Stop the BC switching execution only control requestBCSwitchingOnlyStop(); result = TRUE; } } } return result; } /**@}*/