Index: firmware/App/Controllers/AirTrap.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,36 +8,37 @@ * @file AirTrap.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 01-Mar-2022 * * @author (original) Sean Nash * @date (original) 16-Sep-2020 * ***************************************************************************/ - -#include "AirTrap.h" -#include "AlarmMgmt.h" + +#include "AirTrap.h" +#include "AlarmMgmt.h" #include "FPGA.h" -#include "ModeTreatmentParams.h" -#include "OperationModes.h" -#include "SystemCommMessages.h" +#include "ModeTreatmentParams.h" +#include "OperationModes.h" +#include "SystemCommMessages.h" #include "TaskGeneral.h" -#include "TaskPriority.h" -#include "Timers.h" - -/** - * @addtogroup AirTrap - * @{ - */ - -// ********** private definitions ********** +#include "TaskPriority.h" +#include "Timers.h" -/// Interval (ms/task time) at which the air trap data is published on the CAN bus. +/** + * @addtogroup AirTrap + * @{ + */ + +// ********** private definitions ********** + +/// Interval (ms/task time) at which the air trap data is published on the CAN bus. #define AIR_TRAP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) /// Persistence period for illegal level sensors fault. static const U32 AIR_TRAP_ILLEGAL_LEVELS_PERSISTENCE = ( MS_PER_SECOND * 2 / TASK_PRIORITY_INTERVAL ); /// Volume (in mL) of venous portion of blood circuit line. TODO - get actual volume from Systems. -#define VENOUS_LINE_VOLUME_ML ( 200.0 ) +#define VENOUS_LINE_VOLUME_ML ( 200.0 ) +#define DATA_PUBLISH_COUNTER_START_COUNT 7 ///< Data publish counter start count. /// Defined states for the air trap controller state machine. typedef enum AirTrap_States @@ -52,39 +53,39 @@ // ********** private data ********** static AIR_TRAP_STATE_T airTrapControllerState; ///< Current state of air trap controller state machine. -static U32 airTrapDataPublicationTimerCounter = 0; ///< Used to schedule air trap data publication to CAN bus. - +static U32 airTrapDataPublicationTimerCounter; ///< Used to schedule air trap data publication to CAN bus. + /// Interval (in ms) at which to publish air trap data to CAN bus. -static OVERRIDE_U32_T airTrapDataPublishInterval = { AIR_TRAP_DATA_PUB_INTERVAL, AIR_TRAP_DATA_PUB_INTERVAL, 0, 0 }; -static OVERRIDE_U32_T airTrapLevels[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< Detected air trap level for each level sensor. +static OVERRIDE_U32_T airTrapDataPublishInterval = { AIR_TRAP_DATA_PUB_INTERVAL, AIR_TRAP_DATA_PUB_INTERVAL, 0, 0 }; +static OVERRIDE_U32_T airTrapLevels[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< Detected air trap level for each level sensor. static BOOL pendingStartAirTrapController = FALSE; ///< Flag indicates an air trap controller start request is pending. static BOOL pendingStopAirTrapController = FALSE; ///< Flag indicates an air trap controller stop request is pending. static U32 fillStartTime = 0; ///< Time stamp for start of air trap fill. static U32 airTrapIllegalLevelSensorsCtr = 0; ///< Timer counter for illegal level sensor fault. - -// ********** private function prototypes ********** - -static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ); -static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ); + +// ********** private function prototypes ********** + +static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ); +static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ); static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ); -static void publishAirTrapData( void ); - -/*********************************************************************//** - * @brief - * The initAirTrap function initializes the Air Trap module. - * @details Inputs: none - * @details Outputs: Air Trap module initialized. - * @return none - *************************************************************************/ +static void publishAirTrapData( void ); + +/*********************************************************************//** + * @brief + * The initAirTrap function initializes the Air Trap module. + * @details Inputs: none + * @details Outputs: Air Trap module initialized. + * @return none + *************************************************************************/ void initAirTrap( void ) { U32 i; resetAirTrap(); - airTrapIllegalLevelSensorsCtr = 0; + airTrapIllegalLevelSensorsCtr = DATA_PUBLISH_COUNTER_START_COUNT; for ( i = 0; i < NUM_OF_AIR_TRAP_LEVEL_SENSORS; i++ ) { @@ -182,10 +183,14 @@ ( AIR_TRAP_LEVEL_FLUID == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) { if ( ++airTrapIllegalLevelSensorsCtr >= AIR_TRAP_ILLEGAL_LEVELS_PERSISTENCE ) + { -#ifndef DISABLE_ILLEGAL_AIR_TRAP_ALARM - activateAlarmNoData( ALARM_ID_AIR_TRAP_ILLEGAL_LEVELS ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ILLEGAL_AIR_TRAP_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + activateAlarmNoData( ALARM_ID_AIR_TRAP_ILLEGAL_LEVELS ); + } } } else @@ -215,9 +220,10 @@ if ( TRUE == didTimeout( fillStartTime, fillTimeoutMS ) ) { -#ifndef DISABLE_AIR_TRAP_LEVELING_ALARM - activateAlarmNoData( ALARM_ID_AIR_TRAP_FILL_DURING_TREATMENT ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_AIR_TRAP_LEVELING_ALARM ) != SW_CONFIG_ENABLE_VALUE ) + { + activateAlarmNoData( ALARM_ID_AIR_TRAP_FILL_DURING_TREATMENT ); + } } } } @@ -519,4 +525,4 @@ return result; } -/**@}*/ +/**@}*/ Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r61716bc97ecca8af1ec560333844a8cf602eccb0 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 61716bc97ecca8af1ec560333844a8cf602eccb0) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file BloodFlow.c * -* @author (last) Sean Nash -* @date (last) 04-Jan-2022 +* @author (last) Dara Navaei +* @date (last) 02-Mar-2022 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -107,7 +107,7 @@ #define BP_ML_PER_ROTOR_REV 6.81 ///< Milliliters per rotor revolusion. #define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to motor RPM. #define BP_GEAR_RATIO 32.0 ///< Blood pump motor to blood pump gear ratio. -#define BP_PWM_ZERO_OFFSET 0.1 ///< 10 pct PWM duty cycle = zero speed. +#define BP_PWM_ZERO_OFFSET 0.1F ///< 10 pct PWM duty cycle = zero speed. /// Conversion macro from mL/min to estimated PWM duty cycle %. #define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) @@ -119,11 +119,11 @@ #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. -#define BP_FLOW_ALPHA_Y_INTERCEPT 1.2163 ///< Y intercept used for alpha flow coefficient calculation. -#define BP_FLOW_WEAR_A_TERM 0.000000005665 ///< A term used for wear portion of alpha flow coefficient. -#define BP_FLOW_WEAR_B_TERM 0.0006125 ///< B term used for wear portion of alpha flow coefficient. +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.1050 ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.000000001 ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.00055 ///< B term used for wear portion of alpha flow coefficient. #define BP_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). -#define BP_FLOW_CORRECTION_FACTOR 0.9 // TODO - why do we need this +#define DATA_PUBLISH_COUNTER_START_COUNT 20 ///< Data publish counter start count. /// Enumeration of blood pump controller states. typedef enum BloodPump_States @@ -156,7 +156,7 @@ // ********** private data ********** static BLOOD_PUMP_STATE_T bloodPumpState = BLOOD_PUMP_OFF_STATE; ///< Current state of blood flow controller state machine -static U32 bloodFlowDataPublicationTimerCounter = 0; ///< Used to schedule blood flow data publication to CAN bus +static U32 bloodFlowDataPublicationTimerCounter; ///< Used to schedule blood flow data publication to CAN bus static BOOL isBloodPumpOn = FALSE; ///< Blood pump is currently running static F32 bloodPumpPWMDutyCyclePct = 0.0; ///< Initial blood pump PWM duty cycle static F32 bloodPumpPWMDutyCyclePctSet = 0.0; ///< Currently set blood pump PWM duty cycle @@ -193,6 +193,7 @@ static U16 bpLastMotorHallSensorCounts[ BP_SPEED_CALC_BUFFER_LEN ]; ///< Last hall sensor readings for the blood pump motor static U32 bpMotorSpeedCalcIdx = 0; ///< Index into 1 second buffer of motor speed hall sensor counts static U32 bpMotorSpeedCalcTimerCtr = 0; ///< Counter determines interval for calculating blood pump motor speed from hall sensor count. +static HD_PUMPS_CAL_RECORD_T bloodPumpCalRecord; ///< Blood pump calibration record. // ********** private function prototypes ********** @@ -220,12 +221,14 @@ * @brief * The initBloodFlow function initializes the BloodFlow module. * @details Inputs: none - * @details Outputs: BloodFlow module initialized. + * @details Outputs: bloodFlowDataPublicationTimerCounter * @return none *************************************************************************/ void initBloodFlow( void ) { U32 i; + + bloodFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; signalBloodPumpHardStop(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); @@ -237,7 +240,7 @@ bpMotorSpeedCalcIdx = 0; for ( i = 0; i < BP_SPEED_CALC_BUFFER_LEN; i++ ) { - bpLastMotorHallSensorCounts[ i ] = 0; + bpLastMotorHallSensorCounts[ i ] = getFPGABloodPumpHallSensorCount(); } resetBloodPumpRotorCount(); @@ -278,11 +281,17 @@ // Don't interrupt pump control unless rate or mode is changing if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) - { -#ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) + { + BOOL byPassFlowLimit = FALSE; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + byPassFlowLimit = TRUE; + } #endif + // Verify flow rate of if the bypass flow limit has been enabled + if ( ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) { resetBloodPumpRPMMovingAverage(); targetBloodFlowRate = dirFlowRate; @@ -324,12 +333,16 @@ } result = TRUE; } -#ifndef NO_PUMP_FLOW_LIMITS + else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) - } + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) + } + } } } @@ -358,7 +371,7 @@ U32 rotCnt = CAP( r, BP_MAX_ROTOR_COUNT_FOR_WEAR ); F32 wear = BP_FLOW_WEAR_A_TERM * (F32)rotCnt + BP_FLOW_WEAR_B_TERM; F32 alpha = wear * artPres + BP_FLOW_ALPHA_Y_INTERCEPT; - F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd * BP_FLOW_CORRECTION_FACTOR; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; return flow; } @@ -478,6 +491,21 @@ /*********************************************************************//** * @brief + * The isBloodPumpRampComplete function returns whether the blood pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: bloodPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isBloodPumpRampComplete( void ) +{ + BOOL result = ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ? TRUE : FALSE ); + + return result; +} + +/*********************************************************************//** + * @brief * The resetBloodPumpRotorCount function resets the blood pump rotor counter * that is a proxy for cartridge wear. Call this function after a new cartridge * has been installed. @@ -487,11 +515,14 @@ *************************************************************************/ void resetBloodPumpRotorCount( void ) { -#ifndef WORN_OUT_CARTRIDGE - bloodPumpRotorCounter.data = 0; -#else - bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_WORN_OUT_CARTRIDGE ) != SW_CONFIG_ENABLE_VALUE ) + { + bloodPumpRotorCounter.data = 0; + } + else + { + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; + } } /*********************************************************************//** @@ -973,7 +1004,7 @@ U16 last = bpLastMotorHallSensorCounts[ bpMotorSpeedCalcIdx ]; U32 nextIdx = INC_WRAP( bpMotorSpeedCalcIdx, 0, BP_SPEED_CALC_BUFFER_LEN - 1 ); U16 incDelta = u16DiffWithWrap( bpLastMotorHallSensorCounts[ nextIdx ], bpMotorHallSensorCount ); - U16 decDelta = HEX_64_K - incDelta; + U16 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); U16 spdDelta; S16 delta; @@ -1050,31 +1081,29 @@ BOOL isDirIncorrect; U08 dirErrorCnt = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; -#ifndef DISABLE_PUMP_DIRECTION_CHECKS // Check pump direction error count - if ( lastBloodPumpDirectionCount != dirErrorCnt ) + if ( ( lastBloodPumpDirectionCount != dirErrorCnt ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { lastBloodPumpDirectionCount = dirErrorCnt; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) } -#endif bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); bpDir = ( getMeasuredBloodPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); // Check set direction vs. direction from hall sensors vs. direction from sign of motor controller speed isDirIncorrect = ( bloodPumpDirectionSet != bpDir ) || ( bloodPumpDirectionSet != bpMCDir ); - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS - if ( bloodPumpDirectionSet != bpDir ) + if ( bloodPumpDirectionSet != bpDir ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpDir ) } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpMCDir ) } -#endif } } else @@ -1101,12 +1130,12 @@ F32 measMCMotorSpeed = fabs( getMeasuredBloodPumpMCSpeed() ); // Check for pump running while commanded off - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, ( 0 == targetBloodFlowRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, + ( 0 == targetBloodFlowRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); -#endif } // Checks that only occur when pump is running (and beyond ramp). @@ -1120,20 +1149,18 @@ F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); // Check measured motor speed vs. commanded motor speed while controlling to target - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, - ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, + ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); -#endif } // Check measured rotor speed vs. measured motor speed while controlling to target - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); -#endif } } else @@ -1159,11 +1186,10 @@ // Check blood pump current during running state BOOL const isRunningMCCurrentBad = ( BLOOD_PUMP_OFF_STATE != bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_RUNNING_MA ); - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, bpCurr ); -#endif } } @@ -1177,30 +1203,41 @@ *************************************************************************/ static void checkBloodPumpFlowRate( void ) { -#ifndef DISABLE_PUMP_FLOW_CHECKS - F32 flow = getMeasuredBloodFlowRate(); - - // Range check on measure BP flow rate. - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, ( flow > BP_MAX_FLOW_RATE ) || ( flow < BP_MIN_FLOW_RATE ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); + F32 flow = getMeasuredBloodFlowRate(); + + // Range check on measure BP flow rate. + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, ( flow > BP_MAX_FLOW_RATE ) || ( flow < BP_MIN_FLOW_RATE ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); + } } -#endif } /*********************************************************************//** * @brief * The execBloodFlowTest function executes the state machine for the * BloodFlow self-test. - * @details Inputs: none + * @details Inputs: bloodPumpCalRecord * @details Outputs: none * @return the current state of the BloodFlow self-test. *************************************************************************/ SELF_TEST_STATUS_T execBloodFlowTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; - // TODO - anything to test here? + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&bloodPumpCalRecord, sizeof( HD_PUMPS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PUMPS, ALARM_ID_NO_ALARM ); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } return result; } Index: firmware/App/Controllers/BloodFlow.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/BloodFlow.h (.../BloodFlow.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file BloodFlow.h * * @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @date (last) 14-Jan-2022 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -64,6 +64,7 @@ U32 getBloodPumpMotorCount( void ); U32 getBloodPumpRotorCount( void ); BOOL isBloodPumpRunning( void ); +BOOL isBloodPumpRampComplete( void ); void resetBloodPumpRotorCount( void ); SELF_TEST_STATUS_T execBloodFlowTest( void ); Index: firmware/App/Controllers/BloodLeak.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/BloodLeak.c (.../BloodLeak.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,12 +8,13 @@ * @file BloodLeak.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Peman Montazemi * @date (original) 18-Mar-2021 * ***************************************************************************/ + #include // For sprintf and strlen #include "AlarmMgmt.h" @@ -33,7 +34,7 @@ // ********** private definitions ********** #define BLOOD_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the blood leak data is published on the CAN bus. -#define BLOOD_LEAK_TIMEOUT_MS 500 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) +#define BLOOD_LEAK_TIMEOUT_MS 2000 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) #define BLOOD_LEAK_PERSISTENCE ( 10 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence for blood leak detected alarm. #define BLOOD_LEAK_RESET_TX_FIFO 2 ///< Blood leak reset transmit FIFO command. #define BLOOD_LEAK_START_COMM_CTRL_U_ASCII 21 ///< Blood leak start communication command, ^U (Ctrl-U) in ascii. @@ -52,14 +53,20 @@ #define BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH 15 ///< Blood leak set point sequence maximum length. #define BLOOD_LEAK_WAIT_2_READ_SET_POINT ( 1 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Blood leak wait to read set point in counts. +#define BLOOD_LEAK_WAIT_2_READ_CTRL_U ( 1 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Blood leak wait to read control U in counts. #define BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS 3 ///< Blood leak maximum number of trials to write the set point. +#define BLOOD_LEAK_MAX_CTRL_U_WRITE_TRIALS 3 ///< Blood leak maximum number of trials to write the control U command. #define BLOOD_LEAK_MIN_WAIT_TIME_2_GET_CAL_MS ( 2 * MS_PER_SECOND ) ///< Blood leak minimum wait time to get calibration in milliseconds. +#define DATA_PUBLISH_COUNTER_START_COUNT 60 ///< Data publish counter start count. + /// Defined states for the blood leak detector state machine. typedef enum BloodLeakStates { - BLOOD_LEAK_START_UP_STATE = 0, ///< Start up state. + BLOOD_LEAK_WAIT_FOR_POST_STATE = 0, ///< Wait for post state. + BLOOD_LEAK_START_UP_STATE, ///< Start up state. + BLOOD_LEAK_CHECK_COMM_STATE, ///< Check communication (Control U) state. BLOOD_LEAK_CHECK_SET_POINT_STATE, ///< Check set point state. BLOOD_LEAK_SET_SET_POINT_STATE, ///< Set set point state. BLOOD_LEAK_INIT_STATE, ///< Init state. @@ -78,19 +85,21 @@ static BOOL bloodLeakZeroRequested = FALSE; ///< Blood leak zero requested flag static U32 bloodLeakZeroStartTime = 0; ///< Blood leak zeroing start time. static U32 bloodLeakSelfTestStartTime = 0; ///< Blood leak self-test start time. +static BOOL bloodLeakIsPOSTComplete; ///< Blood leak is POST complete flag. static U32 bloodLeakPersistenceCtr = 0; ///< Blood leak alarm persistence timer counter. static OVERRIDE_U32_T bloodLeakDataPublishInterval = { BLOOD_LEAK_PUB_INTERVAL, BLOOD_LEAK_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish blood leak data to CAN bus. -static U32 bloodLeakDataPublicationTimerCounter = 0; ///< Timer counter used to schedule blood leak data publication to CAN bus. -static U32 bloodLeakUARTCmdIndex; ///< Blood leak UART command index. +static U32 bloodLeakDataPublicationTimerCounter; ///< Timer counter used to schedule blood leak data publication to CAN bus. +static U32 bloodLeakUARTCmdIndex = 0; ///< Blood leak UART command index. static U32 bloodLeakSetPointSeqLength = 0; ///< Blood leak set point sequence actual length. static U08 bloodLeakSetPointSequence[ BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ]; ///< Blood leak set point sequence array. -static U32 bloodLeakWait2ReadSetPointCounter = 0; ///< Blood leak wait to read delay counter. -static U32 bloodLeakCurrentSetPointWriteTry = 0; ///< Blood leak current set point write try number. +static U32 bloodLeakWait2ReadResponseCounter; ///< Blood leak wait to read response counter. +static U32 bloodLeakCommandWriteTryCount; ///< Blood leak current set point write try number. static HD_BLOOD_LEAK_SENSOR_CAL_RECORD_T bloodLeakCalRecord; ///< Blood leak calibration record structure. -static U32 bloodLeakGetCalStartTime = 0; ///< Blood leak get calibration start time. +static U32 bloodLeakGetCalStartTime; ///< Blood leak get calibration start time. +static U32 bloodLeakPrevFPGARegisterCount; ///< Blood leak previous FPGA communications counter. /// Blood leak start up sequence array. static const U08 BLOOD_LEAK_START_UP_SEQUENCE[ BLOOD_LEAK_STARTUP_SEQ_LENGTH ] = { BLOOD_LEAK_RESET_TX_FIFO, @@ -102,7 +111,9 @@ // ********** private function prototypes ********** +static BLOOD_LEAK_STATES_T handleBloodLeakWaitForPostState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakStartupState( void ); +static BLOOD_LEAK_STATES_T handleBloodLeakCheckCommState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakCheckSetPointState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakSetSetPointState( void ); static BLOOD_LEAK_STATES_T handleBloodLeakInitState( void ); @@ -119,15 +130,16 @@ * @details Inputs: none * @details Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, * bloodLeakZeroRequested, bloodLeakZeroRequested, bloodLeakSelfTestStartTime, - * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence, - * bloodLeakWait2ReadSetPointCounter, bloodLeakDataPublicationTimerCounter, - * bloodLeakCurrentSetPointWriteTry, bloodLeakGetCalStartTime + * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence, bloodLeakPrevFPGARegisterCount + * bloodLeakWait2ReadResponseCounter, bloodLeakDataPublicationTimerCounter, + * bloodLeakCommandWriteTryCount, bloodLeakGetCalStartTime, + * bloodLeakIsPOSTComplete * @return none *************************************************************************/ void initBloodLeak( void ) { - bloodLeakDataPublicationTimerCounter = 0; - bloodLeakState = BLOOD_LEAK_START_UP_STATE; + bloodLeakDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + bloodLeakState = BLOOD_LEAK_WAIT_FOR_POST_STATE; bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovInitData = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovData = BLOOD_LEAK_NOT_DETECTED; @@ -138,9 +150,11 @@ bloodLeakSelfTestStartTime = 0; bloodLeakUARTCmdIndex = 0; bloodLeakSetPointSeqLength = 0; - bloodLeakWait2ReadSetPointCounter = 0; - bloodLeakCurrentSetPointWriteTry = 0; + bloodLeakWait2ReadResponseCounter = 0; + bloodLeakCommandWriteTryCount = 0; bloodLeakGetCalStartTime = getMSTimerCount(); + bloodLeakIsPOSTComplete = FALSE; + bloodLeakPrevFPGARegisterCount = 0; // Set the blood leak set pint sequence to 0 to be initialized memset( bloodLeakSetPointSequence, 0x0, BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ); @@ -179,10 +193,18 @@ // Execute blood leak state machine switch( bloodLeakState ) { + case BLOOD_LEAK_WAIT_FOR_POST_STATE: + bloodLeakState = handleBloodLeakWaitForPostState(); + break; + case BLOOD_LEAK_START_UP_STATE: bloodLeakState = handleBloodLeakStartupState(); break; + case BLOOD_LEAK_CHECK_COMM_STATE: + bloodLeakState = handleBloodLeakCheckCommState(); + break; + case BLOOD_LEAK_CHECK_SET_POINT_STATE: bloodLeakState = handleBloodLeakCheckSetPointState(); break; @@ -229,6 +251,7 @@ void zeroBloodLeak( void ) { bloodLeakZeroRequested = TRUE; + bloodLeakUARTCmdIndex = 0; } /*********************************************************************//** @@ -248,7 +271,8 @@ if ( TRUE == calStatus ) { - result = SELF_TEST_STATUS_PASSED; + result = SELF_TEST_STATUS_PASSED; + bloodLeakIsPOSTComplete = TRUE; } else { @@ -260,6 +284,29 @@ /*********************************************************************//** * @brief + * The handleBloodLeakWaitForPostState function handles the wait for POST + * state of the of blood leak state machine. + * @details Inputs: bloodLeakIsPOSTComplete, bloodLeakPrevFPGARegisterCount + * @details Outputs: none + * @return next state + *************************************************************************/ +static BLOOD_LEAK_STATES_T handleBloodLeakWaitForPostState( void ) +{ + BLOOD_LEAK_STATES_T state = BLOOD_LEAK_WAIT_FOR_POST_STATE; + + if ( TRUE == bloodLeakIsPOSTComplete ) + { + // Read the value that is in the FPGA counter so it can be used to make sure the blood leak is communicating after + // sending Ctrl U + bloodLeakPrevFPGARegisterCount = getFPGABloodLeakRegisterCounter(); + state = BLOOD_LEAK_START_UP_STATE; + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleBloodLeakStartupState function handles the startup state of the * of blood leak state machine. * @details Inputs: bloodLeakUARTCmdIndex @@ -286,8 +333,12 @@ // Done with writing all the commands, reset the index and transition if ( bloodLeakUARTCmdIndex >= ( BLOOD_LEAK_STARTUP_SEQ_LENGTH - 1 ) ) { - bloodLeakUARTCmdIndex = 0; - state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + // Wait for the sensor to start communication + if ( ++bloodLeakWait2ReadResponseCounter > BLOOD_LEAK_WAIT_2_READ_CTRL_U ) + { + bloodLeakUARTCmdIndex = 0; + state = BLOOD_LEAK_CHECK_COMM_STATE; + } } else { @@ -299,6 +350,46 @@ /*********************************************************************//** * @brief + * The handleBloodLeakCheckCommState function handles the check communication + * state to ensure the sensor is communicating. + * @details Inputs: bloodLeakCommandWriteTryCount, bloodLeakPrevFPGARegisterCount + * @details Outputs: bloodLeakCommandWriteTryCount, bloodLeakPrevFPGARegisterCount + * @return next state + *************************************************************************/ +static BLOOD_LEAK_STATES_T handleBloodLeakCheckCommState( void ) +{ + BLOOD_LEAK_STATES_T state = BLOOD_LEAK_CHECK_COMM_STATE; + + // Check if the blood leak sensor has started communicating + BOOL isBloodLeakCommunicating = ( bloodLeakPrevFPGARegisterCount != getFPGABloodLeakRegisterCounter() ? TRUE : FALSE ); + + // The sensor is communicating move on + if ( TRUE == isBloodLeakCommunicating ) + { + state = BLOOD_LEAK_CHECK_SET_POINT_STATE; + bloodLeakCommandWriteTryCount = 0; + } + else + { + // If the sensor is not communicating, and the number of writes has not exceeded try again, otherwise alarm + if ( bloodLeakCommandWriteTryCount < BLOOD_LEAK_MAX_CTRL_U_WRITE_TRIALS ) + { + bloodLeakCommandWriteTryCount++; + + bloodLeakPrevFPGARegisterCount = getFPGABloodLeakRegisterCounter(); + state = BLOOD_LEAK_START_UP_STATE; + } + else + { + // TODO alarm. Should we check the BLD communications all the time like in the monitor? + } + } + + return state; +} + +/*********************************************************************//** + * @brief * The handleBloodLeakCheckSetPointState function handles the check set point * state to ensure the set point is set correctly. * @details Inputs: none @@ -311,24 +402,31 @@ U16 bloodLeakSetPoint = getFPGABloodLeakDetectSetPoint(); +#ifdef BOARD_WITH_NO_HARDWARE + // In case it is just a bare board, use this value + bloodLeakCalRecord.setPoint = 20; +#endif + if ( bloodLeakSetPoint != bloodLeakCalRecord.setPoint ) { - if ( bloodLeakCurrentSetPointWriteTry < BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS ) + if ( bloodLeakCommandWriteTryCount < BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS ) { prepareSetPointSeq(); - bloodLeakCurrentSetPointWriteTry++; + bloodLeakCommandWriteTryCount++; state = BLOOD_LEAK_SET_SET_POINT_STATE; } else { - activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SENSOR_SET_POINT_SET_FAILURE ); + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) + { + activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SENSOR_SET_POINT_SET_FAILURE ); + } } - } else { state = BLOOD_LEAK_INIT_STATE; - bloodLeakCurrentSetPointWriteTry = 0; + bloodLeakCommandWriteTryCount = 0; } return state; @@ -367,9 +465,9 @@ } else { - if ( ++bloodLeakWait2ReadSetPointCounter > BLOOD_LEAK_WAIT_2_READ_SET_POINT ) + if ( ++bloodLeakWait2ReadResponseCounter > BLOOD_LEAK_WAIT_2_READ_SET_POINT ) { - bloodLeakWait2ReadSetPointCounter = 0; + bloodLeakWait2ReadResponseCounter = 0; bloodLeakUARTCmdIndex = 0; // Done with writing the set point state = BLOOD_LEAK_CHECK_SET_POINT_STATE; @@ -427,9 +525,10 @@ { if ( TRUE == didTimeout( bloodLeakZeroStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { -#ifndef IGNORE_BLOOD_LEAK_ALARM - activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) + { + activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); + } } } @@ -448,7 +547,6 @@ { BLOOD_LEAK_STATES_T state = BLOOD_LEAK_SELF_TEST_STATE; -#ifndef IGNORE_BLOOD_LEAK_ALARM if ( SELF_TEST_STATUS_IN_PROGRESS == bloodLeakSelfTestStatus ) { if ( FALSE == noFPGABloodLeakDetected() ) // Faked blood leak caused by independent MCU board @@ -461,7 +559,7 @@ bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SELF_TEST_FAILURE ); - } + } } else { @@ -471,9 +569,6 @@ state = BLOOD_LEAK_NORMAL_STATE; } } -#else - state = BLOOD_LEAK_NORMAL_STATE; -#endif return state; } @@ -505,9 +600,10 @@ if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; -#ifndef IGNORE_BLOOD_LEAK_ALARM - activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) + { + activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); + } } } else // Blood leak not detected @@ -518,9 +614,10 @@ } else { -#ifndef IGNORE_BLOOD_LEAK_ALARM - clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) + { + clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); + } } } @@ -603,9 +700,9 @@ // Loop through the number of digits and get each ASCII value for ( i = 0; i < digitCount; i++ ) { - // Write the characters - bloodLeakSetPointSequence[ bufferIndex ] = tempCharBuffer[ i ]; - bufferIndex++; + // Write the characters + bloodLeakSetPointSequence[ bufferIndex ] = tempCharBuffer[ i ]; + bufferIndex++; } // After the characters, insert the carriage return into the buffer Index: firmware/App/Controllers/Bubble.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Bubble.c (.../Bubble.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Bubble.c (.../Bubble.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file Bubble.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Peman Montazemi * @date (original) 06-May-2021 @@ -30,8 +30,9 @@ // ********** private definitions ********** -#define BUBBLE_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the air bubble detector data is published on the CAN bus. -#define BUBBLE_TIMEOUT_MS 500 ///< Air bubble detector timeout for self-test (15 ms extended edge detection) +#define BUBBLE_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the air bubble detector data is published on the CAN bus. +#define BUBBLE_TIMEOUT_MS 500 ///< Air bubble detector timeout for self-test (15 ms extended edge detection) +#define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. /// Defined states for the air bubble detectors state machine. typedef enum BubbleStates @@ -83,6 +84,8 @@ bubblesSelfTestRequested[ bubble ] = FALSE; bubblesSelfTestStartTime[ bubble ] = 0; } + + bubblesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; } /*********************************************************************//** @@ -193,45 +196,48 @@ bubblesStatus[ bubble ].data = BUBBLE_DETECTED; } -#ifndef DISABLE_BUBBLE_ALARMS - // Check status reading and act upon - if ( BUBBLE_DETECTED == getBubbleStatus( bubble ) ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BUBBLE_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) +#endif { - if ( getCurrentOperationMode() == MODE_TREA ) + // Check status reading and act upon + if ( BUBBLE_DETECTED == getBubbleStatus( bubble ) ) { - switch ( treatmentState ) + if ( getCurrentOperationMode() == MODE_TREA ) { - case TREATMENT_BLOOD_PRIME_STATE: - case TREATMENT_DIALYSIS_STATE: - case TREATMENT_END_STATE: - if ( bubble == ADV ) - { - activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ); - } - break; + switch ( treatmentState ) + { + case TREATMENT_BLOOD_PRIME_STATE: + case TREATMENT_DIALYSIS_STATE: + case TREATMENT_END_STATE: + if ( bubble == ADV ) + { + activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ); + } + break; - case TREATMENT_RINSEBACK_STATE: - if ( bubble == ADV ) - { - activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED_RINSEBACK ); - } - break; + case TREATMENT_RINSEBACK_STATE: + if ( bubble == ADV ) + { + activateAlarmNoData( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED_RINSEBACK ); + } + break; - default: - // Ignore other treatment states - break; + default: + // Ignore other treatment states + break; + } } } - } - else // Air bubble not detected - { - if ( bubble == ADV ) + else // Air bubble not detected { - clearAlarmCondition( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ); - clearAlarmCondition( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED_RINSEBACK ); + if ( bubble == ADV ) + { + clearAlarmCondition( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED ); + clearAlarmCondition( ALARM_ID_HD_VENOUS_BUBBLE_DETECTED_RINSEBACK ); + } } } -#endif if ( TRUE == bubblesSelfTestRequested[ bubble ] ) { Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file DGInterface.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 03-Mar-2022 * * @author (original) Sean * @date (original) 08-Apr-2020 @@ -71,25 +71,23 @@ static F32 lgFilteredReservoirWeightInGrams[ NUM_OF_DG_RESERVOIRS ]; // Load cell filtering data -/// Holds load cell samples for large load cell moving average. -static F32 lgLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; -static U32 lgLoadCellReadingsIdx = 0; ///< Index for next sample in large load cell rolling average sample array. -static F32 lgLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. +static F32 lgLoadCellReadings[ NUM_OF_DG_RESERVOIRS ][ SIZE_OF_LARGE_LOAD_CELL_AVG ]; ///< Holds load cell samples for large load cell moving average. +static U32 lgLoadCellReadingsIdx = 0; ///< Index for next sample in large load cell rolling average sample array. +static F32 lgLoadCellReadingsTotal[ NUM_OF_DG_RESERVOIRS ]; ///< Rolling total - used to calc large load cell moving average. // DG Dialysate flow rate -static F32 dgDialysateFlowRateMlMin = 0.0; ///< Latest dialysate flow rate reported by the DG. -static BOOL dgDialysateFlowDataFreshFlag = FALSE; ///< Flag to signal the execDialInFlowMonitor() to process fresh flow rate data +static F32 dgDialysateFlowRateMlMin = 0.0; ///< Latest dialysate flow rate reported by the DG. +static BOOL dgDialysateFlowDataFreshFlag = FALSE; ///< Flag to signal the execDialInFlowMonitor() to process fresh flow rate data // Reservoir data static DG_RESERVOIR_ID_T dgActiveReservoir = DG_RESERVOIR_2; ///< Latest active reservoir reported by the DG. static DG_RESERVOIR_ID_T dgActiveReservoirSet = DG_RESERVOIR_2; ///< Active reservoir commanded. -// TODO remove below variables +// TODO remove below variables static U32 dgReservoirFillVolumeTarget = 0; ///< Latest fill-to volume reported by the DG. 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 DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. static DG_MIXING_RATIOS_T dgMixingRatios; ///< DG mixing ratios. @@ -912,27 +910,30 @@ BOOL const dialysateTempRecovered = fabs( dgDialysateTemp - dgTrimmerTempSet ) < DIALYSATE_TEMP_RECOVERY_TOLERANCE_C ? TRUE : FALSE; -#ifndef DISABLE_DIALYSATE_TEMP_CHECK - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dialysateHighTemp ) ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DIALYSATE_TEMP_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#endif { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dgTrimmerTempSet, dgDialysateTemp ); - } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dialysateHighTemp ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dgTrimmerTempSet, dgDialysateTemp ); + } - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dialysateLowTemp ) ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dgTrimmerTempSet, dgDialysateTemp ); - } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dialysateLowTemp ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dgTrimmerTempSet, dgDialysateTemp ); + } - if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dialysateHighTemp ) ) - { - clearAlarmCondition( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH ); - } + if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH, dialysateHighTemp ) ) + { + clearAlarmCondition( ALARM_ID_DIALYSATE_TEMPERATURE_HIGH ); + } - if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dialysateTempRecovered ) ) - { - clearAlarmCondition( ALARM_ID_DIALYSATE_TEMPERATURE_LOW ); + if ( TRUE == isPersistentAlarmConditionCleared( ALARM_ID_DIALYSATE_TEMPERATURE_LOW, dialysateTempRecovered ) ) + { + clearAlarmCondition( ALARM_ID_DIALYSATE_TEMPERATURE_LOW ); + } } -#endif } // ********** private functions ********** Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r61716bc97ecca8af1ec560333844a8cf602eccb0 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 61716bc97ecca8af1ec560333844a8cf602eccb0) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file DialInFlow.c * -* @author (last) Sean Nash -* @date (last) 04-Jan-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 16-Dec-2019 @@ -104,7 +104,7 @@ /// Macro converts flow rate to motor RPM. #define DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DIP_REV_PER_LITER / ML_PER_LITER ) #define DIP_GEAR_RATIO 32.0 ///< DialIn pump motor to dialIn pump gear ratio. -#define DIP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. +#define DIP_PWM_ZERO_OFFSET 0.1F ///< 10% PWM duty cycle = zero speed. /// Macro converts flow rate to estimate PWM needed to achieve it. #define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) @@ -116,6 +116,8 @@ #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. + /// Enumeration of dialysate inlet pump states. typedef enum DialInPump_States { @@ -147,7 +149,7 @@ // ********** private data ********** static DIAL_IN_PUMP_STATE_T dialInPumpState = DIAL_IN_PUMP_OFF_STATE; ///< Current state of dialIn flow controller state machine -static U32 dialInFlowDataPublicationTimerCounter = 5; ///< Used to schedule dialIn flow data publication to CAN bus +static U32 dialInFlowDataPublicationTimerCounter; ///< Used to schedule dialIn flow data publication to CAN bus static BOOL isDialInPumpOn = FALSE; ///< DialIn pump is currently running static F32 dialInPumpPWMDutyCyclePct = 0.0; ///< Initial dialIn pump PWM duty cycle static F32 dialInPumpPWMDutyCyclePctSet = 0.0; ///< Currently set dialIn pump PWM duty cycle @@ -189,7 +191,8 @@ static F64 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average. static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer. -static U32 dipCurrErrorDurationCtr = 0; ///< Used for tracking persistence of dip current errors. +static U32 dipCurrErrorDurationCtr = 0; ///< Used for tracking persistence of dip current errors. +static HD_PUMPS_CAL_RECORD_T dialInPumpCalRecord; ///< Dialysate inlet calibration record. // ********** private function prototypes ********** @@ -221,6 +224,8 @@ void initDialInFlow( void ) { U32 i; + + dialInFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; signalDialInPumpHardStop(); setDialInPumpDirection( MOTOR_DIR_FORWARD ); @@ -232,7 +237,7 @@ dipMotorSpeedCalcIdx = 0; for ( i = 0; i < DIP_SPEED_CALC_BUFFER_LEN; i++ ) { - dipLastMotorHallSensorCounts[ i ] = 0; + dipLastMotorHallSensorCounts[ i ] = getFPGADialInPumpHallSensorCount(); } // Initialize dialysate inlet flow PI controller @@ -267,10 +272,17 @@ // Don't interrupt pump control unless rate or mode is changing if ( ( dirFlowRate != targetDialInFlowRate ) || ( mode != dialInPumpControlMode ) ) { -#ifndef NO_PUMP_FLOW_LIMITS + BOOL byPassFlowLimit = FALSE; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + byPassFlowLimit = TRUE; + } +#endif + // Verify flow rate - if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) -#endif + if ( ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) { resetDialInFlowMovingAverage(); targetDialInFlowRate = dirFlowRate; @@ -309,12 +321,17 @@ } result = TRUE; } -#ifndef NO_PUMP_FLOW_LIMITS + else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, flowRate ) - } + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, flowRate ) + } + } + } } @@ -398,6 +415,21 @@ return isDialInPumpOn; } +/*********************************************************************//** + * @brief + * The isDialInPumpRampComplete function returns whether the dialysate inlet pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: dialInPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isDialInPumpRampComplete( void ) +{ + BOOL result = ( DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE == dialInPumpState ? TRUE : FALSE ); + + return result; +} + /*********************************************************************//** * @brief * The execDialInFlowMonitor function executes the dialIn flow monitor. @@ -417,18 +449,22 @@ { dipFlow = getDGDialysateFlowRateLMin() * (F64)ML_PER_LITER; // convert rate to mL/min filterDialInFlowReadings( dipFlow ); // process the fresh dialysate flow data - dialysateFlowDataFreshStatusCounter = 0; // reset counter + dialysateFlowDataFreshStatusCounter = 0; } else { // Alarm if not receiving new dialysate flow readings in timely manner - if ( ++dialysateFlowDataFreshStatusCounter > DIP_DIALYSATE_FLOW_DATA_ALARM_THRESHOLD ) + if ( TRUE == isDGCommunicating() ) { - filterDialInFlowReadings( 0.0 ); - if ( TRUE == isDGCommunicating() ) + if ( ++dialysateFlowDataFreshStatusCounter > DIP_DIALYSATE_FLOW_DATA_ALARM_THRESHOLD ) { + filterDialInFlowReadings( 0.0 ); activateAlarmNoData( ALARM_ID_HD_DIALYSATE_FLOW_DATA_NOT_RECEIVE ); } } + else + { + dialysateFlowDataFreshStatusCounter = 0; + } } // Get latest pump speed and current from motor controller @@ -916,7 +952,7 @@ U16 incDelta = ( dipMotorHallSensorCount >= dipLastMotorHallSensorCounts[ nextIdx ] ? \ dipMotorHallSensorCount - dipLastMotorHallSensorCounts[ nextIdx ] : \ ( HEX_64_K - dipLastMotorHallSensorCounts[ nextIdx ] ) + dipMotorHallSensorCount ); - U16 decDelta = HEX_64_K - incDelta; + U16 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); U16 delta; // Determine dialysate inlet pump speed/direction from delta hall sensor count since last interval @@ -979,36 +1015,33 @@ MOTOR_DIR_T dipMCDir, dipDir; U08 dirErrorCnt = getFPGADialInPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; -#ifndef DISABLE_PUMP_DIRECTION_CHECKS // Check pump direction error count - if ( lastDialInPumpDirectionCount != dirErrorCnt ) + if ( ( lastDialInPumpDirectionCount != dirErrorCnt ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { lastDialInPumpDirectionCount = dirErrorCnt; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_INLET_PUMP ) } -#endif dipMCDir = ( getMeasuredDialInPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); dipDir = ( getMeasuredDialInPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); // Check set direction vs. direction from hall sensors if ( dialInPumpDirectionSet != dipDir ) { - if ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) + if ( ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK, (U32)dialInPumpDirectionSet, (U32)dipDir ) -#endif } } // Check set direction vs. direction from sign of motor controller speed else if ( dialInPumpDirectionSet != dipMCDir ) { - if ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) + if ( ( ++errorDialInPumpDirectionPersistTimerCtr >= DIP_DIRECTION_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_DIRECTION_CHECK, (U32)dialInPumpDirectionSet, (U32)dipMCDir ) -#endif } } else @@ -1044,12 +1077,11 @@ { if ( measMotorSpeed > DIP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) { - if ( ++errorDialInMotorOffPersistTimerCtr >= DIP_OFF_ERROR_PERSIST ) + if ( ( ++errorDialInMotorOffPersistTimerCtr >= DIP_OFF_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); -#endif } } else @@ -1075,11 +1107,10 @@ // Check measured motor speed vs. commanded motor speed while controlling to target if ( ( deltaMotorSpeed > DIP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > DIP_MAX_MOTOR_SPEED_ERROR_RPM ) ) { - if ( ++errorDialInMotorSpeedPersistTimerCtr >= DIP_MOTOR_SPEED_ERROR_PERSIST ) + if ( ( ++errorDialInMotorSpeedPersistTimerCtr >= DIP_MOTOR_SPEED_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); -#endif } } else @@ -1090,11 +1121,10 @@ // Check measured rotor speed vs. measured motor speed while controlling to target if ( deltaRotorSpeed > DIP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) { - if ( ++errorDialInRotorSpeedPersistTimerCtr >= DIP_ROTOR_SPEED_ERROR_PERSIST ) + if ( ( ++errorDialInRotorSpeedPersistTimerCtr >= DIP_ROTOR_SPEED_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_IN_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); -#endif } } else @@ -1123,12 +1153,11 @@ F32 flow = getMeasuredDialInFlowRate(); // Range check on measure DPi flow rate. -#ifndef DISABLE_PUMP_FLOW_CHECKS - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, ( flow > DIP_MAX_FLOW_RATE ) || ( flow < DIP_MIN_FLOW_RATE ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, ( flow > DIP_MAX_FLOW_RATE ) || ( flow < DIP_MIN_FLOW_RATE ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, flow ); } -#endif // Check only performed while in treatment mode and while we are in control to target state if ( ( MODE_TREA == getCurrentOperationMode() ) && ( DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE == dialInPumpState ) ) @@ -1140,11 +1169,10 @@ if ( delta > DIP_MAX_FLOW_VS_SPEED_DIFF_RPM ) { - if ( ++errorDialInFlowVsMotorSpeedPersistTimerCtr >= DIP_FLOW_VS_SPEED_PERSIST ) + if ( ( ++errorDialInFlowVsMotorSpeedPersistTimerCtr >= DIP_FLOW_VS_SPEED_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_FLOW_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_IN_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, flow, speed ); -#endif } } else @@ -1177,11 +1205,10 @@ if ( dipCurr > DIP_MAX_CURR_WHEN_STOPPED_MA ) { dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) + if ( ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); -#endif } } else @@ -1196,11 +1223,10 @@ if ( dipCurr > DIP_MAX_CURR_WHEN_RUNNING_MA ) { dipCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) + if ( ( dipCurrErrorDurationCtr > DIP_MAX_CURR_ERROR_DURATION_MS ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MC_CURRENT_CHECK, getMeasuredDialInPumpMCCurrent() ); -#endif } } else @@ -1215,13 +1241,25 @@ * The execDialInFlowTest function executes the state machine for the * DialInFlow self-test. * @details Inputs: none - * @details Outputs: none + * @details Outputs: dialInPumpCalRecord * @return the current state of the DialInFlow self-test. *************************************************************************/ SELF_TEST_STATUS_T execDialInFlowTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&dialInPumpCalRecord, sizeof( HD_PUMPS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PUMPS, ALARM_ID_NO_ALARM ); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + return result; } Index: firmware/App/Controllers/DialInFlow.h =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/DialInFlow.h (.../DialInFlow.h) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Controllers/DialInFlow.h (.../DialInFlow.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file DialInFlow.h * * @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @date (last) 14-Jan-2022 * * @author (original) Sean * @date (original) 16-Dec-2019 @@ -59,6 +59,7 @@ void signalDialInPumpRotorHallSensor( void ); BOOL homeDialInPump( void ); BOOL isDialInPumpRunning( void ); +BOOL isDialInPumpRampComplete( void ); SELF_TEST_STATUS_T execDialInFlowTest( void ); Index: firmware/App/Controllers/DialOutFlow.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file DialOutFlow.c * -* @author (last) Sean Nash -* @date (last) 04-Jan-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 24-Jan-2020 @@ -25,6 +25,7 @@ #include "FPGA.h" #include "InternalADC.h" #include "ModeTreatment.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "PIControllers.h" #include "SafetyShutdown.h" @@ -100,14 +101,15 @@ #define DOP_REV_PER_LITER 146.84 ///< Rotor revolutions per liter. #define DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DOP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to pump motor RPM. #define DOP_GEAR_RATIO 32.0 ///< Pump motor to pump gear ratio. -#define DOP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. +#define DOP_PWM_ZERO_OFFSET 0.1F ///< 10% PWM duty cycle = zero speed. /// Macro converts a flow rate to an estimated PWM duty cycle %. #define DOP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DOP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DOP_GEAR_RATIO * DOP_MOTOR_RPM_TO_PWM_DC_FACTOR + DOP_PWM_ZERO_OFFSET ) /// Conversion from PWM duty cycle % to commanded pump motor speed. #define DOP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DOP_PWM_ZERO_OFFSET) * 4000.0 ) #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define DATA_PUBLISH_COUNTER_START_COUNT 40 ///< Data publish counter start count. /// Enumeration of dialysate outlet pump controller states. typedef enum DialOutPump_States @@ -139,7 +141,7 @@ // ********** private data ********** static DIAL_OUT_PUMP_STATE_T dialOutPumpState = DIAL_OUT_PUMP_OFF_STATE; ///< Current state of the dialysate outlet pump controller state machine. -static U32 dialOutFlowDataPublicationTimerCounter = 6; ///< Timer counter controlling when to publish dialysate outlet data. Set non-zero to phase data publication to CAN bus. +static U32 dialOutFlowDataPublicationTimerCounter; ///< Timer counter controlling when to publish dialysate outlet data. Set non-zero to phase data publication to CAN bus. static BOOL isDialOutPumpOn = FALSE; ///< Flag set to TRUE when dialysate outlet pump is running. static U32 lastGivenRate = 0; ///< Remembers the last given set point rate for the dialysate outlet pump. static F32 dialOutPumpPWMDutyCyclePct = 0.0; ///< Requested PWM duty cycle for dialysate outlet pump (based on given rate). @@ -185,7 +187,8 @@ static U32 errorDialOutRotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for rotor speed error condition. static U32 errorDialOutPumpDirectionPersistTimerCtr = 0; ///< Persistence timer counter for pump direction error condition. -static U08 lastDialOutPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA +static U08 lastDialOutPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA. +static HD_PUMPS_CAL_RECORD_T dialOutPumpCalRecord; ///< Dialysate outlet calibration record. // ********** private function prototypes ********** @@ -214,21 +217,23 @@ * @brief * The initDialOutFlow function initializes the DialOutFlow module. * @details Inputs: none - * @details Outputs: DialOutFlow module initialized. + * @details Outputs: dialOutFlowDataPublicationTimerCounter * @return none *************************************************************************/ void initDialOutFlow( void ) { U32 i; + dialOutFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + signalDialOutPumpHardStop(); setDialOutPumpDirection( MOTOR_DIR_FORWARD ); // Zero motor hall sensors counts buffer dopMotorSpeedCalcIdx = 0; for ( i = 0; i < DOP_SPEED_CALC_BUFFER__LEN; i++ ) { - dopLastMotorHallSensorCounts[ i ] = 0; + dopLastMotorHallSensorCounts[ i ] = getFPGADialOutPumpHallSensorCount(); } dopMeasuredRate = 0.0; @@ -260,10 +265,17 @@ // Don't interrupt pump control unless rate or mode is changing if ( ( fabs( pwmDC - dialOutPumpPWMDutyCyclePct ) > NEARLY_ZERO ) || ( mode != dialOutPumpControlMode ) ) { -#ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) + BOOL byPassFlowLimit = FALSE; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + byPassFlowLimit = TRUE; + } #endif + + // Verify flow rate + if ( ( flowRate <= MAX_DIAL_OUT_FLOW_RATE ) || ( TRUE == byPassFlowLimit ) ) { resetDialOutFlowMovingAverage(); dopControlSignal = FALSE; @@ -272,7 +284,6 @@ dialOutPumpControlMode = mode; // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed dialOutPumpPWMDutyCyclePct = pwmDC; - dialOutPumpPWMDutyCyclePct = MIN( dialOutPumpPWMDutyCyclePct, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); switch ( dialOutPumpState ) { @@ -304,12 +315,15 @@ } result = TRUE; } -#ifndef NO_PUMP_FLOW_LIMITS else // Requested flow rate too high { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) - } +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_OUT_FLOW_SET_TOO_HIGH, flowRate ) + } + } } } @@ -461,6 +475,48 @@ /*********************************************************************//** * @brief + * The isDialOutPumpRampComplete function returns whether the dialysate outlet pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: dialOutPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isDialOutPumpRampComplete( void ) +{ + BOOL result = ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ? TRUE : FALSE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The execDialOutFlowTest function executes the state machine for the + * DialOutFlow self-test. + * @details Inputs: none + * @details Outputs: dialOutPumpCalRecord + * @return the current state of the DialOutFlow self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execDialOutFlowTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&dialOutPumpCalRecord, sizeof( HD_PUMPS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PUMPS, ALARM_ID_NO_ALARM ); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; +} + +/*********************************************************************//** + * @brief * The execDialOutFlowMonitor function executes the dialysate outlet pump * and load cell sensor monitor. Checks are performed. Data is published * at appropriate interval. @@ -809,7 +865,7 @@ U16 incDelta = ( dopMotorHallSensorCount >= dopLastMotorHallSensorCounts[ nextIdx ] ? \ dopMotorHallSensorCount - dopLastMotorHallSensorCounts[ nextIdx ] : \ ( HEX_64_K - dopLastMotorHallSensorCounts[ nextIdx ] ) + dopMotorHallSensorCount ); - U16 decDelta = HEX_64_K - incDelta; + U16 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); U16 delta; // Determine dialysate outlet pump speed/direction from delta hall sensor count since last interval @@ -885,21 +941,19 @@ // Check set direction vs. direction from hall sensors if ( dialOutPumpDirectionSet != dopDir ) { - if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) + if ( ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopDir ) -#endif } } // Check set direction vs. direction from sign of motor controller speed else if ( dialOutPumpDirectionSet != dopMCDir ) { - if ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) + if ( ( ++errorDialOutPumpDirectionPersistTimerCtr >= DOP_DIRECTION_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_DIRECTION_CHECK, (U32)dialOutPumpDirectionSet, (U32)dopMCDir ) -#endif } } else @@ -935,12 +989,11 @@ { if ( measMotorSpeed > DOP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) { - if ( ++errorDialOutMotorOffPersistTimerCtr >= DOP_OFF_ERROR_PERSIST ) + if ( ( ++errorDialOutMotorOffPersistTimerCtr >= DOP_OFF_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); -#endif } } else @@ -965,11 +1018,10 @@ // Check measured motor speed vs. commanded motor speed while controlling to target if ( ( deltaMotorSpeed > DOP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > DOP_MAX_MOTOR_SPEED_ERROR_RPM ) ) { - if ( ++errorDialOutMotorSpeedPersistTimerCtr >= DOP_MOTOR_SPEED_ERROR_PERSIST ) + if ( ( ++errorDialOutMotorSpeedPersistTimerCtr >= DOP_MOTOR_SPEED_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); -#endif } } else @@ -980,11 +1032,10 @@ // Check measured rotor speed vs. measured motor speed while controlling to target if ( deltaRotorSpeed > DOP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) { - if ( ++errorDialOutRotorSpeedPersistTimerCtr >= DOP_ROTOR_SPEED_ERROR_PERSIST ) + if ( ( ++errorDialOutRotorSpeedPersistTimerCtr >= DOP_ROTOR_SPEED_ERROR_PERSIST ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); -#endif } } else @@ -1018,11 +1069,10 @@ if ( dopCurr > DOP_MAX_CURR_WHEN_STOPPED_MA ) { dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) + if ( ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); -#endif } } else @@ -1037,11 +1087,10 @@ if ( dopCurr > DOP_MAX_CURR_WHEN_RUNNING_MA ) { dopCurrErrorDurationCtr += TASK_PRIORITY_INTERVAL; - if ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) + if ( ( dopCurrErrorDurationCtr > DOP_MAX_CURR_ERROR_DURATION_MS ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { -#ifndef DISABLE_MOTOR_CURRENT_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DIAL_OUT_PUMP_MC_CURRENT_CHECK, getMeasuredDialOutPumpMCCurrent() ); -#endif } } else Index: firmware/App/Controllers/DialOutFlow.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/DialOutFlow.h (.../DialOutFlow.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/DialOutFlow.h (.../DialOutFlow.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file DialOutFlow.h * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 24-Jan-2020 @@ -74,8 +74,9 @@ void signalDialOutControl( void ); BOOL homeDialOutPump( void ); BOOL isDialOutPumpRunning( void ); +BOOL isDialOutPumpRampComplete( void ); -// SELF_TEST_STATUS_T execDialOutFlowTest( void ); // TODO - implement later +SELF_TEST_STATUS_T execDialOutFlowTest( void ); F32 getTotalTargetDialOutUFVolumeInMl( void ); F32 getTotalMeasuredUFVolumeInMl( void ); Index: firmware/App/Controllers/Fans.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Fans.c (.../Fans.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Fans.c (.../Fans.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,13 +8,14 @@ * @file Fans.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 03-Mar-2022 * * @author (original) Dara Navaei * @date (original) 04-Aug-2021 * ***************************************************************************/ +#include // For fabs #include "etpwm.h" #include "Fans.h" @@ -53,31 +54,32 @@ #define FANS_MIN_ALLOWED_RPM 150 ///< Fans max allowed RPM value. #define FANS_MIN_RPM_OUT_OF_RANGE_TOL 0.25 ///< Fans min RPM out of range tolerance. #define FANS_MAX_RPM_OUT_OF_RANGE_TOL 0.5 ///< Fans max RPM out of range tolerance. +#define DATA_PUBLISH_COUNTER_START_COUNT 15 ///< Data publish counter start count. /// Fans exec states typedef enum fans_Exec_States { - FANS_EXEC_STATE_WAIT_FOR_POST_STATE = 0, ///< Fans exec state start state - FANS_EXEC_STATE_RUN_STATE, ///< Fans exec state run state - NUM_OF_FANS_EXEC_STATES, ///< Number of fans exec states + FANS_EXEC_STATE_WAIT_FOR_POST_STATE = 0, ///< Fans exec state start state. + FANS_EXEC_STATE_RUN_STATE, ///< Fans exec state run state. + NUM_OF_FANS_EXEC_STATES, ///< Number of fans exec states. } FANS_EXEC_STATES_T; /// Fans status struct typedef struct { - F32 targetDutyCycle; ///< Fan's target duty cycle that was fed to the fans - F32 targetRPM; ///< Fan's target RPM - OVERRIDE_F32_T rpm[ NUM_OF_FANS_NAMES ]; ///< Fan's current tachometers reading in RPM + OVERRIDE_F32_T dutyCycle; ///< Fan's target duty cycle that was fed to the fans. + F32 targetRPM; ///< Fan's target RPM. + OVERRIDE_F32_T rpm[ NUM_OF_FANS_NAMES ]; ///< Fan's current tachometers reading in RPM. } FAN_STATUS_T; static FAN_STATUS_T fansStatus; ///< Fans status. -static FANS_EXEC_STATES_T fansExecState = FANS_EXEC_STATE_WAIT_FOR_POST_STATE; ///< Fans exec state. -static U32 fansControlCounter = 0; ///< Fans control interval counter. -static U32 fansPublishCounter = 0; ///< Fans data publish interval counter. -static BOOL isPOSTComplete = FALSE; ///< Flag that indicates whether POST is complete or not. -static BOOL hasAlarmBeenRaised = FALSE; ///< Flag that indicates whether RPM out of range alarm has been raised once. +static FANS_EXEC_STATES_T fansExecState; ///< Fans exec state. +static U32 fansControlCounter; ///< Fans control interval counter. +static U32 fansPublishCounter; ///< Fans data publish interval counter. +static BOOL isPOSTComplete; ///< Flag that indicates whether POST is complete or not. +static BOOL hasAlarmBeenRaised; ///< Flag that indicates whether RPM out of range alarm has been raised once. static OVERRIDE_U32_T rpmAlarmStartTimeOffset = { 0, 0, 0, 0}; ///< RPM out of range alarm start time offset. -static U32 rpmAlarmStartTime = 0; ///< RPM alarm start time. +static U32 rpmAlarmStartTime; ///< RPM alarm start time. /// Temperature to duty cycle conversion slope (duty cycle not in percent) static const F32 SLOPE = ( FANS_MAX_DUTY_CYCLE - FANS_MIN_DUTY_CYCLE ) / ( MAX_ALLOWED_AMBINET_TEMPERATURE - MIN_ALLOWED_AMBIENT_TEMPERATURE ); @@ -115,20 +117,23 @@ // Initialize the variables fansExecState = FANS_EXEC_STATE_WAIT_FOR_POST_STATE; fansControlCounter = 0; - fansPublishCounter = 0; + fansPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; isPOSTComplete = FALSE; hasAlarmBeenRaised = FALSE; rpmAlarmStartTime = 0; rpmAlarmStartTimeOffset.data = 0; rpmAlarmStartTimeOffset.ovData = 0; rpmAlarmStartTimeOffset.ovInitData = 0; rpmAlarmStartTimeOffset.override = 0; + fansStatus.dutyCycle.data = 0.0; + fansStatus.dutyCycle.ovInitData = 0.0; + fansStatus.dutyCycle.ovData = 0.0; + fansStatus.dutyCycle.override = OVERRIDE_RESET; + fansStatus.targetRPM = 0.0; // Initialize the fans for ( fan = FAN_INLET_1; fan < NUM_OF_FANS_NAMES; fan++ ) { - fansStatus.targetDutyCycle = 0.0; - fansStatus.targetRPM = 0.0; fansStatus.rpm[ fan ].data = 0.0; fansStatus.rpm[ fan ].ovData = 0.0; fansStatus.rpm[ fan ].ovInitData = 0.0; @@ -245,11 +250,6 @@ state = FANS_EXEC_STATE_RUN_STATE; } -#ifndef _VECTORCAST_ // To skip the wait for POST and start running. - // TODO REMOVE - state = FANS_EXEC_STATE_RUN_STATE; - // TODO REMOVE -#endif return state; } @@ -266,7 +266,7 @@ FANS_EXEC_STATES_T state = FANS_EXEC_STATE_RUN_STATE; // Check if it is time to check for the control - if ( ++fansControlCounter > FANS_CONTROL_INTERVAL ) + if ( ( ++fansControlCounter > FANS_CONTROL_INTERVAL ) && ( OVERRIDE_RESET == fansStatus.dutyCycle.override ) ) { // Get the maximum temperature among all the thermistors and temperature sensors to run fan from the hottest temperature F32 temperature = getMaximumTemperature(); @@ -286,43 +286,48 @@ // If the fans calculated duty cycle is greater than the previous calculated duty cycle, we are ramping up // otherwise, we are ramping down - if ( dutyCycle >= fansStatus.targetDutyCycle ) + if ( dutyCycle >= fansStatus.dutyCycle.data ) { // If the delta duty cycle from the previous duty cycle is greater than the max allowed ramp up duty cycle, // otherwise, only add the delta duty cycle - if ( ( dutyCycle - fansStatus.targetDutyCycle ) >= FANS_MAX_ALLOWED_RAMP_UP_DELTA_DUTY_CYCLE ) + if ( ( dutyCycle - fansStatus.dutyCycle.data ) >= FANS_MAX_ALLOWED_RAMP_UP_DELTA_DUTY_CYCLE ) { - fansStatus.targetDutyCycle += FANS_MAX_ALLOWED_RAMP_UP_DELTA_DUTY_CYCLE; + fansStatus.dutyCycle.data += FANS_MAX_ALLOWED_RAMP_UP_DELTA_DUTY_CYCLE; } else { - fansStatus.targetDutyCycle = dutyCycle; + fansStatus.dutyCycle.data = dutyCycle; } } else { // If the delta duty cycle from the previous duty cycle is greater than the max allowed ramp down duty cycle, // otherwise, only add the delta duty cycle - if ( ( fansStatus.targetDutyCycle - dutyCycle ) >= FANS_MAX_ALLOWED_RAMP_DOWN_DELTA_DUTY_CYCLE ) + if ( ( fansStatus.dutyCycle.data - dutyCycle ) >= FANS_MAX_ALLOWED_RAMP_DOWN_DELTA_DUTY_CYCLE ) { // If we are ramping down, set the target duty cycle to max allowed ramp down duty cycle - fansStatus.targetDutyCycle -= FANS_MAX_ALLOWED_RAMP_DOWN_DELTA_DUTY_CYCLE; + fansStatus.dutyCycle.data -= FANS_MAX_ALLOWED_RAMP_DOWN_DELTA_DUTY_CYCLE; } else { - fansStatus.targetDutyCycle = dutyCycle; + fansStatus.dutyCycle.data = dutyCycle; } } // Calculate the target RPM from the duty cycle. - fansStatus.targetRPM = fansStatus.targetDutyCycle * FANS_MAX_ALLOWED_RPM; + fansStatus.targetRPM = fansStatus.dutyCycle.data * FANS_MAX_ALLOWED_RPM; // Set the PWM to inlet and outlet fans - setInletFansDutyCycle( fansStatus.targetDutyCycle ); + setInletFansDutyCycle( fansStatus.dutyCycle.data ); // Reset the counter fansControlCounter = 0; } + else if ( OVERRIDE_KEY == fansStatus.dutyCycle.override ) + { + // The fans are in override mode set the override duty cycle + setInletFansDutyCycle( fansStatus.dutyCycle.ovData ); + } return state; } @@ -418,7 +423,8 @@ // The RPM is expected to be 5500 @ 100% duty cycle // The nominal RPM = duty cycle * 5500 / 1.0 // The RPM tolerance is -25% to +50% of the nominal RPM - F32 fansNominalRPM = fansStatus.targetDutyCycle * FANS_MAX_ALLOWED_RPM; + F32 dutyCycle = ( OVERRIDE_RESET == fansStatus.dutyCycle.override ? fansStatus.dutyCycle.data : fansStatus.dutyCycle.ovData ); + F32 fansNominalRPM = dutyCycle * FANS_MAX_ALLOWED_RPM; F32 fansMinAllowedRPM = fansNominalRPM - ( fansNominalRPM * FANS_MIN_RPM_OUT_OF_RANGE_TOL ); F32 fansMaxAllowedRPM = fansNominalRPM + ( fansNominalRPM * FANS_MAX_RPM_OUT_OF_RANGE_TOL ); @@ -429,7 +435,10 @@ isFanRPMOutOfRange |= ( ( rpm < fansMinAllowedRPM ) || ( rpm > fansMaxAllowedRPM ) ? TRUE : FALSE ); } - if ( FALSE == hasAlarmBeenRaised ) + // Check if the alarm has not been raise yet, raise it then + // Before checking for the alarm, the POST must be completed. The fans POST is after the temperatures POST that should get their + // calibration to be able to apply them and calculate the temperatures that are used to alarm the fans. + if ( ( FALSE == hasAlarmBeenRaised ) && ( TRUE == isPOSTComplete ) ) { isAlarmTriggered = isPersistentAlarmTriggered( ALARM_ID_HD_FAN_RPM_OUT_OF_RANGE, isFanRPMOutOfRange ); @@ -438,20 +447,32 @@ SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_FAN_RPM_OUT_OF_RANGE, rpm ) // Set the alarm flag to TRUE hasAlarmBeenRaised = TRUE; + + // If the alarm has been raised but the start time of the alarm has not been set, set the alarm start timer + if ( 0 == rpmAlarmStartTime ) + { + rpmAlarmStartTime = getMSTimerCount(); + } } - // If the alarm has been raised but the start time of the alarm has not been set, set the alarm start timer - if ( ( TRUE == hasAlarmBeenRaised ) && ( 0 == rpmAlarmStartTime ) ) - { - rpmAlarmStartTime = getMSTimerCount(); - } } // If the alarm has been raised and the alarm has been silent for at least a day, set the flag to FALSE // This way, if the fans RPM are out of range the alarm will be raised again. This alarm is supposed to be raised // and remain silent for a defined period of time. - else if ( ( TRUE == hasAlarmBeenRaised ) && ( ( calcTimeSince( rpmAlarmStartTime ) + getRPMAlarmStartTimeOffset() ) >= SECONDS_IN_A_DAY * MS_PER_SECOND ) ) + else { - hasAlarmBeenRaised = FALSE; - rpmAlarmStartTime = 0; + // Get the offset time since the last alarm. If the offset time has been overridden, then do not include the time that the alarm was raised first. + // Overrides are used to verify the code so what is sent to the firmware from override is intended to be the actual time so check whether the alarm is + // raised properly or not. Adding the start time of the alarm might cause inaccuracy in the verification process. + // For instance, if 86390 seconds is overridden to make sure the alarm is not raise before 24 hours or 86400, if the rpmAlarmStartTime is added to it + // it might make the time to be greater than 86400 seconds and therefore the alarm is raised again while it is not expected. + U32 offsetTime = getRPMAlarmStartTimeOffset(); + U32 elapsedTime = ( OVERRIDE_KEY == rpmAlarmStartTimeOffset.override ? offsetTime : calcTimeSince( rpmAlarmStartTime ) + offsetTime ); + + if ( elapsedTime >= SECONDS_IN_A_DAY * MS_PER_SECOND ) + { + hasAlarmBeenRaised = FALSE; + rpmAlarmStartTime = 0; + } } } @@ -507,7 +528,7 @@ { FANS_DATA_T data; - data.fansDutyCycle = fansStatus.targetDutyCycle * FRACTION_TO_PERCENT_FACTOR; + data.fansDutyCycle = ( OVERRIDE_RESET == fansStatus.dutyCycle.override ? fansStatus.dutyCycle.data : fansStatus.dutyCycle.ovData ) * FRACTION_TO_PERCENT_FACTOR; data.fansTargetRPM = fansStatus.targetRPM; data.fanInlet1RPM = getMeasuredFanRPM( FAN_INLET_1 ); data.rpmAlarmTimeOffset = getRPMAlarmStartTimeOffset(); @@ -628,17 +649,16 @@ * start time offset. * @details Inputs: none * @details Outputs: rpmAlarmStartTimeOffset - * @param hours hours to override - * @param minutes minutes to override + * @param seconds seconds to override * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 hours, U32 minutes ) +BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 seconds ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { - rpmAlarmStartTimeOffset.ovData = rpmAlarmStartTimeOffset.ovData + ( ( hours * MIN_PER_HOUR * SEC_PER_MIN ) + ( minutes * SEC_PER_MIN ) ) * MS_PER_SECOND; + rpmAlarmStartTimeOffset.ovData = seconds * MS_PER_SECOND; rpmAlarmStartTimeOffset.override = OVERRIDE_KEY; result = TRUE; @@ -671,5 +691,54 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetFansDutyCycleOverride function overrides fans duty cycle + * @details Inputs: none + * @details Outputs: fansStatus + * @param value the duty cycle value to be overridden + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetFansDutyCycleOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + if( ( value >= FANS_MIN_DUTY_CYCLE ) && ( value <= FANS_MAX_DUTY_CYCLE ) ) + { + fansStatus.dutyCycle.ovData = value; + fansStatus.dutyCycle.override = OVERRIDE_KEY; + + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetFansDutyCycleOverride function resets the fans duty cycle + * override + * @details Inputs: none + * @details Outputs: fansStatus + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetFansDutyCycleOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + fansStatus.dutyCycle.override = OVERRIDE_RESET; + fansStatus.dutyCycle.ovData = 0.0; + + result = TRUE; + } + + return result; +} + /**@}*/ Index: firmware/App/Controllers/Fans.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Fans.h (.../Fans.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Fans.h (.../Fans.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file Fans.h * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 02-Mar-2022 * * @author (original) Dara Navaei * @date (original) 04-Aug-2021 @@ -58,9 +58,12 @@ BOOL testSetFanRPMOverride( U32 fanId, F32 rpm ); BOOL testResetFanRPMOverride( U32 fanId ); -BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 hours, U32 minutes ); +BOOL testSetFanRPMAlarmStartTimeOffsetOverride( U32 seconds ); BOOL testResetFanRPMAlarmStartTimeOffsetOverride( void ); +BOOL testSetFansDutyCycleOverride( F32 value ); +BOOL testResetFansDutyCycleOverride( void ); + /**@}*/ Index: firmware/App/Controllers/FluidLeak.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/FluidLeak.c (.../FluidLeak.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/FluidLeak.c (.../FluidLeak.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file FluidLeak.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 26-Feb-2022 * * @author (original) Peman Montazemi * @date (original) 09-Mar-2021 @@ -30,11 +30,12 @@ // ********** private definitions ********** -#define FLUID_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the fluid leak data is published on the CAN bus. +#define FLUID_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the fluid leak data is published on the CAN bus. +#define DATA_PUBLISH_COUNTER_START_COUNT 50 ///< Data publish counter start count. // ********** private data ********** -static U32 fluidLeakStatePublicationTimerCounter = 0; ///< Timer counter used to schedule fluid leak publication to CAN bus. +static U32 fluidLeakStatePublicationTimerCounter; ///< Timer counter used to schedule fluid leak publication to CAN bus. /// Interval (in ms) at which to publish fluid leak data to CAN bus. static OVERRIDE_U32_T fluidLeakStatePublishInterval = { FLUID_LEAK_PUB_INTERVAL, FLUID_LEAK_PUB_INTERVAL, 0, 0 }; @@ -53,10 +54,11 @@ *************************************************************************/ void initFluidLeak( void ) { - fluidLeakState.data = FLUID_LEAK_STATE_DRY; - fluidLeakState.ovInitData = FLUID_LEAK_STATE_DRY; - fluidLeakState.ovData = FLUID_LEAK_STATE_DRY; - fluidLeakState.override = OVERRIDE_RESET; + fluidLeakState.data = FLUID_LEAK_STATE_DRY; + fluidLeakState.ovInitData = FLUID_LEAK_STATE_DRY; + fluidLeakState.ovData = FLUID_LEAK_STATE_DRY; + fluidLeakState.override = OVERRIDE_RESET; + fluidLeakStatePublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; } /*********************************************************************//** Index: firmware/App/Controllers/PresOccl.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/PresOccl.c (.../PresOccl.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file PresOccl.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Sean * @date (original) 15-Jan-2020 @@ -18,7 +18,8 @@ #include "PresOccl.h" #include "AlarmMgmt.h" #include "FPGA.h" -#include "ModeTreatmentParams.h" +#include "ModeTreatmentParams.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" @@ -36,16 +37,24 @@ /// Default publication interval for pressure and occlusion data. #define PRES_OCCL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the pressure/occlusion data is published on the CAN bus. - + +#define ARTERIAL_PRESSURE_CONVERSION_OFFSET 0x800000 ///< Arterial pressure conversion coefficient. #define ARTERIAL_PRESSURE_V_BIAS ( 3.0 ) ///< Bias voltage for arterial pressure sensor. #define ARTERIAL_PRESSURE_SENSITIVITY ( 0.000005 ) ///< Sensitivity for arterial pressure sensor is 5 uV / mmHg -#define ARTERIAL_PRESSURE_V_PER_BIT ( ARTERIAL_PRESSURE_V_BIAS / (F32)0x800000 ) ///< Volts per bit in 24-bit arterial pressure sensor reading. +#define ARTERIAL_PRESSURE_V_PER_BIT ( ARTERIAL_PRESSURE_V_BIAS / \ + (F32)ARTERIAL_PRESSURE_CONVERSION_OFFSET ) ///< Volts per bit in 24-bit arterial pressure sensor reading. #define VENOUS_PRESSURE_OFFSET ( 1638 ) ///< Offset for 14-bit venous pressure sensor reading. #define VENOUS_PRESSURE_SCALE ( 14745 - VENOUS_PRESSURE_OFFSET ) ///< Scale for venous pressure sensor. #define VENOUS_PRESSURE_MIN_PSI ( -30.0 ) ///< Minimum of scale for venous pressure sensor reading (in PSI). #define VENOUS_PRESSURE_MAX_PSI ( 30.0 ) ///< Maximum of scale for venous pressure sensor reading (in PSI). +#define MIN_VENOUS_PRESSURE_FOR_RAMP_MMHG ( 0.0 ) ///< Minimum venous pressure during blood pump ramp up (in mmHg). +#define ARTERIAL_PRESSURE_OFFSET ( 1638 ) ///< Offset for 14-bit arterial pressure sensor reading. +#define ARTERIAL_PRESSURE_SCALE ( 14745 - VENOUS_PRESSURE_OFFSET ) ///< Scale for arterial pressure sensor. +#define ARTERIAL_PRESSURE_MIN_PSI ( -30.0 ) ///< Minimum of scale for arterial pressure sensor reading (in PSI). +#define ARTERIAL_PRESSURE_MAX_PSI ( 30.0 ) ///< Maximum of scale for arterial pressure sensor reading (in PSI). + #define ARTERIAL_PRESSURE_SELF_TEST_MIN ( -300.0 ) ///< Minimum self-test value for arterial pressure sensor reading (in mmHg). #define ARTERIAL_PRESSURE_SELF_TEST_MAX ( 100.0 ) ///< Maximum self-test value for arterial pressure sensor reading (in mmHg). #define ARTERIAL_PRESSURE_MAX_MMHG ( 2000.0 ) ///< Maximum arterial pressure reading (in mmHg) for range check. @@ -56,18 +65,22 @@ #define VENOUS_PRESSURE_MAX_MMHG ( 2000.0 ) ///< Maximum venous pressure reading (in mmHg) for range check. #define VENOUS_PRESSURE_MIN_MMHG ( -1500.0 ) ///< Minimum venous pressure reading (in mmHg) for range check. -#define VENOUS_PRESSURE_MIN_TEMP ( 0.0 ) ///< Minimum venous pressure sensor temperature. -#define VENOUS_PRESSURE_MAX_TEMP ( 80.0 ) ///< Maximum venous pressure sensor temperature. - #define PSI_TO_MMHG ( 51.7149 ) ///< Conversion factor for converting PSI to mmHg. #define VENOUS_PRESSURE_NORMAL_OP 0 ///< Venous pressure status bits indicate normal operation. #define VENOUS_PRESSURE_CMD_MODE 1 ///< Venous pressure status bits indicate sensor in command mode. #define VENOUS_PRESSURE_STALE_DATA 2 ///< Venous pressure status bits indicate data is stale (no new data since last fpga read). #define VENOUS_PRESSURE_DIAG_CONDITION 3 ///< Venous pressure status bits diagnostic condition (alarm). +// The new arterial pressure sensor is the same as the venous pressure sensor +#define ARTERIAL_PRESSURE_NORMAL_OP 0 ///< Arterial pressure status bits indicate normal operation. +#define ARTERIAL_PRESSURE_CMD_MODE 1 ///< Arterial pressure status bits indicate sensor in command mode. +#define ARTERIAL_PRESSURE_STALE_DATA 2 ///< Arterial pressure status bits indicate data is stale (no new data since last fpga read). +#define ARTERIAL_PRESSURE_DIAG_CONDITION 3 ///< Arterial pressure status bits diagnostic condition (alarm). + #define OCCLUSION_THRESHOLD_OFFSET 4000 ///< Threshold offset. Combined with initial reading after cartridge install, a threshold is derived above which an occlusion is detected. #define OCCLUSION_CLEAR_THRESHOLD_OFFSET 4000 ///< Threshold offset. Combined with initial reading after cartridge install, a threshold is derived below which an occlusion is cleared. + #define CARTRIDGE_LOADED_THRESHOLD 5000 ///< Threshold above which a cartridge is considered loaded. #define MIN_OCCLUSION_COUNTS 2000 ///< Minimum occlusion sensor reading for range check. #define MAX_OCCLUSION_COUNTS 32766 ///< Maximum occlusion sensor reading for range check. @@ -84,27 +97,30 @@ #define SIZE_OF_SHORT_ART_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 1 ) /// Measured venous pressure is filtered w/ 1 second moving average for inline pressure and unfiltered for occlusion detection. #define SIZE_OF_SHORT_VEN_ROLLING_AVG ( ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) * 1 ) + +#define DATA_PUBLISH_COUNTER_START_COUNT 5 ///< Data publish counter start count. +#define SHIFT_14_BITS 14 ///< Shift 14 bits. /// Defined states for the pressure and occlusion monitor state machine. typedef enum PresOccl_States { - PRESSURE_INIT_STATE = 0, ///< Initialization state. - PRESSURE_CONTINUOUS_READ_STATE, ///< Continuous read sensors state. - NUM_OF_PRESSURE_STATES ///< Number of pressure/occlusion monitor states. + PRESSURE_WAIT_FOR_POST_STATE = 0, ///< Wait for POST state. + PRESSURE_CONTINUOUS_READ_STATE, ///< Continuous read sensors state. + NUM_OF_PRESSURE_STATES ///< Number of pressure/occlusion monitor states. } PRESSURE_STATE_T; /// Defined states for the pressure and occlusion self-test state machine. typedef enum PresOccl_Self_Test_States { - PRESSURE_SELF_TEST_STATE_START = 0, ///< Self test start state. - PRESSURE_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. - PRESSURE_TEST_STATE_COMPLETE, ///< Self test completed state. - NUM_OF_PRESSURE_SELF_TEST_STATES ///< Number of pressure/occlusion self-test states. + PRESSURE_SELF_TEST_STATE_START = 0, ///< Self test start state. + PRESSURE_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. + PRESSURE_TEST_STATE_COMPLETE, ///< Self test completed state. + NUM_OF_PRESSURE_SELF_TEST_STATES ///< Number of pressure/occlusion self-test states. } PRESSURE_SELF_TEST_STATE_T; // ********** private data ********** -static PRESSURE_STATE_T presOcclState = PRESSURE_INIT_STATE; ///< Current state of pressure monitor state machine. +static PRESSURE_STATE_T presOcclState; ///< Current state of pressure monitor state machine. static U32 presOcclDataPublicationTimerCounter = 0; ///< Used to schedule pressure data publication to CAN bus. /// Interval (in ms) at which to publish pressure/occlusion data to CAN bus. @@ -117,18 +133,14 @@ static F32 shortFilteredArterialPressure; ///< Measured arterial pressure after short (1 s) filter. static F32 shortFilteredVenousPressure; ///< Measured venous pressure after short (1 s) filter. -#ifndef DISABLE_PRESSURE_CHECKS static U32 bloodPumpOcclusionAfterCartridgeInstall; ///< Measured blood pump occlusion reading taken after cartridge install. -#endif static U32 emptySalineBagCtr = 0; ///< Timer counter for empty bag detection. static U08 lastArterialPressureReadCtr; ///< Previous arterial pressure sensor read count. static U08 lastVenousPressureReadCtr; ///< Previous venous pressure sensor read count. -#ifndef DISABLE_PRESSURE_CHECKS static U08 lastBPOcclReadCtr; ///< Previous BP occlusion sensor read count. static U08 lastBPErrorCtr; ///< Previous BP error count. -#endif static F32 artPressureReadingsLong[ SIZE_OF_LONG_ART_ROLLING_AVG ]; ///< Holds flow samples for long arterial pressure rolling average. static U32 artPressureReadingsLongIdx = 0; ///< Index for next sample in rolling average array. @@ -144,9 +156,13 @@ static U32 venPressureReadingsShortIdx = 0; ///< Index for next sample in rolling average array. static F32 venPressureReadingsShortTotal = 0.0; ///< Rolling total - used to calc average. static U32 venPressureReadingsShortCount = 0; ///< Number of samples in flow rolling average buffer. +static PRESSURE_SELF_TEST_STATE_T presOcclPostState; ///< Pressure self test post state. +static HD_PRESSURE_SENSORS_CAL_RECORD_T pressureSensorsCalRecord; ///< Pressure sensors calibration record. +static HD_OCCLUSION_SENSORS_CAL_RECORD_T occlusionSensorsCalRecord; ///< Occlusion sensors calibration record. // ********** private function prototypes ********** - + +static PRESSURE_STATE_T handlePresOcclWaitForPOSTState( void ); static PRESSURE_STATE_T handlePresOcclContReadState( void ); static void convertInlinePressures( void ); static void convertOcclusionPressures( void ); @@ -177,21 +193,28 @@ initPersistentAlarm( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); initPersistentAlarm( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, 0, PRES_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, 0, PRES_ALARM_PERSISTENCE ); lastArterialPressureReadCtr = 0; - lastVenousPressureReadCtr = 0; -#ifndef DISABLE_PRESSURE_CHECKS - lastBPOcclReadCtr = 0; - lastBPErrorCtr = 0; -#endif + lastVenousPressureReadCtr = 0; + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + { + lastBPOcclReadCtr = 0; + lastBPErrorCtr = 0; + } - longFilteredArterialPressure = 0.0; - shortFilteredArterialPressure = 0.0; - shortFilteredVenousPressure = 0.0; + longFilteredArterialPressure = 0.0; + shortFilteredArterialPressure = 0.0; + shortFilteredVenousPressure = 0.0; + presOcclDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + presOcclState = PRESSURE_WAIT_FOR_POST_STATE; + presOcclPostState = PRESSURE_SELF_TEST_STATE_START; -#ifndef DISABLE_PRESSURE_CHECKS - bloodPumpOcclusionAfterCartridgeInstall = 0; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + { + bloodPumpOcclusionAfterCartridgeInstall = 0; + } } /*********************************************************************//** @@ -270,9 +293,12 @@ *************************************************************************/ void setOcclusionInstallLevel( void ) { -#ifndef DISABLE_PRESSURE_CHECKS - bloodPumpOcclusionAfterCartridgeInstall = getMeasuredBloodPumpOcclusion(); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + bloodPumpOcclusionAfterCartridgeInstall = getMeasuredBloodPumpOcclusion(); + } } /*********************************************************************//** @@ -287,8 +313,8 @@ // State machine switch ( presOcclState ) { - case PRESSURE_INIT_STATE: - presOcclState = PRESSURE_CONTINUOUS_READ_STATE; + case PRESSURE_WAIT_FOR_POST_STATE: + presOcclState = handlePresOcclWaitForPOSTState(); break; case PRESSURE_CONTINUOUS_READ_STATE: @@ -302,6 +328,26 @@ // Publish pressure/occlusion data on interval publishPresOcclData(); +} + +/*********************************************************************//** + * @brief + * The handlePresOcclWaitForPOSTState function handles the wait for POST + * state. + * @details Inputs: presOcclPostState + * @details Outputs: none + * @return next state + *************************************************************************/ +static PRESSURE_STATE_T handlePresOcclWaitForPOSTState( void ) +{ + PRESSURE_STATE_T result = PRESSURE_WAIT_FOR_POST_STATE; + + if ( PRESSURE_TEST_STATE_COMPLETE == presOcclPostState ) + { + result = PRESSURE_CONTINUOUS_READ_STATE; + } + + return result; } /*********************************************************************//** @@ -342,26 +388,71 @@ *************************************************************************/ static void convertInlinePressures( void ) { - U32 fpgaArtPres = getFPGAArterialPressure(); - S32 artPres = (S32)( fpgaArtPres & MASK_OFF_U32_MSB ) - 0x800000; // Subtract 2^23 from low 24 bits to get signed reading - U08 artPresAlarm = (U08)( fpgaArtPres >> SHIFT_24_BITS ); // High byte is alarm code for arterial pressure - U16 fpgaVenPres = getFPGAVenousPressure(); - U16 venPres = fpgaVenPres & 0x3FFF; // 14-bit data - U08 venPresStatus = (U08)( fpgaVenPres >> 14 ); // High 2 bits is status code for venous pressure - F32 venPresPSI; - F32 venTemp = getTemperatureValue( TEMPSENSOR_VENOUS_PRESSURE_SENSOR ); - U08 venReadCtr = getFPGAVenousPressureReadCounter(); + F32 rawArterialPres = 0.0; + U08 artPresAlarm = 0; + U08 artPresStatus = 0; + F32 venPresPSI = 0.0; + U16 fpgaVenPres = getFPGAVenousPressure(); + U16 venPres = fpgaVenPres & 0x3FFF; // 14-bit data + U08 venPresStatus = (U08)( fpgaVenPres >> SHIFT_14_BITS ); // High 2 bits is status code for venous pressure + U08 venReadCtr = getFPGAVenousPressureReadCounter(); + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) + { + U16 fpgaArtPres = getFPGADVTArterialPressure(); + U16 artPres = fpgaArtPres & 0x3FFF; + rawArterialPres = (F32)artPres; + artPresStatus = (U08)( fpgaArtPres >> SHIFT_14_BITS ); + } + else + { + U32 fpgaArtPres = getFPGAArterialPressure(); + S32 artPres = (S32)( fpgaArtPres & MASK_OFF_U32_MSB ) - ARTERIAL_PRESSURE_CONVERSION_OFFSET; // Subtract 2^23 from low 24 bits to get signed reading + rawArterialPres = (F32)artPres; + artPresAlarm = (U08)( fpgaArtPres >> SHIFT_24_BITS ); // High byte is alarm code for arterial pressure + } + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) +#endif + { + if ( ARTERIAL_PRESSURE_NORMAL_OP == artPresStatus ) + { + U08 artReadCtr = getFPGADVTArterialPressureReadCounter(); + + // Check for stale venous pressure reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR ); + } + // Record arterial pressure sensor read counter for next time around + lastArterialPressureReadCtr = artReadCtr; + + arterialPressure.data = ( (F32)(rawArterialPres - ARTERIAL_PRESSURE_OFFSET) * + (ARTERIAL_PRESSURE_MAX_PSI - ARTERIAL_PRESSURE_MIN_PSI) / (F32)ARTERIAL_PRESSURE_SCALE ) + ARTERIAL_PRESSURE_MIN_PSI; + arterialPressure.data = arterialPressure.data * PSI_TO_MMHG; + } + else if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, TRUE ) ) + { + activateAlarmNoData( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT ); + } + else + { + resetPersistentAlarmTimer( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT ); + } + } // Convert arterial pressure to mmHg if no fault - if ( 0 == artPresAlarm ) + else if ( 0 == artPresAlarm ) { - U08 artReadCtr = getFPGAArterialPressureReadCounter(); + U08 artReadCtr = getFPGAArterialPressureReadCounter(); U08 artErrorCtr = getFPGAArterialPressureErrorCounter(); // Check for stale arterial pressure reading - if ( FALSE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr || artErrorCtr > 0 ) ) ) + // TODO I think we should check the change of the error count not if it is greater than 0? + if ( FALSE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_READ_TIMEOUT_ERROR, ( lastArterialPressureReadCtr == artReadCtr || artErrorCtr > 0 ) ) ) { - arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( (F32)(artPres) / ( ARTERIAL_PRESSURE_SENSITIVITY * ARTERIAL_PRESSURE_V_BIAS ) ) + getF32OverrideValue( &arterialPressureOffset ); + arterialPressure.data = ARTERIAL_PRESSURE_V_PER_BIT * ( rawArterialPres / ( ARTERIAL_PRESSURE_SENSITIVITY * ARTERIAL_PRESSURE_V_BIAS ) ) + + getF32OverrideValue( &arterialPressureOffset ); } else { @@ -372,9 +463,12 @@ } else { -#ifndef DISABLE_PRESSURE_CHECKS - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, (U32)artPresAlarm ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_ARTERIAL_PRESSURE_SENSOR_FAULT, (U32)artPresAlarm ) + } } // Check for stale venous pressure reading @@ -384,19 +478,29 @@ } // Record venous pressure sensor read counter for next time around lastVenousPressureReadCtr = venReadCtr; + // Convert venous pressure to PSI and then mmHg - venPresPSI = ( (F32)(venPres - VENOUS_PRESSURE_OFFSET) * (VENOUS_PRESSURE_MAX_PSI - VENOUS_PRESSURE_MIN_PSI) / (F32)VENOUS_PRESSURE_SCALE ) + VENOUS_PRESSURE_MIN_PSI; + venPresPSI = ( (F32)(venPres - VENOUS_PRESSURE_OFFSET) * (VENOUS_PRESSURE_MAX_PSI - VENOUS_PRESSURE_MIN_PSI) / (F32)VENOUS_PRESSURE_SCALE ) + + VENOUS_PRESSURE_MIN_PSI; + // Convert venous pressure from PSI to mmHg if sensor status is normal if ( VENOUS_PRESSURE_NORMAL_OP == venPresStatus ) { venousPressure.data = venPresPSI * PSI_TO_MMHG; } // If venous pressure sensor status is not normal, fault +#ifndef _RELEASE_ + else if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, TRUE ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, (U32)venPresStatus ) + } + } else { -#ifndef DISABLE_PRESSURE_CHECKS -// SET_ALARM_WITH_1_U32_DATA( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT, (U32)venPresStatus ) // TODO - persistence? YES, need persistence - getting a stale data status. OR maybe speed up ADC in FPGA. -#endif + resetPersistentAlarmTimer( ALARM_ID_VENOUS_PRESSURE_SENSOR_FAULT ); } // Filter inline pressure readings @@ -412,31 +516,33 @@ *************************************************************************/ static void convertOcclusionPressures( void ) { - U08 bpReadCtr = getFPGABloodPumpOcclusionReadCounter(); - U08 bpErrorCtr = getFPGABloodPumpOcclusionErrorCounter(); + U08 bpReadCtr = getFPGABloodPumpOcclusionReadCounter(); + U08 bpErrorCtr = getFPGABloodPumpOcclusionErrorCounter(); -#ifndef DISABLE_PRESSURE_CHECKS - // Check for sensor errors - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, ( bpErrorCtr != lastBPErrorCtr ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, (U32)bpErrorCtr ) - } + // Check for sensor errors + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, ( bpErrorCtr != lastBPErrorCtr ) ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SENSOR_ERROR, (U32)bpErrorCtr ) + } - // Check for stale occlusion reads - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, ( bpReadCtr == lastBPOcclReadCtr ) ) ) - { - activateAlarmNoData( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR ); + // Check for stale occlusion reads + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR, ( bpReadCtr == lastBPOcclReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_OCCLUSION_READ_TIMEOUT_ERROR ); + } } -#endif // Record occlusion sensor readings bloodPumpOcclusion.data = (U32)getFPGABloodPumpOcclusion(); -#ifndef DISABLE_PRESSURE_CHECKS - // Record occlusion read and error counters for next time around - lastBPOcclReadCtr = bpReadCtr; - lastBPErrorCtr = bpErrorCtr; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + { + // Record occlusion read and error counters for next time around + lastBPOcclReadCtr = bpReadCtr; + lastBPErrorCtr = bpErrorCtr; + } } /*********************************************************************//** @@ -451,37 +557,45 @@ { F32 artPres = getFilteredArterialPressure(); -#ifndef DISABLE_ARTERIAL_PRESSURE_CHECK - // Check arterial pressure is in range - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, - ( artPres > ARTERIAL_PRESSURE_MAX_MMHG || artPres < ARTERIAL_PRESSURE_MIN_MMHG ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ARTERIAL_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, artPres ); - } - - // Check arterial pressure during treatment mode - if ( ( MODE_TREA == getCurrentOperationMode() ) && ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE ) ) - { - F32 artLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); - F32 artHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); - - // Check arterial pressure is within user set alarm limits - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres < artLowLimit ) ) + // Check arterial pressure is in range + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, + ( artPres > ARTERIAL_PRESSURE_MAX_MMHG || artPres < ARTERIAL_PRESSURE_MIN_MMHG ) ) ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres, artLowLimit ); + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_OUT_OF_RANGE, artPres ); } - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit ) ) + // Check arterial pressure during treatment mode + if ( ( MODE_TREA == getCurrentOperationMode() ) && ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE ) ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres, artHighLimit ); + F32 artLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); + F32 artHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); + + // If BP is ramping up, extend range to outer limits as pressure may not yet have reached expected range. + if ( isBloodPumpRampComplete() != TRUE ) + { + artLowLimit = (F32)getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT ); + artHighLimit = (F32)getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT ); + } + + // Check arterial pressure is within user set alarm limits + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres < artLowLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_LOW, artPres, artLowLimit ); + } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres > artHighLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_ARTERIAL_PRESSURE_HIGH, artPres, artHighLimit ); + } } + else + { // Reset persistence if alarm is out of scope + isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, FALSE ); + } } - else - { // Reset persistence if alarm is out of scope - isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_LOW, FALSE ); - isPersistentAlarmTriggered( ALARM_ID_ARTERIAL_PRESSURE_HIGH, FALSE ); - } -#endif } /*********************************************************************//** @@ -496,44 +610,52 @@ { F32 venPres = getFilteredVenousPressure(); -#ifndef DISABLE_VENOUS_PRESSURE_CHECK - // Check venous pressure is in range - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres > VENOUS_PRESSURE_MAX_MMHG ) || - TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres < VENOUS_PRESSURE_MIN_MMHG ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VENOUS_PRESSURE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); - } + // Check venous pressure is in range + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres > VENOUS_PRESSURE_MAX_MMHG ) || + TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres < VENOUS_PRESSURE_MIN_MMHG ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_OUT_OF_RANGE, venPres ); + } - // Check venous pressure during treatment mode - if ( ( MODE_TREA == getCurrentOperationMode() ) && ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE ) ) - { - F32 venLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); - F32 venHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); - - // Cannot monitor for low venous pressure while venting air trap - if ( getValveAirTrapStatus() != STATE_OPEN ) + // Check venous pressure during treatment mode + if ( ( MODE_TREA == getCurrentOperationMode() ) && ( getTreatmentState() <= TREATMENT_DIALYSIS_STATE ) ) { - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, venPres < venLowLimit ) ) + F32 venLowLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT ); + F32 venHighLimit = (F32)getTreatmentParameterS32( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); + + // If BP is ramping up, extend range to outer limits as pressure may not yet have reached expected range. + if ( isBloodPumpRampComplete() != TRUE ) { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_LOW, venPres, venLowLimit ); + venLowLimit = MIN_VENOUS_PRESSURE_FOR_RAMP_MMHG; + venHighLimit = (F32)getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT ); } + + // Cannot monitor for low venous pressure while venting air trap + if ( getValveAirTrapStatus() != STATE_OPEN ) + { + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, venPres < venLowLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_LOW, venPres, venLowLimit ); + } + } + else + { // clear persistence if air trap valve is open + isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, FALSE ); + } + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > venHighLimit ) ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres, venHighLimit ); + } } else - { // clear persistence if air trap valve is open + { // Reset persistence if alarm is out of scope isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, FALSE ); + isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, FALSE ); } - - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres > venHighLimit ) ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_VENOUS_PRESSURE_HIGH, venPres, venHighLimit ); - } } - else - { // Reset persistence if alarm is out of scope - isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_LOW, FALSE ); - isPersistentAlarmTriggered( ALARM_ID_VENOUS_PRESSURE_HIGH, FALSE ); - } -#endif } /*********************************************************************//** @@ -549,24 +671,25 @@ U32 bpOccl = getMeasuredBloodPumpOcclusion(); BOOL outOfRange = ( bpOccl < MIN_OCCLUSION_COUNTS || bpOccl > MAX_OCCLUSION_COUNTS ? TRUE : FALSE ); -#ifndef DISABLE_PRESSURE_CHECKS - // Range check occlusion sensor - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, outOfRange ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, bpOccl ); - } + // Range check occlusion sensor + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, outOfRange ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_OUT_OF_RANGE, bpOccl ); + } - // Check for occlusion - if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) - { - signalBloodPumpHardStop(); // Stop pump immediately - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) - } - else if ( bpOccl <= ( OCCLUSION_CLEAR_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) - { - clearAlarmCondition( ALARM_ID_OCCLUSION_BLOOD_PUMP ); + // Check for occlusion + if ( bpOccl > ( OCCLUSION_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) + { + signalBloodPumpHardStop(); // Stop pump immediately + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_OCCLUSION_BLOOD_PUMP, bpOccl ) + } + else if ( bpOccl <= ( OCCLUSION_CLEAR_THRESHOLD_OFFSET + bloodPumpOcclusionAfterCartridgeInstall ) ) + { + clearAlarmCondition( ALARM_ID_OCCLUSION_BLOOD_PUMP ); + } } -#endif } /*********************************************************************//** @@ -747,26 +870,27 @@ *************************************************************************/ void execPresOcclTest( void ) { -#ifndef DISABLE_PRESSURE_CHECKS - U32 const bpPressure = getMeasuredBloodPumpOcclusion(); - F32 const arterialPressure = getFilteredArterialPressure(); - F32 const venousPressure = getFilteredVenousPressure(); + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRESSURE_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) + { + U32 const bpPressure = getMeasuredBloodPumpOcclusion(); + F32 const arterialPressure = getFilteredArterialPressure(); + F32 const venousPressure = getFilteredVenousPressure(); - if ( bpPressure > CARTRIDGE_LOADED_THRESHOLD ) - { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SELF_TEST_FAILURE, bpPressure ); - } + if ( bpPressure > CARTRIDGE_LOADED_THRESHOLD ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BP_OCCLUSION_SELF_TEST_FAILURE, bpPressure ); + } - if ( ( arterialPressure <= ARTERIAL_PRESSURE_SELF_TEST_MIN ) || ( arterialPressure >= ARTERIAL_PRESSURE_SELF_TEST_MAX ) ) - { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE, arterialPressure ); - } + if ( ( arterialPressure <= ARTERIAL_PRESSURE_SELF_TEST_MIN ) || ( arterialPressure >= ARTERIAL_PRESSURE_SELF_TEST_MAX ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ARTERIAL_PRESSURE_SELF_TEST_FAILURE, arterialPressure ); + } - if ( ( venousPressure <= VENOUS_PRESSURE_SELF_TEST_MIN ) || ( venousPressure >= VENOUS_PRESSURE_SELF_TEST_MAX ) ) - { - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_SELF_TEST_FAILURE, venousPressure ); + if ( ( venousPressure <= VENOUS_PRESSURE_SELF_TEST_MIN ) || ( venousPressure >= VENOUS_PRESSURE_SELF_TEST_MAX ) ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_VENOUS_PRESSURE_SELF_TEST_FAILURE, venousPressure ); + } } -#endif } /*********************************************************************//** @@ -780,15 +904,51 @@ { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; -#ifndef DISABLE_OCCLUSION_SELF_TEST - U32 const bpPressure = getMeasuredBloodPumpOcclusion(); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_OCCLUSION_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + U32 const bpPressure = getMeasuredBloodPumpOcclusion(); - if ( ( bpPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( bpPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) + if ( ( bpPressure <= CARTRIDGE_LOADED_THRESHOLD ) || ( bpPressure >= OCCLUSION_CARTRIDGE_LOADED_PRESSURE_READING_MAX ) ) + { + activateAlarmNoData( ALARM_ID_NO_CARTRIDGE_LOADED ); + result = SELF_TEST_STATUS_FAILED; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execPresOcclSelfTest function executes the PresOccl self-test. + * @details Inputs: none + * @details Outputs: pressureSensorsCalRecord, occlusionSensorsCalRecord + * @return the result of the PresOccl self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execPresOcclSelfTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + BOOL calStatus = FALSE; + + // Get the pressure sensors and occlusion sensors calibration records + calStatus |= getNVRecord2Driver( GET_CAL_PRESSURE_SENSORS, (U08*)&pressureSensorsCalRecord, sizeof( HD_PRESSURE_SENSORS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PRESSURE_SESNSORS, ALARM_ID_NO_ALARM ); + + calStatus |= getNVRecord2Driver( GET_CAL_OCCLUSION_SESNSORS, (U08*)&occlusionSensorsCalRecord, sizeof( HD_OCCLUSION_SENSORS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_OCCLUSION_SENSORS, ALARM_ID_NO_ALARM ); + + presOcclPostState = PRESSURE_TEST_STATE_COMPLETE; + + if ( TRUE == calStatus ) { - activateAlarmNoData( ALARM_ID_NO_CARTRIDGE_LOADED ); + result = SELF_TEST_STATUS_PASSED; + } + else + { result = SELF_TEST_STATUS_FAILED; } -#endif return result; } Index: firmware/App/Controllers/PresOccl.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/PresOccl.h (.../PresOccl.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/PresOccl.h (.../PresOccl.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file PresOccl.h * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 15-Jan-2020 @@ -65,7 +65,8 @@ void execPresOccl( void ); void execPresOcclTest( void ); -SELF_TEST_STATUS_T execPresOcclDryTest( void ); +SELF_TEST_STATUS_T execPresOcclDryTest( void ); +SELF_TEST_STATUS_T execPresOcclSelfTest( void ); F32 getMeasuredArterialPressure( void ); F32 getFilteredArterialPressure( void ); Index: firmware/App/Controllers/Switches.c =================================================================== diff -u -rb53c3ab97a715ef9dc823a7148d0c0a52c413865 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Switches.c (.../Switches.c) (revision b53c3ab97a715ef9dc823a7148d0c0a52c413865) +++ firmware/App/Controllers/Switches.c (.../Switches.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Switches.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 25-Jul-2021 @@ -30,6 +30,7 @@ #define SWITCHES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the switches data is published on the CAN bus. #define SWITCHES_DEBOUNCE_TIME_MS ( MS_PER_SECOND / 4 ) ///< Switches FPGA status check interval. +#define DATA_PUBLISH_COUNTER_START_COUNT 4 ///< Data publish counter start count. /// Switch status structure typedef struct @@ -61,7 +62,7 @@ { U08 i; - switchesDataPublicationCounter = 0; + switchesDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; // Initialize all the switches for ( i = 0; i < NUM_OF_DOORS_AND_SWITCHES; i++ ) Index: firmware/App/Controllers/SyringePump.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SyringePump.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Sean Nash * @date (original) 04-Mar-2021 @@ -125,6 +125,8 @@ // Stepper motor toggle time for zero speed (stopped) #define SYRINGE_PUMP_MICROSTEP_TOGGLE_TIME_FOR_STOP 0xFFFFFFFF ///< Syringe pump microstep toggle time setting to indicate zero speed (stopped). +#define DATA_PUBLISH_COUNTER_START_COUNT 10 ///< Data publish counter start count. + /// Control bits to run syringe pump in reverse direction static const U08 SYRINGE_PUMP_CONTROL_RUN_REVERSE = SYRINGE_PUMP_CONTROL_SLEEP_OFF | SYRINGE_PUMP_CONTROL_NOT_RESET | @@ -198,10 +200,8 @@ static S32 syringePumpLastPositions[ SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN ]; ///< Last encoder positions for the syringe pump. static U32 syringePumpMotorSpeedCalcIdx; ///< Index into 1 second buffer of syringe pump encoder positions. static U32 syringePumpSpeedCalcTimerCounter; ///< Used to calculate measured rate from change in position over time. -#ifndef DISABLE_SYRINGE_PUMP_ALARMS static MOTOR_DIR_T syringePumpControllerMeasuredDirection; ///< Measured direction of syringe pump per controller. static MOTOR_DIR_T syringePumpEncoderMeasuredDirection; ///< Measured direction of syringe pump per encoder position relative to previous. -#endif static BOOL syringePumpRetractRequested; ///< Flag indicates a retract operation is requested. static BOOL syringePumpSeekRequested; ///< Flag indicates a plunger seek operation is requested. @@ -259,7 +259,6 @@ static BOOL checkVolumeVsSafetyVolume( BOOL stopPump, F32 pctMargin ); static BOOL checkForStall( BOOL stopPump ); static void publishSyringePumpData( void ); -static BOOL processCalibrationData( void ); /*********************************************************************//** * @brief @@ -281,12 +280,13 @@ syringePumpVolumeStartPosition = 0; syringePumpHomePositionOffset = 0; syringePumpLastPosition = 0; -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - syringePumpControllerMeasuredDirection = MOTOR_DIR_FORWARD; - syringePumpEncoderMeasuredDirection = MOTOR_DIR_FORWARD; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) + { + syringePumpControllerMeasuredDirection = MOTOR_DIR_FORWARD; + syringePumpEncoderMeasuredDirection = MOTOR_DIR_FORWARD; + } - syringePumpDataPublicationTimerCounter = 0; + syringePumpDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; syringePumpSpeedCalcTimerCounter = 0; syringePumpRampTimerCtr = 0; @@ -480,15 +480,16 @@ *************************************************************************/ BOOL retractSyringePump( void ) { -#ifndef ALWAYS_ALLOW_SYRINGE_PUMP_CMDS - if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( heparinDeliveryState != HEPARIN_STATE_OFF ) ) -#else - heparinDeliveryState = HEPARIN_STATE_STOPPED; - if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) ) -#endif + if ( ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) && ( heparinDeliveryState != HEPARIN_STATE_OFF ) ) || + ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_SYRINGE_PUMP_CMDS ) ) == SW_CONFIG_ENABLE_VALUE ) { - syringePumpSetRate = SYRINGE_PUMP_RETRACT_RATE; - syringePumpRetractRequested = TRUE; + heparinDeliveryState = HEPARIN_STATE_STOPPED; + if ( ( SYRINGE_PUMP_OFF_STATE == syringePumpState ) ) + { + syringePumpSetRate = SYRINGE_PUMP_RETRACT_RATE; + syringePumpRetractRequested = TRUE; + } + } return syringePumpRetractRequested; @@ -570,9 +571,10 @@ } else { -#ifndef DISABLE_SYRINGE_PUMP - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_BOLUS_CMD, tgtRate ) -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) != SW_CONFIG_ENABLE_VALUE ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_BOLUS_CMD, syringePumpSetRate ) + } } return syringePumpBolusRequested; @@ -600,9 +602,10 @@ } else { -#ifndef DISABLE_SYRINGE_PUMP - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_CONT_CMD, flowRate ) -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) != SW_CONFIG_ENABLE_VALUE ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_HD_SYRINGE_INVALID_CONT_CMD, flowRate ) + } } return syringePumpContinuousRequested; @@ -906,7 +909,8 @@ if ( TRUE == isNewCalibrationRecordAvailable() ) { // Get the new calibration data and check its validity - processCalibrationData(); + getNVRecord2Driver( GET_CAL_HEPARIN_FORCE_SENSOR, (U08*)&forceSensorCalRecord, sizeof( HD_HEPARIN_FORCE_SENSOR_CAL_RECORD_T ), + 0, ALARM_ID_HD_HEPARIN_FORCE_SENSOR_INVALID_CAL_RECORD ); } S32 encPosition = getFPGASyringePumpEncoderPosition(); @@ -941,12 +945,13 @@ calcSafetyVolumeDelivered(); // Calculate measured rate (mL/hr) calcMeasRate(); -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - // Get measured direction - syringePumpControllerMeasuredDirection = ( ( getSyringePumpEncoderStatus() & SYRINGE_PUMP_ENCODER_DIRECTION_BIT ) != 0 ? MOTOR_DIR_REVERSE : MOTOR_DIR_FORWARD ); - // Calculate direction from encoder position relative to last - syringePumpEncoderMeasuredDirection = ( getSyringePumpPosition() - syringePumpLastPosition >= 0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) + { + // Get measured direction + syringePumpControllerMeasuredDirection = ( ( getSyringePumpEncoderStatus() & SYRINGE_PUMP_ENCODER_DIRECTION_BIT ) != 0 ? MOTOR_DIR_REVERSE : MOTOR_DIR_FORWARD ); + // Calculate direction from encoder position relative to last + syringePumpEncoderMeasuredDirection = ( getSyringePumpPosition() - syringePumpLastPosition >= 0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + } // Check if syringe pump is on while BP is off { @@ -964,9 +969,10 @@ if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR, ( ( getCurrentOperationMode() > MODE_INIT ) && ( lastSyringePumpADCReadCtr == getSyringePumpADCReadCounter() ) ) ) ) { -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) + { + activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR ); + } } lastSyringePumpADCReadCtr = getSyringePumpADCReadCounter(); @@ -1055,7 +1061,8 @@ { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; - BOOL calStatus = processCalibrationData(); + BOOL calStatus = getNVRecord2Driver( GET_CAL_HEPARIN_FORCE_SENSOR, (U08*)&forceSensorCalRecord, sizeof( HD_HEPARIN_FORCE_SENSOR_CAL_RECORD_T ), + 0, ALARM_ID_HD_HEPARIN_FORCE_SENSOR_INVALID_CAL_RECORD ); if ( TRUE == calStatus ) { @@ -1106,14 +1113,13 @@ { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_OFF_STATE; -#ifndef DISABLE_SYRINGE_PUMP_ALARMS // Check position is not changing while stopped - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR, ( syringePumpLastPosition != getSyringePumpPosition() ) ) ) + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR, ( syringePumpLastPosition != getSyringePumpPosition() ) ) ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) ) { activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR ); activateSafetyShutdown(); } -#endif // Check for request flags if ( TRUE == syringePumpRetractRequested ) @@ -1271,9 +1277,10 @@ } else { -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM, syringeVol, txVolume ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM, syringeVol, txVolume ); + } } } @@ -1481,18 +1488,19 @@ { BOOL result = stopPump; -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, ( syringePumpEncoderMeasuredDirection != expDir ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) { - result = TRUE; - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, (U32)syringePumpEncoderMeasuredDirection, (U32)syringePumpState ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, ( syringePumpEncoderMeasuredDirection != expDir ) ) ) + { + result = TRUE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, (U32)syringePumpEncoderMeasuredDirection, (U32)syringePumpState ); + } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, ( syringePumpControllerMeasuredDirection != expDir ) ) ) + { + result = TRUE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, (U32)syringePumpControllerMeasuredDirection, (U32)syringePumpState ); + } } - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, ( syringePumpControllerMeasuredDirection != expDir ) ) ) - { - result = TRUE; - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, (U32)syringePumpControllerMeasuredDirection, (U32)syringePumpState ); - } -#endif return result; } @@ -1619,20 +1627,22 @@ static BOOL checkMeasRate( BOOL stopPump, F32 pctMargin ) { BOOL result = stopPump; -#ifndef DISABLE_SYRINGE_PUMP_ALARMS - F32 rate = getSyringePumpMeasRate(); - F32 max = MAX( rate, syringePumpSetRate ); - F32 min = MIN( rate, syringePumpSetRate ); - F32 error = ( max > 0.0 ? ( 1.0 - fabs( min / max ) ) : 0.0 ); - F32 delta = max - min; - // Alarm on rate if off by more than 5% or 0.1 mL/hr, whichever is greater - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR ) ) ) ) + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) { - result = TRUE; - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, syringePumpSetRate, rate ) + F32 rate = getSyringePumpMeasRate(); + F32 max = MAX( rate, syringePumpSetRate ); + F32 min = MIN( rate, syringePumpSetRate ); + F32 error = ( max > 0.0 ? ( 1.0 - fabs( min / max ) ) : 0.0 ); + F32 delta = max - min; + + // Alarm on rate if off by more than 5% or 0.1 mL/hr, whichever is greater + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR ) ) ) ) + { + result = TRUE; + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, syringePumpSetRate, rate ) + } } -#endif return result; } @@ -1810,7 +1820,7 @@ * The publishSyringePumpData function publishes syringe pump data at the * set interval. * @details Inputs: latest syringe pump data, syringePumpDataPublicationTimerCounter - * @details Outputs: Syringe pump data are published to CAN bus. + * @details Outputs: syringePumpDataPublicationTimerCounter * @return none *************************************************************************/ static void publishSyringePumpData( void ) @@ -1841,49 +1851,12 @@ } } -/*********************************************************************//** - * @brief - * The processCalibrationData function gets the calibration data and makes - * sure it is valid by checking the calibration date. The calibration date - * should not be 0. - * @details Inputs: none - * @details Outputs: forceSensorCalRecord - * @return TRUE if the calibration record is valid, otherwise FALSE - *************************************************************************/ -static BOOL processCalibrationData( void ) -{ - BOOL status = TRUE; + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ - // Get the calibration record from NVDataMgmt - HD_HEPARIN_FORCE_SENSOR_CAL_RECORD_T calData = getHDHeparinForceSensorCalibrationRecord(); - // Check if the calibration data that was received from NVDataMgmt is legitimate - // The calibration date item should not be zero. If the calibration date is 0, - // then the heparin force sensors data is not stored in the NV memory or it was corrupted. - if ( 0 == calData.hdHeparinForceSensor.calibrationTime ) - { -#ifndef SKIP_CAL_CHECK - activateAlarmNoData( ALARM_ID_HD_HEPARIN_FORCE_SENSOR_INVALID_CAL_RECORD ); - status = FALSE; -#endif - } - - // The calibration data was valid, update the local copy - forceSensorCalRecord.hdHeparinForceSensor.fourthOrderCoeff = calData.hdHeparinForceSensor.fourthOrderCoeff; - forceSensorCalRecord.hdHeparinForceSensor.thirdOrderCoeff = calData.hdHeparinForceSensor.thirdOrderCoeff; - forceSensorCalRecord.hdHeparinForceSensor.secondOrderCoeff = calData.hdHeparinForceSensor.secondOrderCoeff; - forceSensorCalRecord.hdHeparinForceSensor.gain = calData.hdHeparinForceSensor.gain; - forceSensorCalRecord.hdHeparinForceSensor.offset = calData.hdHeparinForceSensor.offset; - - return status; -} - - -/************************************************************************* - * TEST SUPPORT FUNCTIONS - *************************************************************************/ - - /*********************************************************************//** * @brief * The testSetSyringePumpDataPublishIntervalOverride function overrides the Index: firmware/App/Controllers/Temperatures.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Temperatures.c (.../Temperatures.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Temperatures.c (.../Temperatures.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Temperatures.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Dara Navaei * @date (original) 01-Aug-2021 @@ -19,6 +19,7 @@ #include "FPGA.h" #include "InternalADC.h" +#include "NVDataMgmt.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" #include "Temperatures.h" @@ -45,11 +46,12 @@ #define MIN_ALLOWED_TEMPERATURE 0.0 ///< Thermistors/sensors minimum allowed temperature reading. #define MAX_ALLOWED_TEMPERATURE 80.0 ///< Thermistors/sensors maximum allowed temperature reading. #define MAX_ALLOWED_TEMP_OUT_OF_RANGE_PERIOD ( 5 * MS_PER_SECOND ) ///< Thermistors/sensors maximum allowed temperature out of range period. +#define DATA_PUBLISH_COUNTER_START_COUNT 6 ///< Data publish counter start count. /// Temperatures exec states typedef enum thermistors_Exec_States { - TEMPERATURES_EXEC_STATE_START_STATE = 0, ///< Temperatures exec state start state. + TEMPERATURES_EXEC_STATE_WAIT_FOR_POST_STATE = 0, ///< Temperatures exec state wait for POST state. TEMPERATURES_EXEC_STATE_GET_ADC_VALUES_STATE, ///< Temperatures exec state get ADC values state. NUM_OF_TEMPERATURES_EXEC_STATES, ///< Number of temperatures exec state. } TEMPERATURES_EXEC_STATES_T; @@ -69,6 +71,8 @@ TEMPERATURES_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Temperatures publish time interval override. static U32 dataPublishCounter; ///< Temperatures data publish timer counter. static U32 adcReadCounter; ///< Temperatures ADC read counter. +static HD_TEMP_SENSORS_CAL_RECORD_T temperaturesCalRecord; ///< Temperatures calibration record. +static BOOL isPOSTComplete; ///< Temperatures POST complete flag. static const F32 THERMISTOR_VOLTAGE_CONV_COEFF = THERMISTOR_REFERENCE_VOLTAGE / (F32)TWELVE_BIT_RESOLUTION; ///< On board thermistor ADC to voltage conversion coefficient. @@ -77,31 +81,35 @@ static const F32 VENOUS_PRESS_SENSOR_TEMP_CONVERSION_COEFF = 200.0 / 2047.0; ///< Venous pressure sensor temperature conversion coefficient. static const F32 VENOUS_PRESS_SENSOR_TEMP_CONVERSION_CONSTANT = 50.0; ///< Venous pressure sensor temperature conversion constant. static const F32 ADC_BOARD_TEMP_SENSOR_CONVERSION_COEFF = 1.0 / 13584.0; ///< ADC board temperatures sensor conversion coefficient. +static const F32 ART_PRESS_SENSOR_TEMP_CONVERSION_COEFF = 200.0 / 2047.0; ///< Arterial pressure sensor temperature conversion coefficient. +static const F32 ART_PRESS_SENSOR_TEMP_CONVERSION_CONSTANT = 50.0; ///< Arterial pressure sensor temperature conversion constant. // ********** private function prototypes ********** -static TEMPERATURES_EXEC_STATES_T handleExecStart( void ); +static TEMPERATURES_EXEC_STATES_T handleExecWaitForPOST( void ); static TEMPERATURES_EXEC_STATES_T handleExecGetADCValues( void ); static void monitorTemperatures( void ); static void convertADC2Temperature( void ); -static F32 calculateThemristorTemperature( S32 adcValue ); +static F32 calculateThemristorTemperature( S32 adcValue ); static void publishTemperaturesData( void ); -static U32 getPublishTemperaturesDataInterval( void ); +static U32 getPublishTemperaturesDataInterval( void ); /*********************************************************************//** * @brief * The initTemperatures function initializes the temperatures module. * @details Inputs: none - * @details Outputs: temperaturesExecState, dataPublishCounter, temperaturesStatus + * @details Outputs: temperaturesExecState, dataPublishCounter, temperaturesStatus, + * isPOSTComplete * @return none *************************************************************************/ void initTemperatures( void ) { U08 i; - temperaturesExecState = TEMPERATURES_EXEC_STATE_START_STATE; - dataPublishCounter = 0; + temperaturesExecState = TEMPERATURES_EXEC_STATE_WAIT_FOR_POST_STATE; + dataPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; + isPOSTComplete = FALSE; for ( i = 0; i < NUM_OF_TEMPERATURES; i++ ) { @@ -122,13 +130,22 @@ *************************************************************************/ SELF_TEST_STATUS_T execTemperaturesSelfTest( void ) { - SELF_TEST_STATUS_T status = SELF_TEST_STATUS_IN_PROGRESS; + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; - // TODO implement the calibration processing function. - // It returns a pass for now - status = SELF_TEST_STATUS_PASSED; + BOOL calStatus = getNVRecord2Driver( GET_CAL_TEMPERATURE_SESNORS, (U08*)&temperaturesCalRecord, sizeof( HD_TEMP_SENSORS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_TEMP_SENSORS, ALARM_ID_NO_ALARM ); + isPOSTComplete = TRUE; - return status; + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; } /*********************************************************************//** @@ -140,11 +157,18 @@ *************************************************************************/ void execTemperatures( void ) { + // Check if a new calibration is available + if ( TRUE == isNewCalibrationRecordAvailable() ) + { + getNVRecord2Driver( GET_CAL_TEMPERATURE_SESNORS, (U08*)&temperaturesCalRecord, sizeof( HD_TEMP_SENSORS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_TEMP_SENSORS, ALARM_ID_NO_ALARM ); + } + // Read the sensors all the time switch ( temperaturesExecState ) { - case TEMPERATURES_EXEC_STATE_START_STATE: - temperaturesExecState = handleExecStart(); + case TEMPERATURES_EXEC_STATE_WAIT_FOR_POST_STATE: + temperaturesExecState = handleExecWaitForPOST(); break; case TEMPERATURES_EXEC_STATE_GET_ADC_VALUES_STATE: @@ -205,18 +229,18 @@ /*********************************************************************//** * @brief - * The handleExecStart function handles the start state of the exec state - * machine. + * The handleExecWaitForPOST function handles the wait for POST state of the + * exec state machine. * @details Inputs: adcReadCounter * @details Outputs: adcReadCounter * @return next state of the exec state machine *************************************************************************/ -static TEMPERATURES_EXEC_STATES_T handleExecStart( void ) +static TEMPERATURES_EXEC_STATES_T handleExecWaitForPOST( void ) { - TEMPERATURES_EXEC_STATES_T state = TEMPERATURES_EXEC_STATE_START_STATE; + TEMPERATURES_EXEC_STATES_T state = TEMPERATURES_EXEC_STATE_WAIT_FOR_POST_STATE; // Give a short time for FPGA to boot up and start sending the ADC reads - if ( ++adcReadCounter > ADC_FPGA_READ_DELAY_COUNT ) + if ( ( ++adcReadCounter > ADC_FPGA_READ_DELAY_COUNT ) && ( TRUE == isPOSTComplete ) ) { state = TEMPERATURES_EXEC_STATE_GET_ADC_VALUES_STATE; adcReadCounter = 0; @@ -247,6 +271,13 @@ temperaturesStatus[ TEMPSENSOR_VENOUS_PRESSURE_SENSOR ].rawADCRead = getFPGAVenousPressureTemperature(); temperaturesStatus[ TEMPSENSOR_PBA_ADC_SENSOR ].rawADCRead = getFPGAPBAADCTemperature(); +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) +#endif + { + temperaturesStatus[ TEMPSENSOR_ARTERIAL_PRESSURE_SENSOR ].rawADCRead = getFPGADVTArterialTemperature(); + } + // Zero the counter for the next round of reading adcReadCounter = 0; } @@ -265,19 +296,29 @@ static void monitorTemperatures( void ) { TEMPERATURES_T sensor; + BOOL isTempOutOfRange = FALSE; - F32 temperature = 0.0; - U32 lastFaultSensor = 0; - F32 faultSensorTemp = 0.0; + F32 temperature = 0.0; + U32 lastFaultSensor = 0; + F32 faultSensorTemp = 0.0; for ( sensor = THERMISTOR_ONBOARD_NTC; sensor < NUM_OF_TEMPERATURES; sensor++ ) { temperature = getTemperatureValue( sensor ); + if ( ( temperature > MAX_ALLOWED_TEMPERATURE ) || ( temperature < MIN_ALLOWED_TEMPERATURE ) ) { isTempOutOfRange = TRUE; - lastFaultSensor = sensor; - faultSensorTemp = temperature; + lastFaultSensor = sensor; + faultSensorTemp = temperature; + +#ifndef _RELEASE_ + if ( ( TEMPSENSOR_ARTERIAL_PRESSURE_SENSOR == sensor ) && + ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) != SW_CONFIG_ENABLE_VALUE ) ) + { + isTempOutOfRange = FALSE; + } +#endif } } @@ -325,11 +366,38 @@ break; case TEMPSENSOR_PBA_ADC_SENSOR: - // Temperature (C) = ((ADC - 0x800000) / 13584) - 272.5 - temperature = ( ( rawADC - ADC_BOARD_TEMP_SENSOR_CONVERSION_CONST_2 ) * ADC_BOARD_TEMP_SENSOR_CONVERSION_COEFF ) - - ADC_BOARD_TEMP_SENSOR_CONVERSION_CONST_1; + +#ifndef _RELEASE_ + // If the software configuration is not enabled to read the DVT arterial pressure, set the temperature to 30 to make sure + // there is no temperature error because the sensor is not available. The old arterial sensor did not have a temperature sensor + // inside it. NOTE: this line of code should be remove later. + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + // Temperature (C) = ((ADC - 0x800000) / 13584) - 272.5 + temperature = ( ( rawADC - ADC_BOARD_TEMP_SENSOR_CONVERSION_CONST_2 ) * ADC_BOARD_TEMP_SENSOR_CONVERSION_COEFF ) - + ADC_BOARD_TEMP_SENSOR_CONVERSION_CONST_1; + } + temperature = 30.0; // TODO PBA_ADC temperature sensor has been remove from all of the devices. Remove the feature in DEN-12224. break; + case TEMPSENSOR_ARTERIAL_PRESSURE_SENSOR: + +#ifndef _RELEASE_ + // TODO + // If the software configuration is not enable to read the DVT arterial pressure, set the temperature to 30 to make sure + // there is no temperature error because the sensor is not available. The old arterial sensor did not have a temperature sensor + // inside it. NOTE: this line of code should be remove later. + temperature = 30.0; + + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) ) +#endif + { + // Temperature (C) = ((ADC / 2047) * 200) - 50 + temperature = ( rawADC * ART_PRESS_SENSOR_TEMP_CONVERSION_COEFF ) - ART_PRESS_SENSOR_TEMP_CONVERSION_CONSTANT; + } + break; + default: // Wrong sensor was called, raise an alarm SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_TEMPERATURE_SENSOR_SELECTED, sensor ); @@ -338,7 +406,21 @@ break; } + // TODO remove this code and the if statement. This configuration is until the new arterial sensor is implemented everywhere so the temperature calibration + // structure can be updated permanently. This way the PBA sensor will be replaced with the new arterial sensor. This is to make sure the + // calibration structure does not fail in different devices with different sensors temperaturesStatus[ sensor ].temperatureValue.data = temperature; + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_DVT_ARTERIAL_PRESSURE_SENSOR ) != SW_CONFIG_ENABLE_VALUE ) + { + // Apply the calibration record the temperature values prior to updating the structures + temperaturesStatus[ sensor ].temperatureValue.data = + pow(temperature, 4) * temperaturesCalRecord.hdTemperatureSensors[ (CAL_DATA_HD_TEMEPERATURE_SENSORS_T)sensor ].fourthOrderCoeff + + pow(temperature, 3) * temperaturesCalRecord.hdTemperatureSensors[ (CAL_DATA_HD_TEMEPERATURE_SENSORS_T)sensor ].thirdOrderCoeff + + pow(temperature, 3) * temperaturesCalRecord.hdTemperatureSensors[ (CAL_DATA_HD_TEMEPERATURE_SENSORS_T)sensor ].secondOrderCoeff + + temperature * temperaturesCalRecord.hdTemperatureSensors[ (CAL_DATA_HD_TEMEPERATURE_SENSORS_T)sensor ].gain + + temperaturesCalRecord.hdTemperatureSensors[ (CAL_DATA_HD_TEMEPERATURE_SENSORS_T)sensor ].offset; + } + } } @@ -411,11 +493,12 @@ TEMPERATURES_DATA_T sensorsData; // Get all the sensors/thermistors temperature values for publication - sensorsData.onboardThermistor = getTemperatureValue( THERMISTOR_ONBOARD_NTC ); - sensorsData.powerSupply1Thermistor = getTemperatureValue( THERMISTOR_POWER_SUPPLY_1 ); - sensorsData.venousPressSensorTemp = getTemperatureValue( TEMPSENSOR_VENOUS_PRESSURE_SENSOR ); - sensorsData.fpgaBoardTempSensor = getTemperatureValue( TEMPSENSOR_FPGA_BOARD_SENSOR ); - sensorsData.pbaADCTempSensor = getTemperatureValue( TEMPSENSOR_PBA_ADC_SENSOR ); + sensorsData.onboardThermistor = getTemperatureValue( THERMISTOR_ONBOARD_NTC ); + sensorsData.powerSupply1Thermistor = getTemperatureValue( THERMISTOR_POWER_SUPPLY_1 ); + sensorsData.venousPressSensorTemp = getTemperatureValue( TEMPSENSOR_VENOUS_PRESSURE_SENSOR ); + sensorsData.fpgaBoardTempSensor = getTemperatureValue( TEMPSENSOR_FPGA_BOARD_SENSOR ); + sensorsData.pbaADCTempSensor = getTemperatureValue( TEMPSENSOR_PBA_ADC_SENSOR ); + sensorsData.arterialPressSensorTemp = getTemperatureValue( TEMPSENSOR_ARTERIAL_PRESSURE_SENSOR ); // Broadcast the temperatures data broadcastData( MSG_ID_HD_TEMPERATURES_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&sensorsData, sizeof( TEMPERATURES_DATA_T ) ); Index: firmware/App/Controllers/Temperatures.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Temperatures.h (.../Temperatures.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Temperatures.h (.../Temperatures.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file Temperatures.h * * @author (last) Dara Navaei -* @date (last) 13-Aug-2021 +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 01-Aug-2021 @@ -41,6 +41,7 @@ TEMPSENSOR_FPGA_BOARD_SENSOR, ///< FPGA board temperature sensor TEMPSENSOR_VENOUS_PRESSURE_SENSOR, ///< Venous pressure sensor temperature TEMPSENSOR_PBA_ADC_SENSOR, ///< PBA ADC temperature sensor + TEMPSENSOR_ARTERIAL_PRESSURE_SENSOR, ///< Arterial pressure sensor temperature NUM_OF_TEMPERATURES, ///< Number of temperatures } TEMPERATURES_T; @@ -52,6 +53,7 @@ F32 fpgaBoardTempSensor; ///< FPGA board temperature sensor F32 venousPressSensorTemp; ///< Venous pressure sensor temperature F32 pbaADCTempSensor; ///< PBA ADC temperature sensor + F32 arterialPressSensorTemp; ///< Arterial pressure sensor temperature } TEMPERATURES_DATA_T; // ********** public function prototypes ********** Index: firmware/App/Controllers/Valves.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Valves.c (.../Valves.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Valves.c (.../Valves.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Valves.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 07-Aug-2020 @@ -21,6 +21,7 @@ #include "FPGA.h" #include "MessageSupport.h" +#include "NVDataMgmt.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskPriority.h" @@ -106,6 +107,8 @@ #define VALVE_CCW_PWM_TO_CNT_CONVERSION( pwm ) ( ( -20 * pwm ) + 2500 ) ///< Valve counter clockwise PWM to count conversion #define VALVE_CCW_CNT_TO_PWM_CONVERSION( cnt ) ( ( -0.05 * cnt ) + 125 ) ///< Valve counter clockwise count to PWM conversion +#define DATA_PUBLISH_COUNTER_START_COUNT 80 ///< Data publish counter start count. + /// Exec valve self test states typedef enum valves_Self_Test_States { @@ -213,18 +216,15 @@ static const U16 VALVE_CONTROL_MODES_RESET_BITS[ NUM_OF_VALVES ] = { VDI_RESET_CONTROL_BIT_MASK, VDO_RESET_CONTROL_BIT_MASK, VBA_RESET_CONTROL_BIT_MASK, VBV_RESET_CONTROL_BIT_MASK }; ///< Valves control modes rest bits -#ifndef DISABLE_3WAY_VALVES -#ifndef DISABLE_VALVE_ALARMS static const U16 VALVE_CONTROL_STATUS_BITS[ NUM_OF_VALVES ][ NUM_OF_VALVE_CONTROL_STATUS ] = { { VDI_INIT_STATUS_BIT_MASK, VDI_ENABLE_PID_STATUS_BIT_MASK, VDI_ENABLE_BYPASS_STATUS_BIT_MASK, VDI_RESET_CONTROL_BIT_MASK }, { VDO_INIT_STATUS_BIT_MASK, VDO_ENABLE_PID_STATUS_BIT_MASK, VDO_ENABLE_BYPASS_STATUS_BIT_MASK, VDO_RESET_CONTROL_BIT_MASK }, { VBA_INIT_STATUS_BIT_MASK, VBA_ENABLE_PID_STATUS_BIT_MASK, VBA_ENABLE_BYPASS_STATUS_BIT_MASK, VBA_RESET_CONTROL_BIT_MASK }, { VBV_INIT_STATUS_BIT_MASK, VBV_ENABLE_PID_STATUS_BIT_MASK, VBV_ENABLE_BYPASS_STATUS_BIT_MASK, VBV_RESET_CONTROL_BIT_MASK } }; ///< Valves control status bits -#endif -#endif static U16 valvesControlSetBits = 0x0000; ///< Valves control set bit static OPN_CLS_STATE_T valveAirTrapStatus; ///< Air trap valve status (open/close) +static HD_VALVES_CAL_RECORD_T valvesCalibrationRecord; ///< Valves calibration record. // Self test function prototypes static VALVE_SELF_TEST_STATE_T handleValveSelfTestEnableValves( void ); @@ -280,11 +280,12 @@ // Initialize some of the variables for ( valve = VDI; valve < NUM_OF_VALVES; valve++ ) { - valvesStatus[ valve ].execState = VALVE_STATE_WAIT_FOR_POST; - valvesStatus[ valve ].current.data = 0.0; - valvesStatus[ valve ].current.ovData = 0.0; + valvesStatus[ valve ].execState = VALVE_STATE_WAIT_FOR_POST; + valvesStatus[ valve ].current.data = 0.0; + valvesStatus[ valve ].current.ovData = 0.0; valvesStatus[ valve ].current.ovInitData = 0.0; - valvesStatus[ valve ].current.override = 0; + valvesStatus[ valve ].current.override = 0; + valvesStatus[ valve ].dataPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; } // Close air trap valve @@ -567,7 +568,10 @@ { VALVE_SELF_TEST_STATE_T state = VALVE_SELF_TEST_COMPLETE; - if ( TRUE == areValvesFunctional() ) + BOOL calStatus = getNVRecord2Driver( GET_CAL_VALVES, (U08*)&valvesCalibrationRecord, sizeof( HD_VALVES_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_VALVES, ALARM_ID_NO_ALARM ); + + if ( ( TRUE == areValvesFunctional() ) && ( TRUE == calStatus ) ) { valvesSelfTestResult = SELF_TEST_STATUS_PASSED; } @@ -734,9 +738,7 @@ valvesStatus[ valve ].hasValveBeenHomed = FALSE; valvesStatus[ valve ].hasHomingFailed = TRUE; state = VALVE_STATE_HOMING_NOT_STARTED; -#ifndef DISABLE_VALVE_ALARMS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_VALVE_HOMING_FAILED, (U32)valve ); -#endif } else { @@ -773,16 +775,6 @@ { VALVE_STATE_T state = VALVE_STATE_IDLE; -#ifdef TST_3WAY_VALVES_ALWAYS_OPEN - static BOOL valvesOpenedForSarina[NUM_OF_VALVES] = { FALSE, FALSE, FALSE, FALSE }; - - if ( FALSE == valvesOpenedForSarina[ valve ] ) - { - valvesOpenedForSarina[ valve ] = TRUE; - setValvePosition( valve, VALVE_POSITION_B_OPEN ); - } -#endif - if ( TRUE == valvesStatus[ valve ].hasHomingBeenRequested ) { state = VALVE_STATE_HOMING_NOT_STARTED; @@ -861,9 +853,8 @@ //valvesStatus[ valve ].hasTransitionBeenRequested = FALSE; TODO remove // Go back to Idle state state = VALVE_STATE_IDLE; -#ifndef DISABLE_VALVE_ALARMS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_VALVE_TRANSITION_TIMEOUT, (U32)valve ); -#endif + // If the valve transition timeout is active and the valve's commanded positions is position C, activate safety shutdown if ( ( TRUE == isAlarmActive( ALARM_ID_HD_VALVE_TRANSITION_TIMEOUT ) ) && ( VALVE_POSITION_C_CLOSE == valvesStatus[ valve ].commandedPosition ) ) { @@ -949,15 +940,12 @@ *************************************************************************/ static void execMonitorValves( void ) { -#ifndef DISABLE_3WAY_VALVES // Check if the valves are still enabled areValvesFunctional(); -#endif // Get the current position of the valves in counts and store them getAndMonitorValvesCurrentFPGAPosition(); -#ifndef DISABLE_3WAY_VALVES // Get the current in ADC and convert them to amps // Check whether any of the valves are over current convertAndMonitorValvesCurrent(); @@ -967,7 +955,6 @@ #ifdef DEBUG_ENABLED getValvesCurrentPWM(); #endif -#endif } /*********************************************************************//** @@ -982,8 +969,6 @@ static BOOL areValvesFunctional( void ) { BOOL result = TRUE; -#ifndef DISABLE_3WAY_VALVES -#ifndef DISABLE_VALVE_ALARMS VALVE_T valve; VALVE_MODE_T mode; @@ -1031,8 +1016,6 @@ result = FALSE; } } -#endif -#endif return result; } @@ -1122,9 +1105,7 @@ // Check if the current is over the threshold for the defined amount of time if ( valvesStatus[ valve ].overCurrentCounter > MAX_OVER_CURRENT_TIME_INTERVAL_COUNTER ) { -#ifndef DISABLE_VALVE_ALARMS SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VALVE_CURRENT_OUT_OF_RANGE, (F32)valve, current ); -#endif } // If the current is below the threshold again and the counter for the time is greater than else if ( ( current < VALVES_CURRENT_THRESHOLD_AMPS ) && ( valvesStatus[ valve ].overCurrentCounter > 0 ) ) @@ -1158,7 +1139,6 @@ valvesStatus[ VBA ].currentPositionInCounts.data = (S32)getFPGAValveBloodArterialPosition(); valvesStatus[ VBV ].currentPositionInCounts.data = (S32)getFPGAValveBloodVenousPosition(); -#ifndef DISABLE_3WAY_VALVES // Check the position of each valve for ( valve = VDI; valve < NUM_OF_VALVES; valve++ ) { @@ -1187,9 +1167,7 @@ if ( valvesStatus[ valve ].positionOutOfRangeCounter > MAX_POS_DEVIATION_TIME_INTERVAL_COUNTER ) { -#ifndef DISABLE_VALVE_ALARMS SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_VALVE_POSITION_OUT_OF_RANGE, (U32)valve, currentPosition ); -#endif } else if ( abs( currentPosition - commandedPosition ) < MAX_DEVIATION_FROM_TARGET_IN_COUNTS && valvesStatus[ valve ].positionOutOfRangeCounter > 0 ) @@ -1198,7 +1176,6 @@ } } } -#endif } /*********************************************************************//** Index: firmware/App/Controllers/Voltages.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Controllers/Voltages.c (.../Voltages.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Controllers/Voltages.c (.../Voltages.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Voltages.c * -* @author (last) Sean Nash -* @date (last) 15-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean Nash * @date (original) 15-Apr-2021 @@ -31,7 +31,8 @@ // ********** private definitions ********** #define VOLTAGES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the voltages data is published on the CAN bus. -#define VOLTAGES_ALARM_PERSISTENCE ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Alarm persistence period for voltage monitor alarms. +#define VOLTAGES_ALARM_PERSISTENCE ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Alarm persistence period for voltage monitor alarms. +#define DATA_PUBLISH_COUNTER_START_COUNT 14 ///< Data publish counter start count. /// Defined states for the voltage monitor state machine. typedef enum Voltages_States @@ -75,7 +76,7 @@ // ********** private data ********** static VOLTAGES_STATE_T voltagesState; ///< Current state of voltages monitor state machine. -static U32 voltagesDataPublicationTimerCounter = 14; ///< Used to schedule voltages monitor data publication to CAN bus. +static U32 voltagesDataPublicationTimerCounter; ///< Used to schedule voltages monitor data publication to CAN bus. /// Interval (in ms) at which to publish voltages monitor data to CAN bus. static OVERRIDE_U32_T voltagesDataPublishInterval = { VOLTAGES_DATA_PUB_INTERVAL, VOLTAGES_DATA_PUB_INTERVAL, 0, 0 }; @@ -102,6 +103,7 @@ U32 i; voltagesState = VOLTAGES_INIT_STATE; + voltagesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; for ( i = 0; i < (U32)NUM_OF_MONITORED_LINES; i++ ) { @@ -210,18 +212,24 @@ { if ( ++voltageAlarmPersistenceCtr[ i ] >= VOLTAGES_ALARM_PERSISTENCE ) { -#ifndef DISABLE_VOLTAGE_MONITOR - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VOLTAGES_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) + } } } else if ( volts < MIN_VOLTAGES[ i ] ) { if ( ++voltageAlarmPersistenceCtr[ i ] >= VOLTAGES_ALARM_PERSISTENCE ) { -#ifndef DISABLE_VOLTAGE_MONITOR - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_VOLTAGES_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_VOLTAGE_OUT_OF_RANGE, (F32)i, volts ) + } } } else Index: firmware/App/HDCommon.h =================================================================== diff -u -rde1b9192ea2d2190b27c012182abc2c986faddcc -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/HDCommon.h (.../HDCommon.h) (revision de1b9192ea2d2190b27c012182abc2c986faddcc) +++ firmware/App/HDCommon.h (.../HDCommon.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file HDCommon.h * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 27-Feb-2020 @@ -25,75 +25,29 @@ #define HD_VERSION_MAJOR 0 #define HD_VERSION_MINOR 6 #define HD_VERSION_MICRO 0 -#define HD_VERSION_BUILD 33 +#define HD_VERSION_BUILD 35 // ********** development build switches ********** // TODO - remove build switches before release #ifndef _RELEASE_ #ifndef _VECTORCAST_ +// Build switches. NOTE: These build switches will remain as #define // #define USING_DEBUGGER 1 // Want to be able to use the debugger and have break points // #define BOARD_WITH_NO_HARDWARE 1 // Target is a PCB w/ no hardware // #define RUN_WITHOUT_DG 1 // Run HD w/o DG // #define SIMULATE_UI 1 // Build w/o requirement that UI be there // #define TASK_TIMING_OUTPUT_ENABLED 1 // Re-purposes alarm lamp pins for task timing - #define DISABLE_ALARM_AUDIO 1 // Disable alarm audio -// #define SKIP_POST 1 // Skip POST tests - all pass -// #define DONT_SKIP_NV_POST 1 // Do not skip NV Data POST - #define DISABLE_AIR_TRAP_LEVELING_ALARM 1 // Disable air trap level control alarms -// #define DISABLE_3WAY_VALVES 1 // Disable 3-way valves -// #define TST_3WAY_VALVES_ALWAYS_OPEN 1 // After POST and homing, open all 4 valves -// #define DISABLE_ACCELS 1 // Disable accelerometer POST and monitoring -// #define DISABLE_CRC_ERROR 1 // Do not error on bad CRC for CAN messages - #define DISABLE_ACK_ERRORS 1 // Do not error on failure of other node(s) to ACK a message -// #define RUN_BP_OPEN_LOOP 1 // Run blood pump in open loop mode -// #define RUN_DPI_OPEN_LOOP 1 // Run dialysate inlet pump in open loop mode - #define WORN_OUT_CARTRIDGE 1 // Running with an old worn out cartridge (max wear) -// #define PBA_ESTIMATION 1 // Estimate arterial pressure rather than look at PBA sensor - #define DISABLE_MOTOR_CURRENT_CHECKS 1 // Do not error on HD pump current checks - #define DISABLE_PUMP_FLOW_CHECKS 1 // Do not error on HD pump flow checks - #define DISABLE_PUMP_SPEED_CHECKS 1 // Do not error on HD pump speed checks - #define DISABLE_PUMP_DIRECTION_CHECKS 1 // Do not error on HD pump direction checks - #define DISABLE_SYRINGE_PUMP 1 // Disable syringe pump functionality - #define ALWAYS_ALLOW_SYRINGE_PUMP_CMDS 1 // Allow syringe pump commands at any time except when pump is busy - #define DISABLE_PRESSURE_CHECKS 1 // Do not error on HD pressure checks - #define DISABLE_ARTERIAL_PRESSURE_CHECK 1 // Do not error on arterial pressure out of range - #define DISABLE_VENOUS_PRESSURE_CHECK 1 // Do not error on venous pressure out of range - -// #define DISABLE_UF_ALARMS 1 // Do not error on HD ultrafiltration checks - #define DISABLE_DIALYSATE_TEMP_CHECK 1 // Disable dialysate temperature check -// #define DISABLE_VALVE_ALARMS 1 // Do not error on HD valve position - #define SKIP_CAL_CHECK 1 -// #define RUN_PUMPS_OPEN_LOOP 1 // BP and DPi pumps will be run open loop (no flow sensor feedback) + #define DISABLE_BATT_COMM 1 // Disable battery communication // #define READ_FPGA_ASYNC_DATA 1 // Test build reads non-priority register page every other time -// #define EMC_TEST_BUILD 1 // EMC test build - HD/DG run separately but connected, HD pumps toggle on/off w/ stop button - #define ALARMS_DEBUG 1 // Triggered alarms sent to debug UART - #define ALARM_VOLUME_DEFAULT_LOW 1 // Set default alarm volume to lowest - #define DISABLE_BATT_COMM 1 // Disable battery communication. - #define SKIP_AIR_BUBBLE_CHECK 1 // Skip air bubble detector self-test. - #define DISABLE_OCCLUSION_SELF_TEST 1 // Skip occlusion sensor self-test. -// #define SKIP_CARTRIDGE_REMOVAL 1 // Skip cartridge removal check // #define DISABLE_FPGA_COUNTER_CHECKS 1 // Disable alarms associated with FPGA read/error counters - #define DISABLE_VOLTAGE_MONITOR 1 // Disable voltage monitoring/alarms - #define ALLOW_1_MIN_TREATMENT_DURATION 1 // Allow user to change treatment duration to as low as 1 minute - #define DISABLE_SYRINGE_PUMP_ALARMS 1 // Disable some syringe pump alarms that are triggering intermittently -// #define NO_PUMP_FLOW_LIMITS 1 // Allow any commanded flow rate for peristaltic pumps -// #define DISABLE_BUBBLE_ALARMS 1 // Disable bubble alarms - #define DISABLE_UI_POST_TEST 1 // Disable the UI POST -// #define DISABLE_UI_COMM_TO_ALARM 1 // Disable UI comm timeouts - #define DISABLE_WD_AND_SFTY_POST_TESTS 1 // Disable watchdog and safety shutdown POST tests - #define DISABLE_ILLEGAL_AIR_TRAP_ALARM 1 // Disable illegal state for air trap alarm - #define SKIP_RESERVOIR_ALARMS 1 // Skip reservoir management alarms - #define IGNORE_BLOOD_LEAK_SELF_TEST 1 // Ignore blood leak self test - #define IGNORE_BLOOD_LEAK_ALARM 1 // Ignore blood leak alarm +// #define EMC_TEST_BUILD 1 // EMC test build - HD/DG run separately but connected, HD pumps toggle on/off w/ stop button + #define DISABLE_WD_AND_SFTY_POST_TESTS 1 // Disable watchdog and safety shutdown POST tests + #define DISABLE_UI_POST_TEST 1 // Disable the UI POST +// #define PBA_ESTIMATION 1 // Estimate arterial pressure rather than look at PBA sensor // Part of DVT build switch - // Skip Pre-Treatment and get to treatment as soon as possible -// #define SKIP_UI_INTERACTION 1 // Skip UI interaction. - #define SKIP_SAMPLE_WATER 1 // Skip pre-treatment sample water - #define SKIP_CONSUMABLE_TESTS 1 // Skip pre-treatment consumable Self-tests - #define SKIP_DRY_SELF_TESTS 1 // Skip pre-treatment dry self-tests -// #define SKIP_PRIMING 1 // Skip Pre-treatment Prime -// #define SKIP_WET_SELF_TESTS 1 // Skip Pre-treatment prime wet self-tests + // TODO stays as a build switch until the calibration structure is updated with the build + #define SKIP_CAL_CHECK 1 // Implement software configuration #include #include Index: firmware/App/Modes/BloodPrime.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file BloodPrime.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 03-Mar-2022 * * @author (original) Sean Nash * @date (original) 06-Feb-2021 @@ -36,7 +36,7 @@ // ********** private definitiions *********** -#define TARGET_BLOOD_PRIME_VOLUME_ML 300.0 ///< Target blood prime volume to prime the blood side circuit (in mL). +#define TUBING_BLOOD_PRIME_VOLUME_ML 80.0 ///< Target blood prime volume to prime the blood side circuit (in mL). #define MAX_BLOOD_PRIME_VOLUME_ERROR_ML 60.0 ///< Maximum error in total additional blood prime volume (20% of total). #define MIN_RAMP_TIME_SEC 60 ///< Minimum ramp time for blood prime (in seconds). @@ -58,6 +58,7 @@ static F32 bloodPrimeRampFlowRate_mL_min; ///< Current blood pump ramp flow rate. static F32 bloodPrimeRampStep_mL; ///< Blood pump volume step size for ramping. +static F32 bloodPrimeTargetVolume_mL; ///< Calculated target blood prime volume (based on selected dialyzer and fixed tubing volume). static U32 bloodPrimeRampControlTimerCtr; ///< Timer counter for determining interval for controlling BP ramp. static U32 bloodPrimePublishTimerCtr; ///< Timer counter for determining interval for blood prime status to be published. @@ -92,8 +93,10 @@ bloodPrimePublishTimerCtr = BLOOD_PRIME_DATA_PUBLISH_INTERVAL; cumulativeBloodPrimeVolume_mL.data = 0.0; expectedBloodPrimeVolume_mL = 0.0; + bloodPrimeTargetVolume_mL = 300.0; resetBloodPrimeFlags(); + bloodPrimeTargetVolume_mL = (F32)TUBING_BLOOD_PRIME_VOLUME_ML + (F32)getDialyzerBloodVolume(); bloodPrimeRampFlowRate_mL_min = (F32)BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN; // Calculate BP ramp step size if ( setBPRate <= BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN ) @@ -103,7 +106,7 @@ else { F32 rampRateSpan = (F32)( setBPRate - BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN ); - F32 estRampSeconds = ( ( TARGET_BLOOD_PRIME_VOLUME_ML / (F32)setBPRate + TARGET_BLOOD_PRIME_VOLUME_ML / (F32)BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN ) / 2.0 ) * (F32)SEC_PER_MIN; + F32 estRampSeconds = ( ( bloodPrimeTargetVolume_mL / (F32)setBPRate + bloodPrimeTargetVolume_mL / (F32)BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN ) / 2.0 ) * (F32)SEC_PER_MIN; if ( estRampSeconds < (F32)MIN_RAMP_TIME_SEC ) { @@ -225,21 +228,20 @@ expectedBloodPrimeVolume_mL += ( (F32)getTargetBloodFlowRate() * BLOOD_PRIME_FLOW_INTEGRATOR ); // Has blood prime completed? - if ( getBloodPrimeVolume() >= TARGET_BLOOD_PRIME_VOLUME_ML ) + if ( getBloodPrimeVolume() >= bloodPrimeTargetVolume_mL ) { initBloodPrime(); // Reset blood prime so that we start anew next time we transition to this sub-mode setBloodIsPrimed( TRUE ); // Signal treatment mode that blood prime is completed signalDialInPumpHardStop(); // Stop dialysate recirculation - dialysis sub-mode will restart dialysate pumps signalBloodPrimeToDialysis(); // Signal treatment mode that it's time to start dialysis cmdStopDGTrimmerHeater(); // Stop trimmer heater - dialysis sub-mode will restart as appropriate } -#ifndef DISABLE_PUMP_FLOW_CHECKS // Is blood prime taking too long based on set BP rate? - else if ( fabs( expectedBloodPrimeVolume_mL - getBloodPrimeVolume() ) > MAX_BLOOD_PRIME_VOLUME_ERROR_ML ) + else if ( ( fabs( expectedBloodPrimeVolume_mL - getBloodPrimeVolume() ) > MAX_BLOOD_PRIME_VOLUME_ERROR_ML ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { activateAlarmNoData( ALARM_ID_BLOOD_PRIME_VOLUME_CHECK_FAILURE ); } -#endif else { // ramp blood pump on ramp interval @@ -287,7 +289,7 @@ BLOOD_PRIME_DATA_PAYLOAD_T data; bloodPrimePublishTimerCtr = 0; - data.targetBloodPrimeVolumeMl = TARGET_BLOOD_PRIME_VOLUME_ML; + data.targetBloodPrimeVolumeMl = bloodPrimeTargetVolume_mL; data.deliveredBloodPrimeVolumeMl = getBloodPrimeVolume(); data.unused = 0.0; // TODO - remove later when UI no longer looking for this field. broadcastData( MSG_ID_HD_BLOOD_PRIME_PROGRESS, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_PRIME_DATA_PAYLOAD_T ) ); Index: firmware/App/Modes/ConsumableSelfTest.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ConsumableSelfTest.c (.../ConsumableSelfTest.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/ConsumableSelfTest.c (.../ConsumableSelfTest.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file ConsumableSelfTest.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 25-Feb-2022 * * @author (original) Quang Nguyen * @date (original) 06-Mar-2021 @@ -18,6 +18,7 @@ #include "ConsumableSelfTest.h" #include "DGInterface.h" #include "ModePreTreat.h" +#include "NVDataMgmt.h" #include "Reservoirs.h" /** @@ -75,18 +76,23 @@ switch( currentConsumableSelfTestState ) { case CONSUMABLE_SELF_TESTS_INSTALL_STATE: -#ifdef SKIP_UI_INTERACTION - consumableInstallConfirmed = TRUE; -#endif + + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + consumableInstallConfirmed = TRUE; + } // TODO: Check for DG straw door status to be open once DG door driver implemented if ( TRUE == consumableInstallConfirmed ) { consumableInstallConfirmed = FALSE; -#ifndef SKIP_CONSUMABLE_TESTS - currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_FILL_CMD_STATE; -#else - currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_COMPLETE_STATE; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CONSUMABLES_TESTS ) != SW_CONFIG_ENABLE_VALUE ) + { + currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_FILL_CMD_STATE; + } + else + { + currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_COMPLETE_STATE; + } } break; @@ -99,21 +105,21 @@ break; case CONSUMABLE_SELF_TESTS_WATER_QUALITY_CHECK_STATE: - if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_BICARB_PUMP_CHECK ) ) + if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_CHECK_INLET_WATER ) ) { currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_BICARB_PUMP_CHECK_STATE; } break; case CONSUMABLE_SELF_TESTS_BICARB_PUMP_CHECK_STATE: - if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_ACID_PUMP_CHECK ) ) + if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_BICARB_PUMP_CHECK ) ) { currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_ACID_PUMP_CHECK_STATE; } break; case CONSUMABLE_SELF_TESTS_ACID_PUMP_CHECK_STATE: - if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION ) ) + if ( ( DG_MODE_FILL == getDGOpMode() ) && ( getDGSubMode() >= DG_FILL_MODE_STATE_ACID_PUMP_CHECK ) ) { currentConsumableSelfTestState = CONSUMABLE_SELF_TESTS_COMPLETE_STATE; cmdStopDGFill(); Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Dialysis.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean * @date (original) 15-Jan-2020 @@ -47,7 +47,7 @@ static const U32 UF_ACCURACY_CHECK_INTERVAL = ((1 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); #define MAX_SALINE_VOLUME_DELIVERED 800 ///< Maximum saline volume delivered for a treatment. -#define SALINE_BOLUS_RATE_ML_MIN 150 ///< Fixed rate for saline bolus delivery. +#define SALINE_BOLUS_RATE_ML_MIN 300 ///< Fixed rate for saline bolus delivery. #define MAX_BOLUS_ERROR_PCT 0.2 ///< Maximum error in saline bolus volume delivered (as a percentage of target). #define MAX_ACTIVE_LOAD_CELL_CHANGE_G 50.0 ///< Maximum delta between new and previous measured UF volume. @@ -184,6 +184,8 @@ *************************************************************************/ void transitionToDialysis( void ) { + PUMP_CONTROL_MODE_T mode = PUMP_CONTROL_MODE_CLOSED_LOOP; + // Set last UF timestamp so UF ref is resumed from this time lastUFTimeStamp = getMSTimerCount(); // Send dialysate outlet pump latest UF volumes @@ -200,21 +202,25 @@ setValvePosition( VBA, VALVE_POSITION_B_OPEN ); setValvePosition( VBV, VALVE_POSITION_B_OPEN ); // Restart pumps -#ifndef RUN_PUMPS_OPEN_LOOP -#ifndef RUN_BP_OPEN_LOOP - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#else - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_BLOOD_PUMP_OPEN_LOOP ) ) + { + mode = PUMP_CONTROL_MODE_OPEN_LOOP; + } #endif -#ifndef RUN_DPI_OPEN_LOOP - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#else - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, mode ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DIALYSATE_INLET_PUMP_OPEN_LOOP ) ) + { + mode = PUMP_CONTROL_MODE_OPEN_LOOP; + } #endif -#else - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); -#endif + + setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, mode ); + setDialOutPumpTargetRate( setDialysateFlowRate + (S32)setUFRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); // Start Heparin pump as appropriate startHeparinPump(); @@ -286,21 +292,24 @@ // Make rate changes in real time if currently performing dialysis. if ( ( TREATMENT_DIALYSIS_STATE == getTreatmentState() ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) { -#ifndef RUN_PUMPS_OPEN_LOOP -#ifndef RUN_BP_OPEN_LOOP - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#else - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + PUMP_CONTROL_MODE_T mode = PUMP_CONTROL_MODE_CLOSED_LOOP; + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_BLOOD_PUMP_OPEN_LOOP ) ) + { + mode = PUMP_CONTROL_MODE_OPEN_LOOP; + } #endif -#ifndef RUN_DPI_OPEN_LOOP - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#else - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, mode ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_DIALYSATE_INLET_PUMP_OPEN_LOOP ) ) + { + mode = PUMP_CONTROL_MODE_OPEN_LOOP; + } #endif -#else - setBloodPumpTargetFlowRate( setBloodFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); - setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); -#endif + setDialInPumpTargetFlowRate( setDialysateFlowRate, MOTOR_DIR_FORWARD, mode ); + setDialOutPumpTargetRate( setDialysateFlowRate + (S32)setUFRate, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_CLOSED_LOOP ); } } @@ -942,15 +951,14 @@ salineBolusAbortRequested = FALSE; result = SALINE_BOLUS_STATE_IDLE; } -#ifndef DISABLE_PUMP_FLOW_CHECKS // Determine if saline bolus is under/over delivering - else if ( fabs( expectedSalineBolusVolume_mL - bolusSalineVolumeDelivered_mL ) > maxBolusErrorMl ) + else if ( ( fabs( expectedSalineBolusVolume_mL - bolusSalineVolumeDelivered_mL ) > maxBolusErrorMl ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { activateAlarmNoData( ALARM_ID_SALINE_BOLUS_VOLUME_CHECK_FAILURE ); errorFound = TRUE; result = SALINE_BOLUS_STATE_IDLE; } -#endif } // Are we stopping the bolus? @@ -1041,9 +1049,12 @@ // Check UF rate over last hour if ( uFMeasRate > MAX_UF_RATE_ML_PER_HOUR ) { -#ifndef DISABLE_UF_ALARMS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); + } } // Increment timer and see if time to start another 1 hour check period if ( ++uFAccuracyCheckTimerCtr >= UF_ACCURACY_CHECK_INTERVAL ) @@ -1056,9 +1067,12 @@ // Check total UF volume error if ( ( fabs( refUFVolume - measUFVolume ) ) >= (F32)MAX_UF_ACCURACY_ERROR_ML ) { -#ifndef DISABLE_UF_ALARMS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_UF_VOLUME_ACCURACY_ERROR, refUFVolume, measUFVolume ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_UF_VOLUME_ACCURACY_ERROR, refUFVolume, measUFVolume ); + } } } @@ -1077,17 +1091,21 @@ DG_RESERVOIR_ID_T activeRes = getDGActiveReservoir(); 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 - resLastVolume[ activeRes ]; // ensure volume change is not too excessive - indication that load cell was impacted by some kind of shock if ( fabs(deltaVolume) > MAX_ACTIVE_LOAD_CELL_CHANGE_G ) { - ALARM_ID_T deltaAlarm = ( getDGActiveReservoir() == DG_RESERVOIR_1 ? ALARM_ID_HD_LOAD_CELL_ACCELERATION_RES_1_ALARM : ALARM_ID_HD_LOAD_CELL_ACCELERATION_RES_2_ALARM ); - SET_ALARM_WITH_1_F32_DATA( deltaAlarm, deltaVolume ); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + ALARM_ID_T deltaAlarm = ( getDGActiveReservoir() == DG_RESERVOIR_1 ? ALARM_ID_HD_LOAD_CELL_ACCELERATION_RES_1_ALARM : + ALARM_ID_HD_LOAD_CELL_ACCELERATION_RES_2_ALARM ); + SET_ALARM_WITH_1_F32_DATA( deltaAlarm, deltaVolume ); + } } else -#endif { // Calculate UF volumes and provide to dialysate outlet pump controller measUFVolume = measUFVolumeFromPriorReservoirs + ( latestResVolume - resStartVolume[ activeRes ] ); Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,14 +7,15 @@ * * @file ModeInitPOST.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ +#include "reg_crc.h" // Used to hold reset reason code at startup before bits get cleared #include "reg_system.h" // Used to access exception status registers for reset reason code at startup #include "Accel.h" @@ -25,18 +26,21 @@ #include "Compatible.h" #include "CPLD.h" #include "DialInFlow.h" +#include "DialOutFlow.h" +#include "Fans.h" #include "FPGA.h" #include "Integrity.h" #include "ModeInitPOST.h" #include "NVDataMgmt.h" #include "OperationModes.h" -#include "reg_crc.h" +#include "PresOccl.h" #include "RTC.h" #include "SafetyShutdown.h" #include "SyringePump.h" #include "system.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" +#include "Temperatures.h" #include "Valves.h" #include "WatchdogMgmt.h" @@ -73,6 +77,8 @@ static DG_VERSIONS_T dgVersion = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ///< Version and compatibility information reported by DG. static U32 startPOSTDelayCounter = 0; ///< Start POST delay counter. +extern U32 savedResetReasonCode; ///< Saved reset reason code from sys_startup.c. + // ********** private function prototypes ********** static HD_POST_STATE_T handlePOSTStatus( SELF_TEST_STATUS_T testStatus ); @@ -192,6 +198,11 @@ postState = handlePOSTStatus( testStatus ); break; + case POST_STATE_DIALYSATE_OUTLET_FLOW: + testStatus = execDialOutFlowTest(); + postState = handlePOSTStatus( testStatus ); + break; + case POST_STATE_BLOOD_LEAK: testStatus = execBloodLeakSelfTest(); postState = handlePOSTStatus( testStatus ); @@ -207,12 +218,20 @@ postState = handlePOSTStatus( testStatus ); break; + case POST_STATE_PRES_OCCL: + testStatus = execPresOcclSelfTest(); + postState = handlePOSTStatus( testStatus ); + break; + case POST_STATE_ALARM_AUDIO: -#ifndef DISABLE_ALARM_AUDIO - testStatus = execAlarmAudioSelfTest(); -#else - testStatus = SELF_TEST_STATUS_PASSED; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ALARM_AUDIO ) != SW_CONFIG_ENABLE_VALUE ) + { + testStatus = execAlarmAudioSelfTest(); + } + else + { + testStatus = SELF_TEST_STATUS_PASSED; + } postState = handlePOSTStatus( testStatus ); break; @@ -222,14 +241,35 @@ break; case POST_STATE_ACCELEROMETER: -#ifndef DISABLE_ACCELS - testStatus = execAccelTest(); -#else - testStatus = SELF_TEST_STATUS_PASSED; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ACCELEROMETERS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + testStatus = execAccelTest(); + } +#ifndef _RELEASE_ + else + { + testStatus = SELF_TEST_STATUS_PASSED; + } +#endif postState = handlePOSTStatus( testStatus ); break; + case POST_STATE_TEMPERATURES: + testStatus = execTemperaturesSelfTest(); + postState = handlePOSTStatus( testStatus ); + break; + + // NOTE: fans self test must be called after temperatures since the + // temperatures must get their calibration first before the fans start monitoring + // for RPM out of range + case POST_STATE_FANS: + testStatus = execFansSelfTest(); + postState = handlePOSTStatus( testStatus ); + break; + case POST_STATE_STUCK_BUTTON: testStatus = execStuckButtonTest(); postState = handlePOSTStatus( testStatus ); @@ -393,6 +433,10 @@ { HD_POST_STATE_T result = postState; +#ifdef BOARD_WITH_NO_HARDWARE + testStatus = SELF_TEST_STATUS_PASSED; +#endif + if ( testStatus == SELF_TEST_STATUS_PASSED ) { // Broadcast passed POST result @@ -447,9 +491,6 @@ // mode previous and current are both published as Init SEND_EVENT_WITH_2_U32_DATA( HD_EVENT_OP_MODE_CHANGE, MODE_INIT, MODE_INIT ) state = POST_STATE_FW_INTEGRITY; -#ifdef SKIP_POST - state = DG_POST_STATE_COMPLETED; -#endif startPOSTDelayCounter = 0; } Index: firmware/App/Modes/ModePostTreat.c =================================================================== diff -u -rb53c3ab97a715ef9dc823a7148d0c0a52c413865 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision b53c3ab97a715ef9dc823a7148d0c0a52c413865) +++ firmware/App/Modes/ModePostTreat.c (.../ModePostTreat.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file ModePostTreat.c * -* @author (last) Behrouz NematiPour -* @date (last) 04-Jan-2022 +* @author (last) Dara Navaei +* @date (last) 15-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -366,9 +366,11 @@ if (( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ) && (STATE_CLOSED == getSwitchStatus( PUMP_TRACK_SWITCH ))) { -#ifdef SKIP_UI_INTERACTION - patientDisconnectionConfirmed = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + patientDisconnectionConfirmed = TRUE; + } + if ( TRUE == patientDisconnectionConfirmed ) { patientDisconnectionConfirmed = FALSE; @@ -409,9 +411,10 @@ { HD_POST_TREATMENT_STATE_T state = HD_POST_TREATMENT_DISPOSABLE_REMOVAL_STATE; -#ifdef SKIP_UI_INTERACTION - disposableRemovalConfirmed = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + disposableRemovalConfirmed = TRUE; + } if ( TRUE == disposableRemovalConfirmed ) { @@ -432,11 +435,16 @@ *************************************************************************/ static HD_POST_TREATMENT_STATE_T handlePostTreatmentVerifyState( void ) { -#ifndef SKIP_CARTRIDGE_REMOVAL - BOOL isCartridgeRemoved = isCartridgeUnloaded(); -#else + // Assuming the cartridge door is removed already. + // This is used when the disable cartridge removal step software configuration is enabled BOOL isCartridgeRemoved = TRUE; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CARTRIDGE_REMOVAL_STEP ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + isCartridgeRemoved = isCartridgeUnloaded(); + } if ( STATE_CLOSED == getSwitchStatus( FRONT_DOOR ) ) { Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -rb53c3ab97a715ef9dc823a7148d0c0a52c413865 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision b53c3ab97a715ef9dc823a7148d0c0a52c413865) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file ModePreTreat.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -46,19 +46,10 @@ #define DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN 100 ///< Patient connection sub-mode dialysate inlet pump flow rate in mL/min. -#ifndef SKIP_PRIMING #define PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML 500 ///< Fill reservoir to this volume (in mL) to flush filter and lines. #define PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML 1300 ///< Fill reservoir one to this volume (in mL) during pre-treatment mode. #define PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML 700 ///< Fill reservoir two to this volume (in mL) during pre-treatment mode. -#else -#define PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML -#define PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML -#define PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML FILL_RESERVOIR_TO_VOLUME_ML -#endif -#define PRIMARY_HEATER_TARGET_TEMP_OFFSET 2.0 //TODO remove ///< Primary heater target temperature offset from trimmer heater temperature. - - /// States of the pre-treatment reservoir management state machine. typedef enum PreTreatmentReservoirMgmt_States { @@ -198,9 +189,10 @@ switch ( currentPreTreatmentState ) { case HD_PRE_TREATMENT_START_STATE: -#ifndef SKIP_SAMPLE_WATER - transitionToSampleWater(); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SAMPLE_WATER ) != SW_CONFIG_ENABLE_VALUE ) + { + transitionToSampleWater(); + } currentPreTreatmentState = HD_PRE_TREATMENT_WATER_SAMPLE_STATE; break; @@ -417,9 +409,10 @@ BOOL accepted = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NO_PATIENT_CONNECTION_CONFIRM; -#ifdef SKIP_UI_INTERACTION - patientConnectionConfirm = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + patientConnectionConfirm = TRUE; + } if ( TRUE == patientConnectionConfirm ) { @@ -606,7 +599,8 @@ execSampleWater(); #ifndef SKIP_SAMPLE_WATER - if ( SAMPLE_WATER_COMPLETE_STATE == getSampleWaterState() ) + if ( ( SAMPLE_WATER_COMPLETE_STATE == getSampleWaterState() ) || + ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SAMPLE_WATER ) ) ) #endif { cmdDGSampleWater( SAMPLE_WATER_CMD_END ); @@ -713,9 +707,10 @@ { HD_PRE_TREATMENT_MODE_STATE_T state = HD_PRE_TREATMENT_CART_INSTALL_STATE; -#ifdef SKIP_UI_INTERACTION - confirmInstallRequested = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + confirmInstallRequested = TRUE; + } if ( TRUE == confirmInstallRequested ) { @@ -833,9 +828,10 @@ verifySwitchStatus(); } -#ifdef SKIP_UI_INTERACTION - continueToTreatmentRequested = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + continueToTreatmentRequested = TRUE; + } if ( TRUE == continueToTreatmentRequested ) { @@ -1025,16 +1021,37 @@ { if ( DG_RESERVOIR_1 == getDGInactiveReservoir() ) { - cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + U32 volume = FILL_RESERVOIR_TO_VOLUME_ML; + + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) != SW_CONFIG_ENABLE_VALUE ) + { + volume = PRE_TREATMENT_FILL_RESERVOIR_ONE_VOLUME_ML; + } + + cmdStartDGFill( volume, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); } else { - cmdStartDGFill( PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + U32 volume = FILL_RESERVOIR_TO_VOLUME_ML; + + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) != SW_CONFIG_ENABLE_VALUE ) + { + volume = PRE_TREATMENT_FILL_RESERVOIR_TWO_VOLUME_ML; + } + + cmdStartDGFill( volume, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); } } else { - cmdStartDGFill( PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); + U32 volume = FILL_RESERVOIR_TO_VOLUME_ML; + + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) != SW_CONFIG_ENABLE_VALUE ) + { + volume = PRE_TREATMENT_FLUSH_RESERVOIR_VOLUME_ML; + } + + cmdStartDGFill( volume, DEFAULT_TARGET_FILL_FLOW_RATE_LPM ); } } @@ -1105,12 +1122,15 @@ if ( FALSE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) { -#ifdef SKIP_PRIMING - reservoirFilledStatus[ DG_RESERVOIR_1 ] = TRUE; -#else - reservoirFlushedStatus[ DG_RESERVOIR_1 ] = TRUE; - cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) ) + { + reservoirFilledStatus[ DG_RESERVOIR_1 ] = TRUE; + } + else + { + reservoirFlushedStatus[ DG_RESERVOIR_1 ] = TRUE; + cmdSetDGActiveReservoir( DG_RESERVOIR_1 ); + } } else if ( ( TRUE == reservoirFlushedStatus[ DG_RESERVOIR_1 ] ) && ( FALSE == reservoirFlushedStatus[ DG_RESERVOIR_2 ] ) ) { Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -279,11 +279,6 @@ BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; - if ( TRUE == getNoNewTreatmentStatus() ) - { - rejReason = REQUEST_REJECT_REASON_NO_NEW_TREATMENT_ALARM_TRIGGERED; - } - if ( ( MODE_STAN != getCurrentOperationMode() ) || ( STANDBY_WAIT_FOR_TREATMENT_STATE != currentStandbyState ) ) { rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r61716bc97ecca8af1ec560333844a8cf602eccb0 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 61716bc97ecca8af1ec560333844a8cf602eccb0) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file ModeTreatment.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -46,11 +46,9 @@ // ********** private definitions ********** #define MAX_TREATMENT_TIME_MINUTES ( 8 * MIN_PER_HOUR ) ///< Maximum treatment time (in minutes). -#ifndef ALLOW_1_MIN_TREATMENT_DURATION + #define MIN_TREATMENT_TIME_MINUTES ( 1 * MIN_PER_HOUR ) ///< Minimum treatment time (in minutes). -#else -#define MIN_TREATMENT_TIME_MINUTES ( 1 ) ///< Minimum treatment time (in minutes). -#endif + #define MAX_DIALYSATE_VOLUME_ML ( 150 * ML_PER_LITER ) ///< Maximum dialysate volume (in mL). #define USER_CONFIRM_CHANGE_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< Require user to confirm UF volume change within this time. @@ -135,6 +133,7 @@ static void resetAlarmSignalFlags( void ); static void broadcastTreatmentSettingsRanges( void ); static void broadcastTreatmentPeriodicData(); +static U32 getTreatmentTimeInMinutes( void ); static TREATMENT_STATE_T handleTreatmentStartState( void ); static TREATMENT_STATE_T handleTreatmentBloodPrimeState( void ); static TREATMENT_STATE_T handleTreatmentDialysisState( void ); @@ -193,9 +192,6 @@ treatmentStartTimeStamp = getRTCTimestamp(); treatmentEndTimeStamp = 0; - initBloodFlow(); - initDialInFlow(); - initDialOutFlow(); } /*********************************************************************//** @@ -975,7 +971,7 @@ // Check if we are in an appropriate treatment state for settings adjustment if ( ( MODE_TREA == currMode ) && ( currentTreatmentState > TREATMENT_START_STATE ) && ( currentTreatmentState < TREATMENT_END_STATE ) && - ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= MIN_TREATMENT_TIME_MINUTES ) ) + ( CALC_ELAPSED_TREAT_TIME_IN_MIN() < treatmentTime ) && ( treatmentTime >= getTreatmentTimeInMinutes() ) ) { F32 uFVolume; U32 dialVolume = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) * treatmentTime; // In mL @@ -1019,7 +1015,7 @@ { rejectReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( treatmentTime < MIN_TREATMENT_TIME_MINUTES ) + else if ( treatmentTime < getTreatmentTimeInMinutes() ) { rejectReason = REQUEST_REJECT_REASON_TREATMENT_TIME_LESS_THAN_MINIMUM; } @@ -1097,7 +1093,7 @@ pendingUFRateChange = 0.0; } // Verify treatment duration change would be valid (leave zero if not valid - UI will disable option) - if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( trtTime >= MIN_TREATMENT_TIME_MINUTES ) && + if ( ( trtTime <= MAX_TREATMENT_TIME_MINUTES ) && ( trtTime >= getTreatmentTimeInMinutes() ) && ( dialVolume <= MAX_DIALYSATE_VOLUME_ML ) ) { result = TRUE; @@ -1449,7 +1445,7 @@ // Compute minimum treatment duration U32 presTime = ( presTreatmentTimeSecs / SEC_PER_MIN ); U32 elapseTime = CALC_ELAPSED_TREAT_TIME_IN_MIN(); - U32 minTime = MAX( (elapseTime + 2), MIN_TREATMENT_TIME_MINUTES ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it is valid for next minute + U32 minTime = MAX( (elapseTime + 2), getTreatmentTimeInMinutes() ); // Treatment duration cannot be < 1 hour. add two minutes to cover rounding and ensure it is valid for next minute // Compute maximum treatment duration (from both UF and dialysate volume perspectives) U32 maxTimeRem = ( MAX_UF_VOLUME_ML - (U32)getUltrafiltrationReferenceVolume() ) / ( presUFRate > 0.0 ? (U32)presUFRate : 1 ); U32 maxTime1 = minTime + maxTimeRem; @@ -1529,7 +1525,31 @@ } } +/*********************************************************************//** + * @brief + * The getTreatmentTimeInMinutes function returns the treatment time in minutes. + * @details Inputs: none + * @details Outputs: none + * @return treatment time in minutes + *************************************************************************/ +static U32 getTreatmentTimeInMinutes( void ) +{ + // Assuming a 1 minute treatment + // NOTE: no # define for the 1 minute treatment time since this is only used for testing + U32 treatmentTime = 1; +#ifndef _RELEASE_ + // Check if the 1 minute treatment software configuration has not been enabled + if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_1_MIN_TREATMENT ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + treatmentTime = MIN_TREATMENT_TIME_MINUTES; + } + + return treatmentTime; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Modes/ModeTreatmentParams.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/ModeTreatmentParams.c (.../ModeTreatmentParams.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file ModeTreatmentParams.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 22-Feb-2022 * * @author (original) Sean Nash * @date (original) 29-May-2020 @@ -65,7 +65,7 @@ { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=0}, {.uInt=0} }, // TREATMENT_PARAM_HEPARIN_TYPE { CRITICAL_DATA_TYPE_U32, {.uInt=0}, {.uInt=60}, {.uInt=30} }, // TREATMENT_PARAM_BP_MEAS_INTERVAL { CRITICAL_DATA_TYPE_U32, {.uInt=50}, {.uInt=150}, {.uInt=75} }, // TREATMENT_PARAM_RINSEBACK_FLOW_RATE - { CRITICAL_DATA_TYPE_S32, {.sInt=-300}, {.sInt=-30}, {.sInt=-300} }, // TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT + { CRITICAL_DATA_TYPE_S32, {.sInt=-300}, {.sInt=70}, {.sInt=-300} }, // TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT { CRITICAL_DATA_TYPE_S32, {.sInt=-270}, {.sInt=100}, {.sInt=100} }, // TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT { CRITICAL_DATA_TYPE_S32, {.sInt=20}, {.sInt=570}, {.sInt=20} }, // TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT { CRITICAL_DATA_TYPE_S32, {.sInt=50}, {.sInt=600}, {.sInt=400} }, // TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT @@ -631,6 +631,56 @@ /*********************************************************************//** * @brief + * The getS32TreatmentParamLowerRangeLimit function returns the lower range + * limit for a given signed integer treatment parameter. + * @details Inputs: none + * @details Outputs: none + * @param param ID of parameter to get lower range limit for + * @return lower range limit for given signed integer treatment parameter + *************************************************************************/ +S32 getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_T param ) +{ + S32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + result = TREAT_PARAMS_PROPERTIES[ param ].min.sInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MIN_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getS32TreatmentParamUpperRangeLimit function returns the upper range + * limit for a given signed integer treatment parameter. + * @details Inputs: none + * @details Outputs: none + * @param param ID of parameter to get upper range limit for + * @return upper range limit for given signed integer treatment parameter + *************************************************************************/ +S32 getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_T param ) +{ + S32 result = 0; + + if ( param < NUM_OF_TREATMENT_PARAMS ) + { + result = TREAT_PARAMS_PROPERTIES[ param ].max.sInt; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MAX_LIMIT, (U32)param ) + } + + return result; +} + +/*********************************************************************//** + * @brief * The extractTreatmentParamsFromPayload function extracts the individual * treatment parameters received from the UI into a staging array where * they will be validated and stay until user confirms them. @@ -871,6 +921,7 @@ return ( ( origTreatmentParams.uFVolume_L * ML_PER_LITER ) / origTreatmentParams.treatmentDuration_min ); } + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -909,7 +960,76 @@ } } } + return result; +} +/*********************************************************************//** + * @brief + * The testUpdateCurrentTreatmentParameters function pulls the current + * treatment parameters from the critical section if data has been + * determined to be valid. Calls sendTestCurrentTreatmentParametersResponse. + * @details Inputs: none + * @details Outputs: CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T containing + * treatment parameters. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSendCurrentTreatmentParameters( void ) +{ + BOOL result = FALSE; + CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T current_treatment_params; + + if ( TRUE == isTestingActivated() ) + { + // Test one parameter for set since all parameters are set after parameter validation. + if(TRUE == isCriticalDataSet( &treatmentParameters[TREATMENT_PARAM_BLOOD_FLOW] )) + { + result = TRUE; + current_treatment_params.accepted = TRUE; + current_treatment_params.treatment_parameters.bloodFlowRate_mL_min = getTreatmentParameterU32(TREATMENT_PARAM_BLOOD_FLOW); + current_treatment_params.treatment_parameters.dialysateFlowRate_mL_min = getTreatmentParameterU32(TREATMENT_PARAM_DIALYSATE_FLOW); + current_treatment_params.treatment_parameters.treatmentDuration_min = getTreatmentParameterU32(TREATMENT_PARAM_TREATMENT_DURATION); + current_treatment_params.treatment_parameters.heparinPreStop_min = getTreatmentParameterU32(TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME); + current_treatment_params.treatment_parameters.salineBolusVolume_mL = getTreatmentParameterU32(TREATMENT_PARAM_SALINE_BOLUS_VOLUME); + current_treatment_params.treatment_parameters.acidConcentrate = getTreatmentParameterU32(TREATMENT_PARAM_ACID_CONCENTRATE); + current_treatment_params.treatment_parameters.bicarbConcentrate = getTreatmentParameterU32(TREATMENT_PARAM_BICARB_CONCENTRATE); + current_treatment_params.treatment_parameters.dialyzerType = getTreatmentParameterU32(TREATMENT_PARAM_DIALYZER_TYPE); + current_treatment_params.treatment_parameters.heparinType = getTreatmentParameterU32(TREATMENT_PARAM_HEPARIN_TYPE); + current_treatment_params.treatment_parameters.bloodPressureMeasurementInterval_min = getTreatmentParameterU32(TREATMENT_PARAM_BP_MEAS_INTERVAL); + current_treatment_params.treatment_parameters.rinsebackFlowRate_mL_min = getTreatmentParameterU32(TREATMENT_PARAM_RINSEBACK_FLOW_RATE); + current_treatment_params.treatment_parameters.arterialPressureLowLimit_mmHg = getTreatmentParameterS32(TREATMENT_PARAM_ART_PRESSURE_LOW_LIMIT); + current_treatment_params.treatment_parameters.arterialPressureHighLimit_mmHg = getTreatmentParameterS32(TREATMENT_PARAM_ART_PRESSURE_HIGH_LIMIT); + current_treatment_params.treatment_parameters.venousPressureLowLimit_mmHg = getTreatmentParameterS32(TREATMENT_PARAM_VEN_PRESSURE_LOW_LIMIT); + current_treatment_params.treatment_parameters.venousPressureHighLimit_mmHg = getTreatmentParameterS32(TREATMENT_PARAM_VEN_PRESSURE_HIGH_LIMIT); + current_treatment_params.treatment_parameters.heparinDispenseRate_mL_hr = getTreatmentParameterF32(TREATMENT_PARAM_HEPARIN_DISPENSE_RATE); + current_treatment_params.treatment_parameters.heparinBolusVolume_mL = getTreatmentParameterF32(TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME); + current_treatment_params.treatment_parameters.dialysateTemperature_degC = getTreatmentParameterF32(TREATMENT_PARAM_DIALYSATE_TEMPERATURE); + current_treatment_params.uFVolume_L = getTreatmentParameterF32(TREATMENT_PARAM_UF_VOLUME); + } + else + { + current_treatment_params.accepted = FALSE; + current_treatment_params.treatment_parameters.bloodFlowRate_mL_min = 0; + current_treatment_params.treatment_parameters.dialysateFlowRate_mL_min = 0; + current_treatment_params.treatment_parameters.treatmentDuration_min = 0; + current_treatment_params.treatment_parameters.heparinPreStop_min = 0; + current_treatment_params.treatment_parameters.salineBolusVolume_mL = 0; + current_treatment_params.treatment_parameters.acidConcentrate = 0; + current_treatment_params.treatment_parameters.bicarbConcentrate = 0; + current_treatment_params.treatment_parameters.dialyzerType = 0; + current_treatment_params.treatment_parameters.heparinType = 0; + current_treatment_params.treatment_parameters.bloodPressureMeasurementInterval_min = 0; + current_treatment_params.treatment_parameters.rinsebackFlowRate_mL_min = 0; + current_treatment_params.treatment_parameters.arterialPressureLowLimit_mmHg = 0; + current_treatment_params.treatment_parameters.arterialPressureHighLimit_mmHg = 0; + current_treatment_params.treatment_parameters.venousPressureLowLimit_mmHg = 0; + current_treatment_params.treatment_parameters.venousPressureHighLimit_mmHg = 0; + current_treatment_params.treatment_parameters.heparinDispenseRate_mL_hr = 0; + current_treatment_params.treatment_parameters.heparinBolusVolume_mL = 0; + current_treatment_params.treatment_parameters.dialysateTemperature_degC = 0; + current_treatment_params.uFVolume_L = 0; + } + sendTestCurrentTreatmentParametersResponse(current_treatment_params); + } return result; } Index: firmware/App/Modes/ModeTreatmentParams.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/ModeTreatmentParams.h (.../ModeTreatmentParams.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/ModeTreatmentParams.h (.../ModeTreatmentParams.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file ModeTreatmentParams.h * -* @author (last) Behrouz NematiPour -* @date (last) 09-Dec-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Sean Nash * @date (original) 29-May-2020 @@ -72,6 +72,17 @@ F32 uFVolume_L; ///< Original ultrafiltration volume (in L) set by user before treatment start } ADJ_TREATMENT_PARAMS_T; + +/// Record structure for current treatment parameters +typedef struct +{ + U32 accepted; ///< Accepted or rejected based on if critical data has been set. + TREATMENT_PARAMS_DATA_PAYLOAD_T treatment_parameters; ///< Record structure of treatment parameters + F32 uFVolume_L; ///< Current ultrafiltration volume (in L). + +} CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T; + + // ********** Public function prototypes ********** void initTreatParamsMode( void ); // Initialize this module @@ -89,14 +100,17 @@ BOOL setTreatmentParameterU32( TREATMENT_PARAM_T param, U32 value ); // Set a specified unsigned integer treatment parameter value BOOL setTreatmentParameterS32( TREATMENT_PARAM_T param, S32 value ); // Set a specified signed integer treatment parameter value BOOL setTreatmentParameterF32( TREATMENT_PARAM_T param, F32 value ); // Set a specified floating point treatment parameter value -U32 getTreatmentParameterU32( TREATMENT_PARAM_T param ); // Get a specified unsigned integer treatment parameter -S32 getTreatmentParameterS32( TREATMENT_PARAM_T param ); // Get a specified signed integer treatment parameter -F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ); // Get a specified floating point treatment parameter +U32 getTreatmentParameterU32( TREATMENT_PARAM_T param ); // Get a specified unsigned integer treatment parameter +S32 getTreatmentParameterS32( TREATMENT_PARAM_T param ); // Get a specified signed integer treatment parameter +F32 getTreatmentParameterF32( TREATMENT_PARAM_T param ); // Get a specified floating point treatment parameter BOOL isTreatmentParamInRange( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ); // Check range for a proposed treatment parameter value -F32 getUltrafiltrationVolumeOriginal( void ); // Get the original ultrafiltration volume, set in pre-treatment mode by user. -F32 getUltrafiltrationRateOriginal( void ); // Get/calculate the original ultrafiltration rate, by ultrafiltration volume and treatment duration set in pre-treatment mode by user. +S32 getS32TreatmentParamLowerRangeLimit( TREATMENT_PARAM_T param ); // Get the lower range limit for a signed integer treatment parameter +S32 getS32TreatmentParamUpperRangeLimit( TREATMENT_PARAM_T param ); // Get the upper range limit for a signed integer treatment parameter +F32 getUltrafiltrationVolumeOriginal( void ); // Get the original ultrafiltration volume, set in pre-treatment mode by user. +F32 getUltrafiltrationRateOriginal( void ); // Get/calculate the original ultrafiltration rate, by ultrafiltration volume and treatment duration set in pre-treatment mode by user. BOOL testSetTreatmentParameter( TREATMENT_PARAM_T param, CRITICAL_DATAS_T value ); // Set a specific treatment parameter value +BOOL testSendCurrentTreatmentParameters(); // Update current treatment parameters /**@}*/ Index: firmware/App/Modes/OperationModes.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file OperationModes.c * * @author (last) Dara Navaei -* @date (last) 12-Nov-2021 +* @date (last) 08-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -37,16 +37,16 @@ // ********** private data ********** -/// HD operation mode broadcast interval (in task interval/sec). -#define BROADCAST_HD_OP_MODE_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) +#define BROADCAST_HD_OP_MODE_INTERVAL ( 250 / TASK_GENERAL_INTERVAL ) ///< HD operation mode broadcast interval (in task interval/sec). +#define DATA_PUBLISH_COUNTER_START_COUNT 11 ///< Data publish counter start count. // ********** private data ********** static volatile BOOL modeRequest[ NUM_OF_MODES - 1 ]; ///< Pending operation mode change requests. static HD_OP_MODE_T lastMode = MODE_INIT; ///< Last operation mode prior to current mode. static HD_OP_MODE_T currentMode = MODE_INIT; ///< Current operation mode. static U32 currentSubMode = 0; ///< The currently active state of the active mode. -static U32 broadcastModeIntervalCtr = 11; ///< Interval counter used to determine when to broadcast operation mode. Initialize to 11 to stagger broadcast. +static U32 broadcastModeIntervalCtr; ///< Interval counter used to determine when to broadcast operation mode. Initialize to 11 to stagger broadcast. /// Interval (in task intervals) at which to publish operation mode data to CAN bus. static OVERRIDE_U32_T opModePublishInterval = { BROADCAST_HD_OP_MODE_INTERVAL, BROADCAST_HD_OP_MODE_INTERVAL, BROADCAST_HD_OP_MODE_INTERVAL, 0 }; static U32 priorSubMode = 0; ///< The prior submode state. @@ -87,9 +87,11 @@ } // Start in init mode - currentMode = MODE_INIT; - currentSubMode = 0; - priorSubMode = 0; + currentMode = MODE_INIT; + currentSubMode = 0; + priorSubMode = 0; + broadcastModeIntervalCtr = DATA_PUBLISH_COUNTER_START_COUNT; + transitionToNewOperationMode( MODE_INIT ); // Call initializers for the individual modes Index: firmware/App/Modes/Prime.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/Prime.c (.../Prime.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/Prime.c (.../Prime.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Prime.c * -* @author (last) Hung Nguyen -* @date (last) 04-Jan-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Quang Nguyen * @date (original) 08-Dec-2020 @@ -61,62 +61,62 @@ /// States of the treatment reservoir management state machine. typedef enum PrimeReservoirMgmt_States { - PRIME_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. - PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. - PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP, ///< After sending drain command, wait for DG to response back. - PRIME_RESERVOIR_MGMT_DRAIN_STATE, ///< Wait for drain to complete. - PRIME_RESERVOIR_MGMT_START_FILL_STATE, ///< Command DG to start filling reservoir. - PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP, ///< After sending fill command, wait for DG to response back. - PRIME_RESERVOIR_MGMT_FILL_STATE, ///< Wait for fill to complete. - PRIME_RESERVOIR_MGMT_FILL_COMPLETE_STATE, ///< Reservoir fill has completed. - PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE, ///< Wait for reservoir 2 become inactive. - NUM_OF_PRIME_RESERVOIR_MGMT_STATES ///< Number of prime reservoir mgmt. states. + PRIME_RESERVOIR_MGMT_START_STATE = 0, ///< If DG not already in re-circ mode, try to get it there. + PRIME_RESERVOIR_MGMT_FLUSH_DG_LINES_STATE, ///< In DG re-circ, wait for lines to flush - then start draining inactive reservoir. + PRIME_RESERVOIR_MGMT_WAIT_FOR_DRAIN_CMD_RESP, ///< After sending drain command, wait for DG to response back. + PRIME_RESERVOIR_MGMT_DRAIN_STATE, ///< Wait for drain to complete. + PRIME_RESERVOIR_MGMT_START_FILL_STATE, ///< Command DG to start filling reservoir. + PRIME_RESERVOIR_MGMT_WAIT_FOR_FILL_CMD_RESP, ///< After sending fill command, wait for DG to response back. + PRIME_RESERVOIR_MGMT_FILL_STATE, ///< Wait for fill to complete. + PRIME_RESERVOIR_MGMT_FILL_COMPLETE_STATE, ///< Reservoir fill has completed. + PRIME_RESERVOIR_MGMT_WAIT_RESERVOIR_TWO_INACTIVE, ///< Wait for reservoir 2 become inactive. + NUM_OF_PRIME_RESERVOIR_MGMT_STATES ///< Number of prime reservoir mgmt. states. } PRIME_RESERVOIR_MGMT_STATE_T; typedef struct { - U32 bloodVolume; ///< Blood volume of the dialyzer in mL. - U32 dialysateVolume; ///< Dialysate volume of the dialyzer in mL. + U32 bloodVolume; ///< Blood volume of the dialyzer in mL. + U32 dialysateVolume; ///< Dialysate volume of the dialyzer in mL. } DIALYZER_VOLUME_DATA_T; // ********** private data ********** -static DIALYZER_VOLUME_DATA_T dialyzerVolumeTable[ ] = { { 82, 170 }, ///< Dialyzer volume table in mL of five types of dialyzer - { 100, 200 }, - { 120, 257 }, - { 87, 233 }, - { 102, 280 } }; +/// Dialyzer volumes (blood and dialysate) table in mL for each type of dialyzer. +static DIALYZER_VOLUME_DATA_T dialyzerVolumeTable[ ] = + { { 82, 170 }, // DIALYZER_TYPE_BBRAUN_PRO_13H + { 100, 200 }, // DIALYZER_TYPE_BBRAUN_PRO_16H + { 120, 257 }, // DIALYZER_TYPE_BBRAUN_PRO_19H + { 87, 233 }, // DIALYZER_TYPE_FRESENIUS_OPTIFLUX_F160NRE + { 102, 280 } }; // DIALYZER_TYPE_FRESENIUS_OPTIFLUX_F180NRE -static U32 primeDialysateDialyzerTimeLimit; ///< Time limit in msec for priming dialysate dialyzer path. -static U32 primeSalineDialyzerTimeLimit; ///< Time limit in msec for priming saline dialyzer path. +static U32 primeDialysateDialyzerTimeLimit; ///< Time limit in msec for priming dialysate dialyzer path. +static U32 primeSalineDialyzerTimeLimit; ///< Time limit in msec for priming saline dialyzer path. -static HD_PRE_TREATMENT_PRIME_STATE_T currentPrimeState; ///< Current state of the prime sub-mode state machine. -static HD_PRE_TREATMENT_PRIME_STATE_T previousPrimeState; ///< Previous state of the prime sub-mode, to use when resuming from pause. -static PRIME_RESERVOIR_MGMT_STATE_T currentReservoirMgmtState; ///< Current reservoir management state. +static HD_PRE_TREATMENT_PRIME_STATE_T currentPrimeState; ///< Current state of the prime sub-mode state machine. +static HD_PRE_TREATMENT_PRIME_STATE_T previousPrimeState; ///< Previous state of the prime sub-mode, to use when resuming from pause. +static PRIME_RESERVOIR_MGMT_STATE_T currentReservoirMgmtState; ///< Current reservoir management state. -static U32 primeStartTime; ///< Starting time of priming (in ms). -static U32 primePauseStartTime; ///< Priming pause start time (in ms). -static U32 primeStatusBroadcastTimerCounter; ///< Prime status data broadcast timer counter used to schedule when to transmit data. +static U32 primeStartTime; ///< Starting time of priming (in ms). +static U32 primePauseStartTime; ///< Priming pause start time (in ms). +static U32 primeStatusBroadcastTimerCounter; ///< Prime status data broadcast timer counter used to schedule when to transmit data. -static BOOL primeStartRequested; ///< Flag indicates user requesting to start prime. -static BOOL primeResumeRequested; ///< Flag indicates user requesting prime resume. +static BOOL primeStartRequested; ///< Flag indicates user requesting to start prime. +static BOOL primeResumeRequested; ///< Flag indicates user requesting prime resume. -static U32 noAirDetectedStartTime; ///< starting time when detecting no air. -static U32 purgeAirTimeOutStartTime; ///< Starting time for purge air state time out. -static U32 primeSalineDialyzerStartTime; ///< Starting time of priming saline dialyzer circuit. -static U32 primeDialysateDialyzerStartTime; ///< Starting time of priming dialysate dialyzer circuit. -static U32 primeDialysateBypassStartTime; ///< Starting time of priming dialysate bypass circuit. -static U32 steadyVolumeSamplingStartTime; ///< Load cell steady volume sampling interval starting time. -static F32 minimumReservoirVolume; ///< Minimum reservoir volume in mL. -static U32 steadyVolumeCount; ///< Use to keep track the number of dVolume/dt < Threshold +static U32 noAirDetectedStartTime; ///< starting time when detecting no air. +static U32 purgeAirTimeOutStartTime; ///< Starting time for purge air state time out. +static U32 primeSalineDialyzerStartTime; ///< Starting time of priming saline dialyzer circuit. +static U32 primeDialysateDialyzerStartTime; ///< Starting time of priming dialysate dialyzer circuit. +static U32 primeDialysateBypassStartTime; ///< Starting time of priming dialysate bypass circuit. +static U32 steadyVolumeSamplingStartTime; ///< Load cell steady volume sampling interval starting time. +static F32 minimumReservoirVolume; ///< Minimum reservoir volume in mL. +static U32 steadyVolumeCount; ///< Use to keep track the number of dVolume/dt < Threshold // ********** private function prototypes ********** static void resetPrimeFlags(); static void setupForPrimePause( void ); static void broadcastPrimingStatus( void ); static void purgeAirValvesBloodPumpControl( void ); -static F32 getDialyzerBloodVolume( void ); -static F32 getDialyzerDialysateVolume( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeWaitForUserStartState( void ); static HD_PRE_TREATMENT_PRIME_STATE_T handlePrimeSalineDialyzerSetupState( void ); @@ -181,11 +181,14 @@ switch ( currentPrimeState ) { case HD_PRIME_START_STATE: -#ifdef SKIP_PRIMING - currentPrimeState = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; -#else - currentPrimeState = HD_PRIME_WAIT_FOR_USER_START_STATE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) ) + { + currentPrimeState = HD_PRIME_RESERVOIR_ONE_FILL_COMPLETE_STATE; + } + else + { + currentPrimeState = HD_PRIME_WAIT_FOR_USER_START_STATE; + } break; case HD_PRIME_WAIT_FOR_USER_START_STATE: @@ -269,9 +272,9 @@ * the selected dialyzer. * @details Inputs: dialyzer volume table * @details Outputs: none - * @return blood volume capacity of the dialyzer in mL + * @return blood volume capacity of the selected dialyzer type in mL *************************************************************************/ -F32 getDialyzerBloodVolume( void ) +U32 getDialyzerBloodVolume( void ) { U32 dialyzerType = getTreatmentParameterU32( TREATMENT_PARAM_DIALYZER_TYPE ); @@ -284,9 +287,9 @@ * of the selected dialyzer. * @details Inputs: dialyzer volume table * @details Outputs: none - * @return dialysate volume capacity of the dialyzer in mL + * @return dialysate volume capacity of the selected dialyzer type in mL *************************************************************************/ -F32 getDialyzerDialysateVolume( void ) +U32 getDialyzerDialysateVolume( void ) { U32 dialyzerType = getTreatmentParameterU32( TREATMENT_PARAM_DIALYZER_TYPE ); @@ -423,9 +426,11 @@ // Keep updating start time until the user requested priming primeStartTime = getMSTimerCount(); -#ifdef SKIP_UI_INTERACTION - primeStartRequested = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_INTERACTION ) ) + { + primeStartRequested = TRUE; + } + if ( TRUE == primeStartRequested ) { primeStartRequested = FALSE; @@ -576,11 +581,14 @@ steadyVolumeSamplingStartTime = getMSTimerCount(); primeDialysateDialyzerStartTime = getMSTimerCount(); - #ifdef SKIP_PRIMING - state = HD_PRIME_WET_SELF_TESTS_STATE; - #else - state = HD_PRIME_DIALYSATE_DIALYZER_STATE; - #endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PRIMING ) ) + { + state = HD_PRIME_WET_SELF_TESTS_STATE; + } + else + { + state = HD_PRIME_DIALYSATE_DIALYZER_STATE; + } } } @@ -824,11 +832,12 @@ signalResumeSelfTests(); } -#ifndef SKIP_WET_SELF_TESTS - execWetSelfTests(); + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_WET_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) + { + execWetSelfTests(); + } - if ( TRUE == isWetSelfTestsPassed() ) -#endif + if ( ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_WET_SELF_TEST ) ) || ( TRUE == isWetSelfTestsPassed() ) ) { state = HD_PRIME_COMPLETE; } Index: firmware/App/Modes/Prime.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/Prime.h (.../Prime.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/Prime.h (.../Prime.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Prime.h * -* @author (last) Quang Nguyen -* @date (last) 05-May-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Quang Nguyen * @date (original) 08-Dec-2020 @@ -32,26 +32,24 @@ // ********** public definitions ********** -#pragma pack(push,1) - /// Payload record structure for a priming status data broadcast message. typedef struct { U32 totalTime; ///< Total priming time in seconds. U32 remainingTime; ///< Remaining time for priming in seconds. } PRIMING_DATA_PAYLOAD_T; -#pragma pack(pop) - // ********** public function prototypes ********** -void initPrime( void ); -void transitionToPrime( void ); -void execPrime( void ); -U32 getPrimeState( void ); +void initPrime( void ); // Initialize prime sub-mode (of pre-treatment mode). +void transitionToPrime( void ); // Transition to prime sub-mode (of pre-treatment mode). +void execPrime( void ); // Execute the prime state machine. +U32 getPrimeState( void ); // Get the current state of the prime state machine. +U32 getDialyzerBloodVolume( void ); // Get the blood volume (in mL) associated with a given dialyzer type. +U32 getDialyzerDialysateVolume( void ); // Get the dialysate volume (in mL) associated with a given dialyzer type. -void signalStartPrime( void ); -void signalResumePrime( void ); +void signalStartPrime( void ); // User has requested to start prime +void signalResumePrime( void ); // User has requested to resume prime /**@}*/ Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file Rinseback.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Sean Nash * @date (original) 20-Jan-2021 @@ -37,7 +37,7 @@ // ********** private definitions ********** -#define TARGET_RINSEBACK_VOLUME_ML 300.0 ///< Target rinseback volume to deliver back to the patient (in mL). TODO - get from Systems when available +#define TUBING_RINSEBACK_VOLUME_ML 80.0 ///< Target rinseback volume to deliver back to the patient (in mL). #define MAX_TOTAL_ADDITIONAL_RINSEBACK_VOLUME_ML 300.0 ///< Maximum total additional rinseback volume allowed : all additionals (in mL). #define MAX_RINSEBACK_VOLUME_ERROR_ML 60.0 ///< Maximum error in total additional rinseback volume (20% of total). #define TARGET_ADDITIONAL_RINSEBACK_VOLUME_ML 10.0 ///< Target rinseback volume for an additional volume request (in mL). @@ -64,6 +64,7 @@ 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 rinsebackTargetVolume_mL; ///< Calculated target rinseback volume (based on selected dialyzer and fixed tubing volume). static OVERRIDE_F32_T cumulativeRinsebackVolume_mL = { 0.0, 0.0, 0.0, 0 }; ///< Total cumulative rinseback volume (in mL) from measured blood flow rate. static F32 expectedRinsebackVolume_mL = 0.0; ///< Total cumulative rinseback volume (in mL) expected based on target blood flow rate. static F32 targetRinsebackVolumePlusAdditional_mL; ///< Target rinseback volume w/ additional volume(s) added (in mL). @@ -125,14 +126,16 @@ { rinsebackState = RINSEBACK_STOP_INIT_STATE; rinsebackRate_mL_min = getTreatmentParameterU32( TREATMENT_PARAM_RINSEBACK_FLOW_RATE ); - targetRinsebackVolumePlusAdditional_mL = TARGET_RINSEBACK_VOLUME_ML; + rinsebackTargetVolume_mL = TUBING_RINSEBACK_VOLUME_ML + (F32)getDialyzerBloodVolume(); + targetRinsebackVolumePlusAdditional_mL = rinsebackTargetVolume_mL; rinsebackTimerCtr = 0; cumulativeRinsebackVolume_mL.data = 0.0; expectedRinsebackVolume_mL = 0.0; additionalRinsebackVolume_mL = 0.0; totalAdditionalRinsebackVolume_mL = 0.0; rinsebackAdditionalTimerCtr = 0; rinsebackPublishTimerCtr = 0; + rinsebackTargetVolume_mL = 300.0; resetRinsebackFlags(); } @@ -378,7 +381,7 @@ result = RINSEBACK_STOP_STATE; } // Has rinseback completed? - else if ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) + else if ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); @@ -398,16 +401,15 @@ setupForRinsebackStopOrPause(); result = RINSEBACK_PAUSED_STATE; } -#ifndef DISABLE_PUMP_FLOW_CHECKS // Is rinseback taking too long? - else if ( fabs( expectedRinsebackVolume_mL - getRinsebackVolume() ) > MAX_RINSEBACK_VOLUME_ERROR_ML ) + else if ( ( fabs( expectedRinsebackVolume_mL - getRinsebackVolume() ) > MAX_RINSEBACK_VOLUME_ERROR_ML ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_FLOW_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) ) { setRinsebackIsCompleted( TRUE ); setupForRinsebackStopOrPause(); activateAlarmNoData( ALARM_ID_RINSEBACK_VOLUME_CHECK_FAILURE ); result = RINSEBACK_STOP_STATE; } -#endif // Otherwise, continue rinseback else { // Has user requested rate change? @@ -482,20 +484,20 @@ RINSEBACK_STATE_T result = RINSEBACK_STOP_STATE; // Have we been in this stopped state for too long w/o having delivered full blood volume back to patient? - if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( getRinsebackVolume() < TARGET_RINSEBACK_VOLUME_ML ) ) + if ( ( rinsebackTimerCtr > MAX_RINSEBACK_TIME ) && ( getRinsebackVolume() < rinsebackTargetVolume_mL ) ) { signalGoToTreatmentStopped(); activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); } // Have we been in this stopped state for too long despite having delivered full blood volume back to patient? - else if ( ( rinsebackTimerCtr > MAX_RINSEBACK_DONE_TIME ) && ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) + else if ( ( rinsebackTimerCtr > MAX_RINSEBACK_DONE_TIME ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { signalGoToTreatmentStopped(); activateAlarmNoData( ALARM_ID_TREATMENT_RINSEBACK_TIMEOUT_ALARM ); clearAlarm( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_WARNING ); } // Have we been in this stopped state for too long despite having delivered full blood volume back to patient? - else if ( ( RINSEBACK_DONE_WARNING_TIME == rinsebackTimerCtr ) && ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) + else if ( ( RINSEBACK_DONE_WARNING_TIME == rinsebackTimerCtr ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { activateAlarmNoData( ALARM_ID_HD_TREATMENT_RINSEBACK_TIMEOUT_WARNING ); } @@ -507,7 +509,7 @@ { additionalRinsebackRequested = FALSE; // deliver additional rinseback volume only if max volume not reached and max time not reached - if ( ( rinsebackTimerCtr < MAX_RINSEBACK_TIME ) || ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) + if ( ( rinsebackTimerCtr < MAX_RINSEBACK_TIME ) || ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { rinsebackAdditionalTimerCtr = 0; additionalRinsebackVolume_mL = 0.0; @@ -580,7 +582,7 @@ { setupForRinsebackStopOrPause(); // If this additional rinseback volume has brought us to "full" rinseback volume, set flag - if ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) + if ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) { setRinsebackIsCompleted( TRUE ); } @@ -896,7 +898,7 @@ { *rejReason = REQUEST_REJECT_REASON_ACTION_DISABLED_IN_CURRENT_STATE; } - else if ( getRinsebackVolume() < TARGET_RINSEBACK_VOLUME_ML ) + else if ( getRinsebackVolume() < rinsebackTargetVolume_mL ) { *rejReason = REQUEST_REJECT_REASON_RINSEBACK_NOT_COMPLETED; } @@ -982,7 +984,7 @@ { RINSEBACK_DATA_PAYLOAD_T data; U32 timeout = MAX_RINSEBACK_TIME / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); - U32 countdown = ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ? MAX_RINSEBACK_DONE_TIME : MAX_RINSEBACK_TIME ); + U32 countdown = ( getRinsebackVolume() >= rinsebackTargetVolume_mL ? MAX_RINSEBACK_DONE_TIME : MAX_RINSEBACK_TIME ); countdown -= rinsebackTimerCtr; // Handle countdown past zero @@ -993,10 +995,10 @@ // Scale to seconds countdown /= ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); - data.targetRinsebackVolumeMl = TARGET_RINSEBACK_VOLUME_ML; + data.targetRinsebackVolumeMl = rinsebackTargetVolume_mL; rinsebackPublishTimerCtr = 0; // If we have completed rinseback, timeout is no longer in force - indicate by zeroing timeout. Also include any additionals to target. - if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( getRinsebackVolume() >= TARGET_RINSEBACK_VOLUME_ML ) ) + if ( ( rinsebackState > RINSEBACK_PAUSED_STATE ) && ( getRinsebackVolume() >= rinsebackTargetVolume_mL ) ) { data.targetRinsebackVolumeMl = targetRinsebackVolumePlusAdditional_mL; timeout = MAX_RINSEBACK_DONE_TIME / ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); Index: firmware/App/Modes/SampleWater.c =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/SampleWater.c (.../SampleWater.c) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Modes/SampleWater.c (.../SampleWater.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SampleWater.c * -* @author (last) Quang Nguyen -* @date (last) 21-May-2021 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Quang Nguyen * @date (original) 19-Feb-2021 @@ -129,9 +129,11 @@ { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; -#ifdef SKIP_SAMPLE_WATER - sampleWaterResult = TRUE; -#endif + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_SAMPLE_WATER ) ) + { + sampleWaterResult = TRUE; + } + if ( TRUE == sampleWaterResult ) { result = SELF_TEST_STATUS_PASSED; Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -rb53c3ab97a715ef9dc823a7148d0c0a52c413865 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision b53c3ab97a715ef9dc823a7148d0c0a52c413865) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SelfTests.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Sean Nash +* @date (last) 02-Mar-2022 * * @author (original) Quang Nguyen * @date (original) 28-Jan-2021 @@ -72,24 +72,6 @@ /// Multiplier to conver flow (mL/min) into volume (mL) for period of general task interval. static const F32 SELF_TEST_FLOW_INTEGRATOR = ( ( 1.0 * TASK_GENERAL_INTERVAL ) / ( SEC_PER_MIN * MS_PER_SECOND ) ); -/// Wet self-tests state machine. -typedef enum Wet_Self_Tests_State -{ - WET_SELF_TESTS_START_STATE = 0, ///< Wet self-tests starting state. - WET_SELF_TESTS_SETUP_STATE, ///< Setup reservoirs for wet self-tests. - WET_SELF_TESTS_BUBBLES_STATE, ///< Wet self-test air bubble detectors state. - WET_SELF_TESTS_PRIME_CHECK_STATE, ///< Prime check wet self-tests state, checks for primed patient lines. - WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE, ///< Blood leak detector self-test state. - WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE, ///< Setup valve and start dialysate pump for first displacement. - WET_SELF_TESTS_FIRST_DISPLACEMENT_STATE, ///< Fill reservoir 2 with 100 mL of dialysate from reservoir 1 state. - WET_SELF_TESTS_FIRST_DISPLACEMENT_VERIFY_STATE, ///< After first displacement completed verify state. - WET_SELF_TESTS_SECOND_DISPLACEMENT_SETUP_STATE, ///< Setup valve and start dialysate pump for second displacement. - WET_SELF_TESTS_SECOND_DISPLACEMENT_STATE, ///< Fill reservoir 1 with 300 mL of dialysate from reservoir 2 state. - WET_SELF_TESTS_SECOND_DISPLACEMENT_VERIFY_STATE, ///< After first displacement completed verify state. - WET_SELF_TESTS_STOPPED_STATE, ///< Wet self-test stopped state. - WET_SELF_TESTS_COMPLETE_STATE, ///< Wet self-test complete state. - NUM_OF_WET_SELF_TESTS_STATES ///< Number of wet self-tests states. -} WET_SELF_TESTS_STATE_T; // ********** private data ********** @@ -235,11 +217,15 @@ F32 const bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); F32 const hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); -#ifndef DISABLE_SYRINGE_PUMP - useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ? TRUE : FALSE ); -#else - useHeparin = FALSE; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) != SW_CONFIG_ENABLE_VALUE ) + { + useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ? TRUE : FALSE ); + } + else + { + useHeparin = FALSE; + } + currentNoCartSelfTestsState = NO_CART_SELF_TESTS_START_STATE; runPumpStartTime = 0; havePumpsStarted = FALSE; @@ -281,7 +267,7 @@ break; case NO_CART_SELF_TESTS_DIALYSATE_FLOW_METERS_STATE: - execDialInFlowTest(); + // TODO as of now, the dialysate flow self test only gets the calibration record so it is only called in POST currentNoCartSelfTestsState = NO_CART_SELF_TESTS_BOARD_TEMPERATURE_STATE; break; @@ -395,13 +381,15 @@ // Ensure occlusion sensor has time to settle after cartridge insertion before starting dry self-tests if ( TRUE == didTimeout( selfTestStartTime, CARTRIDGE_INSERT_PRESSURE_SETTLE_TIME_MS ) ) { - setOcclusionInstallLevel(); // Record occlusion pressure level after a new cartridge is installed. -#ifdef SKIP_DRY_SELF_TESTS - // TODO: Remove once dry self-test is ready to use - currentDrySelfTestsState = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; -#else - currentDrySelfTestsState = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; -#endif + setOcclusionInstallLevel(); // Record occlusion pressure level after a new cartridge is installed + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_DRY_SELF_TESTS ) ) + { + currentDrySelfTestsState = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; + } + else + { + currentDrySelfTestsState = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; + } } break; @@ -845,7 +833,6 @@ static DRY_SELF_TESTS_STATE_T handleDrySelfTestUsedCartridgeCheckState( void ) { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; - BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); if ( ( BUBBLE_DETECTED == ADVBubbleStatus ) && @@ -1078,11 +1065,14 @@ if ( TRUE == selfTestsResumeRequested ) { selfTestsResumeRequested = FALSE; -#ifndef SKIP_DRY_SELF_TESTS - state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; -#else - state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_DRY_SELF_TESTS ) != SW_CONFIG_ENABLE_VALUE ) + { + state = DRY_SELF_TESTS_WAIT_FOR_DOOR_CLOSE_STATE; + } + else + { + state = DRY_SELF_TESTS_SYRINGE_PUMP_PRIME_STATE; + } } return state; @@ -1222,11 +1212,18 @@ BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); -#ifndef SKIP_AIR_BUBBLE_CHECK - if ( ( BUBBLE_NOT_DETECTED == ADABubbleStatus ) && ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) ) -#endif + + if ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) { - zeroBloodLeak(); +#ifndef _RELEASE_ + // TODO do we need both of these? + if ( ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SELF_TESTS_AIR_BUBBLE_CHECK ) != SW_CONFIG_ENABLE_VALUE ) ) +#endif + { + zeroBloodLeak(); + } + state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; *result = SELF_TEST_STATUS_PASSED; } @@ -1252,7 +1249,8 @@ { WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BLOOD_LEAK_DETECTOR_STATE; - if ( SELF_TEST_STATUS_PASSED == getBloodLeakSelfTestStatus() ) + if ( ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_SELF_TEST ) != SW_CONFIG_ENABLE_VALUE ) || + ( SELF_TEST_STATUS_PASSED == getBloodLeakSelfTestStatus() ) ) { settleStartTime = getMSTimerCount(); state = WET_SELF_TESTS_FIRST_DISPLACEMENT_SETUP_STATE; Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -r61716bc97ecca8af1ec560333844a8cf602eccb0 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 61716bc97ecca8af1ec560333844a8cf602eccb0) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file AlarmMgmt.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 26-Feb-2022 * * @author (original) Sean Nash * @date (original) 07-Nov-2019 @@ -115,19 +115,14 @@ static OVERRIDE_U32_T alarmStatusPublishInterval = { ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, ALARM_STATUS_PUBLISH_INTERVAL, 0 }; /// Interval (in task intervals) at which to publish alarm information to CAN bus. static OVERRIDE_U32_T alarmInfoPublishInterval = { ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, ALARM_INFO_PUB_INTERVAL, 0 }; -#ifndef ALARM_VOLUME_DEFAULT_LOW -/// Set alarm audio volume attenuation level (0..4 - lower level = higher gain). -static OVERRIDE_U32_T alarmAudioVolumeLevel = { MIN_ALARM_VOLUME_ATTENUATION, MIN_ALARM_VOLUME_ATTENUATION, MIN_ALARM_VOLUME_ATTENUATION, 0 }; -#else static OVERRIDE_U32_T alarmAudioVolumeLevel = { MAX_ALARM_VOLUME_ATTENUATION, MAX_ALARM_VOLUME_ATTENUATION, MAX_ALARM_VOLUME_ATTENUATION, 0 }; -#endif -/// Alarm audio current (high gain) measured at ADC. -static OVERRIDE_F32_T alarmPrimaryAudioCurrentHG = { 0.0, 0.0, 0.0, 0 }; -/// Alarm audio current (low gain) measured at ADC. -static OVERRIDE_F32_T alarmPrimaryAudioCurrentLG = { 0.0, 0.0, 0.0, 0 }; -/// Alarm backup audio current measured at ADC. -static OVERRIDE_F32_T alarmBackupAudioCurrent = { 0.0, 0.0, 0.0, 0 }; +static OVERRIDE_F32_T alarmPrimaryAudioCurrentHG = { 0.0, 0.0, 0.0, 0 }; /// Alarm audio current (high gain) measured at ADC. + +static OVERRIDE_F32_T alarmPrimaryAudioCurrentLG = { 0.0, 0.0, 0.0, 0 }; /// Alarm audio current (low gain) measured at ADC. + +static OVERRIDE_F32_T alarmBackupAudioCurrent = { 0.0, 0.0, 0.0, 0 }; /// Alarm backup audio current measured at ADC. + static COMP_ALARM_STATUS_T alarmStatus; ///< Record for the current composite alarm status. static ALARM_PRIORITY_RANKS_T alarmPriorityFIFO[ NUM_OF_ALARM_PRIORITIES ]; ///< FIFO - first activated or highest sub-rank alarm in each alarm priority category. @@ -222,7 +217,7 @@ * @return none *************************************************************************/ void execAlarmMgmt( void ) -{ +{ monitorAlarms(); handleAlarmEscalations(); updateAlarmsState(); @@ -914,11 +909,12 @@ { if ( alarmStatus.alarmsState < NUM_OF_ALARM_PRIORITIES ) { -#ifndef DISABLE_ALARM_AUDIO - setAlarmAudioState( alarmStatus.alarmsState, - ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], - ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ALARM_AUDIO ) != SW_CONFIG_ENABLE_VALUE ) + { + setAlarmAudioState( alarmStatus.alarmsState, + ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_GAIN], + ALARM_AUDIO_DIVIDER_LOOKUP_TABLE[volume][ALARM_AUDIO_VOLUME_DIVIDER] ); + } } else { @@ -1042,7 +1038,6 @@ BOOL noResume = FALSE; BOOL noRinseback = FALSE; BOOL noEndTreatment = FALSE; - BOOL noNewTreatment = FALSE; BOOL usrAckReq = FALSE; BOOL noMinimize = TRUE; ALARM_ID_T a; @@ -1055,7 +1050,6 @@ systemFault = ( TRUE == ALARM_TABLE[ a ].alarmIsFault ? TRUE : systemFault ); stop = ( TRUE == ALARM_TABLE[ a ].alarmStops ? TRUE : stop ); noClear = ( TRUE == ALARM_TABLE[ a ].alarmNoClear ? TRUE : noClear ); - noNewTreatment = ( TRUE == ALARM_TABLE[ a ].alarmNoNewTreatment ? TRUE : noNewTreatment ); // Set user alarm recovery actions allowed flags if ( TRUE == alarmUserRecoveryActionEnabled[ ALARM_USER_ACTION_RESUME ] ) { @@ -1115,7 +1109,7 @@ alarmStatus.noResume = noResume; alarmStatus.noRinseback = noRinseback; alarmStatus.noEndTreatment = noEndTreatment; - alarmStatus.noNewTreatment |= noNewTreatment; + alarmStatus.noNewTreatment |= 0; alarmStatus.usrACKRequired = usrAckReq; alarmStatus.noMinimize = noMinimize; } @@ -1203,6 +1197,14 @@ { U32 result = alarmAudioVolumeLevel.data; +#ifndef _RELEASE_ + // Check the software configurations + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_ALARM_VOLUME_DEFAULT_LOW ) ) + { + result = MIN_ALARM_VOLUME_ATTENUATION; + } +#endif + if ( OVERRIDE_KEY == alarmAudioVolumeLevel.override ) { result = alarmAudioVolumeLevel.ovData; Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r3d72b777cf1ceb673d118341c46e2d6d5b7b75f5 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 3d72b777cf1ceb673d118341c46e2d6d5b7b75f5) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file AlarmMgmtSWFaults.h * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Quang Nguyen * @date (original) 20-May-2021 @@ -164,6 +164,8 @@ SW_FAULT_ID_PHANTOM_INTERRUPT, SW_FAULT_ID_UNEXPECTED_DMA_INTERRUPT, // 130 SW_FAULT_ID_INVALID_TREATMENT_RESERVOIR_MANAGEMENT_STATE, + SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MIN_LIMIT, + SW_FAULT_ID_MODE_TREATMENT_PARAMS_INVALID_GET_S32_PARAM_MAX_LIMIT, SW_FAULT_ID_ILLEGAL_MEM_ACCESS, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/FPGA.c =================================================================== diff -u -r596b96528f155bd9f663ed1773fdc80761fc7b31 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 596b96528f155bd9f663ed1773fdc80761fc7b31) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file FPGA.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 14-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -234,6 +234,10 @@ U16 bloodStCount; ///< Reg 434. Blood leak St Count. U16 bloodLEDIntensity; ///< Reg 436. Blood leak LED intensity. U16 bloodRdCounter; ///< Reg 438. Blood leak register counter. + U16 arterialPressure; ///< Reg 440. Arterial pressure sensor. + U16 arterialPressureTemperature; ///< Reg 442. Arterial pressure sensor temperature. + U08 arterialPressureReadCount; ///< Reg 444. Arterial pressure sensor read count. + U08 arterialPressureErrorCount; ///< Reg 445. Arterial pressure sensor error count. } FPGA_SENSORS_T; /// Record structure for FPGA continuous priority writes. @@ -1552,6 +1556,57 @@ /*********************************************************************//** * @brief + * The getFPGADVTArterialPressure function gets the latest arterial pressure reading. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last arterial pressure reading + *************************************************************************/ +U16 getFPGADVTArterialPressure( void ) +{ + return fpgaSensorReadings.arterialPressure; +} + +/*********************************************************************//** + * @brief + * The getFPGADVTArterialTemperature function gets the latest arterial pressure + * sensor temperature reading. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last arterial pressure sensor temperature reading + *************************************************************************/ +U16 getFPGADVTArterialTemperature( void ) +{ + return fpgaSensorReadings.arterialPressureTemperature; +} + +/*********************************************************************//** + * @brief + * The getFPGADVTArterialPressureReadCounter function gets the latest arterial + * pressure sensor read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last arterial pressure sensor read counter + *************************************************************************/ +U08 getFPGADVTArterialPressureReadCounter( void ) +{ + return fpgaSensorReadings.arterialPressureReadCount; +} + +/*********************************************************************//** + * @brief + * The getFPGATDVTArterialPressureErrorCounter function gets the latest arterial + * pressure sensor error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last arterial pressure sensor error counter + *************************************************************************/ +U08 getFPGATDVTArterialPressureErrorCounter( void ) +{ + return fpgaSensorReadings.arterialPressureErrorCount; +} + +/*********************************************************************//** + * @brief * The getFPGAVenousPressure function gets the latest venous pressure reading. * The high 2 bits are status bits: 00=ok, 01=cmd mode, 10=stale data, 11=diag * The low 14 bits are data. Zero is at 1638. Values above are positive, Index: firmware/App/Services/FPGA.h =================================================================== diff -u -r596b96528f155bd9f663ed1773fdc80761fc7b31 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision 596b96528f155bd9f663ed1773fdc80761fc7b31) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file FPGA.h * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 14-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -79,6 +79,12 @@ U32 getFPGAArterialPressure( void ); U08 getFPGAArterialPressureReadCounter( void ); U08 getFPGAArterialPressureErrorCounter( void ); + +U16 getFPGADVTArterialPressure( void ); +U16 getFPGADVTArterialTemperature( void ); +U08 getFPGADVTArterialPressureReadCounter( void ); +U08 getFPGATDVTArterialPressureErrorCounter( void ); + U16 getFPGAVenousPressure( void ); U16 getFPGAVenousPressureTemperature( void ); U08 getFPGAVenousPressureReadCounter( void ); Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r6982379266891326c9d45aecd7d54ad5c85ea69f -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 6982379266891326c9d45aecd7d54ad5c85ea69f) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -10,6 +10,7 @@ #include "MessageSupport.h" #include "ModeTreatment.h" #include "ModeTreatmentParams.h" +#include "NVDataMgmt.h" #include "OperationModes.h" #include "Reservoirs.h" #include "TaskGeneral.h" @@ -71,8 +72,13 @@ static F32 previousUFFlowMLP = 0.0; ///< Previous ultrafiltration flow rate in mL/min. static DG_MIXING_RATIOS_T ratios; ///< Mixing ratios and fill prep time in milliseconds structure. -static const F32 RESERVOIR_DILUTION_RATIO = MAX_RESERVOIR_DILUTION / ( 1.0 - MAX_RESERVOIR_DILUTION ); +static const F32 RESERVOIR_DILUTION_RATIO = MAX_RESERVOIR_DILUTION / ( 1.0 - MAX_RESERVOIR_DILUTION ); ///< Reservoir dilution ratio. +// TODO remove +// FALSE for reservoir 1 and TRUE for reservoir 2 +static BOOL test = TRUE; +// TODO remove + // ********** private function prototypes ********** // Reservoir management functions @@ -201,6 +207,7 @@ 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; + break; } publishReservoirData(); @@ -235,9 +242,12 @@ // Check if the time that the reservoir has been use has exceeded the limit if ( TRUE == didTimeout( timeReservoirInUseMS, MAX_RESERVOIR_DEPLETION_TIME_MS ) ) { -#ifndef SKIP_RESERVOIR_ALARMS - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT, calcTimeSince( timeReservoirInUseMS ) ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RESERVOIRS_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_DEPLETION_TIME_OUT, calcTimeSince( timeReservoirInUseMS ) ) + } } } @@ -504,7 +514,9 @@ timeWaitToFillMS = timeDepleteMS - ( getFillTimeMS() + RESERVOIR_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS ); // If the wait time has elapsed, trigger a fill command - if ( timeWaitToFillMS <= 0 ) + // TODO uncomment + //if ( timeWaitToFillMS <= 0 ) + // TODO uncomment { cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML, targetFillFlowRateLPM ); } @@ -541,9 +553,13 @@ // diluted to much if ( recirculationLevelPct >= MAX_RESERVOIR_RECIRCULATION ) { -#ifndef SKIP_RESERVOIR_ALARMS - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE, recirculationLevelPct ) +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RESERVOIRS_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) #endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_ACTIVE_RESERVOIR_RECIRCULATION_OUT_OF_RANGE, recirculationLevelPct ) + } + } // Check if DG has moved out of the fill mode @@ -565,7 +581,7 @@ * @brief * The handleReservoirMgmtWaitForFillSettleState function executes the reservoir * management wait for fill to settle state. - * @details Inputs: reservoirSwitchTimer + * @details Inputs: reservoirSwitchTimer, volSpentML * @details Outputs: reservoirSwitchTimer, volSpentML * @return next reservoir management state of the state machine *************************************************************************/ @@ -574,26 +590,42 @@ 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( reservoirSwitchStartTimeMS, RESERVOIR_SETTLE_TIME_MS ) ) + if ( ( TRUE == didTimeout( reservoirSwitchStartTimeMS, RESERVOIR_SETTLE_TIME_MS ) ) && ( volSpentML >= (F32)FILL_RESERVOIR_TO_VOLUME_ML ) ) { DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); - // Signal dialysis sub-mode to capture baseline volume for next reservoir. - setStartReservoirVolume( inactiveRes ); + // TODO test code remove + //if ( TRUE == test ) + { + // Signal dialysis sub-mode to capture baseline volume for next reservoir. + setStartReservoirVolume( inactiveRes ); - // Command DG to switch reservoirs - cmdSetDGActiveReservoir( inactiveRes ); + // Command DG to switch reservoirs + cmdSetDGActiveReservoir( inactiveRes ); - // Signal dialysis sub-mode to switch reservoirs - signalReservoirsSwitched(); + // Signal dialysis sub-mode to switch reservoirs + signalReservoirsSwitched(); + } + // TODO test code // Get ready for the next delivery volSpentML = 0.0; // Wait for used reservoir to settle reservoirSwitchStartTimeMS = getMSTimerCount(); - state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; + // TODO test code + // For reservoir test, it should go back to start state + /*if ( FALSE == test ) + { + state = TREATMENT_RESERVOIR_MGMT_START_STATE; + } + else*/ + { + state = TREATMENT_RESERVOIR_MGMT_WAIT_FOR_SWITCH_SETTLE_STATE; + test = FALSE; + } + // TODO test code } return state; Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -rb0e789c01065104761b860e8482c056bf2479916 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision b0e789c01065104761b860e8482c056bf2479916) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SystemComm.c * -* @author (last) Hung Nguyen -* @date (last) 17-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 22-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -310,10 +310,10 @@ canXmitRetryCtr = MAX_XMIT_RETRIES; signalCANXmitsCompleted(); // Clear pending xmit flag clearCANXmitBuffers(); // Clear xmit buffers - nothing is going out right now - } - } - } - } + } // end - are we retrying xmit or are we alone on CAN bus + } // end - pending xmit timeout? + } // end - transmit in progress or not + } // end - DG not alone on CAN bus } /*********************************************************************//** @@ -753,9 +753,12 @@ { if ( TRUE == didTimeout( timeOfLastUICheckIn, UI_COMM_TIMEOUT_IN_MS ) ) { -#ifndef DISABLE_UI_COMM_TO_ALARM - activateAlarmNoData( ALARM_ID_UI_COMM_TIMEOUT ); -#endif +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_UI_COMM_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + activateAlarmNoData( ALARM_ID_UI_COMM_TIMEOUT ); + } } if ( TRUE == didTimeout( timeOfLastDGCheckIn, DG_COMM_TIMEOUT_IN_MS ) ) @@ -781,9 +784,7 @@ { if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { -#ifndef DISABLE_CRC_ERROR SET_ALARM_WITH_1_U32_DATA( ALARM_ID_COMM_TOO_MANY_BAD_CRCS, (U32)ALARM_SOURCE_HD ); -#endif } } @@ -1616,6 +1617,22 @@ handleTestSyringePumpHeprinBolusTargetRateOverrideRequest( message ); break; + case MSG_ID_HD_REQ_CURRENT_TREATMENT_PARAMETERS: + handleTestCurrentTreamtmentParametersRequest( message ); + break; + + case MSG_ID_HD_FANS_DUTY_CYCLE_OVERRIDE: + handleSetFansDutyCycleOverrideRequest( message ); + break; + + case MSG_ID_HD_GET_SW_CONFIG_RECORD: + handleGetHDSoftwareConfigRecord( message ); + break; + + case MSG_ID_HD_SET_SW_CONFIG_RECORD: + handleSetHDSoftwareConfigRecord( message ); + break; + default: // Unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r3d3cc1e6819f83db631270dc0fd019d15739db08 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 3d3cc1e6819f83db631270dc0fd019d15739db08) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SystemCommMessages.c * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -152,18 +152,19 @@ { data[ msgSize++ ] = 0; } - - #ifndef DISABLE_ACK_ERRORS - // If ACK required, add to pending ACK list - if ( TRUE == ackReq ) + + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ACK_ERRORS ) != SW_CONFIG_ENABLE_VALUE ) { - if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) + // If ACK required, add to pending ACK list + if ( TRUE == ackReq ) { - error = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL ) - } + if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) + { + error = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL ) + } + } } - #endif if ( FALSE == error ) { @@ -1818,7 +1819,6 @@ payload.alarmsFlags |= ( almStatus.noResume ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_RESUME) : 0 ); payload.alarmsFlags |= ( almStatus.noRinseback ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_RINSEBACK) : 0 ); payload.alarmsFlags |= ( almStatus.noEndTreatment ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_END_TREATMENT) : 0 ); - payload.alarmsFlags |= ( almStatus.noNewTreatment ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_NEW_TREATMENT) : 0 ); payload.alarmsFlags |= ( almStatus.usrACKRequired ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_USER_MUST_ACK) : 0 ); payload.alarmsFlags |= ( almStatus.alarmsToEscalate ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_ALARMS_TO_ESCALATE) : 0 ); payload.alarmsFlags |= ( almStatus.alarmsSilenced ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_ALARMS_SILENCED) : 0 ); @@ -1995,6 +1995,7 @@ } } + #ifdef EMC_TEST_BUILD BOOL broadcastCANErrorCount( U32 count ) { @@ -2630,6 +2631,8 @@ return result; } + + /*********************************************************************//** * @brief * The handleChangeUFSettingsRequest function handles a ultrafiltration @@ -3115,7 +3118,12 @@ void handleHDSerialNumberRequest( void ) { MESSAGE_T msg; - HD_SYSTEM_RECORD_T system = getHDSystemRecord(); + HD_SYSTEM_RECORD_T system; + + // Get the system's record. There are no arrays of system to check and also, raise no alarm since the system record + // has been already checked in POST + getNVRecord2Driver( GET_SYS_RECORD, (U08*)&system, sizeof( HD_SYSTEM_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + U08 *payloadPtr = msg.payload; // Create a message record @@ -3167,7 +3175,10 @@ void handleHDServiceScheduleRequest( MESSAGE_T *message ) { MESSAGE_T msg; - HD_SERVICE_RECORD_T payload = getHDServiceRecord(); + HD_SERVICE_RECORD_T service; + + getNVRecord2Driver( GET_SRV_RECORD, (U08*)&service, sizeof( HD_SERVICE_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + U08 *payloadPtr = msg.payload; // Create a message record @@ -3176,9 +3187,9 @@ msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ); // Fill message payload - memcpy( payloadPtr, &payload.lastServiceEpochDate, sizeof( U32 ) ); + memcpy( payloadPtr, &service.lastServiceEpochDate, sizeof( U32 ) ); payloadPtr += sizeof( U32 ); - memcpy( payloadPtr, &payload.serviceIntervalSeconds, sizeof( U32 ) ); + memcpy( payloadPtr, &service.serviceIntervalSeconds, sizeof( U32 ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_UI, ACK_REQUIRED ); @@ -5388,7 +5399,7 @@ memcpy(&payloadLength, payloadPtr, sizeof(U32)); payloadPtr += sizeof(U32); - status = setCalibrationRecord( currentMessage, totalMessages, payloadLength, payloadPtr ); + status = receiveRecordFromDialin( NVDATAMGMT_CALIBRATION_RECORD, currentMessage, totalMessages, payloadLength, payloadPtr ); // Respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, status ); @@ -5413,7 +5424,7 @@ // Tester must be logged in if ( TRUE == isTestingActivated() ) { - result = getCalibrationRecord(); + result = sendRecordToDialin( NVDATAMGMT_CALIBRATION_RECORD ); } } @@ -5568,7 +5579,7 @@ memcpy(&payloadLength, payloadPtr, sizeof(U32)); payloadPtr += sizeof(U32); - status = setSystemRecord( currentMessage, totalMessages, payloadLength, payloadPtr ); + status = receiveRecordFromDialin( NVDATAMGMT_SYSTEM_RECORD, currentMessage, totalMessages, payloadLength, payloadPtr ); // Respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, status ); @@ -5593,7 +5604,7 @@ // Tester must be logged in if ( TRUE == isTestingActivated() ) { - result = getSystemRecord(); + result = sendRecordToDialin( NVDATAMGMT_SYSTEM_RECORD ); } } @@ -5684,7 +5695,7 @@ // Tester must be logged in if ( TRUE == isTestingActivated() ) { - result = getServiceRecord(); + result = sendRecordToDialin( NVDATAMGMT_SERVICE_RECORD ); } } @@ -5750,7 +5761,7 @@ memcpy(&payloadLength, payloadPtr, sizeof(U32)); payloadPtr += sizeof(U32); - status = setServiceRecord( currentMessage, totalMessages, payloadLength, payloadPtr ); + status = receiveRecordFromDialin( NVDATAMGMT_SERVICE_RECORD, currentMessage, totalMessages, payloadLength, payloadPtr ); // Respond to request sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, status ); @@ -6805,17 +6816,17 @@ *************************************************************************/ void handleTestFansRPMAlarmStartTimeOffsetOverrideRequest( MESSAGE_T *message ) { - TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + TEST_OVERRIDE_PAYLOAD_T payload; BOOL result = FALSE; // verify payload length - if ( sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) == message->hdr.payloadLen ) + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) { - memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) ); + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); if ( FALSE == payload.reset ) { - result = testSetFanRPMAlarmStartTimeOffsetOverride( payload.state.u32, payload.index ); + result = testSetFanRPMAlarmStartTimeOffsetOverride( payload.state.u32 ); } else { @@ -6827,4 +6838,183 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } +/*********************************************************************//** + * @brief + * The handleSetFansDutyCycleOverrideRequest function handles a + * request to override the fans duty cycle. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleSetFansDutyCycleOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + + if ( FALSE == payload.reset ) + { + result = testSetFansDutyCycleOverride( payload.state.f32 ); + } + else + { + result = testResetFansDutyCycleOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestCurrentTreamtmentParametersRequest function handles a + * request to retrieve the current treatment parameters. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestCurrentTreamtmentParametersRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + // verify payload length + if ( 0 == message->hdr.payloadLen ) + { + result = TRUE; + // ACK request + result = testSendCurrentTreatmentParameters(); + } + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The sendTestCurrentTreatmentParametersResponse function constructs a current + * treatment parameter response message to the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: current treatment prameters response msg constructed and queued. + * @param data response data record + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendTestCurrentTreatmentParametersResponse(CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T current_params) +{ + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_RES_CURRENT_TREATMENT_PARAMETERS; + msg.hdr.payloadLen = sizeof(CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T); + memcpy(payloadPtr, ¤t_params, sizeof(CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T)); + + return serializeMessage(msg, COMM_BUFFER_OUT_CAN_PC, ACK_REQUIRED ); +} + +/*********************************************************************//** + * @brief + * The sendHDSWConfigRecord function sends out the HD software configuration record. + * @details Inputs: none + * @details Outputs: HD software configuration record msg constructed and queued + * @param msgCurrNum: current payload number + * @param msgTotalNum: total number of payloads + * @param length: buffer length to be written + * @param swRcrdAddress: start address of the software configuration record + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendHDSWConfigRecord( U32 payloadCurrNum, U32 payloadTotalNum, U32 length, U08* swRcrdAddress ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_SEND_SW_CONFIG_RECORD; + msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ) + sizeof( U32 ) + length; + + memcpy( payloadPtr, &payloadCurrNum, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + + memcpy( payloadPtr, &payloadTotalNum, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + + memcpy( payloadPtr, &length, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + + memcpy( payloadPtr, swRcrdAddress, length ); + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_PC, ACK_NOT_REQUIRED ); + + return result; +} + +/*********************************************************************//** +* @brief +* The handleGetHDSoftwareConfigRecord function handles a request to get the HD +* software configuration record. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*************************************************************************/ +void handleGetHDSoftwareConfigRecord( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // verify payload length + if ( 0 == message->hdr.payloadLen ) + { + // Tester must be logged in + if ( TRUE == isTestingActivated() ) + { + result = sendRecordToDialin( NVDATAMGMT_SW_CONFIG_RECORD ); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** +* @brief +* The handleSetHDSoftwareConfigRecord function handles a request to set the HD +* software configuration record. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*************************************************************************/ +void handleSetHDSoftwareConfigRecord( MESSAGE_T *message ) +{ + U32 currentMessage; + U32 totalMessages; + U32 payloadLength; + + BOOL status = FALSE; + U08* payloadPtr = message->payload; + + if ( message->hdr.payloadLen >= ( sizeof(currentMessage) + sizeof(totalMessages) + sizeof(payloadLength) ) ) + { + memcpy(¤tMessage, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + memcpy(&totalMessages, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + memcpy(&payloadLength, payloadPtr, sizeof(U32)); + payloadPtr += sizeof(U32); + + status = receiveRecordFromDialin( NVDATAMGMT_SW_CONFIG_RECORD, currentMessage, totalMessages, payloadLength, payloadPtr ); + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, status ); +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r3d3cc1e6819f83db631270dc0fd019d15739db08 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 3d3cc1e6819f83db631270dc0fd019d15739db08) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file SystemCommMessages.h * -* @author (last) Hung Nguyen -* @date (last) 15-Feb-2022 +* @author (last) Dara Navaei +* @date (last) 03-Mar-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -37,6 +37,7 @@ #include "ModePreTreat.h" #include "ModeStandby.h" #include "ModeTreatment.h" +#include "ModeTreatmentParams.h" #include "MsgQueues.h" #include "NVDataMgmt.h" #include "PresOccl.h" @@ -412,6 +413,15 @@ // MSG_ID_DG_CONCENTRATE_MIXING_RATIOS_DATA void handleDGMixingRatios( MESSAGE_T *message ); +// MSG_ID_HD_SEND_SW_CONFIG_RECORD +BOOL sendHDSWConfigRecord( U32 payloadCurrNum, U32 payloadTotalNum, U32 length, U08* swRcrdAddress ); + +// MSG_ID_HD_GET_SW_CONFIG_RECORD +void handleGetHDSoftwareConfigRecord( MESSAGE_T *message ); + +// MSG_ID_HD_SET_SW_CONFIG_RECORD +void handleSetHDSoftwareConfigRecord( MESSAGE_T *message ); + #ifdef EMC_TEST_BUILD // MSG_ID_CAN_ERROR_COUNT BOOL broadcastCANErrorCount( U32 count ); @@ -770,6 +780,15 @@ // MSG_ID_HD_FAN_RPM_ALARM_START_TIME_OVERRIDE void handleTestFansRPMAlarmStartTimeOffsetOverrideRequest( MESSAGE_T *message ); +// MSG_ID_HD_FANS_DUTY_CYCLE_OVERRIDE +void handleSetFansDutyCycleOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_REQ_CURRENT_TREATMENT_PARAMETERS +void handleTestCurrentTreamtmentParametersRequest( MESSAGE_T *message ); + +// MSG_ID_HD_RES_CURRENT_TREATMENT_PARAMETERS +BOOL sendTestCurrentTreatmentParametersResponse(CURRENT_TREATMENT_PARAMS_DATA_PAYLOAD_T current_params); + /**@}*/ #endif Index: firmware/App/Services/WatchdogMgmt.c =================================================================== diff -u -r61716bc97ecca8af1ec560333844a8cf602eccb0 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision 61716bc97ecca8af1ec560333844a8cf602eccb0) +++ firmware/App/Services/WatchdogMgmt.c (.../WatchdogMgmt.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -8,7 +8,7 @@ * @file WatchdogMgmt.c * * @author (last) Dara Navaei -* @date (last) 04-Jan-2022 +* @date (last) 10-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -183,14 +183,13 @@ SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_WATCHDOG_POST_TEST_FAILED, 2.0, v24 ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } -#ifndef DISABLE_ALARM_AUDIO // Verify backup alarm audio is on when w.d. expired - else if ( audioCurrent < MIN_BACKUP_ALARM_CURRENT_MA ) + else if ( ( audioCurrent < MIN_BACKUP_ALARM_CURRENT_MA ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ALARM_AUDIO ) != SW_CONFIG_ENABLE_VALUE ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_WATCHDOG_POST_TEST_FAILED, 3.0, audioCurrent ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } -#endif } else { @@ -215,14 +214,13 @@ SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_WATCHDOG_POST_TEST_FAILED, 4.0, v24 ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } -#ifndef DISABLE_ALARM_AUDIO // Verify backup alarm audio is on when w.d. recovered - else if ( audioCurrent > MAX_BACKUP_ALARM_CURRENT_MA ) + else if ( ( audioCurrent > MAX_BACKUP_ALARM_CURRENT_MA ) && + ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ALARM_AUDIO ) != SW_CONFIG_ENABLE_VALUE ) ) { SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_WATCHDOG_POST_TEST_FAILED, 5.0, audioCurrent ); watchdogSelfTestStatus = SELF_TEST_STATUS_FAILED; } -#endif else { watchdogSelfTestStatus = SELF_TEST_STATUS_PASSED; Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file TaskGeneral.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 23-Jan-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -75,15 +75,16 @@ // Monitor pressure/occlusion sensors execPresOccl(); -#endif + // Monitor voltages execVoltagesMonitor(); // Monitor switches execSwitches(); // Monitor temperatures - execTemperatures(); + execTemperatures(); +#endif // Run operation mode state machine execOperationModes(); @@ -107,12 +108,10 @@ // Monitor/Control fans execFans(); -#endif // Manage NVDataMgmt process record state machine execNVDataMgmtProcessRecord(); -#ifndef RM46_EVAL_BOARD_TARGET // Manage alarm state execAlarmMgmt(); #endif Index: firmware/App/Tasks/TaskPriority.c =================================================================== diff -u -r24b2fe72608344e67ef37234085d15ad5e4fcc37 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 24b2fe72608344e67ef37234085d15ad5e4fcc37) +++ firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -7,8 +7,8 @@ * * @file TaskPriority.c * -* @author (last) Sean Nash -* @date (last) 12-Nov-2021 +* @author (last) Dara Navaei +* @date (last) 26-Feb-2022 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -25,13 +25,14 @@ #include "DialInFlow.h" #include "DialOutFlow.h" #include "FluidLeak.h" -#include "FPGA.h" +#include "FPGA.h" +#include "NVDataMgmt.h" #include "InternalADC.h" #include "SyringePump.h" #include "SystemComm.h" #include "Valves.h" #include "WatchdogMgmt.h" -#include "TaskPriority.h" +#include "TaskPriority.h" /** * @addtogroup TaskPriority @@ -58,10 +59,10 @@ if ( TRUE == uiCommunicated() ) #endif { -#ifndef BOARD_WITH_NO_HARDWARE // 1st pass for FPGA - execFPGAIn(); - + execFPGAIn(); + +#ifndef BOARD_WITH_NO_HARDWARE // Verify processor clock speed against FPGA clock execFPGAClockSpeedTest(); @@ -75,10 +76,11 @@ // Monitor air trap level sensors execAirTrapMonitor(); -#ifndef DISABLE_SYRINGE_PUMP - // Control/Monitor syringe pump - execSyringePump(); -#endif + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SYRINGE_PUMP ) != SW_CONFIG_ENABLE_VALUE ) + { + // Control/Monitor syringe pump + execSyringePump(); + } // Monitor blood pump and flow execBloodFlowMonitor(); @@ -98,18 +100,20 @@ // Monitor air bubble detectors execBubbles(); -#ifndef DISABLE_ACCELS - // Monitor accelerometer - execAccel(); +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ACCELEROMETERS ) != SW_CONFIG_ENABLE_VALUE ) #endif -#ifndef DISABLE_3WAY_VALVES + { + // Monitor accelerometer + execAccel(); + } + // Exec and monitor valves execValves(); #endif -#endif +#endif // 2nd pass for FPGA execFPGAOut(); -#endif } // Check in with watchdog manager Fisheye: Tag 6c1d6a3eaf065c2b2d537d9fef793d73ea328359 refers to a dead (removed) revision in file `firmware/hd_build_history.log'. Fisheye: No comparison available. Pass `N' to diff? Index: firmware/source/sys_selftest.c =================================================================== diff -u -rbc538f960d0bc8c72991817ea52efac4775ce953 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/source/sys_selftest.c (.../sys_selftest.c) (revision bc538f960d0bc8c72991817ea52efac4775ce953) +++ firmware/source/sys_selftest.c (.../sys_selftest.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -46,6 +46,10 @@ #include "Common.h" #include "HDDefs.h" #include "SystemCommMessages.h" + +#define LR_OFFSET_WORD_IN_STACK 22 ///< Offset of the link register from the STACK_MARKER +#define STACK_MARKER 0xCAFECAFE ///< Location in the stack to determine the offset in word from the Link Register +#define LR_OFFSET_ADJUSTMENT 4 ///< Adjust the content of the LR so that the Memory Access Violation does not get call continously /* USER CODE END */ #include "sys_selftest.h" #include "sys_core.h" Index: firmware/source/sys_startup.c =================================================================== diff -u -rf953f3b83163b118fdd8fa37c229a118bdd040f4 -r6c1d6a3eaf065c2b2d537d9fef793d73ea328359 --- firmware/source/sys_startup.c (.../sys_startup.c) (revision f953f3b83163b118fdd8fa37c229a118bdd040f4) +++ firmware/source/sys_startup.c (.../sys_startup.c) (revision 6c1d6a3eaf065c2b2d537d9fef793d73ea328359) @@ -64,6 +64,7 @@ #include "errata_SSWF021_45.h" /* USER CODE BEGIN (1) */ +#include "reg_crc.h" /* USER CODE END */ @@ -150,6 +151,7 @@ if ((SYS_EXCEPTION & POWERON_RESET) != 0U) { /* USER CODE BEGIN (12) */ + crcREG->PSA_SIGREGL1 = SYS_EXCEPTION; /* USER CODE END */ /* Add condition to check whether PLL can be started successfully */ if (_errata_SSWF021_45_both_plls(PLL_RETRIES) != 0U)