/*
 *  Copyright (c) Texas Instruments Incorporated 2024
 *
 *  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 ti_enet_lwipif.c
 *
 * \brief This file contains enet Lwip interface layer implementation for driver callback.
 */

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

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include "ti_enet_config.h"
#include "ti_enet_lwipif.h"
#include <lwip/tcpip.h>
#include <assert.h>

#include <kernel/dpl/TaskP.h>
#include <kernel/dpl/SemaphoreP.h>
#include <kernel/dpl/ClockP.h>
#include <kernel/dpl/SystemP.h>
#include <kernel/dpl/HwiP.h>

#include <enet.h>
#include <per/cpsw.h>
#include <enet_appmemutils_cfg.h>
#include <enet_apputils.h>
#include <enet_appmemutils.h>
#include <enet_appboardutils.h>
#include <enet_appsoc.h>
#include <enet_apprm.h>
#include <pbufQ.h>

#include <lwip2lwipif.h>
#include <custom_pbuf.h>
#include <lwip/prot/ieee.h>

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
#if ENET_CFG_IS_ON(CPSW_CSUM_OFFLOAD_SUPPORT)
#if !LWIP_CHECKSUM_CTRL_PER_NETIF
#error "LWIP_CHECKSUM_CTRL_PER_NETIF is not set in lwipopts.h"
#endif
#endif

#define ENETLWIP_PACKET_POLL_PERIOD_US (1000U)

#define ENETLWIP_APP_POLL_PERIOD       (500U)

#define LWIPIF_NUM_RX_PACKET_TASKS     (1U)

#define LWIPIF_NUM_TX_PACKET_TASKS     (1U)

#define NUM_NETIF_SUPPORTED_MAX        (2U)

/*! \brief RX packet task stack size */
#define LWIPIF_RX_PACKET_TASK_STACK    (1024U)

/*! \brief TX packet task stack size */
#define LWIPIF_TX_PACKET_TASK_STACK    (1024U)

/*! \brief Links status poll task stack size */
#if (_DEBUG_ == 1)
#define LWIPIF_POLL_TASK_STACK         (3072U)
#else
#define LWIPIF_POLL_TASK_STACK         (1024U)
#endif

#define OS_TASKPRIHIGH              8U

#define LWIPIF_RX_PACKET_TASK_PRI      (OS_TASKPRIHIGH)

#define LWIPIF_TX_PACKET_TASK_PRI      (OS_TASKPRIHIGH)

#define LWIP_POLL_TASK_PRI             (OS_TASKPRIHIGH - 1U)


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

typedef struct LwipifEnetApp_Object_s
{
    struct netif gNetif[ENET_SYSCFG_NETIF_COUNT];
    /*
    * Clock handle for triggering the packet Rx notify
    */
    ClockP_Object pollLinkClkObj;
} LwipifEnetApp_Object;
/*
 * Clock handle for triggering the packet Rx notify
 */
    ClockP_Object pollLinkClkObj;


/* For Cpdma Rx scatter-gather implies that #rxpkts = #rxbuffers = #rxpbufs
   For Udma's static Rx scatter-gather, #rxbuffers = #rxpbufs = 4 * #rxpkts */
LWIP_MEMPOOL_DECLARE(RX_POOL, ENET_SYSCFG_TOTAL_NUM_RX_PKT, sizeof(Rx_CustomPbuf), "Rx Custom Pbuf pool");
/* These must be sufficient for total number of rx pbufs and tx packets */
pbufNode gFreePbufArr[ENET_SYSCFG_TOTAL_NUM_RX_PKT * 4];
static LwipifEnetApp_Object gLwipifEnetAppObj;
/* ========================================================================== */
/*                            Function Declaration                            */
/* ========================================================================== */


static void LwipifEnetApp_poll(void *arg);

static void LwipifEnetApp_postPollLink(ClockP_Object *clkObj, void *arg);

void LwipifEnetApp_eventSchedule(EventP_Object *obj);

static void LwipifEnetApp_postPollEvent(ClockP_Object *obj, void* pArg);

static void LwipifEnetApp_postRxPktEvent(void* pArg);

static void LwipifEnetApp_postTxPktEvent(void* pArg);



LwipifEnetApp_Handle LwipifEnetApp_getHandle()
{
    return (LwipifEnetApp_Handle)&gLwipifEnetAppObj;
}

