// Includes #include "reg_het.h" #include "gio.h" #include "Valves.h" #include "FPGA.h" #include "Timers.h" #include "TaskPriority.h" #include "SystemCommMessages.h" /** * @addtogroup Valves * @{ */ // ********** private definitions ********** // Valve dialyzer inlet defines #define VDI_ENABLE_PID_INTERFACE 0x0010 #define VDI_ENABLE_BYPASS_INTERFACE 0x0020 #define VDI_INIT_STATUS_BIT_MASK 0x0040 #define VDI_ENABLE_PID_STATUS_BIT_MASK 0x0080 #define VDI_ENABLE_BYPASS_STATUS_BIT_MASK 0x00100 // Valve dialyzer outlet defines #define VDO_ENABLE_PID_INTERFACE 0x0040 #define VDO_ENABLE_BYPASS_INTERFACE 0x0080 #define VDO_INIT_STATUS_BIT_MASK 0x0200 #define VDO_ENABLE_PID_STATUS_BIT_MASK 0x0400 #define VDO_ENABLE_BYPASS_STATUS_BIT_MASK 0x0800 // Valve blood arterial defines #define VBA_ENABLE_PID_INTERFACE 0x0001 #define VBA_ENABLE_BYPASS_INTERFACE 0x0002 #define VBA_INIT_STATUS_BIT_MASK 0x0001 #define VBA_ENABLE_PID_STATUS_BIT_MASK 0x0002 #define VBA_ENABLE_BYPASS_STATUS_BIT_MASK 0x0004 // Valve blood venous defines #define VBV_ENABLE_PID_INTERFACE 0x0004 #define VBV_ENABLE_BYPASS_INTERFACE 0x0008 #define VBV_INIT_STATUS_BIT_MASK 0x0008 #define VBV_ENABLE_PID_STATUS_BIT_MASK 0x0010 #define VBV_ENABLE_BYPASS_STATUS_BIT_MASK 0x0020 #define ALL_VALVES_ENABLE_PID_INTERFACE 0x0055 #define ADC_TO_CURRENT_CONVERSION_CONSTANT 2048.0 #define INITIAL_EDGE_OFFSET_READ_COUNT 100 #define INITIAL_ENERGIZED_EDGE_UPPER_RANGE 13000U #define INITIAL_ENERGIZED_EDGE_LOWER_RANGE 9000U #define STEP_CHANGE_IN_COUNTS 1000 //#define MAX_POS_DEVIATION_FROM_TARGET_COUNTS 1000 //TODO test this tolerance //#define VALVE_TRANSITION_TIMEOUT_MS 5000 //TODO test the timeout #define MAX_DEVIATION_FROM_TARGET_IN_COUNTS 150U #define MAX_ALLOWED_FAILED_HOMINGS 3U #define HOMING_EDGE_DETECTION_TARGET_COUNTER 12U #define VALVES_CURRENT_THRESHOLD_AMPS 1U #define OVER_CURRENT_COUNTER 100U #define OUT_OF_RANGE_COUNTER 100U #define NEXT_STEP_COMD_TIME_INTERVAL_COUNTER 10U // TODO changed the interval count to every 10 calls in priority task which is 100 ms #define VALVES_DATA_PUB_INTERVAL ( MS_PER_SECOND / ( 10 * TASK_PRIORITY_INTERVAL ) ) // ********** private data ********** /// Exec valve self test states typedef enum valves_Self_Test_States { VALVE_SELF_TEST_ENABLE_VALVES = 0, VALVE_SELF_TEST_CONFIRM_ENABLE, VALVE_SELF_TEST_COMPLETE, NUM_OF_VALVE_SELF_TEST_STATES } VALVE_SELF_TEST_STATE_T; /// Exec valve states typedef enum valve_Exec_States { VALVE_STATE_WAIT_FOR_POST = 0, VALVE_STATE_IDLE, VALVE_STATE_IN_TRANSITION, VALVE_STATE_HOMING_NOT_STARTED, VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE, VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE, NUM_OF_VALVE_STATES, } VALVE_STATE_T; #pragma pack(push, 1) /// Valve status structure typedef struct { VALVE_POSITION_T commandedPosition; VALVE_POSITION_T currentPosition; S16 currentPositionInCounts; S16 targetPositionInCounts; BOOL hasTransitionBeenRequested; VALVE_STATE_T execState; U32 transitionStartTime; //TODO REMOVE? S16 positions[ NUM_OF_VALVE_POSITIONS ]; F32 valveCurrent; U32 valveOverCurrentCounter; U32 valvePositionOutOfRangeCounter; U32 valveDataPublishCounter; U32 valveRestCounter; //TODO REMOVE? // Homing variables U32 numberOfFailedHomings; U32 homingEdgeDetectionCounter; BOOL hasHomingBeenRequested; BOOL hasValveBeenHomed; } VALVE_STATUS_T; #pragma pack(pop) static VALVE_SELF_TEST_STATE_T valveSelfTestState = VALVE_SELF_TEST_ENABLE_VALVES; static SELF_TEST_STATUS_T valvesSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; static VALVE_STATUS_T valvesStatus[ NUM_OF_VALVES ]; static OVERRIDE_U32_T valvesDataPublishInterval = { VALVES_DATA_PUB_INTERVAL, VALVES_DATA_PUB_INTERVAL, 0, 0 }; static OVERRIDE_U32_T valvesPositionOverride[ NUM_OF_VALVES ] = { VALVE_POSITION_C_CLOSE, VALVE_POSITION_C_CLOSE, 0, 0 }; // Self test function prototypes static VALVE_SELF_TEST_STATE_T handleValveSelfTestEnableValves( void ); static VALVE_SELF_TEST_STATE_T handleValveSelfTestConfirmEnable( void ); // Exec function prototypes static void handleValveStateWaitForPost( VALVE_T valve ); static void handleValveStateIdle( VALVE_T valve ); static void handleValveStateInTransition( VALVE_T valve ); static void handleValveStateHomingNotStarted( VALVE_T valve ); static void handleValveStateHomingFindEnergizedEdge( VALVE_T valve ); static void handleValveStateHomingFindDeenergizedEdge( VALVE_T valve ); // Private function prototypes static void execMonitorValves( void ); static BOOL areValvesEnabled( void ); static void setFPGAValue( VALVE_T valve, S16 position ); static void convertAndMonitorValvesCurrent( void ); static void getAndMonitorValvesCurrentPosition( void ); static DATA_GET_PROTOTYPE( U32, getPublishValvesDataInterval ); static void publishValvesData( VALVE_T valve ); /*********************************************************************//** * @brief * The initValves function initializes the valves driver. * @details * Inputs: valveSelfTestState, valvesSelfTestResult, valvesStatus * Outputs: valveSelfTestState, valvesSelfTestResult, valvesStatus * @return: none *************************************************************************/ void initValves( void ) { U08 i; // To set the NHET direction to output //gioSetDirection( hetPORT1, 1 ); valveSelfTestState = VALVE_SELF_TEST_ENABLE_VALVES; valvesSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; // Initialize some of the variables for ( i = 0; i < NUM_OF_VALVES; i++ ) { valvesStatus[ i ].execState = VALVE_STATE_WAIT_FOR_POST; } } /*********************************************************************//** * @brief * The homeValve function sets the homing request flag of a valve to TRUE. * @details * Inputs: valvesStatus * Outputs: valvesStatus (The flag that sets the homing request) * @return: none *************************************************************************/ void homeValve( VALVE_T valve ) { valvesStatus[ valve ].hasHomingBeenRequested = TRUE; } /*********************************************************************//** * @brief * The setValvePosition function sets the requested position of a valve. * @details * Inputs: valvesStatus * Outputs: valvesStatus (commanded position) * @param: valve : Enumeration of the valve * @param: position : Enumeration of the commanded position * @return: returns TRUE if the requested position was legal *************************************************************************/ BOOL setValvePosition( VALVE_T valve, VALVE_POSITION_T position ) { BOOL result = FALSE; // Valve not in position cannot be requested // All the other positions are valid if ( position != VALVE_POSITION_NOT_IN_POSITION ) { valvesStatus[ valve ].commandedPosition = position; valvesStatus[ valve ].hasTransitionBeenRequested = TRUE; result = TRUE; } return result; } /*********************************************************************//** * @brief * The getValvePosition function returns the current position of a valve. * @details * Inputs: none * Outputs: valvesStatus (current position) * @param: valve : Enumeration of the valve * @param: position : Enumeration of the commanded position * @return: returns TRUE if the requested position was legal *************************************************************************/ VALVE_POSITION_T getValvePosition( VALVE_T valve ) { return valvesStatus[ valve ].currentPosition; } /*********************************************************************//** * @brief * The setValveBloodTrap function set the blood trap valve to open or close * position. * @details * Inputs: TODO * Outputs: TODO * @param: state : Enumeration of open or close * @return: TODO : What should we return? *************************************************************************/ BOOL setValveBloodTrap( OPN_CLS_STATE_T state ) { BOOL energized = FALSE; if ( state == STATE_OPEN ) { energized = TRUE; } gioSetBit( hetPORT1, 0x12, energized ); return TRUE; } /*********************************************************************//** * @brief * The execValvesSelfTest function executes the valves self test. * @details * Inputs: valveSelfTestState * Outputs: valveSelfTestState * @return: valvesSelfTestResult : The status of the self test *************************************************************************/ SELF_TEST_STATUS_T execValvesSelfTest( void ) { switch( valveSelfTestState ) { case VALVE_SELF_TEST_ENABLE_VALVES: valveSelfTestState = handleValveSelfTestEnableValves(); break; case VALVE_SELF_TEST_CONFIRM_ENABLE: valveSelfTestState = handleValveSelfTestConfirmEnable(); break; case VALVE_SELF_TEST_COMPLETE: // Do nothing POST completed break; default: //TODO alarm valveSelfTestState = VALVE_SELF_TEST_COMPLETE; } return valvesSelfTestResult; } /*********************************************************************//** * @brief * The execValves function executes the valves exec state machine. * @details * Inputs: none * Outputs: none (All the values are stored in the structure of each valve) * @return: none *************************************************************************/ void execValves( void ) { U08 i; VALVE_STATE_T state; VALVE_T valve; execMonitorValves(); // TODO uncomment the for loop //for ( i = 0; i < NUM_OF_VALVES; i++ ) { //TODO FOR TESTING ONLY REMOVE valve = VDI; i = 0; //TODO FOR TESTING ONLY REMOVE state = valvesStatus[ i ].execState; //valve = (VALVE_T)i; // VDi state machine switch ( state ) { case VALVE_STATE_WAIT_FOR_POST: handleValveStateWaitForPost( valve ); break; case VALVE_STATE_IDLE: handleValveStateIdle( valve ); break; case VALVE_STATE_IN_TRANSITION: handleValveStateInTransition( valve ); break; case VALVE_STATE_HOMING_NOT_STARTED: handleValveStateHomingNotStarted( valve ); break; case VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE: handleValveStateHomingFindEnergizedEdge( valve ); break; case VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE: handleValveStateHomingFindDeenergizedEdge( valve ); break; default: break; } publishValvesData( valve ); } } /*********************************************************************//** * @brief * The handleValveSelfTestEnableValves function starts the valves self test. * @details * Inputs: valvesSelfTestResult * Outputs: nvalvesSelfTestResult * @return: Next state of the self test state machine *************************************************************************/ static VALVE_SELF_TEST_STATE_T handleValveSelfTestEnableValves( void ) { VALVE_SELF_TEST_STATE_T state = VALVE_SELF_TEST_CONFIRM_ENABLE; valvesSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; // Enable the PID controller of all of the valves enableFPGAValvesPIDControl( ALL_VALVES_ENABLE_PID_INTERFACE ); /*(enableFPGAValvesPIDControl( VDI_ENABLE_PID_INTERFACE ); enableFPGAValvesPIDControl( VDO_ENABLE_PID_INTERFACE ); enableFPGAValvesPIDControl( VBA_ENABLE_PID_INTERFACE ); enableFPGAValvesPIDControl( VBV_ENABLE_PID_INTERFACE );*/ return state; } /*********************************************************************//** * @brief * The handleValveSelfTestConfirmEnable function checks to make sure the * valves are enabled properly. * @details * Inputs: valvesSelfTestResult * Outputs: valvesSelfTestResult * @return: Next state of the self test state machine *************************************************************************/ static VALVE_SELF_TEST_STATE_T handleValveSelfTestConfirmEnable( void ) { VALVE_SELF_TEST_STATE_T state = VALVE_SELF_TEST_CONFIRM_ENABLE; // TODO do we need to wait for 50ms? if ( areValvesEnabled() ) { valvesSelfTestResult = SELF_TEST_STATUS_PASSED; state = VALVE_SELF_TEST_COMPLETE; } else { valvesSelfTestResult = SELF_TEST_STATUS_FAILED; state = VALVE_SELF_TEST_COMPLETE; } return state; } /*********************************************************************//** * @brief * The handleValveStateWaitForPost function handles the wait for POST \n * state. * @details * Inputs: valveSelfTestState, valveSelfTestState * Outputs: valveSelfTestState (the next exec state of a valve) * @return: none *************************************************************************/ static void handleValveStateWaitForPost( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_WAIT_FOR_POST; if ( valveSelfTestState == VALVE_SELF_TEST_COMPLETE ) { state = VALVE_STATE_HOMING_NOT_STARTED; } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The handleValveStateIdle function handles the idle state of the valves \n * state machine. * @details * Inputs: valveSelfTestState, valveSelfTestState * Outputs: valveSelfTestState (the next exec state of a valve) * @return: none *************************************************************************/ static void handleValveStateIdle( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_IDLE; if ( valvesStatus[ valve ].hasHomingBeenRequested ) { state = VALVE_STATE_HOMING_NOT_STARTED; } else if ( valvesStatus[ valve ].hasValveBeenHomed && valvesStatus[ valve ].hasTransitionBeenRequested ) { if ( valvesStatus[ valve ].currentPosition != valvesStatus[ valve ].commandedPosition ) { VALVE_POSITION_T commandedPositionEnum = valvesStatus[ valve ].commandedPosition; S16 nextStep = valvesStatus[ valve ].positions[commandedPositionEnum ]; // Just set the valves to transition so it will not be in a known position for a while valvesStatus[ valve ].transitionStartTime = getMSTimerCount(); //valvesStatus[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; setFPGAValue( valve, nextStep ); state = VALVE_STATE_IN_TRANSITION; } } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The handleValveStateInTransition function handles the in transition \n * state of the state machine. * @details * Inputs: valvesStatus (commanded position, current position, current position \n * in counts, has transition been requested flag) * Outputs: valvesStatus * @return: none *************************************************************************/ static void handleValveStateInTransition( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_IN_TRANSITION; S16 nextStep = 0; VALVE_POSITION_T commandedPositionEnum = valvesStatus[ valve ].commandedPosition; VALVE_POSITION_T currentPositionEnum = valvesStatus[ valve ].currentPosition; // Get the corresponding counts of the positions S16 commandedPositionCounts = valvesStatus[ valve ].positions[ commandedPositionEnum ]; S16 currentPositionCounts = valvesStatus[ valve ].currentPositionInCounts; // Check if the valve is within range of the commanded position if ( fabs( fabs(commandedPositionCounts) - fabs(currentPositionCounts) ) <= MAX_DEVIATION_FROM_TARGET_IN_COUNTS ) { // The valve is in range. Set the current position to the commanded position valvesStatus[ valve ].currentPosition = commandedPositionEnum; // Set the transition request to false as it has been serviced valvesStatus[ valve ].hasTransitionBeenRequested = FALSE; // Go back to Idle state state = VALVE_STATE_IDLE; } // Check if the valve's transition time has timed out /*else if ( didTimeout( valvesStatus[ valve ].transitionStartTime, VALVE_TRANSITION_TIMEOUT_MS ) ) { // TODO raise an alarm valvesStatus[ valve ].hasTransitionBeenRequested = FALSE; // Go back to Idle state state = VALVE_STATE_IDLE; }*/ // If everything is good, decide what is the next step else { // If the valve is currently in position A and its commanded position is position B, // subtract the defined number of steps for the next transition // If the valve is currently in position A and its commanded position is position C, // add the defined number of steps for the next transition if ( currentPositionEnum == VALVE_POSITION_A_INSERT_EJECT ) { if ( commandedPositionEnum == VALVE_POSITION_B_OPEN ) { nextStep = valvesStatus[ valve ].currentPositionInCounts - STEP_CHANGE_IN_COUNTS; } if ( commandedPositionEnum == VALVE_POSITION_C_CLOSE ) { nextStep = valvesStatus[ valve ].currentPositionInCounts + STEP_CHANGE_IN_COUNTS; } } // If the valve is currently in position B, add the defined number of steps for the next transition else if ( currentPositionEnum == VALVE_POSITION_B_OPEN ) { nextStep = valvesStatus[ valve ].currentPositionInCounts + STEP_CHANGE_IN_COUNTS; } // If the valve is currently in position C, subtract the defined number of steps for the next transition else if ( currentPositionEnum == VALVE_POSITION_C_CLOSE ) { nextStep = valvesStatus[ valve ].currentPositionInCounts + STEP_CHANGE_IN_COUNTS; } setFPGAValue( valve, nextStep ); } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The handleValveStateHomingNotStarted function handles homing not started \n * state of the state machine. * @details * Inputs: valvesStatus, valveSelfTestState * Outputs: valvesStatus * @return: none *************************************************************************/ static void handleValveStateHomingNotStarted( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_HOMING_NOT_STARTED; // TODO connect this flag to the doors driver later // For now it is assumed the door is closed BOOL isDoorClosed = TRUE; // If homing has been requested or POST is completed and the door has been close for the specified // period of time, start the homing if ( ( valvesStatus[ valve ].hasHomingBeenRequested || valveSelfTestState == VALVE_SELF_TEST_COMPLETE ) && isDoorClosed ) { // Get ready for the energized state valvesStatus[ valve ].homingEdgeDetectionCounter = 0; valvesStatus[ valve ].targetPositionInCounts = STEP_CHANGE_IN_COUNTS; valvesStatus[ valve ].hasValveBeenHomed = FALSE; valvesStatus[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; setFPGAValue( valve, valvesStatus[ valve ].targetPositionInCounts ); state = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The handleValveStateHomingFindEnergizedEdge function handles find \n * energized state of the state machine. * @details * Inputs: valvesStatus, valveSelfTestState * Outputs: valvesStatus * @return: none *************************************************************************/ static void handleValveStateHomingFindEnergizedEdge( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; S16 currentPosition = valvesStatus[ valve ].currentPositionInCounts; S16 targetPosition = valvesStatus[ valve ].targetPositionInCounts; S16 absDeltaPosition = fabs( fabs(currentPosition) - fabs(targetPosition) ); if ( absDeltaPosition > MAX_DEVIATION_FROM_TARGET_IN_COUNTS && ++valvesStatus[ valve ].homingEdgeDetectionCounter >= HOMING_EDGE_DETECTION_TARGET_COUNTER ) { // Current position (positive or negative) will be stored in the Position B of the current valve valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ] = currentPosition; valvesStatus[ valve ].homingEdgeDetectionCounter = 0; valvesStatus[ valve ].targetPositionInCounts = currentPosition - STEP_CHANGE_IN_COUNTS; setFPGAValue( valve, valvesStatus[ valve ].targetPositionInCounts ); state = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; } else if ( absDeltaPosition <= MAX_DEVIATION_FROM_TARGET_IN_COUNTS ) { if ( ++valvesStatus[ valve ].valveRestCounter >= 0 ) //TODO add a #define for the rest time. Do we need the rest? { valvesStatus[ valve ].homingEdgeDetectionCounter = 0; valvesStatus[ valve ].targetPositionInCounts = currentPosition + STEP_CHANGE_IN_COUNTS; setFPGAValue( valve, valvesStatus[ valve ].targetPositionInCounts ); } } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The handleValveStateHomingFindDeenergizedEdge function handles find \n * de-energized state of the state machine. * @details. * Inputs: valvesStatus, valveSelfTestState * Outputs: valvesStatus * @return: none *************************************************************************/ static void handleValveStateHomingFindDeenergizedEdge( VALVE_T valve ) { VALVE_STATE_T state = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; S16 currentPosition = valvesStatus[ valve ].currentPositionInCounts; S16 targetPosition = valvesStatus[ valve ].targetPositionInCounts; S16 absDeltaPosition = fabs( fabs(currentPosition) - fabs(targetPosition) ); if ( absDeltaPosition > MAX_DEVIATION_FROM_TARGET_IN_COUNTS && ++valvesStatus[ valve ].homingEdgeDetectionCounter >= HOMING_EDGE_DETECTION_TARGET_COUNTER ) { S16 energizedEdge = valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ]; S16 absEnergizedDelta = fabs( fabs(energizedEdge) - fabs(currentPosition) ); if ( absEnergizedDelta <= INITIAL_ENERGIZED_EDGE_UPPER_RANGE && absEnergizedDelta >= INITIAL_ENERGIZED_EDGE_LOWER_RANGE ) { S16 positionB = valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ]; // Positions B and C will have an offset from the edge to make sure each time the valve will not hit the edge valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ] = positionB - INITIAL_EDGE_OFFSET_READ_COUNT; valvesStatus[ valve ].positions[ VALVE_POSITION_C_CLOSE ] = currentPosition + INITIAL_EDGE_OFFSET_READ_COUNT; // Position A is the average of the Position B that was read last time and position C that was the target of this state valvesStatus[ valve ].positions[ VALVE_POSITION_A_INSERT_EJECT ] = ( valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ] + valvesStatus[ valve ].positions[ VALVE_POSITION_C_CLOSE ] ) / 2; // Set the current position to Position C and the commanded position to Position A // Request a transition valvesStatus[ valve ].hasValveBeenHomed = TRUE; valvesStatus[ valve ].currentPosition = VALVE_POSITION_C_CLOSE; valvesStatus[ valve ].commandedPosition = VALVE_POSITION_A_INSERT_EJECT; valvesStatus[ valve ].hasTransitionBeenRequested = TRUE; valvesStatus[ valve ].hasHomingBeenRequested = FALSE; valvesStatus[ valve ].numberOfFailedHomings = 0; // Idle will initiate a transition state = VALVE_STATE_IDLE; } // Max number of failed homing. Fault else if ( ++valvesStatus[ valve ].numberOfFailedHomings >= MAX_ALLOWED_FAILED_HOMINGS ) { //TODO Alarm valvesStatus[ valve ].hasValveBeenHomed = FALSE; state = VALVE_STATE_IDLE; } else { state = VALVE_STATE_HOMING_NOT_STARTED; } } else if ( absDeltaPosition <= MAX_DEVIATION_FROM_TARGET_IN_COUNTS ) { if ( ++valvesStatus[ valve ].valveRestCounter >= 0 ) //TODO add a #define for the rest time. Do we need the rest? { valvesStatus[ valve ].homingEdgeDetectionCounter = 0; valvesStatus[ valve ].targetPositionInCounts = currentPosition - STEP_CHANGE_IN_COUNTS; setFPGAValue( valve, valvesStatus[ valve ].targetPositionInCounts ); } } valvesStatus[ valve ].execState = state; } /*********************************************************************//** * @brief * The execMonitorValves function handles monitoring of the valves. The \n * function calls other functions to monitor the values. * @details * Inputs: none * Outputs: none * @return: none *************************************************************************/ static void execMonitorValves( void ) { // TODO check enable status of the valves here too areValvesEnabled(); // Get the current position of the valves in counts and store them getAndMonitorValvesCurrentPosition(); // Get the current in ADC and convert them to amps // Check whether any of the valves are over current convertAndMonitorValvesCurrent(); } /*********************************************************************//** * @brief * The areValvesEnabled function checks the current valves status from FPGA \n * to the enable bit mask of each valve. If any of the valves is not enabled \n * the function raises an alarm. * @details * Inputs: none * Outputs: none * @return: Returns TRUE if all the valves are enabled properly *************************************************************************/ static BOOL areValvesEnabled( void ) { //TODO alarm for the valve status BOOL result = TRUE; U16 status = getFPGAValvesStatus(); // VDi status if ( ! ( status & VDI_INIT_STATUS_BIT_MASK ) ) { result = FALSE; } if ( ! ( status & VDI_ENABLE_PID_STATUS_BIT_MASK ) ) { result = FALSE; } if ( status & VDI_ENABLE_BYPASS_STATUS_BIT_MASK ) { result = FALSE; } // VDo status if ( ! ( status & VDO_INIT_STATUS_BIT_MASK ) ) { result = FALSE; } if ( ! ( status & VDO_ENABLE_PID_STATUS_BIT_MASK ) ) { result = FALSE; } if ( status & VDO_ENABLE_BYPASS_STATUS_BIT_MASK ) { result = FALSE; } // VBA status if ( ! ( status & VBA_INIT_STATUS_BIT_MASK ) ) { result = FALSE; } if ( ! ( status & VBA_ENABLE_PID_STATUS_BIT_MASK ) ) { result = FALSE; } if ( status & VBA_ENABLE_BYPASS_STATUS_BIT_MASK ) { result = FALSE; } // VBV status if ( ! ( status & VBV_INIT_STATUS_BIT_MASK ) ) { result = FALSE; } if ( ! ( status & VBV_ENABLE_PID_STATUS_BIT_MASK ) ) { result = FALSE; } if ( status & VBV_ENABLE_BYPASS_STATUS_BIT_MASK ) { result = FALSE; } return result; } /*********************************************************************//** * @brief * The setFPGAValue function sets the position of a valve to FPGA. * @details * Inputs: none * Outputs: none * @param: valve : Enumeration of the valve * @param: position : Position in counts * @return: none *************************************************************************/ static void setFPGAValue( VALVE_T valve, S16 position ) { switch ( valve ) { case VDI: setFPGAValveDialyzerInletPosition( position ); break; case VDO: setFPGAValveDialyzerOutletPosition( position ); break; case VBA: setFPGAValveBloodArterialPosition( position ); break; case VBV: setFPGAValveBloodVenousPosition( position ); break; default: // TODO alarm break; } } /*********************************************************************//** * @brief * The convertAndMonitorValvesCurrent function gets the current values \n * in counts from FPGA and converts them to current. If any of the values \n * is above the threshold, the function will raise an alarm. * @details * Inputs: valvesStatus * Outputs: valvesStatus * @return: none *************************************************************************/ static void convertAndMonitorValvesCurrent( void ) { U08 i; U16 currentInADC = 0; currentInADC = getFPGAValveDialyzerInletCurrentCounts(); valvesStatus[ VDI ].valveCurrent = ( (F32)currentInADC / ADC_TO_CURRENT_CONVERSION_CONSTANT ) - 1; currentInADC = getFPGAValveDialyzerOutletCurrentCounts(); valvesStatus[ VDO ].valveCurrent = ( (F32)currentInADC / ADC_TO_CURRENT_CONVERSION_CONSTANT ) - 1; currentInADC = getFPGAValveBloodVenousCurrentCounts(); valvesStatus[ VBA ].valveCurrent = ( (F32)currentInADC / ADC_TO_CURRENT_CONVERSION_CONSTANT ) - 1; currentInADC = getFPGAValveBloodArterialCurrentCounts(); valvesStatus[ VBV ].valveCurrent = ( (F32)currentInADC / ADC_TO_CURRENT_CONVERSION_CONSTANT ) - 1; // The current of all the valves for ( i = 0; i < NUM_OF_VALVES; i++) { // Check if the current is over the threshold for the defined amount of time if ( fabs(valvesStatus[ i ].valveCurrent) > VALVES_CURRENT_THRESHOLD_AMPS && ++valvesStatus[ i ].valveOverCurrentCounter > OVER_CURRENT_COUNTER ) { //TODO fault } // If the current is below the threshold again and the counter for the time is greater than // zero, set the counter to zero else if ( fabs(valvesStatus[ i ].valveCurrent) < VALVES_CURRENT_THRESHOLD_AMPS && valvesStatus[ i ].valveOverCurrentCounter > 0 ) { valvesStatus[ i ].valveOverCurrentCounter = 0; } } } /*********************************************************************//** * @brief * The getAndMonitorValvesCurrentPosition function gets the current position \n * of the valves and stores them into the structure of each valve. The function \n * checks whether any of the valves have deviated from their current position \n * if they are in idle state. If any of the valves have deviated, the function \n * raises an alarm. * @details * Inputs: valvesStatus * Outputs: valvesStatus * @return: none *************************************************************************/ static void getAndMonitorValvesCurrentPosition( void ) { U08 i; S16 currentPostion = 0; S16 commandedPoistion = 0; VALVE_POSITION_T commandedPositionEnum; // Get the position of the valves and update the structure of each valve valvesStatus[ VDI ].currentPositionInCounts = getFPGAValveDialyzerInletPosition(); valvesStatus[ VDO ].currentPositionInCounts = getFPGAValveDialyzerOutletPosition(); valvesStatus[ VBA ].currentPositionInCounts = getFPGAValveBloodArterialPosition(); valvesStatus[ VBV ].currentPositionInCounts = getFPGAValveBloodVenousPosition(); // Check the position of each valve for ( i = 0; i < NUM_OF_VALVES; i++ ) { // Check the valve is in Idle state, otherwise the position should not be checked if ( valvesStatus[ i ].execState == VALVE_STATE_IDLE ) { currentPostion = fabs( valvesStatus[ i ].currentPositionInCounts ); commandedPositionEnum = valvesStatus[ i ].commandedPosition; commandedPoistion = fabs( valvesStatus[ i ].positions[ commandedPositionEnum ] ); // Check if the current position has deviated from the position it is supposed to be in // for more than a certain amount of time. If it has, raise an alarm if ( fabs( currentPostion - commandedPoistion ) > MAX_DEVIATION_FROM_TARGET_IN_COUNTS && ++valvesStatus[ i ].valvePositionOutOfRangeCounter > OUT_OF_RANGE_COUNTER ) { // TODO fault } // If the deviation came back to within the maximum amount and the time counter was > 0, // set the counter to 0 else if ( fabs( currentPostion - commandedPoistion ) < MAX_DEVIATION_FROM_TARGET_IN_COUNTS && valvesStatus[ i ].valvePositionOutOfRangeCounter > 0 ) { valvesStatus[ i ].valvePositionOutOfRangeCounter = 0; } } } } /*********************************************************************//** * @brief * The getPublishValvesDataInterval function gets the valves data publish \n * interval. * @details * Inputs: valvesDataPublishInterval * Outputs: none * @return: The data publish time interval *************************************************************************/ U32 getPublishValvesDataInterval( void ) { U32 result = valvesDataPublishInterval.data; if ( OVERRIDE_KEY == valvesDataPublishInterval.override ) { result = valvesDataPublishInterval.ovData; } return result; } /*********************************************************************//** * @brief * The publishValvesData function publishes the data of the valves at the \n * specified time interval. * @details * Inputs: valvesStatus * Outputs: valvesStatus * @return: none *************************************************************************/ static void publishValvesData( VALVE_T valve ) { // Check the counter if ( ++valvesStatus[ valve ].valveDataPublishCounter > getPublishValvesDataInterval() ) { valveData.valveID = (U32)valve; valveData.state = (U32)valvesStatus[ valve ].execState; valveData.currentPosID = (U32)valvesStatus[ valve ].currentPosition; valveData.currentPos = valvesStatus[ valve ].currentPositionInCounts; valveData.nextPos = valvesStatus[ valve ].targetPositionInCounts; valveData.current = valvesStatus[ valve ].valveCurrent; valveData.posC = valvesStatus[ valve ].positions[ VALVE_POSITION_C_CLOSE ]; valveData.posA = valvesStatus[ valve ].positions[ VALVE_POSITION_A_INSERT_EJECT ]; valveData.posB = valvesStatus[ valve ].positions[ VALVE_POSITION_B_OPEN ]; broadcastHDValves(); valvesStatus[ valve ].valveDataPublishCounter = 0; } // TODO REMOVE Fast 10ms publish fastDataRemoveLater.currentPos = valvesStatus[ valve ].currentPositionInCounts; fastDataRemoveLater.current = valvesStatus[ valve ].valveCurrent; fastDataRemoveLater.cmdPosition = valvesStatus[ valve ].targetPositionInCounts; broadcastFastTempHDValves(); // TODO REMOVE } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetValvesDataPublishInterval function overrides the valves \n * data publish interval. * @details * Inputs: valvesDataPublishInterval * Outputs: valvesDataPublishInterval * @param: value : override valve data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetValvesDataPublishInterval( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; valvesDataPublishInterval.ovData = intvl; valvesDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetValvesDataPublishInterval function resets the override \n * of the valves publish interval. * @details * Inputs: valvesDataPublishInterval * Outputs: valvesDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetValvesDataPublishInterval( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; valvesDataPublishInterval.override = OVERRIDE_RESET; valvesDataPublishInterval.ovData = valvesDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetValvesPositionOverride function overrides the valves \n * position. * @details * Inputs: valvesPositionOverride, valvesStatus * Outputs: valvesPositionOverride, valvesStatus * @param valve The valve ID * @param position The position the valve has to transition to * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetValvesPositionOverride( U32 valve, U32 position ) { BOOL result = FALSE; if ( valve < NUM_OF_VALVES ) { if ( TRUE == isTestingActivated() ) { // Get the current position of the valve as the initial position valvesPositionOverride[ valve ].ovInitData = (U32)valvesStatus[ valve ].currentPosition; valvesPositionOverride[ valve ].ovData = position; valvesPositionOverride[ valve ].override = OVERRIDE_KEY; result = setValvePosition( (VALVE_T)valve, (VALVE_POSITION_T)position ); } } return result; } /*********************************************************************//** * @brief * The testResetValvesDataPublishInterval function resets the override \n * of the valves publish interval. * @details * Inputs: valvesDataPublishInterval * Outputs: valvesDataPublishInterval * @param valve The valve ID * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetValvesPositionOverride( U32 valve ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { valvesPositionOverride[ valve ].override = OVERRIDE_RESET; valvesPositionOverride[ valve ].ovData = valvesPositionOverride[ valve ].ovInitData; result = setValvePosition( (VALVE_T)valve, (VALVE_POSITION_T)valvesPositionOverride[ valve ].ovInitData ); } return result; } /**@}*/