/**
 * @file i2c_master.cpp
 *
 * @author FTDI
 * @date 2014-07-01
 *
 * Copyright © 2011 Future Technology Devices International Limited
 * Company Confidential
 *
 * Rivision History:
 * 1.0 - initial version
 */

//------------------------------------------------------------------------------
#include <windows.h>

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>

//------------------------------------------------------------------------------
// include FTDI libraries
//
#include "ftd2xx.h"
#include "LibFT4222.h"


std::vector< FT_DEVICE_LIST_INFO_NODE > g_FT4222DevList;
std::vector< FT_DEVICE_LIST_INFO_NODE > g_FT4222DevList_B;

//------------------------------------------------------------------------------
inline std::string DeviceFlagToString(DWORD flags)
{
    std::string msg;
    msg += (flags & 0x1)? "DEVICE_OPEN" : "DEVICE_CLOSED";
    msg += ", ";
    msg += (flags & 0x2)? "High-speed USB" : "Full-speed USB";
    return msg;
}

void ListFtUsbDevices()
{
    FT_STATUS ftStatus = 0;

    DWORD numOfDevices = 0;
    ftStatus = FT_CreateDeviceInfoList(&numOfDevices);

    for(DWORD iDev=0; iDev<numOfDevices; ++iDev)
    {
        FT_DEVICE_LIST_INFO_NODE devInfo;
        memset(&devInfo, 0, sizeof(devInfo));

        ftStatus = FT_GetDeviceInfoDetail(iDev, &devInfo.Flags, &devInfo.Type,
                                        &devInfo.ID, &devInfo.LocId,
                                        devInfo.SerialNumber,
                                        devInfo.Description,
                                        &devInfo.ftHandle);

        if (FT_OK == ftStatus)
        {
            const std::string desc = devInfo.Description;
            if(desc == "FT4222" || desc == "FT4222 A")
            {
                g_FT4222DevList.push_back(devInfo);
            }
        }
    }
}

void ListFtUsbDevices_B()
{
    FT_STATUS ftStatus = 0;

    DWORD numOfDevices = 0;
    ftStatus = FT_CreateDeviceInfoList(&numOfDevices);

    for(DWORD iDev=0; iDev<numOfDevices; ++iDev)
    {
        FT_DEVICE_LIST_INFO_NODE devInfo;
        memset(&devInfo, 0, sizeof(devInfo));

        ftStatus = FT_GetDeviceInfoDetail(iDev, &devInfo.Flags, &devInfo.Type,
                                        &devInfo.ID, &devInfo.LocId,
                                        devInfo.SerialNumber,
                                        devInfo.Description,
                                        &devInfo.ftHandle);

        if (FT_OK == ftStatus)
        {
            const std::string desc = devInfo.Description;
            if(desc == "FT4222" || desc == "FT4222 B")
            {
                g_FT4222DevList_B.push_back(devInfo);
            }
        }
    }
}

