//----------------------------------------------------------------------------------
// <copyright file="uart.c" company="LiquidRobotics">
//	Copyright (c) Liquid Robotics Corporation.  All rights reserved.
// </copyright>
//
// <summary>
// 	AVR 2650 UART configuration and queue service functions (ISR's are in UART_ISR.S)
// </summary>
//
// <owner>Mike Cookson</owner>
//---------------------------------------------------------------------------------

#include "includes.h"
#include <util/atomic.h>
#include <string.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include "uart.h"


// an array of structures that define variables for each port
uart_t uart_devctl[UART_NUM_PORTS];

// array of pointers to registers
uart_regs_t uart_regs[UART_NUM_PORTS] =
{
	{ 0, (uart_peripheral_t*) (0xC0) },
	{ 1, (uart_peripheral_t*) (0xC8) },
	{ 2, (uart_peripheral_t*) (0xD0) },
	{ 3, (uart_peripheral_t*) (0x130) },
};

// input and output character buffers
char rxbuffer[UART_NUM_PORTS][UART_RX_BUFFER_SIZE] __attribute__((section(".xbig")));
char txbuffer[UART_NUM_PORTS][UART_TX_BUFFER_SIZE] __attribute__((section(".xbig")));

/*PAGE*/
/*
 *******************************************************************************
 *                              INIITALIZE THE UART
 *
 * Description :	Sets up a UART
 *
 * Arguments : 		UART specifier in the range [0-3]
 *
 *					baud rate (e.g. 9600),
 *
 *					data bits:
 *
 *						UART_MODE_FIVE_DATA_BITS
 *						UART_MODE_SIX_DATA_BITS
 *						UART_MODE_SEVEN_DATA_BITS
 *						UART_MODE_EIGHT_DATA_BITS
 *
 *					stop bits:
 *
 *						UART_MODE_ONE_STOP_BIT
 *						UART_MODE_TWO_STOP_BITS
 *
 *					parity:
 *
 *						UART_MODE_NO_PARITY
 *						UART_MODE_EVEN_PARITY
 *						UART_MODE_ODD_PARITY
 *
 * Returns:			OS_ERR_NONE if no error
 *					OS_ERR_UART_ID_INVALID if the port ID is out of range
 *					OS_ERR_UART_DUPLICATE_INIT if the UART was already initialized
 *
 * Notes:			
 *******************************************************************************
 */
uint8_t OSuartInitPort(uint8_t uart_id, uint32_t baud_rate, uint8_t databits, uint8_t stopbits, uint8_t parity)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;
		
	uart_t* puart = &uart_devctl[uart_id];
	uart_regs_t* pregs = &uart_regs[uart_id];
	uart_peripheral_t* pper = pregs->pper;
	uint16_t brrVal = (uint16_t) UART_BRR(baud_rate);
	
	if (puart->prxevent)
		return OS_ERR_UART_DUPLICATE_INIT;

	puart->prxevent = OSMboxCreate((void*) 0);
	puart->ptxevent = OSMboxCreate((void*) 0);

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		OSuartEnableDriver(pregs, OS_TRUE);
		pper->ubrrH = (uint8_t) (brrVal >> 8);
		pper->ubrrL = (uint8_t) brrVal;
		pper->ucsra = 0;
		pper->ucsrb = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
		pper->ucsrc = UART_MODE(UART_MODE_ASYNCH, databits, stopbits, parity);
	}

	return OS_ERR_NONE;
}



/*PAGE*/
/*
 *******************************************************************************
 *                UPDATE THE UART WITH NEW COMMUNICATION PARAMETERS
 *
 * Description :	Modifies the communicatin parameters for a UART
 *
 * Arguments : 		UART specifier in the range [0-3]
 *
 *					baud rate (e.g. 9600),
 *
 *					data bits:
 *
 *						UART_MODE_FIVE_DATA_BITS
 *						UART_MODE_SIX_DATA_BITS
 *						UART_MODE_SEVEN_DATA_BITS
 *						UART_MODE_EIGHT_DATA_BITS
 *
 *					stop bits:
 *
 *						UART_MODE_ONE_STOP_BIT
 *						UART_MODE_TWO_STOP_BITS
 *
 *					parity:
 *
 *						UART_MODE_NO_PARITY
 *						UART_MODE_EVEN_PARITY
 *						UART_MODE_ODD_PARITY
 *
 * Returns:			OS_ERR_NONE if no error
 *					OS_ERR_UART_ID_INVALID if the port ID is out of range
 *					OS_ERR_UART_NOT_INITIALIZED if the UART was not previously initialized
 *
 * Notes:			
 *******************************************************************************
 */
