/*
    FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    This file is part of the FreeRTOS distribution and was contributed
    to the project by Technolution B.V. (www.technolution.nl,
    freertos-riscv@technolution.eu) under the terms of the FreeRTOS
    contributors license.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.

 ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
 ***************************************************************************

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html

 ***************************************************************************
 *                                                                       *
 *    FreeRTOS provides completely free yet professionally developed,    *
 *    robust, strictly quality controlled, supported, and cross          *
 *    platform software that is more than just the market leader, it     *
 *    is the industry's de facto standard.                               *
 *                                                                       *
 *    Help yourself get started quickly while simultaneously helping     *
 *    to support the FreeRTOS project by purchasing a FreeRTOS           *
 *    tutorial book, reference manual, or both:                          *
 *    http://www.FreeRTOS.org/Documentation                              *
 *                                                                       *
 ***************************************************************************

    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?

    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.

    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.

    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
 */

/*
 * main() creates a set of standard demo task and a timer.
 * It then starts the scheduler.  The web documentation provides
 * more details of the standard demo application tasks, which provide no
 * particular functionality, but do provide a good example of how to use the
 * FreeRTOS API.
 *
 *
 * In addition to the standard demo tasks, the following tasks and timer are
 * defined and/or created within this file:
 *
 * "Check" software timer - The check timer period is initially set to three
 * seconds.  Its callback function checks that all the standard demo tasks, and
 * the register check tasks, are not only still executing, but are executing
 * without reporting any errors.
 */


/**
 * @brief FreeRTOS Kernel includes.
 */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"

/**
 * @brief RISC-V and Peripheral includes.
 */

#include "hal.h"
#include "miv_rv32_hal.h"
#include "hw_platform.h"
#include "core_uart_apb.h"
#include "core_gpio.h"
#include "core_timer.h"
#include "phy.h"
#include "drivers/CoreTSE/core_tse.h"
#include"drivers/CoreSysServices_PF/core_sysservices_pf.h"
#include "ethernet_status.h"
#include "rosa_tosa_i2c.h"
#include "hal_assert.h"
/**
 * @brief OAM SDK includes.
 */
#include <api_oam_sdk/common/registers/inc/mr_registers.h>
#include <api_oam_sdk/initialisation/inc/api_init.h>
#include <api_oam_sdk/metroam_hal/inc/mr_hal.h>
#include <api_oam_sdk/test/inc/ccm_test.h>
#include <api_oam_sdk/maintenance_association/inc/ma.h>
#include "egl_assert.h"
#include "gateway_2port_eth.h"
#include "core_tse.h"
#include "osal.h"
#include "network_settings.h"
#include "BasicWEB.h"

/**
 * @brief LWIP stack includes.
 */

#include "lwip/tcpip.h"
#include "lwip/dhcp.h"


/**
 * @brief debug and display  messages.
 */
const char * g_hello_msg = "\n\rWelcome to the OAM ";
const char * g_one_gig_msg = "Continuity Check Messages (CCM)  Demo using PolarFire 1G ethernet interface.\n\r";
const char * g_ten_gig_msg = "Continuity Check Messages (CCM)  Demo using PolarFire 10G ethernet interface.\n\r";
const char * g_ten_gig_sfp_msg = "Continuity Check Messages (CCM)  Demo using PolarFire SFP+ 10G ethernet interface.\n\r";
const char * g_configzl_msg = "\n**SPI is up - ZL30364 configuration completed\n\r";
const char * g_carinit_msg = "\n**Carrier PHY, TSE configuration completed\n\r";
const char * g_sysinit_msg = "\n**System TSE configuration completed\n\r";
const char * g_qsuccess_msg = "\n**xRXQueue setup completed\n\r";
const char * g_qfail_msg = "\n**xRXQueue setup failed!\n\r";
const char * g_ddrchk_msg = "\n**DDR W/R test completed\n\r";
const char * g_eglinit_msg = "\n**Eagle assert init completed\n\r";
const char * g_mrhalinit_msg = "\n**Metroam HAL init completed\n\r";
const char * g_macinit_msg = "\n\r**MAC address assignment completed\n\r";
const char * g_lwipinit_msg = "\n**LWIP Stack init completed\n\r";
const char * g_sys_init_start_msg = "\nSystem initialization is in progress...\n\r";
const char * g_sys_init_end_msg = "\nSystem initialization completed.\n\r";
const char * ccm_interval_msg = "\nSelect CCM interval 1) 100ms 2) 1sec.\n\r";
const char * ccm_10ms_interval_msg = "\nSelected CCM interval is 10ms. \n\r";
const char * ccm_100ms_interval_msg = "\nSelected CCM interval is 100ms\n\r";
const char * ccm_1sec_interval_msg = "\nSelected CCM interval is 1Sec\n\r";
/**
 * @brief Global UART peripheral instance.
 */
