#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <string.h>
#define F_CPU 16000000UL
#include <util/delay.h>

#define TCNT0_SET	131
#define BUFLEN		15
#define STX			2
#define ETX			3
#define CR			0x0D
#define LF			0x0A

#define BAUD 9600
unsigned int ubrr = F_CPU / 16 / BAUD-1;
volatile unsigned int	tic_led;
volatile unsigned char	irx, status;
volatile unsigned long	cas;
char	RxBuf[15], text[50];

#define USARTRX			status & (1<<0)		//pripravene data zo seriaveho portu
#define SET_USARTRX		status |= (1<<0)
#define CLR_USARTRX		status &= ~(1<<0)
#define BLIKANIE		status & (1<<1)		//povolenie blikania ledky
#define SET_BLIKANIE	status |= (1<<1)
#define CLR_BLIKANIE	status &= ~(1<<1)

//------------------------------------------------------------------------------
ISR (TIMER0_OVF_vect)				//Obsluha prerusenia TCO - 2ms
{
	cas++;							//stopky - meranie casu
	if (BLIKANIE) {
		if (++tic_led == 250) {					//pocitadlo do 250 
			tic_led = 0; PORTB ^= (1<<PORTB5);	//250*2ms = 500ms (svieti / nesvieti)
		}
	}
	TCNT0 = TCNT0_SET;
}
//------------------------------------------------------------------------------
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++) USART_Transmit (text[i]);
}
//------------------------------------------------------------------------------
ISR (USART_RX_vect)	//Obsluha prerusenia od RX
{
	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;
}
//------------------------------------------------------------------------------
ISR (INT0_vect) //Obsluha externeho prerusenia INT0
{
	EIFR |= 1<<INTF1; EIMSK |= 1<<INT1;
    CLR_BLIKANIE; PORTB |= (1<<PORTB5); 
	cas=0;
	USART_Transmit_Text("\nStart");
	EIMSK  &= ~(1<<INT0);
}
//------------------------------------------------------------------------------
ISR (INT1_vect) //Obsluha externeho prerusenia INT1
{
	EIFR |= 1<<INTF0; EIMSK |= 1<<INT0;
    SET_BLIKANIE; PORTB &= ~(1<<PORTB5); 
	sprintf(text, "\nStop:%ldms %ld.%03lds", cas*2, cas/500, 2*(cas%500));
	USART_Transmit_Text(text);
	EIMSK  &= ~(1<<INT1);
}
//------------------------------------------------------------------------------
int main (void) {
	unsigned char	jas, pwm;
	char	prikaz_ok;
	
	DDRB |= (1<<DDB5);					//nastavenie LED na vystup 
	DDRD |= (1<<DDD6)|(1<<DDD5);	//Nastavenie OCR0A, OCR0B na vystup
	
	PORTD |= (1<<PORTD2)|(1<<PORTD3);	//Pull Up on INT0, on INT1
	EICRA |= (1<<ISC01)|(1<<ISC11);		// Trigger INT0 on failing edge, INT1 on failing edge
	EIFR |= (1<<INTF0)|(1<<INTF1);		// Clear External INT0, INT1 Flag
	EIMSK |= (1<<INT0)|(1<<INT1);		// Enable INT0, INT1
	
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char) ubrr;
	UCSR0B = (1 << RXEN0) | (1 << TXEN0)  | (1 << RXCIE0);
		UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
		
	//TC0 - normal mode,
	TCCR0B |= (1<<CS02);				//set prescaler to 256 (Timer clock = system clock/256)
	TIFR0 |= 1<<TOV0;					//Clear TOV0 flag
	TIMSK0 |= 1<<TOIE0;	  				//Enable Timer0 overflow interrupt
	TCNT0 = TCNT0_SET;						//Nastavenie TCNT0 
	
	TCCR0A |= (1<<WGM01)|(1<<WGM00);	//set fast PWM (TOP=0xFF)
	TCCR0A |= (1<<COM0A1);				//set non-inverting mode OCR0A (PDA6)
	TCCR0A |= (1<<COM0B1)|(1<<COM0B0);	//set inverting mode OCR0B (PD5)
	OCR0A = 193;
	OCR0B = 193;
	
	USART_Transmit_Text("\nPriklad TC0C\n");
	USART_Transmit_Text("\nZapni    - Led svieti");
	USART_Transmit_Text("\nVypni    - Led zhasne");
	USART_Transmit_Text("\nBlika    - Led blika");
	USART_Transmit_Text("\nPWM_S010 - Strieda Pwm bude 10% (0-100%) (OC0B)");
	USART_Transmit_Text("\nJAS_S050 - Jas Led bude 50% (0-100%) (OC0A)");
	USART_Transmit_Text("\nINT0     - Start - meranie casu");
	USART_Transmit_Text("\nINT1     - Stop - meranie casu\n\n");
	wdt_enable(WDTO_500MS);				//povolenie WDT 0,5sec		
	sei();
	SET_BLIKANIE;
	while(1) { 
		wdt_reset();
		if (USARTRX) {
			CLR_USARTRX; prikaz_ok = '?';
			//Led svieti
			if (!strcmp (RxBuf, "Zapni")) {PORTB |= (1<<PORTB5); CLR_BLIKANIE; prikaz_ok = '+';}
			//Led zhasne
			if (!strcmp (RxBuf, "Vypni")) {PORTB &= ~(1<<PORTB5); CLR_BLIKANIE; prikaz_ok = '+';}
			//Led blika v intervale 500ms
			if (!strcmp (RxBuf, "Blika")) {
				if (BLIKANIE) {CLR_BLIKANIE; PORTB &= ~(1<<PORTB5);}
				else {SET_BLIKANIE;}
				prikaz_ok = '+';
			}
			//Nastavenie pwm signalu v % (OC0B:PD5)  PWM_S010
			if ((RxBuf[0]=='P')&&(RxBuf[1]=='W')&&(RxBuf[2]=='M')&&(RxBuf[3]=='_')&&(RxBuf[4]=='S')) {
				pwm = ((RxBuf[5]-'0')*100 + (RxBuf[6]-'0')*10 + RxBuf[7]-'0');
				if (pwm > 99) pwm = 99;
				if (pwm < 1) pwm = 0;
				OCR0B = TCNT0_SET + (255-TCNT0_SET) * pwm / 100;
				sprintf (text, "\n\rOCR0B=%03d,0x%02X Pwm=%03d%% ", OCR0B, OCR0B, pwm); USART_Transmit_Text(text);
				prikaz_ok = '+';
			}
			//Nastavenie jasu led1 v % (OC0A:PD6)   JAS_S025
			if ((RxBuf[0]=='J')&&(RxBuf[1]=='A')&&(RxBuf[2]=='S')&&(RxBuf[3]=='_')&&(RxBuf[4]=='S')) {
				jas = (RxBuf[5]-'0')*100 + (RxBuf[6]-'0')*10 + RxBuf[7]-'0';
				if (jas > 100) jas = 100;
				if (jas < 1) jas = 1;
				OCR0A = TCNT0_SET + (255-TCNT0_SET) * jas / 100;
				sprintf (text, "\n\rOCR0A=%03d,0x%02X Jas=%03d%% ", OCR0A, OCR0A, jas); USART_Transmit_Text(text);
				prikaz_ok = '+';
			}
			//ak je prikaz uspesny, vysle sa znak +, ak je prikaz nerozpoznany, vysle sa prijaty prikaz a znak ?.
			if (prikaz_ok != '+') {USART_Transmit(CR); USART_Transmit(LF); USART_Transmit_Text(RxBuf);}
			USART_Transmit(prikaz_ok);
		}
	}
}
//------------------------------------------------------------------------------

