//
// Debug Unit to send messages
// By PEK '2006
//
// MCU: AT91SAM7S256
// Experiment board: AT91SAM7S-EK
//

#include "Board.h"

// Macros
#define SET_LED(x)          AT91C_BASE_PIOA->PIO_ODSR = (x)

// Definitions
#define INT_PRIO_DEBUG_RX   4               // Priority of interrupt
#define BAUD_RATE           MCK/16/19200    // 19200 bps

// Setup Debug Unit
__inline void setup_debug(unsigned int uiBaudrate, unsigned int uiParity, unsigned int uiMode)
{
    AT91C_BASE_PIOA->PIO_PDR = AT91C_PA9_DRXD | AT91C_PA10_DTXD;    // Enable peripheral pins
    AT91C_BASE_PIOA->PIO_ASR = AT91C_PA9_DRXD | AT91C_PA10_DTXD;    // Select the A function (Debug Unit)
    AT91C_BASE_DBGU->DBGU_BRGR = uiBaudrate; // Set baud rate
    AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_RSTSTA; // Enable receiver and transmitter
    AT91C_BASE_DBGU->DBGU_MR = uiParity | uiMode;   // Parity and mode
}

// Write byte to Debug Unit
__inline void write_debug_byte(unsigned char ucData)
{
    AT91C_BASE_DBGU->DBGU_THR = ucData; // Send byte
}

// Wait for empty transmit buffer and write byte to Debug Unit
__inline void write_debug_byte_wait(unsigned char ucData)
{
    while(!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXRDY));  // Wait for empty transmit buffer
    write_debug_byte(ucData);
}

// Read byte from Debug Unit
__inline unsigned char read_debug_byte(void)
{
    return AT91C_BASE_DBGU->DBGU_RHR;   // Read byte and reset receive status flag
}

// Wait and read incoming byte from Debug Unit
__inline unsigned char read_debug_byte_wait(void)
{
    while(!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_RXRDY));  // Wait for incoming byte
    return read_debug_byte();
}

// Debug RX ISR
void debug_rx_isr(void)
{
    unsigned char ucData;

    if(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_RXRDY)    // The right kind of system interrupt?
    {
        if(AT91F_US_Error((AT91PS_USART)AT91C_BASE_DBGU))    // Is there errors?
        {
            AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RSTSTA; // Reset status bits
            ucData = read_debug_byte(); // Reset receive status flag
        }
        else
        {
            ucData = read_debug_byte(); // Read byte and reset receive status flag

            SET_LED(~ucData & LED_MASK);    // Set LEDs accordning to received byte

            write_debug_byte_wait(~ucData); // Wait for empty transmit buffer and send the same byte inverted
        }
    }
}

// Main
int main()
{
    // Setup PIO
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;  // Enable clock to PIO
    AT91C_BASE_PIOA->PIO_OER = LED_MASK;    // Output on PA0-PA3
    AT91C_BASE_PIOA->PIO_OWER = LED_MASK;   // Enable to set/clear PA0-PA3 with status register
    SET_LED(0xF); // Clear leds

    // Setup Debug Unit
    setup_debug(BAUD_RATE, AT91C_US_PAR_NONE, AT91C_US_CHMODE_NORMAL);  // Baudrate, no parity, normal mode

    // Setup interrupts
    AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, INT_PRIO_DEBUG_RX, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, debug_rx_isr);
    AT91C_BASE_DBGU->DBGU_IER = AT91C_US_RXRDY; // RX Ready interrupt
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_SYS;

    while(1);
}