UART_instance_t g_uart;

/*-----------------------------------------------------------------------------
 * .
 */

/**
 * @brief Global GPIO instance data.
 */
gpio_instance_t g_gpio_in;
gpio_instance_t g_gpio_out;

/**
 * @brief The queue used by PTPd task to transmit status information to webserver task. */
xQueueHandle xPTPdOutQueue = NULL;

/**
 * @brief Global instance for the timer
 */
timer_instance_t g_timer0;

/**
 * @brief Array for hexadecimal numbers . */
const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
 * @brief structure lwIP MAC interface configuration. */
static struct netif s_EMAC_if;

/**
 * @brief Global variable to get user input for ccm interval. */
uint8_t       g_ccm_interval;

/**
 * @brief Global Semaphore to control the user display messages among the multiple threads. */
osSemaphore_t       g_print_sem = NULL;
/**
 * @brief structure to queue handle. */
extern QueueHandle_t xRXQueue;
/**
 * @brief  Constant values for delay and queue length..
 */

#define DELAY_VALUE 6000000
#define QUEUE_LENGTH 10


/**
 * @brief The period after which the check timer will expire provided no errors have
been reported by any of the standard demo tasks.  ms are converted to the
equivalent in ticks using the portTICK_PERIOD_MS constant.
 */
#define mainCHECK_TIMER_PERIOD_MS			( 3000UL / portTICK_PERIOD_MS )

/**
 * @brief  A block time of zero simply means "don't block". */
#define mainDONT_BLOCK						( 0UL )

/**
 * @brief  constant for ethernet status queue length.
*/

#define ETHERNET_STATUS_QUEUE_LENGTH    1
#define DONT_BLOCK                      0


/**
 * @brief Link status and Receive tasks*/
#if NOT
void prvLinkRXTask(void * pvParameters);
#endif

void prvLinkStatusTask(void * pvParameters);
/**
 * @brief  Ethernet interface configuration function.
 */
static void prvEthernetConfigureInterface(void * param);
/**
 * @brief  FreeRTOS hook for when malloc fails, enable in FreeRTOSConfig.
 */
void vApplicationMallocFailedHook( void );

/**
 * @brief  FreeRTOS hook for when freertos is idling, enable in FreeRTOSConfig.
 */
void vApplicationIdleHook( void );

/**
 * @brief FreeRTOS hook for when a stackoverflow occurs, enable in FreeRTOSConfig.
 */
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );




/**
 * @brief Displays the message to the user using serial terminal program.
 */

void display_output(
        uint8_t* in_buffer,
        uint32_t byte_length
);

/**
 * @brief COnfgiures the ZL30364 module using SPI to provide 1G ethernet clock.
 */
extern void configure_zl30364(void);

