using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace I2C_Sample
{
    class Program
    {
        public const ushort PROLIFIC_VID = 0x67B;
        public const int ERROR_SUCCESS = 0;
        public const int ERROR_INSUFFICIENT_BUFFER = -1;
        public const int ERROR_READ_REGISTER_FAIL = -2;
        public const int ERROR_WRITE_REGISTER_FAIL = -3;
        public const int ERROR_READ_DATA_FAIL = -4;
        public const int ERROR_READ_TIMEOUT = -5;
        public const int ERROR_WRITE_DATA_FAIL = -6;
        public const int ERROR_WRITE_TIMEOUT = -7;
        public const int ERROR_DEVICE_NOT_EXIST = -8;
        public const int ERROR_NOT_GPIO_PIN = -9;
        public const int ERROR_DEVICE_OPEN_FAIL = -10;
        public const int ERROR_DATA_LENGTH_TOO_LARGE = -11;
        public const int ERROR_OTHER_FAIL = -12;
        public const int ERROR_I2C_BUS_BUSY = -13;
        public const int ERROR_I2C_ADDRESS_NACK = -14;
        public const int ERROR_I2C_DATA_NACK = -15;
        public const int ERROR_I2C_PROCESSING = -16;

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)] 
        public static extern int GetSDKVersion(out uint SDKVersion);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int EnumDeviceByVid(ref uint HidDeviceCount, ushort VID);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)] 
        public static extern int EnumDeviceByVidPid(ref uint HidDeviceCount, ushort VID, ushort PID);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int OpenDeviceHandle(uint DeviceIndex, ref System.IntPtr hDeviceHandle);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int CloseDeviceHandle(System.IntPtr hDeviceHandle);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int SetI2CDeviceAddress(System.IntPtr hDeviceHandle, byte DeviceAddress);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int SetI2CFrequency(System.IntPtr hDeviceHandle, byte FreqDiv);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int I2CRead(System.IntPtr hDeviceHandle, ref byte Buffer, ushort NumberOfBytesToRead,
                                    ref ushort NumberOfBytesRead, uint TimeOutms);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int I2CWrite(System.IntPtr hDeviceHandle, ref byte Buffer, ushort NumberOfBytesToWrite, 
                                        ref ushort NumberOfBytesWritten, uint TimeOutms);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int I2CWriteRead(System.IntPtr hDeviceHandle, ref byte WriteBuffer, ushort NumberOfBytesToWrite, 
                                            ref byte byReadBuffer, ushort NumberOfBytesToRead, 
                                            ref ushort nNumberOfBytesUse, uint TimeOutms);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int I2CReset(System.IntPtr hDeviceHandle);

        static void Main(string[] args)
        {
            uint unDeviceCount = 0;
            int nRet = 0;
            nRet = EnumDeviceByVid(ref unDeviceCount, PROLIFIC_VID);    //vid=0x067b
            if (ERROR_SUCCESS == nRet)
            {
                if (unDeviceCount > 0)
                {
                    //System.IntPtr hDeviceHandle = new IntPtr();
                    System.IntPtr hDeviceHandle = System.IntPtr.Zero;
                    nRet = OpenDeviceHandle(0, ref hDeviceHandle);

                    //Set Device Address(7 Bit Device Address)
                    byte by7BitDeviceAddress = 0xA0;
                    nRet = SetI2CDeviceAddress(hDeviceHandle, by7BitDeviceAddress);
                    if (ERROR_SUCCESS == nRet)
                    {
                        Console.WriteLine("Set I2C 7Bit DeviceAddress=0x{0:X}", by7BitDeviceAddress);
                    }
                    else
                    {
                        Console.WriteLine("SetI2CDeviceAddress Fail");
                    }

                    //Set I2C Frequency
                    //nI2CFreqDiv = 4, I2C Frequency(KHz) = 24000/4 = 6 Mhz(Max)
                    //nI2CFreqDiv = 255, I2C Frequency(KHz) = 24000/254 = 94 Khz(Min)
                    byte byI2CFreqDiv = 100;     //100==> 240 KHz
                    nRet = SetI2CFrequency(hDeviceHandle, byI2CFreqDiv);
                    if (ERROR_SUCCESS == nRet)
                    {
                        // Console.WriteLine("Set I2C 7Bit DeviceAddress=0x{0:X}", by7BitDeviceAddress);
                        Console.WriteLine("Set I2C Frequency={0:D} Hz", 24000000 / byI2CFreqDiv);
                    }
                    else
                    {
                        Console.WriteLine("SetI2CFrequency Fail");
                    }

                    //AT24C02, PageWrite
                    //Send I2C Word Address 0x00, Data = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37};
                    byte[] byWriteBuffer = { 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };
                    byte byHidWritePacketSize = 8;
                    ushort nRealDataLen = 0;
                    uint nTimeOutMs = 1000;
                    nRet = I2CWrite(hDeviceHandle, ref byWriteBuffer[0], byHidWritePacketSize,
                                        ref nRealDataLen, nTimeOutMs);
                    if (ERROR_SUCCESS == nRet)
                    {
                        Console.Write("I2C Page Write, WordAddress=0x{0:X}, Data=", byWriteBuffer[0]);
                        for (int n = 1; n < 8; n++)
                        {
                            Console.Write("0x{0:X} ", byWriteBuffer[n]);
                        }
                        Console.Write("\n");
                    }
                    else
                    {
                        Console.WriteLine("I2CWrite Fail");
                    }
                    //AT24C02, Random Read 
                    //Write 1 byte Word Address
                    byte[] byWordAddress = { 0x00 };
                    byte[] byReadBuffer = new byte[7];
                    ushort nNumberOfBytesToRead = 7;
                    nRet = I2CWriteRead(hDeviceHandle, ref byWordAddress[0], 0x01, ref byReadBuffer[0],
                                        nNumberOfBytesToRead, ref nRealDataLen, nTimeOutMs);
                    if (ERROR_SUCCESS == nRet)
                    {
                        Console.Write("I2C Random Read, WordAddress=0x{0:X}, Data=", byWordAddress[0]);
                        for (int n = 0; n <=6 ; n++)
                        {
                            Console.Write("0x{0:X} ", byReadBuffer[n]);
                        }
                        Console.Write("\n");
                    }
                    else
                    {
                        Console.WriteLine("I2C Random Read Fail");
                    }
                    nRet = CloseDeviceHandle(hDeviceHandle);
                }
                else
                {
                    Console.WriteLine("No match Hid device!");
                }
            }
            else
            {
                Console.WriteLine("EnumDeviceByVid fail!");
            }
            Console.ReadLine();
        }
    }
}
