#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include "TWI_master.h"
#include "ADC.h"


unsigned char pomoc ;	//vo funkcii kontrola
signed int pomoc2;		//výsledok rozdielu súčasného priemeru a referenčnej hodnoty 

unsigned char ch,k; 	//pomocné premenné pre cykly for

unsigned int priemer;	//priemer zo všetkých kanálov A/D prevodníka
unsigned char hranica;	//prah spustenia efektu

unsigned int a = 0;		//premenná určujúca periódu aktualizácie svetelného efektu

unsigned char led [8][8];	//pole znázorňujúce rozmiestnenie LED na doske
unsigned char fronta [3][4];//pole, do ktorého sa zapisujú vzniknuté svetelné efekty
unsigned char poradie = 1;	//určuje adresu podriadenej dosky, ktorú riadiaca doska práve osloví

unsigned char indexy [2][64]= //pole určujúce poradie v akom sa prvky z pola led zapisujú do posuvných registrov
{
{4,4,4,5,6,5,6,6,	7,7,7,7,6,5,4,5,	2,2,3,3,2,3,3,2,	1,0,1,0,0,0,1,1,	2,3,3,2,1,0,0,0,  	1,0,1,1,2,3,3,2,	4,4,5,4,5,6,6,7,	7,7,7,6,6,4,5,5	},
{1,2,3,2,1,3,2,3,	2,3,1,0,0,0,0,1,	3,2,3,2,1,1,0,0,	0,0,1,1,2,3,3,2,	5,5,4,4,4,4,5,6,	5,7,7,6,7,7,6,6,	5,6,6,7,7,6,7,7,	5,6,4,4,5,4,4,5	},
//			SHIFT REG 4								SHIFT REG 3								SHIFT REG 2								SHIFT REG1

};

//unsigned char i=0; 		//pomocné premenné, v procese pridelovania adries určujú indexy pola dosky
//unsigned char j=0; 		//do ktorého sa zapisujú adresy
unsigned char strana; 	//parameter svetelného efektu, ktorý určuje veľkosť zobrazovaného útvaru
signed char posun;		//pomocná premenná pre cyklus, v ktorom sa vykresluje efekt (funkcia efekt)
 
unsigned char data_master_passive;	//premenná určujúca, či má na riadiacej doske vzniknúť svetelný efekt 
									//ako reakcia na dianie na susednej doske
unsigned char data_slave;//premenná, ktorú podriadená doska odosiela riadiacej, určuje či a kde vznikol svetelných efekt 	
unsigned char master;	//premenná, ktorá určuje status dosky : 0->podriadená, 1->riadiaca
extern unsigned char adresadek; //určuje poslednú pridelenú adresu, teda aj počet podriadených dosiek
extern unsigned char data_rec;	// premenná, do ktorej sa ukladajú prijaté dáta 

unsigned char index1;	//premenné určujúce indexy podriadenej dosky, na ktorej vznikol
unsigned char index2;	//svetelný efekt v rámci pola dosky
unsigned char offset = 0;	//parameter svetelného efektu, časový offset
unsigned char stredx;	//parametre svetelného efektu, určujúce polohu stredu útvaru
unsigned char stredy;	//ktorý sa zobrazuje

void registry (void);	//funkcia, ktorá nastaví riadiace registry požadovaným spôsobom
void zapis (void);		//vykoná prepis dát na paralelné výstupy posuvných registrov(/LA)
void matica (void);		//prepíše dáta z poľa led do posuvných registrov
void efekt (unsigned char stredx,unsigned char stredy, unsigned char strana);	//vykreslí efekt do poľa led
void nuluj (void);		//naplní pole led nulovým prvkami



unsigned char find (unsigned char poradie);	//nájde danú adresu v poli led, vráti indexy prvku s adresou

int main (void)			//hlavný program
{	
	for (k=0;k<255;k++)	//čakanie po resete
			{
				delay();
				delay();	
			}
	
	pin_init();		//volanie funkcie, ktorá zistí status dosky

	if (master ==1)	//ak je doska označená za riadiacu
		{
	 		registry_master();	//nastavenie registrov pre riadiacu dosku
			
			twi_init();			//volanie funkci, ktorá pridelí pripojeným doskám adresy
	 	}

	else 			//ak je doska označená za podriadenú
		{
			registry_slave();	//nastavenie registrov pre podriadenú dosku
		
			sei();	//povolenie prerušení		

			while( init_end==0);	//prázdny cyklus, beží dokial sa neukončí pridelovanie adries (tj.init_end =1) 

			cli();	//zakázanie prerušení
		}

	registry ();	//nastavenie riadiacich registrov, ktoré majú všetky dosky spoločné


	sei();			//povolenie prerušení
	
	while (1);		//nekonečný cyklus
}


