/*
 *  Copyright 2007 by Texas Instruments Incorporated.
 *  All rights reserved. Property of Texas Instruments Incorporated.
 *  Restricted rights to use, duplicate or disclose this code are
 *  granted through contract.
 *
 *  @(#) TCP/IP_Network_Developers_Kit 1.93.00.09 08-16-2007 (ndk-c09)
 */
/*^M
 *  ======== client.c ========^M
 *^M
 *
 */

//--------------------------------------------------------------------------
// IP Stack Client Demo
//--------------------------------------------------------------------------
// Client.c
//
// Stack initialization functions
//
// Author: Michael A. Denio
// Copyright 2000, 2001 by Texas Instruments Inc.
//--------------------------------------------------------------------------

#include "fa_network.h"

NDK_NETWORK_INFO  net_info;
extern unsigned short BoardID;
// This callback function is called by the evaluation stack 5 min before the
// evaluation period times out.
void evalCallBack()
{
    printf("The Stack is going to shutdown in 5 min\n");
}

//
// Main Thread
//
//
int NetworkInit()
{
    int               rc;
    HANDLE            hCfg;
    CI_SERVICE_TELNET telnet;
    CI_SERVICE_HTTP   http;
	
	CSL_IntcGlobalEnableState state;
//	CSL_intcGlobalNmiEnable();
	// Enable all interrupts 
//	CSL_intcGlobalEnable(&state);	

	// intialize Network infomation

	if(BoardID == 0x40)
	{
		net_info.HostName = "NDKSPB_DSP1";
		net_info.LocalIPAddr = "192.168.0.51";   
		net_info.LocalIPMask = "255.255.255.0";
		net_info.GatewayIP = "192.168.0.1";  
		net_info.DomainName = "demo.net";
		net_info.DNSServer = "0.0.0.0";
	}
	else if(BoardID == 0x80)
	{
		net_info.HostName = "NDKSPB_DSP2";
		net_info.LocalIPAddr = "192.168.0.52";   
		net_info.LocalIPMask = "255.255.255.0";
		net_info.GatewayIP = "192.168.0.1";  
		net_info.DomainName = "demo.net";
		net_info.DNSServer = "0.0.0.0";
	}
	else if(BoardID == 0xC0)
	{
		net_info.HostName = "NDKSPB_DSP3";
		net_info.LocalIPAddr = "192.168.0.53";   
		net_info.LocalIPMask = "255.255.255.0";
		net_info.GatewayIP = "192.168.0.1";  
		net_info.DomainName = "demo.net";
		net_info.DNSServer = "0.0.0.0";
	}
	else if(BoardID == 0x100)
	{
		net_info.HostName = "NDKSPB_DSP4";
		net_info.LocalIPAddr = "192.168.0.54";   
		net_info.LocalIPMask = "255.255.255.0";
		net_info.GatewayIP = "192.168.0.1";  
		net_info.DomainName = "demo.net";
		net_info.DNSServer = "0.0.0.0";
	}
	else{
		net_info.HostName = "NDKSPB_DSP";
		net_info.LocalIPAddr = "192.168.0.60";   
		net_info.LocalIPMask = "255.255.255.0";
		net_info.GatewayIP = "192.168.0.1";  
		net_info.DomainName = "demo.net";
		net_info.DNSServer = "0.0.0.0";
	}

/*
	net_info.HostName = "NDKSPB_DSP";
	net_info.LocalIPAddr = "0.0.0.0";   
	net_info.LocalIPMask = "255.255.255.0";
	net_info.GatewayIP = "0.0.0.0";  
	net_info.DomainName = "demo.net";
	net_info.DNSServer = "0.0.0.0";
*/
    rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
    if( rc )
    {
        printf("NC_SystemOpen Failed (%d)\n",rc);
        for(;;);
    }

    // Print out our banner
    printf(VerStr);

    //
    // Create and build the system configuration from scratch.
    //

    // Create a new configuration
    hCfg = CfgNew();
    if( !hCfg )
    {
        printf("Unable to create configuration\n");
        goto main_exit;
    }

    // The evaluation version of TCP/IP Stack restricts usage of stack
    // to maximum of 24 Hours. If application wants to be notified 5 min
    // before the timeout, it can register a callback function by using
    // the following configuration code section.
    {
        void (*pFxn)() = &evalCallBack;
        CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_SYSINFO_EVALCALLBACK, 0,
                    sizeof(void(*)()), (UINT8*) &pFxn, 0 );
    }


    // We better validate the length of the supplied names
    if( strlen( net_info.DomainName ) >= CFG_DOMAIN_MAX ||
        strlen( net_info.HostName ) >= CFG_HOSTNAME_MAX )
    {
        printf("Names too long\n");
        goto main_exit;
    }

    // Add our global hostname to hCfg (to be claimed in all connected domains)
    CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_HOSTNAME, 0,
                 strlen(net_info.HostName), (UINT8 *)net_info.HostName, 0 );

    // If the IP address is specified, manually configure IP and Gateway
    if( inet_addr(net_info.LocalIPAddr) )
    {
        CI_IPNET NA;
        CI_ROUTE RT;
        IPN      IPTmp;

        // Setup manual IP address
        bzero( &NA, sizeof(NA) );
        NA.IPAddr  = inet_addr(net_info.LocalIPAddr);
        NA.IPMask  = inet_addr(net_info.LocalIPMask);
        strcpy( NA.Domain, net_info.DomainName );
        NA.NetType = 0;

        // Add the address to interface 1
        CfgAddEntry( hCfg, CFGTAG_IPNET, 1, 0,
                           sizeof(CI_IPNET), (UINT8 *)&NA, 0 );

        // Add the default gateway. Since it is the default, the
        // destination address and mask are both zero (we go ahead
        // and show the assignment for clarity).
        bzero( &RT, sizeof(RT) );
        RT.IPDestAddr = 0;
        RT.IPDestMask = 0;
        RT.IPGateAddr = inet_addr(net_info.GatewayIP);

        // Add the route
        CfgAddEntry( hCfg, CFGTAG_ROUTE, 0, 0,
                           sizeof(CI_ROUTE), (UINT8 *)&RT, 0 );

        // Manually add the DNS server when specified
        IPTmp = inet_addr(net_info.DNSServer);
        if( IPTmp )
            CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
                         0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
    }
    // Else we specify DHCP
    else
    {
        CI_SERVICE_DHCPC dhcpc;

        // Specify DHCP Service on IF-1
        bzero( &dhcpc, sizeof(dhcpc) );
        dhcpc.cisargs.Mode   = CIS_FLG_IFIDXVALID;
        dhcpc.cisargs.IfIdx  = 1;
        dhcpc.cisargs.pCbSrv = &ServiceReport;
        dhcpc.param.pOptions = DHCP_OPTIONS;
        dhcpc.param.len = 2;
        CfgAddEntry( hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_DHCPCLIENT, 0,
                     sizeof(dhcpc), (UINT8 *)&dhcpc, 0 );
    }
