/*
 * Copyright (c) 2014-2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *  \file     gateway_app.c
 *
 *  \brief    This file contains gateway application for ETH <-> CAN routing.
 *
 *  \details
 *
 */


 /* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include <stdint.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/v8a/Mmu.h>
#include <ti/sysbios/utils/Load.h>
#include <ti/sysbios/knl/Semaphore.h>

/* OSAL Header files */
#include <ti/osal/osal.h>

/* CSL Header files */
#include <ti/csl/csl_types.h>
#include <ti/csl/soc.h>
#include <ti/csl/hw_types.h>
#include <ti/csl/csl_edma.h>
#include <ti/csl/csl_timer.h>
#include <ti/csl/cslr_mcan.h>
#include <ti/csl/arch/csl_arch.h>
#include <ti/csl/example/utils/uart_console/inc/uartConfig.h>
#include <ti/csl/csl_mcan.h>
#include <ti/csl/cslr_synctimer.h>

#if defined (SOC_AM65XX)
/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/UART_stdio.h>
/* BOARD Header files */
#include <ti/board/board.h>
#endif

/* NDK Dependencies */
#include <ti/ndk/inc/socket.h>
#include <ti/ndk/inc/netmain.h>
#include <ti/ndk/inc/stkmain.h>
#include <sys/time.h>

/* Module Header files */
#include <network_api.h>
#include <utils_prf.h>

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

#if defined (SOC_AM65XX)
#define GATEWAYAPP_MCAN_MODULE                          (CSL_MCU_MCAN0_MSGMEM_RAM_BASE)
#endif

#define GATEWAYAPP_MCAN_STD_ID_FILT_START_ADDR          (0U)
#define GATEWAYAPP_MCAN_STD_ID_FILTER_NUM               (1U)
#define GATEWAYAPP_MCAN_EXT_ID_FILT_START_ADDR          (48U)
#define GATEWAYAPP_MCAN_EXT_ID_FILTER_NUM               (1U)
#define GATEWAYAPP_MCAN_TX_EVENT_START_ADDR             (100U)
#define GATEWAYAPP_MCAN_TX_EVENT_SIZE                   (5U)
#define GATEWAYAPP_MCAN_TX_BUFF_START_ADDR              (148U)
#define GATEWAYAPP_MCAN_TX_BUFF_SIZE                    (5U)
#define GATEWAYAPP_MCAN_TX_FIFO_SIZE                    (5U)
#define GATEWAYAPP_MCAN_FIFO_0_START_ADDR               (548U)
#define GATEWAYAPP_MCAN_FIFO_0_NUM                      (5U)
#define GATEWAYAPP_MCAN_FIFO_1_START_ADDR               (748U)
#define GATEWAYAPP_MCAN_FIFO_1_NUM                      (5U)
#define GATEWAYAPP_MCAN_RX_BUFF_START_ADDR              (948U)

#define GATEWAYAPP_MCAN_EXT_ID_AND_MASK                 (0x1FFFFFFFU)

#define GATEWAYAPP_MCAN_RX_MAILBOX_NUM                    (0U)
#define GATEWAYAPP_MCAN_TX_MAILBOX_NUM                    (1U)
#define GATEWAYAPP_MCAN_TX_MSG_ID                          (0x9U)
#define GATEWAYAPP_MCAN_RX_MSG_ID                          (0x4U)

#if defined (__TI_ARM_V7M4__)
    #define GATEWAYAPP_MCAN_INT0                     (GATEWAYAPP_MCAN_INT0_M4)
    #define GATEWAYAPP_MCAN_INT1                     (GATEWAYAPP_MCAN_INT1_M4)
    #define GATEWAYAPP_MCAN_ECC_INT                  (GATEWAYAPP_MCAN_ECC_INT_M4)
    #define GATEWAYAPP_MCAN_TS_INT                   (GATEWAYAPP_MCAN_TS_INT_M4)
    #define XBAR_CPU                          (CSL_XBAR_IRQ_CPU_ID_IPU1)
    #define XBAR_MCAN_INT0                       (CSL_XBAR_INST_IPU1_IRQ_34)
    #define XBAR_MCAN_INT1                       (CSL_XBAR_INST_IPU1_IRQ_35)
    #define XBAR_MCAN_ECC                        (CSL_XBAR_INST_IPU1_IRQ_36)
    #define XBAR_MCAN_TS                         (CSL_XBAR_INST_IPU1_IRQ_37)
    #define XBAR_INTR0_SOURCE                    (CSL_XBAR_MCAN_IRQ_INT0)
    #define XBAR_INTR1_SOURCE                    (CSL_XBAR_MCAN_IRQ_INT1)
    #define XBAR_INTR_ECC_SOURCE                 (CSL_XBAR_MCAN_IRQ_PARITY)
    #define XBAR_INTR_TS_SOURCE                  (CSL_XBAR_MCAN_IRQ_TS)
#elif defined (_TMS320C6X)
    /* Not yet supported */
#endif
#if defined (SOC_AM65XX)
    #define GATEWAYAPP_MCAN_0_INT0                                   (0U)
    #define GATEWAYAPP_MCAN_0_INT1                                   (1U)
    #define GATEWAYAPP_MCAN_0_TS_INT                                 (4U)
    #define GATEWAYAPP_MCAN_1_INT0                                   (2U)
    #define GATEWAYAPP_MCAN_1_INT1                                   (3U)
    #define GATEWAYAPP_MCAN_1_TS_INT                                 (5U)

