/*
 * Ringpuffer
 * Einfacher Code, der den UART initialisiert und die 
 * empfangenen Bytes in einen Rinpuffer schiebt
 * Sind Bytes im Ringpuffer, werden diese zurueckgeschickt
 * Als Baudrate wird 9600Bd eingestellt
 * http://www.eHaJo.de
 * (C) Hannes Jochriem, 2013
 */
 
#define F_CPU 8000000UL     /* 8MHz */
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
// Prototypen
void long_delay(uint16_t);
 
// Defines:
#define LED1	(1<<PD6)
#define 	PUFFERSIZE	8
 
// globale Variablen
// volatile ist noetig, da die Variablen in der ISR veraendert werden
volatile uint8_t ringpuffer[PUFFERSIZE];
volatile uint8_t ring_schreibe = 0; 
volatile uint8_t ring_lese = 0;
 
// Interrupt Serviceroutine für "Byte am USART empfangen"
ISR(USART_RXC_vect)
{
	uint8_t temp;
 
	// Empfangenes Byte in den Speicher schreiben
	temp = UDR;
 
	// Schreibposition inkrementieren
	ring_schreibe++;
 
	//Schreibposition auf Puffergroesse beschraenken
	ring_schreibe %= PUFFERSIZE;
 
	if(ring_schreibe != ring_lese)
	{	// Puffer ist nicht voll, Byte schreiben
		// LED aus
		PORTD &= ~LED1;
 
		ringpuffer[ring_schreibe] = temp;
	}
	else
	{	// Puffer ist voll, Schreibposition wieder dekrementieren
		// LED an zeigt vollen Buffer an
		PORTD |= LED1;
 
		ring_schreibe--;
	}
}
 
int main()
{
	// LED-Pin als Ausgang definieren
	DDRD |= LED1;
 
	// Receive-Interrupt einschalten, RX und TX einschalten
	UCSRB |= (1<<RXCIE) | (1<<RXEN) | (1<<TXEN);
 
	// 8 Bit Daten:
	UCSRC |= (1<<UCSZ0) | (1<<UCSZ1);
 
	// Baudrate auf 9600Bd einstellen:
	UBRRH = 0;
	UBRRL = 51; 
 
	// Globales Interruptflag einschalten:
	sei();
 
	while(1)
	{
		if(ring_lese != ring_schreibe)
		{ // He, es ist was im Ringpuffer!!!
 
			// Leseposition inkrementieren
			ring_lese++;
 
			// Leseposition auf Puffergroesse beschraenken
			ring_lese %= PUFFERSIZE;
 
			// Byte im Puffer zurücksenden
			UDR = ringpuffer[ring_lese];
 
			// Eine Sekunden warten damit man Versuchsweise den 
			// Rinpuffer volllaufen lassen kann
			long_delay(1000);
		}
	}
 
	return 0;
}
 
void long_delay(uint16_t ms) 
{
        for(; ms>0; ms--) 
                _delay_ms(1);
}