/*******************************************************************************
 * (c) Copyright 2015 Microsemi Corporation.  All rights reserved.
 *
 *
 *
 * SVN $Revision: $
 * SVN $Date: $
 */




/*
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
 */

#include <api_oam_sdk/common/constants/inc/mr_constants.h>
#include <api_oam_sdk/common/registers/inc/mr_registers.h>
#include <api_oam_sdk/isr/inc/cfm_isr.h>
#include <api_oam_sdk/metroam_hal/inc/mr_hal.h>
#include <api_oam_sdk/table_access/inc/table_access.h>
#include <api_oam_sdk/table_access/inc/table_access_constants.h>
#include "netif/etharp.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "arch/sys_arch.h"
#include "lwip/netif.h"
#include <string.h>

#include "semphr.h"

#include "gateway_2port_eth.h"
//VR#include "mss_ethernet_mac.h"
#include "coretse_types.h"

#include "osal.h"
#include "network_utilities.h"

#include "miv_rv32_hal.h"

#include <FreeRTOS.h>
#include <hal_assert.h>
#include <task.h>

/**************************************************************************/
/* Public Functions                                                       */
/**************************************************************************/

void mrProcessLanWanCaptPkt(void *pvParameters);
void mrSendPktToLwip(captPktInfo_t *captPktInfo);
void mrWanCaptPktHandler(captPktInfo_t *captPktInfo);
void mrSendPktToLTProc(captPktInfo_t *captPktInfo);

//--------------------------------------------------------------------------
// Global Variables required by this module
//--------------------------------------------------------------------------

//mrCaptPktCB_t		mrWANCaptPktCB = NULL;
//mrCaptPktCB_t		mrLANCaptPktCB = NULL;

osSemaphore_t		g_gw2p_eth_pkt_rx_sem = NULL;
osSemaphore_t		g_gw2p_eth_LAN_mutex = NULL;
osSemaphore_t		g_gw2p_eth_tx_mutex = NULL;

//--------------------------------------------------------------------------
// External Global Variables
//--------------------------------------------------------------------------
#if defined(MINGOA_ENABLE_DEBUG_LOGGING)
extern 	char		msgStr[500];
#endif
//VR
#if LWIP_NETIF_HOSTNAME
extern char 			netHostNames[PHY_COUNT][20];
#endif
//VRextern	mrDeviceInfo_t		mrDeviceInfo;
//VRextern tse_cfg_t 			g_mac_config[3];

#ifdef HAL_ALLOW_CALLS_FROM_ISR
extern bool		g_isrActive;
#endif

//--------------------------------------------------------------------------
// readNextCaptCpuWord
// This function should be called to read the next Double Word from the
// Captured packet FIFO. After the Dword has been read it updates a
// global captured packet FIFO tail pointer that is used. The FIFO
// used is circular so the tail must wrap at the FIFO size.
//--------------------------------------------------------------------------
int	readNextCaptCpuWord(mrPort_t port, uint32_t *dword, uint16_t *cpuCaptPktTail)
{
    mrHalRamRead((*cpuCaptPktTail),(port == mrPort0 ? CPU_CAPT_FIFO_SEL : CPU_SYS_CAPT_FIFO_SEL),dword);

    // make sure to wrap the tail at the FIFO size (in DWords)
    if (++(*cpuCaptPktTail) >= (MR_CPU_CAPT_FIFO_SIZE/4))
        *cpuCaptPktTail = 0;

    return(NO_ERR);
}

//--------------------------------------------------------------------------
// This function reads the next available captured packet INFO
// from the captured packet FIFO, advances the tail value and returns the
// Reason code and the packet size in bytes.
//--------------------------------------------------------------------------
int	readNextCaptCpuInfo(captPktInfo_t *captPktInfo)
{
    uint32_t	data;

    captPktInfo->pktLen = 0;			// in case there is an error reading the packet

    // read the current FIFO and data packet Tail values from the register
    mrHalRegRead((captPktInfo->port == mrPort0 ? CPU_PKT_FIFO_TAIL_REG_ADDR : CPU_SYS_PKT_FIFO_TAIL_REG_ADDR),&data);

    captPktInfo->cpuCaptPktTail = (uint16_t) ((data & CPU_PKT_FIFO_TAIL_PKT_TAIL_MASK) >> CPU_PKT_FIFO_TAIL_PKT_TAIL_OFFSET);
    captPktInfo->cpuCaptInfoTail = (uint16_t) ((data & CPU_PKT_FIFO_TAIL_INFO_TAIL_MASK) >> CPU_PKT_FIFO_TAIL_INFO_TAIL_OFFSET);

    // Read the info
    mrHalRamRead(captPktInfo->cpuCaptInfoTail,(captPktInfo->port == mrPort0 ? CPU_CAPT_INFO_FIFO_SEL : CPU_SYS_CAPT_INFO_FIFO_SEL),&data);

    // Increment the tail value now...it will be written to
    // HW after the packet has been successfully extracted
    (captPktInfo->cpuCaptInfoTail)++;

    // Extract the 'reason' value and packet length
    captPktInfo->captReason = (uint16_t) ((data & CPU_CAPT_INFO_FIFO_PKT_REASON_MASK) >> CPU_CAPT_INFO_FIFO_PKT_REASON_OFFSET);
    captPktInfo->pktLen = (uint16_t) ((data  & CPU_CAPT_INFO_FIFO_PKT_SIZE_MASK) >> CPU_CAPT_INFO_FIFO_PKT_SIZE_OFFSET);

    return(NO_ERR);
}


//--------------------------------------------------------------------------
// This function is used to read a captured packet out of the HW
// FIFO and place it in a CPU RAM (malloc) and return a pointer
// to that RAM. The HW FIFO space is freed up after the packet has
// been completely removed.
//--------------------------------------------------------------------------
int readGenericPacket(uint8_t* pktPtr, captPktInfo_t captPktInfo)
{
    uint32_t	data;
    int			bytesRemaining;
    uint8_t		*newPtr;
    uint32_t	*dwrdPtr = (uint32_t*)pktPtr;

    bytesRemaining = captPktInfo.pktLen;

    if (pktPtr != NULL)
    {
        newPtr = pktPtr;
        // read any residue remaining.
        while (bytesRemaining > 0)
        {
            readNextCaptCpuWord(captPktInfo.port,dwrdPtr++,&captPktInfo.cpuCaptPktTail);

#if 0
            bytePtr = (uint8_t*)&data;
            bytePtr += 3;	// Need to byte swivel contents to populate the byte array
            if (bytesRemaining < 4)
            {


                switch(bytesRemaining)
                {
                case 1:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %02lX",  (data >> 24));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *(bytePtr+3);
                    break;
                }
                case 2:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %04lX",  (data >> 16));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                case 3:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %06lX", (data >> 8));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                }

            }
            else
            {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                sprintf(msgStr, "CAPT: %08lX", data);
                writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr;

            }
#endif
            bytesRemaining -= 4;
        }
    }
    else
    {
        // No buffer was supplied to received the extracted packet so simply trash it!
        captPktInfo.cpuCaptPktTail += (captPktInfo.pktLen >> 2);  	//inc the tail by the number of Dwords in the packet
        if (captPktInfo.pktLen & 0x3)
            captPktInfo.cpuCaptPktTail++;				// a full dword is used if these is residue

        // make sure to wrap the tail at the FIFO size (in DWords)
        if (captPktInfo.cpuCaptPktTail > (MR_CPU_CAPT_FIFO_SIZE/4))
            captPktInfo.cpuCaptPktTail = captPktInfo.cpuCaptPktTail - (MR_CPU_CAPT_FIFO_SIZE/4);
    }

    if (captPktInfo.port == mrPort0)
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_PKT_TAIL_MASK)
		                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_PKT_CNTR_CTRL_REG_ADDR,CPU_PKT_CNTR_CTRL_DEC_PKT_MASK | CPU_PKT_CNTR_CTRL_DEBUG_FIFO_THRESH_MASK);
    }
    else
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_MASK)
				                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_SYS_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_SYS_PKT_CNTR_CTRL_REG_ADDR,CPU_SYS_PKT_CNTR_CTRL_DEC_PKT_MASK);
    }

    return(NO_ERR);
}

