/**
 * @file  hv_drv_TypecProtocolLayer.c
 * @brief   Protocol Layer Source file
 *          This header file contains the function definition of interface to configure 
 *          UPD HW to transmit and receive PD message,UPD HW Physical layer configuration, Chunking state machine
 * @details This file provides the following functions: \n
 *          (1) \n
 *          (2) \n
 *          (3) \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-25
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date         <th>Change Description
 * <tr><td>Hiview SoC Software Team       <td>2022-08-25   <td>init
 * </table>
*/


#include <hv_drv_TypecStdInc.h>
#include "hv_comm_Assert.h"

extern UINT64 uiPDTimeTick;
static HV_VOS_QUEUE_S*         pstPRLRecvQueue;
#define TYPEC_RX_QUEUE_LENGTH           5

/***************************************************************************************************/
void  PRL_Init (UINT8 u8PortNum)
{
    /* Protocol Tx PHY layer is Reset */
    PRL_ResetPHYLayer (u8PortNum);

    /* Tx configurations - TX bit rate*/
    /* Configure Tx Power up & down time */
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TX_MSG_BITRATE, (PRL_CLK_FREQ_KHZ/PRL_TX_BITRATE_KBPS - 1));        //300K

    /* configure the TX_CTL_A register Enable Auto response mode and retry on Line busy */
    
    /* Rx configurations */
    /* Set up Rx */
    /* Configuring Rx Maximum and Minimum Bit-Rate Bit Period Count Registers */
    /* Configuring CRCReceiveTimer timeout value (tReceive) in terms of 10�s of micro seconds */

    /* Configuring Value of Hard and Cable Reset detection window 
        (maximum packet bit count including preamble) in number of bits.*/

    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_IDLE_COUNTER_LEN, 0x7C);                    //about 30us

#if (HV_TYPEC_GOODCRC_SW_EN == 1)
#else
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL, (BIT(0) | BIT(2)));        //auto response goodcrc
#endif
    /*msgid reset use software config*/
    Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, (UPD_MSGID_RST_SOP_CTRL | UPD_MSGID_RST_SOPP_CTRL));
    Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, (UPD_MSGID_RST_SOP_SEL | UPD_MSGID_RST_SOPP_SEL));
    Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, (UPD_MSGID_RST_SOP_SEL | UPD_MSGID_RST_SOPP_SEL));

    //enable tx
    Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_RX_TX_MAC_CTL, UPD_RXTX_CTL_TX_CHEN);

    /* Enabling PD support */
    Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_CONFIG_HIGH, UPD_CONFIG_HIGH_PD_SUPPORT);

    /* Clear Rx Interrupt Src for HR and FIFO not empty */
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_RX_IRQFLAG, 0xFF);
#if (HV_TYPEC_GOODCRC_SW_EN == 1)
    /* Enable Rx interrupts for HR and FIFO not empty */
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_MSG_RECEIVE_MASKBIT);        //hard reset set in enable RX
#endif
    /* use tx goodcrc replace the rx msg due to auto goodcrc with hardware */
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TX_IRQMASK, UPD_TX_GCRC_FOR_RXMSG_MSKBIT);

    //TX Interrupt TX DONE and TX FAIL, no tx abort
    
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, 0xFF);        //clear
    //Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_IRQMASK, (UPD_TXFSM_SOP_TX_DONE_MASKBIT | UPD_TXFSM_SOP_TX_FAIL_MASKBIT));
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, 0xFF);        //clear
    //Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_P_IRQMASK, (UPD_TXFSM_SOP_P_TX_DONE_MASKBIT | UPD_TXFSM_SOP_P_TX_FAIL_MASKBIT));
                                        
    /* Initialize gasPRL globals*/
    gasPRL[u8PortNum].u32PkdPEstOnTxStatus = CLR_VAL;
    gasPRL[u8PortNum].pFnTxCallback = NULL;
    gasPRL[u8PortNum].u8TxStateISR = PRL_TX_IDLE_ST;
    gasPRL[u8PortNum].u16SOPLastRecvMsgHeader = 0x0000U;
    gasPRL[u8PortNum].u8SOPMsgID = RESET_TO_ZERO;
    gasPRL[u8PortNum].u8SOP_P_MsgID = RESET_TO_ZERO;
    gasPRL[u8PortNum].u8SOP_PP_MsgID = RESET_TO_ZERO;
    
    /* Rx u8RxRcvdISR & u8RxHRRcvdISR are reset*/
    gasPRL[u8PortNum].u8RxRcvdISR = HV_FALSE;
    gasPRL[u8PortNum].u8RxHRRcvdISR = HV_FALSE;
    
    /* u8TxStsDPMSyncISR is reset */
    gasPRL[u8PortNum].u8TxStsDPMSyncISR = HV_FALSE; 
    
    /* Rx Error bit is reset */
    gasPRL [u8PortNum].u8RxError = RESET_TO_ZERO;
    
    /* Reset u8SwapDataRoleISR */
#if (HV_TRUE == INCLUDE_PD_DR_SWAP)
    gasPRL [u8PortNum].u8SwapDataRoleISR = HV_FALSE; 
#endif     
    
    #if  (HV_TRUE == INCLUDE_PD_3_0)
    /* Chunk SM is reset */
    gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = MAX_CONCURRENT_TIMERS;
    PRL_ResetChunkSM (u8PortNum);
    #endif

    Hv_Vos_QUEUE_INIT_PARAMS stQueueInitParam = {0};
    stQueueInitParam.queueLen = TYPEC_RX_QUEUE_LENGTH;
    stQueueInitParam.itemSize = sizeof(PRL_RECVBUFF);
    pstPRLRecvQueue = Hv_Vos_QueueInit(&stQueueInitParam);
    HV_ASSERT_VALID_PTR_VOID(pstPRLRecvQueue);

    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL Init Done\r\n");
}

/***************************************************************************************************/
void PRL_UpdatePowerRole (UINT8 u8PortNum)
{
      //UINT16 u16RxDACValue = PRL_BB_CC_RX_DAC_CTL_CC_RX_DAC_NEU_VALUE;
    UINT8 u8CurrentPwrRole = DPM_GET_CURRENT_POWER_ROLE(u8PortNum);
    
    /* Protocol Tx PHY layer is Reset */
    PRL_ResetPHYLayer (u8PortNum);
    
    /* PD3_AUTO_DECODE is enabled so that HW decodes spec revision from received messages.*/
    /* At init, Rx SOP type is set to all SOP* type*/
    if (PD_ROLE_SOURCE == u8CurrentPwrRole)
    {      
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_RX_SOP_TYPE_SET, (UPD_RX_SOP_TYPE_SOP | UPD_RX_SOP_TYPE_SOP_P | UPD_RX_SOP_TYPE_SOP_PP));
    }
    else
    {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_RX_SOP_TYPE_SET, UPD_RX_SOP_TYPE_SOP);
    }
    
    /* Updates Device's Data & Power role, UPD Spec rev & corresponding retry counter*/
    PRL_UpdateSpecAndDeviceRoles (u8PortNum);
    
    // DEBUG_PRINT_PORT_STR (u8PortNum,"PRL Updated Power Role\r\n");
}

void PRL_UpdateSpecAndDeviceRoles (UINT8 u8PortNum)
{
    UINT8 u8RegVal = 0;
      UINT8 u8HwnRetryCount;
    
    /* HW Retry Counter is updated depending on Spec Rev */
    if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
    {
        u8HwnRetryCount = PRL_HW_RETRY_CNT_2_0;
    }
    else
    {
        u8HwnRetryCount = PRL_HW_RETRY_CNT_3_0;
    }

    //set hw retry count
    u8RegVal = Hv_Typec_RegReadByte(u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER);
    u8RegVal &= ~UPD_TX_RETRY_COUNTER_MASK;
    u8RegVal |= (u8HwnRetryCount << UPD_TX_RETRY_COUNTER_POS);
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER, u8RegVal);
    
}

/***************************************************************************************************/

UINT16 PRL_FormSOPTypeMsgHeader (UINT8 u8PortNum, UINT8 u8MessageType, UINT8 u8ObjectCount, UINT8 u8Extended)
{
    return ((u8MessageType)
           |((UINT16)(DPM_GET_CURRENT_DATA_ROLE(u8PortNum)) << PRL_PORT_DATA_ROLE_BIT_POS)
           |((UINT16)(DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum)) << PRL_SPEC_REV_FIELD_START_BIT_POS)         
           |((UINT16)(DPM_GET_CURRENT_POWER_ROLE(u8PortNum)) << PRL_PORT_POWER_ROLE_OR_CABLE_PLUG_BIT_POS)
           |((UINT16)u8ObjectCount << PRL_DATA_OBJECTS_FIELD_START_BIT_POS)                         
           |((UINT16)u8Extended << PRL_EXTENDED_BIT_POS));
}

UINT16 PRL_FormNonSOPTypeMsgHeader (UINT8 u8PortNum, UINT8 u8MessageType, UINT8 u8ObjectCount, UINT8 u8Extended)
{
    return ((u8MessageType)                                                                         |
              ((UINT16) ((DPM_GET_CURRENT_CBL_PD_SPEC_REV(u8PortNum)) << PRL_SPEC_REV_FIELD_START_BIT_POS))     |
              ((UINT16)u8ObjectCount << PRL_DATA_OBJECTS_FIELD_START_BIT_POS)                     |
            ((UINT16)u8Extended << PRL_EXTENDED_BIT_POS));
}

static void PRL_VdmHpdTimerCB (UCHAR8 ucTypecPortNum, UCHAR8 ucPESubState)
{
    HV_LOG_INFO(TYPEC, "Typec set idle task with VdmHpdTimerCB");
    HV_PSF_HOOK_TASK_PRIORITY_SET(TYPEC_IDLE_TASK_PRIORITY);
}


UINT8 PRL_TransmitGoodCRC (UINT8 u8PortNum)
{  
    UINT8 au8TxPkt [PRL_MAX_PD_LEGACY_PKT_LEN], u8TxSOPSelect = SET_TO_ZERO;
    /* PD3_Auto_Decode and RX_SOP_ENABLE_SOP are enabled by default */
    UINT8 u8RxCtlBRegVal = UPD_RX_SOP_TYPE_SOP; 

    UINT8 u8RegData[4];
    UINT8 u8SOPtype = 0;
    UINT16 u16HeaderRcvd = 0;
    UINT16 u16Header = 1; // MsgTypec is GoodCRC(1)
    UINT16 u16PowerRole = 0; // Power role
    UINT16 u16DataRole = 0; // Data role
    UINT16 u16SpecRevision = 0; // Specification Revision
    UINT16 u16MsgId = 0; // Message ID

    Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_RX_MSG_DATA_BASE, u8RegData, 2);
    u16HeaderRcvd = MAKE_UINT16(u8RegData[1], u8RegData[0]);
    u8SOPtype = Hv_Typec_RegReadByte(u8PortNum, UPD_REG_RO_RX_SOP_TYPE);

    /* SOP -----> ACK: MsgTypec + Rsvd1 + DR + SpecRev + PR + MsgID + ObjCnt + Rsvd2 */
    /* Received message type */    
    if ((PRL_GET_OBJECT_COUNT (u16HeaderRcvd) == PE_OBJECT_COUNT_0) && (PRL_GET_MESSAGE_TYPE (u16HeaderRcvd) == PE_CTRL_GOOD_CRC))
    {
        DEBUG_PRINT_PORT_STR (u8SOPtype,"Received Msg is GoodCRC\r\n");
        return 0;
    }

    u16SpecRevision = ((u16HeaderRcvd & PRL_SPEC_REV_FIELD_MASK) >> PRL_SPEC_REV_FIELD_START_BIT_POS);
    if (u16SpecRevision == 3)
    {
        u16SpecRevision = 2;
    }

    if (PRL_SOP_TYPE == u8SOPtype)
    { 
        if ((PRL_GET_MESSAGE_TYPE (u16HeaderRcvd) == PE_DATA_SOURCE_CAP) && (PRL_GET_OBJECT_COUNT (u16HeaderRcvd) != PE_OBJECT_COUNT_0))
        {
            u16PowerRole = (~u16HeaderRcvd) & BIT(8);
            u16DataRole = (~u16HeaderRcvd) & BIT(5);
            u16MsgId = PRL_GET_MESSAGE_ID(u16HeaderRcvd);
            DEBUG_PRINT_PORT_STR (u16MsgId,"Source Caps, u16MsgId is\r\n");
        }
        else
        {
            DEBUG_PRINT_PORT_STR (u8SOPtype,"Received Msg is SOP and not source cap message\r\n");
            /* HW GoodCRC */
            Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL, (BIT(0) | BIT(2)));        //auto response goodcrc
            /* Rx interrupt Disable*/
            Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_MSG_RECEIVE_MASKBIT);
            return 0;
        }
    }
    else
    {
        u16MsgId = PRL_GET_MESSAGE_ID(u16HeaderRcvd);
        /* for SOPP or SOPPP, the power role is 0 if VIF_Product_Type is 0, date role is 0 */
        u16PowerRole = 0;
        u16DataRole = 0;
        DEBUG_PRINT_PORT_STR (u8SOPtype,"Received Msg is SOPP\r\n");
    }

    u16Header |= (u16MsgId << PRL_MESSAGE_ID_FIELD_START_BIT_POS |
                u16SpecRevision << PRL_SPEC_REV_FIELD_START_BIT_POS |
                u16PowerRole |
                u16DataRole);

    /* Clear Rx Interrupt Src for HR and FIFO not empty */
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_RX_IRQFLAG, 0xFF);

    if (PRL_SOP_P_TYPE == u8SOPtype)
    {   
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_P;
    }
    else if (PRL_SOP_PP_TYPE == u8SOPtype)
    {
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_PP;
    }

    /* Update the RX_CTL_B PD MAC register */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_RX_SOP_TYPE_SET, u8RxCtlBRegVal);

    /* Depending on the Packet type; MessageID is updated in the Pkt Header and 
        PD_MAC Reg is updated for Pkt type */
    switch (u8SOPtype)
    {
        case PRL_SOP_TYPE:
        {
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP;
            break;
        }

        case PRL_SOP_P_TYPE:
        {
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_P;
            break;              
        }

        case PRL_SOP_PP_TYPE:
        {
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_PP;
            break;
        }
          
        default:
        {
            DEBUG_PRINT_PORT_STR (u8PortNum,"Wrong SOP* type detected\r\n");
            break;
        }
    }

    /* Enable the interrupt for Tx_DONE, Tx_ABORT & Tx_FAILED */
    if (u8SOPtype == PRL_SOP_TYPE) {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }
    else {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_P_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }

    /* Load the header to the TxPKT */
    au8TxPkt[0] = LOBYTE(u16Header);
    au8TxPkt[1] = HIBYTE(u16Header);

    /* PD Packet is copied to PD_MAC HW Buffer */
    Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RW_TX_MSG_DATA_BASE, au8TxPkt, 2);    

    /* Update the Tx SOP type reg */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_SOP_TYPE_SET, (u8TxSOPSelect | UPD_TX_SOP_TYPE_FIXED_EN));

    /* Go bit is set & message sent to PHY Layer*/
    /* Spec Ref: PRL_Tx_Wait_for_PHY_response, PRL_Tx_Match_MessageID, PRL_Tx_Check_RetryCounter state is handled by UPD hardware */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(1));
    UINT32 uiCnt = 5000;
    while (uiCnt--)
    {
        asm("nop");
    }

    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(0));
    uiCnt = 10;
    while (uiCnt--)
    {
        asm("nop");
    }
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, SET_TO_ZERO);

    /* PRL state variable is set to PRL_TX_MSG_ON_LINE_ST*/
    PRL_ChangeTxState (u8PortNum, PRL_TX_MSG_ON_LINE_ST);

    // DEBUG_PRINT_PORT_STR (gasPolicyEngine[u8PortNum].ePEState, ">>>> Tx Msg sent <<<< \r\n");
    return PRL_RET_TX_MSG_TRANSMITTED_ON_LINE;
}