uint8_t OSuartUpdatePort(uint8_t uart_id, uint32_t baud_rate, uint8_t databits, uint8_t stopbits, uint8_t parity)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;
		
	uart_t* puart = &uart_devctl[uart_id];
	uart_regs_t* pregs = &uart_regs[uart_id];
	uart_peripheral_t* pper = pregs->pper;
	uint16_t brrVal = (uint16_t) UART_BRR(baud_rate);
	
	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{
		pper->ucsrb = 0;			//_BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);

		pper->ubrrH = (uint8_t) (brrVal >> 8);
		pper->ubrrL = (uint8_t) brrVal;
		pper->ucsra = 0;
		pper->ucsrb = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
		pper->ucsrc = UART_MODE(UART_MODE_ASYNCH, databits, stopbits, parity);
	}

	return OS_ERR_NONE;
}

/*PAGE*/
/*
 *******************************************************************************
 *                          SETS UARTS TO DEFAULT STATE
 *
 * Description:			This routine should be called at program startup to set
 *						the UARTS to their default state before configuring for
 *						individual application need.  By default, the interrupts
 *						will be disabled and the ports will be powered off.
 *
 * Arguments:			n/a
 *
 * Returns:				n/a	
 *
 * Notes:
 *******************************************************************************
 */
void OSuartDefaultState()
{
	uint8_t portnum = 0;
	uart_regs_t* pregs = uart_regs;

	for ( ; portnum < UART_NUM_PORTS; ++portnum, ++pregs)
	{
		pregs->pper->ucsrb = 0;							// turns off all interrupts
		OSuartEnableDriver(pregs, OS_FALSE);			// disable the driver for the port
		OSuartClearDevctl(&uart_devctl[portnum]);		// clears the device control block
	}
}

/*PAGE*/
/*
 *******************************************************************************
 *                          POWERS A PORT DRIVER ON OR OFF
 *
 * Description:			This routine enables or disables the RS232 drivers for a
 *						given port and enables or disables power to the UART
 *
 * Arguments:			state is set to TRUE to power the port on, or FALSE to
 *						power the port off
 *
 * Returns:				n/a	
 *
 * Notes:
 *******************************************************************************
 */
void OSuartEnableDriver(uart_regs_t* pregs, uint8_t state)
{
#if 1
	switch(pregs->uart_id)
	{
		case 0:		UART_CONFIG_PORT_0(state);	break;
		case 1:		UART_CONFIG_PORT_1(state);	break;
		case 2:		UART_CONFIG_PORT_2(state);	break;
		case 3:		UART_CONFIG_PORT_3(state);	break;
	}
#else
	switch(pregs->uart_id)
	{
		case 0:
			
			UART_SET_BY_STATE(!state, PRR0, _BV(PRUSART0));
			UART_SET_REG_MASKS(DDRE, 1, 2);
			UART_SET_BY_STATE(state, PORTE, 8);
			break;

		case 1:

			UART_SET_BY_STATE(!state, PRR1, _BV(PRUSART1));
			UART_SET_REG_MASKS(DDRD, 4, 8);
			UART_SET_REG_MASKS(DDRK, 0, 3);
			UART_SET_REG_MASKS(PORTK, 1, 2);
			break;

		case 2:

			UART_SET_BY_STATE(!state, PRR1, _BV(PRUSART2));
			UART_SET_REG_MASKS(DDRH, 1, 0x32);
			UART_SET_REG_MASKS(PORTH, 0x10, 0x20);
			break;

		case 3:

			UART_SET_BY_STATE(!state, PRR1, _BV(PRUSART3));
			UART_SET_REG_MASKS(DDRJ, 1, 2);
			UART_SET_REG_MASKS(DDRF, 0, 3);
			UART_SET_REG_MASKS(PORTF, 1, 2);
			break;
	}
#endif
}

