/******************************************************************************
�� �� ����DoCAN_ISO15765.c
����������ISO 15765 �淶�涨����Ϸ��������ļ�
��    �ߣ�����
��    ����V1.0
��    �ڣ�2016.7.18
******************************************************************************/

#include "DoCAN_ISO15765.h"

LinkRxFIFOStruct              LinkRxFIFO;
LinkTxCtrlStruct              LinkTxCtrl;

volatile TransportDataUnion   TransportRxData;
volatile TransportDataUnion   TransportTxData;

N_USDataRxStruct              N_USDataRxBuffer;
N_USDataTxStruct              N_USDataTxBuffer;

TransportControlStruct        TpCtrl;
TransportTimingControlStruct  TpTimingCtrl;

uint8_t DiagnosticReceived;

extern void UDS_N_USData_Confirm (uint32_t N_TAtype, N_ResultEnum N_Result);
extern void UDS_N_USData_FF_Indication(uint32_t N_TAtype, uint16_t Length);
extern void UDS_N_USData_Indication(uint32_t N_TAtype, uint8_t *MessageData, uint16_t Length, N_ResultEnum N_Result);

/******************************************************************************
��̨����
******************************************************************************/
/******************************************************************************
��������DoCAN_Communication_Service
��  �ܣ�����CAN���ߵ����ͨ�ŷ����̨���ƺ���
��  ������
����ֵ����
*******************************************************************************
ע  �⣺�÷��������뱻ʵʱ����
******************************************************************************/
void DoCAN_Communication_Service ( void )
{
    
    DoCAN_Update_Timer();
    DoCAN_Handle_Time_Out();

    DoCAN_Receive_And_Assemble_N_USData();
    DoCAN_Disassemble_And_Transmit_N_USData();

/*
    if (TpCtrl.TxReq)
    {
        TpCtrl.TxReq = 0u;
        id = TransportTxData.Frame.Identifier;
        dlc = TransportTxData.Frame.DLC;
        for (i = 0u; i < 8u; ++i)
        {
            data[i] = TransportTxData.Frame.Data[i];
        }
        DoCAN_L_Data_Request(id, dlc, data);
    }
*/
}

/******************************************************************************
��������DoCAN_Timer_Update
��  �ܣ����¶�ʱ����ֵ,����ʱ������Լ�STmin��ʱ
��  ����Interval����ʱ�����θ��µ�ʱ����,��λus
����ֵ����
*******************************************************************************
ע  �⣺�÷��������뱻Ƕ�뵽��ʱ�ж���
******************************************************************************/
void DoCAN_Timer_Update ( uint16_t Interval )
{
    TpTimingCtrl.Cnt += Interval;
}

/******************************************************************************
Services provided by network layer to higher layers
******************************************************************************/
/******************************************************************************
��������DoCAN_N_USData_Request
��  �ܣ��÷�������������������
        This service is used to request the transfer of data. If necessary, the
        network layer segments the data.
��  ����N_TAtype    ��Ŀ���ַ����,����������ʹ�� DIAG_ID_Tx
        MessageData �������������
        Length      �����ݳ���
����ֵ����
******************************************************************************/
void DoCAN_N_USData_Request ( uint32_t N_TAtype, uint8_t MessageData[], uint16_t Length )
{
    uint16_t i;
    uint32_t id;
    uint8_t dlc;
    uint8_t data[8];
    
    /*�ǿ���״̬�²���������*/
    if ( TpCtrl.Process != TP_IDLE )
    {
        DoCAN_N_USData_Confirm ( N_TAtype, N_ERROR );
    }
    else
    {
        if ( ( Length == 0u ) || ( Length > N_USDATA_TX_BUFFER_SIZE ) ) /*�Ƿ��ĳ���*/
        {
            DoCAN_N_USData_Confirm ( N_TAtype, N_ERROR );
        }
        else
        {
            /*�����ݻ��浽����Buffer��*/
            N_USDataTxBuffer.N_TAtype = N_TAtype;
            N_USDataTxBuffer.Length   = Length;

            for ( i = 0u; i < Length; i++ )
            {
                N_USDataTxBuffer.MsgData[i] = MessageData[i];
            }

            /*���´����״̬*/
            TpCtrl.NonStopMode = 0u;
            TpCtrl.TotalLen  = Length;                  /*��¼�ֽ�����*/
            TpCtrl.BSMax     = 0xFFu;                    /*��ʼ��BSMax��ֵ*/
            TpCtrl.STmin     = 0x7Fu;

            /*���ΪN_PDU*/
            if ( TpCtrl.TotalLen < 8u )          /*�����ܳ���С��8,���õ�֡����*/
            {
                TpCtrl.BlockSize = 1u;           /*��֡,Block����Ϊ1*/
                TpCtrl.Len       = TpCtrl.TotalLen;       /*��֡����ȫ��������*/
                TpCtrl.BlockCnt  = 1u;           /*��¼�ѷ���Block��*/

                TransportTxData.N_PDU_SF.N_TAtype    = N_USDataTxBuffer.N_TAtype;
                TransportTxData.N_PDU_SF.N_PCI.Type  = SINGLE_FRAME;
                TransportTxData.N_PDU_SF.N_PCI.SF_DL = ( uint8_t ) ( TpCtrl.TotalLen );
                TransportTxData.N_PDU_SF.DLC         = ( uint8_t ) ( TpCtrl.TotalLen ) + 1u;

                for ( i = 0u; i < TpCtrl.TotalLen; i++ )
                {
                    TransportTxData.N_PDU_SF.N_Data[i] = N_USDataTxBuffer.MsgData[i];
                }
            }
            else                                          /*�����ܳ��ȴ��ڵ���8,���ö�֡����,���ȷ�����֡*/
            {
                if ( ( Length + 1u ) % 7u )       /*����BlockSize*/
                {
                    TpCtrl.BlockSize = ( Length + 8u ) / 7u;    /*��Ч��(Length + 1) / 7 + 1*/
                }
                else
                {
                    TpCtrl.BlockSize = ( Length + 1u ) / 7u;
                }
                TpCtrl.Len       = 6u;            /*��֡�������ݳ���Ϊ6*/
                TpCtrl.BlockCnt  = 1u;            /*��¼�ѷ���Block��*/

                TransportTxData.N_PDU_FF.N_TAtype      = N_USDataTxBuffer.N_TAtype;
                TransportTxData.N_PDU_FF.N_PCI.Type    = FIRST_FRAME;
                TransportTxData.N_PDU_FF.N_PCI.FF_DL_H = ( uint8_t ) ( (uint16_t)(( TpCtrl.TotalLen >> 8u) & (0x000Fu) ));
                TransportTxData.N_PDU_FF.N_PCI.FF_DL_L = ( uint8_t ) ( TpCtrl.TotalLen & 0x00FFu );
                TransportTxData.N_PDU_FF.DLC           = 8u;

                for ( i = 0u; i < 6u; i++ )
                {
                    TransportTxData.N_PDU_FF.N_Data[i] = N_USDataTxBuffer.MsgData[i];
                }
            }

            id = TransportTxData.Frame.Identifier;
            dlc = TransportTxData.Frame.DLC;
            for (i = 0u; i < 8u; ++i)
            {
              data[i] = TransportTxData.Frame.Data[i];
            }
            /*TpCtrl.TxReq = 1u;*/
            DoCAN_Start_Timer ( TIMING_PARA_N_As );      /*����N_As��ʱ*/
            TpCtrl.Process = TP_TX_INIT;                  /*����֡�ѷ���,�ȴ��������*/
            DoCAN_L_Data_Request(id, dlc, data);
        }
    }
}

