//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:    OV3640_module.cpp

Abstract:       OV3640 Camera module control module

Functions:


Notes:


--*/

#include <bsp.h>
#include <module.h>
#include "OV3640_module.h"
#include "OV3640_module_reg.h"


#define PREDEFINED_IMAGE_SIZE       (14)


BYTE SupportedModuleImageSize[PREDEFINED_IMAGE_SIZE][2]
 // SizeValue[0], SizeValue[1]
  = { {0x02, 6},    // QCIF
      {0x02, 5},    // CIF  /*352x288*/
      {0x02, 4},    // QQVGA
      {0x02, 3},    // QVGA
      {0x02, 2},    // VGA
      {0,0},        // SVGA /*800x600*/
      {0x02, 1},    // SXGA /*1280x1024*/
      {0x02, 0},    // UXGA /*1600x1200*/
      {0,0},        // QXGA /*2048x1536*/
      {0,0},        // WVGA /*854x480*/
      {0,0},        // HD720    /*1280x720*/
      {0,0},        // HD1080   /*1920x1080*/
      {0x02, 9},    // SUB_SAMPLING2    /*800x600*/
      {0x02, 0x0B}, // SUB_SAMPLING4    /*400x300*/
    };


#define MODULE_NAME _T("OV3640")

//========================================================
//  Global variable definition

//========================================================
//  OV3640 functions
OV3640::OV3640()
{
    m_oCommIF = NULL;
    memset(&ModuleDescriptor , 0 , sizeof(MODULE_DESCRIPTOR));

}

OV3640::~OV3640()
{
}
OV3640::OV3640(ICamComm *CommIF)
{
    m_oCommIF = CommIF;
}
MODULE_STATUS OV3640::Init()
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));

	RETAILMSG(1, (TEXT("\r\nOV3640::Init\r\n")));

    PHYSICAL_ADDRESS    ioPhysicalBase = {0,0};

    // GPIO Virtual alloc
    ioPhysicalBase.LowPart = BASE_REG_PA_GPIO;
    m_regIOP = (GPIO_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(GPIO_REG), FALSE);
    if (m_regIOP == NULL)
    {
        ERRMSG((_T("[CAMIF:ERR] ++%s(): m_regIOP DrvLib_MapIoSpace failed!\r\n"), _T(__FUNCTION__)));
        return MOD_STATUS_FAIL;
    }

    m_oCommIF = new CamCommI2C();
    if(!m_oCommIF)
    {
        ERRMSG((_T("[CAMIF:ERR] ++%s(): Cannot create Comm Instance!\r\n"), _T(__FUNCTION__)));    
        return MOD_STATUS_FAIL;
    }
    
    ModuleDescriptor.ModuleID = SYSLSI_OV3640;
    ModuleDescriptor.ITUXXX = OV3640_MODULE_ITUXXX;
    ModuleDescriptor.ModuleInterlace = OV3640_MODULE_INTERLACE;
    ModuleDescriptor.MIPI = OV3640_MODULE_MIPI;
    ModuleDescriptor.UVOffset = OV3640_MODULE_UVOFFSET;
    ModuleDescriptor.SourceHSize = OV3640_MODULE_HSIZE;
    ModuleDescriptor.Order422 = OV3640_MODULE_YUVORDER;
    ModuleDescriptor.SourceVSize = OV3640_MODULE_VSIZE;
    ModuleDescriptor.Clock = OV3640_MODULE_CLOCK;
    ModuleDescriptor.Codec = OV3640_MODULE_CODEC;
    ModuleDescriptor.HighRst = OV3640_MODULE_HIGHRST;
    ModuleDescriptor.SourceHOffset = OV3640_MODULE_HOFFSET;
    ModuleDescriptor.SourceVOffset = OV3640_MODULE_VOFFSET;
    ModuleDescriptor.InvPCLK = OV3640_MODULE_INVPCLK;
    ModuleDescriptor.InvVSYNC = OV3640_MODULE_INVVSYNC;
    ModuleDescriptor.InvHREF = OV3640_MODULE_INVHREF;

    DBGMSG(CAMC_FUNC,(_T("%s ModuleDescriptor Dump:%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"), _T(__FUNCTION__),
    ModuleDescriptor.ITUXXX,
    ModuleDescriptor.ModuleInterlace,
    ModuleDescriptor.MIPI,
    ModuleDescriptor.LANE,
    ModuleDescriptor.JPEG,
    ModuleDescriptor.UVOffset,
    ModuleDescriptor.SourceHSize,
    ModuleDescriptor.Order422,
    ModuleDescriptor.SourceVSize,
    ModuleDescriptor.Clock,
    ModuleDescriptor.Codec,
    ModuleDescriptor.HighRst,
    ModuleDescriptor.SourceHOffset,
    ModuleDescriptor.SourceVOffset,
    ModuleDescriptor.InvPCLK,
    ModuleDescriptor.InvVSYNC,
    ModuleDescriptor.InvHREF,
    ModuleDescriptor.JpegSpoofHeight,
    ModuleDescriptor.JpegSpoofWidth,
    ModuleDescriptor.eHSsettle
    ));


    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::Deinit()
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));
    
    if(m_regIOP != NULL)
    {
        MmUnmapIoSpace((PVOID)m_regIOP, sizeof(GPIO_REG));
        m_regIOP = NULL;
    }
    if(m_oCommIF)
    {
        delete m_oCommIF;
        m_oCommIF=NULL;
    }
    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::InitSensor()
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));
    
        
    // Set the i2c slave address and clock
    // add allocation of resources which are used for S5K6AA isp
    // initialize the camera sensor

    
    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::SensorPrepare()
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));
    
       
    // Set the i2c slave address and clock
    // add allocation of resources which are used for S5K6AA isp
    // initialize the camera sensor
 
    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::SensorStart()
{
    int i=0,nLen = 0;
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));
    

    DBGMSG(CAMC_FUNC, (_T("Write Init Command to Module\r\n")));    

	RETAILMSG(1, (TEXT("OV3640::SensorStart\r\n")));
        
    // Set the i2c slave address and clock
    // add allocation of resources which are used for S5K6AA isp
    // initialize the camera sensor
    m_oCommIF->Open(CAM_OV3640_DEVICE_ID, CAM_OV3640_I2C_CLOCK);

    nLen = sizeof(OV3640_YCbCr8bit)/sizeof(OV3640_YCbCr8bit[0]);

    for(i=0; i<nLen; i++)
    {
        // Use Command Register and Data set(2byte per IIC Transaction).
        //RETAILMSG(FALSE,(TEXT("+%s, %d,%d -> %d,%d\n"), _T(__FUNCTION__), MODULE_REGISTER[i][0], MODULE_REGISTER[i][1],
        //    (pCommandBuf+i*sizeof(BYTE)*sizeof(MODULE_REGISTER[0])), pCommandBuf+i*sizeof(BYTE)+1));
            RETAILMSG(1, (TEXT("*")));
		m_oCommIF->WriteRegisters(OV3640_YCbCr8bit[i],sizeof(OV3640_YCbCr8bit[i]));
        
    }

    m_oCommIF->Close();
    
    return MOD_STATUS_SUCCESS;
}


