#include "xparameters.h"
#include "xutil.h"
#include "xio.h"
#include "xgpio.h"
#include "xtime_l.h"
#include "xexception_l.h"
#include "xintc.h"
#include "xstatus.h"
#include "sleep.h"

#include "cdc_hw.h"

#include <string.h>
#include <stdio.h>


//User Device Init and Interupt Setup
static XStatus Device_Init(void);
static XStatus Interrupt_Setup(void);

static void CDC_Handler(void);

short singen(void);


//Handles for Devices
XGpio      pushs;
XGpio      leds;
XIntc      intc;


//Interface Buffer Base Address
#define BUF_RX_BASE_ADDRESS  0x00000000
#define BUF_TX_BASE_ADDRESS  0x00001000

//Define pointer for buffer
unsigned int *buf_rx;
unsigned int *buf_tx;

unsigned int buf_temp[8];

// sine add
short y[3] = {0, 0x1492, 0};      // y(n), y(n-1), y(n-2)
short a1 = 0x7935;                // 2cos(wT)
short a2 = 0xc000;
short sin_temp;


//----------------------------------------------------------------
//MAIN
//----------------------------------------------------------------
int main (void) {
  int i=0, j=0;
  XStatus sys_status;

  //Sets up the interrupt vector table and registers a "do nothing"
  //function for each exception.
  //When using the exception hadler API, this function should be
  //called at the beginning of main() routine.
  XExc_Init();

  //
  //Device Initialization
  //
  sys_status = Device_Init();
  if(sys_status != XST_SUCCESS){ return sys_status; }

  //
  //Device Interrupt Setup
  //
  sys_status = Interrupt_Setup();
  if(sys_status != XST_SUCCESS){ return sys_status; }

  //Initialize interface buffer (with debug value)
  //Assign Phisical Adderss to buffer
  buf_rx = (unsigned int *)BUF_RX_BASE_ADDRESS;
  buf_tx = (unsigned int *)BUF_TX_BASE_ADDRESS;
  
  for(i=0; i<8; i++){
    buf_rx[i]=0;
    buf_tx[i]=0;
    buf_temp[i]=0;
  }
  
  
  //
  //Start Application
  //
  XGpio_DiscreteWrite(&leds, 1, 0xf );
  
  //Main Loop
  while(1){
    if (j==0) {
       REQ_RX_BUF;
       j=1;
    }
    
  }//End of Main Loop

   return 0;
}





//----------------------------------------------------------------
//OPB_CODEC_CNTLR Interrupt Handler
//----------------------------------------------------------------
static void CDC_Handler()
{
  static int l=0;
  static unsigned char p_in=0;
  
  p_in = XGpio_DiscreteRead(&pushs, 1);
  
  sin_temp = singen();
  
  if (p_in == 1) {
    for(l=0; l<8; l++){
        buf_temp[l] = buf_rx[l];
        buf_tx[l] = buf_temp[l];
    }
  } else {
     for(l=0; l<8; l++){
        buf_temp[l] = buf_rx[l];
        buf_tx[l] = buf_temp[l] + (int)(sin_temp << 2);
     }
  }

  SET_TX_BUF;
  usleep(1);
  FREE_TX_BUF;

}

//----------------------------------------------------------------
//Device Initialization
//----------------------------------------------------------------
static XStatus Device_Init()
{
  XStatus sys_status;

  //Initialize GPIO_LEDS Device
  sys_status = XGpio_Initialize(&leds, XPAR_LEDS_4BIT_DEVICE_ID);
  if(sys_status != XST_SUCCESS){ return sys_status; }
  XGpio_SetDataDirection(&leds, 1, 0x0);

  //Initialize GPIO_PUSHSW Device
  sys_status = XGpio_Initialize(&pushs, XPAR_PUSH_BUTTONS_POSITION_DEVICE_ID);
  if(sys_status != XST_SUCCESS){ return sys_status; }
  XGpio_SetDataDirection(&pushs, 1, 0x1);
  
  //Initialize INTC Device
  sys_status = XIntc_Initialize(&intc, XPAR_OPB_INTC_0_DEVICE_ID);
  if(sys_status != XST_SUCCESS){ return sys_status; }

  return XST_SUCCESS;
}


//----------------------------------------------------------------
//Device Interrupt Set up
//----------------------------------------------------------------
static XStatus Interrupt_Setup()
{
  XStatus sys_status;

  //-----------------
  //Register Handlers
  //-----------------

  //INTC
  XExc_RegisterHandler( XEXC_ID_NON_CRITICAL_INT,
                        (XExceptionHandler)XIntc_InterruptHandler,
                        &intc );


  //---------------------
  //Connect the Handlers.
  //---------------------

  //[0]=opb_codec_cntlr
  sys_status = XIntc_Connect( &intc,
                              XPAR_OPB_INTC_0_OPB_CODEC_CNTLR_0_RX_INTR_INTR,
                              (XInterruptHandler)CDC_Handler,
                              (void *)0 );
  if(sys_status != XST_SUCCESS){ return sys_status; }


  //--------------------------------
  //Start Interrupt Handling Process
  //--------------------------------

  //Enable the interrupt.
  XIntc_Enable(&intc, XPAR_OPB_INTC_0_OPB_CODEC_CNTLR_0_RX_INTR_INTR ); //[0]

  //Clear all interrupts for unwanted pending interrupts.
  XIntc_Acknowledge(&intc, XPAR_OPB_INTC_0_OPB_CODEC_CNTLR_0_RX_INTR_INTR ); //[0]

  //Enable non-critical exceptions
  XExc_mEnableExceptions(XEXC_NON_CRITICAL);

  //Start the interrupt controller.
  sys_status = XIntc_Start(&intc, XIN_REAL_MODE);
  if(sys_status != XST_SUCCESS){ return sys_status; }

  return XST_SUCCESS;
}


// sine gen
short singen () {

  y[0] = ((int)a1*y[1] + (int)a2*y[2]) >> 14;
  y[2] = y[1];
  y[1] = y[0];
  
  return(y[0]);
  
}
