/*

    v2.0
	
	
	this program use old code used in another experiment
    
    "int" is used for the ADC and DAC data although it should be unsigned, 
    it should be not a problem at all as this data are limited to 12bits...



*/

#include<ADuC7020.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>

void My_IRQ_Handler(void);

short i = 0;
unsigned char Byte_addr = 0;
int first = 1;
int i2c_cnt = 0;

#define BIGDAT_SZ 256
unsigned short BigDat[BIGDAT_SZ];
char text[512];

unsigned short Vout[4];

unsigned short Vlearn;

double Vin,Vin_gnd;

unsigned short start, stop,start_gnd,stop_gnd,start2,stop2,Vset,wf_len, step_max,N;

unsigned char transf,enab_gnd,busy,remote_trigg;

unsigned int trigg_cnt,v_cnt,wf_cnt;

float Gain;


unsigned char pga_state = 0x08; // gain 1 channel 8


//char format	= 0;


unsigned char* pbuff;

unsigned char* plist[256];



void delay (int length)
{
	while (length >=0)
    	length--;
}


// conversion of the read value into it corresponding 12bits integer
int ADCtoDAT(unsigned long ADC)
{
	return (ADC&0xFFF0000)>>16;
}

unsigned long DATtoADC(int DAT)
{
	unsigned long ADC;
	ADC=DAT;
	return ADC<<16;
}

unsigned long DATtoDAC(unsigned short DAT)
{
	unsigned int ADC;
	ADC=DAT;
	return ADC<<16;
}


int Read_Digital(int n)
{	
    return ((GP0DAT&0x000000FF)>>n)&0x1;
}

void Write_Digital(int n, int state)
{	
    if(state==1)
	  GP2DAT=(0x00000001<<(n+16))|GP2DAT;
	else 
		GP2DAT=~((0x00000001<<(n+16))|(~GP2DAT));
}


void ADCpoweron(int time)
{
	ADCCON = 0x620;	 			// power-on the ADC
	while (time >=0)	  		// wait for ADC to be fully powered on
    time--;
}




void get_DACs(void)
{
	Vout[0]=DAC0DAT>>16;
	Vout[1]=DAC1DAT>>16;
	Vout[2]=DAC2DAT>>16;
	Vout[3]=DAC3DAT>>16;	
}

void set_DACs(void)
{
	DAC0DAT=DATtoDAC(Vout[0]);
	DAC1DAT=DATtoDAC(Vout[1]);
	DAC2DAT=DATtoDAC(Vout[2]);
	DAC3DAT=DATtoDAC(Vout[3]);
}


void set_pga(){
	
	SPITX = 0x3A;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit
	
	SPITX = pga_state;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit

	
}


void get_pga(){
	
	SPITX = 0x7A;//0x3A;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit
	
	SPITX = 0;//pga_state;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit

	delay(500);
	
	SPITX = 0;//0x3A;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit
	
	SPITX = 0;//pga_state;				  // transmit command or any dummy data
 	while ((SPISTA & 0x02) != 0x02) ; // wait for data received status bit
	
}


