/**********************************************************************
*
* Copyright (c) 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: daghdlcdemo.c 11068 2009-04-22 02:26:59Z wilson.zhu $
*
**********************************************************************/

/**********************************************************************
* FILE:         dagaal5demo.c
* DESCRIPTION:  Tool for setting up aal5 connections
*
* HISTORY:
*       09-03-05 DNH 1.0  Initial version.
*
**********************************************************************/

/* DAG headers. */
#include "dagsarapi.h"
#include "dagapi.h"
#include "dagutil.h"
#include "dagema.h"
#include "dag37t_api.h"
#include "d37t_i2c.h"
#include "dagclarg.h"
#include "dagswid.h"


#include "dagaal/aal_config_msg.h"

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

static const char *const kDagaal5demoCvsHeader = "$Id: daghdlcdemo.c 11068 2009-04-22 02:26:59Z wilson.zhu $";
static const char *const kRevisionString = "$Revision: 11068 $";

/* Command line configuration */
typedef struct
{
	int argc;
	char **argv;
	char *device;      /* Dag device */
	int start_xscale;  /* Reset and start xscale */
	int reset_all_filters;  /* Reset and start xscale */
	int use_drb_comm;  /* dag3.7t communication mode: drb or socket */

	uint32_t connectionNum;
	uint32_t max_size;
	uint32_t message;
	uint32_t set_erf_mux;
	sar_mode_t sar_mode;
	net_mode_t net_mode;
	uint32_t swidkey;
	int FILTERLSSU;
	int FILTERFISU;
	int FILTERMSU;
} t_config;

t_config config;                /* Command line configuration */

int verbose = 0;                /* verbose output */

static char dagname[DAGNAME_BUFSIZE];
static char dagname_buf[DAGNAME_BUFSIZE];

uint32_t filter_cnt;
uint32_t filters[256];



enum
{
	CLA_DEVICE,
	CLA_HELP,
	CLA_VERBOSE,
	CLA_VERSION,
	CLA_RST,
	CLA_RESETFILTERS,
	CLA_SWIDKEY,
	CLA_FILTERLSSU,
	CLA_FILTERFISU,
	CLA_FILTERMSU,
	CLA_SET_MUX
};


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


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

/**********************************************************************
* FUNCTION:     scanInputs(config, argc, argv)
* DESCRIPTION:  Read the command line options and fill in the config info.
* INPUTS:       config - pointer to the configuration info to fill in
*               argc   - number of command line tokens
*               argv   - command line token array
* OUTPUTS:      config populated with command line options
* RETURNS:      none
**********************************************************************/
int scanInputs (t_config * config, int argc, char **argv)
{
	ClArgPtr clarg = NULL;
	int argindex;
	int code;
	FILE *errorfile = NULL;
	int dagstream;
	int result;
	
	
	config->argc = argc;
	config->argv = argv;
	config->device = DEFAULT_DEVICE;
	config->start_xscale = 0;
	config->connectionNum = 16;
	config->max_size = 1024*64;
	config->sar_mode = sar_aal5;
	config->net_mode = 0;
	config->set_erf_mux = 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);
	dagclarg_add(clarg, "Reset all filters", "--resetfilters", 'R', CLA_RESETFILTERS);
	dagclarg_add(clarg, "Set the ERF MUX for receive only path", "--seterfmux", 'q', CLA_SET_MUX);
	dagclarg_add_uint(clarg, "Software ID Key", "--key", 'k', "key", &config->swidkey, CLA_SWIDKEY);
	dagclarg_add(clarg, "Add filter LSSU", "--filter-lssu", 'l', CLA_FILTERLSSU);
	dagclarg_add(clarg, "Add filter FISU", "--filter-fisu", 'f', CLA_FILTERFISU);
	dagclarg_add(clarg, "Add filter MSU", "--filter-mssu", 'm', CLA_FILTERMSU);
	
	
	/* 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);
				//return EXIT_SUCCESS;

			case CLA_VERBOSE:
				dagutil_inc_verbosity();
				//verbose++;
				errorfile = stderr;
				break;

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

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

			case CLA_RESETFILTERS:
				config->reset_all_filters = 1;
				break;

			case CLA_SWIDKEY:
				/* Key for Software id change */
				printf("Software ID KEY 0x%x\n",config->swidkey);
				break;

			case CLA_FILTERLSSU:
				config->FILTERLSSU = 1;
				break;

			case CLA_FILTERFISU:
				config->FILTERFISU = 1;
				break;

			case CLA_FILTERMSU:
				config->FILTERMSU = 1;
				break;

			case CLA_SET_MUX:
				config->set_erf_mux = 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;
	
//	
//		case 's':	/* max size to message*/
//			config->max_size = strtol (optarg, NULL, 10);
//			break;
//		case 'n':	/* net mode */
//			config->net_mode = strtol (optarg, NULL, 10);
//			break;
//		case 'm':	/* sar mode */
//			config->sar_mode = strtol (optarg, NULL, 10);
//			break;
}

unsigned char soft_id[D37T_SOFTWARE_ID_SIZE+1];

