Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -r30f049651877229042e3f8700c8596e5b9a1e0f4 -ra997e6d608a9970a948bda978dade1148269ff90 --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision 30f049651877229042e3f8700c8596e5b9a1e0f4) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision a997e6d608a9970a948bda978dade1148269ff90) @@ -56,6 +56,9 @@ #define OCCLUSION_THRESHOLD 25000 ///< Threshold above which an occlusion is detected. #define CARTRIDGE_LOADED_THRESHOLD 5000 ///< Threshold above which a cartridge is considered loaded. +#define EMPTY_SALINE_BAG_THRESHOLD_MMHG -300.0 ///< Threshold below which the saline bag is considered empty (in mmHg). TODO - get real threshold from Systems +#define EMPTY_SALINE_BAG_PERSISTENCE ( 250 / TASK_GENERAL_INTERVAL ) ///< Time that saline bag looks empty before saying it is empty. TODO - use persistent alarm when updated + #define PRES_ALARM_PERSISTENCE ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for pressure alarms. /// Defined states for the pressure and occlusion monitor state machine. @@ -93,6 +96,7 @@ static U32 bloodPumpSelfTestTimerCount = 0; ///< Timer counter for pressure self-test. static U32 staleVenousPressureCtr = 0; ///< Timer counter for stale venous pressure reading. +static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. // ********** private function prototypes ********** @@ -151,6 +155,35 @@ return result; } +/*********************************************************************//** + * @brief + * The isSalineBagEmpty function determines whether the saline bag is empty. + * It is assumed that this function will only be called from mode handling + * (General Task) when pumping (BP) from the saline bag. + * Determination is based on pressure going below a negative threshold. + * @details Inputs: arterial line pressure + * @details Outputs: none + * @return TRUE if arterial line pressure is below threshold, FALSE if not. + *************************************************************************/ +BOOL isSalineBagEmpty( void ) +{ + BOOL result = FALSE; + + if ( getMeasuredArterialPressure() < EMPTY_SALINE_BAG_THRESHOLD_MMHG ) + { + if ( ++emptySalineBagCtr >= EMPTY_SALINE_BAG_PERSISTENCE ) + { + result = TRUE; + } + } + else + { + emptySalineBagCtr = 0; + } + + return result; +} + /*********************************************************************//** * @brief * The execPresOccl function executes the pressure and occlusion monitor. Index: firmware/App/Controllers/PresOccl.h =================================================================== diff -u -r30f049651877229042e3f8700c8596e5b9a1e0f4 -ra997e6d608a9970a948bda978dade1148269ff90 --- firmware/App/Controllers/PresOccl.h (.../PresOccl.h) (revision 30f049651877229042e3f8700c8596e5b9a1e0f4) +++ firmware/App/Controllers/PresOccl.h (.../PresOccl.h) (revision a997e6d608a9970a948bda978dade1148269ff90) @@ -72,6 +72,7 @@ U32 getMeasuredDialOutPumpOcclusion( void ); BOOL isCartridgeLoaded( void ); +BOOL isSalineBagEmpty( void ); BOOL testSetPresOcclDataPublishIntervalOverride( U32 value ); BOOL testResetPresOcclDataPublishIntervalOverride( void ); Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -r1b27784f400d03678a1441cd70ab1c4111bbfa04 -ra997e6d608a9970a948bda978dade1148269ff90 --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 1b27784f400d03678a1441cd70ab1c4111bbfa04) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision a997e6d608a9970a948bda978dade1148269ff90) @@ -24,6 +24,7 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "PresOccl.h" #include "Rinseback.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" @@ -44,6 +45,7 @@ #define MIN_RINSEBACK_FLOW_RATE_ML_MIN 50 ///< Minimum rinseback flow rate (in mL/min). #define MAX_RINSEBACK_FLOW_RATE_ML_MIN 150 ///< Maximum rinseback flow rate (in mL/min). #define MAX_RINSEBACK_SAFETY_VOLUME_MARGIN_PCT 1.2 ///< Maximum rinseback volume measured by independent means (as % of target). +#define MIN_RINSEBACK_SAFETY_VOLUME_MARGIN_PCT 0.8 ///< Minimum rinseback volume measured by independent means (as % of target). /// Interval at which rinseback progress is to be published to UI. #define RINSEBACK_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) @@ -345,16 +347,31 @@ rinsebackLastMotorCount = bldPumpMotorCount; rinsebackVolumeDelivered_Safety = ( (F32)rinsebackMotorCount * VOLUME_PER_BP_MOTOR_REV_ML ); // TODO - include upstream pressure compensation to this calc + // Has user requested to end rinseback? + if ( TRUE == endRinsebackRequested ) + { + endRinsebackRequested = FALSE; + setupForRinsebackStopOrPause(); + result = RINSEBACK_STOP_STATE; + } // Has rinseback completed or user requested to end rinseback? - if ( ( cumulativeRinsebackVolume_mL >= TARGET_RINSEBACK_VOLUME_ML ) || ( TRUE == endRinsebackRequested ) ) + else if ( cumulativeRinsebackVolume_mL >= TARGET_RINSEBACK_VOLUME_ML ) { - if ( FALSE == endRinsebackRequested ) + setRinsebackIsCompleted( TRUE ); + setupForRinsebackStopOrPause(); + result = RINSEBACK_STOP_STATE; + // check for under-delivery + if ( rinsebackVolumeDelivered_Safety < ( TARGET_RINSEBACK_VOLUME_ML * MIN_RINSEBACK_SAFETY_VOLUME_MARGIN_PCT ) ) { - setRinsebackIsCompleted( TRUE ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, rinsebackVolumeDelivered_Safety ); } - endRinsebackRequested = FALSE; + } + // Check for empty saline bag + if ( TRUE == isSalineBagEmpty() ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, 0.0 ); // TODO - give data supporting empty bag detection setupForRinsebackStopOrPause(); - result = RINSEBACK_STOP_STATE; + result = RINSEBACK_PAUSED_STATE; } // Has rinseback operation exceeded max time? else if ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) @@ -375,6 +392,7 @@ { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, rinsebackVolumeDelivered_Safety ); result = RINSEBACK_STOP_STATE; } // Otherwise, continue rinseback @@ -507,6 +525,13 @@ setupForRinsebackStopOrPause(); result = RINSEBACK_STOP_STATE; } + // Check for empty saline bag + if ( TRUE == isSalineBagEmpty() ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, 0.0 ); // TODO - give data supporting empty bag detection + setupForRinsebackStopOrPause(); + result = RINSEBACK_STOP_STATE; + } // Has alarm requested stop? else if( TRUE == rinsebackStopRequested ) {