/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2013 Semtech

Description: Implements the generic UART driver

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis and Gregory Cristian
*/
#include "board.h"
#include "uart-board.h"
#if defined( USE_USB_CDC )
#include "uart-usb-board.h"
#endif

#include "uart.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

extern uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);


/*!
 * Number of times the UartPutBuffer will try to send the buffer before
 * returning ERROR
 */
#define TX_BUFFER_RETRY_COUNT                       10

void UartInit( Uart_t *obj, uint8_t uartId, PinNames tx, PinNames rx )
{
    if( obj->IsInitialized == false )
    {
        obj->IsInitialized = true;

        if( uartId == UART_USB_CDC )
        {
#if defined( USE_USB_CDC )
            UartUsbInit( obj, uartId, NC, NC );
#endif
        }
        else
        {
            UartMcuInit( obj, uartId, tx, rx );
        }
    }
}

void UartConfig( Uart_t *obj, UartMode_t mode, uint32_t baudrate, WordLength_t wordLength, StopBits_t stopBits, Parity_t parity, FlowCtrl_t flowCtrl )
{
    if( obj->IsInitialized == false )
    {
        // UartInit function must be called first.
        assert_param( FAIL );
    }
    if( obj->UartId == UART_USB_CDC )
    {
#if defined( USE_USB_CDC )
        UartUsbConfig( obj, mode, baudrate, wordLength, stopBits, parity, flowCtrl );
#endif
    }
    else
    {
        UartMcuConfig( obj, mode, baudrate, wordLength, stopBits, parity, flowCtrl );
    }
}

void UartDeInit( Uart_t *obj )
{
    obj->IsInitialized = false;
    if( obj->UartId == UART_USB_CDC )
    {
#if defined( USE_USB_CDC )
        UartUsbDeInit( obj );
#endif
    }
    else
    {
        UartMcuDeInit( obj );
    }
}

uint8_t UartPutChar( Uart_t *obj, uint8_t data )
{
    if( obj->UartId == UART_USB_CDC )
    {
#if defined( USE_USB_CDC )
        return UartUsbPutChar( obj, data );
#else
        return 255; // Not supported
#endif
    }
    else
    {
        return UartMcuPutChar( obj, data );
    }
}

uint8_t UartGetChar( Uart_t *obj, uint8_t *data )
{
    if( obj->UartId == UART_USB_CDC )
    {
#if defined( USE_USB_CDC )
        return UartUsbGetChar( obj, data );
#else
        return 255; // Not supported
#endif
    }
    else
    {
        return UartMcuGetChar( obj, data );
    }
}

uint8_t UartPutBuffer( Uart_t *obj, uint8_t *buffer, uint16_t size )
{
    if( obj->UartId == UART_USB_CDC )
    {
#if defined( USE_USB_CDC )
        return UartUsbPutBuffer( obj, buffer, size );
#else
        return 255; // Not supported
#endif
    }
    else
    {
        uint8_t retryCount;
        uint16_t i;

        for( i = 0; i < size; i++ )
        {
            retryCount = 0;
            while( UartPutChar( obj, buffer[i] ) != 0 )
            {
                retryCount++;

                // Exit if something goes terribly wrong
                if( retryCount > TX_BUFFER_RETRY_COUNT )
                {
                    return 1; // Error
                }
            }
        }
        return 0; // OK
    }
}

void  DebugPrintf (char  *p_fmt, ...)
{
    if(1)
    {
        char    str[200u];
        uint8_t  len;

        va_list     vArgs;


        va_start(vArgs, p_fmt);

        vsprintf((char       *)str,
                 (char const *)p_fmt,
                               vArgs);

        va_end(vArgs);

        len = strlen(str);
        CDC_Transmit_FS((uint8_t*) str, len);
        UartPutBuffer(&Uart1, (uint8_t *)str, len);
    }

}

uint8_t UartGetBuffer( Uart_t *obj, uint8_t *buffer, uint16_t size, uint16_t *nbReadBytes )
{
    uint16_t localSize = 0;

    while( localSize < size )
    {
        if( UartGetChar( obj, buffer + localSize ) == 0 )
        {
            localSize++;
        }
        else
        {
            break;
        }
    }
    
    *nbReadBytes = localSize;
    
    if( localSize == 0 )
    {
        return 1; // Empty
    }
    return 0; // OK
}
