/** \file ******************************************************************
* \brief Implementation of USART Stack
* 
* \author Dominic Rathje (dominic.rathje@uni-ulm.de)
* \version 1.0
* \note
* - Compiler          : WinAVR 20100110
* - Supported devices : ATMega8
*
*****************************************************************************/

/** \page uart ATMega USART Stack
* \section intro Introduction
* 
* This File implements a set of functions to send and receive data through the
* hardware USART Module of a AVR ATMega Device.
* 
* Data transfer is fully interrupt driven and fifo buffered.
* 
* \section usage Usage
* 
* To use this USART Stack just copy uart.c and uart.h to your project directory,
* include uart.h wherever you want and ajust the configuration  to your needs.
* 
* \subsection printf Using the USART as stdout
* 
* If you want to use stdio printf functions to write formatted text to the UART you ma want to include the following code:
* \code
#include <stdio.h>
#include <avr/pgmspace.h>
#include "uart0.h"

static FILE pc_out = FDEV_SETUP_STREAM(uart0_putchar, NULL, _FDEV_SETUP_WRITE);
#define pc_print(fmt,...) fprintf_P(&pc_out, PSTR(fmt), ##__VA_ARGS__)
* \endcode
*/

#ifndef _UART_H_
#define _UART_H_ 1



#define UART_DDR	DDRD				///< Data Directory Register of the desired USART
#define RXPIN_bm	(1<<2)				///< Bitmask of the RX-Pin
#define TXPIN_bm	(1<<3)				///< Bitmask of the TX-Pin

#define UART_DATA	UDR					///< USART Data Register

#define RXC_vect	USART_RXC_vect		///< RX-Complete Interrupt Vector
#define DRE_vect	USART_UDRE_vect		///< Data-Register-Empty Interrupt Vector

/** \brief Size ofe the receiver FIFO
 * 
 * the size must be a power of 2 and smaller ore equal to 256. So possible Values are: 2,4,8,16,32,64,128,256 
 */
#define UART_RX_BUFFER_SIZE		64

/** \brief Size ofe the transmitter FIFO
 * 
 * the size must be a power of 2 and smaller ore equal to 256. So possible Values are: 2,4,8,16,32,64,128,256 
 */
#define UART_TX_BUFFER_SIZE 	64


/** \brief Value of Baudrate Register 
 *
 * Equation for Calculating the Baud Rate Register Setting: 
 *  - UBRR = ( f_OSC/(16 * BAUD) ) -1
 *   
 * example values vor F_CPU=7.3728MHz
 *  - 3 => 115200 BAUD
 *  - 11 => 38400 BAUD
 *  - 47 => 9600 BAUD
 * example values vor F_CPU=14.7456MHz
 *  - 7 => 115200 BAUD
 *  - 23 => 38400 BAUD
 *  - 95 => 9600 BAUD
 */
#define UBRR_val 	3

/** \brief set Character Size to 9Bit
 * 
 * Set this to 1 to use 9Bit Character Size. Default is 8Bit
 */
#define UART_CHRSIZE_9BIT 0

/** \brief enable printf compatible functions
 * 
 * In order to save codespace you can set this define to 0 if you do not need printf compatibillity.
 * The value 1 enables the Feature
 */
#define UART_PRINTF_COMPATIBILITY 1

/** \brief enable mpcm functions
 * 
 * In order to save codespace you can set this define to 0 if you do not need the Multi-Processor-Communication-Mode features.. 
 * This will diable the functions uart_senddata() and uart_sendid()
 * The value 1 enables the Feature
 */
#define UART_MPCM_ENABLE 0

/** \brief Initialise the USART Module
 *
 * Configures the Port Registers and the USART Module. Call this function at the beginning of your main function.
 */
void uart_init(void);

/** \brief Send one Byte
 * 
 * This fuction sends one byte by copying the data into the fifo-buffer
 * and enabling the UDRE-Interrupt. The actual transmission is then 
 * initiated by the Interrupt-Service-Routine. If the buffer is full
 * this function waits until the next byte has been transmitted, so it
 * is always successful.
 * 
 * \sa uart_putchar for the printf compatible version
 * \param data Data-Byte to send
 */