int readGenericPacket_littleIndian(uint8_t* pktPtr, captPktInfo_t captPktInfo)
{
    uint32_t	data;
    int		bytesRemaining;
    uint8_t	*bytePtr;
    uint8_t	*newPtr;

    bytesRemaining = captPktInfo.pktLen;

#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
    sprintf(msgStr, "INFO: readGenericPacket:  New captured packet of length = %d", pktLen);
    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif

    if (pktPtr != NULL)
    {
        newPtr = pktPtr;
        // read any residue remaining.
        while (bytesRemaining > 0)
        {
            readNextCaptCpuWord(captPktInfo.port,&data,&captPktInfo.cpuCaptPktTail);

            bytePtr = (uint8_t*)&data;
            bytePtr += 3;	// Need to byte swivel contents to populate the byte array
            if (bytesRemaining < 4)
            {
                switch(bytesRemaining)
                {
                case 1:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %02lX",  (data >> 24));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr;
                    break;
                }
                case 2:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %04lX",  (data >> 16));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                case 3:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %06lX", (data >> 8));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                }
            }
            else
            {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                sprintf(msgStr, "CAPT: %08lX", data);
                writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr;

            }

            bytesRemaining -= 4;
        }
    }
    else
    {
        // No buffer was supplied to received the extracted packet so simply trash it!
        captPktInfo.cpuCaptPktTail += (captPktInfo.pktLen >> 2);  	//inc the tail by the number of Dwords in the packet
        if (captPktInfo.pktLen & 0x3)
            captPktInfo.cpuCaptPktTail++;				// a full dword is used if these is residue

        // make sure to wrap the tail at the FIFO size (in DWords)
        if (captPktInfo.cpuCaptPktTail > (MR_CPU_CAPT_FIFO_SIZE/4))
            captPktInfo.cpuCaptPktTail = captPktInfo.cpuCaptPktTail - (MR_CPU_CAPT_FIFO_SIZE/4);
    }

    if (captPktInfo.port == mrPort0)
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_PKT_TAIL_MASK)
		                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_PKT_CNTR_CTRL_REG_ADDR,CPU_PKT_CNTR_CTRL_DEC_PKT_MASK | CPU_PKT_CNTR_CTRL_DEBUG_FIFO_THRESH_MASK);
    }
    else
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_MASK)
				                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_SYS_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_SYS_PKT_CNTR_CTRL_REG_ADDR,CPU_SYS_PKT_CNTR_CTRL_DEC_PKT_MASK);
    }

    return(NO_ERR);
}

//--------------------------------------------------------------------------
// This function returns the number of packets currently held in the
// WAN (Carrier) Capture FIFO
//--------------------------------------------------------------------------
int	mrGetNumWANPktsPending(void)
{
    uint32_t	numPkts;

    // If the interrupt is disabled we shouldn't fetch any captured packets
    mrHalRegRead(INT_MASK_REG_ADDR, &numPkts);
    if ((numPkts & CAPT_PKT_INT_MASK) == 0)
        return(0);

    mrHalRegRead(CPU_PKT_CNTR_REG_ADDR,&numPkts);

    return((int) numPkts & CPU_PKT_CNTR_MASK);
}

//--------------------------------------------------------------------------
// This function returns the number of packets currently held in the
// LAN (System) Capture FIFO
//--------------------------------------------------------------------------
int	mrGetNumLANPktsPending(void)
{
    uint32_t	numPkts;

    // If the interrupt is disabled we shouldn't fetch any captured packets
    mrHalRegRead(INT_MASK_REG_ADDR, &numPkts);
    if ((numPkts & SYS_CAPT_PKT_INT_MASK) == 0)
        return(0);

    mrHalRegRead(CPU_SYS_PKT_CNTR_REG_ADDR,&numPkts);

    return((int) numPkts & CPU_SYS_PKT_CNTR_MASK);
}

//--------------------------------------------------------------------------
// This function returns information about the next available packet in the
// WAN capture FIFO. It returns the capture reason, packet size in bytes,
// info tail address and packet tail address.
//--------------------------------------------------------------------------
int mrExtractWANCaptPktInfo(captPktInfo_t *captPktInfo)
{
    captPktInfo->port = mrPort0;
    return(readNextCaptCpuInfo(captPktInfo));
}

//--------------------------------------------------------------------------
// This function returns information about the next available packet in the
// LAN capture FIFO. It returns the capture reason, packet size in bytes,
// info tail address and packet tail address.
//--------------------------------------------------------------------------
int mrExtractLANCaptPktInfo(captPktInfo_t *captPktInfo)
{
    captPktInfo->port = mrPort1;
    return(readNextCaptCpuInfo(captPktInfo));
}


//--------------------------------------------------------------------------
// This function extracts the next available packet, based on the tail values in
// captPktInfo, from the WAN capture FIFO. The packet is copied into the
// buffer pointed to by pktBufPtr. If pktBufPtr is NULL then the packet
// will be trashed. The byte order matches the order the bytes arrive
// in on the wire. e.g.
// 01020304050607
// buff[0] -> 01          memory: buf -> 01020304
// buff[1] -> 02              buf + 4 -> 050607xx
// buff[2] -> 03
// buff[3] -> 04
// buff[4] -> 05
// buff[5] -> 06
// buff[6] -> 07
//
//--------------------------------------------------------------------------
int mrExtractWANCaptPkt(uint8_t *pktBufPtr,captPktInfo_t captPktInfo)
{
    captPktInfo.port = mrPort0;
    return(readGenericPacket(pktBufPtr,captPktInfo));
}

//--------------------------------------------------------------------------
// This function extracts the next available packet, based on the tail values in
// captPktInfo, from the LAN capture FIFO. The packet is copied into the
// buffer pointed to by pktBufPtr. If pktBufPtr is NULL then the packet
// will be trashed. The byte order matches the order the bytes arrive
// in on the wire. e.g.
// 01020304050607
// buff[0] -> 01          memory: buf -> 01020304
// buff[1] -> 02              buf + 4 -> 050607xx
// buff[2] -> 03
// buff[3] -> 04
// buff[4] -> 05
// buff[5] -> 06
// buff[6] -> 07
//
//--------------------------------------------------------------------------
int mrExtractLANCaptPkt(uint8_t *pktBufPtr,captPktInfo_t captPktInfo)
{
    captPktInfo.port = mrPort1;
    return(readGenericPacket(pktBufPtr,captPktInfo));
}
extern UART_instance_t g_uart;
void MSYS_EI0_IRQHandler()
{

    uint32_t                interruptBits;
       uint32_t                maskBits;
       uint32_t                rdData;

       signed long switch_context = 0;
   #ifdef DEBUG_PRINT_L2
       UART_polled_tx_string(&g_uart, (const uint8_t *)"External_30_IRQHandler triggered\n\r");
   #endif
       //PLIC_DisableIRQ(External_30_IRQn);
   #if 1
   #ifdef HAL_ALLOW_CALLS_FROM_ISR
       g_isrActive = true;
   #endif

       // read the interrupt reason register and mask bits
       mrHalRegRead(INT_REASON_REG_ADDR,&interruptBits);
       mrHalRegRead(INT_MASK_REG_ADDR,&maskBits);
       //ts_printf("External_30_IRQHandler INT_REASON_REG_ADDR = 0x%x,maskBits =0x%x \n",interruptBits,maskBits);
   #ifdef DEBUG_PRINT_L2
       ts_printf("interruptBits = 0x%x,maskBits =0x%x \n",interruptBits,maskBits);
   #endif
       //-------------------------- Captured CPU Packet Interrupts ---------------------------------------
       // Note: interrupts are not disabled for packet capture sources, so as to ensure they
       // can operate from system start up and during stack setup.
       if (maskBits & interruptBits & (CAPT_PKT_INT_MASK | SYS_CAPT_PKT_INT_MASK))
       {
           UART_polled_tx_string(&g_uart, (const uint8_t *)"External_30_IRQHandler inside check\n\r");
           // packet(s) has been captured on the Carrier (WAN/NNI) port
           // Clear the interrupt bit by reading this register
           mrHalRegRead(CPU_PKT_CLR_INT_REG_ADDR,&rdData);
           mrHalRegRead(CPU_SYS_PKT_INT_CLR_REG_ADDR,&rdData);

           // we can't use the LwIP sys_signal_sem since this can't be used in an ISR
           // release the semaphore and check if a task with a higher priority then the current one is waiting for it
           osSemaphoreGiveFromISR(g_gw2p_eth_pkt_rx_sem, &switch_context);
       }

       // Check if any CFM interrupts have occurred and deal with them
       cfmISRCallback(maskBits,interruptBits);
       mrHalRegRead(CPU_PKT_CLR_INT_REG_ADDR,&rdData);
       mrHalRegRead(CPU_SYS_PKT_INT_CLR_REG_ADDR,&rdData);
   #endif
#ifdef HAL_ALLOW_CALLS_FROM_ISR
    g_isrActive = false;
#endif
}

