//
// 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:    module.cpp

Abstract:       Camera module control common code

Functions:


Notes:


--*/

#include <bsp.h>
#include <drvmsg.h>
#include "Module.h"
#include "i2c_camera.h"

#define IIC_DRIVER_PORT     _T("I2C1:")//_T("I2C0:") // modify by terry 20120426 for x210

CamModule::CamModule()
{
    m_oCommIF = NULL;
}
CamModule::CamModule(ICamComm *CommIF)
{
    m_oCommIF = CommIF;
}

CamModule::~CamModule()
{
}

MODULE_STATUS CamModule::SetOperationMode(CAMIF_OPERATION_MODE mode)
{
    MODULE_MSG( (_T("%s(%s)\r\n"),_T(__FUNCTION__), CAM_OPMODE_TO_STR(mode)));
    OperationMode = mode;

    return MOD_STATUS_SUCCESS;
}

MODULE_STATUS CamModule::StartCapture()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::StopCapture()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::Flash()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::SetBrightness()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::Effect()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::Whitebalance()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}

MODULE_STATUS CamModule::Framerate()
{
    MODULE_MSG( (_T("%s\r\n"), _T(__FUNCTION__)));

    return MOD_STATUS_NOTSUPPORT;
}


CamCommI2C::CamCommI2C()
    : m_dwErr(ERROR_SUCCESS),
      m_dwIICClock(0),
      hI2CDriver(INVALID_HANDLE_VALUE),
      m_BusSlaveAddress(NULL)
{
}

MODULE_STATUS CamCommI2C::Open(DWORD BusSlaveAddress, DWORD dwIICClock)
{
    DWORD bytes;
    MODULE_MSG((TEXT("+%s\n"), _T(__FUNCTION__)));

    hI2CDriver = OpenI2C( IIC_DRIVER_PORT );

    InitI2C(hI2CDriver, BusSlaveAddress, dwIICClock);

    m_dwIICClock = dwIICClock;

    m_BusSlaveAddress = (CHAR)BusSlaveAddress;
    MODULE_MSG((TEXT("-%s\n"), _T(__FUNCTION__)));
    return MOD_STATUS_SUCCESS;
}

CamCommI2C::~CamCommI2C()
{
    Close();
}

void CamCommI2C::Close()
{
    // Close I2C Driver
    if (hI2CDriver!= INVALID_HANDLE_VALUE)
    {
        CloseHandle(hI2CDriver);
        hI2CDriver = INVALID_HANDLE_VALUE;
    }
}

MODULE_STATUS CamCommI2C::WriteRegisters(
    PUCHAR pBuff,   // Optional buffer
    DWORD nRegs     // number of registers
    )
{
    DWORD bytes;        // Read
    DWORD nRetries = 3; // Default retries is 3

   RETAILMSG(0, (TEXT("nRegs = %d\r\n"),nRegs));

    WriteI2C_Camera(hI2CDriver, pBuff, nRegs );
    RETAILMSG(0,(TEXT("-HW_WriteRegisters\n")));

    return MOD_STATUS_SUCCESS;
}

// This function will use Set file itself.
MODULE_STATUS CamCommI2C::WriteRegisters(UINT32 setFileValue)
{
    DMA_ADAPTER_OBJECT Adapter;
    PBYTE pCommandBuf = NULL;
    PHYSICAL_ADDRESS pPhyCommandBuf;
    MODULE_STATUS bRet = MOD_STATUS_SUCCESS;

    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
    Adapter.InterfaceType = Internal;
    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);

    if(pCommandBuf == NULL)
    {
        pCommandBuf  = (PBYTE)HalAllocateCommonBuffer(&Adapter, 4, &pPhyCommandBuf, FALSE);
    }

    if (pCommandBuf == NULL)
    {
        MODULE_ERR((_T("%s(): Failed to allocate DMA buffer for Command Buffer.\r\n"), _T(__FUNCTION__)));
        return MOD_STATUS_FAIL;
    }

    // write at Device D000:SubAddr

    pCommandBuf[0] = ((UCHAR *)&setFileValue)[3];
    pCommandBuf[1] = ((UCHAR *)&setFileValue)[2];
    pCommandBuf[2] = ((UCHAR *)&setFileValue)[1];
    pCommandBuf[3] = ((UCHAR *)&setFileValue)[0];

    bRet = WriteRegisters(pCommandBuf, sizeof(pCommandBuf));

    if(pCommandBuf != NULL)
    {
        HalFreeCommonBuffer(&Adapter, 0, pPhyCommandBuf, (PVOID)pCommandBuf, FALSE);
    }

    return bRet;
}