struct netif* LwipifEnetApp_netifOpen(LwipifEnetApp_Handle handle, uint32_t netifIdx, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw)
{
    const uint32_t lwipIdx2Enet[ENET_SYSCFG_NETIF_COUNT][2] = {{ENET_CPSW_3G, 0},{ENET_CPSW_3G, 0},};
        /* Peripheral type */
    Enet_Type enetType = lwipIdx2Enet[netifIdx][0];

    /* Peripheral instance */
    uint32_t instId = lwipIdx2Enet[netifIdx][1];

    LwipifEnetApp_Object* pObj = (LwipifEnetApp_Object*) handle;
    if (netifIdx < ENET_SYSCFG_NETIF_COUNT)
    {
#if ENET_CFG_IS_ON(CPSW_CSUM_OFFLOAD_SUPPORT)

        /* Enable all Flags except below checksumflags. */
        const uint32_t lwIPChcksumDisableFlags = 0U | NETIF_CHECKSUM_GEN_TCP | NETIF_CHECKSUM_GEN_UDP;
        const uint32_t lwIPChcksumSetFlags = (NETIF_CHECKSUM_ENABLE_ALL & ~lwIPChcksumDisableFlags);
#endif
        netif_add(&pObj->gNetif[netifIdx],
                    ipaddr, 
                    netmask,
                    gw,
                    NULL,
                    LWIPIF_LWIP_init, 
                    netif_input
                 );
        LWIPIF_LWIP_start(enetType, instId, &pObj->gNetif[netifIdx], netifIdx);

        if(netifIdx == ENET_SYSCFG_DEFAULT_NETIF_IDX)
        {
            netif_set_default(&pObj->gNetif[netifIdx]);
        }
#if ENET_CFG_IS_ON(CPSW_CSUM_OFFLOAD_SUPPORT)
        NETIF_SET_CHECKSUM_CTRL(&pObj->gNetif[netifIdx], lwIPChcksumSetFlags);
#endif
    }
    else
    {
        DebugP_log("ERROR: NetifIdx is out of valid range!\r\n");
        EnetAppUtils_assert(FALSE);
    }
    return (&pObj->gNetif[netifIdx]);
}

void LwipifEnetApp_netifClose(LwipifEnetApp_Handle handle, const uint32_t netifIdx)
{
    LwipifEnetApp_Object* pObj = (LwipifEnetApp_Object*) handle;
    netif_remove(&pObj->gNetif[netifIdx]);
}

struct netif* LwipifEnetApp_getNetifFromId(LwipifEnetApp_Handle handle, uint32_t netifIdx)
{
    LwipifEnetApp_Object* pObj = (LwipifEnetApp_Object*) handle;
    struct netif * pNetif = NULL;
    if(netifIdx < ENET_SYSCFG_NETIF_COUNT)
    {
        pNetif = &pObj->gNetif[netifIdx];
    }
    else{
            DebugP_log("ERROR: NetifIdx is out of valid range!\r\n");
            EnetAppUtils_assert(FALSE);
    }

    return pNetif;
}

void LwipifEnetAppCb_getEnetLwipIfInstInfo(Enet_Type enetType, uint32_t instId, LwipifEnetAppIf_GetEnetLwipIfInstInfo *outArgs)
{
    EnetPer_AttachCoreOutArgs attachInfo;
    EnetApp_HandleInfo handleInfo;

    uint32_t coreId = EnetSoc_getCoreId();

    EnetApp_coreAttach(enetType, instId, coreId, &attachInfo);
    EnetApp_acquireHandleInfo(enetType, instId, &handleInfo);

    outArgs->hostPortRxMtu = attachInfo.rxMtu;
    ENET_UTILS_ARRAY_COPY(outArgs->txMtu, attachInfo.txMtu);
    outArgs->isPortLinkedFxn = &EnetApp_isPortLinked;
    outArgs->timerPeriodUs   = ENETLWIP_PACKET_POLL_PERIOD_US;
    outArgs->pPbufInfo = gFreePbufArr;
    outArgs->pPbufInfoSize = sizeof(gFreePbufArr)/sizeof(pbufNode);
    LWIP_MEMPOOL_INIT(RX_POOL);

    /* TX Checksum offload check is removed here. Based on Sysconfig checksum offload
     * configuration, getLwipChecksumDisableFlags() API is updating the Tx,Rx checksum flags in LWIP Stack */
}