/******************************************************************************
��������DoCAN_N_USData_Confirm
��  �ܣ��÷�����������㷢��,����ȷ��ǰһ��ʹ��N_USData.request������
        N_TAtype��ַ���͵������Ƿ������
        The N_USData.confirm service is issued by the network layer. The service
        primitive confirms the completion of an N_USData.request service
        identified by the address information in N_TAtype.
��  ����N_TAtype ��N_USData.confirm��������ķ��͵�ַ
        N_Result ��N_USData.request����Ĵ���״̬
����ֵ����
******************************************************************************/
void DoCAN_N_USData_Confirm ( uint32_t N_TAtype, N_ResultEnum N_Result )
{
    UDS_N_USData_Confirm ( N_TAtype, N_Result );
}


/******************************************************************************
��������DoCAN_N_USData_FF_Indication
��  �ܣ��÷�����������㷢��,�������ϲ�ָʾ��ַΪN_TAtype��һ���֡���ݵ���֡
        �ĵ���
        The N_USData_FF.indication service is issued by the network layer. The
        service primitive indicates to the adjacent upper layer the arrival of
        a FirstFrame (FF) of a segmented message received from a peer protocol
        entity, identified by the address information N_TAtype.
��  ����N_TAtype ���µ��Ķ�֡������֡�ĵ�ַ��Ϣ
        Length   ���µ��Ķ�֡���ݵ��ܳ���
����ֵ����
******************************************************************************/
void DoCAN_N_USData_FF_Indication ( uint32_t N_TAtype, uint16_t Length )
{
    UDS_N_USData_FF_Indication ( N_TAtype, Length );
}

/******************************************************************************
��������DoCAN_N_USData_Indication
��  �ܣ��÷�����������㷢��,�������ϲ�ָ����N_TAtype��ַ�������ĳ���ΪLength
        ��MessageData���ݵĴ��ͽ��N_Result,��ͬʱ������һ����
        The N_USData.indication service is issued by the network layer. The
        service primitive indicates <N_Result> events and delivers
        <MessageData> with <Length> bytes received from a peer protocol entity
        identified by the address information in N_TAtype to the adjacent upper
        layer.
��  ����N_TAtype    �����յ������ݵ�ַ��Ϣ
        MessageData �����յ�������      (����N_ResultΪN_OKʱ��Ч)
        Length      �����յ������ݳ���  (����N_ResultΪN_OKʱ��Ч)
        N_Result    �����ݵĽ��ս��
����ֵ����
******************************************************************************/
void DoCAN_N_USData_Indication ( uint32_t N_TAtype, uint8_t *MessageData, uint16_t Length, N_ResultEnum N_Result )
{
    UDS_N_USData_Indication ( N_TAtype, MessageData, Length, N_Result );
}


/******************************************************************************
�²�ӿں���
******************************************************************************/

/******************************************************************************
��������DoCAN_L_Data_Request
��  �ܣ��÷���ԭ��������<Identifier>�����ض���ʽ��<Data>����
        The service primitive requests transmission of <Data> that shall be
        mapped within specific attributes of the data link protocol data unit
        selected by means of <Identifier>.
��  ����Identifier ������ID
        dlc        �����ݳ���
        Data       ������<Data>��������·��Ĵ�ŵ�ַ
����ֵ����
******************************************************************************/
void DoCAN_L_Data_Request ( uint32_t Identifier, uint8_t dlc, uint8_t Data[] )
{
    uint8_t i;
    uint8_t temp;
    //_CAN_TX_BUF_TYPE canMag;
    
    LinkTxCtrl.Identifier = Identifier;
    //canMag.SendID = Identifier;
    for ( i = 0u; i < dlc; i++ )
    {
        temp = Data[i];
        LinkTxCtrl.Data[i] = temp;
        //canMag.BUFF[i] = temp;
    } 
#if FILLER_BYTE_HANDLING
    for ( i = dlc; i < 8u; i++ )
    {
        LinkTxCtrl.Data[i] = FILLER_BYTE;
        //canMag.BUFF[i] = FILLER_BYTE;
    }
    //canMag.Len = 8u;
    CAN0_TX_BUF_Set(LinkTxCtrl.Data,Identifier,8);
    //MSCAN0_SendMsg(&canMag);
#else
   CAN0_TX_BUF_Set(LinkTxCtrl.Data,Identifier,8);
    //canMag.Len = dlc;
    //MSCAN0_SendMsg(&canMag);
#endif
    LinkTxCtrl.Busy  = 1u;
    //DoCAN_L_Data_Confirm(Identifier, DIAG_COMPLETE);
}

