You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
14 KiB
393 lines
14 KiB
using System;
|
|
using System.Threading;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
using System.IO;
|
|
using Microsoft.VisualBasic;
|
|
using Microsoft.Win32.SafeHandles;
|
|
using System.Runtime.Remoting.Messaging;
|
|
|
|
using LibUsbDotNet;
|
|
using LibUsbDotNet.Main;
|
|
|
|
namespace SSComm
|
|
{
|
|
public partial class USBHID : IUniComm
|
|
{
|
|
public bool Connected { get; private set; } = false;
|
|
|
|
public Int32 lBytesSent;
|
|
public Int32 lBytesReceived;
|
|
|
|
public const Int32 RXFIFOSIZE = 32768;
|
|
public const Int32 TXFIFOSIZE = 16384;
|
|
|
|
public UInt16 DevVID = UInt16.MaxValue;
|
|
public UInt16 DevPID = UInt16.MaxValue;
|
|
public Int32 DevRevision = Int32.MaxValue;
|
|
public string DevSerialNumber = string.Empty;
|
|
public Guid DevGUID = Guid.Empty;
|
|
|
|
public event EventHandler DataReceived;
|
|
|
|
private UsbDevice MyUSBDevice;
|
|
private UsbDeviceFinder MyUSBDeviceFinder;
|
|
private IUsbDevice WholeUSBDevice;
|
|
private UsbEndpointWriter MyUSBWriter;
|
|
private UsbEndpointReader MyUSBReader;
|
|
private UsbSetupPacket MyUSBSetupPacket;
|
|
|
|
private byte[] RXFIFO = new byte[RXFIFOSIZE];
|
|
private Int32 RXReadPos;
|
|
private Int32 RXWritePos;
|
|
|
|
private byte[] TXFIFO = new byte[TXFIFOSIZE];
|
|
private Int32 TXReadPos;
|
|
private Int32 TXWritePos;
|
|
|
|
private System.Threading.Thread bkThread;
|
|
private bool bkThExit;
|
|
private ManualResetEvent bkThInterript = new ManualResetEvent(false);
|
|
|
|
private Hid MyHid = new Hid();
|
|
private DeviceManagement MyDeviceManagement = new DeviceManagement();
|
|
private SafeFileHandle hidHandleR;
|
|
private SafeFileHandle hidHandleW;
|
|
private FileStream hidFSR;
|
|
private FileStream hidFSW;
|
|
private string myDevicePathName;
|
|
|
|
private byte[] rxBuffer;
|
|
private byte[] txBuffer;
|
|
|
|
private object ThisLock = new Object();
|
|
|
|
public bool Connect()
|
|
{
|
|
string[] devicePathName = new string[128];
|
|
bool myDeviceDetected = false;
|
|
|
|
if (Connected) Disconnect();
|
|
|
|
Guid hidGuid = Guid.Empty;
|
|
Hid.HidD_GetHidGuid(ref hidGuid);
|
|
if (MyDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName))
|
|
{
|
|
int memberIndex = 0;
|
|
do
|
|
{
|
|
hidHandleR = FileIO.CreateFile(devicePathName[memberIndex], 0, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0);
|
|
if (!hidHandleR.IsInvalid)
|
|
{
|
|
MyHid.DeviceAttributes.Size = Marshal.SizeOf(MyHid.DeviceAttributes);
|
|
if (Hid.HidD_GetAttributes(hidHandleR, ref MyHid.DeviceAttributes))
|
|
{
|
|
if ((MyHid.DeviceAttributes.VendorID == DevVID) && (MyHid.DeviceAttributes.ProductID == DevPID))
|
|
{
|
|
myDeviceDetected = true;
|
|
myDevicePathName = devicePathName[memberIndex];
|
|
}
|
|
else
|
|
{
|
|
myDeviceDetected = false;
|
|
hidHandleR.Close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
myDeviceDetected = false;
|
|
hidHandleR.Close();
|
|
}
|
|
}
|
|
memberIndex++;
|
|
}
|
|
while (!(myDeviceDetected || memberIndex == devicePathName.Length));
|
|
if (myDeviceDetected)
|
|
{
|
|
MyHid.Capabilities = MyHid.GetDeviceCapabilities(hidHandleR);
|
|
MyHid.GetHidUsage(MyHid.Capabilities);
|
|
hidHandleR.Close();
|
|
hidHandleR = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_READ, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0);
|
|
hidHandleW = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0);
|
|
if (hidHandleR.IsInvalid || hidHandleW.IsInvalid)
|
|
{
|
|
Connected = false;
|
|
hidFSR.Close();
|
|
hidFSW.Close();
|
|
if (!hidHandleR.IsInvalid) hidHandleR.Close();
|
|
if (!hidHandleW.IsInvalid) hidHandleW.Close();
|
|
}
|
|
else
|
|
{
|
|
MyHid.FlushQueue(hidHandleR);
|
|
MyHid.FlushQueue(hidHandleW);
|
|
hidFSR = new FileStream(hidHandleR, FileAccess.Read, MyHid.Capabilities.OutputReportByteLength, false); //false);
|
|
hidFSW = new FileStream(hidHandleW, FileAccess.Write, MyHid.Capabilities.OutputReportByteLength, false); //false);
|
|
rxBuffer = new Byte[MyHid.Capabilities.InputReportByteLength];
|
|
hidFSR.BeginRead(rxBuffer, 0, rxBuffer.Length, new AsyncCallback(ReadCallback), rxBuffer);
|
|
bkThread = new System.Threading.Thread(this.Th_DoWork);
|
|
bkThExit = false;
|
|
bkThread.Start();
|
|
Connected = true;
|
|
}
|
|
}
|
|
}
|
|
return Connected;
|
|
}
|
|
|
|
private void ReadCallback(IAsyncResult ar)
|
|
{
|
|
if (hidFSR != null)
|
|
{
|
|
try
|
|
{
|
|
hidFSR.EndRead(ar);
|
|
if (ar.IsCompleted)
|
|
{
|
|
lBytesReceived += rxBuffer.Length;
|
|
if (RXDataCount + rxBuffer.Length < RXFIFOSIZE)
|
|
{
|
|
for (int i = 1; i < rxBuffer.Length; i++)
|
|
{
|
|
RXFIFO[RXWritePos] = rxBuffer[i];
|
|
RXWritePos = (RXWritePos + 1) % RXFIFOSIZE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("RX FIFO overflow");
|
|
}
|
|
if (DataReceived != null)
|
|
{
|
|
DataReceived(this, new EventArgs());
|
|
}
|
|
}
|
|
hidFSR.BeginRead(rxBuffer, 0, rxBuffer.Length, new AsyncCallback(ReadCallback), rxBuffer);
|
|
}
|
|
catch
|
|
{
|
|
Disconnect();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void Disconnect()
|
|
{
|
|
if (bkThread != null)
|
|
{
|
|
bkThExit = true;
|
|
bkThInterript.Set();
|
|
if (bkThread.ThreadState == System.Threading.ThreadState.Running) bkThread.Join();
|
|
}
|
|
bkThread = null;
|
|
lock (ThisLock)
|
|
{
|
|
if (hidFSR != null)
|
|
{
|
|
hidFSR.Close();
|
|
hidFSR = null;
|
|
}
|
|
if (hidFSW != null)
|
|
{
|
|
hidFSW.Close();
|
|
hidFSW = null;
|
|
}
|
|
if ((hidHandleR != null) && (!(hidHandleR.IsInvalid)))
|
|
{
|
|
hidHandleR.Close();
|
|
}
|
|
if ((hidHandleW != null) && (!(hidHandleW.IsInvalid)))
|
|
{
|
|
hidHandleW.Close();
|
|
}
|
|
hidHandleR = null;
|
|
hidHandleW = null;
|
|
myDevicePathName = "";
|
|
}
|
|
Connected = false;
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
Disconnect();
|
|
lBytesSent = 0;
|
|
lBytesReceived = 0;
|
|
RXReadPos = 0;
|
|
RXWritePos = 0;
|
|
DevVID = UInt16.MaxValue;
|
|
DevPID = UInt16.MaxValue;
|
|
DevRevision = Int32.MaxValue;
|
|
DevGUID = Guid.Empty;
|
|
}
|
|
|
|
public Int32 BytesSent()
|
|
{
|
|
return lBytesSent;
|
|
}
|
|
|
|
public Int32 BytesReceived()
|
|
{
|
|
return lBytesReceived;
|
|
}
|
|
|
|
public Int32 RXDataCount
|
|
{
|
|
get
|
|
{
|
|
Int32 i;
|
|
i = RXWritePos - RXReadPos;
|
|
if (i < 0) i += RXFIFOSIZE;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
public byte ReadByte()
|
|
{
|
|
byte rv;
|
|
if (RXWritePos != RXReadPos)
|
|
{
|
|
rv = RXFIFO[RXReadPos];
|
|
RXReadPos = (RXReadPos + 1) % RXFIFOSIZE;
|
|
return rv;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("SSComm(USBGen_LibUSB).ReadByte: RX FIFO empty!");
|
|
}
|
|
}
|
|
|
|
public Int32 Read(ref byte[] DBuffer, Int32 DOffset, Int32 MaxBytes)
|
|
{
|
|
Int32 i;
|
|
if (MaxBytes < 0) MaxBytes = 0;
|
|
if (MaxBytes > 0)
|
|
{
|
|
i = RXDataCount;
|
|
if (MaxBytes > i) MaxBytes = i;
|
|
if (MaxBytes < i) i = MaxBytes;
|
|
while (i > 0)
|
|
{
|
|
DBuffer[DOffset] = RXFIFO[RXReadPos];
|
|
DOffset += 1;
|
|
RXReadPos = (RXReadPos + 1) % RXFIFOSIZE;
|
|
i -= 1;
|
|
}
|
|
}
|
|
return MaxBytes;
|
|
}
|
|
|
|
public Int32 TXFreeSpace
|
|
{
|
|
get
|
|
{
|
|
Int32 i;
|
|
i = TXWritePos - TXReadPos;
|
|
if (i < 0) i += TXFIFOSIZE;
|
|
i = TXFIFOSIZE - i;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
public void WriteByte(ref byte wb, bool dow = true)
|
|
{
|
|
if (TXFreeSpace > 0)
|
|
{
|
|
TXFIFO[TXWritePos] = wb;
|
|
TXWritePos = (TXWritePos + 1) % TXFIFOSIZE;
|
|
if (dow && (bkThread != null)) bkThInterript.Set();
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("SSComm(USBGen_LibUSB).WriteByte: TX FIFO Full!");
|
|
}
|
|
}
|
|
|
|
public bool Write(ref byte[] DBuffer, int DOffset, int NumBytes)
|
|
{
|
|
Int32 i;
|
|
if (NumBytes > TXFreeSpace) throw new Exception("Not enough space in TX buffer.");
|
|
for (i = 0; i < NumBytes; i++)
|
|
{
|
|
TXFIFO[TXWritePos] = DBuffer[DOffset + i];
|
|
TXWritePos = (TXWritePos + 1) % TXFIFOSIZE;
|
|
}
|
|
if (bkThread != null) bkThInterript.Set();
|
|
return true;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Disconnect();
|
|
}
|
|
|
|
private void MyUSBReader_DataReceived(object sender, LibUsbDotNet.Main.EndpointDataEventArgs e)
|
|
{
|
|
Int32 i;
|
|
if (e.Count > 0)
|
|
{
|
|
lBytesReceived += e.Count;
|
|
if (RXDataCount + e.Count < RXFIFOSIZE)
|
|
{
|
|
for (i = 0; i < e.Count; i++)
|
|
{
|
|
RXFIFO[RXWritePos] = e.Buffer[i];
|
|
RXWritePos = (RXWritePos + 1) % RXFIFOSIZE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("RX FIFO overflow");
|
|
}
|
|
if (DataReceived != null)
|
|
{
|
|
DataReceived(this, new EventArgs());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Th_DoWork()
|
|
{
|
|
Int32 lTXSize;
|
|
Int32 i;
|
|
byte[] b = new byte[MyHid.Capabilities.OutputReportByteLength];
|
|
try
|
|
{
|
|
while (true)
|
|
{
|
|
if (hidFSW != null && hidFSW.CanWrite)
|
|
{
|
|
lTXSize = TXWritePos - TXReadPos;
|
|
if (lTXSize < 0) lTXSize += TXFIFOSIZE;
|
|
if (lTXSize >= (b.Length - 1))
|
|
{
|
|
b[0] = 0;
|
|
for (i = 0; i < (b.Length - 1); i++)
|
|
{
|
|
b[i + 1] = TXFIFO[(TXReadPos + i) % TXFIFOSIZE];
|
|
}
|
|
hidFSW.Write(b, 0, b.Length);
|
|
hidFSW.Flush();
|
|
TXReadPos += b.Length - 1;
|
|
TXReadPos %= TXFIFOSIZE;
|
|
lBytesSent += b.Length - 1;
|
|
}
|
|
else
|
|
{
|
|
bkThInterript.WaitOne(Timeout.Infinite);
|
|
bkThInterript.Reset();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bkThInterript.WaitOne(Timeout.Infinite);
|
|
bkThInterript.Reset();
|
|
}
|
|
if (bkThExit) break;
|
|
}
|
|
}
|
|
catch (ThreadAbortException) { }
|
|
}
|
|
}
|
|
}
|