MODULE_STATUS CamCommI2C::WriteRegisters(UINT16 *setFileValue)
{
    DMA_ADAPTER_OBJECT Adapter;
    PBYTE pCommandBuf = NULL;
    PHYSICAL_ADDRESS pPhyCommandBuf;
    MODULE_STATUS bRet = MOD_STATUS_SUCCESS;

    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
    Adapter.InterfaceType = Internal;
    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);

    if(pCommandBuf == NULL)
    {
        pCommandBuf  = (PBYTE)HalAllocateCommonBuffer(&Adapter, 4, &pPhyCommandBuf, FALSE);
    }

    if (pCommandBuf == NULL)
    {
        MODULE_ERR((_T("%s(): Failed to allocate DMA buffer for Command Buffer.\r\n"), _T(__FUNCTION__)));
        return MOD_STATUS_FAIL;
    }

    // write at Device D000:SubAddr
    pCommandBuf[0] = ((UCHAR *)setFileValue)[1];
    pCommandBuf[1] = ((UCHAR *)setFileValue)[0];
    pCommandBuf[2] = ((UCHAR *)setFileValue)[3];
    pCommandBuf[3] = ((UCHAR *)setFileValue)[2];

    bRet = WriteRegisters(pCommandBuf, 4);

    if(pCommandBuf != NULL)
    {
        HalFreeCommonBuffer(&Adapter, 0, pPhyCommandBuf, (PVOID)pCommandBuf, FALSE);
    }

    return bRet;
}


MODULE_STATUS CamCommI2C::WriteRegisters(UINT16 RegValue, UINT16 DataValue)
{
    DMA_ADAPTER_OBJECT Adapter;
    PBYTE pCommandBuf = NULL;
    PHYSICAL_ADDRESS pPhyCommandBuf;
    MODULE_STATUS bRet = MOD_STATUS_SUCCESS;
	UINT8 *u8Array = (UINT8*)&RegValue;
	UINT8 *u8Array2= (UINT8*)&DataValue;

    unsigned char value = 0;
    static bool bRepeat = false;


    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
    Adapter.InterfaceType = Internal;
    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);

    if(pCommandBuf == NULL)
    {
        pCommandBuf  = (PBYTE)HalAllocateCommonBuffer(&Adapter, 3, &pPhyCommandBuf, FALSE);
    }

    if (pCommandBuf == NULL)
    {
        MODULE_ERR((_T("%s(): Failed to allocate DMA buffer for Command Buffer.\r\n"), _T(__FUNCTION__)));
        return MOD_STATUS_FAIL;
    }

#ifndef TVP5150
	pCommandBuf[0] = u8Array[1];	// Sub Address[15:8]
	pCommandBuf[1] = u8Array[0];	// Sub Address[7:0]
	pCommandBuf[2] = u8Array2[0];	// Data[7:0]
	//pCommandBuf[3] = u8Array2[0];	// Data[7:0]

    bRet = WriteRegisters(pCommandBuf, 3);

#else  // FOR tvp5150

	pCommandBuf[0] = u8Array[0];	// Sub Address[7:0]
	pCommandBuf[1] = u8Array2[0];	//  Data[7:0]

	bRet = WriteRegisters(pCommandBuf, 2);

#endif


#if 0  //added by terry for test
	ReadI2C_Camera(hI2CDriver,pCommandBuf,2,FALSE,&value,1);
	RETAILMSG(1, (TEXT("0x%x\r\n"),value));

  //  if(!bRepeat)
    if(0)
    {
        bRepeat = true;
        pCommandBuf[0] = 0x30;    // Sub Address[15:8]
        pCommandBuf[1] = 0x0a;    // Sub Address[7:0]

        RETAILMSG(1, (TEXT("------------------------------------------------\r\n")));
        // read sensor id
        ReadI2C_Camera(hI2CDriver,pCommandBuf,2,FALSE,&value,1);
        RETAILMSG(1, (TEXT("OV2655 PIDH[%x]\r\n"),value));

        pCommandBuf[0] = 0x30;    // Sub Address[15:8]
        pCommandBuf[1] = 0x0b;    // Sub Address[7:0]
        ReadI2C_Camera(hI2CDriver,pCommandBuf,2,FALSE,&value,1);
        RETAILMSG(1, (TEXT("OV2655 PIDL[%x]\r\n"),value));
     //   RETAILMSG(1, (TEXT("------------------------------------------------\r\n")));
    }


