#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd.h"
#include <util/delay.h>
#include <stdio.h>

#define F_CPU 16000000UL  // 16 MHz

/*-------------------hlavicky funkci-----------------*/

void ON_init (void);
void key_read (void);
void DDS_init (void);
void sendSPI (void);
void freq_DDS (void);
void send_freq_DDS (unsigned long frekvence);
void ADF_init(void);
void check_menu(char sw);
void cut_ADF(unsigned long word);
void send_ADF(void);
unsigned long make_num(unsigned long dolni,unsigned long horni,char text[16]);

/*-------------------globalni promenne----------------*/
    

unsigned char sloupec;					//urceni sloupce pri stisku tlacitka
char znak;								//zmena 29.3 int za char
unsigned char zmena = 0;				// indikace pro menu
unsigned char lower,upper,upper_ADF;	//promenne pro posilani pre SPI
unsigned char D_or_A;					//promenna pro vyber D= DDS, A = ADF
char sw_menu;							// urceni 2 a 4 prvkoveho menu
unsigned long control,Ncounter,Rcounter; // pro nastavovani ADF
unsigned long val;						//pomocna pro zapis do ADF


/*-------------------konstanty------------------------*/
const float Freg_const = 5.592405333;	//kosntanta pro vypocet Freg (2^28/Fclk_DDS)
/*------------rutiny preruseni---------------*/