void uart_sendbyte(uint8_t data);

/** \brief Pull one Byte from RX-Buffer
 * 
 * If the RX-Fifo is enabled any data receives is automaticaly pusched 
 * into the Fifo ba the ISR. This function removes the oldest Byte from the Buffer
 * and copies it into the Memory-Space which is handed over as a parameter.
 * 
 * \sa uart_getchar for the scanf compatible version
 * \param data pointer to a buffer where the received data is copied to
 * \return true if data has been copied. false if the RX buffer was empty
 */
uint8_t uart_getbyte(uint8_t *data);

/** \brief Send one data byte without buffering in the FIFO.
 * 
 * \param data Data-Byte to send
 * \return true if data has been send. else false
 */
uint8_t uart_senddata(uint8_t data);

/** \brief Send one id byte without buffering in the FIFO.
 * 
 * This function is only for use in 9-Bit Character Size and MPCM Mode.
 * The ninth bit es set to 1 to send an address/id frame.
 * 
 * \param data Data-Byte to send
 * \return true if data has been send. else false
 */
uint8_t uart_sendid(uint8_t data);

#if UART_MPCM_ENABLE == 1
/** \brief Send one data byte without buffering in the FIFO.
 * 
 * This function is only for use in 9-Bit Character Size and MPCM Mode.
 * The ninth bit es set to 0 to send an data frame.
 * 
 * \param data Data-Byte to send
 * \return true if data has been send. else false
 */
uint8_t uart_senddata(uint8_t data);

/** \brief Send one id byte without buffering in the FIFO.
 * 
 * This function is only for use in 9-Bit Character Size and MPCM Mode.
 * The ninth bit es set to 1 to send an address/id frame.
 * 
 * \param data Data-Byte to send
 * \return true if data has been send. else false
 */
uint8_t uart_sendid(uint8_t data);
#endif

/** \brief Enable Multiprocessor Communication Mode.*/
inline void uart_mpcm_en(void) {
	UCSRA |= (1<<MPCM);
}

/** \brief Disable Multiprocessor Communication Mode.*/
inline void uart_mpcm_dis(void) {
	UCSRA &= ~(1<<MPCM);
}

/** \brief Enable Data Register Empty Interrupt.*/
inline void uart_udre_int_en(void) {
	UCSRB |= (1<<UDRIE);
}

/** \brief Disable Data Register Empty Interrupt.*/
inline void uart_udre_int_dis(void) {
	UCSRB &= ~(1<<UDRIE);
}

/** \brief Enable Data RX Complete Interrupt.*/
inline void uart_rxc_int_en(void) {
	UCSRB |= (1<<RXCIE);
}

/** \brief Disable Data RX Complete Interrupt.*/
inline void uart_rxc_int_dis(void) {
	UCSRB &= ~(1<<RXCIE);
}


#if UART_PRINTF_COMPATIBILITY == 1
#include <stdio.h>

/**  \brief Send one Byte (printf version)
 * 
 * This fuction sends one byte by copyint the data into the fifo-buffer
 * and enabling the UDRE-Interrupt. The actual transmission is then 
 * initiated by the Interrupt-Service-Routine. If the buffer is full
 * this function waits until the next byte has been transmitted, so it
 * is always successful.
 * 
 * This is the printf compatible version ov uart_sendbyte
 * 
 * \sa uart_sendbyte for the standars version
 * \param data Data-Byte to send
 * \return always 0
 */
int uart_putchar(char c, FILE *sream);

/** \brief Pull one Byte from RX-Buffer
 * 
 * If the RX-Fifo is enabled any data receives is automaticaly pusched 
 * into the Fifo ba the ISR. This function removes the oldest Byte from the Buffer
 * and copies it into the Memory-Space which is handed over as a parameter.
 * 
 * \sa uart_getbyte for the standard version
 * \return received data or _FDEV_EOF
 */
int uart_getchar(FILE *stream);

#endif

#endif //_UART_H_
