/*
 * myNDK.c
 *
 *  Created on: 20.11.2020
 *      Author: mark
 */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Task.h>
#include <stdio.h>

#include <ti/ndk/inc/netmain.h>
#include <ti/ndk/inc/_stack.h>

#include <ti/ndk/config/prototypes.h>

#include <xdc/runtime/System.h>
#include <xdc/runtime/Types.h>

#include <ti/sysbios/knl/Semaphore.h>

#include <ti/ndk/inc/stack/inc/routeif.h>

/*
 *  Local NDK Memory Buffer Pool Definitions
 *
 *  The below variables/defines are used to allow the user's *.cfg settings to
 *  override the defaults that are set in the OSAL's mem_data.c file
 *  src/stack/os/mem_data.c
 *
 */
#include <ti/ndk/inc/_oskern.h>
#include <xdc/cfg/global.h>




/* Our NETCTRL callback functions */
static void ti_ndk_config_Global_NetworkOpen();
static void ti_ndk_config_Global_NetworkClose();
static void ti_ndk_config_Global_NetworkIPAddr(IPN IPAddr, uint IfIdx, uint fAdd);
char *ti_ndk_config_Global_HostName    = "tisoc";

extern void llTimerTick();

/* Main Thread */
Void myStackThread(UArg arg0, UArg arg1)
{
    int rc;
    HANDLE hCfg;

    ti_sysbios_knl_Clock_Params clockParams;

    /* Create the NDK heart beat */
    ti_sysbios_knl_Clock_Params_init(&clockParams);
    clockParams.startFlag = TRUE;
    clockParams.period = 100;
    ti_sysbios_knl_Clock_create(&llTimerTick, clockParams.period, &clockParams, NULL);


    /* THIS MUST BE THE ABSOLUTE FIRST THING DONE IN AN APPLICATION!! */
    rc = NC_SystemOpen(NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT);
    if (rc) {
        xdc_runtime_System_abort("NC_SystemOpen Failed (%d)\n");
    }

    /* Create and build the system configuration from scratch. */
    hCfg = CfgNew();
    if (!hCfg) {
        xdc_runtime_System_printf("Unable to create configuration\n");
        goto main_exit;
    }

    /* add the Ip module configuration settings. */
    ti_ndk_config_ip_init(hCfg);

    /* add the Tcp module configuration settings. */
    ti_ndk_config_tcp_init(hCfg);

    /* add the configuration settings for NDK low priority tasks stack size. */
    rc = 1280;
    CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKLOW,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    /* add the configuration settings for NDK norm priority tasks stack size. */
    rc = 1024;
    CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKNORM,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    /* add the configuration settings for NDK high priority tasks stack size. */
    rc = 1024;
    CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKHIGH,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    /*
     *  Boot the system using this configuration
     *
     *  We keep booting until the function returns 0. This allows
     *  us to have a "reboot" command.
    */
    do
    {
        rc = NC_NetStart(hCfg, ti_ndk_config_Global_NetworkOpen,
                         ti_ndk_config_Global_NetworkClose,
                         ti_ndk_config_Global_NetworkIPAddr);

    } while( rc > 0 );

    /* Delete Configuration */
    CfgFree(hCfg);

    /* Close the OS */
main_exit:
    NC_SystemClose();
    xdc_runtime_System_flush();

}

/*
 *  ti_ndk_config_Global_NetworkOpen
 *
 *  This function is called after the configuration has booted
 */
static void ti_ndk_config_Global_NetworkOpen()
{
}

/*
 *  ti_ndk_config_Global_NetworkClose
 *
 *  This function is called when the network is shutting down,
 *  or when it no longer has any IP addresses assigned to it.
 */
static void ti_ndk_config_Global_NetworkClose()
{
}

/*
 *  ti_ndk_config_Global_NetworkIPAddr
 *
 *  This function is called whenever an IP address binding is
 *  added or removed from the system.
 */
static void ti_ndk_config_Global_NetworkIPAddr(IPN IPAddr, uint IfIdx, uint fAdd)
{
    IPN IPTmp;

    if (fAdd) {
        xdc_runtime_System_printf("Network Added: ");
    }
    else {
        xdc_runtime_System_printf("Network Removed: ");
    }

    // Print a message
    IPTmp = ntohl(IPAddr);
    xdc_runtime_System_printf("If-%d:%d.%d.%d.%d\n", IfIdx,
            (UINT8)(IPTmp>>24)&0xFF, (UINT8)(IPTmp>>16)&0xFF,
            (UINT8)(IPTmp>>8)&0xFF, (UINT8)IPTmp&0xFF);

    {
        extern Void netIPAddrHook();

        /* call user defined network IP address hook */
        netIPAddrHook(IPAddr, IfIdx, fAdd);
    }
    xdc_runtime_System_flush();
}
/*
 * Service Status Reports
 *
 * Function for reporting service status updates.
 */
static char *TaskName[]  = {"Telnet","HTTP","NAT","DHCPS","DHCPC","DNS"};
static char *ReportStr[] = {"","Running","Updated","Complete","Fault"};
static char *StatusStr[] = {"Disabled","Waiting","IPTerm","Failed","Enabled"};
Void ti_ndk_config_Global_serviceReport(uint Item, uint Status,
        uint Report, HANDLE h)
{
    xdc_runtime_System_printf("Service Status: %-9s: %-9s: %-9s: %03d\n",
            TaskName[Item-1], StatusStr[Status],
            ReportStr[Report/256], Report&0xFF);

    xdc_runtime_System_flush();
}



/*
 * ======== ti.ndk.config.Tcp TEMPLATE ========
 */


Void ti_ndk_config_tcp_init(HANDLE hCfg)
{
    {
        Int transmitBufSize = 1024;
        CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPTXBUF,
                CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&transmitBufSize, 0);
    }
    {
        Int receiveBufSize = 1024;
        CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXBUF,
                CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&receiveBufSize, 0);
    }
    {
        Int receiveBufLimit = 2048;
        CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXLIMIT,
                CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&receiveBufLimit, 0);
    }

}

/*
 * ======== ti.ndk.config.Ip TEMPLATE ========
 */

#include <ti/ndk/inc/netmain.h>
#include <ti/ndk/config/prototypes.h>

Void ti_ndk_config_ip_init(HANDLE hCfg)
{
    /* Add our global hostname to hCfg (to be claimed in all connected domains) */
    CfgAddEntry(hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_HOSTNAME, 0,
                 strlen(ti_ndk_config_Global_HostName),
                 (UINT8 *)ti_ndk_config_Global_HostName, 0);

    /* Use DHCP to obtain IP address on interface 1 */
    {
        CI_SERVICE_DHCPC dhcpc;
        UINT8 DHCP_OPTIONS[] =
                {
                DHCPOPT_SUBNET_MASK,
                };

        /* Specify DHCP Service on IF specified by "IfIdx" */
        bzero(&dhcpc, sizeof(dhcpc));
        dhcpc.cisargs.Mode   = 1;
        dhcpc.cisargs.IfIdx  = 1;
        dhcpc.cisargs.pCbSrv = &ti_ndk_config_Global_serviceReport;
        dhcpc.param.pOptions = DHCP_OPTIONS;
        dhcpc.param.len = 1;
        CfgAddEntry(hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_DHCPCLIENT, 0,
                sizeof(dhcpc), (UINT8 *)&dhcpc, 0);
    }
}