#if NOT
void vMainConfigureTimerForRunTimeStats( void )
{

    const unsigned long ulMax32BitValue = 0xffffffffUL;
#if 0
    MSS_TIM64_init( MSS_TIMER_PERIODIC_MODE );
    MSS_TIM64_load_immediate( ulMax32BitValue, ulMax32BitValue );
    MSS_TIM64_start();
#endif
    TMR_init(&g_timer0,
            CORETIMER0_BASE_ADDR,
            TMR_CONTINUOUS_MODE,
            PRESCALER_DIV_1024,
            ulMax32BitValue);
    TMR_start(&g_timer0);
}


unsigned long ulGetRunTimeCounterValue( void )
{
    unsigned long long ullCurrentValue = 0u;
#if 0
    const unsigned long long ulMax64BitValue = 0xffffffffffffffffULL;
    unsigned long *pulHighWord, *pulLowWord;

    pulHighWord = ( unsigned long * ) &ullCurrentValue;
    pulLowWord = pulHighWord++;

    MSS_TIM64_get_current_value( ( uint32_t * ) pulHighWord, ( uint32_t * ) pulLowWord );

    //Convert the down count into an upcount.
    ullCurrentValue = ulMax64BitValue - ullCurrentValue;

    //  Scale to a 32bit number of suitable frequency.
    ullCurrentValue >>= 13;
#endif
    ullCurrentValue = TMR_current_value(&g_timer0);
    // Just return 32 bits.
    return ( unsigned long ) ullCurrentValue;
}
#endif



/**
 * @brief get_mac_address.
 *
 * This function fetches  the MAC address from MAC structure and returns the same.
 */

void get_mac_address(uint8_t * mac_addr)
{
    uint32_t inc;

    for(inc = 0; inc < 6; ++inc)
    {
        mac_addr[inc] = s_EMAC_if.hwaddr[inc];
    }
}

/**
 * @brief get_ip_address.
 *
 * This function fetches  the IP address from MAC structure and returns the same.
 */
uint32_t get_ip_address(void)
{
    return (uint32_t)(s_EMAC_if.ip_addr.addr);
}

#if NOT
void ddr_mem_test()
{
    volatile uint32_t *m = (uint32_t *)0x80200000;
    uint32_t i = 0,count=0;
    uint32_t wr,base= 0x12345678,rd;
    UART_init( &g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, (DATA_8_BITS | NO_PARITY));
    UART_polled_tx_string(&g_uart, (const uint8_t *)"DDR memory testing is in progress\n\r");
    //rd= *(volatile uint32_t *)0x80010000;
    for(i=0;i<1024*256;i++)
    {
        wr= base+i;
        *(m+i)= wr;
        rd = *(m+i);
        if(wr != rd)
        {
            count++;
        }
    }
    if(count==0)
    {
        UART_polled_tx_string(&g_uart, (const uint8_t *)"\n\rDDR3 memory test passed\n\r");
    }
    else
    {
        UART_polled_tx_string(&g_uart, (const uint8_t *)"\n\rDDR3 memory test failed\n\r");
    }
}


void execute_designinfo_service(void)
{
    uint8_t status,data_buffer[128];
    status = SYS_get_design_info(data_buffer, 0);
    if(SYS_SUCCESS == status)
    {

        UART_polled_tx_string(&g_uart, (const uint8_t*)"\r\nDesign Version(MSB first): ");
        //display_output((data_buffer + 33), 1);
        //display_output((data_buffer + 32), 1);
        UART_polled_tx_string(&g_uart,(const uint8_t*)"\r\n");
    }
    else
    {
        UART_polled_tx_string(&g_uart,(const uint8_t*)"DesignInfo Service failed.\r\n");
    }


}
void  GPIO_Init()
{
    GPIO_init(&g_gpio_out, 0x60003000UL, GPIO_APB_32_BITS_BUS);

    /**************************************************************************
     * Configure the GPIOs.
     *************************************************************************/
    GPIO_config( &g_gpio_out, GPIO_0, GPIO_OUTPUT_MODE );

    /**************************************************************************
     * Set the GPIO outputs.
     *************************************************************************/
}
#endif
/**
 * @brief delay function
 *
 * This function produces the delay with a provided value using while statement.
 */
