
/*
 * Copyright (c) 2004-2005 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: dagimademo.c 11067 2009-04-22 01:49:32Z wilson.zhu $
 */
/*	Author : Jason Smith <jason.smith@endace.com> */

#include <stdio.h>
#ifndef _WIN32
#include <fcntl.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include <netinet/in.h>
#else /* _WIN32 */

#include <signal.h>

// #include <getopt.h>
#include <timeofday.h>
// #include <regex.h>
extern char *optarg;
extern int optind;
extern int opterr;

#endif /* _WIN32 */

#include "dagapi.h"
#include "dagutil.h"
#include "dagclarg.h"
#include "dag_ima.h"
#include "dagema.h"
#include "dagswid.h"
#include "dag37t_api.h"

#ifndef _WIN32
#define DEFAULT_DEVICE	"/dev/dag0"     /* default device                    */
#else /* _WIN32 */
#define DEFAULT_DEVICE	"dag0"  /* default device                    */
#endif /* _WIN32 */


static const char *const kDagmapCvsHeader __attribute__ ((unused)) = "$Id: dagimademo.c 11067 2009-04-22 01:49:32Z wilson.zhu $";
static const char *const kRevisionString = "$Revision: 11067 $";

/* Command line configuration */
typedef struct
{
	int argc;
	char **argv;
	char *device;			/* Dag device */
	uint32_t key;			/* Write enable key */
	char *software_id;		/* String to write to software ID */
	int start_xscale;		/* Reset and start xscale */
} t_config;

t_config config;                /* Command line configuration */
int verbose = 0;                /* verbose output */
unsigned char soft_id[D37T_SOFTWARE_ID_SIZE+1];
static 	char dagname_buf[DAGNAME_BUFSIZE] = DEFAULT_DEVICE;
static 	char dagname[DAGNAME_BUFSIZE] = DEFAULT_DEVICE;

/* ---------------------------------------------------------*/
/*	Pretty Print										*/

void
pretty_ifc_mode( ifc_mode_t ifc_mode )
{
	switch( ifc_mode )
	{
		case IFC_ERROR: printf( "IFC_ERROR\n" ); break;
		case IFC_AUTO: printf( "IFC_AUTO\n" ); break;
		case IFC_AUTOBEST: printf( "IFC_AUTOBEST\n" ); break;
		case IFC_MANUAL: printf( "IFC_MANUAL\n" ); break;
		case IFC_FREEFLOW: printf( "IFC_FREEFLOW\n" ); break;
		case IFC_GROUP: printf( "IFC_GROUP\n" ); break;
	}
}

static char*
pretty_group_state( state_group_t state )
{
	switch( state )
	{	case GRP_INVALID: return "GRP_INVALID";
		case GRP_NOT_CONFIGURED: return "GRP_START_UP";
		case GRP_START_UP: return "GRP_START_UP";
		case GRP_START_UP_ACK: return "GRP_START_UP_ACK";
		case GRP_CONFIG_ABORTED_UNSUPPORTED_M: return "GRP_CONFIG_ABORTED_UNSUPPORTED_M";
		case GRP_CONFIG_ABORTED_INCOMPAT_SYM: return "GRP_CONFIG_ABORTED_INCOMPAT_SYM";
		case GRP_CONFIG_ABORTED_UNSUPPORTED_VERSION: return "GRP_CONFIG_ABORTED_ABORTED_1";
		case GRP_CONFIG_ABORTED_ABORTED_2: return "GRP_CONFIG_ABORTED_ABORTED_2";
		case GRP_CONFIG_ABORTED_ABORTED_3: return "GRP_INSUFFICIENT_LINKS";
		case GRP_INSUFFICIENT_LINKS : return "GRP_INSUFFICIENT_LINKS";
		case GRP_BLOCKED: return "GRP_BLOCKED";
		case GRP_OPERATIONAL: return "GRP_OPERATIONAL";
		default : return "UNKNOWN";
	}
}

