Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -racf165d4bdd93d15f77e12e4cef3af7d6fb322ca -r8466e63f95f65a3ffb18c3af85ac99328e41167b --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision acf165d4bdd93d15f77e12e4cef3af7d6fb322ca) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 8466e63f95f65a3ffb18c3af85ac99328e41167b) @@ -52,7 +52,7 @@ #endif /// Interval at which rinseback progress is to be published to UI. -static const U32 RINSEBACK_DATA_PUBLISH_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); +#define RINSEBACK_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) /// Maximum time allowed for rinseback operation until full volume is delivered. Timer is reset whenever BP is running. static const U32 MAX_RINSEBACK_TIME = ( 5 * SEC_PER_MIN * ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); /// Maximum time allowed for each additional rinseback volume delivery. @@ -66,14 +66,16 @@ static U32 rinsebackRate_mL_min; ///< Rinseback rate to use/adjust for this current rinseback only. static U32 rinsebackTimerCtr; ///< Timer counter for time spent in rinseback sub-mode. -static F32 cumulativeRinsebackVolume_mL; ///< Total cumulative rinseback volume (in mL). +static OVERRIDE_F32_T cumulativeRinsebackVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative rinseback volume (in mL). +static OVERRIDE_F32_T rinsebackVolumeDelivered_Safety = { 0.0, 0.0, 0.0, 0 }; ///< The cumulative independent rinseback volume (in mL) calculated so far. static F32 targetRinsebackVolumePlusAdditional_mL; ///< Target rinseback volume w/ additional volume(s) added (in mL). static F32 additionalRinsebackVolume_mL; ///< Total volume (in mL) delivered so far for additional volume request. static S32 rinsebackMotorCount; ///< The cumulative sum of BP motor encoder counts used for independent rinseback volume check. static U32 rinsebackLastMotorCount; ///< The last BP motor encoder count read for independent rinseback volume check. -static F32 rinsebackVolumeDelivered_Safety; ///< The cumulative independent rinseback volume (in mL) calculated so far. static U32 rinsebackAdditionalTimerCtr; ///< Timer counter for duration of an additional rinseback delivery. static U32 rinsebackPublishTimerCtr; ///< Timer counter for determining interval for rinseback status to be published. +/// Interval (in task intervals) at which to publish rinseback data to CAN bus. +static OVERRIDE_U32_T rinsebackPublishInterval = { RINSEBACK_DATA_PUBLISH_INTERVAL, RINSEBACK_DATA_PUBLISH_INTERVAL, RINSEBACK_DATA_PUBLISH_INTERVAL, 0 }; static BOOL startRinsebackRequested; ///< Flag indicates user requesting rinseback start (confirming saline bag move to arterial line end). static BOOL incrRinsebackFlowRateRequested; ///< Flag indicates user requesting rinseback flow rate be increased. @@ -93,6 +95,9 @@ static void setupForRinsebackDelivery( U32 rate ); static void setupForRinsebackStopOrPause( void ); +static F32 getRinsebackVolume( void ); +static F32 getRinsebackSafetyVolume( void ); + static RINSEBACK_STATE_T handleRinsebackStopInitState( void ); static RINSEBACK_STATE_T handleRinsebackRunState( void ); static RINSEBACK_STATE_T handleRinsebackPausedState( void ); @@ -111,6 +116,7 @@ static BOOL handleEndTreatmentUserAction( REQUEST_REJECT_REASON_CODE_T *rejReason ); static void publishRinsebackData( void ); +static U32 getPublishRinsebackInterval( void ); /*********************************************************************//** * @brief @@ -125,11 +131,11 @@ rinsebackRate_mL_min = getTreatmentParameterU32( TREATMENT_PARAM_RINSEBACK_FLOW_RATE ); targetRinsebackVolumePlusAdditional_mL = TARGET_RINSEBACK_VOLUME_ML; rinsebackTimerCtr = 0; - cumulativeRinsebackVolume_mL = 0.0; + cumulativeRinsebackVolume_mL.data = 0.0; + rinsebackVolumeDelivered_Safety.data = 0.0; additionalRinsebackVolume_mL = 0.0; rinsebackMotorCount = 0; rinsebackLastMotorCount = getBloodPumpMotorCount(); - rinsebackVolumeDelivered_Safety = 0.0; rinsebackAdditionalTimerCtr = 0; rinsebackPublishTimerCtr = 0; resetRinsebackFlags(); @@ -233,6 +239,46 @@ /*********************************************************************//** * @brief + * The getRinsebackVolume function gets the calculated blood prime volume + * delivered. + * @details Inputs: cumulativeRinsebackVolume_mL + * @details Outputs: none + * @return the current rinseback volume delivered (in mL). + *************************************************************************/ +static F32 getRinsebackVolume( void ) +{ + F32 result = cumulativeRinsebackVolume_mL.data; + + if ( OVERRIDE_KEY == cumulativeRinsebackVolume_mL.override ) + { + result = cumulativeRinsebackVolume_mL.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getRinsebackSafetyVolume function gets the calculated independent + * blood prime volume delivered. + * @details Inputs: rinsebackVolumeDelivered_Safety + * @details Outputs: none + * @return the current rinseback safety volume delivered (in mL). + *************************************************************************/ +static F32 getRinsebackSafetyVolume( void ) +{ + F32 result = rinsebackVolumeDelivered_Safety.data; + + if ( OVERRIDE_KEY == rinsebackVolumeDelivered_Safety.override ) + { + result = rinsebackVolumeDelivered_Safety.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief * The getCurrentRinsebackState function returns the current state of the * rinseback sub-mode. * @details Inputs: rinsebackState @@ -347,10 +393,10 @@ rinsebackTimerCtr = 0; // Update rinseback volume delivered so far - cumulativeRinsebackVolume_mL += ( getMeasuredBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); + cumulativeRinsebackVolume_mL.data += ( getMeasuredBloodFlowRate() * RINSEBACK_FLOW_INTEGRATOR ); // update independent calculated safety volume delivered so far rinsebackMotorCount = u32BiDiffWithWrap( rinsebackLastMotorCount, getBloodPumpMotorCount() ) / BP_HALL_EDGE_COUNTS_PER_REV; - rinsebackVolumeDelivered_Safety = ( (F32)rinsebackMotorCount * VOLUME_PER_BP_MOTOR_REV_ML ); // TODO - include upstream pressure compensation to this calc + rinsebackVolumeDelivered_Safety.data = ( (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 ) @@ -359,16 +405,16 @@ result = RINSEBACK_STOP_STATE; } // Has rinseback completed? - else if ( cumulativeRinsebackVolume_mL >= TARGET_RINSEBACK_VOLUME_ML ) + else if ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); result = RINSEBACK_STOP_STATE; #ifndef DISABLE_PUMP_FLOW_CHECKS // Check for under-delivery - if ( rinsebackVolumeDelivered_Safety < MIN_RINSEBACK_SAFETY_VOLUME_ML ) + if ( getRinsebackSafetyVolume() < MIN_RINSEBACK_SAFETY_VOLUME_ML ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, rinsebackVolumeDelivered_Safety ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, getRinsebackSafetyVolume() ); } #endif } @@ -387,11 +433,11 @@ } #ifndef DISABLE_PUMP_FLOW_CHECKS // Has independent safety volume exceeded safety limit? - else if ( rinsebackVolumeDelivered_Safety > MAX_RINSEBACK_SAFETY_VOLUME_ML ) + else if ( getRinsebackSafetyVolume() > MAX_RINSEBACK_SAFETY_VOLUME_ML ) { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, rinsebackVolumeDelivered_Safety ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE, TARGET_RINSEBACK_VOLUME_ML, getRinsebackSafetyVolume() ); result = RINSEBACK_STOP_STATE; } #endif @@ -473,7 +519,7 @@ signalRinsebackToRecirc(); } // Has rinseback operation exceeded max time w/o delivering full volume? - if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( cumulativeRinsebackVolume_mL < TARGET_RINSEBACK_VOLUME_ML ) ) + if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( getRinsebackVolume() < TARGET_RINSEBACK_VOLUME_ML ) ) { signalGoToTreatmentStopped(); activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); @@ -482,8 +528,8 @@ { additionalRinsebackRequested = FALSE; // deliver additional rinseback volume only if max volume not reached and max time not reached - if ( ( ( cumulativeRinsebackVolume_mL + TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) <= MAX_TOTAL_RINSEBACK_VOLUME_ML ) && - ( ( rinsebackTimerCtr < MAX_RINSEBACK_TIME ) || ( cumulativeRinsebackVolume_mL >= TARGET_RINSEBACK_VOLUME_ML ) ) ) + if ( ( ( getRinsebackVolume() + TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) <= MAX_TOTAL_RINSEBACK_VOLUME_ML ) && + ( ( rinsebackTimerCtr < MAX_RINSEBACK_TIME ) || ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) ) { rinsebackAdditionalTimerCtr = 0; additionalRinsebackVolume_mL = 0.0; @@ -522,12 +568,12 @@ // update additional rinseback volume delivered so far additionalRinsebackVolume_mL += rinsebackVolumeSinceLast; - cumulativeRinsebackVolume_mL += rinsebackVolumeSinceLast; + cumulativeRinsebackVolume_mL.data += rinsebackVolumeSinceLast; rinsebackAdditionalTimerCtr++; // Has additional rinseback completed or timed out? if ( ( additionalRinsebackVolume_mL >= TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) || - ( cumulativeRinsebackVolume_mL >= MAX_TOTAL_RINSEBACK_VOLUME_ML ) || + ( getRinsebackVolume() >= MAX_TOTAL_RINSEBACK_VOLUME_ML ) || ( rinsebackAdditionalTimerCtr >= MAX_RINSEBACK_ADDITIONAL_TIME ) ) { setupForRinsebackStopOrPause(); @@ -815,7 +861,7 @@ if ( RINSEBACK_STOP_STATE == rinsebackState ) { - if ( ( cumulativeRinsebackVolume_mL + TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) <= MAX_TOTAL_RINSEBACK_VOLUME_ML ) + if ( ( getRinsebackVolume() + TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML ) <= MAX_TOTAL_RINSEBACK_VOLUME_ML ) { result = TRUE; additionalRinsebackRequested = TRUE; @@ -933,15 +979,15 @@ *************************************************************************/ static void publishRinsebackData( void ) { - if ( ++rinsebackPublishTimerCtr >= RINSEBACK_DATA_PUBLISH_INTERVAL ) + if ( ++rinsebackPublishTimerCtr >= getPublishRinsebackInterval() ) { RINSEBACK_DATA_PAYLOAD_T data; U32 timeout = MAX_RINSEBACK_TIME / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); U32 countdown = ( rinsebackTimerCtr >= MAX_RINSEBACK_TIME ? 0 : ( MAX_RINSEBACK_TIME - rinsebackTimerCtr ) / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ); rinsebackPublishTimerCtr = 0; // If we have completed rinseback, timeout is no longer in force - indicate by zeroing timeout - if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( cumulativeRinsebackVolume_mL >= TARGET_RINSEBACK_VOLUME_ML ) ) + if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) { timeout = 0; } @@ -950,7 +996,8 @@ { data.targetRinsebackVolumeMl = targetRinsebackVolumePlusAdditional_mL; } - data.deliveredRinsebackVolumeMl = cumulativeRinsebackVolume_mL; + data.deliveredRinsebackVolumeMl = getRinsebackVolume(); + data.safetyRinsebackVolumeMl = getRinsebackSafetyVolume(); data.rinsebackFlowRateMlMin = rinsebackRate_mL_min; if ( RINSEBACK_RUN_ADDITIONAL_STATE == rinsebackState ) { @@ -962,4 +1009,167 @@ } } +/*********************************************************************//** + * @brief + * The getPublishRinsebackInterval function gets the rinseback data + * publication interval. + * @details Inputs: rinsebackPublishInterval + * @details Outputs: none + * @return the current rinseback publication interval (in task intervals). + *************************************************************************/ +static U32 getPublishRinsebackInterval( void ) +{ + U32 result = rinsebackPublishInterval.data; + + if ( OVERRIDE_KEY == rinsebackPublishInterval.override ) + { + result = rinsebackPublishInterval.ovData; + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetRinsebackVolumeOverride function overrides the calculated + * rinseback volume delivered. + * @details Inputs: none + * @details Outputs: cumulativeRinsebackVolume_mL + * @param vol override calculated rinseback volume (in mL) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetRinsebackVolumeOverride( F32 vol ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + cumulativeRinsebackVolume_mL.ovData = vol; + cumulativeRinsebackVolume_mL.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetRinsebackVolumeOverride function resets the override of the + * calculated rinseback volume. + * @details Inputs: none + * @details Outputs: cumulativeRinsebackVolume_mL + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetRinsebackVolumeOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + cumulativeRinsebackVolume_mL.override = OVERRIDE_RESET; + cumulativeRinsebackVolume_mL.ovData = cumulativeRinsebackVolume_mL.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetRinsebackSafetyVolumeOverride function overrides the calculated + * rinseback volume. + * @details Inputs: none + * @details Outputs: rinsebackVolumeDelivered_Safety + * @param vol override calculated rinseback safety volume (in mL) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetRinsebackSafetyVolumeOverride( F32 vol ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + rinsebackVolumeDelivered_Safety.ovData = vol; + rinsebackVolumeDelivered_Safety.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetRinsebackSafetyVolumeOverride function resets the override of the + * calculated rinseback safety volume. + * @details Inputs: none + * @details Outputs: rinsebackVolumeDelivered_Safety + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetRinsebackSafetyVolumeOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + rinsebackVolumeDelivered_Safety.override = OVERRIDE_RESET; + rinsebackVolumeDelivered_Safety.ovData = rinsebackVolumeDelivered_Safety.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetRinsebackPublishIntervalOverride function sets the override of the + * rinseback data publication interval. + * @details Inputs: none + * @details Outputs: rinsebackPublishInterval + * @param ms milliseconds between rinseback broadcasts + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetRinsebackPublishIntervalOverride( U32 ms ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = ms / TASK_GENERAL_INTERVAL; + + result = TRUE; + rinsebackPublishInterval.ovData = intvl; + rinsebackPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetRinsebackPublishIntervalOverride function resets the override of the + * rinseback data publication interval. + * @details Inputs: none + * @details Outputs: rinsebackPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetRinsebackPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + rinsebackPublishInterval.override = OVERRIDE_RESET; + rinsebackPublishInterval.ovData = rinsebackPublishInterval.ovInitData; + } + + return result; +} + /**@}*/