Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r09e6cf9de34acf18f6e1138bf56ac0edb4821186 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 09e6cf9de34acf18f6e1138bf56ac0edb4821186) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -36,11 +36,15 @@ #define START_DG_CMD TRUE ///< Parameter for DG start/stop command function. True = start. #define STOP_DG_CMD FALSE ///< Parameter for DG start/stop command function. False = stop. - + +// TODO remove #define RESERVOIR_SETTLE_TIME_MS 5000 ///< Time (in ms) allotted for reservoir to settle (after fill, before drain). #define MAX_RESERVOIR_VOLUME_ML 1950.0 ///< Maximum reservoir volume. Switch reservoirs if active reservoir exceeds this volume. +#define MAX_RESERVOIR_DEPLETION_TIME_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Maximum allowed depletion time in milliseconds. +// TODO remove + #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. #define DIALYSATE_TEMP_PERSISTENCE_PERIOD ( 3 * MS_PER_SECOND ) ///< Persistence period for dialysate temperature alarm. @@ -50,20 +54,23 @@ #define DIALYSATE_TEMP_HIGH_LIMIT_C 42.0 ///< Dialysate high temperature limit in degree C. #define DIALYSATE_TEMP_LOW_LIMIT_C 33.0 ///< Dialysate low temperature limit in degree C. +// TODO remove /// States of the treatment reservoir management state machine. typedef enum TreatmentReservoirMgmt_States { TREATMENT_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. - TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. + TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, // TODO remove ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE, ///< Wait for drain to complete. TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE, ///< Wait to fill inactive reservoir (if appropriate) - then start filling inactive reservoir. TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE, ///< Wait for fill to complete. TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE, ///< Wait a bit for filled reservoir to settle before getting baseline weight (volume). - TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE, ///< Wait for active reservoir to be consumed and switch cmd given - then back to flush DG lines state. + TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE, // TODO remove ///< Wait for active reservoir to be consumed and switch cmd given - then back to flush DG lines state. TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Wait for inactive reservoir to settle before getting final weight (volume) before starting to drain. NUM_OF_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of treatment reservoir mgmt. states. -} TREATMENT_RESERVOIR_MGMT_STATE_T; +} TREATMENT_RESERVOIR_MGMT_STATE_T; +// TODO remove + // ********** private data ********** // DG status @@ -108,16 +115,38 @@ static U32 dgReservoirFillVolumeTargetSet = 0; ///< Fill-to volume commanded. static U32 dgReservoirDrainVolumeTarget = 0; ///< Latest drain-to volume reported by the DG. static U32 dgReservoirDrainVolumeTargetSet = 0; ///< Drain-to volume commanded. -static U32 resUseTimer = 0; ///< Used to track time pumping from active reservoir (for volume used calculation). -static F32 resUseVolumeMl = 0.0; ///< Accumulated volume used from active reservoir. + + static DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. +// TOD remove +// TODO New variables for the reservoir management +// TODO add these to the init function +static U32 timeStartMS = 0; ///< Used to track time pumping from active reservoir (for volume used calculation). +static U32 timeDepletionMS = 0; +static F32 volTotalMl = 0.0; +static F32 volSpentMl = 0.0; ///< Accumulated volume used from active reservoir. + +// TODO set the reservoirs alarms properties +// TODO remove + // DG command response static DG_CMD_RESPONSE_T dgCmdResp[ NUM_OF_DG_COMMANDS ]; ///< Keep the latest DG command response for each command. // ********** private function prototypes ********** -static void checkDGRestart( void ); +static void checkDGRestart( void ); + +// Reservoir management functions +static void checkReservoirDepletionTime( void ); +static void checkReservoirMaxVolume( void ); + +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtStartState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtDrainState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitToFillState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtFillState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForFillSettleState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForSwitchSettleState( void ); /*********************************************************************//** * @brief @@ -201,8 +230,8 @@ { currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; resMgmtTimer = 0; - resUseTimer = getMSTimerCount(); - resUseVolumeMl = 0.0; + timeStartMS = getMSTimerCount(); + volSpentMl = 0.0; } /*********************************************************************//** @@ -215,7 +244,7 @@ *************************************************************************/ void dialysisResumed( void ) { - resUseTimer = getMSTimerCount(); + timeStartMS = getMSTimerCount(); } /*********************************************************************//** @@ -226,19 +255,19 @@ * @details Outputs: DG reservoirs (drains & fills) managed. * @return none *************************************************************************/ -void execTreatmentReservoirMgmt( void ) +void execTreatmentReservoirMgmt( void ) // TODO remove this exec DEBUG_DENALI yes later not now! { DG_OP_MODE_T dgOpMode = getDGOpMode(); U32 dgSubMode = getDGSubMode(); - U32 msSinceLastVolumeCalc = calcTimeSince( resUseTimer ); + U32 msSinceLastVolumeCalc = calcTimeSince( timeStartMS ); F32 flowRateMlPerMs = (F32)getTargetDialInFlowRate() / (F32)( MS_PER_SECOND * SEC_PER_MIN ); // Calculate volume used from active reservoir - do not accumulate if saline bolus in progress if ( SALINE_BOLUS_STATE_IN_PROGRESS != getSalineBolusState() ) { - resUseVolumeMl += ( flowRateMlPerMs * msSinceLastVolumeCalc ); + volSpentMl += ( flowRateMlPerMs * msSinceLastVolumeCalc ); } - resUseTimer = getMSTimerCount(); + timeStartMS = getMSTimerCount(); // TODO this should go to one of the handlers probably wait for reservoir to settle state prior to switching to drain // Alarm if active reservoir is full and inactive reservoir is not yet ready if ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) @@ -257,10 +286,10 @@ switch ( currentTrtResMgmtState ) { case TREATMENT_RESERVOIR_MGMT_START_STATE: - currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE; + currentTrtResMgmtState = handleReservoirMgmtStartState(); break; - case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: + case TREATMENT_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE: // TODO remove if ( DG_MODE_GENE == dgOpMode ) { if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) @@ -331,7 +360,7 @@ case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE: // Reservoir switch during treatment should only occur in this state (i.e. when DG is ready). // Switch reservoirs when active reservoir is spent or full (i.e. we have pumped fill volume through dialyzer) and DG ready - if ( ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) || ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) ) + if ( ( volSpentMl >= (F32)dgReservoirFillVolumeTargetSet ) || ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) ) { DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); @@ -341,7 +370,7 @@ cmdSetDGActiveReservoir( inactiveRes ); // Signal dialysis sub-mode to switch reservoirs signalReservoirsSwitched(); - resUseVolumeMl = 0.0; + volSpentMl = 0.0; // Wait for used reservoir to settle resMgmtTimer = getMSTimerCount(); currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; @@ -363,8 +392,78 @@ currentTrtResMgmtState = TREATMENT_RESERVOIR_MGMT_START_STATE; break; } -} +} + + +static void checkReservoirDepletionTime( void ) +{ + if ( TRUE == didTimeout( timeStartMS, MAX_RESERVOIR_DEPLETION_TIME_MS ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT, calcTimeSince( timeStartMS ) ) + } +} + + +static void checkReservoirMaxVolume( void ) +{ + DG_RESERVOIR_ID_T active = getDGActiveReservoir(); + + if ( getReservoirWeight( active ) >= MAX_RESERVOIR_VOLUME_ML ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE, getReservoirWeight( active ) ) + } +} + +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtStartState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_START_STATE; + DG_OP_MODE_T dgOpMode = getDGOpMode(); + + if ( DG_MODE_GENE == dgOpMode ) + { + if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) + { + cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE, FALSE, TRUE ); + } + } + else if ( DG_MODE_DRAI == dgOpMode ) + { + state = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; + } + + return state; +} +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtDrainState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; + DG_OP_MODE_T dgOpMode = getDGOpMode(); + + if ( DG_MODE_GENE == dgOpMode ) + { + state = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; + } + + return state; +} + +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitToFillState( void ) +{ + +} +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtFillState( void ) +{ + +} +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForFillSettleState( void ) +{ + +} +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForSwitchSettleState( void ) +{ + +} + /*********************************************************************//** * @brief * The getDGOpMode function gets the current DG operating mode. @@ -1094,6 +1193,8 @@ #endif } +// ********** private functions ********** + /*********************************************************************//** * @brief * The checkDGRestart function checks to see if DG has restarted after started Index: firmware/App/Controllers/DGInterface.h =================================================================== diff -u -r09e6cf9de34acf18f6e1138bf56ac0edb4821186 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 09e6cf9de34acf18f6e1138bf56ac0edb4821186) +++ firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -31,7 +31,8 @@ */ // ********** public definitions ********** - + +// TODO remove the #defines #define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. #define FILL_RESERVOIR_TO_VOLUME_ML 1700 ///< Fill reservoir to this volume (in mL) during treatment. #define FILL_RESERVOIR_TO_VOLUME_LOW_FLOW_ML 1300 ///< Fill reservoir to this volume (in mL) during treatment if dialysate flow is slow. @@ -111,9 +112,9 @@ void execDGInterfaceMonitor( void ); -void initTreatmentReservoirMgmt( void ); +void initTreatmentReservoirMgmt( void ); // TODO remove void dialysisResumed( void ); -void execTreatmentReservoirMgmt( void ); +void execTreatmentReservoirMgmt( void ); // TODO remove DG_OP_MODE_T getDGOpMode( void ); U32 getDGSubMode( void ); Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -r09e6cf9de34acf18f6e1138bf56ac0edb4821186 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 09e6cf9de34acf18f6e1138bf56ac0edb4821186) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -1176,4 +1176,18 @@ resCurrVolume[ DG_RESERVOIR_2 ] = res2Vol; } +/*********************************************************************//** + * @brief + * The getReservoirUltrafiltrationVol function returns the ultrafiltration + * volume of a reservoir. + * @details Inputs: none + * @details Outputs: resStartVolume[], resFinalVolume[] + * @param reservoirID reservoir ID to calculate the ultrafiltration volume + * @return ultrafiltration volume of the reservoir + *************************************************************************/ +F32 getReservoirUltrafiltrationVol( DG_RESERVOIR_ID_T reservoirID ) +{ + return ( resFinalVolume[ reservoirID ] - resStartVolume[ reservoirID ] ); +} + /**@}*/ Index: firmware/App/Modes/Dialysis.h =================================================================== diff -u -rccfd15568f1e3d304320c2babb2fd4bcf0413304 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision ccfd15568f1e3d304320c2babb2fd4bcf0413304) +++ firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -75,6 +75,7 @@ void signalReservoirsSwitched( void ); void setFinalReservoirVolume( void ); void updateReservoirVolumes( F32 res1Vol, F32 res2Vol ); +F32 getReservoirUltrafiltrationVol( DG_RESERVOIR_ID_T reservoirID ); /**@}*/ Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r5e01e06bf4c6b05665ef096ea873d09b7bc904d3 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 5e01e06bf4c6b05665ef096ea873d09b7bc904d3) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -26,6 +26,7 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "Reservoirs.h" #include "Rinseback.h" #include "RTC.h" #include "SystemCommMessages.h" @@ -236,7 +237,7 @@ { // Initialize treatment mode each time we transition to it initTreatmentMode(); - initTreatmentReservoirMgmt(); + initReservoirs(); // Initialize treatment sub-modes each time we transition to treatment mode initBloodPrime(); initDialysis(); @@ -768,7 +769,8 @@ // Otherwise, execute state machine for treatment dialysis sub-mode else { - execTreatmentReservoirMgmt(); + // execTreatmentReservoirMgmt(); TODO DEBUG_DENALI remove later, yes later not now! + execReservoirs(); execDialysis(); // Handle alarm stoppage if ( TRUE == doesAlarmStatusIndicateStop() ) @@ -826,7 +828,8 @@ // Otherwise execute state machine for treatment stop sub-mode else { - execTreatmentReservoirMgmt(); + //execTreatmentReservoirMgmt(); TODO DEBUG_DENALI remove this later. Not now later! + execReservoirs(); execTreatmentStop(); } Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -rccfd15568f1e3d304320c2babb2fd4bcf0413304 -r549119eae64732f124d22df66de4fc88c56193c0 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision ccfd15568f1e3d304320c2babb2fd4bcf0413304) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -163,6 +163,7 @@ SW_FAULT_ID_SAFETY_SHUTDOWN_INVALID_SELF_TEST_STATE, SW_FAULT_ID_PHANTOM_INTERRUPT, SW_FAULT_ID_UNEXPECTED_DMA_INTERRUPT, // 130 + SW_FAULT_ID_INVALID_TREATMENT_RESERVOIR_MANAGEMENT_STATE, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u --- firmware/App/Services/Reservoirs.c (revision 0) +++ firmware/App/Services/Reservoirs.c (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -0,0 +1,407 @@ + + +// TODO the copyright will be added automatically + +#include "DGInterface.h" +#include "Dialysis.h" +#include "DialInFlow.h" +#include "MessageSupport.h" +#include "OperationModes.h" +#include "Reservoirs.h" +#include "TaskGeneral.h" +#include "Timers.h" + +// ********** private definitions ********** + +#define RESERVOIR_SETTLE_TIME_MS 5000 ///< Allocated time to settle the filled reservoir in milliseconds. + +#define MAX_RESERVOIR_VOLUME_ML 1950.0 ///< Maximum allowed fluid in a reservoir in milliliters. +#define MAX_RESERVOIR_DILUTION 0.15 ///< Maximum reservoir dilution limit. +#define MAX_RESERVOIR_RECIRCULATION 0.1 ///< Maximum reservoir recirculation limit. + +#define MAX_RESERVOIR_DEPLETION_TIME_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Maximum allowed depletion time in milliseconds. +#define RESERVOIR_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the reservoir data is published on the CAN bus. + +// ********** private data ********** + +/// States of the treatment reservoir management state machine. +typedef enum TreatmentReservoirMgmt_States +{ + TREATMENT_RESERVOIR_MGMT_START_STATE = 0, ///< Treatment reservoir management start state. + TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE, ///< Treatment reservoir management drain reservoir state. + TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE, ///< Treatment reservoir management wait to fill state. + TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE, ///< Treatment reservoir management fill state. + TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE, ///< Treatment reservoir management wait for fill to settle state. + TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE, ///< Treatment reservoir management wait for switch to settles state. + NUM_OF_TREATMENT_RESERVOIR_MGMT_STATES ///< Number of treatment reservoir management states. +} TREATMENT_RESERVOIR_MGMT_STATE_T; + +// TODO update the init function with all the newest variables +static TREATMENT_RESERVOIR_MGMT_STATE_T reservoirsState; ///< Treatment mode's reservoirs state. +static U32 timeStartMS = 0; ///< Active reservoir start time in milliseconds. +static U32 timeDepletionMS = 0; ///< Active reservoir depletion time in milliseconds. +static F32 volTotalML = 0.0; ///< Active reservoir total volume in milliliters. +static F32 volSpentML = 0.0; ///< Active reservoir spent volume in milliliters. +static U32 reservoirPublicationCounter = 0; ///< Reservoirs data publication timer counter. +static F32 dilutionLevel = 0.0; +static DG_OP_MODE_T dgOpMode = DG_MODE_INIT; +static U32 dgSubMode = 0; +static U32 timeReservoirInUseMS = 0; +static F32 volSpentUFML = 0.0; +static DG_RESERVOIR_ID_T activeReservoir; +static F32 recirculationLevelPct = 0.0; +static U32 reservoirSwitchTimer = 0; + +// TODO set the reservoirs alarms properties in the alarmsDefs.h so the alarms will be recoverable + +// ********** private function prototypes ********** + +// Reservoir management functions +static void checkReservoirDepletionTime( void ); +static void checkReservoirMaxVolume( void ); +static void publishReservoirData( void ); + +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtStartState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtDrainState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitToFillState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtFillState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForFillSettleState( void ); +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForSwitchSettleState( void ); + +/*********************************************************************//** + * @brief + * The initReservoirs function initializes the treatment reservoir management + * state machine. + * @details Inputs: none + * @details Outputs: reservoirsState, timeStartMS, timeDepletionMS, volTotalMl, + * volSpentMl, reservoirsPublicationCounter TODO add all the variables later + * @return none + *************************************************************************/ +void initReservoirs( void ) +{ + reservoirsState = TREATMENT_RESERVOIR_MGMT_START_STATE; + timeStartMS = 0; + timeDepletionMS = 0; + volTotalML = 0.0; + volSpentML = 0.0; + reservoirPublicationCounter = 0; +} + +/*********************************************************************//** + * @brief + * The execReservoirs function executes the state machine for the treatment + * reservoir management during treatment mode. + * @details Inputs: reservoirsStatus + * @details Outputs: reservoirsStatus + * @return none + *************************************************************************/ +void execReservoirs( void ) +{ + U32 msSinceLastVolumeCalc = calcTimeSince( timeStartMS ); + F32 flowRateMLPerMS = (F32)getTargetDialInFlowRate() / (F32)( MS_PER_SECOND * SEC_PER_MIN ); + + activeReservoir = getDGActiveReservoir(); + dgOpMode = getDGOpMode(); + dgSubMode = getDGSubMode(); + + checkReservoirDepletionTime(); + checkReservoirMaxVolume(); + + // TODO do we need this? Should we not call the reservoir management exec function in saline bolus? + + // Calculate volume used from active reservoir - do not accumulate if saline bolus is in progress + if ( getSalineBolusState() != SALINE_BOLUS_STATE_IN_PROGRESS ) + { + volSpentML += ( flowRateMLPerMS * msSinceLastVolumeCalc ); + } + // Update the reservoir start time + timeStartMS = getMSTimerCount(); + + switch( reservoirsState ) + { + case TREATMENT_RESERVOIR_MGMT_START_STATE: + reservoirsState = handleReservoirMgmtStartState(); + break; + + case TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE: + reservoirsState = handleReservoirMgmtDrainState(); + break; + + case TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE: + reservoirsState = handleReservoirMgmtWaitToFillState(); + break; + + case TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE: + reservoirsState = handleReservoirMgmtFillState(); + break; + + case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE: + reservoirsState = handleReservoirMgmtWaitForFillSettleState(); + break; + + case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE: + reservoirsState = handleReservoirMgmtWaitForSwitchSettleState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_TREATMENT_RESERVOIR_MANAGEMENT_STATE, (U32)reservoirsState ); + reservoirsState = TREATMENT_RESERVOIR_MGMT_START_STATE; + } + + publishReservoirData(); +} + +// ********** private functions ********** + +/*********************************************************************//** + * @brief + * The checkReservoirDepletionTime function checks whether the active reservoir's + * depletion time has elapsed or not. If it has elapsed, it raises an alarm. + * @details Inputs: timeStartMS + * @details Outputs: none + * @return none + *************************************************************************/ +static void checkReservoirDepletionTime( void ) +{ + // Check if the time that the reservoir has been use has exceeded the limit + if ( TRUE == didTimeout( timeReservoirInUseMS, MAX_RESERVOIR_DEPLETION_TIME_MS ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT, calcTimeSince( timeReservoirInUseMS ) ) + } +} + +/*********************************************************************//** + * @brief + * The checkReservoirMaxVolume function checks whether the active reservoir's + * filled volume has exceeded maximum allowed value in milliliters. If it has + * exceeded, it raises an alarm. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +static void checkReservoirMaxVolume( void ) +{ + DG_RESERVOIR_ID_T active = getDGActiveReservoir(); + + if ( getReservoirWeight( active ) >= MAX_RESERVOIR_VOLUME_ML ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE, getReservoirWeight( active ) ) + } +} + +/*********************************************************************//** + * @brief + * The publishReservoirData function publishes reservoirs data during treatment. + * @details Inputs: reservoirsPublicationCounter + * @details Outputs: reservoirsPublicationCounter + * @return none + *************************************************************************/ +static void publishReservoirData( void ) +{ + if ( ++reservoirPublicationCounter > RESERVOIR_DATA_PUB_INTERVAL ) + { + RESERVOIRS_MANAGEMENT_DATA_T data; + + data.reservoirsExecState = (U32)reservoirsState; + + broadcastData( MSG_ID_HD_RESERVOIRS_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( RESERVOIRS_MANAGEMENT_DATA_T ) ); + + reservoirPublicationCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtStartState function executes the reservoir management + * start state. + * @details Inputs: none + * @details Outputs: none + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtStartState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_START_STATE; + + if ( DG_MODE_GENE == dgOpMode ) + { + if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == getDGSubMode() ) + { + cmdStartDGDrain( DRAIN_RESERVOIR_TO_VOLUME_ML, TRUE, FALSE, TRUE ); + } + } + else if ( DG_MODE_DRAI == dgOpMode ) + { + state = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtDrainState function executes the reservoir management + * drain state. + * @details Inputs: none + * @details Outputs: none + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtDrainState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_DRAIN_RESERVOIR_STATE; + + if ( DG_MODE_GENE == dgOpMode ) + { + state = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtWaitToFillState function executes the reservoir management + * wait to fill state. + * @details Inputs: dilutionLevel, volSpentML, dgSubMode + * @details Outputs: dilutionLevel, volSpentML, volSpentUFML, timeDepletionMS + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitToFillState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_WAIT_TO_FILL_STATE; + + // Calculate the dilution level + dilutionLevel = volSpentML / (F32)FILL_RESERVOIR_TO_VOLUME_ML; + + // Check if the dilution level has exceeded the limit or the spent volume is more than the amount of volume in the reservoir + // If it has, trigger the fill command + if ( ( dilutionLevel >= MAX_RESERVOIR_DILUTION ) || ( volSpentML >= (F32)FILL_RESERVOIR_TO_VOLUME_ML ) ) + { + if ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) + { + cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML ); + } + + state = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; + } + else + { + F32 volFreshML = FILL_RESERVOIR_TO_VOLUME_ML - volSpentML; + F32 timeFreshRemaining = volFreshML / ( getDGDialysateFlowRateLMin() * 1000 ); + F32 volMaxUFML = FILL_RESERVOIR_TO_VOLUME_ML * MAX_RESERVOIR_DILUTION; + volSpentUFML = getReservoirUltrafiltrationVol( activeReservoir ); + F32 volRemainingUF = volMaxUFML - volSpentUFML; + F32 timeDepleteRemaining = volRemainingUF / ( volSpentUFML / SEC_PER_MIN ); + + timeDepletionMS = MIN( timeFreshRemaining, timeDepleteRemaining ); + + // TODO what is twait? + + // TODO add the if condition to whether fill should be triggered or not + cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML ); + state = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtFillState function executes the reservoir management + * fill state. + * @details Inputs: recirculationLevelPct, dgOpMode, dgSubMode + * @details Outputs: recirculationLevelPct, reservoirSwitchTimer + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtFillState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_FILL_RESERVOIR_STATE; + + // Check the recirculation level + recirculationLevelPct = ( (F32)FILL_RESERVOIR_TO_VOLUME_ML - volSpentML ) / (F32)FILL_RESERVOIR_TO_VOLUME_ML; + + // If the recirculation level has exceeded the max allowed, raise the alarm to stop using the active reservoir as it has been + // diluted to much + if ( recirculationLevelPct >= MAX_RESERVOIR_RECIRCULATION ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE, recirculationLevelPct ) + } + // TODO check maximum vfill here shouldn't we do it in the mode fill in DG? + // TODO check fill timeout? + + if ( ( DG_MODE_GENE == dgOpMode ) && ( DG_GEN_IDLE_MODE_STATE_FLUSH_WATER == dgSubMode ) ) + { + // Clear any of the recoverable conditions in case they were raised during the fill or wait to fill + clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE ); + clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT ); + clearAlarmCondition( ALARM_ID_HD_ACTIVE_RESERVOIR_WEIGHT_OUT_OF_RANGE ); + + reservoirSwitchTimer = getMSTimerCount(); + state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtWaitForFillSettleState function executes the reservoir + * management wait for fill to settle state. + * @details Inputs: reservoirSwitchTimer + * @details Outputs: reservoirSwitchTimer, volSpentML + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForFillSettleState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_FILL_SETTLE_STATE; + + // Wait for the reservoir to settle and then send the commands to switch the active reservoir + if ( TRUE == didTimeout( reservoirSwitchTimer, RESERVOIR_SETTLE_TIME_MS ) ) + { + DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); + + // Signal dialysis sub-mode to capture baseline volume for next reservoir. + setStartReservoirVolume( inactiveRes ); + + // Command DG to switch reservoirs + cmdSetDGActiveReservoir( inactiveRes ); + + // Signal dialysis sub-mode to switch reservoirs + signalReservoirsSwitched(); + + // Get ready for the next delivery + volSpentML = 0.0; + + // Wait for used reservoir to settle + reservoirSwitchTimer = getMSTimerCount(); + + state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleReservoirMgmtWaitForSwitchSettleState function executes the reservoir + * management wait for switch to settle state. + * @details Inputs: reservoirSwitchTimer + * @details Outputs: none + * @return next reservoir management state of the state machine + *************************************************************************/ +static TREATMENT_RESERVOIR_MGMT_STATE_T handleReservoirMgmtWaitForSwitchSettleState( void ) +{ + TREATMENT_RESERVOIR_MGMT_STATE_T state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; + + if ( TRUE == didTimeout( reservoirSwitchTimer, RESERVOIR_SETTLE_TIME_MS ) ) + { + // Signal dialysis sub-mode to capture final volume of prior reservoir after settling. + setFinalReservoirVolume(); + + // Reset to start state to restart drain, fill, switch process. + state = TREATMENT_RESERVOIR_MGMT_START_STATE; + } + + return state; +} + +/**@}*/ Index: firmware/App/Services/Reservoirs.h =================================================================== diff -u --- firmware/App/Services/Reservoirs.h (revision 0) +++ firmware/App/Services/Reservoirs.h (revision 549119eae64732f124d22df66de4fc88c56193c0) @@ -0,0 +1,38 @@ + +// TODO the copyright will be added automatically + +#ifndef _RESERVOIRS_H_ +#define _RESERVOIRS_H_ + +#include "HDCommon.h" +#include "DGDefs.h" + +/** + * @defgroup Reservoirs Reservoirs + * @brief Reservoir management module. + * + * @addtogroup Reservoirs + * @{ + */ + +// ********** public definitions ********** + +#define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. +#define FILL_RESERVOIR_TO_VOLUME_ML 1500 ///< Fill reservoir to this volume (in mL) during treatment. + +/// Reservoir management publish data structure +typedef struct +{ + U32 reservoirsExecState; ///< Reservoirs exec state. + F32 activeReservoirUFVolML; ///< Active reservoir ultrafiltration volume milliliters. +} RESERVOIRS_MANAGEMENT_DATA_T; + +// ********** public function prototypes ********** + +void initReservoirs( void ); + +void execReservoirs( void ); + +/**@}*/ + +#endif