/**********************************************************
 *                                                        
 * lab13.c
 *
 * EE 477  Spring 2004   R.C. Maher
 *                                                   
 * Based on bp.c                                     
 * Copyright (c) 2001 Analog Devices, Inc.           
 *                                                   
 **********************************************************/

/* ADSP-2106x System Register bit definitions */
#include <def21060.h>
#include <21060.h>
#include <signal.h>
#include <sport.h>
#include <macros.h>
#include <math.h>
#include <filters.h>

				/* DMA Chain pointer bit definitions */
#define CP_PCI 0x20000          /* Program-Controlled Interrupts bit */
#define CP_MAF 0x1ffff          /* Valid memory address field bits   */

#define SetIOP(addr, val)  (* (volatile int *) addr) = (val)
#define GetIOP(addr)       (* (volatile int *) addr)

/**********************************************************/

#define NUM_TAPS 10

float pm coeffs[NUM_TAPS] =
{
#include "fir.h"
};

float dm state[NUM_TAPS+1];

/**********************************************************/

#define SZ_regs_1847 16
int regs_1847[SZ_regs_1847] = {
	/* Note that the MCE bit is maintained throughout initial
	   programming to hold off premature autocalibration. */
	0xc007,                 /* index 0 - left input control RCM WAS 0xc000 */
	0xc107,                 /* index 1 - right input control RCM WAS 0xc100 */
	0xc280,                 /* index 2 - left aux 1 input control */
	0xc380,                 /* index 3 - right aux 1 input control */
	0xc480,                 /* index 4 - left aux 2 input control */
	0xc580,                 /* index 5 - right aux 2 input control */
	0xc600,                 /* index 6 - left dac control */
	0xc700,                 /* index 7 - right dac control */
	0xc85C,                 /* index 8 - data format RCM WAS 0xc850 */
	0xc909,                 /* index 9 - interface configuration */
	0xca00,                 /* index 10 - pin control */
	0xcb00,                 /* index 11 - no register */
	0xcc40,                 /* index 12 - miscellaneous information */
	0xcd00,                 /* index 13 - digital mix control */
	0xce00,                 /* index 14 - no register */
	0x8f00};                /* index 15 - no register */

unsigned rx_buf[3];                          /* receive buffer */
unsigned tx_buf[3] = {0xcc40, 0, 0};         /* transmit buffer */

/* DMA chaining Transfer Control Blocks */
typedef struct {
   unsigned   lpath3;     /* for mesh mulitprocessing  */
   unsigned   lpath2;     /* for mesh multiprocessing  */
   unsigned   lpath1;     /* for mesh multiprocessing  */
   unsigned   db;         /* General purpose register  */
   unsigned   gp;         /* General purpose register  */
   unsigned** cp;         /* Chain Pointer to next TCB */
   unsigned   c;          /* Count register            */
   unsigned   im;         /* Index modifier register   */
   unsigned * ii;         /* Index register            */
} _tcb;

_tcb rx_tcb = {0, 0, 0, 0, 0, 0, 3, 1, 0};      /* receive tcb */
_tcb tx_tcb = {0, 0, 0, 0, 0, 0, 3, 1, 0};      /* transmit tcb */

int cmd_blk[8];                                 /* command block */

static int xmit_count;
static int * xmit_ptr;

static int source;
static int filter;

/**********************************************************/
/*                                                        */
/* Periodic timer interrupt                               */
/*                                                        */
/**********************************************************/
void timer_lo_prior( int sig_num )
{
    sig_num=sig_num;

    // Toggle flag 2 LED.
    set_flag(SET_FLAG2, TGL_FLAG);
}

/**********************************************************/
/*                                                        */
/* Serial port transmit DMA complete                      */
/*                                                        */
/**********************************************************/
void spt0_asserted( int sig_num )
{
    // Check if there are more commands left to transmit.
    if( xmit_count )
    {
        // If so, put the command into the transmit buffer and update count.
        tx_buf[0] = *xmit_ptr++;
        xmit_count--;
    }
}

