/*---------------------------------------------------------------------------*\

	Test program for ERL measurement of vdaa FXO modules.

         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2007 Voicetronix www.voicetronix.com.au

         This library is free software; you can redistribute it and/or
         modify it under the terms of the GNU Lesser General Public
         License version 2.1 as published by the Free Software Foundation;

         This library is distributed in the hope that it will be useful,
         but WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
         MA  02110-1301  USA

\*---------------------------------------------------------------------------*/

#include "scanerl.h"

#include <cstdlib>
#include <cstring>
#include <sys/time.h>


//XXX This isn't part of the public api, because its probably not the way
//    we really want to do it, but it does let us experiment further right now.
extern void set_vdaa_impedance(int board, int port, int impedance);


static int arg_exists(int argc, char *argv[], const char *arg)
{ //{{{
	for(int i = 0; i < argc; ++i)
		if(strcmp(argv[i],arg) == 0) return i;

	return 0;
} //}}}

static void doscan(int h)
{ //{{{
	float  av_erl, max_erl, min_erl;

	printf("\t300\t500\t1000\t2000\t3000\t\tavg\tmax\tmin\tdiff\n");
	scan_erl(h, &av_erl, &max_erl, &min_erl);
	printf("\n");
} //}}}

static int msdiff( const timeval begin, const timeval &end )
{ //{{{

	return ( end.tv_sec  - begin.tv_sec )  * 1000
	     + ( end.tv_usec - begin.tv_usec ) / 1000;

} //}}}

int main(int argc, char *argv[])
{
	const char *impedances[] = { "600 Ohm",
				     "900 Ohm",
				     "270 Ohm + (750 Ohm || 150 nF) and 275 Ohm + (780 Ohm || 150 nF)",
				     "220 Ohm + (820 Ohm || 120 nF) and 220 Ohm + (820 Ohm || 115 nF)",
				     "370 Ohm + (620 Ohm || 310 nF)",
				     "320 Ohm + (1050 Ohm || 230 nF)",
				     "370 Ohm + (820 Ohm || 110 nF)",
				     "275 Ohm + (780 Ohm || 115 nF)",
				     "120 Ohm + (820 Ohm || 110 nF)",
				     "350 Ohm + (1000 Ohm || 210 nF)",
				     "200 Ohm + (680 Ohm || 100 nF)",
				     "600 Ohm + 2.16 uF",
				     "900 Ohm + 1 uF",
				     "900 Ohm + 2.16 uF",
				     "600 Ohm + 1 uF",
				     "Global impedance"
				   };
	int cardnum   = 0;
	int portnum   = 0;
	int impedance = -1;
	int rings     = 1;
	int arg;

	if(arg_exists(argc, argv, "-?") || arg_exists(argc, argv, "--help")) {
		printf("\nIf no --impedance is specified explicitly, and the --scan\n");
		printf("option is not used, then the impedance value will be taken\n");
		printf("from the port's country selection.\n\n");
		printf("--card num       Test card num.  Default is 0\n");
		printf("--port num       Test port num.  Default is 0\n");
		printf("--impedance num  Test impedance num [0 - 15]\n");
		printf("--scan           Test all available impedances\n");
		printf("--playgain db    Set hardware play gain\n");
		printf("--recgain db     Set hardware record gain\n");
		printf("--rings num      Answer after num rings\n\n");
		return EXIT_SUCCESS;
	}
	if((arg = arg_exists(argc,argv,"--card")) != 0) cardnum = atoi(argv[arg+1]);
	if((arg = arg_exists(argc,argv,"--port")) != 0) portnum = atoi(argv[arg+1]);
	if((arg = arg_exists(argc,argv,"--rings")) != 0)  rings = atoi(argv[arg+1]);
	if((arg = arg_exists(argc,argv,"--impedance")) != 0) {
		impedance = atoi(argv[arg+1]);

		if( impedance < 0 || impedance > 15 ) {
			printf("Invalid impedance %d\n", impedance);
			return EXIT_FAILURE;
		}
	}

	try {
		printf("Testing card %d, port %d\n", cardnum, portnum);
		int h = vpb_open(cardnum, portnum);

		if( vpb_get_port_type(h) != VPB_FXO ) {
			printf("Not an FXO port.  Test aborted.\n");
			vpb_close(h);
			return EXIT_FAILURE;
		}
		if((arg = arg_exists(argc, argv, "--recgain")) != 0) {
			float recg = atof(argv[arg+1]);
			vpb_record_set_hw_gain(h, recg);
			printf("record hw gain set to %3.2f dB\n", recg);
		}
		if((arg = arg_exists(argc, argv, "--playgain")) != 0) {
			float playg = atof(argv[arg+1]);
			vpb_play_set_hw_gain(h, playg);
			printf("play hw gain set to %3.2f dB\n", playg);
		}

		if( vpb_get_hookstate(h) != VPB_ONHOOK )
			vpb_sethook_sync(h, VPB_ONHOOK);


		printf("Place a call into the port now.\n");
		printf("Ensure the calling handset is muted for the duration of the test\n");

		timeval last_ring   = { 0, 0 };
		int     countrycode = vpb_get_port_country(h)->code;
		for(;;) {
			VPB_EVENT   e;

			if( vpb_get_event_ch_sync(h, &e) != VPB_OK )
				continue;

			char    s[VPB_MAX_STR];

			vpb_translate_event(&e, s);
			printf("%s",s);

			if(e.type == VPB_RING_OFF) {
				if( countrycode == 81 )
				{ //{{{
					// Ignore NTT fast-ring
					if( last_ring.tv_sec == 0 ) {
						gettimeofday( &last_ring, NULL );
						continue;
					}

					timeval now;
					gettimeofday( &now, NULL );

					if( msdiff( last_ring, now ) < 1500 ) {
						last_ring.tv_sec  = now.tv_sec;
						last_ring.tv_usec = now.tv_usec;
						continue;
					}
				} //}}}
				if( --rings == 0 ) {
					vpb_sethook_sync(e.handle,VPB_OFFHOOK);
					vpb_sleep(1000);
					break;
				}
			}
		}

		if(arg_exists(argc, argv, "--scan")) {
			for(int i = 0; i < 16; ++i) {
				printf("\nfxo_impedance = %d (%s)\n", i, impedances[i]);
				set_vdaa_impedance(cardnum, portnum, i);
				doscan(h);
			}
		}
		else if( impedance >= 0 ) {
			set_vdaa_impedance(cardnum, portnum, impedance);
			doscan(h);
		}
		else doscan(h);

		vpb_sethook_sync(h, VPB_ONHOOK);

		printf("\n");
		vpb_close(h);
	}
	catch (const std::exception &e) {
		fprintf(stderr, "%s: uncaught exception: %s\n", argv[0],
								e.what());
	}

	return EXIT_SUCCESS;
}

