Index: firmware/App/Controllers/AirPump.c =================================================================== diff -u -r64f2edc1b7ec8edda7e500b10c09c2a54dc70fc9 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Controllers/AirPump.c (.../AirPump.c) (revision 64f2edc1b7ec8edda7e500b10c09c2a54dc70fc9) +++ firmware/App/Controllers/AirPump.c (.../AirPump.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -63,7 +63,7 @@ currentAirPumpState = AIR_PUMP_STATE_INIT; airPumpDataPublishInterval.data = AIR_PUMP_DATA_PUB_INTERVAL; airPumpDataPublishInterval.ovData = AIR_PUMP_DATA_PUB_INTERVAL; - airPumpDataPublishInterval.ovInitData = 0; + airPumpDataPublishInterval.ovInitData = AIR_PUMP_DATA_PUB_INTERVAL; airPumpDataPublishInterval.override = OVERRIDE_RESET; } @@ -189,7 +189,7 @@ *************************************************************************/ static void publishAirPumpData( void ) { - if (++airPumpDataPublicationTimerCounter >= getU32OverrideValue( &airPumpDataPublishInterval ) ) + if ( ++airPumpDataPublicationTimerCounter >= getU32OverrideValue( &airPumpDataPublishInterval ) ) { AIR_PUMP_PAYLOAD_T data; Index: firmware/App/Controllers/AirTrap.c =================================================================== diff -u --- firmware/App/Controllers/AirTrap.c (revision 0) +++ firmware/App/Controllers/AirTrap.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,486 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file AirTrap.c +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#include "AirPump.h" +#include "AirTrap.h" +#include "AlarmMgmtTD.h" +#include "LevelSensors.h" +#include "Messaging.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" +#include "Pressures.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "Utilities.h" +#include "Valve2Way.h" + +/** + * @addtogroup AirTrap + * @{ + */ + +// ********** private definitions ********** + +#define AIR_TRAP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the air trap data is published on the CAN bus. +#define AIR_TRAP_FILL_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Air trap fill timeout period (in ms). +#define AIR_PUMP_ON_DELAY_TIME_MS ( 10 * MS_PER_SECOND ) ///< Delay between air pump On (in ms). +#define AIR_PUMP_ON_STOP_TIME_MIN_MS 200 ///< Stop air Pump time. +#define AIR_PUMP_ON_ERROR_MAX_CNT 6 ///< Maximum number of air pump on events within time window before alarm triggered. Do not exceed MAX_TIME_WINDOWED_COUNT. +#define AIR_PUMP_ON_ERROR_TIME_WIN_MS ( 60 * MS_PER_SECOND ) ///< Time window for Air Pump on count error. +#define AIR_TRAP_ILLEGAL_LEVELS_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Air trap illegal values timeout (in ms) +#define VENOUS_LINE_VOLUME_ML ( 200.0F ) ///< Volume (in mL) of venous portion of blood circuit line. TODO - get actual volume from Systems. +#define DATA_PUBLISH_COUNTER_START_COUNT 7 ///< Data publish counter start count. + +/// Air pump on delay after fill adjustment +static const U32 AIR_PUMP_ON_DELAY_ADJUST_AFTER_FILL = ( AIR_PUMP_ON_DELAY_TIME_MS - ( 1 * MS_PER_SECOND ) ); + +/// Defined states for the air trap controller state machine. +typedef enum AirTrap_States +{ + AIR_TRAP_INIT_STATE = 0, ///< Initialization state + AIR_TRAP_MANUAL_CONTROL_STATE, ///< Manually control air trap valve state + AIR_TRAP_VALVE_CLOSED_STATE, ///< Valve closed state - until air detected at lower level + AIR_TRAP_VALVE_OPEN_STATE, ///< Valve open state - until fluid detected at upper level + NUM_OF_AIR_TRAP_STATES ///< Number of air trap controller states +} AIR_TRAP_STATE_T; + +// ********** private data ********** + +static AIR_TRAP_STATE_T airTrapControllerState; ///< Current state of air trap controller state machine. + +static U32 airTrapDataPublicationTimerCounter; ///< Used to schedule air trap data publication to CAN bus. +static OVERRIDE_U32_T airTrapDataPublishInterval; ///< Interval (in ms) at which to publish air trap data to CAN bus. + +static BOOL pendingStartAirTrapController = FALSE; ///< Flag indicates an air trap controller start request is pending. +static BOOL pendingStopAirTrapController = FALSE; ///< Flag indicates an air trap controller stop request is pending. + +static U32 fillStartTime; ///< Time stamp for start of air trap fill. + +static U32 airPumpOnDelayStartTime; ///< Air pump On start time. +static U32 stopAirPumpStartTime; ///< Stop air pump start time. + +static BOOL airTrapValveOpenAtStartOfTreatement; ///< To Keep the fluid level high close to Air trap upper level during start of treatment + +// ********** private function prototypes ********** + +static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ); +static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ); +static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ); +static void publishAirTrapData( void ); + +/*********************************************************************//** + * @brief + * The initAirTrap function initializes the air trap controller unit. + * @details \b Inputs: none + * @details \b Outputs: Air trap controller unit initialized + * @return none + *************************************************************************/ +void initAirTrap(void) +{ + // Initialize level sensors and valve drivers + initLevelSensors(); + init2WayValves(); + + // Initialize controller variables + resetAirTrap(); + airTrapDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + airTrapDataPublishInterval.data = AIR_TRAP_DATA_PUB_INTERVAL; + airTrapDataPublishInterval.ovData = AIR_TRAP_DATA_PUB_INTERVAL; + airTrapDataPublishInterval.ovInitData = AIR_TRAP_DATA_PUB_INTERVAL; + airTrapDataPublishInterval.override = OVERRIDE_RESET; + fillStartTime = 0; + airPumpOnDelayStartTime = 0; + stopAirPumpStartTime = 0; + airTrapValveOpenAtStartOfTreatement = FALSE; +} + +/*********************************************************************//** + * @brief + * The resetAirTrap function resets certain parts of the air trap module + * between treatments. + * @details \b Inputs: none + * @details \b Outputs: Air Trap controller reset. + * @return none + *************************************************************************/ +void resetAirTrap( void ) +{ + airTrapControllerState = AIR_TRAP_INIT_STATE; + pendingStartAirTrapController = FALSE; + pendingStopAirTrapController = FALSE; +} + +/*********************************************************************//** + * @brief + * The startAirTrapControl function requests a start to air trap control. + * @details \b Inputs: airTrapControllerState + * @details \b Outputs: pendingStartAirTrapController + * @return none + *************************************************************************/ +void startAirTrapControl( void ) +{ + if ( FALSE == isAirTrapControlling() ) + { + pendingStartAirTrapController = TRUE; + } +} + +/*********************************************************************//** + * @brief + * The endAirTrapControl function requests a stop to air trap control. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if air trap control ended. + * @details \b Inputs: airTrapControllerState + * @details \b Outputs: pendingStopAirTrapController + * @return none + *************************************************************************/ +void endAirTrapControl( void ) +{ + if ( TRUE == isAirTrapControlling() ) + { + pendingStopAirTrapController = TRUE; + set2WayValveState( VALVE_2_WAY_VBT, STATE_CLOSED ); // Always exit air trap valve control w/ valve closed. + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_CLOSED, 0 ); + signalLowVenousPressureCheck(); // Venous pressure check should continue even after ending auto air trap control + } +} + +/*********************************************************************//** + * @brief + * The isAirTrapControlling function determines whether the air trap is + * currently controlling. + * @details \b Inputs: airTrapControllerState + * @details \b Outputs: none + * @return TRUE if air trap is currently controlling, FALSE if not. + *************************************************************************/ +BOOL isAirTrapControlling( void ) +{ + BOOL result = FALSE; + + if ( airTrapControllerState >= AIR_TRAP_VALVE_CLOSED_STATE ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execAirTrapMonitor function executes the air trap monitor. + * @details \b Alarm: ALARM_ID_TD_AIR_TRAP_ILLEGAL_LEVELS if upper level + * sensor detects liquid while the lower level sensor detects air. + * @details \b Inputs: air trap level sensor readings + * @details \b Outputs: none + * @return none + *************************************************************************/ +void execAirTrapMonitor( void ) +{ + BOOL isAirTrapLevelsValid = FALSE; + AIR_TRAP_LEVELS_T lowerAirTrap, upperAirTrap; + + // Check for illegal levels alarm + if ( TRUE ) // TODO - need a way to determine whether a blood set is installed - if not installed, we would not trigger illegal levels alarm + { + // If the pump track on open, zero the persistent counter to not check the air trap illegal level alarm + checkPersistentAlarm( ALARM_ID_TD_AIR_TRAP_ILLEGAL_LEVELS, FALSE, 0.0, 0.0 ); + } + else + { + lowerAirTrap = getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_LOWER ); + upperAirTrap = getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ); + isAirTrapLevelsValid = ( ( ( AIR_TRAP_LEVEL_AIR == lowerAirTrap ) && ( AIR_TRAP_LEVEL_FLUID == upperAirTrap ) ) ? TRUE : FALSE ); + +#ifndef _RELEASE_ +// if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ILLEGAL_AIR_TRAP_ALARM ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + checkPersistentAlarm( ALARM_ID_TD_AIR_TRAP_ILLEGAL_LEVELS, isAirTrapLevelsValid, lowerAirTrap, upperAirTrap ); + } + } +} + +/*********************************************************************//** + * @brief + * The execAirTrapMonitorTreatment function executes the air trap monitor + * for treatment mode. + * @details \b Alarm: ALARM_ID_TD_AIR_TRAP_FILL_DURING_TREATMENT if air trap + * fill exceeds maximum allowed time to complete. + * @details \b Inputs: airTrapControllerState, fillStartTime + * @details \b Outputs: none + * @return none + *************************************************************************/ +void execAirTrapMonitorTreatment( void ) +{ + // Check air trap fill timeout during treatment + if ( AIR_TRAP_VALVE_OPEN_STATE == airTrapControllerState ) + { + if ( TRUE == didTimeout( fillStartTime, AIR_TRAP_FILL_TIMEOUT_MS ) ) + { +#ifndef _RELEASE_ +// if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_AIR_TRAP_LEVELING_ALARM ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + activateAlarmNoData( ALARM_ID_TD_AIR_TRAP_FILL_DURING_TREATMENT ); + } + } + } +} + +/*********************************************************************//** + * @brief + * The execAirTrapController function executes the air trap control state machine. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if current air trap control + * state is invalid. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if air trap valve closed due to fault. + * @details \b Inputs: airTrapControllerState + * @details \b Outputs: airTrapControllerState + * @return none + *************************************************************************/ +void execAirTrapController( void ) +{ + // If we have faulted, close valve and go to manual control + if ( MODE_FAUL == getCurrentOperationMode() ) + { + airTrapControllerState = AIR_TRAP_MANUAL_CONTROL_STATE; + set2WayValveState( VALVE_2_WAY_VBT, STATE_CLOSED ); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_CLOSED, 0 ); + pendingStartAirTrapController = FALSE; + } + + // Execute air trap state machine + switch( airTrapControllerState ) + { + case AIR_TRAP_INIT_STATE: + airTrapControllerState = AIR_TRAP_MANUAL_CONTROL_STATE; + break; + + case AIR_TRAP_MANUAL_CONTROL_STATE: + airTrapControllerState = handleAirTrapManualControlState(); + break; + + case AIR_TRAP_VALVE_CLOSED_STATE: + airTrapControllerState = handleAirTrapValveClosedState(); + break; + + case AIR_TRAP_VALVE_OPEN_STATE: + airTrapControllerState = handleAirTrapValveOpenState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, (U32)SW_FAULT_ID_AIR_TRAP_INVALID_STATE, (U32)airTrapControllerState ) + airTrapControllerState = AIR_TRAP_INIT_STATE; + break; + } + + // Publish air trap data if due + publishAirTrapData(); +} + +/*********************************************************************//** + * @brief + * The handleAirTrapManualControlState function handles the manual control + * state of the air trap. + * @details \b Inputs: pendingStartAirTrapController + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_MANUAL_CONTROL_STATE; + + // Transition to valve control states when requested + if ( TRUE == pendingStartAirTrapController ) + { + pendingStartAirTrapController = FALSE; + set2WayValveState( VALVE_2_WAY_VBT, STATE_CLOSED ); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_CLOSED, 0 ); + result = AIR_TRAP_VALVE_CLOSED_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleAirTrapValveClosedState function handles the valve closed state + * of the air trap. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if opening air trap valve. + * @details \b Inputs: pendingStopAirTrapController + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_CLOSED_STATE; + + // Air pump stop time based on the blood flow rate + S32 qB = 0; // TODO abs( getTargetBloodFlowRate() ); + U32 qBx = 0; // TODO ( 0 == qB ? MIN_SET_BLOOD_FLOW_RATE : (U32)qB ); + U32 airPumpStopTime = 0; // TODO AIR_PUMP_ON_STOP_TIME_MIN_MS + ( ( qBx - MIN_SET_BLOOD_FLOW_RATE ) / 2 ); + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopAirTrapController ) + { + pendingStopAirTrapController = FALSE; + result = AIR_TRAP_MANUAL_CONTROL_STATE; + + if ( AIR_PUMP_STATE_ON == getAirPumpState() ) + { + setAirPumpState( AIR_PUMP_STATE_OFF ); + } + } + + // Open valve once at start of treatment (blood priming) + else if ( TRUE == airTrapValveOpenAtStartOfTreatement ) + { + airTrapValveOpenAtStartOfTreatement = FALSE; + if ( AIR_PUMP_STATE_ON == getAirPumpState() ) + { + setAirPumpState( AIR_PUMP_STATE_OFF ); + } + + set2WayValveState( VALVE_2_WAY_VBT, STATE_OPEN ); + fillStartTime = getMSTimerCount(); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_OPEN, 0 ); + result = AIR_TRAP_VALVE_OPEN_STATE; + } + + // Turn air pump off after defined time or air detected at upper level + else if ( ( AIR_PUMP_STATE_ON == getAirPumpState() ) && + ( ( TRUE == didTimeout( stopAirPumpStartTime, airPumpStopTime ) ) || + ( ( AIR_TRAP_LEVEL_AIR == getRawLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) && + ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) ) ) ) + + { + setAirPumpState( AIR_PUMP_STATE_OFF ); + airPumpOnDelayStartTime = getMSTimerCount(); + } + + // Turn on air pump if fluid reaches upper level. + else if ( AIR_TRAP_LEVEL_FLUID == getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) + { + if ( ( AIR_PUMP_STATE_OFF == getAirPumpState() ) && + ( TRUE == didTimeout( airPumpOnDelayStartTime, AIR_PUMP_ON_DELAY_TIME_MS ) ) ) + { + setAirPumpState( AIR_PUMP_STATE_ON ); + stopAirPumpStartTime = getMSTimerCount(); + signalInitiatePressureStabilization( USE_SHORT_STABILIZATION_PERIOD ); + } + } + + // Transition to open valve state when air detected at lower level + else if ( ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) && + ( AIR_TRAP_LEVEL_AIR == getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) ) + { + if ( AIR_PUMP_STATE_ON == getAirPumpState() ) + { + setAirPumpState( AIR_PUMP_STATE_OFF ); + } + + set2WayValveState( VALVE_2_WAY_VBT, STATE_OPEN ); + fillStartTime = getMSTimerCount(); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_OPEN, 0 ); + result = AIR_TRAP_VALVE_OPEN_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleAirTrapValveOpenState function handles the valve open state of + * the air trap. + * @details \b Message \b Sent: MSG_ID_TD_EVENT if closing air trap valve + * @details \b Inputs: pendingStopAirTrapController + * @details \b Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_OPEN_STATE; + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopAirTrapController ) + { + pendingStopAirTrapController = FALSE; + result = AIR_TRAP_MANUAL_CONTROL_STATE; + } + // Transition to closed valve state when fluid detected at upper level + else if ( AIR_TRAP_LEVEL_FLUID == getRawLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) + { + set2WayValveState( VALVE_2_WAY_VBT, STATE_CLOSED ); + airPumpOnDelayStartTime = u32DiffWithWrap( AIR_PUMP_ON_DELAY_ADJUST_AFTER_FILL, getMSTimerCount() ); + signalLowVenousPressureCheck(); + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_AIR_TRAP_FILL, STATE_CLOSED, 0 ); + result = AIR_TRAP_VALVE_CLOSED_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishAirTrapData function constructs and sends the air trap data + * broadcast message. + * @details \b Message \b Sent: MSG_ID_TD_AIR_TRAP_DATA + * @details \b Inputs: airTrapDataPublicationTimerCounter, airTrapControllerState, TODO valvestate + * @details \b Outputs: airTrapDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishAirTrapData( void ) +{ + // Publish air trap data on interval + if ( ++airTrapDataPublicationTimerCounter >= getU32OverrideValue( &airTrapDataPublishInterval ) ) + { + AIR_TRAP_PAYLOAD_T data; + + data.lowerLevel = getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_LOWER ); + data.upperLevel = getLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ); + data.rawLowerLevel = getRawLevelSensorState( AIR_TRAP_LEVEL_SENSOR_LOWER ); + data.rawUpperLevel = getRawLevelSensorState( AIR_TRAP_LEVEL_SENSOR_UPPER ); + data.valveState = get2WayValveState( VALVE_2_WAY_VBT ); + data.controlling = isAirTrapControlling(); + + broadcastData( MSG_ID_TD_AIR_TRAP_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( AIR_TRAP_PAYLOAD_T ) ); + airTrapDataPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testAirTrapDataPublishIntervalOverride function overrides the interval + * at which the TD air trap data is published. + * @details \b Inputs: none + * @details \b Outputs: airTrapDataPublishInterval + * @param message Override message from Dialin which includes the interval + * (in ms) to override the air trap broadcast interval to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testAirTrapDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &airTrapDataPublishInterval, TASK_GENERAL_INTERVAL ); + + return result; +} + +/**@}*/ + Index: firmware/App/Controllers/AirTrap.h =================================================================== diff -u --- firmware/App/Controllers/AirTrap.h (revision 0) +++ firmware/App/Controllers/AirTrap.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,63 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file AirTrap.h +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#ifndef __AIR_TRAP_H__ +#define __AIR_TRAP_H__ + +// ********** public definitions ********** + +#include "TDCommon.h" + +/** + * @defgroup AirTrap AirTrap + * @brief Air Trap controller unit. Provides high level control functionality + * to manage the fluid/blood level in the air trap. + * + * @addtogroup AirTrap + * @{ + */ + +// ********** public definitions ********** + +/// Payload record structure for air trap data broadcast message +typedef struct +{ + U32 lowerLevel; ///< Lower air trap level sensor state + U32 upperLevel; ///< Upper air trap level sensor state + U32 rawLowerLevel; ///< Raw Lower air trap level sensor state + U32 rawUpperLevel; ///< Raw Upper air trap level sensor state + U32 valveState; ///< Is air trap valve open or closed + BOOL controlling; ///< Flag indicates whether air trap level is being auto controlled +} AIR_TRAP_PAYLOAD_T; + +// ********** public function prototypes ********** + +void initAirTrap(void); +void resetAirTrap( void ); +void execAirTrapController(void); +void execAirTrapMonitor( void ); +void execAirTrapMonitorTreatment( void ); + +void startAirTrapControl( void ); +void endAirTrapControl( void ); +BOOL isAirTrapControlling( void ); + +BOOL testAirTrapDataPublishIntervalOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u --- firmware/App/Controllers/BloodFlow.c (revision 0) +++ firmware/App/Controllers/BloodFlow.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,1713 @@ +/************************************************************************** +* +* Copyright (c) 2019-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file BloodFlow.c +* +* @author (last) Sean Nash +* @date (last) 07-May-2024 +* +* @author (original) Sean Nash +* @date (original) 07-Nov-2019 +* +***************************************************************************/ + +#include // Used for fabs() functions + +#include "can.h" +#include "etpwm.h" +#include "gio.h" +#include "reg_het.h" + +#include "BloodFlow.h" +#include "CPLD.h" +#include "FPGA.h" +#include "InternalADC.h" +#include "NVDataMgmt.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" +#include "PIControllers.h" +#include "SafetyShutdown.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TaskPriority.h" +#include "Timers.h" +#include "Utilities.h" + +/** + * @addtogroup BloodFlow + * @{ + */ + +// ********** private definitions ********** + +/// Interval (ms/task time) at which the blood flow data is published on the CAN bus. +#define BLOOD_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) + +#define MAX_SETTABLE_BLOOD_FLOW_RATE 700 ///< Maximum settable blood flow rate (in mL/min). + +#define MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE 0.008F ///< Max duty cycle change when ramping up ~ 100 mL/min/s. +#define MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE 0.016F ///< Max duty cycle change when ramping down ~ 200 mL/min/s. +#define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.90F ///< Controller will error if PWM duty cycle > 90%, so set max to 89% +#define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.10F ///< Controller will error if PWM duty cycle < 10%, so set min to 10% + +#define BP_CONTROL_INTERVAL_SEC 10 ///< Blood pump control interval (in seconds). + +/// Interval (ms/task time) at which the blood pump is controlled. +static const U32 BP_CONTROL_INTERVAL = ( BP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); + +#define BP_P_COEFFICIENT 0.0001F ///< P term for blood pump control +#define BP_I_COEFFICIENT 0.00075F ///< I term for blood pump control + +#define BP_HOME_SPEED 400 ///< Target pump speed (in RPM) for homing. +#define BP_HOME_TIMEOUT_MS 10000 ///< Maximum time (in ms) allowed for homing to complete. +#define BP_MAX_ROTOR_HALL_INTERVAL_MS 20000 ///< Maximum time (in ms) allowed between rotor hall sensor detects (50 mL/min worst case). + +/// 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 ( MS_PER_SECOND / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) + +#define BP_MAX_ROTOR_SPEED_RPM 100.0F ///< Maximum rotor speed allowed for blood pump. +#define BP_MIN_ROTOR_PULSES_FOR_MAX_SPEED 2 ///< Minimum rotor pulses indicating excessive speed required for alarm. + +#define BP_MAX_FLOW_RATE 1320.0F ///< Maximum measured BP flow rate allowed. +#define BP_MIN_FLOW_RATE -1320.0F ///< Minimum measured BP flow rate allowed. +#define BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0F ///< Maximum motor speed (RPM) while motor is commanded off. +#define BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0F ///< Maximum difference in speed between motor and rotor (in rotor RPM). +#define BP_MAX_MOTOR_SPEED_ERROR_RPM 300.0F ///< Maximum difference in speed between measured and commanded RPM. +#define BP_MAX_MOTOR_SPEED_VS_TRGT_DIFF_PCT 0.15F ///< Maximum motor speed vs target difference in percent. + +/// Persist time (in ms) for motor off error condition. +static const U32 BP_OFF_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (in ms) motor speed error condition. +static const U32 BP_MOTOR_SPEED_ERROR_PERSIST = ( 5 * MS_PER_SECOND ); +/// Persist time (in ms) pump direction error condition. +static const U32 BP_DIRECTION_ERROR_PERSIST = ( 250 ); +/// Persist time period (in ms) blood pump rotor speed too fast error condition. +static const U32 BP_MAX_ROTOR_SPEED_ERROR_PERSIST = ( 10 * MS_PER_SECOND ); + +#define BP_MAX_CURR_WHEN_STOPPED_MA 150.0F ///< Motor controller current should not exceed this when pump should be stopped. +#define BP_MAX_CURR_WHEN_RUNNING_MA 2000.0F ///< Motor controller current should not exceed this when pump should be running. +#define BP_MAX_CURR_ERROR_DURATION_MS 5000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. + +#define BLOODPUMP_ADC_FULL_SCALE_V 3.0F ///< BP analog signals are 0-3V (while int. ADC ref may be different). +#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. + +/// Macro converts 12 bit ADC value to signed 16-bit value. +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) + +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752F ///< Conversion factor from ADC counts to RPM for blood pump motor (3500 RPM/1998 counts). +#define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238F ///< ~42 BP motor RPM = 1% PWM duty cycle. +#define BP_CURRENT_ADC_TO_MA_FACTOR 3.002F ///< Conversion factor from ADC counts to mA for blood pump motor. + +#define BP_REV_PER_LITER 146.84F ///< Rotor revolutions per liter. +#define BP_ML_PER_ROTOR_REV 6.81F ///< Milliliters per rotor revolusion. +#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to motor RPM. +#define BP_GEAR_RATIO 32.0F ///< Blood pump motor to blood pump gear ratio. +#define BP_PWM_ZERO_OFFSET 0.1F ///< 10 pct PWM duty cycle = zero speed. +#define BP_100_PCT_PWM_RPM_RANGE 4000.0F ///< 10-90% PWM range yields 0-3,200 RPM range. Full 100% PWM range would yield 4,000 RPM range. + +/// Conversion macro from mL/min to estimated PWM duty cycle %. +#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) +/// Conversion from PWM duty cycle % to commanded pump motor speed. +#define BP_PWM_TO_MOTOR_SPEED_RPM(pwm,dir) ( ( ((pwm) - BP_PWM_ZERO_OFFSET) * BP_100_PCT_PWM_RPM_RANGE ) * ( dir == MOTOR_DIR_FORWARD ? 1.0F : -1.0F ) ) +/// Conversion from RPM to PWM duty cycle %. +#define BP_MOTOR_SPEED_RPM_TO_PWM(rpm) ( ( (F32)(rpm) / BP_100_PCT_PWM_RPM_RANGE ) + BP_PWM_ZERO_OFFSET ) +/// Conversion macro from mL/min to estimated PWM duty cycle %. +#define BP_ML_PER_MIN_FROM_PWM(pwm) ( ( ( pwm - BP_PWM_ZERO_OFFSET ) / ( BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR ) ) ) + +/// Measured blood flow is filtered w/ moving average. +#define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 1 ) + +#define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. +#define BP_MIN_DIR_CHECK_SPEED_RPM 10.0F ///< Minimum motor speed before we check pump direction. +#define BP_COMMUTATION_ERROR_MAX_CNT 3 ///< Maximum number of commutation errors within time window before alarm triggered. +#define BP_COMMUTATION_ERROR_TIME_WIN_MS (15 * MS_PER_SECOND) ///< Time window for BP commutation error. + +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.11F ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.00000000896F ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.000550F ///< B term used for wear portion of alpha flow coefficient. +#define BP_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define BP_MIN_ART_PRESSURE_MMHG -200.0F ///< Minimum arterial pressure factored into blood flow calculation. + +#define DATA_PUBLISH_COUNTER_START_COUNT 20 ///< Data publish counter start count. + +/// 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_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_T; + +// Pin assignments for pump stop and direction outputs and rotor hall sensor input +#define STOP_CAN3_PORT_MASK 0x00000002 ///< (Tx - re-purposed as output GPIO for blood pump stop signal) +#define DIR_CAN3_PORT_MASK 0x00000002 ///< (Rx - re-purposed as output GPIO for blood pump direction signal) +#define BP_ROTOR_HALL_SENSOR_NHET_ID 0x0000000C ///< NHET pin number associated with BP rotor hall sensor input +// Blood pump stop and direction macros +#define SET_BP_DIR() {canREG3->RIOC |= DIR_CAN3_PORT_MASK;} ///< Macro to set blood pump direction signal high (forward). +#define CLR_BP_DIR() {canREG3->RIOC &= ~DIR_CAN3_PORT_MASK;} ///< Macro to set blood pump direction signal low (reverse). +#define SET_BP_STOP() {canREG3->TIOC &= ~STOP_CAN3_PORT_MASK;} ///< Macro to set blood pump disable signal low (active low). +#define CLR_BP_STOP() {canREG3->TIOC |= STOP_CAN3_PORT_MASK;} ///< Macro to set blood pump disable signal high (active low). + +// ********** private data ********** + +static BLOOD_PUMP_STATE_T bloodPumpState = BLOOD_PUMP_OFF_STATE; ///< Current state of blood flow controller state machine +static U32 bloodFlowDataPublicationTimerCounter; ///< Used to schedule blood flow data publication to CAN bus +static BOOL isBloodPumpOn = FALSE; ///< Blood pump is currently running +static F32 bloodPumpPWMDutyCyclePct = 0.0; ///< Initial blood pump PWM duty cycle +static F32 bloodPumpPWMDutyCyclePctSet = 0.0; ///< Currently set blood pump PWM duty cycle +static MOTOR_DIR_T bloodPumpDirection = MOTOR_DIR_FORWARD; ///< Requested blood flow direction +static MOTOR_DIR_T bloodPumpDirectionSet = MOTOR_DIR_FORWARD; ///< Currently set blood flow direction +static PUMP_CONTROL_MODE_T bloodPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested blood pump control mode. +static PUMP_CONTROL_MODE_T bloodPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set blood pump control mode. +static U32 errorBloodRotorSpeedPersistTimerCtr = 0; ///< Persistence timer counter for rotor speed error condition. + +/// Interval (in task intervals) at which to publish blood flow data to CAN bus. +static OVERRIDE_U32_T bloodFlowDataPublishInterval = { BLOOD_FLOW_DATA_PUB_INTERVAL, BLOOD_FLOW_DATA_PUB_INTERVAL, BLOOD_FLOW_DATA_PUB_INTERVAL, 0 }; +static S32 targetBloodFlowRate = 0; ///< Requested blood flow rate. +static OVERRIDE_F32_T measuredBloodFlowRate = { 0.0, 0.0, 0.0, 0 }; ///< Measured (calculated now) blood flow rate. +static OVERRIDE_F32_T bloodPumpRotorSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump rotor speed. +static OVERRIDE_F32_T bloodPumpSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor speed. +static OVERRIDE_F32_T adcBloodPumpMCSpeedRPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor controller speed. +static OVERRIDE_F32_T adcBloodPumpMCCurrentmA = { 0.0, 0.0, 0.0, 0 }; ///< Measured blood pump motor controller current. + +static U08 lastBloodPumpDirectionCount = 0; ///< Previous pump direction error count reported by FPGA. + +static F32 rpmReadings[ SIZE_OF_ROLLING_AVG ]; ///< Holds RPM samples for a rolling average. +static U32 rpmReadingsIdx = 0; ///< Index for next sample in rolling average array. +static F32 rpmReadingsTotal = 0.0; ///< Rolling total - used to calc average. +static U32 rpmReadingsCount = 0; ///< Number of samples in RPM rolling average buffer. +static F32 filteredBloodPumpSpeed = 0.0; ///< Filtered blood pump speed used in blood flow estimation. + +static U32 bpControlTimerCounter = 0; ///< Determines when to perform control on blood flow. + +static U32 bpRotorRevStartTime = 0; ///< Blood pump rotor rotation start time (in ms). +static OVERRIDE_U32_T bloodPumpRotorCounter = { 0, 0, 0, 0 }; ///< Running counter for blood pump rotor revolutions. +static U32 bpRotorSpeedTooFastPulseCount; ///< Counter for rotor pulses indicating RPM > 100. +static BOOL bpStopAtHomePosition = FALSE; ///< Stop blood pump at next home position. +static U32 bpHomeStartTime = 0; ///< When did blood pump home command begin? (in ms). + +static U32 bloodPumpMotorEdgeCount = 0; ///< Running counter for blood pump motor revolutions. +static U16 bpLastMotorHallSensorCounts[ BP_SPEED_CALC_BUFFER_LEN ]; ///< Last hall sensor readings for the blood pump motor. +static U32 bpMotorSpeedCalcIdx = 0; ///< Index into 1 second buffer of motor speed hall sensor counts. +static U32 bpMotorSpeedCalcTimerCtr = 0; ///< Counter determines interval for calculating blood pump motor speed from hall sensor count. +static HD_PUMPS_CAL_RECORD_T bloodPumpCalRecord; ///< Blood pump calibration record. + +// ********** private function prototypes ********** + +static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ); +static BLOOD_PUMP_STATE_T handleBloodPumpRampingUpState( void ); +static BLOOD_PUMP_STATE_T handleBloodPumpRampingDownState( void ); +static BLOOD_PUMP_STATE_T handleBloodPumpControlToTargetState( void ); +static void setBloodPumpControlSignalPWM( F32 newPWM ); +static void stopBloodPump( void ); +static void releaseBloodPumpStop( void ); +static void setBloodPumpDirection( MOTOR_DIR_T dir ); +static void publishBloodFlowData( void ); +static void updateBloodPumpSpeedAndDirectionFromHallSensors( void ); +static void checkBloodPumpRotor( void ); +static void checkBloodPumpDirection( void ); +static void checkBloodPumpSpeeds( void ); +static void checkBloodPumpMCCurrent( void ); + +static F32 calcBloodFlow( void ); +static void resetBloodPumpRPMMovingAverage( void ); +static void filterBloodPumpRPMReadings( F32 rpm ); + +/*********************************************************************//** + * @brief + * The initBloodFlow function initializes the BloodFlow module. + * @details Inputs: none + * @details Outputs: bloodFlowDataPublicationTimerCounter + * @return none + *************************************************************************/ +void initBloodFlow( void ) +{ + U32 i; + + bloodFlowDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + bpRotorSpeedTooFastPulseCount = 0; + + signalBloodPumpHardStop(); + setBloodPumpDirection( MOTOR_DIR_FORWARD ); + + // Zero rolling pump speed average buffer + resetBloodPumpRPMMovingAverage(); + + // Zero motor hall sensors counts buffer + bpMotorSpeedCalcIdx = 0; + for ( i = 0; i < BP_SPEED_CALC_BUFFER_LEN; i++ ) + { + bpLastMotorHallSensorCounts[ i ] = getFPGABloodPumpHallSensorCount(); + } + resetBloodPumpRotorCount(); + + // Initialize blood flow PI controller + initializePIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, + BP_P_COEFFICIENT, BP_I_COEFFICIENT, + MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); + + // Initialize persistent alarm for flow sensor + initPersistentAlarm( ALARM_ID_HD_BLOOD_PUMP_OFF_CHECK, 0, BP_OFF_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_PUMP_MOTOR_SPEED_CHECK, 0, BP_MOTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_PUMP_MC_DIRECTION_CHECK, 0, BP_DIRECTION_ERROR_PERSIST ); + initTimeWindowedCount( TIME_WINDOWED_COUNT_BP_COMMUTATION_ERROR, BP_COMMUTATION_ERROR_MAX_CNT, BP_COMMUTATION_ERROR_TIME_WIN_MS ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, 0, BP_MAX_ROTOR_SPEED_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_PUMP_MC_CURRENT_CHECK, 0, BP_MAX_CURR_ERROR_DURATION_MS ); +} + +/*********************************************************************//** + * @brief + * The setBloodPumpTargetFlowRate function sets a new target flow rate and + * pump direction. + * @details Inputs: isBloodPumpOn, bloodPumpDirectionSet + * @details Outputs: targetBloodFlowRate, bloodPumpdirection, bloodPumpPWMDutyCyclePct + * @param flowRate new target blood flow rate + * @param dir new blood flow direction + * @param mode new control mode + * @return TRUE if new flow rate & dir are set, FALSE if not + *************************************************************************/ +BOOL setBloodPumpTargetFlowRate( U32 flowRate, MOTOR_DIR_T dir, PUMP_CONTROL_MODE_T mode ) +{ + BOOL result = FALSE; + + // Direction change while pump is running is not allowed + if ( ( FALSE == isBloodPumpOn ) || ( 0 == flowRate ) || ( dir == bloodPumpDirectionSet ) ) + { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) + { + BOOL isFlowInrange = ( flowRate <= MAX_SETTABLE_BLOOD_FLOW_RATE ? TRUE : FALSE ); + +#ifndef _RELEASE_ + if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) ) + { + isFlowInrange = TRUE; + } +#endif + // Verify flow rate of if the bypass flow limit has been enabled + if ( TRUE == isFlowInrange ) + { + resetBloodPumpRPMMovingAverage(); + targetBloodFlowRate = dirFlowRate; + bloodPumpDirection = dir; + bloodPumpControlMode = 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 + bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) +#ifndef _VECTORCAST_ + /* + * This range check was disabled in VectorCAST since all of its branches cannot be covered. + * This if statement is only executed if the flow rate is less than 700 mL/min and the required duty cycle for that will be 88% and not 90% and above. + * Also the blood flow to PWM conversion macro will have a minimum of 10% duty cycle and therefore, duty cycles below 10% cannot be achieved. + * This range check will stay in the actual code in case there was a memory stomp or other catastrophic cases + */ + bloodPumpPWMDutyCyclePct = RANGE( bloodPumpPWMDutyCyclePct, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE ); +#endif + + switch ( bloodPumpState ) + { + case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + break; + + case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; + + case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + else + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; + + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; + } + + else // Requested flow rate too high + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMPS_FLOW_LIMITS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) + } + } + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setBloodPumpTargetRPM function sets a new target pump speed and pump + * direction. Pump is set to open loop control. + * @details Inputs: none + * @details Outputs: none + * @param rpm new target blood pump speed (in RPM) + * @param dir new blood flow direction + * @return TRUE if new flow rate & direction are set, FALSE if not + *************************************************************************/ +BOOL setBloodPumpTargetRPM( U32 rpm, MOTOR_DIR_T dir ) +{ + BOOL result = FALSE; + F32 pwm = BP_MOTOR_SPEED_RPM_TO_PWM( rpm ); + + result = setBloodPumpTargetFlowRate( (U32)BP_ML_PER_MIN_FROM_PWM( pwm ), dir, PUMP_CONTROL_MODE_OPEN_LOOP ); + + return result; +} + +/*********************************************************************//** + * @brief + * The calcBloodFlow function calculates an estimated blood flow rate from + * blood pump speed, arterial pressure and tubing wear (measured from count + * of rotor revolutions since cartridge install). + * @details Inputs: bloodPumpRotorCounter, arterial pressure + * @details Outputs: none + * @return calculated blood flow rate (mL/min) + *************************************************************************/ +static F32 calcBloodFlow( void ) +{ + F32 artPres = getLongFilteredArterialPressure(); + F32 artPresL= ( artPres > BP_MIN_ART_PRESSURE_MMHG ? artPres : BP_MIN_ART_PRESSURE_MMHG ); + F32 rotSpd = filteredBloodPumpSpeed / BP_GEAR_RATIO; + U32 r = getBloodPumpRotorCount(); + U32 rotCnt = CAP( r, BP_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wear = BP_FLOW_WEAR_A_TERM * (F32)rotCnt + BP_FLOW_WEAR_B_TERM; + F32 alpha = wear * artPresL + BP_FLOW_ALPHA_Y_INTERCEPT; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; + + return flow; +} + +/*********************************************************************//** + * @brief + * The signalBloodPumpHardStop function stops the blood pump immediately. + * @details Inputs: none + * @details Outputs: Blood pump stopped, set point reset, state changed to off + * @return none + *************************************************************************/ +void signalBloodPumpHardStop( void ) +{ + targetBloodFlowRate = 0; + stopBloodPump(); + bloodPumpState = BLOOD_PUMP_OFF_STATE; + bloodPumpPWMDutyCyclePct = BP_PWM_ZERO_OFFSET; + bpControlTimerCounter = 0; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE ); +} + +/*********************************************************************//** + * @brief + * The signalBloodPumpRotorHallSensor function handles the blood pump rotor + * hall sensor detection. Calculates rotor speed (in RPM). Stops pump if + * there is a pending request to home the pump. + * @details Inputs: bpRotorRevStartTime, bpStopAtHomePosition + * @details Outputs: bpRotorRevStartTime, bloodPumpRotorSpeedRPM, bloodPumpRotorCounter + * @return none + *************************************************************************/ +void signalBloodPumpRotorHallSensor( void ) +{ + U32 rotTime = getMSTimerCount(); + U32 deltaTime = calcTimeBetween( bpRotorRevStartTime, rotTime ); + F32 rotSpeed = ( 1.0F / (F32)deltaTime ) * (F32)MS_PER_SECOND * (F32)SEC_PER_MIN; // calculate rotor speed indicating by time between this and previous pulse + + // Increment rotor counter + bloodPumpRotorCounter.data++; + + // Count pulses indicating rotor speed too fast + if ( getMeasuredBloodPumpRotorSpeed() > BP_MAX_ROTOR_SPEED_RPM ) + { + bpRotorSpeedTooFastPulseCount++; + } + else + { + bpRotorSpeedTooFastPulseCount = 0; + } + + // Calculate rotor speed (in RPM) + bloodPumpRotorSpeedRPM.data = rotSpeed; + bpRotorRevStartTime = rotTime; + + // If we are supposed to stop pump at home position, stop pump now. + if ( TRUE == bpStopAtHomePosition ) + { + signalBloodPumpHardStop(); + bpStopAtHomePosition = FALSE; + } +} + +/*********************************************************************//** + * @brief + * The homeBloodPump function initiates a blood pump home operation. + * @details Inputs: bloodPumpState + * @details Outputs: bpStopAtHomePosition, bpHomeStartTime, blood pump started (slow) + * @return none + *************************************************************************/ +BOOL homeBloodPump( void ) +{ + BOOL result = FALSE; + + if ( BLOOD_PUMP_OFF_STATE == bloodPumpState ) + { + bpStopAtHomePosition = TRUE; + bpHomeStartTime = getMSTimerCount(); + result = setBloodPumpTargetRPM( BP_HOME_SPEED, MOTOR_DIR_FORWARD ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpMotorCount function returns the current count for the + * blood pump motor revolution counter. + * @details Inputs: bloodPumpMotorCount + * @details Outputs: none + * @return bloodPumpMotorCount + *************************************************************************/ +U32 getBloodPumpMotorCount( void ) +{ + return bloodPumpMotorEdgeCount; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpRotorCount function returns the current count for the + * blood pump rotor revolution counter. + * @details Inputs: bloodPumpRotorCounter + * @details Outputs: none + * @return bloodPumpRotorCounter + *************************************************************************/ +U32 getBloodPumpRotorCount( void ) +{ + U32 result = bloodPumpRotorCounter.data; + + if ( OVERRIDE_KEY == bloodPumpRotorCounter.override ) + { + result = bloodPumpRotorCounter.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isBloodPumpRunning function returns whether the blood pump is currently + * running or not. + * @details Inputs: isBloodPumpOn + * @details Outputs: none + * @return isBloodPumpOn + *************************************************************************/ +BOOL isBloodPumpRunning( void ) +{ + return isBloodPumpOn; +} + +/*********************************************************************//** + * @brief + * The isBloodPumpRampComplete function returns whether the blood pump has + * completed its ramp up and entered control state (closed or open loop). + * @details Inputs: bloodPumpState + * @details Outputs: none + * @return TRUE if pump is in control state, FALSE if not + *************************************************************************/ +BOOL isBloodPumpRampComplete( void ) +{ + BOOL result = ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ? TRUE : FALSE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The resetBloodPumpRotorCount function resets the blood pump rotor counter + * that is a proxy for cartridge wear. Call this function after a new cartridge + * has been installed. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @return none + *************************************************************************/ +void resetBloodPumpRotorCount( void ) +{ + bloodPumpRotorCounter.data = 0; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_USE_WORN_CARTRIDGE ) ) + { + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; + } +} + +/*********************************************************************//** + * @brief + * The execBloodFlowMonitor function executes the blood flow monitor. + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate, adcBloodPumpMCSpeedRPM, + * adcBloodPumpMCCurrentmA + * @return none + *************************************************************************/ +void execBloodFlowMonitor( void ) +{ + HD_OP_MODE_T opMode = getCurrentOperationMode(); + U16 bpRPM = getIntADCReading( INT_ADC_BLOOD_PUMP_SPEED ); + U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); + + 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; + + filterBloodPumpRPMReadings( getMeasuredBloodPumpMCSpeed() ); + measuredBloodFlowRate.data = calcBloodFlow(); // Pressure and rotor speed already filtered as inputs to calc, so no need to filter flow any further + + // Calculate blood pump motor speed/direction from hall sensor count + updateBloodPumpSpeedAndDirectionFromHallSensors(); + + // Do not start enforcing checks until out of init/POST mode + if ( opMode != MODE_INIT ) + { + // Check pump direction + checkBloodPumpDirection(); + // Check pump controller current + checkBloodPumpMCCurrent(); + // Check pump speeds + checkBloodPumpSpeeds(); + // Check for home position, zero/low speed + checkBloodPumpRotor(); + } + else + { + lastBloodPumpDirectionCount = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + } + + // Publish blood flow data on interval + publishBloodFlowData(); +} + +/*********************************************************************//** + * @brief + * The execBloodFlowController function executes the blood flow controller. + * @details Inputs: bloodPumpState + * @details Outputs: bloodPumpState + * @return none + *************************************************************************/ +void execBloodFlowController( void ) +{ + switch ( bloodPumpState ) + { + case BLOOD_PUMP_OFF_STATE: + bloodPumpState = handleBloodPumpOffState(); + break; + + case BLOOD_PUMP_RAMPING_UP_STATE: + bloodPumpState = handleBloodPumpRampingUpState(); + break; + + case BLOOD_PUMP_RAMPING_DOWN_STATE: + bloodPumpState = handleBloodPumpRampingDownState(); + break; + + case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: + bloodPumpState = handleBloodPumpControlToTargetState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_STATE, bloodPumpState ) + break; + } +} + +/*********************************************************************//** + * @brief + * The handleBloodPumpOffState function handles the blood pump off state + * of the blood pump controller state machine. + * @details Inputs: targetBloodFlowRate, bloodPumpDirection + * @details Outputs: bloodPumpPWMDutyCyclePctSet, bloodPumpDirectionSet, isBloodPumpOn + * @return next state + *************************************************************************/ +static BLOOD_PUMP_STATE_T handleBloodPumpOffState( void ) +{ + BLOOD_PUMP_STATE_T result = BLOOD_PUMP_OFF_STATE; + + // If we have been given a flow rate, setup ramp up and transition to ramp up state + if ( targetBloodFlowRate != 0 ) + { + // Set initial PWM duty cycle + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET + MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + // Allow blood pump to run in requested direction + setBloodPumpDirection( bloodPumpDirection ); + releaseBloodPumpStop(); + isBloodPumpOn = TRUE; + result = BLOOD_PUMP_RAMPING_UP_STATE; + } + else + { + isBloodPumpOn = FALSE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleBloodPumpRampingUpState function handles the ramp up state + * of the blood pump controller state machine. + * @details Inputs: bloodPumpPWMDutyCyclePctSet + * @details Outputs: bloodPumpPWMDutyCyclePctSet + * @return next state + *************************************************************************/ +static BLOOD_PUMP_STATE_T handleBloodPumpRampingUpState( void ) +{ + BLOOD_PUMP_STATE_T result = BLOOD_PUMP_RAMPING_UP_STATE; + + // Have we been asked to stop the blood pump? + if ( 0 == targetBloodFlowRate ) + { + // Start ramp down to stop + bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + result = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + // Have we reached end of ramp up? + else if ( bloodPumpPWMDutyCyclePctSet >= bloodPumpPWMDutyCyclePct ) + { + resetBloodPumpRPMMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); + bloodPumpControlModeSet = bloodPumpControlMode; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; + result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; + } + // Continue ramp up + else + { + bloodPumpPWMDutyCyclePctSet += MAX_BLOOD_PUMP_PWM_STEP_UP_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleBloodPumpRampingDownState function handles the ramp down state + * of the blood pump controller state machine. + * @details Inputs: bloodPumpPWMDutyCyclePctSet + * @details Outputs: bloodPumpPWMDutyCyclePctSet + * @return next state + *************************************************************************/ +static BLOOD_PUMP_STATE_T handleBloodPumpRampingDownState( void ) +{ + BLOOD_PUMP_STATE_T result = BLOOD_PUMP_RAMPING_DOWN_STATE; + + // Have we essentially reached zero speed? + if ( bloodPumpPWMDutyCyclePctSet < (MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE + BP_PWM_ZERO_OFFSET) ) + { + signalBloodPumpHardStop(); + result = BLOOD_PUMP_OFF_STATE; + } + // Have we reached end of ramp down? + else if ( bloodPumpPWMDutyCyclePctSet <= bloodPumpPWMDutyCyclePct ) + { + resetBloodPumpRPMMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; + resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); + bloodPumpControlModeSet = bloodPumpControlMode; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; + result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; + } + // Continue ramp down + else + { + bloodPumpPWMDutyCyclePctSet -= MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE; + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleBloodPumpControlToTargetState function handles the "control to + * target" state of the blood pump controller state machine. + * @details Inputs: none + * @details Outputs: bloodPumpState + * @return next state + *************************************************************************/ +static BLOOD_PUMP_STATE_T handleBloodPumpControlToTargetState( void ) +{ + BLOOD_PUMP_STATE_T result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; + + // Control at set interval + if ( ++bpControlTimerCounter >= BP_CONTROL_INTERVAL ) + { + if ( bloodPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + F32 tgtFlow = (F32)targetBloodFlowRate; + F32 actFlow = getMeasuredBloodFlowRate(); + F32 newPWM; + + newPWM = runPIController( PI_CONTROLLER_ID_BLOOD_FLOW, tgtFlow, actFlow ); + bloodPumpPWMDutyCyclePctSet = newPWM; + setBloodPumpControlSignalPWM( newPWM ); + } + bpControlTimerCounter = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setBloodPumpControlSignalPWM function sets the PWM duty cycle for + * the blood pump to a given %. + * @details Inputs: none + * @details Outputs: blood pump stop signal activated, PWM duty cycle zeroed + * @param newPWM new duty cycle % to apply to PWM + * @return none + *************************************************************************/ +static void setBloodPumpControlSignalPWM( F32 newPWM ) +{ + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( newPWM * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The stopBloodPump function sets the blood pump stop signal. + * @details Inputs: none + * @details Outputs: blood pump stop signal activated, PWM duty cycle zeroed + * @return none + *************************************************************************/ +static void stopBloodPump( void ) +{ + isBloodPumpOn = FALSE; + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET; + etpwmSetCmpA( etpwmREG1, 0 ); + SET_BP_STOP(); +} + +/*********************************************************************//** + * @brief + * The releaseBloodPumpStop function clears the blood pump stop signal. + * @details Inputs: none + * @details Outputs: blood pump stop signal + * @return none + *************************************************************************/ +static void releaseBloodPumpStop( void ) +{ + CLR_BP_STOP(); +} + +/*********************************************************************//** + * @brief + * The setBloodPumpDirection function sets the set blood pump direction to + * the given direction. + * @details Inputs: bloodPumpState + * @details Outputs: bloodPumpState + * @param dir blood pump direction to set + * @return none + *************************************************************************/ +static void setBloodPumpDirection( MOTOR_DIR_T dir ) +{ + switch ( dir ) + { + case MOTOR_DIR_FORWARD: + bloodPumpDirectionSet = dir; + SET_BP_DIR(); + break; + + case MOTOR_DIR_REVERSE: + bloodPumpDirectionSet = dir; + CLR_BP_DIR(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_INVALID_BLOOD_PUMP_DIRECTION, dir ) + break; + } +} + +/*********************************************************************//** + * @brief + * The getTargetBloodFlowRate function gets the target blood flow rate. + * @details Inputs: targetBloodFlowRate + * @details Outputs: none + * @return the current target blood flow rate (in mL/min). + *************************************************************************/ +S32 getTargetBloodFlowRate( void ) +{ + return targetBloodFlowRate; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodFlowRate function gets the measured blood flow + * rate. + * @details Inputs: measuredBloodFlowRate + * @details Outputs: none + * @return the current blood flow rate (in mL/min). + *************************************************************************/ +F32 getMeasuredBloodFlowRate( void ) +{ + F32 result = measuredBloodFlowRate.data; + + if ( OVERRIDE_KEY == measuredBloodFlowRate.override ) + { + result = measuredBloodFlowRate.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpRotorSpeed function gets the measured blood flow + * rate. + * @details Inputs: bloodPumpRotorSpeedRPM + * @details Outputs: none + * @return the current blood flow rate (in mL/min). + *************************************************************************/ +F32 getMeasuredBloodPumpRotorSpeed( void ) +{ + F32 result = bloodPumpRotorSpeedRPM.data; + + if ( OVERRIDE_KEY == bloodPumpRotorSpeedRPM.override ) + { + result = bloodPumpRotorSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpSpeed function gets the measured blood flow + * rate. + * @details Inputs: bloodPumpSpeedRPM + * @details Outputs: none + * @return the current blood flow rate (in mL/min). + *************************************************************************/ +F32 getMeasuredBloodPumpSpeed( void ) +{ + F32 result = bloodPumpSpeedRPM.data; + + if ( OVERRIDE_KEY == bloodPumpSpeedRPM.override ) + { + result = bloodPumpSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpMCSpeed function gets the measured blood pump + * speed. + * @details Inputs: adcBloodPumpMCSpeedRPM + * @details Outputs: none + * @return the current blood pump speed (in RPM). + *************************************************************************/ +F32 getMeasuredBloodPumpMCSpeed( void ) +{ + F32 result = adcBloodPumpMCSpeedRPM.data; + + if ( OVERRIDE_KEY == adcBloodPumpMCSpeedRPM.override ) + { + result = adcBloodPumpMCSpeedRPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getMeasuredBloodPumpMCCurrent function gets the measured blood pump + * current. + * @details Inputs: adcBloodPumpMCCurrentmA + * @details Outputs: none + * @return the current blood pump current (in mA). + *************************************************************************/ +F32 getMeasuredBloodPumpMCCurrent( void ) +{ + F32 result = adcBloodPumpMCCurrentmA.data; + + if ( OVERRIDE_KEY == adcBloodPumpMCCurrentmA.override ) + { + result = adcBloodPumpMCCurrentmA.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishBloodFlowData function publishes blood flow data at the set + * interval. + * @details Inputs: target flow rate, measured flow rate, measured MC speed, + * measured MC current + * @details Outputs: Blood flow data is published to CAN bus. + * @return none + *************************************************************************/ +static void publishBloodFlowData( void ) +{ + // Publish blood flow data on interval + if ( ++bloodFlowDataPublicationTimerCounter >= getU32OverrideValue( &bloodFlowDataPublishInterval ) ) + { + BLOOD_PUMP_STATUS_PAYLOAD_T payload; + HD_OP_MODE_T opMode = getCurrentOperationMode(); + U32 hallSensor = gioGetBit( hetPORT1, BP_ROTOR_HALL_SENSOR_NHET_ID ); + + payload.setPoint = targetBloodFlowRate; + payload.measFlow = getMeasuredBloodFlowRate(); + payload.measRotorSpd = getMeasuredBloodPumpRotorSpeed(); + payload.measPumpSpd = getMeasuredBloodPumpSpeed(); + payload.measMCSpd = getMeasuredBloodPumpMCSpeed(); + payload.measMCCurr = getMeasuredBloodPumpMCCurrent(); + payload.pwmDC = bloodPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + payload.rotorCount = getBloodPumpRotorCount(); + if ( ( MODE_PRET == opMode ) || ( MODE_TREA == opMode ) || ( MODE_POST == opMode ) ) + { // prescribed flow only available in treatment modes + payload.presFlow = getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ); + } + else + { + payload.presFlow = 0; + } + payload.rotorHall = ( hallSensor > 0 ? 0 : 1 ); // 1=home, 0=not home + broadcastData( MSG_ID_BLOOD_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( BLOOD_PUMP_STATUS_PAYLOAD_T ) ); + bloodFlowDataPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The resetBloodPumpRPMMovingAverage function re-initializes the pump speed + * moving average sample buffer. + * @details Inputs: none + * @details Outputs: rpmReadingsTotal, rpmReadingsIdx, rpmReadingsCount all set to zero. + * @return none + *************************************************************************/ +static void resetBloodPumpRPMMovingAverage( void ) +{ + rpmReadingsIdx = 0; + rpmReadingsCount = 0; + rpmReadingsTotal = 0.0; + filteredBloodPumpSpeed = 0.0; +} + +/*********************************************************************//** + * @brief + * The filterBloodPumpRPMReadings function adds a new pump speed sample to + * the filter. + * @details Inputs: none + * @details Outputs: rpmReadings[], rpmReadingsIdx, rpmReadingsCount, rpmReadingsTotal + * @param rpm newest blood pump speed (in RPM) sample to add to filter + * @return none + *************************************************************************/ +static void filterBloodPumpRPMReadings( F32 rpm ) +{ + if ( rpmReadingsCount >= SIZE_OF_ROLLING_AVG ) + { + rpmReadingsTotal -= rpmReadings[ rpmReadingsIdx ]; + } + rpmReadings[ rpmReadingsIdx ] = rpm; + rpmReadingsTotal += rpm; + rpmReadingsIdx = INC_WRAP( rpmReadingsIdx, 0, SIZE_OF_ROLLING_AVG - 1 ); + rpmReadingsCount = INC_CAP( rpmReadingsCount, SIZE_OF_ROLLING_AVG ); + filteredBloodPumpSpeed = rpmReadingsTotal / (F32)rpmReadingsCount; +} + +/*********************************************************************//** + * @brief + * The updateBloodPumpSpeedAndDirectionFromHallSensors function calculates + * the blood pump motor speed and direction from hall sensor counter on + * a 1 second interval. + * @details Inputs: bpLastMotorHallSensorCount, bpMotorSpeedCalcTimerCtr, current count from FPGA + * @details Outputs: bpMotorDirectionFromHallSensors, bloodPumpSpeedRPM + * @return none + *************************************************************************/ +static void updateBloodPumpSpeedAndDirectionFromHallSensors( void ) +{ + if ( ++bpMotorSpeedCalcTimerCtr >= BP_SPEED_CALC_INTERVAL ) + { + U16 bpMotorHallSensorCount = getFPGABloodPumpHallSensorCount(); + U16 last = bpLastMotorHallSensorCounts[ bpMotorSpeedCalcIdx ]; + U32 nextIdx = INC_WRAP( bpMotorSpeedCalcIdx, 0, BP_SPEED_CALC_BUFFER_LEN - 1 ); + U16 incDelta = u16DiffWithWrap( bpLastMotorHallSensorCounts[ nextIdx ], bpMotorHallSensorCount ); + U16 decDelta = ( 0 == incDelta ? 0xFFFF : HEX_64_K - incDelta ); + U16 spdDelta; + S16 delta; + + // Determine blood pump speed/direction from delta hall sensor count since last interval + if ( incDelta < decDelta ) + { + spdDelta = incDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN; + } + else + { + spdDelta = decDelta; + bloodPumpSpeedRPM.data = ( (F32)spdDelta / (F32)BP_HALL_EDGE_COUNTS_PER_REV ) * (F32)SEC_PER_MIN * -1.0; + } + + // Keep a running 32-bit edge count used for safety check on volume in some functions + delta = u16BiDiffWithWrap( last, bpMotorHallSensorCount ); + bloodPumpMotorEdgeCount += ( delta >= 0 ? (U16)delta : 0 ); + + // Update last count for next time + bpLastMotorHallSensorCounts[ nextIdx ] = bpMotorHallSensorCount; + bpMotorSpeedCalcIdx = nextIdx; + bpMotorSpeedCalcTimerCtr = 0; + } +} + +/*********************************************************************//** + * @brief + * The checkBloodPumpRotor function checks the rotor for the blood + * pump. If homing, this function will stop when hall sensor detected. If pump + * is off or running very slowly, rotor speed will be set to zero. + * @details Inputs: bpStopAtHomePosition, bpHomeStartTime, bpRotorRevStartTime, + * bpRotorSpeedTooFastPulseCount + * @details Outputs: pump may be stopped if homing, bloodPumpRotorSpeedRPM may be + * set to zero if too long since last pulse. + * @return none + *************************************************************************/ +static void checkBloodPumpRotor( void ) +{ + F32 rotorSpeed = getMeasuredBloodPumpRotorSpeed(); + + // If homing, check timeout + if ( ( TRUE == bpStopAtHomePosition ) && ( TRUE == didTimeout( bpHomeStartTime, BP_HOME_TIMEOUT_MS ) ) ) + { + signalBloodPumpHardStop(); + bpStopAtHomePosition = FALSE; + } + + // Ensure rotor speed below maximum + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, bpRotorSpeedTooFastPulseCount >= BP_MIN_ROTOR_PULSES_FOR_MAX_SPEED ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, rotorSpeed ) + } + + // If pump is stopped or running very slowly, set rotor speed to zero + if ( TRUE == didTimeout( bpRotorRevStartTime, BP_MAX_ROTOR_HALL_INTERVAL_MS ) ) + { + bloodPumpRotorSpeedRPM.data = 0.0; + } +} + +/*********************************************************************//** + * @brief + * The checkBloodPumpDirection function checks the set direction vs. + * the direction implied by the sign of the measured MC speed. + * @details Inputs: + * @details Outputs: + * @return none + *************************************************************************/ +static void checkBloodPumpDirection( void ) +{ + if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) + { + MOTOR_DIR_T bpMCDir, bpDir; + BOOL isDirIncorrect; + U08 dirErrorCnt = getFPGABloodPumpHallSensorStatus() & PUMP_DIR_ERROR_COUNT_MASK; + F32 measMCSpeed = getMeasuredBloodPumpMCSpeed(); + BOOL minDirSpeed = ( fabs( measMCSpeed ) >= BP_MIN_DIR_CHECK_SPEED_RPM ? TRUE : FALSE ); + BOOL isHallSensorFailed = ( TRUE == minDirSpeed && lastBloodPumpDirectionCount != dirErrorCnt ? TRUE : FALSE ); + + // Check pump direction error count + if ( ( TRUE == isHallSensorFailed ) && ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BP_COMMUTATION_ERROR ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) + } + } + lastBloodPumpDirectionCount = dirErrorCnt; + + bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + bpDir = ( getMeasuredBloodPumpSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); + + // Check set direction vs. direction from hall sensors vs. direction from sign of motor controller speed + isDirIncorrect = ( ( ( bloodPumpDirectionSet != bpDir ) || ( bloodPumpDirectionSet != bpMCDir ) ) && ( TRUE == minDirSpeed ) ); + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_PUMP_MC_DIRECTION_CHECK, isDirIncorrect ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_DIRECTION_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + if ( bloodPumpDirectionSet != bpDir ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpDir ) + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_BLOOD_PUMP_MC_DIRECTION_CHECK, (U32)bloodPumpDirectionSet, (U32)bpMCDir ) + } + } + } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_HD_BLOOD_PUMP_MC_DIRECTION_CHECK ); + } +} + +/*********************************************************************//** + * @brief + * The checkBloodPumpSpeeds function checks several aspects of the blood pump + * speed. + * 1. while pump is commanded off, measured motor speed should be < limit. + * 2. while pump is controlling, measured motor speed should be within allowed range of commanded speed. + * 3. measured motor speed should be within allowed range of measured rotor speed. + * All 3 checks have a persistence time that must be met before an alarm is triggered. + * @details Inputs: bloodPumpState, targetBloodFlowRate, bloodPumpPWMDutyCyclePctSet, bloodPumpDirectionSet + * @details Outputs: errorBloodRotorSpeedPersistTimerCtr, alarm(s) may be triggered + * @return none + *************************************************************************/ +static void checkBloodPumpSpeeds( void ) +{ + F32 measMotorSpeed = getMeasuredBloodPumpSpeed(); + F32 measMCMotorSpeed = getMeasuredBloodPumpMCSpeed(); + + // Check for pump running while commanded off and not trigger alarm when AC power lost condition + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_PUMP_OFF_CHECK, + ( 0 == targetBloodFlowRate ) && ( fabs( measMotorSpeed ) > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) && ( TRUE != getCPLDACPowerLossDetected() ) ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); + activateSafetyShutdown(); + } + } + + // Checks that only occur when pump is running (and beyond ramp). + if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) + { + F32 cmdMotorSpeed = BP_PWM_TO_MOTOR_SPEED_RPM( bloodPumpPWMDutyCyclePctSet, bloodPumpDirectionSet ); + F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); + F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); + F32 measRotorSpeed = fabs( getMeasuredBloodPumpRotorSpeed() ); + F32 measMotorSpeedInRotorRPM = fabs( measMotorSpeed / BP_GEAR_RATIO ); + F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); + F32 measMotorSpeedDeltaPct = fabs( deltaRotorSpeed / measMotorSpeedInRotorRPM ); + + // Check measured motor speed vs. commanded motor speed while controlling to target + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_PUMP_MOTOR_SPEED_CHECK, + ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_BLOOD_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); + } + } + + // Check measured rotor speed vs. measured motor speed while controlling to target + if ( ( deltaRotorSpeed > BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM ) && ( measMotorSpeedDeltaPct > BP_MAX_MOTOR_SPEED_VS_TRGT_DIFF_PCT ) ) + { + if ( ++errorBloodRotorSpeedPersistTimerCtr >= ( getPumpRotorErrorPersistTime( measMotorSpeed, BP_GEAR_RATIO ) / TASK_PRIORITY_INTERVAL ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_PUMP_SPEED_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_HD_BLOOD_PUMP_ROTOR_SPEED_CHECK, measRotorSpeed, measMotorSpeed ); + } + } + } + else + { + errorBloodRotorSpeedPersistTimerCtr = 0; + } + } + else + { + resetPersistentAlarmTimer( ALARM_ID_HD_BLOOD_PUMP_MOTOR_SPEED_CHECK ); + errorBloodRotorSpeedPersistTimerCtr = 0; + + } +} + +/*********************************************************************//** + * @brief + * The checkBloodPumpMCCurrent function checks the measured MC current vs. + * the set state of the blood pump (stopped or running). + * @details Inputs: BP motor controller measured current. + * @details Outputs: Alarm triggered it current too high. + * @return none + *************************************************************************/ +static void checkBloodPumpMCCurrent( void ) +{ + F32 const bpCurr = fabs( getMeasuredBloodPumpMCCurrent() ); + // Check blood pump current during off state + BOOL const isOffMCCurrentBad = ( ( BLOOD_PUMP_OFF_STATE == bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_STOPPED_MA ) ? TRUE : FALSE ); + // Check blood pump current during running state + BOOL const isRunningMCCurrentBad = ( ( BLOOD_PUMP_OFF_STATE != bloodPumpState ) && ( bpCurr > BP_MAX_CURR_WHEN_RUNNING_MA ) ? TRUE : FALSE ); + + if ( ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_PUMP_MC_CURRENT_CHECK, isOffMCCurrentBad || isRunningMCCurrentBad ) ) && + ( getCPLDACPowerLossDetected() != TRUE ) ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_MOTOR_CURRNT_CHECKS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_PUMP_MC_CURRENT_CHECK, bpCurr ); + } + } +} + +/*********************************************************************//** + * @brief + * The execBloodFlowTest function executes the state machine for the + * BloodFlow self-test. + * @details Inputs: bloodPumpCalRecord + * @details Outputs: none + * @return the current state of the BloodFlow self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execBloodFlowTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_PASSED; + + BOOL calStatus = getNVRecord2Driver( GET_CAL_PUMPS, (U08*)&bloodPumpCalRecord, sizeof( HD_PUMPS_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_PUMPS, ALARM_ID_NO_ALARM ); + + if ( TRUE == calStatus ) + { + result = SELF_TEST_STATUS_PASSED; + } + else + { + result = SELF_TEST_STATUS_FAILED; + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetBloodFlowDataPublishIntervalOverride function overrides the + * blood flow data publish interval. + * @details Inputs: none + * @details Outputs: bloodFlowDataPublishInterval + * @param value override blood flow data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetBloodFlowDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_PRIORITY_INTERVAL; + + result = TRUE; + bloodFlowDataPublishInterval.ovData = intvl; + bloodFlowDataPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBloodFlowDataPublishIntervalOverride function resets the override + * of the blood flow data publish interval. + * @details Inputs: none + * @details Outputs: bloodFlowDataPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetBloodFlowDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodFlowDataPublishInterval.override = OVERRIDE_RESET; + bloodFlowDataPublishInterval.ovData = bloodFlowDataPublishInterval.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetBloodFlowRateOverride function overrides the target + * blood flow rate. + * @details Inputs: none + * @details Outputs: targetBloodFlowRate + * @param value override target blood flow rate (in mL/min) + * @param ctrlMode override pump control mode to this mode (0 = closed loop, 1 = open loop) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetBloodFlowRateOverride( S32 value, U32 ctrlMode ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + MOTOR_DIR_T dir; + + if ( value < 0 ) + { + dir = MOTOR_DIR_REVERSE; + } + else + { + dir = MOTOR_DIR_FORWARD; + } + if ( ctrlMode < NUM_OF_PUMP_CONTROL_MODES ) + { + result = setBloodPumpTargetFlowRate( abs(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodFlowRateOverride function overrides the measured + * blood flow rate. + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate + * @param value override measured blood flow rate (in mL/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodFlowRateOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + measuredBloodFlowRate.ovData = value; + measuredBloodFlowRate.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodFlowRateOverride function resets the override of the + * measured blood flow rate. + * @details Inputs: none + * @details Outputs: measuredBloodFlowRate + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodFlowRateOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + measuredBloodFlowRate.override = OVERRIDE_RESET; + measuredBloodFlowRate.ovData = measuredBloodFlowRate.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpRotorSpeedOverride function overrides the measured + * blood pump rotor speed. + * @details Inputs: none + * @details Outputs: bloodPumpRotorSpeedRPM + * @param value override measured blood pump rotor speed (in RPM) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodPumpRotorSpeedOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorSpeedRPM.ovData = value; + bloodPumpRotorSpeedRPM.override = OVERRIDE_KEY; + // since override may occur while pump is actually stopped, may not get pulses to reach min pulse count for alarm + if ( value > BP_MAX_ROTOR_SPEED_RPM ) + { + bpRotorSpeedTooFastPulseCount = BP_MIN_ROTOR_PULSES_FOR_MAX_SPEED; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpRotorSpeedOverride function resets the override of the + * measured blood pump rotor speed. + * @details Inputs: none + * @details Outputs: bloodPumpRotorSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpRotorSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorSpeedRPM.override = OVERRIDE_RESET; + bloodPumpRotorSpeedRPM.ovData = bloodPumpRotorSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpSpeedOverride function overrides the measured + * blood pump motor speed. + * @details Inputs: none + * @details Outputs: bloodPumpSpeedRPM + * @param value override measured blood pump motor speed (in RPM) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodPumpSpeedOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpSpeedRPM.ovData = value; + bloodPumpSpeedRPM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpSpeedOverride function resets the override of the + * measured blood pump motor speed. + * @details Inputs: none + * @details Outputs: bloodPumpSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpSpeedRPM.override = OVERRIDE_RESET; + bloodPumpSpeedRPM.ovData = bloodPumpSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpMCSpeedOverride function overrides the measured + * blood pump motor speed. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCSpeedRPM + * @param value override measured blood pump speed (in RPM) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodPumpMCSpeedOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCSpeedRPM.ovData = value; + adcBloodPumpMCSpeedRPM.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpMCSpeedOverride function resets the override of the + * measured blood pump motor speed. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCSpeedRPM + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpMCSpeedOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCSpeedRPM.override = OVERRIDE_RESET; + adcBloodPumpMCSpeedRPM.ovData = adcBloodPumpMCSpeedRPM.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredBloodPumpMCCurrentOverride function overrides the measured + * blood pump motor current. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCCurrentmA + * @param value override measured blood pump current (in mA) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredBloodPumpMCCurrentOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCCurrentmA.ovData = value; + adcBloodPumpMCCurrentmA.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredBloodPumpMCCurrentOverride function resets the override of the + * measured blood pump motor current. + * @details Inputs: none + * @details Outputs: adcBloodPumpMCCurrentmA + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredBloodPumpMCCurrentOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + adcBloodPumpMCCurrentmA.override = OVERRIDE_RESET; + adcBloodPumpMCCurrentmA.ovData = adcBloodPumpMCCurrentmA.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetBloodPumpRotorCountOverride function overrides the blood pump + * rotor counter value. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @param value override blood pump rotor counter value + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetBloodPumpRotorCountOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorCounter.ovData = value; + bloodPumpRotorCounter.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetBloodPumpRotorCountOverride function resets the override + * of the blood pump rotor counter. + * @details Inputs: none + * @details Outputs: bloodPumpRotorCounter + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetBloodPumpRotorCountOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + bloodPumpRotorCounter.override = OVERRIDE_RESET; + bloodPumpRotorCounter.ovData = bloodPumpRotorCounter.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetBloodPumpTargetDutyCycle function sets the duty cycle of the + * blood pump by calling setBloodPumpTargetFlowRate. + * @details Inputs: none + * @details Outputs: none + * @param value duty cycle of the blood pump (as a percentage). + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testSetBloodPumpTargetDutyCycle( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + setBloodPumpTargetFlowRate( (U32)BP_ML_PER_MIN_FROM_PWM( value ), MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + result = TRUE; + } + + return result; +} + +/**@}*/ Index: firmware/App/Controllers/BloodFlow.h =================================================================== diff -u --- firmware/App/Controllers/BloodFlow.h (revision 0) +++ firmware/App/Controllers/BloodFlow.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,101 @@ +/************************************************************************** +* +* Copyright (c) 2019-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file BloodFlow.h +* +* @author (last) Dara Navaei +* @date (last) 23-Jan-2024 +* +* @author (original) Sean Nash +* @date (original) 07-Nov-2019 +* +***************************************************************************/ + +#ifndef __BLOOD_FLOW_H__ +#define __BLOOD_FLOW_H__ + +#include "TDCommon.h" + +/** + * @defgroup BloodFlow BloodFlow + * @brief Blood Pump & Blood Flow controller/monitor module. Monitors the + * blood flow rate and controls the blood pump. + * + * @addtogroup BloodFlow + * @{ + */ + +// ********** public definitions ********** + +#define MAX_SET_BLOOD_FLOW_RATE 500 ///< Maximum blood flow rate (in mL/min). +#define MIN_SET_BLOOD_FLOW_RATE 100 ///< Minimum blood flow rate (in mL/min). +#define SALINE_BOLUS_FLOW_RATE 150 ///< Saline bolus flow rate (in mL/min). + +#define VOLUME_PER_BP_MOTOR_REV_ML 0.216F ///< Theoretical volume (mL) of blood/saline volume per motor revolution. +#define BP_HALL_EDGE_COUNTS_PER_REV 48 ///< Number of hall sensor edge counts per motor revolution. + +/// Payload record structure for a blood pump data message. +typedef struct +{ + S32 setPoint; ///< Set point. + F32 measFlow; ///< Measured flow in mL/min. + F32 measRotorSpd; ///< Measured rotor speed in RPM. + F32 measPumpSpd; ///< Measured pump speed in RPM. + F32 measMCSpd; ///< Measured motor speed in RPM. + F32 measMCCurr; ///< Measure motor current in Amps. + F32 pwmDC; ///< Duty cycle. + U32 rotorCount; ///< Rotor count. + U32 presFlow; ///< Blood flow in mL/min. + U32 rotorHall; ///< Rotor hall in counts. +} BLOOD_PUMP_STATUS_PAYLOAD_T; + +// ********** public function prototypes ********** + +void initBloodFlow( void ); +void execBloodFlowMonitor( void ); +void execBloodFlowController( void ); + +BOOL setBloodPumpTargetFlowRate( U32 flowRate, MOTOR_DIR_T dir, PUMP_CONTROL_MODE_T mode ); +BOOL setBloodPumpTargetRPM( U32 rpm, MOTOR_DIR_T dir ); +void signalBloodPumpHardStop( void ); +void signalBloodPumpRotorHallSensor( void ); +BOOL homeBloodPump( void ); +U32 getBloodPumpMotorCount( void ); +U32 getBloodPumpRotorCount( void ); +BOOL isBloodPumpRunning( void ); +BOOL isBloodPumpRampComplete( void ); +void resetBloodPumpRotorCount( void ); + +SELF_TEST_STATUS_T execBloodFlowTest( void ); + +S32 getTargetBloodFlowRate( void ); +F32 getMeasuredBloodFlowRate( void ); +F32 getMeasuredBloodPumpRotorSpeed( void ); +F32 getMeasuredBloodPumpSpeed( void ); +F32 getMeasuredBloodPumpMCSpeed( void ); +F32 getMeasuredBloodPumpMCCurrent( void ); + +BOOL testSetBloodFlowDataPublishIntervalOverride( U32 value ); +BOOL testResetBloodFlowDataPublishIntervalOverride( void ); +BOOL testSetTargetBloodFlowRateOverride( S32 value, U32 bloodPumpControlMode ); +BOOL testSetMeasuredBloodFlowRateOverride( F32 value ); +BOOL testResetMeasuredBloodFlowRateOverride( void ); +BOOL testSetMeasuredBloodPumpRotorSpeedOverride( F32 value ); +BOOL testResetMeasuredBloodPumpRotorSpeedOverride( void ); +BOOL testSetMeasuredBloodPumpSpeedOverride( F32 value ); +BOOL testResetMeasuredBloodPumpSpeedOverride( void ); +BOOL testSetMeasuredBloodPumpMCSpeedOverride( F32 value ); +BOOL testResetMeasuredBloodPumpMCSpeedOverride( void ); +BOOL testSetMeasuredBloodPumpMCCurrentOverride( F32 value ); +BOOL testResetMeasuredBloodPumpMCCurrentOverride( void ); +BOOL testSetBloodPumpRotorCountOverride( U32 value ); +BOOL testResetBloodPumpRotorCountOverride( void ); +BOOL testSetBloodPumpTargetDutyCycle( F32 value ); + +/**@}*/ + +#endif Index: firmware/App/Controllers/Valves.c =================================================================== diff -u --- firmware/App/Controllers/Valves.c (revision 0) +++ firmware/App/Controllers/Valves.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,605 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file Valves.c +* +* @author (last) Sean +* @date (last) 08-Oct-2024 +* +* @author (original) Sean +* @date (original) 08-Oct-2024 +* +***************************************************************************/ + +#include "AlarmMgmtTD.h" +#include "Messaging.h" +#include "OperationModes.h" +#include "PersistentAlarm.h" +#include "TaskGeneral.h" +#include "Timers.h" +#include "Valves.h" + +/** + * @addtogroup Valves + * @{ + */ + +// ********** private definitions ********** + +#define VALVES_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Valves data publish interval. +#define DATA_PUBLISH_COUNTER_START_COUNT 13 ///< Valves data publish start counter. +#define VALVE_HOME_MIN_POS_CHG 10 ///< Minimum encoder position change to indicate a home operation is still moving toward edge. +#define VALVE_HOME_BACK_OFF_EDGE 10 ///< Encoder counts to back off of detected edge position. +#define MAX_ALLOWED_FAILED_VALVE_HOMINGS 3U ///< Maximum allowed failed valve home attempts +#define MAX_HOME_FULL_TRAVEL_DIFF 100U ///< Maximum allowed difference in full travel encoder counts between expected and measured during home operation. + +/// Valve controller states +typedef enum valve_Control_States +{ + VALVE_STATE_WAIT_FOR_POST = 0, ///< Valve state wait for POST + VALVE_STATE_HOMING_NOT_STARTED, ///< Valve state homing not started + VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE, ///< Valve state homing find energized edge + VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE, ///< Valve state homing find de-energized edge + VALVE_STATE_IDLE, ///< Valve state idle + VALVE_STATE_IN_TRANSITION, ///< Valve state in transition + NUM_OF_VALVE_STATES, ///< Number of valve exec states +} VALVE_STATE_T; + +/// Valve status structure +typedef struct +{ + VALVE_POSITION_T commandedPosition; ///< Valve commanded position enum + VALVE_POSITION_T currentPosition; ///< Valve current position enum + VALVE_POSITION_T pendingCommandedPosition; ///< Valve pending position enum + S16 targetEncPosition; ///< Valve target position in encoder counts + S16 currentEncPosition; ///< Valve current position in encoder counts + S16 priorEncPosition; ///< Valve prior position in encoder counts + BOOL hasTransitionBeenRequested; ///< Valve transition request flag + VALVE_STATE_T controlState; ///< Valve control state + U32 transitionStartTime; ///< Valve transition start time + S16 positionsABC[ NUM_OF_VALVE_POSITIONS ]; ///< Valve positions (in encoder counts) for positions A, B, and C + U32 overCurrentCounter; ///< Valve over current counter + U32 positionOutOfRangeCounter; ///< Valve position out of range counter + // Homing variables + U32 numberOfFailedHomings; ///< Valve number of failed homing + U32 homingEdgeDetectionCounter; ///< Valve homing counter when there is not much travel + BOOL hasHomingBeenRequested; ///< Valve homing request flag + BOOL hasValveBeenHomed; ///< Valve homing completed flag + BOOL hasHomingFailed; ///< Valve homing failed flag +} VALVE_STATUS_T; + +/// Payload record structure for pinch valve set position request +typedef struct +{ + U32 valve; ///< which pinch valve to set (0=VBA, 1=VBV) + U32 pos; ///< 1=A, 2=B, 3=C +} VALVE_PINCH_SET_CMD_PAYLOAD_T; + +/// Payload record structure for pinch valve home request +typedef struct +{ + U32 valve; ///< which pinch valve to home (0=VBA, 1=VBV) + BOOL force; ///< Flag indicates whether home should be forced to happen even if already homed. + BOOL tubing; ///< Flag indicates whether tubing will be present. +} VALVE_PINCH_HOME_CMD_PAYLOAD_T; + +// ********** private data ********** + +static VALVE_STATUS_T currentValveStates[ NUM_OF_VALVES ]; ///< Current status of each valve. +static U32 valvesDataPublicationTimerCounter; ///< Valves data broadcast timer counter. +static OVERRIDE_U32_T valvesDataPublishInterval; ///< Valves data broadcast interval (in ms). +static SELF_TEST_STATUS_T valvesSelfTestResult; ///< Valves self test result. +//static TD_VALVES_CAL_RECORD_T valvesCalibrationRecord; ///< Valves calibration record. + +// ********** private function prototypes ********** + +static VALVE_STATE_T handleValvesWait4PostState( VALVE_T valve ); +static VALVE_STATE_T handleValvesNotHomedState( VALVE_T valve ); +static VALVE_STATE_T handleValvesFindEnergizedEdgeState( VALVE_T valve ); +static VALVE_STATE_T handleValvesFindDeenergizedEdgeState( VALVE_T valve ); +static VALVE_STATE_T handleValvesIdleState( VALVE_T valve ); +static VALVE_STATE_T handleValvesTransitionState( VALVE_T valve ); + +static void publishValvesData( void ); + +/*********************************************************************//** + * @brief + * The initValves function initializes the valves controller unit. + * @details \b Inputs: none + * @details \b Outputs: Valves unit initialized + * @return none + *************************************************************************/ +void initValves(void) +{ + // Initialize driver + initRotaryValvesDriver(); + + // Initialize controller variables + memset( ¤tValveStates[0], 0, sizeof( currentValveStates ) ); + valvesDataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + valvesDataPublishInterval.data = VALVES_DATA_PUB_INTERVAL; + valvesDataPublishInterval.ovData = VALVES_DATA_PUB_INTERVAL; + valvesDataPublishInterval.ovInitData = 0; + valvesDataPublishInterval.override = OVERRIDE_RESET; +} + +/*********************************************************************//** + * @brief + * The setValvePosition function sets the commanded position for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve or position given. + * @details \b Inputs: none + * @details \b Outputs: currentValveStates[] + * @param valve ID of valve to command position for + * @param position ID of position to command valve to + * @return TRUE if command accepted, FALSE if not + *************************************************************************/ +BOOL setValvePosition( VALVE_T valve, VALVE_POSITION_T position ) +{ + BOOL result = FALSE; + + if ( ( valve < NUM_OF_VALVES ) && ( position < NUM_OF_VALVE_POSITIONS ) ) + { + currentValveStates[ valve ].commandedPosition = position; + result = TRUE; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_PARAM, + ( (U32)valve << SHIFT_16_BITS_FOR_WORD_SHIFT ) | (U32)position ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getValvePosition function returns the current position of a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: none + * @param valve ID of valve to get current position of + * @return Current position of the given valve + *************************************************************************/ +VALVE_POSITION_T getValvePosition( VALVE_T valve ) +{ + VALVE_POSITION_T result = VALVE_POSITION_NOT_IN_POSITION; + + if ( valve < NUM_OF_VALVES ) + { + result = currentValveStates[ valve ].currentPosition; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE1, (U32)valve ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execValvesController function executes the valves state machine. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if a valve control state is invalid. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: currentValveStates[] + * @return none + *************************************************************************/ +void execValvesController( void ) +{ + VALVE_T valve; + + // update valve readings + readValves(); + + for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) + { + switch( currentValveStates[ valve ].controlState ) + { + case VALVE_STATE_WAIT_FOR_POST: + currentValveStates[ valve ].controlState = handleValvesWait4PostState( valve ); + break; + + case VALVE_STATE_HOMING_NOT_STARTED: + currentValveStates[ valve ].controlState = handleValvesNotHomedState( valve ); + break; + + case VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE: + currentValveStates[ valve ].controlState = handleValvesFindEnergizedEdgeState( valve ); + break; + + case VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE: + currentValveStates[ valve ].controlState = handleValvesFindDeenergizedEdgeState( valve ); + break; + + case VALVE_STATE_IDLE: + currentValveStates[ valve ].controlState = handleValvesIdleState( valve ); + break; + + case VALVE_STATE_IN_TRANSITION: + currentValveStates[ valve ].controlState = handleValvesTransitionState( valve ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_STATE, (U32)currentValveStates[ valve ].controlState ) + break; + } + } + + publishValvesData(); +} + +/*********************************************************************//** + * @brief + * The handleValvesWait4PostState function handles the Wait for POST state + * of the state machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: current operating mode + * @details \b Outputs: none + * @param valve ID of valve for which to handle the Wait for POST state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesWait4PostState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_WAIT_FOR_POST; + + if ( valve < NUM_OF_VALVES ) + { + if ( getCurrentOperationMode() != MODE_INIT ) + { + nextState = VALVE_STATE_HOMING_NOT_STARTED; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE2, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The handleValvesNotHomedState function handles the Not Homed state + * of the state machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: currentValveStates[] + * @param valve ID of valve for which to handle the Not Homed state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesNotHomedState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_HOMING_NOT_STARTED; + + if ( valve < NUM_OF_VALVES ) + { + if ( TRUE == currentValveStates[ valve ].hasHomingBeenRequested ) + { + U16 mag = ( 2 * ROTARY_VALVE_FULL_SWING_TRAVEL_COUNTS ); + + // command valve to move to energized edge (end of travel) + currentValveStates[ valve ].homingEdgeDetectionCounter = 0; + currentValveStates[ valve ].targetEncPosition = ROTARY_VALVE_FULL_SWING_TRAVEL_COUNTS; + currentValveStates[ valve ].hasValveBeenHomed = FALSE; + currentValveStates[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; + setValveCmdChangePosition( valve, (U16)mag, MOTOR_DIR_FORWARD ); + nextState = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE3, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The handleValvesFindEnergizedEdgeState function handles the Find Energized + * Edge state of the state machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: currentValveStates[] + * @param valve ID of valve for which to handle the Find Energized Edge state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesFindEnergizedEdgeState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; + + if ( valve < NUM_OF_VALVES ) + { + S16 curPos = currentValveStates[ valve ].currentEncPosition; + + // have we found foward edge of travel? + if ( fabs( curPos - currentValveStates[ valve ].priorEncPosition ) < VALVE_HOME_MIN_POS_CHG ) + { + U16 mag = ( 2 * ROTARY_VALVE_FULL_SWING_TRAVEL_COUNTS ); + + // Record edge position + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ] = curPos - VALVE_HOME_BACK_OFF_EDGE; + // command valve to move to de-energized edge (end of travel) + currentValveStates[ valve ].homingEdgeDetectionCounter = 0; + currentValveStates[ valve ].targetEncPosition = 0; + setValveCmdChangePosition( valve, (U16)mag, MOTOR_DIR_REVERSE ); + nextState = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE4, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The handleValvesFindDeenergizedEdgeState function handles the Find + * De-energized Edge state of the state machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: + * @details \b Outputs: + * @param valve ID of valve for which to handle the Find De-energized Edge state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesFindDeenergizedEdgeState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; + + if ( valve < NUM_OF_VALVES ) + { + S16 curPos = currentValveStates[ valve ].currentEncPosition; + + // have we found forward edge of travel? + if ( fabs( currentValveStates[ valve ].priorEncPosition - curPos ) < VALVE_HOME_MIN_POS_CHG ) + { + S16 posC = curPos + VALVE_HOME_BACK_OFF_EDGE; + S16 edgeDelta = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ] - posC; + U32 expDelta = abs( (S16)ROTARY_VALVE_FULL_SWING_TRAVEL_COUNTS - edgeDelta ); + + // verify edge to edge travel is reasonable + if ( expDelta <= MAX_HOME_FULL_TRAVEL_DIFF ) + { + // Record edge position + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] = curPos + VALVE_HOME_BACK_OFF_EDGE; + // calculate and record middle position + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_A_INSERT_EJECT ] = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] + \ + ( ( currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ] - currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] ) / 2 ); + // Set the current position to Position C and the commanded position to Position A + currentValveStates[ valve ].hasValveBeenHomed = TRUE; + currentValveStates[ valve ].currentPosition = VALVE_POSITION_C_CLOSE; + currentValveStates[ valve ].pendingCommandedPosition = VALVE_POSITION_A_INSERT_EJECT; + currentValveStates[ valve ].hasTransitionBeenRequested = TRUE; + currentValveStates[ valve ].hasHomingBeenRequested = FALSE; + currentValveStates[ valve ].numberOfFailedHomings = 0; + nextState = VALVE_STATE_IDLE; + } + // if home failed, attempt retry or fault if out of retries + else + { + currentValveStates[ valve ].numberOfFailedHomings++; + if ( currentValveStates[ valve ].numberOfFailedHomings > MAX_ALLOWED_FAILED_VALVE_HOMINGS ) + { + currentValveStates[ valve ].hasValveBeenHomed = FALSE; + currentValveStates[ valve ].hasHomingFailed = TRUE; + currentValveStates[ valve ].hasHomingBeenRequested = FALSE; + // TODO SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_VALVE_HOMING_FAILED, (U32)valve, (U32)edgeDelta ); + } + nextState = VALVE_STATE_HOMING_NOT_STARTED; + } + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE5, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The handleValvesIdleState function handles the Idle state of the state + * machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: + * @details \b Outputs: + * @param valve ID of valve for which to handle the Idle state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesIdleState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_IDLE; + + if ( valve < NUM_OF_VALVES ) + { + // handle a home request + if ( TRUE == currentValveStates[ valve ].hasHomingBeenRequested ) + { + nextState = VALVE_STATE_HOMING_NOT_STARTED; + } + // handle a position change request + else if ( TRUE == currentValveStates[ valve ].hasTransitionBeenRequested ) + { + + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE6, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The handleValvesTransitionState function handles the Transition state + * of the state machine for a given valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: + * @details \b Outputs: + * @param valve ID of valve for which to handle the Transition state + * @return next state of the state machine for the given valve + *************************************************************************/ +VALVE_STATE_T handleValvesTransitionState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_IN_TRANSITION; + + if ( valve < NUM_OF_VALVES ) + { + + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE7, (U32)valve ) + } + + return nextState; +} + +/*********************************************************************//** + * @brief + * The execValvesSelfTest function executes the valves self-test. Calibration + * factors are loaded from non-volatile memory and CRC checked. + * @details \b Inputs: Calibration record stored in non-volatile memory. + * @details \b Outputs: valvesCalibrationRecord + * @return self-test result (pass/fail) + *************************************************************************/ +SELF_TEST_STATUS_T execValvesSelfTest( void ) +{ + BOOL calStatus = TRUE; /* TODO getNVRecord2Driver( GET_CAL_VALVES, (U08*)&valvesCalibrationRecord, sizeof( HD_VALVES_CAL_RECORD_T ), + NUM_OF_CAL_DATA_HD_VALVES, ALARM_ID_NO_ALARM );*/ + + if ( TRUE == calStatus ) + { + valvesSelfTestResult = SELF_TEST_STATUS_PASSED; + } + else + { + valvesSelfTestResult = SELF_TEST_STATUS_FAILED; + } + + return valvesSelfTestResult; +} + +/*********************************************************************//** + * @brief + * The publishValvesData function constructs and sends the valves data + * broadcast message. + * @details \b Message \b Sent: MSG_ID_TD_VALVES_DATA + * @details \b Inputs: valvesDataPublicationTimerCounter, valvesDataPublishInterval + * @details \b Outputs: valvesDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishValvesData( void ) +{ + if ( ++valvesDataPublicationTimerCounter >= getU32OverrideValue( &valvesDataPublishInterval ) ) + { + VALVE_T valve; + + for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) + { + TD_VALVE_DATA_T data; + + data.valveID = (U32)valve; + data.state = (U32)currentValveStates[ valve ].controlState; + data.currentPosID = (U32)currentValveStates[ valve ].currentPosition; + data.currentPos = getValveEncoderPosition( valve ); + data.cmdPos = (U32)currentValveStates[ valve ].commandedPosition; + + broadcastData( MSG_ID_TD_VALVES_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( TD_VALVE_DATA_T ) ); + } + + valvesDataPublicationTimerCounter = 0; + } +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testValvesDataPublishIntervalOverride function overrides the interval + * at which the TD valves data is published. + * @details \b Inputs: none + * @details \b Outputs: valvesDataPublishInterval + * @param message Override message from Dialin which includes the interval + * (in ms) to override the air pump broadcast interval to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testValvesDataPublishIntervalOverride( MESSAGE_T *message ) +{ + BOOL result = u32BroadcastIntervalOverride( message, &valvesDataPublishInterval, TASK_GENERAL_INTERVAL ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testValveSetABCCmdPosition function handles a Dialin command to set + * a given valve to a given A/B/C position. + * @details \b Inputs: none + * @details \b Outputs: currentValveStates[] + * @param message Override message from Dialin which includes the ID of the + * valve and the position to command it to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testValveSetABCCmdPosition( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD + if ( TRUE == isTestingActivated() ) + { + VALVE_PINCH_SET_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(VALVE_PINCH_SET_CMD_PAYLOAD_T) ); + if ( ( (VALVE_T)payload.valve < NUM_OF_VALVES ) && ( (VALVE_POSITION_T)payload.pos < NUM_OF_VALVE_POSITIONS ) ) + { + result = setValvePosition( (VALVE_T)payload.valve, (VALVE_POSITION_T)payload.pos ); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testHomeValve function handles a Dialin command to home a given valve. + * @details \b Inputs: none + * @details \b Outputs: currentValveStates[] + * @param message Override message from Dialin which includes the ID of the + * valve to home and related flags. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testHomeValve( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD + if ( TRUE == isTestingActivated() ) + { + VALVE_PINCH_HOME_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(VALVE_PINCH_HOME_CMD_PAYLOAD_T) ); + if ( (VALVE_T)payload.valve < NUM_OF_VALVES ) + { + result = homeValve( (VALVE_T)payload.valve, payload.force, payload.tubing ); + } + } + + return result; +} + +/**@}*/ + Index: firmware/App/Controllers/Valves.h =================================================================== diff -u --- firmware/App/Controllers/Valves.h (revision 0) +++ firmware/App/Controllers/Valves.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,74 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file Valves.h +* +* @author (last) Sean +* @date (last) 08-Oct-2024 +* +* @author (original) Sean +* @date (original) 08-Oct-2024 +* +***************************************************************************/ + +#ifndef __VALVES_H__ +#define __VALVES_H__ + +// ********** public definitions ********** + +#include "TDCommon.h" +#include "RotaryValve.h" + +/** + * @defgroup Valves Valves + * @brief Valves controller unit. Provides higher level control of the pinch valves. + * + * @addtogroup Valves + * @{ + */ + +// ********** public definitions ********** + +/// Valves positions +typedef enum valveStatesNames +{ + VALVE_POSITION_NOT_IN_POSITION = 0, ///< Valve position is unknown (cannot be used as a command) + VALVE_POSITION_A_INSERT_EJECT, ///< Position A, Insert/Eject (current position or commanded) + VALVE_POSITION_B_OPEN, ///< Position B, Open (current position or commanded) + VALVE_POSITION_C_CLOSE, ///< Position C, Close (current position or commanded) + NUM_OF_VALVE_POSITIONS, ///< Number of valve positions +} VALVE_POSITION_T; + +#pragma pack(push, 1) +/// TD valves broadcast data +typedef struct +{ + U32 valveID; ///< Valve ID + U32 state; ///< Current state of the state machine + U32 currentPosID; ///< Current position (enum) + S16 currentPos; ///< Current position in encoder counts + S16 cmdPos; ///< Commanded position (enum) +} TD_VALVE_DATA_T; +#pragma pack(pop) + +// ********** public function prototypes ********** + +void initValves(void); +void execValvesController(void); +SELF_TEST_STATUS_T execValvesSelfTest( void ); + +BOOL homeValve( VALVE_T valve, BOOL force, BOOL cartridge ); +BOOL setValvePosition( VALVE_T valve, VALVE_POSITION_T position ); +VALVE_POSITION_T getValvePosition( VALVE_T valve ); + +BOOL testValvesDataPublishIntervalOverride( MESSAGE_T *message ); +BOOL testValveSetABCCmdPosition( MESSAGE_T *message ); +BOOL testHomeValve( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Drivers/BubbleDetector.c =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Drivers/BubbleDetector.c (.../BubbleDetector.c) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Drivers/BubbleDetector.c (.../BubbleDetector.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -56,7 +56,7 @@ * @note This function should be called periodically to maintain fresh * sensor readings for all bubble detectors. * @details \b Inputs: FPGA - * @details \b Outputs: none + * @details \b Outputs: currentBubbleState[] * @return none *************************************************************************/ void readBubbleDetectors( void ) @@ -72,7 +72,7 @@ * The getBubbleDetectedState function gets the current bubble detected state * for a given bubble detector sensor. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given sensor is invalid. - * @details \b Inputs: currentBubbleState + * @details \b Inputs: currentBubbleState[] * @details \b Outputs: none * @param sensor ID of bubble detector sensor to get state for. * @return The current state of the given bubble detector sensor. Index: firmware/App/Drivers/GLXferPump.c =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Drivers/GLXferPump.c (.../GLXferPump.c) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Drivers/GLXferPump.c (.../GLXferPump.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -70,7 +70,7 @@ } else { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_AIR_PUMP_INVALID_MOTOR_STATE_SELECTED, (U32)state ) + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_AIR_PUMP_INVALID_STATE, (U32)state ) } } @@ -112,7 +112,6 @@ U32 state; memcpy( &state, message->payload, sizeof(U32) ); - result = TRUE; if ( state < NUM_OF_AIR_PUMP_MOTOR_STATES ) { setAirPumpMotorState( (AIR_PUMP_MOTOR_STATE_T)state ); Index: firmware/App/Drivers/GLXferPump.h =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Drivers/GLXferPump.h (.../GLXferPump.h) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Drivers/GLXferPump.h (.../GLXferPump.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -43,7 +43,7 @@ // ********** public function prototypes ********** -void initGasLiqXferPumpDriver(void); +void initGasLiqXferPumpDriver( void ); void setAirPumpMotorState( AIR_PUMP_MOTOR_STATE_T state ); AIR_PUMP_MOTOR_STATE_T getAirPumpMotorState( void ); Index: firmware/App/Drivers/LevelSensors.c =================================================================== diff -u --- firmware/App/Drivers/LevelSensors.c (revision 0) +++ firmware/App/Drivers/LevelSensors.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,213 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file LevelSensors.c +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#include "LevelSensors.h" +#include "FpgaTD.h" +#include "Messaging.h" +#include "Timers.h" + +/** + * @addtogroup LevelSensors + * @{ + */ + +// ********** private definitions ********** + +#define AIR_TRAP_LEVEL_DEBOUNCE_TIME_MS ( 400 ) ///< Air trap level sensor debounce time (in ms). + +// ********** private data ********** + +static OVERRIDE_U32_T rawLevelStates[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< Raw air trap level states before debounce (overrideable). +static OVERRIDE_U32_T currentLevelStates[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< Current raw level sensor states (overrideable). +static U32 airTrapLevelsDebounceStartTime[ NUM_OF_AIR_TRAP_LEVEL_SENSORS ]; ///< Debounce start time for airtrap level sensors. + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The initLevelSensors function initializes the Level Sensors unit. + * @details \b Inputs: none + * @details \b Outputs: Level Sensors unit is initialized. + * @return none + *************************************************************************/ +void initLevelSensors( void ) +{ + AIR_TRAP_LEVEL_SENSORS_T airTrapLevelSensor; + + for( airTrapLevelSensor = AIR_TRAP_LEVEL_FIRST; airTrapLevelSensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS; airTrapLevelSensor++ ) + { + airTrapLevelsDebounceStartTime[ airTrapLevelSensor ] = 0; + rawLevelStates[ airTrapLevelSensor ].data = AIR_TRAP_LEVEL_AIR; + rawLevelStates[ airTrapLevelSensor ].ovData = AIR_TRAP_LEVEL_AIR; + rawLevelStates[ airTrapLevelSensor ].ovInitData = AIR_TRAP_LEVEL_AIR; + rawLevelStates[ airTrapLevelSensor ].override = OVERRIDE_RESET; + currentLevelStates[ airTrapLevelSensor ].data = AIR_TRAP_LEVEL_AIR; + currentLevelStates[ airTrapLevelSensor ].ovData = AIR_TRAP_LEVEL_AIR; + currentLevelStates[ airTrapLevelSensor ].ovInitData = AIR_TRAP_LEVEL_AIR; + currentLevelStates[ airTrapLevelSensor ].override = OVERRIDE_RESET; + } +} + +/*********************************************************************//** + * @brief + * The readLevelSensors function gets the current level sensor state + * for a all level sensors from the FPGA. + * @note This function should be called periodically to maintain fresh + * sensor readings for all level sensors. + * @details \b Inputs: FPGA + * @details \b Outputs: rawLevelStates[], currentLevelStates[], + * airTrapLevelsDebounceStartTime[] + * @return none + *************************************************************************/ +void readLevelSensors( void ) +{ + BOOL lowAir, highAir; + AIR_TRAP_LEVEL_SENSORS_T airTrapLevelSensor; + + // Get latest raw level sensor states from FPGA + getFPGAAirTrapLevels( &lowAir, &highAir ); + currentLevelStates[ AIR_TRAP_LEVEL_SENSOR_LOWER ].data = (U32)( FALSE == lowAir ? AIR_TRAP_LEVEL_FLUID : AIR_TRAP_LEVEL_AIR ); + currentLevelStates[ AIR_TRAP_LEVEL_SENSOR_UPPER ].data = (U32)( FALSE == highAir ? AIR_TRAP_LEVEL_FLUID : AIR_TRAP_LEVEL_AIR ); + + // Debounce raw air trap level sensor readings + for( airTrapLevelSensor = AIR_TRAP_LEVEL_FIRST; airTrapLevelSensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS; airTrapLevelSensor++ ) + { + // Check if the raw level sensor status is not the same as the recorded data + if ( getRawLevelSensorState( airTrapLevelSensor ) != (AIR_TRAP_LEVELS_T)currentLevelStates[ airTrapLevelSensor ].data ) + { + // If the debounce time is 0, start the timer + if ( 0 == airTrapLevelsDebounceStartTime[ airTrapLevelSensor ] ) + { + airTrapLevelsDebounceStartTime[ airTrapLevelSensor ] = getMSTimerCount(); + } + // If the debounce time has elapsed, update the level sensor status to the new status + else if ( TRUE == didTimeout( airTrapLevelsDebounceStartTime[ airTrapLevelSensor ], AIR_TRAP_LEVEL_DEBOUNCE_TIME_MS ) ) + { + // reset the debounce time + airTrapLevelsDebounceStartTime[ airTrapLevelSensor ] = 0; + // update recent level status + currentLevelStates[ airTrapLevelSensor ].data = (U32)getRawLevelSensorState( airTrapLevelSensor ); + } + } + else + { + airTrapLevelsDebounceStartTime[ airTrapLevelSensor ] = 0; + } + } +} + +/*********************************************************************//** + * @brief + * The getLevelSensorState function gets the current debounced sensor state + * for a given level sensor. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: currentLevelStates[] + * @details \b Outputs: none + * @param sensor ID of level sensor to get state for. + * @return The current state of the given level sensor. + *************************************************************************/ +AIR_TRAP_LEVELS_T getLevelSensorState( AIR_TRAP_LEVEL_SENSORS_T sensor ) +{ + AIR_TRAP_LEVELS_T result = AIR_TRAP_LEVEL_AIR; + + if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) + { + result = (AIR_TRAP_LEVELS_T)currentLevelStates[ sensor ].data; + if ( OVERRIDE_KEY == currentLevelStates[ sensor ].override ) + { + result = (AIR_TRAP_LEVELS_T)currentLevelStates[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_LEVEL_SENSOR_INVALID_SENSOR, sensor ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getRawLevelSensorState function gets the current raw sensor state + * for a given level sensor. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given sensor is invalid. + * @details \b Inputs: rawLevelStates[] + * @details \b Outputs: none + * @param sensor ID of level sensor to get state for. + * @return The current state of the given level sensor. + *************************************************************************/ +AIR_TRAP_LEVELS_T getRawLevelSensorState( AIR_TRAP_LEVEL_SENSORS_T sensor ) +{ + AIR_TRAP_LEVELS_T result = AIR_TRAP_LEVEL_AIR; + + if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) + { + result = (AIR_TRAP_LEVELS_T)rawLevelStates[ sensor ].data; + if ( OVERRIDE_KEY == rawLevelStates[ sensor ].override ) + { + result = (AIR_TRAP_LEVELS_T)rawLevelStates[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_LEVEL_SENSOR_INVALID_SENSOR, sensor ) + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testRawLevelSensorOverride function overrides the raw sensor state + * for a given level sensor. + * @details \b Inputs: none + * @details \b Outputs: rawLevelStates[] + * @param message Override message from Dialin which includes an ID of + * the sensor to override and the state to override the sensor to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testRawLevelSensorOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, &rawLevelStates[0], NUM_OF_AIR_TRAP_LEVEL_SENSORS - 1, 0, NUM_OF_AIR_TRAP_LEVELS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testLevelSensorOverride function overrides the sensor state for a + * given level sensor. + * @details \b Inputs: none + * @details \b Outputs: currentLevelStates[] + * @param message Override message from Dialin which includes an ID of + * the sensor to override and the state to override the sensor to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testLevelSensorOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, ¤tLevelStates[0], NUM_OF_AIR_TRAP_LEVEL_SENSORS - 1, 0, NUM_OF_AIR_TRAP_LEVELS - 1 ); + + return result; +} + +/**@}*/ Index: firmware/App/Drivers/LevelSensors.h =================================================================== diff -u --- firmware/App/Drivers/LevelSensors.h (revision 0) +++ firmware/App/Drivers/LevelSensors.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,63 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file LevelSensors.h +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#ifndef __LEVEL_SENSORS_H__ +#define __LEVEL_SENSORS_H__ + +#include "TDCommon.h" + +/** + * @defgroup LevelSensors LevelSensors + * @brief The Level sensors unit provides low-level functions to monitor a + * high and low level sensor for an air trap. + * + * @addtogroup LevelSensors + * @{ + */ + +// ********** public definitions ********** + +/// Enumeration of air trap level sensors monitored by this module. +typedef enum AirTrapLevelSensors +{ + AIR_TRAP_LEVEL_SENSOR_LOWER = 0, ///< Lower air trap sensor + AIR_TRAP_LEVEL_FIRST = AIR_TRAP_LEVEL_SENSOR_LOWER, ///< First air trap level sensor + AIR_TRAP_LEVEL_SENSOR_UPPER, ///< Upper air trap sensor + NUM_OF_AIR_TRAP_LEVEL_SENSORS ///< Number of air trap sensors +} AIR_TRAP_LEVEL_SENSORS_T; + +/// Enumeration of air trap level sensor levels. +typedef enum AirTrapLevelSensorLevels +{ + AIR_TRAP_LEVEL_AIR = 0, ///< Air trap level sensor detects air + AIR_TRAP_LEVEL_FLUID, ///< Air trap level sensor detects fluid + NUM_OF_AIR_TRAP_LEVELS ///< Number of air trap level sensor levels +} AIR_TRAP_LEVELS_T; + +// ********** public function prototypes ********** + +void initLevelSensors( void ); +void readLevelSensors( void ); +AIR_TRAP_LEVELS_T getLevelSensorState( AIR_TRAP_LEVEL_SENSORS_T sensor ); +AIR_TRAP_LEVELS_T getRawLevelSensorState( AIR_TRAP_LEVEL_SENSORS_T sensor ); + +BOOL testRawLevelSensorOverride( MESSAGE_T *message ); +BOOL testLevelSensorOverride( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Drivers/PeristalticPump.c =================================================================== diff -u --- firmware/App/Drivers/PeristalticPump.c (revision 0) +++ firmware/App/Drivers/PeristalticPump.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,211 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file PeristalticPump.c +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#include "AlarmMgmtTD.h" +#include "FpgaTD.h" +#include "Messaging.h" +#include "PeristalticPump.h" + +/** + * @addtogroup PeristalticPump + * @{ + */ + +// ********** private definitions ********** + +#define MAX_PUMP_SPEED_RPM 5000U ///< Maximum speed (in RPM) that a peristaltic pump can be set to. + +// ********** private data ********** + +static S32 pumpSetSpeedRPM; ///< Current set speed for the pump (in RPM). Negative indicates reverse direction. +static OVERRIDE_S32_T pumpMeasSpeedRPM; ///< Latest measured pump speed (in RPM). +static BOOL pumpHomeRequested; ///< Flag indicates a pump home operation has been requested. + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The initPeristalticPumpDriver function initializes the peristaltic pump + * driver unit. + * @details \b Inputs: none + * @details \b Outputs: currentAirPumpMotorState + * @return none + *************************************************************************/ +void initPeristalticPumpDriver(void) +{ + pumpHomeRequested = FALSE; + pumpSetSpeedRPM = 0; + pumpMeasSpeedRPM.data = 0; + pumpMeasSpeedRPM.ovData = 0; + pumpMeasSpeedRPM.ovInitData = 0; + pumpMeasSpeedRPM.override = OVERRIDE_RESET; + + setBloodPumpDirection( MOTOR_DIR_FORWARD ); + resetBloodPumpHomeRequest(); + setBloodPumpSetSpeed( 0 ); + setBloodPumpEnabled( TRUE ); +} + +/*********************************************************************//** + * @brief + * The readPeristalticPumps function gets the current readings for the + * peristaltic pump from the FPGA. + * @note This function should be called periodically to maintain fresh + * sensor readings for the pump. + * @details \b Inputs: pumpSetSpeedRPM, pumpHomeRequested, FPGA + * @details \b Outputs: pumpMeasSpeedRPM, pumpHomeRequested + * @return none + *************************************************************************/ +void readPeristalticPumps( void ) +{ + // update measured pump speed + if ( pumpSetSpeedRPM < 0 ) + { + pumpMeasSpeedRPM.data = (S32)( (S16)getBloodPumpSpeed() * -1 ); + } + else + { + pumpMeasSpeedRPM.data = (S32)( (S16)getBloodPumpSpeed() ); + } + + // clear home command if previously requested + if ( TRUE == pumpHomeRequested ) + { + pumpHomeRequested = FALSE; + resetBloodPumpHomeRequest(); + } +} + +/*********************************************************************//** + * @brief + * The cmdPeristalticPumpHome function initiates a pump home operation. + * @details \b Inputs: none + * @details \b Outputs: pumpHomeRequested, FPGA + * @return none + *************************************************************************/ +void cmdPeristalticPumpHome( void ) +{ + pumpHomeRequested = TRUE; + homeBloodPump(); +} + +/*********************************************************************//** + * @brief + * The setPeristalticPumpSetSpeed function sets the target pump speed (in RPM). + * @note A negative set speed indicates reverse (CCW) direction. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given set speed is out + * of range. + * @details \b Inputs: none + * @details \b Outputs: pumpSetSpeedRPM + * @param rpm Speed (in RPM) to set as pump target speed. + * @return TRUE if set speed command successful, FALSE if not. + *************************************************************************/ +BOOL setPeristalticPumpSetSpeed( S32 rpm ) +{ + BOOL result = FALSE; + + if ( abs( rpm ) < MAX_PUMP_SPEED_RPM ) + { + U16 setRpm = (U16)( abs( rpm ) ); + MOTOR_DIR_T dir = MOTOR_DIR_FORWARD; + + if ( rpm < 0 ) + { + dir = MOTOR_DIR_REVERSE; + } + pumpSetSpeedRPM = rpm; + setBloodPumpDirection( dir ); + setBloodPumpSetSpeed( setRpm ); + result = TRUE; + } + else + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, (F32)SW_FAULT_ID_PERISTALTIC_PUMP_SET_SPEED_OUT_OF_RANGE, rpm ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getPeristalticPumpSetSpeed function gets the current pump set + * speed in RPM. + * @note A negative speed indicates reverse direction. + * @details \b Inputs: pumpSetSpeedRPM + * @details \b Outputs: none + * @return Latest pump set speed in RPM. + *************************************************************************/ +S32 getPeristalticPumpSetSpeed( void ) +{ + return pumpSetSpeedRPM; +} + +/*********************************************************************//** + * @brief + * The getPeristalticPumpMeasSpeed function gets the latest measured pump + * speed in RPM. + * @note A negative speed indicates reverse direction. + * @details \b Inputs: pumpMeasSpeedRPM + * @details \b Outputs: none + * @return Latest measured pump speed in RPM. + *************************************************************************/ +S32 getPeristalticPumpMeasSpeed( void ) +{ + S32 result = pumpMeasSpeedRPM.data; + + if ( OVERRIDE_KEY == pumpMeasSpeedRPM.override ) + { + result = pumpMeasSpeedRPM.ovData; + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetPeristalticPumpSetSpeed function sets the pump to a given speed + * (RPM). A negative speed indicates reverse (CCW) direction. + * @details \b Inputs: none + * @details \b Outputs: pumpSetSpeedRPM + * @param message set message from Dialin which includes the speed (RPM) to set + * the peristaltic pump to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testSetPeristalticPumpSetSpeed( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD and override type is valid + if ( TRUE == isTestingActivated() ) + { + S32 speed; + + memcpy( &speed, message->payload, sizeof(S32) ); + result = setPeristalticPumpSetSpeed( (S16)speed ); + } + + return result; +} + +/**@}*/ + Index: firmware/App/Drivers/PeristalticPump.h =================================================================== diff -u --- firmware/App/Drivers/PeristalticPump.h (revision 0) +++ firmware/App/Drivers/PeristalticPump.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,52 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file PeristalticPump.h +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#ifndef __PERISTALTIC_PUMP_H__ +#define __PERISTALTIC_PUMP_H__ + +// ********** public definitions ********** + +#include "TDCommon.h" + +/** + * @defgroup PeristalticPump PeristalticPump + * @brief Peristaltic pump driver unit. Provides low level functions + * to control a peristaltic pump. + * + * @addtogroup PeristalticPump + * @{ + */ + +// ********** public definitions ********** + + +// ********** public function prototypes ********** + +void initPeristalticPumpDriver( void ); +void readPeristalticPumps( void ); + +BOOL setPeristalticPumpSetSpeed( S32 rpm ); +S32 getPeristalticPumpSetSpeed( void ); +S32 getPeristalticPumpMeasSpeed( void ); + +void cmdPeristalticPumpHome( void ); + +BOOL testSetPeristalticPumpSetSpeed( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Drivers/PressureSensor.c =================================================================== diff -u -ra91074d04b607deabe4fbf714d40e9d191590359 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Drivers/PressureSensor.c (.../PressureSensor.c) (revision a91074d04b607deabe4fbf714d40e9d191590359) +++ firmware/App/Drivers/PressureSensor.c (.../PressureSensor.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -19,7 +19,8 @@ #include "Messaging.h" #include "PersistentAlarm.h" #include "PressureCommon.h" -#include "PressureSensor.h" +#include "PressureSensor.h" +#include "Utilities.h" /** * @addtogroup PressureSensor @@ -28,18 +29,37 @@ // ********** private definitions ********** +#define BAR_TO_MMHG ( 750.062F ) ///< Conversion factor for converting bar to mmHg. + +#define PRES_SENSORS_ZERO_OFFSET ( 1638.0F ) ///< Zero offset for pressure sensor readings. +#define PRES_SENSORS_DIVISOR ( 14745.0F - PRES_SENSORS_ZERO_OFFSET ) ///< Divisor for pressure sensor conversion from counts to bars. +#define PRES_SENSORS_RANGE_IN_BARS ( 1.6F - 0.0F ) ///< Range (in bars) of the pressure sensors (0..1.6). + #define PRES_SENSORS_COUNT_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Pressure sensors read and error count timeout in milliseconds. +#define FPGA_PRESSURE_READING_BIT_COUNT 14 ///< Number of bits in a pressure reading from the FPGA. +#define FPGA_PRESSURE_STATUS_BITS_MASK 0xC000 ///< Bit mask for status bits of pressure reading register. +#define FPGA_PRESSURE_READING_BITS_MASK 0x3FFF ///< Bit mask for pressure bits of pressure reading register. + +#define PRESSURE_NORMAL_OP 0 ///< Pressure status bits indicate normal operation. +#define PRESSURE_CMD_MODE 1 ///< Pressure status bits indicate sensor in command mode. +#define PRESSURE_STALE_DATA 2 ///< Pressure status bits indicate data is stale (no new data since last fpga read). +#define PRESSURE_DIAG_CONDITION 3 ///< Pressure status bits diagnostic condition (alarm). + // ********** private data ********** static OVERRIDE_F32_T currentPressureReadings[ NUM_OF_PRESSURE_SENSORS ]; ///< Current pressure sensor pressure readings (overrideable). static OVERRIDE_F32_T currentPresTempReadings[ NUM_OF_PRESSURE_SENSORS ]; ///< Current pressure sensor temperature readings (overrideable). static OVERRIDE_U32_T lastPressureReadCounter[ NUM_OF_PRESSURE_SENSORS ]; ///< Last pressure sensor read count (Overrideable). static OVERRIDE_U32_T lastPressureErrorCounter[ NUM_OF_PRESSURE_SENSORS ]; ///< Last pressure sensor error count (Overrideable). +static U32 currentPressureStatus[ NUM_OF_PRESSURE_SENSORS ]; ///< Current status of pressure sensors. // ********** private function prototypes ********** static void checkPressureSensors( void ); +static F32 convertPressureRdg2mmHg( S16 counts ); +static F32 getPresureReadingFromFPGARegReading( U16 fpgaReg ); +static U32 getPressureStatusFromFPGARegReading( U16 fpgaReg ); /*********************************************************************//** * @brief @@ -74,6 +94,8 @@ lastPressureErrorCounter[ i ].ovData = 0; lastPressureErrorCounter[ i ].ovInitData = 0; lastPressureErrorCounter[ i ].override = OVERRIDE_RESET; + + currentPressureStatus[ i ] = PRESSURE_STALE_DATA; } // Initialize the FPGA persistent alarms @@ -97,9 +119,16 @@ *************************************************************************/ void readPressureSensors( void ) { + U16 PBA = getPBAPressure(); + U16 PBO = getPBOPressure(); + + // Update status of pressure sensors + currentPressureStatus[ PRESSURE_SENSOR_ARTERIAL ] = getPressureStatusFromFPGARegReading( PBA ); + currentPressureStatus[ PRESSURE_SENSOR_VENOUS ] = getPressureStatusFromFPGARegReading( PBO ); + // Update and convert raw pressures to mmHg - currentPressureReadings[ PRESSURE_SENSOR_ARTERIAL ].data = convertPressureReading2mmHg( getPBAPressure() ); - currentPressureReadings[ PRESSURE_SENSOR_VENOUS ].data = convertPressureReading2mmHg( getPBOPressure() ); + currentPressureReadings[ PRESSURE_SENSOR_ARTERIAL ].data = convertPressureRdg2mmHg( PBA ); + currentPressureReadings[ PRESSURE_SENSOR_VENOUS ].data = convertPressureRdg2mmHg( PBO ); // Update and convert raw pressure sensor temperatures to deg C currentPresTempReadings[ PRESSURE_SENSOR_ARTERIAL ].data = convertPressureTempReading2DegC( getPBATemperature() ); @@ -117,6 +146,58 @@ /*********************************************************************//** * @brief + * The convertPressureRdg2mmHg function converts a raw pressure count from + * the FPGA and converts it to mmHg. + * @details \b Inputs: none + * @details \b Outputs: none + * @param counts the raw pressure reading in counts from the FPGA + * @return the pressure in mmHg + *************************************************************************/ +static F32 convertPressureRdg2mmHg( S16 counts ) +{ + F32 rdg = getPresureReadingFromFPGARegReading( counts ); + F32 bar = ( ( rdg - PRES_SENSORS_ZERO_OFFSET ) * ( PRES_SENSORS_RANGE_IN_BARS ) / ( PRES_SENSORS_DIVISOR ) ); + F32 mmHg = bar * BAR_TO_MMHG; + + return mmHg; +} + +/*********************************************************************//** + * @brief + * The getPresureReadingFromFPGARegReading function extracts the signed + * pressure reading (in counts) from the FPGA register reading. + * @details \b Inputs: none + * @details \b Outputs: none + * @param fpgaReg the value read from the FPGA register + * @return the pressure portion of the FPGA register value, sign extended + *************************************************************************/ +static F32 getPresureReadingFromFPGARegReading( U16 fpgaReg ) +{ + U16 rdg = fpgaReg & FPGA_PRESSURE_READING_BITS_MASK; // mask off status bits + S16 ext = signExtend16( rdg, FPGA_PRESSURE_READING_BIT_COUNT - 1 ); // sign extend reading in case it's negative + + return (F32)ext; +} + +/*********************************************************************//** + * @brief + * The getPressureStatusFromFPGARegReading function extracts the status + * from the FPGA register reading. + * @details \b Inputs: none + * @details \b Outputs: none + * @param fpgaReg the value read from the FPGA register + * @return the status portion of the FPGA register value + *************************************************************************/ +static U32 getPressureStatusFromFPGARegReading( U16 fpgaReg ) +{ + U16 rdg = fpgaReg & FPGA_PRESSURE_STATUS_BITS_MASK; // mask off reading bits + U32 result = rdg >> FPGA_PRESSURE_READING_BIT_COUNT; // shift status bits to lsb + + return result; +} + +/*********************************************************************//** + * @brief * The checkPressureSensors function checks the read and error counters for * each pressure sensor. * @details \b Alarm: ALARM_ID_TD_ARTERIAL_SENSOR_TIMEOUT_FAULT if the @@ -133,6 +214,16 @@ checkFPGAPersistentAlarms( FPGA_PERS_ERROR_VENOUS_PRESSURE_SESNOR, getPressureSensorReadCount( PRESSURE_SENSOR_VENOUS ) ); checkFPGAPersistentErrorCountAlarm( FPGA_PERS_ERROR_ARTERIAL_PRESSURE_SENSOR, getPressureSensorErrorCount( PRESSURE_SENSOR_ARTERIAL ) ); checkFPGAPersistentErrorCountAlarm( FPGA_PERS_ERROR_VENOUS_PRESSURE_SESNOR, getPressureSensorErrorCount( PRESSURE_SENSOR_VENOUS ) ); + + // verify status of pressure sensors + if ( currentPressureStatus[ PRESSURE_SENSOR_ARTERIAL ] != PRESSURE_NORMAL_OP ) + { + // TODO - alarm? + } + if ( currentPressureStatus[ PRESSURE_SENSOR_ARTERIAL ] != PRESSURE_NORMAL_OP ) + { + // TODO - alarm? + } } /*********************************************************************//** Index: firmware/App/Drivers/PressureSensor.h =================================================================== diff -u -r0c8ae7b952186d912c77d8c2cfb7dad809fa5225 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Drivers/PressureSensor.h (.../PressureSensor.h) (revision 0c8ae7b952186d912c77d8c2cfb7dad809fa5225) +++ firmware/App/Drivers/PressureSensor.h (.../PressureSensor.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -31,7 +31,7 @@ // ********** public definitions ********** -/// Enumeration of pressure sensors monitored by this module. +/// Enumeration of pressure sensors monitored by this unit. typedef enum PressureSensors { PRESSURE_SENSOR_ARTERIAL = 0, ///< Arterial blood line pressure sensor Index: firmware/App/Drivers/RotaryValve.c =================================================================== diff -u --- firmware/App/Drivers/RotaryValve.c (revision 0) +++ firmware/App/Drivers/RotaryValve.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,366 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file RotaryValve.c +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#include "AlarmMgmtTD.h" +#include "FpgaTD.h" +#include "Messaging.h" +#include "RotaryValve.h" + +/** + * @addtogroup RotaryValve + * @{ + */ + +// ********** private definitions ********** + +#define VALVE_ENC_COUNT_2_MICRO_STEP_CONVERSION 6.25F ///< 6.25 microsteps per encoder count. + +#define VALVE_MOTOR_DRIVER_FAULT_BIT_MASK 0x1 ///< Bit mask for valve motor driver fault. +#define VALVE_DIRECTION_FAULT_BIT_MASK 0x2 ///< Bit mask for valve direction fault. +#define VALVE_INCORRECT_ENCODER_STATUS_BIT_MASK 0x4 ///< Bit mask for valve incorrect encoder sensor fault. + +/// Bit mask for all (OR'd) valve faults. +#define VALVE_GEN_FAULT_BIT_MASK ( VALVE_MOTOR_DRIVER_FAULT_BIT_MASK | VALVE_DIRECTION_FAULT_BIT_MASK | VALVE_INCORRECT_ENCODER_STATUS_BIT_MASK ) + +#pragma pack(push, 1) +/// Payload record structure for rotary valve set position request +typedef struct +{ + U32 valve; ///< which rotary valve to set position for (0=VBA, 1=VBV) + S16 stepChange; ///< number of steps to change position (pos indicates CW, neg indicates CCW) +} VALVE_ROTARY_SET_CMD_PAYLOAD_T; +#pragma pack(pop) + +// ********** private data ********** + +static U08 valveControl[ NUM_OF_VALVES ]; ///< Current control bits for each valve. +static OVERRIDE_U32_T valveStatus[ NUM_OF_VALVES ]; ///< Current status bits for each valve. +static S16 commandValvePosChange[ NUM_OF_VALVES ]; ///< Current commanded valve position changes. Negative indicates CCW direction. +static OVERRIDE_S32_T currentValveEncPosition[ NUM_OF_VALVES ]; ///< Current encoder valve positions (overrideable). Negative indicates CCW direction. + +// ********** private function prototypes ********** + +static U08 getValveStatus( VALVE_T valve ); + +/*********************************************************************//** + * @brief + * The initRotaryValvesDriver function initializes the rotary valves driver + * unit. + * @details \b Inputs: none + * @details \b Outputs: Rotary valves driver unit is initialized + * @return none + *************************************************************************/ +void initRotaryValvesDriver(void) +{ + U32 i; + + for ( i = FIRST_VALVE; i < NUM_OF_VALVES; i++ ) + { + valveControl[ i ] = FPGA_PINCH_VALVES_1_32_STEP | FPGA_PINCH_VALVES_NOT_RESET | FPGA_PINCH_VALVES_NOT_SLEEP; // enable valves, configure for 1/32 step control + commandValvePosChange[ i ] = 0; + currentValveEncPosition[ i ].data = 0; + currentValveEncPosition[ i ].ovData = 0; + currentValveEncPosition[ i ].ovInitData = 0; + currentValveEncPosition[ i ].override = OVERRIDE_RESET; + valveStatus[ i ].data = 0; + valveStatus[ i ].ovData = 0; + valveStatus[ i ].ovInitData = 0; + valveStatus[ i ].override = OVERRIDE_RESET; + } + + // set valve control bits once at startup + setVBAControl( valveControl[ VBA ] ); + setVBVControl( valveControl[ VBV ] ); +} + +/*********************************************************************//** + * @brief + * The readValves function gets the current position and status of all rotary + * pinch valves from the FPGA. + * @note This function should be called periodically to maintain fresh + * status and positions for all valves. + * @details \b Alarm: ALARM_ID_TD_PINCH_VALVE_FAULT if valve reports a driver, + * direction, or encoder fault. + * @details \b Inputs: FPGA + * @details \b Outputs: valveStatus[], currentValveEncPosition[] + * @return none + *************************************************************************/ +void readValves( void ) +{ + U32 i; + S16 cmdPos[ NUM_OF_VALVES ]; + + // Get latest valve status and positions from FPGA + cmdPos[ VBV ] = getVBVCmdPosition(); + currentValveEncPosition[ VBV ].data = (S32)getValveEncoderPosition( VBV ); + valveStatus[ VBV ].data = getVBVStatus(); + cmdPos[ VBA ] = getVBACmdPosition(); + currentValveEncPosition[ VBA ].data = (S32)getValveEncoderPosition( VBA ); + valveStatus[ VBA ].data = getVBAStatus(); + + // TODO check commanded position vs. commanded position read back from FPGA - alarm different for some persistent period of time + + // Check valves status for faults + for ( i = FIRST_VALVE; i < NUM_OF_VALVES; i++ ) + { + U32 status = getValveStatus( (VALVE_T)i ); + + if ( ( status & VALVE_GEN_FAULT_BIT_MASK ) != 0 ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_PINCH_VALVE_FAULT, i, status ) + } + } +} + +/*********************************************************************//** + * @brief + * The setValveCmdChangePosition function sets the commanded magnitude (in + * steps or microsteps as appropriate) for a position change of a given valve. + * @details \b Message \Sent: MSG_ID_TD_EVENT for TD_EVENT_VALVE_POS_CHANGE + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve given. + * @details \b Inputs: none + * @details \b Outputs: commandValvePosChange[] + * @param valve Valve to set new commanded change in position for + * @param mag Magnitude of position change for valve (in encoder counts) + * @param dir Direction to move valve + * @return none. + *************************************************************************/ +void setValveCmdChangePosition( VALVE_T valve, U16 mag, MOTOR_DIR_T dir ) +{ + if ( valve < NUM_OF_VALVES ) + { + S16 chg = (S16)mag * ( MOTOR_DIR_REVERSE == dir ? -1 : 1 ); + U08 ctrl; + F32 temp; + + // log event showing valve position change commanded + SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_VALVE_POS_CHANGE, (U32)commandValvePosChange[ valve ], (U32)chg ); + // convert magnitude of change from encoder counts to microsteps + temp = (F32)chg * VALVE_ENC_COUNT_2_MICRO_STEP_CONVERSION; + chg = (S16)((S32)((temp) + FLOAT_TO_INT_ROUNDUP_OFFSET)); + mag = (S16)(abs(chg)); + // give FPGA valve change command + commandValvePosChange[ valve ] = chg; + if ( VBA == valve ) + { + ctrl = getVBAControl(); + if ( MOTOR_DIR_REVERSE == dir ) + { + setVBAControl( ( ctrl | FPGA_PINCH_VALVES_REVERSE ) ); + } + else + { + setVBAControl( ( ctrl & ~FPGA_PINCH_VALVES_REVERSE ) ); + } + setVBAPosition( mag ); + } + else + { + ctrl = getVBVControl(); + if ( MOTOR_DIR_REVERSE == dir ) + { + setVBVControl( ( ctrl | FPGA_PINCH_VALVES_REVERSE ) ); + } + else + { + setVBVControl( ( ctrl & ~FPGA_PINCH_VALVES_REVERSE ) ); + } + setVBVPosition( mag ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE1, (U32)valve ) + } +} + +/*********************************************************************//** + * @brief + * The getValveCmdTravel function gets the most recent commanded travel (in + * encoder counts) for a given valve. + * @note A negative return value indicates travel in the reverse (CCW) direction. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve given. + * @details \b Inputs: commandValvePosChange[] + * @details \b Outputs: none + * @param valve ID of valve to get commanded position for + * @return Commanded position change (in encoder counts) for the given valve + *************************************************************************/ +S16 getValveCmdTravel( VALVE_T valve ) +{ + S16 result = 0; + + if ( valve < NUM_OF_VALVES ) + { + F32 temp = (F32)commandValvePosChange[ valve ] / VALVE_ENC_COUNT_2_MICRO_STEP_CONVERSION; // convert magnitude of change from microsteps to encoder counts + + result = (S16)((S32)((temp) + FLOAT_TO_INT_ROUNDUP_OFFSET)); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE2, (U32)valve ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getValveEncoderPosition function gets the current actual position + * (in encoder counts) for a given valve. + * @note There are 1024 encoder counts per revolution. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve given. + * @details \b Inputs: currentValveEncPosition[] + * @details \b Outputs: none + * @param valve ID of valve to get actual position for + * @return Actual position for the given valve + *************************************************************************/ +S16 getValveEncoderPosition( VALVE_T valve ) +{ + S16 result = 0; + + if ( valve < NUM_OF_VALVES ) + { + result = (S16)(currentValveEncPosition[ valve ].data); + if ( OVERRIDE_KEY == currentValveEncPosition[ valve ].override ) + { + result = (S16)(currentValveEncPosition[ valve ].ovData); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE3, (U32)valve ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getValveStatus function gets the current status for a given valve. + * Status bits: + * 0-motor driver fault + * 1-direction fault + * 2-incorrect encoder sensor fault + * 3..7-reserved + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve given. + * @details \b Inputs: valveStatus[] + * @details \b Outputs: none + * @param valve ID of valve to get status for + * @return Status for the given valve + *************************************************************************/ +static U08 getValveStatus( VALVE_T valve ) +{ + U08 result = 0; + + if ( valve < NUM_OF_VALVES ) + { + result = (U08)( valveStatus[ valve ].data & MASK_OFF_U32_MSBS ); + if ( OVERRIDE_KEY == valveStatus[ valve ].override ) + { + result = (U08)( valveStatus[ valve ].ovData & MASK_OFF_U32_MSBS ); + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_VALVES_INVALID_VALVE4, (U32)valve ) + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testValveEncoderPositionOverride function overrides the valve encoder + * position for a given valve. + * @details \b Inputs: none + * @details \b Outputs: currentValveEncPosition[] + * @param message Override message from Dialin which includes an ID of + * the valve to override and the position to override the valve to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testValveEncoderPositionOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, (OVERRIDE_U32_T*)¤tValveEncPosition[0], NUM_OF_VALVES - 1, 0, HEX_32_BIT_FULL_SCALE ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testValveStatusOverride function overrides the valve status for a + * given valve. + * @details \b Inputs: none + * @details \b Outputs: valveStatus[] + * @param message Override message from Dialin which includes an ID of + * the valve to override and the status to override the valve to. + * @return TRUE if override request is successful, FALSE if not + *************************************************************************/ +BOOL testValveStatusOverride( MESSAGE_T *message ) +{ + BOOL result = u32ArrayOverride( message, &valveStatus[0], NUM_OF_VALVES - 1, 0, MASK_OFF_U32_MSBS ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetValve function commands a given valve to change position by a + * given number of encoder counts. + * @note A negative travel value indicates the travel should be in reverse + * (CCW) direction. + * @details \b Inputs: none + * @details \b Outputs: commandValvePosChange[] + * @param message set message from Dialin which includes the state to set + * the air pump to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testSetValve( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD + if ( TRUE == isTestingActivated() ) + { + VALVE_ROTARY_SET_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(VALVE_ROTARY_SET_CMD_PAYLOAD_T) ); + if ( payload.valve < NUM_OF_VALVES ) + { + MOTOR_DIR_T dir = MOTOR_DIR_FORWARD; + U16 mag; + + if ( payload.stepChange < 0 ) + { + dir = MOTOR_DIR_REVERSE; + } + mag = (U16)( abs( payload.stepChange ) ); + setValveCmdChangePosition( (VALVE_T)payload.valve, mag, dir ); + result = TRUE; + } + } + + return result; +} + +/**@}*/ + Index: firmware/App/Drivers/RotaryValve.h =================================================================== diff -u --- firmware/App/Drivers/RotaryValve.h (revision 0) +++ firmware/App/Drivers/RotaryValve.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,64 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file RotaryValve.h +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#ifndef __ROTARY_VALVE_H__ +#define __ROTARY_VALVE_H__ + +// ********** public definitions ********** + +#include "TDCommon.h" + +/** + * @defgroup RotaryValve RotaryValve + * @brief Rotary valve driver unit. Provides low level functions + * to control a rotary (driven/turned by DC motor) valve. + * + * @addtogroup RotaryValve + * @{ + */ + +// ********** public definitions ********** + +#define ROTARY_VALVE_MICROSTEP_FRACTION 32 ///< Rotary valve motors configured for 1/32 step microstepping. +#define ROTARY_VALVE_GEAR_RATIO 3.7F ///< Rotary valve motor gear ratio is 3.7:1. +#define ROTARY_VALVE_FULL_SWING_TRAVEL_DEG 200.0F ///< Rotary valve swing arm travel range is appx. 200 degrees. +#define ROTARY_VALVE_FULL_SWING_TRAVEL_COUNTS 2048 ///< Rotary valve swing arm travel range is appx. 2048 enconder counts. + +/// rotary pinch valve names +typedef enum valveNames +{ + VBA = 0, ///< Arterial rotary pinch valve + FIRST_VALVE = VBA, ///< First valve + VBV, ///< Venous rotary pinch valve + NUM_OF_VALVES ///< Number of valves +} VALVE_T; + +// ********** public function prototypes ********** + +void initRotaryValvesDriver( void ); +void readValves( void ); +void setValveCmdChangePosition( VALVE_T valve, U16 mag, MOTOR_DIR_T dir ); +S16 getValveCmdTravel( VALVE_T valve ); +S16 getValveEncoderPosition( VALVE_T valve ); + +BOOL testValveEncoderPositionOverride( MESSAGE_T *message ); +BOOL testValveStatusOverride( MESSAGE_T *message ); +BOOL testSetValve( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Drivers/Valve2Way.c =================================================================== diff -u --- firmware/App/Drivers/Valve2Way.c (revision 0) +++ firmware/App/Drivers/Valve2Way.c (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,151 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file Valve2Way.c +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#include "AlarmMgmtTD.h" +#include "FpgaTD.h" +#include "GPIO.h" +#include "Messaging.h" +#include "Valve2Way.h" + +/** + * @addtogroup Valve2Way + * @{ + */ + +// ********** private definitions ********** + +/// Payload record structure for 2-way valve set request +typedef struct +{ + U32 valve; ///< which 2-way valve to set (0=VBT) + U32 state; ///< 0=closed, 1=open +} VALVE_2_WAY_SET_CMD_PAYLOAD_T; + +// ********** private data ********** + +static OPN_CLS_STATE_T current2WayValveStates[ NUM_OF_2_WAY_VALVES ]; ///< Current 2-way valve states (open/closed). + +// ********** private function prototypes ********** + +/*********************************************************************//** + * @brief + * The init2WayValves function initializes the 2-way valve driver unit. + * @details \b Inputs: none + * @details \b Outputs: current2WayValveStates[] + * @return none + *************************************************************************/ +void init2WayValves(void) +{ + // Close all 2-way valves + current2WayValveStates[ VALVE_2_WAY_VBT ] = STATE_CLOSED; + setVBTValveState( STATE_CLOSED ); +} + +/*********************************************************************//** + * @brief + * The set2WayValveState function sets a given 2-way valve to a given state + * (open/closed). + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve or state given. + * @details \b Inputs: none + * @details \b Outputs: current2WayValveStates[] + * @param valve ID of 2-way valve to set state for + * @param state ID of state to set valve to + * @return none. + *************************************************************************/ +void set2WayValveState( VALVE_2_WAY_T valve, OPN_CLS_STATE_T state ) +{ + if ( ( valve < NUM_OF_2_WAY_VALVES ) && ( state < NUM_OF_OPN_CLS_STATES ) ) + { + if ( VALVE_2_WAY_VBT == valve ) + { + // if state is changing, set the valve to the given open/closed state + if ( state != current2WayValveStates[ valve ] ) + { + setVBTValveState( state ); + current2WayValveStates[ valve ] = state; + } + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_2_WAY_VALVE_INVALID_VALVE_OR_STATE1, + (((U32)valve << SHIFT_16_BITS_FOR_WORD_SHIFT) | (U32)state ) ) + } +} + +/*********************************************************************//** + * @brief + * The get2WayValveState function gets the current state of a given 2-way + * valve. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if invalid valve given. + * @details \b Inputs: current2WayValveStates[] + * @details \b Outputs: none + * @return Current open/closed state of the given 2-way valve. + *************************************************************************/ +OPN_CLS_STATE_T get2WayValveState( VALVE_2_WAY_T valve ) +{ + OPN_CLS_STATE_T result = STATE_CLOSED; + + if ( valve < NUM_OF_2_WAY_VALVES ) + { + result = current2WayValveStates[ valve ]; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_2_WAY_VALVE_INVALID_VALVE_OR_STATE2, (U32)valve ) + } + + return result; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSet2WayValve function sets a given 2-way valve to a given state (open/closed). + * @details \b Inputs: none + * @details \b Outputs: current2WayValveStates[] + * @param message set message from Dialin which includes the valve to set + * and the state to set the valve to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testSet2WayValve( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with TD + if ( TRUE == isTestingActivated() ) + { + VALVE_2_WAY_SET_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(VALVE_2_WAY_SET_CMD_PAYLOAD_T) ); + if ( ( (VALVE_2_WAY_T)payload.valve < NUM_OF_2_WAY_VALVES ) && ( (OPN_CLS_STATE_T)payload.state < NUM_OF_OPN_CLS_STATES ) ) + { + set2WayValveState( (VALVE_2_WAY_T)payload.valve, (OPN_CLS_STATE_T)payload.state ); + result = TRUE; + } + } + + return result; +} + +/**@}*/ + Index: firmware/App/Drivers/Valve2Way.h =================================================================== diff -u --- firmware/App/Drivers/Valve2Way.h (revision 0) +++ firmware/App/Drivers/Valve2Way.h (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -0,0 +1,53 @@ +/************************************************************************** +* +* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file Valve2Way.h +* +* @author (last) Sean +* @date (last) 03-Oct-2024 +* +* @author (original) Sean +* @date (original) 03-Oct-2024 +* +***************************************************************************/ + +#ifndef __VALVE_2_WAY_H__ +#define __VALVE_2_WAY_H__ + +// ********** public definitions ********** + +#include "TDCommon.h" + +/** + * @defgroup Valve2Way Valve2Way + * @brief 2 way valve driver unit. Provides low level functions + * to control a a 2 way valve. + * + * @addtogroup Valve2Way + * @{ + */ + +// ********** public definitions ********** + +/// 2 way valve names +typedef enum valves2WayNames +{ + VALVE_2_WAY_VBT = 0, ///< Air trap relief valve + NUM_OF_2_WAY_VALVES ///< Number of 2 way valves +} VALVE_2_WAY_T; + +// ********** public function prototypes ********** + +void init2WayValves( void ); +void set2WayValveState( VALVE_2_WAY_T valve, OPN_CLS_STATE_T state ); +OPN_CLS_STATE_T get2WayValveState( VALVE_2_WAY_T valve ); + +BOOL testSet2WayValve( MESSAGE_T *message ); + +/**@}*/ + +#endif Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -ra91074d04b607deabe4fbf714d40e9d191590359 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision a91074d04b607deabe4fbf714d40e9d191590359) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -122,6 +122,24 @@ SW_FAULT_ID_BUTTONS_STOP_BUTTON_NOT_CONSUMED = 91, SW_FAULT_ID_PRES_OCCL_INVALID_STATE = 92, SW_FAULT_ID_PRES_LIMITS_INVALID_STATE = 93, + SW_FAULT_ID_LEVEL_SENSOR_INVALID_SENSOR = 94, + SW_FAULT_ID_AIR_TRAP_INVALID_STATE = 95, + SW_FAULT_ID_2_WAY_VALVE_INVALID_VALVE_OR_STATE1 = 96, + SW_FAULT_ID_2_WAY_VALVE_INVALID_VALVE_OR_STATE2 = 97, + SW_FAULT_ID_VALVES_INVALID_VALVE1 = 98, + SW_FAULT_ID_VALVES_INVALID_VALVE2 = 99, + SW_FAULT_ID_VALVES_INVALID_VALVE3 = 100, + SW_FAULT_ID_VALVES_INVALID_VALVE4 = 101, + SW_FAULT_ID_PERISTALTIC_PUMP_SET_SPEED_OUT_OF_RANGE = 102, + SW_FAULT_ID_TD_VALVES_INVALID_PARAM = 103, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE1 = 104, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE2 = 105, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE3 = 106, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE4 = 107, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE5 = 108, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE6 = 109, + SW_FAULT_ID_TD_VALVES_INVALID_VALVE7 = 110, + SW_FAULT_ID_TD_VALVES_INVALID_STATE = 111, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/AlarmMgmtTD.c =================================================================== diff -u -ra0d405d152c0f451ebf3c25e3c2cfa49a4db17cd -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/AlarmMgmtTD.c (.../AlarmMgmtTD.c) (revision a0d405d152c0f451ebf3c25e3c2cfa49a4db17cd) +++ firmware/App/Services/AlarmMgmtTD.c (.../AlarmMgmtTD.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -141,8 +141,6 @@ alarmStatus.alarmsSilenced = FALSE; alarmStatus.alarmsSilenceStart = 0; alarmStatus.alarmsSilenceExpiresIn = 0; - alarmStatus.alarmsEscalatesIn = 0; - alarmStatus.alarmsToEscalate = FALSE; alarmStatus.alarmTop = ALARM_ID_NO_ALARM; alarmStatus.topAlarmConditionDetected = FALSE; alarmStatus.systemFault = FALSE; @@ -1218,7 +1216,7 @@ // Lamp and audio timing sync'd with alarm status broadcast so UI/lamp/audio can stay in sync setAlarmLamp(); setAlarmAudio(); -// broadcastAlarmStatus( alarmStatus ); + broadcastAlarmStatus( alarmStatus ); alarmStatusPublicationTimerCounter = 0; } @@ -1240,7 +1238,7 @@ data.uiAlarmButtonBlocks[ ALARM_BUTTON_STATE_BLOCK_RINSEBACK ] = (U08)alarmButtonBlockers[ ALARM_BUTTON_STATE_BLOCK_RINSEBACK ]; data.uiAlarmButtonBlocks[ ALARM_BUTTON_STATE_BLOCK_END_TREATMENT ] = (U08)alarmButtonBlockers[ ALARM_BUTTON_STATE_BLOCK_END_TREATMENT ]; -// broadcastData( MSG_ID_TD_ALARM_INFORMATION_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( ALARM_INFO_PAYLOAD_T ) ); + broadcastData( MSG_ID_TD_ALARM_INFORMATION_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( ALARM_INFO_PAYLOAD_T ) ); alarmInfoPublicationTimerCounter = 0; } } @@ -1253,7 +1251,7 @@ /*********************************************************************//** * @brief - * The testSetAlarmStartOverride function overrides the start time for a + * The testSetAlarmStartTimeOverride function overrides the start time for a * given alarm with a given start time. * @details \b Inputs: msTimerCount * @details \b Outputs: alarmStartedAt[] @@ -1263,7 +1261,7 @@ * triggered. * @return TRUE if override is successful, FALSE if not *************************************************************************/ -BOOL testSetAlarmStartOverride( MESSAGE_T *message ) +BOOL testSetAlarmStartTimeOverride( MESSAGE_T *message ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T override; @@ -1309,13 +1307,17 @@ * @details \b Message \b Sent: MSG_ID_ALARM_CLEARED for each active alarm. * @details \b Inputs: none * @details \b Outputs: alarmIsActive[], alarmStartedAt[] - * @param key A 32-bit supervisor alarm key required to perform this function + * @param message Pointer to a clear all alarms message which contains a + * 32-bit supervisor alarm key required to perform this function * @return TRUE if command was successful, FALSE if rejected *************************************************************************/ -BOOL testClearAllAlarms( U32 key ) +BOOL testClearAllAlarms( MESSAGE_T *message ) { BOOL result = FALSE; + U32 key; + memcpy( &key, message->payload, sizeof(U32) ); + // Verify key if ( SUPERVISOR_ALARM_KEY == key ) { @@ -1356,96 +1358,36 @@ /*********************************************************************//** * @brief - * The testSetAlarmStatusPublishIntervalOverride function sets the override - * of the alarm status publication interval. + * The testAlarmStatusPublishIntervalOverride function overrides the interval + * at which the TD alarm status data is published. * @details \b Inputs: none * @details \b Outputs: alarmStatusPublishInterval - * @param ms Number of milliseconds between alarm status broadcasts - * @return TRUE if override set is successful, FALSE if not + * @param message Override message from Dialin which includes the interval + * (in ms) to override the alarm status broadcast interval to. + * @return TRUE if override request is successful, FALSE if not *************************************************************************/ -BOOL testSetAlarmStatusPublishIntervalOverride( U32 ms ) +BOOL testAlarmStatusPublishIntervalOverride( MESSAGE_T *message ) { - BOOL result = FALSE; + BOOL result = u32BroadcastIntervalOverride( message, &alarmStatusPublishInterval, TASK_GENERAL_INTERVAL ); - if ( TRUE == isTestingActivated() ) - { - U32 intvl = ms / TASK_GENERAL_INTERVAL; - - result = TRUE; - alarmStatusPublishInterval.ovData = intvl; - alarmStatusPublishInterval.override = OVERRIDE_KEY; - } - return result; } /*********************************************************************//** * @brief - * The testResetAlarmStatusPublishIntervalOverride function resets the - * override of the alarm status publication interval. + * The testAlarmInfoPublishIntervalOverride function overrides the interval + * at which the TD alarm information is published. * @details \b Inputs: none - * @details \b Outputs: alarmStatusPublishInterval - * @return TRUE if override reset is successful, FALSE if not - *************************************************************************/ -BOOL testResetAlarmStatusPublishIntervalOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - alarmStatusPublishInterval.override = OVERRIDE_RESET; - alarmStatusPublishInterval.ovData = alarmStatusPublishInterval.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetAlarmInfoPublishIntervalOverride function sets the override - * of the alarm information publication interval. - * @details \b Inputs: none * @details \b Outputs: alarmInfoPublishInterval - * @param ms Number of milliseconds between alarm info broadcasts - * @return TRUE if override set is successful, FALSE if not + * @param message Override message from Dialin which includes the interval + * (in ms) to override the alarm information broadcast interval to. + * @return TRUE if override request is successful, FALSE if not *************************************************************************/ -BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ) +BOOL testAlarmInfoPublishIntervalOverride( MESSAGE_T *message ) { - BOOL result = FALSE; + BOOL result = u32BroadcastIntervalOverride( message, &alarmInfoPublishInterval, TASK_GENERAL_INTERVAL ); - 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 \b Inputs: none - * @details \b Outputs: alarmInfoPublishInterval - * @return TRUE if override reset is 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; -} - /**@}*/ Index: firmware/App/Services/AlarmMgmtTD.h =================================================================== diff -u -r380b0afc95467d0861ff3aa2cdcde5d5d7ac85e7 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/AlarmMgmtTD.h (.../AlarmMgmtTD.h) (revision 380b0afc95467d0861ff3aa2cdcde5d5d7ac85e7) +++ firmware/App/Services/AlarmMgmtTD.h (.../AlarmMgmtTD.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -58,8 +58,6 @@ BOOL alarmsSilenced; ///< Alarms are currently silenced? U32 alarmsSilenceStart; ///< Time stamp for when alarms were silenced (ms) U32 alarmsSilenceExpiresIn; ///< Time until alarm silence expires (seconds) - 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 topAlarmConditionDetected; ///< Condition for top alarm is still being detected BOOL systemFault; ///< A system fault is active? @@ -113,7 +111,6 @@ { U32 alarmState; ///< Alarm state: 0 = no alarms, 1 = low priority, 2 = medium priority, 3 = high priority U32 alarmTop; ///< ID of top active alarm - U32 escalatesIn; ///< Top active alarm escalates in this many seconds U32 silenceExpiresIn; ///< Silencing of alarms expires in this many seconds U16 alarmsFlags; ///< Bit flags: 1 = true, 0 = false for each bit flag } ALARM_COMP_STATUS_PAYLOAD_T; @@ -155,12 +152,10 @@ void handleActiveAlarmListRequest( void ); void handleResendActiveAlarmsRequest( void ); -BOOL testSetAlarmStartOverride( MESSAGE_T *message ); -BOOL testClearAllAlarms( U32 key ); -BOOL testSetAlarmStatusPublishIntervalOverride( U32 ms ); -BOOL testResetAlarmStatusPublishIntervalOverride( void ); -BOOL testSetAlarmInfoPublishIntervalOverride( U32 ms ); -BOOL testResetAlarmInfoPublishIntervalOverride( void ); +BOOL testSetAlarmStartTimeOverride( MESSAGE_T *message ); +BOOL testClearAllAlarms( MESSAGE_T *message ); +BOOL testAlarmStatusPublishIntervalOverride( MESSAGE_T *message ); +BOOL testAlarmInfoPublishIntervalOverride( MESSAGE_T *message ); /**@}*/ Index: firmware/App/Services/CpldInterface.c =================================================================== diff -u -rc596f2433ccbcfde4663960eaa931f74820f487d -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/CpldInterface.c (.../CpldInterface.c) (revision c596f2433ccbcfde4663960eaa931f74820f487d) +++ firmware/App/Services/CpldInterface.c (.../CpldInterface.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -378,19 +378,24 @@ /*********************************************************************//** * @brief - * The testSetSafetyShutdownOverride function overrides the safety + * The testSafetyShutdownOverride function overrides the safety * shutdown. * @details \b Inputs: none * @details \b Outputs: HD safety shutdown overridden * @param value TRUE to activate safety shutdown, FALSE to de-activate it. * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetSafetyShutdownOverride( U32 value ) +BOOL testSafetyShutdownOverride( MESSAGE_T *message ) { - BOOL result = FALSE; + BOOL result = FALSE; + TEST_OVERRIDE_PAYLOAD_T payload; + OVERRIDE_TYPE_T ovType = getOverridePayloadFromMessage( message, &payload ); - if ( TRUE == isTestingActivated() ) + // Verify tester has logged in with f/w and override type is valid + if ( ( TRUE == isTestingActivated() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { + BOOL value = (BOOL)payload.state.u32; + // Remember natural state before override so we can reset safetyShutdownOverrideResetState = safetyShutdownActivated; // Override safety shutdown signal Index: firmware/App/Services/CpldInterface.h =================================================================== diff -u -rc596f2433ccbcfde4663960eaa931f74820f487d -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/CpldInterface.h (.../CpldInterface.h) (revision c596f2433ccbcfde4663960eaa931f74820f487d) +++ firmware/App/Services/CpldInterface.h (.../CpldInterface.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -59,8 +59,7 @@ SELF_TEST_STATUS_T execSafetyShutdownTest( void ); void resetSafetyShutdownPOSTState( void ); -BOOL testSetSafetyShutdownOverride( U32 value ); -BOOL testResetSafetyShutdownOverride( void ); +BOOL testSafetyShutdownOverride( MESSAGE_T *message ); /**@}*/ Index: firmware/App/Services/FpgaTD.c =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/FpgaTD.c (.../FpgaTD.c) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Services/FpgaTD.c (.../FpgaTD.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -45,13 +45,11 @@ #define MAX_FPGA_COMM_FAILURES 3 ///< FPGA maximum comm failures per MAX_FPGA_COMM_FAILURES_WINDOW_MS #define MIN_POWER_ON_TIME_FOR_COMM_FAILS ( 1 * MS_PER_SECOND ) ///< Allow FPGA comm errors for first second after power-up -#define FPGA_PINCH_VALVES_STOPPED 0x00 ///< FPGA pinch valve control register setting to stop valve motors. -#define FPGA_VBV_CLOSED_LOOP 0x01 ///< Bit mask for running VBV motor in closed loop mode. -#define FPGA_VBA_CLOSED_LOOP 0x02 ///< Bit mask for running VBA motor in closed loop mode. -#define FPGA_VBV_OPEN_LOOP 0x04 ///< Bit mask for running VBV motor in open loop mode. -#define FPGA_VBA_OPEN_LOOP 0x80 ///< Bit mask for running VBA motor in open loop mode. +#define FPGA_BP_ENABLE_BIT_MASK 0x01 ///< Bit mask for enabling the blood pump. +#define FPGA_BP_DIRECTION_FWD_BIT_MASK 0x02 ///< Bit mask for setting the blood pump direction. +#define FPGA_BP_HOME_BIT_MASK 0x04 ///< Bit mask for requesting a blood pump home operation. -//#define FPGA_VALVES_MIN_PWM_MODE_COUNT 2500 ///< FPGA valves minimum PWM in PWM mode in counts. +#define FPGA_VBT_OPEN_BIT_MASK 0x01 ///< Bit mask for setting VBT valve position to open. #define FPGA_INPUT_VOLTAGE_SCALE 3.0F ///< FPGA source and aux voltage. #define FPGA_PVN_VOLTAGE_SCALE 1.0F ///< FPGA pvn voltage. @@ -70,10 +68,6 @@ #define FPGA_ADV_BUBBLE_STATUS_MASK 0x0002 ///< Bit mask for venous air bubble detector input status. #define FPGA_ADV_BUBBLE_SELF_TEST_CMD 0x08 ///< Bit for venous air bubble detector self-test command. -#define FPGA_PBO_TEMP_DIVISOR 2047.0F ///< Used in conversion of PBo temperature reading to deg C. -#define FPGA_PBO_TEMP_GAIN 200.0F ///< Used in conversion of PBo temperature reading to deg C. -#define FPGA_PBO_TEMP_OFFSET 50.0F ///< Used in conversion of PBo temperature reading to deg C. - // FPGA Sensors Record #pragma pack(push,1) @@ -96,25 +90,29 @@ U08 reserved1; ///< Reg 261. Reserved and available for future use. U16 sPumpDACSet; ///< Reg 262. Syringe pump DAC setting. U16 sPumpDACEEProm; ///< Reg 264. Syringe pump DAC EEProm data. - S32 PBoPressure; ///< Reg 266. PBo raw pressure data. - S32 PBoTemperature; ///< Reg 270. PBo raw temperature data. - U08 PBoReadCount; ///< Reg 274. PBo read count. - U08 PBoErrorCount; ///< Reg 275. PBo error count. - S32 PBAPressure; ///< Reg 276. PBA raw pressure data. - S32 PBATemperature; ///< Reg 280. PBA raw temperature data. - U08 PBAReadCount; ///< Reg 284. PBA read count. - U08 PBAErrorCount; ///< Reg 285. PBA error count. - S16 ATAPSpeed; ///< Reg 286. ATAP speed. + U16 PBoPressure; ///< Reg 266. PBo raw pressure data. + S16 PBoTemperature; ///< Reg 268. PBo raw temperature data. + U08 PBoReadCount; ///< Reg 270. PBo read count. + U08 PBoErrorCount; ///< Reg 271. PBo error count. + U32 reserved3; ///< Reg 272. Reserved and available for future use. + U16 PBAPressure; ///< Reg 276. PBA raw pressure data. + S16 PBATemperature; ///< Reg 278. PBA raw temperature data. + U08 PBAReadCount; ///< Reg 280. PBA read count. + U08 PBAErrorCount; ///< Reg 281. PBA error count. + S16 VBACmdPosition; ///< Reg 282. VBA commanded position (200 steps/rev). + S16 VBAEncPosition; ///< Reg 284. VBA encoder position (1024 counts/rev). + U08 VBAStatus; ///< Reg 286. VBA status. + U08 reserved4; ///< Reg 287. Reserved and available for future use. U08 BEMStatus; ///< Reg 288. BEM status. U08 BEMEncStatus; ///< Reg 289. BEM encoder status. S32 BEMEncPosition; ///< Reg 290. BEM encoder position. - S16 BPSpeed; ///< Reg 294. BP measured speed. + S16 BPSpeed; ///< Reg 294. BP measured speed (RPM). S16 BPTorque; ///< Reg 296. BP measured torque. S16 BPSpeedFromHall; ///< Reg 298. BP measured speed from hall sensor(s). - S16 VBVPosition; ///< Reg 300. VBV encoder position. - U08 VBVStatus; ///< Reg 302. VBV status register. - U08 VBAStatus; ///< Reg 303. VBA status register. - S16 VBAPosition; ///< Reg 304. VBA encoder position. + S16 VBVCmdPosition; ///< Reg 300. VBV commanded position (200 steps/rev). + S16 VBVEncPosition; ///< Reg 302. VBV encoder position (1024 counts/rev). + U08 VBVStatus; ///< Reg 304. VBV status. + U08 BPStatus; ///< Reg 305. BP status. U16 GPIOReg; ///< Reg 306. GPIO register. U08 HEPStatus; ///< Reg 308. HEP status register. U08 HEPAdcReadCount; ///< Reg 309. HEP ADC read counter. @@ -132,6 +130,12 @@ U16 fpgaCompatibilityRev; ///< Reg 332. Compatibility revision. U08 VBTStatus; ///< Reg 334. VBT status register. U08 VBTStatusPWM; ///< Reg 335. VBT PWM status register. + S16 ACPower1Current; ///< Reg 336. AC power current - 1. + S16 ACPower1Voltage; ///< Reg 338. AC power voltage - 1. + S16 ACPower2Current; ///< Reg 340. AC power current - 2. + S16 ACPower2Voltage; ///< Reg 342. AC power voltage - 2. + S16 ACPower3Current; ///< Reg 344. AC power current - 3. + S16 ACPower3Voltage; ///< Reg 346. AC power voltage - 3. } FPGA_SENSORS_T; /// Record structure for FPGA continuous priority writes. @@ -145,21 +149,23 @@ U16 VBTPWMLowPeriod; ///< Reg 10. VBT PWM low signal period register. U16 VBTPWMPeriod; ///< Reg 12. VBT PWM period register. U16 VBTPWMPUllInTime; ///< Reg 14. VBT PWM pull in time register. - U16 ATAPSetSpeed; ///< Reg 16. Air pump speed set register. + U16 ACHeaterPWM; ///< Reg 16. AC heater PWM duty cycle set register. U08 ATAPControl; ///< Reg 18. Air pump control register. U08 BEMControl; ///< Reg 19. Blood ejector stepper motor control register. U16 BEMSetSpeed; ///< Reg 20. Blood ejector stepper motor step register. - U16 BPSetSpeed; ///< Reg 22. Blood pump speed set register. + U16 BPSetSpeed; ///< Reg 22. Blood pump speed set register (RPM). U08 BPControl; ///< Reg 24. Blood pump control register. - U08 pinchValveControl; ///< Reg 25. Pinch valve control register (VBA and VBV). - S16 VBVPosition; ///< Reg 26. VBV position set register. - S16 VBAPosition; ///< Reg 28. VBA position set register. - U16 VBVStepSpeed; ///< Reg 30. VBV step speed set register. - U16 VBAStepSpeed; ///< Reg 32. VBA step speed set register. - U08 alarmControl; ///< Reg 34. Alarm audio register. - U08 reserved3; ///< Reg 35. Reserved. - U32 reserved4; ///< Reg 36. Reserved. - U32 reserved5; ///< Reg 40. Reserved. + U08 VBVControl; ///< Reg 25. VBV control register. + U16 VBVPosition; ///< Reg 26. VBV position set register (200 steps/rev). + U16 VBAPosition; ///< Reg 28. VBA position set register (200 steps/rev). + U16 VBAControl; ///< Reg 30. VBA control register. + U08 reserved3; ///< Reg 31. Reserved. + U16 reserved4; ///< Reg 32. Reserved. + U08 alarmControl; ///< Reg 34. Alarm audio control register. + U08 reserved5; ///< Reg 35. Reserved. + U32 reserved6; ///< Reg 36. Reserved. + U16 reserved7; ///< Reg 40. Reserved. + U16 reserved8; ///< Reg 42. Reserved. U08 sensorTest; ///< Reg 44. Sensor self-test control register. } FPGA_ACTUATORS_T; @@ -196,9 +202,9 @@ memset( &fpgaActuatorSetPoints, 0, sizeof(FPGA_ACTUATORS_T) ); fpgaActuatorSetPoints.alarmControl = (U08)MIN_ALARM_VOLUME_ATTENUATION << 2; // Start alarm audio volume at maximum - // Set VBA and VBV to be "stopped". - // the valves will not move to 0 position - fpgaActuatorSetPoints.pinchValveControl = FPGA_PINCH_VALVES_STOPPED; + // Set VBA and VBV to default configuration + disabled so they do not run immediately on power up + fpgaActuatorSetPoints.VBAControl = FPGA_PINCH_VALVES_1_32_STEP | FPGA_PINCH_VALVES_DISABLE | FPGA_PINCH_VALVES_NOT_RESET | FPGA_PINCH_VALVES_NOT_SLEEP; + fpgaActuatorSetPoints.VBVControl = FPGA_PINCH_VALVES_1_32_STEP | FPGA_PINCH_VALVES_DISABLE | FPGA_PINCH_VALVES_NOT_RESET | FPGA_PINCH_VALVES_NOT_SLEEP; // initialize FPGA comm failures windowed timer count initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES, MAX_FPGA_COMM_FAILURES_WINDOW_MS); @@ -407,7 +413,106 @@ /*********************************************************************//** * @brief - * The getFPGABloodPumpHallSensorCount function gets the latest blood pump + * The setBloodPumpEnabled function enables or disables the blood pump per + * the given flag. + * @details \b Inputs: none + * @details \b Outputs: Blood pump enabled or disabled (bit 0 of BP control register) + * @param enable TRUE if BP enable is requested, FALSE if BP disable is requested + * @return none + *************************************************************************/ +void setBloodPumpEnabled( BOOL enable ) +{ + if ( TRUE == enable ) + { + fpgaActuatorSetPoints.BPControl |= FPGA_BP_ENABLE_BIT_MASK; + } + else + { + fpgaActuatorSetPoints.BPControl &= ~((U08)FPGA_BP_ENABLE_BIT_MASK); + } +} + +/*********************************************************************//** + * @brief + * The setBloodPumpDirection function sets the direction for the blood pump + * motor to the given direction. + * @details \b Inputs: none + * @details \b Outputs: Blood pump motor direction is set (bit 1 of BP control register). + * 0 - CW (forward) + * 1 - CCW (reverse) + * @param dir the desired direction for the blood pump motor (fwd or rev) + * @return none + *************************************************************************/ +void setBloodPumpDirection( MOTOR_DIR_T dir ) +{ + if ( MOTOR_DIR_REVERSE == dir ) + { + fpgaActuatorSetPoints.BPControl &= ~((U08)FPGA_BP_DIRECTION_FWD_BIT_MASK); + } + else + { + fpgaActuatorSetPoints.BPControl |= FPGA_BP_DIRECTION_FWD_BIT_MASK; + } +} + +/*********************************************************************//** + * @brief + * The homeBloodPump function sets the bit requesting that the blood pump + * be homed. + * @details \b Inputs: none + * @details \b Outputs: BP home request is set (bit 2 of BP control register). + * @return none + *************************************************************************/ +void homeBloodPump( void ) +{ + fpgaActuatorSetPoints.BPControl |= FPGA_BP_HOME_BIT_MASK; +} + +/*********************************************************************//** + * @brief + * The resetBloodPumpHomeRequest function resets the fpga blood pump home + * request. + * @note This function should be called after request is made and transmission + * to FPGA is complete. + * @details \b Inputs: none + * @details \b Outputs: BP home request is cleared (bit 2 of BP control register) + * @return none + *************************************************************************/ +void resetBloodPumpHomeRequest( void ) +{ + fpgaActuatorSetPoints.BPControl &= ~((U08)FPGA_BP_HOME_BIT_MASK); +} + +/*********************************************************************//** + * @brief + * The setBloodPumpSetSpeed function sets the fpga blood pump set speed + * to the given speed (0..3000 RPM). + * @details \b Inputs: none + * @details \b Outputs: BP set speed is set + * @param rpm the set point for the BP speed (in RPM). + * @return none + *************************************************************************/ +void setBloodPumpSetSpeed( U16 rpm ) +{ + fpgaActuatorSetPoints.BPSetSpeed = rpm; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpSpeed function gets the latest blood pump speed (in RPM) + * from the FPGA. + * @details \b Inputs: fpgaSensorReadings + * @details \b Outputs: none + * @return Latest blood pump speed. + *************************************************************************/ +U16 getBloodPumpSpeed( void ) +{ + return fpgaSensorReadings.BPSpeed; +} + +/*********************************************************************//** + * @brief + * The getBloodPumpHallSensorCount 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 * counting down, indicates motor is running in reverse direction. Counter will @@ -416,14 +521,14 @@ * @details \b Outputs: none * @return Latest blood pump hall sensor count reading. *************************************************************************/ -U16 getFPGABloodPumpHallSensorCount( void ) +U16 getBloodPumpHallSensorCount( void ) { return 0;//fpgaSensorReadings.bloodPumpHallSensorCount; } /*********************************************************************//** * @brief - * The getFPGABloodPumpHallSensorStatus function gets the latest blood pump + * The getBloodPumpHallSensorStatus function gets the latest blood pump * hall sensor status. * Bit 7 - Derived direction of the blood pump motor (0=Fwd, 1=Rev) * Bit 6 - Unused @@ -432,22 +537,22 @@ * @details \b Outputs: none * @return latest blood pump hall sensor status reading. *************************************************************************/ -U08 getFPGABloodPumpHallSensorStatus( void ) +U08 getBloodPumpHallSensorStatus( void ) { return 0;//fpgaSensorReadings.bloodPumpHallSensorStatus; } /*********************************************************************//** * @brief * The getPBAPressure function gets the latest arterial pressure reading. - * High byte indicates alarm status for ADC channel. - * @note Low 24-bits are channel reading. Subtract 2^23 from low 24 bits to get - * signed channel 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. * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none * @return latest arterial pressure reading *************************************************************************/ -S32 getPBAPressure( void ) +U16 getPBAPressure( void ) { return fpgaSensorReadings.PBAPressure; } @@ -460,7 +565,7 @@ * @details \b Outputs: none * @return latest arterial pressure sensor temperature reading *************************************************************************/ -S32 getPBATemperature( void ) +S16 getPBATemperature( void ) { return fpgaSensorReadings.PBATemperature; } @@ -501,7 +606,7 @@ * @details \b Outputs: none * @return latest venous pressure reading *************************************************************************/ -S32 getPBOPressure( void ) +U16 getPBOPressure( void ) { return fpgaSensorReadings.PBoPressure; } @@ -514,7 +619,7 @@ * @details \b Outputs: none * @return latest venous pressure sensor temperature reading *************************************************************************/ -S32 getPBOTemperature( void ) +S16 getPBOTemperature( void ) { return fpgaSensorReadings.PBoTemperature; } @@ -582,14 +687,22 @@ /*********************************************************************//** * @brief * The setFPGAValvesControlMode function sets the valves control mode. + * @note VBTControl register bit 0 will drive state of VBT valve (0=closed, 1=open). * @details \b Inputs: fpgaActuatorSetPoints * @details \b Outputs: fpgaActuatorSetPoints * @param bits : The bits to enable the PID controller of a valve * @return none *************************************************************************/ -void setFPGAValvesControlMode( U16 bits ) +void setVBTValveState( OPN_CLS_STATE_T state ) { - //fpgaActuatorSetPoints.fpgaPIDControl = bits; + if ( STATE_OPEN == state ) + { + fpgaActuatorSetPoints.VBTControl |= FPGA_VBT_OPEN_BIT_MASK; + } + else + { + fpgaActuatorSetPoints.VBTControl &= ~((U08)FPGA_VBT_OPEN_BIT_MASK); + } } /*********************************************************************//** @@ -637,33 +750,95 @@ /*********************************************************************//** * @brief - * The setVBVPosition function sets the target encoder position of VBV - * in counts + * The setVBAControl function sets the control bits for the venous pinch valve. + * Microstep setting: bits 0..2: + * 0=full step (100% torque) + * 1=1/2 step (100% torque) + * 2=1/16 step + * 3=1/32 step + * 4=full step (modified) + * 5=1/2 step (modified) + * 6=1/4 step + * 7=1/8 step + * Direction: bit 3 + * 0=forward + * 1=reverse + * Enable: bit 4 (active low) + * 0=enabled + * 1=disabled + * Reset: bit 5 (active low) + * 0=reset (set to 1 after power up) + * Sleep: bit 6 (active low) + * 0=sleep mode + * Reserved: bit 7 * @details \b Inputs: none * @details \b Outputs: fpgaActuatorSetPoints + * @param controlBits The control bits to apply to the venous pinch valve. + * @return none + *************************************************************************/ +void setVBVControl( U08 controlBits ) +{ + +} + +/*********************************************************************//** + * @brief + * The getVBVControl function gets the current control bits for the VBV. + * @details \b Inputs: fpgaActuatorSetPoints + * @details \b Outputs: none + * @return fpgaActuatorSetPoints.VBVControl + *************************************************************************/ +U08 getVBVControl( void ) +{ + return fpgaActuatorSetPoints.VBVControl; +} + +/*********************************************************************//** + * @brief + * The setVBVPosition function sets the travel from current position for the + * VBV in counts (or microcounts if microstepping is set in control register). + * @details \b Inputs: none + * @details \b Outputs: fpgaActuatorSetPoints * @param setPoint The target encoder position of the VBV in counts * @return none *************************************************************************/ -void setVBVPosition( S16 setPoint ) +void setVBVPosition( U16 setPoint ) { fpgaActuatorSetPoints.VBVPosition = setPoint; } /*********************************************************************//** * @brief - * The getVBVPosition function returns the current encoder position of - * VBV in counts + * The getVBVEncoderPosition function reads the current encoder position of the + * VBV in counts. + * @note There are 1024 encoder counts per revolution. The encoder position + * register provides the number of steps traveled since last command given. * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none * @return The current encoder position of VBV *************************************************************************/ -S16 getVBVPosition( void ) +S16 getVBVEncoderPosition( void ) { - return fpgaSensorReadings.VBVPosition; + return fpgaSensorReadings.VBVEncPosition; } /*********************************************************************//** * @brief + * The getVBVCmdPosition function returns the current amount of travel + * from the pre-command position in steps (or microsteps if microstepping is + * set in control register) for VBV. + * @note There are 200 steps per revolution + * @details \b Inputs: fpgaSensorReadings + * @details \b Outputs: none + * @return The commanded encoder position of VBV + *************************************************************************/ +S16 getVBVCmdPosition( void ) +{ + return fpgaSensorReadings.VBVCmdPosition; +} + +/*********************************************************************//** + * @brief * The getVBVStatus function reads the status of the venous pinch valve. * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none @@ -676,67 +851,102 @@ /*********************************************************************//** * @brief - * The getFPGAValveBloodVenousCurrentCounts function returns the current - * of VBV in counts - * @details \b Inputs: fpgaSensorReadings + * The setVBAControl function sets the control bits for the arterial pinch valve. + * Microstep setting: bits 0..2: + * 0=full step (100% torque) + * 1=1/2 step (100% torque) + * 2=1/16 step + * 3=1/32 step + * 4=full step (modified) + * 5=1/2 step (modified) + * 6=1/4 step + * 7=1/8 step + * Direction: bit 3 + * 0=forward + * 1=reverse + * Enable: bit 4 (active low) + * 0=enabled + * 1=disabled + * Reset: bit 5 (active low) + * 0=reset (set to 1 after power up) + * Sleep: bit 6 (active low) + * 0=sleep mode + * Reserved: bit 7 + * @details \b Inputs: none + * @details \b Outputs: fpgaActuatorSetPoints + * @param controlBits The control bits to apply to the arterial pinch valve. + * @return none + *************************************************************************/ +void setVBAControl( U08 controlBits ) +{ + fpgaActuatorSetPoints.VBAControl = controlBits; +} + +/*********************************************************************//** + * @brief + * The getVBAControl function gets the current control bits for the VBA. + * @details \b Inputs: fpgaActuatorSetPoints * @details \b Outputs: none - * @return The latest current of VBV + * @return fpgaActuatorSetPoints.VBAControl *************************************************************************/ -U16 getFPGAValveBloodVenousCurrentCounts( void ) +U08 getVBAControl( void ) { - return 0;//fpgaSensorReadings.VBVCurrent; + return fpgaActuatorSetPoints.VBAControl; } /*********************************************************************//** * @brief - * The setVBAPosition function sets the target encoder position of the VBA - * in counts + * The setVBAPosition function sets the travel from current position for the + * VBA in counts (or microcounts if microstepping is set in control register). * @details \b Inputs: none * @details \b Outputs: fpgaActuatorSetPoints * @param setPoint The target encoder position of the VBA in counts * @return none *************************************************************************/ -void setVBAPosition( S16 setPoint ) +void setVBAPosition( U16 setPoint ) { fpgaActuatorSetPoints.VBAPosition = setPoint; } /*********************************************************************//** * @brief - * The getVBAPosition function reads the current encoder position of the - * VBA in counts + * The getVBAEncoderPosition function reads the current encoder position of the + * VBA in counts. + * @note There are 1024 encoder counts per revolution * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none * @return The latest encoder position of VBA *************************************************************************/ -S16 getVBAPosition( void ) +S16 getVBAEncoderPosition( void ) { - return fpgaSensorReadings.VBAPosition; + return fpgaSensorReadings.VBAEncPosition; } /*********************************************************************//** * @brief - * The getVBAStatus function reads the status of the arterial pinch valve. + * The getVBACmdPosition function returns returns the current amount of travel + * from the pre-command position in steps (or microsteps if microstepping is + * set in control register) for VBA. + * @note There are 200 steps per revolution * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none - * @return Latest status of the arterial pinch valve + * @return The commanded encoder position of VBA *************************************************************************/ -U16 getVBAStatus( void ) +S16 getVBACmdPosition( void ) { - return fpgaSensorReadings.VBAStatus; + return fpgaSensorReadings.VBACmdPosition; } /*********************************************************************//** * @brief - * The getFPGAValveBloodArterialCurrentCounts function reads the current - * of VBA in counts + * The getVBAStatus function reads the status of the arterial pinch valve. * @details \b Inputs: fpgaSensorReadings * @details \b Outputs: none - * @return The latest current of VBA + * @return Latest status of the arterial pinch valve *************************************************************************/ -U16 getFPGAValveBloodArterialCurrentCounts( void ) +U16 getVBAStatus( void ) { - return 0;//fpgaSensorReadings.; + return fpgaSensorReadings.VBAStatus; } /*********************************************************************//** Index: firmware/App/Services/FpgaTD.h =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/FpgaTD.h (.../FpgaTD.h) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Services/FpgaTD.h (.../FpgaTD.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -31,6 +31,12 @@ // ********** public definitions ********** +#define FPGA_PINCH_VALVES_1_32_STEP 0x03 ///< Bit mask for configuring pinch valve for 1/32 step. +#define FPGA_PINCH_VALVES_REVERSE 0x08 ///< Bit mask for configuring pinch valve for reverse direction. +#define FPGA_PINCH_VALVES_DISABLE 0x10 ///< Bit mask for configuring pinch valve to be disabled. +#define FPGA_PINCH_VALVES_NOT_RESET 0x20 ///< Bit mask for configuring pinch valve to not be in reset. +#define FPGA_PINCH_VALVES_NOT_SLEEP 0x40 ///< Bit mask for configuring pinch valve to not be in sleep mode. + // ********** public function prototypes ********** void initFpgaTD( void ); @@ -48,38 +54,49 @@ void setAlarmAudioState( U32 state, U32 volumeLevel, U32 volumeDivider ); -U16 getFPGABloodPumpHallSensorCount( void ); -U08 getFPGABloodPumpHallSensorStatus( void ); +void setBloodPumpEnabled( BOOL enable ); +void setBloodPumpDirection( MOTOR_DIR_T dir ); +void homeBloodPump( void ); +void resetBloodPumpHomeRequest( void ); +void setBloodPumpSetSpeed( U16 rpm ); +U16 getBloodPumpSpeed( void ); -S32 getPBAPressure( void ); -S32 getPBATemperature( void ); -U08 getPBAReadCounter( void ); -U08 getPBAErrorCounter( void ); +U16 getBloodPumpHallSensorCount( void ); +U08 getBloodPumpHallSensorStatus( void ); -S32 getPBOPressure( void ); -S32 getPBOTemperature( void ); -U08 getPBOReadCounter( void ); -U08 getPBOErrorCounter( void ); +U16 getPBAPressure( void ); +S16 getPBATemperature( void ); +U08 getPBAReadCounter( void ); +U08 getPBAErrorCounter( void ); +U16 getPBOPressure( void ); +S16 getPBOTemperature( void ); +U08 getPBOReadCounter( void ); +U08 getPBOErrorCounter( void ); + F32 getFPGABackupAlarmAudioCurrent( void ); void getFPGAAirTrapLevels( BOOL *airAtLower, BOOL *airAtUpper ); -void setFPGAValvesControlMode( U16 bits ); - BOOL ADVBubbleDetected( void ); void setFPGAVenousBubbleSelfTest( void ); void clearFPGAVenousBubbleSelfTest( void ); -void setVBVPosition( S16 setPoint ); -S16 getVBVPosition( void ); +void setVBTValveState( OPN_CLS_STATE_T state ); + +void setVBVControl( U08 controlBits ); +U08 getVBVControl( void ); +void setVBVPosition( U16 setPoint ); +S16 getVBVEncoderPosition( void ); +S16 getVBVCmdPosition( void ); U16 getVBVStatus( void ); -U16 getFPGAValveBloodVenousCurrentCounts( void ); -void setVBAPosition( S16 setPoint ); -S16 getVBAPosition( void ); +void setVBAControl( U08 controlBits ); +U08 getVBAControl( void ); +void setVBAPosition( U16 setPoint ); +S16 getVBAEncoderPosition( void ); +S16 getVBACmdPosition( void ); U16 getVBAStatus( void ); -U16 getFPGAValveBloodArterialCurrentCounts( void ); U16 getFPGABoardTemperature( void ); U32 getFPGAPBAADCTemperature( void ); Index: firmware/App/Services/Messaging.c =================================================================== diff -u -ra91074d04b607deabe4fbf714d40e9d191590359 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/Messaging.c (.../Messaging.c) (revision a91074d04b607deabe4fbf714d40e9d191590359) +++ firmware/App/Services/Messaging.c (.../Messaging.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -18,17 +18,24 @@ #include // For memcpy() #include "AirPump.h" +#include "AirTrap.h" +#include "AlarmMgmt.h" #include "Bubbles.h" #include "Buttons.h" #include "Compatible.h" +#include "LevelSensors.h" #include "Messaging.h" #include "OperationModes.h" #include "PAL.h" #include "PressureSensor.h" +#include "RotaryValve.h" #include "Switches.h" #include "SystemCommTD.h" #include "Utilities.h" +#include "Valve2Way.h" +#include "Valves.h" #include "Voltages.h" +#include "Watchdog.h" /** * @addtogroup Messaging @@ -91,7 +98,24 @@ MSG_ID_TD_ALARM_AUDIO_LEVEL_OVERRIDE_REQUEST, MSG_ID_TD_ALARM_AUDIO_CURRENT_HG_OVERRIDE_REQUEST, MSG_ID_TD_ALARM_AUDIO_CURRENT_LG_OVERRIDE_REQUEST, - MSG_ID_TD_BACKUP_ALARM_AUDIO_CURRENT_OVERRIDE_REQUEST + MSG_ID_TD_BACKUP_ALARM_AUDIO_CURRENT_OVERRIDE_REQUEST, + MSG_ID_TD_AIR_TRAP_LEVEL_OVERRIDE_REQUEST, + MSG_ID_TD_AIR_TRAP_LEVEL_RAW_OVERRIDE_REQUEST, + MSG_ID_TD_AIR_TRAP_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + MSG_ID_TD_2_WAY_VALVE_SET_STATE_REQUEST, + MSG_ID_TD_ROTARY_PINCH_VALVE_SET_POS_REQUEST, + MSG_ID_TD_ROTARY_PINCH_VALVE_STATUS_OVERRIDE_REQUEST, + MSG_ID_TD_ROTARY_PINCH_VALVE_POSITION_OVERRIDE_REQUEST, + MSG_ID_TD_VALVES_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + MSG_ID_TD_PINCH_VALVE_SET_POSITION_REQUEST, + MSG_ID_TD_PINCH_VALVE_HOME_REQUEST, + MSG_ID_TD_ALARM_STATUS_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + MSG_ID_TD_ALARM_INFO_PUBLISH_INTERVAL_OVERRIDE_REQUEST, + MSG_ID_TD_ALARM_START_TIME_OVERRIDE_REQUEST, + MSG_ID_TD_ALARM_CLEAR_ALL_ALARMS_REQUEST, + MSG_ID_TD_WATCHDOG_OVERRIDE_REQUEST, + MSG_ID_TD_ALARM_STATE_OVERRIDE_REQUEST, + MSG_ID_TD_SAFETY_SHUTDOWN_OVERRIDE_REQUEST }; /// Message handling function table @@ -114,7 +138,24 @@ &testAlarmAudioVolumeLevelOverride, &testPrimaryAlarmAudioCurrentHGOverride, &testPrimaryAlarmAudioCurrentLGOverride, - &testBackupAlarmAudioCurrentOverride + &testBackupAlarmAudioCurrentOverride, + &testLevelSensorOverride, + &testRawLevelSensorOverride, + &testAirTrapDataPublishIntervalOverride, + &testSet2WayValve, + &testSetValve, + &testValveStatusOverride, + &testValveEncoderPositionOverride, + &testValvesDataPublishIntervalOverride, + &testValveSetABCCmdPosition, + &testHomeValve, + &testAlarmStatusPublishIntervalOverride, + &testAlarmInfoPublishIntervalOverride, + &testSetAlarmStartTimeOverride, + &testClearAllAlarms, + &testWatchdogTaskCheckInOverride, + &testAlarmStateOverride, + &testSafetyShutdownOverride }; #define NUM_OF_FUNCTION_HANDLERS (sizeof(MSG_FUNCTION_HANDLERS) / sizeof(MsgFuncPtr)) @@ -372,16 +413,51 @@ } } +// Send message helper functions +/*********************************************************************//** + * @brief + * The broadcastAlarmStatus function constructs an alarm status msg to + * be broadcast and queues the msg for transmit on the appropriate CAN channel. + * @details \b Inputs: none + * @details \b Outputs: alarm status msg constructed and queued. + * @param almStatus alarm status record + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ) +{ + BOOL result; + ALARM_COMP_STATUS_PAYLOAD_T payload; + payload.alarmState = (U32)almStatus.alarmsState; + payload.alarmTop = (U32)almStatus.alarmTop; + payload.silenceExpiresIn = almStatus.alarmsSilenceExpiresIn; + payload.alarmsFlags = ( almStatus.systemFault ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_SYSTEM_FAULT) : 0 ); + payload.alarmsFlags |= ( almStatus.stop ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_STOP) : 0 ); + payload.alarmsFlags |= ( almStatus.noClear ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_CLEAR) : 0 ); + payload.alarmsFlags |= ( almStatus.noResume ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_RESUME) : 0 ); + payload.alarmsFlags |= ( almStatus.noRinseback ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_RINSEBACK) : 0 ); + payload.alarmsFlags |= ( almStatus.noEndTreatment ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_NO_END_TREATMENT) : 0 ); + payload.alarmsFlags |= ( almStatus.ok ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_OK_BUTTON_ONLY) : 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.noBloodRecirc ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_BLOOD_RECIRC) : 0 ); + payload.alarmsFlags |= ( almStatus.noDialRecirc ? BIT_BY_POS(ALARM_STATE_FLAG_BIT_POS_DIALYSATE_RECIRC) : 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 ); + + result = broadcastData( MSG_ID_ALARM_STATUS_DATA, COMM_BUFFER_OUT_CAN_TD_ALARM, (U08*)&payload, sizeof( ALARM_COMP_STATUS_PAYLOAD_T ) ); + + return result; +} + + // *********************************************************************** // ***************** Message Sending Helper Functions ******************** // *********************************************************************** - - /*********************************************************************//** * @brief * The sendEvent function constructs a TD event message and queues the msg Index: firmware/App/Services/Messaging.h =================================================================== diff -u -ra0d405d152c0f451ebf3c25e3c2cfa49a4db17cd -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Services/Messaging.h (.../Messaging.h) (revision a0d405d152c0f451ebf3c25e3c2cfa49a4db17cd) +++ firmware/App/Services/Messaging.h (.../Messaging.h) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -147,7 +147,8 @@ // ACK MSG BOOL sendACKMsg( MESSAGE_T *message ); -void handleUITDResetInServiceModeRequest( MESSAGE_T* message ); +// Send message helper functions +BOOL broadcastAlarmStatus( COMP_ALARM_STATUS_T almStatus ); // Test Support Messaging Functions ************************** @@ -157,12 +158,12 @@ void handleIncomingMessage( MESSAGE_T *message ); BOOL handleTesterLogInRequest( MESSAGE_T *message ); +BOOL testTDSoftwareResetRequest( MESSAGE_T *message ); + +// Test send message helper functions BOOL sendEvent( TD_EVENT_ID_T event, EVENT_DATA_T dat1, EVENT_DATA_T dat2 ); BOOL sendOffButtonMsgToUI( U08 prompt ); -// MSG_ID_TD_SOFTWARE_RESET_REQUEST -BOOL testTDSoftwareResetRequest( MESSAGE_T *message ); - /**@}*/ #endif Index: firmware/App/Tasks/TaskGeneral.c =================================================================== diff -u -r64f2edc1b7ec8edda7e500b10c09c2a54dc70fc9 -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision 64f2edc1b7ec8edda7e500b10c09c2a54dc70fc9) +++ firmware/App/Tasks/TaskGeneral.c (.../TaskGeneral.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -16,12 +16,15 @@ ***************************************************************************/ #include "AirPump.h" +#include "AirTrap.h" #include "Messaging.h" #include "OperationModes.h" +#include "PeristalticPump.h" #include "Pressures.h" #include "Switches.h" #include "SystemCommTD.h" #include "TaskGeneral.h" +#include "Valves.h" #include "Voltages.h" #include "WatchdogMgmt.h" @@ -63,7 +66,7 @@ // Monitor voltages execVoltagesMonitor(); -// // Monitor DD + // Monitor DD // execDDInterfaceMonitor(); // Monitor pressure sensors @@ -72,28 +75,34 @@ // Monitor switches execSwitches(); -// // Monitor temperatures + // Monitor temperatures // execTemperatures(); -// -// // Monitor processor RAM status + + // Monitor processor RAM status // execRAMMonitor(); + // Monitor peristaltic pump(s) + readPeristalticPumps(); + // Run operation mode state machine execOperationModes(); -// // Control air trap valve -// execAirTrapController(); -// -// // Control blood pump + // Control air trap valve + execAirTrapController(); + + // Control pinch valves + execValvesController(); + + // Control blood pump // execBloodFlowController(); -// + // Control Air Pump execAirPumpController(); -// // Monitor/Control fan + // Monitor/Control fan // execFan(); -// -// // Manage NVDataMgmt process record state machine + + // Manage NVDataMgmt process record state machine // execNVDataMgmtProcessRecord(); // Manage alarm state Index: firmware/App/Tasks/TaskPriority.c =================================================================== diff -u -r3a8cf075eb6f0d255f516ac26bac7fbaacfde14a -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision 3a8cf075eb6f0d255f516ac26bac7fbaacfde14a) +++ firmware/App/Tasks/TaskPriority.c (.../TaskPriority.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -15,6 +15,7 @@ * ***************************************************************************/ +#include "AirTrap.h" #include "Bubbles.h" #include "Buttons.h" #include "FPGA.h" @@ -59,7 +60,7 @@ execInternalADC(); // Monitor air trap level sensors -// execAirTrapMonitor(); + execAirTrapMonitor(); // Monitor blood pump and flow // execBloodFlowMonitor(); Index: firmware/source/sys_main.c =================================================================== diff -u -r16b571d559e0fd64be547111f2ba460cfc08be1e -rd9b5f588d81e15ed3849222bed3362e15dbf4b0a --- firmware/source/sys_main.c (.../sys_main.c) (revision 16b571d559e0fd64be547111f2ba460cfc08be1e) +++ firmware/source/sys_main.c (.../sys_main.c) (revision d9b5f588d81e15ed3849222bed3362e15dbf4b0a) @@ -64,6 +64,7 @@ #include "TDCommon.h" #include "AirPump.h" +#include "AirTrap.h" #include "Bubbles.h" #include "Buttons.h" #include "CpldInterface.h" @@ -79,6 +80,7 @@ #include "TaskBG.h" #include "Timers.h" #include "Utilities.h" +#include "Valves.h" #include "Voltages.h" #include "WatchdogMgmt.h" @@ -195,6 +197,8 @@ initVoltagesMonitor(); // Initialize controllers initAirPump(); + initAirTrap(); + initValves(); // Initialize modes initOperationModes(); }