/**
 * @file hsr_prp_menu.c
 * @brief Contains routines for HSR/PRP menu options and helper functions
 *
 */
/*
 * Copyright (c) 2015, 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.
 **/

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

#include "hsr_prp_menu.h"
#include "hsrPrp_firmware.h"
#include "hsr_prp_fw_offsets.h"

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
#define RED_REM_NODE_TYPE_STR_DANP     "DANP   "
#define RED_REM_NODE_TYPE_STR_VDANP    "VDANP  "
#define RED_REM_NODE_TYPE_STR_REDBOXP  "REDBOXP"
#define RED_REM_NODE_TYPE_STR_DANH     "DANH   "
#define RED_REM_NODE_TYPE_STR_VDANH    "VDANH  "
#define RED_REM_NODE_TYPE_STR_REDBOXH  "REDBOXH"
#define RED_REM_NODE_TYPE_STR_SANA     "SAN A  "
#define RED_REM_NODE_TYPE_STR_SANB     "SAN B  "
#define RED_REM_NODE_TYPE_STR_SANAB    "SAN AB "
#define RED_REM_NODE_TYPE_STR_UNKNOWN  "UNKNOWN"

#define RED_HSR_LRE_MODE_H             "MODE H"
#define RED_HSR_LRE_MODE_N             "MODE N"
#define RED_HSR_LRE_MODE_T             "MODE T"
#define RED_HSR_LRE_MODE_U             "MODE U"
#define RED_HSR_LRE_MODE_M             "MODE M"
#define RED_HSR_LRE_MODE_UNKNOWN       "UNKNOWN"

//#define MINIMIZE_STATS

/**Interface macid index*/
#define INTERFACE_MAC 0
/**Port1 macid index*/
#define PORT1_MAC     1
/**Port2 macid index*/
#define PORT2_MAC     2

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

extern ICSSEMAC_Handle emachandle;
extern TimeSync_ParamsHandle_t timeSyncHandle;

/*Indicates PTP error*/
extern uint8_t ptpError;
extern uint8_t deviceInSync;

#ifdef PTP_TESTING

/*Used to track min/max offset from master
 * Useful for testing*/
int32_t min_offset = PTP_MIN_OFFSET_INIT_VAL;
int32_t max_offset = PTP_MAX_OFFSET_INIT_VAL;

#endif //PTP_TESTING

/*IP address stored here*/
char IPString[20];
//extern S25FL_Handle flashHandle;
extern Board_flashHandle flashHandle;

/*Set to 1 after IP address is assigned*/
uint8_t check_ip = 0;

/**An HSR/PRP example frame with the header*/
uint8_t hsrPrpTestFrame[HSR_PRP_TEST_FRAME_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
                                                    0x45, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x3A, 0xD1
                                                   };

/* board flash handle */
#if defined(SOC_AM335x)
Board_flashHandle flashHandle;
#elif defined(SOC_K2G)
extern Board_flashHandle flashHandle;
extern Board_flashHandle boardFlashHandle;
#else
extern S25FL_Handle flashHandle;
#endif

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

extern void initSNMP(void);

uint8_t HSR_EmacSocMACAddrGet(uint8_t instance, uint8_t *macId)
{
    uint8_t retVal = 0;
    uint8_t i = 0;
    uint8_t *tempPtr = macId;

    for(i = 0; i < 6; i++)
    {
        *tempPtr++ = ((((ICSS_EmacObject *)emachandle->object)->emacInitcfg)->macId)[i];
    }

    switch(instance)
    {
        case INTERFACE_MAC:
            retVal = 1;
            break;

        case PORT1_MAC:
            macId[5] += 1;
            retVal = 1;
            break;

        case PORT2_MAC:
            macId[5] += 2;
            retVal = 1;
            break;

        default:
            break;
    }

    return retVal;
}

#ifdef ICSS_PROTOCOL_HSR
char *getHsrLreModePrintStr(ICSSEMAC_Handle emachandle)
{
    uint16_t mode = *((uint16_t *)(((((ICSS_EmacHwAttrs *)
                                      emachandle->hwAttrs)->emacBaseAddrCfg)->dataRam0BaseAddr) + LRE_HSR_MODE));

    switch(mode)
    {
        case MODEH:
            return RED_HSR_LRE_MODE_H;

        case MODEN:
            return RED_HSR_LRE_MODE_N;

        case MODET:
            return RED_HSR_LRE_MODE_T;

        case MODEU:
            return RED_HSR_LRE_MODE_U;

        case MODEM:
            return RED_HSR_LRE_MODE_M;

        default:
            break;
    }

    return RED_HSR_LRE_MODE_UNKNOWN;
}
#endif /* ICSS_PROTOCOL_HSR */
void printHelpMenu()
{

    UART_printf("\n\r******************HSR/PRP Application Help Menu**********************\n\r");
    UART_printf("\n\rNode Table:\n Every HSR/PRP device on the network broadcasts Supervision frames.\n\r");
    UART_printf("The Node table implementation keeps track of it. It has a maximum of 128 entries.\n\r");
    UART_printf("The node table view presents a consolidated view of the node table.\n\r");
    UART_printf("\n\r");

    UART_printf("\n\rStatistics:\n The implementation monitors incoming and outgoing frames.\n\r");
    UART_printf("The statistics view shows a consolidated view of the same.\n\r");
    UART_printf("\n\r");
    UART_printf("\n\rPTP/1588:\n TI HSR switch supports PTP/1588 Ordinary and Transparent Clock.\n\r");
    UART_printf("The view shows certain key parameters critical for monitoring.\n\r");
    UART_printf("\n\r");
    UART_printf("\n\rRx/Tx Test:\n Select this option to run a simple redundancy test.\n");
    UART_printf("\n\rUpon selecting the menu option a sub-menu option appears asking to fix a device\n\r");
    UART_printf("as Receiver or Transmitter. If a device is chosen as a receiver it waits for 120 frames\n\r");
    UART_printf("to be received or a 3 minute timeout (whichever is earlier) and then exits\n\r");
    UART_printf("If a device is configured as Transmitter then it starts transmitting 1 frame per second on both ports\n\r");
    UART_printf("as per HSR/PRP implementation with a led toggle value which is interpreted on the receiver as a bit pattern\n\r");
    UART_printf("to toggle the digital IO LED's. The current pattern is 0 then 1 then 11 then 111 and so on\n\r");
    UART_printf("\n\r\n\r");
    UART_printf("\n\r************************End of Help Menu***************************\n\r");

}

