#define UNIXFILES
#include <sys/file.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <vaxuba/dsc.h>
#include <vaxuba/dsreg.h>
#include <sys/stat.h>
#include "sfheader.h"
#include <errno.h>
#include "virgil.h"

short fid;
SFHEADER sfh;

main(argc,argv)
int argc;
char *argv[];

{
	char *buffer,*cp,*sfname;
	long nsamps,blksize,originalsize,sf,result,sfd,i,nskips,chans;
	int status,shutup(),pid,(*oldint)(),(*oldquit)(),rtn,w,errno;
	int loadword(), dmaword;
	float srate,dur,inskip;
	double atof();
	struct stat sfst;
	
	srate=dur=inskip=chans=0;

	while((*++argv)[0] == '-') {
		argc -= 2; /* Take away two args */
		for(cp = argv[0]+1; *cp; cp++) {
			switch(*cp) { /* Grap options */
			case 'r': 
				srate = atof(*++argv);
				printf("Sampling rate reset to %f\n",srate);
				break;
			case 'd': 
				dur = atof(*++argv);
				printf("Play duration is %f\n",dur);
				break;
			case 's': 
				inskip = atof(*++argv);
				printf("Input skip is %f\n",inskip);	
				break;
			case 'c':
				chans = atoi(*++argv);
				printf("Number of channels reset to %d\n",
								chans);
				break;
			default:  
				printf("Don't know about option: %c\n",*cp);
			}
		}

	}
        sfname = argv[0];
	rwopensf(sfname,sfd,sfh,sfst,"myread",result,2);
	if(result < 0) exit(0);
	printf("name: %s   sr: %f   nchans: %d  class: %d\n",sfname,
                sfsrate(&sfh),sfchans(&sfh),sfclass(&sfh));
	srate = (srate ? srate : sfsrate(&sfh));
	chans = (chans ? chans : sfchans(&sfh));
	originalsize = ((sfst.st_size - SIZEOF_HEADER)/SF_SHORT)/chans;
	dur = dur ? dur : ((float)originalsize/srate) - inskip;

	if((inskip + dur) > (.01 + originalsize/srate)) {
		printf("The file is not that big. Duration = %f\n",dur);
		exit(1);
	}
				
	nsamps=dur * srate * chans;

	nskips = inskip * srate * (float)chans * SF_SHORT;
	nskips -= nskips % (chans * SF_SHORT);
	if(sflseek(sfd,nskips,0) == -1) {
		printf("Bad lseek on soundfile\n");
		exit(1);
	}

	blksize=sfst.st_blksize;
	if(sfclass(&sfh) != 2) {
	       printf("You can't record on this file, not made of integers.\n");
	       exit(1);
	}
	if ((pid = fork()) == 0) {
		(void) signal(SIGINT,SIG_IGN);
		(void) signal(SIGQUIT,SIG_IGN);
		(void) signal(SIGTSTP,SIG_IGN);
		(void) signal(SIGSTOP,SIG_IGN);
		if((dmaword = loadword(srate,chans,ATOD)) < 0) {
			perror("loadword");
			exit(1);
		}
		i=dsdac42(sfd,nsamps,blksize,dmaword);  
		exit(i);
	}
	oldint = signal(SIGINT, shutup);
	oldquit = signal(SIGQUIT, shutup);
	/* wait for process, or interrupts */
	while ((w = wait(&status)) != pid) {
		if (w == -1) {
			if (errno == EINTR)
				continue;
			break;
		}
	}
	signal(SIGINT,oldint);
	signal(SIGQUIT,oldquit);
	close(sfd);
}

shutup() 
{
	int fid;
	if((fid = open("/dev/drreset0",0)) < 0) 
		perror("shutup"); 
}

extern  errno;
/* how many buffers */
# define UBSIZE		4
# define BP16BIT        2

short *dsbuf;

char *ddserrs[] = {
	"missing arguments/parameters",
	"converters in use",
	"buffer size wasn't modulo bsize",
	"buffer size was too small",
	"disk error",
	"converter error",
	"dsreset clobbered us",
	"sync time out",
	""
};


