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

namespace Uart_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;

        //UART_FLOW_CONTROL MODE
        public enum UART_FLOW_CONTROL
        {
            UART_RTS_CTS_DTR_DSR_FLOW_CONTROL = 0x10,	//1 00
            UART_DTR_DSR_FLOW_CONTROL = 0x14,	//1 01
            UART_RTS_CTS_FLOW_CONTROL = 0x18,	//1 10
            UART_SW_FLOW_CONTROL = 0x0C,		//0 11
            UART_DISABLE_FLOW_CONTROL = 0x1C,	//1 11
        }

        //STOP BIT
        public enum UART_STOP_BIT
        {
            UART_ONE_STOP_BIT = 0,
            UART_ONE_POINT_FIVE_STOP_BIT = 1,
            UART_TWO_STOP_BIT = 2,
        }

        //PARITY
        public enum UART_PARITY_TYPE
        {
            UART_PARITY_NONE = 0,
            UART_PARITY_ODD = 1,
            UART_PARITY_EVEN = 2,
            UART_PARITY_MARK = 3,
            UART_PARITY_SPACE = 4,
        }

        //DATA BIT
        public enum UART_DATA_BIT
        {
            UART_DATA_BIT_5 = 5,
            UART_DATA_BIT_6 = 6,
            UART_DATA_BIT_7 = 7,
            UART_DATA_BIT_8 = 8,
        }

        [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 OpenDeviceHandle(uint DeviceIndex, ref IntPtr hDeviceHandle);

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

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

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

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int SetUartConfig(IntPtr hDeviceHandle, uint BaudRate, UART_STOP_BIT StopBit, 
                                                UART_PARITY_TYPE ParityType, UART_DATA_BIT Databit, 
                                                UART_FLOW_CONTROL FlowControl);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int GetUartConfig(IntPtr hDeviceHandle, ref uint BaudRate, ref UART_STOP_BIT StopBit,
                                                ref UART_PARITY_TYPE ParityType, ref UART_DATA_BIT Databit,
                                                ref UART_FLOW_CONTROL FlowControl);

        [DllImport("HidDeviceSdk.dll", CallingConvention = CallingConvention.Winapi)]
        public static extern int SetXonXoffSymbol(IntPtr hDeviceHandle, byte Xon, byte Xoff);

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

        static void Main(string[] args)
        {
            uint nHidDeviceCount = 0;
            System.IntPtr hDeviceHandle = System.IntPtr.Zero;
            int nRet = 0;
            uint nBaudRate = 115200;     // 115200 bps

            UART_STOP_BIT nStopBit = UART_STOP_BIT.UART_ONE_STOP_BIT;
            UART_PARITY_TYPE nParityType = UART_PARITY_TYPE.UART_PARITY_NONE;
            UART_DATA_BIT nDataBit = UART_DATA_BIT.UART_DATA_BIT_8;
            UART_FLOW_CONTROL nFlowControl = UART_FLOW_CONTROL.UART_DISABLE_FLOW_CONTROL;
            nRet = EnumDeviceByVid(ref nHidDeviceCount, 0x67B);
            // Step1: Enum Device (&067B ==> USB VID)
            if (ERROR_SUCCESS == nRet )
            {
                if (0 < nHidDeviceCount)
                {
                    // Step2: Open Hid Device Array index, ex: 0
                    nRet = OpenDeviceHandle(0, ref hDeviceHandle);
                    if (ERROR_SUCCESS == nRet)
                    {
                        // Step3: Set Uart Config
                        nRet = SetUartConfig(hDeviceHandle, nBaudRate, nStopBit, nParityType, nDataBit, nFlowControl);
                        if(ERROR_SUCCESS == nRet) {
                            Console.WriteLine("SetUartConfig Success!");
                        }
                        else {
                            Console.WriteLine("SetUartConfig Fail!");
                        }
                        
                        byte[] byWriteBuffer = { 0x30, 0x31, 0x32, 0x33, 0x34 };
						uint nNumberOfBytesToRead = 5;
                        byte[] byReadBuffer = new byte[5];
                        uint nNumberOfBytesToWrite = 5;
                        uint nNumberOfBytesWritten = 0;
                        uint nTimeOutms = 8; // 8 ms

                        // Step4: Write
                        if (ERROR_SUCCESS == UartWrite(hDeviceHandle, ref byWriteBuffer[0], nNumberOfBytesToWrite,
                                            ref nNumberOfBytesWritten, nTimeOutms))
                        {
                            Console.Write("Write Uart Data: ");
                            for (int n = 0; n <= 4; n++)
                                Console.Write("0x{0:X} ", byWriteBuffer[n]);
                            Console.WriteLine("");
                        }
                        else
                            Console.WriteLine("Write Uart Data Fail!");

                        // Step5: Read
                        uint nNumberOfBytesRead = 0;
                        if (0 == UartRead(hDeviceHandle, ref byReadBuffer[0], nNumberOfBytesToRead,
                                            ref nNumberOfBytesRead, nTimeOutms))
                        {
                            Console.Write("Read Uart Data: ");
                            for (int n = 0; n <= 4; n++)
                                Console.Write("0x{0:X} ", byReadBuffer[n]);
                            Console.WriteLine("");
                        }
                        else
                            Console.WriteLine("Read Uart Data Fail!");
                        // Step6: Close Hid Device
                        nRet = CloseDeviceHandle(hDeviceHandle);
                    }
                    else
                        Console.WriteLine("Open Device Fail!");
                }
                else
                    Console.WriteLine("No match Hid device!");
            }
            else
                Console.WriteLine("EnumDeviceByVid fail");
            Console.ReadLine();
        }
    }
}