#endif

#if defined (ENABLE_LOOPBACK)
#define GATEWAYAPP_MCAN_STD_ID_MASK              (0x7FFU << 18U)
#define GATEWAYAPP_MCAN_EXT_ID_MASK              (0x1FFFFFFFU)
#define GATEWAYAPP_MCAN_STD_ID_SHIFT             (18U)
#define GATEWAYAPP_MCAN_EXT_ID_SHIFT             (0U)
#endif

/* ========================================================================== */
/*                         Structure Declarations                             */
/* ========================================================================== */

typedef struct GatewayApp_s
{
    /* Network socket object for TX */
    Network_SockObj     netTxSockObj;
    /* Network socket object for RX */
    Network_SockObj     netRxSockObj;
    /* CAN RX msg semaphore */
    Semaphore_Handle    canRxMsgSem;
    /* CAN TX msg semaphore */
    Semaphore_Handle    canTxMsgSem;
    /* Task handle for Gateway TX task */
    Task_Handle         hGatewayTxTask;
    /* Task handle for Gateway RX task */
    Task_Handle         hGatewayRxTask;
    /* Total CAN messages transmitted */
    uint32_t            canMsgTxCnt;
    /* Total CAN messages received */
    uint32_t            canMsgRxCnt;
    /* Receive buffer for CAN data */
    uint8_t             recvBuffer[1600U];
}GatewayAppStruct;

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

/**
 * \brief   This function will configure MCAN module
 *
 * \param   none.
 *
 * \retval  status      configuration status.
 */
static int32_t GatewayApp_mcanConfig(void);

/**
 * \brief   This function will configure interrupt for MCAN interrupts
 *
 * \param   none.
 *
 * \retval  status      configuration status.
 */
static int32_t GatewayApp_mcanIntConfig(void);

/**
 * \brief   This is Interrupt Service Routine for MCAN interrupt 0.
 *
 * \param   none.
 *
 * \retval  none.
 */
static void GatewayApp_mcanIntr0ISR(uintptr_t handle);

/**
 * \brief   This is Interrupt Service Routine for MCAN TimeStamp interrupt.
 *
 * \param   none.
 *
 * \retval  none.
 */
static void GatewayApp_mcanTSIntrISR(uintptr_t handle);

#ifdef GATEWAYAPP_PRINTMCANMSG
/**
 * \brief   This API will MCAN Rx Msg.
 *
 * \param   rxMsg           received message object.
 *
 * \retval  none.
 */
static void GatewayApp_mcanPrintRxMsg(const MCAN_RxBufElement *rxMsg);
#endif

#ifdef GATEWAYAPP_PRINTMCANMSG
/**
 * \brief   This API will MCAN Tx Msg.
 *
 * \param   txMsg           message object to be transmitted.
 *
 * \retval  none.
 */
static void GatewayApp_mcanPrintTxMsg(const MCAN_TxBufElement *txMsg);
#endif

/**
 * \brief   This API will load the register from ECC memory bank.
 *
 * \param   txMsg           message object to be transmitted.
 *
 * \return  None.
 */
static int32_t GatewayApp_mcanTx(MCAN_TxBufElement *txMsg);

/* Gateway routing (RX/TX) tasks prototype */
void GatewayApp_mcanTxTask(UArg arg0, UArg arg1);
void GatewayApp_mcanRxTask(UArg arg0, UArg arg1);
void GatewayApp_cpuLoadTask(UArg arg0, UArg arg1);
void GatewayApp_mcanBusOffRecovery(uint32_t module);

#if defined (ENABLE_LOOPBACK)
void GatewayApp_mcanLpbkTest(void);
static int32_t GatewayApp_mcanTxRxMessageCheck(const MCAN_TxBufElement *txMsg,
                                               const MCAN_RxBufElement *rxMsg);
#endif

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

MCAN_ECCErrStatus   gMcaneccErr;
uint32_t            gMcanAppdataSize[16U] =
                            {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U};
#ifdef MCAN_POLLINGMODE
volatile uint32_t   gMcanIsrIntr0Flag = 1U;
volatile uint32_t   gMcanIsrIntr1Flag = 1U;
#endif

GatewayAppStruct gatewayAppObj;

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
void GatewayApp_mcanTrcvCfg(void)
{
#if defined (SOC_AM65XX)
    uint32_t regVal = 0U;

    /* Configure SOC_PADCONFIG_143 to set it '1' to take
       MCAN transceiver out of STB mode */
    /* Unlock lock key registers for Partition 7: IO PAD
       configuration registers in MAIN_CTRL_MMR */
    /* write Partition 7 Lock Key 0 Register */
    CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + 0x1D008, 0x68EF3490);
    /* write Partition 7 Lock Key 1 Register */
    CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + 0x1D00C, 0xD172BC5A);
    /* Check for unlock */
    regVal = CSL_REG32_RD(CSL_CTRL_MMR0_CFG0_BASE + 0x1D008);
    while ((regVal & 0x1) != 0x1U)
    {
    }

    /* Unlocking done */
    /* Take MCAN transceiver out of STB mode for MCAN0 */
    regVal = CSL_REG32_RD(CSL_CTRL_MMR0_CFG0_BASE + 0x1C23C);
    regVal &= 0U;
    regVal |= 0x10060007U;
    CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + 0x1C23C, regVal);
    regVal = CSL_REG32_RD(CSL_GPIO1_BASE + 0x38);
    regVal &= (~(1U << 0xF));
    CSL_REG32_WR(CSL_GPIO1_BASE + 0x38, regVal);
    regVal = CSL_REG32_RD(CSL_GPIO1_BASE + 0x3C);
    regVal |= (1U << 0xF);
    CSL_REG32_WR(CSL_GPIO1_BASE + 0x3C, regVal);

    /* Take MCAN transceiver out of STB mode for MCAN1 */
    regVal = CSL_REG32_RD(CSL_CTRL_MMR0_CFG0_BASE + 0x1C28C);
    regVal &= 0U;
    regVal |= 0x10060007U;
    CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + 0x1C28C, regVal);
    regVal = CSL_REG32_RD(CSL_GPIO1_BASE + 0x60);
    regVal &= (~(1U << 0x3));
    CSL_REG32_WR(CSL_GPIO1_BASE + 0x60, regVal);
    regVal = CSL_REG32_RD(CSL_GPIO1_BASE + 0x64);
    regVal |= (1U << 0x3);
    CSL_REG32_WR(CSL_GPIO1_BASE + 0x64, regVal);