#define HPD_RETRY_COUNTS    1
/***************************************************************************************************/

UINT8 PRL_TransmitMsg (UINT8 u8PortNum, UINT8 u8SOPType, UINT32 u32Header, UINT8 *pu8DataBuffer, 
                       PRLTxCallback pfnTxCallback, UINT32 u32PkdPEstOnTxStatus)
{  
    UINT8 u8MsgId, u8PktLen, au8TxPkt [PRL_MAX_PD_LEGACY_PKT_LEN], u8TxSOPSelect = SET_TO_ZERO;
    /* PD3_Auto_Decode and RX_SOP_ENABLE_SOP are enabled by default */
    UINT8 u8RxCtlBRegVal = UPD_RX_SOP_TYPE_SOP; 
    UINT8 u8HwnRetryCount = SET_TO_ZERO, u8TxParamC = SET_TO_ZERO;
    PRL_RECVBUFF stPRLRecvBuff = {0};
    
    static UINT8 u8HpdRetry = HPD_RETRY_COUNTS;

    // if((pu8DataBuffer != NULL) && (((UINT32)pu8DataBuffer)%4 == 0))
    // {
    //     if(*((UINT32 *)pu8DataBuffer) == 0xFF01A106)
    //     {
    //         if(*((UINT32 *)(pu8DataBuffer+4)) == 0x0000008A)
    //         {
    //             Hv_Vos_Delayus(5000);
    //         }
    //     }
    // }
            
    #if (HV_TRUE == INCLUDE_PD_3_0)
    UINT16 u16MsgDataIndex;
    
    /* Checks whether the message is extended PD packet & chunk state machine is enabled*/
    if ((!gasChunkSM [u8PortNum].u8EnableChunkSM) && (PRL_IS_EXTENDED_MSG(u32Header)))
    {
          /* Spec Ref: TCH_Prepare_To_Send_Chunked_Message - "Chunk Number To Send = 0" */
      
          /* Extended message is copied to global buffer & Chunk SM is enabled*/
      
          /* Copying SOP type*/
          gasExtendedMsgBuff [u8PortNum].u8SOPtype = u8SOPType;
        
        /* Message Header is stored */
        gasExtendedMsgBuff [u8PortNum].u16Header = PRL_GET_MSG_HEADER(u32Header);
        
        /* ChunkNumber is set to zero*/
        gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent = RESET_TO_ZERO;
        
        /* PE will specify the data size alone. Other Extended Message Header fields are populated by PRL.
        Request Chunk bit is set as 0 indicating Response chunk.
        Chunked bit is enabled as unchunked extended messages is not supported in UPD.
        Response Chunk Extended Message header is formed using 
        PRL_FORM_RESPONSE_CHUNK_EXT_MSG_HEADER with chunk Number & Data Size parameter and it is stored.
        */
        gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader = PRL_FORM_RESPONSE_CHUNK_EXT_MSG_HEADER (
                                                                    gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent,
                                                                     PRL_GET_DATA_SIZE (PRL_GET_EXTENDED_MSG_HEADER(u32Header))
                                                                       );
        
        /* if pu8DataBuffer is not NULL*/
        if (pu8DataBuffer != NULL)
        {
            /* copying message data*/
            for (u16MsgDataIndex = SET_TO_ZERO; 
                    u16MsgDataIndex <= PRL_GET_DATA_SIZE(gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader); 
                        u16MsgDataIndex++)
            {                
                gasExtendedMsgBuff [u8PortNum].u8Data [u16MsgDataIndex] =  pu8DataBuffer [u16MsgDataIndex];
            }
        }
        
        
        /* Copying Callback*/
        gasChunkSM [u8PortNum].u32pkdTmrID_TxSt = u32PkdPEstOnTxStatus;
        gasChunkSM [u8PortNum].pFnTxCallback = pfnTxCallback;
        
        /* Total Chunk packet to be sent is updated*/
        PRL_UpdateTotalChunkNumVar (u8PortNum);
        
        /* Assigning Chunk state to PRL_TCH_SEND_RESPONSE_CHUNK_ST */
        gasChunkSM [u8PortNum].u8ChunkState    = PRL_TCH_SEND_RESPONSE_CHUNK_ST;                                                
        
          /* Chunk state machine is enabled*/
        gasChunkSM [u8PortNum].u8EnableChunkSM = HV_TRUE;
        DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM Enabled\r\n");
        
        return PRL_RET_TX_MSG_CHUNKING_ENABLED;
    }
    
    #endif
    
    /* update the PDMAC globals */
    gasPRL[u8PortNum].u32PkdPEstOnTxStatus = u32PkdPEstOnTxStatus;
    gasPRL[u8PortNum].pFnTxCallback = pfnTxCallback;

    
#if (HV_TYPEC_GOODCRC_SW_EN == 1)
    /* HW GoodCRC*/
    if (PRL_SOP_TYPE == u8SOPType)
    {
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL, (BIT(0) | BIT(2)));
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_MSG_RECEIVE_MASKBIT);
    }
#endif

    /* Enable RX_SOP_ENABLE_SOP_P and RX_SOP_ENABLE_SOP_PP based on the type of 
       packet transmitted */
    if (PRL_SOP_P_TYPE == u8SOPType)
    {   
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_P;
    }
    else if (PRL_SOP_PP_TYPE == u8SOPType)
    {
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_PP;
    }
    else 
    {
        /* Do Nothing */
    }
    /* Update the RX_CTL_B PD MAC register */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_RX_SOP_TYPE_SET, u8RxCtlBRegVal);
    
    /* Set the Hardware retry count as 0 for VDMs */
    if (PE_DATA_VENDOR_DEFINED != PRL_GET_MESSAGE_TYPE(u32Header))
    {
        if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
        {
            u8HwnRetryCount = PRL_HW_RETRY_CNT_2_0;
        }
        else
        {
            u8HwnRetryCount = PRL_HW_RETRY_CNT_3_0;
        }
    }
    u8TxParamC = Hv_Typec_RegReadByte (u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER); 
    
    u8TxParamC &= ~UPD_TX_RETRY_COUNTER_MASK;
    u8TxParamC |= (u8HwnRetryCount << UPD_TX_RETRY_COUNTER_POS);
    
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER, u8TxParamC); 
    
    /* Depending on the Packet type; MessageID is updated in the Pkt Header and 
        PD_MAC Reg is updated for Pkt type */
    switch (u8SOPType)
    {
        case PRL_SOP_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOPMsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP;
            break;
        }

        case PRL_SOP_P_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOP_P_MsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_P;
            break;              
        }

        case PRL_SOP_PP_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOP_PP_MsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_PP;
            break;
        }
          
        default:
        {
            u8MsgId = SET_TO_ZERO;
            DEBUG_PRINT_PORT_STR (u8PortNum,"Wrong SOP* type detected\r\n");
            break;
        }
    }

    /* MessageID is updated to header */
    u32Header |= (u8MsgId << PRL_MESSAGE_ID_FIELD_START_BIT_POS);
    
    /* Spec Ref: PRL_Tx_Construct_Message - Construct message
                                    Pass message to PHY Layer*/
    /* PD message is constructed */
    u8PktLen = PRL_BuildTxPacket (u8PortNum, u32Header, pu8DataBuffer, au8TxPkt);  

    /* Enable the interrupt for Tx_DONE, Tx_ABORT & Tx_FAILED */
    if (u8SOPType == PRL_SOP_TYPE) {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }
    else {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_P_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }
    
    /* PD Packet is copied to PD_MAC HW Buffer */
    Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RW_TX_MSG_DATA_BASE, au8TxPkt, u8PktLen);    
    
    /* Update the Tx SOP type reg */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_SOP_TYPE_SET, (u8TxSOPSelect | UPD_TX_SOP_TYPE_FIXED_EN));
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    /* Tx Buffering on CA*/
    if (PRL_Tx_CA_SRC_SINKTXTIMER_ON_ST == gasPRL [u8PortNum].u8TxStateISR)
    {      
        /* if Timer SinkTxTimer is ON, Tx Message is just buffered in Tx_FIFO by not setting Go bit*/
        PRL_ChangeTxState (u8PortNum, PRL_TX_MSG_BUFFERED_ON_CA_ST);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Tx Msg Buffered due to CA\r\n");
        
        return PRL_RET_TX_MSG_BUFFERED;
    }
    #endif
    
    /* Tx_Discard handling*/
    if (Hv_Vos_QueueTimedRecv(pstPRLRecvQueue, (VOID*)&stPRLRecvBuff, 0))
    {
        gasPRL[u8PortNum].u8RxRcvdISR = HV_TRUE;
        gasPRLRecvBuff [u8PortNum].u16Header = stPRLRecvBuff.u16Header;
        HV_PSF_HOOK_MEMCPY(gasPRLRecvBuff[u8PortNum].u8DataObj, stPRLRecvBuff.u8DataObj, PRL_MAX_DATA_OBJ_SIZE);
        gasPRLRecvBuff [u8PortNum].u8SOPtype = stPRLRecvBuff.u8SOPtype;
    }
    else
    {
        gasPRL[u8PortNum].u8RxRcvdISR = HV_FALSE;
    }

    if (((gasPRL[u8PortNum].u8RxRcvdISR) &&                            /* Checks whether a message is received */
            (PRL_SOP_TYPE == gasPRLRecvBuff[u8PortNum].u8SOPtype))     /* Checks whether received message is PRL_SOP_TYPE type*/
            || (DPM_IS_FRS_SIG_XMT_OR_RCV_DONE(u8PortNum))) /* Checks whether FRS signal is transmitted or received */
    {
        // re enqueue pstPRLRecvQueue
        Hv_Vos_QueueSendFromISR(pstPRLRecvQueue, &stPRLRecvBuff);

          /* Spec Ref: Protocol Layer Message transmission Shall enter the PRL_Tx_Discard_Message state whenever:
                -> Protocol Layer Message reception receives an incoming Message or
                -> The Fast Role Swap signal is being transmitted (see Section 5.8.5.6)
                -> The Fast Role Swap signal is detected (see Section 5.8.6.3). */
         
        
          /* According to Message Discarding Rules, if SOP packet is received. Tx Packet in queue is discarded*/
          /* And Message ID Counter is incremented*/
          PRL_IncrementMsgID (u8PortNum);                
        
        /* Spec Ref: PRL_Tx_PHY_Layer_Reset - Resets Tx PHY Layer
                        Entered on condition "discarding Complete" */
        PRL_ResetPHYLayer (u8PortNum);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Tx Msg Discarded\r\n");
        
        return PRL_RET_TX_MSG_DISCARD_ON_RCV;
    }    

    /* Go bit is set & message sent to PHY Layer*/
    /* Spec Ref: PRL_Tx_Wait_for_PHY_response, PRL_Tx_Match_MessageID, PRL_Tx_Check_RetryCounter state is handled by UPD hardware */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(1));
    UINT32 uiCnt = 5000;
    while (uiCnt--)
    {
        asm("nop");
    }

    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(0));
    uiCnt = 10;
    while (uiCnt--)
    {
        asm("nop");
    }
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, SET_TO_ZERO);
    
    /* PRL state variable is set to PRL_TX_MSG_ON_LINE_ST*/
    PRL_ChangeTxState (u8PortNum, PRL_TX_MSG_ON_LINE_ST);

    if(HV_PSF_HOOK_TASK_PRIORITY_GET() != TYPEC_NORMAL_TASK_PRIORITY)
    {
        HV_PSF_HOOK_TASK_PRIORITY_SET(TYPEC_NORMAL_TASK_PRIORITY);
    }

    // DEBUG_PRINT_PORT_STR (gasPolicyEngine[u8PortNum].ePEState, ">>>> Tx Msg sent <<<< \r\n");

    if((pu8DataBuffer != NULL) && (((UINT32)pu8DataBuffer)%4 == 0) && (u8HpdRetry > 0))
    {
        if (eSVDM_ATTENTION == (eSVDMCmd) DPM_GET_VDM_CMD(*((UINT32 *)pu8DataBuffer)))
        {
            if(*((UINT32 *)(pu8DataBuffer+4)) == 0x00000018A)
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"App_AMESetDpIrqHpd end\r\n");
            }
            if(*((UINT32 *)(pu8DataBuffer+4)) == 0x0000008A)
            {
                if(--u8HpdRetry == 0)
                {
                    gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMHpdHighFlag = HV_FALSE;
                    // PDTimer_Start((1000), PRL_VdmHpdTimerCB, u8PortNum, (UCHAR8)ePE_INVALIDSUBSTATE);
                    u8HpdRetry = HPD_RETRY_COUNTS;

                    DEBUG_PRINT_PORT_STR (u8PortNum,"Set HPD High in tx\r\n"); 
                    HV_LOG_INFO(TYPEC, "Set HPD High in tx!");
                }
            }
        }
    }

    return PRL_RET_TX_MSG_TRANSMITTED_ON_LINE;
}