void lock_StabPulse_i2c(void)
{
	// define variables
	unsigned int cnt_N;
	double sum,sum_gnd;
	unsigned short Vout2;
	//double Vin,Vin_gnd;
	//int Vmean;
	int step = 100;
	short armed; // this is used to detect the trigger : 
				 // when the trigger input is low armed is set to 1
				 // when a measurement start it is set to 0
	short valid_data;
	int k;
	unsigned short Data[256];
	//unsigned int tmp_dat[256];


	POWKEY1 = 0x01;
	POWCON = 0x00;		   				// 41.78MHz
	POWKEY2 = 0xF4;
	 

	//GP1CON = 0x00000000;    // IO initialization
	//GP1DAT = 0xFF000000;	// set P1.n as digital output
	
	GP0CON = 0x00000000;	// IO initialization
	//GP0DAT = 0x00000000;	// set P0.n as digital input



	// ADC&DAC setting
	ADCpoweron(20000); // power on ADC
	REFCON = 0x01;	   // internal 2.5V reference
	DAC0CON = 0x12;	   // AGND-ARef range 0x12 2.5V
	DAC1CON = 0x12;	   // AGND-ARef range 0x12 2.5V
	DAC2CON = 0x12;	   // AGND-ARef range 0x12 2.5V
	DAC3CON = 0x12;	   // AGND-ARef range 0x12 2.5V
	ADCCP = 0x03;	   // conversion on ADC0
	ADCCON = 0x3E4;    // continuous conversion

	// IO setting
    GP2CON = 0x00000000;    // IO initialization
	GP2DAT = 0xFF000000;	// set P2.n as digital output
	GP0CON = 0x00000000;	// IO initialization
	GP0DAT = 0x00000000;	// set P0.n as digital input
	

	// locking parameters initialization
//	cnt = 0;      // 
	N = 10;       // number of measume,ts for averaging
	Vin = 0;      // initialize the voltage of first step
	Vin_gnd = 0;
//	Vmean = 2000;
	start = 20;
	stop = 30;
	start_gnd = 0;
	stop_gnd = 10;
	wf_len = 200;
	Vset = 200;
	Vlearn = 2000;
	step = 50;
	step_max = 100;
	Gain = 1;


	
	GP1CON = 0x22220022;				// configure SPI such the P1.0 and P1.1 are set for I2C0
										// P1.2 and P1.3 are set for GPIO (connected on 50Ohms driver TTL)
										// P1.4-7 on SPI
	SPIDIV = 0xCC;						// set SPI clock 40960000/(2x(1+SPIDIV))
										// 0xCC = 100kHz
										// 
	SPICON = 0x1043;					// enable SPI master in continuous transfer mode 
										// slave select will stay low during the all transmission
	
	
	IRQ = My_IRQ_Handler;
	IRQEN = 0x200;					// I2C0 Slave Interupt
	
	I2C0CFG = 0x04001;
	// Slave ID		  		
	I2C0ID0 = (0x50)<<1;//(0x50 + (((GP0DAT&0x000000FF)>>5)&0x1)+(((GP0DAT&0x000000FF)>>7)&0x1)*2)<<1;
	I2C0STX = 0x00;
	I2C0STX = 0x00;

	// assignation of the different pointers for the I2C exchange of data
	for (k=0;k<16;k++){
		plist[k] = (unsigned char*)(BigDat+k*16);
		plist[k+50] = (unsigned char*)(text+k*32);
	}
	
	for(i=0;i<BIGDAT_SZ;i++)
		BigDat[i]=0;

	sprintf(text,"pulse stabilization v2.0 => %s\ncompiled: %s\nbecause we can!",__func__,__DATE__);
	
	for (k=0;k<4;k++){
		plist[100+k] = (unsigned char*)(Vout+k);
	}
	// 104	to execute the function get_DACs
	// 105	to execute the function set_DACs
	
	plist[110] = (unsigned char*)&Vlearn;
	plist[111] = (unsigned char*)&Vin;
	plist[112] = (unsigned char*)&Vin_gnd;
	plist[113] = (unsigned char*)&wf_cnt;
	plist[114] = (unsigned char*)&v_cnt;
	plist[115] = (unsigned char*)&remote_trigg;	

	plist[120] = (unsigned char*)&I2C0ID0;
	plist[121] = (unsigned char*)&ADCCP;
	plist[122] = (unsigned char*)&transf;
	plist[123] = (unsigned char*)&wf_len;
	plist[124] = (unsigned char*)&trigg_cnt;

	plist[125] = (unsigned char*)&Vset;
	plist[126] = (unsigned char*)&N;
	plist[127] = (unsigned char*)&start;
	plist[128] = (unsigned char*)&stop;
	plist[129] = (unsigned char*)&start2;
	plist[130] = (unsigned char*)&stop2;
	plist[131] = (unsigned char*)&start_gnd;
	plist[132] = (unsigned char*)&stop_gnd;
	plist[133] = (unsigned char*)&enab_gnd;
	plist[134] = (unsigned char*)&Gain;
	plist[135] = (unsigned char*)&step_max;
	plist[136] = (unsigned char*)&pga_state;
	
		
	
		
	DAC0DAT = DATtoADC(10);
	DAC1DAT = DATtoADC(20);
	DAC2DAT = DATtoADC(2000);
	DAC3DAT = DATtoADC(40);
	
	Vset=0;

	Vout[3] = 111;
	set_DACs();

	transf = 0;
	trigg_cnt = 0;
	wf_cnt = 0;
	v_cnt = 0;
	cnt_N = 0;
	enab_gnd = 0;
	remote_trigg = 0;
	valid_data=0;


	// main loop for the locking
	while(1){
		
		// trigg in is on p0.3 => we check that it is low first (rising edge detection)
		if((((GP0DAT&0x000000FF)>>3)&0x1)==0){
			armed = 1;
		}		

		// now p0.3 is high => this is our rising edge
		if(((((GP0DAT&0x000000FF)>>3)&0x1)==1 && armed==1) || remote_trigg){
			
			armed = 0;
			//busy = 0;	
			//*** aquisition of the waveform  ***
			/*for(k=0;k<wf_len;k++){
				while(!ADCSTA){}	// wait for the end of ADC conversion
				tmp_dat[k]= ADCDAT; // read voltage from ADC0
			}
			for(k=0;k<wf_len;k++){
				Data[k]= (tmp_dat[k]&0xFFF0000)>>16; // read voltage from ADC0
			
			}*/
			for(k=0;k<wf_len;k++){
				while(!ADCSTA){}	// wait for the end of ADC conversion
				Data[k]= (unsigned short)(ADCDAT >> 16); // read voltage from ADC0
			}
			
			trigg_cnt++;

			if(busy==0){ // supposed to guaranty that no i2c transfer has been performed during the wf acquisition
				//*** copy for the i2c ***			
				memcpy(BigDat,Data,256*sizeof(short));
				wf_cnt++;
				
				cnt_N++;
						
				//sum of the data
				for(k=start;k<stop;k++){
					sum += Data[k];
					//cnt++;
				}
				for(k=start_gnd;k<stop_gnd;k++){
					sum_gnd += Data[k];
					//cnt_gnd++;
				}
				if(cnt_N>=N){
					Vin = sum/(cnt_N*(stop-start));	// calculate average value
					Vin_gnd = sum_gnd/(cnt_N*(stop_gnd-start_gnd));	// calculate average value
					valid_data = 1;
					v_cnt++;
					sum = 0; // initialization	of the measurement
					sum_gnd = 0;
					cnt_N = 0;
				}
			}
			else busy = 0;
			

			//*** feedback *** (mode is on pin p0.6)

			// LOCK MODE
			/*if((((GP0DAT&0x000000FF)>>6)&0x1)==1){
				if(valid_data==1){
					valid_data=0;
					cnt_N=0;
					//cnt_gnd=0;
					step = (Vset-Vin+Vin_gnd*enab_gnd)*Gain;
					if (step>step_max)
						step = step_max;
					else if (step<-step_max)
						step = -step_max;
					Vout2 = Vout2 + step;
					if(Vout2>4095){
						Write_Digital(0,1);
						Vout2 = 4090;
					}
					else{
						Write_Digital(0,0);
					}	 		
				}
			}*/

			// LEARN MODE
			// we set the outputs to the average voltage
			// and save the current input level as the set point of the next locking enable
			/*else{
				if(valid_data==1){
					valid_data=0;
					Vset = Vin-Vin_gnd*enab_gnd;
					cnt_N=0;
				}
				Vout2 = Vlearn;
			}

			//this line could also be inserted in the if conditions and thus not set every loops
			DAC2DAT = DATtoADC(Vout2); // output voltage
			*/
		}
		
	}
}




