Index: firmware/App/Controllers/Valves.c =================================================================== diff -u -rb824ef4b479578c5aa702abd9147aef505a6fb04 -r153784735cd268c81765544a581e36d76067d344 --- firmware/App/Controllers/Valves.c (.../Valves.c) (revision b824ef4b479578c5aa702abd9147aef505a6fb04) +++ firmware/App/Controllers/Valves.c (.../Valves.c) (revision 153784735cd268c81765544a581e36d76067d344) @@ -43,7 +43,9 @@ #define VALVE_FORCE_HOME TRUE ///< Force valve to home even if already homed. #define ZERO_ENC_DEBOUNCE_THRESHOLD_CNT 5 ///< Valves zero encoder debounce threshold count. #define ZERO_ENC_DEBOUNCE_TIMEOUT_MS ( 0.25 * MS_PER_SECOND ) ///< Valves zero encoder debounce timeout in milliseconds. -#define POS_D_PARTIAL_CLOSE_FROM_ZERO_CNT 32 ///< Position D partial close from zero position in counts. +#define VALVE_OFFEST_FROM_EDG_CNT 296 ///< Valves offset from the edge. +#define POS_C_FROM_ZERO_CNT VALVE_OFFEST_FROM_EDG_CNT ///< Position C from zero position in counts. +#define POS_D_PARTIAL_CLOSE_FROM_ZERO_CNT ( POS_C_FROM_ZERO_CNT + 32 ) ///< Position D partial close from zero position in counts. /// Valve controller states typedef enum Valve_Control_States @@ -54,21 +56,12 @@ VALVE_STATE_ENABLE_VALVE, ///< Valve state enable valve. 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 homing status -typedef enum Valve_Homing_Status -{ - VALVE_HOMING_INIT = 0, ///< Valve homing init. - VALVE_HOMING_FORWARD, ///< Valve homing forward. - VALVE_HOMING_REVERSE, ///< Valve homing reverse. - VALVE_HOMING_COMPLETE, ///< Valve homing complete. - NUM_OF_VALVE_HOMING_STATE, ///< Number of valve homing. -} VALVE_HOMING_STATUS_T; - /// Valve status structure typedef struct { @@ -86,10 +79,9 @@ // Homing variables BOOL hasHomingBeenRequested; ///< Valve homing request flag. BOOL hasValveBeenHomed; ///< Valve homing completed flag. - BOOL hasHomingFailed; ///< Valve homing failed flag - S16 proposedEnergizedPos; ///< Valve homing proposed energized position. BOOL hasValveBeenReset; ///< Valve homing has valve been reset. - VALVE_HOMING_STATUS_T valveHomingStatus; ///< Valve homing status. + S16 currentMaxEncPositionCnt; ///< Valve homing current maximum encoder position counts. + S16 previousMaxEncPositionCnt; ///< Valve homing previous maximum encoder position counts. } VALVE_STATUS_T; /// Payload record structure for pinch valve set position request @@ -123,9 +115,12 @@ static VALVE_STATE_T handleValvesEnableValve( 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 checkValveInRange( VALVE_T valve, SW_FAULT_ID_T SWFault ); +static BOOL hasEdgeBeenReached( VALVE_T valve ); +static S16 convertCountToDivision8( S16 count ); static void publishValvesData( void ); /*********************************************************************//** @@ -272,9 +267,12 @@ for ( valve = FIRST_VALVE; valve < NUM_OF_VALVES; valve++ ) { - // update valve encoder positions - currentValveStates[ valve ].priorEncPosition = currentValveStates[ valve ].currentEncPosition; - currentValveStates[ valve ].currentEncPosition = getValveEncoderPosition( valve ); + // Update valve encoder positions + currentValveStates[ valve ].priorEncPosition = currentValveStates[ valve ].currentEncPosition; + currentValveStates[ valve ].currentEncPosition = getValveEncoderPosition( valve ); + // Update valve max encoder positions + currentValveStates[ valve ].previousMaxEncPositionCnt = currentValveStates[ valve ].currentMaxEncPositionCnt; + currentValveStates[ valve ].currentMaxEncPositionCnt = getValveMaximumEncoderPosition( valve ); // execute valve state machine switch ( currentValveStates[ valve ].controlState ) @@ -303,6 +301,10 @@ 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; @@ -322,6 +324,31 @@ /*********************************************************************//** * @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 handleValvesWait4PostState function handles the Wait for POST state * of the state machine for a given valve. * @details \b Inputs: current operating mode @@ -411,16 +438,12 @@ if ( valveEncPosistion >= ZERO_ENC_DEBOUNCE_THRESHOLD_CNT ) { - // Keep reseting the debouce timer until the encoder count is less than the encoder count is less than the number + // Keep reseting the debounce timer until the encoder count is less than the encoder count is less than the number currentValveStates[ valve ].valveOpsStartTime = getMSTimerCount(); } else if ( TRUE == didTimeout( currentValveStates[ valve ].valveOpsStartTime, ZERO_ENC_DEBOUNCE_TIMEOUT_MS ) ) { - // Position C is hard coded as count 8. - // Position D is hard coded as an offset form 0. - currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] = ROTARY_VALVE_MICROSTEP_FRACTION; - currentValveStates[ valve ].positionsABC[ VALVE_POSITION_D_PARTIAL_CLOSE ] = POS_D_PARTIAL_CLOSE_FROM_ZERO_CNT; - nextState = VALVE_STATE_HOMING_NOT_STARTED; + nextState = VALVE_STATE_HOMING_NOT_STARTED; } return nextState; @@ -443,52 +466,27 @@ if ( TRUE == currentValveStates[ valve ].hasHomingBeenRequested ) { - currentValveStates[ valve ].proposedEnergizedPos = ROTARY_VALVE_INIT_FULL_SWING_COUNTS; + // Getting ready for homing enable the homing bit upon transitioning to homing not started + setValveHomingEnableDisable( valve, TRUE ); - //switch ( currentValveStates[ valve ].valveHomingStatus ) - //{ - // case VALVE_HOMING_INIT: - // currentValveStates[ valve ].proposedEnergizedPos = 1880; //ROTARY_VALVE_INIT_FULL_SWING_COUNTS; - // break; - // - // case VALVE_HOMING_FORWARD: - // currentValveStates[ valve ].proposedEnergizedPos += ROTARY_VALVE_MICROSTEP_FRACTION; - // break; - // - // case VALVE_HOMING_REVERSE: - // currentValveStates[ valve ].proposedEnergizedPos -= ROTARY_VALVE_MICROSTEP_FRACTION; - // break; - // - // default: - // // Do nothing as complete has nothing to do - // break; - //} + // TODO figure out the new valve homing failure alarm + // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_VALVE_HOMING_FAILED, (U32)valve, (U32)currentValveStates[ valve ].proposedEnergizedPos ) - if ( ( currentValveStates[ valve ].proposedEnergizedPos <= ROTARY_VALVE_ENERGIZED_EDGE_MIN_COUNTS ) || - ( currentValveStates[ valve ].proposedEnergizedPos >= ROTARY_VALVE_ENERGIZED_EDGE_MAX_COUNTS ) ) - { - currentValveStates[ valve ].hasHomingFailed = TRUE; - currentValveStates[ valve ].hasHomingBeenRequested = FALSE; - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_VALVE_HOMING_FAILED, (U32)valve, (U32)currentValveStates[ valve ].proposedEnergizedPos ) - } - else - { - // Command valve to move to energized edge (end of travel) - currentValveStates[ valve ].valveOpsStartTime = 0; - currentValveStates[ valve ].hasValveBeenHomed = FALSE; - currentValveStates[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; - nextState = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; - setValveCmdChangePosition( valve, (U16)currentValveStates[ valve ].proposedEnergizedPos, MOTOR_DIR_FORWARD ); - } + // Command valve to move to energized edge (end of travel) + currentValveStates[ valve ].valveOpsStartTime = 0; + currentValveStates[ valve ].hasValveBeenHomed = FALSE; + currentValveStates[ valve ].currentPosition = VALVE_POSITION_NOT_IN_POSITION; + nextState = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; + setValveCmdChangePosition( valve, (U16)ROTARY_VALVE_INIT_ENERGIZED_COUNTS, MOTOR_DIR_FORWARD ); } return nextState; } /*********************************************************************//** * @brief - * The handleValvesFindEnergizedEdgeState function handles the Find Energized - * Edge state of the state machine for a given valve. + * The handleValvesFindEnergizedEdgeState function handles the find energized + * edge state of the state machine for a given valve. * @details \b Inputs: currentValveStates[] * @details \b Outputs: currentValveStates[] * @param valve ID of valve for which to handle the Find Energized Edge state @@ -497,71 +495,56 @@ static VALVE_STATE_T handleValvesFindEnergizedEdgeState( VALVE_T valve ) { VALVE_STATE_T nextState = VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE; - S16 curPos = currentValveStates[ valve ].currentEncPosition; checkValveInRange( valve, SW_FAULT_ID_TD_VALVES_INVALID_FIND_ENERGIZED_EDGE ); - // have we found forward edge of travel? - if ( abs( curPos - currentValveStates[ valve ].priorEncPosition ) < VALVE_HOME_MIN_POS_CHG ) + if ( TRUE == hasEdgeBeenReached( valve ) ) { - if ( 0 == currentValveStates[ valve ].valveOpsStartTime ) - { - currentValveStates[ valve ].valveOpsStartTime = getMSTimerCount(); - } - else if ( TRUE == didTimeout( currentValveStates[ valve ].valveOpsStartTime, HOMING_EDGE_DETECTION_TIMEOUT_MS ) ) - { - //if ( VALVE_HOMING_INIT == currentValveStates[ valve ].valveHomingStatus ) - //{ - // S16 tgtPos = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ]; - // S16 mag = curPos - tgtPos; // calculate magnitude of position change - // - // // Set commanded position and transition start time stamp - // // Transition back to position C to try the next energized position. It has to start from position C - // currentValveStates[ valve ].commandedPosition = VALVE_POSITION_C_CLOSE; - // currentValveStates[ valve ].valveOpsStartTime = getMSTimerCount(); - // currentValveStates[ valve ].valveHomingStatus = VALVE_HOMING_FORWARD; - // nextState = VALVE_STATE_IN_TRANSITION; - // // Command FPGA to move valve to commanded position - // setValveCmdChangePosition( valve, (U16)(mag), MOTOR_DIR_REVERSE ); - //} - //else - { - S16 posC = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ]; - S16 posA = posC + ( ( curPos - posC ) / 2 ); + nextState = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; + } - // If position A was calculated to not be a division of 8 it is rounded down to be a division of 8 - posA = ( posA % ROTARY_VALVE_MICROSTEP_FRACTION ) < 4 ? ( posA >> 3 ) << 3 : posA; + return nextState; +} - currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ] = curPos; - currentValveStates[ valve ].positionsABC[ VALVE_POSITION_A_INSERT_EJECT ] = posA; - currentValveStates[ valve ].hasValveBeenHomed = TRUE; - currentValveStates[ valve ].currentPosition = VALVE_POSITION_B_OPEN; - currentValveStates[ valve ].pendingCommandedPosition = VALVE_POSITION_A_INSERT_EJECT; - currentValveStates[ valve ].valveHomingStatus = VALVE_HOMING_COMPLETE; - currentValveStates[ valve ].hasTransitionBeenRequested = TRUE; - currentValveStates[ valve ].hasHomingBeenRequested = FALSE; - nextState = VALVE_STATE_IDLE; - } - } - } - else if ( curPos <= 0 ) - { - switch ( currentValveStates[ valve ].valveHomingStatus ) - { - case VALVE_HOMING_INIT: - case VALVE_HOMING_FORWARD: - currentValveStates[ valve ].valveHomingStatus = VALVE_HOMING_REVERSE; - break; +/*********************************************************************//** + * @brief + * The handleValvesFindDeenergizedEdgeState function handles the find Deenergized + * edge state of the state machine for a given valve. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: currentValveStates[] + * @param valve ID of valve for which to handle the find deenergized edge state + * @return next state of the state machine for the given valve + *************************************************************************/ +static VALVE_STATE_T handleValvesFindDeenergizedEdgeState( VALVE_T valve ) +{ + VALVE_STATE_T nextState = VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE; + S16 posB = 0; + S16 posC = 0; + S16 posA = 0; - default: - // If init or forward modes, then reverse again. - break; - } + checkValveInRange( valve, SW_FAULT_ID_TD_VALVES_INVALID_FIND_DEENERGIZED_EDGE ); - currentValveStates[ valve ].hasValveBeenReset = FALSE; - nextState = VALVE_STATE_RESET_VALVE; - } + // Done with homing disable the homing bit + setValveHomingEnableDisable( valve, FALSE ); + // TODO in the future this needs to be searched + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] = VALVE_OFFEST_FROM_EDG_CNT; + // TODO in the future this needs to be searched + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_D_PARTIAL_CLOSE ] = POS_D_PARTIAL_CLOSE_FROM_ZERO_CNT; + + posB = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ]; + posC = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ]; + posA = posC + ( ( posB - posC ) / 2 ); + posA = convertCountToDivision8( posA ); + + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_A_INSERT_EJECT ] = posA; + currentValveStates[ valve ].hasValveBeenHomed = TRUE; + currentValveStates[ valve ].currentPosition = VALVE_POSITION_B_OPEN; + currentValveStates[ valve ].pendingCommandedPosition = VALVE_POSITION_A_INSERT_EJECT; + currentValveStates[ valve ].hasTransitionBeenRequested = TRUE; + currentValveStates[ valve ].hasHomingBeenRequested = FALSE; + nextState = VALVE_STATE_IDLE; + return nextState; } @@ -583,26 +566,10 @@ // handle a home request if ( TRUE == currentValveStates[ valve ].hasHomingBeenRequested ) { - if ( VALVE_HOMING_COMPLETE == currentValveStates[ valve ].valveHomingStatus ) - { - S16 tgtPos = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ]; - S16 mag = currentValveStates[ valve ].currentEncPosition - tgtPos; // calculate magnitude of position change - - // Set commanded position and transition start time stamp - // Transition back to position C to try the next energized position. It has to start from position C - currentValveStates[ valve ].commandedPosition = VALVE_POSITION_C_CLOSE; - currentValveStates[ valve ].valveOpsStartTime = getMSTimerCount(); - currentValveStates[ valve ].valveHomingStatus = VALVE_HOMING_INIT; - currentValveStates[ valve ].hasValveBeenReset = FALSE; - nextState = VALVE_STATE_IN_TRANSITION; - // Command FPGA to move valve to commanded position - setValveCmdChangePosition( valve, (U16)(mag), MOTOR_DIR_REVERSE ); - } - else if ( VALVE_HOMING_INIT == currentValveStates[ valve ].valveHomingStatus ) - { - currentValveStates[ valve ].hasValveBeenReset = FALSE; - nextState = VALVE_STATE_HOMING_NOT_STARTED; - } + // Homing has been requested, enable the homing bit. + setValveHomingEnableDisable( valve, TRUE ); + // Transition to enable homing to set the encode to 0. + nextState = VALVE_STATE_ENABLE_VALVE; } // handle a position change request else if ( TRUE == currentValveStates[ valve ].hasTransitionBeenRequested ) @@ -650,7 +617,7 @@ if ( abs( delta ) < VALVE_TRANSITION_MIN_TGT_DELTA ) { currentValveStates[ valve ].currentPosition = currentValveStates[ valve ].commandedPosition; - nextState = ( VALVE_HOMING_COMPLETE != currentValveStates[ valve ].valveHomingStatus ? VALVE_STATE_HOMING_NOT_STARTED : VALVE_STATE_IDLE ); + nextState = VALVE_STATE_IDLE; } // is transition taking too long? else if ( ( TRUE == didTimeout( currentValveStates[ valve ].valveOpsStartTime, VALVE_TRANSITION_TIMEOUT_MS ) ) && @@ -673,46 +640,87 @@ /*********************************************************************//** * @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) + * The checkValveInRange function checks whether the selected valve is in range + * and if not it will trigger the provided software fault. + * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param valve the valve check whether it is in range + * @param SWFault the provided software fault to trigger + * @return none *************************************************************************/ -SELF_TEST_STATUS_T execValvesSelfTest( void ) +static void checkValveInRange( VALVE_T valve, SW_FAULT_ID_T SWFault ) { - 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 ( valve >= NUM_OF_VALVES ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, (U32)SWFault, (U32)valve ) + } +} - if ( TRUE == calStatus ) +/*********************************************************************//** + * @brief + * The hasEdgeBeenReached function checks whether the valve has reached to + * its edge or not. + * @details \b Inputs: currentValveStates[] + * @details \b Outputs: currentValveStates[] + * @param valve ID of valve for which to check its edge + * @return TRUE if the edge has been reached otherwise, FALSE + *************************************************************************/ +static BOOL hasEdgeBeenReached( VALVE_T valve ) +{ + BOOL status = FALSE; + S16 previousMaxEnc = currentValveStates[ valve ].previousMaxEncPositionCnt; + S16 currentMaxEnc = currentValveStates[ valve ].currentMaxEncPositionCnt; + + checkValveInRange( valve, SW_FAULT_ID_VALVES_INVALID_VALVE_FINDING_EDGE ); + + if ( abs( currentMaxEnc - previousMaxEnc ) < VALVE_HOME_MIN_POS_CHG ) { - valvesSelfTestResult = SELF_TEST_STATUS_PASSED; + if ( 0 == currentValveStates[ valve ].valveOpsStartTime ) + { + currentValveStates[ valve ].valveOpsStartTime = getMSTimerCount(); + } + else if ( TRUE == didTimeout( currentValveStates[ valve ].valveOpsStartTime, HOMING_EDGE_DETECTION_TIMEOUT_MS ) ) + { + status = TRUE; + currentMaxEnc = convertCountToDivision8( currentMaxEnc ); + currentMaxEnc -= VALVE_OFFEST_FROM_EDG_CNT; + + currentValveStates[ valve ].valveOpsStartTime = 0; + + if ( VALVE_STATE_HOMING_FIND_ENERGIZED_EDGE == currentValveStates[ valve ].controlState ) + { + currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ] = currentMaxEnc; + } + // TODO uncomment the deenergized edge + //else if ( VALVE_STATE_HOMING_FIND_DEENERGIZED_EDGE == currentValveStates[ valve ].controlStat ) + //{ + // currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ] = currentMaxEnc + //} + } } else { - valvesSelfTestResult = SELF_TEST_STATUS_FAILED; + currentValveStates[ valve ].valveOpsStartTime = 0; } - return valvesSelfTestResult; + return status; } /*********************************************************************//** * @brief - * The checkValveInRange function checks whether the selected valve is in range - * and if not it will trigger the provided software fault. - * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT if given valve is invalid. + * The convertCountToDivision8 function converts the provided data to be in + * division of 8. * @details \b Inputs: none * @details \b Outputs: none - * @param valve the valve check whether it is in range - * @param SWFault the provided software fault to trigger - * @return none + * @param count the value to be converted to the division of 8 + * @return the converted value *************************************************************************/ -static void checkValveInRange( VALVE_T valve, SW_FAULT_ID_T SWFault ) +static S16 convertCountToDivision8( S16 count ) { - if ( valve >= NUM_OF_VALVES ) - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, (U32)SWFault, (U32)valve ) - } + S16 convCount = ( count >> 3 ) << 3; + + return convCount; } /*********************************************************************//** @@ -743,6 +751,7 @@ data.posB = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_B_OPEN ]; data.posC = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_C_CLOSE ]; data.posD = currentValveStates[ valve ].positionsABC[ VALVE_POSITION_D_PARTIAL_CLOSE ]; + data.maxHomingPos = currentValveStates[ valve ].currentMaxEncPositionCnt; broadcastData( MSG_ID_TD_VALVES_DATA, COMM_BUFFER_OUT_CAN_TD_BROADCAST, (U08*)&data, sizeof( TD_VALVE_DATA_T ) ); }