UINT8 PRL_TransmitUrgentMsg (UINT8 u8PortNum, UINT8 u8SOPType, UINT32 u32Header, UINT8 *pu8DataBuffer, 
                       PRLTxCallback pfnTxCallback, UINT32 u32PkdPEstOnTxStatus)
{  
    UINT8 u8MsgId, u8PktLen, au8TxPkt [PRL_MAX_PD_LEGACY_PKT_LEN], u8TxSOPSelect = SET_TO_ZERO;
    /* PD3_Auto_Decode and RX_SOP_ENABLE_SOP are enabled by default */
    UINT8 u8RxCtlBRegVal = UPD_RX_SOP_TYPE_SOP; 
    UINT8 u8HwnRetryCount = SET_TO_ZERO, u8TxParamC = SET_TO_ZERO; 
    
    static UINT8 u8HpdRetry = HPD_RETRY_COUNTS;

    #if (HV_TRUE == INCLUDE_PD_3_0)
    UINT16 u16MsgDataIndex;
    
    /* Checks whether the message is extended PD packet & chunk state machine is enabled*/
    if ((!gasChunkSM [u8PortNum].u8EnableChunkSM) && (PRL_IS_EXTENDED_MSG(u32Header)))
    {
          /* Spec Ref: TCH_Prepare_To_Send_Chunked_Message - "Chunk Number To Send = 0" */
      
          /* Extended message is copied to global buffer & Chunk SM is enabled*/
      
          /* Copying SOP type*/
          gasExtendedMsgBuff [u8PortNum].u8SOPtype = u8SOPType;
        
        /* Message Header is stored */
        gasExtendedMsgBuff [u8PortNum].u16Header = PRL_GET_MSG_HEADER(u32Header);
        
        /* ChunkNumber is set to zero*/
        gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent = RESET_TO_ZERO;
        
        /* PE will specify the data size alone. Other Extended Message Header fields are populated by PRL.
        Request Chunk bit is set as 0 indicating Response chunk.
        Chunked bit is enabled as unchunked extended messages is not supported in UPD.
        Response Chunk Extended Message header is formed using 
        PRL_FORM_RESPONSE_CHUNK_EXT_MSG_HEADER with chunk Number & Data Size parameter and it is stored.
        */
        gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader = PRL_FORM_RESPONSE_CHUNK_EXT_MSG_HEADER (
                                                                    gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent,
                                                                     PRL_GET_DATA_SIZE (PRL_GET_EXTENDED_MSG_HEADER(u32Header))
                                                                       );
        
        /* if pu8DataBuffer is not NULL*/
        if (pu8DataBuffer != NULL)
        {
            /* copying message data*/
            for (u16MsgDataIndex = SET_TO_ZERO; 
                    u16MsgDataIndex <= PRL_GET_DATA_SIZE(gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader); 
                        u16MsgDataIndex++)
            {                
                gasExtendedMsgBuff [u8PortNum].u8Data [u16MsgDataIndex] =  pu8DataBuffer [u16MsgDataIndex];
            }
        }
        
        
        /* Copying Callback*/
        gasChunkSM [u8PortNum].u32pkdTmrID_TxSt = u32PkdPEstOnTxStatus;
        gasChunkSM [u8PortNum].pFnTxCallback = pfnTxCallback;
        
        /* Total Chunk packet to be sent is updated*/
        PRL_UpdateTotalChunkNumVar (u8PortNum);
        
        /* Assigning Chunk state to PRL_TCH_SEND_RESPONSE_CHUNK_ST */
        gasChunkSM [u8PortNum].u8ChunkState    = PRL_TCH_SEND_RESPONSE_CHUNK_ST;                                                
        
          /* Chunk state machine is enabled*/
        gasChunkSM [u8PortNum].u8EnableChunkSM = HV_TRUE;
        DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM Enabled\r\n");
        
        return PRL_RET_TX_MSG_CHUNKING_ENABLED;
    }
    
    #endif
    
    /* update the PDMAC globals */
    gasPRL[u8PortNum].u32PkdPEstOnTxStatus = u32PkdPEstOnTxStatus;
    gasPRL[u8PortNum].pFnTxCallback = pfnTxCallback;

    /* Enable RX_SOP_ENABLE_SOP_P and RX_SOP_ENABLE_SOP_PP based on the type of 
       packet transmitted */
    if (PRL_SOP_P_TYPE == u8SOPType)
    {   
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_P;
    }
    else if (PRL_SOP_PP_TYPE == u8SOPType)
    {
        u8RxCtlBRegVal |= UPD_RX_SOP_TYPE_SOP_PP;
    }
    else 
    {
        /* Do Nothing */
    }
    /* Update the RX_CTL_B PD MAC register */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_RX_SOP_TYPE_SET, u8RxCtlBRegVal);
    
    /* Set the Hardware retry count as 0 for VDMs */
    if (PE_DATA_VENDOR_DEFINED != PRL_GET_MESSAGE_TYPE(u32Header))
    {
        if (PD_SPEC_REVISION_2_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
        {
            u8HwnRetryCount = PRL_HW_RETRY_CNT_2_0;
        }
        else
        {
            u8HwnRetryCount = PRL_HW_RETRY_CNT_3_0;
        }
    }
    u8TxParamC = Hv_Typec_RegReadByte (u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER); 
    
    u8TxParamC &= ~UPD_TX_RETRY_COUNTER_MASK;
    u8TxParamC |= (u8HwnRetryCount << UPD_TX_RETRY_COUNTER_POS);
    
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_RETRY_COUNTER, u8TxParamC); 
    
    /* Depending on the Packet type; MessageID is updated in the Pkt Header and 
        PD_MAC Reg is updated for Pkt type */
    switch (u8SOPType)
    {
        case PRL_SOP_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOPMsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP;
            break;
        }

        case PRL_SOP_P_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOP_P_MsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_P;
            break;              
        }

        case PRL_SOP_PP_TYPE:
        {
            u8MsgId = gasPRL[u8PortNum].u8SOP_PP_MsgID;
            u8TxSOPSelect = UPD_RX_SOP_TYPE_SOP_PP;
            break;
        }
          
        default:
        {
            u8MsgId = SET_TO_ZERO;
            DEBUG_PRINT_PORT_STR (u8PortNum,"Wrong SOP* type detected\r\n");
            break;
        }
    }

    /* MessageID is updated to header */
    u32Header |= (u8MsgId << PRL_MESSAGE_ID_FIELD_START_BIT_POS);
    
    /* Spec Ref: PRL_Tx_Construct_Message - Construct message
                                    Pass message to PHY Layer*/
    /* PD message is constructed */
    u8PktLen = PRL_BuildTxPacket (u8PortNum, u32Header, pu8DataBuffer, au8TxPkt);  

    /* Enable the interrupt for Tx_DONE, Tx_ABORT & Tx_FAILED */
    if (u8SOPType == PRL_SOP_TYPE) {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }
    else {
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, 0xFF);        //clear
        Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_TXFSM_SOP_P_IRQMASK, (UPD_TXFSM_TX_DONE_MASKBIT | UPD_TXFSM_TX_FAIL_MASKBIT | UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT));
    }
    
    /* PD Packet is copied to PD_MAC HW Buffer */
    Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RW_TX_MSG_DATA_BASE, au8TxPkt, u8PktLen);    
    
    /* Update the Tx SOP type reg */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_SOP_TYPE_SET, (u8TxSOPSelect | UPD_TX_SOP_TYPE_FIXED_EN));
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    /* Tx Buffering on CA*/
    if (PRL_Tx_CA_SRC_SINKTXTIMER_ON_ST == gasPRL [u8PortNum].u8TxStateISR)
    {      
        /* if Timer SinkTxTimer is ON, Tx Message is just buffered in Tx_FIFO by not setting Go bit*/
        PRL_ChangeTxState (u8PortNum, PRL_TX_MSG_BUFFERED_ON_CA_ST);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Tx Msg Buffered due to CA\r\n");
        
        return PRL_RET_TX_MSG_BUFFERED;
    }
    #endif

    /* Go bit is set & message sent to PHY Layer*/
    /* Spec Ref: PRL_Tx_Wait_for_PHY_response, PRL_Tx_Match_MessageID, PRL_Tx_Check_RetryCounter state is handled by UPD hardware */
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(1));
    UINT32 uiCnt = 5000;
    while (uiCnt--)
    {
        asm("nop");
    }

    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(0));
    uiCnt = 10;
    while (uiCnt--)
    {
        asm("nop");
    }
    Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, SET_TO_ZERO);
    
    /* PRL state variable is set to PRL_TX_MSG_ON_LINE_ST*/
    PRL_ChangeTxState (u8PortNum, PRL_TX_MSG_ON_LINE_ST);

    if(HV_PSF_HOOK_TASK_PRIORITY_GET() != TYPEC_NORMAL_TASK_PRIORITY)
    {
        HV_PSF_HOOK_TASK_PRIORITY_SET(TYPEC_NORMAL_TASK_PRIORITY);
    }

    // DEBUG_PRINT_PORT_STR (gasPolicyEngine[u8PortNum].ePEState, ">>>> Tx Msg sent <<<< \r\n");

    if((pu8DataBuffer != NULL) && (((UINT32)pu8DataBuffer)%4 == 0) && (u8HpdRetry > 0))
    {
        if (eSVDM_ATTENTION == (eSVDMCmd) DPM_GET_VDM_CMD(*((UINT32 *)pu8DataBuffer)))
        {
            if(*((UINT32 *)(pu8DataBuffer+4)) == 0x0000018A)
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"App_AMESetDpIrqHpd end\r\n");
            }
            if(*((UINT32 *)(pu8DataBuffer+4)) == 0x0000008A)
            {
                if(--u8HpdRetry == 0)
                {
                    gasCfgStatusData.sVDMPerPortData[u8PortNum].u8SVDMHpdHighFlag = HV_FALSE;
                    // PDTimer_Start((1000), PRL_VdmHpdTimerCB, u8PortNum, (UCHAR8)ePE_INVALIDSUBSTATE);
                    u8HpdRetry = HPD_RETRY_COUNTS;

                    DEBUG_PRINT_PORT_STR (u8PortNum,"Set HPD High in tx\r\n"); 
                    HV_LOG_INFO(TYPEC, "Set HPD High in tx!");
                }
            }
        }
    }

    return PRL_RET_TX_MSG_TRANSMITTED_ON_LINE;
}
/***************************************************************************************************/

UINT8 PRL_BuildTxPacket (UINT8 u8PortNum, UINT32 u32Header, const UINT8 *pu8DataBuffer, UINT8 *pu8TxPkt)
{
    UINT8 u8DataIndex , u8PktIndex = SET_TO_ZERO, 
        u8DataObjSizeInBytes = (PRL_GET_OBJECT_COUNT(u32Header) * PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES);
    /* Info: while handling u8DataObjSizeinBytes for extended message, size of extended message header
                is not accounted nor the Chunk padded bytes count if any */
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    UINT8 u8ZeroPadding = SET_TO_ZERO, u8LastChunkDataObjCnt;
    UINT16 u16ExtendedMsgHeader = SET_TO_ZERO;
    
    if (PRL_IS_EXTENDED_MSG(u32Header))
    {
          /* Spec Ref: TCH_Sending_Chunked_Message - Entered on condition " Chunk Passed" */
          
        u16ExtendedMsgHeader = PRL_GET_EXTENDED_MSG_HEADER(u32Header);
        /* if Request chunk packet */
        if (PRL_IS_REQUEST_CHUNK_MSG (u16ExtendedMsgHeader))
        {
              /* Request Chunk packet has two bytes of Extended Message Header alone.
                Hence, two bytes is zero padded & no data */
            u8ZeroPadding = PRL_REQUEST_CHUNK_PADDING_BYTE_NUMBER;
            u8DataObjSizeInBytes = PRL_REQUEST_CHUNK_DATA_SIZE;
        }
        else
        {
              /* if it is not last chunk response packet, MaxExtendedMsgChunkLen is assigned */
            u8DataObjSizeInBytes = PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES;
                
              /* if it is Response Chunk packet & last chunk*/
            if (gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent == gasChunkSM [u8PortNum].u8TotalChunkPkt)
            {
                  /* if last chunk response packet is not MaxExtendedMsgChunkLen */
                if ((PRL_GET_DATA_SIZE(u16ExtendedMsgHeader) % PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES))
                {
                      /* size of last chunk packet data is calculated*/
                    u8DataObjSizeInBytes = (PRL_GET_DATA_SIZE(u16ExtendedMsgHeader) % PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES);
                    
                    /* if the data size with Extended message header size should be 4 byte aligned . 
                        Else The packet must be padded to 4 byte alignment*/
                    u8ZeroPadding = ((u8DataObjSizeInBytes + PRL_EXTN_MSG_HEADER_SIZE_IN_BYTES) % PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES);
                    
                    /* Data Object Count is calculated for last chunk packet */
                    u8LastChunkDataObjCnt = ((u8DataObjSizeInBytes + PRL_EXTN_MSG_HEADER_SIZE_IN_BYTES) / PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES);
                    
                    if (u8ZeroPadding)
                    {
                        /* if the packet is to be zero padded, number of bytes to be padded is updated
                            as well as the Data Object count for last packet is incremented*/
                        u8ZeroPadding = PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES - u8ZeroPadding;
                        u8LastChunkDataObjCnt++;
                    }
                    
                    /* Data object count for the last chunk packet is updated to the header*/
                    u32Header = PRL_FORM_COMBINED_MSG_HEADER (u16ExtendedMsgHeader,
                                  PRL_UPDATE_MSG_HEADER_DATA_OBJECT_COUNT(PRL_GET_MSG_HEADER(u32Header), u8LastChunkDataObjCnt));
                }
            }                            
        }    
    }
    
    #endif /*endif for INCLUDE_PD_3_0*/
            
    /* Load the header to the TxPKT */
    pu8TxPkt [u8PktIndex] = LOBYTE(u32Header);
    pu8TxPkt [++u8PktIndex] = HIBYTE(u32Header);
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    if (PRL_IS_EXTENDED_MSG(u32Header))
    {
        /* If extended, Extended Message header is loaded */
        pu8TxPkt [++u8PktIndex] = LOBYTE(u16ExtendedMsgHeader);
        pu8TxPkt [++u8PktIndex] = HIBYTE(u16ExtendedMsgHeader);
    }
    #endif
    
    /* if pu8DataBuffer is not NULL*/
    if (pu8DataBuffer != NULL)
    {
        /* Load the Data Object or data*/
        for (u8DataIndex = SET_TO_ZERO; u8DataIndex < u8DataObjSizeInBytes; u8DataIndex++)
        {
            pu8TxPkt [++u8PktIndex] = pu8DataBuffer [u8DataIndex];
        }
    }
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    /* zero padding in case the data byte is not 4 byte aligned*/
    while (u8ZeroPadding)
    {
        pu8TxPkt [++u8PktIndex] = PRL_ZERO_PADDING_BYTE;
        u8ZeroPadding --;
    }
    #endif
    
    /* Packet length is returned*/
    return (++u8PktIndex);
}

/***************************************************************************************************/

void PRL_SendCableorHardReset (UINT8 u8PortNum, UINT8 u8CableorHardReset, PRLTxCallback pfnTxCallback, UINT32 u32PkdPEstOnTxStatus)
{
      /* update the PDMAC globals */
    gasPRL[u8PortNum].u32PkdPEstOnTxStatus = u32PkdPEstOnTxStatus;
    gasPRL[u8PortNum].pFnTxCallback = pfnTxCallback;
        
    if (u8CableorHardReset)
    {
        /* enable Cable reset and go bit to transmit CR */
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL1, UPD_TX_CONTROL1_CABLE_HARD_RST);
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL1, UPD_TX_CONTROL1_CABLE_HARD_RST_REQ);
        
        /* Tx state variable is set to Cable Reset*/
        PRL_ChangeTxState (u8PortNum, PRL_TX_CABLE_RESET_ST);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL_TX_CABLE_RESET_SENT\r\n");        
    }
    else
    {
        /* enable Hard reset and go bit to transmit HR */
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL1, UPD_TX_CONTROL1_CABLE_HARD_RST);
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL1, UPD_TX_CONTROL1_CABLE_HARD_RST_REQ);
        
        /* Tx state variable is set to Hard Reset*/
        PRL_ChangeTxState (u8PortNum, PRL_TX_HARD_RESET_ST);

        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL_TX_HARD_RESET_SENT\r\n");
    }    
}