void delay(uint32_t div)
{
    volatile uint32_t delay_count = 40000000/div ;/// 128u;

    while(delay_count > 0u)
    {
        --delay_count;
    }
}


/**
 * @brief display_output function
 *
 * This function displays the messages using uart peripheral.
 */

void display_output
(
        uint8_t* in_buffer,
        uint32_t byte_length
)
{
    uint32_t inc;
    uint8_t byte = 0;

    UART_send(&g_uart, (const uint8_t*)" ", sizeof(" "));
    for(inc = 0; inc < byte_length; ++inc)
    {
        if((inc > 1u) &&(0u == (inc % 16u)))
        {
            UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n "));
        }

        byte = in_buffer[inc];
        UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1);
        UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1);

    }

}

/**
 * @brief ts_free function
 *
 * This function frees the memory allocated.
 */
void ts_free(void *memPtr)
{
    //osMutexTake(ts_mem_mgnt_mutex,0);
    free(memPtr);
    //vPortFree(memPtr);
}
/**
 * @brief ts_malloc function
 *
 * This function allocates memory .
 */

void * ts_malloc(uint32_t size)
{
    void *memPtr;
    memPtr = malloc(size);
    return(memPtr);
}

/**
 * @brief Global g_EMAC_if
 *
 * holds the number of Phys for the ethernet interface .
 */

extern struct netif     g_EMAC_if[PHY_COUNT];

/**
 * @brief Global g_init_in_prog
 *
 * flag to represent the initialization is in progress .
 */
volatile bool           g_init_in_prog;
/**
 * @brief Global mrDeviceInfo
 *
 * structure to hold OAM IP device information .
 */
mrDeviceInfo_t      mrDeviceInfo;


/**
 * @brief function init_10g_tse_cores
 *
 * This function initializes the 10G MAC ethernet interfaces .
 */

void init_10g_tse_cores()
{


    *(volatile unsigned int *) (TSE_BASEADDR + 0x28C) = 0x1C000; // PADDR[9:6]=0xA, PADDR[5:2] = 0x3, MAC Tx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR + 0x290) = 0x10C;//0x00C;   // PADDR[9:6]=0xA, Offset 0x4, MAC Tx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR + 0x2C0) = 0x0; //0x8; // PADDR[9:6]=0xB, Offset 0x0, MAC Rx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR + 0x2CC) = 0x1C000; // PADDR[9:6]=0xB, offset 0x3, MAC Rx Config Register



#ifdef DEBUG_PRINT_L2
    ts_printf("** 10G MAC init completed...**\r\n");
#endif


    // 10G MACCORE_1
#if 0
    UART_send(&g_uart, (const uint8_t *)"\r\n 10G MAC_CORE_1 APB access",
            sizeof("\r\n 10G MAC_CORE_1 APB access"));
    *(volatile unsigned int *) (TSE_BASEADDR_SYS + 0x28C) = 0x1C000; // PADDR[9:6]=0xA, PADDR[5:2] = 0x3, MAC Tx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR_SYS + 0x290) = 0x10C; // PADDR[9:6]=0xA, Offset 0x4, MAC Tx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR_SYS + 0x2C0) = 0x8; // PADDR[9:6]=0xB, Offset 0x0, MAC Rx Config Register
    *(volatile unsigned int *) (TSE_BASEADDR_SYS + 0x2CC) = 0x1C000; // PADDR[9:6]=0xB, offset 0x3, MAC Rx Config Register

    temp_data = *(volatile unsigned int *) (TSE_BASEADDR_SYS + 0x28c);
    display_output(&temp_data,4);
#endif

}

/**
 * @brief function init_tse_cores
 *
 * This function initializes the 1G MAC ethernet interfaces .
 */

void init_tse_cores()
{

    tse_init();

    Phy_advertise();
    phy_autonegotiation();

#ifdef DEBUG_PRINT_L2
    UART_send(&g_uart, (const uint8_t *)"\n**TSE_1 initialization completed\n\r",
            sizeof("\n**TSE_1 initialization completed\n\r"));
#endif

    tse_init_sys();

}


