/*
*********************************************************************
* Includes
*********************************************************************
*/

#include "kwp2000_tp.h"
#include "kwp2000_service.h"
#include "kwp2000_protocol.h"
#include "kwp2000_interface.h"

/*
*********************************************************************
* structure
*********************************************************************
*/

typedef unsigned char Kwp2000_Service_t(unsigned char *, unsigned char *);

typedef struct
{
    unsigned char sId;
    Kwp2000_Service_t *Kwp2000_Servie;
} Kwp2000_ServiceTab_Entry_t;

/*
*********************************************************************
* variable
*********************************************************************
*/

unsigned long Kwp2000_ComState_Flag;

/*
*********************************************************************
* function
*********************************************************************
*/
void Kwp2000_CallService(unsigned char Sid_u8);
unsigned char kwp2000_CalcSeriveTabSize(void);

/*-----------------------------------------------------------------------------------*/
const Kwp2000_ServiceTab_Entry_t Kwp2000_ServiceTab[] =
{
    {KWP2000_ECURESET_REQUEST,                              kwp_EcuReset                        }, /* 0x11 */
    {KWP2000_TESTERPRESENT_REQUEST,                         kwp_TesterPresent                   }, /* 0x3E */
    {KWP2000_STARTCOMMUNICATION_REQUEST,                    kwp_StartCommunication              }, /* 0x81 */
    {KWP2000_STOPCOMMUNICATION_REQUEST,                     kwp_StopCommunication               }, /* 0x82 */
    {KWP2000_READECUIDENTIFICATION_REQUEST,                 kwp_readEcuIdentification           }, /* 0x1A */
    {KWP2000_WRITEDATABYLOCALIDENTIFIER_REQUEST,            kwp_writeDataByLocalIdentifier      }, /* 0x3B */
    {KWP2000_READDATABYLOCALIDENTIFIER_REQUEST,             kwp_readDataByLocalIdentifier       }, /* 0x21 */
    {KWP2000_READDATABYCOMMONIDENTIFIER_REQUEST,            kwp_readDataByCommonIdentifier      }, /* 0x22 */
    {KWP2000_READDIAGNOSTICTROUBLECODESBYSTATUS_REQUEST,    kwp_readDataStatusofDTC             }, /* 0x18 */
    {KWP2000_CLEARDIAGNOSTICINFORMATION_REQUEST,            kwp_ClearDiagnosticInformation      }, /* 0x14 */
    {KWP2000_SECURITYACCESS_REQUEST,                        kwp_readDataAccessMode              }, /* 0x27 */
    {KWP2000_STARTROUTINEBYLOCALIDENTIFIER_REQUEST,         kwp_StartroutInebykocalIdentifier   }, /* 0x31 */
};

/*-------------------------------------------------------------------------
* Function Name  : Kwp2000_CallService
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void Kwp2000_CallService(unsigned char Sid_u8)
{
    unsigned char serviceFound;
    unsigned char index;

    serviceFound = 0;
    Kwp2000_Negative.ResponseCode = 0;
#if 0
    for (index = 0; index < kwp2000_CalcSeriveTabSize(); index++)
    {
        if (Kwp2000_ServiceTab[index].sId == Sid_u8)
        {
            serviceFound = 1;

            Kwp2000_ComState.Tx_len = Kwp2000_ServiceTab[index].Kwp2000_Servie((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                      (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
            break;
        }
    }
#endif
    switch (Sid_u8)
    {
    case KWP2000_ECURESET_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_EcuReset((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                               (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_TESTERPRESENT_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_TesterPresent((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_STARTCOMMUNICATION_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_StartCommunication((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_STOPCOMMUNICATION_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_StopCommunication((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_READECUIDENTIFICATION_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_readEcuIdentification((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_WRITEDATABYLOCALIDENTIFIER_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_writeDataByLocalIdentifier((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_READDATABYLOCALIDENTIFIER_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_readDataByLocalIdentifier((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_READDATABYCOMMONIDENTIFIER_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_readDataByCommonIdentifier((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_READDIAGNOSTICTROUBLECODESBYSTATUS_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_readDataStatusofDTC((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_CLEARDIAGNOSTICINFORMATION_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_ClearDiagnosticInformation((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_SECURITYACCESS_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_readDataAccessMode((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    case KWP2000_STARTROUTINEBYLOCALIDENTIFIER_REQUEST:
        serviceFound = 1;
        Kwp2000_ComState.Tx_len = kwp_StartroutInebykocalIdentifier((unsigned char *)&Kwp2000_ComState.TxBuffer[4],
                                  (unsigned char *)&Kwp2000_ComState.Request_Datas[1]);
        break;
    default:
        break;
    }

    if (serviceFound == 0)
    {
        Kwp2000_ComState.Tx_len = kwp_NegativeResponse(Sid_u8, KWP2000_serviceNotSupported, (unsigned char *)&Kwp2000_ComState.TxBuffer[4]);
    }
    else if (Kwp2000_Negative.ResponseCode) /*其他负反馈处理 后添加原来没有*/
    {
        Kwp2000_ComState.Tx_len = kwp_NegativeResponse(Sid_u8, Kwp2000_Negative.ResponseCode, (unsigned char *)&Kwp2000_ComState.TxBuffer[4]);
        Kwp2000_Negative.ResponseCode = 0;
    }

    if (Kwp2000_ComState.Tx_len != 0)
    {
        Kwp2000_ComState.Tx_len += Kwp2000_PrepareHeader(Kwp2000_ComState.Tx_len);

        *(Kwp2000_ComState.Response_Datas + Kwp2000_ComState.Tx_len) = Kwp2000_ChecksumCalculate(Kwp2000_ComState.Response_Datas, Kwp2000_ComState.Tx_len);

        Kwp2000_ComState.Tx_len++;
    }
}