void registry (void)//funkcia nastaví riadiace registre pre chod dosky	
{
    				
	TIMSK = (1<<TOIE0);		//povolenie prerušenia po pretečení čítača 0
	TCCR2 = (1<<WGM21)|(1<<WGM20)|(2<<COM20)|(6<<CS20);	
		//WGM -> nastavenie rýchlej PWM
		//COM -> nastavenie neinvertujúceho módu
		//CS2 -> preddelička fc/256

	//0b01101110;		
	TCCR0 = (1<<WGM01)|(1<<WGM00)|(2<<COM20)|(5<<CS20);
		//WGM -> nastavenie rýchlej PWM
		//COM -> nastavenie neinvertujúceho módu
		//CS0 -> preddelička fc/1024

	//0b01101101;

	TCCR1A = (2<<COM1A0)|(2<<COM1B0)|(1<<WGM10);
	//0b10100001;
	TCCR1B = (5<<CS10)|(1<<WGM12);
	//0b00001101;
		//COM1A,COM1B -> nastavenie neinvertujúceho módu
		//WGM -> nastavenie rýchlej PWM, 8bitový čítač
		//CS1 -> preddelička fc/1024	 
	


	// PB3,PD4,PD5 a PD7 sú výstupy PWM generátoru => signály OE/
	// PD0,PD1 -> dátový a hodinový signál
	// PC2 -> signál /LA

	DDRB = (1<<PB3)|(1<<PB0);
	//0b00001000;
				
	DDRD = 	(1<<PD0)|(1<<PD1)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
	//0b10110011;
			
	PORTD = (1<<PD4)|(1<<PD5)|(1<<PD7);
	// 0b11110000;
	PORTB = (1<<PB3);
	//0b00001000;

	OCR2 = 100;		// nastavenie štartovacích hodnôt komparačných registrov
	OCR0 = 100;
	OCR1AH = 0;
	OCR1AL = 50;
	OCR1BH = 0;
	OCR1BL = 70;


	
	ADMUX 	|= (0<<REFS1)|(1<<REFS0)|(0<<ADLAR);		
		//REFS -> nastavenie ref. napätia
		//ADLAR -> zarovnanie výsledku dolava
	
	ADCSRA	|= (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 	
		//ADEN -> povolenie AD prevodníku
		//ADSC -> štart prevodu
		//ADPS -> predelička (128)
		//ADIE -> povolenie prerušenia
		//ADATE -> spúšťanie prevodu po určenej udalosti (free-running mode)
}


void zapis (void)
{
	PORTB &= ~(!0<<PB0);	//dátový a hodinový signál do nízkej úrovne
	PORTD &= ~(!0<<PD1);
		
	PORTD &= ~(!0<<PD6);	//signál /LA do nízkej úrovne
	
	asm("nop");				
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	PORTD |= (1<<PD6);		// zápis /LA PD6, dáta na paralelné výstupy (pri prvej doske PC2)
	asm("nop");
	asm("nop");
	asm("nop");
	PORTD &= ~(!0<<PD6); 	//signál /LA do nízkej úrovne
}

//----------------------------------------------------------------------------------------------------------
//Obsluha prerušenia po pretečení čítača 0 
//----------------------------------------------------------------------------------------------------------

ISR (TIMER0_OVF_vect)
{
	a++;			// zväčšenie pomocnej premennej, určuje periódu opakovania obsluhy

	if (a==7)
		{	
			a=0;	// vynulovanie pomocnej premennej
			
			nuluj();// vynulovanie poľa led


			for (ch = 0; ch < 3; ch++)	// cyklus, ktorý kontroluje či boli aktivované efekty
			{
				if ((fronta  [ch][2] > 0)&(fronta [ch][3]==0))  // ak je efekt aktivovaný a zároveň nemá nastavený offset
					{
				
						stredx = fronta [ch][0] ;		// z poľa fronta sa vyberú údaje pre efekt (súradnice polohy a veľkosť)
						stredy = fronta [ch][1] ;
						strana = fronta [ch][2] ;

						efekt (stredx,stredy,strana);	// volanie funkcie, ktorá efekt vykreslí v poli led
			
						fronta [ch][2] += 1;			// zväčší sa veľkosť útvaru
			
					if (fronta [ch][2] > 5)				// ak dosiahne útvar max.veľkosť
						{
							fronta [ch][2] = 0;			// deaktivuje sa príslušný efekt
						}
					}

			
				if (fronta [ch][3] == 1)			// ak je offset rovný 1, aktivuje sa efekt vo fronte
					{
						fronta [ch][2] = 1;			// aktivácia efektu
						fronta [ch][3] = 0;
					}
				
				if	(fronta [ch][3] > 1)			// znižovanie offsetu pokial ešte nedosiahol hodnotu 1
					{
						fronta [ch][3] -- ;
					}
			}


			matica ();								// odoslanie dát z poľa led do posuvných registrov

			if ((fronta [0][2]+fronta [1][2]+fronta [2][2]) ==0)
				{
					komp = 0;						// ak nie je aktívny žiaden efekt, hodnota kompenzačnej premennej je 0			
				}
					

		}

	OCR2 += 10;		//zmena hodnôt komparačných registrov
	OCR0 += 10;
	OCR1AL += 10;
	OCR1BL += 10;

	
	if (adresadek > 0)							// ak boli nájdené susedné dosky
				{
					if (data_slave > 0)			// ak doska M zachytila efekt, najprv pošle susedným doská inf. o reakcii
						{
							data_slave --;		// dekrementácia premennej (aby zodpovedala indexu fototranzistora)
															
							dosky_switch(data_slave,0,0);	// odoslanie dát, pre indexy 0,0 (efekt vznikol na riadiacej doske)
							
							data_slave = 0;		// vynulovanie premennej (hodnota 0 dovtedy, pokial nevznikne ďalší efekt)
						}

					status_write = twi_start_address(poradie,1);	// oslovenie dosky (podľa hodnoty premennej poradie), či bol vyvolaný efekt
					data_rec = twi_read();		// prijatie dát od podriadenej dosky

					if (data_rec >0)				// kontrola odpovede ak bola nenulová, tak bol vyvolaný efekt
						{
							pomoc = find (poradie);			// podľa adresy (premenná poradie) sa nájdu súradnice podriadenej dosky (v poli dosky), ktorá poslala dáta
							index1 = (pomoc >> 4); 			// oddelenie súradníc do index1,index2
							index2 = (pomoc & 0b00001111);
							data_rec -- ;		// dekrementácia prijatých dát (aby zodpovedali indexu fototranzistora)
							dosky_switch(data_rec, index1, index2);
						}

					
					if (data_master_passive >0 )// testovanie či bola v predošlom určená na reakciu aj riadiaca doska 
						{
							offset = (data_master_passive>>4);	// oddelenie offsetu a čísla fototranzistora
							data_master_passive = (data_master_passive & 0b00001111);
							data_master_passive -= 1;		// dekrementácia premennej (aby zodpovedala indexu fototranzistora)
							set_parameters (data_master_passive,offset);	// zapísanie reakcie do poľa aktívnych efektov
							data_master_passive = 0;		// vypnutie odozvy na susedný svetelný efekt
						}
	
					
					poradie ++;					//inkrementácia adresy
	
					if	(poradie > adresadek)	// ak dosiahne poslednú adresu, skočí zase na prvú
						{
							poradie = 1;
						} 
				}
}


void nuluj (void)			// funkcia vynuluje pole led
{
	for (ch=0;ch<8;ch++)	//vynulovanie matice
		{
			for (i=0;i<8;i++)
				{
					led [i][ch]=0;
				}
		}
}


void efekt (unsigned char stredx, unsigned char stredy, unsigned char strana)
{	//funkcia, ktorá zakreslí efekt do poľa led

	for (posun =(-strana);posun<(strana+1);posun++)		// zápis vzoru, medze iteračnej premennej podľa hodnoty parametra strana (veľkosť útvaru)
		{	// najskôr sa kontroluje, či indexy neprekročilo rozmery poľa led
			if (((stredx - strana) > (-1)) & ((stredy + posun)<7) & ((stredy + posun)>(-1)))
				led [stredx - strana][stredy + posun] = 1;	// ak indexy splňujú podmienky, zapíše sa na dané miesto v poli led nenulový prvok (1)

			if (((stredx + strana) < 7) & ((stredy + posun)<7) & ((stredy + posun)>(-1)))
				led [stredx + strana][stredy + posun] = 1;

			if (((stredy - strana) > (-1)) & ((stredx+posun)<7) & ((stredx + posun)>(-1)))
				led [stredx + posun][stredy - strana] = 1;

			if (((stredy + strana) < 7) & ((stredx+posun)<7) & ((stredx + posun)>(-1)))
				led [stredx + posun][stredy + strana] = 1;

		}

}



void matica (void)	// zapisuje obsah pola led do posuvných registrov
{
	for (k=0;k<64;k++)
		{
			if (led [indexy[0][k]][indexy[1][k]]> 0)	// poradie odosielania prvkov je zapísané v poli indexy 
					{ 
						 PORTD |= (1<<PD1);				// ak je daný prvok nenulový, odošle sa log.1
						 asm("nop");					// podržanie úrovne pred hodinovým signálom
						 asm("nop");
						 PORTB |= (1<<PB0);			// hodinový signál
						 asm("nop");
						 PORTB &= ~(!0<<PB0);

					}
			else
					{
						 PORTD &= ~(!0<<PD1);			// ak je daný prvok nulová, odošle sa log.0
						 asm("nop");
						 asm("nop");
						 PORTB |= (1<<PB0);			// hodinový signál
						 asm("nop");
						 PORTB &= ~(!0<<PB0);
					}
		}

	zapis();		// prepis dát na paralelné výstupy posuvných registrov
}




