// Copyright (c) 2001-2004 Rowley Associates Limited.
//
// This file may be distributed under the terms of the License Agreement
// provided with this software.
//
// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
////////////////////////////////////////////////////////////////////////////////
//
//                    Atmel EB40A Interrupt Example
//
// Description
// -----------
// This example demonstrates a simple interrupt handler. When running, pressing
// the SW1-SW4 buttons causes the irq_handler to execute which toggles
// the LEDs.
//
////////////////////////////////////////////////////////////////////////////////

#include <targets/AT91x408xx.h>

// Interrupt definitions
#define AIC_SMR(n) (*(&AIC_SMR0 + n))
#define AIC_SVR(n) (*(&AIC_SVR0 + n))

#define AIC_PRIOR                       0x07    /* Priority */
#define AIC_SRCTYPE                     0x60    /* Source Type Definition */

#define AIC_SRCTYPE_INT_LEVEL_SENSITIVE 0x00    /* Level Sensitive */
#define AIC_SRCTYPE_INT_EDGE_TRIGGERED  0x20    /* Edge Triggered */
#define AIC_SRCTYPE_EXT_LOW_LEVEL       0x00    /* Low Level */
#define AIC_SRCTYPE_EXT_NEGATIVE_EDGE   0x20    /* Negative Edge */
#define AIC_SRCTYPE_EXT_HIGH_LEVEL      0x40    /* High Level */
#define AIC_SRCTYPE_EXT_POSITIVE_EDGE   0x60    /* Positive Edge */

// Peripheral interrupts
#define FIQ_ID          0       /* Fast Interrupt */
#define SWIRQ_ID        1       /* Soft Interrupt (generated by the AIC) */
#define US0_ID          2       /* USART Channel 0 interrupt */
#define US1_ID          3       /* USART Channel 1 interrupt */
#define TC0_ID          4       /* Timer Channel 0 interrupt */
#define TC1_ID          5       /* Timer Channel 1 interrupt */
#define TC2_ID          6       /* Timer Channel 2 interrupt */
#define WDI_ID          7       /* Watchdog interrupt */
#define PIO_ID          8       /* Parallel I/O Controller A interrupt */

#define IRQ0_ID         16      /* External interrupt 0 */
#define IRQ1_ID         17      /* External interrupt 1 */
#define IRQ2_ID         18      /* External interrupt 2 */

// PIO definitions
#define SW1 (1 << 12)
#define SW2 (1 << 9)
#define SW3 (1 << 1)
#define SW4 (1 << 2)

#define LED_3           1<<3
#define LED_4           1<<4
#define LED_5           1<<5
#define LED_6           1<<6
#define LED_16          1<<16
#define LED_17          1<<17
#define LED_18          1<<18
#define LED_19          1<<19
#define LEDS (LED_3 | LED_4 | LED_5 | LED_6 | LED_16 | LED_17 | LED_18 | LED_19)

void pio_irq_handler(void) __attribute__ ((interrupt ("IRQ")));

void
pio_irq_handler(void)
{
  unsigned long isr = PIO_ISR;
  unsigned long pdsr = PIO_PDSR;
  if (isr & SW1)
    {
      if (pdsr & SW1)
        PIO_CODR = LED_16 | LED_17;
      else
        PIO_SODR = LED_16 | LED_17;
    }
  if (isr & SW2)
    {
      if (pdsr & SW2)
        PIO_CODR = LED_18 | LED_19;
      else
        PIO_SODR = LED_18 | LED_19;
    }
  if (isr & SW3)
    {
      if (pdsr & SW3)
        PIO_CODR = LED_3 | LED_4;
      else
        PIO_SODR = LED_3 | LED_4;
    }
  if (isr & SW4)
    {
      if (pdsr & SW4)
        PIO_CODR = LED_5 | LED_6;
      else
        PIO_SODR = LED_5 | LED_6;
    }
  // Signal end of interrupt
  AIC_EOICR = 0;
}

int
main(void)
{
  // Put LDR PC, [PC, #-0xF20] instruction into IRQ vector in order to use 
  // hardware interrupt vectoring.
  *(volatile unsigned int *)0x00000018 = 0xE51FFF20;

   // Set up PIO interrupt
  __ARMLIB_enableIRQ();
  AIC_IDCR = 1 << PIO_ID;
  AIC_SVR(PIO_ID) = (unsigned)pio_irq_handler;
  AIC_SMR(PIO_ID) = AIC_SRCTYPE_INT_LEVEL_SENSITIVE;
  AIC_ICCR = 1 << PIO_ID;
  AIC_IECR = 1 << PIO_ID;

  // Setup PIO
  // LEDs SW1, SW2, SW3 and SW4 push buttons are debounced, buffered and connected to P12/FIQ, P9/IRQ0, P1/TIOA0 and P2/TIOB0, respectively.
  PIO_IER = SW1 | SW2 | SW3 | SW4;
  PIO_PER = LEDS | SW1 | SW2 | SW3 | SW4;
  PIO_OER = LEDS;
 
  while(1);

}