/*-------------------------------------------------------------------------
* Function Name  : Kwp2000_Handle
* Description    :
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
void Kwp2000_Handle(void)
{
    if ((Kwp2000_ComMode & PROTOCOL) == KWP2000)
    {
        /*在FAST_INIT之后，如果在RX中断中接收数据，在转为几首模式，在FAST_INIT后加一个超时时间
        如果FAST_INIT后10ms没有接到新到来得数据就会回到等待空闲模式避免来个wakeup后仪表无法接收数据*/
        /*
        if(Kwp2000_ComMode == KWP2000_FAST_INIT)
        {
            Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
        }
        */
        switch (Kwp2000_ComMode)
        {
        case KWP2000_WAIT_RECEPTION: /* 0x22 */
            if (Kwp2000_ComState.Rx_len >= 1)
            {
                Kwp2000_ComState.headerSize = Kwp2000_FormatAnalyse();
                Kwp2000_ComMode = KWP2000_WAIT_HEADER;
            }
            break;
        case KWP2000_WAIT_HEADER: /* 0x23 */
            if (Kwp2000_ComState.Rx_len >= Kwp2000_ComState.headerSize)
            {
                Kwp2000_HeaderAnalyse();

                /* Tests the Target address */
                if (kwp2000_AddressTest() != 1)
                {
                    /* This message is not for this ECU */
                    Kwp2000_CommuniationDown();
                    Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
                }
                else
                {
                    Kwp2000_ComMode = KWP2000_WAIT_DATAS;
                }
            }
            break;
        case KWP2000_COMMUNICATION: /* 0x25 */
        case KWP2000_WAIT_DATAS:    /* 0x24 */
            if (Kwp2000_ComState.Rx_len > (Kwp2000_ComState.headerSize + Kwp2000_ComState.kwp2000_Len))
            {
                Kwp2000_ComState.kwp2000_Checksum = Kwp2000_ComState.RxBuffer[Kwp2000_ComState.headerSize + Kwp2000_ComState.kwp2000_Len];

                if (Kwp2000_VerifyChecksum())
                {
                    Kwp2000_ComMode = KWP2000_BUILD_RESPONSE;
                    break;
                }
                else
                {
                    Kwp2000_CommuniationDown();
                    Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
                    break;
                }
            }
            else
            {
            }
            break;
        case KWP2000_BUILD_RESPONSE: /* 0x26 */
            if (!Kwp2000_ComState.ResponsePending)
            {
                Kwp2000_ComState.SId = *(Kwp2000_ComState.Request_Datas);
            }
            else
            {
                /* do nothing */
            }

            Kwp2000_ComState_Flag++;
            if (Kwp2000_ComState_Flag > 7)
            {
                Kwp2000_ComState_Flag = 0;
                Kwp2000_CallService(Kwp2000_ComState.SId);
            }

            if (Kwp2000_ComState.Tx_len != 0)
            {
                Kwp2000_AscTx(Kwp2000_ComState.Response_Datas); /*qitiancun 数据发送----20220303----*/
                Kwp2000_ComMode = KWP2000_SEND_RESPONSE;
            }
            else
            {
                Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
            }
            break;
        case KWP2000_SEND_RESPONSE: /* 0x27 */
            /* Wait when sending response message */
            if (Kwp2000_ComState.Tx_len)
            {
            }
            else
            {
            }
            break;
        case KWP2000_MODIFY_CONFIG: /* 0x28  */
            switch (Kwp2000_Modify.typeOfModif)
            {
            case KWP2000_MODIFY_NULL:
                Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
                Kwp2000_ComState.Rx_len = 0;
                break;

            case KWP2000_MODIFY_BAUDRATE:
                Kwp2000_ComMode = KWP2000_WAIT_RECEPTION;
                Kwp2000_AscSwitchBaudrate(Kwp2000_Modify.newBaudRate);
                Kwp2000_Modify.typeOfModif = KWP2000_MODIFY_NULL;
                Kwp2000_ComState.Rx_len = 0;
                break;

            case KWP2000_MODIFY_RESET:
                Kwp2000_ComState.Rx_len = 0;
                switch (Kwp2000_Modify.resetType)
                {
                case 0x01:
                    // Reset_SWResetRequest(SWRESET_GRP_POWERON_E, SWRESET_POWERON_E, 0x0);  qitiancun
                    break;
                case 0x6A:
                    // Reset_SWResetRequest(SWRESET_GRP_SB_E, SWRESET_RB_PROG_E, 0x0);  qitiancun
                    break;
                default:
                    /*do nothing */
                    break;
                }
                break;

            case KWP2000_MODIFY_END:
                Kwp2000_ProtocolInit();
                break;

            default:
                break;
            }
            break;
        case KWP2000_END:
            break;
        default:
            break;
        }
    }
}

/*-------------------------------------------------------------------------
* Function Name  : kwp2000_CalcSeriveTabSize
* Description    : kwp2000 Calculate Serive Table Size
* Input          :
* Output         : None
* Return         : None
* onther         :
--------------------------------------------------------------------------*/
unsigned char kwp2000_CalcSeriveTabSize(void)
{
    //return (unsigned char)(sizeof(Kwp2000_ServiceTab) / sizeof(Kwp2000_ServiceTab_Entry_t));
}
