423 lines
13 KiB
C#
423 lines
13 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO.Ports;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using DTS.Common.DASResource;
|
||
|
|
using DTS.Common.Interface.Connection;
|
||
|
|
using DTS.Common.Utilities.Logging;
|
||
|
|
|
||
|
|
namespace DTS.Common.WINUSBConnection
|
||
|
|
{
|
||
|
|
public class UsbRecAsyncResult : 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 class CDCUSBConnection : IConnection
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// returns true if the das has been soft disconnected or not
|
||
|
|
/// </summary>
|
||
|
|
public bool IsSoftDisconnected { get; private set; } = false;
|
||
|
|
/// <summary>
|
||
|
|
/// connect the das
|
||
|
|
/// :note does nothing for CDCUSB, we don't have a soft disconnect option
|
||
|
|
/// </summary>
|
||
|
|
public void SoftConnect()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// disconnect the das
|
||
|
|
/// :note does nothing for CDCUSB, we don't have a soft disconnect option
|
||
|
|
/// </summary>
|
||
|
|
public void SoftDisconnect()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
void IConnection.KeepAliveErrorReceived()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
public string GetConnectionData() { return ""; }
|
||
|
|
public const int DTS_VENDOR_ID = 0x1CB9;
|
||
|
|
public const string DTS_VENDOR_ID_STR = "VID_1CB9";
|
||
|
|
private const string DTS_TSR2_CDCUSB_PRODUCT_ID_STR = "PID_001A";
|
||
|
|
private static List<string> _regKeys;
|
||
|
|
private static readonly object KEY_LOCK = new object();
|
||
|
|
public static IList<string> RegKeys
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
lock (KEY_LOCK)
|
||
|
|
{
|
||
|
|
if (null != _regKeys) return _regKeys;
|
||
|
|
_regKeys = new List<string>();
|
||
|
|
ReadTSR2CDCUSBRegKeys();
|
||
|
|
}
|
||
|
|
return _regKeys;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// Searches the system registry for a key that corresponds to the Peak CAN USB
|
||
|
|
/// vendor and product ID.
|
||
|
|
/// </summary>
|
||
|
|
internal static void ReadTSR2CDCUSBRegKeys()
|
||
|
|
{
|
||
|
|
var ourKey = ReadOurNameRegistryKey();
|
||
|
|
if (null == ourKey) { return; }
|
||
|
|
foreach (var subKey in ourKey.GetSubKeyNames())
|
||
|
|
{
|
||
|
|
RegKeys.Add(subKey);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
internal static Microsoft.Win32.RegistryKey ReadOurNameRegistryKey()
|
||
|
|
{
|
||
|
|
var key = Microsoft.Win32.Registry.LocalMachine;
|
||
|
|
const string ourName = @"SYSTEM\CurrentControlSet\Enum\USB\" + DTS_VENDOR_ID_STR + "&" + DTS_TSR2_CDCUSB_PRODUCT_ID_STR;
|
||
|
|
key = key.OpenSubKey(ourName);
|
||
|
|
|
||
|
|
return key;
|
||
|
|
}
|
||
|
|
/// <summary>
|
||
|
|
/// current upload rate in b/s
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public double GetCurrentUploadRate() { return 0D; }
|
||
|
|
/// <summary>
|
||
|
|
/// current download rate in b/s
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public double GetCurrentDownloadRate() { return 0D; }
|
||
|
|
public event EventHandler OnDisconnected;
|
||
|
|
private int _baudRate = 9600;
|
||
|
|
private Parity _parity = Parity.None;
|
||
|
|
private StopBits _stopBits = StopBits.One;
|
||
|
|
private const int DATA_BITS = 8;
|
||
|
|
public string PortName { get; set; }
|
||
|
|
private readonly SerialPort _comPort = new SerialPort();
|
||
|
|
|
||
|
|
private string _devicePathname;
|
||
|
|
protected bool _Connected;
|
||
|
|
protected volatile bool Disposed;
|
||
|
|
protected volatile bool Disposing;
|
||
|
|
|
||
|
|
public bool Connected => _Connected;
|
||
|
|
|
||
|
|
public string ConnectString => _devicePathname;
|
||
|
|
|
||
|
|
public System.Net.Sockets.SocketFlags Flags { get; set; }
|
||
|
|
|
||
|
|
private class AUSBRecFix
|
||
|
|
{
|
||
|
|
public readonly AsyncCallback Callback;
|
||
|
|
public readonly UsbRecAsyncResult USBResult;
|
||
|
|
|
||
|
|
public AUSBRecFix(AsyncCallback callback, UsbRecAsyncResult usbResult)
|
||
|
|
{
|
||
|
|
Callback = callback;
|
||
|
|
USBResult = usbResult;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public CDCUSBConnection()
|
||
|
|
{
|
||
|
|
Disposed = false;
|
||
|
|
Disposing = false;
|
||
|
|
_Connected = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
~CDCUSBConnection()
|
||
|
|
{
|
||
|
|
Dispose(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
Dispose(true);
|
||
|
|
|
||
|
|
// Use SupressFinalize in case a subclass
|
||
|
|
// of this type implements a finalizer.
|
||
|
|
GC.SuppressFinalize(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
protected virtual void Dispose(bool disposing)
|
||
|
|
{
|
||
|
|
// make sure we're not already disposed
|
||
|
|
if (Disposed)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (disposing)
|
||
|
|
{
|
||
|
|
Disposing = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_comPort.IsOpen)
|
||
|
|
{
|
||
|
|
_comPort.Close();
|
||
|
|
_Connected = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
Disposed = true;
|
||
|
|
Disposing = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Create(string connectString)
|
||
|
|
{
|
||
|
|
//Create(connectString); - this is recursive!
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Create(string connectString, string hostIPAddress)
|
||
|
|
{
|
||
|
|
foreach (var regKey in RegKeys)
|
||
|
|
{
|
||
|
|
if (!connectString.Contains(regKey.ToLower())) continue;
|
||
|
|
var ourKey = ReadOurNameRegistryKey();
|
||
|
|
ourKey = ourKey.OpenSubKey(regKey);
|
||
|
|
ourKey = ourKey?.OpenSubKey("Device Parameters");
|
||
|
|
var value = (string)ourKey?.GetValue("PortName");
|
||
|
|
PortName = value;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
_devicePathname = connectString;
|
||
|
|
}
|
||
|
|
|
||
|
|
#region Disconnect
|
||
|
|
|
||
|
|
public IAsyncResult BeginDisconnect(bool reuseSocket,
|
||
|
|
AsyncCallback cb,
|
||
|
|
Object state)
|
||
|
|
{
|
||
|
|
var rar = new UsbRecAsyncResult
|
||
|
|
{
|
||
|
|
AsyncState = state,
|
||
|
|
AsyncWaitHandle = new ManualResetEvent(false),
|
||
|
|
CompletedSynchronously = false,
|
||
|
|
IsCompleted = false,
|
||
|
|
buffer = null,
|
||
|
|
Offset = 0,
|
||
|
|
Size = 0
|
||
|
|
};
|
||
|
|
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
|
||
|
|
{
|
||
|
|
throw new Exception(DASResource.Strings.CDCUSBConnection_BeginDisconnect_Err1);
|
||
|
|
}
|
||
|
|
return rar;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void EndDisconnect(IAsyncResult ar)
|
||
|
|
{
|
||
|
|
var rar = ar as UsbRecAsyncResult;
|
||
|
|
|
||
|
|
if (_comPort.IsOpen)
|
||
|
|
{
|
||
|
|
_comPort.Close();
|
||
|
|
_Connected = false;
|
||
|
|
_comPort.Dispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
((ManualResetEvent)rar?.AsyncWaitHandle)?.Set();
|
||
|
|
}
|
||
|
|
|
||
|
|
#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)
|
||
|
|
{
|
||
|
|
var rar = new UsbRecAsyncResult
|
||
|
|
{
|
||
|
|
AsyncState = state,
|
||
|
|
AsyncWaitHandle = new ManualResetEvent(false),
|
||
|
|
CompletedSynchronously = false,
|
||
|
|
IsCompleted = false,
|
||
|
|
buffer = null,
|
||
|
|
Offset = 0,
|
||
|
|
Size = 0
|
||
|
|
};
|
||
|
|
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
|
||
|
|
{
|
||
|
|
// "USBConnection.BeginConnect: Unable to enqueue function"
|
||
|
|
throw new Exception(DASResource.Strings.CDCUSBConnection_BeginConnect_Err1);
|
||
|
|
}
|
||
|
|
return rar;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void NetCallbackFix(object obj)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (Disposed) return;
|
||
|
|
var ausbrf = obj as AUSBRecFix;
|
||
|
|
ausbrf?.Callback(ausbrf.USBResult);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
APILogger.Log(@"PcanUsbConnection.NetCallbackFix: Exception " + ex.Message + @" " + ex.StackTrace);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public void EndConnect(IAsyncResult ar)
|
||
|
|
{
|
||
|
|
var rar = ar as UsbRecAsyncResult;
|
||
|
|
|
||
|
|
if (_comPort.IsOpen)
|
||
|
|
{
|
||
|
|
_comPort.Close();
|
||
|
|
_Connected = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
_comPort.BaudRate = _baudRate;
|
||
|
|
_comPort.DataBits = DATA_BITS;
|
||
|
|
_comPort.StopBits = _stopBits;
|
||
|
|
_comPort.Parity = _parity;
|
||
|
|
_comPort.PortName = PortName;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
_comPort.Open();
|
||
|
|
}
|
||
|
|
catch (Exception)
|
||
|
|
{
|
||
|
|
_Connected = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
_Connected = true;
|
||
|
|
|
||
|
|
((ManualResetEvent)rar?.AsyncWaitHandle)?.Set();
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Send
|
||
|
|
|
||
|
|
public IAsyncResult BeginSend(byte[] buffer, int offset, int size,
|
||
|
|
AsyncCallback cb, object state)
|
||
|
|
{
|
||
|
|
var rar = new UsbRecAsyncResult
|
||
|
|
{
|
||
|
|
AsyncState = state,
|
||
|
|
AsyncWaitHandle = new ManualResetEvent(false),
|
||
|
|
CompletedSynchronously = false,
|
||
|
|
IsCompleted = false,
|
||
|
|
buffer = buffer,
|
||
|
|
Offset = offset,
|
||
|
|
Size = size
|
||
|
|
};
|
||
|
|
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
|
||
|
|
{
|
||
|
|
// "WINUSBConnection.BeginSend: Unable to enqueue function"
|
||
|
|
throw new Exception(DASResource.Strings.CDCUSBConnection_BeginSend_Err1);
|
||
|
|
}
|
||
|
|
return rar;
|
||
|
|
}
|
||
|
|
|
||
|
|
public int EndSend(IAsyncResult ar)
|
||
|
|
{
|
||
|
|
var rar = ar as UsbRecAsyncResult;
|
||
|
|
if (null == rar)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
_comPort.Write(rar.buffer, 0, rar.Size);
|
||
|
|
|
||
|
|
((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)
|
||
|
|
{
|
||
|
|
var rar = new UsbRecAsyncResult
|
||
|
|
{
|
||
|
|
AsyncState = state,
|
||
|
|
AsyncWaitHandle = new ManualResetEvent(false),
|
||
|
|
CompletedSynchronously = false,
|
||
|
|
IsCompleted = false,
|
||
|
|
buffer = buffer,
|
||
|
|
Offset = offset,
|
||
|
|
Size = size
|
||
|
|
};
|
||
|
|
if (!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar)))
|
||
|
|
{
|
||
|
|
// "WINUSBConnection.BeginReceive: Unable to enqueue function"
|
||
|
|
throw new Exception(DASResource.Strings.CDCUSBConnection_BeginReceive_Err1);
|
||
|
|
}
|
||
|
|
return rar;
|
||
|
|
}
|
||
|
|
|
||
|
|
//private DateTime _lastHeartbeat;
|
||
|
|
public int EndReceive(IAsyncResult ar)
|
||
|
|
{
|
||
|
|
var rar = ar as UsbRecAsyncResult;
|
||
|
|
int bytesRead;
|
||
|
|
|
||
|
|
do
|
||
|
|
{
|
||
|
|
bytesRead = _comPort.Read(rar.buffer, 0, rar.Size);
|
||
|
|
if (0 == bytesRead)
|
||
|
|
{
|
||
|
|
Thread.Sleep(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
} while (0 == bytesRead);
|
||
|
|
|
||
|
|
((ManualResetEvent)rar.AsyncWaitHandle).Set();
|
||
|
|
return bytesRead;
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
}
|