/**********************************************************/
/*                                                        */
/* Serial port receive DMA complete                       */
/*                                                        */
/* Sample processing code goes here!                      */
/*                                                        */
/**********************************************************/
void spr0_asserted( int sig_num )
{
    float filter_input,filter_output;
    int i;

/* On entry to this function,                             */
/* rx_buf[1] is left channel input sample                 */

filter_input = (int) rx_buf[1];


/* Just pass the input to the output                      */
/* (your FIR will replace next line)                      */

filter_output = filter_input;


//Make left and right outputs the same ( left: tx_buf[1], right: tx_buf[2] )
tx_buf[1]= (int)filter_output;
tx_buf[2]= tx_buf[1];

}

/**********************************************************/
/*                                                        */
/*                                                        */
/*                                                        */
/**********************************************************/
void setup_sports ( void )
{
    /* Configure SHARC serial port SPORT0 */

    /* Multichannel communications setup */
    sport0_iop.mtcs  = 0x00070007;       /* transmit on words 0,1,2,16,17,18 */
    sport0_iop.mrcs  = 0x00070007;       /* receive on words 0,1,2,16,17,18  */
    sport0_iop.mtccs = 0x00000000;       /* no companding on transmit        */
    sport0_iop.mrccs = 0x00000000;       /* no companding on receive         */

    /* TRANSMIT CONTROL REGISTER */
    /* STCTL0 <= 0x001c00f2      */
    /* An alternate (and more efficient) way of doing this would be to   */
    /* write the 32-bit register all at once with a statement like this: */
    /*        SetIOP(STCTL0, 0x001c00f2);                                */
    /* But the following is more descriptive...                          */

    sport0_iop.txc.mfd   = 1;    /* multichannel frame delay (MFD)       */
    sport0_iop.txc.schen = 1;    /* Tx DMA chaining enable               */
    sport0_iop.txc.sden  = 1;    /* Tx DMA enable                        */
    sport0_iop.txc.lafs  = 0;    /* Late TFS (alternate)                 */
    sport0_iop.txc.ltfs  = 0;    /* Active low TFS                       */
    sport0_iop.txc.ditfs = 0;    /* Data independent TFS                 */
    sport0_iop.txc.itfs  = 0;    /* Internally generated TFS             */
    sport0_iop.txc.tfsr  = 0;    /* TFS Required                         */

    sport0_iop.txc.ckre  = 0;    /* Data and FS on clock rising edge     */
    sport0_iop.txc.gclk  = 0;    /* Enable clock only during transmission*/
    sport0_iop.txc.iclk  = 0;    /* Internally generated Tx clock        */
    sport0_iop.txc.pack  = 0;    /* Unpack 32b words into two 16b tx's   */

    sport0_iop.txc.slen  = 15;   /* Data word length minus one           */
    sport0_iop.txc.sendn = 0;    /* Data word endian 1 = LSB first       */
    sport0_iop.txc.dtype = SPORT_DTYPE_RIGHT_JUSTIFY_SIGN_EXTEND;
				/* Data type specifier                  */
    sport0_iop.txc.spen  = 0;    /* Enable (clear for MC operation)      */

    /* RECEIVE CONTROL REGISTER */
    /* SRCTL0 <= 0x1f8c20f2     */
    sport0_iop.rxc.nch   = 31;   /* multichannel number of channels - 1  */
    sport0_iop.rxc.mce   = 1;    /* multichannel enable                  */
    sport0_iop.rxc.spl   = 0;    /* Loop back configure (test)           */
    sport0_iop.rxc.d2dma = 0;    /* Enable 2-dimensional DMA array       */
    sport0_iop.rxc.schen = 1;    /* Rx DMA chaining enable               */
    sport0_iop.rxc.sden  = 1;    /* Rx DMA enable                        */
    sport0_iop.rxc.lafs  = 0;    /* Late RFS (alternate)                 */
    sport0_iop.rxc.ltfs  = 0;    /* Active low RFS                       */
    sport0_iop.rxc.irfs  = 0;    /* Internally generated RFS             */
    sport0_iop.rxc.rfsr  = 1;    /* RFS Required                         */
    sport0_iop.rxc.ckre  = 0;    /* Data and FS on clock rising edge     */
    sport0_iop.rxc.gclk  = 0;    /* Enable clock only during transmission*/
    sport0_iop.rxc.iclk  = 0;    /* Internally generated Rx clock        */
    sport0_iop.rxc.pack  = 0;    /* Pack two 16b rx's into 32b word      */  

    sport0_iop.rxc.slen  = 15;   /* Data word length minus one           */
    sport0_iop.rxc.sendn = 0;    /* Data word endian 1 = LSB first       */
    sport0_iop.rxc.dtype = SPORT_DTYPE_RIGHT_JUSTIFY_SIGN_EXTEND;
				/* Data type specifier                  */
    sport0_iop.rxc.spen = 0;     /* Enable (clear for MC operation)      */

    /* Enable sport0 xmit & rcv irqs (DMA enabled) */
    interrupt(SIG_SPR0I, spr0_asserted);
    interrupt(SIG_SPT0I, spt0_asserted);

    /* Set up Transmit Transfer Control Block for chained DMA */
    tx_tcb.ii = tx_buf;          /* DMA source buffer address                */
    tx_tcb.cp = &tx_tcb.ii;      /* define ptr to next TCB (point to self)   */
    SetIOP(CP2, (((int)&tx_tcb.ii) & CP_MAF) | CP_PCI);
				/* define ptr to current TCB (kick off DMA) */
				/* (SPORT0 transmit uses DMA ch 2)          */

    /* Set up Receive Transfer Control Block for chained DMA */
    rx_tcb.ii = rx_buf;          /* DMA destination buffer address           */
    rx_tcb.cp = &rx_tcb.ii;      /* define ptr to next TCB (point to self)   */
    SetIOP(CP0, (((int)&rx_tcb.ii) & CP_MAF) | CP_PCI);
				/* define ptr to current TCB (kick off DMA) */
				/* (SPORT0 receive uses DMA ch 0)           */

}
/**********************************************************/
/*                                                        */
/*                                                        */
/*                                                        */
/**********************************************************/
void send_1847_config_cmds( void )
{
    // Set up pointer and counter to transmit commands.
    xmit_ptr   = regs_1847;
    xmit_count = SZ_regs_1847;

    // Wait for all commands to be transmitted.
    while( xmit_count )
        idle();

    // Wait for AD1847 autocal to start.
    while( !(rx_buf[0] & 0x0002) )
        idle();

    // Wait for AD1847 autocal to finish.
    while( rx_buf[0] & 0x0002 )
        idle();

    return;
}