char*
atmrx_print_state( atmrx_mode_t atmrxmode )
{
	switch( atmrxmode )
	{	case ATMRX_AUTO: return "ATMRX_INVALID";
		case ATMRX_AUTOBEST: return "ATMRX_AUTOBEST";
		case ATMRX_MANUAL: return "ATMRX_MANUAL";
		case ATMRX_FREEFLOW: return "ATMRX_FREEFLOW";
	}
	
	return "INVALID";
}

char* 
iesm_print_state( ifsm_state_t ifsm_state )
{
	switch( ifsm_state )
	{	case IESM_WORKING: return "IESM_WORKING";
		case IESM_OIF: return "IESM_OIF";
		case IESM_LIF: return "IESM_LIF";
		default: return "Unrecognized state";
	}
}

char* 
ifsm_print_state( ifsm_state_t ifsm_state )
{
	switch( ifsm_state )
	{	case IFSM_HUNT: return "IFSM_HUNT";
		case IFSM_PRESYNC: return "IFSM_PRESYNC";
		case IFSM_SYNC: return "IFSM_SYNC";
		default: return "Unrecognized state";
	}
}

char* 
rxlsm_print_state( state_rx_t state_rx )
{
	switch( state_rx )
	{	case RX_INVALID: return "RX_INVALID";
		case RX_DELETED: return "RX_DELETED";
		case RX_UNASSIGNED: return "RX_UNASSIGNED";
		case RX_UNUSABLE_1: //return "RX_UNUSABLE_1";
		case RX_UNUSABLE_2: //return "RX_UNUSABLE_2";
		case RX_UNUSABLE_3: //return "RX_UNUSABLE_3";
		case RX_UNUSABLE_4: //return "RX_UNUSABLE_4";
		case RX_UNUSABLE_5: return "RX_UNUSABLE";
		case RX_USABLE: return "RX_USABLE";
		case RX_ACTIVE: return "RX_ACTIVE";
		case RX_BLOCKING: return "RX_BLOCKING";
		default:
			dagutil_error( "di_rxlsm_print_state : invalid state: %d\n", state_rx );
			return NULL;
	}
	
	return NULL;
}

char* 
txlsm_print_state( state_tx_t state_tx )
{
	switch( state_tx )
	{	case TX_INVALID: return "TX_INVALID";
		case TX_UNASSIGNED: return "TX_UNASSIGNED";
		case TX_DELETED: return "TX_DELETED";
		case TX_UNUSABLE_1: // return "TX_UNUSABLE_1";
		case TX_UNUSABLE_2: // return "TX_UNUSABLE_2";
		case TX_UNUSABLE_3: // return "TX_UNUSABLE_3";
		case TX_UNUSABLE_4: // return "TX_UNUSABLE_4";
		case TX_UNUSABLE_5: return "TX_UNUSABLE";
		case TX_USABLE: return "TX_USABLE";
		case TX_ACTIVE: return "TX_ACTIVE";
		default:
			dagutil_error( "di_txlsm_print_state : invalid state: %d\n", state_tx );
			return NULL;
	}
	
	return NULL;
}

/* ---------------------------------------------------------*/

enum
{
	CLA_DEVICE,
	CLA_HELP,
	CLA_VERBOSE,
	CLA_VERSION,
	CLA_RST
};

static void
print_version(void)
{
	printf("dagimademo (DAG %s) %s\n", kDagReleaseVersion, kRevisionString);
}

/* ---------------------------------------------------------*/

static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("Usage: dagimademo [options]\n");
	dagclarg_display_usage(clarg, stdout);
}

