Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -r27f3db92495948d4c1192421c1b0c20338c4a034 -rba15d3e6250e8cd3cd3ef39cb64a93f91c3caba2 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 27f3db92495948d4c1192421c1b0c20338c4a034) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision ba15d3e6250e8cd3cd3ef39cb64a93f91c3caba2) @@ -79,7 +79,7 @@ static F32 totalSalineVolumeDelivered; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). static F32 bolusSalineVolumeDelivered; ///< Volume (mL) of current bolus delivered so far. static F32 bolusSalineVolumeDelivered_Safety; ///< Volume (mL) of current bolus delivered so far according to safety monitor. -static U32 bolusSalineMotorCount; ///< Blood pump motor rev count during saline bolus to calculate saline bolus volume independently for safety. +static S32 bolusSalineMotorCount; ///< Blood pump motor rev count during saline bolus to calculate saline bolus volume independently for safety. static U32 bolusSalineLastMotorCount; ///< Last blood pump count from last saline bolus volume update. static U32 bolusSalineLastVolumeTimeStamp; ///< Time stamp for last saline volume update. @@ -94,14 +94,14 @@ static UF_STATE_T handleUFStartState( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFPausedState( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFRunningState( DIALYSIS_STATE_T *dialysisState ); -static UF_STATE_T handleUFOffState( DIALYSIS_STATE_T *dialysisState ); -static UF_STATE_T handleUFCompletedState( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusIdleState( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusWait4Pumps2Stop( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusInProgressState( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusMaxDeliveredState( DIALYSIS_STATE_T *dialysisState ); +static void startHeparinPump( void ); + static void checkUFAccuracyAndVolume( void ); static void updateUFVolumes( void ); @@ -201,7 +201,8 @@ setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); #endif setDialOutPumpTargetRate( setDialysateFlowRate + (S32)setUFRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - // TODO - Heparin pump + // Start Heparin pump as appropriate + startHeparinPump(); // Tell DG to start heating dialysate cmdStartDGTrimmerHeater(); @@ -215,6 +216,42 @@ /*********************************************************************//** * @brief + * The startHeparinPump function sets the syringe pump running as appropriate + * when starting/resuming dialysis sub-mode. + * @details Inputs: Heparin treatment parameters, treatment time remaining + * @details Outputs: Syringe pump started/stopped as appropriate + * @return none + *************************************************************************/ +static void startHeparinPump( void ) +{ + HEPARIN_STATE_T currentHeparinState = getHeparinState(); + U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); + U32 minRem = getTreatmentTimeRemainingSecs() / SEC_PER_MIN; + F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); + F32 hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); + + // Do not run syringe pump if no Heparin included in prescription or it was paused or if Heparin should be stopped at this stage of treatment + if ( ( minRem > preStop ) && ( HEPARIN_STATE_STOPPED == currentHeparinState ) ) + { + // If not done with bolus, start/resume bolus + if ( ( bolusVol > 0.0 ) && ( getSyringePumpVolumeDelivered() < bolusVol ) ) + { + startHeparinBolus(); // TODO - check return status + } + // Otherwise, start/resume continuous delivery + else + { + startHeparinContinuous(); // TODO - check return status + } + } + else + { + stopSyringePump(); + } +} + +/*********************************************************************//** + * @brief * The setDialysisParams function sets the dialysis treatment parameters. * This function should be called prior to beginning dialysis treatment * and when the user changes one or more parameters during treatment. @@ -261,7 +298,7 @@ setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - // TODO - stop Heparin pump + stopSyringePump(); // Tell DG to stop heating dialysate cmdStopDGTrimmerHeater(); } @@ -392,7 +429,7 @@ * volume collected so far for current treatment. * @details Inputs: measUFVolume, measUFVolumeFromPriorReservoirs * @details Outputs: none - * @return currentUFState + * @return measUFVolume *************************************************************************/ F32 getUltrafiltrationVolumeCollected( void ) { @@ -403,6 +440,19 @@ /*********************************************************************//** * @brief + * The getUltrafiltrationReferenceVolume function gets the current ultrafiltration + * reference volume. + * @details Inputs: measUFVolume, measUFVolumeFromPriorReservoirs + * @details Outputs: none + * @return refUFVolume + *************************************************************************/ +F32 getUltrafiltrationReferenceVolume( void ) +{ + return refUFVolume; +} + +/*********************************************************************//** + * @brief * The pauseUF function pauses ultrafiltration. * @details Inputs: currentDialysisState, currentUFState * @details Outputs: currentUFState, outlet pump set point @@ -446,8 +496,6 @@ // Send response w/ reason code if rejected sendUFPauseResumeResponse( result, rejectReason, currentUFState ); - // Send state data immediately for UI update - broadcastTreatmentTimeAndState(); return result; } @@ -474,7 +522,7 @@ setDialOutPumpTargetRate( setDialysateFlowRate + FLOAT_TO_INT_WITH_ROUND( setUFRate ), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Restart UF time accumulation for reference volume calculation lastUFTimeStamp = getMSTimerCount(); - // Go to UF paused state + // Go to UF running state currentUFState = UF_RUNNING_STATE; } else @@ -552,7 +600,22 @@ static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ) { DIALYSIS_STATE_T result = DIALYSIS_UF_STATE; + U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); + U32 minRem = getTreatmentTimeRemainingSecs() / SEC_PER_MIN; + // Stop Heparin delivery if we have reached Heparin pre-stop point + if ( getTreatmentTimeRemainingSecs() < preStop ) + { + stopSyringePump(); + setHeparinCompleted(); + } + // TODO - find a better way to start continuous delivery after bolus completes + if ( HEPARIN_STATE_STOPPED == getHeparinState() ) + { + startHeparinPump(); + } + + // Handle current ultrafiltration state switch ( currentUFState ) { case UF_START_STATE: @@ -567,17 +630,9 @@ currentUFState = handleUFRunningState( &result ); break; - case UF_OFF_STATE: - currentUFState = handleUFOffState( &result ); - break; - - case UF_COMPLETED_STATE: - currentUFState = handleUFCompletedState( &result ); - break; - default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIALYSIS_INVALID_UF_STATE, currentUFState ) - currentUFState = UF_COMPLETED_STATE; + currentUFState = UF_PAUSED_STATE; break; } @@ -637,16 +692,9 @@ { UF_STATE_T result; - if ( maxUFVolumeML < NEARLY_ZERO ) - { - result = UF_OFF_STATE; - } - else - { - lastUFTimeStamp = getMSTimerCount(); - uFTimeMS = 0; - result = UF_RUNNING_STATE; - } + lastUFTimeStamp = getMSTimerCount(); + uFTimeMS = 0; + result = UF_RUNNING_STATE; return result; } @@ -681,17 +729,6 @@ salineBolusStartRequested = FALSE; } } - // Handle auto-resume after saline bolus - else if ( TRUE == salineBolusAutoResumeUF ) - { - salineBolusAutoResumeUF = FALSE; - // Set outlet pump to dialysate rate + set UF rate - setDialOutPumpTargetRate( setDialysateFlowRate + FLOAT_TO_INT_WITH_ROUND( setUFRate ), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); - // Restart UF time accumulation for reference volume calculation - lastUFTimeStamp = getMSTimerCount(); - // Resume UF - result = UF_RUNNING_STATE; - } return result; } @@ -719,16 +756,17 @@ // Update UF ref volume in UF running state only refUFVolume += ( ( (F32)msSinceLast / MS_PER_SECOND ) / SEC_PER_MIN ) * setUFRate; - // Calculate UF volumes and provide to dialysate outlet pump controller - updateUFVolumes(); - - // If we have reached target UF volume, UF is complete + // If we have reached target UF volume, UF is complete - set UF rate to zero for remainder of treatment if ( refUFVolume >= maxUFVolumeML ) { - result = UF_COMPLETED_STATE; + setUFRate = 0.0; } + + // Calculate UF volumes and provide to dialysate outlet pump controller + updateUFVolumes(); + // Handle saline bolus start request from user - else if ( TRUE == salineBolusStartRequested ) + if ( TRUE == salineBolusStartRequested ) { if ( SALINE_BOLUS_STATE_IDLE == currentSalineBolusState ) { @@ -750,74 +788,6 @@ /*********************************************************************//** * @brief - * The handleUFCompletedOrOffState function handles the UF Off state - * of the ultrafiltration state machine. - * @details Inputs: none - * @details Outputs: UF volumes updated and provided to DPo pump controller. - * @param dialysisState next dialysis state - * @return next ultrafiltration state - *************************************************************************/ -static UF_STATE_T handleUFOffState( DIALYSIS_STATE_T *dialysisState ) -{ - UF_STATE_T result = UF_OFF_STATE; - - // Calculate UF volumes and provide to dialysate outlet pump controller - updateUFVolumes(); - - // Handle saline bolus start request from user - if ( TRUE == salineBolusStartRequested ) - { - salineBolusAutoResumeUF = FALSE; - // Go to saline bolus state - if ( SALINE_BOLUS_STATE_IDLE == currentSalineBolusState ) - { - *dialysisState = DIALYSIS_SALINE_BOLUS_STATE; - } - else - { - salineBolusStartRequested = FALSE; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The handleUFCompletedState function handles the UF Completed - * state of the ultrafiltration state machine. This is a terminal state. - * @details Inputs: none - * @details Outputs: UF volumes updated and provided to DPo pump controller. - * @param dialysisState next dialysis state - * @return next ultrafiltration state - *************************************************************************/ -static UF_STATE_T handleUFCompletedState( DIALYSIS_STATE_T *dialysisState ) -{ - UF_STATE_T result = UF_COMPLETED_STATE; - - // Calculate UF volumes and provide to dialysate outlet pump controller - updateUFVolumes(); - - // Handle saline bolus start request from user - if ( TRUE == salineBolusStartRequested ) - { - salineBolusAutoResumeUF = FALSE; - // Go to saline bolus state - if ( SALINE_BOLUS_STATE_IDLE == currentSalineBolusState ) - { - *dialysisState = DIALYSIS_SALINE_BOLUS_STATE; - } - else - { - salineBolusStartRequested = FALSE; - } - } - - return result; -} - -/*********************************************************************//** - * @brief * The handleSalineBolusIdleState function handles the idle state of the * saline bolus state machine. * @details Inputs: none @@ -834,15 +804,10 @@ { salineBolusStartRequested = FALSE; // Cmd all pumps to stop -#ifndef RUN_PUMPS_OPEN_LOOP setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#else - setBloodPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialOutPumpTargetRate( 0, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); -#endif + stopSyringePump(); // Begin saline bolus result = SALINE_BOLUS_STATE_WAIT_FOR_PUMPS_STOP; } @@ -913,26 +878,21 @@ F32 bolusTargetVolume = (F32)getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); F32 bldFlowRate = getMeasuredBloodFlowRate(); // TODO - should I use raw flow instead of filtered here??? F32 volSinceLastUpdateMl = bldFlowRate * timeSinceLastVolumeUpdateMin; - U32 bldPumpMotorCount = getBloodPumpMotorCount(); - U32 bldPumpMotorDelta = u32DiffWithWrap( bolusSalineLastMotorCount, bldPumpMotorCount ); // Update saline bolus volumes bolusSalineLastVolumeTimeStamp = getMSTimerCount(); bolusSalineVolumeDelivered += volSinceLastUpdateMl; totalSalineVolumeDelivered += volSinceLastUpdateMl; - bolusSalineMotorCount += bldPumpMotorDelta; - bolusSalineLastMotorCount = bldPumpMotorCount; - bolusSalineVolumeDelivered_Safety = ( (F32)bolusSalineMotorCount * VOLUME_PER_BP_MOTOR_REV_ML ); // TODO - include upstream pressure compensation to this calc + bolusSalineMotorCount = u32BiDiffWithWrap( bolusSalineLastMotorCount, getBloodPumpMotorCount() ) / BP_HALL_EDGE_COUNTS_PER_REV; + bolusSalineVolumeDelivered_Safety = ( (F32)bolusSalineMotorCount * VOLUME_PER_BP_MOTOR_REV_ML ); // TODO - include upstream pressure compensation to this calc (from PBA). -#ifndef DISABLE_SALINE_BOLUS_CHECKS - // TODO - check for empty saline bag - if ( 0 ) + // Check for empty saline bag per arterial line pressure + if ( TRUE == isSalineBagEmpty() ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, 0.0 ); // TODO - give data supporting empty bag detection + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_EMPTY_SALINE_BAG, getMeasuredArterialPressure() ); errorFound = TRUE; result = SALINE_BOLUS_STATE_IDLE; } -#endif // Determine if we have reached maximum saline delivery volume if ( ( totalSalineVolumeDelivered >= (F32)MAX_SALINE_VOLUME_DELIVERED ) ) @@ -947,7 +907,7 @@ // If safety thinks we have under-delivered the bolus, throw a fault if ( bolusSalineVolumeDelivered_Safety < ( bolusTargetVolume * MIN_SALINE_BOLUS_VOLUME_PCT ) ) { -#ifndef DISABLE_SALINE_BOLUS_CHECKS +#ifndef DISABLE_PUMP_FLOW_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_SALINE_BOLUS_VOLUME_CHECK_FAILURE, bolusTargetVolume, bolusSalineVolumeDelivered_Safety ); errorFound = TRUE; #endif @@ -963,7 +923,7 @@ // Determine if safety thinks we have over-delivered the bolus else if ( bolusSalineVolumeDelivered_Safety > ( bolusTargetVolume * MAX_SALINE_BOLUS_VOLUME_PCT ) ) { -#ifndef DISABLE_SALINE_BOLUS_CHECKS +#ifndef DISABLE_PUMP_FLOW_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_SALINE_BOLUS_VOLUME_CHECK_FAILURE, bolusTargetVolume, bolusSalineVolumeDelivered_Safety ); errorFound = TRUE; result = SALINE_BOLUS_STATE_IDLE; @@ -989,6 +949,7 @@ // Resume UF if appropriate if ( TRUE == salineBolusAutoResumeUF ) { + salineBolusAutoResumeUF = FALSE; currentUFState = UF_RUNNING_STATE; } // Resume dialysis @@ -1034,7 +995,7 @@ { SALINE_BOLUS_DATA_PAYLOAD_T data; - data.maxSalineVolumeMl = MAX_SALINE_VOLUME_DELIVERED; + data.tgtSalineVolumeMl = getTreatmentParameterU32( TREATMENT_PARAM_SALINE_BOLUS_VOLUME ); data.cumSalineVolumeMl = totalSalineVolumeDelivered; data.bolSalineVolumeMl = bolusSalineVolumeDelivered; broadcastSalineBolusData( data ); @@ -1091,7 +1052,8 @@ static void updateUFVolumes( void ) { DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); - F32 latestResVolume = getReservoirWeightSmallFilter( activeRes ); + LOAD_CELL_ID_T loadCell = ( activeRes == DG_RESERVOIR_1 ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); + F32 latestResVolume = getLoadCellWeight( loadCell ); #ifndef DISABLE_UF_ALARMS F32 deltaVolume = latestResVolume - resFinalVolume[ activeRes ];