//preteceni citace rotuje nuly pres sloupce maticove klavesnice, aktualni sloupec ukazuje promenna sloupec
ISR(TIMER1_OVF_vect){

	switch (PORTC){
	case 0xF0: {
				PORTC = 0x70;
				sloupec = 1;
				break;
				}
	case 0x70: {
				PORTC = 0xB0;
				sloupec = 2;
				break;
				}
	case 0xB0: {
				PORTC = 0xD0;
				sloupec = 3;
				break;
				}
	case 0xD0: {
				PORTC = 0xE0;
				sloupec = 4;
				break;
				}
	case 0xE0: {
				PORTC = 0x70;
				sloupec = 1;
				break;
				}
	}
 	
}
/*-----------------------main---------------------------*/
int main (void){
/*-----------------------MENU---------------------------*/

ON_init();							//inicializace
check_menu(2);						//kontrola stisku spravne klavesy
if(znak == 0x0A){					//vyber polozky v MENU
	DDS_init();						//inicializace DDS
	while(1){						//zajisteni zacyklnei v hlavni nabidce
		lcd_clrscr();			
		lcd_puts("A-Frequency");
		lcd_gotoxy(0,1);
		lcd_puts("B-Shape");

		check_menu(2);				//kontrola stisku spravne klavesy
		if(znak == 0x0A){			//vyber polozky v MENU
			freq_DDS();				//procedura pro zapis frekvence do DDS
		// zmena 15.5	key_read();				//cteni znaku z klavesnice
		//	while(znak != 0x0A)		//vyber polozky v MENU
		//		key_read();			//cteni znaku z klavesnice
			
			}
		if(znak == 0x0B){			//vyber polozky v MENU
			lcd_clrscr();
			lcd_puts("A-Sinus");
			lcd_gotoxy(0,1);
			lcd_puts("B-Triangle");
			check_menu(2);			//kontrola stisku spravne klavesy

			if(znak == 0x0A){		//vyber polozky v MENU
				lower = 0b00000000;	//priprava slova pro zapis do registru DDS
				upper = 0b00100000; //nastaveni B28 a MODE sinus
				sendSPI();			//procedura pro zapis pomoci SPI
				lcd_clrscr();
				lcd_puts("Sinus");
				_delay_ms(2000);	//prodleva 2s
				}

			if(znak == 0x0B){		//vyber polozky v MENU
				lower = 0b00000010;	//priprava slova pro zapis do registru DDS
				upper = 0b00100000; // nastaveni B28 a MODE triangular
				sendSPI();			//procedura pro zapis pomoci SPI
				lcd_clrscr();
				lcd_puts("Triangular");
				_delay_ms(2000);
				}
			}
	}								
}


if(znak == 0x0B){
	ADF_init();
	while(1){
	lcd_clrscr();
	lcd_puts("A-Ncnt");
	lcd_gotoxy(7,0);
	lcd_puts("B-Rcnt");
	lcd_gotoxy(0,1);
	lcd_puts("C-opts");
	lcd_gotoxy(7,1);
	lcd_puts("D-presc");

	check_menu(4);
	if(znak == 0x0A){
		lcd_clrscr();
		lcd_puts("A-5BIT count");
		lcd_gotoxy(0,1);
		lcd_puts("B-13BIT count");
		
		check_menu(2);
		if (znak == 0x0A){
		
			val = make_num(0,31,"A-counter=");		//nacteni cisla v zavorce dolni,horni mez a vypis
			val <<= 2;								//posunuti na pozici v registru
			Ncounter &= 0b111111111111111110000011;	//zamaskovani registru
			Ncounter |= val;						//zapis do registru
			send_ADF();								//vyslani

			}

		if (znak == 0x0B){
		
			val = make_num(3,8191,"B-counter=");	//nacteni cisla v zavorce dolni,horni mez a vypis
			val <<= 8;								//posunuti na pozici v registru
			Ncounter &= 0b111000000000000011111111;	//zamaskovani registru
			Ncounter |= val;						//zapis do registru
			send_ADF();								//vyslani

			}
		}
	if(znak == 0x0B){
		
		val = make_num(1,16383,"R-counter=");		//nacteni cisla v zavorce dolni,horni mez a vypis
		val <<= 2;								//posunuti na pozici v registru
		Rcounter &= 0b111111110000000000000011;	//zamaskovani registru
		Rcounter |= val;						//zapis do registru
		send_ADF();								//vyslani
		
		}
/*

		check_menu(2);
		if(znak == 0x0A){
			lower = 0b00000000;
			upper = 0b00100000;  // nastaveni B28 a MODE sinus
			sendSPI();
			lcd_clrscr();
			lcd_puts("Sinus");
			_delay_ms(2000);
		}
*/
	if(znak == 0x0C){
		lcd_clrscr();
		lcd_puts("A-CSet");
		lcd_gotoxy(7,0);
		lcd_puts("B-OPow");
		lcd_gotoxy(0,1);
		lcd_puts("C-MCon");
		lcd_gotoxy(7,1);
		lcd_puts("D-Div2");

		check_menu(4);
		if (znak == 0x0A){
			lcd_clrscr();
			lcd_puts("Current set.(mA)");
			_delay_ms(1000);

			lcd_clrscr();
			lcd_puts("A-0.31");
			lcd_gotoxy(7,0);
			lcd_puts("B-0.93");
			lcd_gotoxy(0,1);
			lcd_puts("C-1.56");
			lcd_gotoxy(7,1);
			lcd_puts("D-2.5");

			check_menu(4);
			if (znak == 0x0A){

				val = 0;
				val <<= 17;
				control &= 0b111100011111111111111111;
				control |= val; 
				}

			if (znak == 0x0B){
	
				val = 2;
				val <<= 17;
				control &= 0b111100011111111111111111;
				control |= val; 
				}
			
			if (znak == 0x0C){

				val = 4;
				val <<= 17;
				control &= 0b111100011111111111111111;
				control |= val; 
				}

			if (znak == 0x0D){

				val = 7;
				val <<= 17;
				control &= 0b111100011111111111111111;
				control |= val; 
				}

			}
		
		if (znak == 0x0B){
			lcd_clrscr();
			lcd_puts("Out Pow.(dBm)");
			_delay_ms(1000);

			lcd_clrscr();
			lcd_puts("A- -14");
			lcd_gotoxy(7,0);
			lcd_puts("B- -11");
			lcd_gotoxy(0,1);
			lcd_puts("C- -8");
			lcd_gotoxy(7,1);
			lcd_puts("D- -5");

			check_menu(4);
			if (znak == 0x0A){

				val = 0;
				val <<= 12;
				control &= 0b111111111100111111111111;
				control |= val; 
				}

			if (znak == 0x0B){

				val = 1;
				val <<= 12;
				control &= 0b111111111100111111111111;
				control |= val; 
				}
			
			if (znak == 0x0C){
			
				val = 3;
				val <<= 12;
				control &= 0b111111111100111111111111;
				control |= val; 
				}

			if (znak == 0x0D){
				
				val = 4;
				val <<= 12;
				control &= 0b111111111100111111111111;
				control |= val; 
				}

			}
		}
	if(znak == 0x0D){
		
		lcd_clrscr();
		lcd_puts("presclarer");
		}
		
	_delay_ms(5000);	
	}								//6.5 dodelat menicko
	
}
while(1){
	}
 
}

