/**
 * @file uds_ip.c
 * @brief 
 * @version 0.1
 * @date 2024-08-31
 * 
 * (c) Copyright 2024 Yuntu Microelectronics co.,ltd.
 * 
 * All Rights Reserved
 * 
 */

/*==================================================================================================
 *                                 GENERAL INCLUDE FILES
==================================================================================================*/
#include "uds_ip.h"
#include "stddef.h"
#include "string.h"
#include "interrupt_manager.h"
#include "Uds_Service.h"
#include "stdlib.h"
#include <stdint.h>
#include "KeyGenAlgoInterfaceEx.h"
/*==================================================================================================
 *                           SECURITY ACCESS INCLUDE FILES AND MACROS
==================================================================================================*/
#if (defined CPU_YTM32B1ME0) || (defined CPU_YTM32B1MD1) || (defined CPU_YTM32B1MC0) || (defined CPU_YTM32B1HA0)
// #include "trng_driver.h"
// #include "hcu_driver.h"
#define AES_SEED_LEN 		16
#endif
#define ATTEMPT_CNT_MAX     5
/*==================================================================================================
 *                           FLASH INCLUDE FILES MACROS AND VARIABLES
==================================================================================================*/
#ifndef UDS_PROGRAM_CHUNK_SIZE 
#define UDS_PROGRAM_CHUNK_SIZE 256
#endif

#ifndef UDS_ERASE_CHUNK_SECTOR_SIZE
#define UDS_ERASE_CHUNK_SECTOR_SIZE 16
#endif

__attribute__((section(".fbl_bss"))) volatile uint32_t KeepInBootVar;
/*==================================================================================================
 *         RequestDownload RequestUpload TransferData MACROS
==================================================================================================*/
#ifndef UDS_MAX_BLOCK_SIZE
#define UDS_MAX_BLOCK_SIZE 0x82
#endif

/*==================================================================================================
 *                          CRC INCLUDE FILES AND MACROS
==================================================================================================*/

#if defined CPU_YTM32B1HA0
#include "pcrc_driver.h"
#define INST_PCRC        (0)
#else
#include "crc_driver.h"
#endif
#define INST_CRC        (0)


/*==================================================================================================
 *                                   LOCAL FUNCTION
==================================================================================================*/

/*==================================================================================================
 *                                       VARIABLES
==================================================================================================*/

uds_bool_t resetCommand = uds_false;
/*==================================================================================================
 *                                       GLOBAL FUNCTIONS
==================================================================================================*/

#define QUICK_REPL(channel,sid,sf) do{\
    if(sf&0x80){\
        Uds_NoResponse(channel);\
    }else{\
        Uds_SendPositiveResponse(channel, sid, &sf, 1);\
    }\
}while(0)



void UDS_IP_TesterPresentA(uds_channel_t channel, uds_u8_t* data, uds_u16_t dataLength, void* param){
    if(dataLength<2){
        Uds_SendNegativeResponse(channel, data[0], UDS_NRC_IMLOIF, NULL, 0);
    }else{
        QUICK_REPL(channel, data[0], data[1]);
    }
}


void UDS_IP_SessionA(uds_channel_t channel, uds_u8_t* data, uds_u16_t dataLength, void* param){
    if(dataLength<2){
        Uds_SendNegativeResponse(channel, data[0], UDS_NRC_IMLOIF, NULL, 0);
    }else{
        uds_subfunc_t sf[8]={0x55};
        sf[0] = data[1];
        sf[1] = 0x00;
        sf[2] = 0x00;//P2_Server    0x32
        sf[3] = 0x00;//             0x13
        sf[4] = 0x00;//P2*_Server   0x88
        Uds_SetSession(channel, sf[0]);
        Uds_SendPositiveResponse(channel, data[0], &sf[0], 5); // DLC behind SID

        if (data[1] == UDS_SESSION_PROGRAMMING)
        {
            KeepInBootVar = 1;
            resetCommand = true;
        }
    }
}