// -----------------------------------------------------------------------------------------------------
// int writeSysTxPkt(uint8_t* pktPtr, uint16_t pktLen);
// This function copies the byte array pointed to by pktPtr and with length pktLen bytes into the
// system side Tx FIFO, ready to be transmitted. The system Tx FIFO can only hold one packet at a
// time so the packet is copied to the start of the FIFO.
// This function should only be called if HW indicates that the previous packet was sent
// -----------------------------------------------------------------------------------------------------
int writeSysTxPkt(uint8_t* pktPtr, uint16_t pktLen)
{
    int			k;
    uint16_t	dwrdCnt;
    uint32_t	dwrd;
    uint8_t		residue;
    uint8_t*	bytePtr = pktPtr;

    if ((pktLen > 2048) || (pktLen < 14))
    {
#ifdef	MINGOA_ENABLE_ERROR_LOGGING
        sprintf(errorMsgRing[nextErrIdx()],"ERROR: writeSysTxPkt - invalid packet length (%d)\n",pktLen);
        writeLog(MINGOA_ERROR_LEVEL,errorMsgRing[prevErrHead]);
#endif
        return(ERR_PKT_LEN_INVALID);
    }

    dwrdCnt = pktLen >> 2;
    residue = (uint8_t) (pktLen & 0x3);  // => pktLen MOD 4

    for (k=0;k<dwrdCnt;k++)
    {
        dwrd = 0;
        dwrd = (uint32_t) *bytePtr;
        bytePtr++;
        dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
        bytePtr++;
        dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
        bytePtr++;
        dwrd = (dwrd << 8) | (uint32_t) *bytePtr;	// = {B0,B1,B3,B3}
        bytePtr++;
        // Write the Dword value
        mrHalRamWrite(k<<1, CPU_SYS_TX_RAM_SEL,dwrd);

        // write the control word
        if (k==0)
            mrHalRamWrite(1, CPU_SYS_TX_RAM_SEL,MR_SOP_MASK_BIT);
        else if (k == dwrdCnt-1)
        {
            // If it's the last full Dword and there is no residue it need to be marked EOP
            if (residue == 0)
                mrHalRamWrite((k<<1)+1, CPU_SYS_TX_RAM_SEL,MR_EOP_MASK_BIT);
            else
                mrHalRamWrite((k<<1)+1, CPU_SYS_TX_RAM_SEL,0);
        }
        else
            mrHalRamWrite((k<<1)+1, CPU_SYS_TX_RAM_SEL,0);
    }

    // Take care of the residue bytes if there are any...
    // For MoreThanIP MAC the encoding for MOD,EOP and SOP is
    // MOD[1:0] = 00 => data 31:0 valid
    // MOD[1:0] = 01 => data 7:0 valid
    // MOD[1:0] = 10 => data 15:0 valid
    // MOD[1:0] = 11 => data 23:0 valid
    // {MOD[1:0],EOP,SOP} = CPU_SYS_TX_RAM_SEL[35:32] i.e. Odd address
    if (residue)
    {
        dwrd = 0;
        switch(residue)
        {
        case(1): {dwrd = ((uint32_t) (*bytePtr)) << 24; break;}
        case(2): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16);break;}
        case(3): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16) + (((uint32_t) *(bytePtr+2)) << 8);break;}
        }
        mrHalRamWrite(k<<1, CPU_SYS_TX_RAM_SEL,dwrd);
        mrHalRamWrite((k<<1)+1, CPU_SYS_TX_RAM_SEL,MR_EOP_MASK_BIT + (residue << MR_MOD_BITS_OFFSET));
    }
    return(NO_ERR);
}


// -----------------------------------------------------------------------------------------------------
// int writeCarrierTxPkt(uint8_t* pktPtr, uint16_t pktLen);
// -----------------------------------------------------------------------------------------------------
int writeCarrierTxPkt(uint8_t* pktPtr, uint16_t pktLen)
{
    uint16_t	dwrdCnt;
    int			k;
    uint32_t	dwrd;
    uint8_t		residue;
    uint8_t*	bytePtr = pktPtr;
    uint32_t	cpuPktBaseAddr;
    uint16_t	rawByteLen;

    cpuPktBaseAddr = MR_CPU_CARR_TX_BUF;

    if ((pktLen > MR_CPU_CARR_TX_BUF_SIZE-2) || (pktLen < 14))
    {
#ifdef	MINGOA_ENABLE_ERROR_LOGGING
        sprintf(errorMsgRing[nextErrIdx()],"ERROR: writeCarrierTxPkt - invalid packet length (%d)\n",pktLen);
        writeLog(MINGOA_ERROR_LEVEL,errorMsgRing[prevErrHead]);
#endif
        return(ERR_PKT_LEN_INVALID);
    }

    // Add 2 to the packet length to account for the packet len
    // field that must be added to the first 2 bytes of the template
    rawByteLen = pktLen;		// save the packet length before it is adjusted
    pktLen += 2;

    // calculate the dword length and residue bytes...
    dwrdCnt = pktLen >> 2;
    residue = (uint8_t) (pktLen & 0x3);  // => pktLen MOD 4

    for (k=0;k<dwrdCnt;k++)
    {
        if (k == 0)
        {
            dwrd = rawByteLen;
            dwrd = (dwrd << 4) + 4;			// The header Dword length is set to 4
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
        }
        else
        {
            dwrd = 0;
            dwrd = (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;	// = {B0,B1,B3,B3}
            bytePtr++;
        }
        // Write the Dword value
        mrHalRamWrite(cpuPktBaseAddr++, EXT_SRAM_SEL,dwrd);
    }

    // Take care of the residue bytes if there are any...
    if (residue)
    {
        dwrd = 0;
        switch(residue)
        {
        case(1): {dwrd = ((uint32_t) (*bytePtr)) << 24; break;}
        case(2): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16);break;}
        case(3): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16) + (((uint32_t) *(bytePtr+2)) << 8);break;}
        }
        mrHalRamWrite(cpuPktBaseAddr, EXT_SRAM_SEL,dwrd);
    }
    return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// int writeCarrierTxPkt(uint8_t* pktPtr, uint16_t pktLen);
// -----------------------------------------------------------------------------------------------------
int writeCpuTxPkt(uint8_t* pktPtr, uint16_t pktLen)
{
    uint16_t	dwrdCnt;
    int			k;
    uint32_t	dwrd;
    uint8_t		residue;
    uint8_t*	bytePtr = pktPtr;
    uint32_t	cpuPktBaseAddr;
    uint16_t	rawByteLen;

    cpuPktBaseAddr = MR_BA_CPU_PKT_TX;

    if ((pktLen > (CPU_TX_PKT_ENTRY_SIZE*4)-2) || (pktLen < 14))
    {
        ts_printf("ETH ERROR: Tx packet too large\n");
        return(ERR_PKT_LEN_INVALID);
    }

    // Add 2 to the packet length to account for the packet len
    // field that must be added to the first 2 bytes of the template
    rawByteLen = pktLen;		// save the packet length before it is adjusted
    pktLen += 2;

    // calculate the dword length and residue bytes...
    dwrdCnt = pktLen >> 2;
    residue = (uint8_t) (pktLen & 0x3);  // => pktLen MOD 4

    for (k=0;k<dwrdCnt;k++)
    {
        if (k == 0)
        {
            dwrd = rawByteLen;
            dwrd = (dwrd << 4) + 4;			// The header Dword length is set to 4
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
        }
        else
        {
            dwrd = 0;
            dwrd = (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;
            bytePtr++;
            dwrd = (dwrd << 8) | (uint32_t) *bytePtr;	// = {B0,B1,B3,B3}
            bytePtr++;
        }
        // Write the Dword value
        mrHalRamWrite(cpuPktBaseAddr++, EXT_SRAM_SEL,dwrd);
    }

    // Take care of the residue bytes if there are any...
    if (residue)
    {
        dwrd = 0;
        switch(residue)
        {
        case(1): {dwrd = ((uint32_t) (*bytePtr)) << 24; break;}
        case(2): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16);break;}
        case(3): {dwrd = (((uint32_t) (*bytePtr)) << 24) + (((uint32_t) *(bytePtr+1)) << 16) + (((uint32_t) *(bytePtr+2)) << 8);break;}
        }
        mrHalRamWrite(cpuPktBaseAddr, EXT_SRAM_SEL,dwrd);
    }
    return(NO_ERR);
}