/*--------------------podprogramy------------------------*/

void ON_init (void){			//inicializace procesoru a displeje

	DDRB = 0xFF; 			//definovani portu B jako vystup (pro SPI) 
	PORTB = 0xFF;			//nastaveni portu B na log 1(FSYNC musi byt v log. 1)
	DDRC = 0xF0;			//PORTC spodni 4 bity vstupni vrchni vystup
	PORTC = 0xF0;			//vychozi nastaveni portu C
	TCCR1B = 0b00000001; 	//nastaveni predlelicky na 1 timer 1 16 bit
	sei();					//povoleni globalniho preruseni
	TIMSK |= (1<<2);		//povoloneni preruseni po preteceni od citace 1

	lcd_init(LCD_DISP_ON);	//inicializace a zapnuti displeje

	lcd_gotoxy(6,0);		//nastaveni kurzoru na 6 sloupec,prvni radek
	lcd_puts("UREL");		//vypsani retezce
	lcd_gotoxy(4,1);		//nastaveni kurzotu na 4 sloupec,druhy radek
	lcd_puts("VUT BRNO");	//vypsani retezce

	_delay_ms(3000);		//cekej 3s
	lcd_clrscr();			//smazani displeje

	lcd_gotoxy(2,0);
	lcd_puts("Pleas select");
	lcd_gotoxy(2,1);
	lcd_puts("your device");
	_delay_ms(5000);
	lcd_clrscr();
	lcd_puts("A - AD9834");
	lcd_gotoxy(0,1);
	lcd_puts("B - ADF4360-7");
}

/*--------------------------------------------------------*/
void key_read (void){ 		//kontrola stisknute klavesy

	unsigned char stisk = 0;//promena pro kontrolu stisku tlacitka
	unsigned char radky = 0;	//obraz radku portu C
	
	
	while(stisk == 0){

		radky = PINC;			//nahravani do pomocne promenne			
		radky &= 0x0F;			//maskovani pomocne promenne
		
		if (radky == 0x07 || radky == 0x0B || radky == 0x0D || radky == 0x0E){
		_delay_ms(2);			//prodleva 2ms a nasledne overeni stisku
		
			if (radky == (PINC&0x0F))
			{
			stisk = 1;			//stisk nastal
			}
		}						//konec testovani tlacitka
	}
	//if (stisk == 1) 				uprava 5.1
	
	TIMSK |= (0<<2);		//zakaz preruseni po preteceni od citace 1
	switch (radky)			//prepinace pro rozliseni zmacknuti
		{

		case 0x0F: break;

		case 0x07: 	switch (sloupec)		//prirazeni prislusne klavesy promenne znak
					{
					case 1:{ znak = 1;
						//lcd_putc('1');
						break;}
					case 2:{ znak = 2;
						//lcd_putc('2');
						break;}
					case 3:{ znak = 3;
						//lcd_putc('3');
						break;}
					case 4:{ znak = 0x0A;
						//lcd_putc('A');
						break;}
					}
					break;

		case 0x0B: 	switch (sloupec)
					{
					case 1:{ znak = 4;
						//lcd_putc('4');
						break;}
					case 2:{ znak = 5;
						//lcd_putc('5');
						break;}
					case 3:{ znak = 6;
						//lcd_putc('6');
						break;}
					case 4:{ znak = 0x0B;
						//lcd_putc('B');
						break;}
					}
					break;
		
		case 0x0D: 	switch (sloupec)
					{
					case 1:{ znak = 7;
						//lcd_putc('7');
						break;}
					case 2:{ znak = 8;
						//lcd_putc('8');
						break;}
					case 3:{ znak = 9;
						//lcd_putc('9');
						break;}
					case 4:{ znak = 0x0C;
						//lcd_putc('C');
						break;}
					}
					break;

		case 0x0E: 	switch (sloupec)
					{
					case 1:{ znak = 0x0E;
						break;}
					case 2:{ znak = 0;
						//lcd_putc('0');
						break;}
					case 3:{ znak = 0x0F;
						break;}
					case 4:{ znak = 0x0D;
						//lcd_putc('D');
						break;}
					}
					break;
		}
		_delay_ms(150); 		//prodleva pro prijemny stisk
		TIMSK |= (1<<2);		//povoloneni preruseni po preteceni od citace 1	
     
}
/*----------------------------------------------------*/