/*
    // Specify TELNET service for our Console example
    bzero( &telnet, sizeof(telnet) );
    telnet.cisargs.IPAddr = INADDR_ANY;
    telnet.cisargs.pCbSrv = &ServiceReport;
    telnet.param.MaxCon   = 2;
    telnet.param.Callback = &ConsoleOpen;
    CfgAddEntry( hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_TELNET, 0,
                 sizeof(telnet), (UINT8 *)&telnet, 0 );
*/
    // Create RAM based WEB files for HTTP
//    AddWebFiles();

    // HTTP Authentication
    {
        CI_ACCT CA;

        // Name our authentication group for HTTP (Max size = 31)
        // This is the authentication "realm" name returned by the HTTP
        // server when authentication is required on group 1.
        CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_SYSINFO_REALM1,
                     0, 30, (UINT8 *)"DSP_CLIENT_DEMO_AUTHENTICATE1", 0 );

        // Create a sample user account who is a member of realm 1.
        // The username and password are just "username" and "password"
        strcpy( CA.Username, "username" );
        strcpy( CA.Password, "password" );
        CA.Flags = CFG_ACCTFLG_CH1;  // Make a member of realm 1
        rc = CfgAddEntry( hCfg, CFGTAG_ACCT, CFGITEM_ACCT_REALM,
                          0, sizeof(CI_ACCT), (UINT8 *)&CA, 0 );
    }

    // Specify HTTP service
    bzero( &http, sizeof(http) );
    http.cisargs.IPAddr = INADDR_ANY;
    http.cisargs.pCbSrv = &ServiceReport;
    CfgAddEntry( hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_HTTP, 0,
                 sizeof(http), (UINT8 *)&http, 0 );

    //
    // Configure IPStack/OS Options
    //

    // We don't want to see debug messages less than WARNINGS
    rc = DBG_WARN;
    CfgAddEntry( hCfg, CFGTAG_OS, CFGITEM_OS_DBGPRINTLEVEL,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    //
    // This code sets up the TCP and UDP buffer sizes
    // (Note 8192 is actually the default. This code is here to
    // illustrate how the buffer and limit sizes are configured.)
    //

    // TCP Transmit buffer size
    rc = 8192;
    CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPTXBUF,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    // TCP Receive buffer size (copy mode)
    rc = 8192;
    CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXBUF,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    // TCP Receive limit (non-copy mode)
    rc = 8192;
    CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKTCPRXLIMIT,
                 CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );

    // UDP Receive limit
    rc = 8192;
    CfgAddEntry( hCfg, CFGTAG_IP, CFGITEM_IP_SOCKUDPRXLIMIT,
                 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, NetworkOpen, NetworkClose, NetworkIPAddr );
    } while( rc > 0 );

    // Free the WEB files
