
#include <STDIO.H>

#include <C8051F040M.H>  //8051C040
//#include <C8051F040M2.H>	//8051C023 pro simulaci

#include <math.H>

//#include <I2c.h>


const int posedge=0x21, negedge=0x11; //definice nastaveni pro pole citacu
	
unsigned int a=50;//a - z kolika hodnot podle Archive_Base se bere do archivu
unsigned int valsend=10; //valsend z kolika ZMERENYCH max na com, mereno cca 500/s, 
						 //minimalne 1, port to stiha ale je toho MOC	
unsigned int Lcd_tm=1525; //citac 1 dava preruseni za 3050/s
unsigned int Archive_Base=305; 

unsigned char com_RDY;*i2cpointer,adresa,j[4],stop,archive,Byte_Number,i2clenght,odeslat,k,values,WORD;	  
int fall[2],rise[2],fallold[2],per[2],act[2],s,s2,h,p=450,i;//kdyz zmenis pocet hodnot k archovaci					
																	// "p" zmen i rozmer zrychleni
float maxacc[2],maxacclcd[2],maxaccold[2],zrychlenix [450],zrychleniy [450],tmp,aacc[2],corr[2],maxCOM[2];

unsigned char tx_buf[16];
unsigned char slave_i2c=0x00;   // Adresa slave zarizeni na I2C sbernici

bit SM_BUSY;

#define  EIEEN  0x0A 	//extended interrupt enable



#define WRITE 0x00                  // SMBus WRITE command
#define READ  0x01                  // SMBus READ command

#define  SMB_BUS_ERROR  0x00        // (all modes) BUS ERROR
#define  SMB_START      0x08        // (MT & MR) START transmitted
#define  SMB_RP_START   0x10        // (MT & MR) repeated START
#define  SMB_MTADDACK   0x18        // (MT) Slave address + W transmitted;
                                    //  ACK received
#define  SMB_MTADDNACK  0x20        // (MT) Slave address + W transmitted;
                                    //  NACK received
#define  SMB_MTDBACK    0x28        // (MT) data byte transmitted; ACK rec'vd
#define  SMB_MTDBNACK   0x30        // (MT) data byte transmitted; NACK rec'vd
#define  SMB_MTARBLOST  0x38        // (MT) arbitration lost
#define  SMB_MRADDACK   0x40        // (MR) Slave address + R transmitted;
                                    //  ACK received
#define  SMB_MRADDNACK  0x48        // (MR) Slave address + R transmitted;
                                    //  NACK received
#define  SMB_MRDBACK    0x50        // (MR) data byte rec'vd; ACK transmitted
#define  SMB_MRDBNACK   0x58        // (MR) data byte rec'vd; NACK transmitted



//#include <I2c.c>
#include <LCD.c>



float pocitej () 
	{
	per[i]=fall[i]-fallold[i];
	if (per[i]<0)
		per[i]+=32576;
	act[i]=rise[i]-fall[i];
	if (act[i]<0)
		act[i]+=32576;
	
	fallold[i]=fall[i];
	tmp=(20*((float)act[i]/per[i]-0.5)-corr[i]);
	if(fabs(tmp)>15)
		{
		if (tmp>0)  tmp=15;
			else	tmp=-15;
		}
	
	return  tmp;
	}









void posli_I2C (float c, float d)
{
		com_RDY=0;
		sprintf (tx_buf,"%-.2f %-.2f;  ",c,d);
		//tx_buf[14]=0x0D;
		//tx_buf[15]=0x0A;
		
		Byte_Number	=	0; //nulovani indexu I2c
		SFRPAGE	=	0x01;
		TI1		=	1;		//start prenosu pres COM
		SFRPAGE	=	0x00;
		i2clenght=16;
		
	STA=1; //zacatek prenosu pres I2C
}