void printConfig(ICSSEMAC_Handle emachandle)
{

    NIMU_IF_REQ device;
    uint8_t macId[6];
    char macAdd[32];
#ifdef ICSS_PROTOCOL_HSR
    char pBuf[100];
#endif

    device.index = 1;
    device.name[0] = 0;
    /*Print IP address, MAC address and UART menu options*/

    UART_printf("\nICSS_EMAC_DRV_VERSION_ID\t: 0x%x\n", ICSS_EMAC_DRV_VERSION_ID);

    if(check_ip)
    {
        /*Print IP address*/
        UART_printf("\n\rIP Address \t: ");
        UART_printf(IPString);

        /*Print MAC address*/
        NIMUIoctl(NIMU_GET_DEVICE_MAC, &device, macId, sizeof(macId));
        sprintf(macAdd, "%x:%x:%x:%x:%x:%x", (char)macId[0], (char)macId[1],
                (char)macId[2], (char)macId[3], (char)macId[4], (char)macId[5]);
        UART_printf("\n\rMac Id \t\t: ");
        UART_printf(macAdd);
    }

#ifdef ICSS_PROTOCOL_HSR
    char *mode = getHsrLreModePrintStr(emachandle);
    sprintf(pBuf,
            "\n\r"
            "Device config\t: HSR %s\n\r",
            mode);
    UART_printf(pBuf);
#endif /* ICSS_PROTOCOL_HSR */

#ifdef ICSS_PROTOCOL_PRP
    UART_printf("\n\rDevice config\t: PRP \n\r");
#endif /* ICSS_PROTOCOL_HSR */

    UART_printf("\n\rHSR/PRP Application Menu Options. Press key (Upper/Lower)\n");
    UART_printf("*******************************************\n\r");
    UART_printf("S : Show Statistics\n\r");
    UART_printf("L : Show LRE Statistics\n\r");
    UART_printf("C : Show HSR/PRP Configuration\n\r");
    UART_printf("N : Show Ring members/Node Table\n\r");
    UART_printf("M : Multicast filter handling\n\r");
    UART_printf("V : VLAN filter handling\n\r");
    UART_printf("F : Host Rx Interrupt Config | 0 : Disable | 1. Enable | 2. Enable with Adaptive Logic\n\r");
    UART_printf("I : Assign IP address\n\r");
    UART_printf("P : Show PTP/1588 status\n\r");
    UART_printf("R : Run Rx/Tx test\n\r");
    UART_printf("H : Help menu. Shows details on all the options\n\r");
    UART_printf("********************************************\n\r");

}

void printPTPSubMenu(void)
{

    UART_printf("********************************************\n\r");
    UART_printf("\n\rPTP Sub Menu Options. Press key (Upper/Lower)\n");
    UART_printf("C : Change PTP configuration (to master if slave and vice versa)\n\r");
    UART_printf("S : Show PTP/1588 status\n\r");
    UART_printf("R : Reset min max values\n\r");
    UART_printf("********************************************\n\r");

}

void printVlanFilterSubMenu(void)
{

    UART_printf("********************************************\n\r");
    UART_printf("\n\rVLAN filter Sub Menu Options. Press key (Upper/Lower)\n");
    UART_printf("D : Disable VLAN filtering\n\r");
    UART_printf("E : Enable VLAN filtering\n\r");
    UART_printf("A : Add VID\n\r");
    UART_printf("R : Remove VID\n\r");
    UART_printf("H : Untagged frames host receive enable\n\r");
    UART_printf("N : Untagged frames host receive disable\n\r");
    UART_printf("P : Priority frames host receive enable\n\r");
    UART_printf("Q : Priority frames host receive disable\n\r");
    UART_printf("S : Supervision frames to skip VLAN filter flow\n\r");
    UART_printf("F : Supervision frames to enter VLAN filter flow\n\r");
    UART_printf("********************************************\n\r");

}