dsdac42(sfd,  nsamps, blksize, dmaword) 
	int sfd;
	long	nsamps; /* number of samples to convert */
	long	blksize; /* File system block size */
{
	struct ds_seq dsseq;
	struct ds_err dserr;
	struct ds_fs dsf;
	register int dacfid, cnt=0, erno;
	short j;

		printf("DSCOUNT=%D ",
			 nsamps * BP16BIT);

	if (nsamps < 1) {
		 fprintf(stderr, "dsdac: can't convert 0 samples!\n"); 
	 	return(-1);
	}


	/* ds driver will use this buffer for sample data transfer */
	if (dsbuf == NULL)
		if ((dsbuf = (short *) valloc((unsigned) 
		    blksize * UBSIZE)) == NULL) {
			perror("valloc");
			return(1);
		}

	bcopy((char *) &sfh, (char *) dsbuf, sizeof(SFHEADER));

		while ((dacfid = open("/dev/dr", 2)) < 0) 
			if (errno != ENXIO) {
				perror("dsdac:open");
				return(-1);
			}

		dsf.bnosiz = sfd;
		if (ioctl(dacfid, DS42BSD, &dsf) == -1) 
			{ perror("dsblks"); goto errout; }
		dsf.bnosiz = dmaword;
		/* just to set parameters for my board */
		if (ioctl(dacfid, DSWORD, &dsf) == -1)
			{ perror("dsword"); goto errout; }
		printf("Using write of %d bytes\n",nsamps  * BP16BIT);

		puts("RECORD");

		if (read(dacfid, (char *) dsbuf, nsamps * BP16BIT) == -1) {
			perror("write");
			if (ioctl(dacfid, DSERRS, &dserr) == -1) 
				{ perror("dserrs"); goto errout; }
			switch (dserr.errors) {
				case EDS_ARGS : erno = 0; break;
				case EDS_ACC : erno = 1; break;
				case EDS_MOD : erno = 2; break;
				case EDS_SIZE : erno = 3; break;
				case EDS_DISK : erno = 4; break;
				case EDS_CERR : erno = 5; break;
				case EDS_RST : erno = 6; break;
				default: erno = 8; break;
			}
		fprintf(stderr, "%d %s dmacsr=%o, asccsr=%o, errors=%o\n",erno,  
				ddserrs[erno], 
					dserr.dma_csr & ((u_short) -1), 
					dserr.asc_csr & ((u_short) -1),
					dserr.errors & ((u_short) -1));
		    puts("E_DACS");
		    goto errout;
		}

		if(close(dacfid))
			printf("Bad close\n");
	free((char *) dsbuf);
	puts("!");
	return(0);

errout:
	free((char *) dsbuf);
	close(dacfid);
	return(1);
}

loadword(opsrate,opchans,function)
float opsrate;
{ 
	int val = opsrate;
	int word;
	switch(val) {
	case 7000 : 
		word = CLOCK56 | DIV8; 
		break;
	case 7500 : 
		word = CLOCK60 | DIV8; 
		break;
	case 14000 : 
		word = CLOCK56 | DIV4; 
		break;
	case 15000 :
		word = CLOCK60 | DIV4;  
		break;
	case 28000 :
		word = CLOCK56 | DIV2 ; 
		break;
	case 30000 : 
		word = CLOCK60 | DIV2 ; 
		break;
	case 1 : 
		word = PULSE; 
		printf(" Use pulse generator.  Make sure it is on.\n");
		break;
	default : 
		printf(" Not one of my available sampling rates, tryagain.");
		return(-1);
	}
	switch(opchans) {
	case 1 :
		word |= CHAN1; 
		break;
	case 2 :
		word |= CHAN1 | CHAN2 ;
		break;
	case 4 :
		word |= CHAN1 | CHAN2 | CHAN3 | CHAN4 ;
		if(function == ATOD) {
			printf("You cannot do A-D in 4 channels\n");
			return(-1);
		}
		break;
	case 8 :
		word |= CHAN3 ;  	/* to use for 14k conversion */
		break;
	case 16 :
		word |= CHAN3 | CHAN4 ; /* to use for 14k stereo conversion */
		break;
	default :
		printf( " Bad channel specification \n");
		return(-1);
	}
	return(word | (function == ATOD ? function | IOLINK : function));
}