/******************************************************************************
��������DoCAN_L_Data_Confirm
��  �ܣ��÷���ԭ������ȷ�Ͼ����ض�<Identifier>�ı����Ƿ�����ɡ�
        <TransferStatus>�������ڴ��ݷ����������״̬��
        The service primitive confirms the completion of an L_Data.request
        service for a specific <Identifier>.The parameter <TransferStatus>
        provides the status of the service request.
��  ����Identifier     ������ID
        TransferStatus ��Not_Complete - δ���
                         Complete     - �ѷ������
����ֵ����
******************************************************************************/
void DoCAN_L_Data_Confirm ( uint32_t Identifier, uint8_t TransferStatus )
{
    /*������ݷ��ͳɹ�,�շ�״̬��Ӧ�ı�*/
    if (LinkTxCtrl.Identifier  == Identifier)
    {
        if (TransferStatus == DIAG_COMPLETE)
        {
            switch ( TpCtrl.Process )
            {
            case TP_TX_INIT :
                if ( TpCtrl.BlockSize == 1u )       /*BlockSizeΪ1,��֡���ͳɹ�*/
                {
                    TpCtrl.Process = TP_IDLE;               /*�������ݷ������,�ص�����״̬*/
                    DoCAN_Stop_Timer();                     /*ֹͣ��ʱ*/
                    DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_OK );
                }
                else                                      /*BlockSize��Ϊ1,��֡���ͳɹ�*/
                {
                    DoCAN_Start_Timer ( TIMING_PARA_N_Bs ); /*����N_Bs��ʱ*/
                    TpCtrl.Process = TP_TX_RTS;             /*�ȴ����ջ����ɶ�֡����*/
                }
                break;

            case TP_TX_CTS  :
                TpCtrl.BlockCnt++;
                if ( TpCtrl.BlockCnt == TpCtrl.BlockSize ) /*���һ֡�������*/
                {
                    TpCtrl.Process = TP_IDLE;               /*�������ݷ������,�ص�����״̬*/
                    DoCAN_Stop_Timer();                     /*ֹͣ��ʱ*/
                    /* DoCAN_Start_Timer(TIMING_PARA_N_Bs);*/
                    DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_OK );
                }
                else
                {
                    /* DoCAN_Start_Timer ( TIMING_PARA_N_Bs ); //����/����N_Bs��ʱ*/
                    if ( TpCtrl.BSMax )                     /*�����Լ�����������֡,������STmin��ʱ*/
                    {
                        DoCAN_Stop_Timer();
                        DoCAN_Start_STmin_Timer ( TpCtrl.STmin );
                    }
                    else
                    {
                        DoCAN_Start_Timer ( TIMING_PARA_N_Bs );
                    }
                }
                break;

            case TP_RX_RTS  :
                DoCAN_Start_Timer ( TIMING_PARA_N_Cr );   /*����N_Cr��ʱ*/
                TpCtrl.Process = TP_RX_CTS;
                break;

            case TP_RX_WAIT :
                DoCAN_Start_Timer ( TIMING_PARA_N_Cr );   /*����N_Cr��ʱ*/
                TpCtrl.Process = TP_RX_CTS;
                break;

            case TP_RX_OVFL :
                TpCtrl.Process = TP_IDLE;                 /*ֹͣ���չ���*/
                DoCAN_Stop_Timer();                       /*ֹͣ��ʱ*/
                DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                            N_USDataRxBuffer.Length, N_ERROR );
                break;

            default         :
                break;
            }
        }
        else
        {
           /* TpCtrl.TxReq = 1u;*/                                             /*����ʧ��,�ط�*/
        }
    }
}

/******************************************************************************
��������DoCAN_L_Data_Indication
��  �ܣ��÷���ԭ���ʾһ��������·���¼��������ϲ㲢����<Identifier>����<Data>
        The service primitive indicates a data link layer event to the adjacent
        upper layer and delivers <Data> identified by <Identifier>
��  ����Identifier ������ID
        dlc        �����ݳ���
        pData      ������<Data>��������·��Ĵ�ŵ�ַ
����ֵ����
******************************************************************************/
void DoCAN_L_Data_Indication ( uint32_t Identifier, uint8_t dlc, uint8_t pData[] )
{
    uint8_t i;

    if ( LinkRxFIFO.Depth >= LINK_RX_FIFO_MAX_DEPTH )                  /*FIFOδ��ʱװ�뱨��,������������*/
    {
        /*#if DOCAN_DEBUG_EN
                LINK_RX_FIFO_OVERFLOW_INDICATOR();
        #endif*/
    }
    else
    {
        LinkRxFIFO.LinkData[LinkRxFIFO.IPtr].Identifier = Identifier;      /*װ�뱨��ID*/
        for ( i = 0u; i < dlc; i++ )                                        /*��������*/
        {
            LinkRxFIFO.LinkData[LinkRxFIFO.IPtr].Data[i] =  pData[i];
        }
        LinkRxFIFO.LinkData[LinkRxFIFO.IPtr].DLC = dlc;                    /*���汨�ĳ���*/

        LinkRxFIFO.Depth++;                                                /*�±���װ��,���+1*/
        LinkRxFIFO.IPtr++;                                                 /*����ָ��+1*/
        if ( LinkRxFIFO.IPtr >= LINK_RX_FIFO_MAX_DEPTH )
        {
            LinkRxFIFO.IPtr = 0u;
        }
    }
}

/******************************************************************************
�����Э�����
******************************************************************************/

/******************************************************************************
��������DoCAN_Receive_And_Assemble_N_USData();
��  �ܣ�����N_PDU����������
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Receive_And_Assemble_N_USData ( void )
{
    DoCAN_Get_N_PDU();

    if ( TransportRxData.N_PDU.New )
    {
        switch ( TransportRxData.N_PDU.N_PCI.Type )
        {
        case SINGLE_FRAME       :
            DoCAN_Receive_Single_Frame_N_Data();
            break;

        case FIRST_FRAME        :
            DoCAN_Receive_First_Frame_N_Data();
            DoCAN_Transmit_Flow_Control();     /*��֡������Ϻ���뷢������֡*/
            break;

        case CONSECUTIVE_FRAME  :
            DoCAN_Receive_Consecutive_Frame_N_Data();
            DoCAN_Transmit_Flow_Control();     /*��������һ��BlockSizeʱ,��Ҫ��������֡*/
            break;

        case FLOW_CONTROL       :
            DoCAN_Receive_Flow_Control();
            break;

        default                 :
            DoCAN_Handle_Unknown_N_PDU();
            break;
        }
        TransportRxData.N_PDU_FC.New = 0u;
    }
}

/******************************************************************************
��������DoCAN_Get_N_PDU
��  �ܣ���������·���ȡN_PDU(network protocol data unit)
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Get_N_PDU ( void )
{
    uint8_t i;

    if ( LinkRxFIFO.Depth )                                                                     /*FIFO��������*/
    {
        TransportRxData.Frame.Identifier = LinkRxFIFO.LinkData[LinkRxFIFO.OPtr].Identifier;     /*ȡ��ID*/
        for ( i = 0u; i < 8u; i++ )                                                             /*��������*/
        {
            TransportRxData.Frame.Data[i] = LinkRxFIFO.LinkData[LinkRxFIFO.OPtr].Data[i];
        }
        TransportRxData.Frame.DLC = LinkRxFIFO.LinkData[LinkRxFIFO.OPtr].DLC;                   /*ȡ�����ĳ���*/
        TransportRxData.Frame.New = 1u;

        LinkRxFIFO.Depth--;                                                                     /*������ȡ��,���-1*/
        LinkRxFIFO.OPtr++;                                                                      /*���ָ��+1*/
        if ( LinkRxFIFO.OPtr >= LINK_RX_FIFO_MAX_DEPTH )
        {
            LinkRxFIFO.OPtr = 0u;
        }
    }
}

