/*
 *  Copyright 2020-2024 Yuntu Microelectronics co.,ltd
 *  All rights reserved.
 * 
 *  YUNTU Confidential. This software is owned or controlled by YUNTU and may only be
 *  used strictly in accordance with the applicable license terms. By expressly
 *  accepting such terms or by downloading, installing, activating and/or otherwise
 *  using the software, you are agreeing that you have read, and that you agree to
 *  comply with and are bound by, such license terms. If you do not agree to be
 *  bound by the applicable license terms, then you may not retain, install,
 *  activate or otherwise use the software. The production use license in
 *  Section 2.3 is expressly granted for this software.
 * 
 * @file cantp_cfg.c
 * @brief 
 * 
 */


#include "cantp_types.h"
#include "cantp_cfg.h"
#include "cantp_hal.h"
#include "cantp_fifo.h"
#include "can_config.h"
#include "flexcan_driver.h"

/* ============================================================================================== */
/*                                           CONFIG VAR                                           */
/* ============================================================================================== */
extern void Uds_CanTpTxConfirm(pdu_id_type txSduId, cantp_core_res_type res);
extern void Uds_CanTpRxIndicate(pdu_id_type rxSduId, cantp_core_res_type res);

cantp_ch_config_array_type_t CanTp_chConfigArray[1] = {
    {
        .addrType = CANTP_ADDR_TYPE_PHYSICAL,
        .compareByte = 0x00,
        .addrByte = 0x00,
        .bs = 10,
        .maxWtf = 0,
        .inst = 0,
        .TX_DL = 8,
        .SF_DL = 7U, 
        .padding = true,
        .paddingValue = 0xaa
    },
};

cantp_time_array_type_t CanTp_timeArray[1] = {
    {
        .nAs = 1000,
        .nAr = 1000,
        .nBs = 1000,
        .nBr = 50,
        .nCr = 1000,
        .nCs = 50,
        .stMin = 10
    },
};

const cantp_u8 CanTp_pciOffsetArray[1] = 
{0, };

cantp_config_t CanTp_Config = {
    .chConfig = CanTp_chConfigArray,
    .timeMap = CanTp_timeArray,
    .pciOffsetArray = CanTp_pciOffsetArray,
    .rxCallback = Uds_CanTpRxIndicate,
    .txCallback = Uds_CanTpTxConfirm,
};

/* ============================================================================================== */
/*                                      HAL CONFIG FUNCTIONS                                      */
/* ============================================================================================== */
static flexcan_msgbuff_t CanTp_Hal_RxBufferArray[1];

static cantp_u8 CanTp_Hal_TxPduArray[1];

flexcan_data_info_t CanTp_Hal_data_info_array[1] = {
    {
        .msg_id_type = FLEXCAN_MSG_ID_STD,
        .data_length = 8,
#if FEATURE_CAN_HAS_FD
        .fd_enable   = false,   
        .fd_padding  = 170,
        .enable_brs  = false,
#endif
        .is_remote   = false,
    },
};

const cantp_u8 CanTp_txMbConfigArray[1] = 
{1, };

const cantp_u8 CanTp_rxMbConfigArray[1] = 
{0, };

const cantp_u32 CanTp_txIdArray[1] = 
{0x6FF, };

const cantp_u32 CanTp_rxIdArray[1] = 
{0x700, };

__attribute__((weak)) void CanTp_Core_RxIndication(pdu_id_type rxPduId, const pdu_info_type_t* pduInfoPtr)
{
    (void)rxPduId;
    (void)pduInfoPtr;
}

__attribute__((weak)) void CanTp_Core_TxConfirmation(pdu_id_type txPduId, cantp_return_type result)
{
    (void)txPduId;
    (void)result;
}

static void CanTp_Hal_EventCallback(
    uint8_t inst,
    flexcan_event_type_t eventType,
    uint32_t mbIdx,
    flexcan_state_t *flexCanState
);
cantp_hal_rx_indication_type CanTp_Hal_rxIndicationCallback = CanTp_Core_RxIndication;
cantp_hal_tx_confirmation_type CanTp_Hal_txConfirmationCallback = CanTp_Core_TxConfirmation;

cantp_return_type CanTp_Hal_Init()
{   
    /* Initial all channel */
    status_t status = STATUS_SUCCESS;

    FLEXCAN_DRV_InstallEventCallback(0, CanTp_Hal_EventCallback, CANTP_NULL);
    status |= FLEXCAN_DRV_ConfigTxMb(0, 1, &CanTp_Hal_data_info_array[0],0x6FF);
    status |= FLEXCAN_DRV_ConfigRxMb(0, 0, &CanTp_Hal_data_info_array[0],0x700);
    status |= FLEXCAN_DRV_Receive(0, 0, &CanTp_Hal_RxBufferArray[0]);
    DEV_ASSERT(status == STATUS_SUCCESS);
    return CANTP_E_NOT_OK;
}