void LwipifEnetAppCb_getTxHandleInfo(LwipifEnetAppIf_GetTxHandleInArgs *inArgs,
                                     LwipifEnetAppIf_TxHandleInfo *outArgs)
{
    uint32_t i;
    EnetDma_Pkt *pPktInfo;
    EnetApp_GetTxDmaHandleOutArgs  txChInfo;
    EnetApp_GetDmaHandleInArgs     txInArgs;

    /* Open TX channel */
    txInArgs.cbArg     = inArgs->cbArg;
    txInArgs.notifyCb  = inArgs->notifyCb;

    EnetApp_getTxDmaHandle(inArgs->chId,
                          &txInArgs,
                          &txChInfo);

    outArgs->hTxChannel = txChInfo.hTxCh;
    outArgs->txChNum = txChInfo.txChNum;
    outArgs->numPackets = txChInfo.maxNumTxPkts;
    outArgs->disableEvent = 1;

    /* Initialize the DMA free queue */
    EnetQueue_initQ(inArgs->pktInfoQ);

    for (i = 0U; i < txChInfo.maxNumTxPkts; i++)
    {
        /* Initialize Pkt info Q from allocated memory */
        pPktInfo = EnetMem_allocEthPktInfoMem(&inArgs->cbArg,
                                              ENETDMA_CACHELINE_ALIGNMENT);

        EnetAppUtils_assert(pPktInfo != NULL);
        ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_FREEQ);
        EnetQueue_enq(inArgs->pktInfoQ, &pPktInfo->node);

    }

}

void LwipifEnetAppCb_getRxHandleInfo(LwipifEnetAppIf_GetRxHandleInArgs *inArgs,
                                     LwipifEnetAppIf_RxHandleInfo *outArgs)
{
    uint32_t i;
    EnetDma_Pkt *pPktInfo;
    Rx_CustomPbuf *cPbuf;

    EnetApp_HandleInfo handleInfo;
    EnetPer_AttachCoreOutArgs attachInfo;
    uint32_t coreId          = EnetSoc_getCoreId();
    EnetApp_GetRxDmaHandleOutArgs  rxChInfo;
    EnetApp_GetDmaHandleInArgs     rxInArgs;
    uint32_t numCustomPbuf;
    uint32_t scatterSegments[] =
    {
        ENET_UTILS_ALIGN(1536, ENETDMA_CACHELINE_ALIGNMENT) /* Keep this size aligned with R5F cacheline of 32B */
    };
    EnetApp_acquireHandleInfo(inArgs->enetType, inArgs->instId, &handleInfo);
    EnetApp_coreAttach(inArgs->enetType, inArgs->instId, coreId, &attachInfo);

    /* Open RX channel */
    rxInArgs.cbArg     = inArgs->cbArg;
    rxInArgs.notifyCb  = inArgs->notifyCb;

    EnetApp_getRxDmaHandle(inArgs->chId,
                          &rxInArgs,
                          &rxChInfo);
    numCustomPbuf = rxChInfo.maxNumRxPkts;
    outArgs->rxFlowIdx = rxChInfo.rxChNum;
    outArgs->hRxFlow      = rxChInfo.hRxCh;
    outArgs->numPackets   = rxChInfo.maxNumRxPkts;
    outArgs->disableEvent = 1;

    for (uint32_t i = 0; i < rxChInfo.numValidMacAddress; i++)
    {
        EnetUtils_copyMacAddr(&outArgs->macAddr[inArgs->chId][0U], rxChInfo.macAddr[i]);
        EnetAppUtils_print("Host MAC address-%d : ",inArgs->chId);
        EnetAppUtils_printMacAddr(&outArgs->macAddr[inArgs->chId][0U]);
    }

    /* Initialize the DMA free queue */
    EnetQueue_initQ(inArgs->pReadyRxPktQ);
    EnetQueue_initQ(inArgs->pFreeRxPktInfoQ);
    pbufQ_init(inArgs->pFreePbufInfoQ);

    for (i = 0U; i < rxChInfo.maxNumRxPkts; i++)
    {

        pPktInfo = EnetMem_allocEthPkt(&inArgs->cbArg,
                           ENETDMA_CACHELINE_ALIGNMENT,
                           ENET_ARRAYSIZE(scatterSegments),
                           scatterSegments);
        EnetAppUtils_assert(pPktInfo != NULL);
        ENET_UTILS_SET_PKT_APP_STATE(&pPktInfo->pktState, ENET_PKTSTATE_APP_WITH_READYQ);

        /* Put all the filled pPktInfo into readyRxPktQ and submit to driver */
        EnetQueue_enq(inArgs->pReadyRxPktQ, &pPktInfo->node);
    }

    EnetQueue_verifyQCount(inArgs->pReadyRxPktQ);
    for (i = 0U; i < numCustomPbuf; i++)
    {
        /* Allocate the Custom Pbuf structures and put them in freePbufInfoQ */
        cPbuf = NULL;
        cPbuf = (Rx_CustomPbuf*)LWIP_MEMPOOL_ALLOC(RX_POOL);
        EnetAppUtils_assert(cPbuf != NULL);
        cPbuf->p.custom_free_function = custom_pbuf_free;
        cPbuf->customPbufArgs         = (Rx_CustomPbuf_Args)inArgs->cbArg;
        cPbuf->next                   = NULL;
        cPbuf->alivePbufCount         = 0U;
        cPbuf->orgBufLen              = 0U;
        cPbuf->orgBufPtr              = NULL;
        cPbuf->p.pbuf.flags          |= PBUF_FLAG_IS_CUSTOM;
        pbufQ_enQ(inArgs->pFreePbufInfoQ, &(cPbuf->p.pbuf));
    }

}