/******************************************************************************
��������DoCAN_Receive_Single_Frame_N_Data
��  �ܣ���֡���ݽ���
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Receive_Single_Frame_N_Data ( void )
{
    uint8_t i;
    uint32_t temp;
    if ( ( TpCtrl.Process & TP_DIR_MASK ) == TP_TX ) /*�����в�����*/
    {}
    else
    {
        /*---------------------------------------------------------------------------
        Whether the interleaving Tester Present messages would lead to a loss of CF
        or termination of the reception of an ongoing multiple frame request
        2018.11.29
        ---------------------------------------------------------------------------*/
        temp = TransportRxData.N_PDU_SF.N_TAtype;
        if (( TpCtrl.Process != TP_IDLE ) && ( temp != DIAG_ID_Rx_PHY ))
        {}
        else
        {
            /*---------------------------------------------------------------------------
            Tester sends a Single frame with a CAN-DLC shorter and equal to the transport
            protocol data length field. ECU must not send a response.
            2018.11.28���ӳ��Ȼ�Ҫ����8
            ---------------------------------------------------------------------------*/
            i = TransportRxData.N_PDU_SF.N_PCI.SF_DL;
            if ( TransportRxData.N_PDU_SF.DLC <= i )
            {}
            else if (TransportRxData.N_PDU_SF.DLC != 8u )
            {}
            else
            {
                /*---------------------------------------------------------------------------
                Tester sends a Single frame with a data length that is not allowed by the
                protocol. ECU must not send a response.
                ---------------------------------------------------------------------------*/
                if ( TransportRxData.N_PDU_SF.N_PCI.SF_DL == 0u )
                {}
                else if (TransportRxData.N_PDU_SF.N_PCI.SF_DL > 7u )
                {}
                else
                {
                    N_USDataRxBuffer.N_TAtype = TransportRxData.N_PDU_SF.N_TAtype;
                    N_USDataRxBuffer.Length   = TransportRxData.N_PDU_SF.N_PCI.SF_DL;
                    for ( i = 0u; i < N_USDataRxBuffer.Length; i ++ )
                    {
                        N_USDataRxBuffer.MsgData[i] = TransportRxData.N_PDU_SF.N_Data[i];
                    }

                    TpCtrl.Process = TP_IDLE;               /*�������,�ص�IDLE״̬*/
                    DoCAN_Stop_Timer();
                    DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                                N_USDataRxBuffer.Length, N_OK );
                }
            }
        }
    }
}

/******************************************************************************
��������DoCAN_Receive_First_Frame_N_Data
��  �ܣ�������֡���ݲ���ʼ����֡���ݽ���
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Receive_First_Frame_N_Data ( void )
{
    uint8_t  i;
    uint16_t Len;

    if ( ( TpCtrl.Process & TP_DIR_MASK ) == TP_TX ) /*�����в�����*/
    {}
    else
    {
        /*-----------------------------------------------------------------------------
        Tester sends a functional addressed First frame. ECU must not send a response.
        -----------------------------------------------------------------------------*/
        if ( TransportRxData.N_PDU_FF.N_TAtype != DIAG_ID_Rx_PHY )
        {}
        else
        {
            /*---------------------------------------------------------------------------
            (8.3) A FirstFrame protocol data unit (FF N_PDU), containing the first six
            data bytes
            ---------------------------------------------------------------------------*/
            if ( TransportRxData.N_PDU_FF.DLC != 8u )  /*��֡�ܳ�(N_PCI + N_Data)ӦΪ8*/
            {}
            else
            {
                /*---------------------------------------------------------------------------
                Tester sends a First frame with Data length set to 0. ECU must not send a
                response.
                -----------------------------------------------------------------------------
                (8.5.3.3) If the network layer receives an FF with an FF_DL that is less than
                eight when using normal addressing, then the network layer shall ignore the
                received FF N_PDU and not transmit an FC N_PDU.
                ---------------------------------------------------------------------------*/
                Len   = ( uint16_t ) ( TransportRxData.N_PDU_FF.N_PCI.FF_DL_H );
                Len <<= 8u;
                Len  |= ( uint16_t ) ( TransportRxData.N_PDU_FF.N_PCI.FF_DL_L );

                if ( Len < 8u )
                {}
                else
                {
                    /*---------------------------------------------------------------------------
                    Tester sends a First frame of a segmented request. After the receipt of the
                    ECU Flow Control the Tester sends another segmented request. The ECU must
                    send a response for the second request.
                    ---------------------------------------------------------------------------*/
#if (N_MAX_BS)
                    TpCtrl.NonStopMode = 0u;
#else
                    TpCtrl.NonStopMode = 1u;
#endif

                    TpCtrl.Len       = 6u;             /*��֡����6�ֽ�*/
                    TpCtrl.TotalLen  = Len;                     /*��¼�ֽ�����*/
                    TpCtrl.BlockCnt  = 1u;             /*��֡����1��block*/
                    TpCtrl.BSMax     = N_MAX_BS;                /*װ������BS��*/
                    TpCtrl.WFTCnt    = N_WFTmax;                /*װ�����ȴ�����*/

                    /*��֡��6�ֽ�����,����֡��7�ֽ�����,�����ֽ�������Block����*/
                    if ( ( TpCtrl.TotalLen + 1u ) % 7u )
                    {
                        TpCtrl.BlockSize = ( TpCtrl.TotalLen + 8u ) / 7u;   /*��Ч��(TpCtrl.TotalLen + 1) / 7 + 1*/
                    }
                    else
                    {
                        TpCtrl.BlockSize = ( TpCtrl.TotalLen + 1u ) / 7u;
                    }

                    /*��ʼ������֡����*/
                    N_USDataRxBuffer.N_TAtype = TransportRxData.N_PDU_FF.N_TAtype;
                    N_USDataRxBuffer.Length   = Len;
                    for ( i = 0u; i < 6u; i ++ )
                    {
                        N_USDataRxBuffer.MsgData[i] = TransportRxData.N_PDU_FF.N_Data[i];
                    }

                    DoCAN_Start_Timer ( TIMING_PARA_N_Br ); /*����N_Br��ʱ*/
                    TpCtrl.Process = TP_RX_INIT;
                    DoCAN_N_USData_FF_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.Length );
                }
            }
        }
    }
}