int
main(int argc, char **argv)
{
	int res;
	int addr;
	int temperature;
	uint32_t version, type;
//	sar_mode_t mode = sar_aal0;
	int dagfd;
	
	memset (&config, 0, sizeof (config));
	scanInputs (&config, argc, argv);

	printf("\nEndace DAG3.7T HDLC configuration demo\n");
	printf("(c) 2005 Endace Technology Ltd.\n\n");
		
	dagutil_set_progname( "daghdlcdemo" );
	
	if ((dagfd = dag_open(config.device)) < 0)
	{
		fprintf (stderr, "dag_open %s: %s\n", config.device,
				 strerror (errno));
		exit(EXIT_FAILURE);
	}
	
	/*	Make sure we don't set the ERF MUX direction without prior 
		concent from the user! */
	if( config.set_erf_mux )
	{
		printf("SET MUX Packet flow\n");
		if (dag_set_mux(dagfd, DA_DATA_TO_HOST, DA_DATA_TO_IOP, DA_DATA_TO_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(EXIT_FAILURE);
		}
	}

	/* Restart the xScale if required */
	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(EXIT_FAILURE);
		}
	}


	/* 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(EXIT_FAILURE);
	}

	/* Set board debug flags */
	d37t_set_debug(dagfd, 0);
	//read inital software ID 	
	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);
	}
	
	soft_id[10] = 0;
	soft_id[11] = 0;
	//write new software ID	
	res = 0;
	if(config.swidkey)
		res = d37t_write_software_id(dagfd, 10, soft_id, config.swidkey);
		if (res)
		{
			printf("d37t_write_software_id() failed res=%d\n", res);
		};

	//red writen software id 
	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);
	}

//-------------------- Reset all Filters --------------------	
	if(config.reset_all_filters) {
	
		printf("Reset all filters \n");
		res = hdlc_msg_reset_all_filters(dagfd);
		if (res<0)
		{
			printf("hdlc_msg_reset_all_filters() failed, res=%d\n", res);
		} else 
		{
			filter_cnt = 0;
		};
	};
	
//-------------------- FISU Filter --------------------	
	if( config.FILTERFISU )
	{
		printf("Setup Filter for FISU packets fro MTP layer2\n");
		res = hdlc_msg_set_filter(dagfd,20,0x000000FC,0x00000000, DAG_EQ, DAG_FILTER_LEVEL_BOARD,0,0,0);
		if (res<0)
		{
			printf("hdlc_msg_set_filter() failed, res=%d\n", res);
		} else 
		{
			filters[filter_cnt++]=res;
		};
	};
//--------------------LSSU Filter --------------------------------		
	if( config.FILTERLSSU )
	{
		printf("Setup Filter for LSSU packets\n");
		res = hdlc_msg_set_filter(dagfd,20,0x000000FC,0x00000004, DAG_GE, DAG_FILTER_LEVEL_BOARD,0,0,0);
		if (res<0)
		{
			printf("hdlc_msg_set_filter() failed, res=%d\n", res);
		} else 
		{
			filters[filter_cnt++]=res;
		}
		// sub filter 
		printf("Setup subfilter for LSSU packets\n");
		res = hdlc_msg_set_subfilter(dagfd,20,0x000000FC,0x00000008, DAG_LE, DAG_FILTER_LEVEL_BOARD,
												0,0,0,filters[filter_cnt-1],DAG_AND_LIST);
		if (res<0)
		{
			printf("hdlc_msg_set_subfilter() failed, res=%d\n", res);
		} else 
		{
			filters[filter_cnt++]=res;
		};
	};
//-------------------- MSU Filter---------------------------------------
	
	if( config.FILTERMSU )
	{
		printf("Setup Filter for MSU packets\n");
		res = hdlc_msg_set_filter(dagfd,20,0x000000FC,0x0000000C, DAG_GE, DAG_FILTER_LEVEL_BOARD,0,0,0);
		if (res<0)
		{
			printf("hdlc_msg_set_filter() failed, res=%d\n", res);
		} else 
		{
			filters[filter_cnt++]=res;
		}
	};
//-------------------------------------------------------------

	
	/* at this point we need to set up an aal5 connection on the required virtual connection*/

	
	/* the default in NNI so this is just done for demonstration purposes */
	//this is for AAL5 not fo hdlc 
	//if (0 != dagsar_vci_set_net_mode(dagfd, DAG37T_INTERFACE, config.connectionNum, 
	//	config.VPI, config.VCI, config.net_mode))
	//{
	//	printf("set net mode failed\n");
	//	return 1;
	//}
	//else
	//{
	//	printf("net mode set\n");
	//}
	
	/*set to reassemble AAL5 frames */
	//if (0 != dagsar_vci_set_sar_mode(dagfd, DAG37T_INTERFACE, config.connectionNum, 
	//	config.VPI, config.VCI, config.sar_mode))
	//{
	//	printf("set sar mode failed\n");
	//	return 1;
	//}
	//else
	//{
	//	printf("sar mode set\n");
	//}
	
	//if (0 != dagsar_set_buffer_size(dagfd, config.max_size))
	//{
	//	printf("set buffer size failed \n");
	//	return 1;
	//}
	//else
	//{
	//	printf("buffer size altered \n");
	//}
	
	/* it is possible to check the mode a virtual connection is in.  This will verify the 
	 * mode set earlier did set the mode to the correct option 
	 */
	//mode = dagsar_vci_get_sar_mode(dagfd, DAG37T_INTERFACE,  config.connectionNum, config.VPI, config.VCI);

	//if (mode != config.sar_mode)
//	{
//		printf("mode was not returned correctly %d \n", mode);
//		return 1;
//	}
//	else
//	{
//		printf("mode recognised\n");
//	}
	
	/* start the connection so data can be collected */
//	if (0 != dagsar_vci_activate(dagfd, DAG37T_INTERFACE,  config.connectionNum, 
//		config.VPI, config.VCI))
//	{
//		printf("activation failed\n");
//		return 1;
//	}
//	else
//	{
//		printf("activation complete\n");
//	}

	
	dagema_close_conn(dagfd, 0);
	dag_close (dagfd);
	
	return EXIT_SUCCESS;
}