static void CanTp_Hal_EventCallback(
    uint8_t inst,
    flexcan_event_type_t eventType,
    uint32_t mbIdx,
    flexcan_state_t *flexCanState
)
{
    switch (eventType)
    {
        case FLEXCAN_EVENT_RX_COMPLETE:
            for (cantp_u8 idx = 0; idx < 1U; idx++)
            {
                if (CanTp_chConfigArray[idx].inst == inst &&
                    CanTp_rxMbConfigArray[idx] == mbIdx &&
                    CanTp_Hal_RxBufferArray[idx].msgId == CanTp_rxIdArray[idx])
                {
                    pdu_info_type_t tempPduInfo;
                    tempPduInfo.sduLength = CanTp_Hal_RxBufferArray[idx].dataLen;
                    tempPduInfo.sduDataPtr = CanTp_Hal_RxBufferArray[idx].data;
                    CanTp_Hal_rxIndicationCallback(idx, &tempPduInfo);
                    break;
                }
            }
            break;
        case FLEXCAN_EVENT_TX_COMPLETE:
            for (cantp_u8 idx = 0; idx < 1U; idx++)
            {
                if ((CanTp_chConfigArray[idx].inst == inst) &&
                    (CanTp_txMbConfigArray[idx] == mbIdx))
                {
                    CanTp_Hal_txConfirmationCallback(CanTp_Hal_TxPduArray[idx], CANTP_E_OK);
                    break;
                }
            }
            break;
        default:
            break;
    }
}

cantp_u8 CanTp_Hal_TxDlcArray[7] = {12, 16, 20, 24, 32, 48, 64};
cantp_u8 CanTp_Hal_GetTxLength(cantp_u8 len)
{
    cantp_u8 res = len;
    if (len > 8)
    {
        for (cantp_u8 idx = 0U; idx < 7; idx++)
        {
            if (len <= CanTp_Hal_TxDlcArray[idx])
            {
                res = CanTp_Hal_TxDlcArray[idx];
                break;
            }
        }
    }
    return res;
}

cantp_u8 CanTp_Hal_minRxSFLenArray[14] = {
    /* 12 */
    8,
    /* 16 */
    11,
    /* 20 */
    15,
    /* 24 */
    19,
    /* 28, 32 */
    23, 23,
    /* 36, 40, 44, 48 */
    31, 31, 31, 31,
    /* 52, 56, 60, 64 */
    47, 47, 47, 47,
};
cantp_u8 CanTp_Hal_GetRxMinLength(cantp_u8 rxLen)
{
    return CanTp_Hal_minRxSFLenArray[rxLen/4 - 3];
}

cantp_hal_tx_res_type CanTp_Hal_Transmit(cantp_u8 pduId, const pdu_info_type_t* pduInfoPtr)
{
    cantp_hal_tx_res_type res = CANTP_HAL_TX_NOT_OK;
    cantp_u8 sduId = pduId / 2U;
    cantp_u8 inst = CanTp_chConfigArray[sduId].inst;
    // TODO add metadata use for autosar
    CanTp_Hal_data_info_array[sduId].data_length = CanTp_Hal_GetTxLength(pduInfoPtr->sduLength);
    CanTp_Hal_TxPduArray[sduId] = pduId;
    if (STATUS_SUCCESS == FLEXCAN_DRV_Send(
        inst,
        CanTp_txMbConfigArray[sduId],
        &CanTp_Hal_data_info_array[sduId],
        CanTp_txIdArray[sduId],
        pduInfoPtr->sduDataPtr
    ))
    {
        res = CANTP_HAL_TX_OK;
    }
    return res;
}

cantp_hal_tx_res_type CanTp_Hal_GetMBStatus(pdu_id_type sduId)
{
    cantp_hal_tx_res_type res = CANTP_HAL_TX_NOT_OK;
    cantp_u8 inst = CanTp_chConfigArray[sduId].inst;

    if (sduId < CANTP_CHANNEL_NUM)
    {
        if (STATUS_BUSY == FLEXCAN_DRV_GetTransferStatus(inst, CanTp_txMbConfigArray[sduId]))
        {
            res = CANTP_HAL_TX_BUSY;
        }
        else
        {
            res = CANTP_HAL_TX_WAIT;
        }
    }
    return res;
}

void CanTp_Hal_Mainfunction()
{
    if (FLEXCAN_DRV_GetTransferStatus(0, 0) != STATUS_BUSY)
    {
        FLEXCAN_DRV_Receive(0, 0, &CanTp_Hal_RxBufferArray[0]);
    }
}

/* ============================================================================================== */
/*                                      FIFO CONFIG FUNCTIONS                                     */
/* ============================================================================================== */
cantp_fifo_res_type CanTp_Fifo_Init()
{
    cantp_fifo_res_type fifoRes = CANTP_FIFO_RES_SUCCESS;
    fifoRes |= CanTp_Fifo_ApplyFifo(0, 1024);
    fifoRes |= CanTp_Fifo_ApplyFifo(1, 1024);
    return fifoRes;
}