/******************************************************************************************************/

void PRL_EnableRx (UINT8 u8PortNum, UINT8 u8Enable)
{
    if (u8Enable)
    {
          /* Enable the PD_MAC Receiver */
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_RX_TX_MAC_CTL, UPD_RXTX_CTL_RX_CHEN);
        /* Enable reception of Hardreset*/
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RO_RX_IRQFLAG, UPD_RX_HARD_RST_MASKBIT);
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_HARD_RST_MASKBIT);
        /* Enable channel busy */
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RO_RX_IRQFLAG, UPD_RX_CHANNEL_BUSY_MASKBIT);
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_CHANNEL_BUSY_MASKBIT);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Receiver enabled\r\n");
    }
    else
    {
          /* PD_MAC Receiver is disabled */
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_RX_TX_MAC_CTL, UPD_RXTX_CTL_RX_CHEN);
        /* Disable reception of Hardreset*/
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_HARD_RST_MASKBIT);
        /* Disable channel busy */
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_RX_IRQMASK, UPD_RX_CHANNEL_BUSY_MASKBIT);
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Receiver disabled\r\n");
    }
}

/*******************************************************************************************************/

UINT8 PRL_ReceiveMsg (UINT8 u8PortNum, UINT8 *pu8SOPType, UINT32 *pu32Header, UINT8 *pu8DataBuffer, PRLRxCallback pfnRxCallback)
{
    UINT16 u16DataSize, u8Return;
 
    u8Return = PRL_ProcessRcvdMsg(u8PortNum);
    
    if ((PRL_RET_NO_MSG_RCVD == u8Return) && (!gasPRL [u8PortNum].u8RxError) && (!gasPRL [u8PortNum].u8RxHRRcvdISR))
    {
        /* No Message is received. Return PRL_RET_NO_MSG_RCVD */
        return PRL_RET_NO_MSG_RCVD;
    }
    
    if (u8Return & PRL_RET_MSG_RCVD)
    {
          /* Non - Extended message is returned here */
        /* RxPacket is copied from global buffer */
        
        *pu8SOPType = gasPRLRecvBuff[u8PortNum].u8SOPtype;
        *pu32Header = gasPRLRecvBuff[u8PortNum].u16Header;
        
        /* if pu8DataBuffer is not NULL*/
        if (pu8DataBuffer != NULL)
        {
              /* data from global buffer is copied to local buffer */
            for (u16DataSize = SET_TO_ZERO; 
                 u16DataSize < (PRL_GET_OBJECT_COUNT(gasPRLRecvBuff[u8PortNum].u16Header) * PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES); 
                 u16DataSize++)
            {
                pu8DataBuffer [u16DataSize] = gasPRLRecvBuff[u8PortNum].u8DataObj[u16DataSize];
            }
        }
    }
    
    #if (HV_TRUE == INCLUDE_PD_3_0)
    else if (u8Return & PRL_RET_EXT_MSG_RCVD)
    {
        /* Extended message is received */
        *pu8SOPType = gasExtendedMsgBuff [u8PortNum].u8SOPtype;
        *pu32Header = PRL_FORM_COMBINED_MSG_HEADER (gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader, 
                                                    gasExtendedMsgBuff [u8PortNum].u16Header);
        /* if pu8DataBuffer is not NULL*/
        if (pu8DataBuffer != NULL)
        {
              /* data from global buffer is copied to local buffer */
            for (u16DataSize = SET_TO_ZERO;    \
                 u16DataSize < (PRL_GET_DATA_SIZE(gasExtendedMsgBuff[u8PortNum].u16ExtendedMsgHeader));    \
                 u16DataSize++)
            {
                pu8DataBuffer [u16DataSize] = gasExtendedMsgBuff[u8PortNum].u8Data[u16DataSize];
            }
        }
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Extd Msg rcvd passed to PE\r\n");
        
    }
    /*Note: gasPRL [u8PortNum].u8RxError is used only for PRL_RX_CHUNK_RCV_ERROR*/
    else if (gasPRL [u8PortNum].u8RxError)
    {
          /* Chunk State Error*/
        u8Return = PRL_RET_RCV_CHUNK_ERROR;
        /* RxIntrStatus is cleared*/
        gasPRL [u8PortNum].u8RxError &= ~PRL_RX_CHUNK_RCV_ERROR;
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Rx Chunk Error \r\n");
    }
    #endif
    else
    {
       /* Hard Reset Process pending*/
        u8Return = PRL_RET_HARD_RESET_RCVD; 
    }
    
    /* if pfnRxCallback is not NULL, pfnRxCallback is called */
    if (pfnRxCallback != NULL)
    {
        pfnRxCallback(u8PortNum, u8Return);
    }
    
    return u8Return;    
}

/*******************************************************************************************************/

void PRL_HandleISR (UINT8 u8PortNum)
{  
    UINT8 u8TxSOPType;
    UINT8 u8RxIrqStat = SET_TO_ZERO;
    UINT8 u8RxIrqStat2 = SET_TO_ZERO;
    UINT8 u8TxIrqStat = SET_TO_ZERO;
    
    UINT32 u32PkdPEstOnTxStatus;
    
    /*Read the overall Mac Interrupt */
    Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_RX_IRQFLAG, &u8RxIrqStat, BYTE_LEN_1);
    Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_TX_IRQFLAG, &u8RxIrqStat2, BYTE_LEN_1);
#if (HV_TYPEC_GOODCRC_SW_EN == 1)
    // 这个地方是用来软件对Rx Msg中SOPP类型的Msg回复ACK用
    if (UPD_RX_MSG_RECEIVE_MASKBIT & u8RxIrqStat)
    {
        if (PRL_TransmitGoodCRC(u8PortNum) == PRL_RET_TX_MSG_TRANSMITTED_ON_LINE)
        {
            DEBUG_PRINT_PORT_STR(u8RxIrqStat<<16 | u8RxIrqStat2, "SOPP u8RxIrqStat u8RxIrqStat2\r\n")
            // Hv_Typec_RegisterWriteISR(u8PortNum, UPD_REG_RO_TX_IRQFLAG, &u8RxIrqStat2, BYTE_LEN_1);
            return;
        }

        Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RO_RX_IRQFLAG, &u8RxIrqStat, BYTE_LEN_1);
    }

    if (UPD_RX_HARD_RST_MASKBIT & u8RxIrqStat)
    {
        Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RO_RX_IRQFLAG, &u8RxIrqStat, BYTE_LEN_1);
        /*Enable the HR flag*/
        gasPRL [u8PortNum].u8RxHRRcvdISR = HV_TRUE;
        /*Enable PD message processing by FW*/
        gasPRL[u8PortNum].u8RxDisable = HV_FALSE;
        /*Setting the Hard reset received flag*/
        gasPolicyEngine[u8PortNum].u8HardResetRcvdISR = HV_TRUE;
        DEBUG_PRINT_PORT_STR(u8PortNum, "Hard reset is set by HW\r\n")
        return;
    }
#endif

    u8TxSOPType = (UPD_TX_SOP_TYPE_MASK & (Hv_Typec_RegReadByte (u8PortNum, UPD_REG_RW_TX_SOP_TYPE_SET)));

    //DEBUG_PRINT_PORT_STR(u8RxIrqStat, "PRL_HandleISR -> u8RxIrqStat\n");
    //DEBUG_PRINT_PORT_STR(u8RxIrqStat2, "PRL_HandleISR -> u8RxIrqStat2\n");
    //DEBUG_PRINT_PORT_STR(u8TxSOPType, "PRL_HandleISR -> u8TxSOPType\n");
    
    if (u8TxSOPType == UPD_TX_SOP_TYPE_SOP) {
        Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, &u8TxIrqStat, BYTE_LEN_1);
    }
    else {
        Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, &u8TxIrqStat, BYTE_LEN_1);
    }

    //DEBUG_PRINT_PORT_STR(u8TxIrqStat, "PRL_HandleISR -> u8TxIrqStat\n");
    
    /* Tx MAC interrupt Handling */
    if (u8TxIrqStat)
    {
          /* Read Tx interrupt */
        
        /* Clear the Tx interrupt Status Register */
        if (u8TxSOPType == UPD_TX_SOP_TYPE_SOP) {
            Hv_Typec_RegisterWriteISR(u8PortNum, UPD_REG_RO_TXFSM_SOP_IRQFLAG, &u8TxIrqStat, BYTE_LEN_1);
        }
        else {
            Hv_Typec_RegisterWriteISR(u8PortNum, UPD_REG_RO_TXFSM_SOP_P_IRQFLAG, &u8TxIrqStat, BYTE_LEN_1);
        }

        /* Update the PD_MAC state */
        if (UPD_TXFSM_TX_DONE_MASKBIT & u8TxIrqStat)
        {
            gasPRL [u8PortNum].u8TxStateISR = PRL_TX_DONE_ST;
            
            gasPRL[u8PortNum].u8TxStsDPMSyncISR = HV_FALSE;   
        }

        if (UPD_TXFSM_NOGCRC_TIME_OUT_MASKBIT & u8TxIrqStat)
        {
            gasPRL [u8PortNum].u8TxStateISR = PRL_TX_ABORTED_ST;
            
            gasPRL[u8PortNum].u8TxStsDPMSyncISR = HV_FALSE;  
            
            gasPRL[u8PortNum].u8SOPMsgID = RESET_TO_ZERO;

        }

        /* PD_MAC state variable is updated depending Tx interrupt received */
        if (UPD_TXFSM_TX_FAIL_MASKBIT & u8TxIrqStat)
        {
            gasPRL [u8PortNum].u8TxStateISR = PRL_TX_FAILED_ST;
            
            gasPRL[u8PortNum].u8TxStsDPMSyncISR = HV_FALSE;  
        }
        /* Spec Ref: PRL_Tx_Message_Sent & PRL_Tx_Transmission_Error - Increment the MessageIDCounter.
                                                            Inform Policy Engine message sent */
        /* Increment the MessageID based on SOP* Type */
        if (gasPRL [u8PortNum].u8TxStateISR != PRL_TX_EOP_ST && gasPRL [u8PortNum].u8TxStateISR != PRL_TX_ABORTED_ST)
        {
            PRL_IncrementMsgID (u8PortNum);
        }
        
        /* Tx callback is called */
        if (gasPRL [u8PortNum].pFnTxCallback != NULL)
        {
              u32PkdPEstOnTxStatus = gasPRL[u8PortNum].u32PkdPEstOnTxStatus;
            gasPRL [u8PortNum].pFnTxCallback(u8PortNum, 
                                                LOBYTE(u32PkdPEstOnTxStatus),             /* u8TxDonePEst */
                                                HIBYTE(u32PkdPEstOnTxStatus),            /* u8TxDonePESubst*/                                 
                                                LOBYTE(HIWORD(u32PkdPEstOnTxStatus)),    /* u8TxFailedPEst */
                                                HIBYTE(HIWORD(u32PkdPEstOnTxStatus)));    /* u8TxFailedPESubst */
        }
        
        /* Txstate is set back to idle after callback*/
        gasPRL [u8PortNum].u8TxStateISR =  PRL_TX_IDLE_ST;
    }

#if (HV_TYPEC_GOODCRC_SW_EN == 1)
    if (u8RxIrqStat2)
    {
        /* update the PDMAC variable depending on Rx interrupt received */
        if (UPD_TX_GCRC_FOR_RXMSG_MSKBIT & u8RxIrqStat2)
        {
            /* Enable SW GoodCRC */
            // Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL, (BIT(0) | BIT(2)));
            DEBUG_PRINT_PORT_STR(u8RxIrqStat2, "Tx GoodCRC Intr Done\r\n");
            /* Received message is processed */
            PRL_ProcessRxFIFOISR (u8PortNum);
        }

        Hv_Typec_RegisterWriteISR(u8PortNum, UPD_REG_RO_TX_IRQFLAG, &u8RxIrqStat2, BYTE_LEN_1);
    }
#else
    if (u8RxIrqStat|u8RxIrqStat2)
    {
        /* Read Rx interrupt */                
        /* Clear the Rx interrupt status register */
        Hv_Typec_RegisterWriteISR (u8PortNum, UPD_REG_RO_RX_IRQFLAG, &u8RxIrqStat, BYTE_LEN_1);
        Hv_Typec_RegisterWriteISR(u8PortNum, UPD_REG_RO_TX_IRQFLAG, &u8RxIrqStat2, BYTE_LEN_1);

        /* update the PDMAC variable depending on Rx interrupt received */
        if (UPD_TX_GCRC_FOR_RXMSG_MSKBIT & u8RxIrqStat2)
        {
            /* Received message is processed */
            PRL_ProcessRxFIFOISR (u8PortNum);            
        }
        
        if (UPD_RX_HARD_RST_MASKBIT & u8RxIrqStat)
        {
            /*Enable the HR flag*/
            gasPRL [u8PortNum].u8RxHRRcvdISR = HV_TRUE;
            /*Enable PD message processing by FW*/
            gasPRL[u8PortNum].u8RxDisable = HV_FALSE;
            /*Setting the Hard reset received flag*/
            gasPolicyEngine[u8PortNum].u8HardResetRcvdISR = HV_TRUE;
            DEBUG_PRINT_PORT_STR(u8PortNum, "Hard reset is set by HW\r\n");
        }
    }
#endif
}

/******************************************************************************************************/

void PRL_IncrementMsgID (UINT8 u8PortNum)
{
      /* Read the Tx SOP type */
    UINT8 u8TxSOPType = (UPD_TX_SOP_TYPE_MASK & (Hv_Typec_RegReadByte (u8PortNum, UPD_REG_RW_TX_SOP_TYPE_SET)));
    
    /* Depending on the SOP* type, MessageID for that SOP* Type is incremented */ 
    switch (u8TxSOPType)
    {
        case UPD_TX_SOP_TYPE_SOP:
        {
            gasPRL[u8PortNum].u8SOPMsgID = PRL_INCREMENT_MSG_ID(gasPRL[u8PortNum].u8SOPMsgID);
            break;
         }
              
        case UPD_TX_SOP_TYPE_SOP_P:
        {
            gasPRL[u8PortNum].u8SOP_P_MsgID = PRL_INCREMENT_MSG_ID(gasPRL[u8PortNum].u8SOP_P_MsgID);
            break;
        }

        case UPD_TX_SOP_TYPE_SOP_PP:
        {
            gasPRL[u8PortNum].u8SOP_PP_MsgID = PRL_INCREMENT_MSG_ID(gasPRL[u8PortNum].u8SOP_PP_MsgID);
            break;
        }
        
        default:
        {
            break;
        }
    }
}

