#define PROCESSED_OK 8
#define ALIGN_OK 1
#define ENABLE 0
#define DELAY_CE 6
#define DELAY_INC 7
#define COMMUNICATION_OK 9
#define CHANNEL_SELECT 2
#define DATA_VALID 10
#define MODE_SELECT 11	

#define SET(VAR, BIT) (VAR |= (1 << BIT ))
#define UNSET(VAR, BIT) (VAR &= ~(1 << BIT ))
#define ISSET(VAR, BIT) (VAR & (1 << BIT ))

/***************************** Include Files *******************************/
#include "delayer.h"

/************************** Function Definitions ***************************/
u32 channel_select;
u32 mode_select;

unsigned int *DELAYER_ADDR = XPAR_DELAYER_0_S00_AXI_BASEADDR;
u32 slv_reg0 = 0;

unsigned int delay_align_all(){ //do whole align process
	int i = 0;
	while(i < 15){
		delay_bit_align(i);
		i++;
	}
	while(i < 15){
		delay_word_align(i);
		i++;
	}
}
unsigned int delay_wait_until_updated(){ //waits for ip core acknowledgment
	u32 readData;
	u32 mask;
	readData = DELAYER_mReadReg(DELAYER_ADDR, 1);
	readData = readData;
	mask = 1 << 12;
	readData = readData & mask;
	while(readData == 0){
		readData = DELAYER_mReadReg(DELAYER_ADDR, 1);
		readData = readData;
		mask = 1 << 12;
		readData = readData & mask;
	}
}

unsigned int delay_bit_align(unsigned int channel){ //bit align of selected channel
	int i = 0;
	int pattern1 = 0b101010101010;
	int pattern2 = 0b010101010101;
	int image_data;
	int mark1 = 0;
	int mark2 = 0;
	int mark3 = 0;
	int posun = 0;

	delay_enable();
	delay_set_pattern(0);
	delay_set_channel(channel);
	delay_send_data();
	image_data = delay_get_data();

	while(image_data != pattern1 && image_data != pattern2){ //searches for data correct delay
		delay_delay_inc();
		delay_send_data();
		i++;
		image_data = delay_get_data();
	}

	while(image_data == pattern1 || image_data == pattern2){ //searches for data incorrect delay
		delay_delay_inc();
		delay_send_data();
		i++;
		image_data = delay_get_data();
	}
	mark1 = i;
	while(image_data != pattern1 && image_data != pattern2){ //searches for data correct delay
		delay_delay_inc();
		delay_send_data();
		i++;
		image_data = delay_get_data();
	}
	mark2 = i;
	while(image_data == pattern1 || image_data == pattern2){ //searches for data incorrect delay
		delay_delay_inc();
		delay_send_data();
		i++;
		image_data = delay_get_data();
	}
	mark3 = i;

	posun = (mark1 + mark3) / 2;
	if(posun >= mark2 && posun < mark3){
		while(i > posun){ //returns the delay to calculated position
			image_data = delay_get_data();
			delay_delay_dec();
			delay_send_data();
			i--;
		}
		image_data = delay_get_data();
		if(image_data != pattern1 && image_data != pattern2){
			print("DELAYER: Done");
		}
	}else{
		print("DELAYER: Error");
	}
	delay_disable();
	delay_clean_reg();
	delay_send_data();

}

unsigned int delay_word_align(unsigned int channel){ //byte align of selected channel
	int i = 0;
	int pattern1 = 0b100000000000;
	int image_data;
	int mark1 = 0;
	int mark2 = 0;
	int mark3 = 0;
	int posun = 0;

	delay_enable();
	delay_set_pattern(1);
	delay_set_channel(channel);
	delay_send_data();
	image_data = delay_get_data();

	while(image_data != pattern1){ //searches for data correct delay
		delay_bit_shift();
		delay_send_data();
		image_data = delay_get_data();
	}
	delay_disable();
	delay_clean_reg();
	delay_send_data();

}

unsigned int delay_set_channel(unsigned int channel){ //selects the channel (for reading and writing)
	switch (channel){
		case 0:			channel_select = "0000";
		case 1:			channel_select = "0001";
		case 2:			channel_select = "0010";
		case 3:			channel_select = "0011";
		case 4:			channel_select = "0100";
		case 5:			channel_select = "0101";
		case 6:			channel_select = "0110";
		case 7:			channel_select = "0111";
		case 8:			channel_select = "1000";
		case 9:			channel_select = "1001";
		case 10:		channel_select = "1010";
		case 11:		channel_select = "1011";
		case 12:		channel_select = "1100";
		case 13:		channel_select = "1101";
		case 14:		channel_select = "1110";
		case 15:		channel_select = "1111";
		}
	slv_reg0 |= channel_select << CHANNEL_SELECT;
}

unsigned int delay_bit_shift(){ //bitslip of selected chännel
	SET(slv_reg0,DELAY_INC);
}
unsigned int delay_delay_inc(){ //selected channel delay increment
	SET(slv_reg0,DELAY_CE);
	SET(slv_reg0,DELAY_INC);
}
unsigned int delay_delay_dec(){ //selected channel delay decrement
	SET(slv_reg0,CHANNEL_SELECT);
	SET(slv_reg0,DELAY_CE);
	UNSET(slv_reg0,DELAY_INC);
}
u32 delay_get_data(){	//sends sample of image data
	u32 data;
	data = DELAYER_mReadReg(DELAYER_ADDR, 1);
	return data;
}
unsigned int delay_send_data(){ //Sends whole slv_reg0 variable value to the ip core (channel_select, enable, mode..). Without this command, no changes will execute!
	DELAYER_mWriteReg(DELAYER_ADDR, 0, slv_reg0 + (0 << DATA_VALID)); //DATA_VALID = 0 sets ip core for transfer
	DELAYER_mWriteReg(DELAYER_ADDR, 0, slv_reg0);
	DELAYER_mWriteReg(DELAYER_ADDR, 0, slv_reg0 + (1 << DATA_VALID)); //DATA_VALID = 1 (rising_edge) transfer completed
	delay_wait_until_updated();
}
unsigned int delay_clean_reg(){ //resets slv_reg0 variable value
	slv_reg0 = 0;
}
unsigned int delay_set_pattern(unsigned int pattern){	
  //sets selected pattern via SPI:
  //0 - bit alignment (101010101010)													
	//1 - word alignment(100000000000) - not used
	spi_write(0x04, 0x38, 0b00111101); //5xpattern,1xbackground,1xenable
	switch (pattern){
		case 0: //sets pattern to 101010101010
			spi_write(0x04, 0x44, 0b10101010); //8xPGDATA1
			spi_write(0x04, 0x45, 0b00001010); //4xPGDATA1

		case 1: //not used, sets pattern to 100000000000
			spi_write(0x04, 0x46, 0b00000000); //8xPGDATA2
			spi_write(0x04, 0x47, 0b00000000); //4xPGDATA2
	}

}
unsigned int delay_enable(){						//ip core enable
	SET(slv_reg0,ENABLE);
}
unsigned int delay_disable(){						//ip core disable
	UNSET(slv_reg0,ENABLE);
}
unsigned int delay_set_mode(unsigned int mode){ //Sets the delay mode
	switch (mode){
		case 0:			mode_select = "00"; //bit 		align
		case 1:			mode_select = "01"; //word 		align
		case 2:			mode_select = "10"; //channel 	align
	}
	slv_reg0 |= mode_select << MODE_SELECT;
}
