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

#include "Board.h"

// Definitions
#define INT_PRIO_DEBUG      4               // Priority of interrupts
#define BAUD_RATE           MCK/16/19200    // 19200 bps
#define MSG_LEN             5               // Length of messages

// Global variables
char cpBuffer[MSG_LEN];  // Buffer


// 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
}

// Debug Unit ISR
void debug_unit_isr(void)
{
    if(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_ENDRX)    // Receive interrupt?
    {
        if(!AT91F_US_Error((AT91PS_USART)AT91C_BASE_DBGU))    // Is there not any errors?
        {
            AT91F_PDC_DisableRx(AT91C_BASE_PDC_DBGU);   // Disable read
            AT91F_PDC_SetRx(AT91C_BASE_PDC_DBGU, 0, MSG_LEN);  // Reset status flag (add value to counter)

            AT91F_PDC_SetTx(AT91C_BASE_PDC_DBGU, cpBuffer, MSG_LEN);  // Setup DMA for write operations
            AT91F_PDC_EnableTx(AT91C_BASE_PDC_DBGU);    // Enable write to send the same message back
        }
    }
    else if(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_ENDTX)    // Transmit interrupt?
    {
        if(!AT91F_US_Error((AT91PS_USART)AT91C_BASE_DBGU))    // Is there not any errors?
        {
            // Message sent ok
        }

        AT91F_PDC_DisableTx(AT91C_BASE_PDC_DBGU);   // Disable write
        AT91F_PDC_SetTx(AT91C_BASE_PDC_DBGU, 0, MSG_LEN);  // Reset status flag (add value to counter)

        AT91F_PDC_SetRx(AT91C_BASE_PDC_DBGU, cpBuffer, MSG_LEN);  // Setup DMA for read operations
        AT91F_PDC_EnableRx(AT91C_BASE_PDC_DBGU);    // Enable read
    }
}

// Main
int main()
{
    // Setup Debug Unit
    setup_debug(BAUD_RATE, AT91C_US_PAR_NONE, AT91C_US_CHMODE_NORMAL);  // Baudrate, no parity, normal mode
    AT91F_PDC_SetRx(AT91C_BASE_PDC_DBGU, cpBuffer, MSG_LEN);  // Setup DMA for read operations
    AT91F_PDC_SetTx(AT91C_BASE_PDC_DBGU, 0, MSG_LEN);   // Add value to write counter to reset status flag
    AT91F_PDC_EnableRx(AT91C_BASE_PDC_DBGU);    // Enable read

    // Setup interrupts
    AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, INT_PRIO_DEBUG, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, debug_unit_isr);
    AT91F_DBGU_InterruptEnable(AT91C_BASE_DBGU, AT91C_US_ENDRX | AT91C_US_ENDTX);    // Enable RX and TX interrupt
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_SYS;

    while(1);
}

