//  A to D test code
// NOTE -- Aref is pin 32


#include <Mega32.h>
#include <stdio.h> // sprintf
#include <stdlib.h>
#include <math.h>

//I like these definitions
#define begin {
#define end   }  
#define LCDwidth 16 //characters
       
//calc constants
#define clock_tick 6.25e-8
#define mps2	  6.0956392045e-2
//convert to disp units
//#define velocity_convert .0981 // m/s
// .0981 * .001 m/km /3600
#define velocity_convert 0.35316    //km/hr
#define distance_convert  .000000981//m
#define hp_convert 0.0003725

//State machine state names
#define MaybePush 1
#define MaybePush1 2
#define Push 3
#define NoPush 4
#define MaybeNoPush 5
//State machine for program
#define Calibrate 0
#define GetWeight 1
#define Measure 2
#define Type 3
#define ZeroGWait 4

       
#define Accel 1
#define Velocity	2
#define Distance 3
#define HP 4
#define Time 5

//calistate
#define zero 1
#define one	2
#define negone 3
#define Display 4

//type states
#define zero60 1
#define zero30 2
#define quarter 3
#define eighth   4
#define brake 5
#define zero100 0
//sub state
#define Stop_Measure 0xff 
#define Start_Measure 0x00

/* Use an 1x16 alphanumeric LCD connected
   to PORTC as follows:
   
  [LCD]   [AT90S8515 DIP40]
   1 GND- 20 GND
   2 +5V- 40 VCC
   3 VLC 10k trimpot wiper (trimpot ends go to +5 and gnd) 
   4 RS - 21 PC0
   5 RD - 22 PC1
   6 EN - 23 PC2
  11 D4 - 25 PC4
  12 D5 - 26 PC5
  13 D6 - 27 PC6
  14 D7 - 28 PC7 
  
  3.22 =-1g
  3.82 =0g
  4.57= 1g
*/
  
#asm
    .equ __lcd_port=0x15
#endasm
#include <lcd.h> // LCD driver routines

char lcd_buffer_g[4];    // LCD display buffer  
char lcd_buffer_g2[4]; 
char lcd_buffer_v[10];
char lcd_buffer_d[10];
char lcd_buffer_t[10]; 
char lcd_buffer[10];

double zerog,oneg,negoneg;//calibration values

char lcd_buffer_w[5];
int Ain ; 		//raw A to D number
double voltage ;		//scaled input voltage
double current_g,previous_g,current_v, previous_v,current_d,previous_d,maxg,maxv;
double truev,trued;
double weight;//weight of car + person
unsigned int dispCounter;
float finaltime;// count to when to update lcd
char ProgState, substate, stateIter,firstint,isdone;      //state var, and state loop counter
char currentOut,dispState,buttonState,caliState,typeState;
double hp,maxhp,max1g,maxn1g;
double bottomslope;
char stopCondition , AutoStart;
double round(double,char );


