Index: firmware/App/Controllers/AirTrap.c =================================================================== diff -u -re5d1d67106a93a6cd1b5692b586625d715732e2f -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision e5d1d67106a93a6cd1b5692b586625d715732e2f) +++ firmware/App/Controllers/AirTrap.c (.../AirTrap.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -82,8 +82,18 @@ *************************************************************************/ void initAirTrap( void ) { + U32 i; + resetAirTrap(); airTrapIllegalLevelSensorsCtr = 0; + + for ( i = 0; i < NUM_OF_AIR_TRAP_LEVEL_SENSORS; i++ ) + { + airTrapLevels[i].data = 0; + airTrapLevels[i].ovData = 0; + airTrapLevels[i].ovInitData = 0; + airTrapLevels[i].override = OVERRIDE_RESET; + } } /*********************************************************************//** @@ -204,7 +214,7 @@ if ( TRUE == didTimeout( fillStartTime, fillTimeoutMS ) ) { -#ifndef DISABLE_AIR_TRAP_LEVELING +#ifndef DISABLE_AIR_TRAP_LEVELING_ALARM activateAlarmNoData( ALARM_ID_AIR_TRAP_FILL_DURING_TREATMENT ); #endif } Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -r126ad9f684cd96bc38d5e1ab5d79f5238681e3e5 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 126ad9f684cd96bc38d5e1ab5d79f5238681e3e5) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -46,8 +46,8 @@ #define MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE 0.008 ///< Max duty cycle change when ramping up ~ 100 mL/min/s. #define MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE 0.016 ///< Max duty cycle change when ramping down ~ 200 mL/min/s. -#define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.88 ///< Controller will error if PWM duty cycle > 90%, so set max to 88% -#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.12 ///< Controller will error if PWM duty cycle < 10%, so set min to 12% +#define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89% +#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10% /// Interval (ms/task time) at which the blood pump is controlled. static const U32 BP_CONTROL_INTERVAL = ( 10000 / TASK_GENERAL_INTERVAL ); @@ -59,7 +59,7 @@ /// Interval (ms/task time) at which the blood pump speed is calculated (every 40 ms). #define BP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) /// Number of hall sensor counts kept in buffer to hold last 1 second of count data. -#define BP_SPEED_CALC_BUFFER_LEN ( 1000 / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) +#define BP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define BP_MAX_ROTOR_SPEED_RPM 100.0 ///< Maximum rotor speed allowed for blood pump. #define BP_MAX_FLOW_VS_SPEED_DIFF_RPM 200.0 ///< Maximum difference between measured speed and speed implied by measured flow. @@ -82,14 +82,19 @@ #define BP_MAX_CURR_WHEN_STOPPED_MA 150.0 ///< Motor controller current should not exceed this when pump should be stopped #define BP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running #define BP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm - -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + +#ifndef V2_0_SYSTEM + #define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle +#else + #define BP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle +#endif #define BP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for blood pump motor #define BP_REV_PER_LITER 150.0 ///< Rotor revolutions per liter #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_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00028 ///< ~28 BP motor RPM = 1% PWM duty cycle #define BP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed /// Conversion factor 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 ) @@ -105,25 +110,35 @@ #define FLOW_SIG_STRGTH_ALARM_PERSIST ( 5 * MS_PER_SECOND ) #define MIN_FLOW_SIG_STRENGTH 0.9 ///< Minimum flow sensor signal strength (90%). -#define BFM_SENSOR_PARAM_CORRUPT_STATUS 0x7 ///< Blood flow meter NVM parameter status. +/// Blood flow fast read timeout alarm persistence. +#define BLOOD_FLOW_FAST_READ_TO_PERSIST 100 +/// Blood flow slow read timeout alarm persistence. +#define BLOOD_FLOW_SLOW_READ_TO_PERSIST ( MS_PER_SECOND * 3 ) +/// Blood flow comm error persistence. +#define BLOOD_FLOW_COMM_ERROR_PERSIST MS_PER_SECOND + +#define BFM_SENSOR_CONNECTED_STATUS 0x00 ///< Blood flow meter connected status. +#define BFM_SENSOR_PARAM_CORRUPT_STATUS 0x07 ///< Blood flow meter NVM parameter status. + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. /// Enumeration of blood pump controller states. typedef enum BloodPump_States { - BLOOD_PUMP_OFF_STATE = 0, ///< Blood pump off state. - BLOOD_PUMP_RAMPING_UP_STATE, ///< Blood pump ramping up state. - BLOOD_PUMP_RAMPING_DOWN_STATE, ///< Blood pump ramping down state. - BLOOD_PUMP_CONTROL_TO_TARGET_STATE, ///< Blood pump controlling to target state. - NUM_OF_BLOOD_PUMP_STATES ///< Number of blood pump states. + BLOOD_PUMP_OFF_STATE = 0, ///< Blood pump off state + BLOOD_PUMP_RAMPING_UP_STATE, ///< Blood pump ramping up state + BLOOD_PUMP_RAMPING_DOWN_STATE, ///< Blood pump ramping down state + BLOOD_PUMP_CONTROL_TO_TARGET_STATE, ///< Blood pump controlling to target state + NUM_OF_BLOOD_PUMP_STATES ///< Number of blood pump states } BLOOD_PUMP_STATE_T; /// Enumeration of blood pump self-test states. typedef enum BloodFlow_Self_Test_States { - BLOOD_FLOW_SELF_TEST_STATE_START = 0, ///< Blood pump self-test start state. - BLOOD_FLOW_TEST_STATE_IN_PROGRESS, ///< Blood pump self-test in progress state. - BLOOD_FLOW_TEST_STATE_COMPLETE, ///< Blood pump self-test completed state. - NUM_OF_BLOOD_FLOW_SELF_TEST_STATES ///< Number of blood pump self-test states. + BLOOD_FLOW_SELF_TEST_STATE_START = 0, ///< Blood pump self-test start state + BLOOD_FLOW_TEST_STATE_IN_PROGRESS, ///< Blood pump self-test in progress state + BLOOD_FLOW_TEST_STATE_COMPLETE, ///< Blood pump self-test completed state + NUM_OF_BLOOD_FLOW_SELF_TEST_STATES ///< Number of blood pump self-test states } BLOOD_FLOW_SELF_TEST_STATE_T; // Pin assignments for pump stop and direction outputs @@ -171,11 +186,15 @@ 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 F32 flowReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds flow samples for a rolling average -static U32 flowReadingsIdx = 0; ///< Index for next sample in rolling average array -static F32 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average -static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer +static F32 flowReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds flow samples for a rolling average. +static U32 flowReadingsIdx = 0; ///< Index for next sample in rolling average array. +static F32 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average. +static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer. +static U08 lastBloodFlowFastPacketReadCtr = 0; ///< Previous read counter for the blood flow fast packets. +static U08 lastBloodFlowSlowPacketReadCtr = 0; ///< Previous read counter for the blood flow slow packets. +static U08 lastBloodFlowCommErrorCount = 0; ///< Previous BP flow sensor comm error count. + // ********** private function prototypes ********** static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ); @@ -423,13 +442,40 @@ HD_OP_MODE_T opMode = getCurrentOperationMode(); U16 bpRPM = getIntADCReading( INT_ADC_BLOOD_PUMP_SPEED ); U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); - -#ifndef V1_5_SYSTEM F32 bpFlow = ( getFPGABloodFlow() * bloodFlowCalGain ) + bloodFlowCalOffset; -#else - F32 bpFlow = ( ( getFPGABloodFlow() * -1.0 ) * bloodFlowCalGain ) + bloodFlowCalOffset; // Blood flow sensor installed backwards on HD + U08 fpReadCtr = getFPGABloodFlowFastPacketReadCounter(); + U08 spReadCtr = getFPGABloodFlowSlowPacketReadCounter(); + U08 flowErrorCtr = getFPGABloodFlowErrorCounter(); + U08 flowStatus = getFPGABloodFlowMeterStatus(); + +#ifndef DISABLE_PUMP_FLOW_CHECKS + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR, ( flowErrorCtr != lastBloodFlowCommErrorCount ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR ); + } + if ( flowStatus != BFM_SENSOR_CONNECTED_STATUS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_BLOOD_FLOW_STATUS_SELF_TEST_FAILURE, (U32)flowStatus ); + } + lastBloodFlowCommErrorCount = flowErrorCtr; #endif - + +#ifndef DISABLE_FPGA_COUNTER_CHECKS + // Check for stale flow reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR, ( fpReadCtr == lastBloodFlowFastPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR ); + } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR, ( spReadCtr == lastBloodFlowSlowPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR ); + } +#endif + + // Record flow read counters for next time around + lastBloodFlowFastPacketReadCtr = fpReadCtr; + lastBloodFlowSlowPacketReadCtr = spReadCtr; + adcBloodPumpMCSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpRPM)) * BP_SPEED_ADC_TO_RPM_FACTOR; adcBloodPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * BP_CURRENT_ADC_TO_MA_FACTOR; bloodFlowSignalStrength.data = getFPGABloodFlowSignalStrength(); @@ -715,7 +761,7 @@ * @details Outputs: none * @return the current blood flow data publication interval (in task intervals). *************************************************************************/ -U32 getPublishBloodFlowDataInterval( void ) +U32 getPublishBloodFlowDataInterval( void ) { U32 result = bloodFlowDataPublishInterval.data; @@ -1193,7 +1239,7 @@ HD_FLOW_SENSORS_CAL_RECORD_T cal = getHDFlowSensorsCalibrationRecord(); // Retrieve blood flow sensor calibration data and check for sensor connected status - if ( BFM_SENSOR_PARAM_CORRUPT_STATUS != getFPGABloodFlowMeterStatus() ) + if ( BFM_SENSOR_PARAM_CORRUPT_STATUS != bfmStatus ) { #ifndef DISABLE_CAL_CHECK if ( cal.hdFlowSensors[ CAL_DATA_HD_BLOOD_FLOW_SENSOR ].calibrationTime == 0 ) @@ -1330,7 +1376,7 @@ /*********************************************************************//** * @brief - * The testResetOffButtonStateOverride function resets the override of the + * The testResetMeasuredBloodFlowRateOverride function resets the override of the * measured blood flow rate. * @details Inputs: none * @details Outputs: measuredBloodFlowRate Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r9feea867113c62088f0ce91750127972dbd9bf53 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 9feea867113c62088f0ce91750127972dbd9bf53) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -16,13 +16,15 @@ ***************************************************************************/ #include "DialInFlow.h" +#include "Dialysis.h" #include "DGDefs.h" +#include "DGInterface.h" #include "ModeInitPOST.h" -#include "ModeTreatment.h" +#include "ModeTreatment.h" +#include "ModeTreatmentParams.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "Timers.h" -#include "DGInterface.h" /** * @addtogroup DGInterface @@ -36,6 +38,8 @@ #define RESERVOIR_SETTLE_TIME_MS 5000 ///< Time (in ms) allotted for reservoir to settle (after fill, before drain). +#define MAX_RESERVOIR_VOLUME_ML 1950.0 ///< Maximum reservoir volume. Switch reservoirs if active reservoir exceeds this volume. + #define SIZE_OF_LARGE_LOAD_CELL_AVG 32 ///< Large load cell moving average has 32 samples. /// States of the treatment reservoir management state machine. @@ -226,6 +230,19 @@ } resUseTimer = getMSTimerCount(); + // Alarm if active reservoir is full and inactive reservoir is not yet ready + if ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) + { + if ( currentTrtResMgmtState < TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE ) + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_RESERVOIR_FULL_AND_DG_NOT_READY_TO_SWITCH, getReservoirWeight( getDGActiveReservoir() ), (F32)currentTrtResMgmtState ) + } + else + { + clearAlarmCondition( ALARM_ID_HD_RESERVOIR_FULL_AND_DG_NOT_READY_TO_SWITCH ); + } + } + // Treatment reservoir mgmt. state machine switch ( currentTrtResMgmtState ) { @@ -265,8 +282,14 @@ if ( DG_MODE_CIRC == dgOpMode ) { if ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == dgSubMode ) - { - cmdStartDGFill( FILL_RESERVOIR_TO_VOLUME_ML ); + { + U32 fillToVolume = FILL_RESERVOIR_TO_VOLUME_ML; + + if ( getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ) <= SLOW_DIALYSATE_FLOW_ML_MIN ) + { + fillToVolume = FILL_RESERVOIR_TO_VOLUME_LOW_FLOW_ML; + } + cmdStartDGFill( fillToVolume ); } } else @@ -297,9 +320,8 @@ case TREATMENT_RESERVOIR_MGMT_WAIT_FOR_RES_SWITCH_STATE: // Reservoir switch during treatment should only occur in this state (i.e. when DG is ready). - // Switch reservoirs when active reservoir is spent (i.e. we have pumped fill volume through dialyzer) and DG ready - if ( ( DG_MODE_CIRC == getDGOpMode() ) && ( DG_RECIRCULATE_MODE_STATE_RECIRC_WATER == getDGSubMode() ) && - ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) ) + // Switch reservoirs when active reservoir is spent or full (i.e. we have pumped fill volume through dialyzer) and DG ready + if ( ( resUseVolumeMl >= (F32)dgReservoirFillVolumeTargetSet ) || ( getReservoirWeight( getDGActiveReservoir() ) > MAX_RESERVOIR_VOLUME_ML ) ) { DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); @@ -518,6 +540,23 @@ return result; } +/*********************************************************************//** + * @brief + * The getReservoirWeight function gets the load cell weight of a given + * reservoir. + * @details Inputs: loadCellWeightInGrams[] + * @details Outputs: none + * @param resID ID of reservoir to get weight for + * @return the current weight of the given reservoir in grams + *************************************************************************/ +F32 getReservoirWeight( DG_RESERVOIR_ID_T resID ) +{ + LOAD_CELL_ID_T lc = ( DG_RESERVOIR_1 == resID ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); + F32 wt = getLoadCellWeight( lc ); + + return wt; +} + /*********************************************************************//** * @brief * The setDGOpMode function sets the latest DG operating mode reported by @@ -670,7 +709,7 @@ loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_PRIMARY ].data = res2Primary; loadCellWeightInGrams[ LOAD_CELL_RESERVOIR_2_BACKUP ].data = res2Backup; - // feed new weight samples into filters and update moving averages + // Feed new weight samples into filters and update moving averages for ( res = DG_RESERVOIR_1; res < NUM_OF_DG_RESERVOIRS; res++ ) { F32 wt = ( res == DG_RESERVOIR_1 ? res1Primary : res2Primary ); @@ -680,6 +719,9 @@ lgFilteredReservoirWeightInGrams[ res ] = lgLoadCellReadingsTotal[ res ] / (F32)SIZE_OF_LARGE_LOAD_CELL_AVG; } lgLoadCellReadingsIdx = INC_WRAP( lgLoadCellReadingsIdx, 0, SIZE_OF_LARGE_LOAD_CELL_AVG - 1 ); + + // Update Dialysis sub-mode with new reservoir volumes + updateReservoirVolumes( res1Primary, res2Primary ); } /*********************************************************************//** Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r126ad9f684cd96bc38d5e1ab5d79f5238681e3e5 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 126ad9f684cd96bc38d5e1ab5d79f5238681e3e5) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -46,8 +46,8 @@ #define MAX_DIAL_IN_PUMP_PWM_STEP_UP_CHANGE 0.0133 ///< Max duty cycle change when ramping up ~ 200 mL/min/s. #define MAX_DIAL_IN_PUMP_PWM_STEP_DN_CHANGE 0.02 ///< Max duty cycle change when ramping down ~ 300 mL/min/s. -#define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.88 ///< Controller will error if PWM duty cycle > 90%, so set max to 88%. -#define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.12 ///< Controller will error if PWM duty cycle < 10%, so set min to 12%. +#define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. +#define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. /// Interval (ms/task time) at which the dialIn pump is controlled. static const U32 DIP_CONTROL_INTERVAL = ( 10000 / TASK_GENERAL_INTERVAL ); @@ -83,14 +83,19 @@ #define DIP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DIP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define DIP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for dialIn pump motor. +#ifndef V2_0_SYSTEM + #define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor. + #define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle +#else + #define DIP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle +#endif #define DIP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialIn pump motor. #define DIP_REV_PER_LITER 150.0 ///< Rotor revolutions per liter. /// 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_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00028 ///< ~28 BP motor RPM = 1% PWM duty cycle. #define DIP_PWM_ZERO_OFFSET 0.1 ///< 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 ) @@ -107,8 +112,18 @@ #define FLOW_SIG_STRGTH_ALARM_PERSIST ( 5 * MS_PER_SECOND ) #define MIN_FLOW_SIG_STRENGTH 0.9 ///< Minimum flow sensor signal strength (90%). -#define DFM_SENSOR_PARAM_CORRUPT_STATUS 0x7 ///< Dialysate flow meter NVM parameter corrupt status. +/// Dialysate flow fast read timeout alarm persistence. +#define DIALYSATE_FLOW_FAST_READ_TO_PERSIST 100 +/// Dialysate flow slow read timeout alarm persistence. +#define DIALYSATE_FLOW_SLOW_READ_TO_PERSIST ( MS_PER_SECOND * 3 ) +/// Blood flow comm error persistence. +#define DIALYSATE_FLOW_COMM_ERROR_PERSIST MS_PER_SECOND +#define DFM_SENSOR_CONNECTED_STATUS 0x00 ///< Dialysate flow meter connected status. +#define DFM_SENSOR_PARAM_CORRUPT_STATUS 0x07 ///< Dialysate flow meter NVM parameter corrupt status. + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. + /// Enumeration of dialysate inlet pump states. typedef enum DialInPump_States { @@ -177,13 +192,18 @@ static U32 errorDialInRotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for rotor speed error condition. static U32 errorDialInPumpDirectionPersistTimerCtr = 0; ///< Persistence timer counter for pump direction error condition. -static F32 flowReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds flow samples for a rolling average -static U32 flowReadingsIdx = 0; ///< Index for next sample in rolling average array -static F32 flowReadingsTotal = 0.0; ///< Rolling total - used to calc average -static U32 flowReadingsCount = 0; ///< Number of samples in flow rolling average buffer +static F32 flowReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds flow samples for a rolling average. +static U32 flowReadingsIdx = 0; ///< Index for next sample in rolling average array. +static F32 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 U08 lastDialysateFlowFastPacketReadCtr = 0; ///< Previous read counter for the dialysate flow fast packets. +static U08 lastDialysateFlowSlowPacketReadCtr = 0; ///< Previous read counter for the dialysate flow slow packets. +static U08 lastDialInPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA. +static U08 lastDialysateFlowCommErrorCount = 0; ///< Previous DPi flow sensor comm error count. + // ********** private function prototypes ********** static DIAL_IN_PUMP_STATE_T handleDialInPumpOffState( void ); @@ -237,6 +257,9 @@ // Initialize persistent alarm for flow sensor signal strength too low initPersistentAlarm( ALARM_ID_DIALYSATE_FLOW_SIGNAL_STRENGTH_TOO_LOW, FLOW_SIG_STRGTH_ALARM_PERSIST, FLOW_SIG_STRGTH_ALARM_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_DP_FLOW_READ_TIMEOUT_ERROR, 0, DIALYSATE_FLOW_FAST_READ_TO_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_DP_FLOW_SLOW_READ_TIMEOUT_ERROR, 0, DIALYSATE_FLOW_SLOW_READ_TO_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_DP_FLOW_SENSOR_ERROR, 0, DIALYSATE_FLOW_COMM_ERROR_PERSIST ); } /*********************************************************************//** @@ -395,7 +418,39 @@ HD_OP_MODE_T opMode = getCurrentOperationMode(); U16 dipRPM = getIntADCReading( INT_ADC_DIAL_IN_PUMP_SPEED ); U16 dipmA = getIntADCReading( INT_ADC_DIAL_IN_PUMP_MOTOR_CURRENT ); - F32 dipFlow = ( getFPGADialysateFlow() * dialInFlowCalGain ) + dialInFlowCalOffset; + F32 dipFlow = ( getFPGADialysateFlow() * dialInFlowCalGain ) + dialInFlowCalOffset; + U08 fpReadCtr = getFPGADialysateFlowFastPacketReadCounter(); + U08 spReadCtr = getFPGADialysateFlowSlowPacketReadCounter(); + U08 flowErrorCtr = getFPGADialysateFlowErrorCounter(); + U08 flowStatus = getFPGADialysateFlowMeterStatus(); + +#ifndef DISABLE_PUMP_FLOW_CHECKS + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DP_FLOW_SENSOR_ERROR, ( flowErrorCtr != lastDialysateFlowCommErrorCount ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_DP_FLOW_SENSOR_ERROR ); + } + if ( flowStatus != DFM_SENSOR_CONNECTED_STATUS ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_DIALYSATE_FLOW_STATUS_SELF_TEST_FAILURE, (U32)flowStatus ); + } + lastDialysateFlowCommErrorCount = flowErrorCtr; +#endif + +#ifndef DISABLE_FPGA_COUNTER_CHECKS + // Check for stale flow reading + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DP_FLOW_READ_TIMEOUT_ERROR, ( fpReadCtr == lastDialysateFlowFastPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_DP_FLOW_READ_TIMEOUT_ERROR ); + } + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DP_FLOW_SLOW_READ_TIMEOUT_ERROR, ( spReadCtr == lastDialysateFlowSlowPacketReadCtr ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_DP_FLOW_SLOW_READ_TIMEOUT_ERROR ); + } +#endif + + // Record flow read counters for next time around + lastDialysateFlowFastPacketReadCtr = fpReadCtr; + lastDialysateFlowSlowPacketReadCtr = spReadCtr; adcDialInPumpMCSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(dipRPM)) * DIP_SPEED_ADC_TO_RPM_FACTOR; adcDialInPumpMCCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(dipmA)) * DIP_CURRENT_ADC_TO_MA_FACTOR; @@ -975,7 +1030,15 @@ if ( DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE == dialInPumpState ) { MOTOR_DIR_T dipMCDir, dipDir; + U08 dirErrorCnt = getFPGADialInPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + // Check pump direction error count + if ( lastDialInPumpDirectionCount != dirErrorCnt ) + { + lastDialInPumpDirectionCount = dirErrorCnt; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_INLET_PUMP ) + } + dipMCDir = ( getMeasuredDialInPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); dipDir = ( getMeasuredDialInPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); @@ -1230,7 +1293,7 @@ // Get the flow sensors calibration record HD_FLOW_SENSORS_CAL_RECORD_T cal = getHDFlowSensorsCalibrationRecord(); - if ( DFM_SENSOR_PARAM_CORRUPT_STATUS != getFPGADialysateFlowMeterStatus() ) + if ( DFM_SENSOR_PARAM_CORRUPT_STATUS != dfmStatus ) { #ifndef DISABLE_CAL_CHECK if ( cal.hdFlowSensors[ CAL_DATA_HD_DIALYZER_FLOW_SENSOR ].calibrationTime == 0 ) Index: firmware/App/Controllers/DialOutFlow.c =================================================================== diff -u -re5d1d67106a93a6cd1b5692b586625d715732e2f -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision e5d1d67106a93a6cd1b5692b586625d715732e2f) +++ firmware/App/Controllers/DialOutFlow.c (.../DialOutFlow.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -44,12 +44,12 @@ #define MAX_DIAL_OUT_FLOW_RATE 650 ///< Maximum dialysate outlet pump flow rate in mL/min. #define MIN_DIAL_OUT_FLOW_RATE 100 ///< Minimum dialysate outlet pump flow rate in mL/min. -#define DPO_FLOW_ADJ_DUE_TO_HIGHER_INLET_PRES 1.000 ///< Adjustment factor to account for higher pump inlet pressure (than DPi pump inlet). +#define DPO_FLOW_ADJ_DUE_TO_HIGHER_INLET_PRES 1.200 ///< Adjustment factor to account for higher pump inlet pressure (than DPi pump inlet). #define MAX_DIAL_OUT_PUMP_PWM_STEP_UP_CHANGE 0.0133 ///< Maximum duty cycle change when ramping up ~ 200 mL/min/s. #define MAX_DIAL_OUT_PUMP_PWM_STEP_DN_CHANGE 0.02 ///< Maximum duty cycle change when ramping down ~ 300 mL/min/s. -#define MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.88 ///< Controller will error if PWM duty cycle > 90%, so set max to 88%. -#define MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.12 ///< Controller will error if PWM duty cycle < 10%, so set min to 12%. +#define MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. +#define MIN_DIAL_OUT_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. /// Interval (ms/task time) at which the dialysate outlet pump is controlled. static const U32 DOP_CONTROL_INTERVAL = ( 2000 / TASK_GENERAL_INTERVAL ); @@ -81,7 +81,13 @@ #define DOP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DOP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define DOP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor. +#ifndef V2_0_SYSTEM + #define DOP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialysate outlet pump motor. + #define DOP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle +#else + #define DOP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor + #define DOP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle +#endif #define DOP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialysate outlet pump motor. #define DOP_ADC_FULL_SCALE_V 3.0 ///< DPo analog signals are 0-3V (while int. ADC ref V may be different). #define DOP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. @@ -92,11 +98,12 @@ #define DOP_REV_PER_LITER 150.0 ///< 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_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00028 ///< ~28 DPo motor RPM = 1% PWM duty cycle. #define DOP_PWM_ZERO_OFFSET 0.1 ///< 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 ) +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. + /// Enumeration of dialysate outlet pump controller states. typedef enum DialOutPump_States { @@ -165,6 +172,8 @@ //static DIAL_OUT_PUMP_SELF_TEST_STATE_T dialOutPumpSelfTestState = DIAL_OUT_PUMP_SELF_TEST_STATE_START; ///< Current state of the dialysate outlet pump self-test state machine. //static U32 dialOutPumpSelfTestTimerCount = 0; ///< Timer counter for time reference during self-test. +static U08 lastDialOutPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA + // ********** private function prototypes ********** static DIAL_OUT_PUMP_STATE_T handleDialOutPumpOffState( void ); @@ -246,6 +255,7 @@ 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 = DOP_PWM_FROM_ML_PER_MIN(adjFlow); + dialOutPumpPWMDutyCyclePct = MIN( dialOutPumpPWMDutyCyclePct, MAX_DIAL_OUT_PUMP_PWM_DUTY_CYCLE ); switch ( dialOutPumpState ) { @@ -786,7 +796,15 @@ if ( DIAL_OUT_PUMP_CONTROL_TO_TARGET_STATE == dialOutPumpState ) { MOTOR_DIR_T dopMCDir, dopDir; + U08 dirErrorCnt = getFPGADialOutPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + // Check pump direction error count + if ( lastDialOutPumpDirectionCount != dirErrorCnt ) + { + lastDialOutPumpDirectionCount = dirErrorCnt; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_DIALYSATE_OUTLET_PUMP ) + } + dopMCDir = ( getMeasuredDialOutPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); dopDir = ( getMeasuredDialOutPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); Index: firmware/App/Controllers/SyringePump.c =================================================================== diff -u -re5d1d67106a93a6cd1b5692b586625d715732e2f -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision e5d1d67106a93a6cd1b5692b586625d715732e2f) +++ firmware/App/Controllers/SyringePump.c (.../SyringePump.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -20,6 +20,7 @@ #include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.h" +#include "SafetyShutdown.h" #include "SyringePump.h" #include "SystemCommMessages.h" #include "TaskPriority.h" @@ -34,8 +35,6 @@ /// Default publication interval for syringe pump data. #define SYRINGE_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) -/// Speed check interval. -#define SYRINGE_PUMP_SPEED_CHECK_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) #define BD_SYRINGE_ID_RADIUS_CM ( 1.402 / 2.0 ) ///< Radius from inner diameter (in cm) of supported BD syringe. /// Milliliters per mm of syringe plunger travel. @@ -61,12 +60,16 @@ #define MIN_HEPARIN_BOLUS_RATE 1.2 ///< Minimum Heparin bolus flow rate (in mL/hr). #define MAX_HEPARIN_BOLUS_RATE 24.0 ///< Maximum Heparin bolus flow rate (in mL/hr). #define HEPARIN_BOLUS_TIME_HR ( 5.0 / MIN_PER_HOUR ) ///< Duration (in hours) of Heparin bolus. -#define SYRINGE_PUMP_RETRACT_RATE 10800.0 ///< Retract rate is 15 mL/ 5 s = 3 mL/s = 10,800 mL/hr. +#define SYRINGE_PUMP_RETRACT_RATE 3600.0 ///< Retract rate is 5 mL/ 5 s = 1 mL/s = 3,600 mL/hr. #define SYRINGE_PUMP_SEEK_RATE 3600.0 ///< Seek plunger rate is 5 mL/ 5 s = 1 mL/s = 3,600 mL/hr. #define SYRINGE_PUMP_PRIME_RATE 635.0 ///< Prime rate is 0.5 mm ^ 2 x PI x 450 mm = 0.353 mL / 2s = 635 mL/hr. #define SYRINGE_PUMP_MAX_RATE 11000.0 ///< Maximum rate of the syringe pump (in mL/hr). -#define SYRINGE_PUMP_RATE_ALARM_PERSISTENCE ( 1 * MS_PER_SECOND ) ///< Alarm persistence period for syringe pump speed check alarms. +#define SYRINGE_PUMP_RATE_ALARM_PERSISTENCE 2000 ///< Alarm persistence period (in ms) for syringe pump speed check alarms. +#define SYRINGE_PUMP_DIR_ALARM_PERSISTENCE 1000 ///< Alarm persistence period (in ms) for syringe pump direction check alarms. +#define SYRINGE_PUMP_OFF_ALARM_PERSISTENCE 500 ///< Alarm persistence period (in ms) for syringe pump off check alarms. +#define SYRINGE_PUMP_OCCLUSION_ALARM_PERSISTENCE 30 ///< Alarm persistence period (in ms) for syringe pump occlusion alarms. +#define SYRINGE_PUMP_ADC_READ_PERSISTENCE 100 ///< Syringe pump ADC stale read alarm persistence time (in ms). #define STEPS_TO_MICROSTEPS( s ) ( (s) * 32.0 ) ///< Macro conversion from steps to microsteps. #define MICROSTEPS_TO_STEPS( m ) ( (m) / 32.0 ) ///< Macro conversion from microsteps to steps. @@ -86,9 +89,11 @@ #define FIVE_PCT_OVER_ALLOWANCE 1.05 ///< Allow 5 percent over target before alarming on over travel. /// Expected position of empty in relation to home postion. -#define SYRINGE_PUMP_EMPTY_POS ( SYRINGE_ENCODER_COUNTS_PER_ML * 11.0 ) +#define SYRINGE_PUMP_EMPTY_POS ( SYRINGE_ENCODER_COUNTS_PER_ML * 11.0 ) // TODO - get syringe volume from home to empty (11 mL is placeholder) /// Margin of error for empty position determination. #define SYRINGE_PUMP_EMPTY_POS_MARGIN ( SYRINGE_ENCODER_COUNTS_PER_ML * 0.5 ) +/// Minimum retract position. +#define SYRINGE_PUMP_RETRACT_POS_MIN ( SYRINGE_ENCODER_COUNTS_PER_ML * -0.5 ) #define SYRINGE_PUMP_START_RAMP_SPEED 300000 ///< Starting speed for all syringe pump operations to ramp up from. #define SYRINGE_PUMP_RAMP_DIVISOR 5 ///< Used for ramping profile. @@ -136,6 +141,15 @@ #define SYRINGE_PUMP_ENCODER_DIRECTION_ERROR_BITS 0x3F ///< Syringe pump encoder direction error counter bits in FPGA register. #define SYRINGE_PUMP_ENCODER_DIRECTION_BIT 0x80 ///< Syringe pump encoder direction bit in FPGA register. +/// Interval (ms/task time) at which the syringe pump speed is calculated (every 40 ms). +#define SYRINGE_PUMP_SPEED_CALC_INTERVAL ( 40 / TASK_PRIORITY_INTERVAL ) +/// Number of syringe pump encoder positions kept in buffer to hold last 1 second of position data. +#define SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / SYRINGE_PUMP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) + +#define SYRINGE_PUMP_RAMP_STALL_TIME ( 500 / TASK_PRIORITY_INTERVAL ) ///< Syringe pump ramp stall timeout. +#define SYRINGE_PUMP_RAMP_STALL_RETRIES 3 ///< Syringe pump ramp stall retries allowed. +#define SYRINGE_PUMP_STALL_SPEED_THRESHOLD 0.05 ///< Minimum syringe pump speed to be considered not stalled. + /// Defined states for the syringe pump control state machine. typedef enum SyringePump_States { @@ -150,39 +164,36 @@ NUM_OF_SYRINGE_PUMP_STATES ///< Number of syringe pump control states } SYRINGE_PUMP_STATE_T; -/// Defined states for the syringe pump self-test state machine. -typedef enum Syringe_Pump_Self_Test_States -{ - SYRINGE_PUMP_SELF_TEST_STATE_START = 0, ///< Self test start state. - SYRINGE_PUMP_TEST_STATE_IN_PROGRESS, ///< Self test in progress state. - SYRINGE_PUMP_TEST_STATE_COMPLETE, ///< Self test completed state. - NUM_OF_SYRINGE_PUMP_SELF_TEST_STATES ///< Number of syringe pump self-test states. -} SYRINGE_PUMP_SELF_TEST_STATE_T; - // ********** private data ********** static SYRINGE_PUMP_STATE_T syringePumpState; ///< Current state of syringe pump control state machine. static U32 syringePumpDataPublicationTimerCounter; ///< Used to schedule syringe pump data publication to CAN bus. -static U32 syringePumpSpeedCalcTimerCounter; ///< Used to calculate measured rate from change in position over time. static U32 syringePumpRampTimerCtr; ///< Used to track ramp up time. static HEPARIN_STATE_T heparinDeliveryState; ///< Current state of Heparin delivery. /// Interval (in ms) at which to publish syringe pump data to CAN bus. static OVERRIDE_U32_T syringePumpDataPublishInterval = { SYRINGE_PUMP_DATA_PUB_INTERVAL, SYRINGE_PUMP_DATA_PUB_INTERVAL, 0, 0 }; -static OVERRIDE_F32_T syringePumpMeasRate = {0.0, 0.0, 0.0, 0 }; ///< Measured rate for syringe pump (in mL/hr). -static OVERRIDE_F32_T syringePumpMeasForce = {0.0, 0.0, 0.0, 0 }; ///< Measured driver force (in V). -static OVERRIDE_F32_T syringePumpMeasSyringeDetectionSwitch = {0, 0, 0, 0 }; ///< Measured syringe detect switch (in V). -static OVERRIDE_F32_T syringePumpMeasHome = {0.0, 0.0, 0.0, 0 }; ///< Measured optical home (in V). -static OVERRIDE_S32_T syringePumpPosition = {0, 0, 0, 0 }; ///< Encoder based position (in steps). -static OVERRIDE_F32_T syringePumpVolumeDelivered = {0.0, 0.0, 0.0, 0 }; ///< Measured volume delivered (in mL). +static OVERRIDE_F32_T syringePumpMeasRate = { 0.0, 0.0, 0.0, 0 }; ///< Measured rate for syringe pump (in mL/hr). +static OVERRIDE_F32_T syringePumpMeasForce = { 0.0, 0.0, 0.0, 0 }; ///< Measured driver force (in V). +static OVERRIDE_F32_T syringePumpMeasSyringeDetectionSwitch = { 0, 0, 0, 0 }; ///< Measured syringe detect switch (in V). +static OVERRIDE_F32_T syringePumpMeasHome = { 0.0, 0.0, 0.0, 0 }; ///< Measured optical home (in V). +static OVERRIDE_S32_T syringePumpPosition = { 0, 0, 0, 0 }; ///< Encoder based position (in steps). +static OVERRIDE_F32_T syringePumpVolumeDelivered = { 0.0, 0.0, 0.0, 0 }; ///< Measured volume delivered (in mL). +static OVERRIDE_U32_T syringePumpStatus = {0, 0, 0, 0}; ///< Syringe pump status reported by FPGA. +static OVERRIDE_U32_T syringePumpEncoderStatus = {0, 0, 0, 0}; ///< Syringe pump encoder status reported by FPGA. +static OVERRIDE_U32_T syringePumpADCandDACStatus = {0, 0, 0, 0}; ///< Syringe pump ADC and DAC status reported by FPGA. +static OVERRIDE_U32_T syringePumpADCReadCtr = {0, 0, 0, 0}; ///< Syringe pump ADC read counter reported by FPGA. static F32 syringePumpSetRate; ///< Set rate for syringe pump (in mL/hr). static U32 syringePumpSetToggleTime; ///< Set rate for syringe pump (in uSec/toggle). static U32 syringePumpRampUpToggleTime; ///< Current ramp rate for syringe pump (in uSec/toggle). static F32 syringePumpSafetyVolumeDelivered; ///< Calculated volume (in mL) (from set rate over time). static S32 syringePumpVolumeStartPosition; ///< Start position for the current volume calculation. static S32 syringePumpHomePositionOffset; ///< FPGA reported position when at home postion. -static S32 syringePumpPosition1SecAgo; ///< Position recorded at last 1 Hz speed check. +static S32 syringePumpLastPosition; ///< Position previously recorded. +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. 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. @@ -195,6 +206,7 @@ static BOOL syringePumpPositionKnown; ///< Flag indicates we know position from a prior retract to home. static BOOL syringePumpPlungerFound; ///< Flag indicates plunger was found. +static BOOL syringeVolumeAdequate; ///< Flag indicates whether Heparin volume is sufficient to complete treatment. static BOOL syringePumpPrimeCompleted; ///< Flag indicates prime operation was completed. static BOOL syringePumpDACVrefWriteInProgress; ///< Flag indicates DAC Vref write is in progress. @@ -206,6 +218,9 @@ // static SYRINGE_PUMP_SELF_TEST_STATE_T syringePumpSelfTestState; ///< Current syringe pump self-test state. // static U32 syringePumpSelfTestTimerCount; ///< Timer counter for syringe pump self-test. +static U32 syringePumpStallCtr; ///< Counts time when position is not changing during ramp. +static U32 syringePumpStallRetryCount; ///< Counts pump ramp up stall retries. + // ********** private function prototypes ********** static void resetSyringePumpRequestFlags( void ); @@ -216,6 +231,10 @@ static F32 getSyringePumpSyringeDetectorV( void ); static F32 getSyringePumpHomeDetectorV( void ); static F32 getSyringePumpForceV( void ); +static U08 getSyringePumpStatus( void ); +static U08 getSyringePumpEncoderStatus( void ); +static U08 getSyringePumpADCReadCounter( void ); +static U08 getSyringePumpADCandDACStatus( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpInitState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpOffState( void ); static SYRINGE_PUMP_STATE_T handleSyringePumpRetractState( void ); @@ -228,11 +247,13 @@ static void calcStepperToggleTimeForTargetRate( F32 rate ); static void calcMeasRate( void ); static void calcSafetyVolumeDelivered( void ); +static BOOL checkDirection( BOOL stopPump, MOTOR_DIR_T expDir ); static BOOL checkOcclusionOrEmpty( BOOL stopPump ); static BOOL checkSyringeRemoved( BOOL stopPump ); static BOOL checkMaxTravel( BOOL stopPump, S32 maxPos ); static BOOL checkMeasRate( BOOL stopPump, F32 pctMargin ); static BOOL checkVolumeVsSafetyVolume( BOOL stopPump, F32 pctMargin ); +static BOOL checkForStall( BOOL stopPump ); static void publishSyringePumpData( void ); /*********************************************************************//** @@ -244,6 +265,8 @@ *************************************************************************/ void initSyringePump( void ) { + U32 i; + syringePumpState = SYRINGE_PUMP_INIT_STATE; heparinDeliveryState = HEPARIN_STATE_OFF; @@ -252,7 +275,7 @@ syringePumpSafetyVolumeDelivered = 0.0; syringePumpVolumeStartPosition = 0; syringePumpHomePositionOffset = 0; - syringePumpPosition1SecAgo = 0; + syringePumpLastPosition = 0; syringePumpControllerMeasuredDirection = MOTOR_DIR_FORWARD; syringePumpEncoderMeasuredDirection = MOTOR_DIR_FORWARD; @@ -262,10 +285,30 @@ syringePumpPositionKnown = FALSE; syringePumpPlungerFound = FALSE; + syringeVolumeAdequate = FALSE; syringePumpPrimeCompleted = FALSE; lastSyringePumpADCReadCtr = 0; + // Zero pump position counts buffer + syringePumpMotorSpeedCalcIdx = 0; + for ( i = 0; i < SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN; i++ ) + { + syringePumpLastPositions[ i ] = 0; + } + + syringePumpStallCtr = 0; + syringePumpStallRetryCount = 0; + + // Initialize persistent alarms + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR, 0, SYRINGE_PUMP_ADC_READ_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_ENCODER_DIRECTION_ERROR, 0, SYRINGE_PUMP_DIR_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_CONTROLLER_DIRECTION_ERROR, 0, SYRINGE_PUMP_DIR_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, 0, SYRINGE_PUMP_OFF_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR, 0, SYRINGE_PUMP_OFF_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, 0, SYRINGE_PUMP_RATE_ALARM_PERSISTENCE ); + initPersistentAlarm( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, 0, SYRINGE_PUMP_OCCLUSION_ALARM_PERSISTENCE ); + // Reset request flags resetSyringePumpRequestFlags(); } @@ -274,13 +317,13 @@ * @brief * The resetSyringePumpRequestFlags function resets request flags. * @details Inputs: none - * @details Outputs: syringePumpSetRate, syringePumpRetractRequested + * @details Outputs: request flags reset * @return TRUE if request accepted, FALSE if not *************************************************************************/ static void resetSyringePumpRequestFlags( void ) { syringePumpRetractRequested = FALSE; - syringePumpSeekRequested = FALSE;;; + syringePumpSeekRequested = FALSE; syringePumpPrimeRequested = FALSE; syringePumpBolusRequested = FALSE; syringePumpContinuousRequested = FALSE; @@ -428,7 +471,12 @@ *************************************************************************/ 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 { syringePumpSetRate = SYRINGE_PUMP_RETRACT_RATE; syringePumpRetractRequested = TRUE; @@ -470,6 +518,10 @@ { syringePumpSetRate = SYRINGE_PUMP_PRIME_RATE; syringePumpPrimeRequested = TRUE; + // Reset volume and start pos before starting prime operation + syringePumpVolumeDelivered.data = 0.0; + syringePumpSafetyVolumeDelivered = 0.0; + syringePumpVolumeStartPosition = getSyringePumpPosition(); } return syringePumpPrimeRequested; @@ -497,6 +549,10 @@ { syringePumpSetRate = tgtRate; syringePumpBolusRequested = TRUE; + // Reset volume and start pos before starting bolus operation + syringePumpVolumeDelivered.data = 0.0; + syringePumpSafetyVolumeDelivered = 0.0; + syringePumpVolumeStartPosition = getSyringePumpPosition(); } } else @@ -706,6 +762,85 @@ /*********************************************************************//** * @brief + * The getSyringePumpStatus function gets the current syringe pump status. + * @details Inputs: syringePumpStatus + * @details Outputs: none + * @return the current syringe pump status. + *************************************************************************/ +static U08 getSyringePumpStatus() +{ + U08 result = (U08)(syringePumpStatus.data & MASK_OFF_U32_MSBS); + + if ( OVERRIDE_KEY == syringePumpStatus.override ) + { + result = (U08)(syringePumpStatus.ovData & MASK_OFF_U32_MSBS); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getSyringePumpEncoderStatus function gets the current syringe pump + * encoder status. + * @details Inputs: syringePumpEncoderStatus + * @details Outputs: none + * @return the current syringe pump encoder status. + *************************************************************************/ +static U08 getSyringePumpEncoderStatus() +{ + U08 result = (U08)(syringePumpEncoderStatus.data & MASK_OFF_U32_MSBS); + + if ( OVERRIDE_KEY == syringePumpEncoderStatus.override ) + { + result = (U08)(syringePumpEncoderStatus.ovData & MASK_OFF_U32_MSBS); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getSyringePumpADCReadCounter function gets the current syringe pump + * ADC read counter. + * @details Inputs: syringePumpADCReadCtr + * @details Outputs: none + * @return the current syringe pump ADC read counter. + *************************************************************************/ +static U08 getSyringePumpADCReadCounter() +{ + U08 result = (U08)(syringePumpADCReadCtr.data & MASK_OFF_U32_MSBS); + + if ( OVERRIDE_KEY == syringePumpADCReadCtr.override ) + { + result = (U08)(syringePumpADCReadCtr.ovData & MASK_OFF_U32_MSBS); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getSyringePumpADCandDACStatus function gets the current syringe pump + * ADC and DAC status reported by the FPGA. + * @details Inputs: syringePumpADCandDACStatus + * @details Outputs: none + * @return the current syringe pump ADC and DAC status. + *************************************************************************/ +static U08 getSyringePumpADCandDACStatus() +{ + U08 result = (U08)(syringePumpADCandDACStatus.data & MASK_OFF_U32_MSBS); + + if ( OVERRIDE_KEY == syringePumpADCandDACStatus.override ) + { + result = (U08)(syringePumpADCandDACStatus.ovData & MASK_OFF_U32_MSBS); + } + + return result; +} + +/*********************************************************************//** + * @brief * The isSyringeDetected function determines whether a syringe is currently * detected. * @details Inputs: syringePumpMeasSyringeDetectionSwitch @@ -779,6 +914,20 @@ /*********************************************************************//** * @brief + * The isSyringeVolumeAdequate function determines whether the syringe has + * sufficient Heparin volume to complete the treatment per user settings. + * Call this function after seek operation. + * @details Inputs: syringeVolumeAdequate + * @details Outputs: none + * @return TRUE if syringe volume is sufficient to complete the treatment, FALSE if not. + *************************************************************************/ +BOOL isSyringeVolumeAdequate( void ) +{ + return syringeVolumeAdequate; +} + +/*********************************************************************//** + * @brief * The isSyringePumpPrimed function determines whether the syringe pump * prime operation was completed. * @details Inputs: syringePumpPrimeCompleted @@ -787,7 +936,7 @@ *************************************************************************/ BOOL isSyringePumpPrimed( void ) { - return syringePumpPrimeCompleted;; + return syringePumpPrimeCompleted; } /*********************************************************************//** @@ -800,47 +949,58 @@ static void execSyringePumpMonitor( void ) { S32 encPosition = getFPGASyringePumpEncoderPosition(); - U08 pmpStatus = getFPGASyringePumpStatus(); - U08 encStatus = getFPGASyringePumpEncoderStatus(); - U08 adcReadCtr = getFPGASyringePumpADCReadCounter(); + // Get latest FPGA status + syringePumpStatus.data = (U32)getFPGASyringePumpStatus(); + syringePumpEncoderStatus.data = (U32)getFPGASyringePumpEncoderStatus(); + syringePumpADCandDACStatus.data = (U32)getFPGASyringePumpADCandDACStatus(); + syringePumpADCReadCtr.data = (U32)getFPGASyringePumpADCReadCounter(); + // Get latest ADC data and convert to V syringePumpMeasHome.data = ( (F32)getFPGASyringePumpADCChannel2() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; syringePumpMeasSyringeDetectionSwitch.data = ( (F32)getFPGASyringePumpADCChannel1() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; syringePumpMeasForce.data = ( (F32)getFPGASyringePumpADCChannel0() * SYRINGE_PUMP_ADC_REF_V ) / SYRINGE_PUMP_ADC_FULL_SCALE_BITS; // Apply home offset to encoder position + syringePumpLastPosition = getSyringePumpPosition(); syringePumpPosition.data = encPosition - syringePumpHomePositionOffset; // Calculate volume delivered from position syringePumpVolumeDelivered.data = (F32)(syringePumpPosition.data - syringePumpVolumeStartPosition) / SYRINGE_ENCODER_COUNTS_PER_ML; calcSafetyVolumeDelivered(); // Calculate measured rate (mL/hr) calcMeasRate(); // Get measured direction - syringePumpControllerMeasuredDirection = ( ( encStatus & SYRINGE_PUMP_ENCODER_DIRECTION_BIT ) != 0 ? MOTOR_DIR_REVERSE : MOTOR_DIR_FORWARD ); - // TODO - calc direction from encoder pos relative to last - // syringePumpEncoderMeasuredDirection = TBD; + 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 ); - // TODO - check if syringe pump is on while BP is off (w/ a little persistence). - - if ( syringePumpDACVrefWriteInProgress != TRUE ) + // Check if syringe pump is on while BP is off { - // Check ADC read is fresh - if ( lastSyringePumpADCReadCtr == adcReadCtr ) // TODO - add persistence + BOOL runWhileOff = ( ( ( SYRINGE_PUMP_HEP_BOLUS_STATE == syringePumpState ) || ( SYRINGE_PUMP_HEP_CONTINUOUS_STATE == syringePumpState ) ) && + ( isBloodPumpRunning() != TRUE ) ); + + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, runWhileOff ) ) { - // activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR ); // TODO - restore when issue with read counter resolved + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_RUNNING_WHILE_BP_OFF_ERROR, (U32)syringePumpState ); } - lastSyringePumpADCReadCtr = adcReadCtr; + } - // Check encoder direction error. // TODO check direction in states - if ( ( encStatus & SYRINGE_PUMP_ENCODER_DIRECTION_ERROR_BITS ) != 0) + if ( syringePumpDACVrefWriteInProgress != TRUE ) + { + // Check ADC read is fresh (takes FPGA a while to configure ADC so don't check until after init/POST mode + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR, + ( ( getCurrentOperationMode() > MODE_INIT ) && ( lastSyringePumpADCReadCtr == getSyringePumpADCReadCounter() ) ) ) ) { - // TODO - alarm? +#ifndef DISABLE_SYRINGE_PUMP_ALARMS + activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_ADC_ERROR ); +#endif } + lastSyringePumpADCReadCtr = getSyringePumpADCReadCounter(); + // Check pump status - if ( pmpStatus != 0 ) + if ( getSyringePumpStatus() != 0 ) { - // TODO - pump failure fault + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_FAULT, (U32)getSyringePumpStatus() ); } } } @@ -937,9 +1097,14 @@ { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_OFF_STATE; - // TODO - check position is not changing while stopped - // activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR ); - // activateSafetyShutdown(); +#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() ) ) ) + { + activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_NOT_STOPPED_ERROR ); + activateSafetyShutdown(); + } +#endif // Check for request flags if ( TRUE == syringePumpRetractRequested ) @@ -990,6 +1155,9 @@ // Calculate target FPGA rate from set rate in mL/hr converted to microstep toggle interval in uSec calcStepperToggleTimeForTargetRate( syringePumpSetRate ); setFPGASyringePumpStepToggleTime( syringePumpRampUpToggleTime ); + // Reset stall detect variables + syringePumpStallRetryCount = 0; + syringePumpStallCtr = 0; } // Reset ramp up timer @@ -1009,14 +1177,15 @@ static SYRINGE_PUMP_STATE_T handleSyringePumpRetractState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_RETRACT_STATE; + BOOL stopPump = FALSE; - // Handle ramp up + // Handle ramp up rampSyringePump(); // Stop retract when home position is detected if ( TRUE == isSyringePumpHome() ) { - stopSyringePump(); + stopPump = TRUE; // Set position to zero after retract reaches home position syringePumpHomePositionOffset = getFPGASyringePumpEncoderPosition(); syringePumpPosition.data = 0; @@ -1027,18 +1196,28 @@ syringePumpSafetyVolumeDelivered = 0.0; // Reset flags syringePumpPlungerFound = FALSE; + syringeVolumeAdequate = FALSE; syringePumpPrimeCompleted = FALSE; - result = SYRINGE_PUMP_OFF_STATE; + // Clear insufficient volume alarm condition in case we're retracting to allow user to resolve alarm + clearAlarmCondition( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM ); } - else if ( syringePumpControllerMeasuredDirection != MOTOR_DIR_REVERSE ) + // If position known from prior retract, ensure we don't retract beyond minimum position + else if ( ( TRUE == syringePumpPositionKnown ) && ( getSyringePumpPosition() < SYRINGE_PUMP_RETRACT_POS_MIN ) ) { - // TODO - alarm w/ some persistence + stopPump = TRUE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OVER_TRAVEL_ERROR, (U32)getSyringePumpPosition(), (U32)SYRINGE_PUMP_RETRACT_STATE ); } - else if ( syringePumpEncoderMeasuredDirection != MOTOR_DIR_REVERSE ) + + stopPump = checkForStall( stopPump ); + + stopPump = checkDirection( stopPump, MOTOR_DIR_REVERSE ); + + // If anything found that would require stopping the pump, stop pump and go to off state + if ( TRUE == stopPump ) { - // TODO - alarm w/ some persistence + stopSyringePump(); + result = SYRINGE_PUMP_OFF_STATE; } - // TODO - if position known from prior retract, ensure we don't go lower than -TBD position return result; } @@ -1062,23 +1241,43 @@ // Is plunger contact detected? if ( getSyringePumpForceV() >= SYRINGE_FORCE_PLUNGER_THRESHOLD_V ) { + S32 pos = getSyringePumpPosition(); + F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); + F32 contRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); + U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); + U32 setTxDur = getTreatmentParameterU32( TREATMENT_PARAM_TREATMENT_DURATION ); + F32 hepDurHr = ( (F32)( setTxDur - preStop ) / (F32)MIN_PER_HOUR ) - HEPARIN_BOLUS_TIME_HR; + F32 txVolume = bolusVol + ( hepDurHr * contRate ); + F32 syringeVol = ( SYRINGE_PUMP_EMPTY_POS - (F32)pos ) / SYRINGE_MICRO_STEPS_PER_ML; + stopPump = TRUE; syringePumpPlungerFound = TRUE; syringePumpVolumeDelivered.data = 0.0; syringePumpSafetyVolumeDelivered = 0.0; - syringePumpVolumeStartPosition = syringePumpPosition.data; + syringePumpVolumeStartPosition = pos; + + // Check estimated syringe volume needed for treatment vs. volume detected - if insufficient for treatment needs, alarm + if ( syringeVol >= txVolume ) + { + syringeVolumeAdequate = TRUE; + } + else + { +#ifndef DISABLE_SYRINGE_PUMP_ALARMS + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_NOT_ENOUGH_HEPARIN_ALARM, syringeVol, txVolume ); +#endif + } } // Has syringe been removed? stopPump = checkSyringeRemoved( stopPump ); - // Check for occlusion - stopPump = checkOcclusionOrEmpty( stopPump ); + // Check max position > empty + 0.5 mL + stopPump = checkMaxTravel( stopPump, SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ); - // TODO - check max position > TBD + // Check pump direction + stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); - // TODO - calc estimate syringe volume - if insufficient for treatment needs, alarm - // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { @@ -1124,6 +1323,9 @@ // Check position > max travel stopPump = checkMaxTravel( stopPump, syringePumpVolumeStartPosition + ( SYRINGE_PUMP_PRIME_VOLUME_ML * TEN_PCT_OVER_ALLOWANCE * SYRINGE_ENCODER_COUNTS_PER_ML ) ); + // Check pump direction + stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); + // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { @@ -1171,6 +1373,9 @@ // Check position > max travel stopPump = checkMaxTravel( stopPump, syringePumpVolumeStartPosition + ( bolusVol * FIVE_PCT_OVER_ALLOWANCE * SYRINGE_ENCODER_COUNTS_PER_ML ) ); + // Check pump direction + stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); + // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { @@ -1203,7 +1408,7 @@ // Check for occlusion stopPump = checkOcclusionOrEmpty( stopPump ); - // Check position > max travel + // Check position > empty + 0.5 mL stopPump = checkMaxTravel( stopPump, SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ); // Check for commanded vs. meas. rate @@ -1212,6 +1417,9 @@ // Check volume vs. safety volume stopPump = checkVolumeVsSafetyVolume( stopPump, SYRINGE_PUMP_VOLUME_CHECK_MARGIN ); + // Check pump direction + stopPump = checkDirection( stopPump, MOTOR_DIR_FORWARD ); + // If anything found that would require stopping the pump, stop pump and go to off state if ( TRUE == stopPump ) { @@ -1226,18 +1434,18 @@ * @brief * The handleSyringePumpCalibrateForceSensorState function handles the * calibrate force sensor state of the syringe pump control state machine. - * of the pressure/occlusion monitor state machine. + * of the syringe pump control state machine. * @details Inputs: DAC status * @details Outputs: syringePumpDACVrefWriteInProgress, ADC read mode restored * @return next state *************************************************************************/ static SYRINGE_PUMP_STATE_T handleSyringePumpCalibrateForceSensorState( void ) { SYRINGE_PUMP_STATE_T result = SYRINGE_PUMP_CONFIG_FORCE_SENSOR_STATE; - U08 adcDACStatus= getFPGASyringePumpADCandDACStatus(); + U08 adcDACStatus= getSyringePumpADCandDACStatus(); // Wait for DAC setting write to EEPROM to complete - if ( ( getFPGASyringePumpADCandDACStatus() & SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_DAC_WR_DONE ) != 0 ) + if ( ( adcDACStatus & SYRINGE_PUMP_ADC_DAC_ERROR_COUNT_DAC_WR_DONE ) != 0 ) { syringePumpDACVrefWriteInProgress = FALSE; // Switch back from DAC to ADC control @@ -1248,14 +1456,44 @@ // Check DAC write error else if ( ( adcDACStatus & SYRINGE_PUMP_DAC_WRITE_ERROR_BIT ) != 0 ) { - // TODO - alarm + activateAlarmNoData( ALARM_ID_HD_SYRINGE_PUMP_DAC_WRITE_ERROR ); } return result; } /*********************************************************************//** * @brief + * The checkDirection function checks the measured direction of the syringe + * pump vs. the given expected direction. + * @details Inputs: syringePumpMeasForce.data, syringePumpPosition.data + * @details Outputs: alarm triggered if max force detected + * @param stopPump flag passed in by caller indicating whether pump should be stopped + * @param expDir expected direction of syringe pump + * @return TRUE if pump should be stopped, FALSE if not + *************************************************************************/ +static BOOL checkDirection( BOOL stopPump, MOTOR_DIR_T expDir ) +{ + BOOL result = stopPump; + +#ifndef DISABLE_SYRINGE_PUMP_ALARMS + 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 ); + } +#endif + + return result; +} + +/*********************************************************************//** + * @brief * The checkOcclusionOrEmpty function checks the force sensor for excessive * pressure. Would indicate occlusion or jam or empty syringe. * @details Inputs: syringePumpMeasForce.data, syringePumpPosition.data @@ -1268,7 +1506,7 @@ BOOL result = stopPump; F32 force = getSyringePumpForceV(); - if ( force >= SYRINGE_FORCE_OCCLUSION_THRESHOLD_V ) + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_OCCLUSION, ( force >= SYRINGE_FORCE_OCCLUSION_THRESHOLD_V ) ) ) { S32 pos = getSyringePumpPosition(); @@ -1326,7 +1564,7 @@ BOOL result = stopPump; S32 pos = getSyringePumpPosition(); - if ( pos > ( SYRINGE_PUMP_EMPTY_POS + SYRINGE_PUMP_EMPTY_POS_MARGIN ) ) + if ( pos > ( SYRINGE_PUMP_EMPTY_POS - SYRINGE_PUMP_EMPTY_POS_MARGIN ) ) { result = TRUE; heparinDeliveryState = HEPARIN_STATE_EMPTY; @@ -1335,6 +1573,10 @@ else if ( pos > maxPos ) { result = TRUE; + if ( syringePumpState != SYRINGE_PUMP_PRIME_STATE ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_OVER_TRAVEL_ERROR, (U32)pos, (U32)syringePumpState ); + } } return result; @@ -1359,13 +1601,14 @@ F32 delta = max - min; F32 error = ( max > 0.0 ? ( 1.0 - fabs( min / max ) ) : 0.0 ); +#ifndef DISABLE_SYRINGE_PUMP_ALARMS // Alarm on rate if off by more than 5% or 0.1 mL/hr, whichever is greater - if ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR ) ) + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, ( ( error > pctMargin ) && ( delta > SYRINGE_PUMP_MAX_RATE_ERROR_ML_HR ) ) ) ) { - // TODO - needs persistence -// result = TRUE; -// SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, syringePumpSetRate, rate ) + result = TRUE; + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_SYRINGE_PUMP_SPEED_ERROR, syringePumpSetRate, rate ) } +#endif return result; } @@ -1403,18 +1646,60 @@ /*********************************************************************//** * @brief + * The checkForStall function checks whether the syringe pump has stalled. + * If stall detected, the ramp up will be restarted up to 3 times. + * If cannot resolve the stall within 3 retries, a stall fault is triggered. + * @details Inputs: syringePumpMeasRate.data, syringePumpStallCtr, syringePumpStallRetryCount + * @details Outputs: syringePumpStallCtr, syringePumpStallRetryCount + * @param stopPump flag passed in by caller indicating whether pump should be stopped + * @return TRUE if pump should be stopped, FALSE if not +*************************************************************************/ +static BOOL checkForStall( BOOL stopPump ) +{ + BOOL result = stopPump; + + // Check for stall + if ( fabs( getSyringePumpMeasRate() ) < SYRINGE_PUMP_STALL_SPEED_THRESHOLD ) + { + if ( ++syringePumpStallCtr >= SYRINGE_PUMP_RAMP_STALL_TIME ) + { + if ( ++syringePumpStallRetryCount <= SYRINGE_PUMP_RAMP_STALL_RETRIES ) + { + syringePumpSetToggleTime++; // lower target rate (by increasing time between steps) + syringePumpRampTimerCtr = 0; // restart ramp + syringePumpRampUpToggleTime = SYRINGE_PUMP_START_RAMP_SPEED; + syringePumpStallCtr = 0; // reset stall counter + } + else + { + result = TRUE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SYRINGE_PUMP_STALL, (U32)getSyringePumpPosition(), (U32)syringePumpState ); + } + } + } + else + { + syringePumpStallCtr = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief * The rampSyringePump function handles the ramp-up for the syringe pump. * @details Inputs: syringePumpRampTimerCtr, syringePumpSetToggleTime * @details Outputs: syringePumpRampUpToggleTime * @return none *************************************************************************/ static void rampSyringePump( void ) { + // Ramp up syringe pump toward target speed syringePumpRampTimerCtr++; if ( syringePumpRampUpToggleTime > syringePumpSetToggleTime ) { syringePumpRampUpToggleTime = (U32)((F32)SYRINGE_PUMP_START_RAMP_SPEED / - (F32)( syringePumpRampTimerCtr * syringePumpRampTimerCtr * syringePumpRampTimerCtr / SYRINGE_PUMP_RAMP_DIVISOR )); + (F32)( ( syringePumpRampTimerCtr * syringePumpRampTimerCtr * syringePumpRampTimerCtr ) / SYRINGE_PUMP_RAMP_DIVISOR ) ); if ( syringePumpRampUpToggleTime > syringePumpSetToggleTime ) { setFPGASyringePumpStepToggleTime( syringePumpRampUpToggleTime ); @@ -1437,38 +1722,48 @@ *************************************************************************/ static void calcStepperToggleTimeForTargetRate( F32 rate ) { - F32 conv = 0.0; + double temp; + F32 conv; // Convert given rate to stepper toggle period - conv = rate * SYRINGE_MICRO_STEPS_PER_ML; // = uSteps/hr - conv /= (F32)( MIN_PER_HOUR * SEC_PER_MIN); // = uSteps/sec - conv /= MICRO_SECONDS_PER_SECOND; // = uSteps/uSec - conv *= SYRINGE_TOGGLES_PER_STEP; // = toggles/uSec + temp = (double)rate * SYRINGE_MICRO_STEPS_PER_ML; // = uSteps/hr + temp /= (double)( MIN_PER_HOUR * SEC_PER_MIN); // = uSteps/sec + temp /= MICRO_SECONDS_PER_SECOND; // = uSteps/uSec + conv = (F32)temp * SYRINGE_TOGGLES_PER_STEP; // = toggles/uSec conv = 1.0 / conv; // = uSec/toggle // Set stepper toggle time to calculated value syringePumpSetToggleTime = FLOAT_TO_INT_WITH_ROUND( conv ); // Set stepper ramp toggle time to initial ramp up speed initially syringePumpRampUpToggleTime = SYRINGE_PUMP_START_RAMP_SPEED; + // Reset ramp stall timer and retry counters + syringePumpStallCtr = 0; + syringePumpStallRetryCount = 0; } /*********************************************************************//** * @brief * The calcMeasRate function calculates the measured rate from a given delta - * position in last 10 ms. - * @details Inputs: syringePumpPosition1SecAgo, syringePumpSpeedCalcTimerCounter + * position in last 1 second. + * @details Inputs: syringePumpLastPositions[], syringePumpSpeedCalcTimerCounter * @details Outputs: syringePumpMeasRate, syringePumpSpeedCalcTimerCounter * @return none *************************************************************************/ static void calcMeasRate( void ) { - if ( ++syringePumpSpeedCalcTimerCounter > SYRINGE_PUMP_SPEED_CHECK_INTERVAL ) + if ( ++syringePumpSpeedCalcTimerCounter >= SYRINGE_PUMP_SPEED_CALC_INTERVAL ) { - S32 countsPerSec = syringePumpPosition.data - syringePumpPosition1SecAgo; + S32 pos = getSyringePumpPosition(); + U32 nextIdx = INC_WRAP( syringePumpMotorSpeedCalcIdx, 0, SYRINGE_PUMP_SPEED_CALC_BUFFER_LEN - 1 ); + S32 countsPerSec = pos - syringePumpLastPositions[ syringePumpMotorSpeedCalcIdx ]; // Calc delta between pos 1 second ago and pos now S32 countsPerHr = countsPerSec * ( MIN_PER_HOUR * SEC_PER_MIN); - F32 mLPerHr = (F32)countsPerHr / SYRINGE_ENCODER_COUNTS_PER_ML; + F32 mLPerHr = (F32)((double)countsPerHr / (double)SYRINGE_ENCODER_COUNTS_PER_ML); + // Set latest measured rate syringePumpMeasRate.data = mLPerHr; - syringePumpPosition1SecAgo = syringePumpPosition.data; + + // Update last position for next time + syringePumpLastPositions[ syringePumpMotorSpeedCalcIdx ] = pos; + syringePumpMotorSpeedCalcIdx = nextIdx; syringePumpSpeedCalcTimerCounter = 0; } } @@ -1511,31 +1806,18 @@ data.heparinDeliveryState = (U32)heparinDeliveryState; data.syringePumpVolumeDelivered = getSyringePumpVolumeDelivered(); data.syringePumpSafetyVolume = syringePumpSafetyVolumeDelivered; + data.syringePumpStatus = ( (U32)getSyringePumpStatus() << SHIFT_24_BITS ) | + ( (U32)getSyringePumpEncoderStatus() << SHIFT_16_BITS_FOR_WORD_SHIFT ) | + ( (U32)getSyringePumpADCandDACStatus() << SHIFT_8_BITS_FOR_BYTE_SHIFT ) | + ( (U32)getSyringePumpADCReadCounter() ); broadcastSyringePumpData( data ); broadcastHeparinData( data.syringePumpVolumeDelivered ); syringePumpDataPublicationTimerCounter = 0; } } -/*********************************************************************//** - * @brief - * The execSyringePumpTest function executes the state machine for the - * syringe pump self-test. - * @details Inputs: none - * @details Outputs: none - * @return the current state of the syringe pump self-test. - *************************************************************************/ -SELF_TEST_STATUS_T execSyringePumpTest( void ) -{ - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - // TODO - implement self-test(s) - - return result; -} - - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -1913,4 +2195,184 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetSyringePumpStatus function overrides the syringe pump + * status. + * @details Inputs: none + * @details Outputs: syringePumpStatus + * @param status override syringe pump status with this value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetSyringePumpStatus( U32 status ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpStatus.ovData = status; + syringePumpStatus.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetSyringePumpStatus function resets the override of the + * syringe pump status. + * @details Inputs: none + * @details Outputs: syringePumpStatus + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetSyringePumpStatus( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpStatus.override = OVERRIDE_RESET; + syringePumpStatus.ovData = syringePumpStatus.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetSyringePumpEncoderStatus function overrides the syringe + * pump encoder status. + * @details Inputs: none + * @details Outputs: syringePumpEncoderStatus + * @param status override syringe pump encoder status with this value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetSyringePumpEncoderStatus( U32 status ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpEncoderStatus.ovData = status; + syringePumpEncoderStatus.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetSyringePumpEncoderStatus function resets the override + * of the syringe pump encoder status. + * @details Inputs: none + * @details Outputs: syringePumpEncoderStatus + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetSyringePumpEncoderStatus( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpEncoderStatus.override = OVERRIDE_RESET; + syringePumpEncoderStatus.ovData = syringePumpEncoderStatus.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetSyringePumpADCandDACStatus function overrides the syringe + * pump ADC and DAC status. + * @details Inputs: none + * @details Outputs: syringePumpADCandDACStatus + * @param status override syringe pump ADC and DAC status with this value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetSyringePumpADCandDACStatus( U32 status ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpADCandDACStatus.ovData = status; + syringePumpADCandDACStatus.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetSyringePumpADCandDACStatus function resets the override + * of the syringe pump ADC and DAC status. + * @details Inputs: none + * @details Outputs: syringePumpADCandDACStatus + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetSyringePumpADCandDACStatus( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpADCandDACStatus.override = OVERRIDE_RESET; + syringePumpADCandDACStatus.ovData = syringePumpADCandDACStatus.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetSyringePumpADCReadCounter function overrides the syringe + * pump ADC read counter. + * @details Inputs: none + * @details Outputs: syringePumpADCReadCtr + * @param ctr override syringe pump ADC read counter with this value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetSyringePumpADCReadCounter( U32 ctr ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpADCReadCtr.ovData = ctr; + syringePumpADCReadCtr.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetSyringePumpADCReadCounter function resets the override + * of the syringe pump ADC read counter. + * @details Inputs: none + * @details Outputs: syringePumpADCReadCtr + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetSyringePumpADCReadCounter( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + syringePumpADCReadCtr.override = OVERRIDE_RESET; + syringePumpADCReadCtr.ovData = syringePumpADCReadCtr.ovInitData; + } + + return result; +} + /**@}*/ Index: firmware/App/Controllers/Valves.c =================================================================== diff -u -re5d1d67106a93a6cd1b5692b586625d715732e2f -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Controllers/Valves.c (.../Valves.c) (revision e5d1d67106a93a6cd1b5692b586625d715732e2f) +++ firmware/App/Controllers/Valves.c (.../Valves.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -1220,7 +1220,7 @@ static void publishValvesData( VALVE_T valve ) { // Check the counter - if ( ++valvesStatus[ valve ].dataPublishCounter > getPublishValvesDataInterval() ) + if ( ++valvesStatus[ valve ].dataPublishCounter >= getPublishValvesDataInterval() ) { HD_VALVE_DATA_T valveData; valveData.valveID = (U32)valve; Index: firmware/App/HDCommon.h =================================================================== diff -u -r84bb8663dae71170e1743a2bed37b0aa47465b47 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/HDCommon.h (.../HDCommon.h) (revision 84bb8663dae71170e1743a2bed37b0aa47465b47) +++ firmware/App/HDCommon.h (.../HDCommon.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -25,52 +25,61 @@ #define HD_VERSION_MAJOR 0 #define HD_VERSION_MINOR 5 #define HD_VERSION_MICRO 0 -#define HD_VERSION_BUILD 0 +#define HD_VERSION_BUILD 9037 // ********** development build switches ********** // TODO - remove build switches before release #ifndef _RELEASE_ #ifndef _VECTORCAST_ -// #define BOARD_WITH_NO_HARDWARE 1 +// #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 - #define DISABLE_AIR_TRAP_LEVELING 1 // Disable air trap level control + #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 USE_LIBRARY_TIME_FUNCTIONS 1 // Use the C library functions mktime() and gmtime() for epoch<=>date conversions + #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_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 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 DISABLE_PRESSURE_CHECKS 1 // Do not error on HD pressure checks +// #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_UF_ALARMS 1 // Do not error on HD ultrafiltration checks - #define DISABLE_VALVE_ALARMS 1 // Do not error on HD valve position - #define DISABLE_CAL_CHECK 1 +// #define DISABLE_VALVE_ALARMS 1 // Do not error on HD valve position + #define DISABLE_CAL_CHECK 1 // Disable calibration checks // #define RUN_PUMPS_OPEN_LOOP 1 // BP and DPi pumps will be run open loop (no flow sensor feedback) // #define RAW_FLOW_SENSOR_DATA 1 // Test build will not filter flow sensor data // #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 TEMP_UI_ALARM_SILENCE_FIX 1 // Temporary UI fix for handling alarm silence request msg #define SKIP_PRIMING 1 // Skip Pre-treatment Prime #define SKIP_WET_SELF_TESTS 1 // Skip Pre-treatment prime wet self-tests -// #define V1_5_SYSTEM 1 // Build for v1.5 system +// #define V2_0_SYSTEM 1 // Build for v2.0 system #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_UI_INTERACTION 1 // Skip UI interaction. #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 SKIP_CARTRIDGE_REMOVAL 1 // Skip cartridge removal check #define SKIP_EMPTY_RES_CHECK 1 // Skip reservoir empty 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 #include #include Index: firmware/App/Modes/BloodPrime.c =================================================================== diff -u -rea0047d0cb48b899475cf519e7e4997d96f5e538 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision ea0047d0cb48b899475cf519e7e4997d96f5e538) +++ firmware/App/Modes/BloodPrime.c (.../BloodPrime.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -39,10 +39,13 @@ // TODO - get from Systems when available #define TARGET_BLOOD_PRIME_VOLUME_ML 300.0 ///< Target blood prime volume to prime the blood side circuit (in mL). #define MIN_RAMP_TIME_SEC 60 ///< Minimum ramp time for blood prime (in seconds). + +#ifndef DISABLE_PUMP_FLOW_CHECKS /// Maximum blood prime volume measured by independent means (as % of target). static const F32 MAX_BLOOD_PRIME_SAFETY_VOLUME_ML = ( TARGET_BLOOD_PRIME_VOLUME_ML * 1.2 ); /// Minimum blood prime volume measured by independent means (as % of target). static const F32 MIN_BLOOD_PRIME_SAFETY_VOLUME_ML = ( TARGET_BLOOD_PRIME_VOLUME_ML * 0.8 ); +#endif /// Initial flow rate for blood pump when starting blood prime operation. #define BLOOD_PRIME_INIT_BP_FLOW_RATE_ML_MIN 100 Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -r40e0116bbada6d1780bfa832a9c4684ba9fcfcc8 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 40e0116bbada6d1780bfa832a9c4684ba9fcfcc8) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -62,6 +62,8 @@ static F32 measUFVolume; ///< Current total measured volume for ultrafiltration (Where are we w/r/t ultrafiltration). static F32 resStartVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir start volume for ultrafiltration (i.e. where did we start with each reservoir). static F32 resFinalVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir final volume for ultrafiltration (i.e. where did we end after switch with each reservoir). +static F32 resCurrVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir current volume. +static F32 resLastVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir previous volume. static F32 measUFVolumeFromPriorReservoirs; ///< Current total ultrafiltration volume from previous reservoirs in current treatment. static U32 uFTimeMS; ///< Current elapsed ultrafiltration time (in ms). Used for calculating UF reference volume. @@ -75,7 +77,7 @@ static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. static BOOL salineBolusStartRequested; ///< Flag indicates a saline bolus start has been requested by user. static BOOL salineBolusAbortRequested; ///< Flag indicates a salien bolus abort has been requested by user. -static BOOL salineBolusAutoResumeUF; ///< Flag indicates UF should be auto-resumed after saline bolus completes. +static BOOL salineBolusAutoResumeUF = FALSE; ///< Flag indicates UF should be auto-resumed after saline bolus completes. static F32 totalSalineVolumeDelivered; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). static F32 bolusSalineVolumeDelivered; ///< Volume (mL) of current bolus delivered so far. static F32 bolusSalineVolumeDelivered_Safety; ///< Volume (mL) of current bolus delivered so far according to safety monitor. @@ -125,6 +127,8 @@ refUFVolume = 0.0; measUFVolume = 0.0; measUFVolumeFromPriorReservoirs = 0.0; + // Send reset UF volumes to dialysate outlet pump + setDialOutUFVolumes( refUFVolume, measUFVolume ); uFTimeMS = 0; lastUFTimeStamp = 0; @@ -156,14 +160,18 @@ { salineBolusStartRequested = FALSE; salineBolusAbortRequested = FALSE; - salineBolusAutoResumeUF = FALSE; bolusSalineVolumeDelivered = 0.0; bolusSalineVolumeDelivered_Safety = 0.0; bolusSalineMotorCount = 0; if ( currentSalineBolusState != SALINE_BOLUS_STATE_MAX_DELIVERED ) { currentSalineBolusState = SALINE_BOLUS_STATE_IDLE; } + if ( TRUE == salineBolusAutoResumeUF ) + { + salineBolusAutoResumeUF = FALSE; + currentUFState = UF_RUNNING_STATE; + } } /*********************************************************************//** @@ -226,12 +234,12 @@ { HEPARIN_STATE_T currentHeparinState = getHeparinState(); U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); - U32 minRem = getTreatmentTimeRemainingSecs() / SEC_PER_MIN; + F32 minRem = (F32)getTreatmentTimeRemainingSecs() / (F32)SEC_PER_MIN; F32 bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); F32 hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_DISPENSE_RATE ); // Do not run syringe pump if no Heparin included in prescription or it was paused or if Heparin should be stopped at this stage of treatment - if ( ( minRem > preStop ) && ( HEPARIN_STATE_STOPPED == currentHeparinState ) ) + if ( ( minRem > (F32)preStop ) && ( HEPARIN_STATE_STOPPED == currentHeparinState ) ) { // If not done with bolus, start/resume bolus if ( ( bolusVol > 0.0 ) && ( getSyringePumpVolumeDelivered() < bolusVol ) ) @@ -241,7 +249,14 @@ // Otherwise, start/resume continuous delivery else { - startHeparinContinuous(); // TODO - check return status + if ( hepRate > 0.0 ) + { + startHeparinContinuous(); // TODO - check return status + } + else + { + setHeparinCompleted(); + } } } else @@ -329,14 +344,14 @@ { rejReason = REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE; } - else if ( currSalineBolusState != SALINE_BOLUS_STATE_IDLE ) - { - rejReason = REQUEST_REJECT_REASON_SALINE_BOLUS_IN_PROGRESS; - } else if ( totalSalineVolumeDelivered >= (F32)MAX_SALINE_VOLUME_DELIVERED ) { rejReason = REQUEST_REJECT_REASON_SALINE_MAX_VOLUME_REACHED; } + else if ( currSalineBolusState != SALINE_BOLUS_STATE_IDLE ) + { + rejReason = REQUEST_REJECT_REASON_SALINE_BOLUS_IN_PROGRESS; + } else { accept = TRUE; @@ -612,10 +627,10 @@ { DIALYSIS_STATE_T result = DIALYSIS_UF_STATE; U32 preStop = getTreatmentParameterU32( TREATMENT_PARAM_HEPARIN_PRE_STOP_TIME ); - U32 minRem = getTreatmentTimeRemainingSecs() / SEC_PER_MIN; + F32 minRem = (F32)getTreatmentTimeRemainingSecs() / (F32)SEC_PER_MIN; // Stop Heparin delivery if we have reached Heparin pre-stop point - if ( getTreatmentTimeRemainingSecs() < preStop ) + if ( minRem <= (F32)preStop ) { stopSyringePump(); setHeparinCompleted(); @@ -1063,7 +1078,7 @@ LOAD_CELL_ID_T loadCell = ( activeRes == DG_RESERVOIR_1 ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); F32 latestResVolume = getLoadCellWeight( loadCell ); #ifndef DISABLE_UF_ALARMS - F32 deltaVolume = latestResVolume - resFinalVolume[ activeRes ]; + 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 ) @@ -1137,4 +1152,22 @@ measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); } +/*********************************************************************//** + * @brief + * The updateReservoirVolumes function updates the reservoir volumes based + * on new load cell readings. + * @details Inputs: none + * @details Outputs: resCurrVolume[], resLastVolume[] + * @param res1Vol new volume for reservoir 1 + * @param res2Vol new volume for reservoir 2 + * @return none + *************************************************************************/ +void updateReservoirVolumes( F32 res1Vol, F32 res2Vol ) +{ + resLastVolume[ DG_RESERVOIR_1 ] = resCurrVolume[ DG_RESERVOIR_1 ]; + resLastVolume[ DG_RESERVOIR_2 ] = resCurrVolume[ DG_RESERVOIR_2 ]; + resCurrVolume[ DG_RESERVOIR_1 ] = res1Vol; + resCurrVolume[ DG_RESERVOIR_2 ] = res2Vol; +} + /**@}*/ Index: firmware/App/Modes/Dialysis.h =================================================================== diff -u -r40e0116bbada6d1780bfa832a9c4684ba9fcfcc8 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision 40e0116bbada6d1780bfa832a9c4684ba9fcfcc8) +++ firmware/App/Modes/Dialysis.h (.../Dialysis.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -74,6 +74,7 @@ void setStartReservoirVolume( DG_RESERVOIR_ID_T reservoirID ); void signalReservoirsSwitched( void ); void setFinalReservoirVolume( void ); +void updateReservoirVolumes( F32 res1Vol, F32 res2Vol ); /**@}*/ Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r161dc3734f29dcd986683008a01c30114279698b -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 161dc3734f29dcd986683008a01c30114279698b) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -19,16 +19,19 @@ #include "AlarmLamp.h" #include "BloodFlow.h" #include "Buttons.h" +#include "Compatible.h" #include "CPLD.h" #include "DialInFlow.h" #include "FPGA.h" #include "Integrity.h" -#include "OperationModes.h" -#include "RTC.h" -#include "WatchdogMgmt.h" #include "ModeInitPOST.h" #include "NVDataMgmt.h" +#include "OperationModes.h" +#include "RTC.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" #include "Valves.h" +#include "WatchdogMgmt.h" /** * @addtogroup HDInitAndPOSTMode @@ -37,16 +40,26 @@ // ********** private definitions ********** +/// Delay (in task intervals) after POST completes. +#define POST_COMPLETED_DELAY ( 2 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) + + // ********** private data ********** -static HD_POST_STATE_T postState = POST_STATE_START; ///< Current state of initialize and POST mode. -static BOOL postCompleted = FALSE; ///< Flag indicates whether POST is completed. -static BOOL postPassed = FALSE; ///< Flag indicates all POST tests passed. -static BOOL tempPOSTPassed = TRUE; ///< Flag indicates all POST tests have passed so far. +static HD_POST_STATE_T postState; ///< Current state of initialize and POST mode. +static BOOL postCompleted; ///< Flag indicates whether POST is completed. +static BOOL postPassed; ///< Flag indicates all POST tests passed. +static BOOL tempPOSTPassed; ///< Flag indicates all POST tests have passed so far. +static BOOL uiPOSTPassed; ///< Final result for UI POST tests (TRUE = passed, FALSE = failed). +static BOOL dgPOSTPassed; ///< Final result for DG POST tests (TRUE = passed, FALSE = failed). + +static U32 postCompleteDelayTimerCtr; ///< Timer counter for 2 second delay after POST completes and before transitioning to Standbymode. + // ********** private function prototypes ********** static HD_POST_STATE_T handlePOSTStatus( SELF_TEST_STATUS_T testStatus ); +static SELF_TEST_STATUS_T execFWCompatibilityTest( void ); /*********************************************************************//** * @brief @@ -61,6 +74,9 @@ postCompleted = FALSE; postPassed = FALSE; tempPOSTPassed = TRUE; + uiPOSTPassed = FALSE; + dgPOSTPassed = FALSE; + postCompleteDelayTimerCtr = 0; } /*********************************************************************//** @@ -102,7 +118,7 @@ switch ( postState ) { case POST_STATE_START: - postState = POST_STATE_FW_INTEGRITY; + postState = POST_STATE_FW_COMPATIBILITY; #ifdef SKIP_POST postState = POST_STATE_COMPLETED; #endif @@ -112,6 +128,11 @@ #endif break; + case POST_STATE_FW_COMPATIBILITY: + testStatus = execFWCompatibilityTest(); + postState = handlePOSTStatus( testStatus ); + break; + case POST_STATE_FW_INTEGRITY: testStatus = execIntegrityTest(); postState = handlePOSTStatus( testStatus ); @@ -122,11 +143,6 @@ postState = handlePOSTStatus( testStatus ); break; - case POST_STATE_FPGA: - testStatus = execFPGATest(); - postState = handlePOSTStatus( testStatus ); - break; - case POST_STATE_RTC: testStatus = execRTCSelfTest(); postState = handlePOSTStatus( testStatus ); @@ -152,6 +168,11 @@ postState = handlePOSTStatus( testStatus ); break; + case POST_STATE_ALARM_AUDIO: + testStatus = execAlarmAudioSelfTest(); + postState = handlePOSTStatus( testStatus ); + break; + case POST_STATE_ALARM_LAMP: #ifdef DONT_SKIP_NV_POST // Skip the rest of the POSTs @@ -171,9 +192,14 @@ postState = handlePOSTStatus( testStatus ); break; - // Should be last POST case POST_STATE_STUCK_BUTTON: testStatus = execStuckButtonTest(); + postState = handlePOSTStatus( testStatus ); + break; + + // Should be last POST (and last POST test must be a test that completes in a single call) + case POST_STATE_FPGA: + testStatus = execFPGATest(); handlePOSTStatus( testStatus ); // Ignoring return value because last test if ( TRUE == tempPOSTPassed ) @@ -186,14 +212,20 @@ } break; + // TODO - add POST test requiring all DG and UI POST tests to pass + case POST_STATE_COMPLETED: // Set overall HD POST status to "passed" postPassed = TRUE; // Set overall HD POST completed status to TRUE postCompleted = TRUE; - // TODO - send POST status on CAN - // Go to standby mode - requestNewOperationMode( MODE_STAN ); + // Broadcast final POST passed + sendPOSTFinalResult( TRUE ); + // Delay before going to standby mode + if ( ++postCompleteDelayTimerCtr > POST_COMPLETED_DELAY ) + { + requestNewOperationMode( MODE_STAN ); + } break; case POST_STATE_FAILED: @@ -217,11 +249,39 @@ *************************************************************************/ void signalAlarmActionToInitAndPOSTMode( ALARM_ACTION_T action ) { + // TODO - anything required here? +} +/*********************************************************************//** + * @brief + * The signalUIPOSTFinalResult function records the final POST result for + * the UI. + * @details Inputs: none + * @details Outputs: uiPOSTPassed + * @param passed TRUE if UI POST tests all passed, FALSE if any UI POST test failed + * @return none + *************************************************************************/ +void signalUIPOSTFinalResult( BOOL passed ) +{ + uiPOSTPassed = passed; } /*********************************************************************//** * @brief + * The signalDGPOSTFinalResult function records the final POST result for + * the DG. + * @details Inputs: none + * @details Outputs: dgPOSTPassed + * @param passed TRUE if DG POST tests all passed, FALSE if any DG POST test failed + * @return none + *************************************************************************/ +void signalDGPOSTFinalResult( BOOL passed ) +{ + dgPOSTPassed = passed; +} + +/*********************************************************************//** + * @brief * The isPOSTCompleted function determines whether all HD POST have * been run and completed. If true, call the isPOSTPassed() to see final * result (pass/fail). @@ -262,12 +322,19 @@ if ( testStatus == SELF_TEST_STATUS_PASSED ) { - result = (HD_POST_STATE_T)((int)postState + 1); // Move on to next POST test + // Broadcast passed POST result + sendPOSTTestResult( (HD_POST_STATE_T)((int)postState), TRUE ); + // Move on to next POST test + result = (HD_POST_STATE_T)((int)postState + 1); } else if ( testStatus == SELF_TEST_STATUS_FAILED ) { - requestAlarmLampPattern( LAMP_PATTERN_FAULT ); + // At least one POST has failed tempPOSTPassed = FALSE; + // Broadcast failed POST results + sendPOSTTestResult( (HD_POST_STATE_T)((int)postState), FALSE ); + sendPOSTFinalResult( FALSE ); + // Test that failed should have triggered a fault which will request fault mode, so should POST state machine should never see FAILED state and will fault if it does result = POST_STATE_FAILED; } else @@ -277,3 +344,21 @@ return result; } + +/*********************************************************************//** + * @brief + * The execFWCompatibilityTest function executes the firmware compatibility test. + * @details Inputs: none + * @details Outputs: none + * @return in progress, passed, or failed + *************************************************************************/ +static SELF_TEST_STATUS_T execFWCompatibilityTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + + // TODO - implement + + return result; +} + +/**@}*/ Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r340ca3700bbc4235d85d82864597fe17ab4b557a -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 340ca3700bbc4235d85d82864597fe17ab4b557a) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -136,8 +136,7 @@ break; default: - // TODO - s/w fault - currentStandbyState = STANDBY_START_STATE; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_STANDBY_INVALID_STATE, currentStandbyState ); break; } #else @@ -225,7 +224,7 @@ break; default: - // TODO - s/w fault + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_MODE_STANDBY_INVALID_STATE, currentStandbyState ); currentStandbyState = STANDBY_START_STATE; break; } @@ -323,22 +322,34 @@ BOOL signalUserInitiateTreatment( void ) { BOOL result = FALSE; - REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NOT_ALLOWED_IN_CURRENT_MODE; + REQUEST_REJECT_REASON_CODE_T rejReason = REQUEST_REJECT_REASON_NONE; - if ( ( MODE_STAN == getCurrentOperationMode() ) && ( STANDBY_WAIT_FOR_TREATMENT_STATE == currentStandbyState ) ) + if ( TRUE == getNoNewTreatmentStatus() ) { - if ( TRUE == isDGCommunicating() ) - { - treatStartReqReceived = TRUE; - result = TRUE; - rejReason = REQUEST_REJECT_REASON_NONE; - } - else - { - rejReason = REQUEST_REJECT_REASON_DG_COMM_LOST; - } + 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; + } + + if ( TRUE != isDGCommunicating() ) + { + rejReason = REQUEST_REJECT_REASON_DG_COMM_LOST; + } + + if ( ( DG_MODE_STAN != getDGOpMode() ) || ( DG_STANDBY_MODE_STATE_IDLE != getDGSubMode() ) ) + { + rejReason = REQUEST_REJECT_REASON_DG_NOT_IN_STANDBY_IDLE_STATE; + } + + if ( REQUEST_REJECT_REASON_NONE == rejReason ) + { + result = TRUE; + treatStartReqReceived = TRUE; + } + sendInitiateTreatmentResponseMsg( result, rejReason ); return result; Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r40e0116bbada6d1780bfa832a9c4684ba9fcfcc8 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 40e0116bbada6d1780bfa832a9c4684ba9fcfcc8) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -45,9 +45,11 @@ // ********** 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). -#define MAX_UF_RATE_ML_MIN ( (F32)2500 / (F32)MIN_PER_HOUR ) ///< Maximum ultrafiltration rate (in mL/min). -#define MAX_UF_VOLUME_ML ( 8 * ML_PER_LITER ) ///< Maximum ultrafiltration volume (in mL). +#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. @@ -139,7 +141,7 @@ bloodIsPrimed = FALSE; treatmentCompleted = FALSE; - rinsebackDone = TRUE; + rinsebackDone = FALSE; treatmentTimeMS = 0; lastTreatmentTimeStamp = 0; @@ -661,6 +663,7 @@ // Otherwise execute state machine for treatment stop sub-mode else { + execTreatmentReservoirMgmt(); execTreatmentStop(); } Index: firmware/App/Modes/Rinseback.c =================================================================== diff -u -rb5accb82ac043938255883b6c60a6f81795569b0 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision b5accb82ac043938255883b6c60a6f81795569b0) +++ firmware/App/Modes/Rinseback.c (.../Rinseback.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -43,10 +43,13 @@ #define RINSEBACK_FLOW_RATE_ADJ_ML_MIN 25 ///< Adjustment amount (in mL/min) to apply when user requests increase/decrease in flow rate. #define MIN_RINSEBACK_FLOW_RATE_ML_MIN 50 ///< Minimum rinseback flow rate (in mL/min). #define MAX_RINSEBACK_FLOW_RATE_ML_MIN 150 ///< Maximum rinseback flow rate (in mL/min). + +#ifndef DISABLE_PUMP_FLOW_CHECKS /// Maximum rinseback volume measured by independent means (as % of target). static const F32 MAX_RINSEBACK_SAFETY_VOLUME_ML = ( TARGET_RINSEBACK_VOLUME_ML * 1.2 ); /// Minimum rinseback volume measured by independent means (as % of target). static const F32 MIN_RINSEBACK_SAFETY_VOLUME_ML = ( TARGET_RINSEBACK_VOLUME_ML * 0.8 ); +#endif /// Interval at which rinseback progress is to be published to UI. static const U32 RINSEBACK_DATA_PUBLISH_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -re63c54262fd4ccd8ffd9ef9bb49e66458893528f -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision e63c54262fd4ccd8ffd9ef9bb49e66458893528f) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -18,6 +18,7 @@ #include "AirTrap.h" #include "BloodFlow.h" #include "BloodLeak.h" +#include "Bubble.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" @@ -74,6 +75,7 @@ { 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. @@ -137,6 +139,7 @@ static WET_SELF_TESTS_STATE_T handleWetSelfTestStartState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestSetupState( void ); +static WET_SELF_TESTS_STATE_T handleWetSelfTestBubblesState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestPrimeCheckState( SELF_TEST_STATUS_T *result ); static WET_SELF_TESTS_STATE_T handleWetSelfTestBloodLeakDetectorState( void ); static WET_SELF_TESTS_STATE_T handleWetSelfTestFirstDisplacementSetupState( void ); @@ -212,10 +215,10 @@ void transitionToNoCartSelfTests( void ) { F32 const bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); - F32 const hepRate = 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 ) ); + useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ? TRUE : FALSE ); #else useHeparin = FALSE; #endif @@ -341,14 +344,6 @@ *************************************************************************/ void transitionToDrySelfTests() { - F32 const bolusVol = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); - F32 const hepRate = getTreatmentParameterF32( TREATMENT_PARAM_HEPARIN_BOLUS_VOLUME ); - -#ifndef DISABLE_SYRINGE_PUMP - useHeparin = ( ( bolusVol > 0.0 ) || ( hepRate > 0.0 ) ); -#else - useHeparin = FALSE; -#endif currentDrySelfTestsState = DRY_SELF_TESTS_START_STATE; pressureSelfTestBloodPumpRunStartTime = 0; pressureSelfTestNormalizedStartTime = 0; @@ -513,6 +508,10 @@ currentWetSelfTestsState = handleWetSelfTestSetupState(); break; + case WET_SELF_TESTS_BUBBLES_STATE: + currentWetSelfTestsState = handleWetSelfTestBubblesState(); + break; + case WET_SELF_TESTS_PRIME_CHECK_STATE: currentWetSelfTestsState = handleWetSelfTestPrimeCheckState( &result ); break; @@ -650,7 +649,7 @@ if ( TRUE == useHeparin ) { - if ( ( FALSE == isSyringePumpHome() ) && ( TRUE == isSyringePumpStopped() ) ) + if ( TRUE == isSyringePumpStopped() ) { retractSyringePump(); } @@ -800,11 +799,10 @@ { DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_USED_CARTRIDGE_CHECK_STATE; - // TODO: Use appropriate sensor driver - BOOL const isADADetectedAir = getFPGAArterialAirBubbleStatus(); - BOOL const isADVDetectedAir = getFPGAVenousAirBubbleStatus(); + BUBBLE_STATUS_T const ADABubbleStatus = getBubbleStatus( ADA ); + BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); - if ( ( TRUE == isADADetectedAir ) && ( TRUE == isADVDetectedAir ) && + if ( ( BUBBLE_DETECTED == ADABubbleStatus ) && ( BUBBLE_DETECTED == ADVBubbleStatus ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) && ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) ) { @@ -1078,6 +1076,34 @@ if ( setupDisplacementVolume <= 0 ) { signalDialInPumpHardStop(); + selfTestBubble( ADA ); + selfTestBubble( ADV ); + state = WET_SELF_TESTS_BUBBLES_STATE; + } + + if ( TRUE == doesAlarmStatusIndicateStop() ) + { + state = WET_SELF_TESTS_STOPPED_STATE; + setupForSelfTestsStop(); + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleWetSelfTestBubblesState function waiting for air bubble detectors + * self-tests to finish. + * @details Inputs: bubbleSelfTestStatus + * @details Outputs: none + * @return the next state of wet self-tests state machine + *************************************************************************/ +static WET_SELF_TESTS_STATE_T handleWetSelfTestBubblesState( void ) +{ + WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_BUBBLES_STATE; + + if ( ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADA ) ) && ( SELF_TEST_STATUS_PASSED == getBubbleSelfTestStatus( ADV ) ) ) + { state = WET_SELF_TESTS_PRIME_CHECK_STATE; } @@ -1104,12 +1130,11 @@ WET_SELF_TESTS_STATE_T state = WET_SELF_TESTS_PRIME_CHECK_STATE; *result = SELF_TEST_STATUS_FAILED; - // TODO: Use appropriate sensor driver - BOOL const isADADetectedAir = getFPGAArterialAirBubbleStatus(); - BOOL const isADVDetectedAir = getFPGAVenousAirBubbleStatus(); + BUBBLE_STATUS_T const ADABubbleStatus = getBubbleStatus( ADA ); + BUBBLE_STATUS_T const ADVBubbleStatus = getBubbleStatus( ADV ); #ifndef SKIP_AIR_BUBBLE_CHECK - if ( ( FALSE == isADADetectedAir ) && ( FALSE == isADVDetectedAir ) ) + if ( ( BUBBLE_NOT_DETECTED == ADABubbleStatus ) && ( BUBBLE_NOT_DETECTED == ADVBubbleStatus ) ) #endif { zeroBloodLeak(); @@ -1128,7 +1153,7 @@ /*********************************************************************//** * @brief - * The handleWetSelfTestBloodLeakDetectorState function handles zeoring and + * The handleWetSelfTestBloodLeakDetectorState function handles zeroing and * self-test for blood leak detector. * @details Inputs: none * @details Outputs: next self-test state Index: firmware/App/Modes/TreatmentEnd.c =================================================================== diff -u -rd3e396a8b52d79faa3b408e7533320d8f8cb76c0 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Modes/TreatmentEnd.c (.../TreatmentEnd.c) (revision d3e396a8b52d79faa3b408e7533320d8f8cb76c0) +++ firmware/App/Modes/TreatmentEnd.c (.../TreatmentEnd.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -223,6 +223,11 @@ setupForTxEndPausedState(); result = TREATMENT_END_PAUSED_STATE; } + // Is treatment end requested? + else if ( TRUE == txEndAlarmEndTreatmentRequested ) + { + signalEndTreatment(); + } // Is final rinseback requested? else if ( ( TRUE == txEndRinsebackRequested ) || ( TRUE == txEndAlarmRinsebackRequested ) ) { Index: firmware/App/Services/AlarmMgmt.c =================================================================== diff -u -r8ec997d92b561aa3763f751302693bd432540f3e -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 8ec997d92b561aa3763f751302693bd432540f3e) +++ firmware/App/Services/AlarmMgmt.c (.../AlarmMgmt.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -20,8 +20,10 @@ #define __ALARM_MGMT_C__ #include "AlarmLamp.h" -#include "FPGA.h" +#include "FPGA.h" +#include "InternalADC.h" #include "OperationModes.h" +#include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "Timers.h" @@ -35,6 +37,8 @@ /// Interval to control lamp and audio and to publish alarm status data. static const U32 ALARM_STATUS_PUBLISH_INTERVAL = ( ALARM_LAMP_AND_AUDIO_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ); +/// Interval (ms/task time) at which the alarm information is published on the CAN bus. +#define ALARM_INFO_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) #define ALARM_SILENCE_EXPIRES_IN_SECS (60) ///< Alarm silence expiration time in seconds. @@ -49,12 +53,16 @@ /// A blank alarm data record for alarms that do not include alarm data when triggered. const ALARM_DATA_T BLANK_ALARM_DATA = { ALARM_DATA_TYPE_NONE, 0 }; -// Pin assignment for backup alarm audio enable -#define BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK 0x00000001 ///< Pin SPI3-CS0 - re-purposed as output GPIO for back audio enable. +/// Pin SPI3-CS0 - re-purposed as output GPIO for backup alarm audio enable. +#define BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK 0x00000001 // Backup alarm audio enable/disable macros #define SET_BACKUP_AUDIO_ENABLE() {mibspiREG3->PC3 |= BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK;} ///< Macro to enable backup alarm audio. #define CLR_BACKUP_AUDIO_ENABLE() {mibspiREG3->PC3 &= ~BACKUP_AUDIO_ENABLE_SPI3_PORT_MASK;} ///< Macro to disable backup alarm audio. +#define ALARM_AUDIO_TEST_TONE 4 ///< Alarm audio state for continuous test tone. +#define ALARM_AUDIO_CURRENT_HG_MIN_MA 10.0 ///< Minimum audio current (high gain) during test tone self-test (in mA). +#define ALARM_AUDIO_CURRENT_LG_MIN_MA 10.0 ///< Minimum audio current (low gain) during test tone self-test (in mA). + /// Alarm priority ranking record. typedef struct { @@ -68,19 +76,37 @@ static BOOL alarmIsActive[ NUM_OF_ALARM_IDS ]; ///< Table - current state of each alarm static BOOL alarmIsDetected[ NUM_OF_ALARM_IDS ]; ///< Table - current state of each alarm condition (detected or cleared) static OVERRIDE_U32_T alarmStartedAt[ NUM_OF_ALARM_IDS ]; ///< Table - when alarm became active for each alarm (if active) or zero (if inactive) +static U32 alarmStatusPublicationTimerCounter = 0; ///< Used to schedule alarm status publication to CAN bus. +static U32 alarmInfoPublicationTimerCounter = 0; ///< Used to schedule alarm information publication to CAN bus. + +/// 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 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. static BOOL alarmUserRecoveryActionEnabled[ NUMBER_OF_ALARM_USER_ACTIONS ]; ///< Alarm user recovery actions enabled flags. -static U32 alarmAudioVolumeLevel = 3; //MIN_ALARM_VOLUME_ATTENUATION; ///< Set alarm audio volume attenuation level (0..4 - lower level = higher gain). -static U32 alarmStatusPublicationTimerCounter = 0; ///< Used to schedule alarm status publication to CAN bus. - +/// Flag indicates whether alarm audio test tone should be output. +static BOOL alarmAudioTestToneRequested; + // ********** private function prototypes ********** static void activateAlarm( ALARM_ID_T alarm ); - + +static void monitorAlarms( void ); static void updateAlarmsState( void ); static void setAlarmLamp( void ); static void setAlarmAudio( void ); @@ -92,6 +118,9 @@ static void resetAlarmPriorityFIFO( ALARM_PRIORITY_T priority ); static U32 getAlarmStartTime( ALARM_ID_T alarmID ); + +static void publishAlarmInfo( void ); +static U32 getPublishAlarmInfoInterval( void ); /*********************************************************************//** * @brief @@ -132,7 +161,7 @@ alarmStatus.alarmsSilenceExpiresIn = 0; alarmStatus.alarmsEscalatesIn = 0; alarmStatus.alarmTop = ALARM_ID_NO_ALARM; - alarmStatus.topAlarmConditionnDetected = FALSE; + alarmStatus.topAlarmConditionDetected = FALSE; alarmStatus.systemFault = FALSE; alarmStatus.stop = FALSE; alarmStatus.lampOn = FALSE; @@ -143,6 +172,8 @@ alarmStatus.noNewTreatment = FALSE; alarmStatus.noDialRecirc = FALSE; alarmStatus.usrACKRequired = FALSE; + + alarmAudioTestToneRequested = FALSE; } /*********************************************************************//** @@ -156,6 +187,7 @@ *************************************************************************/ void execAlarmMgmt( void ) { + monitorAlarms(); handleAlarmEscalations(); updateAlarmsState(); updateAlarmsFlags(); @@ -557,10 +589,21 @@ *************************************************************************/ void setAlarmAudioVolume( U32 volumeLevel ) { + BOOL accepted = FALSE; + U32 rejReason = REQUEST_REJECT_REASON_NONE; + if ( ( volumeLevel > 0 ) && ( volumeLevel <= MAX_ALARM_VOLUME_LEVEL ) ) { // Convert volume level to attenuation level - alarmAudioVolumeLevel = MAX_ALARM_VOLUME_LEVEL - volumeLevel; + alarmAudioVolumeLevel.data = MAX_ALARM_VOLUME_LEVEL - volumeLevel; + accepted = TRUE; } + else + { + rejReason = REQUEST_REJECT_REASON_PARAM_OUT_OF_RANGE; + } + + // Send response to UI + sendAlarmAudioVolumeSetResponse( accepted, rejReason ); } /*********************************************************************//** @@ -643,6 +686,27 @@ return result; } + +/*********************************************************************//** + * @brief + * The monitorAlarms function monitors alarm audio current. + * @details Inputs: alarmStatusTable[] + * @details Outputs: alarmPriorityFIFO[], alarmStatus + * @return none + *************************************************************************/ +static void monitorAlarms( void ) +{ + U32 volume = getAlarmAudioVolume(); + + alarmPrimaryAudioCurrentHG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); + alarmPrimaryAudioCurrentLG.data = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); + alarmBackupAudioCurrent.data = getIntADCVoltageConverted( INT_ADC_BACKUP_ALARM_CURRENT ); + + // TODO - Check current vs. expected audio output + + // Publish alarm information at interval + publishAlarmInfo(); +} /*********************************************************************//** * @brief @@ -706,7 +770,8 @@ // Update alarm to display per highest priority FIFO alarmStatus.alarmsState = highestPriority; - alarmStatus.alarmTop = alarmPriorityFIFO[ highestPriority ].alarmID; + alarmStatus.alarmTop = alarmPriorityFIFO[ highestPriority ].alarmID; + alarmStatus.topAlarmConditionDetected = alarmIsDetected[ alarmStatus.alarmTop ]; alarmStatus.systemFault = faultsActive; alarmStatus.noDialRecirc = dialysateRecircBlocked; } @@ -780,22 +845,29 @@ *************************************************************************/ static void setAlarmAudio( void ) { - if ( TRUE == alarmStatus.alarmsSilenced ) + U32 volume = getAlarmAudioVolume(); + + if ( TRUE == alarmAudioTestToneRequested ) + { // Play test tone at max volume for next 50 ms + setAlarmAudioState( ALARM_AUDIO_TEST_TONE, 0 ); + alarmAudioTestToneRequested = FALSE; + } + else if ( TRUE == alarmStatus.alarmsSilenced ) { - setAlarmAudioState( ALARM_PRIORITY_NONE, alarmAudioVolumeLevel ); + setAlarmAudioState( ALARM_PRIORITY_NONE, volume ); } - else // Alarms not silenced + else { if ( alarmStatus.alarmsState < NUM_OF_ALARM_PRIORITIES ) { #ifndef DISABLE_ALARM_AUDIO - setAlarmAudioState( alarmStatus.alarmsState, alarmAudioVolumeLevel ); + setAlarmAudioState( alarmStatus.alarmsState, volume ); #endif } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_AUDIO_INVALID_ALARM_STATE, alarmStatus.alarmsState ) - setAlarmAudioState( ALARM_PRIORITY_HIGH, alarmAudioVolumeLevel ); + setAlarmAudioState( ALARM_PRIORITY_HIGH, volume ); } } } @@ -914,6 +986,7 @@ BOOL noEndTreatment = FALSE; BOOL noNewTreatment = FALSE; BOOL usrAckReq = FALSE; + BOOL noMinimize = TRUE; ALARM_ID_T a; // Determine alarm flags @@ -954,7 +1027,7 @@ } // Alarm table loop // If top alarm condition not cleared, block resume and rinseback flags - if ( TRUE == alarmStatus.topAlarmConditionnDetected ) + if ( TRUE == alarmStatus.topAlarmConditionDetected ) { noResume = TRUE; noRinseback = TRUE; @@ -963,14 +1036,20 @@ // If top alarm requires user ack or no other user options enabled for recoverable alarm and condition cleared, set user ack flag and block other flags if ( ( TRUE == ALARM_TABLE[ alarmStatus.alarmTop ].alarmUserAckRequired ) || ( ( FALSE == alarmStatus.noClear ) && ( noResume ) && ( noRinseback ) && ( noEndTreatment ) && - ( FALSE == alarmStatus.topAlarmConditionnDetected ) ) ) + ( FALSE == alarmStatus.topAlarmConditionDetected ) ) ) { usrAckReq = TRUE; noResume = TRUE; noRinseback = TRUE; noEndTreatment = TRUE; } + // If in Treatment-Stop state, allow user to minimize the alarm window + if ( ( MODE_TREA == getCurrentOperationMode() ) && ( TREATMENT_STOP_STATE == getTreatmentState() ) ) + { + noMinimize = FALSE; + } + // Set updated alarm flags alarmStatus.systemFault = systemFault; alarmStatus.stop = stop; @@ -980,6 +1059,7 @@ alarmStatus.noEndTreatment = noEndTreatment; alarmStatus.noNewTreatment |= noNewTreatment; alarmStatus.usrACKRequired = usrAckReq; + alarmStatus.noMinimize = noMinimize; } /*********************************************************************//** @@ -1027,6 +1107,171 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_ALARM_MGMT_INVALID_FIFO_TO_RESET, priority ) } } + +/*********************************************************************//** + * @brief + * The publishAlarmInfo function publishes alarm information at the set + * interval. + * @details Inputs: + * @details Outputs: alarm information are published to CAN bus. + * @return none + *************************************************************************/ +static void publishAlarmInfo( void ) +{ + // Publish voltages monitor data on interval + if ( ++alarmInfoPublicationTimerCounter >= getPublishAlarmInfoInterval() ) + { + ALARM_INFO_PAYLOAD_T data; + + data.audioVolume = MAX_ALARM_VOLUME_LEVEL - getAlarmAudioVolume(); // convert back to 1..5 volume level for publication + data.audioCurrHG = getAlarmAudioPrimaryHighGainCurrent(); + data.audioCurrLG = getAlarmAudioPrimaryLowGainCurrent(); + data.backupAudioCurr = getAlarmAudioBackupCurrent(); + data.safetyShutdown = isSafetyShutdownActivated(); + + broadcastAlarmInfo( data ); + alarmInfoPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The getPublishAlarmInfoInterval function gets the blood flow data + * publication interval. + * @details Inputs: alarmInfoPublishInterval + * @details Outputs: none + * @return the current alarm information publication interval (in task intervals). + *************************************************************************/ +static U32 getPublishAlarmInfoInterval( void ) +{ + U32 result = alarmInfoPublishInterval.data; + + if ( OVERRIDE_KEY == alarmInfoPublishInterval.override ) + { + result = alarmInfoPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getAlarmAudioVolume function gets the current alarm audio volume level. + * @details Inputs: alarmAudioVolumeLevel + * @details Outputs: none + * @return the current alarm audio volume level. + *************************************************************************/ +U32 getAlarmAudioVolume( void ) +{ + U32 result = alarmAudioVolumeLevel.data; + + if ( OVERRIDE_KEY == alarmAudioVolumeLevel.override ) + { + result = alarmAudioVolumeLevel.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getAlarmAudioPrimaryHighGainCurrent function gets the current alarm + * audio high gain current. + * @details Inputs: alarmPrimaryAudioCurrentHG + * @details Outputs: none + * @return the current alarm audio high gain current (in mA). + *************************************************************************/ +F32 getAlarmAudioPrimaryHighGainCurrent( void ) +{ + F32 result = alarmPrimaryAudioCurrentHG.data; + + if ( OVERRIDE_KEY == alarmPrimaryAudioCurrentHG.override ) + { + result = alarmPrimaryAudioCurrentHG.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getAlarmAudioPrimaryLowGainCurrent function gets the current alarm + * audio low gain current. + * @details Inputs: alarmPrimaryAudioCurrentLG + * @details Outputs: none + * @return the current alarm audio low gain current (in mA). + *************************************************************************/ +F32 getAlarmAudioPrimaryLowGainCurrent( void ) +{ + F32 result = alarmPrimaryAudioCurrentLG.data; + + if ( OVERRIDE_KEY == alarmPrimaryAudioCurrentLG.override ) + { + result = alarmPrimaryAudioCurrentLG.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getAlarmAudioBackupCurrent function gets the current backup alarm + * audio current. + * @details Inputs: alarmBackupAudioCurrent + * @details Outputs: none + * @return the current backup alarm audio current (in mA). + *************************************************************************/ +F32 getAlarmAudioBackupCurrent( void ) +{ + F32 result = alarmBackupAudioCurrent.data; + + if ( OVERRIDE_KEY == alarmBackupAudioCurrent.override ) + { + result = alarmBackupAudioCurrent.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execAlarmAudioSelfTest function outputs a test audio tone and + * measures the audio current level. The test passes if the audio current + * exceeds TBD mA. + * @details Inputs: alarmBackupAudioCurrent + * @details Outputs: none + * @return the current backup alarm audio current (in mA). + *************************************************************************/ +SELF_TEST_STATUS_T execAlarmAudioSelfTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; + + if ( alarmAudioTestToneRequested != TRUE ) + { + alarmAudioTestToneRequested = TRUE; + setAlarmAudio(); + } + else + { + F32 almHGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_HG ); + F32 almLGCurrent = getIntADCVoltageConverted( INT_ADC_PRIMARY_ALARM_CURRENT_LG ); + + // Check if alarm audio current is sufficiently high indicating alarm tone is being output +// TODO - need tone to be on longer than 50ms. make duration long (1 sec) at first to characterize the audio, then change to exit test when threshold met or t/o +// if ( ( almHGCurrent > ALARM_AUDIO_CURRENT_HG_MIN_MA ) && +// ( almLGCurrent > ALARM_AUDIO_CURRENT_LG_MIN_MA ) ) + { + result = SELF_TEST_STATUS_PASSED; + } +// else +// { +// result = SELF_TEST_STATUS_FAILED; +// SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_ALARM_AUDIO_SELF_TEST_FAILURE, almHGCurrent, almLGCurrent ); +// } + } + + return result; +} /************************************************************************* @@ -1197,6 +1442,233 @@ } return result; +} + +/*********************************************************************//** + * @brief + * The testSetAlarmInfoPublishIntervalOverride function sets the override of the + * alarm information publication interval. + * @details Inputs: none + * @details Outputs: alarmInfoPublishInterval + * @param ms milliseconds between alarm info broadcasts + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = ms / TASK_GENERAL_INTERVAL; + + result = TRUE; + alarmInfoPublishInterval.ovData = intvl; + alarmInfoPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetAlarmInfoPublishIntervalOverride function resets the override of the + * alarm information publication interval. + * @details Inputs: none + * @details Outputs: alarmInfoPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetAlarmInfoPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmInfoPublishInterval.override = OVERRIDE_RESET; + alarmInfoPublishInterval.ovData = alarmInfoPublishInterval.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetAlarmAudioVolumeLevelOverride function sets the override of the + * alarm audio volume. + * @details Inputs: none + * @details Outputs: alarmAudioVolumeLevel + * @param volume volume level (1..5) of alarm audio + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetAlarmAudioVolumeLevelOverride( U32 volume ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmAudioVolumeLevel.ovData = MAX_ALARM_VOLUME_LEVEL - volume; + alarmAudioVolumeLevel.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetAlarmAudioVolumeLevelOverride function resets the override of the + * alarm audio volume. + * @details Inputs: none + * @details Outputs: alarmAudioVolumeLevel + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetAlarmAudioVolumeLevelOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmAudioVolumeLevel.override = OVERRIDE_RESET; + alarmAudioVolumeLevel.ovData = alarmAudioVolumeLevel.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetPrimaryAlarmAudioCurrentHGOverride function sets the override of the + * alarm audio current (high gain) in mA. + * @details Inputs: none + * @details Outputs: alarmPrimaryAudioCurrentHG + * @param mA milliamps measured from high gain channel of primary alarm audio + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetPrimaryAlarmAudioCurrentHGOverride( F32 mA ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmPrimaryAudioCurrentHG.ovData = mA; + alarmPrimaryAudioCurrentHG.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetPrimaryAlarmAudioCurrentHGOverride function resets the override of the + * alarm audio current (high gain). + * @details Inputs: none + * @details Outputs: alarmPrimaryAudioCurrentHG + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetPrimaryAlarmAudioCurrentHGOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmPrimaryAudioCurrentHG.override = OVERRIDE_RESET; + alarmPrimaryAudioCurrentHG.ovData = alarmPrimaryAudioCurrentHG.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetPrimaryAlarmAudioCurrentLGOverride function sets the override of the + * alarm audio current (low gain) in mA. + * @details Inputs: none + * @details Outputs: alarmPrimaryAudioCurrentLG + * @param mA milliamps measured from low gain channel of primary alarm audio + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetPrimaryAlarmAudioCurrentLGOverride( F32 mA ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmPrimaryAudioCurrentLG.ovData = mA; + alarmPrimaryAudioCurrentLG.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetPrimaryAlarmAudioCurrentLGOverride function resets the override of the + * alarm audio current (low gain). + * @details Inputs: none + * @details Outputs: alarmPrimaryAudioCurrentLG + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetPrimaryAlarmAudioCurrentLGOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmPrimaryAudioCurrentLG.override = OVERRIDE_RESET; + alarmPrimaryAudioCurrentLG.ovData = alarmPrimaryAudioCurrentLG.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetBackupAlarmAudioCurrentOverride function sets the override of the + * alarm audio current (backup) in mA. + * @details Inputs: none + * @details Outputs: alarmBackupAudioCurrent + * @param mA milliamps measured from backup channel of primary alarm audio + * @return TRUE if override set successful, FALSE if not + *************************************************************************/ +BOOL testSetBackupAlarmAudioCurrentOverride( F32 mA ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmBackupAudioCurrent.ovData = mA; + alarmBackupAudioCurrent.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBackupAlarmAudioCurrentOverride function resets the override of the + * alarm audio current (backup). + * @details Inputs: none + * @details Outputs: alarmBackupAudioCurrent + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetBackupAlarmAudioCurrentOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + alarmBackupAudioCurrent.override = OVERRIDE_RESET; + alarmBackupAudioCurrent.ovData = alarmBackupAudioCurrent.ovInitData; + } + + return result; } /**@}*/ Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -r8ec997d92b561aa3763f751302693bd432540f3e -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 8ec997d92b561aa3763f751302693bd432540f3e) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -52,7 +52,7 @@ ALARM_ACTION_ACK, ///< User selected Ack from alarm recovery options NUMBER_OF_ALARM_ACTIONS ///< Number of alarm actions } ALARM_ACTION_T; - + #pragma pack(push, 4) /// Record structure for detailing the properties of the current composite alarm status. typedef struct @@ -64,7 +64,7 @@ BOOL alarmsToEscalate; ///< Are any active alarms due to escalate (should UI show count down timer?) U32 alarmsEscalatesIn; ///< Time until alarm will escalate (seconds) ALARM_ID_T alarmTop; ///< ID of current top alarm that will drive lamp/audio and UI should be displaying right now - BOOL topAlarmConditionnDetected; ///< Condition for top alarm is still being detected + BOOL topAlarmConditionDetected; ///< Condition for top alarm is still being detected BOOL systemFault; ///< A system fault is active? BOOL stop; ///< We should be in controlled stop right now BOOL noClear; ///< No recovery will be possible @@ -74,6 +74,7 @@ BOOL noNewTreatment; ///< No new treatments may be started even if current treatment is ended BOOL noDialRecirc; ///< No dialysate re-circulation allowed at this time BOOL usrACKRequired; ///< The user must acknowledge top alarm + BOOL noMinimize; ///< Prevent user from minimizing the alarm window BOOL lampOn; ///< The alarm lamp is on } COMP_ALARM_STATUS_T; @@ -116,6 +117,17 @@ ALARM_DATA_TYPES_T dataType; ///< The type of alarm data provided. ALARM_DATAS_T data; ///< The alarm data of specified type. } ALARM_DATA_T; + +/// Payload record structure for the alarm info message. +typedef struct +{ + U32 audioVolume; ///< Audio volume level (1..5) + F32 audioCurrHG; ///< Primary alarm audio current - high gain (mA) + F32 audioCurrLG; ///< Primary alarm audio current - low gain (mA) + F32 backupAudioCurr; ///< Backup alarm audio current (mA) + BOOL safetyShutdown; ///< Safety shutdown activated? (T/F) +} ALARM_INFO_PAYLOAD_T; + #pragma pack(pop) #pragma pack(push, 2) @@ -153,12 +165,28 @@ BOOL getNoNewTreatmentStatus( void ); void handleActiveAlarmListRequest( void ); + +U32 getAlarmAudioVolume( void ); +F32 getAlarmAudioPrimaryHighGainCurrent( void ); +F32 getAlarmAudioPrimaryLowGainCurrent( void ); +F32 getAlarmAudioBackupCurrent( void ); +SELF_TEST_STATUS_T execAlarmAudioSelfTest( void ); BOOL testSetAlarmStateOverride( U32 alarmID, BOOL value ); BOOL testResetAlarmStateOverride( U32 alarmID ); BOOL testSetAlarmStartOverride( U32 alarmID, U32 value ); BOOL testResetAlarmStartOverride( U32 alarmID ); -BOOL testClearAllAlarms( U32 key ); +BOOL testClearAllAlarms( U32 key ); +BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ); +BOOL testResetAlarmInfoPublishIntervalOverride( void ); +BOOL testSetAlarmAudioVolumeLevelOverride( U32 volume ); +BOOL testResetAlarmAudioVolumeLevelOverride( void ); +BOOL testSetPrimaryAlarmAudioCurrentHGOverride( F32 mA ); +BOOL testResetPrimaryAlarmAudioCurrentHGOverride( void ); +BOOL testSetPrimaryAlarmAudioCurrentLGOverride( F32 mA ); +BOOL testResetPrimaryAlarmAudioCurrentLGOverride( void ); +BOOL testSetBackupAlarmAudioCurrentOverride( F32 mA ); +BOOL testResetBackupAlarmAudioCurrentOverride( void ); /**@}*/ Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r3d667b0820cfb0a8d1dbc96f4ca205da77c3ff03 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 3d667b0820cfb0a8d1dbc96f4ca205da77c3ff03) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -153,6 +153,8 @@ SW_FAULT_ID_INVALID_RTI_NOTIFICATION, SW_FAULT_ID_INVALID_CAN_MESSAGE_BOX, SW_FAULT_ID_INVALID_CONSUMABLE_SELF_TEST_STATE, + SW_FAULT_ID_HD_INVALID_BUBBLE_STATE, // 125 + SW_FAULT_ID_HD_INVALID_BUBBLE_ID, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/FPGA.c =================================================================== diff -u -r3d667b0820cfb0a8d1dbc96f4ca205da77c3ff03 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 3d667b0820cfb0a8d1dbc96f4ca205da77c3ff03) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -20,8 +20,9 @@ #include "sci.h" #include "sys_dma.h" -#include "FPGA.h" #include "Comm.h" +#include "Compatible.h" +#include "FPGA.h" #include "SystemCommMessages.h" #include "Utilities.h" @@ -82,15 +83,23 @@ #define FPGA_AIRTRAP_LEVEL_HIGH_MASK 0x0004 ///< Bit mask for air trap upper level sensor. #define FPGA_FLUID_LEAK_STATE_MASK 0x0040 ///< Bit mask for fluid leak detector. + #define FPGA_BLOOD_LEAK_STATUS_MASK 0x1000 ///< Bit mask for blood leak detector. #define FPGA_BLOOD_LEAK_ZERO_STATE_MASK 0x2000 ///< Bit mask for blood leak detector zero. - #define FPGA_BLOOD_LEAK_ZERO_CMD 0x02 ///< Bit for blood leak detector zero command. #define FPGA_BLOOD_LEAK_SELF_TEST_CMD 0x01 ///< Bit for blood leak detector self test command. -#define FPGA_ADA_INPUT_STATUS_MASK 0x0001 ///< Bit mask for arterial air bubble detector input status. -#define FPGA_ADV_INPUT_STATUS_MASK 0x0002 ///< Bit mask for venous air bubble detector input status. +#define FPGA_ADA_BUBBLE_STATUS_MASK 0x0001 ///< Bit mask for arterial air bubble detector input status. +#define FPGA_ADV_BUBBLE_STATUS_MASK 0x0002 ///< Bit mask for venous air bubble detector input status. +#define FPGA_ADA_BUBBLE_SELF_TEST_CMD 0x04 ///< Bit for arterial air bubble detector self-test command. +#define FPGA_ADV_BUBBLE_SELF_TEST_CMD 0x08 ///< Bit for venous air bubble detector self-test command. +#define FPGA_PBO_TEMP_DIVISOR 2047.0 ///< Used in conversion of PBo temperature reading to deg C. +#define FPGA_PBO_TEMP_GAIN 200.0 ///< Used in conversion of PBo temperature reading to deg C. +#define FPGA_PBO_TEMP_OFFSET 50.0 ///< Used in conversion of PBo temperature reading to deg C. + +#define FPGA_ALARM_AUDIO_VOLUME_SHIFT 3 ///< Shift alarm audio volume 3 bits to left before writing to register. + // FPGA Sensors Record #pragma pack(push,1) /// Record structure for FPGA header read. @@ -525,9 +534,14 @@ } // If retries for commands exceeds limit, fault - if ( fpgaCommRetryCount > MAX_COMM_ERROR_RETRIES ) + if ( ( fpgaCommRetryCount > MAX_COMM_ERROR_RETRIES ) +#ifdef _RELEASE_ + || ( fpgaSensorReadings.errorCountProcessor > MAX_COMM_ERROR_RETRIES ) ) +#else + ) +#endif { - activateAlarmNoData( ALARM_ID_HD_FPGA_COMM_TIMEOUT ); + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_COMM_TIMEOUT, fpgaCommRetryCount, (U32)fpgaSensorReadings.errorCountProcessor ) } // Reset comm flags after processing incoming responses @@ -866,7 +880,23 @@ // Check FPGA reported correct ID if ( FPGA_EXPECTED_ID == fpgaHeader.fpgaId ) { - result = SELF_TEST_STATUS_PASSED; + // Check FPGA compatibility w/ firmware + if ( fpgaHeader.fpgaRevMajor > MIN_HD_FPGA_MAJOR ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + if ( ( MIN_HD_FPGA_MAJOR == fpgaHeader.fpgaRevMajor ) && ( fpgaHeader.fpgaRev >= MIN_HD_FPGA_MINOR ) ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_FPGA_POST_TEST_FAILED, (U32)fpgaHeader.fpgaRevMajor, (U32)fpgaHeader.fpgaRev ) + } + } } else { @@ -1071,6 +1101,7 @@ * 1 - Low priority alarm tone (c e) * 2 - Medium priority alarm tone (c f# c) * 3 - High priority alarm tone (c f# c - c f#) + * 4 - Continuous test tone (e) * @param volumeLevel the level of attenuation to command (0..4) * 4 - 3 dB gain * 3 - 6 dB gain @@ -1079,25 +1110,24 @@ * 0 - 15 dB gain * @return none *************************************************************************/ -void setAlarmAudioState( ALARM_PRIORITY_T state, U32 volumeLevel ) +void setAlarmAudioState( U32 state, U32 volumeLevel ) { - if ( ( state < NUM_OF_ALARM_PRIORITIES ) && ( volumeLevel <= MAX_ALARM_VOLUME_ATTENUATION ) ) - { - U08 audioCmd = (U08)state; + U08 audioCmd = (U08)state; - audioCmd |= ( (U08)volumeLevel << 2 ); + audioCmd |= ( (U08)volumeLevel << FPGA_ALARM_AUDIO_VOLUME_SHIFT ); + + if ( ( state <= NUM_OF_ALARM_PRIORITIES ) && ( volumeLevel <= MAX_ALARM_VOLUME_ATTENUATION ) ) + { fpgaActuatorSetPoints.alarmControl = audioCmd; } else { - U08 audioCmd = (U08)ALARM_PRIORITY_HIGH; - + // S/w fault to indicate issue w/ s/w + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_ALARM_AUDIO_PARAM, (U32)audioCmd ) // Set alarm audio to high priority, max volume for safety since s/w seems to be having trouble setting audio correctly - audioCmd |= ( (U08)MIN_ALARM_VOLUME_ATTENUATION << 2 ); + audioCmd = (U08)ALARM_PRIORITY_HIGH; + audioCmd |= ( (U08)MIN_ALARM_VOLUME_ATTENUATION << FPGA_ALARM_AUDIO_VOLUME_SHIFT ); fpgaActuatorSetPoints.alarmControl = audioCmd; - // S/w fault to indicate issue w/ s/w - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_FPGA_INVALID_ALARM_AUDIO_PARAM, volumeLevel ) - } } @@ -1141,30 +1171,82 @@ /*********************************************************************//** * @brief - * The getFPGADialysateFlow function gets the latest dialysate flow reading. + * The getFPGABloodFlowMeterStatus function gets the blood flow meter status. * @details Inputs: fpgaSensorReadings * @details Outputs: none - * @return last dialysate flow reading + * @return current blood flow meter status *************************************************************************/ -F32 getFPGADialysateFlow( void ) +U08 getFPGABloodFlowMeterStatus( void ) { - return fpgaSensorReadings.dialysateFlowLast; + return fpgaSensorReadings.bloodFlowMeterDeviceStatus; } /*********************************************************************//** * @brief - * The getFPGABloodFlowMeterStatus function gets the blood flow meter status. + * The getFPGABloodFlowFastPacketReadCounter function gets the blood + * flow meter fast packet read counter. * @details Inputs: fpgaSensorReadings * @details Outputs: none - * @return current blood flow meter status + * @return current blood flow meter fast packet read counter *************************************************************************/ -U08 getFPGABloodFlowMeterStatus( void ) +U08 getFPGABloodFlowFastPacketReadCounter( void ) { - return fpgaSensorReadings.bloodFlowMeterDeviceStatus; + return fpgaSensorReadings.bloodFlowMeterDataPktCount; } /*********************************************************************//** * @brief + * The getFPGABloodFlowSlowPacketReadCounter function gets the blood + * flow meter slow packet read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current blood flow meter slow packet read counter + *************************************************************************/ +U08 getFPGABloodFlowSlowPacketReadCounter( void ) +{ + return ( fpgaSensorReadings.bloodFlowMeterSlowPktCounts & MASK_OFF_NIBBLE_LSB ) >> SHIFT_BITS_BY_4; +} + +/*********************************************************************//** + * @brief + * The getFPGABloodFlowStatusPacketReadCounter function gets the blood + * flow meter status packet read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current blood flow meter status packet read counter + *************************************************************************/ +U08 getFPGABloodFlowStatusPacketReadCounter( void ) +{ + return ( fpgaSensorReadings.bloodFlowMeterSlowPktCounts & MASK_OFF_NIBBLE_MSB ); +} + +/*********************************************************************//** + * @brief + * The getFPGABloodFlowErrorCounter function gets the blood flow meter + * error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current blood flow meter error counter + *************************************************************************/ +U08 getFPGABloodFlowErrorCounter( void ) +{ + return fpgaSensorReadings.bloodFlowMeterErrorCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialysateFlow function gets the latest dialysate flow reading. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last dialysate flow reading + *************************************************************************/ +F32 getFPGADialysateFlow( void ) +{ + return fpgaSensorReadings.dialysateFlowLast; +} + +/*********************************************************************//** + * @brief * The getFPGADialysateFlowMeterStatus function gets the dialysate flow meter status. * @details Inputs: fpgaSensorReadings * @details Outputs: none @@ -1177,6 +1259,58 @@ /*********************************************************************//** * @brief + * The getFPGADialysateFlowFastPacketReadCounter function gets the dialysate + * flow meter fast packet read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current dialysate flow meter fast packet read counter + *************************************************************************/ +U08 getFPGADialysateFlowFastPacketReadCounter( void ) +{ + return fpgaSensorReadings.dialysateFlowMeterDataPktCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialysateFlowSlowPacketReadCounter function gets the dialysate + * flow meter slow packet read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current dialysate flow meter slow packet read counter + *************************************************************************/ +U08 getFPGADialysateFlowSlowPacketReadCounter( void ) +{ + return ( fpgaSensorReadings.dialysateFlowMeterSlowPckCounts & MASK_OFF_NIBBLE_LSB ) >> SHIFT_BITS_BY_4; +} + +/*********************************************************************//** + * @brief + * The getFPGADialysateFlowStatusPacketReadCounter function gets the dialysate + * flow meter status packet read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current dialysate flow meter status packet read counter + *************************************************************************/ +U08 getFPGADialysateFlowStatusPacketReadCounter( void ) +{ + return ( fpgaSensorReadings.dialysateFlowMeterSlowPckCounts & MASK_OFF_NIBBLE_MSB ); +} + +/*********************************************************************//** + * @brief + * The getFPGADialysateFlowErrorCounter function gets the dialysate flow meter + * error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return current dialysate flow meter error counter + *************************************************************************/ +U08 getFPGADialysateFlowErrorCounter( void ) +{ + return fpgaSensorReadings.dialysateFlowMeterErrorCount; +} + +/*********************************************************************//** + * @brief * The getFPGABloodPumpHallSensorCount function gets the latest blood pump * hall sensor count. Count is a 16 bit free running counter. If counter is * counting up, indicates motor is running in forward direction. If counter is @@ -1195,9 +1329,9 @@ * @brief * The getFPGABloodPumpHallSensorStatus function gets the latest blood pump * hall sensor status. - * Bit 0 - Derived direction of the blood pump motor (0=Fwd, 1=Rev) - * Bit 1 - A direction error was detected in the current hall sensor phase - * Bit 2 - A direction error was detected since the last read of this register + * Bit 7 - Derived direction of the blood pump motor (0=Fwd, 1=Rev) + * Bit 6 - Unused + * Bit 5-0 - Direction error count since power-up (rolls over) * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last blood pump hall sensor status reading. @@ -1227,9 +1361,9 @@ * @brief * The getFPGADialInPumpHallSensorStatus function gets the latest dialysate inlet pump * hall sensor status. - * Bit 0 - Derived direction of the dialyste inlet pump motor (0=Fwd, 1=Rev) - * Bit 1 - A direction error was detected in the current hall sensor phase - * Bit 2 - A direction error was detected since the last read of this register + * Bit 7 - Derived direction of the dialysate inlet pump motor (0=Fwd, 1=Rev) + * Bit 6 - Unused + * Bit 5-0 - Direction error count since power-up (rolls over) * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate inlet pump hall sensor status reading. @@ -1259,9 +1393,9 @@ * @brief * The getFPGADialOutPumpHallSensorStatus function gets the latest dialysate outlet pump * hall sensor status. - * Bit 0 - Derived direction of the dialysate outlet pump motor (0=Fwd, 1=Rev) - * Bit 1 - A direction error was detected in the current hall sensor phase - * Bit 2 - A direction error was detected since the last read of this register + * Bit 7 - Derived direction of the dialysate outlet pump motor (0=Fwd, 1=Rev) + * Bit 6 - Unused + * Bit 5-0 - Direction error count since power-up (rolls over) * @details Inputs: fpgaSensorReadings * @details Outputs: none * @return last dialysate outlet pump hall sensor status reading. @@ -1311,6 +1445,84 @@ /*********************************************************************//** * @brief + * The getFPGABloodPumpOcclusionReadCounter function gets the latest blood + * pump occlusion read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last blood pump occlusion read counter + *************************************************************************/ +U08 getFPGABloodPumpOcclusionReadCounter( void ) +{ + return fpgaSensorReadings.bloodOcclusionReadCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialInPumpOcclusionReadCounter function gets the latest dialysate + * inlet pump occlusion read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last dialysate inlet pump occlusion read counter + *************************************************************************/ +U08 getFPGADialInPumpOcclusionReadCounter( void ) +{ + return fpgaSensorReadings.dialysateInOcclusionReadCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialOutPumpOcclusionReadCounter function gets the latest dialysate + * outlet pump occlusion read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last dialysate outlet pump occlusion read counter + *************************************************************************/ +U08 getFPGADialOutPumpOcclusionReadCounter( void ) +{ + return fpgaSensorReadings.dialysateOutOcclusionReadCount; +} + +/*********************************************************************//** + * @brief + * The getFPGABloodPumpOcclusionErrorCounter function gets the latest blood + * pump occlusion error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last blood pump occlusion error counter + *************************************************************************/ +U08 getFPGABloodPumpOcclusionErrorCounter( void ) +{ + return fpgaSensorReadings.bloodOcclusionErrorCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialInPumpOcclusionErrorCounter function gets the latest dialysate + * inlet pump occlusion error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last dialysate inlet pump occlusion error counter + *************************************************************************/ +U08 getFPGADialInPumpOcclusionErrorCounter( void ) +{ + return fpgaSensorReadings.dialysateInOcclusionErrorCount; +} + +/*********************************************************************//** + * @brief + * The getFPGADialOutPumpOcclusionErrorCounter function gets the latest dialysate + * outlet pump occlusion error counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last dialysate outlet pump occlusion error counter + *************************************************************************/ +U08 getFPGADialOutPumpOcclusionErrorCounter( void ) +{ + return fpgaSensorReadings.dialysateOutOcclusionErrorCount; +} + +/*********************************************************************//** + * @brief * The getFPGAArterialPressure function gets the latest arterial pressure reading. * High byte indicates alarm status for ADC channel. * Low 24-bits are channel reading. Subtract 2^23 from low 24 bits to get @@ -1326,7 +1538,7 @@ /*********************************************************************//** * @brief - * The getFPGAVenousPressure function gets the venous arterial pressure reading. + * 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, * below are negative. @@ -1341,6 +1553,34 @@ /*********************************************************************//** * @brief + * The getFPGAVenousPressureTemperature function gets the latest venous pressure + * sensor temperature reading. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last venous pressure sensor temperature reading + *************************************************************************/ +F32 getFPGAVenousPressureTemperature( void ) +{ + F32 result = ( (F32)fpgaSensorReadings.venousTemperature / FPGA_PBO_TEMP_DIVISOR ) * FPGA_PBO_TEMP_GAIN - FPGA_PBO_TEMP_OFFSET; + + return result; +} + +/*********************************************************************//** + * @brief + * The getFPGAVenousPressureReadCounter function gets the latest venous pressure + * sensor read counter. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return last venous pressure sensor read counter + *************************************************************************/ +U08 getFPGAVenousPressureReadCounter( void ) +{ + return fpgaSensorReadings.venousReadCounter; +} + +/*********************************************************************//** + * @brief * The setFPGASyringePumpControlFlags function sets the syringe pump control * register per given bit flags. * @details Inputs: none @@ -1602,36 +1842,6 @@ /*********************************************************************//** * @brief - * The getFPGAArterialAirBubbleStatus function gets the latest arterial air - * bubble detector status. - * @details Inputs: fpgaSensorReadings - * @details Outputs: none - * @return TRUE if air bubble is detected, otherwise FALSE - *************************************************************************/ -BOOL getFPGAArterialAirBubbleStatus( void ) -{ - U16 const status = fpgaSensorReadings.fpgaGPIO & FPGA_ADA_INPUT_STATUS_MASK; - - return ( 0 == status ? TRUE : FALSE ); -} - -/*********************************************************************//** - * @brief - * The getFPGAVenousAirBubbleStatus function gets the latest venous air - * bubble detector status. - * @details Inputs: fpgaSensorReadings - * @details Outputs: none - * @return TRUE if air bubble is detected, otherwise FALSE - *************************************************************************/ -BOOL getFPGAVenousAirBubbleStatus( void ) -{ - U16 const status = fpgaSensorReadings.fpgaGPIO & FPGA_ADV_INPUT_STATUS_MASK; - - return ( 0 == status ? FALSE : TRUE ); -} - -/*********************************************************************//** - * @brief * The getDoorState function gets the current state of door switch. * @details Inputs: none * @details Outputs: none @@ -1719,9 +1929,9 @@ * @brief * The setFPGABloodLeakZero function sets the Blood Leak detector into * zeroing mode via the FPGA. - * @details Inputs: fpgaSensorReadings - * @details Outputs: none - * @return FPGABloodLeakZeroDetected + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints + * @return none *************************************************************************/ void setFPGABloodLeakZero( void ) { @@ -1745,9 +1955,9 @@ * @brief * The setFPGABloodLeakSelfTest function sets the Blood Leak detector into * self-test mode via the FPGA. - * @details Inputs: fpgaSensorReadings - * @details Outputs: none - * @return FPGABloodLeakZeroDetected + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints + * @return: none *************************************************************************/ void setFPGABloodLeakSelfTest( void ) { @@ -1769,6 +1979,78 @@ /*********************************************************************//** * @brief + * The noFPGABubbleDetected function returns TRUE if no air bubble has been + * detected and FALSE if an air bubble has been detected. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return noFPGABubbleDetected + *************************************************************************/ +BOOL noFPGABubbleDetected( U32 bubble ) +{ + U16 noFPGABubbleDetected = 0; + + if ( bubble == ADA ) + { + noFPGABubbleDetected = fpgaSensorReadings.fpgaGPIO & FPGA_ADA_BUBBLE_STATUS_MASK; + } + else if ( bubble == ADV ) + { + noFPGABubbleDetected = fpgaSensorReadings.fpgaGPIO & FPGA_ADV_BUBBLE_STATUS_MASK; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_ID, bubble ) + } + + return ( 0 != noFPGABubbleDetected ? TRUE : FALSE ); +} + +/*********************************************************************//** + * @brief + * The setFPGABubbleSelfTest function sets the given air bubble detector into + * self-test mode via the FPGA. + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints + * @return: none + *************************************************************************/ +void setFPGABubbleSelfTest( U32 bubble ) +{ + if ( bubble == ADA ) + { + fpgaActuatorSetPoints.fpgaSensorTest |= FPGA_ADA_BUBBLE_SELF_TEST_CMD; + } + else if ( bubble == ADV ) + { + fpgaActuatorSetPoints.fpgaSensorTest |= FPGA_ADV_BUBBLE_SELF_TEST_CMD; + } +} + +/*********************************************************************//** + * @brief + * The clearFPGABubbleSelfTest function clears the given air bubble detector + * from self-test mode via the FPGA. + * @details Inputs: none + * @details Outputs: fpgaActuatorSetPoints + * @return: none + *************************************************************************/ +void clearFPGABubbleSelfTest( U32 bubble ) +{ + if ( bubble == ADA ) + { + fpgaActuatorSetPoints.fpgaSensorTest &= ~FPGA_ADA_BUBBLE_SELF_TEST_CMD; + } + else if ( bubble == ADV ) + { + fpgaActuatorSetPoints.fpgaSensorTest &= ~FPGA_ADV_BUBBLE_SELF_TEST_CMD; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_INVALID_BUBBLE_ID, bubble ) + } +} + +/*********************************************************************//** + * @brief * The setValveDialyzerInletPosition function sets the position of VDi * in counts * @details Inputs: fpgaActuatorSetPoints Index: firmware/App/Services/FPGA.h =================================================================== diff -u -r5a515a3cdc780cab4657e9b5c013944126f9cc28 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision 5a515a3cdc780cab4657e9b5c013944126f9cc28) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -52,16 +52,24 @@ void getFPGAVersions( U08 *Id, U08 *Maj, U08 *Min, U08 *Lab ); -void setAlarmAudioState( ALARM_PRIORITY_T state, U32 volumeLevel ); +void setAlarmAudioState( U32 state, U32 volumeLevel ); F32 getFPGABloodFlowSignalStrength( void ); F32 getFPGADialysateFlowSignalStrength( void ); F32 getFPGABloodFlow( void ); -F32 getFPGADialysateFlow( void ); - U08 getFPGABloodFlowMeterStatus( void ); +U08 getFPGABloodFlowFastPacketReadCounter( void ); +U08 getFPGABloodFlowSlowPacketReadCounter( void ); +U08 getFPGABloodFlowStatusPacketReadCounter( void ); +U08 getFPGABloodFlowErrorCounter( void ); + +F32 getFPGADialysateFlow( void ); U08 getFPGADialysateFlowMeterStatus( void ); +U08 getFPGADialysateFlowFastPacketReadCounter( void ); +U08 getFPGADialysateFlowSlowPacketReadCounter( void ); +U08 getFPGADialysateFlowStatusPacketReadCounter( void ); +U08 getFPGADialysateFlowErrorCounter( void ); U16 getFPGABloodPumpHallSensorCount( void ); U08 getFPGABloodPumpHallSensorStatus( void ); @@ -72,9 +80,17 @@ U32 getFPGAArterialPressure( void ); U16 getFPGAVenousPressure( void ); +F32 getFPGAVenousPressureTemperature( void ); +U08 getFPGAVenousPressureReadCounter( void ); U16 getFPGABloodPumpOcclusion( void ); U16 getFPGADialInPumpOcclusion( void ); U16 getFPGADialOutPumpOcclusion( void ); +U08 getFPGABloodPumpOcclusionReadCounter( void ); +U08 getFPGADialInPumpOcclusionReadCounter( void ); +U08 getFPGADialOutPumpOcclusionReadCounter( void ); +U08 getFPGABloodPumpOcclusionErrorCounter( void ); +U08 getFPGADialInPumpOcclusionErrorCounter( void ); +U08 getFPGADialOutPumpOcclusionErrorCounter( void ); void setFPGASyringePumpControlFlags( U08 bitFlags ); void setFPGASyringePumpADCandDACControlFlags( U08 bitFlags ); @@ -97,8 +113,6 @@ void getFPGAAccelStatus( U16 *cnt, U16 *accelFPGAFaultReg ); void getFPGAAirTrapLevels( BOOL *airAtLower, BOOL *airAtUpper ); -BOOL getFPGAArterialAirBubbleStatus( void ); -BOOL getFPGAVenousAirBubbleStatus( void ); void setFPGASensorTest( U08 sensorTest ); @@ -116,6 +130,10 @@ void setFPGABloodLeakSelfTest( void ); void clearFPGABloodLeakSelfTest( void ); +BOOL noFPGABubbleDetected( U32 bubble ); +void setFPGABubbleSelfTest( U32 bubble ); +void clearFPGABubbleSelfTest( U32 bubble ); + void setFPGAValveDialyzerInletPosition( S16 setPoint ); S16 getFPGAValveDialyzerInletPosition( void ); U16 getFPGAValveDialyzerInletCurrentCounts( void ); Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -red6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision ed6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -943,8 +943,10 @@ if ( TRUE == didTimeout( timeOfLastDGCheckIn, DG_COMM_TIMEOUT_IN_MS ) ) { +#ifndef RUN_WITHOUT_DG activateAlarmNoData( ALARM_ID_DG_COMM_TIMEOUT ); dgIsCommunicating = FALSE; +#endif } } } @@ -1205,6 +1207,10 @@ handleHeparinCommandRequest( message ); break; + case MSG_ID_UI_SET_ALARM_AUDIO_VOLUME_LEVEL_CMD: + handleAlarmAudioVolumeSetCmd( message ); + break; + case MSG_ID_UI_SET_UF_VOLUME_PARAMETER: handleUFVolumeSetRequest( message ); break; @@ -1269,40 +1275,28 @@ handleDGCmdResp( message ); break; - case MSG_ID_UI_ACTIVE_ALARMS_LIST_REQUEST: - handleUIActiveAlarmsListRequest( message ); + case MSG_ID_UI_HD_SET_RTC_REQUEST: + handleUIClockSyncRequest( message ); break; - case MSG_ID_TESTER_LOGIN_REQUEST: - handleTesterLogInRequest( message ); + case MSG_ID_DG_POST_FINAL_TEST_RESULT: + handleDGPOSTFinalResult( message ); break; - case MSG_ID_HD_SET_CALIBRATION_RECORD: - handleSetHDCalibrationRecord( message ); + case MSG_ID_UI_POST_FINAL_TEST_RESULT: + handleUIPOSTFinalResult( message ); break; - case MSG_ID_HD_GET_CALIBRATION_RECORD: - handleGetHDCalibrationRecord( message ); + case MSG_ID_UI_ACTIVE_ALARMS_LIST_REQUEST: + handleUIActiveAlarmsListRequest( message ); break; - case MSG_ID_HD_SET_SYSTEM_RECORD: - handleSetHDSystemRecord( message ); + case MSG_ID_TESTER_LOGIN_REQUEST: + handleTesterLogInRequest( message ); break; - case MSG_ID_HD_GET_SYSTEM_RECORD: - handleGetHDSystemRecord( message ); - break; - - case MSG_ID_HD_GET_SERVICE_RECORD: - handleGetHDServiceRecord( message ); - break; - - case MSG_ID_HD_SET_SERVICE_RECORD: - handleSetHDServiceRecord( message ); - break; - default: - // Unrecognized message ID received - ignore + // Un-recognized or un-handled message ID received - ignore break; } @@ -1553,6 +1547,18 @@ handleBloodLeakZeroRequest( message ); break; + case MSG_ID_HD_BUBBLES_DATA_SEND_INTERVAL_OVERRIDE: + handleSetBubblesDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_HD_BUBBLE_STATUS_OVERRIDE: + handleSetBubbleStatusOverrideRequest( message ); + break; + + case MSG_ID_HD_BUBBLE_SELF_TEST_REQUEST: + handleBubbleSelfTestRequest( message ); + break; + case MSG_ID_HD_SET_OP_MODE_REQUEST: handleTestSetOpModeRequest( message ); break; @@ -1593,6 +1599,74 @@ handleTestSyringePumpMeasuredVolumeOverrideRequest( message ); break; + case MSG_ID_HD_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE: + handleTestMonitoredVoltagesSendIntervalOverrideRequest( message ); + break; + + case MSG_ID_HD_MONITORED_VOLTAGES_OVERRIDE: + handleTestMonitoredVoltageOverrideRequest( message ); + break; + + case MSG_ID_HD_ALARM_INFO_SEND_INTERVAL_OVERRIDE: + handleTestAlarmInfoSendIntervalOverrideRequest( message ); + break; + + case MSG_ID_HD_ALARM_AUDIO_VOLUME_LEVEL_OVERRIDE: + handleTestAlarmAudioVolumeOverrideRequest( message ); + break; + + case MSG_ID_HD_ALARM_AUDIO_CURRENT_HG_OVERRIDE: + handleTestAlarmAudioCurrentHgOverrideRequest( message ); + break; + + case MSG_ID_HD_ALARM_AUDIO_CURRENT_LG_OVERRIDE: + handleTestAlarmAudioCurrentLgOverrideRequest( message ); + break; + + case MSG_ID_HD_ALARM_BACKUP_AUDIO_CURRENT_OVERRIDE: + handleTestAlarmBackupAudioCurrentOverrideRequest( message ); + break; + + case MSG_ID_HD_SYRINGE_PUMP_STATUS_OVERRIDE: + handleTestSyringePumpStatusOverrideRequest( message ); + break; + + case MSG_ID_HD_SYRINGE_PUMP_ENCODER_STATUS_OVERRIDE: + handleTestSyringePumpEncoderStatusOverrideRequest( message ); + break; + + case MSG_ID_HD_SYRINGE_PUMP_ADC_DAC_STATUS_OVERRIDE: + handleTestSyringePumpADCandDACStatusOverrideRequest( message ); + break; + + case MSG_ID_HD_SYRINGE_PUMP_ADC_READ_COUNTER_OVERRIDE: + handleTestSyringePumpADCReadCtrOverrideRequest( message ); + break; + + case MSG_ID_HD_SET_CALIBRATION_RECORD: + handleSetHDCalibrationRecord( message ); + break; + + case MSG_ID_HD_GET_CALIBRATION_RECORD: + handleGetHDCalibrationRecord( message ); + break; + + case MSG_ID_HD_SET_SYSTEM_RECORD: + handleSetHDSystemRecord( message ); + break; + + case MSG_ID_HD_GET_SYSTEM_RECORD: + handleGetHDSystemRecord( message ); + break; + + case MSG_ID_HD_GET_SERVICE_RECORD: + handleGetHDServiceRecord( message ); + break; + + case MSG_ID_HD_SET_SERVICE_RECORD: + handleSetHDServiceRecord( message ); + break; + default: // Unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -red6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision ed6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -497,6 +497,38 @@ return result; } +/*********************************************************************//** + * @brief + * The sendAlarmAudioVolumeSetResponse function constructs an alarm audio + * volume set request response to the UI and queues the msg for transmit on the + * appropriate CAN channel. + * @details Inputs: none + * @details Outputs: Alarm audio volume set. + * @param accepted flag indicating whether request was accepted + * @param rejReason rejection reason code + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendAlarmAudioVolumeSetResponse( U32 accepted, U32 rejReason ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_ALARM_AUDIO_VOLUME_SET_RESPONSE; + msg.hdr.payloadLen = sizeof( U32 ) * 2; + + memcpy( payloadPtr, &accepted, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &rejReason, sizeof( U32 ) ); + + // 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_HD_2_UI, ACK_REQUIRED ); + + return result; +} + /*********************************************************************//** * @brief * The sendTreatmentParamsRangesToUI function constructs a treatment parameter @@ -1211,27 +1243,72 @@ * The handleDGCmdResp function handles a DG command response message. * @details Inputs: none * @details Outputs: message handled, response constructed and queued for transmit. - * @param messagePtr pointer to the message to handle. + * @param message pointer to the message to handle. * @return none *************************************************************************/ -void handleDGCmdResp( MESSAGE_T *messagePtr ) +void handleDGCmdResp( MESSAGE_T *message ) { BOOL result = FALSE; - if ( messagePtr->hdr.payloadLen == sizeof( DG_CMD_RESPONSE_T ) ) + if ( message->hdr.payloadLen == sizeof( DG_CMD_RESPONSE_T ) ) { DG_CMD_RESPONSE_T dgCmdResponse; result = TRUE; - memcpy( &dgCmdResponse, messagePtr->payload, sizeof( DG_CMD_RESPONSE_T ) ); + memcpy( &dgCmdResponse, message->payload, sizeof( DG_CMD_RESPONSE_T ) ); handleDGCommandResponse( &dgCmdResponse ); } - sendAckResponseMsg( (MSG_ID_T)messagePtr->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_DG, result ); + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_DG, result ); } /*********************************************************************//** * @brief + * The handleUIClockSyncRequest function handles a UI clock sync message. + * @details Inputs: none + * @details Outputs: message handled, response constructed and queued for transmit. + * @param messagePtr pointer to the message to handle. + * @return none + *************************************************************************/ +void handleUIClockSyncRequest( MESSAGE_T *message ) +{ + BOOL result = FALSE; + U32 rejReason = REQUEST_REJECT_REASON_NONE; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + if ( message->hdr.payloadLen == sizeof( U32 ) ) + { + U32 epoch; + + memcpy( &epoch, message->payload, sizeof( U32 ) ); + result = setRTCEpoch( epoch ); + if ( FALSE == result ) + { + rejReason = REQUEST_REJECT_REASON_INVALID_DATE_OR_TIME; + } + } + else + { + rejReason = REQUEST_REJECT_REASON_INVALID_REQUEST_FORMAT; + } + + // Create a response message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_UI_SET_RTC_RESPONSE; + msg.hdr.payloadLen = sizeof( BOOL ) + sizeof( U32 ); + memcpy( payloadPtr, &result, sizeof( BOOL ) ); + payloadPtr += sizeof( BOOL ); + memcpy( payloadPtr, &rejReason, sizeof( U32 ) ); + + // 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_HD_2_UI, ACK_REQUIRED ); + + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_UI, result ); +} + +/*********************************************************************//** + * @brief * The handleDGOpMode function handles a DG broadcast of its current mode. * @details Inputs: none * @details Outputs: message handled, response constructed and queued for transmit. @@ -1337,14 +1414,43 @@ 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 ); payload.alarmsFlags |= ( almStatus.lampOn ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_LAMP_ON) : 0 ); - payload.alarmsFlags |= ( almStatus.topAlarmConditionnDetected ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_TOP_CONDITION) : 0 ); + payload.alarmsFlags |= ( almStatus.noMinimize ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_MINIMIZE) : 0 ); + payload.alarmsFlags |= ( almStatus.topAlarmConditionDetected ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_TOP_CONDITION) : 0 ); memcpy( payloadPtr, &payload, sizeof( ALARM_COMP_STATUS_PAYLOAD_T ) ); // 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_HD_ALARM, ACK_NOT_REQUIRED ); return result; +} + +/*********************************************************************//** + * @brief + * The broadcastAlarmInfo function constructs an alarm information msg to + * be broadcast and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: alarm information msg constructed and queued. + * @param data alarm information record + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastAlarmInfo( ALARM_INFO_PAYLOAD_T data ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_ALARM_INFORMATION; + msg.hdr.payloadLen = sizeof( ALARM_INFO_PAYLOAD_T ); + + memcpy( payloadPtr, &data, sizeof( ALARM_INFO_PAYLOAD_T ) ); + + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); + + return result; } /*********************************************************************//** @@ -1608,6 +1714,34 @@ result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_BROADCAST, ACK_NOT_REQUIRED ); return result; +} + +/*********************************************************************//** + * @brief + * The broadcastVoltagesData function constructs a monitored voltages data msg to + * be broadcast and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: monitored voltages data msg constructed and queued. + * @param data Latest monitored voltage values. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastVoltagesData( VOLTAGES_DATA_PAYLOAD_T data ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_VOLTAGES_DATA; + msg.hdr.payloadLen = sizeof( VOLTAGES_DATA_PAYLOAD_T ); + + memcpy( payloadPtr, &data, sizeof( VOLTAGES_DATA_PAYLOAD_T ) ); + + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); + + return result; } /*********************************************************************//** @@ -2138,6 +2272,41 @@ /***********************************************************************//** * @brief + * The broadcastBubblesData function constructs an HD air bubble data msg to \n + * be broadcasted and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: air bubbles data msg constructed and queued + * @param status air bubbles status + * @param state air bubbles states + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastBubblesData( U32 statusADA, U32 stateADA, U32 statusADV, U32 stateADV ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_BUBBLES_DATA; + msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ) + sizeof( U32 ) + sizeof( U32 ); + + memcpy( payloadPtr, &statusADA, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &stateADA, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &statusADV, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &stateADV, sizeof( U32 ) ); + + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); + + return result; +} + +/***********************************************************************//** + * @brief * The broadcastPrimeData function constructs a prime data msg to \n * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details Inputs: none @@ -2401,14 +2570,24 @@ *************************************************************************/ void handleUIAlarmSilenceRequest( MESSAGE_T *message ) { +#ifndef TEMP_UI_ALARM_SILENCE_FIX if ( message->hdr.payloadLen == sizeof( U32 ) ) +#else + if ( message->hdr.payloadLen == sizeof( U08 ) ) +#endif { U08 *payloadPtr = message->payload; +#ifndef TEMP_UI_ALARM_SILENCE_FIX U32 cmd; memcpy( &cmd, payloadPtr, sizeof( U32 ) ); + signalAlarmSilence( (ALARM_SILENCE_CMD_T)cmd ); +#else + U08 cmd; + memcpy( &cmd, payloadPtr, sizeof( U08 ) ); signalAlarmSilence( (ALARM_SILENCE_CMD_T)cmd ); +#endif } else { @@ -2444,6 +2623,117 @@ } } +/*********************************************************************//** + * @brief + * The sendPOSTTestResult function constructs an HD POST test result message + * and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: HD POST test result msg constructed and queued. + * @param test ID of HD POST test + * @param passed TRUE if POST test passed, FALSE if not + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendPOSTTestResult( HD_POST_STATE_T test, BOOL passed ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + U32 testID = (U32)test; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_POST_SINGLE_TEST_RESULT; + msg.hdr.payloadLen = sizeof( BOOL ) + sizeof( U32 ); + + memcpy( payloadPtr, &passed, sizeof( BOOL ) ); + payloadPtr += sizeof( BOOL ); + memcpy( payloadPtr, &testID, sizeof( U32) ); + + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); // TODO - make ack required when UI ready + + return result; + +} + +/*********************************************************************//** + * @brief + * The sendPOSTFinalResult function constructs an HD POST final result message + * and queues the msg for transmit on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: HD POST final result msg constructed and queued. + * @param passed TRUE if HD POST passed, FALSE if not + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendPOSTFinalResult( BOOL passed ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_POST_FINAL_TEST_RESULT; + msg.hdr.payloadLen = sizeof( BOOL ); + + memcpy( payloadPtr, &passed, sizeof( BOOL ) ); + + // 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_HD_BROADCAST, ACK_NOT_REQUIRED ); // TODO - make ack required when UI ready + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDGPOSTFinalResult function handles a DG POST final result message. + * @details Inputs: none + * @details Outputs: DG POST final result delivered to InitPOST mode. + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleDGPOSTFinalResult( MESSAGE_T *message ) +{ + if ( message->hdr.payloadLen == sizeof( BOOL ) ) + { + U08 *payloadPtr = message->payload; + BOOL passed; + + memcpy( &passed, payloadPtr, sizeof( BOOL ) ); + + // TODO - handle DG POST final result + } + else + { + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_UI, FALSE ); + } +} + +/*********************************************************************//** + * @brief + * The handleUIPOSTFinalResult function handles a UI POST final result message. + * @details Inputs: none + * @details Outputs: UI POST final result delivered to InitPOST mode. + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleUIPOSTFinalResult( MESSAGE_T *message ) +{ + if ( message->hdr.payloadLen == sizeof( BOOL ) ) + { + U08 *payloadPtr = message->payload; + BOOL passed; + + memcpy( &passed, payloadPtr, sizeof( BOOL ) ); + + // TODO - handle UI POST final result + } + else + { + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_UI, FALSE ); + } +} + /*********************************************************************//** * @brief * The handleOffButtonConfirmMsgFromUI function handles a response to an @@ -3004,6 +3294,31 @@ /*********************************************************************//** * @brief + * The handleAlarmAudioVolumeSetCmd function handles a alarm audio volume + * set request message from the UI. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleAlarmAudioVolumeSetCmd( MESSAGE_T *message ) +{ + if ( sizeof( U32 ) == message->hdr.payloadLen ) + { + U32 payload; + + memcpy( &payload, &message->payload[0], sizeof( U32 ) ); + + setAlarmAudioVolume( payload ); + } + else + { + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_HD_2_UI, FALSE ); + } +} + +/*********************************************************************//** + * @brief * The handleSalineBolusRequest function handles a saline bolus request * message from the UI. * @details Inputs: none @@ -5140,6 +5455,96 @@ /*********************************************************************//** * @brief + * The handleSetBubblesDataBroadcastIntervalOverrideRequest function handles a + * request to override the air bubble detectors data broadcast interval. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleSetBubblesDataBroadcastIntervalOverrideRequest( 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 = testSetBubblesDataPublishIntervalOverride( (U32)( payload.state.u32 ) ); + } + else + { + result = testResetBubblesDataPublishIntervalOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleSetBubbleStatusOverrideRequest function handles a request to + * override a given air bubble detector status. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleSetBubbleStatusOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // Verify payload length + if ( sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_ARRAY_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetBubbleStatusOverride( (BUBBLE_STATUS_T)payload.state.u32, (BUBBLES_T)payload.index ); + } + else + { + result = testResetBubbleStatusOverride( (BUBBLES_T)payload.index ); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleBubbleSelfTestRequest function handles a request to + * self-test a given air bubble detector. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleBubbleSelfTestRequest( MESSAGE_T *message ) +{ + U32 payload; + BOOL result = FALSE; + + // Verify payload length + if ( sizeof( U32 ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( U32 ) ); + result = TRUE; + selfTestBubble( (BUBBLES_T)payload ); + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief * The handleHDSoftwareResetRequest function handles a request to reset the * HD firmware processor. * @details Inputs: none @@ -5710,4 +6115,356 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } +/*********************************************************************//** + * @brief + * The handleTestMonitoredVoltagesSendIntervalOverrideRequest function handles a + * request to override the monitored HD voltages data publication interval. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestMonitoredVoltagesSendIntervalOverrideRequest( 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 = testSetVoltagesDataPublishIntervalOverride( payload.state.u32 ); + } + else + { + result = testResetVoltagesDataPublishIntervalOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestMonitoredVoltageOverrideRequest function handles a + * request to override the monitored HD voltage override. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestMonitoredVoltageOverrideRequest( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // Verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + if ( FALSE == payload.reset ) + { + result = testSetLineLevelOverride( payload.index, payload.state.f32 ); + } + else + { + result = testResetLineLevelOverride( payload.index ); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestAlarmInfoSendIntervalOverrideRequest function handles a + * request to override the HD alarm information broadcast interval. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestAlarmInfoSendIntervalOverrideRequest( 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 = testSetAlarmInfoPublishIntervalOverride( payload.state.u32 ); + } + else + { + result = testResetAlarmInfoPublishIntervalOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestAlarmAudioVolumeOverrideRequest function handles a + * request to override the alarm audio volume level. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestAlarmAudioVolumeOverrideRequest( 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 = testSetAlarmAudioVolumeLevelOverride( payload.state.u32 ); + } + else + { + result = testResetAlarmAudioVolumeLevelOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestAlarmAudioCurrentHgOverrideRequest function handles a + * request to override the alarm audio (high gain) current. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestAlarmAudioCurrentHgOverrideRequest( 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 = testSetPrimaryAlarmAudioCurrentHGOverride( payload.state.f32 ); + } + else + { + result = testResetPrimaryAlarmAudioCurrentHGOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestAlarmAudioCurrentLgOverrideRequest function handles a + * request to override the alarm audio (low gain) current. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestAlarmAudioCurrentLgOverrideRequest( 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 = testSetPrimaryAlarmAudioCurrentLGOverride( payload.state.f32 ); + } + else + { + result = testResetPrimaryAlarmAudioCurrentLGOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestAlarmBackupAudioCurrentOverrideRequest function handles a + * request to override the backup alarm audio current. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestAlarmBackupAudioCurrentOverrideRequest( 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 = testSetBackupAlarmAudioCurrentOverride( payload.state.f32 ); + } + else + { + result = testResetBackupAlarmAudioCurrentOverride(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestSyringePumpStatusOverrideRequest function handles a + * request to override the syringe pump status. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestSyringePumpStatusOverrideRequest( 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 = testSetSyringePumpStatus( payload.state.u32 ); + } + else + { + result = testResetSyringePumpStatus(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestSyringePumpEncoderStatusOverrideRequest function handles a + * request to override the syringe pump encoder status. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestSyringePumpEncoderStatusOverrideRequest( 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 = testSetSyringePumpEncoderStatus( payload.state.u32 ); + } + else + { + result = testResetSyringePumpEncoderStatus(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestSyringePumpADCandDACStatusOverrideRequest function handles a + * request to override the syringe pump ADC & DAC status. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestSyringePumpADCandDACStatusOverrideRequest( 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 = testSetSyringePumpADCandDACStatus( payload.state.u32 ); + } + else + { + result = testResetSyringePumpADCandDACStatus(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestSyringePumpADCReadCtrOverrideRequest function handles a + * request to override the syringe pump ADC read counter. + * @details Inputs: none + * @details Outputs: message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestSyringePumpADCReadCtrOverrideRequest( 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 = testSetSyringePumpADCReadCounter( payload.state.u32 ); + } + else + { + result = testResetSyringePumpADCReadCounter(); + } + } + + // Respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -red6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9 -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision ed6e1e131ccb7a9a586cfb766ea270fc3cbdc1c9) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -22,6 +22,7 @@ #include "BloodFlow.h" #include "BloodLeak.h" #include "BloodPrime.h" +#include "Bubble.h" #include "DGInterface.h" #include "DialInFlow.h" #include "DialOutFlow.h" @@ -38,6 +39,7 @@ #include "Rinseback.h" #include "SyringePump.h" #include "Valves.h" +#include "Voltages.h" /** * @defgroup SystemCommMessages SystemCommMessages @@ -80,6 +82,18 @@ // MSG_ID_ALARM_CONDITION_CLEARED void handleAlarmUserAction( MESSAGE_T *message ); +// MSG_ID_HD_POST_SINGLE_TEST_RESULT +BOOL sendPOSTTestResult( HD_POST_STATE_T test, BOOL passed ); + +// MSG_ID_HD_POST_FINAL_TEST_RESULT +BOOL sendPOSTFinalResult( BOOL passed ); + +// MSG_ID_DG_POST_FINAL_TEST_RESULT +void handleDGPOSTFinalResult( MESSAGE_T *message ); + +// MSG_ID_UI_POST_FINAL_TEST_RESULT +void handleUIPOSTFinalResult( MESSAGE_T *message ); + // MSG_ID_LOAD_CELL_READINGS void handleLoadCellReadingsFromDG( MESSAGE_T *message ); @@ -176,6 +190,12 @@ // MSG_ID_HD_HEPARIN_PAUSE_RESUME_RESPONSE BOOL sendHeparinCommandResponse( U32 accepted, U32 rejReason ); +// MSG_ID_UI_SET_ALARM_AUDIO_VOLUME_LEVEL_CMD +void handleAlarmAudioVolumeSetCmd( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_AUDIO_VOLUME_SET_RESPONSE +BOOL sendAlarmAudioVolumeSetResponse( U32 accepted, U32 rejReason ); + // MSG_ID_UI_SAMPLE_WATER_CMD void handleSampleWaterCmd( MESSAGE_T *message ); @@ -282,6 +302,9 @@ // MSG_ID_DG_COMMAND_RESPONSE void handleDGCmdResp( MESSAGE_T *messagePtr ); + +// MSG_ID_UI_HD_SET_RTC_REQUEST: +void handleUIClockSyncRequest( MESSAGE_T *message ); // MSG_ID_DG_OP_MODE void handleDGOpMode( MESSAGE_T *message ); @@ -292,7 +315,10 @@ BOOL broadcastAccelData( F32 x, F32 y, F32 z, F32 xm, F32 ym, F32 zm, F32 xt, F32 yt, F32 zt ); // MSG_ID_ALARM_STATUS -BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); +BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); + +// MSG_ID_HD_ALARM_INFORMATION +BOOL broadcastAlarmInfo( ALARM_INFO_PAYLOAD_T data ); // MSG_ID_ALARM_TRIGGERED BOOL broadcastAlarmTriggered( U32 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); @@ -323,6 +349,9 @@ // MSG_ID_PRESSURE_OCCLUSION_DATA BOOL broadcastPresOcclData( PRESSURE_OCCLUSION_DATA_T data ); + +// MSG_ID_HD_VOLTAGES_DATA +BOOL broadcastVoltagesData( VOLTAGES_DATA_PAYLOAD_T data ); // MSG_ID_RTC_EPOCH BOOL broadcastRTCEpoch( U32 epoch ); @@ -378,6 +407,9 @@ // MSG_ID_HD_BLOOD_LEAK_DATA BOOL broadcastBloodLeakData( BLOOD_LEAK_STATUS_T status, U32 state ); +// MSG_ID_HD_BUBBLES_DATA +BOOL broadcastBubblesData( U32 statusADA, U32 stateADA, U32 statusADV, U32 stateADV ); + // MSG_ID_HD_PRIMING_STATUS_DATA BOOL broadcastPrimeData( PRIMING_DATA_PAYLOAD_T *primeDataPtr ); @@ -555,9 +587,6 @@ void handleSetHDValvePWMOverrideRequest( MESSAGE_T *message ); #endif -// MSG_ID_HD_SET_PARAMETER_TREATMENT_PARAMETER -void handleTestSetTreatmentParameter( MESSAGE_T *message ); - // MSG_ID_HD_SOFTWARE_RESET_REQUEST void handleHDSoftwareResetRequest( MESSAGE_T *message ); @@ -591,6 +620,15 @@ // MSG_ID_HD_BLOOD_LEAK_ZERO_REQUEST void handleBloodLeakZeroRequest( MESSAGE_T *message ); +// MSG_ID_HD_BUBBLES_DATA_SEND_INTERVAL_OVERRIDE +void handleSetBubblesDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_BUBBLE_STATUS_OVERRIDE +void handleSetBubbleStatusOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_BUBBLE_SELF_TEST_REQUEST +void handleBubbleSelfTestRequest( MESSAGE_T *message ); + // MSG_ID_SUPER_CLEAR_ALARMS_CMD void handleTestSuperClearAlarmsRequest( MESSAGE_T *message ); @@ -642,6 +680,39 @@ // MSG_ID_HD_SYRINGE_PUMP_MEASURED_VOLUME_OVERRIDE: void handleTestSyringePumpMeasuredVolumeOverrideRequest( MESSAGE_T *message ); +// MSG_ID_HD_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE +void handleTestMonitoredVoltagesSendIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_MONITORED_VOLTAGES_OVERRIDE +void handleTestMonitoredVoltageOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_INFO_SEND_INTERVAL_OVERRIDE +void handleTestAlarmInfoSendIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_AUDIO_VOLUME_LEVEL_OVERRIDE +void handleTestAlarmAudioVolumeOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_AUDIO_CURRENT_HG_OVERRIDE +void handleTestAlarmAudioCurrentHgOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_AUDIO_CURRENT_LG_OVERRIDE +void handleTestAlarmAudioCurrentLgOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_ALARM_BACKUP_AUDIO_CURRENT_OVERRIDE +void handleTestAlarmBackupAudioCurrentOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_SYRINGE_PUMP_STATUS_OVERRIDE +void handleTestSyringePumpStatusOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_SYRINGE_PUMP_ENCODER_STATUS_OVERRIDE +void handleTestSyringePumpEncoderStatusOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_SYRINGE_PUMP_ADC_DAC_STATUS_OVERRIDE +void handleTestSyringePumpADCandDACStatusOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HD_SYRINGE_PUMP_ADC_READ_COUNTER_OVERRIDE +void handleTestSyringePumpADCReadCtrOverrideRequest( MESSAGE_T *message ); + /**@}*/ #endif Index: firmware/HD.dil =================================================================== diff -u -r850f74b97895fd0f6c4728541ac2582f7b5c5a0b -r44a100f8e5210a02c23b8fcc4527d8e96d577381 --- firmware/HD.dil (.../HD.dil) (revision 850f74b97895fd0f6c4728541ac2582f7b5c5a0b) +++ firmware/HD.dil (.../HD.dil) (revision 44a100f8e5210a02c23b8fcc4527d8e96d577381) @@ -7020,12 +7020,12 @@ DRIVER.I2C.VAR.I2C_DATACOUNT.VALUE=8 DRIVER.I2C.VAR.I2C_ADDRMODE.VALUE=7BIT_AMODE DRIVER.I2C.VAR.I2C_PORT_BIT0_FUN.VALUE=0 -DRIVER.I2C.VAR.I2C_PORT_BIT0_PDR.VALUE=0 +DRIVER.I2C.VAR.I2C_PORT_BIT0_PDR.VALUE=1 DRIVER.I2C.VAR.I2C_BC_VALUE.VALUE=0x0003 DRIVER.I2C.VAR.I2C_PORT_BIT1_FUN.VALUE=0 DRIVER.I2C.VAR.I2C_RM_ENA.VALUE=1 DRIVER.I2C.VAR.I2C_BC.VALUE=8_BIT -DRIVER.I2C.VAR.I2C_PORT_BIT1_PDR.VALUE=0 +DRIVER.I2C.VAR.I2C_PORT_BIT1_PDR.VALUE=1 DRIVER.I2C.VAR.I2C_TXRX_VALUE.VALUE=0 DRIVER.I2C.VAR.I2C_SCDLVL.VALUE=0 DRIVER.I2C.VAR.I2C_PORT_BIT0_PSL.VALUE=1