//Compiler:             Codevision 1.24.6   
//Target:               ATmega8 
//Clock frequency:      15.36Mhz
//Author:               Brody Radford - www.heythatsneat.org

#include <mega8.h>
#include <delay.h>         
#include <stdio.h>

#define MAXFWD          10
#define MAXREV          -10                   
#define OFF             0   
#define lightOn()       PORTD.4 = 0
#define lightOff()      PORTD.4 = 1  
#define TGint           0b10000000 //timer gate pin        
#define CLKint          0b01000000 //phase clock 1       
#define readyScan()     GICR = TGint  
#define startScan()     GICR = TGint | CLKint
#define stopScan()      GICR = 0
#define LED             PORTD.7
#define grnLED          PORTB.5 
#define redLED          PORTB.4        
#define ADCSTART        0b01000000  
#define CH0             0
#define CH7             7   
              

signed int      pxlCount,               //Pixel clock divisor counter  
                pxlDiv = 7,             //Pixel clock divisor
                pxlData[255],           //Image data
                lineThreshold = 100,     //"dark" level
                lineLeft,               //Index of left edge
                lineRight,              //Index of right edge
                pxlDataIndex,           //Image data index  
                foo,            //???
                light = 62,     //Light level 
                dark = 120,     //Dark level  
                bottom = 5,     //Image bottom
                top = 190,      //Image top 
                centre = 95,    //Image centre = top/2           
                error,          //Distance from image centre to line centre  
                speedLeft,      //Left motor speed
                speedRight,     //Right motor speed              
                width;          //Width of line                                   
unsigned int    pxlStart = 180, //Yay, first useful pixels!
                pxlEnd = 1900,  //No more useful pixels here                   
                clkCount;       //Pixel clock counter                     
float           lightAvg = 0;         
//Flags
char            fCal = 1, 
                fTx,            //Transmit image if true
                fBusy = 1; 
                
// Speed range is +/- 10
speedR(signed char speedL)
{
        OCR1AL = speedL+90;
}

speedL(signed char speedR)
{
        OCR1BL = speedR+90;
}                           

interrupt [EXT_INT1] TG_START()
{                
        lightOn(); //And there was light...            
        clkCount = 0; 
        pxlDataIndex = 0;
        pxlCount = 0;  
        startScan();
        grnLED=!grnLED; //blink the led       
}   
                
interrupt [EXT_INT0] Clock()
{            
        // ************ Count the clock pulse *********
        clkCount++;   
        // ************ Useful pixel range ************
        if((clkCount >= pxlStart) && (clkCount <= pxlEnd))  
        {                                 
                // ******** Measure pixels ********                       
                if(pxlCount > pxlDiv) //every pxlDiv-th pixel
                {       
                        ADCSRA |= ADCSTART; //start adc
                        pxlCount = 0;//new measurement                                         
                }else pxlCount++;           
        } 
        
        // *********** Measurement cycle complete *********
        if(clkCount > pxlEnd)
        {       
                stopScan(); 
                fBusy = 0;
        }                           
}      
     
interrupt [USART_RXC] rx()
{     
        foo = UDR; //flush buffer 
        fTx = 1;      
} 

interrupt [ADC_INT] adcDone()
{         
        pxlData[pxlDataIndex] = ADCH;   
        pxlDataIndex++;               
}        

interrupt [TIM2_COMP] t2Cmp()
{              
        
}  

interrupt [TIM0_OVF] t0_ovf()
{        

}   
       