/*******************************************************************************************************/

void PRL_ProcessRxFIFOISR (UINT8 u8PortNum)
{        
    UINT8 u8RegData[4];
    PRL_RECVBUFF stPRLRecvBuff = {0};

    Hv_Typec_RegisterReadISR(u8PortNum, UPD_REG_RO_RX_MSG_DATA_BASE, u8RegData, 2);
    stPRLRecvBuff.u16Header = MAKE_UINT16(u8RegData[1], u8RegData[0]);
    Hv_Typec_RegisterReadISR(u8PortNum, (UPD_REG_RO_RX_MSG_DATA_BASE+2), stPRLRecvBuff.u8DataObj, sizeof(stPRLRecvBuff.u8DataObj));
    stPRLRecvBuff.u8SOPtype = Hv_Typec_RegReadByte(u8PortNum, UPD_REG_RO_RX_SOP_TYPE);

    if (!gasPRL[u8PortNum].u8RxDisable)
    {
        /* Received bit is set */
        gasPRL[u8PortNum].u8RxRcvdISR = HV_TRUE;
    }

    if (gasPRL[u8PortNum].u8RxRcvdISR == HV_TRUE)
    {
        // 检查是否为 VDM 消息
        if (PRL_GET_MESSAGE_TYPE (stPRLRecvBuff.u16Header) == PE_DATA_VENDOR_DEFINED &&
            DPM_VDM_REQ == DPM_GET_VDM_CMD_TYPE (*(stPRLRecvBuff.u8DataObj)))
        {
            // 立即处理 VDM 消息
            Hv_Drv_Typec_HandleVDM(u8PortNum, stPRLRecvBuff.u16Header, stPRLRecvBuff.u8DataObj);
        }
        // CTS: PROT.ALL3.05 PROT.ALL3.06 Fail 立刻处理chunk msg
        /***********************************************Extended Message Handling**************************************************************/
        /* if received message is extended message*/
        else if (PRL_IS_EXTENDED_MSG(stPRLRecvBuff.u16Header))
        {
            gasPRLRecvBuff [u8PortNum].u16Header = stPRLRecvBuff.u16Header;
            HV_PSF_HOOK_MEMCPY(gasPRLRecvBuff[u8PortNum].u8DataObj, stPRLRecvBuff.u8DataObj, PRL_MAX_DATA_OBJ_SIZE);
            gasPRLRecvBuff [u8PortNum].u8SOPtype = stPRLRecvBuff.u8SOPtype;

            /* Extended Message header is formed with the DataObj obtained*/
            UINT16 u16ExtendedMsgHeader = MAKE_UINT16(gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_1],\
                                                gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_0]);
            DEBUG_PRINT_PORT_STR (gasPRLRecvBuff [u8PortNum].u16Header<<16 | u16ExtendedMsgHeader,"PRL: u16Header and u16ExtendedMsgHeader\r\n");
#if (HV_PROJECT_CONFIG_TYPEC_CTS == HV_CONFIG_ON)
            /*******************************************************REQUEST_CHUNK Handling******************************************************/
            /* Checks whether received message is Chunk Response or Request */
            if (PRL_IS_REQUEST_CHUNK_MSG(u16ExtendedMsgHeader))
            {
                /* CONFIG_PRL_CHUNK_SENDER_REQUEST_TIMEOUT_MS is killed on receiving Chunk Request */
                PRL_KillCAorChunkSMTimer (u8PortNum);
                
                if ((PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader) == gasChunkSM[u8PortNum].u8ChunkNumExpectedOrSent)
                        && PRL_IS_MSG_CHUNKED(u16ExtendedMsgHeader))
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Chunk Request received\r\n");
                    
                    /* If Chunk number request received and ChunkNumber of next Chunk to be sent is equal,
                    PRL_TCH_SEND_RESPONSE_CHUNK_ST is assigned to send next chunk packet*/
                    gasChunkSM [u8PortNum].u8ChunkState    = PRL_TCH_SEND_RESPONSE_CHUNK_ST;
                }
                else
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Request Chunk number mismatch\r\n");
                    
                    /* Spec Ref: TCH_Report_Error - Report Error to Policy Engine. 
                                                    Entered on condition 
                                                (Chunk Request Rcvd & Chunk Number != Chunk Number to Send) */
                    /* if Chunk number does not match, error state is assigned.
                        It is transmission error, Thus PE is informed through call back*/
                    PRL_TxOriginalCBfromCH (u8PortNum, PRL_TX_FAILED_ST);
                }
                
            } /* end of if for IS_REQ_CHUNK_MSG*/
            
            /***********************************************************************************************************************************/
            /**********************************************RESPONSE CHUNK Handling**************************************************************/
            else
            {
                /* Chunk Response is handled here */
                
                /* Spec Ref: RCH_Processing_Extended_Message - Entered on Condition 
                                                                Received Extended Message & (Chunking = 1 & Chunked = 1)*/
            
                /* if the received chunk is 1st response, then Chunk SM is enabled
                    ChunkSM related globals are updated & Chunk response is stored in global*/
            
                if (PRL_FIRST_CHUNK_PACKET == PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader))
                {
                /* if Chunk SM Chunk message is already in process & other message is received*/
                    if (gasChunkSM [u8PortNum].u8EnableChunkSM)
                    {
                        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Unexpected Chunk msg rcvd\r\n");
                        
                        /* Unexpected message received*/
                        if ((PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST == gasChunkSM [u8PortNum].u8ChunkState)
                            || (PRL_RCH_SEND_CHUNK_REQUEST_ST == gasChunkSM [u8PortNum].u8ChunkState)
                            || (PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST == gasChunkSM [u8PortNum].u8ChunkState))
                        {
                            /* Chunk Rx Handling*/
                            /* Spec Ref: On RCH_WAITING_CHUNK if other message received Report RCH_Report_Error*/
                            gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                        }
                        else
                        {                    
                        /* Spec Ref: TCH_Message_Received : Clear the Extended message buffers
                                    Passed the received message to Chunked Rx Engine*/
                        }
                        /* Reset the Chunk State machine*/
                        PRL_ResetChunkSM (u8PortNum);
                        /* New message received is processed below*/
                    }
                    
                    /* Spec Ref: RCH_Processing_Extended_Message: 
                        If first chunk: Set Chunk_Number_Expected = 0 and Num bytes received = 0 */
                    gasChunkSM [u8PortNum].u8EnableChunkSM = HV_TRUE;
                    DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM Enabled\r\n");
                        
                    /* copying the message to global buffer */
                    
                    /* SOP* Type of received packet*/
                    gasExtendedMsgBuff [u8PortNum].u8SOPtype = gasPRLRecvBuff [u8PortNum].u8SOPtype;
                
                    /*Header is copied */
                    gasExtendedMsgBuff [u8PortNum].u16Header = gasPRLRecvBuff [u8PortNum].u16Header;
                    
                    /* Extended message header is copied to the global*/
                    gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader = u16ExtendedMsgHeader;
                    
                    /* Total Chunk packet to be sent is updated*/
                    PRL_UpdateTotalChunkNumVar (u8PortNum);                
                }
                else
                {
                    /* CONFIG_PRL_CHUNK_SENDER_RESPONSE_TIMEOUT_MS is killed on receiving Chunk Response if it is not first Chunk Response packet*/
                    PRL_KillCAorChunkSMTimer (u8PortNum);
                }
                            
                if ((PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader) == gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent)
                        && PRL_IS_MSG_CHUNKED(u16ExtendedMsgHeader))
                {
                    /* Spec Ref: RCH_Processing_Extended_Message: If expected Chunk Number: 
                                Append data to Extended_Message_Buffer;
                                Increment Chunk_Number_Expected and adjust Num bytes received. */
                
                    /* Data Buffer is copied*/
                    /* Data buffer copy is started from 2 as first two bytes of data Extended Message Header */
                    for (UINT8 u8PDOIndex = PRL_EXTN_MSG_HEADER_SIZE_IN_BYTES; 
                            u8PDOIndex < PRL_GET_OBJECT_COUNT(gasPRLRecvBuff [u8PortNum].u16Header) * PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES; 
                                u8PDOIndex++)
                    {
                        gasExtendedMsgBuff [u8PortNum].u8Data[gasChunkSM [u8PortNum].u16RxReceivedBytes++] = gasPRLRecvBuff [u8PortNum].u8DataObj[u8PDOIndex];
                    }
                    
                    /* if received chunk response is last chunk packet*/
                    if (gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent == gasChunkSM [u8PortNum].u8TotalChunkPkt)
                    {
                        /* all the chunk packet expected is received. Hence PE is informed through INTR status*/

                        // 将消息加入队列
                        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Chunk data all rcvd, notify state machine\r\n");
                        
                        /* Validate the PD Message and get the status whether the message needs to be processed */
                        if (PE_ValidateMessage(u8PortNum, gasPRLRecvBuff[u8PortNum].u16Header) != PE_MSG_HANDLED)
                        {
                            Hv_Vos_QueueSendFromISR(pstPRLRecvQueue, &stPRLRecvBuff);
                        }
                    }
                    else
                    {
                        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Chunk Response Rcvd\r\n");
                        
                        /* If the received Chunk response is not the last chunk response packet
                            PRL_RCH_SEND_CHUNK_REQUEST_ST is assigned to to request for next chunk*/
                        gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_SEND_CHUNK_REQUEST_ST;
                        
                        /* Increment the chunk number expected */
                        gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent++;

                        /* CTS 要求收到chunk response后要在tChunkReceiverRequest(15ms)内回Request */
                        DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM PRL_RCH_SEND_CHUNK_REQUEST_ST immediately\r\n");
                        
                        /* Check Abort flag before sending chunk Request*/
                        if (gasChunkSM [u8PortNum].u8AbortFlag)
                        {
                            /* Set the abort state*/
                            gasChunkSM [u8PortNum].u8ChunkState = PRL_CH_ABORT_ST;
                        }
                        else
                        {
                        
                            /* Chunk Request to receive next chunk Response is transmitted*/
                        
                            /* Extended Message Header is formed with Chunk number excepted (u8ChunkNumExpectedOrSent).
                            Message header is formed with received Message header stored (gasExtendedMsgBuff [u8PortNum].u16Header)
                            and Number of data object applicable for Request packet
                            Extended message Header & Message Header is combined as UINT32 & used in PRL_TransmitMsg */

                            HV_PSF_HOOK_TASK_PRIORITY_SET(TYPEC_URGENT_TASK_PRIORITY);
                            if (PRL_RET_TX_MSG_TRANSMITTED_ON_LINE == PRL_TransmitMsg (u8PortNum,
                                                                        gasExtendedMsgBuff [u8PortNum].u8SOPtype,     /* SOP Type */
                                                                        PRL_FormRequestChunkMsgHeader(u8PortNum),    /* Extended Msg Header + Msg Header*/
                                                                        NULL,                                         /* no data byte*/
                                                                        PRL_RCHChunkSMStateChange_RCHCB,            /* Callback*/
                                                                        PRL_BUILD_PKD_TXST_U32 (
                                                                            PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST,    /* Tx_DONE Chunk st*/
                                                                            NULL,                                    
                                                                            PRL_RCH_CHUNK_RECV_ERROR_ST,            /* Tx_FAILED Chunk state*/
                                                                            NULL)))
                            {
                                /* Next CH SM state is assigned*/
                                gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST;
                            }
                            else
                            {
                                /* if message is not transmitted on line PRL_RCH_CHUNK_RECV_ERROR_ST is assigned*/
                                gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                            }
                        
                        }
                    }
                }
                else
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Response Chunk number mismatch\r\n");
                    /* PRL_RCH_CHUNK_RECV_ERROR_ST is assigned to indicate PE*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                }            
            } /* end of if for IS_REQ_CHUNK_MSG*/
            /***********************************************************************************************************************************/
#endif
        } /* end of if check for IsExtendedMsg*/
        else
        {
            // 将消息加入队列
            Hv_Vos_QueueSendFromISR(pstPRLRecvQueue, &stPRLRecvBuff);
        }
    }

#if (HV_TRUE == INCLUDE_PD_DR_SWAP)
    UINT8 u8TxParamC = SET_TO_ZERO; 
    
    /* Update the Port Data Role field in TX_PARAM_C register if there has 
       been a change as a result of DR_Swap */
    if (gasPRL[u8PortNum].u8SwapDataRoleISR)
    {
        gasPRL[u8PortNum].u8SwapDataRoleISR = HV_FALSE; 
        
        Hv_Typec_RegisterReadISR (u8PortNum, PRL_TX_PARAM_C, &u8TxParamC, BYTE_LEN_1);
        
        u8TxParamC &= ~PRL_TX_PARAM_C_PORT_DATA_ROLE_MASK; 
        u8TxParamC |= PRL_UPDATE_TX_PARAM_C_PORT_DATA_ROLE(DPM_GET_CURRENT_DATA_ROLE(u8PortNum));
        
        Hv_Typec_RegisterWriteISR (u8PortNum, PRL_TX_PARAM_C, &u8TxParamC, BYTE_LEN_1);
    }
#endif 
}

/******************************************************************************************************/

void PRL_ResetPRLSpecificSOP (UINT8 u8PortNum, UINT8 u8SOPType)
{
      /* Spec Ref: PRL_Tx_Layer_Reset_for_Transmit - Entered on soft Reset Message request Received from Policy Engine 
                                            Reset MessageIDCounter.
                                            Protocol Layer message reception transition to PRL_Rx_WAIT_FOR_PHY_MESSAGE state */
  
      /* corresponding Tx & RX Message ID of SOP type is reset is reset */

    //reset MSG ID by hardware auto
    /* PRL_SOP_TYPE value is 0, it cannot be masked. Always SOP_TYPE & NON_SOP_TYPE message
        counter reset must be called separately */
    if (PRL_SOP_TYPE == u8SOPType)
    {
        gasPRL[u8PortNum].u8SOPMsgID = RESET_TO_ZERO;
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOP_SEL);
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOP_SEL);
    }
    
    if (PRL_SOP_P_TYPE & u8SOPType)
    {
        gasPRL[u8PortNum].u8SOP_P_MsgID = RESET_TO_ZERO;
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOPP_SEL);
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOPP_SEL);
    }
    
    if (PRL_SOP_PP_TYPE & u8SOPType)
    {
          gasPRL[u8PortNum].u8SOP_PP_MsgID = RESET_TO_ZERO;
        Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOPP_SEL);
        Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_MSGID_RST_SOP, UPD_MSGID_RST_SOPP_SEL);
    }
}

/******************************************************************************************************/