void LwipifEnetAppCb_releaseTxHandle(LwipifEnetAppIf_ReleaseTxHandleInfo *releaseInfo)
{
    EnetApp_HandleInfo handleInfo;
    EnetPer_AttachCoreOutArgs attachInfo;
    EnetDma_PktQ fqPktInfoQ;
    EnetDma_PktQ cqPktInfoQ;
    uint32_t coreId = EnetSoc_getCoreId();

    EnetApp_acquireHandleInfo(releaseInfo->enetType, releaseInfo->instId, &handleInfo);
    EnetApp_coreAttach(releaseInfo->enetType, releaseInfo->instId, coreId, &attachInfo);

    /* Close TX channel */
    EnetQueue_initQ(&fqPktInfoQ);
    EnetQueue_initQ(&cqPktInfoQ);
    EnetApp_closeTxDma(releaseInfo->txChNum,
                       handleInfo.hEnet,
                       attachInfo.coreKey,
                       coreId,
                       &fqPktInfoQ,
                       &cqPktInfoQ);
    releaseInfo->txFreePktCb(releaseInfo->txFreePktCbArg, &fqPktInfoQ, &cqPktInfoQ);
    EnetApp_coreDetach(releaseInfo->enetType, releaseInfo->instId, coreId, attachInfo.coreKey);
    EnetApp_releaseHandleInfo(releaseInfo->enetType, releaseInfo->instId);
}

void LwipifEnetAppCb_releaseRxHandle(LwipifEnetAppIf_ReleaseRxHandleInfo *releaseInfo)
{
    EnetApp_HandleInfo handleInfo;
    EnetPer_AttachCoreOutArgs attachInfo;
    EnetDma_PktQ fqPktInfoQ;
    EnetDma_PktQ cqPktInfoQ;
    uint32_t coreId = EnetSoc_getCoreId();

    EnetApp_acquireHandleInfo(releaseInfo->enetType, releaseInfo->instId, &handleInfo);
    EnetApp_coreAttach(releaseInfo->enetType, releaseInfo->instId, coreId, &attachInfo);

    /* Close RX channel */
    EnetQueue_initQ(&fqPktInfoQ);
    EnetQueue_initQ(&cqPktInfoQ);
    EnetApp_closeRxDma(releaseInfo->rxChNum,
                       handleInfo.hEnet,
                       attachInfo.coreKey,
                       coreId,
                       &fqPktInfoQ,
                       &cqPktInfoQ);

    releaseInfo->rxFreePktCb(releaseInfo->rxFreePktCbArg, &fqPktInfoQ, &cqPktInfoQ);
    EnetApp_coreDetach(releaseInfo->enetType, releaseInfo->instId, coreId, attachInfo.coreKey);
    EnetApp_releaseHandleInfo(releaseInfo->enetType, releaseInfo->instId);
}