#if 0 // REMOVED FOR V2
// -----------------------------------------------------------------------------------------------------
// This function allows one to send a user constructed packet on the LAN (system) port.
// The packet must be stored in a byte array of no more than MR_MAX_CPU_LAN_TX_PKT bytes.
// A pointer to that byte array and the length of the packet in bytes are passed into
// this function. If the HW is not busy sending a previous packet then this packet will
// be copied into the HW packet buffer and HW instructed to send it ASAP. The function
// will return without error (i.e. 0)
// If the HW is busy or there is an error then this function will return with a non-zero
// error code. If HW is busy then the error code will be ERR_SYS_PKT_TX_BUSY. It is
// the customers responsibility to construct a 're-try' mechanism if one is needed.
// -----------------------------------------------------------------------------------------------------
#ifdef METROAM_DLL
METROAM_API int __stdcall mrSendLanPkt(uint8_t pktData[MR_MAX_CPU_LAN_TX_PKT],uint16_t pktLen)
#else
int mrSendLanPkt(uint8_t pktData[MR_MAX_CPU_LAN_TX_PKT],uint16_t pktLen)
#endif
{
#ifdef REMOTE_API_CALLS
    return(apiDLL_mrSendLanPkt(&pktData[0],pktLen));
#else

    int			retVal;
    uint32_t	rdData;

    // Only proceed if the Tx FIFO is NOT Busy
    mrHalRegRead(CPU_PKT_CNTR_CTRL_REG_ADDR,&rdData);
    if (rdData & MR_CPU_SYS_PKT_RDY)
        return(ERR_SYS_PKT_TX_BUSY);

    // Writing to the Sys packet Tx logic requires a semaphore
    osSemaphoreTake(g_gw2p_eth_LAN_mutex,0);


    // Write the data packet into the FIFO
    if ((retVal = writeSysTxPkt(pktData,pktLen)))
        return(retVal);

    // Next set the control bit to say send the packet
    mrHalRegWrite(CPU_PKT_CNTR_CTRL_REG_ADDR, MR_CPU_SYS_PKT_RDY | CPU_PKT_CNTR_CTRL_DEBUG_FIFO_THRESH_MASK);

    // Release the semaphore
    osSemaphoreGive(g_gw2p_eth_LAN_mutex);

    return(retVal);
#endif
}

// -----------------------------------------------------------------------------------------------------
// This function allows one to send a user constructed packet on the WAN (carrier) port.
// The packet must be stored in a byte array of no more than MR_MAX_CPU_WAN_TX_PKT bytes.
// A pointer to that byte array and the length of the packet in bytes are passed into
// this function. If the HW is not busy sending a previous packet then this packet will
// be copied into the HW packet buffer and HW instructed to send it ASAP. The function
// will return without error (i.e. 0)
// If the HW is busy or there is an error then this function will return with a non-zero
// error code. If HW is busy then the error code will be ERR_CPU_PKT_TX_BUSY. It is
// the customers responsibility to construct a 're-try' mechanism if one is needed.
// -----------------------------------------------------------------------------------------------------
#ifdef METROAM_DLL
METROAM_API int __stdcall mrSendWanPkt(uint8_t pktData[MR_MAX_CPU_WAN_TX_PKT],uint16_t pktLen)
#else
int mrSendWanPkt(uint8_t pktData[MR_MAX_CPU_WAN_TX_PKT],uint16_t pktLen)
#endif
{
#ifdef REMOTE_API_CALLS
    return(apiDLL_mrSendWanPkt(&pktData[0],pktLen));
#else

    int		retVal;
    uint32_t	rdData;

    // Only proceed if the Tx FIFO is NOT Busy
    mrHalRegRead(CPU_CARR_TX_REG_ADDR,&rdData);
    if (rdData & CPU_CARR_TX_PKT_RDY_MASK)
        return(ERR_CPU_PKT_TX_BUSY);

    // Writing to the Sys packet Tx logic requires a semaphore
    osSemaphoreTake(g_gw2p_eth_tx_mutex,0);

    // Write the data packet into the Template
    if ((retVal = writeCarrierTxPkt(pktData,pktLen)))
        return(retVal);

    // Next set the control bit to say send the packet
    mrHalRegWrite(CPU_CARR_TX_REG_ADDR, CPU_CARR_TX_PKT_RDY_MASK | 0x2);

    // Release the semaphore
    osSemaphoreGive(g_gw2p_eth_tx_mutex);

    return(retVal);
#endif
}
#endif
// -----------------------------------------------------------------------------------------------------
// This function allows one to send a user constructed packet on the WAN (carrier) port.
// The packet must be stored in a byte array of no more than MR_MAX_CPU_WAN_TX_PKT bytes.
// A pointer to that byte array and the length of the packet in bytes are passed into
// this function. If the HW is not busy sending a previous packet then this packet will
// be copied into the HW packet buffer and HW instructed to send it ASAP. The function
// will return without error (i.e. 0)
// If the HW is busy or there is an error then this function will return with a non-zero
// error code. If HW is busy then the error code will be ERR_CPU_PKT_TX_BUSY. It is
// the customers responsibility to construct a 're-try' mechanism if one is needed.
// -----------------------------------------------------------------------------------------------------
#ifdef METROAM_DLL
METROAM_API int __stdcall mrSendCpuPkt(uint8_t pktData[MR_MAX_CPU_WAN_TX_PKT],uint16_t pktLen,iFace_t iFace)
#else
int mrSendCpuPkt(uint8_t pktData[MR_MAX_CPU_WAN_TX_PKT],uint16_t pktLen,iFace_t iFace)
#endif
{
#ifdef REMOTE_API_CALLS
    return(apiDLL_mrSendCpuPkt(&pktData[0],pktLen, iFace));
#else

    int			retVal;
    uint32_t	rdData;
    uint8_t		retry = 0;

    // Writing to the Sys packet Tx logic requires a semaphore
    osSemaphoreTake(g_gw2p_eth_tx_mutex,0);

    // Only proceed if the Tx FIFO is NOT Busy
    RETRY_TX:
    mrHalRegRead(CPU_TX_REG_ADDR,&rdData);
    // Only wait for 10 iterations of this loop before giving up...something is wrong!
    if (rdData & CPU_TX_PKT_START_BUSY_MASK)
    {
        retry++;
        if (retry == 10)
        {
            ts_printf("ETH ERROR: Tx busy, pkt not sent\n");
            // Release the semaphore
            osSemaphoreGive(g_gw2p_eth_tx_mutex);
            return(ERR_CPU_PKT_TX_BUSY);
        }
        else
        {
            goto RETRY_TX;
        }
    }

    // Write the data packet into the Template
    if ((retVal = writeCpuTxPkt(pktData,pktLen)))
    {
        // Release the semaphore
        osSemaphoreGive(g_gw2p_eth_tx_mutex);
        return(retVal);
    }

    // Next set the control bit to say send the packet and set the destination port
    mrHalRegWrite(CPU_TX_REG_ADDR, CPU_TX_PKT_START_BUSY_MASK | 0x2 | ((iFace << CPU_TX_PKT_PORT_OFFSET) & CPU_TX_PKT_PORT_MASK));

    // Release the semaphore
    osSemaphoreGive(g_gw2p_eth_tx_mutex);

    return(retVal);
#endif
}