#endif

    if(pCommandBuf != NULL)
    {
        HalFreeCommonBuffer(&Adapter, 0, pPhyCommandBuf, (PVOID)pCommandBuf, FALSE);
    }

    return bRet;
}




DWORD CamCommI2C::ReadRegisters(
    PUCHAR pBuff,       // Optional buffer
    UCHAR StartReg,     // Start Register
    DWORD nRegs         // Number of Registers
    )
{
    DWORD bytes;
    ReadI2C_Camera(hI2CDriver, &StartReg, 1 , FALSE, pBuff, nRegs);
    return m_dwErr;
}

//MODULE_STATUS CamCommI2C::WriteRegisterSeq(UINT16 Regs[][2])
MODULE_STATUS CamCommI2C::WriteRegisterSeq(UINT16 Regs[][2],INT nLen)
{
    int i = 0;

#if 1 // added by terry for ov2655
    if(nLen<0)
        return MOD_STATUS_FAIL;
    //nLen = sizeof(ov2655_init_reg)/sizeof(ov2655_init_reg[0]);

    // Do iteration when the END Mark appears
    for ( i=0; i<nLen; i++ )
    {
        //MODULE_INF((TEXT("111 %s {0x%02x, 0x%02x}\r\n"), _T(__FUNCTION__), Regs[i][0], Regs[i][1]));

        if ( Regs[i][0] == 0x0000 )
        {
            Sleep(Regs[i][1]);
        }
        else
        {
            if(WriteRegisters(Regs[i][0],Regs[i][1]) != MOD_STATUS_SUCCESS )
            {
                MODULE_ERR((TEXT("111%s : No. %d command failed\r\n"),  _T(__FUNCTION__),i));
                return MOD_STATUS_FAIL;
            }

            //Sleep(1);

        }


    }



#else

    // Do iteration when the END Mark appears
    for ( i=0; (Regs[i][0] != COMMAND_SEQ_END_MARK) ; i++ )
    {
        MODULE_INF((TEXT("111 %s {0x%02x, 0x%02x}\r\n"), _T(__FUNCTION__), Regs[i][0], Regs[i][1]));

        if ( Regs[i][0] == COMMAND_SEQ_DELAY_MARK )
        {
            Sleep(Regs[i][1]);
        }
        else
        {
            if ( WriteRegisters(Regs[i]) != MOD_STATUS_SUCCESS )
            {
                MODULE_ERR((TEXT("111%s : No. %d command failed\r\n"),  _T(__FUNCTION__),i));
                return MOD_STATUS_FAIL;
            }

            //Sleep(1);
        }
    }
#endif

    return MOD_STATUS_SUCCESS;
}

// For MIPI 16bit command, sequence
MODULE_STATUS CamCommI2C::WriteRegisterSeq(UINT32 Regs[])
{
    MODULE_STATUS i2c_status = MOD_STATUS_SUCCESS;
    int i = 0;
    UINT8 compValue = 0;
    int RetryCount = 0;

    // Do iteration when the END Mark appears
    for ( i=0; (Regs[i] & 0xFFFF0000) != COMMAND_SEQ_END_MARK; i++ )
    {
        MODULE_INF( (TEXT("[S5K6AA] {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}\r\n"), ((UINT8 *)&Regs[i])[0],((UINT8 *)&Regs[i])[1],((UINT8 *)&Regs[i])[2],((UINT8 *)&Regs[i])[3]));

        // Don't remove this delay routine. the s5k6aa isp needs sufficient delay in each sequence
        Sleep(10);

        if ( (Regs[i] & 0xFFFF0000) == COMMAND_SEQ_DELAY_MARK )
        {
            MODULE_INF( (TEXT("[S5K6AA] Sleep(%d)\r\n"), (Regs[i] & 0x0000FFFF)));
            Sleep((Regs[i] & 0x0000FFFF));
        }
        else
        {
            i2c_status = WriteRegisters(Regs[i]);
        }
    }

    return i2c_status;
}