/**
 * @brief function eth_interface_config
 *
 * This function determines the ethernet interface sequence depending on hardware.
 */

void eth_interface_config(uint32_t *cpuif_metroam_add)
{
#define ONE_GIG 0x11
#define TEN_GIG 0x22
#define TEN_GIG_SFP 0x33
    uint8_t user_code[64];


    SYS_init(PF_SYSTEM_SERVICE);
    SYS_get_user_code(user_code,0);
    switch(user_code[0])
    {
    case ONE_GIG:
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_one_gig_msg);
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_sys_init_start_msg);
        configure_zl30364(); //1G clock
        init_tse_cores(); //1G
        *cpuif_metroam_add = NID_BASEADDR_1G;
        break;
    case TEN_GIG:
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_ten_gig_msg);
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_sys_init_start_msg);
        init_10g_tse_cores(); //10G
        *cpuif_metroam_add = NID_BASEADDR_10G;
        break;
    case TEN_GIG_SFP:
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_ten_gig_sfp_msg);
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_sys_init_start_msg);
        config_rosatosa(); //SFP
        init_10g_tse_cores();
        *cpuif_metroam_add = NID_BASEADDR_10G;
        break;
    default:
        ;
    }

}
/**
 * @brief function get_ccm_interval
 *
 * This function gets the user input to change the CCM interval.
 *  CCM interval  1. 10ms 2. 100ms 3. 1sec.
 */
void get_ccm_interval()
{
    uint8_t rx_data[1] = {'3'};
    uint8_t rx_size = 0;
    uint32_t delay_timeout = 0x4FFFFF;

    g_ccm_interval = ccmInterval1s;
    UART_polled_tx_string(&g_uart, (const uint8_t *)ccm_interval_msg);
    while((rx_size == 0) && (delay_timeout> 0))
    {
        rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) );
        delay_timeout --;
    }
    if(rx_size>0)
    {
        if(rx_data[0] == '1')
        {
            g_ccm_interval = ccmInterval100ms;
            UART_polled_tx_string(&g_uart, (const uint8_t *)ccm_100ms_interval_msg );
        }
        else
        {
            g_ccm_interval = ccmInterval1s;
            UART_polled_tx_string(&g_uart, (const uint8_t *)ccm_1sec_interval_msg  );
        }
    }
    else
    {
        UART_polled_tx_string(&g_uart, (const uint8_t *)ccm_1sec_interval_msg  );
    }


}

/**
 * @brief function main
 *
 * This function has the sequence of steps to implement the OAM CCM demo using freeRtos tasks.
 * Post System initialization, the startCCMTestProcess will be executed.
 *  The startCCMTestProcess runs the CCM Task.
 */

int main( void )
{

    networkConfig_t     networkConfig[PHY_COUNT];
    uint32_t cpuif_metroam_add;

    osSemaphoreCreateBinary(g_print_sem);
    HAL_ASSERT(g_print_sem != NULL);
    // UART Init and Welcome Message
    UART_init( &g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, (DATA_8_BITS | NO_PARITY));


#ifdef DEBUG_PRINT_L1
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_hello_msg);

#endif
    eth_interface_config(&cpuif_metroam_add);

#ifdef DEBUG_PRINT_L2
    //configure_zl30364();
    //UART_polled_tx_string(&g_uart, (const uint8_t *)g_configzl_msg);
#endif


    xRXQueue = xQueueCreate( QUEUE_LENGTH, sizeof( uint32_t ) );
    if( xRXQueue == NULL )
    {
        /* Queue was not created and must not be used. */
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_qfail_msg);
    }
    else
    {
#ifdef DEBUG_PRINT_L2
        UART_polled_tx_string(&g_uart, (const uint8_t *)g_qsuccess_msg);
#endif
    }

    // Initialise Assert so that asserts are logged
    egl_assert_init();