/*PAGE*/
/*
 *******************************************************************************
 *                   SETS A DEVCTL STRUCTURE TO DEFAULT STATE
 *
 * Description:			This routine sets the indicated devctl structure to the
 *						default state.  Note that initially the pointers are not
 *						set up for a mailbox: this also indicates that the port
 *						has not been enabled.  This routine should only be called
 *						at startup since it overwrites the event pointers in the
 *						structure.
 *
 * Arguments:			puart points to a devctl block to be initiialized
 *
 * Returns:				n/a	
 *
 * Notes:
 *******************************************************************************
 */
void OSuartClearDevctl(uart_t* puart)
{
	puart->frame_errors = 0;
	puart->uart_overrun_errors = 0;
	puart->fifo_overrun_errors = 0;
	puart->rxinptr = 0;
	puart->rxoutptr = 0;
	puart->txinptr = 0;
	puart->txoutptr = 0;
	puart->rxcnt = 0;
	puart->uart_base = (uint8_t*) 0;
	puart->prxevent = (OS_EVENT*) 0;
	puart->stale_EMPTY = 1;
	puart->stale_STALE = 0;
	puart->ptxevent = (OS_EVENT*) 0;
	puart->txcnt = 0;
}


/*PAGE*/
/*
 *******************************************************************************
 *                              GET A CHARACTER FROM THE UART
 *
 * Description :    Gets a character from the UART
 *
 * Arguments   :    uart_id specifies the port from which to read [0-3]
 *
 *					max_wait is the number of ticks to wait, 0=wait forever
 *					(see OSMboxPend)
 *
 *					err points to a variable that indicates the status of the
 *					function (if NULL no error value is returned):
 *
 *						OS_ERR_NONE indicates that a character was read
 *
 *						OS_ERR_TIMEOUT indicates no character was read within
 *						the timeout
 *
 *						OS_ERR_UART_ID_INVALID if the uart_id was out of range
 *
 *						OS_ERR_UART_NOT_INITIALIZED if the uart was not initialized
 *
 *					See OSMboxPend for other possible values.
 *
 * Returns     :    The character that was read or 0 if an error occurred
 * 
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartGetCharWait(uint8_t uart_id, uint16_t max_wait, uint8_t *err)
{
	if (uart_id >= UART_NUM_PORTS)
	{
		if (err) *err = OS_ERR_UART_ID_INVALID;
		return 0;
	}

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
	{
		if (err) *err = OS_ERR_UART_NOT_INITIALIZED;
		return 0;
	}

	uint8_t localerr = OS_ERR_NONE;
	uint8_t data = 0;
	BOOLEAN dataRead = OS_FALSE;

    do {

        // pull a character from the buffer atomically (if the buffer is not empty)
		OS_CPU_SR cpu_sr;
		OS_ENTER_CRITICAL();

        if (puart->rxcnt)
		{
			if (!--puart->rxcnt)
				puart->stale_EMPTY = 1;

            data = rxbuffer[uart_id][puart->rxoutptr++];
			dataRead = OS_TRUE;
        }

		OS_EXIT_CRITICAL();

        // there was no character so wait for the event to be posted
		if (!dataRead)
        	OSMboxPend(puart->prxevent, max_wait, &localerr);
//        	OSMboxPend(puart->prxevent, max_wait, err);


    } while (!dataRead && (localerr == OS_ERR_NONE));



	if (err) *err = localerr;
    return data;
}

/*PAGE*/
/*
 *******************************************************************************
 *                              PUT A CHARACTER TO THE UART
 *
 * Description :    Puts a character to the UART
 *
 * Arguments   :    uart_it specifies the UART in the range [0-3]
 *
 *                  ch is the character to send to the UART
 *
 *                  timeout is the number of ticks to wait for the FIFO to become
 *					available, 0=wait forever (see OSMboxPend)
 *
 * Returns     :    The OS return status of the function:
 *
 *						OS_ERR_NONE indicates that the character was put into the
 *						FIFO
 *
 *						OS_ERR_TIMEOUT indicates that the FIFO was never made
 *						available for write within the specified timeout
 *
 *						OS_ERR_UART_ID_INVALID if the uart_id was out of range
 *
 *						OS_ERR_UART_NOT_INITIALIZED if the uart was not initialized
 *
 *					See OSMboxPend for other possible values.
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartPutCharWait(uint8_t uart_id, uint8_t ch, uint16_t timeout)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

    uint8_t res = OS_ERR_NONE;
	uart_peripheral_t* pper = uart_regs[uart_id].pper;
	BOOLEAN written = OS_FALSE;

    do {

		// while checking for interrupts enabled and inserting into FIFO, keep
		// interrupts disabled
		OS_CPU_SR cpu_sr;
		OS_ENTER_CRITICAL();

		// if interrupts are disabled ...			
		if ((pper->ucsrb & _BV(UDRIE0)) == 0)
		{
			// if the data register is empty, just write the character
			if (pper->ucsra & _BV(UDRE0))
			{
				pper->udr = ch;
				written = OS_TRUE;
			}
		}

		// if there's enough space to write another character, then write it
		// and enable interrupts
		if (!written && (puart->txcnt < (UART_TX_BUFFER_SIZE-1))) // txcnt is only 8 bits, so don't fill completely
		{
			++puart->txcnt;
			txbuffer[uart_id][puart->txinptr++] = ch;
			pper->ucsrb |= _BV(UDRIE0);
			written = OS_TRUE;
		}

		OS_EXIT_CRITICAL();


        // if no character written, wait for the task to wake up
		if (!written)
        	OSMboxPend(puart->ptxevent, timeout, &res);

    } while(!written && (res == OS_ERR_NONE));

    return res;   // returns the result
}

/*PAGE*/
/*
 *******************************************************************************
 *          TRANSMITS OR BUFFERS A STRING FOR TRANSMISSION WITH TIMEOUT
 *
 * Description :    Transmits a string or buffers data for transmission,
 *					bounded by a timeout (i.e. the function will not wait
 *					for more than the indicated timeout for space in the
 *					transmit buffer to be made available.)
 *
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					pstr points to a null-terminated string to be transmitted
 *
 *					timeout is the number of timer ticks to wait for space
 *					in the transmit buffer (0=wait forever)
 *
 *					err points to the variable that receives the status of the
 *					function
 *
 * Returns     :    The number of bytes actually transmitted or bufferred for
 *					transmission
 *
 *					The variable that "err" points to will be set as follows:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 *					See OSMboxPend for other possible values.
 *
 * Notes       :    
 *******************************************************************************
 */