/******************************************************************************
��������DoCAN_Receive_Consecutive_Frame_N_Data
��  �ܣ���������֡����
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Receive_Consecutive_Frame_N_Data ( void )
{
    uint8_t i;

    /*---------------------------------------------------------------------------
    Tester sends a request with a response that is longer than one frame. After
    the Flow control the Tester sends a Consecutive frame. ECU must send a
    diagnostic response for the first request. ECU must not send a response
    for the Consecutive frame.
    -----------------------------------------------------------------------------
    Tester sends a single Consecutive frame. The ECU must not send a response.
    ---------------------------------------------------------------------------*/
    if ( TpCtrl.Process != TP_RX_CTS )
    {}
    else
    {
        if ( TransportRxData.N_PDU_CF.N_TAtype != DIAG_ID_Rx_PHY )
        {}
        else
        {
            /*---------------------------------------------------------------------------
            Send a request which requires more than 4 frames. Drop the third consecutive
            frame (CF). The ECU should not respond.
            -----------------------------------------------------------------------------
            Send a multi frame message to the ECU. Send the first consecutive frame (CF)
            twice. No response is expected.
            ---------------------------------------------------------------------------*/
            if ( TransportRxData.N_PDU_CF.N_PCI.SN != ( uint8_t ) ( TpCtrl.BlockCnt & (0x000Fu) ) )
            {
                TpCtrl.Process = TP_IDLE;               /*ֹͣ���չ���*/
                DoCAN_Stop_Timer();                     /*ֹͣ��ʱ*/
                DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                            N_USDataRxBuffer.Length, N_WRONG_SN );
            }
            else
            {
                TpCtrl.BlockCnt++;                        /*���յ�1��Block*/
                TpCtrl.BSMax--;

                if ( TpCtrl.BlockCnt < TpCtrl.BlockSize ) /*�˴ν��ղ������һ֡*/
                {
                    if ( TransportRxData.N_PDU_CF.DLC != 8u ) /*��ʱ����֡�ܳ�(N_PCI + N_Data)ӦΪ8*/
                    {}
                    else
                    {
                        for ( i = 0u; i < 7u; i++ )
                        {
                            N_USDataRxBuffer.MsgData[TpCtrl.Len] = TransportRxData.N_PDU_CF.N_Data[i];
                            TpCtrl.Len++;
                        }
                        DoCAN_Start_Timer ( TIMING_PARA_N_Cr ); /*����N_Cr��ʱ*/
                    }
                }
                else                                      /*�˴ν��������һ֡*/
                {
                    /*-------------------------------------------------------------------------
                    In a segmented request the Tester sends a Consecutive frame with a CAN-DLC
                    shorter or equal to transport protocol data length field. ECU must not send
                    a response.
                    2018.11.28���ӳ���Ӧ�õ���8
                    -------------------------------------------------------------------------*/
                    if ( TransportRxData.N_PDU_CF.DLC <= TpCtrl.TotalLen - TpCtrl.Len )
                    {}
                    else if ( TransportRxData.N_PDU_CF.DLC != 8u )/*��ʱ����֡�ܳ�Ӧ��С��ʣ�����ݳ���*/
                    {}
                    else
                    {
                        i = 0u;
                        while ( TpCtrl.Len < TpCtrl.TotalLen )
                        {
                            N_USDataRxBuffer.MsgData[TpCtrl.Len] = TransportRxData.N_PDU_CF.N_Data[i];
                            i++;
                            TpCtrl.Len++;
                        }

                        TpCtrl.Process = TP_IDLE;               /*�������,�ص�IDLE״̬*/
                        DoCAN_Stop_Timer();
                        DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                                    N_USDataRxBuffer.Length, N_OK );
                    }
                }
            }
        }
    }
}

