using System;
using System.Collections.Generic;
using System.Text;
using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
using LibUsbDotNet.DeviceNotify;
using LibUsbDotNet.DeviceNotify.Linux;
using LibUsbDotNet.LibUsb;

namespace USBComponent
{
    class USB
    {
        private int myPID = 0x0020;  //产品ID
        private int myVID = 0x1500;  //供应商ID
        private static UsbDevice MyUsbDevice;
        private UsbEndpointReader reader;
        private UsbEndpointWriter writer;
        private static UsbDeviceFinder MyUsbFinder;
        private byte[] recDataBuff;
        public int recDataBuffCount = 0;
        public bool recDataBuffFlag = false;
        public bool connectionStatus = false;

        public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
        public delegate void USBDataReceivedEventHandler(object sender, EndpointDataEventArgs e);
        public event USBDataReceivedEventHandler USBDataReceived;
        protected virtual void OnUSBDataReceived(EndpointDataEventArgs e)//引发事件的方法，PuComputer事件中有此方法引发
        //虚方法，子类可以重载此方法
        {
            USBDataReceivedEventHandler DataReceived = USBDataReceived;//防止可能存在的线程同步问题

            if (DataReceived != null)
            {
                DataReceived(this, e);
            }
        }
        public USB(int vid, int pid)
        {
            myPID = pid;
            myVID = vid;
            if (InitializeUSB())
            {
                connectionStatus = true;
            }
        }

        public USB()
        {
            if (InitializeUSB())
            {
                connectionStatus = true;
            }
        }

        public bool InitializeUSB()
        {
            UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent;
            try
            {
                MyUsbFinder = new UsbDeviceFinder(myVID, myPID);
                //查找并打开USB设备。
                MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
                
                //检测设备是否存在。
                if (MyUsbDevice == null) throw new Exception("Device Not Found.");
                //打开设备
                if (!MyUsbDevice.Open()) throw new Exception("Open Device Failed.");

                //如果把USB设备(libusb-win32, linux libusb-1.0)作为一个整体，它提供一个IUsbDevice接口。
                IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
                //如果变量"wholeUsbDevice"的值是null，它不需要支持配置和接口。
                if (!ReferenceEquals(wholeUsbDevice, null))
                {
                    //这是一个整设备，在使用它之前需要设置配置描述符和接口描述符。
                    // 选择配置描述符1
                    wholeUsbDevice.SetConfiguration(1);
                    // 申明接口描述符0
                    wholeUsbDevice.ClaimInterface(0);
                }
                //设置端点2为读。
                reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep02);
                //设置端点3为写。
                writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep03);
                reader.DataReceivedEnabled = true;
                reader.DataReceived += (OnRxEndPointData); //定义自动接受接受窗口的内容，调用OnRxEndPointData函数
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool sendData(string sendData)
        {
            try
            {
                ErrorCode ecWrite = ErrorCode.None;
                int transferredOut;
                UsbTransfer usbWriteTransfer;
                byte[] bytesToSend = Encoding.Default.GetBytes(sendData);

                ecWrite = writer.SubmitAsyncTransfer(bytesToSend, 0, bytesToSend.Length, 100, out usbWriteTransfer);
                if (ecWrite != ErrorCode.None)
                {
                    return false;
                }
                ecWrite = usbWriteTransfer.Wait(out transferredOut);
                usbWriteTransfer.Dispose();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool sendData(byte []sendData,int count)
        {
            try
            {
                ErrorCode ecWrite = ErrorCode.None;
                int transferredOut;
                UsbTransfer usbWriteTransfer;

                ecWrite = writer.SubmitAsyncTransfer(sendData, 0, count, 100, out usbWriteTransfer);
                if (ecWrite != ErrorCode.None)
                {
                    return false;
                }
                ecWrite = usbWriteTransfer.Wait(out transferredOut);
                usbWriteTransfer.Dispose();
                return true;
            }
            catch
            {
                return false;
            }
        }

        private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
        {
            try
            {
                if (e.EventType == EventType.DeviceArrival)
                {
                    //看看目前新连接的USB设备是不是目标设备
                    if (e.Device.IdProduct == myPID && e.Device.IdVendor == myVID)
                    {
                        //发现目标设备并打开该设备
                        if (!InitializeUSB())
                        {
                            connectionStatus = false;
                            throw new Exception("USB设备打开失败");
                        }
                        connectionStatus = true;
                        throw new Exception("该USB设备是目标设备");
                    }
                    else
                    {
                        connectionStatus = false;
                        throw new Exception("该USB设备不是目标设备");
                    }
                }
                else if (e.EventType == EventType.DeviceRemoveComplete)
                {
                    connectionStatus = false;
                    //看看目前移除的USB设备是不是目标设备
                    if (e.Device.IdProduct == myPID && e.Device.IdVendor == myVID)
                    {
                        MyUsbDevice.Close();
                        CloseUSB();
                        throw new Exception("移除的USB设备是目标设备");
                    }
                    else
                    {
                        throw new Exception("移除的USB设备不是目标设备");
                    }
                }
            }
            catch
            {
            }
        }

        private void OnRxEndPointData(object sender, EndpointDataEventArgs e)
        {
            if (USBDataReceived != null)
            {
                this.OnUSBDataReceived(e);
            }
            else
            {

                recDataBuffCount = e.Count;
                recDataBuff = new byte[recDataBuffCount];
                for (int i = 0; i < recDataBuffCount; i++)
                {
                    recDataBuff[i] = e.Buffer[i];
                }
                recDataBuffFlag = true;
            }
        }

        public string recData()
        {
            if (recDataBuffFlag)
            {
                return Encoding.Default.GetString(recDataBuff);
            }
            return "";
        }

        public byte[] recData(byte []temp)
        {
            if (recDataBuffFlag)
            {
                return recDataBuff;
            }
            return null;
        }

        public void CloseUSB()
        {
            if (!ReferenceEquals(reader, null))
                reader.Dispose();
            if (!ReferenceEquals(writer, null))
                writer.Dispose();
            if (!ReferenceEquals(MyUsbDevice, null))
                MyUsbDevice.Close();
            if (!ReferenceEquals(MyUsbFinder, null))
                MyUsbDevice.Close();
        }
    }
}