void SMBUS_ISR (void) interrupt 7
{
ET0		=	0;
   switch (SMB0STA){                   // Status code for the SMBus (SMB0STA register)

      // Master Transmitter/Receiver: START condition transmitted.
      // The R/W bit of the COMMAND word sent after this state will
      // always be a zero (W) because for both read and write,
      // the memory address must be written first.
      case SMB_START:
         SMB0DAT = (adresa & 0xFE);   // Load address of the slave to be accessed.
         STA = 0;                      // Manually clear START bit
         Byte_Number=0;
		 break;

      // Master Transmitter/Receiver: Repeated START condition transmitted.
      // This state should only occur during a read, after the memory address has been
      // sent and acknowledged.
      case SMB_RP_START:
         SMB0DAT = slave_i2c;            // COMMAND should hold slave address + R.
         STA = 0;
         Byte_Number=0;				  //restart odesilani..
         break;

      // Master Transmitter: Slave address + WRITE transmitted.  ACK received.
      case SMB_MTADDACK:
         WORD=tx_buf[Byte_Number];
		 SMB0DAT = WORD;           // prvni bajt 
         Byte_Number++;                              
         break;

      // Master Transmitter: Slave address + WRITE transmitted.  NACK received.
      // The slave is not responding.  Send a STOP followed by a START to try again.
      case SMB_MTADDNACK:
         STO = 1;
         STA = 1;
         Byte_Number=0;				  //restart odesilani
         break;

      // Master Transmitter: Data byte transmitted.  ACK received.
      // This state is used in both READ and WRITE operations.  Check BYTE_NUMBER
      // for memory address status - if only HIGH_ADD has been sent, load LOW_ADD.
      // If LOW_ADD has been sent, check COMMAND for R/W value to determine 
      // next state.
      case SMB_MTDBACK:
      	//switch (BYTE_NUMBER){
      //      case 7:                    // 
      //        SMB0DAT = ;      // 
      //         BYTE_NUMBER--;          // 
      //        break;
          		if (Byte_Number<i2clenght)                    
              			if (adresa & 0x01)
						{   							 // If R/W=READ, sent repeated START, prenos  bajtu znovu
                  			STO = 0;
                  			STA = 1;
				  			Byte_Number=0;	
               			} 
               			else 
						{ 
				 		 	WORD=tx_buf[Byte_Number];
				  			SMB0DAT = WORD;      // If R/W=WRITE, load byte to write.
                  			Byte_Number++;
               			
						if (59==tx_buf[Byte_Number]) // strednik ynamena konec radku
							{ 
							tx_buf[Byte_Number+1]=0x0D;
							tx_buf[Byte_Number+2]=0x0A;
							i2clenght=Byte_Number+3;	//delka retezce
							}
						
						}
               break;
           		if (Byte_Number==i2clenght)                   // If BYTE_NUMBER=0, transfer is finished.
               		{
			   		STO = 1;
               		SM_BUSY = 0;            // Free SMBus
            	
					}
         break;


      // Master Transmitter: Data byte transmitted.  NACK received.
      // Slave not responding.  Send STOP followed by START to try again.
      case SMB_MTDBNACK:
         STO = 1;
         STA = 1;
         Byte_Number=0;
		 break;

      // Master Transmitter: Arbitration lost.
      // Should not occur.  If so, restart transfer.
      case SMB_MTARBLOST:
         STO = 1;
         STA = 1;
         Byte_Number=0;
		 break;

      default:
         STO = 1;                      // Reset communication.
         SM_BUSY = 0;
         break;
      }

   SI=0;                               // clear interrupt flag
ET0		=	1;
}




void nacti() interrupt 9 
{

unsigned char pocitat[2];

	if 	(1==CCF0)  //preruseni z counteru0
	{
		i=0;
		if (posedge==PCA0C0) //reakce  na nabeznou hranu
		   	{
			
			rise[i]=PCA0L0;
			rise[i]+=PCA0H0<<8;	  // nacteni 2 8bit reg
			PCA0C0=negedge;	//prepnuti na cekani na sestupnou
			
			pocitat[i]=1;
			values++;
			} 
				
		else 		//reakce na sestupnou hranu
			{
		
			fall[i]=PCA0L0;
			fall[i]+=PCA0H0<<8;
			PCA0C0=posedge;
		
			};
		
	

	CCF0=0;
	};
 ///////////////////////////////////////////////////

	if 	(1==CCF1)  //preruseni z counteru1 DEJ i=1
	{
	i=1;
	if (posedge==PCA0C1) //reakce  na nabeznou hranu
		   	{
		
			rise[i]=PCA0L1;
			rise[i]+=PCA0H1<<8;
			
			PCA0C1=negedge;	//prepnuti na cekani na sestupnou
			
			pocitat[i]=1;
			} 
				
		else 		//reakce na sestupnou hranu
			{
		
			fall[i]=PCA0L1;
			fall[i]+=PCA0H1<<8;
						
			PCA0C1=posedge;
		
			};
		
 //////////////////////////////////////////////////////



	CCF1=0;

	};
for (i=0;i<2;i++)
	{
	if (1==pocitat[i])
		{
		pocitat[i]=0;
		
		tmp=pocitej();
		aacc[i]=tmp;
		if (s<0) aacc[i]=0;
			if (fabs(maxacc[i])<fabs(tmp))
				{
				maxacc[i]=tmp;  //maximalni zrychleni
				}
			if (fabs(maxCOM[i])<fabs(tmp))
				{
				maxCOM[i]=tmp;  //maximalni zrychleni
				}
		}
	
	}





 //EA=1;  //enable  int.


}


