/**********************************************************************
*
* 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: dagaal5demo.c 11066 2009-04-22 01:25:02Z 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 "dagclarg.h"
#include "dagema.h"
#include "dag37t_api.h"
#include "d37t_i2c.h"
#include "dagswid.h"


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

static const char *const kDagaal5demoCvsHeader = "$Id: dagaal5demo.c 11066 2009-04-22 01:25:02Z wilson.zhu $";
static const char *const kRevisionString = "$Revision: 11066 $";

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

	uint32_t VCI;
	uint32_t VPI;
	uint32_t connectionNum;
	uint32_t max_size;
	uint32_t message;
	sar_mode_t sar_mode;
	net_mode_t net_mode;
} t_config;

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

enum
{
	CLA_DEVICE,
	CLA_HELP,
	CLA_VERBOSE,
	CLA_VERSION,
	CLA_RST,
	CLA_VCI,
	CLA_VPI,
	CLA_CN,
	CLA_AALBUF,
	CLA_SARMODE,
	CLA_NETMODE
};


/*****************************************************************************/
/*** Functions                                                             ***/
/*****************************************************************************/


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

static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf(	"dagaal5demo is a demonstration of the Endace AAL reassembler\n");
	printf("For complete details of the available functionality consult the SAR API guide.\n");
	printf("Usage: dagaal5demo [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 dagstream;
	int result;
	int argindex;
	int code;
	FILE *errorfile = NULL;
	uint32_t vci, vpi, sar_mode, net_mode, cn_num, max_size;
	
	config->argc = argc;
	config->argv = argv;
	config->device = DEFAULT_DEVICE;
	config->start_xscale = 0;
	config->VCI = 64;
	config->VPI = 28;
	config->connectionNum = 16;
	config->max_size = 1024*64;
	config->sar_mode = sar_aal5;
	config->net_mode = 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_uint(clarg, "VCI to configure <64>.", "--vci", 'c', "VCI", &vci, CLA_VCI); 
	dagclarg_add_uint(clarg, "VPI to configure <28>.", "--vpi", 'p', "VPI", &vpi, CLA_VPI); 
	dagclarg_add_uint(clarg, "connection number to configure <16>.", "--cnum", 'C', "connection_num", &cn_num, CLA_CN); 
	dagclarg_add_uint(clarg, "AAL buffer size to use <65536>.", "--bufsize", 's', "max_size", &max_size, CLA_AALBUF); 
	dagclarg_add_uint(clarg, "reassembly type to use <2> 0=ATM 1=AAL2 2=AAL5.", "--type", 'm', "sar_mode", &sar_mode, CLA_SARMODE); 
	dagclarg_add_uint(clarg, " net type to use <0> 0=nni 1=uni", "--nettype", 'n', "net_mode", &net_mode, CLA_NETMODE); 


	/* 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;

			case CLA_VCI:
				config->VCI = vci;
				break;

			case CLA_VPI:
				config->VPI = vpi;
				break;

			case CLA_CN:
				config->connectionNum = cn_num;
				break;

			case CLA_AALBUF:
				config->max_size = max_size;
				break;

			case CLA_SARMODE:
				config->sar_mode = sar_mode;
				break;

			case CLA_NETMODE:
				config->net_mode = net_mode;
				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;
}

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 AAL5 configuration demo\n");
	printf("(c) 2005 Endace Technology Ltd.\n\n");

	
	if ((dagfd = dag_open(config.device)) < 0)
	{
		fprintf (stderr, "dag_open %s: %s\n", config.device,
				 strerror (errno));
		exit(EXIT_FAILURE);
	}
	
	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);
	
	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);
	}
	
	/* at this point we need to set up an aal5 connection on the required virtual connection*/

	/* deactivate the connection so configuration changes can be made */
	if (0 != dagsar_vci_deactivate(dagfd, DAG37T_INTERFACE, config.connectionNum, 
		config.VPI, config.VCI))
	{
		printf("deactivation failed\n");
		return 1;
	}
	else
	{
		printf("deactivation complete\n");
	}
	
	/* the default in NNI so this is just done for demonstration purposes */
	if (0 != dagsar_channel_set_net_mode(dagfd, DAG37T_INTERFACE, config.connectionNum, 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;
}
