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

    FILE....: CIDTEST.CPP
    TYPE....: C++ program
    AUTHOR..: David Rowe
    DATE....: 24/7/01

    Demo program for using VPB CID, combines samcid.cpp & deccid.cpp.
    JK 23/4/02: This program decodes the CID after each ring instead of waiting
    to detect the first ring. This is a more robust solution than waiting for 
    the first ring before decoding as spurious glitches can cause false 
    ring events to fire.  

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

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

         Voicetronix Voice Processing Board (VPB) Software

         Copyright (C) 1999-2001 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 as published by the Free Software Foundation; either
         version 2.1 of the License, or (at your option) any later version.

         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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
	 USA

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

#include "../kbhit.h"
#include "../threads.h"

#include "vpbapi.h"
#include "verbose.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>


void wait_for_ring(int h);
void *rec_thread(void *pv);

// size of buffer to store CID signal in (may need to be adjusted)
#define N (8000*4)

typedef struct {
	int   h;
	short buf[N];
} THREAD_INFO;


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

int main(int argc, char * argv[])
{
	int             h, hdial, port, dport, arg,ret,cnt;
	pthread_t       thread;
	char            number_str[VPB_MAX_STR];
	THREAD_INFO     ti;

	if (argc < 2) {
		printf("usage: cidtest Port[0..3] [-dial Port Number]\n");
		exit(0);
	}


	port = atoi(argv[1]);
	h = vpb_open(0, port);
	vpb_cid_debug_on("cid.txt");

	// option to dial out of another port (useful for testing at
	// remote locations)
	if ((arg = arg_exists(argc, argv, "-dial")) != 0) {
		dport = atoi(argv[arg+1]);
		hdial = vpb_open(0, dport);
		vpb_sethook_sync(hdial, VPB_OFFHOOK);
		printf("OK, dialing %s down port %d\n", argv[arg+2],
		       dport);
		vpb_dial_sync(hdial, argv[arg+2]);
	}

	//	printf("Waiting for first ring.....\n");
	//	wait_for_ring(h);
      ret = 1 ;
      cnt = 100; /* wait for 10 rings*/
      //while ((ret != VPB_OK) && cnt>0){
      while (cnt>0){

	ti.h = h;
	pthread_create(&thread, NULL, rec_thread, (void*)&ti);
	printf("Recording, Waiting for ring.....\n");
	wait_for_ring(h);
	vpb_record_terminate(h);
	cnt--;
	printf("OK, now decoding.....\n");
	ret = vpb_cid_decode(number_str, ti.buf, N);
	if(ret != VPB_OK)
	  printf("Error code %d\n",ret);
	else
	 printf("CID number: %s\n", number_str);
      }
	vpb_close(h);
	if ((arg = arg_exists(argc, argv, "-dial")) != 0) {
		vpb_close(hdial);
	}

	return 0;
}

void wait_for_ring(int h) {
	VPB_EVENT e;
	int       ret;

	while(1) {
		ret = vpb_get_event_ch_async(h, &e);
		if (ret == VPB_OK) {
			if (e.type == VPB_RING)
				return;
			if (e.type == VPB_DROP)
				return;
		}
		if (e.type != VPB_DROP)
			vpb_sleep(100);
	}
}

// Records CID samples to a buffer

void *rec_thread(void *pv) {
	THREAD_INFO *ti = (THREAD_INFO*)pv;

	// record buffer of samples between rings

	vpb_record_buf_start(ti->h, VPB_LINEAR);
	vpb_record_buf_sync(ti->h, (char*)ti->buf, sizeof(short)*N);
	vpb_record_buf_finish(ti->h);

	return(NULL);
}


