#include <msp430x14x.h>
#include <stdio.h>

#include "basic.h"
#include "config.h"
#include "eventq.h"

typedef int Boolean;
// enum {false = 0, true = 1};

#define RXBUF_SIZE    (64)

static volatile unsigned char rxBuf[RXBUF_SIZE];
static volatile unsigned char rxBuf_ReadIndex;
static volatile unsigned char rxBuf_WriteIndex;
static volatile unsigned int charactersReceived;

#define TXBUF_SIZE    (256)
#define BUFFER_EMPTY  1

static volatile unsigned char txBuf[TXBUF_SIZE];
static volatile unsigned char txBuf_ReadIndex;
static volatile unsigned char txBuf_WriteIndex;
static volatile unsigned int charactersToTransmit;
static volatile unsigned char txBuf_Empty;

static unsigned int txCharsDropped = 0;

void UART_Init(void)
{
  txBuf_Empty = BUFFER_EMPTY;
  txBuf_ReadIndex = txBuf_WriteIndex = charactersToTransmit = 0;  
  rxBuf_ReadIndex = rxBuf_WriteIndex = charactersReceived = 0;  
  
  UCTL0 = CHAR;                         // 8-bit character
  UTCTL0 = SSEL1;                       // UCLK = ACLK
  UBR00 = 0x80;                         // 3.6864Mhz/9600 - 384 or 0x180
  UBR10 = 0x01;                         //
  UMCTL0 = 0x00;                        // no modulation
  ME1 |= UTXE0 + URXE0;                 // Enable USART0 TXD/RXD
  IE1 |= UTXIE0 + URXIE0;               // Enable USART0 TX & RX interrupts

  _EINT();  
}

void UART_Transmit(unsigned char byte)
{
  txBuf[txBuf_WriteIndex++] = byte;
  txBuf_WriteIndex &= (TXBUF_SIZE - 1);
  IE1 = IE1 & ~UTXIE0;                  // Disable Transmit Interrupt
  charactersToTransmit++;
  IE1 = IE1 | UTXIE0;                  // Enable Transmit Interrupt
  if (txBuf_Empty && charactersToTransmit) {
    txBuf_Empty = !BUFFER_EMPTY;
    TXBUF_0 = txBuf[txBuf_ReadIndex++];
    txBuf_ReadIndex &= (TXBUF_SIZE - 1);
    charactersToTransmit--;
  }
}

#if __VER__ < 200
interrupt [ UART0TX_VECTOR ] void UART_0_TX_Interrupt( void )
#else
#pragma vector=UART0TX_VECTOR
__interrupt void UART_0_TX_Interrupt( void )
#endif
{
  if (charactersToTransmit) {
    TXBUF_0 = txBuf[txBuf_ReadIndex++];
    txBuf_ReadIndex &= (TXBUF_SIZE - 1);
    charactersToTransmit--;   
  } else
    txBuf_Empty = BUFFER_EMPTY;

  _EINT();
}

Boolean UART_TransmitBufferFull(void)
{
  Boolean value;
  IE1 = IE1 & ~UTXIE0;                  // Disable Transmit Interrupt
  value = (charactersToTransmit == (TXBUF_SIZE - 1)) ? true : false; 
  IE1 = IE1 | UTXIE0;                  // Enable Transmit Interrupt 
  return value;
}

unsigned char UART_Receive(void)
{
  unsigned char byte;

  if (charactersReceived) {
    byte = rxBuf[rxBuf_ReadIndex++];
    rxBuf_ReadIndex &= (RXBUF_SIZE - 1);
    IE1 = IE1 & ~URXIE0;                  // Disable Receive Interrupt
    charactersReceived--;   
    IE1 = IE1 |  URXIE0;                  // Enable Receive Interrupt
    return byte;
  } else
    return 0;
}

#if __VER__ < 200
interrupt [ UART0RX_VECTOR ] void UART_0_RX_Interrupt( void )
#else
#pragma vector=UART0RX_VECTOR
__interrupt void UART_0_RX_Interrupt( void )
#endif
{
  rxBuf[rxBuf_WriteIndex++] = RXBUF_0;
  rxBuf_WriteIndex &= (RXBUF_SIZE - 1);
  charactersReceived++;
  eventqUrgentPut(EVENTQ_EVENT_UART0RX);
  _EINT();
  
}