uint16_t OSuartPutStrWait(uint8_t uart_id, char* pstr, uint16_t timeout, uint8_t* err)
{
	return OSuartPutBlockWait(uart_id, (uint8_t*) pstr, (uint16_t) strlen(pstr), timeout, err);
}

/*PAGE*/
/*
 *******************************************************************************
 *      TRANSMITS OR BUFFERS A BLOCK OF DATA FOR TRANSMISSION WITH TIMEOUT
 *
 * Description :    Transmits a block of data or buffers data for transmission,
 *					bounded by a timeout (i.e. the function will not wait
 *					for more than the indicated timeout for space in the
 *					transmit buffer to be made available.)
 *
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					pdata points to the block of data to transmit
 *
 *					count is the number of bytes to be transmitted
 *
 *					timeout is the number of timer ticks to wait for space
 *					in the transmit buffer (0=wait forever)
 *
 *					err points to the variable that receives the status of the
 *					function (NULL indicates that no error status should be
 *					returned)
 *
 * Returns     :    The number of bytes actually transmitted or bufferred for
 *					transmission
 *
 *					The variable that "err" points to will be set as follows:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 *					See OSMboxPend for other possible values.
 *
 * Notes       :    
 *******************************************************************************
 */
uint16_t OSuartPutBlockWait(uint8_t uart_id, uint8_t* pdata, uint16_t count, uint16_t timeout, uint8_t* err)
{
	uint8_t* pdata2 = pdata;
	uint8_t localerr = OS_ERR_NONE;
    
	while(count-- && ((localerr = OSuartPutCharWait(uart_id, *pdata2, timeout)) == OS_ERR_NONE))
		++pdata2;

	if (err) *err = localerr;

	return pdata2-pdata;
}

