
#include "terasic_includes.h"
#include "i2c.h"
//#include "math.h"
//#include "lcd.h"

#define CAMERA_I2C_ADDR  0x20 // 0x30 if SADDR is high, otherwise, 0x20;


typedef struct{
    alt_u16 Addr;
    alt_u16 Data;
}WDR_CAMERA_REG;

// default use context A
WDR_CAMERA_REG szCameraRegList[] = {
    
    {0x301A, 0x0001}, // reset register
    {0xFFFF, 200}, // wait 200 ms to ensure VCO has locked      
    {0x301A, 0x10D8}, // reset register
    {0xFFFF, 100}, // wait 100 ms to ensure VCO has locked      

    
    {0x30D4, 0x4007}, // Column Correction
    {0x3044, 0x0400}, // dark control
    {0x30D4, 0x6007}, // Column Correction
    {0x30D4, 0xE007}, // Column Correction
    

    {0x305E, 0x0020}, // context-A, global gain
    //{0x3056, 0x0008}, // context-A, Green 1 Gain (default 0x0008)
    //{0x305C, 0x0008}, // context-A,  Green 2 Gain (default 0x0008)
    {0x3058, 0x004A}, // context-A, Blue Gain (default 0x0008)
    {0x3058, 0x003A}, // context-A, Blue Gain (default 0x0008)
    {0x305A, 0x002A}, // context-A, Red Gain (default 0x0008)
        
    {0x3082, 0x0028}, // Linear Mode, operation_mode_ctrl 
    {0x3012, 0x0200}, // coarse_intergration_time        
    {0x3012, 0x0C00}, // coarse_intergration_time // explosure?    
    {0x3032, 0x0000}, // digital binning, no binning

    {0x3002, 2}, // context-A, y_addr_start, (default 2)
    {0x3004, 0}, // context-A, x_addr_start, (default 0)
    
    //{0x3006, 600-1-2}, // context-A, y_addr_ends, 600 (default 965)
    //{0x3008, 800-1}, // context-A, x_addr_ends, 800 (default 1283)
    {0x3006, 720-1-2}, // context-A, y_addr_ends, 720 (default 965)  //## lou mod
    {0x3008, 1280-1}, // context-A, x_addr_ends, 1280 (default 1283)
    
   // {0x300A, 0x02F2}, // frame_length_lines 
   // {0x300C, 0x0672}, // line_length_pck (default 0x672)
   // {0x301A, 0x10D8}, // reset register 
   // {0x31D0, 0x0001}, // HDR_COMP
    
    
    
    // config pll. 27.0MHZ x2ch/(2x4x2) = 74.25 MHZ
    // config pll. 25.0MHZ x2ch/(2x4x3) = 45.8 MHZ
    {0x302C, 0x0002}, // context-A, VT_SYS_CLK_DIV (default 0x01, 1~16)
    {0x302A, 0x0004}, // context-A, VT_PIX_CLK_DIV (default 0x06, 4~16)
    {0x302E, 0x0002}, // context-A, PRE_PLL_CLK_DIV (default 0x02, 1~64)
    {0x3030, 0x002C}, // context-A, PLL_MULTIPLIER (default 0x2c, 32~384)
    {0xFFFF, 1}, // wait 1 ms to ensure VCO has locked      

    
    {0x30B0, 0x1300},  //digital_test    
    
   // {0x3100, 0x001A}, // ae_ctrl_reg, automaticcontrol of digital gain by AE is enabled
    {0x3100, 0x001A | 0x04 | 0x01}, // high-gain & enble AE    
    
    {0x301A, 0x0058 | 0x8084}, // reset register, enable parallel data interface & stream mode
    
#if 0
    // test pattern
    {0x3070, 0x0001}, // sodli color test pattern
  //  {0x3070, 0x0002}, // scale test pattern
    {0x3072, 0xFFFF}, //red
    {0x3074, 0x0000}, //green-red
    {0x3076, 0x0000}, //blue
    {0x3078, 0x0000}, //green-blue
#endif        

};