/******************************************************************************
��������DoCAN_Receive_Flow_Control
��  �ܣ���������֡����
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Receive_Flow_Control ( void )
{
    /*--------------------------------------------------------------------------
    Tester sends a segmented request interrupted by a Flow control after the ECU
    Flow control. After that the Tester sends the remaining consecutive frames.
    ECU should send a diagnostic response for the request.
    -----------------------------------------------------------------------------
    Tester sends a single Flow Control. The ECU must not send a response.
    ---------------------------------------------------------------------------*/
    if ( ( TpCtrl.Process != TP_TX_RTS ) && ( TpCtrl.Process != TP_TX_CTS ) && ( TpCtrl.Process != TP_TX_WAIT ) )
    {}
    else
    {
        /*---------------------------------------------------------------------------
        Tester sends a request with a response that is longer than one frame. After
        the First frame is received the Tester sends a functional addressed Flow
        control. ECU must abort sending of the response.
        ---------------------------------------------------------------------------*/
        if ( TransportRxData.N_PDU_FC.N_TAtype != DIAG_ID_Rx_PHY )
        {
            DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_ERROR );
            DoCAN_Stop_Timer();                   /*ֹͣ��ʱ*/
            TpCtrl.Process = TP_IDLE;             /*��ֹ���ݷ���,�ص�����״̬*/
        }
        else
        {
            /*---------------------------------------------------------------------------
            Tester sends a Flow control with a too short CAN-DLC for a response that is
            longer than one frame. ECU must not send Consecutive frames. After that the
            tester sends a new request. ECU must send a response for the last request.
            ---------------------------------------------------------------------------*/
            if( TransportRxData.N_PDU_FC.DLC != 8u )
            {
                DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_ERROR );
                DoCAN_Stop_Timer();                   /*ֹͣ��ʱ*/
                TpCtrl.Process = TP_IDLE;             /*��ֹ���ݷ���,�ص�����״̬*/
            }
            else
            {
                switch ( TransportRxData.N_PDU_FC.N_PCI.FS )
                {
                case FC_FS_CTS  :
                    if ( TpCtrl.NonStopMode )
                    {
                        break;
                    }

                    /*-------------------------------------------------------
                    Tester sends a Flow control with Blocksize 0 for a
                    response that is longer than one frame. ECU must send the
                    complete response.
                    ---------------------------------------------------------
                    Tester sends a Flow control with Blocksize 0 for a
                    response that is longer than one frame. ECU must send the
                    complete response without waiting for another Flow
                    control. Tester verifies that every Consecutive frame is
                    received within TimeoutCr.
                    -------------------------------------------------------*/
                    if ( TransportRxData.N_PDU_FC.N_PCI.BS == 0u )
                    {
                        TpCtrl.NonStopMode = 1u;
                    }

                    /*-------------------------------------------------------
                    Tester sends a Flow control with a special Blocksize for
                    a response that is longer than one frame. ECU must send
                    the number of Consecutive frames that matches the
                    blocksize. Blocksize 1, 8 and 20 is checked if the
                    response is long enough.
                    -------------------------------------------------------*/
                    else
                    {
                        TpCtrl.BSMax = TransportRxData.N_PDU_FC.N_PCI.BS;
                    }

                    /*-------------------------------------------------------
                    Tester sends a Flow control for a response that is longer
                    than one frame. ECU must send the complete response.
                    Tester verifies that the time between the Consecutive
                    Frames is not below STMin time. This is tested for STMin
                    values 1,10,20,30,40,50 and 60.
                    2018.11.29����Ϊ���ڷ�����֡ʱ���Եڶ������ص�stmin
                    -------------------------------------------------------*/
                    if ( TpCtrl.Process != TP_TX_CTS )
                    {
                        if ( TransportRxData.N_PDU_FC.N_PCI.STmin != 0u)
                        {
                            TpCtrl.STmin = TransportRxData.N_PDU_FC.N_PCI.STmin;
                        }
                        else
                        {
                            TpCtrl.STmin = 1u;
                        }
                    }
                    /*-------------------------------------------------------
                    Request a service where the response requires more than
                    one response frame. Tester sends two Flow Controls (FC)
                    instead of one. A response from the ECU is expected.
                    -------------------------------------------------------*/
                    TpCtrl.Process = TP_TX_CTS;             /*���ͻ������ɷ���*/
                    DoCAN_Stop_Timer();
                    DoCAN_Start_STmin_Timer ( TpCtrl.STmin ); /*����STmin��ʱ*/
                    break;

                case FC_FS_WAIT :
                    if ( TpCtrl.NonStopMode )
                    {
                        break;
                    }

                    /*-------------------------------------------------------
                    Tester sends a Flow control with Status value wait (WT)
                    for a response that is longer than one frame. ECU must
                    not send Consecutive frames. After the N_Bs Timeout the
                    Tester sends another Flow control with status continue to
                    send (CTS). Then the tester sends a new request. ECU must
                    send a response for the last request.
                    -------------------------------------------------------*/
                    TpCtrl.Process = TP_TX_WAIT;            /*���ջ������ͻ��ȴ�*/
                    DoCAN_Start_Timer ( TIMING_PARA_N_Bs ); /*����/����N_Bs��ʱ*/
                    break;

                case FC_FS_OVFL :
                    if ( TpCtrl.NonStopMode )
                    {
                        break;
                    }

                    /*-------------------------------------------------------
                    Tester sends a Flow control with status overflow for a
                    response that is longer than one frame. ECU must not send
                    Consecutive frame(s).
                    ---------------------------------------------------------
                    Tester sends a request with a response that is longer
                    than one frame. After sending the Flow control the Tester
                    receives the first Consecutive frame and sends another
                    Flow control with status overflow (OVFLW). ECU must send
                    a diagnostic response for the first request. ECU must not
                    send a response for the Flow control.
                    -------------------------------------------------------*/
                    if ( TpCtrl.Process == TP_TX_RTS )
                    {
                        DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_BUFFER_OVFLW );
                        DoCAN_Stop_Timer();                   /*ֹͣ��ʱ*/
                        TpCtrl.Process = TP_IDLE;             /*��ֹ���ݷ���,�ص�����״̬*/
                    }
                    break;

                default         : /*-------------------------------------------------------
                                  Tester sends a Flow control with an invalid Status value
                                  (3-15) for a response that is longer than one frame. ECU
                                  must not send a response.
                                  -------------------------------------------------------*/
                    DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_INVALID_FS );
                    DoCAN_Stop_Timer();                   /*ֹͣ��ʱ*/
                    TpCtrl.Process = TP_IDLE;             /*��ֹ���ݷ���,�ص�����״̬*/
                    break;
                }
            }
        }
    }
}

/******************************************************************************
��������DoCAN_Transmit_Flow_Control
��  �ܣ����ݵ�ǰ�Ľ��ջ�״̬��������֡
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Transmit_Flow_Control ( void )
{
      uint8_t i;
      uint32_t id;
      uint8_t dlc;
      uint8_t data[8];
  
    if ( TpCtrl.Process == TP_RX_INIT )
    {
        /*-------------------------------------------------------------------------
        (8.5.3.3) If the network layer receives an FF with an FF_DL that is greater
        than the available receiver buffer size, then this shall be considered as
        an error condition. The network layer shall abort the message reception and
        send an FC N_PDU with the parameter FlowStatus = Overflow.
        -------------------------------------------------------------------------*/
        if ( N_USDataRxBuffer.Length > N_USDATA_RX_BUFFER_SIZE )
        {
            TransportTxData.N_PDU_FC.N_PCI.FS = FC_FS_OVFL;
            TpCtrl.Process = TP_RX_OVFL;
        }
        else
        {
            TransportTxData.N_PDU_FC.N_PCI.FS = FC_FS_CTS;
            TpCtrl.Process = TP_RX_RTS;
        }

        TransportTxData.N_PDU_FC.N_TAtype    = DIAG_ID_Tx;
        TransportTxData.N_PDU_FC.N_PCI.Type  = FLOW_CONTROL;
        TransportTxData.N_PDU_FC.N_PCI.BS    = TpCtrl.BSMax;
        /*---------------------------------------------------------------------------
        Tester sends a segmented request to check for a valid STMin time in the ECU
        Flow control. The STMin time value must be within 0x01-0x7F or 0xF1-0xF9.
        ---------------------------------------------------------------------------*/
        TransportTxData.N_PDU_FC.N_PCI.STmin = N_STmin;
        TransportTxData.N_PDU_FC.DLC         = 3u;

        /*TpCtrl.TxReq = 1u;*/
       
        id = TransportTxData.Frame.Identifier;
        dlc = TransportTxData.Frame.DLC;
        for (i = 0u; i < 8u; ++i)
        {
          data[i] = TransportTxData.Frame.Data[i];
        }
        DoCAN_Start_Timer ( TIMING_PARA_N_Ar );      /*����N_Ar��ʱ*/
        DoCAN_L_Data_Request(id, dlc, data);
        
        
    }
    else if ( TpCtrl.Process == TP_RX_CTS )
    {
        if ( TpCtrl.BSMax )           /*��Ȼû�н�����һ��BS��N_PDU*/
        {}
        else
        {
            if ( TpCtrl.NonStopMode )     /*�������������ģʽ(BS��������0)*/
            {}
            else
            {
                /*
                if (0)                        //�������ȴ�����,���͵ȴ�FC֡
                {
                  if(TpCtrl.WFTCnt == 0)
                  {
                    TpCtrl.Process = TP_IDLE;
                    DoCAN_Stop_Timer();
                    DoCAN_N_USData_Indication(N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                              N_USDataRxBuffer.Length, N_WFT_OVRN);
                    return;
                  }

                  TpCtrl.WFTCnt--;
                  TransportTxData.N_PDU_FC.N_PCI.FS = FC_FS_WAIT;
                }*/

                TpCtrl.BSMax = N_MAX_BS;      /*����װ������BS��*/
                TransportTxData.N_PDU_FC.N_PCI.FS = FC_FS_CTS;
                TpCtrl.Process = TP_RX_RTS;   /*�ȴ�RTS�������*/

                TransportTxData.N_PDU_FC.N_TAtype    = DIAG_ID_Tx;
                TransportTxData.N_PDU_FC.N_PCI.Type  = FLOW_CONTROL;
                TransportTxData.N_PDU_FC.N_PCI.BS    = TpCtrl.BSMax;
                /*---------------------------------------------------------------------------
                Tester sends a segmented request to check for a valid STMin time in the ECU
                Flow control. The STMin time value must be within 0x01-0x7F or 0xF1-0xF9.
                ---------------------------------------------------------------------------*/
                TransportTxData.N_PDU_FC.N_PCI.STmin = N_STmin;
                TransportTxData.N_PDU_FC.DLC         = 3u;

                /*TpCtrl.TxReq = 1u;*/
                id = TransportTxData.Frame.Identifier;
                dlc = TransportTxData.Frame.DLC;
                for (i = 0u; i < 8u; ++i)
                {
                    data[i] = TransportTxData.Frame.Data[i];
                }
		DoCAN_Start_Timer ( TIMING_PARA_N_Ar );      /*����N_Ar��ʱ*/		
                DoCAN_L_Data_Request(id, dlc, data);
                
               
            }
        }
    }
    else
    {}
}

