/*
 *            Copyright (c) 1998-2000 by NETsilicon Inc.
 *
 *  This software is copyrighted by and is the sole property of 
 *  NETsilicon.  All rights, title, ownership, or other interests
 *  in the software remain the property of NETsilicon.  This
 *  software may only be used in accordance with the corresponding
 *  license agreement.  Any unauthorized use, duplication, transmission,  
 *  distribution, or disclosure of this software is expressly forbidden.
 *
 *  This Copyright notice may not be removed or modified without prior
 *  written consent of NETsilicon.
 *
 *  NETsilicon, reserves the right to modify this software
 *  without notice.
 *
 *  NETsilicon
 *  411 Waverley Oaks Road                  USA 781.647.1234
 *  Suite 227                               http://www.netsilicon.com
 *  Waltham, MA 02452                       AmericaSales@netsilicon.com
 *
 *************************************************************************
 *
 *     Module Name: fsock_test.c
 *         Version: 1.00
 *   Original Date: 8/17/00
 *          Author: Eric Lowe
 *        Language: ARM C++ / Ver 2.11
 * Compile Options: 
 * Compile defines: 
 *       Libraries: 
 *    Link Options: 
 *
 *    Entry Points: 
 *
 * Description.
 * =======================================================================
 * This module contains the test code for FAST UDP API evaluation.  
 *                                                                        
 *                                                                        
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 * ECL 08/13/2000   based on TCP/IP BM test
 *
 *
 */

#include <string.h>
#include <stdio.h>
#include <tx_api.h>
#include <sockapi.h>
#include <fsock.h>

#define MAX_BUFFERS     10
#define MAX_SIZE        1470
#define NUM_OF_FDS      1
#define FS_PORT         7777
#define RCV_BUFFER_SIZE 16000

extern char    Data[];

static char  rcvUdpData[RCV_BUFFER_SIZE];

#ifdef REGAULR_UDP
#define fSockInit(a)
#define fSocket(a,b,c)          socket(a,b,c)
#define fBind(a,b,c)            bind(a,b,c)
#define fSendTo(a,b,c,d,e,f)    sendto(a,b,c,0,e,f)
#define fGetBuff(a,b)           (char *)malloc(b)
#define fSocketClose(a)         socketclose(a)
#endif

static void clean_up(int sock, char *str)
{
	printf("Fsock App: %s, errno = %d\n",str,getErrno());
	if (sock > 0)

	    fSocketClose(sock);

}