void DDS_init(void){

	unsigned long f_out = 1000; 			//nastaveni inicializacni frekvence 1000Hz
	lcd_clrscr();
	lcd_gotoxy(4,0);						//vypis na displej
	lcd_puts("Selected:");
	lcd_gotoxy(5,1);
	lcd_puts("AD9834");
	
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL);	// nastaveni SPI 
	D_or_A = 0;								//nastaveni prepinace na DDS(pro SPI)
	send_freq_DDS(f_out);					//zmena frekvence
	
	_delay_ms(1000);						//prodleva pro vypis daneho zarizeni

}

/*----------------------------------------------------*/
// 12.5 zmena pridano nastaveni FSYNC pro ADF (podminka vyberu)


void sendSPI (void){					//Poslani 16bit(24-bit pro ADF) dat na SPI v MSB->LSB

	if(D_or_A == 1){						//podminka rozhodujici zda se jedna o zapis do DDS(16 bit) nebo ADF(24bit)
		PORTB = (0<<0);						//nastaveni FSYNC pro prenos do ADF (LOW) (PRO ADF JE FSYNC NA PINU 0 PORTU B)
		SPDR = upper_ADF;						//vyslani dat na SPI	
		while(!(SPSR & (1<<SPIF)));
		}
	else PORTB = (0<<1);					//nastaveni FSZYNC na 0 (PRO DDS JE FSYNC NA PINU 1 PORTU B)

	SPDR = upper;						//vyslani dat na SPI	
	while(!(SPSR & (1<<SPIF)));
	
	
	SPDR = lower;
	while(!(SPSR & (1<<SPIF)));				//vyslani dat na SPI

	
	if(D_or_A == 1)
		PORTB = (1<<0);						//konec prenosu FSYNC (high) PRO ADF
	else
		PORTB = (1<<1);						//konec prenosu FSYNC (high) pro DDS
}

/*---------------------------------------------------*/

void freq_DDS (void){

	char buffer[16];
	unsigned long f_out = 0;		//Pozadovana frekvence v Hz a mezi- pomocna promenna

	f_out = make_num(0,10000000,"f(Hz):"); //parametr funkce udava dovoleny rozsah
	send_freq_DDS(f_out);
	sprintf(buffer,"f =%lu Hz",f_out); 		// %lu unsigned long
	lcd_clrscr();
	lcd_puts(buffer);
	lcd_gotoxy(0,1);
	lcd_puts("A - MENU");
	key_read();				//cteni znaku z klavesnice
	while(znak != 0x0A)		//vyber polozky v MENU
		key_read();			//cteni znaku z klavesnice

}
/*--------------------------------------------*/

void send_freq_DDS (unsigned long frekvence){

	unsigned char Byte1,Byte2,Byte3,Byte4;
	long Freg;

	//poslani resetu a vyber B28
	lower = 0b00000000; 			//nastaveni nizsiho bytu
	upper = 0b00100001;				//nastaveniho vyssiho bytu
	sendSPI();						//poslani pres funkci

    // rozdeleni 28 bitoveho freg na 4x 8 bitove a vyslani
	Freg = frekvence*Freg_const;
	Byte1 = (unsigned char)(Freg & 0xFF);
	Byte2 = (unsigned char)(((Freg >> 8) & 0x3F)|0x40); 
	Byte3 = (unsigned char)((Freg >> 14) & 0xFF);
	Byte4 = (unsigned char)(((Freg >> 22) & 0x3F)|0x40); 

		//spodnich 14 bitu
		lower = Byte1;
		upper = Byte2;	 
		sendSPI();	

		//vrchnich 14 bitu
		lower = Byte3;
		upper = Byte4;
		sendSPI();

	// zapis do phase registru (pou)
	lower = 0;
	upper = 0b11000000;							//zapis 0 do phase registru 0
	sendSPI();

	//ukonceni resetu a nastaveni odpovidajicich registru
	lower = 0;
	upper = 0b0010000;
	sendSPI();


}

/*--------------------------------------------------------*/