void printMulticastFilterSubMenu(void)
{

    UART_printf("********************************************\n\r");
    UART_printf("\n\rMulticast filter Sub Menu Options. Press key (Upper/Lower)\n");
    UART_printf("D : Disable multicast filtering\n\r");
    UART_printf("E : Enable multicast filtering\n\r");
    UART_printf("M : Configure mask\n\r");
    UART_printf("A : Add multicast MAC ID\n\r");
    UART_printf("R : Remove multicast MAC ID\n\r");
    UART_printf("********************************************\n\r");

}

void printPTPStatus(TimeSync_ParamsHandle_t timeSyncHandle)
{
    char pBuf[1024];
    uint64_t seconds = 0;
    uint32_t nanoseconds = 0;

    if(!TimeSync_isEnabled(timeSyncHandle))
    {
        UART_printf("\n\r PTP is disabled. Forgot to call ptpEnable() ?");
    }

    else
    {

        sprintf(pBuf, "\n\rPeer Delay on P1 :\t\t\t%d ns",
                (int)timeSyncHandle->tsRunTimeVar->pathDelay[0]);
        UART_printf(pBuf);
        sprintf(pBuf, "\n\rPeer Delay on P2 :\t\t\t%d ns",
                (int)timeSyncHandle->tsRunTimeVar->pathDelay[1]);
        UART_printf(pBuf);

        if(timeSyncHandle->timeSyncConfig.isMaster)
        {
            UART_printf("\n\r\n\r--------DUT configured as Master---------");
        }

        else
        {
            UART_printf("\n\r\n\r--------DUT configured as Slave---------");

            TimeSync_getCurrentTime(timeSyncHandle, &nanoseconds, &seconds);

            UART_printf("\n\r*********PTP/1588 Params********");
            sprintf(pBuf, "\n\rClock Drift :\t\t\t\t%d ns",
                    (int)timeSyncHandle->tsRunTimeVar->clockDrift);
            UART_printf(pBuf);
            sprintf(pBuf, "\n\rCurr offset :\t\t\t\t%d ns",
                    (int)timeSyncHandle->tsRunTimeVar->currOffset);
            UART_printf(pBuf);
#ifdef PTP_TESTING
            sprintf(pBuf, "\n\rMin offset :\t\t\t\t%d ns",
                    (int)min_offset);
            UART_printf(pBuf);
            sprintf(pBuf, "\n\rMax offset :\t\t\t\t%d ns",
                    (int)max_offset);
            UART_printf(pBuf);
            sprintf(pBuf, "\n\rNum Sync Missed :\t\t\t%d",
                    (int)(int)timeSyncHandle->numSyncMissed);
            UART_printf(pBuf);
#endif //PTP_TESTING
            sprintf(pBuf, "\n\rUTC Offset (Seconds field) :\t\t%ld seconds",
                    (long int)seconds);
            UART_printf(pBuf);
            sprintf(pBuf, "\n\rMaster connected on Port :\t\t%d",
                    (int)timeSyncHandle->tsRunTimeVar->syncPortNum);
            UART_printf(pBuf);
            UART_printf("\n\r*******************************");

        }

    }

}

void printConfiguration(ICSSEMAC_Handle emachandle)
{
    char pMsg[1024];
    RED_CONFIG cfg;

    mmZeroInit(&cfg, sizeof(RED_CONFIG));

    sprintf(pMsg,
            "\n\r"
            "C O N F I G U R A T I O N\n\r"
            "\n\r");
    UART_printf(pMsg);

    if(RedGetConfiguration(&cfg, emachandle) == RED_OK)
    {
        sprintf(pMsg,
                "    sup address: %08x%04x\n\r"
                "\n\r"
                "                           Node Table  Duplicate Host Table  Duplicate Port Table\n\r"
                "                 --------------------  --------------------  --------------------\n\r"
                "           size:             %08x              %08x              %08x\n\r"
                "    arbitration:             %08x              %08x\n\r"
                " check interval:             %08x              %08x              %08x\n\r"
                "    forget time:             %08x              %08x\n\r"
                "        counter:             %08x              %08x  %08x    %08x\n\r",
                (unsigned int)OS_NetToHost32(cfg.supAddressHi),
                (unsigned int)OS_NetToHost16((uint16_t)(cfg.supAddressLow & 0x0000FFFF)),
                (unsigned int)cfg.nodeTableSize, (unsigned int)cfg.duplicateHostTableSize,
                (unsigned int)cfg.duplicatePortTableSize,
                (unsigned int)cfg.nodeTableArbitration,
                (unsigned int)cfg.hostDuplicateArbitration,
                (unsigned int)cfg.nodeTableCheckInterval,
                (unsigned int)cfg.duplicateHostCheckInterval,
                (unsigned int)cfg.duplicatePortCheckInterval,
                (unsigned int)cfg.nodeForgetTime, (unsigned int)cfg.duplicateForgetTime,
                (unsigned int)cfg.nodeTableCounter, (unsigned int)cfg.duplicateHostCounter,
                (unsigned int)cfg.duplicatePort0Counter,
                (unsigned int)cfg.duplicatePort1Counter);
        UART_printf(pMsg);
    }

    else
    {
        sprintf(pMsg, "redGetConfiguration failed!\n\r");
        UART_printf(pMsg);
    }
}