static void LwipifEnetApp_postPollEvent(ClockP_Object *obj, void* pArg)
{
    EventP_Object* pEvent = (EventP_Object*) pArg;
    const int32_t status = EventP_setBits(pEvent, AppEventId_NETIFMNGR_POLL);

    if (status != SystemP_SUCCESS)
    {
        EnetAppUtils_print("Failed to post Poll Event handle\r\n");
        EnetAppUtils_assert(false);
    }
}

static void LwipifEnetApp_postRxPktEvent(void* pArg)
{
    EventP_Object* pEvent = (EventP_Object*) pArg;
    const int32_t status = EventP_setBits(pEvent, AppEventId_NETIFMNGR_RXPKT);

    if (status != SystemP_SUCCESS)
    {
        EnetAppUtils_print("Failed to post Rx Event handle\r\n");
        EnetAppUtils_assert(false);
    }
}

static void LwipifEnetApp_postTxPktEvent(void* pArg)
{
    EventP_Object* pEvent = (EventP_Object*) pArg;
    const int32_t status = EventP_setBits(pEvent, AppEventId_NETIFMNGR_TXPKT);

    if (status != SystemP_SUCCESS)
    {
        EnetAppUtils_print("Failed to post Tx Event handle\r\n");
        EnetAppUtils_assert(false);
    }
}

/*
* create a function called postEvent[i]. each event, each postfxn.
*/
static void LwipifEnetApp_postSemaphore(void *pArg)
{
    SemaphoreP_Object *pSem = (SemaphoreP_Object *) pArg;
    SemaphoreP_post(pSem);
}

int32_t LwipifEnetApp_getNetifIdx(LwipifEnetApp_Handle handle, struct netif* netif)
{
    LwipifEnetApp_Object* pObj = (LwipifEnetApp_Object*) handle;

    int32_t idx = -1;

    for (uint32_t i = 0; i < 2; i++)
    {
        if (&pObj->gNetif[i] == netif)
        {
            idx = i;
            break;
        }
    }

    return idx;
}
void LwipifEnetApp_startSchedule(LwipifEnetApp_Handle handle, struct netif *netif
    ,EventP_Object* p_hEvent
    )
{
    ClockP_Params clkPrms;

    Enet_notify_t rxNotify =
    {
       .cbFxn = &LwipifEnetApp_postRxPktEvent, //gives different cb fxn for different events.
       .cbArg = p_hEvent //
    };
    Enet_notify_t txNotify =
    {
        .cbFxn = &LwipifEnetApp_postTxPktEvent,
        .cbArg = p_hEvent
    };

    LWIPIF_LWIP_setNotifyCallbacks(netif, &rxNotify, &txNotify);


    ClockP_Params_init(&clkPrms);
    clkPrms.start     = 0;
    clkPrms.period    = ENETLWIP_APP_POLL_PERIOD;
    clkPrms.args      = p_hEvent;
    clkPrms.callback  = &LwipifEnetApp_postPollEvent;
    clkPrms.timeout   = ENETLWIP_APP_POLL_PERIOD;

    /* Creating timer and setting timer callback function*/
    int32_t status = ClockP_construct(&pollLinkClkObj, &clkPrms);
    if (status == SystemP_SUCCESS)
    {
        /* Set timer expiry time in OS ticks */
        ClockP_setTimeout(&pollLinkClkObj, ENETLWIP_APP_POLL_PERIOD);
        ClockP_start(&pollLinkClkObj);
    }
    else
    {
        EnetAppUtils_assert (status == SystemP_SUCCESS);
    }
}