char putchar (char c)
{
  
	
	  if(c=='\n')
    	LCDpozice(0,1);
  		else
    	LCDdata(c);
  		return c;

}


void ctikbd()
{
int pocet;
unsigned char prvnia,prvnis;
float pom;
	{
	switch (P2)
		{
		case 0xBF:				//STOP
		 	
				 						  //priznak stop
			if 	(0==stop) 
				{
				EIE1=0x00;					//vypnuti mereni
				stop=1;
				prvnia=1;
				prvnis=1;
				printf("X=%.2 fG   STOP \nY=%.2 fG ",zrychlenix[j[1]],zrychleniy[j[1]]);
				LCDpozice(0,0);
				h=j[1];
				pocet=p;
				
				while (0xBF==P2);
				}
				
				else 
				{
				while (0xBF==P2);
				stop=0;
				
				
				

				PCA0C0 = negedge;
				PCA0C1 = negedge;
				CCF0=1;
				CCF1=1;
				EIE1=EIEEN;					
				maxacc[0]=0;
				maxacc[1]=0;
				aacc[0]=0;
				aacc[1]=0;
				
				s=-20;
				}
			
				
				break;
		  
		
		case 0xEF:			//ZERO
		    //if (1==stop)
		 		//	{
			
				corr[0]+=maxacc[0]*0.9;  //empiricka konstanta, aby to lip fungovalo :-)
				corr[1]+=maxacc[1]*0.9;
				s=-5;
				printf("X=%.2 fG   ZERO \nY=%.2 fG ",aacc[0],aacc[1]);
				LCDpozice(0,0);
			
				while (0xEF==P2);
			
				
			//	}

				break;


		case 0xFB:		//LCDINIT
			//if (1==stop)
			//	{
				
				EA=0;
				LCDinicializace();
				s=-5;
				printf("X=%.2 fG   INIT \nY=%.2 fG ",maxacc[0],maxacc[1]);
				LCDpozice(0,0);
			
				while(0xFB==P2);
				EA=1;				

			//	}
				
		

				break;
		
		case 0xDF: 		//history back

			if (1==stop)
				{
			
				h--;
				if (h<0) h=p-1;
				pocet--;
				if (pocet<1) pocet=p;
				LCDpozice(0,0);
				printf("X=%.2 fG   HIST \nY=%.2 fG %i/%i  " ,zrychlenix[h],zrychleniy[h],pocet,p);
				LCDpozice(0,0);				

				while(0xDF==P2);

				}

				break;

		case 0x7F:    //history fwd

			if (1==stop)
				{
			
				h++;
				if (h>(p-1)) h=0;
				
				pocet++;
				if (pocet>p) pocet=1;
				
				LCDpozice(0,0);
				printf("X=%.2 fG   HIST \nY=%.2 fG %i/%i  ",zrychlenix[h],zrychleniy[h],pocet,p);
				LCDpozice(0,0);
				
				while(0x7F==P2);

				}

				break;
		
		case 0xF7:  // history send

			if (1==stop)

				{
				h=j[1];			//zacatek historie
				while (0==com_RDY);
				while(0xF7==P2);				
				printf("X=%.2 fG SENDING \nY=%.2 fG        ",zrychlenix[j[1]],zrychleniy[j[1]]);
				LCDpozice(0,0);

				for (k=0;k<p;k++)
					{
					if (0==com_RDY)
						{
						k--;  //cekani na volny port
						}	
						
						else
						{
						
						posli_I2C (zrychlenix[h],zrychleniy[h]);
						h--;
						
						if (h<0) h=p-1;
						
						}

					
				
					}
												
				
				}
				h=j[1];
			
			for (k=0;k<500;k++) //pauza
				{
				k++;
				k--;
				}	
			
			if (1==stop) printf("X=%.2 fG   STOP \nY=%.2 fG ",zrychlenix[j[1]],zrychleniy[j[1]]);
			LCDpozice(0,0);

			break;

		case 0xFE:
			if (1==stop)
			if (1==prvnia)
				{
				prvnia=0;
				pom=(float)500/valsend;
				printf("Value send SPEED  \n   %.0f/s ",pom);	
				LCDpozice(0,0);	
				}		
			else
			{

			
			switch(valsend)
				{
				case 1:
					valsend=5;
					break;

				case 5:
					valsend=10;
					break;

				case 10:
					valsend=50;
					break;

				case 50:
					valsend=100;
					break;

				case 100:
					valsend=500;
					break;
									
				case 500:
					valsend=1;
					break;
				}
			
			pom=(float)500/valsend;
			printf("Value send SPEED  \n   %.0f/s       ",pom);	
			LCDpozice(0,0);
					
			while (0xFE==P2);
			}	
			break;

		
		case 0xFd:
			if (1==stop)
			{
			if (1==prvnia)
				{
				prvnia=0;
				
				printf("Archive MAX every    \n Ta=%.1 fs          ",pom);
				LCDpozice(0,0);	
			
				}
			
			else
			{
			switch(a)
			{ 
				case 1:
					a=2;
					break;

				case 2:
					a=5;
					break;
					
				case 5:
					a=10;
					break;

				case 10:
					a=20;
					break;

				case 20:
					a=50;
					break;

				case 50:
					a=100;
					
					break;
									
				case 100:
					a=300;
					break;
				
				case 300:
					a=600;
					break;
								
				case 600:
					a=1;
					break;

				}
			}

			pom=(float)a*((float)Archive_Base/3050);
			printf("Archive MAX every    \n Ta=%.1fs          ",pom);
			LCDpozice(0,0);	
			while (0xFd==P2);
			}	
		
		default:
		
		break;
		}
	}
}





 

