/* Program for use on a target system */

/*Interrupt Service Routine */
/*  This is called when the SIO port becomes full.
    It takes the data and fills a fifo data structure
    from which the windowing and fft routines copy and
    process.  

    The input buffering is double buffered */

/* The sampling rate is 8.192 kHz.  With an FFT buffer length of 1024
    points, the equivalent filter bandwidth of the FFT is 8 Hz.  The 
    sliding of the FFTs needs to be done at a rate significantly 
    higher than the risetime of the bandwidth of the fft equivalent
    filters.  

    The sampling rate on the fft equivalent filters is 8192 Hz / 128 =
    64 Hz, or 8 times the equivalent filter bandwidth of 8 Hz.

*/

#define SIMULATE 1  /* setup to simulate I/O  */

#define M 10  /* Must be log base 2 of N */
#define N 1024 /* Number of complex valued points */
#define SIGTHRESH (20.0 / N)
#define BUFLEN (N+128)*2   /*   */
#define BUFLENEND (BUFLEN-1)
#define PROCLEN N*2  /* number of points, 2 numbers, complex valued */
#define PROCLENEND (PROCLEN-1)
#define BW2 4 /* half the filter bandwidth in fft frequency bins */
#define PI 3.141592653
#define PI2 1.5707963
#define PI32 4.7123889 /* 3/2 times PI */
#define TWOPI 6.2831853

#include <libap.h>

#ifndef SIMULATE
#include "inout.asm"
#endif


/* FFT Processing buffers */
float fftbuf1[PROCLEN-1], fftbuf1end[1];
float fftbuf2[PROCLEN-1], fftbuf2end[1];

/* Ready flag for FFT processing buffers */
int fft_rd_flag;

/*Input buffers for interrupt service routine */
float *inbufptr, *inbufptrend, *outbufptr, *outbufend;
float inbuf[PROCLEN-1], inbufend[1], inbufx[BUFLEN-PROCLEN-1],
    inbufxend[1];

#ifdef SIMULATE
/* Simulated input variables */
float xarg, xstep;
#endif

#ifdef SIMULATE
void set_pcw( c)
int *c;
{
}

void set_ioc( c)
int *c;
{
}
#endif

#ifdef SIMULATE

/* Simulated input from SIO */
float sim_sioin()
{
    register float temp;

    /* Simulated input */
    if( xarg < PI)
    {
        if( xarg < PI2) temp = sin( xarg);
        else temp = sin( PI - xarg);
    } else
    {
        if( xarg < PI32)  temp = -sin( xarg - PI);
        else temp = sin( xarg - TWOPI);
    }
    xarg += xstep;
    if( xarg > TWOPI) xarg = xarg - TWOPI;

    return(temp);
}

void sim_sioout( c)
char *c;
{
}

#endif

/* SIO input interrupt service routine */
void sioin_int()
{
    register float temp, *lptr;

    lptr = inbufptr;
	/* input sio data, real valued  */
#ifndef SIMULATE
	*lptr++ = sioin();
#else
    *lptr++ = sim_sioin(); /* Simulated input */
#endif

	*lptr++ = 0;    /* imaginary part is zero */
    inbufptr = lptr;
}

/* SIO output interrupt service routine */
void sioout_int()
{
	register float *optr;

	optr = outbufptr;

#ifndef SIMULATE
 	sioout( optr);
#else
    sim_sioout( optr);
#endif

	optr++;

	/* This section circularizes the output buffer, and also
        changes the buffer when the background process has a
        new buffer ready.  The fft_rd_flag is the signal */
	if( optr > outbufend)
	{
		if( fft_rd_flag == 2)
		{
			optr = fftbuf2;
			outbufend = fftbuf2end;
		}
		else 
		{
			optr = fftbuf1;
			outbufend = fftbuf1end;
		}
	}
    outbufptr = optr;
}

main()
{

	register int i;
	register float *windedptr, *shiftoutptr, *shiftinptr;

#ifdef SIMULATE
    /* Initialize simulated I/O variables */
    xarg = 0;
    xstep = 10 * 3.1415 / 256;
#endif

	/* Setup SIO input interrupt service routine pointers */
	inbufptr = inbuf;
	inbufptrend = inbufend;

	/* Setup SIO output interrupt service routine */
	outbufptr = fftbuf1;
	outbufend = fftbuf1end;
	fft_rd_flag = 0; /* no FFT buffers are ready */

	/* Setup the SIO */
	/* OLEN is 16 bits; CKI is CKI/24; OUT is msb first;
        IN is msb first; no DMA; SAN is clear; AOL has OLD
        internally generated; AOC has OCK internally generated;
        ILEN is 16 bits; AIL has ILD internally generated;
        AIC has ICK internally generated; SLEN is 16; BC has ICK
        ASY has SY internal */
	set_ioc( 0x70b99);

	/* Start SIO input interrupt */
	set_pcw( 0x1017);

	for(;;)
	{

		/* wait for input buffer to come full */
		while( inbufptr < inbufxend )
		{
#ifdef SIMULATE
            /* Simulated I/O */
            sioin_int();
#endif
		}

		/* Move data into place for FFT processing,
            and window the data.  Interrupts are
            disabled to prevent data corruption */
		set_pcw( 0x0017); /* Disable all interrupts, set wait states to 2 */

		{
			register float *windedptr, *shiftoutptr, *shiftinptr;

			windedptr = fftbuf1end; /* end of processing buffer */
			shiftoutptr = inbufxend; /* end of input buffer */
			shiftinptr = inbufend;
			for( i = 0; i++ < N;)
			{
                /* Real part */
				*windedptr-- = *shiftinptr;
				*shiftinptr-- = *shiftoutptr--;
                /* Imaginary part */
				*windedptr-- = *shiftinptr;
				*shiftinptr-- = *shiftoutptr--;
			}
		}
		inbufptr = inbuf + PROCLEN; /* reinitialize for ISR */
		set_pcw( 0x1017);

		/* Do the FFT, in place */
		chamm0(N,M,fftbuf1);
		fft(N,M,fftbuf1);


		/* set ready flag for fftbuf1, signal to sio output interrupt  */
		fft_rd_flag = 1;

		/* wait for input buffer to come full again */
		while( inbufptr < inbufxend )
		{
#ifdef SIMULATE
            /* Simulated I/O */
            sioin_int();
#endif
		}

		/* Move data into place for FFT processing,
            and window the data.  Interrupts are
            disabled to prevent data corruption */
		set_pcw( 0x0017);

		{
			register float *windedptr, *shiftoutptr, *shiftinptr;

			windedptr = fftbuf2end;
			shiftoutptr = inbufxend;
			shiftinptr = inbufend;
			for( i = 0; i++ < N;)
			{
                /* Real part */
				*windedptr-- = *shiftinptr;
				*shiftinptr-- = *shiftoutptr--;
                /* Imaginary part */
				*windedptr-- = *shiftinptr;
				*shiftinptr-- = *shiftoutptr--;
			}
		}
		set_pcw( 0x1017);

		/* Do the FFT, in place */
		chamm0(N,M,fftbuf2);
		fft(N,M,fftbuf2);



		/* set ready flag for fftbuf2, signal to sio output interrupt  */
		fft_rd_flag = 2;

	}
}