void printStatistics(ICSSEMAC_Handle emachandle)
{
    char pMsg[1024];
    RED_STATISTICS stats;

#ifndef MINIMIZE_STATS
#ifdef ICSS_PROTOCOL_HSR
    char *mode = getHsrLreModePrintStr(emachandle);
    sprintf(pMsg,
            "\n\r"
            "HSR %s\n\r",
            mode);
    UART_printf(pMsg);
#endif /* ICSS_PROTOCOL_HSR */

    sprintf(pMsg,
            "\n\r"
            "S T A T I S T I C S\n\r"
            "\n\r");
    UART_printf(pMsg);
#endif

    if(RedGetStatistics(&stats, emachandle) != RED_OK)
    {
        sprintf(pMsg, "hsrGetIndexArrayEntry failed!\n\r");
        UART_printf(pMsg);
        return;
    }

#ifdef MINIMIZE_STATS
    UART_printf("\n%08d (%08d) - %08d (%08d) - %08d ", (int)stats.cntLookupErrA, (int)stats.cntErrorsA, (int)stats.cntLookupErrB, (int)stats.cntErrorsB, (int)stats.cntTxC);
#else
    sprintf(pMsg,
            "Lookup error A : %08d\n\r"
            "Lookup error B : %08d\n\r"
            "\n\r",
            (int)stats.cntLookupErrA, (int)stats.cntLookupErrB);
    UART_printf(pMsg);

    sprintf(pMsg,
            "      Tx  WrongLan        Rx    Errors     Nodes     Proxy    Unique   Duplic.     Multi     OwnRx\n\r"
            "--------  --------  --------  --------  --------  --------  --------  --------  --------  --------\n\r"
            "%08d  %08d  %08d  %08d  %08d  %08d  %08d  %08d  %08d  %08d\n\r"
            "%08d  %08d  %08d  %08d                      %08d  %08d  %08d  %08d\n\r"
            "%08d  %08d  %08d  %08d                      %08d  %08d  %08d\n\r",
            (int)stats.cntTxA, (int)stats.cntErrWrongLanA, (int)stats.cntRxA,
            (int)stats.cntErrorsA,
            (int)stats.cntNodes, (int)stats.cntProxyNodes,
            (int)stats.cntUniqueA, (int)stats.cntDuplicateA, (int)stats.cntMultiA,
            (int)stats.cntOwnRxA,
            (int)stats.cntTxB, (int)stats.cntErrWrongLanB, (int)stats.cntRxB,
            (int)stats.cntErrorsB,
            (int)stats.cntUniqueB, (int)stats.cntDuplicateB, (int)stats.cntMultiB,
            (int)stats.cntOwnRxB,
            (int)stats.cntTxC, (int)stats.cntErrWrongLanC, (int)stats.cntRxC,
            (int)stats.cntErrorsC,
            (int)stats.cntUniqueC, (int)stats.cntDuplicateC, (int)stats.cntMultiC);
    UART_printf(pMsg);

#ifdef RED_STATS_DBG
    sprintf(pMsg,
            " H_OFlow   F_OFlow  H_F_Acqu  H_F_Acqu    debug1     debu2    debug3   debug4\n\r"
            "--------  --------  --------  --------  --------  --------  --------  --------\n\r"
            "%08d  %08d  %08d  %08d  %08d  %08d  %08d  %08d\n\r"
            "%08d  %08d  %08d  %08d\n\r",
            stats.RXA_OVERFLOW, stats.RXA_FWD_OVERFLOW, stats.RXA_FAILACQU_QUEUE,
            stats.RXA_FWD_FAILACQU_QUEUE , stats.DEBUG_1, stats.DEBUG_2, stats.DEBUG_3,
            stats.DEBUG_4,
            stats.RXB_OVERFLOW, stats.RXB_FWD_OVERFLOW, stats.RXB_FAILACQU_QUEUE,
            stats.RXB_FWD_FAILACQU_QUEUE);
    UART_printf(pMsg);
#endif /* RED_STATS_DBG */
#endif
}

