#include "xparameters.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "xstatus.h"
#include "my_timer.h"
#include "xintc.h"

#define TIMER_RESET   0x00000000
#define TIMER_RUN     0x40000000
#define TIMER_EXPIRED 0x80000000
#define TIMER_HALFSEC 0x02FAF080
#define TIMER_TEST 	 0x002AF080

XGpio GpioOutput;
Xuint32 my_timer;
unsigned int *my_timer_p =
         (unsigned int *) XPAR_MY_TIMER_0_BASEADDR;

//----------------------------------------------------
// INTERRUPT HANDLER FUNCTION
//----------------------------------------------------
void MY_TIMER_Intr_Handler(void * baseaddr_p)
{
  static Xuint32 led_data;
  Xuint32 baseaddr;
  Xuint32 IpStatus;

  baseaddr = (Xuint32) baseaddr_p;

  // Get the timer interrupt status
  IpStatus = MY_TIMER_mReadReg(baseaddr,
                      MY_TIMER_INTR_IPISR_OFFSET);

  // If timer caused the interrupt then switch LEDs
  if (IpStatus){
    // If LEDs are ON then turn OFF and vice versa
    led_data = led_data ^ 0xFF;
    XGpio_DiscreteWrite(&GpioOutput, 1, led_data);
//	 xil_printf(".");
    // Reset the timer and hence the interrupt
    MY_TIMER_mWriteSlaveReg1(baseaddr, 0, TIMER_RESET);
    MY_TIMER_mWriteSlaveReg1(baseaddr, 0, TIMER_RUN);
  }
}

//----------------------------------------------------
// MAIN FUNCTION
//----------------------------------------------------
int main (void)
{
  Xuint32 status;

  // Clear screen
  xil_printf("%c[2J",27);
  xil_printf("  Timer Project from ");
  xil_printf("http://www.fpgadeveloper.com\r\n");
  xil_printf("  --------------------------------");
  xil_printf("-----------------\r\n\r\n");

  //----------------------------------------------------
  // REGISTER INTERRUPT HANDLER
  //----------------------------------------------------
  xil_printf("  - Registering interrupt handler\r\n");
  XIntc_RegisterHandler(XPAR_XPS_INTC_0_BASEADDR,
    XPAR_XPS_INTC_0_MY_TIMER_0_IP2INTC_IRPT_INTR,
    MY_TIMER_Intr_Handler,
    (void *)XPAR_MY_TIMER_0_BASEADDR);

  //----------------------------------------------------
  // INITIALIZE THE TIMER PERIPHERAL
  //----------------------------------------------------
  xil_printf("  - Initializing the timer peripheral\r\n");
  // Check that the my_timer peripheral exists
  XASSERT_NONVOID(my_timer_p != XNULL);
  my_timer = (Xuint32) my_timer_p;
  // Load the delay register with the delay time of 0.5s
  MY_TIMER_mWriteSlaveReg0(my_timer, 0, TIMER_TEST);

  //----------------------------------------------------
  // SETUP THE LEDs
  //----------------------------------------------------
  xil_printf("  - Setting up the LEDs\r\n");
  // Initialize the GPIO driver
  status = XGpio_Initialize(&GpioOutput,
                            XPAR_LEDS_8BIT_DEVICE_ID);
  if (status != XST_SUCCESS)
    return XST_FAILURE;
  // Set the direction for all signals to be outputs
  XGpio_SetDataDirection(&GpioOutput, 1, 0x0);
  // Turn the LEDs ON
  XGpio_DiscreteWrite(&GpioOutput, 1, 0xFF);

  //----------------------------------------------------
  // ENABLE INTERRUPTS
  //----------------------------------------------------
  xil_printf("  - Enabling interrupts\r\n");
  // Enable INTC interrupts
  XIntc_MasterEnable(XPAR_XPS_INTC_0_BASEADDR);
  XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR,
    XPAR_MY_TIMER_0_IP2INTC_IRPT_MASK);
  // Enable timer interrupts
  MY_TIMER_EnableInterrupt(my_timer_p);
  // Enable Microblaze interrupts
  microblaze_enable_interrupts();

  // Start the timer
  xil_printf("  - Starting the timer\r\n\r\n");
  MY_TIMER_mWriteSlaveReg1(my_timer, 0, TIMER_RUN);

  xil_printf("    SUCCESS!\r\n");
  while(1){
  }
}