int gateway_mac_init(uint8_t *wanMAC, uint8_t *lanMAC, uint8_t *mgntMAC, struct netif *netif)
{
    uint32_t  rdDword;
    uint16_t  tOutCount;



    // First create a binary semaphore that will be used by the ISR to let
    // the receive packet processing task know that new packet(s) have arrived
    if (g_gw2p_eth_pkt_rx_sem == NULL)
        osSemaphoreCreateBinary(g_gw2p_eth_pkt_rx_sem);
    osSemaphoreTake(g_gw2p_eth_pkt_rx_sem, 0);

    // Create a Mutex to protect the Pkt Tx hardware for the LAN
    if (g_gw2p_eth_LAN_mutex == NULL)
        g_gw2p_eth_LAN_mutex = osMutexCreate();

    // Create a Mutex to protect the Pkt Tx hardware for the WAN
    if (g_gw2p_eth_tx_mutex == NULL)
        g_gw2p_eth_tx_mutex = osMutexCreate();

    // Ensure the semaphore and Mutex are created
    ASSERT(g_gw2p_eth_pkt_rx_sem != NULL);
    ASSERT(g_gw2p_eth_LAN_mutex != NULL);
    ASSERT(g_gw2p_eth_tx_mutex != NULL);
#if 1
    // Ensure the Tails are 0'd and the Capture FIFO is flushed before starting
    mrHalRegWrite(CPU_PKT_FIFO_TAIL_REG_ADDR,0);
    mrHalRegWrite(CPU_PKT_CNTR_CTRL_REG_ADDR,CPU_PKT_CNTR_CTRL_FLUSH_FIFO_MASK | CPU_PKT_CNTR_CTRL_DEBUG_FIFO_THRESH_MASK);
    mrHalRegWrite(CPU_SYS_PKT_FIFO_TAIL_REG_ADDR,0);
    mrHalRegWrite(CPU_SYS_PKT_CNTR_CTRL_REG_ADDR,CPU_SYS_PKT_CNTR_CTRL_FLUSH_FIFO_MASK);

    // Set the MAC for the Carrier Port (default = 00-A0-69-0C-24-B0)
    writePortMacRam(mrPort0,wanMAC);
    uint8_t temp[6];
    readPortMacRam(mrPort0,temp);

    // Set the MAC for the Virtual Mgnt Port (default = 00-A0-69-0C-24-B1)
    writePortMacRam(mrPort1,lanMAC);
    readPortMacRam(mrPort1,temp);

    // Set the MAC for the Virtual Mgnt Port (default = 00-A0-69-0C-24-B2)
    writePortMacRam(mrMgntPort,mgntMAC);
    readPortMacRam(mrMgntPort,temp);

    mrHalRegWrite(CPU_MGNT_VLAN_CTRL_REG_ADDR,CPU_MGNT_VLAN_CTRL_MATCH_MAC_MASK);
#endif
    //VR Begin - Handled using bare metal code
#if 0
    // reset the SFP and Disable Tx in MetRoam..
    mrHalRegWrite(TX_INIT_REG_ADDR,TX_INIT_REG_SFP_TX_DIS_MASK);

    // release the SFPs from reset and Enable Tx in MetRoam
    mrHalRegWrite(TX_INIT_REG_ADDR,0);	// !!! MAC init should not enable the Tx...Its done later during API init.

    // ######################################
    // Configure Sys MAC
    // ======================================
    // Write Config Reg
    mrHalRamWrite(2, SYSMAC_SEL, 0x1800018 | MR_MAC_RESET_BIT_MASK);
    mrHalRamRead(2, SYSMAC_SEL, &rdDword);
    tOutCount = 1000;
    while ((rdDword & MR_MAC_RESET_BIT_MASK) && tOutCount-- > 0)
        mrHalRamRead(2, SYSMAC_SEL, &rdDword);

    // Write ipgLen
    mrHalRamWrite(0x17, SYSMAC_SEL, 0xC);

    // Frame Length
    mrHalRamWrite(5, SYSMAC_SEL, 12000);

    // RX thresholds
    //RxSectMT
    mrHalRamWrite(7, SYSMAC_SEL, 0);
    //RXSecFull
    mrHalRamWrite(8, SYSMAC_SEL, 16);		// Was 16 - 4th Sep 2013
    //RX AE
    mrHalRamWrite(0xB, SYSMAC_SEL, 8);
    //RX AF
    mrHalRamWrite(0xC, SYSMAC_SEL, 8);

    // TX Thresholds
    //TxSecMT
    mrHalRamWrite(9, SYSMAC_SEL, 16);
    //TXSecFull
    mrHalRamWrite(0xA, SYSMAC_SEL, 16);
    //TX AE
    mrHalRamWrite(0xD, SYSMAC_SEL, 8);
    //Tx AF
    mrHalRamWrite(0xE, SYSMAC_SEL, 11);


    //Disable TX Zero Padding feature
    mrHalRamWrite(0x3A, SYSMAC_SEL, 0);
    //Disable RX Zero Padding feature
    mrHalRamWrite(0x3B, SYSMAC_SEL, 0);

    // Write Config Reg - enable Tx and RX
    mrHalRamWrite(2, SYSMAC_SEL, 0x180001B);

    // ######################################
    // Configure Carr MAC
    // ======================================

    // Write Config Reg
    mrHalRamWrite(2, CARRMAC_SEL, 0x1800018 | MR_MAC_RESET_BIT_MASK);
    mrHalRamRead(2, CARRMAC_SEL, &rdDword);
    tOutCount = 1000;
    while ((rdDword & MR_MAC_RESET_BIT_MASK) && tOutCount-- > 0)
        mrHalRamRead(2, CARRMAC_SEL, &rdDword);

    // Write ipgLen
    mrHalRamWrite(0x17, CARRMAC_SEL, 12);

    // Frame Length
    mrHalRamWrite(5, CARRMAC_SEL, 12000);

    // RX Thresholds
    // RxSectMT
    mrHalRamWrite(7, CARRMAC_SEL, 0);
    // RxSectFull
    mrHalRamWrite(8, CARRMAC_SEL, 16);		// Was 16 - 4th Sep 2013
    // RxFifoAE
    mrHalRamWrite(0xB, CARRMAC_SEL, 8);
    // RxFifoAF
    mrHalRamWrite(0xC, CARRMAC_SEL, 8);

    // TX Thresholds
    //TxSecMT
    mrHalRamWrite(9, CARRMAC_SEL, 16);
    //TXSecFull
    mrHalRamWrite(0xA, CARRMAC_SEL, 16);
    //TX AE
    mrHalRamWrite(0xD, CARRMAC_SEL, 8);
    //Tx AF
    mrHalRamWrite(0xE, CARRMAC_SEL, 11);

    //Disable TX Zero Padding feature
    mrHalRamWrite(0x3A, CARRMAC_SEL, 0);
    //Disable RX Zero Padding feature
    mrHalRamWrite(0x3B, CARRMAC_SEL, 0);

    // Write Config Reg - enable Tx and RX
    mrHalRamWrite(2, CARRMAC_SEL, 0x180001B);
#endif
    //VR End - Handled using bare metal code

    // Enable the interrupt bits for Carr and Sys captured packet interrupts
    //mrHalRegRead(INT_MASK_REG_ADDR, &rdDword);
#if 1
    mrHalRegWrite(INT_MASK_REG_ADDR, 0xFFFFFFFF );//SYS_CAPT_PKT_INT_MASK | CAPT_PKT_INT_MASK);
#endif
#if 0
    mrHalRegWrite(0xc004, 0);
    mrHalRegWrite(0x3004, 0xFFFFFFFF);
    mrHalRegWrite(0xc030, 0x55555555);
    mrHalRegWrite(0xc040, 0x3000);
    mrHalRegWrite(0xc038, 0xcafe);
    mrHalRegWrite(0xc03C, 0x00);
#endif

#if SFP == 1
    // On the SFP only we need to pull sys_los signal low once the MACs are alive
    //msaClrLOS();
#endif

    xTaskCreate(mrProcessLanWanCaptPkt, ( signed char * ) "OAM_ethernet", 1024, netif, tskIDLE_PRIORITY+4, NULL);
    //PLIC_init();
    //PLIC_SetPriority(External_30_IRQn,1); //m
    //VR Clear Pending Function not available for RISCV
    //NVIC_ClearPendingIRQ(External_1_IRQn);
    //ts_printf("Plic External_30_IRQn enabled in gateway_mac_init\n\r ");
   // PLIC_EnableIRQ(External_30_IRQn); //m



    return(NO_ERR);
}


/* @Function Description -  TSE transmit API to send data to the MAC
 *
 *
 * @API TYPE - Public
 * @param  net  - NET structure associated with the TSE MAC instance
 * @param  data - pointer to the data payload
 * @param  data_bytes - number of bytes of the data payload to be sent to the MAC
 * @return SUCCESS if success, else a negative value
 */