void main(void)
begin 
   // initialize the LCD for 16 char wide
   lcd_init(LCDwidth);      	//initialize the display
   lcd_clear();       		//clear the display
   
   //init the A to D converter 
   //channel zero/ left adj /
  
   ADMUX = 0b00100000;   
   //enable ADC and set prescaler to 1/64*8MHz=125,000
   ADCSR = 0x80 + 0x06; 
   MCUCR = 0b00001000; //choose ADC mode   
    
   DDRD = 0x00; //input
   PORTD= 0xFF;
   
	//init timer 1 to generate time base for measuring
  OCR1A = 2500; 	    //generate 10msec time base
  TCCR1B = 11; 		//pre-scalar at 64; clear-on-match
  TCCR1A = 0x00;	//turn off pwm and oc lines
  TIMSK = 0x10;		//enable interrupt T1 cmp
  firstint=  1;   
  dispCounter = 0;
  isdone  =0; 
  dispState= 0;
  caliState = one; 
 
  typeState = zero60;
   AutoStart= 0;
    stopCondition=1;
  buttonState = NoPush;  
  substate = Stop_Measure; 
  maxn1g = 128;                     
   #asm
   	sei
   #endasm
          
    
    //collect weight information
   
   // measure and display loop 
   stateIter = 0;
   ProgState = Calibrate;
   //weight = 0;
   
   while (1) {  
   
   			switch(typeState) {
  				 	case zero60:
  				 			if (truev >= 97 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
  				 	case zero30:
  				 		if (truev >= 48.5 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
  				 		case zero100:
  				 			if (truev >= 159 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
  				 		case quarter:
  				 		if (trued >= .398 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
  				 	 case eighth:
  				 		if (trued >= .199 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
  				 	case brake:
  				 		if (current_g==0 && dispCounter > 150 && ProgState == Measure)
  				 				finaltime = (float)dispCounter/100;
  				 	break;
    	    
    	}  
    
  	
	}
   		
 }
   

     
  
              
//timer 1 overflow ISR
interrupt [TIM1_COMPA] void t1_cmpA(void)  

  {  
  	switch(ProgState){ 
  	          //semi-auto matic calibrtion 
  	          
  			case Type:  
  				
  				switch(typeState) {
  				 	case zero60:
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("00-60mph");
  				 	break;
  				 		case zero30:
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("00-30mph");
  				 	break;
  				 		case zero100:
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("0-100mph");
  				 	break;
  				 		case quarter:
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("1/4 mile");
  				 	break;
  				 		case eighth:
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("1/8 mile");
  				 	break;
  				 	case brake:
  				 		lcd_clear();
  				 		lcd_gotoxy(0,0);
  				 		lcd_putsf("brake");
  				 	break;
  				 
  				}
  					switch (buttonState) { 
  	   			
  	   			
  	   					
    	   				case NoPush:
    	   						if (PIND==0b11111101)  buttonState = MaybePush;
    	   						
    	   						
    	   					break;	    
    	   			    //if pushed
    	   			    case MaybePush:
    	   			    	if (PIND==0b11111101) {
    	   			    		 buttonState = Push;
    	   			    		 typeState = (typeState+1)%6;//wrap around
	  							
    	   					}
    	   			    	else buttonState= NoPush;
    	   			    	break;	
    	   				case Push:
    	   					if (PIND==0b11111101)  {
    	   					
    	   					
    	   					} else	buttonState = MaybeNoPush;
    	   					break;
    	   				case MaybeNoPush:
    	   				      	if (PIND==0b11111101)  
    	   				      		buttonState = Push;
    	   				      	else
    	   				      		buttonState= NoPush;
    	   				      	break;
    	   				      	
    	   				
    	   		 }   
  				
  			     	if (PIND==0b11111011)  ProgState = GetWeight;
  			
  			break;
  			case Calibrate:  
  				 if (stateIter==0) {
  				 	lcd_gotoxy(0,0);
  				 	lcd_putsf("Calibrate");
  				  	lcd_gotoxy(0,1);
  				  	lcd_putsf("1G VERT");
  				 	buttonState = NoPush;
  				 	stateIter++;
  				 }
  				
  			    ADCSR = ADCSR | 0x40; 
	   			Ain = ADCH;
	  			voltage = (double)Ain ;
	  			
	  			lcd_buffer[1] = 0;		
	  			lcd_gotoxy(8,1);
	  			itoa(Ain,lcd_buffer);
	  			lcd_puts(lcd_buffer);
	  				
  	   					
  		         	
  	   			switch (buttonState) { 
  	   			
  	   			
  	   					
    	   				case NoPush:
    	   						if (PIND==0b11111101)  buttonState = MaybePush;
    	   						
    	   							switch (caliState) {
    	   			    		 	 
    	   			    		 	 	case one:
    	   			    		 	 		//when searching for 1 g point take max sample
    	   			    		 	 		max1g= fmax(max1g,voltage);
    	   			    		 	 	      
    	   			    		 	 	break;
    	   			    		 	 	case negone:
    	   			    		 	         //take min for neg 1 g
    	   			    		 	          maxn1g = fmin(maxn1g,voltage);
    	   			    		 	          
    	   			    		 	    break;
    	   			    		 	    
    	   			    		 	}
    	   					break;	    
    	   			    //if pushed
    	   			    case MaybePush:
    	   			    	if (PIND==0b11111101) {
    	   			    		 buttonState = Push;
    	   			    		 
	  								//voltage = (voltage/256)*4.92  ;
    	   			    		 	switch (caliState) {
    	   			    		 	 
    	   			    		 	 	case one:
    	   			    		 	 	      
    	   			    		 	 	      oneg= max1g;
    	   			    		 	 	      caliState = negone;
    	   			    		 	 	       //set up next poart
    	   			    		 	 	    	lcd_gotoxy(0,1);
  				 								lcd_putsf("-1G VERT");
    	   			    		 	 	break;
    	   			    		 	 	case negone:
    	   			    		 	
    	   			    		 	          //negoneg = voltage;
    	   			    		 	          negoneg= maxn1g;
    	   			    		 	          ProgState = Type;
    	   			    		 	          caliState = Display;//ensure it doesn't go back thr
    	   			    		 	           
    	   			    		 	          // do some serious calc
    	   			    		 	          zerog = (oneg+ negoneg)/2.0;//extrapolate 0g
    	   			    		 	          bottomslope = (oneg-negoneg)/2.0; //slope
    	   			    		 	          
    	   			    		 	          lcd_clear();
    	   			    		 	          
    	   			    		 	    break;
    	   			    		 	    
    	   			    		 	}
    	   					}
    	   			    	else buttonState= NoPush;
    	   			    	break;	
    	   				case Push:
    	   					if (PIND==0b11111101)  {
    	   					
    	   					
    	   					} else	buttonState = MaybeNoPush;
    	   					break;
    	   				case MaybeNoPush:
    	   				      	if (PIND==0b11111101)  
    	   				      		buttonState = Push;
    	   				      	else
    	   				      		buttonState= NoPush;
    	   				      	break;
    	   				      	
    	   				
    	   		 }   
    	   		 
  			
  			
  			break;
   		
   			case GetWeight:
             //pin4 is hardware reset
             	     
	   			     lcd_gotoxy(0,0);
	   			     lcd_putsf("Enter Weight(kg)");
	   			     
	   			     
	   		    
	   			 
   			     if (PIND==0b11111101)  {
   			     	weight = weight + 5;
   			     }
   			     else if (PIND==0b11111011)  {
   			     	weight = weight - 5;
   			     	weight = fmax(weight,0);
   			     } 
   			     
   			     
   			    
 				 if (PIND==0b11111110) {
 				 
 				 	ProgState = ZeroGWait;
 				 	buttonState = NoPush;
 				 	stateIter=0; 				 	
 				 	}
 				 lcd_gotoxy(0,1);
 				 
 				 ftoa(weight,0,lcd_buffer_w);
      			 lcd_puts(lcd_buffer_w);
   			     
   			     
   			break;   
   			case ZeroGWait:
   			 /*	lcd_gotoxy(0,0);
 				ftoa(oneg,2,lcd_buffer_g);
      			lcd_puts(lcd_buffer_g);
      				lcd_gotoxy(8,0);
 				ftoa(negoneg,2,lcd_buffer_g);
      			lcd_puts(lcd_buffer_g);
      				lcd_gotoxy(0,1);
 				ftoa(zerog,2,lcd_buffer_g);
      			lcd_puts(lcd_buffer_g);
   			
   			/*/
   					if (stateIter==0) {  
   						lcd_clear();
   						lcd_gotoxy(0,0);
   						lcd_putsf("Level:0.0g");
   						stateIter++;
   					}
   			      	ADCSR = ADCSR | 0x40; 
				   	Ain = ADCH;
				  	voltage = (double)Ain ;
  	
		   			//find g values
				    if (voltage< zerog-10) {
			    		current_g = (voltage - zerog)/bottomslope; 
				    }// in g-units
				    else if (voltage>zerog+10) {
			    		current_g = (voltage - zerog)/bottomslope; 
				    }// in g-units
				    else {current_g = 0.0;}                                          
				    
				    if (PIND == 0b11111101){//auto or manual start?
			         	AutoStart++;
			         	AutoStart=AutoStart%2;
			        
			        } 
        	
			        
			        	switch (buttonState) {
    	   		
    	   				case NoPush:
    	   						if (PIND==0b11111011)  buttonState = MaybePush;
    	   					break;	    
    	   			   
    	   			    case MaybePush:
    	   			    	if (PIND==0b11111011) {
    	   			    		 
    	   			    		  	dispCounter = 0;
			         				ProgState = Measure;
 				 					buttonState = NoPush;
 				 					if (AutoStart==0) { 
	 				 					substate= Start_Measure;
	 				 				}
	 				 	
 				 	   		
    	   						lcd_clear();
    	   					}
    	   			    	else buttonState= NoPush;
    	   			    	break;	
    	   				case Push:
    	   					if (PIND==0b11111011)  {
    	   					
    	   					
    	   					} else	buttonState = MaybeNoPush;
    	   					break;
    	   				case MaybeNoPush:
    	   				      	if (PIND==0b11111011)  
    	   				      		buttonState = Push;
    	   				      	else
    	   				      		buttonState= NoPush;
    	   				      	break;
    	   				      	
    	   				
    	   		 }
			        
			        if (dispCounter%25==0) { //do display
			         	lcd_gotoxy(0,1);
 				 
 				 		ftoa(current_g,2,lcd_buffer_g);
      			 		lcd_puts(lcd_buffer_g);
      			 		
      			 		lcd_gotoxy(7,1);
      			 		if (AutoStart==0) {
      			 			lcd_putsf("Manu");
      			 		}
      			 		else {
      			 			lcd_putsf("Auto");
      					} 
      					//ftoa(voltage,2,lcd_buffer_g);
      			 		//lcd_puts(lcd_buffer_g);
			        
			        }  
   			
   			break;
   			
   			case Measure:
   			
   				switch(typeState) {
  				 	case zero60:
  				 			if (truev >= 99)
  				 				stopCondition = 0;
  				 	break;
  				 	case zero30:
  				 		if (truev >= 49)
  				 				stopCondition = 0;
  				 	break;
  				 		case zero100:
  				 			if (truev >= 160)
  				 				stopCondition = 0;
  				 	break;
  				 		case quarter:
  				 		if (trued >= .4)
  				 				stopCondition = 0;
  				 	break;
  				 		case eighth:
  				 		if (trued >= .2)
  				 				stopCondition = 0;
  				 	break;  
  				 		case brake:
  				 		if (current_g==0 && dispCounter > 150)
  				 				stopCondition = 0;
  				 	break;
    	    
    			}  
    	if (stopCondition==0) {
    	    
    		if (isdone==0) {
      	   		lcd_gotoxy(2,0); 
      	
    	  		if (current_g > 0) {
	      			ftoa(current_g,2 ,lcd_buffer_g);
	      			lcd_puts(lcd_buffer_g);
      				}
      			else {  
      				ftoa(current_g,2 ,lcd_buffer_g2);
      				lcd_puts(lcd_buffer_g2);
       			}
      	
	      	
	      		//distance
      			lcd_gotoxy(10,0);   
      			ftoa(current_d*distance_convert,2 ,lcd_buffer_d);
    	  		lcd_puts(lcd_buffer_d);
 				  //velocity
      			lcd_gotoxy(2,1);
    	  		truev = current_v*velocity_convert;
    	  		
    	  		//ftoa(truev,10,lcd_buffer_v);
    	  		ftoa((float)finaltime/100,2,lcd_buffer_v);
    	   		lcd_puts(lcd_buffer_v);  
    	   		isdone=  1;
    	   		currentOut= 1;       
       		 	lcd_clear();
    	   	}
    	   	else{
    	   	
    	   	
    	   		
    	   		
    	   		
    	   		switch (buttonState) {
    	   		
    	   				case NoPush:
    	   						if (PIND==0b11111101)  buttonState = MaybePush;
    	   					break;	    
    	   			    case MaybePush:
    	   			    	if (PIND==0b11111101)  buttonState = MaybePush1;
    	   			    	else buttonState= NoPush;
    	   			    	break;
    	   			    case MaybePush1:
    	   			    	if (PIND==0b11111101) {
    	   			    		 buttonState = Push;
    	   			    		 	if (currentOut ==Time) currentOut= 1;
    	   						else currentOut++;
    	   						dispState = 0;
    	   						lcd_clear();
    	   					}
    	   			    	else buttonState= NoPush;
    	   			    	break;	
    	   				case Push:
    	   					if (PIND==0b11111101)  {
    	   					
    	   					
    	   					} else	buttonState = MaybeNoPush;
    	   					break;
    	   				case MaybeNoPush:
    	   				      	if (PIND==0b11111101)  
    	   				      		buttonState = Push;
    	   				      	else
    	   				      		buttonState= NoPush;
    	   				      	break;
    	   				      	
    	   				
    	   		 }
    	   			   	   				
    	   				
   			     
    	   	 	 switch (currentOut) {
    	   	 	 
    	   	 	 	case Accel:
    	   	 	 	lcd_gotoxy(0,0);
    	   	 	 	lcd_putsf("Max Accel(g):");
    	   	 	 	lcd_gotoxy(1,1);
    	   	 	 	ftoa(maxg,2,lcd_buffer_g);
    	   	 	 	lcd_puts(lcd_buffer_g); 
    	   	 	 	
    	   	 	 	
    	   	 	 	break;
    	   	 	 	
    	   	 	 	case Velocity:
    	   	 	 	lcd_gotoxy(0,0);
    	   	 	 	lcd_putsf("Max Velocity(mph):");
    	   	 	 	lcd_gotoxy(1,1);
    	   	 	 	ftoa(maxv*0.62,2,lcd_buffer_v);
    	   	 	 	lcd_puts(lcd_buffer_v); 
    	   	 	 	
    	   	 	 	break;
    	   	 	 	case Distance:
    	   	 	 	lcd_gotoxy(0,0);
    	   	 	 	lcd_putsf("Distance:(ft)");
    	   	 	 	lcd_gotoxy(1,1);
    	   	 	 	ftoa(trued*3280,3,lcd_buffer_d);
    	   	 	 	lcd_puts(lcd_buffer_d); 
    	   	 	 	
    	   	 	 	break;
    	   	 	 	
    	   	 	 	case HP:
    	   	 	 		lcd_gotoxy(0,0);
    	   	 	 		lcd_putsf("Max HP:");
    	   	 	 		lcd_gotoxy(1,1);
    	   	 	 		ftoa(maxhp,2,lcd_buffer_t);
    	   	 	 		lcd_puts(lcd_buffer_t); 
    	   	 	 	break;
    	   	 	 	case Time:
    	   	 	 	     lcd_gotoxy(0,0);
    	   	 	 		lcd_putsf("Time(s):");
    	   	 	 		lcd_gotoxy(1,1);
    	   	 	 		ftoa(finaltime,2,lcd_buffer_t);
    	   	 	 		lcd_puts(lcd_buffer_t); 
    	   	 	 	
    	   	 	 
    	   	 	 
    	   	 	 }//end switch
    	   	 	 
    	   	 	 
    	   	 	 
    	   	 	 if (PIND==0b11111110) {
    	   	 	 	firstint=  1;   
  					dispCounter = 0;
					isdone  =0; 
					dispState= 0;
					caliState = one; 
					ProgState = Type;
					typeState = zero60;
					AutoStart= 0;
					stopCondition=1;
					buttonState = NoPush;  
					substate = Stop_Measure;  
					current_g= 0;
					current_d = 0;
					current_v = 0;
					truev = 0;
					trued= 0;
					lcd_clear();
					stateIter= 0;
    	   	 	 }
    	   	
    	   	}
    	   	
       	 
    			 
    	 //stop   
    	}  
    else if (substate == Start_Measure) {
	  	//32.184975ft/s^2 = 1g 
	  	//0.0060956392045 miles/s^2 = 1g
	  	//1 clock tick =  0.0000000625sec+ 
  	   	ADCSR = ADCSR | 0x40; 
	   	Ain = ADCH;
	  	voltage = (double)Ain ;
  	
	   //find g values
	    if (voltage< zerog-10) {
	    	current_g = (voltage - zerog)/bottomslope; 
	    }// in g-units
	    else if (voltage>zerog+10) {
	    	current_g = (voltage - zerog)/bottomslope; 
	    }// in g-units
	    else {current_g = 0.0;}
        
        current_g=round(current_g,2);
        
        
        if (firstint==1) {
        	current_v = 0;
        	//firstint=0;
        } 
     
     	//integrate
	    
	    current_v = current_g + previous_v;
	    current_d = current_v + previous_d;
		
       
     
     
     
    
	    if (dispCounter%50==0) { 
	    
	    	if (firstint==1) {
	    		maxg=  0;
	        	current_v = 0;
	        	current_d=  0;
	       	 	firstint=0;
	       	 	maxhp = 0;
       	 	} 
        	
		  	// display the voltage            
	  		//g force
		  	lcd_gotoxy(0,0);             
 	 		lcd_putsf("g=");
 	 		lcd_gotoxy(8,0);             
  			lcd_putsf("d=");      
	  		lcd_gotoxy(0,1);
	  		lcd_putsf("t="); 
    	  	lcd_gotoxy(2,0); 
      	
    	
		    
    	  	if (current_g > 0) {
    	  		ftoa(current_g,2 ,lcd_buffer_g);
    	  		lcd_puts(lcd_buffer_g);
    	  		}
    	  	else {  
    	  		ftoa(current_g,2 ,lcd_buffer_g2);
    	  		lcd_puts(lcd_buffer_g2);
  	   		}
      	
  	    	
  	    	//distance
  	    	lcd_gotoxy(10,0);   
  	    	
  	    	ftoa(trued,2 ,lcd_buffer_d);
  	    	lcd_puts(lcd_buffer_d);
  			  //velocity
  	    	lcd_gotoxy(2,1);
  	        
  	    	//ftoa(truev,10,lcd_buffer_v);
  	    	//itoa(dispCounter,lcd_buffer_v);
  	    	ftoa((float)dispCounter/100,2,lcd_buffer_v);
  	     	lcd_puts(lcd_buffer_v);
  	     	
  	     	dispCounter++;
  	     	isdone= 0 ;
  	  }
    
  	  else{
  	  		dispCounter++;
  	  }
      	    //calucate carryover values, pass over integration
      	 	truev = current_v*velocity_convert;
      	    trued = current_d*distance_convert;
      	    
      	    hp = truev* current_g*9.81 *weight*hp_convert;
                                
  	    	previous_g = current_g;
  	    	previous_v = current_v;
  	    	previous_d = current_d;
  	    	if(dispCounter > 3) maxg = fmax(current_g,maxg);  
  	    	maxv = fmax(truev,maxv);
  	    	maxhp = fmax(hp,maxhp);
  	    	
   	}
   	else { 
   		ADCSR = ADCSR | 0x40; 
	   	Ain = ADCH;
	  	voltage = (double)Ain ;
  	
	   //find g values
	    if (voltage< zerog-7) {
	    	current_g = (voltage - zerog)/bottomslope; 
	    }// in g-units
	    else if (voltage>zerog+7) {
	    	current_g = (voltage - zerog)/bottomslope; 
	    }// in g-units
	    else {current_g = 0.0;}
	    
	    if (fabs(current_g)>0.25) {//acceleration threshold to start measure
	     	substate=Start_Measure;
	    }
   		
    }//end if  	
  	}//end switch
  }  

   //rounds a float to 'places' digits including leading 0
   //0.xxx or x.xxx or even xxxxe^
  double round(double toRound, char places) {
  		char rounda[10];
  		
   	 ftoa(toRound,places,rounda);
     return atof(rounda);
  
  
  }