void printLreStatistics(ICSSEMAC_Handle emachandle)
{
    uint16_t i;

    char lreStats[][50] = {"LRE_START", "LRE_CNT_TX_A", "LRE_CNT_TX_B", "LRE_CNT_TX_C", "LRE_CNT_ERRWRONGLAN_A",
                           "LRE_CNT_ERRWRONGLAN_B", "LRE_CNT_ERRWRONGLAN_C", "LRE_CNT_RX_A", "LRE_CNT_RX_B",
                           "LRE_CNT_RX_C", "LRE_CNT_ERRORS_A", "LRE_CNT_ERRORS_B", "LRE_CNT_ERRORS_C",
                           "LRE_CNT_NODES", "LRE_CNT_PROXY_NODES", "LRE_CNT_UNIQUE_RX_A", "LRE_CNT_UNIQUE_RX_B",
                           "LRE_CNT_UNIQUE_RX_C", "LRE_CNT_DUPLICATE_RX_A", "LRE_CNT_DUPLICATE_RX_B",
                           "LRE_CNT_DUPLICATE_RX_C", "LRE_CNT_MULTIPLE_RX_A", "LRE_CNT_MULTIPLE_RX_B",
                           "LRE_CNT_MULTIPLE_RX_C", "LRE_CNT_OWN_RX_A", "LRE_CNT_OWN_RX_B", "LRE_DUPLICATE_DISCARD",
                           "LRE_TRANSPARENT_RECEPTION", "LRE_NODE_TABLE_LOOKUP_ERROR_A", "LRE_NODE_TABLE_LOOKUP_ERROR_B",
                           "LRE_NODE_TABLE_FULL", "LRE_MULTICAST_DROPPED", "LRE_VLAN_DROPPED", "LRE_INTR_TMR_EXP"
#ifdef LRE_DEBUG_STATS
                           , "LRE_TOTAL_RX_A", "LRE_TOTAL_RX_B", "LRE_OVERFLOW_PRU0", "LRE_OVERFLOW_PRU1",
                           "LRE_DD_PRU0", "LRE_DD_PRU1", "LRE_CNT_SUP_PRU0", "LRE_CNT_SUP_PRU1"
#endif
                          };

    for(i = 0; i < (sizeof(lreStats) / sizeof(lreStats[0])); i++)
    {
        UART_printf("%s %x\n", lreStats[i], *((uint32_t *)(((((ICSS_EmacHwAttrs *)
                                              emachandle->hwAttrs)->emacBaseAddrCfg)->sharedDataRamBaseAddr) + LRE_START +
                                              i * 4)));
    }
}

char *getNodeTypePrintStr(uint8_t nodeEntryStatus)
{
    uint8_t remNodeType = (nodeEntryStatus & NT_REM_NODE_TYPE_MASK) >>
                          NT_REM_NODE_TYPE_SHIFT;
    uint8_t hsrBitSet   = (nodeEntryStatus & NT_REM_NODE_HSR_BIT);

    switch(remNodeType)
    {
        case NT_REM_NODE_TYPE_SANA:
            return RED_REM_NODE_TYPE_STR_SANA;

        case NT_REM_NODE_TYPE_SANB:
            return RED_REM_NODE_TYPE_STR_SANB;

        case NT_REM_NODE_TYPE_SANAB:
            return RED_REM_NODE_TYPE_STR_SANAB;

        case NT_REM_NODE_TYPE_DAN:
            if(hsrBitSet)
            {
                return RED_REM_NODE_TYPE_STR_DANH;
            }

            else
            {
                return RED_REM_NODE_TYPE_STR_DANP;
            }

        case NT_REM_NODE_TYPE_REDBOX:
            if(hsrBitSet)
            {
                return RED_REM_NODE_TYPE_STR_REDBOXH;
            }

            else
            {
                return RED_REM_NODE_TYPE_STR_REDBOXP;
            }

        case NT_REM_NODE_TYPE_VDAN:
            if(hsrBitSet)
            {
                return RED_REM_NODE_TYPE_STR_VDANH;
            }

            else
            {
                return RED_REM_NODE_TYPE_STR_VDANP;
            }

        default:
            break;
    }

    return RED_REM_NODE_TYPE_STR_UNKNOWN;
}

uint8_t getDuplicateDiscardPrintVal(uint8_t nodeEntryStatus)
{
    return ((nodeEntryStatus & NT_REM_NODE_DUP_MASK) >> NT_REM_NODE_DUP_SHIFT);
}

void printSnmpNodeTable(hsrPrpHandle *hsrPrphandle)
{
    Int32 index = 0;
    Int32 nodes = 0;
    char *nodeType = NULL;
    uint8_t dupDiscard = 1;
    char pMsg[1024];
    RED_NODE_TABLE nodeTable;
    RED_NODE_TABLE_ENTRY *entry;

    sprintf(pMsg,
            "\n\r"
            "N O D E   T A B L E (SNMP API)\n\r"
            "\n\r");
    UART_printf(pMsg);

    nodeTable.max = getLreNodeTableSize(emachandle);

    nodeTable.cnt = 0;
    nodeTable.entries = malloc(sizeof(RED_NODE_TABLE_ENTRY) * nodeTable.max);

    if(nodeTable.entries == NULL)
    {
        sprintf(pMsg, "malloc failed!\n\r");
        UART_printf(pMsg);
        return;
    }

    nodes = getLreNodeTable(&nodeTable, hsrPrphandle);

    if(nodes <= 0)
    {
        if(nodes == 0)
        {
            sprintf(pMsg, "Node Table is empty!\n\r");
            UART_printf(pMsg);
        }

        else
        {
            sprintf(pMsg, "getLreNodeTable failed! Err: %d\n\r", (int)nodes);
            UART_printf(pMsg);
        }
    }

    else
    {
        sprintf(pMsg,
                "Idx         MacAddress     Type  DD        Rx   LineErr     RxSup  TlsSup     Tls\n\r"
                "---  -----------------  -------  --  --------  --------  --------  ------  ------\n\r");
        UART_printf(pMsg);

        for(index = 0; index < nodes; index++)
        {
            entry = &nodeTable.entries[index];
            nodeType = getNodeTypePrintStr(entry->status);
            dupDiscard = getDuplicateDiscardPrintVal(entry->status);
            sprintf(pMsg,
                    "%03d  %02x-%02x-%02x-%02x-%02x-%02x  %s  %02d  %08d  %08d  %08d  %06d  %06d\n\r"
                    "                                     %08d  %08d  %08d          %06d\n\r",
                    (int)index, entry->src[0], entry->src[1], entry->src[2], entry->src[3],
                    entry->src[4], entry->src[5],
                    nodeType, (int)dupDiscard, (int)entry->cntRxA, (int)entry->errRxA,
                    (int)entry->cntRxSupA,
                    (int)entry->timeLasSeenS, (int)entry->timeLasSeenA,
                    (int)entry->cntRxB, (int)entry->errRxB, (int)entry->cntRxSupB,
                    (int)entry->timeLasSeenB);
            UART_printf(pMsg);
        }
    }

    free(nodeTable.entries);
}