#endif

}

void GatewayApp_initTasks(void)
{
    Semaphore_Params semParams;
#ifndef MCAN_POLLINGMODE
    int32_t configStatus = STW_SOK;
#endif

    Utils_consolePrintf("\nGatewayApp: Starting GATEWAY Tasks...\n");

    memset (&gatewayAppObj, 0U, sizeof(GatewayAppStruct));

    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    gatewayAppObj.canRxMsgSem = ((void *)Semaphore_create(0, &semParams, NULL));

    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    gatewayAppObj.canTxMsgSem = ((void *)Semaphore_create(0, &semParams, NULL));

    gatewayAppObj.netTxSockObj.port = 1000U;
    NetworkCreate(&gatewayAppObj.netTxSockObj);
    Utils_consolePrintf("\nGatewayApp: Network Tx socket open done..\n");

    gatewayAppObj.netRxSockObj.port = 2000U;
    NetworkCreate(&gatewayAppObj.netRxSockObj);
    Utils_consolePrintf("\nGatewayApp: Network Rx socket open done..\n");

    GatewayApp_mcanTrcvCfg();

#ifndef MCAN_POLLINGMODE
    /* Interrupt Configuration */
    configStatus = GatewayApp_mcanIntConfig();
#endif

    configStatus = GatewayApp_mcanConfig();

    if (STW_SOK == configStatus)
    {
#ifndef MCAN_POLLINGMODE
        /* Enable Interrupts */
        MCAN_enableIntr(GATEWAYAPP_MCAN_MODULE, MCAN_INTR_MASK_ALL, (uint32_t)TRUE);
        MCAN_enableIntr(GATEWAYAPP_MCAN_MODULE,
                        MCAN_INTR_SRC_RES_ADDR_ACCESS, (uint32_t)FALSE);

        /* Enable Transmission interrupt */
        configStatus = MCAN_txBufTransIntrEnable(GATEWAYAPP_MCAN_MODULE,
                                                 GATEWAYAPP_MCAN_TX_MAILBOX_NUM,
                                                 (uint32_t)TRUE);
        if (STW_SOK != configStatus)
        {
            Utils_consolePrintf("\nGatewayApp: Error in Adding Transmission Request...\n");
        }

        /* Select Interrupt Line for MCAN TX and RX interrupts. */
        MCAN_selectIntrLine(GATEWAYAPP_MCAN_MODULE,
                            MCAN_INTR_MASK_ALL,
                            MCAN_INTR_LINE_NUM_0);
        /* Enable Interrupt Line */
        MCAN_enableIntrLine(GATEWAYAPP_MCAN_MODULE,
                            MCAN_INTR_LINE_NUM_0,
                            1U /* enable */);
#endif

#if defined (ENABLE_LOOPBACK)
        /* send a message and receive it back since loop-back is enabled */
        GatewayApp_mcanLpbkTest();
#else
        Task_Params taskParams;

        Task_Params_init(&taskParams);
        taskParams.priority = 9U;
        taskParams.stackSize = 0x1400;
        taskParams.arg0 = (UArg)NULL;
        gatewayAppObj.hGatewayTxTask = Task_create (GatewayApp_mcanTxTask, &taskParams, NULL);

        /* Create app task to start sending/receiving CAN/ETH messages */
        Task_Params_init(&taskParams);
        /* Keep CAN RX task slightly higher than TX */
        taskParams.priority = 10U;
        taskParams.stackSize = 0x1400;
        taskParams.arg0 = (UArg)NULL;
        gatewayAppObj.hGatewayRxTask = Task_create (GatewayApp_mcanRxTask, &taskParams, NULL);


        /* Reset and start load monitoring */
        Utils_prfInit();
        Utils_prfLoadCalcStart();

        /* Register Gateway tasks with load monitoring framework */
        Utils_prfLoadRegister(gatewayAppObj.hGatewayRxTask, "Gateway Rx");
        Utils_prfLoadRegister(gatewayAppObj.hGatewayTxTask, "Gateway Tx");

        Utils_prfLoadCalcReset();

        Task_Params_init(&taskParams);
        taskParams.instance->name = "CPU_LOAD";
        taskParams.priority = 1U;
        Task_create(GatewayApp_cpuLoadTask, &taskParams,NULL);
#endif
    }
    else
    {
        Utils_consolePrintf("GatewayApp: MCAN config failed!!\n");
    }

    return;
}