err_t gateway_mac_raw_send(struct netif *netif, struct pbuf *pkt)
{
    unsigned           len;
    unsigned           l;
    struct pbuf        *p;
    uint32_t            *data;
    uint32_t			*ActualData;
    uint8_t				retry;
    int					retVal;
    uint8_t				localBuf[512];

    int mrSendWanPkt(uint8_t *data, uint16_t pktLen);
    int mrSendLanPkt(uint8_t *data, uint16_t pktLen);
    ts_printf(("inside gateway_mac_raw_send \n\r"));

    if (pkt->len < pkt->tot_len)
    {
        // If the packet is in a chain of buffer then concatenate them into one buffer...

        // If the packet size is greater than the buffer available the exit with error
        if (pkt->tot_len > 512)
            return(ERR_BUF);

        // Concatenate the buffers...
        len = 0;
        for(p = pkt; p != NULL; p = p->next)
        {
            data = p->payload;
            l = p->len;

            // uncache the ethernet frame
            //ActualData = (void *)alt_remap_uncached (data, l);

            memcpy(&localBuf[len],(uint8_t*)data,l);
            len += l;
        }
        ActualData =(uint32_t*) localBuf;
    }
    else
    {
        // packet is in a single pbuf so point to that.
        len = pkt->tot_len;
        // Uncache the buffer
        //ActualData = (void *)alt_remap_uncached (pkt->payload, len);
        ActualData = pkt->payload;
    }

    // Attempt to send the packet...
    retry 	= 0;
    retVal 	= 0;
    RETRY_SEND:
    // WAN port will be number 1, LAN port number 2
    if (*((uint8_t*)netif->state) == 1)
    {
        retVal = mrSendCpuPkt(((uint8_t*)ActualData) + ETH_PAD_SIZE,(uint16_t)len,wanPort);
        if ((retVal != 83) && (retVal != 0)) //ERR_CPU_PKT_TX_BUSY
            return(retVal);
    }
    else if (*((uint8_t*)netif->state) == 2)
    {
        retVal = mrSendCpuPkt(((uint8_t*)ActualData) + ETH_PAD_SIZE,(uint16_t)len,lanPort);
        if ((retVal != 76) && (retVal != 0)) //ERR_SYS_PKT_TX_BUSY
            return(retVal);
    }

    if (retVal && (++retry < 10))
        goto RETRY_SEND;

    if (retry >= 10)
    {
        ts_printf(("RM:packet tx failed. Port busy\n"));
        return(retVal);
    }

    LINK_STATS_INC(link.xmit);

    return ERR_OK;
}
//VR unused function

int get_nvm_mac_addr_for_iface(int iface, struct netif* netif, unsigned char mac_addr[6])
{
    int				retVal;
    networkConfig_t networkConfig;
    static int mac_inc = 0;
    iface = mac_inc;
    mac_inc++;
    // Retrieve the network settings stored in flash - use the MAC from IF 0 for all interfaces
    //retVal = get_board_network_settings(iface,&networkConfig);
    retVal = 1;
    if ((retVal == 0) && (networkConfig.signature == 0x5AFE))
    {
        memcpy(mac_addr,&networkConfig.macAddr,6);
    }
    else
    {
        // set defaults if there are no values in flash 00-A0-69-0C-24-B0
        mac_addr[0] = 0x00;
        mac_addr[1] = 0xA0;
        mac_addr[2] = 0x69;
        mac_addr[3] = 0x0C;
        mac_addr[4] = 0x24;
        mac_addr[5] = 0xB0 + iface;
    }
    // only show info if net is not NULL
    if (netif)
    {
#ifdef DEBUG_PRINT_L2
        ts_printf("[ethernet] Using Ethernet MAC address %02x:%02x:%02x:%02x:%02x:%02x for E%c\n",
                mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], netif->name[1]);
#endif

    }

    return EXIT_SUCCESS;
}

static void gateway_low_level_init(struct netif *netif)
{
    unsigned char own_hw_adr[6];

    // Use the Management MAC address for both the WAN and LAN port in LWIP.
    get_nvm_mac_addr_for_iface(0, netif, own_hw_adr);
    netif->hwaddr[0] = own_hw_adr[0];
    netif->hwaddr[1] = own_hw_adr[1];
    netif->hwaddr[2] = own_hw_adr[2];
    netif->hwaddr[3] = own_hw_adr[3];
    netif->hwaddr[4] = own_hw_adr[4];
    netif->hwaddr[5] = own_hw_adr[5];

    /* set MAC hardware address length */
    netif->hwaddr_len = ETHARP_HWADDR_LEN;

    /* maximum transfer unit */
    netif->mtu = 1500;

    /* device capabilities */
    /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; // ND removed NETIF_FLAG_LINK_UP

}

err_t gateway_ethernetif_init(struct netif *netif)
{
    LWIP_ASSERT("netif != NULL", (netif != NULL));

#if LWIP_NETIF_HOSTNAME
    /* Initialize interface hostname */
    netif->hostname = (char*)&netHostNames[*((uint8_t*)netif->state)];
#endif /* LWIP_NETIF_HOSTNAME */

    /*
     * Initialize the snmp variables and counters inside the struct netif.
     * The last argument should be replaced with your link speed, in units
     * of bits per second.
     */
    //NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);  // LINK_SPEED_OF_YOUR_NETIF_IN_BPS
    NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);  // LINK_SPEED_OF_YOUR_NETIF_IN_BPS

    //netif->state = NULL;
    if (*((uint8_t*)netif->state) == 1) {
        netif->name[0] = 'E';
        netif->name[1] = '0';
    } else {
        netif->name[0] = 'E';
        netif->name[1] = '1';
    }

    /* We directly use etharp_output() here to save a function call.
     * You can instead declare your own function an call etharp_output()
     * from it if you have to do some checks before sending (e.g. if link
     * is available...) */
    netif->output = etharp_output;
    netif->linkoutput = gateway_mac_raw_send;

    /* initialize the low level hardware */
    gateway_low_level_init(netif);

    return ERR_OK;
}

#if 0
//--------------------------------------------------------------------------
// readNextCaptCpuWord
// This function should be called to read the next Double Word from the
// Captured packet FIFO. After the Dword has been read it updates a
// global captured packet FIFO tail pointer that is used. The FIFO
// used is circular so the tail must wrap at the FIFO size.
//--------------------------------------------------------------------------
int	readNextCaptCpuWord(mrPort_t port, uint32_t *dword, uint16_t *cpuCaptPktTail)
{
    mrHalRamRead((*cpuCaptPktTail),(port == mrPort0 ? CPU_CAPT_FIFO_SEL : CPU_SYS_CAPT_FIFO_SEL),dword);

    // make sure to wrap the tail at the FIFO size (in DWords)
    if (++(*cpuCaptPktTail) >= (MR_CPU_CAPT_FIFO_SIZE/4))
        *cpuCaptPktTail = 0;

    return(NO_ERR);
}

//--------------------------------------------------------------------------
// This function reads the next available captured packet INFO
// from the captured packet FIFO, advances the tail value and returns the
// Reason code and the packet size in bytes.
//--------------------------------------------------------------------------
int	readNextCaptCpuInfo(captPktInfo_t *captPktInfo)
{
    uint32_t	data;
    int		retVal;

    captPktInfo->pktLen = 0;			// in case there is an error reading the packet

    // read the current FIFO and data packet Tail values from the register
    if ((retVal = mrHalRegRead((captPktInfo->port == mrPort0 ? CPU_PKT_FIFO_TAIL_REG_ADDR : CPU_SYS_PKT_FIFO_TAIL_REG_ADDR),&data)))
        return(retVal);

    captPktInfo->cpuCaptPktTail = (uint16_t) ((data & CPU_PKT_FIFO_TAIL_PKT_TAIL_MASK) >> CPU_PKT_FIFO_TAIL_PKT_TAIL_OFFSET);
    captPktInfo->cpuCaptInfoTail = (uint16_t) ((data & CPU_PKT_FIFO_TAIL_INFO_TAIL_MASK) >> CPU_PKT_FIFO_TAIL_INFO_TAIL_OFFSET);

    // Read the info
    if ((retVal = mrHalRamRead(captPktInfo->cpuCaptInfoTail,(captPktInfo->port == mrPort0 ? CPU_CAPT_INFO_FIFO_SEL : CPU_SYS_CAPT_INFO_FIFO_SEL),&data)))
        return(retVal);

    // Increment the tail value now...it will be written to
    // HW after the packet has been successfully extracted
    (captPktInfo->cpuCaptInfoTail)++;

    // Extract the 'reason' value and packet length
    captPktInfo->captReason = (uint16_t) ((data & CPU_CAPT_INFO_FIFO_PKT_REASON_MASK) >> CPU_CAPT_INFO_FIFO_PKT_REASON_OFFSET);
    captPktInfo->pktLen = (uint16_t) ((data  & CPU_CAPT_INFO_FIFO_PKT_SIZE_MASK) >> CPU_CAPT_INFO_FIFO_PKT_SIZE_OFFSET);

    return(NO_ERR);
}