//    RemoveWebFiles();

    // Delete Configuration
    CfgFree( hCfg );

    // Close the OS
main_exit:
    NC_SystemClose();
    return(0);
}


//
// System Task Code [ Server Daemon Servers ]
//
static HANDLE hEcho=0;



//
// NetworkOpen
//
// This function is called after the configuration has booted
//
static void NetworkOpen()
{
    // Create our local servers

	hEcho = TaskCreate( FA_TCPServer, "FA_TCPServer", OS_TASKPRINORM, 0x1400, 0, 0, 0 );
}

//
// 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 NetworkClose()
{
    fdCloseSession( hEcho );
    // Kill any active console
//    ConsoleClose();
}

//
// NetworkIPAddr
//
// This function is called whenever an IP address binding is
// added or removed from the system.
//
static void NetworkIPAddr( IPN IPAddr, uint IfIdx, uint fAdd )
{
    static uint fAddGroups = 0;
    IPN IPTmp;
/*
    if( fAdd )
        printf("Network Added: ");
    else
        printf("Network Removed: ");
*/
    // Print a message
    IPTmp = ntohl( IPAddr );
    printf("If-%d:%d.%d.%d.%d\n", IfIdx,
            (UINT8)(IPTmp>>24)&0xFF, (UINT8)(IPTmp>>16)&0xFF,
            (UINT8)(IPTmp>>8)&0xFF, (UINT8)IPTmp&0xFF );

    // This is a good time to join any multicast group we require
    if( fAdd && !fAddGroups )
    {
        fAddGroups = 1;
//              IGMPJoinHostGroup( inet_addr("224.1.2.3"), IfIdx );
    }
}

//
// DHCP_reset()
//
// Code to reset DHCP client by removing it from the active config,
// and then reinstalling it.
//
// Called with:
// IfIdx    set to the interface (1-n) that is using DHCP.
// fOwnTask set when called on a new task thread (via TaskCreate()).
//
void DHCP_reset( uint IfIdx, uint fOwnTask )
{
    CI_SERVICE_DHCPC dhcpc;
    HANDLE h;
    int    rc,tmp;
    uint   idx;

    // If we were called from a newly created task thread, allow
    // the entity that created us to complete
    if( fOwnTask )
        TaskSleep(500);

    // Find DHCP on the supplied interface
    for(idx=1; ; idx++)
    {
        // Find a DHCP entry
        rc = CfgGetEntry( 0, CFGTAG_SERVICE, CFGITEM_SERVICE_DHCPCLIENT,
                          idx, &h );
        if( rc != 1 )
            goto RESET_EXIT;

        // Get DHCP entry data
        tmp = sizeof(dhcpc);
        rc = CfgEntryGetData( h, &tmp, (UINT8 *)&dhcpc );

        // If not the right entry, continue
        if( (rc<=0) || dhcpc.cisargs.IfIdx != IfIdx )
        {
            CfgEntryDeRef(h);
            h = 0;
            continue;
        }

        // This is the entry we want!

        // Remove the current DHCP service
        CfgRemoveEntry( 0, h );

        // Specify DHCP Service on specified IF
        bzero( &dhcpc, sizeof(dhcpc) );
        dhcpc.cisargs.Mode   = CIS_FLG_IFIDXVALID;
        dhcpc.cisargs.IfIdx  = IfIdx;
        dhcpc.cisargs.pCbSrv = &ServiceReport;
        CfgAddEntry( 0, CFGTAG_SERVICE, CFGITEM_SERVICE_DHCPCLIENT, 0,
                     sizeof(dhcpc), (UINT8 *)&dhcpc, 0 );
        break;
    }

RESET_EXIT:
    // If we are a function, return, otherwise, call TaskExit()
    if( fOwnTask )
        TaskExit();
}