/*PAGE*/
/*
 *******************************************************************************
 *                          HANDLE TIMER TICK TASKS FOR UART
 *
 * Description :    Handles timer tick tasks for the UART, which includes waking
 *					up pending tasks where the queue is not empty.  The algorithm
 *					is:
 *
 *						for each port
 *							if the port is configured
 *								if the EMPTY flag is off
 *									if the STALE flag is is on
 *										if there are any tasks waiting, post a NULL
 *									else
 *										set STALE
 *									endif
 * 								endif
 *								if the transmitter fifo is empty and at least one
 *								task waiting
 *									wake up waiting tasks
 *								endif
 *							endif
 *						endfor
 *
 * Arguments   :    n/a
 *
 * Returns     :    n/a
 *
 * Notes       :    Call only from the timer tick ISR with interrupts disabled.
 *******************************************************************************
 */
void OSuartTimerTickHandler(void)
{
	uart_t* puart = uart_devctl;			// point to start of devctl blocks
  uint8_t portNum = 0;          // current port number

	// for each port ...
  for ( ; portNum < UART_NUM_PORTS; ++puart, ++portNum)
	{
		// if the port is configured
		if (puart->prxevent)
		{
			// if the receiver fifo is not empty
			if (!puart->stale_EMPTY)
			{
				// if the data is already marked stale, wake up any task that is sleeping
				if (puart->stale_STALE)
				{
					if (puart->prxevent->OSEventGrp != 0)
            OSMboxPost(puart->prxevent, (void*) (0x100+portNum));
				}

				// otherwise, 
				else
					puart->stale_STALE = 1;
			}

			// if the transmitter fifo is empty and one or more tasks waiting, wake up
			if (!puart->txcnt && (puart->ptxevent->OSEventGrp != 0))
        OSMboxPost(puart->ptxevent, (void*) (0x200+portNum));
		}
	}
}