void PRL_OnHardResetComplete (UINT8 u8PortNum)
{    
    /* gasPRL [u8PortNum].u8RxHRRcvdISR is cleared as Hard Reset is processed*/
    /* gasPRL [u8PortNum].u8RxHRRcvdISR is ISR & foreground sync variable. 
        Interrupt is disabled to prevent variable corruption */
    HV_PSF_HOOK_DISABLE_GLOBAL_INTERRUPT();
    gasPRL [u8PortNum].u8RxHRRcvdISR = HV_FALSE;
    HV_PSF_HOOK_ENABLE_GLOBAL_INTERRUPT();
    
    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL_HR_COMPLETE\r\n");

    Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_TX_MSG_CONTROL1, UPD_TX_CONTROL1_CABLE_HARD_RST_REQ);

    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_MCU_FINISH_HARD_RST_SET, SET_TO_ONE);    
    Hv_Vos_Delayus(500);
    Hv_Typec_RegWriteByte(u8PortNum, UPD_REG_RW_MCU_FINISH_HARD_RST_SET, SET_TO_ZERO);
    
    /* When HR is received from port partner, EN_RCV bit is cleared. 
        Hence, after HR completion it is re-enabled */
    //not support, to add
   
#if (HV_TRUE == INCLUDE_PD_DR_SWAP)
    /* If there has been a Data Role Swap the Hard Reset Shall cause the 
       Port Data Role to be changed back to DFP for a Port with the Rp resistor 
       asserted and UFP for a Port with the Rd resistor asserted.*/
    DPM_UpdateDataRole (u8PortNum, DPM_GET_CURRENT_POWER_ROLE(u8PortNum)); 
    
    PRL_UpdateSpecAndDeviceRoles (u8PortNum);
#endif     
            
}

/******************************************************************************************************/

void PRL_ResetPHYLayer (UINT8 u8PortNum)
{
      /* Spec Ref: PRL_TX_PHY_Layer_Reset - Reset PHY Layer
                                Entered on condition Soft Reset Message from PHY Layer or Exit from Hard Reset */
    Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_TYPEC_RST, UPD_TYPEC_PD_RST_RSTN_USBPD);
    Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_TYPEC_RST, UPD_TYPEC_PD_RST_RSTN_USBPD);
}

/******************************************************************************************************/

UINT8 PRL_ProcessRcvdMsg (UINT8 u8PortNum)
{
    UINT8 u8Return = PRL_RET_NO_MSG_RCVD;
    PRL_RECVBUFF stPRLRecvBuff = {0};

    if (!Hv_Vos_QueueTimedRecv(pstPRLRecvQueue, (VOID*)&stPRLRecvBuff, 0))
    {
        gasPRL[u8PortNum].u8RxRcvdISR = HV_FALSE;
        return u8Return;
    }
    gasPRL[u8PortNum].u8RxRcvdISR = HV_TRUE;

    gasPRLRecvBuff [u8PortNum].u16Header = stPRLRecvBuff.u16Header;
    HV_PSF_HOOK_MEMCPY(gasPRLRecvBuff[u8PortNum].u8DataObj, stPRLRecvBuff.u8DataObj, PRL_MAX_DATA_OBJ_SIZE);
    gasPRLRecvBuff [u8PortNum].u8SOPtype = stPRLRecvBuff.u8SOPtype;

    DEBUG_PRINT_PORT_STR (gasPRL[u8PortNum].u16SOPLastRecvMsgHeader<<16 | gasPRLRecvBuff [u8PortNum].u16Header,
        "LAST MSG and Current RECV MSG Header\r\n");

    if ((PRL_GET_OBJECT_COUNT(gasPRLRecvBuff [u8PortNum].u16Header) == 0x00) && (PRL_GET_MESSAGE_TYPE(gasPRLRecvBuff [u8PortNum].u16Header) == 0x01))        //goodcrc
    {
    }
    else
    {
        /**
         * 解决黑鲨手机4Pro的一个bug。
         * 对于黑鲨手机4Pro，手机关机后重启，关机后不会detach，
         * 然后开机后会重新request source cap。
         * 这个时候存在一种情况，就是Last Recv Msg和当前的一样，
         * 所以下面需要修改这个逻辑，如果一样并且是Request的话，
         * 就仍需要enqueue进行处理。
         */
        if (gasPRL[u8PortNum].u16SOPLastRecvMsgHeader == gasPRLRecvBuff [u8PortNum].u16Header
            && PRL_GET_MESSAGE_TYPE(gasPRLRecvBuff [u8PortNum].u16Header) != PE_DATA_REQUEST)
        {
            HV_PSF_HOOK_DISABLE_GLOBAL_INTERRUPT();
            /* gasPRL[u8PortNum].u8RxRcvdISR is ISR & foreground sync variable. 
                Interrupt is disabled to prevent variable corruption */
            gasPRL[u8PortNum].u8RxRcvdISR = HV_FALSE;
            
            HV_PSF_HOOK_ENABLE_GLOBAL_INTERRUPT();
            return u8Return;
        }
        gasPRL[u8PortNum].u16SOPLastRecvMsgHeader = gasPRLRecvBuff [u8PortNum].u16Header;
    }

    #if (HV_TRUE == INCLUDE_PD_3_0)
    #if 1 //CTS
/***********************************************Extended Message Handling**************************************************************/
    /* if received message is extended message*/
    if (PRL_IS_EXTENDED_MSG(gasPRLRecvBuff [u8PortNum].u16Header))
    {
        /* Extended Message header is formed with the DataObj obtained*/
        UINT16 u16ExtendedMsgHeader = MAKE_UINT16(gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_1],\
                                            gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_0]);
        /* 下面处理的目的是在收到chunk data的最后一个数据后， 对于所有收到的数据进行处理 */
        /* Checks received message is Chunk Response */
        if (!PRL_IS_REQUEST_CHUNK_MSG(u16ExtendedMsgHeader))
        {
            /* CONFIG_PRL_CHUNK_SENDER_RESPONSE_TIMEOUT_MS is killed on receiving Chunk Response if it is not first Chunk Response packet*/
            PRL_KillCAorChunkSMTimer (u8PortNum);

            if ((PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader) == gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent)
                    && PRL_IS_MSG_CHUNKED(u16ExtendedMsgHeader))
            {
                /* if received chunk response is last chunk packet*/
                if (gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent == gasChunkSM [u8PortNum].u8TotalChunkPkt)
                {
                    /* all the chunk packet expected is received. Hence PE is informed through INTR status*/
                    
                    /* Chunk SM is reset*/
                    PRL_ResetChunkSM (u8PortNum);
                    
                    /* Return value is set to PRL_RET_EXT_MSG_RCVD to indicate Extended Message has received */
                    u8Return =  PRL_RET_EXT_MSG_RCVD;
                }
            }
        } /* end of if for IS_REQ_CHUNK_MSG*/
    } /* end of if check for IsExtendedMsg*/
    #else
/***********************************************Extended Message Handling**************************************************************/
    /* if received message is extended message*/
    if (PRL_IS_EXTENDED_MSG(gasPRLRecvBuff [u8PortNum].u16Header))
    {
        /* Extended Message header is formed with the DataObj obtained*/
        UINT16 u16ExtendedMsgHeader = MAKE_UINT16(gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_1],\
                                            gasPRLRecvBuff [u8PortNum].u8DataObj[INDEX_0]);
#if (HV_TRUE == INCLUDE_PD_3_0_CHUNK)
        /*******************************************************REQUEST_CHUNK Handling******************************************************/
          /* Checks whether received message is Chunk Response or Request */
        if (PRL_IS_REQUEST_CHUNK_MSG(u16ExtendedMsgHeader))
        {
              /* CONFIG_PRL_CHUNK_SENDER_REQUEST_TIMEOUT_MS is killed on receiving Chunk Request */
            PRL_KillCAorChunkSMTimer (u8PortNum);
            
            if ((PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader) == gasChunkSM[u8PortNum].u8ChunkNumExpectedOrSent)
                    && PRL_IS_MSG_CHUNKED(u16ExtendedMsgHeader))
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Chunk Request received\r\n");
                
                  /* If Chunk number request received and ChunkNumber of next Chunk to be sent is equal,
                PRL_TCH_SEND_RESPONSE_CHUNK_ST is assigned to send next chunk packet*/
                gasChunkSM [u8PortNum].u8ChunkState    = PRL_TCH_SEND_RESPONSE_CHUNK_ST;
            }
            else
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Request Chunk number mismatch\r\n");
                
                  /* Spec Ref: TCH_Report_Error - Report Error to Policy Engine. 
                                                Entered on condition 
                                            (Chunk Request Rcvd & Chunk Number != Chunk Number to Send) */
                /* if Chunk number does not match, error state is assigned.
                    It is transmission error, Thus PE is informed through call back*/
                PRL_TxOriginalCBfromCH (u8PortNum, PRL_TX_FAILED_ST);
            }
            
        } /* end of if for IS_REQ_CHUNK_MSG*/
        
        /***********************************************************************************************************************************/
        /**********************************************RESPONSE CHUNK Handling**************************************************************/
        else
        {
              /* Chunk Response is handled here */
            
            /* Spec Ref: RCH_Processing_Extended_Message - Entered on Condition 
                                                            Received Extended Message & (Chunking = 1 & Chunked = 1)*/
          
            /* if the received chunk is 1st response, then Chunk SM is enabled
                ChunkSM related globals are updated & Chunk response is stored in global*/
          
            if (PRL_FIRST_CHUNK_PACKET == PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader))
            {
               /* if Chunk SM Chunk message is already in process & other message is received*/
                if (gasChunkSM [u8PortNum].u8EnableChunkSM)
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Unexpected Chunk msg rcvd\r\n");
                     
                    /* Unexpected message received*/
                    if ((PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST == gasChunkSM [u8PortNum].u8ChunkState)
                        || (PRL_RCH_SEND_CHUNK_REQUEST_ST == gasChunkSM [u8PortNum].u8ChunkState)
                        || (PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST == gasChunkSM [u8PortNum].u8ChunkState))
                    {
                        /* Chunk Rx Handling*/
                        /* Spec Ref: On RCH_WAITING_CHUNK if other message received Report RCH_Report_Error*/
                        gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                    }
                    else
                    {                    
                    /* Spec Ref: TCH_Message_Received : Clear the Extended message buffers
                                Passed the received message to Chunked Rx Engine*/
                    }
                    /* Reset the Chunk State machine*/
                    PRL_ResetChunkSM (u8PortNum);
                    /* New message received is processed below*/
                }
                
                /* Spec Ref: RCH_Processing_Extended_Message: 
                    If first chunk: Set Chunk_Number_Expected = 0 and Num bytes received = 0 */
                gasChunkSM [u8PortNum].u8EnableChunkSM = HV_TRUE;
                DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM Enabled\r\n");
                    
                /* copying the message to global buffer */
                
                /* SOP* Type of received packet*/
                gasExtendedMsgBuff [u8PortNum].u8SOPtype = gasPRLRecvBuff [u8PortNum].u8SOPtype;
            
                /*Header is copied */
                gasExtendedMsgBuff [u8PortNum].u16Header = gasPRLRecvBuff [u8PortNum].u16Header;
                
                /* Extended message header is copied to the global*/
                gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader = u16ExtendedMsgHeader;
                
                /* Total Chunk packet to be sent is updated*/
                PRL_UpdateTotalChunkNumVar (u8PortNum);                
            }
            else
            {
                  /* CONFIG_PRL_CHUNK_SENDER_RESPONSE_TIMEOUT_MS is killed on receiving Chunk Response if it is not first Chunk Response packet*/
                PRL_KillCAorChunkSMTimer (u8PortNum);
            }
                        
            if ((PRL_GET_CHUNK_NUMBER(u16ExtendedMsgHeader) == gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent)
                    && PRL_IS_MSG_CHUNKED(u16ExtendedMsgHeader))
            {
                  /* Spec Ref: RCH_Processing_Extended_Message: If expected Chunk Number: 
                            Append data to Extended_Message_Buffer;
                            Increment Chunk_Number_Expected and adjust Num bytes received. */
            
                /* Data Buffer is copied*/
                /* Data buffer copy is started from 2 as first two bytes of data Extended Message Header */
                for (UINT8 u8PDOIndex = PRL_EXTN_MSG_HEADER_SIZE_IN_BYTES; 
                        u8PDOIndex < PRL_GET_OBJECT_COUNT(gasPRLRecvBuff [u8PortNum].u16Header) * PRL_SINGLE_DATAOBJ_SIZE_IN_BYTES; 
                            u8PDOIndex++)
                {
                    gasExtendedMsgBuff [u8PortNum].u8Data[gasChunkSM [u8PortNum].u16RxReceivedBytes++] = gasPRLRecvBuff [u8PortNum].u8DataObj[u8PDOIndex];
                }
                
                /* if received chunk response is last chunk packet*/
                if (gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent == gasChunkSM [u8PortNum].u8TotalChunkPkt)
                {
                    /* all the chunk packet expected is received. Hence PE is informed through INTR status*/
                    
                    /* Chunk SM is reset*/
                    PRL_ResetChunkSM (u8PortNum);
                    
                    /* Return value is set to PRL_RET_EXT_MSG_RCVD to indicate Extended Message has received */
                    u8Return =  PRL_RET_EXT_MSG_RCVD;                    
                }
                else
                {
                    DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Chunk Response Rcvd\r\n");
                    
                    /* If the received Chunk response is not the last chunk response packet
                        PRL_RCH_SEND_CHUNK_REQUEST_ST is assigned to to request for next chunk*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_SEND_CHUNK_REQUEST_ST;
                    
                    /* Increment the chunk number expected */
                    gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent++;

                    /* CTS 要求收到chunk response后要在tChunkReceiverRequest(15ms)内回Request */
                    DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM PRL_RCH_SEND_CHUNK_REQUEST_ST immediately\r\n");
                    
                    /* Check Abort flag before sending chunk Request*/
                    if (gasChunkSM [u8PortNum].u8AbortFlag)
                    {
                        /* Set the abort state*/
                        gasChunkSM [u8PortNum].u8ChunkState = PRL_CH_ABORT_ST;
                    }
                    else
                    {
                    
                        /* Chunk Request to receive next chunk Response is transmitted*/
                    
                        /* Extended Message Header is formed with Chunk number excepted (u8ChunkNumExpectedOrSent).
                        Message header is formed with received Message header stored (gasExtendedMsgBuff [u8PortNum].u16Header)
                        and Number of data object applicable for Request packet
                        Extended message Header & Message Header is combined as UINT32 & used in PRL_TransmitMsg */
                        if (PRL_RET_TX_MSG_TRANSMITTED_ON_LINE == PRL_TransmitMsg (u8PortNum,
                                                                    gasExtendedMsgBuff [u8PortNum].u8SOPtype,     /* SOP Type */
                                                                    PRL_FormRequestChunkMsgHeader(u8PortNum),    /* Extended Msg Header + Msg Header*/
                                                                    NULL,                                         /* no data byte*/
                                                                    PRL_RCHChunkSMStateChange_RCHCB,            /* Callback*/
                                                                    PRL_BUILD_PKD_TXST_U32 (
                                                                        PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST,    /* Tx_DONE Chunk st*/
                                                                        NULL,                                    
                                                                        PRL_RCH_CHUNK_RECV_ERROR_ST,            /* Tx_FAILED Chunk state*/
                                                                        NULL)))
                        {
                            /* Next CH SM state is assigned*/
                            gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST;
                        }
                        else
                        {
                            /* if message is not transmitted on line PRL_RCH_CHUNK_RECV_ERROR_ST is assigned*/
                            gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                        }
                    
                    }
                }
            }
            else
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Response Chunk number mismatch\r\n");
                  /* PRL_RCH_CHUNK_RECV_ERROR_ST is assigned to indicate PE*/
                gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
            }            
        } /* end of if for IS_REQ_CHUNK_MSG*/
        #else
        u8Return |=  PRL_RET_MSG_RCVD;
        #endif

        /***********************************************************************************************************************************/
    
    } /* end of if check for IsExtendedMsg*/
    #endif
    /***************************************************Non-Extended Message Handling******************************************************/
    else    
    {
        if ((gasChunkSM [u8PortNum].u8EnableChunkSM) && (PRL_GET_MESSAGE_TYPE(gasPRLRecvBuff [u8PortNum].u16Header) != PE_CTRL_PING))
        {
              /* Unexpected message received and received message is not PING */
            if ((PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST == gasChunkSM [u8PortNum].u8ChunkState)
                || (PRL_RCH_SEND_CHUNK_REQUEST_ST == gasChunkSM [u8PortNum].u8ChunkState)
                || (PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST == gasChunkSM [u8PortNum].u8ChunkState))
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Unexpected msg rcvd other than Ping & Chunk msg\r\n");
                  
                /* Chunk SM is reset*/
                PRL_ResetChunkSM (u8PortNum);
                    
                /* Spec Ref: On RCH_WAITING_CHUNK if other message received Report RCH_Report_Error*/
                u8Return = PRL_RET_RCV_CHUNK_ERROR;
            }
            else
            {
                DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Unexpected msg rcvd other than Ping & Chunk msg\r\n");
                /* Spec Ref: TCH_Message_Received - Clear Extended Message Buffer. Pass message to Chunked Rx*/
                PRL_ResetChunkSM (u8PortNum);
            }
        }
        /* if it is not an extended message, Message is copied to globals & PE is informed*/
        /* Return value is set to PRL_RET_MSG_RCVD to indicate Message has received */
        u8Return |=  PRL_RET_MSG_RCVD;
             
    }/*end of else for IsExtendedMsg*/
    
    /* if the message is received in process of Collision avoidance, the pending message is discarded
        by setting the Tx state to PRL_TX_IDLE_ST*/
    if ((PRL_TX_MSG_BUFFERED_ON_CA_ST == gasPRL [u8PortNum].u8TxStateISR) || \
           (PRL_Tx_CA_SRC_SINKTXTIMER_ON_ST == gasPRL [u8PortNum].u8TxStateISR))
    {
            /* Collision avoidance timer is killed in case active*/
           PRL_KillCAorChunkSMTimer (u8PortNum);
           
           /* PRL_TX_IDLE_ST is assigned*/
           PRL_ChangeTxState (u8PortNum, PRL_TX_IDLE_ST);
    }
    
    #else
        /* Return value is set to PRL_RET_MSG_RCVD to indicate Message has received */
        u8Return |=  PRL_RET_MSG_RCVD;
     #endif /* for INCLUDE_PD_3_0 */
    HV_PSF_HOOK_DISABLE_GLOBAL_INTERRUPT();
    /* gasPRL[u8PortNum].u8RxRcvdISR is ISR & foreground sync variable. 
        Interrupt is disabled to prevent variable corruption */
    gasPRL[u8PortNum].u8RxRcvdISR = HV_FALSE;
    
    HV_PSF_HOOK_ENABLE_GLOBAL_INTERRUPT();
    
    return u8Return;
}