void UDS_IP_SecurityAccessA(uds_channel_t channel, uds_u8_t* data, uds_u16_t dataLength, void* param){
    uds_sid_t sid=data[0];
    uds_subfunc_t sf= data[1];
    uds_nrc_t nrc=UDS_NRC_GR;
    uds_bool_t ok=uds_false;
    static uds_u8_t seedBuf[UDS_CHANNEL_NUM][4] = { 0u };
    static uds_u8_t keyBuf[UDS_CHANNEL_NUM][4] = { 0u };
    static uds_bool_t seedState[UDS_CHANNEL_NUM] = { uds_false };
    static uds_u8_t attemptsCnt[UDS_CHANNEL_NUM] = { 0 };
    do{
        if((sf < 0x01)||(sf > 0x7E))
        {
            nrc=UDS_NRC_SFNS;
            break;
        }
        /* requestSeed */
        if(sf % 2 != 0)
        {
            uds_u32_t randseed;
            randseed = SysTick->VAL;

            srand(randseed);
            for (uds_u8_t i = 0; i < 4; i++) {
                seedBuf[channel][i] = (uds_u8_t)rand();
            }

            uds_u8_t tmpData[5];
            /* subfunction */
            tmpData[0]=data[1];
            /* seed */
            for (uds_u8_t i = 0; i < 4; i++) {
                tmpData[i+1] = seedBuf[channel][i];
            }
            attemptsCnt[channel] = 0;
            seedState[channel] = uds_true;
            ok=uds_true;
            Uds_SendPositiveResponse(channel, sid, tmpData, 5);
        }
        /* sendKey */
        else{
            if(seedState[channel] == uds_false)
            {
                /*requestSequenceError*/
                nrc=UDS_NRC_RSE;
                break;
            }
            if(attemptsCnt[channel] > ATTEMPT_CNT_MAX)
            {
                nrc=UDS_NRC_ENOA;
                break;
            }
            /* sid,subfunc,4Byte data */
            if(dataLength != 6)
            {
                nrc=UDS_NRC_IK;
                attemptsCnt[channel]++;
                break;
            }

            uds_u8_t i = 0;
            uint32_t keysize;
            uds_u8_t RxKey[4];
            for (i = 0; i < 4; i++)
            {
                RxKey[i] = data[i+2];
            }

            VKeyGenResultEx status = KGRE_Ok;
            status = GenerateKeyEx(&seedBuf[channel][0],4,1,1,&keyBuf[channel][0],1024,&keysize);
            (void)status;

            for (i = 0; i < keysize; i++)
            {
                if (RxKey[i] != keyBuf[channel][i])
                {
                    attemptsCnt[channel]++;
                    nrc=UDS_NRC_IK;
                    break;
                }
            }
            if(i == 4)
            {
                seedState[channel] = uds_false;
                attemptsCnt[channel] = 0;
                ok=uds_true;
                Uds_SetSecureLevel(channel, sf/2);
                Uds_SendPositiveResponse(channel, sid, &data[1], 1);
            }
        }
    }
    while(0);
    if(ok==uds_false){
        Uds_SendNegativeResponse(channel, sid, nrc, NULL, 0);
    }
}


void UDS_IP_ECUResetSoftResetA(uds_channel_t channel, uds_u8_t* data, uds_u16_t dataLength, void* param){
    uds_sid_t sid=data[0];
    uds_nrc_t nrc=UDS_NRC_GR;
    uds_bool_t ok=uds_false;
    do{
        if(dataLength != 2){
            /* incorrectMessageLengthOrInvalidFormat */
            nrc=UDS_NRC_IMLOIF;
            break;
        }
        ok=uds_true;
        // resetCommand = uds_true;
        QUICK_REPL(channel, data[0], data[1]);

    }
    while(0);
    if(ok==uds_false){
        Uds_SendNegativeResponse(channel, sid, nrc, NULL, 0);
    }
}

void udsRxCallback(uds_channel_t channel, uds_u8_t* data, uds_u16_t dataLength)
{
    /*If we received any uds frame when startup < KEEP_IN_BOOT_TIME ms, we will keep in boot */
    // if(eclipseTime<KEEP_IN_BOOT_TIME) {
    //     forceKeepInBoot=true;
    // }
}