void printNodeTable(hsrPrpHandle *hsrPrphandle)
{
    RED_BIN_ARRAY_ENTRY *binArrayBase = hsrPrphandle->binArrayBase;
    RED_BIN_ARRAY_ENTRY *pbinArrayNode;

    RED_NODE_TABLE_ENTRY *nodeTableBase = hsrPrphandle->nodeTableBase;
    RED_NODE_TABLE_ENTRY *pnodeTableNode;

    uint16_t i, j;

#if DEBUG_HSR
    RED_INDEX_ARRAY_ENTRY *indexArrayBase = (RED_INDEX_ARRAY_ENTRY *)((((
            ICSS_EmacHwAttrs *)
                                            icssEmacHandle->hwAttrs)->emacBaseAddrCfg)->sharedDataRamBaseAddr
                                            + INDEX_ARRAY_NT);

    for(i = 0; i < INDEX_TABLE_MAX_ENTRIES; i++)
        if((indexArrayBase + i)->binNoEntries >= 1)
        {
            UART_printf("%d %d\n", i, (indexArrayBase + i)->binNoEntries);
        }

#endif

    char pMsg[1024];
    sprintf(pMsg,
            "\n\r"
            "N O D E   T A B L E   N E W\n\r"
            "\n\r"
            "Idx         MacAddress     Type  DD        Rx   LineErr     RxSup  TlsSup     Tls\n\r"
            "---  -----------------  -------  --  --------  --------  --------  ------  ------\n\r");
    UART_printf(pMsg);

    for(i = 0, j = 0; i < BIN_ARRAY_MAX_ENTRIES; i++)
    {
        pbinArrayNode = binArrayBase + i;

        if(pbinArrayNode->nodetable_offset != CONST_NODETABLE_INVALID)
        {
            pnodeTableNode = nodeTableBase + pbinArrayNode->nodetable_offset;

            char *nodeType = NULL;
            uint8_t dupDiscard = 1;
            nodeType = getNodeTypePrintStr(pnodeTableNode->status);
            dupDiscard = getDuplicateDiscardPrintVal(pnodeTableNode->status);
            sprintf(pMsg,
                    "%03d  %02x-%02x-%02x-%02x-%02x-%02x  %s  %02d  %08d  %08d  %08d  %06d  %06d\n\r"
                    "                                     %08d  %08d  %08d          %06d\n\r",
                    ++j,
                    pbinArrayNode->MacId[3],
                    pbinArrayNode->MacId[2],
                    pbinArrayNode->MacId[1],
                    pbinArrayNode->MacId[0],
                    pbinArrayNode->MacId[5],
                    pbinArrayNode->MacId[4],
                    nodeType,
                    (int)dupDiscard,
                    (int)pnodeTableNode->cntRxA,
                    (int)pnodeTableNode->errRxA,
                    (int)pnodeTableNode->cntRxSupA,
                    (int)pnodeTableNode->timeLasSeenS,
                    (int)pnodeTableNode->timeLasSeenA,
                    (int)pnodeTableNode->cntRxB,
                    (int)pnodeTableNode->errRxB,
                    (int)pnodeTableNode->cntRxSupB,
                    (int)pnodeTableNode->timeLasSeenB);
            UART_printf(pMsg);
        }
    }
}

void runRxTxTest(ICSSEMAC_Handle emachandle)
{

    char byte;
    uint8_t originalPrioQueue[4];
    UART_printf("\n\rTo configure device as Transmitter enter T or t. To configure as receiver enter R or r : \t");
    byte = (char) UART_getc();

    if((byte == 'R') || (byte == 'r'))
    {
        UART_printf("\n\rDevice configured as receiver, will wait for 3 minutes to receive packets");
        /*Take backup*/
        memcpy(originalPrioQueue,
               ((ICSSEMAC_Object *)(emachandle->object))->emacInitcfg->ethPrioQueue, 4);

        ((ICSSEMAC_Object *)(
             emachandle->object))->emacInitcfg->ethPrioQueue[ICSS_EMAC_QUEUE1] = 1;
        ((ICSSEMAC_Object *)(
             emachandle->object))->emacInitcfg->ethPrioQueue[ICSS_EMAC_QUEUE2] = 1;
        ((ICSSEMAC_Object *)(
             emachandle->object))->emacInitcfg->ethPrioQueue[ICSS_EMAC_QUEUE3] = 1;
        ((ICSSEMAC_Object *)(
             emachandle->object))->emacInitcfg->ethPrioQueue[ICSS_EMAC_QUEUE4] = 1;

        /*Wait 3 minutes*/
        TaskP_sleep(3 * 60000);
        memcpy(((ICSSEMAC_Object *)(emachandle->object))->emacInitcfg->ethPrioQueue,
               originalPrioQueue, 4);
    }

    else if((byte == 'T') || (byte == 't'))
    {
        UART_printf("\n\rDevice configured as transmitter, sending packets now");
        txHSRPRPTestFrame(emachandle);
    }

    else
    {
        UART_printf("\n\rDidn't catch that, going back to main menu");
    }

}

