/******************************************************************************
  @file     hal_uart.c

  @brief    UART interface library. No HW flow control and optionally
            buffered TX transmission. Reception is always buffered.

******************************************************************************/

/******************************************************************************
* INCLUDES
*/
#include "hal_types.h"
#include "hal_uart.h"
#include "hal_board.h"
#include "util_buffer.h"
#include "hal_int.h"
#include "hal_mcu.h"
#include "hal_led_trxeb.h"

/******************************************************************************
* LOCAL VARIABLES
*/
static ringBuf_t rbRxBuf;

#ifndef HAL_DIRECT_UART_TX
static ringBuf_t rbTxBuf;
#endif

/**************************************************************************//**
* @fn      halUartRxIntEnable
*
* @brief   Enable UART RX interrupts on USCI_A1.
*
* @param   none
*
* @return  none
******************************************************************************/
static void halUartRxIntEnable(void)
{
    UCA1IE |= UCRXIE;
}


/**************************************************************************//**
* @fn      void halUartTxIntEnable(void)
*
* @brief   Enable UART TX interrupt on USCI_A1.
*
* @param   none
*
* @return  none
******************************************************************************/
#ifndef HAL_DIRECT_UART_TX
static void halUartTxIntEnable(void)
{
    UCA1IE |= UCTXIE;
}
#endif


/**************************************************************************//**
* @fn      halUartRxIntDisable(void)
*
* @brief   Disable UART RX interrupt on USCI_A1.
*
* @param   none
*
* @return  none
******************************************************************************/
static void halUartRxIntDisable(void)
{
    UCA1IE &= ~UCRXIE;
}


/**************************************************************************//**
* @fn      halUARTTxIntDisable
*
* @brief   Disable UART TX interrupt on USCI_A1.
*
* @param   none
*
* @return  none
******************************************************************************/
#ifndef HAL_DIRECT_UART_TX
static void halUartTxIntDisable(void)
{
    UCA1IE &= ~UCTXIE;
}
#endif


/**************************************************************************//**
* @fn      halUartRxGetByte(void)
*
* @brief   Read byte from UART RX buffer on USCI_A1.
*
* @param   none
*
* @return  none
******************************************************************************/
static uint8 halUartRxGetByte(void)
{
    return UCA1RXBUF;
}


/**************************************************************************//**
* @fn       halUartInit(uint8 baudrate, uint8 options)
*
* @brief    Initalise UART on USCI_A1. Supports the 8-N-1 format at baud rates
*           9600, 38400, 57600 and 115200 running on 8 MHz SMCLK.
*
* @param    baudrate    Baudrate
* @param    options     This parameter is ignored
*
* @return   none
******************************************************************************/
void halUartInit(uint8 baudrate, uint8 options)
{
    // For the moment, this UART implementation only
    // supports communication 8N1
    // i.e. ignore options arguments.

    UCA1CTL1 |= UCSWRST;                    // Keep USCI logic in reset state

    UCA1CTL1 |= UCSSEL1;                    // Set clock source SMCLK
    UCA1CTL1 &= ~UCSSEL0;

    switch (baudrate)
    {
    case HAL_UART_BAUDRATE_9600:
        UCA1BR0 = 0x41;                     // 8 MHz 9600
        UCA1BR1 = 0x03;                     // 8 MHz 9600
        break;

    case HAL_UART_BAUDRATE_19200:
        UCA1BR0 = 0xA0;                     // 8 MHz 19200
        UCA1BR1 = 0x01;                     // 8 MHz 19200
        break;

    case HAL_UART_BAUDRATE_38400:
        UCA1BR0 = 0xD0;                     // 8 MHz 38400
        UCA1BR1 = 0x00;                     // 8 MHz 38400
        break;

    case HAL_UART_BAUDRATE_57600:
        UCA1BR0 = 0x8A;                     // 8 MHz 57600
        UCA1BR1 = 0x00;                     // 8 MHz 57600
        break;

    case HAL_UART_BAUDRATE_115200:
        UCA1BR0 = 0x45;                     // 8 MHz 115200
        UCA1BR1 = 0x00;                     // 8 MHz 115200
        break;

    default:
        break;
    }

    UCA1CTL0 &= ~UCPEN;                     // No parity
    UCA1CTL0 &= ~UCSPB;                     // 1 stop bit
    UCA1CTL0 &= ~UC7BIT;                    // 8 data bits

    P5SEL |= BIT6;                          // P5.6 = USCI_A1 TXD
    P5SEL |= BIT7;                          // P5.7 = USCI_A1 RXD

    UCA1CTL1 &= ~UCSWRST;                   // Initialize USCI_A1 state machine

    bufInit(&rbRxBuf);                      // Initialize ringbuffer

    halUartRxIntEnable();                   // Enable RX interrupt

//    // Enable RX Flow
//    halUartEnableRxFlow(TRUE);

}