void CheckDHCPOptions();

//
// Service Status Reports
//
// Here's a quick example of using 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" };
static void ServiceReport( uint Item, uint Status, uint Report, HANDLE h )
{
	char *DNSServer = "0.0.0.0";
 //   printf( "Service Status: %-9s: %-9s: %-9s: %03d\n",
 //       TaskName[Item-1], StatusStr[Status],
 //           ReportStr[Report/256], Report&0xFF );

    //
    // Example of adding to the DHCP configuration space
    //
    // When using the DHCP client, the client has full control over access
    // to the first 256 entries in the CFGTAG_SYSINFO space.
    //
    // Note that the DHCP client will erase all CFGTAG_SYSINFO tags except
    // CFGITEM_DHCP_HOSTNAME. If the application needs to keep manual
    // entries in the DHCP tag range, then the code to maintain them should
    // be placed here.
    //
    // Here, we want to manually add a DNS server to the configuration, but
    // we can only do it once DHCP has finished its programming.
    //
    if( Item == CFGITEM_SERVICE_DHCPCLIENT &&
        Status == CIS_SRV_STATUS_ENABLED &&
        (Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
         Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW)) )
    {
        IPN IPTmp;

        // Manually add the DNS server when specified
        IPTmp = inet_addr(DNSServer);
        if( IPTmp )
            CfgAddEntry( 0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
                         0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
#if 0        
        // We can now check on what the DHCP server supplied in 
        // response to our DHCP option tags.
        CheckDHCPOptions();   
#endif
                     
    }

    // Reset DHCP client service on failure
    if( Item==CFGITEM_SERVICE_DHCPCLIENT && (Report&~0xFF)==NETTOOLS_STAT_FAULT )
    {
        CI_SERVICE_DHCPC dhcpc;
        int tmp;

        // Get DHCP entry data (for index to pass to DHCP_reset).
        tmp = sizeof(dhcpc);
        CfgEntryGetData( h, &tmp, (UINT8 *)&dhcpc );

        // Create the task to reset DHCP on its designated IF
        // We must use TaskCreate instead of just calling the function as
        // we are in a callback function.
        TaskCreate( DHCP_reset, "DHCPreset", OS_TASKPRINORM, 0x1000,
                    dhcpc.cisargs.IfIdx, 1, 0 );
    }
}

void CheckDHCPOptions()
{
    char IPString[16];
    IPN  IPAddr;
    int  i, rc;

    // Now scan for DHCPOPT_SERVER_IDENTIFIER via configuration
//    printf("\nDHCP Server ID:\n");
    for(i=1;;i++)
    {
        // Try and get a DNS server
        rc = CfgGetImmediate( 0, CFGTAG_SYSINFO, DHCPOPT_SERVER_IDENTIFIER,
                              i, 4, (UINT8 *)&IPAddr );
        if( rc != 4 )
            break;

        // We got something

        // Convert IP to a string:
        NtIPN2Str( IPAddr, IPString );
//        printf("DHCP Server %d = '%s'\n", i, IPString);
    }
/*
    if( i==1 )
        printf("None\n\n");
    else
        printf("\n");
*/
    // Now scan for DHCPOPT_ROUTER via the configuration
//    printf("Router Information:\n");
    for(i=1;;i++)
    {
        // Try and get a DNS server
        rc = CfgGetImmediate( 0, CFGTAG_SYSINFO, DHCPOPT_ROUTER,
                              i, 4, (UINT8 *)&IPAddr );
        if( rc != 4 )
            break;

        // We got something

        // Convert IP to a string:
        NtIPN2Str( IPAddr, IPString );
//        printf("Router %d = '%s'\n", i, IPString);
    }
/*
    if( i==1 )
        printf("None\n\n");
    else
        printf("\n");
*/
}
