/*
 * Copyright (c) 2003-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: dagpps.c 12570 2010-03-17 01:03:09Z sfd $
 */

/* Endace headers. */
#include "dagapi.h"
#include "dag_platform.h"
#include "dagutil.h"
#include "dagclarg.h"

/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagpps.c 12570 2010-03-17 01:03:09Z sfd $";
static const char* const kRevisionString = "$Revision: 12570 $";

static char dagname_buf[DAGNAME_BUFSIZE] = "dag0";
static char dagname[DAGNAME_BUFSIZE];
static int dagstream = 0;

/* Commandline argument codes. */
enum
{
	CLA_DEVICE,
	CLA_HELP,
	CLA_VERSION,
	CLA_VERBOSE
};

/* Internal routines. */
static void print_version(void);
static void print_usage(ClArgPtr);


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

static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("dagpps - Endace DAG card PPS utility.\n");
	printf("Usage: dagpps [options]\n");
	dagclarg_display_usage(clarg, stdout);
	
}


int
dagpps_main(int argc, char *argv[])
{
	ClArgPtr clarg;
	FILE* errorfile = NULL;
	int argindex;
	int clarg_result;
	int	dagfd;
	uint8_t*	iom;
	dag_reg_t	*regs;
	uint32_t	duck_base, regn, count, pps, on=0, off=0;
	dag_reg_t	result[DAG_REG_MAX_ENTRIES];
	daginf_t	*daginf;
	char		t[] = "|/-\\";
	int code;

	dagutil_set_progname("dagpps");

	/* Set up default DAG device. */
	if (-1 == dag_parse_name(dagname_buf, dagname, DAGNAME_BUFSIZE, &dagstream))
	{
		dagutil_panic("dag_parse_name(%s): %s\n", dagname_buf, strerror(errno));
	}

	/* 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_string(clarg, "DAG device to use (default: dag0)", "--device", 'd', "device", dagname_buf, DAGNAME_BUFSIZE, CLA_DEVICE);
	dagclarg_add(clarg, "increase verbosity.", "--verbose", 'v', CLA_VERBOSE);


	/* Parse the command line options. */
	clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	while (1 == clarg_result)
	{
		switch(code)
		{
			case CLA_HELP:
				print_usage(clarg);
				return EXIT_SUCCESS;
				break;

			case CLA_VERSION:
				print_version();
				return EXIT_SUCCESS;
				break;

			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));
				}
				break;

			case CLA_VERBOSE:
				dagutil_inc_verbosity();
				break;

			default:
				dagutil_panic("unknown option");
				print_usage(clarg);
				return EXIT_FAILURE;

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

	if (-1 == clarg_result)
	{
		if (argindex < argc)
		{
			dagutil_error("while processing option %s\n", argv[argindex]);
		}
		dagclarg_display_usage(clarg, stderr);
		return EXIT_FAILURE;
	}
	
	if((dagfd = dag_open(dagname)) < 0)
		dagutil_panic("dag_open failed: %s\n", strerror(errno));

	regs = dag_regs(dagfd);

	iom = dag_iom(dagfd);
	daginf = dag_info(dagfd);

	/* Find DUCK */
	regn=0;
	if ((dag_reg_table_find(regs, 0, DAG_REG_DUCK, result, &regn)) || (!regn))
		dagutil_panic("No DUCK found!\n");
	else {
		duck_base = DAG_REG_ADDR(*result);
	}

	for( count = 10*1000*1000 ; count ; count--) {
		pps = *(iom + duck_base);
		if(pps & 0x04)
			on++;
		else
			off++;
		if((count % 100000) == 0) {
			printf("%c\r", t[3-((count/100000)%4)] );
			fflush(stdout);
		}
	}
	printf("on %u, off %u\n", on, off);
	if((on == 0) || (off == 0)) {
		printf("No pulse detected - check cabling\n");
	} else if(on > off) {
		printf("Inverted pulse, check your cabling!\n");
	} else {
		printf("Positive pulse, cabling is correct.\n");
		on = (on + 7) / 10; /* round to next microsecond */
		printf("Pulse length about %u microseconds.\n", on);
	}

#if defined(__linux__) || defined(__FreeBSD__) || (defined(__SVR4) && defined(__sun))
	munmap(iom, daginf->iom_size);
#endif

	dag_close(dagfd);
	return EXIT_SUCCESS;
}


#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
	return dagpps_main(argc, (char**) argv);
}
#endif /* ENDACE_UNIT_TEST */