#define SENSOR_OPERATION_MODE_CTRL 0x3082

bool SetHiDyMode(bool bHiDy){
    bool bSuccess;
    alt_u16 Value16=0;
    
    bSuccess = I2CL_Read16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CAMERA_I2C_ADDR, SENSOR_OPERATION_MODE_CTRL, &Value16);
    if (bSuccess){
        Value16 = (Value16 & 0xFFFC) | (bHiDy?0x00:0x01);
        bSuccess = I2CL_Write16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CAMERA_I2C_ADDR, SENSOR_OPERATION_MODE_CTRL, Value16);    
    }
    
    printf("HiDy Mode: %s (Value=%02Xh, %s)\r\n", bHiDy?"ON":"OFF", Value16, bSuccess?"Success":"NG");
    return bSuccess;
}



int main()
{
    bool bSuccess = TRUE;
    const alt_u32 DeviceAddr = 0xBA;
    int i, num;
    alt_u32 sw, pre_sw=-1;
    alt_u32 GlobalGain = 8;
    alt_u32 Shutter = 0x400;
    alt_u16 data16;
    
//    if (LCD_Open()){
//        LCD_TextOut("WDR Camera Demo");
//    }
//    printf("WDR Camera Demo\r\n");
//     
//    
//    IOWR(LED_BASE, 0, 0x00); // LED is high-active
    
   
    // WDR Camera reset
    IOWR(CAMERA_RESET_N_BASE, 0, 0x01);
    IOWR(CAMERA_RESET_N_BASE, 0, 0x00);
    usleep(1000); // assert RESET_BAR for at least 1ms
    IOWR(CAMERA_RESET_N_BASE, 0, 0x01);
    
    usleep(20000); // wait for 150000 extclk
    //printf("Camera Register Access!\n");
    
    
    ///////////////////////////////////////
    //I2CL_Write16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CameraDeviceAddr, 0x301A, 0x0001);
    //usleep(200*1000);
    //I2CL_Write16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CameraDeviceAddr, 0x301A, 0x10D8);
    //usleep(200*1000);
    
    ///////////////////////////////////////
    // check chip id (expecte: 2400h)
    if (I2CL_Read16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CAMERA_I2C_ADDR, 0x3000, &data16)){
        printf("Chip id = %04Xh\r\n", data16);
    }else{
        printf("Failed to read chip id\r\n");
    }
  
    ///////////////////////////////////////
    // write reg
   
    // WDR CAMERA
  
    num = sizeof(szCameraRegList)/sizeof(szCameraRegList[0]);
    
    for(i=0;i<num && bSuccess;i++){
        if (szCameraRegList[i].Addr == 0xFFFF)
            usleep(szCameraRegList[i].Data*1000);
        else
            bSuccess = I2CL_Write16(CAMERA_SCL_BASE, CAMERA_SDA_BASE, CAMERA_I2C_ADDR, szCameraRegList[i].Addr, szCameraRegList[i].Data);
    } 
     
    
    printf("Camera configuration done (%s).\r\n", bSuccess?"Success":"NG");
  
   
//    IOWR(LED_BASE, 0, bSuccess?0xAA:0x00);
    
  
    while(1){
        
        sw = IORD(SW_BASE, 0) & 0x08;
        if (sw != pre_sw){
            pre_sw = sw;
            
            // SW[0] HiDy or Linear Mode
            SetHiDyMode(((sw>>3) & 0x01)?TRUE:FALSE);
//            LCD_Clear();
//            if (sw & 0x01)
//                LCD_TextOut("WDR Camera Demo\nHiDy Mode");
//            else    
//                LCD_TextOut("WDR Camera Demo\nLinear Mode");
            
        }
                            
    }
          

  return 0;
}