void txHSRPRPTestFrame(ICSSEMAC_Handle emachandle)
{
    /*sequence id*/
    uint8_t seq_num = 1;
    uint16_t tx_count;
    uint32_t status = 0;
    ICSS_EmacTxArgument txArg;

    /*Add sequence id to bytes stream*/
    hsrPrpTestFrame[START_OF_UDP_HEADER + 2] = seq_num;

    tx_count = 0;

    while(1)
    {
        if(tx_count < NUM_HSR_TEST_FRAMES)
        {
            txArg.icssEmacHandle = emachandle;
            txArg.srcAddress = hsrPrpTestFrame;
            txArg.lengthOfPacket = (int32_t)HSR_PRP_TEST_FRAME_SIZE;
            txArg.queuePriority = ICSS_EMAC_QUEUE1;
            /*Port number is irrelevant in HSR/PRP since packet is duplicated*/
            txArg.portNumber = 0;

            if(((((ICSSEMAC_Object *)
                    emachandle->object)->callBackHandle)->txCallBack)->callBack != NULL)
            {
                status = ((((ICSSEMAC_Object *)
                            emachandle->object)->callBackHandle)->txCallBack)->callBack(&txArg,
                                    ((((ICSS_EmacObject *)
                                       emachandle->object)->callBackHandle)->txCallBack)->userArg);

            }

            if(status != 0)
            {
                UART_printf("Failed to transmit\n");
            }

            seq_num = (1 << (tx_count % 9)) - 1;
            hsrPrpTestFrame[START_OF_UDP_HEADER + 2] = seq_num;
            tx_count++;

            TaskP_sleep(500);
        }

        if(tx_count >= NUM_HSR_TEST_FRAMES)
        {
            break;
        }

    }
}

void parseAndCheckHSRPRPTestFrame(uint8_t *tempFrame)
{

    /*check for marker and toggle LED's*/
    if((tempFrame[START_OF_UDP_HEADER] == 0xAB)
            && (tempFrame[START_OF_UDP_HEADER + 1] == 0xAC))
    {
        /*Set DGIO status as per data received from transmitter*/
        Board_setDigOutput(tempFrame[START_OF_UDP_HEADER + 2]);
    }

}

uint8_t readAndAssignIPAddress()
{

    uint32_t ipAddr;
    uint8_t returnVal = FALSE;
    char bkupIPString[20];

    memset(bkupIPString, 0x0, sizeof(bkupIPString));

    while(1)
    {
        UART_gets(bkupIPString, -2);

        if(isValidIP(bkupIPString))
        {
            /*Found IP address*/
            returnVal = TRUE;
            break;
        }

        else
        {
            UART_printf("\n\rIllegal value entered");
            returnVal =  FALSE;
            break;
        }
    }

    if(FALSE == returnVal)
    {
        return returnVal;
    }

    memcpy(IPString, bkupIPString, 20);
    ipAddr = inet_addr(IPString);

    if(addIPAddress(ipAddr))
    {
        UART_printf("\n\rAssigned IP \t: ");
        UART_printf(IPString);
    }

    memcpy(hsrPrpTestFrame + START_OF_IP_ADDRESS, &ipAddr, 4);

    changeIPEndianness(&ipAddr);
    uint32_t ioMode;
    ioMode = BOARD_FLASH_QSPI_IO_MODE_QUAD;

    uint32_t blockNum, pageNum;      /* Block, page number */

    Board_flashOffsetToBlkPage(flashHandle, SPI_EEPROM_DEVICEIP_OFFSET,
                               &blockNum, &pageNum);

    Board_flashEraseBlk(flashHandle, blockNum);

    Board_flashWrite(flashHandle, SPI_EEPROM_DEVICEIP_OFFSET, (uint8_t *)&ipAddr, 4,
                     (void *)(&ioMode));
    return returnVal;

}

void removeIPAddress()
{
    CI_IPNET NA;
    HANDLE      hCfgIpAddr;

    if(CfgGetImmediate(0, CFGTAG_IPNET, 1, 1, sizeof(NA),
                       (unsigned char *)&NA) == sizeof(NA))
    {
        /* get the current static IP entry */
        CfgGetEntry(0, CFGTAG_IPNET, 1, 1, &hCfgIpAddr);

        /* remove the current static IP entry */
        CfgRemoveEntry(0, hCfgIpAddr);
    }
}

