This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,503 @@
using System;
using System.Threading;
using System.Runtime.InteropServices;
using DTS.Common.DASResource;
using DTS.Common.USBFramework;
using DTS.Common.Utilities.Logging;
using DTS.Common.Interface.Connection;
using DTS.Common.Classes.Connection;
using System.Threading.Tasks;
namespace DTS.Common.WINUSBConnection
{
public class WINUSBConnection : IConnection
{
/// <summary>
/// returns true if the unit is currently soft disconnected
/// </summary>
public bool IsSoftDisconnected { get; private set; } = false;
/// <summary>
/// connect the unit
/// :note does nothing for WINUSB as we have no disconnect option yet:
/// </summary>
public void SoftConnect()
{
}
/// <summary>
/// disconnect the unit
/// :note does nothing for WINUSB as we have no disconnect option yet:
/// </summary>
public void SoftDisconnect()
{
}
void IConnection.KeepAliveErrorReceived()
{
}
public string GetConnectionData() { return ""; }
private readonly DeviceManagement _wusbDeviceManagement;
private WinUsbDevice _sliceDev;
public event EventHandler OnDisconnected;
public double GetCurrentUploadRate() { return 0D; }
public double GetCurrentDownloadRate() { return 0D; }
public bool Connected { get; private set; }
public string ConnectString { get; private set; }
public System.Net.Sockets.SocketFlags Flags { get; set; }
private class AUSBRecFix
{
public readonly AsyncCallback Callback;
public WinUSBRecAsyncResult USBResult;
public AUSBRecFix(AsyncCallback callback, WinUSBRecAsyncResult usbResult)
{
Callback = callback;
USBResult = usbResult;
}
}
public class WinUSBRecAsyncResult : IAsyncResult
{
public object AsyncState { get; set; }
public WaitHandle AsyncWaitHandle { get; set; }
public bool CompletedSynchronously { get; set; }
public bool IsCompleted { get; set; }
public byte[] Buffer { get; set; }
public int Offset { get; set; }
public int Size { get; set; }
public WinUSBRecAsyncResult(object state)
{
AsyncState = state;
AsyncWaitHandle = new ManualResetEvent(false);
CompletedSynchronously = false;
IsCompleted = false;
Buffer = null;
Offset = 0;
Size = 0;
}
}
public WINUSBConnection()
{
Disposed = false;
ConnectString = string.Empty;
Connected = false;
_wusbDeviceManagement = new DeviceManagement();
_sliceDev = null;
}
#region Exit handling
~WINUSBConnection()
{
Dispose(false);
try
{
APILogger.Log("failed to dispose WINUSBConnection - finalizer is disposing now.");
}
catch { }
}
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected volatile bool Disposed;
protected int Disposing;
private readonly Mutex _usbConnectionMutex = new Mutex(false, "USBConnection");
protected virtual void Dispose(bool disposing)
{
if (Interlocked.Exchange(ref Disposing, 1) != 0) { return; }
// make sure we're not already disposed
if (Disposed)
return;
if (disposing)
{
try
{
if (_wusbDeviceManagement != null)
{
_wusbDeviceManagement.Dispose();
}
DisposeSliceDev();
}
catch
{
// we have to suppress all exceptions here
}
}
Connected = false;
Disposed = true;
}
#endregion
public void Create(string connectString)
{
//Create(connectString); this is recursive!
}
public void Create(string connectString, string hostIPAddress)
{
ConnectString = connectString;
}
#region Disconnect
public IAsyncResult BeginDisconnect(bool reuseSocket,
AsyncCallback cb,
Object state)
{
if (_sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is null");
}
if (cb == null)
{
throw new ArgumentException("WINUSBConnection.BeginDisconnect: callback is null");
}
Connected = false;
var rar = new WinUSBRecAsyncResult(state);
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
{
throw new Exception(DASResource.Strings.WINUSBConnection_BeginDisconnect_Err1);
}
return rar;
}
public void EndDisconnect(IAsyncResult asyncResult)
{
if (_sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is null");
}
var rar = asyncResult as WinUSBRecAsyncResult;
if (rar == null)
{
throw new ArgumentException("WINUSBConnection.EndDisconnect: argument is not a WinUSBRecAsyncResult");
}
DisposeSliceDev();
((ManualResetEvent)rar.AsyncWaitHandle).Set();
}
private void DisposeSliceDev()
{
_usbConnectionMutex.WaitOne(1000);
try
{
if (null != _sliceDev)
{
_sliceDev.Dispose();
_sliceDev = null;
}
}
catch (Exception ex) { APILogger.Log("could not release USB handle ", ex); }
finally { _usbConnectionMutex.ReleaseMutex(); }
}
#endregion
#region Accept
public IAsyncResult BeginAccept(AsyncCallback callback,
Object state)
{
throw new NotSupportedException();
}
public IConnection EndAccept(IAsyncResult asyncResult)
{
throw new NotSupportedException();
}
#endregion
#region Listen
public void Listen(int backlog)
{
throw new NotSupportedException();
}
#endregion
#region Bind
public void Bind(int port)
{
throw new NotSupportedException();
}
#endregion
#region Connect
public IAsyncResult BeginConnect(AsyncCallback cb, object state)
{
if (_sliceDev != null || Connected)
{
throw new NotConnectedException("WINUSBConnection.BeginConnect: already connected");
}
if (cb == null)
{
throw new ArgumentException("WINUSBConnection.BeginConnect: callback is null");
}
var rar = new WinUSBRecAsyncResult(state);
var ausbrf = new AUSBRecFix(cb, rar);
(ausbrf?.USBResult.AsyncWaitHandle as ManualResetEvent).Reset();
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, ausbrf))
{
throw new Exception(DASResource.Strings.WINUSBConnection_BeginConnect_Err1);
}
rar.AsyncWaitHandle.WaitOne();
return rar;
}
private void NetCallbackFix(object obj)
{
var ausbrf = obj as AUSBRecFix;
try
{
ausbrf?.Callback(ausbrf.USBResult);
}
catch (Exception ex)
{
APILogger.Log("MessageBox", DASResource.Strings.Communication_WinUSBConnectionCallbackFailed, ex);
}
finally
{
(ausbrf?.USBResult.AsyncWaitHandle as ManualResetEvent).Set();
}
}
public void EndConnect(IAsyncResult ar)
{
_usbConnectionMutex.WaitOne();
var rar = ar as WinUSBRecAsyncResult;
try
{
if (_sliceDev != null || Connected)
{
throw new NotConnectedException("WINUSBConnection.EndConnect: already connected");
}
if (rar == null)
{
throw new ArgumentException("WINUSBConnection.EndConnect: argument is not a WinUSBRecAsyncResult");
}
if (string.IsNullOrEmpty(ConnectString))
{
throw new ArgumentException("WINUSBConnection.EndConnect: ConnectString is invalid");
}
_sliceDev = new WinUsbDevice();
}
catch (Exception ex) { APILogger.Log("exception in connecting USB", ex); throw; }
finally { _usbConnectionMutex.ReleaseMutex(); }
var success = _sliceDev.GetDeviceHandle(ConnectString);
if (!success)
{
Connected = false;
DisposeSliceDev();
((ManualResetEvent)rar.AsyncWaitHandle).Set();
throw new NotConnectedException("WINUSBConnection.EndConnect: connect failed");
}
if (_sliceDev.InitializeDevice())
{
Connected = true;
}
else
{
var error = DeviceManagementDeclarations.GetLastError();
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("WINUSBConnection.EndConnect: connect failed: ", w32.Message);
}
catch { }
throw new NotConnectedException("WINUSBConnection.EndConnect: connect failed (" + error + ")");
}
((ManualResetEvent)rar.AsyncWaitHandle).Set();
}
#endregion
#region Send
public IAsyncResult BeginSend(byte[] buffer, int offset, int size,
AsyncCallback cb, object state)
{
if (!Connected || _sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is not connected");
}
if (buffer == null || buffer.Length == 0 || offset < 0 || size < 0 || offset + size > buffer.Length || cb == null)
{
throw new ArgumentException("WINUSBConnection.EndConnect: invalid parameters");
}
var rar = new WinUSBRecAsyncResult(state)
{
Buffer = buffer,
Offset = offset,
Size = size
};
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
{
throw new Exception(DASResource.Strings.WINUSBConnection_BeginSend_Err1);
}
return rar;
}
public int EndSend(IAsyncResult ar)
{
if (!Connected || _sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is not connected");
}
var rar = ar as WinUSBRecAsyncResult;
if (rar == null)
{
throw new ArgumentException("WINUSBConnection.EndSend: argument is not a WinUSBRecAsyncResult");
}
var bytes = new byte[rar.Size];
Buffer.BlockCopy(rar.Buffer, 0, bytes, 0, rar.Size);
if (_sliceDev.MyDevInfo.UseHybridBulkIntMode)
{
if (!_sliceDev.SendViaInterruptTransfer(ref bytes, (uint)rar.Size))
{
Connected = false;
((ManualResetEvent)rar.AsyncWaitHandle).Set();
throw new Exception(DASResource.Strings.WINUSBConnection_EndSend_Err1);
}
}
else
{
if (!_sliceDev.SendViaBulkTransfer(ref bytes, (uint)rar.Size))
{
Connected = false;
((ManualResetEvent)rar.AsyncWaitHandle).Set();
throw new Exception(DASResource.Strings.WINUSBConnection_EndSend_Err1);
}
}
((ManualResetEvent)rar.AsyncWaitHandle).Set();
return rar.Size;
}
public Task<int> SendAsync(byte[] sendBuffer, int bufferStartOffset, int bufferSizeToSend)
{
return Task<int>.Factory.FromAsync(
(callback, state) => BeginSend(sendBuffer, bufferStartOffset, bufferSizeToSend, callback, state),
EndSend, state: null
);
}
#endregion
#region Receive
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size,
AsyncCallback cb, object state)
{
if (!Connected || _sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is not connected");
}
if (buffer == null || buffer.Length == 0 || offset < 0 || size < 0 || offset + size > buffer.Length || cb == null)
{
throw new ArgumentException("WINUSBConnection.EndConnect: invalid parameters");
}
var rar = new WinUSBRecAsyncResult(state)
{
Buffer = buffer,
Offset = offset,
Size = size
};
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
{
throw new Exception(DASResource.Strings.WINUSBConnection_BeginReceive_Err1);
}
return rar;
}
public int EndReceive(IAsyncResult ar)
{
if (!Connected || _sliceDev == null)
{
throw new NotConnectedException("WINUSBConnection is not connected");
}
var rar = ar as WinUSBRecAsyncResult;
if (rar == null)
{
throw new ArgumentException("WINUSBConnection.EndReceive: argument is not a WinUSBRecAsyncResult");
}
try
{
uint bytesRead = 0;
var bytes = new byte[rar.Size];
var success = true;
while (success && 0 == bytesRead)
{
_sliceDev.ReadViaBulkTransfer(Convert.ToByte(_sliceDev.MyDevInfo.BulkInPipe),
(uint)rar.Size,
ref bytes,
ref bytesRead,
ref success);
if (0 == bytesRead)
{
Thread.Sleep(1);
}
}
if (success)
{
Buffer.BlockCopy(bytes, 0, rar.Buffer, 0, (int)bytesRead);
rar.Size = (int)bytesRead;
((ManualResetEvent)rar.AsyncWaitHandle).Set();
return rar.Size;
}
// the connection is now closed
Connected = false;
((ManualResetEvent)rar.AsyncWaitHandle).Set();
return 0;
}
catch (Exception ex)
{
Connected = false;
if (!(ex is NullReferenceException))
{
APILogger.LogString("WINUSBConnection.EndReceive: Exception caught");
APILogger.LogException(ex);
}
return 0;
}
}
#endregion
}
}