main()
{                   

       unsigned char count; 
     
        //LEDs
        DDRB.5 = 1; //grn led  
        DDRB.4 = 1; //red led         
        DDRD.5 = 1; //led -
        DDRD.7 = 1; //led +         
        //Camera lights
        DDRD.4 = 1;                      
              
//         TCCR0 = 0b00000101; // 1024 pre  
//         TIMSK = 0b10000001; //T0 overflow int on  
        
//         TCCR2 = 0b01111001;
//         DDRB.3 = 1;        
//         OCR2 = 0;       
        
        //UART
        UCSRA = 0;
        UCSRB = 0b10011000;//tx and rx en, rx int en
        UCSRC = 0b10000110;
        UBRRL = 24; //38400       
        //Servos                    
        TCCR1A = 0b10100011; //10-bit fast pwm, toggle OC pins, 58.6Hz pwm frequency, 16.7us timer tick
        TCCR1B = 0b00001100; //256 prescaler
        DDRB.1 = 1; //oc1a
        DDRB.2 = 1; //oc1b  
        speedL(OFF);
        speedR(OFF);                  
        //ADC                    
        ADMUX =  0b00100000 | CH0;
        ADCSRA = 0b10001000;  //enable ADC, int on
        //External ints
        MCUCR = 0b00001111; //rising edge   
        SREG.7 = 1;  //Global ints on                  
                
        // ******* calibrate light level *********  
// while(1)
// {  
//         if(fTx)
//         {  
//                 fTx = 0;
//                 lightOn(); 
//                 //delay_ms(500);
//                 readyScan();  
//                 //delay_ms(500);   
//                while(fBusy); 
//         //         readyScan();      
//         //         //delay_ms(100);
//         //         while(fBusy); 
//         //         readyScan();      
//         //         //delay_ms(100);
//         //         while(fBusy); 
//                 redLED = 1;                                           
//                 for(pxlDataIndex=0; pxlDataIndex<250; pxlDataIndex++)
//                 {                                        
//                         putchar(pxlData[pxlDataIndex]);                                  
//                 }    
//                 redLED = 0;    
//                 //Average middle of image  
//                 for(count = 50; count < 51; count++)
//                 {
//                         lightAvg = lightAvg + pxlData[count];
//                 }  
//         }         
// }     
//         lightAvg = pxlData[50]; 
//         lightOn();
//         while(lightAvg == 76);
        //Cool blinky trick
//         for(count = 0; count<3; count++)
//         {
//                 lightOn();
//                 delay_ms(5);
//                 lightOff();
//                 delay_ms(250);
//         }
 //       lineThreshold = light + (dark - light)/2;  
//         speedR(10);     
//         speedL(10);
        readyScan(); 
        while(1)
        {             
                if(!fBusy)
                {
                        fBusy = 1;                           
                      //  lightOff(); //save some battery     
                                                                        
                        //Flush debug vars  
                        for(count = 195; count<245; count++)
                                pxlData[count] = 0;
                                          
                        // *** Find line edges ***
                        for(lineLeft = bottom; (pxlData[lineLeft] < lineThreshold) && (lineLeft <= top); lineLeft++); //left side 
                        for(lineRight = top; (pxlData[lineRight] < lineThreshold) && (lineRight >= bottom) ; lineRight--); //Right side                                
//                         for(lineLeft = bottom;       (pxlData[lineLeft] < lineThreshold);    lineLeft++); 
                        //left side 
//                         for(lineRight = top;         (pxlData[lineRight] < lineThreshold);   lineRight--); //Right side
                        width = lineRight - lineLeft;     
                        //Calculate error
                        error = ((lineLeft + width/2) - centre)/15;
                        //Limit error
                        if(error>MAXFWD)
                                error = MAXFWD;
                        if(error<MAXREV)
                                error = MAXREV;                            
                        if((lineLeft > 189) || (lineRight < 10)) //No line found
                        {        
                                speedL(OFF);
                                speedR(OFF);     
//                                 speedL(-3);
//                                 speedR(-3);
//                                 delay_ms(3000); 
                        }else //Update motors
                        {               
                                speedL(3+error);
                                speedR(3-error);
                        }        
                        //Debug vars
                        pxlData[200] = lineLeft;
                        pxlData[205] = lineRight;
                        pxlData[210] = width;  
                        pxlData[215] = lineThreshold; 
                        pxlData[220] = error; 
                        pxlData[225] = lightAvg;
                        //Spit out the data  
                        if(fTx)
                        {      
                                fTx = 0; 
                                redLED = 1;                                           
                                for(pxlDataIndex=0; pxlDataIndex<250; pxlDataIndex++)
                                {                                        
                                        putchar(pxlData[pxlDataIndex]);                                  
                                }    
                                redLED = 0;                                
                        }    
                        readyScan(); 
                }                                                  
        }         
}                                  