uint8_t addIPAddress(uint32_t dwIPAddress)
{
    CI_IPNET NA;
    char chvalidIP[16];

    NtIPN2Str(dwIPAddress, chvalidIP);

    if(!(isValidIP(chvalidIP)))
    {
        return FALSE;
    }

    removeIPAddress();
    /* Setup manual IP address */
    bzero(&NA, sizeof(NA));


    NA.IPAddr = dwIPAddress;
    NA.IPMask  = inet_addr("255.255.255.0");
    strcpy(NA.Domain, "demo.net");
    NA.NetType = 0;

    /* add a new static IP entry */
    CfgAddEntry(0, CFGTAG_IPNET, 1, 0,
                sizeof(CI_IPNET), (unsigned char *)&NA, 0);
    return TRUE;
}

int isValidIP(const char *ip_str)
{
    unsigned int n1, n2, n3, n4;

    if(sscanf(ip_str, "%u.%u.%u.%u", &n1, &n2, &n3, &n4) != 4)
    {
        return FALSE;
    }

    if((n1 != 0) && (n1 <= 255) && (n2 <= 255) && (n3 <= 255)
            && (n4 <= 255))
    {
        char buf[64];
        sprintf(buf, "%u.%u.%u.%u", n1, n2, n3, n4);

        if(strcmp(buf, ip_str))
        {
            return 0;
        }

        return TRUE;
    }

    return FALSE;
}

int isValidMacid(char *macid_str)
{
    unsigned int n1, n2, n3, n4, n5, n6;

    if(sscanf(macid_str, "%u %u %u %u %u %u", &n1, &n2, &n3, &n4, &n5, &n6) != 6)
    {
        return FALSE;
    }

    if((n1 != 0) && (n1 <= 255) && (n2 <= 255) && (n3 <= 255)
            && (n4 <= 255) && (n5 <= 255) && (n6 <= 255))
    {
        char buf[64];
        sprintf(buf, "%u %u %u %u %u %u", n1, n2, n3, n4, n5, n6);

#if DEBUG_MC_FLT
        UART_printf("buf:%s macid_str:%s",
                    buf, macid_str);
#endif

        if(strcmp(buf, macid_str))
        {
            return 0;
        }

        return TRUE;
    }

    return FALSE;
}

void changeIPEndianness(uint32_t *dwIPAddress)
{
    uint32_t dwTempIP;

    dwTempIP = * dwIPAddress << 24;
    dwTempIP |= (* dwIPAddress & 0xFF00) << 8;
    dwTempIP |= (* dwIPAddress & 0xFF0000) >> 8;
    dwTempIP |= (* dwIPAddress & 0xFF000000) >> 24;
    * dwIPAddress = dwTempIP;
}

#ifdef PTP_TESTING
void monitorPTPStatus_Task(UArg arg0, UArg arg1)
{
    TimeSync_ParamsHandle_t timeSyncHandle = NULL;
    timeSyncHandle = (TimeSync_ParamsHandle_t)arg0;

    while(1)
    {
        if(timeSyncHandle->tsRunTimeVar->stateMachine &
                TS_STATE_MACHINE_DEVICE_IN_SYNC)
        {
            if(timeSyncHandle->tsRunTimeVar->currOffset < min_offset)
            {
                min_offset = timeSyncHandle->tsRunTimeVar->currOffset;
            }

            if(timeSyncHandle->tsRunTimeVar->currOffset > max_offset)
            {
                max_offset = timeSyncHandle->tsRunTimeVar->currOffset;
            }
        }

        TaskP_sleep(200);
    }
}
#endif //PTP_TESTING

void intr_pac_config(ICSSEMAC_Handle icssEmacHandle, uint32_t intrPacStatus)
{
    uint8_t *intrPacing = (uint8_t *)(((((ICSS_EmacHwAttrs *)
                                         icssEmacHandle->hwAttrs)->emacBaseAddrCfg)->sharedDataRamBaseAddr) +
                                      INTR_PAC_STATUS_OFFSET);

    uint32_t *timeOutValuePru0 = (uint32_t *)(((((ICSS_EmacHwAttrs *)
                                 icssEmacHandle->hwAttrs)->emacBaseAddrCfg)->sharedDataRamBaseAddr) +
                                 INTR_PAC_TMR_EXP_OFFSET_PRU0);
    uint32_t *timeOutValuePru1 = (uint32_t *)(((((ICSS_EmacHwAttrs *)
                                 icssEmacHandle->hwAttrs)->emacBaseAddrCfg)->sharedDataRamBaseAddr) +
                                 INTR_PAC_TMR_EXP_OFFSET_PRU1);

    *intrPacing = intrPacStatus;

    if(intrPacStatus == INTR_PAC_DIS_ADP_LGC_DIS)
    {
        UART_printf("Pacing mode : Interrupt pacing disabled\n");
    }

    else if(intrPacStatus == INTR_PAC_ENA_ADP_LGC_DIS)
    {
        UART_printf("Pacing mode : Interrupt pacing enabled with adaptive logic disabled\n");

        UART_printf("Enter the timerExpiration value:");
        char bkupMacidString[30];
        UART_gets(bkupMacidString, -2);

        unsigned int timerExpiration;
        sscanf(bkupMacidString, "%u", &timerExpiration);

        *timeOutValuePru0 = timerExpiration;
        *timeOutValuePru1 = timerExpiration;
    }

    else if(intrPacStatus == INTR_PAC_ENA_ADP_LGC_ENA)
    {
        UART_printf("Pacing mode : Interrupt pacing enabled with adaptive logic enabled\n");
    }
}