void ADF_init(void){
	
	SPCR = (1<<SPE)|(1<<MSTR);	// nastaveni SPI pro AFD (MSB->LSB, CPOL -> 0, Master)
	D_or_A = 1;								//nastaveni prepinace na ADF(pro SPI)

	Rcounter = 0b000000000000000011001001; //nastaveni regisrtu R counter
											//Band select clock 1; ABP 3ns
											 
	control =  0b000010000001110100000000; // nastaveni kontrolniho registru
														
	Ncounter = 0b000000100010110000001010; // nastaveni registru N counter B-562 a-4

	send_ADF();			//uprava a vyslani dat do ADF

/*zkouska 16.5
	

	upper_ADF = 0b00000000;
	upper = 	0b00000000;
	lower = 	0b11001001;
	sendSPI();

	upper_ADF = 0b00001000;
	upper = 	0b00011101;
	lower = 	0b00000000;
	sendSPI();

	_delay_ms(10);
	upper_ADF = 0b00000010;
	upper = 	0b00101100;
	lower = 	0b00001010;
	sendSPI();
	
*/
						
	lcd_clrscr();
	lcd_gotoxy(4,0);
	lcd_puts("Selected:");
	lcd_gotoxy(2,1);
	lcd_puts("ADF4360-7");
	_delay_ms(1000);

}
/*--------------------------------------------------------*/

void check_menu(char sw){	//parametr sw udava zda se jedna o menu o 2(sw = 2) nebo 4(sw = 4) prvkove 

znak = 1;				//inicializace premenne znak
zmena = 0;				//inicializace promenne zmena
while(zmena != 1 ){  		//?podminka while zrejmne nestihala vyhodnotit dva vyrazy v logickem souctu?
	
	key_read();				//?(nastavalo preruseni od citace) proto pouzita pomocna promenna zmena a IF?
	if(znak == 0x0A)
		zmena = 1;

	if(znak == 0x0B)
		zmena = 1;
	
	if(sw == 4){				// podminka pro menu o 4 prvcich
		if(znak == 0x0C)
			zmena = 1;

		if(znak == 0x0D)
			zmena = 1;
		}	
	}
}

/*------------------------------------------------------*/
void cut_ADF(unsigned long word){

	unsigned char Byte1,Byte2,Byte3;

    // rozdeleni 24 bitoveho cisla na 3x 8 bitove a vyslani
	Byte1 = (unsigned char)(word & 0xFF);
	Byte2 = (unsigned char)(((word >> 8) & 0xFF)); 
	Byte3 = (unsigned char)((word >> 16) & 0xFF); 

		//vyslani 24 bitu
		lower = Byte1;
		upper = Byte2;
		upper_ADF = Byte3;	 
		sendSPI();	

}
/*------------------------------------------------------*/
void send_ADF(void){

	cut_ADF(Rcounter);
	_delay_ms(1);

	cut_ADF(control);
	_delay_ms(10);

	cut_ADF(Ncounter);

}
/*------------------------------------------------------*/

unsigned long make_num(unsigned long dolni,unsigned long horni,char text[16]){

unsigned long cislo = 0,mezi;
int A = 0;
int buffer2[16];
int i,j;

zmena = 1;						//inicilaizace promenne zmena ktera je vyuzita jako ukazatel nedovoleneho rozsahu
while(zmena != 0){
		lcd_clrscr();
		lcd_puts(text);
		cislo = 0;
		A = 0;
		
											
	znak = 1;
	while (znak != 0x0D){
		key_read();
		if(znak == 1 || znak == 2 || znak == 3 || znak == 4 || znak == 5 || znak == 6 || znak == 7 || znak == 8 || znak == 9 || znak == 0 ) {
			lcd_putc(znak+0x30);		//vypis klavesy
			buffer2[A] =  znak;			// rozliseni stisku ciselne klavesy
			A++;
			
		} 			
	}
	for(i = 0;i < A;i++){				//udela z pole nactenych cisel cele cislo
		mezi= buffer2[i];
		for(j=0;j<((A-1)-i);j++)
			mezi = mezi*(10);
		cislo += mezi;
	}
	zmena = 0;
	znak =1;							//vynulovani priznaku pro dalsi vykonavani programu
	if (cislo < dolni || cislo>horni){ 	//podminka pro kontrolu dovoleno rozsahu
		lcd_clrscr();
		lcd_puts("Invalid Value");
		_delay_ms(2000);
		zmena = 1;						//zmena vyuzita jako uzakazel na nedovoleny rozsah
		}
		}
return cislo;
}