int main(void)
{ 
	
	lock_StabPulse_i2c();

	return 0;
}





/*************************************************/
/*************************************************/
/************	IRQ Service Routine  *************/
/*************************************************/
/*************************************************/



void My_IRQ_Handler()
{
	int status = I2C0SSTA;
	busy = 1;
	
	// Slave Recieve
	if ((status & 0x08)==0x08)   // Slave Recieve IRQ
	{			
			if(first==1){
				first=0;
				Byte_addr=I2C0SRX;
				I2C0FSTA|= 1 << 8;

				i2c_cnt = 0;
				if(Byte_addr==122)
					transf = 1;
				if(Byte_addr==104)
					get_DACs();
				if(Byte_addr==105)
					set_DACs();
				if(Byte_addr==137)
					set_pga();
				if(Byte_addr==138)
					get_pga();

				Write_Digital(2,0);
				pbuff = plist[Byte_addr];
				I2C0STX = pbuff[0];	
			
			}
			else {
				pbuff[i2c_cnt] = I2C0SRX;
				i2c_cnt++;	
			}		
	}
	
	// Slave Transmit
	else if ((status & 0x04)==0x04)   // Slave Transmit IRQ
	{
		i2c_cnt ++;
		I2C0STX = pbuff[i2c_cnt];
		I2C0ADR = 0xA1;
		//if(Byte_addr>=110 && Byte_addr<=113 && i2c_cnt==1)
			//set_DACs();	   			   		
	}
	
	else if((status & 0x0400)==0x0400)   // 
	{
		 first = 1;
		 //Write_Digital(2,1);
	}
	
	busy=1;
}
