//
// AVR USART common operations
// Homelab library
//
// Department of Mechatronics
// Tallinn University of Technology
// © Copyrights 2009
//

//
// Include usart.h only once
//
#ifndef _USART_H_
#define _USART_H_

//
// Include common library
//
#include "common.h"

//
// Include avrlibc files
//
#include <avr/io.h>

//
// Take use of bit manipulation operations
//
#include "bit.h"

//
// C++ compatibility
//
#ifdef __cplusplus
extern "C" {
#endif

//
// Configuration types
//
typedef enum
{
	USART_DATABITS_5 = 0X00,
	USART_DATABITS_6 = 0X01,
	USART_DATABITS_7 = 0X02,
	USART_DATABITS_8 = 0X03,
	USART_DATABITS_9 = 0X07
}
usart_databits;

typedef enum
{
	USART_STOPBITS_ONE = 0X00,
	USART_STOPBITS_TWO = 0X01
}
usart_stopbits;

typedef enum
{
	USART_PARITY_NONE = 0X00,
	USART_PARITY_EVEN = 0X02,
	USART_PARITY_ODD  = 0X03
}
usart_parity;

//
// Baudrate configuration type and macro
//
#define usart_baudrate unsigned short
#define USART_BAUDRATE_ASYNC(baud) (F_CPU / 16 / baud - 1)

#if defined (__AVR_ATmega2561__) || defined (__AVR_ATmega128__)
//
// Structure for holding registry addresses
//
typedef const struct
{
	_REG_PTR_ data;
	_REG_PTR_ control_a;
	_REG_PTR_ control_b;
	_REG_PTR_ control_c;
	_REG_PTR_ baud_high;
	_REG_PTR_ baud_low;
}
usart;

//
// Macro for defining a USART port
//
#define USART(index) \
	{ \
		(_REG_PTR_)&UDR ## index, \
		(_REG_PTR_)&UCSR ## index ## A, \
		(_REG_PTR_)&UCSR ## index ## B, \
		(_REG_PTR_)&UCSR ## index ## C, \
		(_REG_PTR_)&UBRR ## index ## H, \
		(_REG_PTR_)&UBRR ## index ## L, \
	}

//
// Initializing USART
//
extern void usart_init_async(	usart port,
                                usart_databits data_bits,
                                usart_stopbits stop_bits,
                                usart_parity parity,
                                usart_baudrate baudrate);

//
// Sending character
//
extern void usart_send_char(usart port, char symbol);

//
// Sending text
//
extern void usart_send_string(usart port, char *text);

//
// Send formatted string
//
extern void usart_send_stringf(usart port, const char *format, ...);

//
// Reading character
//
extern bool usart_try_read_char(usart port, char *symbol);

//
// Reading string
//
void usart_read_string(usart port, char *data, unsigned int maxlen);

//
// Has data received ?
//
inline bool usart_has_data(usart port)
{
	if(bit_is_set(*port.control_a, 7)) return true;			//7 = RXCn
	else return false;
}

//
// Reading character
//
inline char usart_read_char(usart port)
{
	return *port.data;
}

//
// Receive complete interrupt configuration
//
inline void usart_rx_interrupt_enable(usart port, bool enable)
{
	bit_set_to(*port.control_b, 7, enable);	//7 = RXCIEn
}

//
// Transmit complete interrupt configuration
//
inline void usart_tx_interrupt_enable(usart port, bool enable)
{
	bit_set_to(*port.control_b, 6, enable);	//6 = TXCIEn
}

//
// Ready (data register empty) interrupt configuration
//
inline void usart_ready_interrupt_enable(usart port, bool enable)
{
	bit_set_to(*port.control_b, 5, enable);	//5 = UDRIEn
}

#elif defined (__AVR_ATxmega128A1U__)
#define USART0	USARTD0
#define USART1	USARTC1

#define usart uint8_t
#define USART(index) index

//
// Initializing USART
//
extern void usart_init_async(	uint8_t port,
                                uint8_t data_bits,
                                uint8_t stop_bits,
                                uint8_t parity,
                                uint32_t baudrate);

//
// Sending character
//
extern void usart_send_char(uint8_t port, char symbol);

//
// Sending text
//
extern void usart_send_string(uint8_t port, char *text);

//
// Send formatted string
//
extern void usart_send_stringf(uint8_t port, const char *format, ...);

//
// Reading character
//
extern bool usart_try_read_char(uint8_t port, char *symbol);

//
// Reading string
//
void usart_read_string(uint8_t port, char *data, unsigned int maxlen);

//
// Has data received ?
//
inline bool usart_has_data(uint8_t port)
{
	if(!port)
	{
		if(bit_is_set(USART0.STATUS, USART_RXCIF_bp)) return true;			//7 = RXCn
		else return false;
	}
	else
	{
		if(bit_is_set(USART1.STATUS, USART_RXCIF_bp)) return true;			//7 = RXCn
		else return false;
	}

}

//
// Reading character
//
inline char usart_read_char(uint8_t port)
{
	if(!port)
		return USART0.DATA;
	else
		return USART1.DATA;
}
#endif


//
// C++ compatibility
//
#ifdef __cplusplus
}
#endif

#endif