/******************************************************************************************************/

UINT32 PRL_IsAnyMsgPendinginPRL (UINT8 u8PortNum)
{
    /* If there are any pending message unprocessed by the PRL
        Message header is returned else zero */
    if (gasPRL[u8PortNum].u8RxRcvdISR)
    {
        return gasPRLRecvBuff[u8PortNum].u16Header;
    }
    else
    {
        return HV_FALSE;
    }
}
/******************************************************************************************************/

/* Below are PD 3.0 Spec related functions */

#if (HV_TRUE == INCLUDE_PD_3_0)

/******************************************************************************************************************************************

                                    COLLISION AVOIDANCE APIS for Source
*******************************************************************************************************************************************/

void PRL_SetCollisionAvoidance (UINT8 u8PortNum, UINT8 u8Enable)
{
    /*If the current spec role is not 3.0 return */
    if (DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum) != PD_SPEC_REVISION_3_0)
    {
        return;
    } 
    
    /* Spec Reference: PRL_Tx_Src_Source_Tx - Set Rp = SinkTxNG 
       Rp = SinkTxNG 1.5A @ 5v is set  
       Spec Reference: PRL_tx_Src_Sink_Tx - Set Rp = SinkTxOK 
       Rp = SinkTxOk 3A @ 5v is set */    
    TypeC_SetRpCollAvoidance (u8PortNum, u8Enable);
    
    if (TYPEC_SINK_TXNG == u8Enable)
    {                
            /* Spec Reference: PRL_Tx_Src_Pending - Start sinkTxTimer*/
            /* SinkTxTimer is started. */
            gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = PDTimer_Start (PRL_SINKTX_TIMEOUT_MS,\
                                                            PRL_CASinkTx_TimerCB, u8PortNum, (UINT8)SET_TO_ZERO);
            
            /* u8Txstate is set to PRL_Tx_CA_SRC_SINKTXTIMER_ON_ST*/
            PRL_ChangeTxState (u8PortNum, PRL_Tx_CA_SRC_SINKTXTIMER_ON_ST);
                    
            DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: SINK_TX_TMR ON\r\n");
    }
}

/******************************************************************************************************/

void PRL_CASinkTx_TimerCB (UINT8 u8PortNum, UINT8 u8DummyVariable)
{
      /* Spec Reference: PRL_Tx_Construct_Message or PRL_Tx_Layer_Reset_for_Transmit - Entered on condition
                        Message pending (except Soft Reset) & SinkTxTimer timeout
                        Soft Reset Message pending & SinkTxTimer timeout respectively */
    /* Pending message if any in the Tx FIFO is transmitted on SinkTxTimer Times out*/
    PRL_CommitPendingTxOnCAISR (u8PortNum);
    
    /* setting the Timer ID to Max value*/
    gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = MAX_CONCURRENT_TIMERS;    
}

/******************************************************************************************************/

UINT8 PRL_IsAMSInitiatable (UINT8 u8PortNum)
{
    UINT8 u8ReturnVal = HV_TRUE, u8CurrentPwrRole = DPM_GET_CURRENT_POWER_ROLE(u8PortNum);
    
    /*If the port is 3.0 check whether the port is capable of initiating an AMS*/
    if (PD_SPEC_REVISION_3_0 == DPM_GET_CURRENT_PD_SPEC_REV(u8PortNum))
    {        
        if (PD_ROLE_SINK == u8CurrentPwrRole)
        {
            /* Check for Rp Value */
            if (((gasTypeCcontrol[u8PortNum].u8PortSts & TYPEC_CURR_RPVAL_MASK) \
                    >> TYPEC_CURR_RPVAL_POS) != TYPEC_RP_CURRENT_30)
            {
                /* Rp is not SinkTxOK and hence, AMS cannot be initiated */
                u8ReturnVal = HV_FALSE;         
            }    
        }
        else if (PD_ROLE_SOURCE == u8CurrentPwrRole)
        {
            if (gasPRL [u8PortNum].u8TxStateISR != PRL_TX_IDLE_ST)
            {
                /* Tx is not  in Idle*/
                u8ReturnVal = HV_FALSE;
            }
        }
        else
        {
            /*Do nothing*/
        }
    }
    return u8ReturnVal;
}

/******************************************************************************************************/

void PRL_CommitPendingTxOnCAISR (UINT8 u8PortNum)
{
    if (gasPRL[u8PortNum].u8RxRcvdISR)                            /* Checks whether a message is received */
    {
        /* if there is a pending message in Rx, discard the Tx commitment queued due to CA*/ 
        PRL_ResetPHYLayer (u8PortNum);
        
        /* PRL_TX_IDLE_ST is assigned to PRL state*/
        gasPRL [u8PortNum].u8TxStateISR = PRL_TX_IDLE_ST;
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Tx Msg Discarded on Rcv\r\n");        
    }
    else if (PRL_TX_MSG_BUFFERED_ON_CA_ST == gasPRL [u8PortNum].u8TxStateISR)
    {
        /* Spec Ref: PRL_Tx_Layer_Reset_for_Transmit & PRL_Tx_Construct_Message - Entered on Condition
                Soft Reset Message pending & Rp = SinkTxOK and
                Message pending (except Soft Reset) & Rp = SinkTxOK respectively */
      
        /* Go bit is set to transmit the message buffered in Tx FIFO & message Pkt is transmitted on PHY */
        Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(1));
        Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, BIT(0));
        Hv_Typec_RegWriteByte (u8PortNum, UPD_REG_RW_TX_MSG_BUFFER_CTRL, SET_TO_ZERO);

        /* PRL_TX_MSG_ON_LINE_ST is assigned to PRL state as Buffered message is tranmitted on line*/
        gasPRL [u8PortNum].u8TxStateISR = PRL_TX_MSG_ON_LINE_ST;
        
        DEBUG_PRINT_PORT_STR (u8PortNum,"PRL: Buffered Tx Msg sent on line\r\n");
    }
    else
    {
        /* PRL_TX_IDLE_ST is assigned to PRL state*/
        gasPRL [u8PortNum].u8TxStateISR = PRL_TX_IDLE_ST;
    }
}

/********************************************************************************************************************************************/

void PRL_TCHChunkSMStateChange_TCHCB (UINT8 u8PortNum, UINT8 u8TimerID, UINT8 TxDoneSt, UINT8 TxAbortSt, UINT8 TxFailSt)
{
      /* Callback for Chunk Request Messages*/ 
    /* Policy engine state is assigned based  on Tx Interrupt status*/
    if (PRL_TX_DONE_ST == gasPRL[u8PortNum].u8TxStateISR)
    {
        /* Checks whether GoodCRC received is not last Chunk Response packet*/
        if (gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent != gasChunkSM [u8PortNum].u8TotalChunkPkt)
        {
              /* TCH_WAIT_CHUNK_REQUEST - Increment Chunk Number to Send
                                        Start ChunkSenderRequest Timer
                                        TCH_WAIT_CHUNK_REQUEST is entered from TCH_SENDING_CHUNKED MESSAGE
                                        on "Message Transmitted from Protocol Layer & Not Last chunk".
                                         */
            /* Increment the chunk number to send*/
            gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent++;
            
            /* Start ChunkSenderRequestTimer*/
            gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = PDTimer_Start (PRL_CHUNKSENDERREQUEST_TIMEOUT_MS, 
                                                                         PRL_ChunkStateChange_TimerCB, 
                                                                         u8PortNum, 
                                                                         PRL_TCH_CHUNKSENDERREQUEST_TIMEOUT_ST);
            /* Assigning PRL_TCH_EXPECT_CHUNK_REQUEST_WAIT_ST state*/
            gasChunkSM [u8PortNum].u8ChunkState = PRL_TCH_EXPECT_CHUNK_REQUEST_WAIT_ST;
        }
        else
        {
              /* TCH_MESSAGE_SENT - Inform Policy Engine of Message Sent.
                                    TCH_MESSAGE_SENT is entered on condition
                                    "Message Transmitted received from Protocol Layer & Last Chunk" */
              /* GoodCRC for last Chunk is received*/
            /* all the Chunk packets are sent successfully. PE is informed through the Callback
                Chunk SM is Reset */
              PRL_TxOriginalCBfromCH (u8PortNum, PRL_TX_DONE_ST);
        }
    }
    
    /* In case of Transmission failure of Chunk packet, PE is informed through CB
        & Chunk State machine is reset*/
    else if ((PRL_TX_ABORTED_ST == gasPRL[u8PortNum].u8TxStateISR) || \
            (PRL_TX_FAILED_ST == gasPRL[u8PortNum].u8TxStateISR))
    {
          /* TCH_REPORT_ERROR - Report Error to Policy Engine. 
                                        TCH_REPORT_ERROR entered on condition 
                                            (Transmission Error) */
        PRL_TxOriginalCBfromCH (u8PortNum, gasPRL[u8PortNum].u8TxStateISR);
    }
    else
    {
        /* Do Nothing */
    }
}

/******************************************************************************************************/

void PRL_RCHChunkSMStateChange_RCHCB (UINT8 u8PortNum, UINT8 u8TimerID, UINT8 TxDoneSt, UINT8 TxAbortSt, UINT8 TxFailSt)
{
      /* Callback for Chunk Request Tx Message*/
  
    if (PRL_TX_DONE_ST == gasPRL[u8PortNum].u8TxStateISR)
    {
          /* if GOODCRC is received, SenderRequestTimer is started*/
        gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = PDTimer_Start (PRL_CHUNKSENDERRESPONSE_TIMEOUT_MS, 
                                                                     PRL_ChunkStateChange_TimerCB, 
                                                                     u8PortNum, 
                                                                     PRL_RCH_CHUNK_RECV_ERROR_ST);
        
        /* PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST is assigned to wait for Chunk Request packet*/
        
        gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST;
    }
    else if ((PRL_TX_ABORTED_ST == gasPRL[u8PortNum].u8TxStateISR) || (PRL_TX_FAILED_ST == gasPRL[u8PortNum].u8TxStateISR))
    {
          /* Spec Ref: RCH_Report_Error - Report Error to Policy Engine 
                                        Entered on condition "Unexpected Chunk Number" */
        
          /* If at all, Request Chunk packet is fails. PE is informed*/
        gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
        
    }
    else
    {
        /* Do Nothing */
    }
}

/******************************************************************************************************/

void PRL_ChunkStateChange_TimerCB (UINT8 u8PortNum, UINT8 u8ChunkState)
{
      /* callback for SenderRequestTimer and SenderResponseTimer*/
    gasChunkSM [u8PortNum].u8ChunkState = u8ChunkState;

     /* setting the Timer ID to Max value*/
    gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = MAX_CONCURRENT_TIMERS;
    
    DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: ChunkTimer time out \r\n");        
}

/******************************************************************************************************/

void PRL_UpdateTotalChunkNumVar (UINT8 u8PortNum)
{
    /* Total Number of chunk to be sent or received is updated */
      /* -1 is done as Chunk packet starts from Chunk 0 */
    gasChunkSM [u8PortNum].u8TotalChunkPkt = ((PRL_GET_DATA_SIZE(gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader) /
                                                   PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES) - 1);
    if ((PRL_GET_DATA_SIZE(gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader) % PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES))
    {
        gasChunkSM [u8PortNum].u8TotalChunkPkt++;
    }
}