//--------------------------------------------------------------------------
// This function is used to read a captured packet out of the HW
// FIFO and place it in a CPU RAM (malloc) and return a pointer
// to that RAM. The HW FIFO space is freed up after the packet has
// been completely removed.
//--------------------------------------------------------------------------
int readGenericPacket(uint8_t* pktPtr, captPktInfo_t captPktInfo)
{
    uint32_t	data;
    int		bytesRemaining;
    uint8_t	*bytePtr;
    uint8_t	*newPtr;

    bytesRemaining = captPktInfo.pktLen;

#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
    sprintf(msgStr, "INFO: readGenericPacket:  New captured packet of length = %d", pktLen);
    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif

    if (pktPtr != NULL)
    {
        newPtr = pktPtr;
        // read any residue remaining.
        while (bytesRemaining > 0)
        {
            readNextCaptCpuWord(captPktInfo.port,&data,&captPktInfo.cpuCaptPktTail);

            bytePtr = (uint8_t*)&data;
            bytePtr += 3;	// Need to byte swivel contents to populate the byte array
            if (bytesRemaining < 4)
            {
                switch(bytesRemaining)
                {
                case 1:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %02lX",  (data >> 24));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr;
                    break;
                }
                case 2:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %04lX",  (data >> 16));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                case 3:
                {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                    sprintf(msgStr, "CAPT: %06lX", (data >> 8));
                    writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr--;
                    *(newPtr++) = *bytePtr;
                    break;
                }
                }
            }
            else
            {
#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_CAPT_PKT)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_CAPT_PKT)))
                sprintf(msgStr, "CAPT: %08lX", data);
                writeLog(MINGOA_DEBUG_LEVEL_CAPT_PKT,msgStr);
#endif
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr--;
                *(newPtr++) = *bytePtr;

            }

            bytesRemaining -= 4;
        }
    }
    else
    {
        // No buffer was supplied to received the extracted packet so simply trash it!
        captPktInfo.cpuCaptPktTail += (captPktInfo.pktLen >> 2);  	//inc the tail by the number of Dwords in the packet
        if (captPktInfo.pktLen & 0x3)
            captPktInfo.cpuCaptPktTail++;				// a full dword is used if these is residue

        // make sure to wrap the tail at the FIFO size (in DWords)
        if (captPktInfo.cpuCaptPktTail > (MR_CPU_CAPT_FIFO_SIZE/4))
            captPktInfo.cpuCaptPktTail = captPktInfo.cpuCaptPktTail - (MR_CPU_CAPT_FIFO_SIZE/4);
    }

    if (captPktInfo.port == mrPort0)
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_PKT_TAIL_MASK)
		                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_PKT_CNTR_CTRL_REG_ADDR,CPU_PKT_CNTR_CTRL_DEC_PKT_MASK | CPU_PKT_CNTR_CTRL_DEBUG_FIFO_THRESH_MASK);
    }
    else
    {
        // update the tails to free up space in the FIFOs.
        data = ((((uint32_t)captPktInfo.cpuCaptPktTail) << CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_PKT_TAIL_MASK)
				                        | ((((uint32_t)captPktInfo.cpuCaptInfoTail) << CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_OFFSET) & CPU_SYS_PKT_FIFO_TAIL_INFO_TAIL_MASK);
        mrHalRegWrite(CPU_SYS_PKT_FIFO_TAIL_REG_ADDR,data);

        // decrement the packet count by 1
        mrHalRegWrite(CPU_SYS_PKT_CNTR_CTRL_REG_ADDR,CPU_SYS_PKT_CNTR_CTRL_DEC_PKT_MASK);
    }

    return(NO_ERR);
}
#endif

//--------------------------------------------------------------------------
// If a captured packet is identified as being diverted to the CPU (reason = 0xF)
// then this function can be used to send the packet to the lwIP Network Stack
// for processing. The captPktInfo->ifaceInfo parameter must contain a pointer
// to a netif structure that is used by lwIP to identify the network interface
// on which the packet was received and on which to send a reply, if required.
//--------------------------------------------------------------------------
void mrSendPktToLwip(captPktInfo_t *captPktInfo)
{
    struct netif 	*netif;
    struct eth_hdr	*ethhdr;
    struct pbuf 	*p;
    uint32_t		*pkt;
    uint16_t		sop;
    uint32_t		rdData;
    uint16_t		pktBufLen;

    netif = captPktInfo->ifaceInfo;
    /*
	if ((captPktInfo->pktLen + ETH_PAD_SIZE ) > PBUF_POOL_BUFSIZE)
	{
		printf("OOPs! Packet too big for buffer\n");
		//must throw away the packet!!
		readGenericPacket(NULL,*captPktInfo);
		return;
	}
	else
	{
		// Generate a new pbuf
		p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
		if (p == NULL)
		{
			printf("OOPs! NO pbuf avail\n");
			return;		// No CPU RAM! Leave pkts in FIFO and HW will discard until RAM is free'd up
		}
		p = (void *) alt_remap_uncached(p,sizeof *p);
		p->payload = (void *) alt_remap_uncached(p->payload,PBUF_POOL_BUFSIZE);
	}
     */
    // Generate a new pbuf
    pktBufLen = captPktInfo->pktLen + ETH_PAD_SIZE;
    if (pktBufLen & 0x3)
    {
        // Ensure that the packet buffer is a multiple of 4 bytes
        pktBufLen &= ~0x3;
        pktBufLen += 4;
    }
    p = pbuf_alloc(PBUF_RAW, pktBufLen, PBUF_RAM);
    if (p == NULL)
    {
        ts_printf("OOPs! NO pbuf avail\n");
        return;		// No CPU RAM! Leave pkts in FIFO and HW will discard until RAM is free'd up
    }
    //p = (void *) alt_remap_uncached(p,sizeof *p);
    //p->payload = (void *) alt_remap_uncached(p->payload,PBUF_POOL_BUFSIZE);

    sop = captPktInfo->cpuCaptPktTail;

    // move received packet into a new pbuf
    // Note: the "+ ETH_PAD_SIZE" is to add the required padding at the start of the buffer
    // this helps lwIP extract the header fields quickly on a 32bit processor
    if (readGenericPacket(((uint8_t *)p->payload) + ETH_PAD_SIZE,*captPktInfo))
    {
        pbuf_free(p);
        // error extracting packet, silently ignore this
        return;
    }
    p->len		= captPktInfo->pktLen + ETH_PAD_SIZE;
    p->tot_len	= captPktInfo->pktLen + ETH_PAD_SIZE;

    // points to packet payload, which starts with an Ethernet header
    ethhdr = p->payload;

    LINK_STATS_INC(link.recv);

#if NO_SYS
    switch (htons(ethhdr->type)) {
    /* IP or ARP packet? */
    case ETHTYPE_IP:
    case ETHTYPE_ARP:
#if PPPOE_SUPPORT
        /* PPPoE packet? */
    case ETHTYPE_PPPOEDISC:
    case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
        /* full packet send to tcpip_thread to process */
        if (netif->input(p, netif) != ERR_OK) {
            LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
            pbuf_free(p);
            p = NULL;
        }
        break;

    default:
        pbuf_free(p);
        p = NULL;
        break;
    }
#else
    switch (htons(ethhdr->type)) {
    /* IP packet? */
    case ETHTYPE_IP:
    case ETHTYPE_ARP:
#if PPPOE_SUPPORT
        /* PPPoE packet? */
    case ETHTYPE_PPPOEDISC:
    case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
        //netif->input(p, netif);
        if (netif->input(p, netif) != 0)
        {
            // There was an error sending the last packet (probably insufficient MEMP_TCPIP_MSG_INPKT)
            pbuf_free( p );
            p = NULL;
        }
        break;

    default:
        pkt = (uint32_t*) p->payload;
        if ((*pkt & 0xFFFF0000) != 0xFFFF0000)
        {
            printf("sop %d\n",sop);
            printf("len %d\n",captPktInfo->pktLen);
            printf("xdw0: %08lX\n", *pkt++);
            printf("xdw1: %08lX\n", *pkt++);
            printf("xdw2: %08lX\n", *pkt++);
            printf("xdw3: %08lX\n", *pkt++);
            printf("xdw4: %08lX\n\n", *pkt++);
            // *** disable any further packet capture in this interface
            mrHalRegRead(INT_MASK_REG_ADDR, &rdData);
            rdData &= ~SYS_CAPT_PKT_INT_MASK;
            mrHalRegWrite(INT_MASK_REG_ADDR, rdData);
        }
        pbuf_free( p );
        p = NULL;

        break;
    }
#endif
    return;
}

