init
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user