/**********************************************************/
/*                                                        */
/*                                                        */
/*                                                        */
/**********************************************************/
void init_21k( void )
{
    // Disable timer and set rate to 4 Hz.
    timer_off();
    timer_set( 10000000, 10000000 );

    // Initialize pointer and counter to transmit commands.
    xmit_count = 0;
    xmit_ptr   = regs_1847;

    // Enable interrupt nesting.
    asm( "#include <def21060.h>" );
    asm( "bit set mode1 NESTM;"  );

    // Enable timer (low priority) interrupt.
    interrupt( SIG_TMZ, timer_lo_prior );

    // Turn flag LEDs off.
    set_flag( SET_FLAG2, SET_FLAG );

    return;
}

/**********************************************************/
/*                                                        */
/*                                                        */
/*                                                        */
/**********************************************************/
void main ( void )
{
    int i;
    int x;

    // Initialize state array for FIR filter.
    for( i=0 ; i<NUM_TAPS+1 ; i++ )
        state[i] = 0;
    
    // Initialize some SHARC registers.
    init_21k();

    // Reset the Codec.
    set_flag( SET_FLAG0, CLR_FLAG );    /* Put CODEC into RESET  */
    for( x=0 ; x<0xffff ; x++ )         /* Hold CODEC in RESET */
        ;
    set_flag( SET_FLAG0, SET_FLAG );    /* Release CODEC from RESET */

    // Configure SHARC serial port.
    setup_sports();
    
    // Send setup commands to CODEC.
    send_1847_config_cmds();
	send_1847_config_cmds();
	
    // Turn on all LEDs.
    set_flag(SET_FLAG2, CLR_FLAG);

    // Turn on the timer.
    timer_on();

    
    // Loop forever.
    for(;;)
    {
        idle();
    };
}

/**********************************************************/
/*                                                        */
/* End of lab13.c                                         */
/*                                                        */
/**********************************************************/