#if 0
//--------------------------------------------------------------------------
// This function returns the number of packets currently held in the
// WAN (Carrier) Capture FIFO
//--------------------------------------------------------------------------
int	mrGetNumWANPktsPending(void)
{
    uint32_t	numPkts;
    int		retVal;

    // If the interrupt is disabled we shouldn't fetch any captured packets
    mrHalRegRead(INT_MASK_REG_ADDR, &numPkts);
    if ((numPkts & CAPT_PKT_INT_MASK) == 0)
        return(0);

    if ((retVal = mrHalRegRead(CPU_PKT_CNTR_REG_ADDR,&numPkts)))
        return(retVal);

    return((int) numPkts & CPU_PKT_CNTR_MASK);
}

//--------------------------------------------------------------------------
// This function returns the number of packets currently held in the
// LAN (System) Capture FIFO
//--------------------------------------------------------------------------
int	mrGetNumLANPktsPending(void)
{
    uint32_t	numPkts;
    int		retVal;

    // If the interrupt is disabled we shouldn't fetch any captured packets
    mrHalRegRead(INT_MASK_REG_ADDR, &numPkts);
    if ((numPkts & SYS_CAPT_PKT_INT_MASK) == 0)
        return(0);

    if ((retVal = mrHalRegRead(CPU_SYS_PKT_CNTR_REG_ADDR,&numPkts)))
        return(retVal);

    return((int) numPkts & CPU_SYS_PKT_CNTR_MASK);
}
#endif


//--------------------------------------------------------------------------
// This function is called to extract Link Trace packets (LTM or LTR)
// and pass them onto the LT processing thread.
//--------------------------------------------------------------------------
void mrSendPktToLTProc(captPktInfo_t *captPktInfo)
{
    ts_printf("LT packet received\n");
    readGenericPacket(NULL,*captPktInfo);
}

//--------------------------------------------------------------------------
// This function is used as the callback function for handling packets
// captured on the WAN port. Different packet types must be diverted to
// different packet handlers base on the capture reason.
// Un-know or un-handled packet types are trashed.
//--------------------------------------------------------------------------
void mrWanCaptPktHandler(captPktInfo_t *captPktInfo)
{
    switch (captPktInfo->captReason)
    {
#ifdef MINOGA_INCLUDE_EFM
    // If EFM support is included process the packets appropriately
    case MR_EFM_EVENT_NOTIF_PKT:
    case MR_EFM_VAR_REQ_PKT:
    case MR_EFM_VAR_RESP_PKT:
    case MR_EFM_INFO_WITH_ORG_PKT:
    case MR_EFM_ORG_SPECIFIC_PKT:
    case MR_EFM_LB_CTRL_PKT:
    {
        if((retVal = efmProcCaptPackets(captReason,pktLen,message)))
            return(retVal);
        break;
    }
#endif

    case MR_CAPT_REASON_MAC_MATCH:
    case MR_CAPT_REASON_BC_MATCH:
        mrSendPktToLwip(captPktInfo);
        break;

#ifdef MRLINKTRACE_H_
    case MR_CAPT_REASON_LTM:
    {
        MR_TRACE(MR_CAPT_PKT_DEBUG, ("LTM packet Received on port %d\n",captPktInfo->port));
        processLTM(captPktInfo);
        break;
    }

    case MR_CAPT_REASON_LTR:
    {
        MR_TRACE(MR_CAPT_PKT_DEBUG, ("LTR packet Received on port %d\n",captPktInfo->port));
        processLTR(captPktInfo);
        break;
    }
#else
    case MR_CAPT_REASON_LTM:
    case MR_CAPT_REASON_LTR:
        mrSendPktToLTProc(captPktInfo);
        break;
#endif

    default:
        //must throw away the packet!!
        ts_printf("WAN Unrecognised packet - discarding\n");
        readGenericPacket(NULL,*captPktInfo);
        break;
    }
}


//--------------------------------------------------------------------------
// This function should be called as an OS task/thread to handle processing
// of captured packet on the WAN and LAN ports. If either port receives an
// interrupt informing it of an available captured packet then this function
// will call the appropriate callback function. The mrRegisterCaptPktCallback()
// function must be called by the user to register the appropriate callback
// for the interface. If no call back is registered then all packets are
// trashed as they are received.
// mrWanCaptPktHandler is an example callback function for the WAN port
// mrSendPktToLwip is an appropriate callback function for the LAN port
//--------------------------------------------------------------------------
void mrProcessLanWanCaptPkt(void *pvParameters)
{
    xSemaphoreHandle	captSem = NULL;
    captPktInfo_t	captPktInfo;
    int				numWanPktsPending;
    int				numLanPktsPending;
    void			*wanIFaceInfo;
    void			*lanIFaceInfo;


    captSem = g_gw2p_eth_pkt_rx_sem;

#ifdef MRLINKTRACE_H_
    // This will configure the HW and SW to add Link Trace support...
    mrLinkTraceInit();
#endif

    // pass on any parameters to the callback function.
    // In lwIP this will be the Ethernet interface info
    wanIFaceInfo = (struct netif*) pvParameters;
    lanIFaceInfo = ((struct netif*) pvParameters) + 1;
#ifdef DEBUG_PRINT_L2
    ts_printf("LAN & WAN packet capture active\n");
#endif
    while(1)
    {
        if (captSem != NULL)
        {
            osSemaphoreTake(captSem,0);  // wait forever = 0
            ts_printf(" wait forever = 0\n");
        }

        else if ((mrGetNumWANPktsPending() == 0) && (mrGetNumLANPktsPending() == 0))
        {
            vTaskDelay(1000 * portTICK_RATE_MS);  // delay polling for 2ms
            ts_printf(" delay polling for 2ms\n");
        }


        numWanPktsPending = mrGetNumWANPktsPending();
        numLanPktsPending = mrGetNumLANPktsPending();
        while (numWanPktsPending || numLanPktsPending)
        {
            ts_printf(" some pkts\n");
            if(numWanPktsPending)      // read and process all pending pkts
            {
                captPktInfo.port = mrPort0;
                captPktInfo.ifaceInfo = wanIFaceInfo;
                readNextCaptCpuInfo(&captPktInfo);
                /*
				if (mrWANCaptPktCB != NULL)
					mrWANCaptPktCB(&captPktInfo);	// call the callback function
				else
					readGenericPacket(NULL,captPktInfo);  // This will trash the packet
                 */
                mrSendPktToLwip(&captPktInfo);
            }

            if(numLanPktsPending)      // read and process all pending pkts
            {
                captPktInfo.port = mrPort1;
                captPktInfo.ifaceInfo = lanIFaceInfo;
                readNextCaptCpuInfo(&captPktInfo);
                /*
				if (mrLANCaptPktCB != NULL)
					mrLANCaptPktCB(&captPktInfo);	// call the callback function
				else
					readGenericPacket(NULL,captPktInfo);  // This will trash the packet
                 */
                mrSendPktToLwip(&captPktInfo);
            }

            // Before iterating around the while loop re-check if there are pkts pending on either
            numWanPktsPending = mrGetNumWANPktsPending();
            numLanPktsPending = mrGetNumLANPktsPending();
            vTaskDelay(10 * portTICK_RATE_MS);  // if busy, play nice with other tasks!
        } // while
    } // while
}
