#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#define BUFLEN		50

volatile unsigned int	ticTC0;
volatile unsigned char	irx, status;
char	TxBuf[100];
char	EEPROM_Buf[100], RxBuf[BUFLEN+1];

#define STX		2
#define ETX		3
#define BAUD	57600	//bitrate
#define UBRR F_CPU/16/BAUD-1
#define USARTRX			(status & (1<<0))		
#define SET_USARTRX		(status |= (1<<0))
#define CLR_USARTRX		(status &= ~(1<<0))
//--------------------------------------------------------------------
ISR (TIMER0_OVF_vect)
{ 
	ticTC0++; 
	if (ticTC0 == 250) {PORTB  ^= (1<<PORTB5); ticTC0 = 0;}
	TCNT0 = 131;
}
//------------------------------------------------------------------------------
ISR (USART_RX_vect)		
{
	char	temp;
	temp = UDR0;
	if (temp == STX) {irx = 0; return;}
	if (irx < BUFLEN) RxBuf[irx++] = temp;
	if (temp == ETX) {RxBuf[irx]='\0'; SET_USARTRX;}
	return;
}
//--------------------------------------------------------------------
void InitTimerCounter_0 (void)		
{
	TCCR0B = (1<<CS02);				
	TIFR0 = 1<<TOV0;				
	TIMSK0 = 1<<TOIE0;			  	
	TCNT0 = 0xC1;				 
}
//--------------------------------------------------------------------
void USART_Init (unsigned int ubrr)	
{
	UBRR0H = (unsigned char)(ubrr>>8);	
	UBRR0L = (unsigned char)ubrr;
	UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); 
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); 
}
//--------------------------------------------------------------------
void USART_Transmit (char dataout)
{
	while(!(UCSR0A & (1 << UDRE0)));
	UDR0 = dataout;
}
//------------------------------------------------------------------------------
void USART_Transmit_Text (char *text) {
	unsigned char	i;
	for (i=0; i<strlen(text); i++) {
		while(!(UCSR0A & (1 << UDRE0)));
		UDR0 = text[i];	
	}
}
//-------------------------------------------------------------------------------
void EEPROM_write (unsigned int Address, unsigned char Data)
{
	while (EECR & (1<<EEPE));	/*Wait for completion of previous write*/
	EEAR = Address;				/*Set up address and data registers*/
	EEDR = Data;
	EECR |= (1<<EEMPE);			/*Write logical one to EEMWE*/
	EECR |= (1<<EEPE);			/*Start eeprom write by setting EEWE*/
}
//-------------------------------------------------------------------------------
unsigned char EEPROM_read_byte (unsigned int Address)
{
	while (EECR & (1<<EEPE));	/*Wait for completion of previous write*/
	EEAR = Address;				/*Set up address and data registers*/
	EECR |= (1<<EERE);			/*Start eeprom read by writing EERE*/
	return EEDR;				/*Return data from data register*/
}
//-------------------------------------------------------------------------------
void EEPROM_clear (char data)
{
	unsigned int	i;

	for (i=0; i<1024; i++) {
		wdt_reset();
		EEPROM_write(i, data);
	}
}
//-------------------------------------------------------------------------------
void EEPROM_write_buffer (unsigned int Address, char* buffer)
{
	unsigned char	i;

	for (i=0; i<strlen(buffer); i++) {
		wdt_reset();
		EEPROM_write(Address + i, buffer[i]);
	}
}
//-------------------------------------------------------------------------------
void EEPROM_read (unsigned int Address, unsigned int count)
{
	unsigned char	i, j;
	
	sprintf (EEPROM_Buf, "\n\r0x%03X:%04d", Address, count); USART_Transmit_Text(EEPROM_Buf);
	for (i=0; i<(count/16); i++) {
		wdt_reset(); 
		sprintf (EEPROM_Buf, "\n\r0x%03X:", Address+i*0x10); USART_Transmit_Text(EEPROM_Buf);
		for (j=0; j < 16; j++) {
			sprintf (EEPROM_Buf, "%02X ",  EEPROM_read_byte(Address+i*16+j));
			USART_Transmit_Text(EEPROM_Buf);
		}
	}
}
//-------------------------------------------------------------------------------
void EEPROM_read_ASCII (unsigned int Address, unsigned char count)
{
	unsigned int	i;
	char	znak;
	
	sprintf (EEPROM_Buf, "\n\r0x%03X:%02d\n\r", Address, count); USART_Transmit_Text(EEPROM_Buf);
	for (i=0; i < count; i++) {
		wdt_reset(); 
		znak = EEPROM_read_byte(Address+i);
		if (!isalnum(znak) && !ispunct(znak) && !isspace(znak)) znak = '?';
		USART_Transmit (znak);
	}
}
//------------------------------------------------------------------------------
int main (void) {
	unsigned char	prikaz_ok, i;
	char	prikaz[6];
	unsigned int	adr, poc;

	wdt_enable(WDTO_1S);
	DDRB |= (1<<DDB5);
	USART_Init (UBRR);
	InitTimerCounter_0();	
	sei();
	USART_Transmit_Text("\n\rTest internej pamate EEPROM");
	USART_Transmit_Text("\n\rEECLR - eeprom clear");
	USART_Transmit_Text("\n\rEE_RD_adr_count - read EE_RD00001024");
	USART_Transmit_Text("\n\rEERDA_adr_count - read ascii EERDA000034");
	USART_Transmit_Text("\n\rEEWRA_adr_text - write ascii EEWRA0000Zaklady Mikroprocesorovej Techniky");
	while(1) { 
		wdt_reset();
		if (USARTRX) {
			CLR_USARTRX; prikaz_ok = '?';
			for (i=0; i<5; i++) prikaz[i]=RxBuf[i];
			prikaz[5]='\0';
			//$02EECLR$FF$03
			if (!strcmp (prikaz, "EECLR")) {
				prikaz_ok = '+';
				sprintf(TxBuf,"\n\rEEPROM Clear 0x%02X", RxBuf[5]); 
				USART_Transmit_Text(TxBuf);
				EEPROM_clear (RxBuf[5]);
				USART_Transmit_Text("\n\rOK");
			}
			//$02EE_RD00001024$03
			if (!strcmp (prikaz, "EE_RD")) {
				prikaz_ok = '+';
				adr = (RxBuf[5]-'0')*1000 + (RxBuf[6]-'0')*100 + (RxBuf[7]-'0')*10 + RxBuf[8]-'0';
				poc = (RxBuf[9]-'0')*1000 + (RxBuf[10]-'0')*100 + (RxBuf[11]-'0')*10 + RxBuf[12]-'0';
				if (poc%0x10) poc = poc+0x10-poc%0x10; //kontrola na 16 bytov
				EEPROM_read (adr, poc);
			}
			//$02EERDA000034$03
			if (!strcmp (prikaz, "EERDA")) {
				prikaz_ok = '+';
				adr = (RxBuf[5]-'0')*1000 + (RxBuf[6]-'0')*100 + (RxBuf[7]-'0')*10 + RxBuf[8]-'0';
				poc = (RxBuf[9]-'0')*10 + RxBuf[10]-'0';
				EEPROM_read_ASCII (adr, (char)poc);
			}
			//$02EEWRA0000Zaklady Mikroprocesorovej Techniky$03
			if (!strcmp (prikaz, "EEWRA")) {
				prikaz_ok = '+';
				adr = (RxBuf[5]-'0')*1000 + (RxBuf[6]-'0')*100 + (RxBuf[7]-'0')*10 + RxBuf[8]-'0';
				for (i=0; i<100; i++) {
					if (RxBuf[i+9] != ETX) EEPROM_Buf[i]=RxBuf[i+9];
					else {EEPROM_Buf[i]='\0'; break;}
					USART_Transmit(EEPROM_Buf[i]);
				}
				EEPROM_write_buffer (adr, EEPROM_Buf);
			}
			USART_Transmit(prikaz_ok);
		}
	}
}
//------------------------------------------------------------------------------