void GatewayApp_ipAddrHookFxn (uint32_t IPAddr, uint32_t IfIdx, uint32_t fAdd)
{
    char ipAddrStr[20U];

    NtIPN2Str(IPAddr, ipAddrStr);

    Utils_consolePrintf("\n\rGatewayApp: BOARD IP address I/F 1: %s\n\r", ipAddrStr);

    /* Now that we have IP address, create gateway tasks */
    GatewayApp_initTasks();
}

/* ========================================================================== */
/*                          Static Function Definitions                       */
/* ========================================================================== */

static int32_t GatewayApp_mcanIntConfig(void)
{
    int32_t configStatus = STW_SOK;

    HwiP_Params hwiParams;
    HwiP_Handle gIntrHandle;
    uint32_t int0Num, intrTS;

    int0Num = GATEWAYAPP_MCAN_0_INT0;
    intrTS = GATEWAYAPP_MCAN_0_TS_INT;

    /* Clear out any pending interrupts */
    HwiP_clearInterrupt(int0Num);
    /* Populate the interrupt parameters */
    HwiP_Params_init(&hwiParams);
    hwiParams.arg = (uintptr_t) NULL;
    /* Register interrupt */
    gIntrHandle = HwiP_create(int0Num,
                              &GatewayApp_mcanIntr0ISR,
                              &hwiParams);
    if(gIntrHandle == NULL)
    {
        Utils_consolePrintf("GatewayApp: Cannot Register MCAN IRQ");
    }

    /* Clear out any pending interrupts */
    HwiP_clearInterrupt(intrTS);
    /* Populate the interrupt parameters */
    HwiP_Params_init(&hwiParams);
    hwiParams.arg = (uintptr_t) NULL;
    /* Register interrupt */
    gIntrHandle = HwiP_create(intrTS,
                              &GatewayApp_mcanTSIntrISR,
                              &hwiParams);
    if(gIntrHandle == NULL)
    {
        Utils_consolePrintf("GatewayApp: Cannot Register MCAN IRQ");
    }


    Utils_consolePrintf("GatewayApp: CrossBar/Interrupt Configuration done.\n");

    return configStatus;
}

