/************************************************************************** * * Copyright (c) 2026-2026 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 PinchValve.c * * @author (last) Varshini Nagabooshanam * @date (last) 08-Jul-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 08-Jul-2026 * ***************************************************************************/ #include "Common.h" #include "FpgaTD.h" #include "PinchValve.h" #include "RotaryValve.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup PinchValve * @{ */ // ********** private definitions ********** #define PINCH_VALVE_STATUS_POLL_INTERVAL_MS 10 ///< FPGA status polling interval in (ms). #define PINCH_VALVE_COMMAND_TIMEOUT_MS 1000 ///< Maximum FPGA command execution time. #define PINCH_VALVE_DEFAULT_VELOCITY 3342 #define PINCH_VALVE_FPGA_CMD_START_BIT_MASK 0x01 ///< Bit 0 starts a command transaction. (TODO: To change the comments later) #define PINCH_VALVE_FPGA_CMD_WRITE_ONLY_BIT_MASK 0x02 ///< Bit 1 selects a write-only command. #define PINCH_VALVE_FPGA_CMD_TX_COUNT_SHIFT 2 ///< Bits 4-2 contain transmit word count. #define PINCH_VALVE_FPGA_CMD_RX_COUNT_SHIFT 5 ///< Bits 7-5 contain receive word count. #define PINCH_VALVE_FPGA_CMD_WORD_COUNT_MASK 0x07 ///< Three-bit FPGA word-count mask. #define PINCH_VALVE_SPI_DONE_BIT_MASK 0x01 ///< SPI command completed. #define PINCH_VALVE_SPI_TX_COUNT_MASK 0x0E ///< SPI status bits 3-1: transmitted words. #define PINCH_VALVE_SPI_TX_COUNT_SHIFT 1 #define PINCH_VALVE_SPI_RX_COUNT_MASK 0x30 ///< SPI status bits 5-4: received words. #define PINCH_VALVE_SPI_RX_COUNT_SHIFT 4 #define PINCH_VALVE_SPI_CONTROLLER_FAULT_BIT_MASK 0x40 ///< SPI status bit 6: controller fault. #define PINCH_VALVE_ENABLE_BIT_MASK 0x01 ///< Enable controller. #define PINCH_VALVE_RESET_BIT_MASK 0x02 ///< Reset controller. #define PINCH_VALVE_MAX_INPUT_WORDS 3 ///< Maximum number of command input words. #define PINCH_VALVE_MAX_OUTPUT_WORDS 3 ///< Maximum number of command output words. #define PINCH_VALVE_MAX_TRANSMIT_WORDS 4 #define PINCH_VALVE_PMD_CMD_SET_POSITION 0x0010 #define PINCH_VALVE_PMD_CMD_SET_VELOCITY 0x0011 #define PINCH_VALVE_PMD_CMD_UPDATE 0x001A #define PINCH_VALVE_PMD_CMD_GET_EVENT_STATUS 0x0031 #define PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS 0x0034 #define PINCH_VALVE_PMD_CMD_GET_ACTUAL_POSITION 0x0037 #define PINCH_VALVE_PMD_CMD_SET_ACTUAL_POSITION 0x004D #define PINCH_VALVE_PMD_CMD_SET_PROFILE_MODE 0x00A0 #define PINCH_VALVE_PMD_CMD_GET_ACTIVITY_STATUS 0x00A6 #define PINCH_VALVE_PROFILE_MODE_VELOCITY 1 #define PINCH_VALVE_PROFILE_MODE_S_CURVE 2 #define PINCH_VALVE_RESET_EVENT_STATUS_VALUE 0xFFEE #define PINCH_VALVE_DEFAULT_VELOCITY 3342 #define PINCH_VALVE_ACTIVITY_PHASE_INITIALIZED_MASK 0x0001 #define PINCH_VALVE_ACTIVITY_AXIS_SETTLED_MASK 0x0080 #define PINCH_VALVE_EVENT_MOTION_COMPLETE_MASK 0x0001 #define PINCH_VALVE_EVENT_MOTION_ERROR_MASK 0x0010 /// Pinch valve function state machine. typedef enum pinchValveFunctionStates { PINCH_VALVE_FUNCTION_IDLE_STATE = 0, PINCH_VALVE_FUNCTION_SEND_STATE, PINCH_VALVE_FUNCTION_WAIT_STATE } PINCH_VALVE_FUNCTION_STATE_T; /// Low-level FPGA command state machine. typedef enum pinchValveCommandStates { PINCH_VALVE_CMD_IDLE_STATE = 0, PINCH_VALVE_CMD_SET_CMD_STATE, PINCH_VALVE_CMD_XMIT_CMD_STATE, PINCH_VALVE_CMD_WAIT_DONE_STATE, PINCH_VALVE_CMD_READ_WORDS_STATE, PINCH_VALVE_CMD_ERROR_STATE } PINCH_VALVE_CMD_STATE_T; /// Result of the active low level command. typedef enum pinchValveCommandResults { PINCH_VALVE_CMD_RESULT_IDLE = 0, PINCH_VALVE_CMD_RESULT_BUSY, PINCH_VALVE_CMD_RESULT_COMPLETE, PINCH_VALVE_CMD_RESULT_ERROR } PINCH_VALVE_CMD_RESULT_T; /// Pinch Valve Function. typedef enum pinchValveFunctions { PINCH_VALVE_FUNCTION_NONE = 0, PINCH_VALVE_FUNCTION_HOME, PINCH_VALVE_FUNCTION_SET_POSITION } PINCH_VALVE_FUNCTION_T; /// Pinch valve command request. typedef struct { U16 cmdHeader; ///< Command header. U16 inputWord1; ///< Input word 1. U16 inputWord2; ///< Input word 2. U16 inputWord3; ///< Input word 3. U08 inputWordCount; ///< Number of valid input words, excluding the command header. U08 outputWordCount; ///< Number of output words expected. BOOL writeOnly; ///< TRUE for a write-only command. } PINCH_VALVE_COMMAND_T; /// Response from the FPGA command interface. typedef struct { U16 outputWord1; ///< Output word 1. U16 outputWord2; ///< Output word 2. U16 outputWord3; ///< Output word 3. U08 spiCmdStatus; ///< FPGA SPI command status. U08 readCount; ///< FPGA read count. U08 errorCount; ///< FPGA invalid command error count. } PINCH_VALVE_RESPONSE_T; /// Pinch Valve Command for Homing. typedef enum pinchValveHomingCommandIndexes { PINCH_VALVE_HOME_CMD_SET_PROFILE_MODE = 0, PINCH_VALVE_HOME_CMD_RESET_EVENTS_B, PINCH_VALVE_HOME_CMD_SET_VELOCITY_B, PINCH_VALVE_HOME_CMD_UPDATE_B, PINCH_VALVE_HOME_CMD_GET_ACTIVITY_STATUS, PINCH_VALVE_HOME_CMD_GET_EVENT_STATUS_B, PINCH_VALVE_HOME_CMD_SET_ACTUAL_POSITION_ZERO, PINCH_VALVE_HOME_CMD_RESET_EVENTS_C, PINCH_VALVE_HOME_CMD_SET_VELOCITY_C, PINCH_VALVE_HOME_CMD_UPDATE_C, PINCH_VALVE_HOME_CMD_GET_EVENT_STATUS_C, PINCH_VALVE_HOME_CMD_GET_ACTUAL_POSITION_C, PINCH_VALVE_HOME_CMD_RESET_EVENTS_COMPLETE, NUM_OF_PINCH_VALVE_HOMING_COMMANDS } PINCH_VALVE_HOMING_COMMAND_INDEX_T; /// Pinch Valve Command for Set-Position. typedef enum pinchValvePositionCommandIndexes { PINCH_VALVE_POSITION_CMD_SET_PROFILE_MODE = 0, PINCH_VALVE_POSITION_CMD_SET_VELOCITY, PINCH_VALVE_POSITION_CMD_GET_ACTIVITY_STATUS, PINCH_VALVE_POSITION_CMD_GET_EVENT_STATUS_BEFORE, PINCH_VALVE_POSITION_CMD_RESET_EVENT_STATUS, PINCH_VALVE_POSITION_CMD_SET_POSITION, PINCH_VALVE_POSITION_CMD_UPDATE, PINCH_VALVE_POSITION_CMD_GET_EVENT_STATUS_AFTER, PINCH_VALVE_POSITION_CMD_GET_ACTUAL_POSITION, PINCH_VALVE_POSITION_CMD_RESET_EVENT_STATUS_COMPLETE, NUM_OF_PINCH_VALVE_POSITION_COMMANDS } PINCH_VALVE_POSITION_COMMAND_INDEX_T; // ********** private data ********** const S32 HOMING_VELOCITY_FWD = 3342; ///< ** add a comment later *** const S32 HOMING_VELOCITY_REV = -3342; // This array is used for both H1_VALV and H19_VALV. The active valve only determines which FPGA register access functions run. static PINCH_VALVE_COMMAND_T homingCommands[ NUM_OF_PINCH_VALVE_HOMING_COMMANDS ] = { { PINCH_VALVE_PMD_CMD_SET_PROFILE_MODE, PINCH_VALVE_PROFILE_MODE_VELOCITY, 0, 0, 1, 0, FALSE }, { PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS, PINCH_VALVE_RESET_EVENT_STATUS_VALUE, 0, 0, 1, 0, FALSE }, { PINCH_VALVE_PMD_CMD_SET_VELOCITY, (HOMING_VELOCITY_FWD >> 16), (HOMING_VELOCITY_FWD & 0xFFFF), 0, 2, 0, FALSE }, { PINCH_VALVE_PMD_CMD_UPDATE, 0, 0, 0, 0, 0, FALSE }, { PINCH_VALVE_PMD_CMD_GET_ACTIVITY_STATUS, 0, 0, 0, 0, 1, FALSE }, { PINCH_VALVE_PMD_CMD_GET_EVENT_STATUS, 0, 0, 0, 0, 1, FALSE }, { PINCH_VALVE_PMD_CMD_SET_ACTUAL_POSITION, 0, 0, 0, 2, 0, FALSE }, { PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS, PINCH_VALVE_RESET_EVENT_STATUS_VALUE, 0, 0, 1, 0, FALSE }, { PINCH_VALVE_PMD_CMD_SET_VELOCITY, (HOMING_VELOCITY_REV >> 16), (HOMING_VELOCITY_REV & 0xFFFF), 0, 2, 0, FALSE }, { PINCH_VALVE_PMD_CMD_UPDATE, 0, 0, 0, 0, 0, FALSE }, { PINCH_VALVE_PMD_CMD_GET_ACTUAL_POSITION, 0, 0, 0, 0, 2, FALSE }, { PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS, PINCH_VALVE_RESET_EVENT_STATUS_VALUE, 0, 0, 1, 0, FALSE } }; static PINCH_VALVE_COMMAND_T positionCommands[ NUM_OF_PINCH_VALVE_POSITION_COMMANDS ] = { { PINCH_VALVE_PMD_CMD_SET_PROFILE_MODE, PINCH_VALVE_PROFILE_MODE_S_CURVE, 0, 0, 1, 0, FALSE }, { PINCH_VALVE_PMD_CMD_SET_VELOCITY, 0, 0, 0, 2, 0, FALSE }, { PINCH_VALVE_PMD_CMD_GET_ACTIVITY_STATUS, 0, 0, 0, 0, 1, FALSE }, { PINCH_VALVE_PMD_CMD_GET_EVENT_STATUS, 0, 0, 0, 0, 1, FALSE }, { PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS, PINCH_VALVE_RESET_EVENT_STATUS_VALUE, 0, 0, 1, 0, FALSE }, { PINCH_VALVE_PMD_CMD_SET_POSITION, 0, 0, 0, 2, 0, FALSE }, { PINCH_VALVE_PMD_CMD_UPDATE, 0, 0, 0, 0, 0, FALSE }, { PINCH_VALVE_PMD_CMD_GET_EVENT_STATUS, 0, 0, 0, 0, 1, FALSE }, { PINCH_VALVE_PMD_CMD_GET_ACTUAL_POSITION, 0, 0, 0, 0, 2, FALSE }, { PINCH_VALVE_PMD_CMD_RESET_EVENT_STATUS, PINCH_VALVE_RESET_EVENT_STATUS_VALUE, 0, 0, 1, 0, FALSE } }; static PINCH_VALVE_FUNCTION_STATE_T functionState; ///< Current function state. static PINCH_VALVE_CMD_STATE_T commandState; ///< Current command state. static PINCH_VALVE_FUNCTION_T activeFunction; static VALVE_T activeValve; ///< Valve executing the current command. static PINCH_VALVE_COMMAND_T pendingCommand; ///< Command waiting to be started. static PINCH_VALVE_COMMAND_T activeCommand; ///< Command currently being executed. static PINCH_VALVE_COMMAND_T *activeCommandArray; static U08 activeCommandCount; static U08 activeCommandIndex; static PINCH_VALVE_RESPONSE_T currentResponse; ///< Response for the active command. static PINCH_VALVE_RESPONSE_T lastResponse[ NUM_OF_VALVES ]; ///< Last response for each valve. static PINCH_VALVE_CMD_RESULT_T commandResult; ///< Latest driver result. static U08 enableResetValue[ NUM_OF_VALVES ]; ///< Last enable/reset value written per valve. static U08 errorCountAtCommandStart; ///< Error counter captured before command start. static S32 currentValvePosition[ NUM_OF_VALVES ]; static U32 executeStartTime; ///< Execute transaction start time. static U32 statusPollStartMSCount; ///< Status polling interval start time. // ********** private function prototypes ********** static PINCH_VALVE_CMD_RESULT_T getPinchValveCommandResult( void ); static BOOL getPinchValveResponse( VALVE_T valve, PINCH_VALVE_RESPONSE_T *response ); static BOOL setPinchValveCommand( VALVE_T valve, const PINCH_VALVE_COMMAND_T *command ); static void writePinchValveCommandRegisters( void ); static BOOL transmitPinchValveCommand( void ); static void readPinchValveCommandResponse( void ); static void clearPinchValveFpgaCommand( void ); static BOOL setPinchValveFpgaCommandByte( const PINCH_VALVE_COMMAND_T *command, U08 *fpgaCommand ); static BOOL isPinchValveCommandDone( void ); static BOOL isPinchValveControllerFaultActive( void ); static BOOL didPinchValveErrorCountChange( void ); static BOOL arePinchValveWordCountsValid( void ); static U08 readPinchValveErrorCount( VALVE_T valve ); static BOOL isValidPinchValve( VALVE_T valve ); static BOOL isValidPinchValveCommand( const PINCH_VALVE_COMMAND_T *command ); static void clearPinchValveResponse( PINCH_VALVE_RESPONSE_T *response ); static void setSigned32CommandWords( PINCH_VALVE_COMMAND_T *command, S32 value ); static S32 getSigned32ResponseValue( const PINCH_VALVE_RESPONSE_T *response ); static BOOL isPinchValveCommandCompleted( BOOL *repeatCommand ); /*********************************************************************//** * @brief * The initPinchValveDriver function initializes the pinch valve * communication driver. * @details \b Inputs: none * @details \b Outputs: PinchValve driver unit is initialized * @return none *************************************************************************/ void initPinchValveDriver( void ) { U32 valve; functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; commandState = PINCH_VALVE_CMD_IDLE_STATE; activeFunction = PINCH_VALVE_FUNCTION_NONE; activeValve = H1_VALV; commandResult = PINCH_VALVE_CMD_RESULT_IDLE; activeCommandArray = 0; activeCommandCount = 0; activeCommandIndex = 0; clearPinchValveResponse( ¤tResponse ); for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) { clearPinchValveResponse( &lastResponse[ valve ] ); enableResetValue[ valve ] = 0; currentValvePosition[ valve ] = 0; } setSigned32CommandWords( &homingCommands[ PINCH_VALVE_HOME_CMD_SET_VELOCITY_B ], PINCH_VALVE_DEFAULT_VELOCITY ); setSigned32CommandWords( &homingCommands[ PINCH_VALVE_HOME_CMD_SET_VELOCITY_C ], -PINCH_VALVE_DEFAULT_VELOCITY ); setSigned32CommandWords( &homingCommands[ PINCH_VALVE_HOME_CMD_SET_ACTUAL_POSITION_ZERO ], 0 ); setSigned32CommandWords( &positionCommands[ PINCH_VALVE_POSITION_CMD_SET_VELOCITY ], PINCH_VALVE_DEFAULT_VELOCITY ); setSigned32CommandWords( &positionCommands[ PINCH_VALVE_POSITION_CMD_SET_POSITION ], 0 ); errorCountAtCommandStart = 0; executeStartTime = 0; statusPollStartMSCount = 0; setH1FPGACmd( 0 ); setH19FPGACmd( 0 ); } /*********************************************************************//** * @brief * The execPinchValveCommand function executes the low-level FPGA command * state machine. * @details \b Inputs: activeCommand, activeValve, * @details \b Outputs: currentResponse, commandState, * and commandResult * @return none *************************************************************************/ void execPinchValveCommand( void ) { switch ( commandState ) { case PINCH_VALVE_CMD_IDLE_STATE: execPinchValveFunction(); break; case PINCH_VALVE_CMD_SET_CMD_STATE: writePinchValveCommandRegisters(); if ( PINCH_VALVE_CMD_ERROR_STATE != commandState ) { errorCountAtCommandStart = readPinchValveErrorCount( activeValve ); commandState = PINCH_VALVE_CMD_XMIT_CMD_STATE; } break; case PINCH_VALVE_CMD_XMIT_CMD_STATE: if ( TRUE == transmitPinchValveCommand() ) { executeStartTime = getMSTimerCount(); statusPollStartMSCount = executeStartTime; commandState = PINCH_VALVE_CMD_WAIT_DONE_STATE; } else { commandState = PINCH_VALVE_CMD_ERROR_STATE; } break; case PINCH_VALVE_CMD_WAIT_DONE_STATE: if ( TRUE == didTimeout( executeStartTime, PINCH_VALVE_COMMAND_TIMEOUT_MS ) ) { readPinchValveCommandResponse(); commandState = PINCH_VALVE_CMD_ERROR_STATE; } else if ( TRUE == didTimeout( statusPollStartMSCount, PINCH_VALVE_STATUS_POLL_INTERVAL_MS ) ) { readPinchValveCommandResponse(); statusPollStartMSCount = getMSTimerCount(); if ( ( TRUE == didPinchValveErrorCountChange() ) || ( TRUE == isPinchValveControllerFaultActive() ) ) { commandState = PINCH_VALVE_CMD_ERROR_STATE; } else if ( TRUE == isPinchValveCommandDone() ) { commandState = PINCH_VALVE_CMD_READ_WORDS_STATE; } } break; case PINCH_VALVE_CMD_READ_WORDS_STATE: readPinchValveCommandResponse(); if ( ( TRUE == didPinchValveErrorCountChange() ) || ( TRUE == isPinchValveControllerFaultActive() ) || ( FALSE == arePinchValveWordCountsValid() ) ) { commandState = PINCH_VALVE_CMD_ERROR_STATE; } else { lastResponse[ activeValve ] = currentResponse; clearPinchValveFpgaCommand(); commandResult = PINCH_VALVE_CMD_RESULT_COMPLETE; commandState = PINCH_VALVE_CMD_IDLE_STATE; } break; case PINCH_VALVE_CMD_ERROR_STATE: readPinchValveCommandResponse(); lastResponse[ activeValve ] = currentResponse; clearPinchValveFpgaCommand(); commandResult = PINCH_VALVE_CMD_RESULT_ERROR; commandState = PINCH_VALVE_CMD_IDLE_STATE; break; default: clearPinchValveFpgaCommand(); commandResult = PINCH_VALVE_CMD_RESULT_ERROR; commandState = PINCH_VALVE_CMD_IDLE_STATE; functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; activeFunction = PINCH_VALVE_FUNCTION_NONE; break; } } /*********************************************************************//** * @brief * The homePinchValve function starts the common homing command sequence. * @note homingCommands[] is shared by H1 and H19. Only the FPGA register set * changes according to the selected valve. * @details \b Inputs: * @details \b Outputs: * @param valve H1_VALV or H19_VALV. * @return TRUE if accepted, FALSE otherwise. *************************************************************************/ BOOL homePinchValve( VALVE_T valve ) { BOOL result = FALSE; if ( ( TRUE == isValidPinchValve( valve ) ) && ( FALSE == isPinchValveBusy() ) ) { pendingValveHomeRequest[ valve ] = TRUE; // activeValve = valve; // activeFunction = PINCH_VALVE_FUNCTION_HOME; // activeCommandArray = homingCommands; // commandResult = PINCH_VALVE_CMD_RESULT_BUSY; // functionState = PINCH_VALVE_FUNCTION_SEND_STATE; result = TRUE; } return result; } /*********************************************************************//** * @brief * The setPinchValvePosition function starts a raw position command sequence. * //TODO: Need too fix the code f * @details \b Inputs: * @details \b Outputs: * @param valve H1_VALV or H19_VALV. * @param position Signed destination position. * @return TRUE if accepted, FALSE otherwise. *************************************************************************/ BOOL setPinchValvePosition( VALVE_T valve, S32 position ) { BOOL result = FALSE; if ( ( TRUE == isValidPinchValve( valve ) ) && ( FALSE == isPinchValveBusy() ) ) { setSigned32CommandWords( &positionCommands[ PINCH_VALVE_POSITION_CMD_SET_POSITION ], position ); activeValve = valve; activeFunction = PINCH_VALVE_FUNCTION_SET_POSITION; activeCommandArray = positionCommands; activeCommandCount = (U08)NUM_OF_PINCH_VALVE_POSITION_COMMANDS; activeCommandIndex = 0; commandResult = PINCH_VALVE_CMD_RESULT_BUSY; functionState = PINCH_VALVE_FUNCTION_SEND_STATE; result = TRUE; } return result; } /*********************************************************************//** * @brief * The getPinchValvePosition function returns the latest actual position. * @details \b Inputs: currentValvePosition * @details \b Outputs: none * @param valve H1_VALV or H19_VALV. * @return Latest signed position, or 0 for an invalid valve. *************************************************************************/ S32 getPinchValvePosition( VALVE_T valve ) { S32 result = 0; if ( TRUE == isValidPinchValve( valve ) ) { result = currentValvePosition[ valve ]; } return result; } /*********************************************************************//** * @brief * The setPinchValveEnableReset function sets the enable and reset * register for the selected valve. * @details \b Inputs: valve, enable, reset * @details \b Outputs: FPGA enable/reset register, enableResetValue[] * @param valve H1_VALV or H19_VALV. * @param enable TRUE to enable the controller. * @param reset TRUE to assert the reset bit. * @return none *************************************************************************/ void setPinchValveEnableReset( VALVE_T valve, BOOL enable, BOOL reset ) { U08 value = 0; if ( TRUE == enable ) { value |= PINCH_VALVE_ENABLE_BIT_MASK; } if ( TRUE == reset ) { value |= PINCH_VALVE_RESET_BIT_MASK; } if ( H1_VALV == valve ) { enableResetValue[ H1_VALV ] = value; setH1EnableReset( value ); } else if ( H19_VALV == valve ) { enableResetValue[ H19_VALV ] = value; setH19EnableReset( value ); } else { // TODO: Check with Sean and update later (Invalid valve. The caller can verify the valve before calling) } } /*********************************************************************//** * @brief * The getPinchValveEnableReset function returns the last enable/reset value * written for the selected valve. * @details \b Inputs: enableResetValue[] * @details \b Outputs: none * @param valve H1_VALV or H19_VALV. * @return Last enable/reset value, or 0 for an invalid valve. *************************************************************************/ U08 getPinchValveEnableReset( VALVE_T valve ) { U08 result = 0; if ( TRUE == isValidPinchValve( valve ) ) { result = enableResetValue[ valve ]; } return result; } /*********************************************************************//** * @brief * The isPinchValveBusy function indicates whether a command is active. * @details \b Inputs: functionState, commandState * @details \b Outputs: none * @return TRUE if the driver is busy, FALSE otherwise. *************************************************************************/ BOOL isPinchValveBusy( void ) { return ( ( PINCH_VALVE_FUNCTION_IDLE_STATE != functionState ) || ( PINCH_VALVE_CMD_IDLE_STATE != commandState ) ); } /*********************************************************************//** * @brief * The execPinchValveFunction function executes the IDLE, SEND, and * WAIT state machine. * @details \b Inputs: functionState, commandState * @details \b Outputs: functionState, commandState, commandResult * @return none *************************************************************************/ void execPinchValveFunction( void ) { VALVE_T valve; for ( valve = (VALVE_T)0; valve < NUM_OF_VALVES; valve++ ) { switch ( functionState[ valve ] ) { case PINCH_VALVE_FUNCTION_IDLE_STATE: if ( TRUE == pendingValveHomeRequest[ valve ] ) { activeCommandCount = (U08)NUM_OF_PINCH_VALVE_HOMING_COMMANDS; activeCommandIndex = 0; activeCommandArray = &homingCommands[0]; functinState[ valve ] = PINCH_VALVE_FUNCTION_SEND_STATE; } break; case PINCH_VALVE_FUNCTION_SEND_STATE: if ( ( activeCommandArray != 0 ) && ( activeCommandIndex < activeCommandCount ) && ( TRUE == setPinchValveCommand( valve, &activeCommandArray[ activeCommandIndex ] ) ) ) { functionState = PINCH_VALVE_FUNCTION_WAIT_STATE; } else { commandResult = PINCH_VALVE_CMD_RESULT_ERROR; functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; //activeFunction = PINCH_VALVE_FUNCTION_NONE; } break; case PINCH_VALVE_FUNCTION_WAIT_STATE: //PINCH_VALVE_CMD_RESULT_T cmdResult = getPinchValveCommandResult(); //if ( PINCH_VALVE_CMD_RESULT_COMPLETE == cmdResult ) if ( IDLE_STATE == commandState[ valve ] ) { if ( ++activeCommandIndex >= NUM_OF_>>>>> ) { functionState[ valve ] = PINCH_VALVE_FUNCTION_IDLE_STATE; } else { functionState[ valve ] = PINCH_VALVE_FUNCTION_SEND_STATE; } // BOOL repeatCommand = FALSE; // // if ( TRUE == isPinchValveCommandCompleted( &repeatCommand ) ) // { // if ( TRUE == repeatCommand ) // { // commandResult = PINCH_VALVE_CMD_RESULT_BUSY; // functionState = PINCH_VALVE_FUNCTION_SEND_STATE; // } // else // { // activeCommandIndex++; // // if ( activeCommandIndex >= activeCommandCount ) // { // commandResult = PINCH_VALVE_CMD_RESULT_COMPLETE; // functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; // activeFunction = PINCH_VALVE_FUNCTION_NONE; // } // else // { // commandResult = PINCH_VALVE_CMD_RESULT_BUSY; // functionState = PINCH_VALVE_FUNCTION_SEND_STATE; // } // } // } // else // { // commandResult = PINCH_VALVE_CMD_RESULT_ERROR; // functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; // activeFunction = PINCH_VALVE_FUNCTION_NONE; // } // } // else if ( PINCH_VALVE_CMD_RESULT_ERROR == cmdResult ) // { // functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; // activeFunction = PINCH_VALVE_FUNCTION_NONE; // } break; default: // TODO - s/w fault // commandResult = PINCH_VALVE_CMD_RESULT_ERROR; // functionState = PINCH_VALVE_FUNCTION_IDLE_STATE; // activeFunction = PINCH_VALVE_FUNCTION_NONE; break; } } } /*********************************************************************//** * @brief * The getPinchValveCommandResult function returns the low-level result. * @details \b Inputs: commandResult * @details \b Outputs: none * @return Latest command result. *************************************************************************/ static PINCH_VALVE_CMD_RESULT_T getPinchValveCommandResult( void ) { return commandResult; } /*********************************************************************//** * @brief * The getPinchValveResponse function returns the last response for a valve. * @details \b Inputs: lastResponse[] * @details \b Outputs: response * @param valve H1_VALV or H19_VALV. * @param response Destination for the response data. * @return TRUE if the response was returned, FALSE otherwise. *************************************************************************/ BOOL getPinchValveResponse( VALVE_T valve, PINCH_VALVE_RESPONSE_T *response ) { BOOL result = FALSE; if ( ( TRUE == isValidPinchValve( valve ) ) && ( response != 0 ) ) { *response = lastResponse[ valve ]; result = TRUE; } return result; } /*********************************************************************//** * @brief * The setPinchValveCommand function requests execution * @details \b Inputs: valve, command * @details \b Outputs: pendingCommand, functionState, commandResult * @param valve H1_VALV or H19_VALV. * @return TRUE if the request was accepted, FALSE otherwise. *************************************************************************/ BOOL setPinchValveCommand( VALVE_T valve, const PINCH_VALVE_COMMAND_T *command ) { BOOL result = FALSE; if ( ( TRUE == isValidPinchValve( valve ) ) && ( TRUE == isValidPinchValveCommand( command ) ) && ( PINCH_VALVE_FUNCTION_IDLE_STATE == functionState ) && ( PINCH_VALVE_CMD_IDLE_STATE == commandState ) ) { activeValve = valve; pendingCommand = *command; commandResult = PINCH_VALVE_CMD_RESULT_BUSY; functionState = PINCH_VALVE_FUNCTION_SEND_STATE; result = TRUE; } return result; } /*********************************************************************//** * @brief * The isPinchValveCommandCompleted function handles returned PMD data. * @details \b Inputs: activeFunction, activeCommandIndex, lastResponse * @details \b Outputs: currentValvePosition, repeatCommand * @param repeatCommand Set TRUE when the current status command shall repeat. * @return TRUE if the response is valid, FALSE if an error occurred. *************************************************************************/ static BOOL isPinchValveCommandCompleted( BOOL *repeatCommand ) { BOOL result = TRUE; PINCH_VALVE_RESPONSE_T response; if ( repeatCommand == 0 ) { result = FALSE; } else { *repeatCommand = FALSE; if ( FALSE == getPinchValveResponse( activeValve, &response ) ) { result = FALSE; } else if ( PINCH_VALVE_FUNCTION_HOME == activeFunction ) { if ( PINCH_VALVE_HOME_CMD_GET_ACTIVITY_STATUS == activeCommandIndex ) { U16 required = PINCH_VALVE_ACTIVITY_PHASE_INITIALIZED_MASK | PINCH_VALVE_ACTIVITY_AXIS_SETTLED_MASK; if ( required != ( response.outputWord1 & required ) ) { *repeatCommand = TRUE; } } else if ( ( PINCH_VALVE_HOME_CMD_GET_EVENT_STATUS_B == activeCommandIndex ) || ( PINCH_VALVE_HOME_CMD_GET_EVENT_STATUS_C == activeCommandIndex ) ) { if ( 0 == ( response.outputWord1 & ( PINCH_VALVE_EVENT_MOTION_COMPLETE_MASK | PINCH_VALVE_EVENT_MOTION_ERROR_MASK ) ) ) { *repeatCommand = TRUE; } } else if ( PINCH_VALVE_HOME_CMD_GET_ACTUAL_POSITION_C == activeCommandIndex ) { currentValvePosition[ activeValve ] = getSigned32ResponseValue( &response ); } } else if ( PINCH_VALVE_FUNCTION_SET_POSITION == activeFunction ) { if ( PINCH_VALVE_POSITION_CMD_GET_ACTIVITY_STATUS == activeCommandIndex ) { U16 required = PINCH_VALVE_ACTIVITY_PHASE_INITIALIZED_MASK | PINCH_VALVE_ACTIVITY_AXIS_SETTLED_MASK; if ( required != ( response.outputWord1 & required ) ) { *repeatCommand = TRUE; } } else if ( PINCH_VALVE_POSITION_CMD_GET_EVENT_STATUS_BEFORE == activeCommandIndex ) { if ( 0 != ( response.outputWord1 & PINCH_VALVE_EVENT_MOTION_ERROR_MASK ) ) { result = FALSE; } } else if ( PINCH_VALVE_POSITION_CMD_GET_EVENT_STATUS_AFTER == activeCommandIndex ) { if ( 0 != ( response.outputWord1 & PINCH_VALVE_EVENT_MOTION_ERROR_MASK ) ) { result = FALSE; } else if ( 0 == ( response.outputWord1 & PINCH_VALVE_EVENT_MOTION_COMPLETE_MASK ) ) { *repeatCommand = TRUE; } } else if ( PINCH_VALVE_POSITION_CMD_GET_ACTUAL_POSITION == activeCommandIndex ) { currentValvePosition[ activeValve ] = getSigned32ResponseValue( &response ); } } else { result = FALSE; } } return result; } /*********************************************************************//** * @brief * The writePinchValveCommandRegisters function writes the command header and * input words through the FpgaTD interface. * @details \b Inputs: activeValve, activeCommand * @details \b Outputs: FPGA command header and input registers * @return none *************************************************************************/ static void writePinchValveCommandRegisters( void ) { if ( H1_VALV == activeValve ) { setH1CmdHeader( activeCommand.cmdHeader ); setH1InputWord1( activeCommand.inputWord1 ); setH1InputWord2( activeCommand.inputWord2 ); setH1InputWord3( activeCommand.inputWord3 ); } else if ( H19_VALV == activeValve ) { setH19CmdHeader( activeCommand.cmdHeader ); setH19InputWord1( activeCommand.inputWord1 ); setH19InputWord2( activeCommand.inputWord2 ); setH19InputWord3( activeCommand.inputWord3 ); } else { commandState = PINCH_VALVE_CMD_ERROR_STATE; } } /*********************************************************************//** * @brief * The transmitPinchValveCommand function builds and writes the FPGA command * byte. * @details \b Inputs: activeValve, activeCommand * @details \b Outputs: FPGA command register * @return TRUE if the command byte was valid and written. *************************************************************************/ static BOOL transmitPinchValveCommand( void ) { BOOL result = FALSE; U08 fpgaCommand; if ( TRUE == setPinchValveFpgaCommandByte( &activeCommand, &fpgaCommand ) ) { if ( H1_VALV == activeValve ) { setH1FPGACmd( fpgaCommand ); result = TRUE; } else if ( H19_VALV == activeValve ) { setH19FPGACmd( fpgaCommand ); result = TRUE; } else { //TODO: Check with Sean and remove later } } return result; } /*********************************************************************//** * @brief * The readPinchValveCommandResponse function reads the active valve response * through the FpgaTD interface. * @details \b Inputs: activeValve, FPGA response registers * @details \b Outputs: currentResponse * @return none *************************************************************************/ static void readPinchValveCommandResponse( void ) { if ( H1_VALV == activeValve ) { currentResponse.spiCmdStatus = getH1SPICmdStatus(); currentResponse.readCount = getH1ReadCount(); currentResponse.errorCount = getH1ErrorCount(); currentResponse.outputWord1 = getH1OutputWord1(); currentResponse.outputWord2 = getH1OutputWord2(); currentResponse.outputWord3 = getH1OutputWord3(); } else if ( H19_VALV == activeValve ) { currentResponse.spiCmdStatus = getH19SPICmdStatus(); currentResponse.readCount = getH19ReadCount(); currentResponse.errorCount = getH19ErrorCount(); currentResponse.outputWord1 = getH19OutputWord1(); currentResponse.outputWord2 = getH19OutputWord2(); currentResponse.outputWord3 = getH19OutputWord3(); } else { clearPinchValveResponse( ¤tResponse ); } } /*********************************************************************//** * @brief * The clearPinchValveFpgaCommand function clears the active valve FPGA command * register. * @details \b Inputs: activeValve * @details \b Outputs: FPGA command register * @return none *************************************************************************/ static void clearPinchValveFpgaCommand( void ) { if ( H1_VALV == activeValve ) { setH1FPGACmd( 0 ); } else if ( H19_VALV == activeValve ) { setH19FPGACmd( 0 ); } } /*********************************************************************//** * @brief * The setPinchValveFpgaCommandBytePinchValveFpgaCommandByte function builds the FPGA command byte. * @details The transmit count includes the command header, so one is added to * the number of input words. * @details \b Inputs: command * @details \b Outputs: fpgaCommand * @param command Pinch valve command request. * @param fpgaCommand Destination for the built FPGA command byte. * @return TRUE if the word counts are valid. *************************************************************************/ static BOOL setPinchValveFpgaCommandByte( const PINCH_VALVE_COMMAND_T *command, U08 *fpgaCommand ) { BOOL result = FALSE; if ( ( command != 0 ) && ( fpgaCommand != 0 ) ) { U08 transmitWordCount = (U08)( command->inputWordCount + 1 ); if ( ( command->inputWordCount <= PINCH_VALVE_MAX_INPUT_WORDS ) && ( command->outputWordCount <= PINCH_VALVE_MAX_OUTPUT_WORDS ) && ( transmitWordCount <= PINCH_VALVE_MAX_TRANSMIT_WORDS ) ) { *fpgaCommand = PINCH_VALVE_FPGA_CMD_START_BIT_MASK; if ( TRUE == command->writeOnly ) { *fpgaCommand |= PINCH_VALVE_FPGA_CMD_WRITE_ONLY_BIT_MASK; } *fpgaCommand |= (U08)( ( transmitWordCount & PINCH_VALVE_FPGA_CMD_WORD_COUNT_MASK ) << PINCH_VALVE_FPGA_CMD_TX_COUNT_SHIFT ); *fpgaCommand |= (U08)( ( command->outputWordCount & PINCH_VALVE_FPGA_CMD_WORD_COUNT_MASK ) << PINCH_VALVE_FPGA_CMD_RX_COUNT_SHIFT ); result = TRUE; } } return result; } /*********************************************************************//** * @brief * The isPinchValveCommandDone function checks the SPI command-done bit. * @details \b Inputs: currentResponse * @details \b Outputs: none * @return TRUE if the FPGA transaction is complete. *************************************************************************/ static BOOL isPinchValveCommandDone( void ) { return ( ( currentResponse.spiCmdStatus & PINCH_VALVE_SPI_DONE_BIT_MASK ) != 0 ); } /*********************************************************************//** * @brief * The isPinchValveControllerFaultActive function checks the controller fault * status bit. * @details \b Inputs: currentResponse * @details \b Outputs: none * @return TRUE if the controller fault bit is active. *************************************************************************/ static BOOL isPinchValveControllerFaultActive( void ) { return ( ( currentResponse.spiCmdStatus & PINCH_VALVE_SPI_CONTROLLER_FAULT_BIT_MASK ) != 0 ); } /*********************************************************************//** * @brief * The didPinchValveErrorCountChange function checks whether the active * transaction incremented the invalid-command counter. * @details \b Inputs: errorCountAtCommandStart, currentResponse.errorCount * @details \b Outputs: none * @return TRUE if the error count changed. *************************************************************************/ static BOOL didPinchValveErrorCountChange( void ) { return ( currentResponse.errorCount != errorCountAtCommandStart ); } /*********************************************************************//** * @brief * The arePinchValveWordCountsValid function verifies the FPGA-reported * transmitted and received word counts. * @details \b Inputs: currentResponse.spiCmdStatus, activeCommand * @details \b Outputs: none * @return TRUE if reported counts match the command. *************************************************************************/ static BOOL arePinchValveWordCountsValid( void ) { U08 expectedTransmitCount = (U08)( activeCommand.inputWordCount + 1 ); U08 transmittedCount = (U08)( ( currentResponse.spiCmdStatus & PINCH_VALVE_SPI_TX_COUNT_MASK ) >> PINCH_VALVE_SPI_TX_COUNT_SHIFT ); U08 receivedCount = (U08)( ( currentResponse.spiCmdStatus & PINCH_VALVE_SPI_RX_COUNT_MASK ) >> PINCH_VALVE_SPI_RX_COUNT_SHIFT ); return ( ( transmittedCount == expectedTransmitCount ) && ( receivedCount == activeCommand.outputWordCount ) ); } /*********************************************************************//** * @brief * The readPinchValveErrorCount function returns the current error count for * the selected valve. * @details \b Inputs: FPGA response registers * @details \b Outputs: none * @param valve H1_VALV or H19_VALV. * @return Current error count, or 0 for an invalid valve. *************************************************************************/ static U08 readPinchValveErrorCount( VALVE_T valve ) { U08 result = 0; if ( H1_VALV == valve ) { result = getH1ErrorCount(); } else if ( H19_VALV == valve ) { result = getH19ErrorCount(); } else { // TODO: Check with Sean and Remove later ( Invalid valve ) } return result; } /*********************************************************************//** * @brief * The isValidPinchValve function validates a valve ID. * @details \b Inputs: valve * @details \b Outputs: none * @param valve Valve to validate. * @return TRUE if the valve is H1 or H19. *************************************************************************/ static BOOL isValidPinchValve( VALVE_T valve ) { return ( ( H1_VALV == valve ) || ( H19_VALV == valve ) ); } /*********************************************************************//** * @brief * The isValidPinchValveCommand function validates a generic command request. * @details \b Inputs: command * @details \b Outputs: none * @param command Command to validate. * @return TRUE if the request is valid. *************************************************************************/ static BOOL isValidPinchValveCommand( const PINCH_VALVE_COMMAND_T *command ) { BOOL result = FALSE; if ( command != 0 ) { if ( ( command->inputWordCount <= PINCH_VALVE_MAX_INPUT_WORDS ) && ( command->outputWordCount <= PINCH_VALVE_MAX_OUTPUT_WORDS ) ) { result = TRUE; } } return result; } /*********************************************************************//** * @brief * The clearPinchValveResponse function clears a response structure. * @details \b Inputs: response * @details \b Outputs: response * @param response Response structure to clear. * @return none *************************************************************************/ static void clearPinchValveResponse( PINCH_VALVE_RESPONSE_T *response ) { if ( response != 0 ) { response->outputWord1 = 0; response->outputWord2 = 0; response->outputWord3 = 0; response->spiCmdStatus = 0; response->readCount = 0; response->errorCount = 0; } } /*********************************************************************//** * @brief * The setSigned32CommandWords function stores a signed 32-bit value. * @details \b Inputs: value * @details \b Outputs: * @param command Command to update. * @return none *************************************************************************/ static void setSigned32CommandWords( PINCH_VALVE_COMMAND_T *command, S32 value ) { if ( command != 0 ) { U32 rawValue = (U32)value; command->inputWord1 = (U16)( ( rawValue >> 16 ) & 0xFFFF ); command->inputWord2 = (U16)( rawValue & 0xFFFFU ); } } /*********************************************************************//** * @brief * The getSigned32ResponseValue function combines two PMD output words. * @details \b Inputs: response * @details \b Outputs: none * @param response PMD response. * @return Signed 32-bit value. *************************************************************************/ static S32 getSigned32ResponseValue( const PINCH_VALVE_RESPONSE_T *response ) { S32 result = 0; if ( response != 0 ) { U32 rawValue = ( (U32)response->outputWord1 << 16 ) | (U32)response->outputWord2; result = (S32)rawValue; } return result; } /**@}*/