void LwipifEnetApp_getRxChIDs(const Enet_Type enetType, const uint32_t instId, uint32_t netifIdx, uint32_t* pRxChIdCount, uint32_t rxChIdList[LWIPIF_MAX_RX_CHANNELS_PER_PHERIPHERAL])
{
    int32_t netif2ChMap[ENET_SYSCFG_NETIF_COUNT][LWIPIF_MAX_RX_CHANNELS_PER_PHERIPHERAL] = {{ENET_DMA_RX_CH0, -1,},{ENET_DMA_RX_CH0, -1,},};
    uint32_t chCount;
    
    EnetAppUtils_assert(netifIdx < ENET_SYSCFG_NETIF_COUNT);
    
    for (chCount = 0U; (chCount < LWIPIF_MAX_RX_CHANNELS_PER_PHERIPHERAL) && (netif2ChMap[netifIdx][chCount] != -1); chCount++)
    {
        rxChIdList[chCount] = netif2ChMap[netifIdx][chCount];
    }
    
    /* verifiy the user params */
    switch (enetType)
    {
    case ENET_ICSSG_SWITCH:
    {
        EnetAppUtils_assert(chCount == 2);
        break;
    }
    case ENET_ICSSG_DUALMAC:
    case ENET_CPSW_3G:
    case ENET_CPSW_2G:
    {
        EnetAppUtils_assert(chCount == 1);
        break;
    }
    default:
    {
        EnetAppUtils_assert(false);
    }
    }
    *pRxChIdCount = chCount;
    return;
}

void LwipifEnetApp_getTxChIDs(const Enet_Type enetType, const uint32_t instId, uint32_t netifIdx, uint32_t* pTxChIdCount, uint32_t txChIdList[LWIPIF_MAX_TX_CHANNELS_PER_PHERIPHERAL])
{
    int32_t netif2ChMap[ENET_SYSCFG_NETIF_COUNT][LWIPIF_MAX_TX_CHANNELS_PER_PHERIPHERAL] = {{ENET_DMA_TX_CH0},{ENET_DMA_TX_CH0},};
    uint32_t chCount;
    
    EnetAppUtils_assert(netifIdx < ENET_SYSCFG_NETIF_COUNT);
    
    for (chCount = 0U; (chCount < LWIPIF_MAX_TX_CHANNELS_PER_PHERIPHERAL) && (netif2ChMap[netifIdx][chCount] != -1); chCount++)
    {
        txChIdList[chCount] = netif2ChMap[netifIdx][chCount];
    }

    /* verifiy the user params */
    switch (enetType)
    {
    case ENET_ICSSG_SWITCH:
    case ENET_ICSSG_DUALMAC:
    case ENET_CPSW_3G:
    case ENET_CPSW_2G:
    {
        EnetAppUtils_assert(chCount == 1);
        break;
    }
    default:
    {
        EnetAppUtils_assert(false);
    }
    }
    
    *pTxChIdCount = chCount;
    return;
}

void LwipifEnetApp_getProxyArpRxChIDs(const Enet_Type enetType, const uint32_t instId, uint32_t netifIdx, uint32_t* pRxChIdCount, uint32_t rxChIdList[LWIPIF_MAX_RX_CHANNELS_PER_PHERIPHERAL])
{
}

void LwipifEnetApp_getVepaRxChIDs(const Enet_Type enetType, const uint32_t instId, uint32_t netifIdx, uint32_t* pRxChIdCount, uint32_t rxChIdList[LWIPIF_MAX_RX_CHANNELS_PER_PHERIPHERAL])
{
}

void LwipifEnetApp_setupProxyArphandler(const Enet_Type enetType, const uint32_t instId, Lwip2Enet_RxHandle hRx)
{
}

void LwipifEnetApp_setupPacketDuplicationRoute(const Enet_Type enetType, const uint32_t instId, Lwip2Enet_RxHandle hRx)
{
}

Lwip2Enet_RxMode_t LwipifEnetAppCb_getRxMode(Enet_Type enetType, uint32_t instId)
{
    const bool hasSwitchModeEnabled = false; 
    Lwip2Enet_RxMode_t rxMode = Lwip2Enet_RxMode_SwitchSharedChannel;
    if (hasSwitchModeEnabled)
    {
        rxMode = Lwip2Enet_RxMode_SwitchSharedChannel;
    }
    else
    {
        rxMode = Lwip2Enet_RxMode_MacSharedChannel;
    }
    return rxMode;
}


void LwipifEnetApp_eventSchedule(EventP_Object *obj)
{
    
}

static void LwipifEnetApp_postPollLink(ClockP_Object *clkObj, void *arg)
{
    if (arg != NULL)
    {
        SemaphoreP_Object *hPollSem = (SemaphoreP_Object *) arg;
        SemaphoreP_post(hPollSem);
    }
}