static int32_t GatewayApp_mcanConfig(void)
{
    uint32_t                   fdoe;
    int32_t                    configStatus = STW_SOK;
    MCAN_RevisionId            revId;
    MCAN_InitParams            initParams;
    MCAN_ConfigParams          configParams;
    MCAN_MsgRAMConfigParams    msgRAMConfigParams;
    MCAN_StdMsgIDFilterElement stdFiltelem;
    MCAN_BitTimingParams       bitTimes;

    /* Initialize MCAN Init params */
    initParams.fdMode          = 0x1U;
    initParams.brsEnable       = 0x1U;
    initParams.txpEnable       = 0x0U;
    initParams.efbi            = 0x0U;
    initParams.pxhddisable     = 0x0U;
    initParams.darEnable       = 0x0U;
    initParams.wkupReqEnable   = 0x1U;
    initParams.autoWkupEnable  = 0x1U;
    initParams.emulationEnable = 0x1U;
    initParams.emulationFAck   = 0x0U;
    initParams.clkStopFAck     = 0x0U;
    initParams.wdcPreload      = 0xFFU;
    initParams.tdcEnable       = 0x1U;
    initParams.tdcConfig.tdcf  = 0xAU;
    initParams.tdcConfig.tdco  = 0x6U;
    /* Initialize MCAN Config params */
    configParams.monEnable         = 0x0U;
    configParams.asmEnable         = 0x0U;
    configParams.tsPrescalar       = 0xFU;
    configParams.tsSelect          = 0x0U;
    configParams.timeoutSelect     = MCAN_TIMEOUT_SELECT_CONT;
    configParams.timeoutPreload    = 0xFFFFU;
    configParams.timeoutCntEnable  = 0x0U;
    configParams.filterConfig.rrfs = 0x1U;
    configParams.filterConfig.rrfe = 0x1U;
    configParams.filterConfig.anfe = 0x1U;
    configParams.filterConfig.anfs = 0x1U;
    /* Initialize Message RAM Sections Configuration Parameters */
    msgRAMConfigParams.flssa                = GATEWAYAPP_MCAN_STD_ID_FILT_START_ADDR;
    msgRAMConfigParams.lss                  = GATEWAYAPP_MCAN_STD_ID_FILTER_NUM;
    msgRAMConfigParams.flesa                = GATEWAYAPP_MCAN_EXT_ID_FILT_START_ADDR;
    msgRAMConfigParams.lse                  = GATEWAYAPP_MCAN_EXT_ID_FILTER_NUM;
    msgRAMConfigParams.txStartAddr          = GATEWAYAPP_MCAN_TX_BUFF_START_ADDR;
    msgRAMConfigParams.txBufNum             = GATEWAYAPP_MCAN_TX_BUFF_SIZE;
    msgRAMConfigParams.txFIFOSize           = 0U;
    msgRAMConfigParams.txBufMode            = 0U;
    msgRAMConfigParams.txBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.txEventFIFOStartAddr = GATEWAYAPP_MCAN_TX_EVENT_START_ADDR;
    msgRAMConfigParams.txEventFIFOSize      = GATEWAYAPP_MCAN_TX_BUFF_SIZE;
    msgRAMConfigParams.txEventFIFOWaterMark = 3U;
    msgRAMConfigParams.rxFIFO0startAddr     = GATEWAYAPP_MCAN_FIFO_0_START_ADDR;
    msgRAMConfigParams.rxFIFO0size          = GATEWAYAPP_MCAN_FIFO_0_NUM;
    msgRAMConfigParams.rxFIFO0waterMark     = 3U;
    msgRAMConfigParams.rxFIFO0OpMode        = 0U;
    msgRAMConfigParams.rxFIFO1startAddr     = GATEWAYAPP_MCAN_FIFO_1_START_ADDR;
    msgRAMConfigParams.rxFIFO1size          = GATEWAYAPP_MCAN_FIFO_1_NUM;
    msgRAMConfigParams.rxFIFO1waterMark     = 3U;
    msgRAMConfigParams.rxFIFO1OpMode        = 0U;
    msgRAMConfigParams.rxBufStartAddr       = GATEWAYAPP_MCAN_RX_BUFF_START_ADDR;
    msgRAMConfigParams.rxBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.rxFIFO0ElemSize      = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.rxFIFO1ElemSize      = MCAN_ELEM_SIZE_64BYTES;
    /* Initialize Tx Buffer Config params */
    stdFiltelem.sfid2 = 0x0U;
    stdFiltelem.sfid1 = GATEWAYAPP_MCAN_RX_MSG_ID;
    stdFiltelem.sfec  = 0x7U;
    stdFiltelem.sft   = 0x0U;
    /* Initialize bit timings
     * Configuring 1Mbps and 5Mbps as nominal and data bit-rate respectively */
    bitTimes.nomRatePrescalar   = 0x7U;
    bitTimes.nomTimeSeg1        = 0x5U;
    bitTimes.nomTimeSeg2        = 0x2U;
    bitTimes.nomSynchJumpWidth  = 0x0U;
    bitTimes.dataRatePrescalar  = 0x1U;
    bitTimes.dataTimeSeg1       = 0x3U;
    bitTimes.dataTimeSeg2       = 0x2U;
    bitTimes.dataSynchJumpWidth = 0x0U;

    /* Get MCANSS Revision ID */
    MCAN_getRevisionId(GATEWAYAPP_MCAN_MODULE, &revId);
    Utils_consolePrintf("GatewayApp: MCANSS Revision ID:\n");
    Utils_consolePrintf("GatewayApp: scheme:0x%x\n", revId.scheme);
    Utils_consolePrintf("GatewayApp: Business Unit:0x%x\n", revId.bu);
    Utils_consolePrintf("GatewayApp: Module ID:0x%x\n", revId.modId);
    Utils_consolePrintf("GatewayApp: RTL Revision:0x%x\n", revId.rtlRev);
    Utils_consolePrintf("GatewayApp: Major Revision:0x%x\n", revId.major);
    Utils_consolePrintf("GatewayApp: Custom Revision:0x%x\n", revId.custom);
    Utils_consolePrintf("GatewayApp: Minor Revision:0x%x\n", revId.minor);
    /* Enable Auto wakeup */
    fdoe = MCAN_isFDOpEnable(GATEWAYAPP_MCAN_MODULE);
    if ((uint32_t)TRUE == fdoe)
    {
        Utils_consolePrintf("GatewayApp: CAN-FD operation is enabled through E-Fuse.\n");
    }
    else
    {
        Utils_consolePrintf("GatewayApp: CAN-FD operation is disabled through E-Fuse.\n");
    }
    /* wait for memory initialization to happen */
    while (FALSE == MCAN_isMemInitDone(GATEWAYAPP_MCAN_MODULE))
    {}
    /* Get endianess value */
    Utils_consolePrintf("GatewayApp: Endianess Value: 0x%x\n",
                       MCAN_getEndianVal(GATEWAYAPP_MCAN_MODULE));
    /* Put MCAN in SW initialization mode */
    MCAN_setOpMode(GATEWAYAPP_MCAN_MODULE, MCAN_OPERATION_MODE_SW_INIT);
    while (MCAN_OPERATION_MODE_SW_INIT != MCAN_getOpMode(GATEWAYAPP_MCAN_MODULE))
    {}
    /* Initialize MCAN module */
    MCAN_init(GATEWAYAPP_MCAN_MODULE, &initParams);
    /* Configure MCAN module */
    MCAN_config(GATEWAYAPP_MCAN_MODULE, &configParams);
    /* Configure Bit timings */
    MCAN_setBitTime(GATEWAYAPP_MCAN_MODULE, &bitTimes);
    /* Set Extended ID Mask */
    MCAN_setExtIDAndMask(GATEWAYAPP_MCAN_MODULE, GATEWAYAPP_MCAN_EXT_ID_AND_MASK);
    /* Configure Message RAM Sections */
    MCAN_msgRAMConfig(GATEWAYAPP_MCAN_MODULE, &msgRAMConfigParams);
    /* Configure Standard ID filter element */
    MCAN_addStdMsgIDFilter(GATEWAYAPP_MCAN_MODULE, 0U, &stdFiltelem);

#if defined (ENABLE_LOOPBACK)
    MCAN_lpbkModeEnable(GATEWAYAPP_MCAN_MODULE, MCAN_LPBK_MODE_INTERNAL, TRUE);
#endif

    /* Take MCAN out of the SW initialization mode */
    MCAN_setOpMode(GATEWAYAPP_MCAN_MODULE, MCAN_OPERATION_MODE_NORMAL);
    while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(GATEWAYAPP_MCAN_MODULE))
    {}

    return configStatus;
}

