/* monitor -- scan buffers coming from the DAC (/dev/ai0)
 *
 * Revisions:
 * 1.1 12/16/87 --  Basic play by bgg, dressed-up by jwp 
 * 	(error handling, signal traps, multiple files)
 * 1.3 5/88 -- forking process to handle new driver, smaller
 *	DMA buffers -- bgg
 *
 * NOTE:  monitor does not use the same interrupt/buffering scheme
 *	that play and record do; some buffer overruns may occur.
 */

#include <stdio.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/map.h>
#include "aireg.h"
#include "aivar.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "sfheader.h"

#define CLOCK1 14400000
#define CLOCK2 14318180

int d;
struct aud_conv stuff;

main(argc,argv)

int argc;
char *argv[];

{
	int f,chans;
	float srate;
	short peakval;
	void byebye();
	int buid_srint();
	int id,status;

	d = open("/dev/ai0",0,2);

	stuff.a_nbytes = 9999999;
	stuff.a_fd = 0;
	stuff.a_flags = 0;
	stuff.a_numdbs = 2;

	fprintf(stderr,"Enter number of channels: ");
	scanf("%d",&chans);
	fprintf(stderr,"Enter sampling rate: ");
	scanf("%f",&srate);
	stuff.a_nchans = chans;
	stuff.a_srate = build_srint(srate,chans);
	stuff.a_scanflag = 1;

	signal(SIGHUP,byebye);
	signal(SIGINT,byebye);
	signal(SIGQUIT,byebye);
	signal(SIGBUS,byebye);
	signal(SIGSEGV,byebye);
	signal(SIGTERM,byebye);
	signal(SIGTSTP,SIG_IGN);

	if (ioctl(d,AIO_SET_ADC,&stuff) < 0) {
		fprintf(stderr,"Can't set DAC (errno = %d)",errno);
		fprintf(stderr," -- try again\n");
		ioctl(d,AIO_RESET,&stuff);
		close(d);
		exit(-1);
		}

	
	/* monitor */
	if ( (id = fork() ) == 0 ) {	/* child does the playing */
		signal(SIGHUP,SIG_IGN);
		signal(SIGINT,SIG_IGN);
		signal(SIGQUIT,SIG_IGN);
		signal(SIGBUS,SIG_IGN);
		signal(SIGSEGV,SIG_IGN);
		signal(SIGTERM,SIG_IGN);
		signal(SIGTSTP,SIG_IGN);
		if (ioctl(d,AIO_SCAN,&stuff) < 0) {
			fprintf(stderr,"Error on conversion (errno = %d) ",errno);
			fprintf(stderr,"-- try again\n");
			ioctl(d,AIO_RESET,&stuff);
			close(d);
			exit(-1);
			}
		return(0);
		}
	
	while(1) {
		ioctl(d,AIO_GETSCAN,&peakval);
		if (peakval > 0) {
			if (peakval < 32767) {
				printf("%d\n",peakval);
				}
			else {
				printf("%d <------- Yikes!!!!!!! Saturation!!!!!!!\n",peakval);
				}
			}
		}
}


void byebye(sig)
int sig;
{
	fprintf(stderr,"monitor: Terminated (signal %d)\n",sig);
	if (sig == SIGINT) {
		signal(SIGINT,SIG_IGN);
		}
	ioctl(d,AIO_STOP,&stuff);
	signal(SIGINT,SIG_DFL);
	signal(SIGQUIT,SIG_DFL);
	signal(SIGTERM,SIG_DFL);
	signal(SIGTSTP,SIG_DFL);
	sleep(2); /* wait for dac to flush */
	close(d);
	exit(0);
}


/* convert sampling rate to ds16 lo and hi SR register format */
build_srint(desired,nchans)
float desired;
int nchans;
{
	float	basis1,basis2,fbase1,fbase2,basis;
	int	ibase1,ibase2,ibasis,result,tbase = 0;
	short	lo,hi,tophi;
	char	*byter;

	basis1 = CLOCK1/desired;
	basis2 = CLOCK2/desired;
	ibase1 = basis1;
	ibase2 = basis2;
	fbase1 = basis1 - (float)ibase1;
	fbase2 = basis2 - (float)ibase2;

	if (ibase1 > 4096) {
		if (ibase2 > 4096) {
			fprintf(stderr,"sampling rate too low\n");
			exit(-1);
			}
		else {
			tbase = CLOCK2;
			basis = basis2;
			}
		}
	else {
		if (ibase2 > 4096) {
			tbase = CLOCK1;
			basis = basis1;
			}
		}
	
	if (tbase == 0) {
		if (fbase1 < fbase2) {
			if ( ABS(fbase2 - .99999) < fbase1 ) {
				tbase = CLOCK2;
				basis = basis2;
				}
			else {
				tbase = CLOCK1;
				basis = basis1;
				}
			}
		    else {
			if ( ABS(fbase1 - .99999) < fbase2 ) {
				tbase = CLOCK1;
				basis = basis1;
				}
			else {
				tbase = CLOCK2;
				basis = basis2;
				}
			}
		}
	
	ibasis = basis;
	if ( (basis - (float)ibasis) > 0.5 )
		basis += 1.0;

	ibasis = basis;
	result = 4096 - ibasis;

	if (result < 0) {
		fprintf(stderr,"bad SR selection, result = %d\n",result);
		exit(-1);
		}
	
	byter = (char *)&result;
	byter += 2;
	hi = (*byter & 0x00ff) | ( (*byter << 8) & 0xff00 );
	byter += 1;
	lo = (*byter & 0x00ff) | ( (*byter << 8) & 0xff00 );

	tophi = 0x0000;
	if ( (int)desired*nchans > 50000 )
		tophi = 0x4040;
	if (tbase == CLOCK2)
		tophi = tophi | 0x1010;
	
	hi = hi | tophi;
	result = (lo & 0x0000ffff) | ( (hi << 16) & 0xffff0000 );
/*	result = ( (lo << 16) & 0xffff0000) | (hi & 0x0000ffff); */
	
	return(result);
}