/*	
	Read the command line options and fill in the config info.	
	Returns a config structure popluated with command line options
*/
int hg_scanInputs (t_config * config, int argc, char **argv)
{
	ClArgPtr clarg = NULL;
	int result;
	int argindex;
	int code;
	FILE *errorfile = NULL;
	int dagstream;
	
	config->argc = argc;
	config->argv = argv;
	config->device = DEFAULT_DEVICE;
	config->key = 0;
	config->software_id = NULL;
	config->start_xscale = 0;
	
	/* Set up the command line options. */
	clarg = dagclarg_init( argc, (const char* const *) argv );
	
	dagclarg_add( clarg, "display help (this page).", "--help", 'h', CLA_HELP );
	dagclarg_add_long_option( clarg, CLA_HELP, "--usage" );
	dagclarg_add_short_option( clarg, CLA_HELP, '?' );
	dagclarg_add( clarg, "display version information.", "--version", 'V', CLA_VERSION );
	dagclarg_add( clarg, "increase verbosity.", "--verbose", 'v', CLA_VERBOSE );
	dagclarg_add_string( clarg, "DAG device to use.  Default: dag0.", "--device", 'd', "device", dagname_buf, DAGNAME_BUFSIZE, CLA_DEVICE );
	dagclarg_add( clarg, "reset and start the xscale", "--rst", 'x', CLA_RST );

	/* Parse the command line options. */
	result = dagclarg_parse( clarg, errorfile, &argindex, &code );
	while( 1 == result )
	{
		switch (code)
		{
			case CLA_DEVICE:
				if ( -1 == dag_parse_name( dagname_buf, dagname, DAGNAME_BUFSIZE, &dagstream ))
				{
					dagutil_panic( "dag_parse_name(%s): %s\n", dagname_buf, strerror( errno ));
				}
				config->device = dagname;
				dagutil_verbose_level( 2, "device=%s\n", config->device );
				break;

			case CLA_HELP:
				print_usage(clarg);
				exit(EXIT_SUCCESS);

			case CLA_VERBOSE:
				dagutil_inc_verbosity();
				errorfile = stderr;
				break;

			case CLA_VERSION:
				print_version();
				exit(EXIT_SUCCESS);

			case CLA_RST:
				config->start_xscale = 1;
				break;

			default:
			/* Unknown option. */
				dagutil_error("unknown option %s\n", argv[argindex]); 
				print_usage(clarg);
				return EXIT_FAILURE;
		}

		result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	}

	if( -1 == result )
	{
		if( argindex < argc )
		{
			dagutil_error("while processing option %s\n", argv[argindex]);
		}
		dagclarg_display_usage(clarg, stderr);
		return EXIT_FAILURE;
	}
	
	return 0;
}

