#include "config.h"
#include "pt_cornell_1_2_1.h"
#include "tft_gfx.h"
#include "tft_master.h"

#define CCLK    (40000000)
#define PBCLK   (CCLK/4)
#define Fsck    375000
#define BRG_VAL (PBCLK/2/Fsck)

#pragma config OSCIOFNC = ON

//pixel size
#define x_num 40//x_num= 320 column/8
#define y_num 240//y_num = 240 row

unsigned char pixel[x_num][y_num];
unsigned char temp;
unsigned char count;
unsigned char pixel_flag;
unsigned char rgb_flag;

unsigned short state_VS, state_HR, state_PCLK;
unsigned short last_state_VS, last_state_HR, last_state_PCLK;
char buffer_s[16];//tft display buffer
char send_buffer[16];//uart send buffer
unsigned char capture_finish;//data capture flag
unsigned int x, y;
unsigned short i, j, c;

//decoding parameter
unsigned char decode[320][10];
unsigned char temp;
unsigned char threhold;
char result;
char temp_result;
char space = '\n';
unsigned short p,q,m;
unsigned char last_state,state;
unsigned char number;
int num_send_chars;

int main(void)
{
    
    PT_setup();
    SYSTEMConfigPerformance(PBCLK);
    SYSTEMConfig(CCLK, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
    
    //pin setup
    PORTSetPinsDigitalIn(IOPORT_B, BIT_13); //pin24 VSYNC
    mPORTBClearBits(BIT_12);
    
    PORTSetPinsDigitalIn(IOPORT_A, BIT_4);  //pin12 HREF
    mPORTAClearBits(BIT_4);
    
    PORTSetPinsDigitalIn(IOPORT_B, BIT_7);  //pin16 PCLK
    mPORTBClearBits(BIT_7);
    
    PORTSetPinsDigitalIn(IOPORT_A, BIT_2); //pin9 button
    mPORTAClearBits(BIT_2);
    
    PORTSetPinsDigitalIn(IOPORT_B, BIT_11); //pin22 D2
    mPORTBClearBits(BIT_11);
    
    PORTSetPinsDigitalIn(IOPORT_B, BIT_5); //pin14 D3
    mPORTBClearBits(BIT_5);
    
    //ov7670 configuration
    ovSetUp();
    //close I2C
    CloseI2C1();
    
    //init tft
    tft_init_hw();
    tft_begin();
    tft_fillScreen(ILI9340_BLACK);
    tft_setRotation(1);     // 320*240
     
    while(1){   // never stops

        if(!capture_finish){    // start to capture the whole image
            while(1){   // break when capture finished               
                state_VS = mPORTBReadBits(BIT_13);
                if(state_VS == 0 && last_state_VS > 0 ){    // detect the falling edge
                    while (mPORTBReadBits(BIT_13) == 0){    // VSYNC == low
                        state_HR = mPORTAReadBits(BIT_4);
                        if (state_HR > 0 && last_state_HR == 0){    // detect the rising edge
                            while (mPORTAReadBits(BIT_4)){  // HREF == high                                  
                                state_PCLK = mPORTBReadBits(BIT_7);
                                if (last_state_PCLK == 0 && state_PCLK != 0 ){
                                    
                                    /*
                                     *RGB444
                                     *each pixel uses 2 bytes
                                     *R parameter is the second half of first byte
                                     */
                                    //when the second byte comes, ignore it and store R taken before 
                                    if (pixel_flag == 1){                     
                                        if (rgb_flag == 1)
                                        {
                                            temp = temp | 1;
                                        }
                                        
                                        if(count < 7){
                                            temp = temp << 1;
                                            count++;                                       
                                        }
                                        else{     
                                            pixel[x][y] = temp;
                                            temp = 0;
                                            count = 0;
                                            x++;
                                        }
                                        pixel_flag = 0;
                                    }
                                    //when the first byte comes, take the R 
                                    else{
                                        if(mPORTBReadBits(BIT_11)&&mPORTBReadBits(BIT_5)) rgb_flag = 1;
                                        else rgb_flag = 0;
                                        pixel_flag++;
                                    }
                               }
                               last_state_PCLK = state_PCLK;          
                            } 
                            y++;
                            x = 0;
                            count = 0;
                        }
                        last_state_HR = state_HR;
                        if(y==(y_num - 1)){
                            capture_finish = 1;
                            x = 0;
                            y = 0;
                            break;   // break to display
                        }                  
                    }
                }
                last_state_VS = state_VS;
                if(capture_finish) break;

                       
            }
        }
        
        if(capture_finish){   // Image capture is over, start the display
            while(capture_finish){   // break when display finished
                //when the decoding button is pushed, decoding begins
               if(mPORTAReadBits(BIT_2)==0){
                    tft_setTextColor(ILI9340_RED);
                    tft_setTextSize(3);
                    tft_setCursor(10, 50);
                    tft_writeString("decoding");
                    result = 0;
                    
                    last_state = 0;
                    //take 120 to 129 row for decoding
                    for (p=0;p<39;p++){
                        for(q=0;q<8;q++){
                            if((pixel[p][120]>>(7-q))&0x01!=0)
                                decode[p*8+q][0] = 1;
                            else
                                decode[p*8+q][0] = 0;
                            if((pixel[p][121]>>(7-q))&0x01!=0)
                                decode[p*8+q][1] = 1;
                            else
                                decode[p*8+q][1] = 0;
                            if((pixel[p][122]>>(7-q))&0x01!=0)
                                decode[p*8+q][2] = 1;
                            else
                                decode[p*8+q][2] = 0;
                            if((pixel[p][123]>>(7-q))&0x01!=0)
                                decode[p*8+q][3] = 1;
                            else
                                decode[p*8+q][3] = 0;
                            if((pixel[p][124]>>(7-q))&0x01!=0)
                                decode[p*8+q][4] = 1;
                            else
                                decode[p*8+q][4] = 0;
                            if((pixel[p][125]>>(7-q))&0x01!=0)
                                decode[p*8+q][5] = 1;
                            else
                                decode[p*8+q][5] = 0;
                            if((pixel[p][126]>>(7-q))&0x01!=0)
                                decode[p*8+q][6] = 1;
                            else
                                decode[p*8+q][6] = 0;
                            if((pixel[p][127]>>(7-q))&0x01!=0)
                                decode[p*8+q][7] = 1;
                            else
                                decode[p*8+q][7] = 0;
                            if((pixel[p][128]>>(7-q))&0x01!=0)
                                decode[p*8+q][8] = 1;
                            else
                                decode[p*8+q][8] = 0;
                            if((pixel[p][129]>>(7-q))&0x01!=0)
                                decode[p*8+q][9] = 1;
                            else
                                decode[p*8+q][9] = 0;
                            
                        }
                    }
                    
                num_send_chars = 0;
                //decode the image between 40 to 280 column
                //30 columns as one bit, totally 8 bits
                for(p = 40;p<=250;p+=30){
                    temp_result = 0;
                    for (q = p;q<p+30;q++){
                        temp_result = temp_result + decode[q][0]+decode[q][1]+decode[q][2]+decode[q][3]+decode[q][4]
                                      +decode[q][5]+decode[q][6]+decode[q][7]+decode[q][8]+decode[q][9];
                    }
                    if (temp_result >= 30)
                        send_buffer[num_send_chars] = 1;
                    else
                        send_buffer[num_send_chars] = 0;
                    num_send_chars = num_send_chars+1;
                }
                //add a "3" as the signal of ending, when "3" appears, uart ends sending
                send_buffer[num_send_chars] = 3;
                num_send_chars = 0;
                while (send_buffer[num_send_chars] != 3){
                    printf("%d",send_buffer[num_send_chars]);
                    num_send_chars++;
                }
                //send a space in the end, tell WIFI module to end receiving 
                printf("%c",space);
                
                
               //display the decoding result
                tft_setTextColor(ILI9340_YELLOW);
                tft_setTextSize(3);
                tft_setCursor(45, 200);
                sprintf(buffer_s,"%d", send_buffer[0]);
                tft_writeString(buffer_s);
                tft_setCursor(75, 200);
                sprintf(buffer_s,"%d", send_buffer[1]);
                tft_writeString(buffer_s);
                tft_setCursor(105, 200);
                sprintf(buffer_s,"%d", send_buffer[2]);
                tft_writeString(buffer_s);
                tft_setCursor(135, 200);
                sprintf(buffer_s,"%d", send_buffer[3]);
                tft_writeString(buffer_s);
                tft_setCursor(165, 200);
                sprintf(buffer_s,"%d", send_buffer[4]);
                tft_writeString(buffer_s);
                tft_setCursor(195, 200);
                sprintf(buffer_s,"%d", send_buffer[5]);
                tft_writeString(buffer_s);
                tft_setCursor(225, 200);
                sprintf(buffer_s,"%d", send_buffer[6]);
                tft_writeString(buffer_s);
                tft_setCursor(255, 200);
                sprintf(buffer_s,"%d", send_buffer[7]);
                tft_writeString(buffer_s);
                    
                }
                
            //if button is un-pushed, display the image
            else{
                for(j=0;j<y_num;j++){
                    for(i=0;i<x_num;i++){
                        for(count=0;count<8;count++){ 
                            if(pixel[i][j] & 0x80) tft_drawPixel((i * 8 + count), j, ILI9340_WHITE);
                            else tft_drawPixel((i * 8 + count), j, ILI9340_BLUE);
                            pixel[i][j] = pixel[i][j] << 1;
                        }
                    }
                        
                }
                    
                //draw rectangles to help locate
                tft_drawRoundRect(40, 0, 240, 240, 2,ILI9340_RED);
                tft_drawRoundRect(70, 0, 180, 240, 2,ILI9340_RED);
                tft_drawRoundRect(100, 0, 120, 240, 2,ILI9340_RED);
                tft_drawRoundRect(130, 0, 60, 240, 2,ILI9340_RED);
                tft_drawRoundRect(160, 0, 1, 240, 2,ILI9340_RED);
                
            }

            capture_finish = 0;
            
            }
            
        }
    } 
}
 
void ovSetUp(){
    OpenI2C1( I2C_EN, BRG_VAL );
    
    // Config the frame size
    StartI2C1();//Send the Start Bit
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x42);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x12);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x14);  // QVGA & RGB output
    IdleI2C1();//Wait to complete
    StopI2C1();//Send the Stop condition
    IdleI2C1();//Wait to complete
    
    // Config the frequency
    StartI2C1();//Send the Start Bit
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x42);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x11);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0xBF);  // 1011 1111, 128 division
    IdleI2C1();//Wait to complete
    StopI2C1();//Send the Stop condition
    IdleI2C1();//Wait to complete
    
    // Config the RGB output format
    StartI2C1();//Send the Start Bit
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x42);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x40);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x08);  // RGB 444
    IdleI2C1();//Wait to complete
    StopI2C1();//Send the Stop condition
    IdleI2C1();//Wait to complete
    
    // Config the RGB 444 format
    StartI2C1();//Send the Start Bit
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x42);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x8C);
    IdleI2C1();//Wait to complete
    MasterWriteI2C1(0x02);  // 0010, xRGB
    IdleI2C1();//Wait to complete
    StopI2C1();//Send the Stop condition
    IdleI2C1();//Wait to complete
 
    return;
 }


void i2c_wait(unsigned int cnt){
    while(--cnt){
        Nop();
        Nop();
    }
    return;
}