/******************************************************************************
��������DoCAN_Handle_Unknown_N_PDU
��  �ܣ��������յ���δ֪���͵�N_PDU
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Handle_Unknown_N_PDU ( void )
{

}

/******************************************************************************
��������DoCAN_Disassemble_And_Transmit_N_USData
��  �ܣ������ݲ��Ϊ����֡(CF)�����ͳ�ȥ
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Disassemble_And_Transmit_N_USData ( void )
{
    uint8_t i;
    uint32_t id;
    uint8_t dlc;
    uint8_t data[8];
    uint8_t Len;

    if ( TpCtrl.Process != TP_TX_CTS )  /*δ������ʱ�����Է�������֡*/
    {}
    else
    {
        /*����STmin��ʱʱ�䵽����һ��*/
        if ( DoCAN_Get_STmin_Timer_Status() == STmin_TIME_UP )
        {
            TransportTxData.N_PDU_CF.N_TAtype   = N_USDataTxBuffer.N_TAtype;
            TransportTxData.N_PDU_CF.N_PCI.Type = CONSECUTIVE_FRAME;
            TransportTxData.N_PDU_CF.N_PCI.SN   = ( uint8_t ) ( TpCtrl.BlockCnt & 0x000Fu );

            /*��BSMax��С��0ʱ,��·�����ݷ�����Ϻ�,������������STmin������(�����DoCAN_L_Data_Confirm������*/
            /*���STmin_TIME_UP״̬�������ٳ���,�Ӷ�ֹͣ������֡�ķ���*/
            /*ֱ�����µ�CF֡������BSMax������ֵ,��N_Bs��ʱ��ʱ*/
            TpCtrl.BSMax--;

            if (TpCtrl.BlockCnt < TpCtrl.BlockSize - 1u)         /*��Ҫ���͵Ĳ������һ֡*/
            {
                TransportTxData.N_PDU_CF.DLC = 8u;
                for ( i = 0u; i < 7u; i++ )
                {
                    TransportTxData.N_PDU_CF.N_Data[i] = N_USDataTxBuffer.MsgData[TpCtrl.Len];
                    TpCtrl.Len++;
                }

                /*TpCtrl.TxReq = 1u;*/
                id = TransportTxData.Frame.Identifier;
                dlc = TransportTxData.Frame.DLC;
                for (i = 0u; i < 8u; ++i)
                {
                  data[i] = TransportTxData.Frame.Data[i];
                }
                DoCAN_Start_Timer ( TIMING_PARA_N_As );      /*����N_As��ʱ*/
	        DoCAN_L_Data_Request(id, dlc, data);
               
               
            }
            else if (TpCtrl.BlockCnt == TpCtrl.BlockSize - 1u)   /*��Ҫ�������һ֡*/
            {
                Len = ( uint8_t ) ( TpCtrl.TotalLen - TpCtrl.Len );

                TransportTxData.N_PDU_CF.DLC = Len + 1u;
                for ( i = 0u; i < Len; i++ )
                {
                    TransportTxData.N_PDU_CF.N_Data[i] = N_USDataTxBuffer.MsgData[TpCtrl.Len];
                    TpCtrl.Len++;
                }
                id = TransportTxData.Frame.Identifier;
                dlc = TransportTxData.Frame.DLC;
                for (i = 0u; i < 8u; ++i)
                {
                  data[i] = TransportTxData.Frame.Data[i];
                }
		DoCAN_Start_Timer ( TIMING_PARA_N_As );      /*����N_As��ʱ*/		  
                DoCAN_L_Data_Request(id, dlc, data);
               /* TpCtrl.TxReq = 1u;*/
               
              
            }
            else    /*�ѷ���֡�������ܴ���֡����,�����д�����*/
            {
                DoCAN_Stop_Timer();                           /*ֹͣ��ʱ*/
                TpCtrl.Process = TP_IDLE;                     /*��ֹ���ݷ���,�ص�����״̬*/
                DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_ERROR );
            }
        }
    }
}

/******************************************************************************
�����ʱ�����
******************************************************************************/
/******************************************************************************
��������DoCAN_Update_Timer
��  �ܣ���ʱ�����º���
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Update_Timer ( void )
{
    uint16_t CurrentCnt;
    uint16_t Dec;

    CurrentCnt = TpTimingCtrl.Cnt;
    if ( CurrentCnt != TpTimingCtrl.LastCnt ) /*��ʱ������ֵ�и���*/
    {
        if ( CurrentCnt > TpTimingCtrl.LastCnt )
        {
            Dec = CurrentCnt - TpTimingCtrl.LastCnt;
        }
        else
        {
            Dec = 65535u - TpTimingCtrl.LastCnt + 1u + CurrentCnt;
        }

        TpTimingCtrl.LastCnt = CurrentCnt;

        if ( TpTimingCtrl.Type != TIMING_PARA_NONE )
        {
            if ( TpTimingCtrl.NTimer )
            {
                if ( TpTimingCtrl.NTimer > ( uint32_t ) Dec )
                {
                    TpTimingCtrl.NTimer -= Dec;
                }
                else
                {
                    TpTimingCtrl.NTimer  = 0u;
                }
            }
        }

        if ( TpTimingCtrl.STminStatus == STmin_TIMING )
        {
            if ( TpTimingCtrl.STimer )
            {
                if ( TpTimingCtrl.STimer > ( uint32_t ) Dec )
                {
                    TpTimingCtrl.STimer -= Dec;
                }
                else
                {
                    TpTimingCtrl.STimer  = 0u;
                }
            }

            if ( TpTimingCtrl.STimer == 0u )
            {
                TpTimingCtrl.STminStatus = STmin_TIME_UP;
            }
        }
    }
}

