//*****************************************************************************
//
// UARTFunctions.c - UART functions used in the CAN - UART bridge.
//
// Copyright (c) 2020 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
//
//   Redistribution and use in source and binary forms, with or without
//   modification, are permitted provided that the following conditions
//   are met:
//
//   Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the
//   distribution.
//
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "main.h"

static int rx_count;


//*****************************************************************************
//
// Configure the UART and its pins.  This must be called before UARTCharPut().
//
//*****************************************************************************
void ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0
    //
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    MAP_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Initialize the UART for I/O.
    //
    MAP_UARTConfigSetExpClk(UART0_BASE, 16000000, UART_BAUD,
        UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE);
    MAP_UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    MAP_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
    MAP_IntEnable(INT_UART0);
    // Initialize the circular buffer
    circular_buf_init(&g_sUARTBuffer, g_ui8UARTRxBuffer);
    rx_count = 0;
}

//*****************************************************************************
//
// CAN 0 Interrupt Handler. It checks for the cause of the interrupt, and
// maintains a count. When a receive interrupt occurs at least 4 bytes are
// in the FIFO. When 8 bytes are received, send them to the buffer for TX
// When a receive timeout occurs, read the FIFO and send all to the buffer.
// The goal is to store 8 bytes at a time in the buffer when continuous bytes
// are received, but to put any remaining bytes in the buffer when there is a
// break in the reception (receive timeout).
//
//*****************************************************************************
void UART0IntHandler(void)
{
    static uint8_t data[8];
    int i;

    if(MAP_UARTIntStatus(UART0_BASE, true) & UART_INT_RX)
    {
        MAP_UARTIntClear(UART0_BASE, UART_INT_RX);
        for(i = 0; i < 4; i++)
        {
            data[rx_count++] = MAP_UARTCharGet(UART0_BASE);
        }
        if(rx_count == 8)
        {
            for(i = 0; i < 8; i++)
            {
                if(circular_buf_put(&g_sUARTBuffer, data[i]) == false)
                {
                    g_ui32ErrFlag |= ERROR_UART_FIFO_FULL;
                    break;
                }
            }
            rx_count = 0;
        }
    }
    if(MAP_UARTIntStatus(UART0_BASE, true) & UART_INT_RT)
    {
        MAP_UARTIntClear(UART0_BASE, UART_INT_RT);
        while((i = MAP_UARTCharGetNonBlocking(UART0_BASE)) != -1)
        {
            data[rx_count++] = i;
        }
        for(i = 0; i < rx_count; i++)
        {
            if(circular_buf_put(&g_sUARTBuffer, data[i]) == false)
            {
                g_ui32ErrFlag |= ERROR_UART_FIFO_FULL;
                break;
            }
        }
        rx_count = 0;
    }
}