//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(int argc, char const *argv[])
{
	//**********Open Device: FT4222_A for I2C
    ListFtUsbDevices();

    if(g_FT4222DevList.empty()) {
        printf("No FT4222 device is found!\n");
        return 0;
    }

    const FT_DEVICE_LIST_INFO_NODE& devInfo = g_FT4222DevList[0];

    printf("Open Device\n");
    printf("  Flags= 0x%x, (%s)\n", devInfo.Flags, DeviceFlagToString(devInfo.Flags).c_str());
    printf("  Type= 0x%x\n",        devInfo.Type);
    printf("  ID= 0x%x\n",          devInfo.ID);
    printf("  LocId= 0x%x\n",       devInfo.LocId);
    printf("  SerialNumber= %s\n",  devInfo.SerialNumber);
    printf("  Description= %s\n",   devInfo.Description);
    printf("  ftHandle= 0x%x\n",    devInfo.ftHandle);


    FT_HANDLE ftHandle = NULL;

    FT_STATUS ftStatus;
    ftStatus = FT_OpenEx((PVOID)g_FT4222DevList[0].LocId, FT_OPEN_BY_LOCATION, &ftHandle);
    if (FT_OK != ftStatus)
    {
        printf("Open a FT4222 device failed!\n");
        return 0;
    }

	//**********Open Device: FT4222_B for GPIO
    ListFtUsbDevices_B();

    if(g_FT4222DevList_B.empty()) {
        printf("No FT4222 device is found!\n");
        return 0;
    }

	/*
    const FT_DEVICE_LIST_INFO_NODE& devInfo = g_FT4222DevList[0];

    printf("Open Device\n");
    printf("  Flags= 0x%x, (%s)\n", devInfo.Flags, DeviceFlagToString(devInfo.Flags).c_str());
    printf("  Type= 0x%x\n",        devInfo.Type);
    printf("  ID= 0x%x\n",          devInfo.ID);
    printf("  LocId= 0x%x\n",       devInfo.LocId);
    printf("  SerialNumber= %s\n",  devInfo.SerialNumber);
    printf("  Description= %s\n",   devInfo.Description);
    printf("  ftHandle= 0x%x\n",    devInfo.ftHandle);
	*/

    FT_HANDLE ftHandle_B = NULL;

    //FT_STATUS ftStatus;
    ftStatus = FT_OpenEx((PVOID)g_FT4222DevList_B[0].LocId, FT_OPEN_BY_LOCATION, &ftHandle_B);
    if (FT_OK != ftStatus)
    {
        printf("Open a FT4222_B device failed!\n");
        return 0;
    }


	//*********** Init for Set VIO and I2C's Pull up resistance ************
	// disable Suspenout, it use the same pin with gpio2
    ftStatus=FT4222_SetSuspendOut(ftHandle_B, false);

	// disable WakeUp Interrupt, it use the same pin with gpio3
	ftStatus=FT4222_SetWakeUpInterrupt(ftHandle_B, false);

	GPIO_Dir gpioDir[4];

    gpioDir[0] = GPIO_INPUT;
    gpioDir[1] = GPIO_INPUT;
    gpioDir[2] = GPIO_OUTPUT;
    gpioDir[3] = GPIO_OUTPUT;

	FT4222_GPIO_Init(ftHandle_B, gpioDir);
	FT4222_GPIO_Write(ftHandle_B, GPIO_PORT3, 1);

	ftStatus = FT4222_I2CMaster_Init(ftHandle, 100);

	//*********Set VIO**************
	double VIO=3.2; //Set VIO=3.2V; The range is from 1.7~3.3V
	uint16 iVIO_Value = (uint16)(((2 * VIO - 3.3) / 3.3) * 65535);

	uint16 slaveAddr = 0x61;
    uint8 VIO_master_data[] = {0x60, (byte)(iVIO_Value >> 8), (byte)(iVIO_Value & 0xFF)};
    //uint8 slave_data[4];
    uint16 sizeTransferred = 0;

	ftStatus = FT4222_I2CMaster_Write(ftHandle, slaveAddr, VIO_master_data, sizeof(VIO_master_data), &sizeTransferred);
    if (FT_OK == ftStatus)
    {
        printf("Set VIO= %f (V)",VIO);
    }
	//**************************************************

	//*********Set I2C's Pull up resistance**************
	slaveAddr=0x20;
	uint8 I2C_Pullup_master_data[]={0x03,0xFF};
	ftStatus = FT4222_I2CMaster_Write(ftHandle, slaveAddr, I2C_Pullup_master_data, sizeof(I2C_Pullup_master_data), &sizeTransferred);

	I2C_Pullup_master_data[0]=0x07;
	//I2C_Pullup_master_data[1]=0xEE; //I2C Pull up resistance=1K
    //I2C_Pullup_master_data[1]=0xFF; //I2C Pull up resistance=NC
    //I2C_Pullup_master_data[1]=0x00; //I2C Pull up resistance=680R
	I2C_Pullup_master_data[1]=0xDD; //I2C Pull up resistance=3.9K
	ftStatus = FT4222_I2CMaster_Write(ftHandle, slaveAddr, I2C_Pullup_master_data, sizeof(I2C_Pullup_master_data), &sizeTransferred);
	//**************************************************
	
	//****** Init for User *****************************
	FT4222_GPIO_Write(ftHandle_B, GPIO_PORT3, 0);
	//**************************************************


	//****** Write two bytes to E2PROM's address=0x20; ******
	slaveAddr=0x51;
	uint8 E2_Write_master_data[]={0x20,0x91,0xA2};
	ftStatus = FT4222_I2CMaster_Write(ftHandle, slaveAddr, E2_Write_master_data, sizeof(E2_Write_master_data), &sizeTransferred);

	//****** Read two bytes from E2PROM.Current Address=0x20;            
	slaveAddr=0x51;
	uint8 E2_Read_Address_master_data[]={0x20};
	ftStatus = FT4222_I2CMaster_Write(ftHandle, slaveAddr, E2_Read_Address_master_data, sizeof(E2_Read_Address_master_data), &sizeTransferred);

	uint8 E2_Read_Data_slave_data[2];
	ftStatus = FT4222_I2CMaster_Read(ftHandle, slaveAddr, E2_Read_Data_slave_data, sizeof(E2_Read_Data_slave_data), &sizeTransferred);
	//**************************************************	

    printf("UnInitialize FT4222\n");
    FT4222_UnInitialize(ftHandle);

    printf("Close FT device\n");
    FT_Close(ftHandle);
	FT_Close(ftHandle_B);
    return 0;
}