void interval() interrupt 1 
{

	s++;
	s2++;
	TF0=0;
	if (0>s)
		{
		maxacc[0]=0;
		maxacc[1]=0;
		zrychlenix[j[1]]=0;
		zrychleniy[j[1]]=0;		
		archive=0;
		}
	else
	{
	if (0==stop)
	
	{
	if ((valsend-1)<values)  //redukce datoveho toku, jinak toho je fakt mega moc, values>pocet vypocitanych hodnot
		{
		if (1==com_RDY)

			{ 
			posli_I2C(maxCOM[0],maxCOM[1]);
			maxCOM[0]=0;
			maxCOM[1]=0;
			values=0;
			}
		}
			
	ctikbd();
	if (Archive_Base<s2)
		{


		//zrychlenix[j[1]]=maxacc[0];	 
		//zrychleniy[j[1]]=maxacc[1];	
		if (fabs(maxacc[0])>fabs(zrychlenix[j[1]])) zrychlenix[j[1]]=maxacc[0];
		if (fabs(maxacc[1])>fabs(zrychleniy[j[1]])) zrychleniy[j[1]]=maxacc[1];	
		if (fabs(maxacc[0])>fabs(maxacclcd[0])) maxacclcd[0]=maxacc[0];
		if (fabs(maxacc[1])>fabs(maxacclcd[1])) maxacclcd[1]=maxacc[1];
		maxacc[0]=0;
		maxacc[1]=0;
		
		archive++;
		if (archive>a)
			{
			archive=0;		//maximum z kolika hodnot se zaznamena > cas zaznamu
			j[1]=j[1]+1;
			if ((p-1)<j[1]) j[1]=0;
			}
		
				

		s2=0;
		
		}
	if (Lcd_tm<s) //nastaveni intervalu vypisu na LCD, 
	{
	ET0	=	0;	


	
		printf("X=%.2 fG   RUN  \nY=%.2 fG           ",maxacclcd[0],maxacclcd[1]);
		LCDpozice(0,0);
			
		maxacclcd[0]=0;
		maxacclcd[1]=0;

		
			//uzavreny cyklus hodnot..
		s=0;
			
	ET0=1;	
	}	
	
	
}
else
  {
  ctikbd();
  }
  }
}	  