/******************************************************************************
��������DoCAN_Handle_Time_Out
��  �ܣ���ʱ����
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Handle_Time_Out ( void )
{
    if ( TpTimingCtrl.NTimer == 0u )           /*��ʱ��ʱ*/
    {
        switch ( TpTimingCtrl.Type )
        {
        case TIMING_PARA_N_As :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ�����շ�,�ص�����״̬*/
                DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_TIMEOUT_A );
            }
            break;

        case TIMING_PARA_N_Ar :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ�����շ�,�ص�����״̬*/
                DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                            N_USDataRxBuffer.Length, N_TIMEOUT_A );
            }
            break;

        case TIMING_PARA_N_Bs :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ���ݷ���,�ص�����״̬*/
                DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_TIMEOUT_Bs );
            }
            break;

        case TIMING_PARA_N_Br :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ�����շ�,�ص�����״̬*/
                DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                            N_USDataRxBuffer.Length, N_ERROR );
            }
            break;

        case TIMING_PARA_N_Cs :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ�����շ�,�ص�����״̬*/
                DoCAN_N_USData_Confirm ( N_USDataTxBuffer.N_TAtype, N_ERROR );
            }
            break;

        case TIMING_PARA_N_Cr :
            if ( TpCtrl.Process != TP_IDLE )
            {
                TpCtrl.Process = TP_IDLE;   /*��ֹ���ݽ���,�ص�����״̬*/
                DoCAN_N_USData_Indication ( N_USDataRxBuffer.N_TAtype, N_USDataRxBuffer.MsgData, \
                                            N_USDataRxBuffer.Length, N_TIMEOUT_Cr );
            }
            break;

        default               :
            break;
        }

        DoCAN_Stop_Timer();                     /*ֹͣ��ʱ*/
    }
}

void UDS_TP_ArTimeOutHandle(void)
{
   
    //Can_Uds_Abort();
}

/******************************************************************************
��������DoCAN_Start_Timer
��  �ܣ�����ʱ��ʱ��
��  ����TimingParameter ��ʱ�����,���������в����е�һ��
                          TIMING_PARA_N_As
                          TIMING_PARA_N_Ar
                          TIMING_PARA_N_Bs
                          TIMING_PARA_N_Br
                          TIMING_PARA_N_Cs
                          TIMING_PARA_N_Cr
����ֵ����
******************************************************************************/
void DoCAN_Start_Timer ( uint8_t TimingParameter )
{
    switch ( TimingParameter )
    {
    case TIMING_PARA_N_As :
        TpTimingCtrl.Type   = TIMING_PARA_N_As;
        TpTimingCtrl.NTimer = N_As * (uint32_t) 1000;
        break;

    case TIMING_PARA_N_Ar :
        TpTimingCtrl.Type   = TIMING_PARA_N_Ar;
        TpTimingCtrl.NTimer = N_Ar * (uint32_t) 1000;
        break;

    case TIMING_PARA_N_Bs :
        TpTimingCtrl.Type   = TIMING_PARA_N_Bs;
        TpTimingCtrl.NTimer = N_Bs * (uint32_t) 1000;
        break;

    case TIMING_PARA_N_Br :
        TpTimingCtrl.Type   = TIMING_PARA_N_Br;
        TpTimingCtrl.NTimer = N_Br * (uint32_t) 1000;
        break;

    case TIMING_PARA_N_Cs :
        TpTimingCtrl.Type   = TIMING_PARA_N_Cs;
        TpTimingCtrl.NTimer = N_Cs * (uint32_t) 1000;
        break;

    case TIMING_PARA_N_Cr :
        TpTimingCtrl.Type   = TIMING_PARA_N_Cr;
        TpTimingCtrl.NTimer = N_Cr * (uint32_t) 1000;
        break;

    default               :
        TpTimingCtrl.Type   = TIMING_PARA_NONE;
        TpTimingCtrl.NTimer = (uint32_t) 0;
        break;

    }
}

/******************************************************************************
��������DoCAN_Stop_Timer
��  �ܣ�ֹͣʱ��ʱ��
��  ������
����ֵ����
******************************************************************************/
void DoCAN_Stop_Timer ( void )
{
    TpTimingCtrl.Type = TIMING_PARA_NONE;
}

/******************************************************************************
��������DoCAN_Start_STmin_Timer
��  �ܣ�����STmin��ʱ��
��  ����STminTime��STminʱ��
����ֵ����
******************************************************************************/
void DoCAN_Start_STmin_Timer ( uint8_t STminTime )
{
    if ( STminTime <= 0x7Fu )                              /*0x00 - 0x7F��0ms - 127ms*/
    {
      
        STminTime++;
      
      TpTimingCtrl.STimer = ((uint32_t) (STminTime) * (uint32_t) 1000);
    }
    else if ( ( STminTime >= 0xF1u ) && ( STminTime <= 0xF9u ) ) /*0xF1 - 0xF9��100us - 900us*/
    {
        TpTimingCtrl.STimer = (((uint32_t) STminTime) & (uint32_t) 0x0000000F) * (uint32_t) 100;
    }
    else                                                  /*Reserved   ��127ms*/
    {
        TpTimingCtrl.STimer = ( uint32_t ) 128000;
    }

    TpTimingCtrl.STminStatus = STmin_TIMING;              /*STmin��ʼ��ʱ*/
}

/******************************************************************************
��������DoCAN_Get_STmin_Timer_Status
��  �ܣ���ȡ��ǰSTmin��ʱ����״̬
��  ������
����ֵ��STmin_TIMER_IDLE��STmin��ʱ������
        STmin_TIME_UP   ��STmin��ʱʱ�䵽
        STmin_TIMING    ��STmin��ʱ����ʱ��
******************************************************************************/
uint8_t DoCAN_Get_STmin_Timer_Status ( void )
{
    uint8_t Status;

    Status = TpTimingCtrl.STminStatus;

    if ( Status == STmin_TIME_UP )
    {
        TpTimingCtrl.STminStatus = STmin_TIMER_IDLE;
    }
    return Status;
}