int main( int argc, char **argv )
{
	int dagfd;
	uint32_t i, y, x;
	uint32_t grouphandle = DEF_GROUPID;
	ifc_mode_t ifc_mode;
	atmrx_mode_t atmrx_mode;
	iesm_state_t iesm_state;
	ifsm_state_t ifsm_state;
	state_rx_t state_rx;
	state_tx_t state_tx;
	uint32_t ifcmask;
	state_group_t group_state;
	uint32_t numgroups;
	dag_group_settings_t group_settings;
	dag_um_icpctrl um_icpctrl;
	dag_link_fe_alarms_t fealarms;
	dag_link_ne_alarms_t nealarms;
	dag_link_ICP_statistics_t linkstats;
	dag_link_ne_defect_statistics_t nedefects;
	dag_link_fe_defect_statistics_t fedefects;
	uint32_t groupmask;
	uint32_t version, type;
	uint32_t linkidmask;
	int linkID = DEFAULT_LINK_ID;
	int temperature;
	int OIFtoggle = 0;
	int addr;
	uint32_t wCount = 0;
	int res = 0;
	int numlinks = 0;
	
		
	memset( &config, 0, sizeof ( config ));
	hg_scanInputs (&config, argc, argv);
	
	printf("\nEndace DAG3.7T IMA Monitor Configuration demo\n");
	printf("(c) 2006 Endace Technology Ltd.\n\n");

	/*	Open a file descriptor for the DAG card. */
	if(( dagfd = dag_open( config.device )) < 0 )
	{
		fprintf (stderr, "dag_open %s: %s\n", config.device, strerror (errno));
		exit( 0 );
	}
	
	/*	Configure the ERF Mux so that ERF packets are first send to the XScale,
		and then to the Host. */
	if( dag_set_mux( dagfd, DA_DATA_TO_LINE, DA_DATA_TO_IOP, DA_DATA_TO_HOST ))
	{
		fprintf(stderr, "dag_set_mux failed\n");
		exit( 0 );
	}
	
	/* Restart the xScale if specified by the user */
	if( config.start_xscale )
	{
		printf( "Restarting XScale ... please wait this may take up to 60 seconds to complete\n" );
		if( dagema_reset_processor( dagfd, 0 ) < 0 )
		{
			printf( "Failed to reset XScale (error code %d)\n", dagema_get_last_error());
			exit( 0 );
		}
		
		printf( "Restarted the XScale\n" );
	}
	
	/* Open a connection to the EMA */
	if(( res = dagema_open_conn( dagfd )) < 0 )
	{
		printf("Failed to connect to board (error code %d)\n", dagema_get_last_error());
		exit( 0 );
	}
	
	res = d37t_read_software_id(dagfd, D37T_SOFTWARE_ID_SIZE, soft_id);
	if( res )
	{
		printf("d37t_read_software_id() failed res=%d\n", res);
	}
	else
	{
		/* Replace any non-printable characters with spaces for this demo */
		for( addr=0; addr<D37T_SOFTWARE_ID_SIZE; addr++ )
		{
			if (soft_id[addr])
			{
				if (!isgraph(soft_id[addr])) 
					soft_id[addr] = ' ';
			}
		}
		
		/* Null terminate it just in case */
		soft_id[D37T_SOFTWARE_ID_SIZE] = 0;
		
		printf("Software ID: \"%s\"\n", soft_id);
	}
	
	res = d37t_read_version(dagfd, &version, &type);
	if (res)
	{
		printf("d37t_read_version() failed res=%d\n", res);
	}
	else
	{
		printf("version = %u type = %u\n", version, type);
	}
	
	
	res = d37t_read_temperature(dagfd, 0, &temperature);
	if (res)
	{
		printf("d37t_read_temperature() failed, res=%d\n", res);
	}
	else
	{
		printf("Temperature: %d Degrees Celcius\n", temperature);
	}
	
	/* --------------------------------------------------------- */
	/* Query the status of the ATM receiver */
	atmrx_mode = dagima_atmrx_get_mode( dagfd );
	
	printf( "The ATM receiver mode is: %s\n", atmrx_print_state( atmrx_mode ));
	
	/* --------------------------------------------------------- */
	/*	Adding a group, this will depend on the local environment. */
	
// 	printf("\nAdd a group with physical interfaces 1 & 2\n");
// 	res = dagima_add_rx_group( dagfd, 0x00000003 );
// 	
// 	/*	As this is the first group added, it will have a handle of 0,
// 		however this assumption should not be made in production 
// 		code. */
// 	if( res < 0 )
// 	{
// 		printf( "Adding of group failed!\n" );
// 	}
// 	
// 	/*	Sleep for a bit, to see if some packets come through. */
// 	sleep( 2 );
// 	
// 	/*	Remove all the groups by calling dagima_atmrx_reset */
// 	printf("\nRemove the group by calling dagima_remove_group" );
// 	res = dagima_remove_group( dagfd, 0 );
	
	/* --------------------------------------------------------- */	
	/*	From now on, we'll autobest configure and let it setup
		the groups. 
	*/
	printf( "\nSet the IMA to AUTOBEST mode\n");
	dagima_atmrx_set_mode( dagfd, IFC_AUTOBEST );
	
	printf( "\nSleep for a little while ( 3 sec ) to let the groups configure themselves\n" );
	sleep( 5 );
	
	/* --------------------------------------------------------- */
	/* Query the status of the IFC's */
	for( i = 0; i < 16; i++ )
	{
		ifc_mode = dagima_ifc_get_mode( dagfd, i );
		
		if( ifc_mode < 0 )
		{
			printf( "Failed to get IFC mode for IFC: %d\n", i );
		}
		
		printf( "Mode of ifc %u is ", i );
		pretty_ifc_mode( ifc_mode );
	}
	
	/* --------------------------------------------------------- */
	/*	Remove the group(s), autobest will add it back in		 */
	numgroups = dagima_avail_groups( dagfd, &groupmask );
	if( numgroups >= 0 )
	{
		printf( "Available group mask %#x\n", groupmask );
		
		for( y = 0; y < MAX_GROUPS; y++ )
		{
			if(( groupmask >> y ) & 1 )
			{
				printf( "Attempting to remove GRP Handle: %d\n", y );
				
				if( dagima_remove_group( dagfd, y ) < 0 )
				{
					printf( "Failed to remove GRP Handle: %d\n", y );
				}
				else
				{
					printf( "Successfully removed GRP Handle: %d\n", y );
				}
				
				break;
			}
		}
	}
	
	printf( "Sleeping for a bit to let AUTOBEST add the group back in\n" );
	sleep( 2 );
	
	/* --------------------------------------------------------- */
	/* Query the number of available groups */
	numgroups = dagima_avail_groups( dagfd, &groupmask );
	if( numgroups <= 0 )
	{
		printf( "\nNo available groups\n" );
	}
	else
	{
		printf( "\nThere are %u groups available, group mask: 0x%08x\n", 
				numgroups, groupmask );
		
		for( y = 0; y < MAX_GROUPS; y++ )
		{
			if(( groupmask >> y ) & 1 )
			{
				grouphandle = y;
				
				/* --------------------------------------------------------- */
				/*	Retrieve the group settings, supply the group handle, the 
					group settings consist of the following: the handle, 
					number of interfaces, and the frame length. */
				if( dagima_group_get_settings( dagfd, grouphandle, &group_settings ) < 0 )
				{
					printf( "Failed to retrieve group settings for GRP Handle: %d\n", grouphandle );
				}
				
				printf( "\nGRP Handle: %d, IFC count: %d, Frame Len: %d\n",
							grouphandle, group_settings.num_ifcs, group_settings.frame_len );
				
				/* --------------------------------------------------------- */
				/*	Extract the group IFC's mask, indicates which groups are
					part of the IMA.
				*/
				if( dagima_group_get_ifcmask( dagfd, grouphandle, &ifcmask ) < 0 )
				{
					printf( "Failed to retrieve IFC mask for GRP Handle: %d\n", grouphandle );
				}
				
				printf("GRP Handle: %d, IFC mask: 0x%08x\n", grouphandle, ifcmask );
				
				if( dagima_group_get_state( dagfd, grouphandle, &group_state ) < 0 )
				{
					printf( "Failed to retrieve state for GRP Handle: %d\n", grouphandle );
				}
				
				printf( "GRP Handle: %d, state: %s\n", grouphandle, pretty_group_state( group_state ));
				
				/* --------------------------------------------------------- */
				/*	Have a look at some of the link internals. 				*/
				numlinks = dagima_group_get_rx_linkidmask( dagfd, grouphandle, &linkidmask );
						
				if( numlinks == 0 )
				{
					printf( "\nGRP Handle: %d, No available links\n", grouphandle );
				}
				
				printf( "GRP Handle: %d, links: %d, link mask: 0x%08x\n",
						grouphandle, numlinks, linkidmask );
				
				/*	This will return a link ID to the last link. */
				for( x = 0; x < MAX_INTERFACE; 
					 x++ )
				{
					if(( linkidmask >> x ) & 1 )
					{
						linkID = x;
						
						if(( OIFtoggle = dagima_link_get_OIF_toggle( dagfd, grouphandle, linkID )) < 0 )
						{
							printf( "Failed to get OIF toggle, GRP Handle %d, Link ID: %d\n",
									grouphandle, linkID );
						}
						else
						{
							printf( "\nGRP Handle: %d, Link ID: %d, OIF toggle: %d\n", 
										grouphandle, linkID, OIFtoggle );
						}
						
						if( dagima_link_get_ifsm_state( dagfd, grouphandle, linkID, &ifsm_state ) < 0 )
						{
							printf( "Failed to get IFSM state, GRP Handle %d, Link ID: %d\n", 
									grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, IFSM state: %s\n", 
									grouphandle, linkID, ifsm_print_state( ifsm_state ));
						}
						
						if( dagima_link_get_iesm_state( dagfd, grouphandle, linkID, &iesm_state ) < 0 )
						{
							printf( "Failed to get IESM state, GRP Handle: %d, Link ID: %d\n", 
									grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, IESM state: %s\n", 
									grouphandle, linkID, iesm_print_state( iesm_state ));
						}
						
						if( dagima_link_get_rxlsm_state( dagfd, grouphandle, linkID, &state_rx ) < 0 )
						{
							printf( "Failed to get Rx LSM state, GRP Handle: %d, Link ID: %d\n", 
									grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, Rx LSM state: %s\n", 
									grouphandle, linkID, rxlsm_print_state( state_rx ));
						}
						
						if( dagima_link_get_txlsm_state( dagfd, grouphandle, linkID, &state_tx ) < 0 )
						{
							printf( "Failed to get Tx LSM state, GRP Handle: %d, Link ID: %d\n",
									grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, Tx LSM state: %s\n", 
									grouphandle, linkID, txlsm_print_state( state_tx ));
						}
						
						if( dagima_link_get_ne_alarms( dagfd, grouphandle, linkID, &nealarms ) < 0 )
						{
							printf( "GRP Handle: %d, Link ID: %d, Failed to get NE alarms\n", grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, FE ALARM LIF: %d\n", grouphandle, linkID, nealarms.LIF );
							printf( "GRP Handle: %d, Link ID: %d, FE ALARM LODS: %d\n", grouphandle, linkID, nealarms.LODS );
							printf( "GRP Handle: %d, Link ID: %d, FE ALARM RFI_IMA: %d\n", grouphandle, linkID, nealarms.RFI_IMA );
						}
						
						if( dagima_link_get_fe_alarms( dagfd, grouphandle, linkID, &fealarms ) < 0 )
						{
							printf( "GRP Handle: %d, Link ID: %d, Failed to get FE alarms\n", grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, NE ALARM Tx Unusable FE: %d\n", grouphandle, linkID, fealarms.tx_unusable_FE );
							printf( "GRP Handle: %d, Link ID: %d, NE ALARM Rx Unusable FE: %d\n", grouphandle, linkID, fealarms.rx_unusable_FE );
						}
						
						if( dagima_link_get_ICP_statistics( dagfd, grouphandle, linkID, &linkstats ) < 0 )
						{
							printf( "GRP Handle: %d, Link ID: %d, Failed to get ICP statistics\n", grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, errored ICP: %d\n", grouphandle, linkID, linkstats.errored_ICP );
							printf( "GRP Handle: %d, Link ID: %d, invalid ICP: %d\n", grouphandle, linkID, linkstats.invalid_ICP );
							printf( "GRP Handle: %d, Link ID: %d, valid ICP: %d\n", grouphandle, linkID, linkstats.valid_ICP );
							printf( "GRP Handle: %d, Link ID: %d, missing ICP: %d\n", grouphandle, linkID, linkstats.missing_ICP );
						}
						
						if( dagima_link_get_ne_defect_statistics( dagfd, grouphandle, linkID, &nedefects ) < 0 )
						{
							printf( "GRP Handle: %d, Link ID: %d, Failed to get NE defect statistics\n", grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, AIS: %d\n", grouphandle, linkID, nedefects.AIS );
							printf( "GRP Handle: %d, Link ID: %d, LCD: %d\n", grouphandle, linkID, nedefects.LCD );
							printf( "GRP Handle: %d, Link ID: %d, LIF: %d\n", grouphandle, linkID, nedefects.LIF );
							printf( "GRP Handle: %d, Link ID: %d, tx_LODS: %d\n", grouphandle, linkID, nedefects.tx_LODS );
							printf( "GRP Handle: %d, Link ID: %d, rx_LODS: %d\n", grouphandle, linkID, nedefects.rx_LODS );
						}
						
						if( dagima_link_get_fe_defect_statistics( dagfd, grouphandle, linkID, &fedefects ) < 0 )
						{
							printf( "GRP Handle: %d, Link ID: %d, Failed to get FE defect statistics\n", grouphandle, linkID );
						}
						else
						{
							printf( "GRP Handle: %d, Link ID: %d, Tx_FC_FE: %d\n", grouphandle, linkID, fedefects.Tx_FC_FE );
							printf( "GRP Handle: %d, Link ID: %d, Rx_FC_FE: %d\n", grouphandle, linkID, fedefects.Rx_FC_FE );
						}
					}
				}
			}
		}
	}
	
	/* --------------------------------------------------------- */
	/*	We can also control how the ICP cells are treated, incase
		we want to send them through to the host for analysis. */
	
	/*	First determine what the ATM Rx settings are regarding, 
		how cells are treated across all groups. */
	if( dagima_um_get_icpctrl( dagfd, &um_icpctrl ) < 0 )
	{
		printf( "\nFailed to get UM ICP control flags\n" );
	}
	else
	{
		printf( "\nUM control, ICP drop: %d, ICP Send TRL: %d, Filler drop: %d\n",
				um_icpctrl.icp_drop, um_icpctrl.icp_send_trl, um_icpctrl.filler_drop );
	}
	
	printf( "\nUM control, Setting TRL send: %d\n", 1 );
	
	/*	Set it so that ICP cells are sent through. */
	dagima_um_set_icpctrl( dagfd, 1, 1, 1 );
	
	printf( "Sleeping a bit to let some ICP cells through\n\n" );
	sleep( 2 );
	
	/*	You should be able to see ICP cells from the TRL being written 
		at this point. */
	
	printf( "UM control, Setting TRL send: %d\n", 0 );
	
	dagima_um_set_icpctrl( dagfd, 1, 0, 1 );
	
	printf("\n");
	
	/* --------------------------------------------------------- */
	
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_ALL_CELLS );
	printf( "%u total cell received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_DATA_CELLS );
	printf( "%u data cells received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_IDLE_CELLS );
	printf( "%u idle cells received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_ICP_CELLS );
	printf( "%u ICP cells received for ATM Rx\n\n", wCount );
	
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_ALL_CELLS );
	printf( "%u total cell received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_DATA_CELLS );
	printf( "%u data cells received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_IDLE_CELLS );
	printf( "%u idle cells received for ATM Rx\n", wCount );
	wCount = dagima_atmrx_get_stats(dagfd, DAG_IMA_ICP_CELLS );
	printf( "%u ICP cells received for ATM Rx\n\n", wCount );
	
	for( i = 0; i < 16; i++ )
	{
		wCount = dagima_ifc_get_stats(dagfd, DAG_IMA_ALL_CELLS, i);
		printf("%u total cells received on ifc %u\n", wCount, i);
		wCount = dagima_ifc_get_stats(dagfd, DAG_IMA_DATA_CELLS, i);
		printf("%u data cells received on ifc %u\n", wCount, i);
		wCount = dagima_ifc_get_stats(dagfd, DAG_IMA_IDLE_CELLS, i);
		printf("%u idle cells received on ifc %u\n", wCount, i);
		wCount = dagima_ifc_get_stats(dagfd, DAG_IMA_ICP_CELLS, i);
		printf("%u ICP cells received on ifc %u\n\n", wCount, i);
	}
	
	dagema_close_conn( dagfd, 0 );

	return 0;
}