static void GatewayApp_mcanIntr0ISR(uintptr_t handle)
{
    uint32_t intrStatus, arbErrFlag, dataErrFlag;

    intrStatus = MCAN_getIntrStatus(GATEWAYAPP_MCAN_MODULE);
    MCAN_clearIntrStatus(GATEWAYAPP_MCAN_MODULE, intrStatus);
    if (MCAN_INTR_SRC_TRANS_COMPLETE ==
        (intrStatus & MCAN_INTR_SRC_TRANS_COMPLETE))
    {
#ifdef MCAN_POLLINGMODE
        gMcanIsrIntr0Flag = 0U;
#endif
        Semaphore_post((Semaphore_Handle)gatewayAppObj.canTxMsgSem);
    }

    if (MCAN_INTR_SRC_DEDICATED_RX_BUFF_MSG ==
        (intrStatus & MCAN_INTR_SRC_DEDICATED_RX_BUFF_MSG))
    {
#ifdef MCAN_POLLINGMODE
        gMcanIsrIntr1Flag = 0U;
#endif
        Semaphore_post((Semaphore_Handle)gatewayAppObj.canRxMsgSem);
    }

    arbErrFlag = (intrStatus & MCAN_INTR_SRC_PROTOCOL_ERR_ARB);
    dataErrFlag = (intrStatus & MCAN_INTR_SRC_PROTOCOL_ERR_DATA);

    if ((arbErrFlag == MCAN_INTR_SRC_PROTOCOL_ERR_ARB) ||
        (dataErrFlag == MCAN_INTR_SRC_PROTOCOL_ERR_DATA))
    {
        Semaphore_post((Semaphore_Handle)gatewayAppObj.canTxMsgSem);
    }
}

static void GatewayApp_mcanTSIntrISR(uintptr_t handle)
{
    /* GatewayApp: Time Stamp overflow happened */
}

#ifdef GATEWAYAPP_PRINTMCANMSG
static void GatewayApp_mcanPrintTxMsg(const MCAN_TxBufElement *txMsg)
{
    uint32_t loopCnt;

    Utils_consolePrintf("\nMessage ID: 0x%x", txMsg->id);

    Utils_consolePrintf("\nMessage Remote Transmission Request: 0x%x",
                       txMsg->rtr);

    Utils_consolePrintf(
        "\nMessage Extended Frame ID(0:11Bit ID/1:29bit ID): 0x%x",
        txMsg->xtd);

    Utils_consolePrintf(
        "\nMessage Error State Indicator(0:Error Active/1:Error Passive): 0x%x",
        txMsg->esi);

    Utils_consolePrintf("\nMessage Data Length Code: 0x%x", txMsg->dlc);

    Utils_consolePrintf("\nMessage BRS: 0x%x", txMsg->brs);

    Utils_consolePrintf("\nMessage CAN FD format: 0x%x", txMsg->fdf);

    Utils_consolePrintf("\nMessage Store Tx Events: 0x%x", txMsg->efc);

    Utils_consolePrintf("\nMessage Marker: 0x%x", txMsg->mm);

    for (loopCnt = 0U; loopCnt < gMcanAppdataSize[txMsg->dlc]; loopCnt++)
    {
        Utils_consolePrintf("\nMessage DataByte%d", loopCnt);
        Utils_consolePrintf(": 0x%x", txMsg->data[loopCnt]);
    }
}
#endif

#ifdef GATEWAYAPP_PRINTMCANMSG
static void GatewayApp_mcanPrintRxMsg(const MCAN_RxBufElement *rxMsg)
{
    uint32_t loopCnt;

    Utils_consolePrintf("\nMessage ID: 0x%x", rxMsg->id);
    Utils_consolePrintf("\nMessage Remote Transmission Request: 0x%x", rxMsg->rtr);
    Utils_consolePrintf(
        "\nMessage Extended Frame ID(0:11Bit ID/1:29bit ID): 0x%x",
        rxMsg->xtd);
    Utils_consolePrintf(
        "\nMessage Error State Indicator(0:Error Active/1:Error Passive): 0x%x",
        rxMsg->esi);
    Utils_consolePrintf("\nMessage TimeStamp: 0x%x", rxMsg->rxts);
    Utils_consolePrintf("\nMessage Data Length Code: 0x%x", rxMsg->dlc);
    Utils_consolePrintf("\nMessage BRS: 0x%x", rxMsg->brs);
    Utils_consolePrintf("\nMessage CAN FD format: 0x%x", rxMsg->fdf);
    Utils_consolePrintf("\nMessage Filter Index: 0x%x", rxMsg->fidx);
    Utils_consolePrintf("\nMessage Accept Non-matching Frame: 0x%x", rxMsg->anmf);
    for (loopCnt = 0U; loopCnt < gMcanAppdataSize[rxMsg->dlc]; loopCnt++)
    {
        Utils_consolePrintf("\nMessage DataByte%d", loopCnt);
        Utils_consolePrintf(": 0x%x", rxMsg->data[loopCnt]);
    }
}
#endif