/**************************************************************************//**
* @fn      halUartWrite(const uint8* buf, uint8 length)
*
* @brief   Write data buffer to UART on USCI_A1.
*
* @param   buf      Pointer to buffer with data to write
* @param   length   Number of bytes to write
*
* @return  Number of bytes written
******************************************************************************/
uint8 halUartWrite(const uint8* buf, uint8 length)
{
    uint16 i;
    for(i = 0; i < length; i++)
    {
        while( !(UCA1IFG & UCTXIFG) );   // Wait for TX buffer ready to receive new byte
        UCA1TXBUF = buf[i];            // Output character
    }
    return (i+1);
}


#ifndef HAL_DIRECT_UART_TX
/**************************************************************************//**
* @fn      halUartBufferedWrite(const uint8* buf, uint8 length)
*
* @brief   Write data buffered to UART. Data is written into a buffer, and the
*          buffer is emptied by UART TX interrupt ISR.
*          @warning THIS FUNCTION HAS NOT BEED THOROUGHLY TESTED!
*
* @param   buf      Pointer to buffer with data to write
*          length   Number of bytes to write
*
* @return  none
******************************************************************************/
uint8 halUartBufferedWrite(const uint8* buf, uint8 length)
{
    uint8 nBytes=0;
    uint8 ch;

    // Try to push the given bytes to buffer, try until there's room.
    while ( (nBytes += bufPut(&rbTxBuf,buf,length)) == 0 )

    // Wait a bit before we send data
    halMcuWaitMs(5);

    // Enable UART TX interrupt
    halUartTxIntEnable();

    // Init TX by pushing the first byte from buffer to USCI_A1.
    // ISR fixes the rest ...
    if ( bufGet(&rbTxBuf,&ch,1) == 1 )
    {
        UCA1TXBUF = ch;
    }

    return nBytes;
}
#endif


/**************************************************************************//**
* @fn      halUartRead(uint8* buf, uint8 length)
*
* @brief   Read data from UART Rx buffer on USCI_A1.
*
* @param   buf      Pointer to buffer with data to read in to
* @param   length   Number of bytes to read
*
* @return  Byte read from buffer
******************************************************************************/
uint8 halUartRead(uint8* buf, uint8 length)
{
    return bufGet(&rbRxBuf, (uint8 *)buf, length);
}


/**************************************************************************//**
* @fn      halUartGetNumRxBytes(void)
*
* @brief   Returns number of bytes in RX buffer
*
* @param   none
*
* @return  Number of bytes in RX buffer
******************************************************************************/
uint8 halUartGetNumRxBytes(void)
{
    return bufNumBytes(&rbRxBuf);
}


/**************************************************************************//**
* @fn      halUartEnableRxFlow
*
* @brief   Signal ready/not ready to receive characters on UART.
*          @warning Flow control is currently NOT supported on TrxEB!
*
* @param   enable   TRUE to signal ready to receive on UART
*                   FALSE to signal not ready to receive on UART
*
* @return  none
******************************************************************************/
void halUartEnableRxFlow(uint8 enable)
{
    // Enable RX flow
    if(enable) {
        //HAL_RTS_CLR();
    }
    // Disable RX flow
    else {
        //HAL_RTS_SET();
    }
}


/**************************************************************************//**
* @fn       HAL_ISR_FUNCTION(usciA1_ISR, USCI_A1)
*
* @brief    usciA1_ISR(): ISR framework for the USCI_A1 Receive and Transmit
*           components.
*
* @param    none
*
* @return   none
******************************************************************************/
HAL_ISR_FUNCTION(usciA1_ISR,USCI_A1)
{
    uint8 ch;

    // TX and RX interrupts share interrupt vector. Switch through USCI_A1
    // interrupt vector register to figure out what interrupt has occurred.
    switch( __even_in_range(UCA1IV,4) )
  {
    case 0: break;                          // Vector 0 - no interrupt
    case 2:                                 // Vector 2 - RXIFG
        ch = halUartRxGetByte();
        bufPut(&rbRxBuf,&ch,1); // Put byte in buffer
        break;
#ifndef HAL_DIRECT_UART_TX
    case 4:                                 // Vector 4 - TXIFG
        // If we have a bytes in buffer, get it and push it to UART buffer
        if (bufGet(&rbTxBuf,&ch,1)==1)
        {
            UCA1TXBUF = ch;
        }
        // If buffer empty, disable uart TX interrupt
        if( (bufNumBytes(&rbTxBuf)) == 0 )
        {
            halUartTxIntDisable();
        }
      break;
#endif
    default: break;
  }
    __low_power_mode_off_on_exit();
}


/***********************************************************************************
  Copyright 2007 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
***********************************************************************************/