#ifdef DEBUG_PRINT_L2
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_eglinit_msg);
#endif

    // Initialise the MetRoam HAL
    mrHalInit(cpuif_metroam_add);
#ifdef DEBUG_PRINT_L2
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_mrhalinit_msg);
#endif
    // Verify and read the Network Settings
    verifyNvmNetworkSettings(networkConfig);

    // Copy the initial network settings to a global parameter
    mrDeviceInfo.mgntMAC = networkConfig[0].macAddr;
    mrDeviceInfo.wanMAC = networkConfig[1].macAddr;
    mrDeviceInfo.lanMAC = networkConfig[2].macAddr;
    // Initialise the MACs in the fabric and load the receive packet processing task
    gateway_mac_init(mrDeviceInfo.wanMAC,mrDeviceInfo.lanMAC,mrDeviceInfo.mgntMAC,&g_EMAC_if[0]);
#ifdef DEBUG_PRINT_L2
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_macinit_msg);
#endif


    // Start the LWIP Stack
    tcpip_init(configureEthernetInterfaces, (void*)networkConfig);
#ifdef DEBUG_PRINT_L2
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_lwipinit_msg);
#endif
#ifdef DEBUG_PRINT_L1
    UART_polled_tx_string(&g_uart, (const uint8_t *)g_sys_init_end_msg);
#endif
#if ENABLE_NETBIOS
    netbios_init();
    ts_printf("NetBios Enabled\n");
#endif
#if ENABLE_SNTP
    sntp_init();
    ts_printf("SNTP Enabled\n");
#endif
#if NOT
    osTaskCreate(vBasicWEBServer,"WEBSVR      ",2048,NULL,OS_STACK_THREAD_PRIO - 1,NULL);
#endif
    /*Get the user input to select the CCM interval*/
    get_ccm_interval();

    g_init_in_prog = true;
       apiInit();
       g_init_in_prog = false;
    /* Create the OAM CCM FreeRTOS task */

    startCCMTestProcess();



    /* Start the kernel.  From here on, only tasks and interrupts will run. */
#ifdef DEBUG_PRINT_L2
    UART_polled_tx_string(&g_uart, (const uint8_t *)"**Starting vTaskStartScheduler\n\r");
#endif
    /* Enable the interrupts mapped from OAM ip to Mi-V softprocessor */
    HAL_enable_interrupts();
    MRV_enable_local_irq(MRV32_MSYS_EIE0_IRQn );
    /* Start the FreeRTOS scheduler to manage the execution of tasks */
    vTaskStartScheduler();

    /*
     * If all is well, the scheduler will now be running, and the following line
     * will never be reached.  If the following line does execute, then there
     * was insufficient FreeRTOS heap memory available for the idle and/or timer
     * tasks to be created.  See the memory management section on the FreeRTOS
     * web site for more details.
     */
    /* Exit FreeRTOS */
    return 0;
}
/*-----------------------------------------------------------*/

/*-----------------------------------------------------------*/
/**
 * @brief function vApplicationMallocFailedHook
 *
 * vApplicationMallocFailedHook() will only be called if
    configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
    function that will get called if a call to pvPortMalloc() fails.
    pvPortMalloc() is called internally by the kernel whenever a task, queue,
    timer or semaphore is created.  It is also called by various parts of the
    demo application.  If heap_1.c or heap_2.c are used, then the size of the
    heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
    FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
    to query the size of free heap space that remains (although it does not
    provide information on how the remaining heap might be fragmented).
 */

void vApplicationMallocFailedHook( void )
{

    UART_polled_tx_string(&g_uart, (const uint8_t *)"vApplicationMallocFailedHook\n\r");
    taskDISABLE_INTERRUPTS();
    for( ;; );
}
/*-----------------------------------------------------------*/
/**
 * @brief function vApplicationIdleHook
 * * This function is called on each cycle of the idle task.  In this case it
     * does nothing useful, other than report the amount of FreeRTOS heap that
     * remains unallocated.
 */