/*PAGE*/
/*
 *******************************************************************************
 *                       READ UART READ BUFFER STATISTICS
 *
 * Description :    Reads the statistics for the UART "read" ring buffer into
 *					variables indicated by the provided pointers; any pointer
 *					can be NULL, skipping return of that item.
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					pRXCount points to a variable that recieves the number of
 *					bytes available for read immediately (NULL=don't read)
 *
 *					pFrameErrors points to a variable that receives the number
 *					of frame errors (NULL=don't read)
 *
 *					pUARTOverruns points to a variable that receives the number
 *					of events in which the UART was not read before another
 *					byte was received (NULL=don't read)
 *
 *					pFIFOOverrun points to a variable that recieves the number
 *					of events in which the read buffer was full when another
 *					byte was read.
 *
 * Returns     :    A code indicating success or failure of the call:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartGetReadStats(uint8_t uart_id, uint16_t* pRxCount, uint16_t* pFrameErrors, uint16_t* pUARTOverruns, uint16_t* pFIFOOverruns)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

	OS_CPU_SR cpu_sr;
	OS_ENTER_CRITICAL();

	if (pRxCount)		*pRxCount = puart->rxcnt;
	if (pFrameErrors)	*pFrameErrors = puart->frame_errors;
	if (pUARTOverruns)	*pUARTOverruns = puart->uart_overrun_errors;
	if (pFIFOOverruns)	*pFIFOOverruns = puart->fifo_overrun_errors;

	OS_EXIT_CRITICAL();
	return OS_ERR_NONE;
}

/*PAGE*/
/*
 *******************************************************************************
 *                       READ UART WRITE BUFFER STATISTICS
 *
 * Description :    Reads the statistics for the UART "write" ring buffer into
 *					variables indicated by the provided pointers; any pointer
 *					can be NULL, skipping return of that item.
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					pTxCount points to a variable that recieves the number of
 *					bytes buffered for output over the serial port.
 *
 * Returns     :    A code indicating success or failure of the call:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartGetWriteStats(uint8_t uart_id, uint16_t* pTxCount)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

	OS_CPU_SR cpu_sr;
	OS_ENTER_CRITICAL();

	if (pTxCount)		*pTxCount = puart->txcnt;

	OS_EXIT_CRITICAL();
	return OS_ERR_NONE;
}

/*PAGE*/
/*
 *******************************************************************************
 *                       READ UART BUFFER OFFSETS
 *
 * Description :    Reads the read and write ring buffer offsets for a port into
 *					variables indicated by the provided pointers; any pointer
 *					can be NULL, skipping return of that item.
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					pRxIn points to a variable that will receive the offset in
 *					the "read" ring at which the next byte from the UART will be
 *					stored (NULL=don't read)
 *
 *					pRxOut points to a variable that will receive the offset in
 *					the "read" ring at which the next byte returned by the port
 *					read function will be read (NULL=don't read)
 *
 *					pTxIn points to a variable that will recieve the offset in
 *					the "write" ring at which the next byte will be buffered for
 *					transmission (NULL=don't read)
 *
 *					pTxOut points to a variable that will recieve the offset in
 *					the "write" wring from which the transmitter ISR will read
 *					the next byte to be sent over the UART
 *
 * Returns     :    A code indicating success or failure of the call:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartGetBufferOffsets(uint8_t uart_id, uint8_t* pRxIn, uint8_t* pRxOut, uint8_t* pTxIn, uint8_t* pTxOut)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

	OS_CPU_SR cpu_sr;
	OS_ENTER_CRITICAL();

	if (pRxIn)			*pRxIn = puart->rxinptr;
	if (pRxOut)			*pRxOut = puart->rxoutptr;
	if (pTxIn)			*pTxIn = puart->txinptr;
	if (pTxOut)			*pTxOut = puart->txoutptr;

	OS_EXIT_CRITICAL();
	return OS_ERR_NONE;
}

/*PAGE*/
/*
 *******************************************************************************
 *                       READ UART BUFFER OFFSETS
 *
 * Description :    Resets the in, out, and count values for UART buffers
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *
 *					flags indicates whether to reset the Receive, transmit,
 *						or both buffers for the given port
 *
 * Returns     :    A code indicating success or failure of the call:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartFlushBuffers(uint8_t uart_id, uint8_t flags)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

	OS_CPU_SR cpu_sr;
	OS_ENTER_CRITICAL();

	if(flags & UART_RX_BUFFER)
	{
		puart->rxinptr = 0;
		puart->rxoutptr = 0;
		puart->rxcnt = 0;
		puart->stale_EMPTY = 1;
		puart->stale_STALE = 0;
	}

	if(flags & UART_TX_BUFFER)
	{
		puart->txinptr = 0;
		puart->txoutptr = 0;
		puart->txcnt = 0;
	}

	OS_EXIT_CRITICAL();
	return OS_ERR_NONE;
}


/*PAGE*/
/*
 *******************************************************************************
 *                       GET NUMBER OF CHARACTERS IN RECEIVE FIFO
 *
 * Description :    Returns the number of bytes currently in the UART's Receive FIFO
 *
 * Arguments   :    uart_id is the UART ID number, indicating the port (0..3)
 *                  pCount is a pionter to the variable that will receive the
 *                         of bytes available in the receive FIFO
 *
 * Returns     :    A code indicating success or failure of the call:
 *
 *						OS_ERR_NONE indicates successful execution
 *
 *						OS_ERR_UART_ID_INVALID indicates that uart_id is out of
 *						range
 *
 *						OS_ERR_UART_NOT_INITIALIZED indicates that the UART was
 *						not initialized yet
 *
 * Notes       :    
 *******************************************************************************
 */
uint8_t OSuartGetRxFifoCount(uint8_t uart_id, uint8_t* pCount)
{
	if (uart_id >= UART_NUM_PORTS)
		return OS_ERR_UART_ID_INVALID;

	uart_t* puart = &uart_devctl[uart_id];

	if (!puart->prxevent)
		return OS_ERR_UART_NOT_INITIALIZED;

	OS_CPU_SR cpu_sr;
	OS_ENTER_CRITICAL();

	*pCount = puart->rxcnt;

	OS_EXIT_CRITICAL();
	return OS_ERR_NONE;
}

