/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2013-2014
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
* ============================================================================
Example to show the usage and performance of GE on KeyStone device.
VLAN, CPTS, PA, SA are not covered in this example.
This example can run on single Device with internal loopback.
With two Devices, external loopback or transfer between two Devices can be tested. 
  You should run this project on the second core of the second Device firstly, 
  and then the first core of the first Device
* =============================================================================
 *  Revision History
 *  ===============
 *  June 10, 2013 Brighton Feng   File Created
 *  October 20, 2014 Brighton Feng   Updated for K2E/K2L
 *  November 23, 2014 Brighton Feng   Support each port run in different mode
 * ============================================================================
 */
#include <stdio.h>
#include <string.h>

#include "K2_common.h"
#include "K2_GE_Init_drv.h"
#include "K2_Board_Init.h"
#include "GE_debug.h"
#include "GE_test.h"
#include "GE_Interrupts.h"
#include "GE_PktDMA_init.h"
#include "GE_packets_process.h"

//The port connection state for the test
GE_Port_Config ge_port_cfg[GE_NUM_ETHERNET_PORT]=
{
/*	ethernet_mode 	               port_connect           loopback_mode*/
#if 0
	{ETHERNET_AUTO_NEGOTIAT_SLAVE, GE_PORT_CABLE_CONNECT, ETHERNET_LOOPBACK_DISABLE}, //SGMII port 0
	{ETHERNET_AUTO_NEGOTIAT_SLAVE, GE_PORT_CABLE_CONNECT, ETHERNET_LOOPBACK_DISABLE}//SGMII port 1
#else 
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SERDES_INTERNAL_LOOPBACK}, //SGMII port 0
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SGMII_LOOPBACK}//SGMII port 1
#endif
#if (GE_NUM_ETHERNET_PORT>2)
	,{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SERDES_INTERNAL_LOOPBACK}, //SGMII port 2
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SGMII_LOOPBACK}//SGMII port 3
#endif
#if (GE_NUM_ETHERNET_PORT>4)
	,{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SERDES_INTERNAL_LOOPBACK}, //SGMII port 4
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SGMII_LOOPBACK}, //SGMII port 5
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_SGMII_LOOPBACK}, //SGMII port 6
	{ETHERNET_1000M_FULLDUPLEX, GE_PORT_NO_CONNECT, ETHERNET_MAC_LOOPBACK}//SGMII port 7
#endif
};

/*interval (in millisecond) between test iterations*/
#ifdef DEVICE_K2E
#define TEST_ITERATION_INTERVAL_MS 		17000
#else
#define TEST_ITERATION_INTERVAL_MS 		10000
#endif

#define TEST_PACKET_SIZE_MIN 			128
#define TEST_PACKET_SIZE_MAX 			8192

/*MAX number of packets transferred through one port per iteration*/
#define MAX_PACKETS_PER_ITERATION 		16
#define MIN_PACKETS_PER_ITERATION 		1

volatile Uint32 uiNumPackets= MIN_PACKETS_PER_ITERATION;
volatile Uint32 uiPacketBytes= TEST_PACKET_SIZE_MIN;

/*the defualt FDQ for TX of each port.
If there is no valid packet in the default FDQ, 
DDR_HOST_SIZE1_FDQ will be used instead.*/
unsigned long long Tx_FDQ[GE_NUM_ETHERNET_PORT]=
{
	DDR_HOST_SIZE1_FDQ,
	DDR_HOST_SIZE1_FDQ
#if (GE_NUM_ETHERNET_PORT>2)
	,DDR_HOST_SIZE1_FDQ,
	DDR_HOST_SIZE1_FDQ
#endif
#if (GE_NUM_ETHERNET_PORT>4)
	,DDR_HOST_SIZE1_FDQ,
	DDR_HOST_SIZE1_FDQ,
	DDR_HOST_SIZE1_FDQ,
	MSMC_RAM_HOST_SIZE1_FDQ
#endif
};

/*use long long type (8 bytes) for MAC address, but only lower 6 bytes are valid.
Please note the byte order, MAC address byte 5 is in the lowest bits.
Each MAC address corresponding to a Ethernet port*/
unsigned long long Source_MAC_address[GE_NUM_ETHERNET_PORT]=
{
	0x888888000001,
	0x888888000002
#if (GE_NUM_ETHERNET_PORT>2)
	,0x888888000003,
	0x888888000004
#endif
#if (GE_NUM_ETHERNET_PORT>4)
	,0x888888000005,
	0x888888000006,
	0x888888000007,
	0x888888000008
#endif
};
unsigned long long Dest_MAC_address[GE_NUM_ETHERNET_PORT]=
{
	0x888888000101,
	0x888888000102
#if (GE_NUM_ETHERNET_PORT>2)
	,0x888888000103,
	0x888888000104
#endif
#if (GE_NUM_ETHERNET_PORT>4)
	,0x888888000105,
	0x888888000106,
	0x888888000107,
	0x888888000108
#endif
};