static int32_t GatewayApp_mcanTx(MCAN_TxBufElement *txMsg)
{
    int32_t  configStatus = STW_EFAIL, testStatus = STW_SOK;
    MCAN_ProtocolStatus protStatus;

    /* Write message to Msg RAM */
    MCAN_writeMsgRam(GATEWAYAPP_MCAN_MODULE,
                     MCAN_MEM_TYPE_BUF,
                     GATEWAYAPP_MCAN_TX_MAILBOX_NUM,
                     txMsg);
    /* Add request for transmission */
    configStatus += MCAN_txBufAddReq(GATEWAYAPP_MCAN_MODULE,
                                     GATEWAYAPP_MCAN_TX_MAILBOX_NUM);

#ifndef MCAN_POLLINGMODE
    /* put semaphore code here */
    Semaphore_pend((Semaphore_Handle)gatewayAppObj.canTxMsgSem, BIOS_WAIT_FOREVER);
#else
    while (gMcanIsrIntr0Flag)
    {}
    gMcanIsrIntr0Flag = 1U;
#endif

    MCAN_getProtocolStatus(GATEWAYAPP_MCAN_MODULE, &protStatus);

    /* Checking for Errors */
    if (((MCAN_ERR_CODE_NO_ERROR == protStatus.lastErrCode) ||
         (MCAN_ERR_CODE_NO_CHANGE == protStatus.lastErrCode)) &&
        ((MCAN_ERR_CODE_NO_ERROR == protStatus.dlec) ||
         (MCAN_ERR_CODE_NO_CHANGE == protStatus.dlec)) &&
        (0U == protStatus.pxe))
    {
    }
    else
    {
        Utils_consolePrintf(
        "\nGatewayApp: Error in transmission with payload Bytes:%d",
        gMcanAppdataSize[txMsg->dlc]);
        if (protStatus.errPassive == 1U)
        {
            Utils_consolePrintf("\nGatewayApp: MCAN Node is in Error Passive State.\n");
        }
        if (protStatus.busOffStatus == 1U)
        {
            Utils_consolePrintf("\nGatewayApp: MCAN Node is in bus Off State\n");
            /* Initiate Bus-Off recovery */
            GatewayApp_mcanBusOffRecovery(GATEWAYAPP_MCAN_MODULE);
        }
        testStatus = STW_EFAIL;
    }

    return testStatus;
}

void GatewayApp_mcanTxMsgInit(MCAN_TxBufElement *pTxMsg)
{
    /* Initialize message to transmit */
    pTxMsg->id  = (uint32_t)((uint32_t)(GATEWAYAPP_MCAN_TX_MSG_ID) << 18U);
    pTxMsg->rtr = 0U;
    pTxMsg->xtd = 0U;
    pTxMsg->esi = 0U;
    pTxMsg->brs = 1U;
    pTxMsg->fdf = 1U;
    pTxMsg->dlc =0xF;
    pTxMsg->efc = 1U;
    pTxMsg->mm  = 0xAAU;
}

void GatewayApp_mcanTxTask(UArg arg0, UArg arg1)
{
    MCAN_TxBufElement txMsg;

    Utils_consolePrintf("\nGatewayApp: MCAN Transmitter app started..\n");

    GatewayApp_mcanTxMsgInit(&txMsg);

    while(1)
    {
        if (0U == NetworkReadPayload(&gatewayAppObj.netRxSockObj, gatewayAppObj.recvBuffer, 64U))
        {
            memcpy(&txMsg.data[0U], gatewayAppObj.recvBuffer, 64U);

            txMsg.dlc =0xF;

            GatewayApp_mcanTx(&txMsg);

            gatewayAppObj.canMsgTxCnt++;
        }
        else
        {
            /* TaskSleep(10); */
        }

    }


}

void GatewayApp_mcanRxTask(UArg arg0, UArg arg1)
{
    /* This is receiver side application */
    MCAN_TxBufElement          txMsg;
    uint32_t bitPos, status;
    int32_t testStatus = STW_SOK;
    MCAN_RxBufElement    rxMsg;
    MCAN_RxNewDataStatus newDataStatus;
    MCAN_ErrCntStatus    errCounter;

    txMsg.dlc = 0xFU;

    while (testStatus == STW_SOK)
    {
#ifndef MCAN_POLLINGMODE
        /* put semaphore code here */
        Semaphore_pend((Semaphore_Handle)gatewayAppObj.canRxMsgSem, BIOS_WAIT_FOREVER);
#endif
        /* Checking for Errors */
        MCAN_getErrCounters(GATEWAYAPP_MCAN_MODULE, &errCounter);

        if ((0U == errCounter.recErrCnt) &&
            (0U == errCounter.canErrLogCnt))
        {
            bitPos = (1U << GATEWAYAPP_MCAN_RX_MAILBOX_NUM);
            MCAN_getNewDataStatus(GATEWAYAPP_MCAN_MODULE, &newDataStatus);
            MCAN_clearNewDataStatus(GATEWAYAPP_MCAN_MODULE, &newDataStatus);
            if (bitPos < 32)
            {
                status = newDataStatus.statusLow;
            }
            else
            {
                status = newDataStatus.statusHigh;
            }
            if ((status & bitPos) == bitPos)
            {
                MCAN_readMsgRam(GATEWAYAPP_MCAN_MODULE,
                                MCAN_MEM_TYPE_BUF,
                                GATEWAYAPP_MCAN_RX_MAILBOX_NUM,
                                GATEWAYAPP_MCAN_RX_MAILBOX_NUM,
                                &rxMsg);

                gatewayAppObj.canMsgRxCnt++;
            }

#ifdef GATEWAYAPP_PRINTMCANMSG
            GatewayApp_mcanPrintRxMsg(&rxMsg);
#endif

#if !defined (ENABLE_LOOPBACK)
            NetworkWritePayload(&gatewayAppObj.netTxSockObj, &(rxMsg.data[0U]), 64U);
#else
            GatewayApp_mcanTxRxMessageCheck((MCAN_TxBufElement *)arg0, &rxMsg);
#endif
        }
        else
        {
            Utils_consolePrintf(
            "\nGatewayApp: Error in reception with payload Bytes:%d",
            gMcanAppdataSize[txMsg.dlc]);
            testStatus = STW_EFAIL;
        }
    }

}