void main (void)
{
	WDTCN = 0xde;			//watchdog disable
   	WDTCN = 0xad;
	SFRPAGE = CONFIG_PAGE;                 // Switch to configuration page

//	P1MDOUT	=	0xFF;	// nastaveni portu 1 jako push-pull (asi nemusi byt, ma pull-up rezistory)
	XBR0	=	0x11;  // XBR0.0 smbus, XBR0.3>5 PCA, pro cex0 a 1 zapsat 010, zapnuty PCA, SMB
	
	XBR1	=	0x80;  // XBR2.6 Crossbar Enable !!!! jinak to nejede BLBCE :-)
	XBR2    = 	0x44;  // zapnuty UART1  a XBAR ENABLE
						//musis tady nastavit crossbar, aby vedel kde ma port!!!!!
 	
	LCDinicializace();// co nejdriv, trva to tak aby z toho nebyl binec
	LCDpodsviceni(1); //jen aby to nekricelo, stejne nebude pouzito, nechce se mi to mazat
	LCDvymaz();
	printf("X=%.2 fG   STOP \nY=%.2 fG ",maxacc[0],maxacc[1]);
													    	
	
	SFRPAGE	= 0x0f;
	OSCICN	=	0xc3;	//sysclk /1	
//	P0MDOUT	=	0x04;	//COM port do push/pull
//	SCON1	=	0x00;    //com port.. nema enable flag..
	SFRPAGE = 	0x00;


	PCA0C0 	=	0x11; //0010 0001 pca0 0 zachytny rezim pozitivni hrana, povoleni INT od tohoto modulu
	PCA0C1  =	0x11; //pca0 1 zachytny rezim negativni hrana 00010001, aby byl prvni vysledek normalnejsi...
	PCA0MD	= 	0x08; //counter mode pole citacu zaonuto, kmitocet oscilatoru 
	
	CCF0	=	0 ;   //vychozi inicializace, aby preruseni nevzniklo "preventivne hned pri povoleni"
	CCF1	=	0 ;
	//XBR0	= 	0x08; //nastaveni crossbar, vstupy PCA0,1 na P0.0,1
	
	SMB0CN = 0x44;		// Enable SMBus with ACKs on acknowledge 

//	ENSMB	=	1;
	SMB0CR 	=	 -100;// SMBus clock rate, v datasheetu je DIVNY VZOREC
	SM_BUSY = 	0;    // pripraveni SMBUS na pouziti
//	SMB0ADR	=	0x20;
//	EIP1	=	0x0A;	//priorita preruseni z PCA a SMBUS	na HIGH

	EIE1 	= 	EIEEN; //povoleni preruseni z PCA0 a SMBUS
	EIE2	=	0x40;	//UART1 interrupt enable
	EIP1	=	0x08; //PCA priority HIGH
	EIP2	=	0x40;	//com1 high priority


	maxacc[0]=0;
	maxacc[1]=0;
	stop=0;
	j[0]=0;
	j[1]=0;
	s=-20; 	// stabilizace, aby nesly prvni nejaky haluze
	corr[0]=0;
	corr[1]=0;
	
	for (i=0;i<p;i++)
		{
		zrychlenix[i]=0;
		zrychleniy[i]=0;	

		}

	CKCON 	=	0x18; //casovac 0 sysclk, casovac 1 sysclk pro tmr0 sysclk/12 10
	TMOD	=	0x20; //13bit citac TM0, auto reload TM1
//	TH1		=	0x96; // reload tm1, 2B pro UART1 57kBd
//	TL1		=	0x96;	
//	TCON	=	0x50; //timer0,1 run
//	com_RDY	=	1;     // COM port ready

	ET0		=	1;    //interrupt enable timer 0
	CR		=	1;    //counter run PCA0
	EA		=	1; 	  //globalni povoleni INT

while(1);

}