static int transmit_datagrams(int sock, struct sockaddr_in *fsin, char *rcvData)
{
    int             numDatagrams, result, szData;
    int		        totalBytes, totalTime,i, allocated, left_to_send;
    char            *t_data[MAX_BUFFERS ],*xdata, ch;
    char 	        *pkt_buf,*t_pkt_buf[MAX_BUFFERS];	
    unsigned long   start, stop;
   
    /*  setup data pointers */
    for (i=0 ; i < MAX_BUFFERS ; i++)
    { 
      int  hold_int = 0x30+ i;
      char hold = (char)hold_int;

      t_data[i] = strchr(Data,hold);
    }

    xdata = strstr(Data, "X");

    sscanf(rcvData, "%c %d %d", &ch, &szData, &numDatagrams);

#ifdef REGAULR_UDP
    for(i=0; i<MAX_BUFFERS; i++)
    {
        t_pkt_buf[i] = (char *)malloc(szData);
        if (t_pkt_buf[i] == NULL)
             break;

        fmemcpy(t_pkt_buf[i],t_data[i],8);
    }

    allocated = i;
#endif

    /*  Record the start time   */
    start = tx_time_get();

    left_to_send = numDatagrams - 1;

    while (left_to_send > 0)
    {
#ifndef REGAULR_UDP
        /*  Send Null commands  */

        int cnt = MAX_BUFFERS < left_to_send ? MAX_BUFFERS : left_to_send;
 
        for(i=0; i < cnt; i++)
        {
            t_pkt_buf[i] = fGetBuff(sock,szData);
            if (t_pkt_buf[i] == NULL)
	            break;

            fmemcpy(t_pkt_buf[i],t_data[i],8);
	    }
	    allocated = i;
#endif
	    if (allocated)
	    {
	        for(i=0; i < allocated; i++)
	        {
		        result = fSendTo(sock,t_pkt_buf[i],szData,1,fsin,sizeof(struct sockaddr_in));
		        if (result < 0)
		        {
		            printf("fSendTo: errno  %d\n", getErrno());
		            goto ret;
		        }
	        }
	    }
        left_to_send -= allocated;
    }
    /*  Send the eXit command  */

    pkt_buf = fGetBuff(sock,MAX_SIZE);
    if (pkt_buf)
    {
	    fmemcpy(pkt_buf,xdata,8);

	    result = fSendTo(sock,pkt_buf,MAX_SIZE,1,fsin,sizeof(struct sockaddr_in));
  
	    if (result < 0)
	    {
	        printf("fSendTo: errno %d\n", getErrno());
            goto ret;
	    }
    }
    else
    {
	    printf("Could not get last buffer\n");
        numDatagrams--;
    }
    
    /*  record the stop time    */
    stop = tx_time_get();

    totalBytes  = numDatagrams * szData;
    totalTime   = (int)(stop - start) * 10;

    if (totalTime)
    {
        printf ("Xmit: %d datagrams (%d bytes) in %d msecs [%d Kbps %d pps].\n", 
                numDatagrams, totalBytes, totalTime, totalBytes/totalTime, (numDatagrams * 1000)/totalTime);
    }
    else
    {
        printf ("Xmit: %d datagrams (%d bytes) in %d msecs.\n", numDatagrams, totalBytes, totalTime);
    }

ret:
    result = result < 0 ? -1 : 0;
    return result;
}



void fsockapp(ULONG thread_input)
{
    long                sock;               /* socket descriptor    */
    struct sockaddr_in  fsin;               /* Internet endpoint address	*/
    int                 addrlen,result,opt;
  	
     /*  open the datagram socket    */

   fSockInit(NUM_OF_FDS);
   sock = fSocket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0)
    {
        clean_up(sock,"Could not open a socket");
	    return;
    }

    memset((void *)&fsin, 0, sizeof(fsin));
    fsin.sin_family        = AF_INET;
    fsin.sin_addr.s_addr   = htonl(INADDR_ANY);
    fsin.sin_port          = htons(FS_PORT);


    result = fBind(sock, &fsin, sizeof(fsin));
    if (result < 0)
    {
		clean_up(sock,"Couldn't bind a socket");
		return;
    }

    opt = 1;
    result = setsockopt(sock, SOL_SOCKET, SO_NOCHKSUM, (char *)&opt, sizeof(int));
    if (result < 0)
    {
        printf("setsockopt SO_NOCHKSUM failure: errno: %d\n", getErrno());
        closesocket(sock);
        return;
    }

    printf("Fsock App Ready.\n");

    /*  Receive the data    */
    do 
    {
	addrlen = sizeof(fsin);
        result = recvfrom(sock, rcvUdpData, RCV_BUFFER_SIZE, 0, &fsin, &addrlen);
        if (result < 0)
        {
			clean_up(sock,"recv failure");
       		return;
        }

        printf("received[%d] UDP \'%c\' command.\n", result, rcvUdpData[0]);

        switch (rcvUdpData[0])
        {
        case 'T':
            result = transmit_datagrams(sock, &fsin, rcvUdpData);
            break;
        default:
            if (result<20)
            {
                rcvUdpData[result] = 0;
                printf ("UDP data was '%d %d %d'\n", rcvUdpData[0], rcvUdpData[1], rcvUdpData[2]);
            }
			result = 0;
            break;
        }
		if (result < 0)
			return;
    }
    while (1);
}