void GatewayApp_cpuLoadTask(UArg arg0, UArg arg1)
{
    while(1)
    {
        Utils_prfLoadUpdate();

        /* print every 10 seconds */
        Utils_consolePrintf("\nGatewayApp: CAN stats - Received %d Transmitted %d", gatewayAppObj.canMsgRxCnt, gatewayAppObj.canMsgTxCnt);

        Utils_prfLoadPrintAll(1U);

        gatewayAppObj.canMsgRxCnt = 0U;
        gatewayAppObj.canMsgTxCnt = 0U;

        Utils_prfLoadCalcReset();

        Task_sleep(5000U);
    }
}

void GatewayApp_mcanBusOffRecovery(uint32_t module)
{
    MCAN_ProtocolStatus protStatus;
    MCAN_ErrCntStatus errCnt;

    /* Take MCAN out of the SW initialization mode */
    MCAN_setOpMode(module, MCAN_OPERATION_MODE_NORMAL);
    while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(module))
    {}
    /* wait for 129 occurrences of Bus Idle (129 × 11 consecutive recessive bits)
       before resuming normal operation. */
    /* The MCAN_ECR[14:8] REC field is used to count these sequences */
    /* Wait till first 11 consecutive recessive bits are detected */
    /* After resetting CCCR.INIT bit, MCAN writes to '5'(MCAN_ERR_CODE_BIT0_ERROR) to PSR.LEC */
    MCAN_getProtocolStatus(module, &protStatus);
    while (protStatus.lastErrCode != MCAN_ERR_CODE_BIT0_ERROR)
    {
        MCAN_getProtocolStatus(module, &protStatus);
    }
    /* This is 7 bit field(max value 127), so wait till it becomes none zero */
    /* wait for rest 128 occurrences */
    MCAN_getErrCounters(module, &errCnt);
    while (errCnt.recErrCnt != 0U)
    {
        MCAN_getErrCounters(module, &errCnt);
    }
    MCAN_getProtocolStatus(module, &protStatus);
    if ((protStatus.errPassive == 0U) &&
        (protStatus.busOffStatus == 0U) &&
        (protStatus.warningStatus == 0U))
    {
        Utils_consolePrintf("\nCurrent State: Error Active\n");
    }
}

#if defined (ENABLE_LOOPBACK)
void GatewayApp_mcanLpbkTest()
{
    MCAN_TxBufElement txMsg;
    uint32_t loopCnt;

    GatewayApp_mcanTxMsgInit(&txMsg);

    /* set ID to receive message */
    txMsg.id  = (uint32_t)((uint32_t)(GATEWAYAPP_MCAN_RX_MSG_ID) << 18U);
    txMsg.dlc =0xF;
    for (loopCnt = 0U; loopCnt < gMcanAppdataSize[txMsg.dlc]; loopCnt++)
    {
        txMsg.data[loopCnt] = loopCnt;
    }
    /* transmit message */
    GatewayApp_mcanTx(&txMsg);
    GatewayApp_mcanRxTask((UArg)&txMsg, NULL);
}

static int32_t GatewayApp_mcanTxRxMessageCheck(const MCAN_TxBufElement *txMsg,
                                               const MCAN_RxBufElement *rxMsg)
{
    uint32_t msgMask, loopCnt;
    int32_t retStatus = STW_SOK;

    /* Check/Compare Rx message with Tx message */
    if(txMsg->xtd == 1U)
    {
        msgMask = GATEWAYAPP_MCAN_EXT_ID_MASK;
    }
    else
    {
        msgMask = GATEWAYAPP_MCAN_STD_ID_MASK;
    }
    if (((txMsg->id & msgMask) == (rxMsg->id & msgMask)) &&
        (txMsg->rtr == rxMsg->rtr) &&
        (txMsg->xtd == rxMsg->xtd) &&
        (txMsg->esi == rxMsg->esi) &&
        (txMsg->dlc == rxMsg->dlc) &&
        (txMsg->brs == rxMsg->brs) &&
        (txMsg->fdf == rxMsg->fdf))
    {
        for (loopCnt = 0U;
             loopCnt < gMcanAppdataSize[rxMsg->dlc];
             loopCnt++)
        {
            if (txMsg->data[loopCnt] != rxMsg->data[loopCnt])
            {
                break;
            }
        }
        if(loopCnt == gMcanAppdataSize[rxMsg->dlc])
        {
            retStatus = STW_SOK;
        }
        else
        {
            retStatus = STW_EFAIL;
        }
    }
    else
    {
        retStatus = STW_EFAIL;
    }

    Utils_consolePrintf("\nGATEWAYAPP: All tests have passed\n");

    return retStatus;
}
#endif
/* end of file */
