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

#include <stdio.h>
#include <stdarg.h>
#include "usart.h"

//
// Initializing USART
//
void usart_init_async(usart port,
		usart_databits data_bits,
		usart_stopbits stop_bits,
		usart_parity parity,
		usart_baudrate baudrate)
{	
	// No special features
	*port.control_a = 0x00;

	// Enable receiver and transmitter, data bits (high part)
	*port.control_b = 
			bit_mask(4) |			//RXENn
			bit_mask(3) |			//TXENn
			(data_bits & 0x04);

	// Parity, stop bits, data bits (low part)
	*port.control_c =
			((parity    & 0x03) << 4) |
			((stop_bits & 0x01) << 3) |
			((data_bits & 0x03) << 1);

	// Set baud rate
	*port.baud_high = (baudrate >> 8) & 0xFF;
	*port.baud_low  = baudrate & 0xFF;
}

//
// Sending character
//
void usart_send_char(usart port, char symbol)
{
	//
	// Wait for buffer to empty
	//
	while (bit_is_clear(*port.control_a, 5))	//5 = UDREn
	{
		// Do nothing
	}

	//
	// Send the character
	//
	*port.data = symbol;
}

//
// Sending string
//
void usart_send_string(usart port, char *text)
{
	//
	// Send every character in string (exept the null terminator)
	//
	while (*text != 0)
	{
		usart_send_char(port, *text++);		
	}
}

//
// Send formatted string
// 
void usart_send_stringf(usart port, const char *format, ...)
{		
	va_list args;
	char text[64];
	unsigned char i, len;
	
	va_start(args, format);
	len = vsprintf (text, format, args);
	va_end(args);
		
	// Send all the characters
	for (i = 0; i < len; i++)
	{
		usart_send_char(port, text[i]);
	}	
}

//
// Reading character
//
bool usart_try_read_char(usart port, char *symbol)
{
	if (!usart_has_data(port))
	{
		return false;
	}
	
	*symbol = usart_read_char(port);
	
	return true;
}

//
// Reading string with maxlen length or until \r char
//
void usart_read_string(usart port, char *data, unsigned int maxlen)
{
    int i;

    for (i=0; i< maxlen-1; i++)
    {
        //wait for char arriving
        while (!usart_has_data(port)) {}

        //save char and look for end indicator
        if ((*data = usart_read_char(port))  == '\r')
        {
            *data = 0; //string terminator
            return;
        }

        //move pointer
        data++;
    }

    //string terminator
    *data = 0;
}