MODULE_STATUS OV3640::Power(BOOL bOnOff)
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s - OnOff=%d\r\n"), MODULE_NAME, _T(__FUNCTION__), bOnOff));

    if ( bOnOff == TRUE )
    {
        PowerStatus = MOD_PWR_STATUS_ON;
    }
    else
    {
        PowerStatus = MOD_PWR_STATUS_OFF;
    }

    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::Standby(BOOL bActive)
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s - Active=%d\r\n"), MODULE_NAME, _T(__FUNCTION__), bActive));

    if ( bActive == TRUE )
    {

        PowerStatus = MOD_PWR_STATUS_STANDBY;
    }
    else
    {

        PowerStatus = MOD_PWR_STATUS_ON;
    }

    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::Reset(BOOL bActive)
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s - Active=%d\r\n"), MODULE_NAME, _T(__FUNCTION__), bActive));

    if ( bActive == TRUE )
    {
        PowerStatus = MOD_PWR_STATUS_RESET_ACTIVE;
    }
    else
    {
        PowerStatus = MOD_PWR_STATUS_RESET_DEACTIVE;
    }
    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS OV3640::GetSupportFormat(MODULE_DESCRIPTOR *outModuleDesc)
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s\r\n"), MODULE_NAME, _T(__FUNCTION__)));

    memcpy(outModuleDesc, &ModuleDescriptor, sizeof(MODULE_DESCRIPTOR));

    DBGMSG(CAMC_FUNC,(_T("gModuleDesc Dump:%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n"),
                    outModuleDesc->ITUXXX,
                    outModuleDesc->ModuleInterlace,
                    outModuleDesc->MIPI,
                    outModuleDesc->LANE,                    
                    outModuleDesc->JPEG,
                    outModuleDesc->UVOffset,
                    outModuleDesc->SourceHSize,
                    outModuleDesc->Order422,
                    outModuleDesc->SourceVSize,
                    outModuleDesc->Clock,
                    outModuleDesc->Codec,
                    outModuleDesc->HighRst,
                    outModuleDesc->SourceHOffset,
                    outModuleDesc->SourceVOffset,
                    outModuleDesc->InvPCLK,
                    outModuleDesc->InvVSYNC,
                    outModuleDesc->InvHREF
                    ));

    return MOD_STATUS_SUCCESS;
}

// OV3640 isp support only yuv422(UYVY) format
// So, we don't check the media format
MODULE_STATUS OV3640::SetFormatSize(CAMIF_IMG_SIZE Size)
{
    DBGMSG(CAMC_FUNC, (_T("[%s] %s - %s, Size = %d\r\n"), MODULE_NAME, _T(__FUNCTION__), CAM_OPMODE_TO_STR(OperationMode), Size));
    MODULE_STATUS Status = MOD_STATUS_SUCCESS;

    return Status;
}


