/************************************************************************** * * Copyright (c) 2024-2025 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 Nash * @date (last) 18-Apr-2025 * * @author (original) Sean Nash * @date (original) 24-Oct-2024 * ***************************************************************************/ #include "AlarmMgmtTD.h" #include "CpldInterface.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_TRANSITION_MIN_TGT_DELTA 10 ///< Minimum encoder position delta from target position to end transition state. #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. #define VALVE_TRANSITION_TIMEOUT_MS 3000U ///< Valves transition time out in ms #define VALVE_FORCE_HOME TRUE ///< Force valve to home even if already homed /// 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=H1, 1=H19) 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=H1, 1=H19) 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 homeValve function requests a valve homing operation on 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 that is set to be homed * @param force flag indicating whether homing should be forced even if already homed * @param cartridge flag indicating whether a cartridge may be present requiring a more lax homing * @return TRUE if the homing command accepted otherwise, FALSE *************************************************************************/ BOOL homeValve( VALVE_T valve, BOOL force, BOOL cartridge ) { BOOL result = FALSE; if ( valve < NUM_OF_VALVES ) { VALVE_STATE_T currState = currentValveStates[ valve ].controlState; if ( ( VALVE_STATE_HOMING_NOT_STARTED == currState ) || ( VALVE_STATE_IDLE == currState ) ) { // If haven't already homed the valves, home the valves if ( ( currentValveStates[ valve ].hasValveBeenHomed != TRUE ) || ( VALVE_FORCE_HOME == force ) ) { currentValveStates[ valve ].hasHomingBeenRequested = TRUE; } // Otherwise, go to position A (home position) else { setValvePosition( valve, VALVE_POSITION_A_INSERT_EJECT ); } result = TRUE; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_VALVES_INVALID_VALVE8, (U32)valve ) } return result; } /*********************************************************************//** * @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 ].pendingCommandedPosition = position; currentValveStates[ valve ].hasTransitionBeenRequested = TRUE; 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; // get latest valve readings from FPGA readValves(); for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) { // update valve encoder positions currentValveStates[ valve ].priorEncPosition = currentValveStates[ valve ].currentEncPosition; currentValveStates[ valve ].currentEncPosition = getValveEncoderPosition( valve ); // execute valve state machine 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; SET_ALARM_WITH_2_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: currentValveStates[] * @details \b Outputs: currentValveStates[], cmd to FPGA * @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 ) { currentValveStates[ valve ].hasTransitionBeenRequested = FALSE; if ( currentValveStates[ valve ].currentPosition != currentValveStates[ valve ].pendingCommandedPosition ) { S16 curPos = currentValveStates[ valve ].currentEncPosition; S16 tgtPos = currentValveStates[ valve ].positionsABC[ currentValveStates[ valve ].pendingCommandedPosition ]; S16 mag = tgtPos - curPos; // calculate magnitude of position change MOTOR_DIR_T dir = ( mag < 0 ? MOTOR_DIR_REVERSE : MOTOR_DIR_FORWARD ); // determine direction of position change // set commanded position and transition start time stamp currentValveStates[ valve ].commandedPosition = currentValveStates[ valve ].pendingCommandedPosition; currentValveStates[ valve ].transitionStartTime = getMSTimerCount(); // command FPGA to move valve to commanded position setValveCmdChangePosition( valve, (U16)( abs(mag) ), dir ); // go on to transition state nextState = VALVE_STATE_IN_TRANSITION; } } } 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: currentValveStates[] * @details \b Outputs: currentValveStates[] * @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 ) { S16 curPos = currentValveStates[ valve ].currentEncPosition; S16 tgtPos = currentValveStates[ valve ].positionsABC[ currentValveStates[ valve ].commandedPosition ]; S16 delta = tgtPos - curPos; // have we completed the transition? if ( abs( delta ) < VALVE_TRANSITION_MIN_TGT_DELTA ) { currentValveStates[ valve ].currentPosition = currentValveStates[ valve ].commandedPosition; nextState = VALVE_STATE_IDLE; } // is transition taking too long? else if ( ( TRUE == didTimeout( currentValveStates[ valve ].transitionStartTime, VALVE_TRANSITION_TIMEOUT_MS ) ) && ( getCPLDACPowerLossDetected() != TRUE ) ) { // Go back to Idle state and set the valve position to not in position because it was not able to get to the target position currentValveStates[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; nextState = VALVE_STATE_IDLE; SET_ALARM_WITH_1_U32_DATA( ALARM_ID_TD_VALVE_TRANSITION_TIMEOUT, (U32)valve ); // If the valve's commanded position is C, activate safety shutdown if ( VALVE_POSITION_C_CLOSE == currentValveStates[ valve ].commandedPosition ) { activateSafetyShutdown(); } } } 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 valves 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() ) { // Verify payload length is valid if ( sizeof( VALVE_PINCH_SET_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { 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() ) { // Verify payload length is valid if ( sizeof( VALVE_PINCH_HOME_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) { 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; } /**@}*/