//MMU memory ranges tables
MMU_Memory_Map_Range memory_ranges[]=
{
	{//MSMC RAM
    .uiVirtualAddress   = 0x0C000000,
    .ullPhysicalAddress = 0x0C000000,
    .uiByteCnt          = MSMC_RAM_SIZE_BYTES,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_X,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	},                     
	{//DDR3A               
    .uiVirtualAddress   = 0x80000000,
    .ullPhysicalAddress = 0x800000000ULL, 	
#if (DDR3A_SIZE_BYTES>0x80000000ULL)
    .uiByteCnt          = 0x80000000, 	
#else
    .uiByteCnt          = DDR3A_SIZE_BYTES, 	
#endif
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#if (2==CSL_DDR3_PER_CNT)
	,{//DDR3B
    .uiVirtualAddress   = 0x60000000,
    .ullPhysicalAddress = 0x60000000, 	
    .uiByteCnt          = 0x20000000,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_INNER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#endif
#ifdef CSL_OSR_DATA 	//for K2L only
	,{//OSR
    .uiVirtualAddress   = CSL_OSR_DATA,
    .ullPhysicalAddress = CSL_OSR_DATA,
    .uiByteCnt          = 0x00200000,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_INNER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#endif
};

MMU_Long_Format_Config mmu_cfg=
{
	.memory_map        = memory_ranges,
	.uiNumMemMapRanges = sizeof(memory_ranges)/sizeof(MMU_Memory_Map_Range),
	.ullpMMU3rdLevelTT = NULL, 	//No level 3 translation table
	.bAlignCheck       = TRUE,
	.tableCacheAttr    = MMU_TAB_ATTR_CACHE_WB_WA,
	.tableShareAttr	   = MMU_MEM_ATTR_INNER_SHARE,
};

Ethernet_Port_Config ethernet_port_cfg[GE_NUM_ETHERNET_PORT]; 

Ethernet_ALE_Config ale_cfg;

Ethernet_MDIO_Config mdio_cfg;

K2_GE_Config ge_cfg;

volatile Uint32 Timer_ISR_flag;

char * GE_mode_str[]=
{
	"auto negotiation (slave) ",
	"auto negotiation (master)",
	"forced 10M fullduplex    ",
	"forced 100M fullduplex   ",
	"forced 1000M fullduplex  ",
	"forced 10G fullduplex    "
};
char* GE_port_connection_str[]=
{
	"is not used    ",
	"no connection  ",
	"SGMII connected",
	"cable connected", 	
};
char* GE_port_loopback_str[]=
{
	"MAC loopback            ",
	"SGMII loopback          ",
	"SerDes internal loopback",
	"external line loopback  ",
	"SerDes external loopback",
	"no loopback             "
};

void print_test_setup()
{
	int i;
	for(i=0; i<GE_NUM_ETHERNET_PORT; i++)
	{
		printf("Ethernet port %d test setup: %s, %s, %s\n", i,
			GE_port_connection_str[ge_port_cfg[i].port_connect],
			GE_mode_str[ge_port_cfg[i].ethernet_mode],
			GE_port_loopback_str[ge_port_cfg[i].loopback_mode]
			);
	}
}

/*wait for link ready for the ports connected*/
void Wait_GE_link()
{
	int i;
	Uint32 uiStartCCNT;
	
	for(i=0; i<GE_NUM_ETHERNET_PORT; i++)
	{
		if(GE_PORT_CABLE_CONNECT == ge_port_cfg[i].port_connect)
		{
			uiStartCCNT= CP15_read_CCNT();
		    /* Wait until the PHY link up. */
			while(0==(gpMDIO_regs->LINK_REG&(1<<i)))
			{
				if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
				{
					printf("Wait for port %d PHY link...\n", i);
					uiStartCCNT= CP15_read_CCNT();
				}
			}
			/* Clear Interrupt events in MDIO*/
			gpMDIO_regs->LINK_INT_RAW_REG= 1<<i;

			print_GE_link_ability(i);
		}
		else if(GE_PORT_SGMII_CONNECT==ge_port_cfg[i].port_connect)
		{
			uiStartCCNT= CP15_read_CCNT();
			while(0==(gpSGMII_regs[i]->STATUS_REG
				&CSL_CPSGMII_STATUS_REG_LINK_MASK))
			{
				if(CCNT_count_cycle_from(uiStartCCNT)>0x3FFFFFFF)
				{
					printf("Wait for port %d SGMII link up...\n", i);
					uiStartCCNT= CP15_read_CCNT();
				}
			}
		}
	}		
}

/*For all tests, the ALE is setup to receive all packets.
For these tests, transmit will use direct packet (indpendent of ALE).*/
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
CSL_CPSW_5GF_ALE_UNICASTADDR_ENTRY ALE_entries[GE_NUM_ETHERNET_PORT];
#else 	//K2E or K2L
CSL_CPSW_ALE_UNICASTADDR_ENTRY ALE_entries[GE_NUM_ETHERNET_PORT];
#endif
//setup ALE entries for the destination MAC addresses
void ALE_Entries_Init(ALE_Test_Mode ALE_test_mode)
{
	int i;

	if(ALE_BYPASS==ALE_test_mode)
		return;

	for(i=0; i<GE_NUM_ETHERNET_PORT; i++)
	{
		ALE_entries[i].macAddress[0]= (_hill(Dest_MAC_address[i])>>8)&0xFF;
		ALE_entries[i].macAddress[1]= (_hill(Dest_MAC_address[i])>>0)&0xFF;
		ALE_entries[i].macAddress[2]= (_loll(Dest_MAC_address[i])>>24)&0xFF;
		ALE_entries[i].macAddress[3]= (_loll(Dest_MAC_address[i])>>16)&0xFF;
		ALE_entries[i].macAddress[4]= (_loll(Dest_MAC_address[i])>>8)&0xFF;
		ALE_entries[i].macAddress[5]= (_loll(Dest_MAC_address[i])>>0)&0xFF;

		ALE_entries[i].portNumber= 0; //all packect are received to host port (0)
	
		ALE_entries[i].ucastType    = ALE_UCASTTYPE_UCAST_NOAGE;  
		ALE_entries[i].secureEnable = 0;  
		ALE_entries[i].blockEnable  = 0;  
	}

	ale_cfg.unicastEntries= ALE_entries;
	ale_cfg.num_unicastEntries= GE_NUM_ETHERNET_PORT;
	ge_cfg.ale_cfg= &ale_cfg;
}

//TX packets on all ports
void GE_Tx()
{
	int i;
	Uint32 uiTX_port_mask= 0; 	//each bit for one port: 0->Don't TX; 1->TX
	
	for(i=0; i<GE_NUM_ETHERNET_PORT; i++)
	{
		if(GE_PORT_NOT_USED==ge_port_cfg[i].port_connect)
			continue;
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			continue;
		if((ETHERNET_EXTERNAL_LINE_LOOPBACK<=ge_port_cfg[i].loopback_mode)&&
			(0==(gpSGMII_regs[i]->STATUS_REG&CSL_CPSGMII_STATUS_REG_LINK_MASK)))
			continue;

		uiTX_port_mask |= (1<<i);
	}

	GE_transfer_packets(uiTX_port_mask, uiNumPackets, uiPacketBytes);
}

void SGMII_SerDes_external_loopback_setup()
{
	int i;
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	for(i=0; i<MIN(4, GE_NUM_ETHERNET_PORT); i++)
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			K2_SerDes_lane_external_loopback_enable(CSL_NETCP_SERDES_CFG_REGS, i);
#elif defined(DEVICE_K2E)
	for(i=0; i<MIN(4, GE_NUM_ETHERNET_PORT); i++)
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			K2_SerDes_lane_external_loopback_enable(CSL_NETCP_SERDES_0_CFG_REGS, i);

	for(i=4; i<GE_NUM_ETHERNET_PORT; i++)
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			K2_SerDes_lane_external_loopback_enable(CSL_NETCP_SERDES_1_CFG_REGS, i-4);
#else 	//K2L
	for(i=0; i<MIN(2,GE_NUM_ETHERNET_PORT); i++)
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			K2_SerDes_lane_external_loopback_enable(CSL_CSISC2_2_SERDES_CFG_REGS, i);

	for(i=2; i<GE_NUM_ETHERNET_PORT; i++)
		if(ETHERNET_SERDES_EXTERNAL_LOOPBACK==ge_port_cfg[i].loopback_mode)
			K2_SerDes_lane_external_loopback_enable(CSL_CSISC2_3_SERDES_CFG_REGS, i-2);
#endif
}

int main()
{
	int i;
	Bool bUseMDIO= FALSE;
	Timer64_Config tmrCfg;
	
	/*for two devices test, use CPU number as Device number,
	so, the program should be run on core 0 of Device0 and core 1 of Device1*/
	Uint32 uiDeviceNum= K2_Get_device_number();

	/*common initialization for internal modules in K2 device 
	enable GIC, memory protection interrupts, EDC for MSMC RAM */
	K2_common_device_init();
	/*initialize GIC interface for CPU, enable IRQ, FIQ, PMU*/
	K2_common_CPU_init();

	//enable exception handling
	KeyStone_Exception_cfg(TRUE);

	//make QMSS access to MSMC RAM sharable with ARM core
	K2_SMS_MPAX_init(PRIVID_QM_SECOND, MSMC_SHARE);

	//make PKTDMA access to MSMC RAM sharable with ARM core
	K2_SMS_MPAX_init(PRIVID_PKTDMA_SRIO_USB, MSMC_SHARE);

	//CPU speed= MAIN_PLL_REF_CLK_MHZ*MAIN_PLL_MULTIPLIER/MAIN_PLL_DIVISOR
	KeyStone_main_PLL_init(MAIN_PLL_REF_CLK_MHZ, MAIN_PLL_MULTIPLIER, MAIN_PLL_DIVISOR);

#ifndef DEVICE_K2E 	//K2E only has main PLL for both ARM and DSP cores
	//ARM core speed= ARM_PLL_REF_CLK_MHZ*ARM_PLL_MULTIPLIER/ARM_PLL_DIVISOR
	K2_ARM_PLL_init(ARM_PLL_REF_CLK_MHZ, ARM_PLL_MULTIPLIER, ARM_PLL_DIVISOR);
	//K2_ARM_PLL_init(125, 8, 1);
#endif

	//DDR configuration
	K2_DDR3A_config(NULL, NULL);
#if (2==CSL_DDR3_PER_CNT)
	//K2_DDR3B_config(NULL, NULL);
#endif

	/*MMU configure for ARM core*/
	MMU_long_format_init(&mmu_cfg);
	CP15_ICacheEnable();
	CP15_DCacheEnable();
	calc_cycle_measure_overhead();

   	//initialize GE port
	/*clear configuration structrue to make sure unused field is 0 (default value)*/
	memset(ethernet_port_cfg, 0, sizeof(ethernet_port_cfg));
	memset(&ale_cfg, 0, sizeof(ale_cfg));
	memset(&mdio_cfg, 0, sizeof(mdio_cfg));
	memset(&ge_cfg, 0, sizeof(ge_cfg));

	ge_cfg.serDesInputRefClock = SGMII_SERDES_REF_CLK;

	for(i=0; i<GE_NUM_ETHERNET_PORT; i++)
	{
		if(GE_PORT_NOT_USED==ge_port_cfg[i].port_connect)
			continue;

		if((GE_PORT_NO_CONNECT>=ge_port_cfg[i].port_connect)&&
			(ETHERNET_EXTERNAL_LINE_LOOPBACK<=ge_port_cfg[i].loopback_mode))
		{
			printf("Ethernet port %d can not do external test without external connection\n", i);
			ge_port_cfg[i].port_connect= GE_PORT_NOT_USED;
			ge_port_cfg[i].loopback_mode= ETHERNET_MAC_LOOPBACK;
			continue;
		}
		
		if((GE_PORT_NO_CONNECT>=ge_port_cfg[i].port_connect)&&
			(ETHERNET_AUTO_NEGOTIAT_MASTER>=ge_port_cfg[i].ethernet_mode))
		{
			printf("Ethernet port %d can not auto-negotiate without external connection\n", i);
			ge_port_cfg[i].port_connect= GE_PORT_NOT_USED;
			ge_port_cfg[i].ethernet_mode= ETHERNET_1000M_FULLDUPLEX;
			continue;
		}
		
		/*Serdes lanes are enabled for SGMII loopback or 
		when external connection is availible*/
		if((GE_PORT_SGMII_CONNECT==ge_port_cfg[i].port_connect)
			||(GE_PORT_CABLE_CONNECT==ge_port_cfg[i].port_connect)
			||(GE_TEST_SGMII_LOOPBACK<=ge_port_cfg[i].port_connect))
			ethernet_port_cfg[i].bSerdesLaneEnable = TRUE;

		ethernet_port_cfg[i].loopback_mode=ge_port_cfg[i].loopback_mode;
				
		ethernet_port_cfg[i].mode= ge_port_cfg[i].ethernet_mode;
		if((ge_port_cfg[i].ethernet_mode == ETHERNET_AUTO_NEGOTIAT_SLAVE)||
			(ge_port_cfg[i].ethernet_mode == ETHERNET_AUTO_NEGOTIAT_MASTER))
		{
			bUseMDIO= TRUE;
			
			/*for test with two Devices, if auto negotiation is used, 
			one should be master, and the other should be slave*/
			if(uiDeviceNum) 	//the second Device
			{
				//swap the master/slave for the second Device
				if(ge_port_cfg[i].ethernet_mode == ETHERNET_AUTO_NEGOTIAT_MASTER)
					ge_port_cfg[i].ethernet_mode = ETHERNET_AUTO_NEGOTIAT_SLAVE;
				else
					ge_port_cfg[i].ethernet_mode = ETHERNET_AUTO_NEGOTIAT_MASTER;
			}
		}	

		/*for external line loopback test with two Devices,
		set the SerDes of the second device for external loopback*/
		if(uiDeviceNum&& 	//the second Device
			(ge_port_cfg[i].loopback_mode== ETHERNET_EXTERNAL_LINE_LOOPBACK)) 	
		{
			ge_port_cfg[i].loopback_mode= ETHERNET_SERDES_EXTERNAL_LOOPBACK;
		}

		ethernet_port_cfg[i].CPPI_Src_ID= i+1;
		ethernet_port_cfg[i].TX_flow_control_enable= TRUE;
		ethernet_port_cfg[i].RX_flow_control_enable= TRUE;
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
		ethernet_port_cfg[i].RX_FIFO_Max_blocks= 8;
		ethernet_port_cfg[i].ethenet_port_statistics_enable= TRUE;
		ethernet_port_cfg[i].host_port_statistics_enable= TRUE;
#else
		ethernet_port_cfg[i].statistics_enable= TRUE;
#endif
		ethernet_port_cfg[i].flow_control_MAC_Address= Source_MAC_address[i];
		ethernet_port_cfg[i].prmiscuous_mode = ETHERNET_RX_CMF_EN;
		ge_cfg.ethernet_port_cfg[i]= &ethernet_port_cfg[i];
	}

	if(bUseMDIO)
	{
		//MDIO is enabled in negotiation mode
		ge_cfg.mdio_cfg= &mdio_cfg;
		
		/*The MDIO clock can operate at up to 2.5 MHz, 
		but typically operates at 1.0 MHz.*/
		mdio_cfg.clock_div= 350; 	/*350MHz/350= 1MHz*/
		mdio_cfg.link_INT0_PHY_select= MDIO_INT_SELECT_PHY_0;
		mdio_cfg.link_INT1_PHY_select= MDIO_INT_SELECT_PHY_1;
	
	}
	
	ge_cfg.RX_MAX_length= 9504;

	print_test_setup();

	ALE_Entries_Init(ALE_RECEIVE_ALL);

	K2_GE_Init(&ge_cfg);
	SGMII_SerDes_external_loopback_setup();
	
	GE_PktDMA_init();
	GE_Interrupts_Init();

	Wait_GE_link();

	//setup a timer to trigger packet transfer periodic
	tmrCfg.timer_num= 16+CP15_get_CPU_ID();
	tmrCfg.timerMode= TIMER_PERIODIC_PULSE;
	tmrCfg.period= (unsigned long long)TEST_ITERATION_INTERVAL_MS*gMain_Core_Speed_Hz/6000;
	//tmrCfg.period= 0x7FFFFFFFu/6;
	tmrCfg.pulseWidth= 3;
	Timer64_Init(&tmrCfg);

	//clear statistics
	GE_Test_init();

	/*for external line loopback test with two Devices*/
	if(uiDeviceNum&& 	//the second Device
		(ge_port_cfg[i].loopback_mode== ETHERNET_EXTERNAL_LINE_LOOPBACK)) 	
	{
		puts("Device1 ready for loopback test...");
	}
	else
	{
		do
		{
			GE_Tx(); 	//send packets
			Timer_ISR_flag=0;
			while(0==Timer_ISR_flag);	//wait for timer interrupt
		}while(uiNumPackets<=MAX_PACKETS_PER_ITERATION);
	}

	//clear TX parameters
	GE_Test_init();

#if 0
	puts("TX complete. Standby for RX...");
	while(1);
#else 	//for auto test
	puts("GE test complete.\n");
#endif
}

/*Timer ISR:
Bandwidth information is calculated and printed,
start the next test iteration*/
void Timer_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	//show the result information of the last test iteration
	print_GE_status_error();
	GE_Test_result();

	//prepare parameters for next test iteration
	uiPacketBytes *= 8;
	if(uiPacketBytes>TEST_PACKET_SIZE_MAX)
	{
		uiPacketBytes= TEST_PACKET_SIZE_MIN;
		uiNumPackets *= 4;
	}

	puts("");

	Timer_ISR_flag= 1;
}

