/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 * 
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include "uds.h"


/*******************************************************************************
 * the defines
 ******************************************************************************/

#define UDS_GET_SUB_FUNCTION_SUPPRESS_POSRSP(byte)      (((byte) >> 7u)&0x01u)


/*******************************************************************************
 * the typedefs
 ******************************************************************************/


/*******************************************************************************
 * the globals
 ******************************************************************************/


/*******************************************************************************
 * the functions
 ******************************************************************************/

static bool Uds_IsSidValid(UdsType *obj, uint8_t sid)
{
    uint16_t i=0;
    for(i=0; i<obj->serviceNum; ++i) 
    {
        if(obj->seviceTable[i].sid == sid) 
        {
            return true;
        }
    }
    return false;
}


void Uds_Init(UdsType *obj, const Uds_ParamsType *pParams)
{
    IsoTp_Init(&obj->isotp, &pParams->isotpParams);

    obj->session = 0x01; /* Default session */
    obj->securityLevel = 0; /* None security level */
    obj->suppressPosRsp = false;
    obj->timeStamp_ms = 0;
    obj->p2Server_ms = pParams->p2Server_ms;
    obj->p2xServer_10ms = pParams->p2xServer_10ms;
    obj->s3Server_ms = pParams->s3Server_ms;

    Stimer_Init(&obj->p2ServerTimer);
    Stimer_Init(&obj->p2xServerTimer);
    Stimer_Init(&obj->s3ServerTimer);

    uint32_t i=0;
    for(i=0; i<UDS_MAX_PAYLOAD_SIZE; ++i) 
    {
        obj->payload[i] = 0;
    }
}


void Uds_Run(UdsType *obj)
{
    uint16_t outSize = 0;
    int8_t result = 0;
    uint8_t sid = 0;
    uint32_t i=0;
    
    IsoTp_Poll(&obj->isotp);

    result = IsoTp_Receive(&obj->isotp, &obj->isFuncAddr, obj->payload, UDS_MAX_PAYLOAD_SIZE, &outSize);
    if (ISOTP_RET_OK == result) 
    {
        /* Handle received message */
        sid = obj->payload[0];
        if(Uds_IsSidValid(obj, sid)) 
        {
            for(i=0; i<obj->serviceNum; ++i) 
            {
                if(obj->seviceTable[i].sid == sid) 
                {
                    if(obj->seviceTable[i].subFuncOwner)
                    {
                        obj->suppressPosRsp = UDS_GET_SUB_FUNCTION_SUPPRESS_POSRSP(obj->payload[1]);
                    }
                    else
                    {
                        obj->suppressPosRsp = 0;
                    }

                    obj->curServiceIdx = i;

                    obj->seviceTable[i].service(obj, obj->payload, outSize);
                    break;
                }
            }
        }
        else 
        {
            Uds_NegativeResponse(obj, sid, NRC_SERVICE_NOT_SUPPORTED);
        }
    }

    if(true == Stimer_Timeout(&obj->s3ServerTimer))
    {
        obj->session = 0x01; /* Default session */
        obj->securityLevel = 0; /* None security level */

        Stimer_Init(&obj->s3ServerTimer);
    }
}