/******************************************************************************************************/
void PRL_ResetChunkSM (UINT8 u8PortNum)
{
      /* Chunk SM is reset Completely*/
    gasChunkSM [u8PortNum].u8EnableChunkSM = RESET_TO_ZERO;
    gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent = RESET_TO_ZERO;
    gasChunkSM [u8PortNum].u8TotalChunkPkt = RESET_TO_ZERO;
    gasChunkSM [u8PortNum].u16RxReceivedBytes = RESET_TO_ZERO;
    gasChunkSM [u8PortNum].u8ChunkState = PRL_CH_CHUNK_IDLE_ST;
    PRL_KillCAorChunkSMTimer (u8PortNum);  
}

/******************************************************************************************************/

void PRL_TxOriginalCBfromCH (UINT8 u8PortNum, UINT8 u8TxStateforCB)
{
    UINT32 u32pkdTmrIDTxSt;
    
    /* Interrupt enable disable is done as the call back is expected to be called in ISR*/
    HV_PSF_HOOK_DISABLE_GLOBAL_INTERRUPT();
      /* Checks whether Tx Callback is not present */
    if (gasChunkSM [u8PortNum].pFnTxCallback != NULL)
    {
        /* PRL Txstate is assigned as PRL_TX_FAILED_ST & callback is called*/
        gasPRL [u8PortNum].u8TxStateISR = u8TxStateforCB;
        u32pkdTmrIDTxSt = gasChunkSM[u8PortNum].u32pkdTmrID_TxSt;
        gasChunkSM [u8PortNum].pFnTxCallback(u8PortNum, 
                                        LOBYTE(u32pkdTmrIDTxSt),     /* Next PE state for PRL_TX_DONE_ST or PRL_TX_EOP_ST incase of HR */
                                        HIBYTE(u32pkdTmrIDTxSt),     /* Next PE sub state for PRL_TX_DONE_ST or PRL_TX_EOP_ST incase of HR*/                                 
                                        LOBYTE(HIWORD(u32pkdTmrIDTxSt)),    /* Next PE state for PRL_TX_ABORT or TX_FAILED */
                                        HIBYTE(HIWORD(u32pkdTmrIDTxSt)));    /* Next PE sub state for PRL_TX_ABORT or TX_FAILED*/
        /* PRL Tx state is set back to PRL_TX_IDLE_ST after the callback*/
        gasPRL [u8PortNum].u8TxStateISR = PRL_TX_IDLE_ST;        
    }
    
    HV_PSF_HOOK_ENABLE_GLOBAL_INTERRUPT();
            
    /* Reset the CHUNK SM*/
    PRL_ResetChunkSM (u8PortNum);    
}                
/******************************************************************************************************/

void PRL_RunChunkStateMachine (UINT8 u8PortNum)
{    
    if (!gasChunkSM [u8PortNum].u8EnableChunkSM)
    {
          /* if Chunk SM is not enabled, Return*/
        return;
    }
    
    switch (gasChunkSM [u8PortNum].u8ChunkState)
    {      
        case PRL_CH_CHUNK_IDLE_ST:
        /* Common Idle state for RCH & TCH */
          
        case PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST:
        /* wait for Chunk response packet Reception */
        {
            break;
        }
        
        case PRL_RCH_SEND_CHUNK_REQUEST_ST:
        {
              DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM PRL_RCH_SEND_CHUNK_REQUEST_ST\r\n");
            
            /* Check Abort flag before sending chunk Request*/
            if (gasChunkSM [u8PortNum].u8AbortFlag)
            {
                /* Set the abort state*/
                gasChunkSM [u8PortNum].u8ChunkState = PRL_CH_ABORT_ST;
            }
            else
            {
              
                /* Chunk Request to receive next chunk Response is transmitted*/
            
                /* Extended Message Header is formed with Chunk number excepted (u8ChunkNumExpectedOrSent).
                Message header is formed with received Message header stored (gasExtendedMsgBuff [u8PortNum].u16Header)
                and Number of data object applicable for Request packet
                Extended message Header & Message Header is combined as UINT32 & used in PRL_TransmitMsg */
            
                if (PRL_RET_TX_MSG_TRANSMITTED_ON_LINE == PRL_TransmitMsg (u8PortNum,
                                                            gasExtendedMsgBuff [u8PortNum].u8SOPtype,     /* SOP Type */
                                                            PRL_FormRequestChunkMsgHeader(u8PortNum),    /* Extended Msg Header + Msg Header*/
                                                            NULL,                                         /* no data byte*/
                                                            PRL_RCHChunkSMStateChange_RCHCB,            /* Callback*/
                                                            PRL_BUILD_PKD_TXST_U32 (
                                                                PRL_RCH_EXPECT_RESPONSE_CHUNK_WAIT_ST,    /* Tx_DONE Chunk st*/
                                                                 NULL,                                    
                                                                  PRL_RCH_CHUNK_RECV_ERROR_ST,            /* Tx_FAILED Chunk state*/
                                                                  NULL)))
                {
                    /* Next CH SM state is assigned*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST;
                }
                else
                {
                      /* if message is not transmitted on line PRL_RCH_CHUNK_RECV_ERROR_ST is assigned*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_RCH_CHUNK_RECV_ERROR_ST;
                }
            
            }
            break;
        }   /* end of case PRL_RCH_SEND_CHUNK_REQUEST_ST */
        
        case PRL_RCH_WAIT_FOR_CHUNK_REQUEST_STATUS_ST:
        /* Idle state waiting for GOODCRC or Transmission error for the Request Chunk sent */
        {
            break;
        }
        
        case PRL_RCH_CHUNK_RECV_ERROR_ST:
        {
              /* Error bit is set to indicate policy engine*/
              gasPRL [u8PortNum].u8RxError = PRL_RX_CHUNK_RCV_ERROR;
              PRL_ResetChunkSM (u8PortNum);
            break;
        }
        
        case PRL_TCH_SEND_RESPONSE_CHUNK_ST:
        {
            /* Check the Abort flag before sending the Response*/
            if (gasChunkSM [u8PortNum].u8AbortFlag)
            {
                /* Set the abort state*/
                gasChunkSM [u8PortNum].u8ChunkState = PRL_CH_ABORT_ST;                
            }
            else
            {
                  /* TCH state to send Chunk packet*/
                  
                  /* Extended Header is updated for Current Chunk packet to be sent */
                UINT8 u8ChunkNumber    = gasChunkSM[u8PortNum].u8ChunkNumExpectedOrSent;
                /*Extended message is updated and stored*/
                UINT32 u32CombinedMessageHeader = PRL_UPDATE_EXT_MSG_HEADER_CHUNK_NUMBER(
                                                    gasExtendedMsgBuff [u8PortNum].u16ExtendedMsgHeader,
                                                    u8ChunkNumber);
                u32CombinedMessageHeader = PRL_FORM_COMBINED_MSG_HEADER((UINT16)u32CombinedMessageHeader,
                                                    (gasExtendedMsgBuff [u8PortNum].u16Header));            /* Extended Msg Header + Msg Header*/
                DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM PRL_TCH_SEND_RESPONSE_CHUNK_ST\r\n");
                
                /* TCH_CONSTRUCT_CHUNKED_MESSAGE - Construct Message Chunk and pass to Protocol Layer */
                /* Chunk Response is transmitted*/              
                if (PRL_RET_TX_MSG_TRANSMITTED_ON_LINE == PRL_TransmitMsg (u8PortNum,
                                    gasExtendedMsgBuff [u8PortNum].u8SOPtype,                     /* SOP Type */
                                    u32CombinedMessageHeader,                                    /* message header*/
                                    &gasExtendedMsgBuff[u8PortNum].u8Data[
                                      (u8ChunkNumber * PRL_MAX_EXTN_MSG_CHUNK_LEN_IN_BYTES)],     /* Corresponding Chunk's Data*/
                                    PRL_TCHChunkSMStateChange_TCHCB,                            /* Callback*/
                                    PRL_BUILD_PKD_TXST_U32 (MAX_CONCURRENT_TIMERS,                /* u32PkdPEstOnTxStatus*/
                                                                PRL_TCH_EXPECT_CHUNK_REQUEST_WAIT_ST,    /* Tx_DONE Chunk state*/
                                                                PRL_TCH_CHUNK_TX_ERROR_ST,                /* Tx_FAILED Chunk state*/
                                                                PRL_TCH_CHUNK_TX_ERROR_ST)))            /* Tx_ABORT Chunk state*/
                {
                    /* Assigning PRL_TCH_WAIT_FOR_REQUEST_CHUNK_STATUS_ST state*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_TCH_WAIT_FOR_REQUEST_CHUNK_STATUS_ST;
                }
                else
                {
                      /* If message is not transmitted on line, PRL_TCH_CHUNK_TX_ERROR_ST error state is assigned*/
                    gasChunkSM [u8PortNum].u8ChunkState = PRL_TCH_CHUNK_TX_ERROR_ST;
                }
            } /* end of PRL_TCH_SEND_RESPONSE_CHUNK_ST case*/
            break;
        }
        
        case PRL_TCH_CHUNKSENDERREQUEST_TIMEOUT_ST:
        {
              if (PRL_FIRST_CHUNK_PACKET == gasChunkSM [u8PortNum].u8ChunkNumExpectedOrSent)
            {
                /*Spec Ref: TCH Shall transition to the TCH_Message_Sent state when
                  ChunkSenderRequestTimer has expired and Chunk Number equals zero.*/
                  PRL_TxOriginalCBfromCH (u8PortNum, PRL_TX_DONE_ST);
            }
            else
            {
                  /* Spec Ref: ChunkSenderRequestTimer has expired and Chunk Number is greater than zero.
                            TCH transit to TCH_Report_Error*/
                gasChunkSM [u8PortNum].u8ChunkState = PRL_TCH_CHUNK_TX_ERROR_ST;
            }
              
            break;    
        }    
        
        case PRL_TCH_CHUNK_TX_ERROR_ST:
        {
              DEBUG_PRINT_PORT_STR (u8PortNum, "PRL: Chunk SM PRL_TCH_CHUNK_TX_ERROR_ST\r\n");
            
              /* On any transmission error, PE is informed through the callback */
              PRL_TxOriginalCBfromCH (u8PortNum, PRL_TX_FAILED_ST);
            
            break;
        }
        
        case PRL_CH_ABORT_ST:
        {
            /* if abort flag is set, reset the Chunking SM */
            PRL_ResetChunkSM (u8PortNum);
            gasChunkSM [u8PortNum].u8AbortFlag = RESET_TO_ZERO;
            break;
        }
        
        case PRL_TCH_WAIT_FOR_REQUEST_CHUNK_STATUS_ST:
        /* Idle wait state till we receive a GOODCRC or Transmission Error for sent Chunk packet*/
        case PRL_TCH_EXPECT_CHUNK_REQUEST_WAIT_ST:
        /* Idle state waiting for Chunk Request to be received*/
        default:
        {
            break;
        }      
    }    
}

/******************************************************************************************************/

UINT32 PRL_FormRequestChunkMsgHeader (UINT8 u8PortNum)
{                        
    UINT32 u32CombinedHeader;
      if (PRL_SOP_TYPE == gasExtendedMsgBuff [u8PortNum].u8SOPtype)
    {
        u32CombinedHeader = PRL_FormSOPTypeMsgHeader (u8PortNum, 
                                  PRL_GET_MESSAGE_TYPE(gasExtendedMsgBuff [u8PortNum].u16Header),
                                  PRL_REQUEST_CHUNK_DATA_OBJ_CNT, PRL_EXTENDED_MSG);
    }
    else
    {
    
        u32CombinedHeader = PRL_FormNonSOPTypeMsgHeader (u8PortNum, 
                                    PRL_GET_MESSAGE_TYPE(gasExtendedMsgBuff [u8PortNum].u16Header),
                                     PRL_REQUEST_CHUNK_DATA_OBJ_CNT, PRL_EXTENDED_MSG);
    }
    
    u32CombinedHeader = PRL_FORM_COMBINED_MSG_HEADER(PRL_FORM_REQUEST_CHUNK_EXT_MSG_HEADER(gasChunkSM[u8PortNum].u8ChunkNumExpectedOrSent), 
                                    (UINT16)u32CombinedHeader);
    return u32CombinedHeader;
}

/******************************************************************************************************/
void PRL_KillCAorChunkSMTimer (UINT8 u8PortNum)
{
    PDTimer_Kill (gasChunkSM [u8PortNum].u8CAorChunkSMTimerID);
    gasChunkSM [u8PortNum].u8CAorChunkSMTimerID = MAX_CONCURRENT_TIMERS;
}

/******************************************************************************************************/
#endif /*INCLUDE_PD_3_0*/

/******************************************************************************************************/

void PRL_ConfigureBISTCarrierMode (UINT8 u8PortNum, UINT8 u8BISTCarriermode)
{
    //UINT8 u8OKToTx;
    if (u8BISTCarriermode)
    {

          /* Check whether message can sent on line*/
        //do
        //{
        //    u8OKToTx = Hv_Typec_RegReadByte (u8PortNum, PRL_TX_CTL_B);
        ///}while (!(u8OKToTx & PRL_TX_CTL_B_OK_TO_TX));
        DEBUG_PRINT_PORT_STR (u8PortNum,"TYPEC Enter BIST Pattern!!!\r\n");
          Hv_Typec_RegByteSetBit(u8PortNum, UPD_REG_RW_BIST_PATT_CTRL, UPD_BIST_PATT_CTRL_MASK);
    }
    else
    {
          /* BIST Tx is reset*/
        DEBUG_PRINT_PORT_STR (u8PortNum,"TYPEC Exit BIST Pattern!!!\r\n");
          Hv_Typec_RegByteClearBit(u8PortNum, UPD_REG_RW_BIST_PATT_CTRL, UPD_BIST_PATT_CTRL_MASK);
    }
}

/******************************************************************************************************/

void PRL_ChangeTxState (UINT8 u8PortNum, UINT8 u8TxStateISR)
{
    HV_PSF_HOOK_DISABLE_GLOBAL_INTERRUPT();
    gasPRL[u8PortNum].u8TxStateISR = u8TxStateISR;
    HV_PSF_HOOK_ENABLE_GLOBAL_INTERRUPT();
}

/******************************************************************************************************/

void PRL_ResetProtocolLayer (UINT8 u8PortNum)
{
    /*Reset the UPD Protocol Layer for all SOPs*/
    PRL_ResetPRLSpecificSOP (u8PortNum, PRL_SOP_TYPE);
    PRL_ResetPRLSpecificSOP (u8PortNum, (PRL_SOP_P_TYPE | PRL_SOP_PP_TYPE));
     
    /* Disable the Tx interrupt*/
    Hv_Typec_RegWriteByte (u8PortNum, PRL_TX_IRQ_EN, CLR_VAL);
    
    /*Enable Receiver*/
    gasPRL[u8PortNum].u8RxDisable = HV_FALSE; 
    
    /* Reset the PHY layer*/
    PRL_ResetPHYLayer (u8PortNum);        
}

/******************************************************************************************************/