void vApplicationIdleHook( void )
{
    volatile size_t xFreeStackSpace;


    xFreeStackSpace = xPortGetFreeHeapSize();

    if( xFreeStackSpace > 100 )
    {
        /*
         * By now, the kernel has allocated everything it is going to, so if
         * there is a lot of heap remaining unallocated then the value of
         * configTOTAL_HEAP_SIZE in FreeRTOSConfig.h can be reduced accordingly.
         */
    }

}
/*-----------------------------------------------------------*/
/**
 * @brief function vApplicationStackOverflowHook
 * Run time stack overflow checking is performed if
    configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
    function is called if a stack overflow is detected.
 */
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
    ( void ) pcTaskName;
    ( void ) pxTask;

    /*  */
    taskDISABLE_INTERRUPTS();
    for( ;; );
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
/**
 * @brief function prvEthernetConfigureInterface
 *  this function binds the ip address to the ethernet interface by configuring.
 */
static void prvEthernetConfigureInterface(void * param)
{
    struct ip_addr xIpAddr, xNetMast, xGateway;
    extern err_t ethernetif_init( struct netif *netif );

    /* Parameters are not used - suppress compiler error. */
    ( void ) param;

    /* Create and configure the EMAC interface. */
#ifdef NET_USE_DHCP
    IP4_ADDR( &xIpAddr, 0, 0, 0, 0 );
    IP4_ADDR( &xGateway, 192, 168, 1, 254 );
#else
    IP4_ADDR( &xIpAddr, 169, 254, 1, 23 );
    IP4_ADDR( &xGateway, 169, 254, 1, 23 );
#endif

    IP4_ADDR( &xNetMast, 255, 255, 255, 0 );

    netif_add( &s_EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input );

    /* bring it up */

#ifdef NET_USE_DHCP
    dhcp_start(&s_EMAC_if);
#else
    netif_set_up(&s_EMAC_if);
#endif

    /* make it the default interface */
    netif_set_default(&s_EMAC_if);
}



/**
 * @brief function prvLinkStatusTask
 * function checks for the IP address availability when configuration is done.
 */
uint32_t ip_addr;
void prvLinkStatusTask(void * pvParameters)
{
    static uint8_t acquired = 0;
    uint8_t buf[50]={0};
    uint16_t address[4];
    UART_polled_tx_string(&g_uart, (const uint8_t *)"Acquiring IP address");
    for(;;)
    {
        volatile uint8_t linkup;


        /* Run through loop every 2000 milliseconds. */
        vTaskDelay(2000 / portTICK_RATE_MS);

        if(0 == acquired)
        {
            ip_addr = get_ip_address();
            if(0 != ip_addr)
            {
                acquired = 1;
            }
            UART_polled_tx_string(&g_uart, (const uint8_t *)".");
        }

        if(acquired == 1)
        {

            address[0] = ((uint16_t)((ip_addr >> 24u) & 0x000000FFu));
            address[1] = ((int)((ip_addr >> 16u) & 0x000000FFu));
            address[2] = ((int)((ip_addr >> 8u) & 0x000000FFu));
            address[3] = ((int)((ip_addr ) & 0x000000FFu));

            sprintf(buf, "\n\r %d.%d.%d.%d\n\r",address[3],address[2],address[1],address[0]);

            UART_polled_tx_string(&g_uart, (const uint8_t *)buf);
            vTaskDelay(2000 / portTICK_RATE_MS);
            break;


        }
    }
    vTaskDelete( NULL );
}
/**
 * @brief function vApplicationTickHook
 *  The tick hook function  receives a number from each 'hook' co-routine
 * then sends a number to each co-routine.  An error is flagged if a send or
 * receive fails, or an unexpected number is received.
 * */
void vApplicationTickHook( void )
{
          // do - nothing. place holder for the  future implementation
}
