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,422 @@
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
}
}

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{3A40C700-1D50-4524-AFFB-0D59F0F0F9CB}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DTS.DASLib.Connection</RootNamespace>
<AssemblyName>WINUSBConnection</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<SccProjectName>
</SccProjectName>
<SccLocalPath>
</SccLocalPath>
<SccAuxPath>
</SccAuxPath>
<SccProvider>
</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<NoWarn>0067</NoWarn>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<NoWarn>0067</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<Compile Include="CDCUSBConnection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WINUSBDevice.cs" />
<Compile Include="WINUSBDeviceApi.cs" />
<Compile Include="WINUSBConnection.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\DTS.Common.DASResource\DTS.Common.DASResource.csproj">
<Project>{f621ce48-bb4b-4cfc-a325-9410b721cc44}</Project>
<Name>DTS.Common.DASResource</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\DTS.Common.Utilities\DTS.Common.Utilities.csproj">
<Project>{d6da1b74-c711-43c2-91b1-1908a8d04dbf}</Project>
<Name>DTS.Common.Utilities</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\DTS.Common\DTS.Common.csproj">
<Project>{F7A0804F-61A4-40AE-83D0-F1137622B592}</Project>
<Name>DTS.Common</Name>
</ProjectReference>
<ProjectReference Include="..\USBFramework\DTS.Common.USBFramework.csproj">
<Project>{30f9a58b-6808-4c93-a294-7267c3d2e7eb}</Project>
<Name>DTS.Common.USBFramework</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Design\DTS.Common.WINUSBConnectionClassDiagram.cd" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="DTS.Common.WINUSBConnection.UsbRecAsyncResult" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="2.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAIAAAAAgAAAAAAAEAAAAAAAABAQAABAAAAAgAA=</HashCode>
<FileName>CDCUSBConnection.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.WINUSBConnection.CDCUSBConnection" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="0.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAQhEIAACAQTEhAAOJAJgIBAgCiAFAgACAAAABCIEA=</HashCode>
<FileName>CDCUSBConnection.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.WINUSBConnection.WINUSBConnection" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="0.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAQhAIAACAQTEhCAAIAJgIAAAAgBEAAAAAAAABCIEA=</HashCode>
<FileName>WINUSBConnection.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="DTS.Common.WINUSBConnection.WinUsbDevice" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="2.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>FhACEAQEACgQAgIAISCCBAAgIAQABICCADAACAAAwKg=</HashCode>
<FileName>WINUSBDevice.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WINUSBConnection")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WINUSBConnection")]
[assembly: AssemblyCopyright("Copyright © 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("F3C369E6-BFFB-41bc-B8E8-A31094CED447")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.06.0081")]
[assembly: AssemblyFileVersion("1.06.0081")]

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
}
}

View File

@@ -0,0 +1,827 @@
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using DTS.Common.USBFramework;
using DTS.Common.Utilities.Logging;
namespace DTS.Common.WINUSBConnection
{
/// <summary>
/// Routines for the WinUsb driver supported by Windows Vista and Windows XP.
/// </summary>
///
internal sealed partial class WinUsbDevice : IDisposable
{
private volatile bool _bDisposed;
~WinUsbDevice()
{
if (!_bDisposed)
{
try
{
APILogger.Log("WinUSBDevice not disposed before finalizer. Disposing now");
}
catch { }
Dispose();
}
}
internal struct DevInfo
{
internal SafeFileHandle DeviceHandle;
internal IntPtr WinUSBHandle;
internal Byte BulkInPipe;
internal Byte BulkOutPipe;
internal Byte InterruptInPipe;
internal Byte InterruptOutPipe;
internal UInt32 DeviceSpeed;
internal bool UseHybridBulkIntMode;
}
internal DevInfo MyDevInfo;
public void Dispose()
{
if (_bDisposed) return;
_bDisposed = true;
CloseDeviceHandle();
}
/// <summary>
/// Closes the device handle obtained with CreateFile and frees resources.
/// </summary>
///
internal void CloseDeviceHandle()
{
try
{
if (MyDevInfo.WinUSBHandle != IntPtr.Zero)
{
WinUsb_Free(MyDevInfo.WinUSBHandle);
MyDevInfo.WinUSBHandle = IntPtr.Zero;
}
}
catch (AccessViolationException)
{
}
try
{
if (MyDevInfo.DeviceHandle == null || MyDevInfo.DeviceHandle.IsInvalid) return;
if (MyDevInfo.DeviceHandle.IsInvalid) return;
MyDevInfo.DeviceHandle.Dispose();
MyDevInfo.DeviceHandle = null;
}
catch
{
}
}
/// <summary>
/// Initiates a Control Read transfer. Data stage is device to host.
/// </summary>
///
/// <param name="dataStage"> The received data. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
internal bool Do_Control_Read_Transfer(ref byte[] dataStage)
{
// Vendor-specific request to an interface with device-to-host Data stage.
WinUSBSetupPacket setupPacket;
setupPacket.RequestType = 0XC1;
// The request number that identifies the specific request.
setupPacket.Request = 2;
// Command-specific value to send to the device.
setupPacket.Index = 0;
// Number of bytes in the request's Data stage.
setupPacket.Length = Convert.ToUInt16(dataStage.Length);
// Command-specific value to send to the device.
setupPacket.Value = 0;
// ***
// winusb function
// summary
// Initiates a control transfer.
// paramaters
// Device handle returned by WinUsb_Initialize.
// WinUSBSetupPacket structure
// Buffer to hold the returned Data-stage data.
// Number of data bytes to read in the Data stage.
// Number of bytes read in the Data stage.
// Null pointer for non-overlapped.
// returns
// True on success.
// ***
uint bytesReturned = 0;
var success = WinUsb_ControlTransfer(MyDevInfo.WinUSBHandle,
setupPacket,
dataStage,
Convert.ToUInt16(dataStage.Length),
ref bytesReturned,
IntPtr.Zero);
return success;
}
/// <summary>
/// Initiates a Control Write transfer. Data stage is host to device.
/// </summary>
///
/// <param name="dataStage"> The data to send. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
internal bool Do_Control_Write_Transfer(byte[] dataStage)
{
// Vendor-specific request to an interface with host-to-device Data stage.
WinUSBSetupPacket setupPacket;
setupPacket.RequestType = 0X41;
// The request number that identifies the specific request.
setupPacket.Request = 1;
// Command-specific value to send to the device.
var index = Convert.ToUInt16(0);
setupPacket.Index = index;
// Number of bytes in the request's Data stage.
setupPacket.Length = Convert.ToUInt16(dataStage.Length);
// Command-specific value to send to the device.
var value = Convert.ToUInt16(0);
setupPacket.Value = value;
// ***
// winusb function
// summary
// Initiates a control transfer.
// parameters
// Device handle returned by WinUsb_Initialize.
// WinUSBSetupPacket structure
// Buffer containing the Data-stage data.
// Number of data bytes to send in the Data stage.
// Number of bytes sent in the Data stage.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
uint bytesReturned = 0;
var success = WinUsb_ControlTransfer(MyDevInfo.WinUSBHandle,
setupPacket,
dataStage,
Convert.ToUInt16(dataStage.Length),
ref bytesReturned,
IntPtr.Zero);
return success;
}
/// <summary>
/// Requests a handle with CreateFile.
/// </summary>
///
/// <param name="devicePathName"> Returned by SetupDiGetDeviceInterfaceDetail
/// in an SP_DEVICE_INTERFACE_DETAIL_DATA structure. </param>
///
/// <returns>
/// The handle.
/// </returns>
internal bool GetDeviceHandle(string devicePathName)
{
var security = new FileIO.SECURITY_ATTRIBUTES
{
lpSecurityDescriptor = IntPtr.Zero,
bInheritHandle = Convert.ToInt32(true)
};
security.nLength = Marshal.SizeOf(security);
System.Diagnostics.Trace.Assert(null == MyDevInfo.DeviceHandle || MyDevInfo.DeviceHandle.IsClosed);
// ***
// API function
// summary
// Retrieves a handle to a device.
// parameters
// Device path name returned by SetupDiGetDeviceInterfaceDetail
// Type of access requested (read/write).
// FILE_SHARE attributes to allow other processes to access the device while this handle is open.
// Security structure. Using Null for this may cause problems under Windows XP.
// Creation disposition value. Use OPEN_EXISTING for devices.
// Flags and attributes for files. The winsub driver requires FILE_FLAG_OVERLAPPED.
// Handle to a template file. Not used.
// Returns
// A handle or INVALID_HANDLE_VALUE.
// ***
MyDevInfo.DeviceHandle = FileIO.CreateFile(devicePathName,
FileIO.GENERIC_WRITE | FileIO.GENERIC_READ,
FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE,
ref security,
FileIO.OPEN_EXISTING,
FileIO.FILE_ATTRIBUTE_NORMAL | FileIO.FILE_FLAG_OVERLAPPED,
0);
if (!MyDevInfo.DeviceHandle.IsInvalid)
{
return true;
}
FileIODeclarations.GetLastError();
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("GetDeviceHandle(", devicePathName, ") - error - ", w32.Message);
}
catch { }
return false;
}
/// <summary>
/// Initializes a device interface and obtains information about it.
/// Calls these winusb API functions:
/// WinUsb_Initialize
/// WinUsb_QueryInterfaceSettings
/// WinUsb_QueryPipe
/// </summary>
/// <returns>
/// True on success, False on failure.
/// </returns>
internal bool InitializeDevice()
{
USBInterfaceDescriptor ifaceDescriptor;
ifaceDescriptor.bLength = 0;
ifaceDescriptor.bDescriptorType = 0;
ifaceDescriptor.bInterfaceNumber = 0;
ifaceDescriptor.bAlternateSetting = 0;
ifaceDescriptor.bNumEndpoints = 0;
ifaceDescriptor.bInterfaceClass = 0;
ifaceDescriptor.bInterfaceSubClass = 0;
ifaceDescriptor.bInterfaceProtocol = 0;
ifaceDescriptor.iInterface = 0;
WinUSBPipeInformation pipeInfo;
pipeInfo.PipeTypes = 0;
pipeInfo.PipeId = 0;
pipeInfo.MaximumPacketSize = 0;
pipeInfo.Interval = 0;
MyDevInfo.UseHybridBulkIntMode = false;
// ***
// winusb function
// summary
// get a handle for communications with a winusb device '
// parameters
// Handle returned by CreateFile.
// Device handle to be returned.
// returns
// True on success.
// ***
var success = WinUsb_Initialize(MyDevInfo.DeviceHandle, ref MyDevInfo.WinUSBHandle);
if (!success) return false;
// ***
// winusb function
// summary
// Get a structure with information about the device interface.
// parameters
// handle returned by WinUsb_Initialize
// alternate interface setting number
// USBInterfaceDescriptor structure to be returned.
// returns
// True on success.
success = WinUsb_QueryInterfaceSettings(MyDevInfo.WinUSBHandle,
0,
ref ifaceDescriptor);
if (success)
{
// Get the transfer type, endpoint number, and direction for the interface's
// bulk and interrupt endpoints. Set pipe policies.
// ***
// winusb function
// summary
// returns information about a USB pipe (endpoint address)
// parameters
// Handle returned by WinUsb_Initialize
// Alternate interface setting number
// Number of an endpoint address associated with the interface.
// (The values count up from zero and are NOT the same as the endpoint address
// in the endpoint descriptor.)
// WinUSBPipeInformation structure to be returned
// returns
// True on success
// ***
var pipeTimeout = Convert.ToUInt32(0);
for (var i = 0; i <= ifaceDescriptor.bNumEndpoints - 1; i++)
{
WinUsb_QueryPipe(MyDevInfo.WinUSBHandle,
0,
Convert.ToByte(i),
ref pipeInfo);
if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeBulk && UsbEndpointDirectionIn(pipeInfo.PipeId))
{
MyDevInfo.BulkInPipe = pipeInfo.PipeId;
SetPipePolicy
(MyDevInfo.BulkInPipe,
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
Convert.ToByte(false));
SetPipePolicy
(MyDevInfo.BulkInPipe,
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
pipeTimeout);
}
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeBulk && UsbEndpointDirectionOut(pipeInfo.PipeId))
{
MyDevInfo.BulkOutPipe = pipeInfo.PipeId;
SetPipePolicy
(MyDevInfo.BulkOutPipe,
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
Convert.ToByte(false));
SetPipePolicy
(MyDevInfo.BulkOutPipe,
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
pipeTimeout);
}
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeInterrupt && UsbEndpointDirectionIn(pipeInfo.PipeId))
{
MyDevInfo.InterruptInPipe = pipeInfo.PipeId;
SetPipePolicy
(MyDevInfo.InterruptInPipe,
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
Convert.ToByte(false));
SetPipePolicy
(MyDevInfo.InterruptInPipe,
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
pipeTimeout);
}
else if (pipeInfo.PipeTypes == USBDPipeTypes.UsbdPipeTypeInterrupt && UsbEndpointDirectionOut(pipeInfo.PipeId))
{
MyDevInfo.InterruptOutPipe = pipeInfo.PipeId;
SetPipePolicy
(MyDevInfo.InterruptOutPipe,
Convert.ToUInt32(PolicyType.IgnoreShortPackets),
Convert.ToByte(false));
SetPipePolicy
(MyDevInfo.InterruptOutPipe,
Convert.ToUInt32(PolicyType.PipeTransferTimeout),
pipeTimeout);
MyDevInfo.UseHybridBulkIntMode = true;
}
}
}
return success;
}
/// <summary>
/// Is the current operating system Windows XP or later?
/// The WinUSB driver requires Windows XP or later.
/// </summary>
///
/// <returns>
/// True if Windows XP or later, False if not.
/// </returns>
internal bool IsWindowsXpOrLater()
{
var myEnvironment = Environment.OSVersion;
// Windows XP is version 5.1.
var versionXP = new Version(5, 1);
return myEnvironment.Version >= versionXP;
}
/// <summary>
/// Gets a value that corresponds to a USBDeviceSpeeds.
/// </summary>
internal bool QueryDeviceSpeed()
{
// ***
// winusb function
// summary
// Get the device speed.
// (Normally not required but can be nice to know.)
// parameters
// Handle returned by WinUsb_Initialize
// Requested information type.
// Number of bytes to read.
// Information to be returned.
// returns
// True on success.
// ***
uint length = 1;
var speed = new byte[1];
var success = WinUsb_QueryDeviceInformation(MyDevInfo.WinUSBHandle,
DEVICE_SPEED,
ref length,
ref speed[0]);
if (success)
{
MyDevInfo.DeviceSpeed = Convert.ToUInt32(speed[0]);
}
return success;
}
/// <summary>
/// see winerror.h, these are error codes that we can expect or have received from
/// read pipe
/// </summary>
private const long ERROR_GEN_FAILURE = 31L;
private const long ERROR_LOCK_VIOLATION = 33L;
private const long ERROR_INVALID_HANDLE = 6L;
private const long ERROR_OPERATION_ABORTED = 995L;
private const long ERROR_IO_INCOMPLETE = 996L;
private const long ERROR_IO_PENDING = 997L;
private const long ERROR_NOT_ENOUGH_MEMORY = 8L;
private const long ERROR_SEM_TIMEOUT = 121L;
/// <summary>
/// Attempts to read data from a bulk IN endpoint.
/// </summary>
/// <param name="pipeId"> Endpoint address. </param>
/// <param name="bytesToRead"> Number of bytes to read. </param>
/// <param name="buffer"> Buffer for storing the bytes read. </param>
/// <param name="bytesRead"> Number of bytes read. </param>
/// <param name="success"> Success or failure status. </param>
///
internal void ReadViaBulkTransfer(byte pipeId,
uint bytesToRead,
ref byte[] buffer,
ref uint bytesRead,
ref bool success)
{
try
{
// ***
// winusb function
// summary
// Attempts to read data from a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer to store the data.
// Maximum number of bytes to return.
// Number of bytes read.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
success = WinUsb_ReadPipe
(MyDevInfo.WinUSBHandle,
pipeId,
buffer,
bytesToRead,
ref bytesRead,
IntPtr.Zero);
if (success) return;
long lastError = Marshal.GetLastWin32Error();
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
switch (w32.NativeErrorCode)
{
case (int)ERROR_IO_PENDING:
case (int)ERROR_IO_INCOMPLETE:
case (int)ERROR_OPERATION_ABORTED:
break;
default:
APILogger.Log(string.Format("ReadViaBulkTransfer failed Message:{0} Error: {1}", w32.Message, w32.NativeErrorCode));
break;
}
}
catch { }
switch (lastError)
{
case ERROR_GEN_FAILURE:
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe General failure - " + ERROR_GEN_FAILURE.ToString());
break;
case ERROR_LOCK_VIOLATION:
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Lock violation - " + ERROR_LOCK_VIOLATION.ToString());
break;
case ERROR_INVALID_HANDLE://do we clean up if the handle is invalid?
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Invalid Handle - " + ERROR_INVALID_HANDLE.ToString());
break;
case ERROR_IO_PENDING://this one should be okay
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe I/O Pending - " + ERROR_IO_PENDING.ToString());
break;
case ERROR_NOT_ENOUGH_MEMORY://this we'd probably never see
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Not Enough Memory - " + ERROR_NOT_ENOUGH_MEMORY.ToString());
break;
case ERROR_SEM_TIMEOUT:
//APILogger.LogString("WinUSBDevice::WinUsb_ReadPipe Semaphore timeout - " + ERROR_SEM_TIMEOUT.ToString());
break;
}
}
catch (Exception ex)
{
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("ReadViaBulkTranser - error ", ex.Message, " - ", w32.Message);
}
catch { }
throw;
}
}
/// <summary>
/// Attempts to read data from an interrupt IN endpoint.
/// </summary>
/// <param name="pipeId"> Endpoint address. </param>
/// <param name="bytesToRead"> Number of bytes to read. </param>
/// <param name="buffer"> Buffer for storing the bytes read. </param>
/// <param name="bytesRead"> Number of bytes read. </param>
/// <param name="success"> Success or failure status. </param>
///
internal void ReadViaInterruptTransfer(byte pipeId,
uint bytesToRead,
ref byte[] buffer,
ref uint bytesRead,
ref bool success)
{
try
{
// ***
// winusb function
// summary
// Attempts to read data from a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer to store the data.
// Maximum number of bytes to return.
// Number of bytes read.
// Null pointer for non-overlapped.
// Returns
// True on success.
// ***
success = WinUsb_ReadPipe(MyDevInfo.WinUSBHandle,
pipeId,
buffer,
bytesToRead,
ref bytesRead,
IntPtr.Zero);
if (success) return;
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("ReadViaInterruptTransfer failed, ", w32.Message);
}
catch { }
}
catch (Exception ex)
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("ReadViaInterruptTransfer failed, ", ex.Message, " - ", w32.Message);
throw;
}
}
/// <summary>
/// Attempts to send data via a bulk OUT endpoint.
/// </summary>
///
/// <param name="buffer"> Buffer containing the bytes to write. </param>
/// <param name="bytesToWrite"> Number of bytes to write. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
internal bool SendViaBulkTransfer(ref byte[] buffer, uint bytesToWrite)
{
uint bytesWritten = 0;
// ***
// winusb function
// summary
// Attempts to write data to a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer with data to write.
// Number of bytes to write.
// Number of bytes written.
// IntPtr.Zero for non-overlapped I/O.
// Returns
// True on success.
// ***
System.Threading.Thread.Sleep(5);
var success = WinUsb_WritePipe
(MyDevInfo.WinUSBHandle,
MyDevInfo.BulkOutPipe,
buffer,
bytesToWrite,
ref bytesWritten,
IntPtr.Zero);
if (success) return true;
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("WritePipe failed, buffer[", BitConverter.ToString(buffer, 0, Convert.ToInt32(bytesToWrite)), "], bytes: ", bytesToWrite, ", ", w32.Message);
}
catch { }
return false;
}
/// <summary>
/// Attempts to send data via an interrupt OUT endpoint.
/// </summary>
///
/// <param name="buffer"> Buffer containing the bytes to write. </param>
/// <param name="bytesToWrite"> Number of bytes to write. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
internal bool SendViaInterruptTransfer(ref byte[] buffer, uint bytesToWrite)
{
uint bytesWritten = 0;
// ***
// winusb function
// summary
// Attempts to write data to a device interface.
// parameters
// Device handle returned by WinUsb_Initialize.
// Endpoint address.
// Buffer with data to write.
// Number of bytes to write.
// Number of bytes written.
// IntPtr.Zero for non-overlapped I/O.
// Returns
// True on success.
// ***
var success = WinUsb_WritePipe
(MyDevInfo.WinUSBHandle,
MyDevInfo.InterruptOutPipe,
buffer,
bytesToWrite,
ref bytesWritten,
IntPtr.Zero);
if (success) return true;
try
{
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
APILogger.Log("SendViaInterruptTransfer failed - bytes[", BitConverter.ToString(buffer, 0, Convert.ToInt32(bytesToWrite)), "] - ", w32.Message);
}
catch { }
return false;
}
/// <summary>
/// Sets pipe policy.
/// Used when the value parameter is a Byte (all except PIPE_TRANSFER_TIMEOUT).
/// </summary>
///
/// <param name="pipeId"> Pipe to set a policy for. </param>
/// <param name="policyType"> POLICY_TYPE member. </param>
/// <param name="value"> Policy value. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
///
private bool SetPipePolicy(byte pipeId, uint policyType, byte value)
{
// ***
// winusb function
// summary
// sets a pipe policy
// parameters
// handle returned by WinUsb_Initialize
// identifies the pipe
// POLICY_TYPE member.
// length of value in bytes
// value to set for the policy.
// returns
// True on success
// ***
var success = WinUsb_SetPipePolicy
(MyDevInfo.WinUSBHandle,
pipeId,
policyType,
Convert.ToUInt32(1),
ref value);
return success;
}
/// <summary>
/// Sets pipe policy.
/// Used when the value parameter is a UInt32 (PIPE_TRANSFER_TIMEOUT only).
/// </summary>
///
/// <param name="pipeId"> Pipe to set a policy for. </param>
/// <param name="policyType"> POLICY_TYPE member. </param>
/// <param name="value"> Policy value. </param>
///
/// <returns>
/// True on success, False on failure.
/// </returns>
///
private bool SetPipePolicy(byte pipeId, uint policyType, uint value)
{
// ***
// winusb function
// summary
// sets a pipe policy
// parameters
// handle returned by WinUsb_Initialize
// identifies the pipe
// POLICY_TYPE member.
// length of value in bytes
// value to set for the policy.
// returns
// True on success
// ***
var success = WinUsb_SetPipePolicy1
(MyDevInfo.WinUSBHandle,
pipeId,
policyType,
Convert.ToUInt32(4),
ref value);
return success;
}
/// <summary>
/// Is the endpoint's direction IN (device to host)?
/// </summary>
///
/// <param name="addr"> The endpoint address. </param>
/// <returns>
/// True if IN (device to host), False if OUT (host to device)
/// </returns>
private static bool UsbEndpointDirectionIn(int addr)
{
var usbEndpointDirectionInReturn = (addr & 0X80) == 0X80;
return usbEndpointDirectionInReturn;
}
/// <summary>
/// Is the endpoint's direction OUT (host to device)?
/// </summary>
///
/// <param name="addr"> The endpoint address. </param>
///
/// <returns>
/// True if OUT (host to device, False if IN (device to host)
/// </returns>
private static bool UsbEndpointDirectionOut(int addr)
{
var usbEndpointDirectionOutReturn = (addr & 0X80) == 0;
return usbEndpointDirectionOutReturn;
}
}
}

View File

@@ -0,0 +1,132 @@
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
namespace DTS.Common.WINUSBConnection
{
/// <summary>
/// These declarations are translated from the C declarations in various files
/// in the Windows DDK. The files are:
///
/// winddk\6001\inc\api\usb.h
/// winddk\6001\inc\api\usb100.h
/// winddk\6001\inc\api\winusbio.h
///
/// (your home directory and release number may vary)
/// </summary>
internal sealed partial class WinUsbDevice
{
internal const uint DEVICE_SPEED = 1;
internal const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
internal enum PolicyType
{
ShortPacketTerminate = 1,
AutoClearStall,
PipeTransferTimeout,
IgnoreShortPackets,
AllowPartialReads,
AutoFlush,
RawIO,
}
internal enum USBDPipeTypes
{
UsbdPipeTypeControl,
UsbdPipeTypeIsochronous,
UsbdPipeTypeBulk,
UsbdPipeTypeInterrupt,
}
internal enum USBDeviceSpeeds
{
UsbLowSpeed = 1,
UsbFullSpeed,
UsbHighSpeed,
}
[StructLayout(LayoutKind.Sequential)]
internal struct USBConfigurationDescriptor
{
internal byte bLength;
internal byte bDescriptorType;
internal ushort wTotalLength;
internal byte bNumInterfaces;
internal byte bConfigurationValue;
internal byte iConfiguration;
internal byte bmAttributes;
internal byte MaxPower;
}
[StructLayout(LayoutKind.Sequential)]
internal struct USBInterfaceDescriptor
{
internal byte bLength;
internal byte bDescriptorType;
internal byte bInterfaceNumber;
internal byte bAlternateSetting;
internal byte bNumEndpoints;
internal byte bInterfaceClass;
internal byte bInterfaceSubClass;
internal byte bInterfaceProtocol;
internal byte iInterface;
}
[StructLayout(LayoutKind.Sequential)]
internal struct WinUSBPipeInformation
{
internal USBDPipeTypes PipeTypes;
internal byte PipeId;
internal ushort MaximumPacketSize;
internal byte Interval;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct WinUSBSetupPacket
{
internal byte RequestType;
internal byte Request;
internal ushort Value;
internal ushort Index;
internal ushort Length;
}
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_ControlTransfer(IntPtr interfaceHandle, WinUSBSetupPacket setupPacket, byte[] buffer, uint bufferLength, ref uint lengthTransferred, IntPtr overlapped);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_Free(IntPtr interfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_Initialize(SafeFileHandle deviceHandle, ref IntPtr interfaceHandle);
// Use this declaration to retrieve DEVICE_SPEED (the only currently defined InformationType).
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_QueryDeviceInformation(IntPtr interfaceHandle, uint informationType, ref uint bufferLength, ref byte buffer);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_QueryInterfaceSettings(IntPtr interfaceHandle, byte alternateInterfaceNumber, ref USBInterfaceDescriptor usbAltInterfaceDescriptor);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_QueryPipe(IntPtr interfaceHandle, byte alternateInterfaceNumber, byte pipeIndex, ref WinUSBPipeInformation pipeInformation);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_ReadPipe(IntPtr interfaceHandle, byte pipeId, byte[] buffer, uint bufferLength, ref uint lengthTransferred, IntPtr overlapped);
// Two declarations for WinUsb_SetPipePolicy.
// Use this one when the returned Value is a Byte (all except PIPE_TRANSFER_TIMEOUT):
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_SetPipePolicy(IntPtr interfaceHandle, byte pipeId, uint policyType, uint valueLength, ref byte Value);
// Use this alias when the returned Value is a UInt32 (PIPE_TRANSFER_TIMEOUT only):
[DllImport("winusb.dll", SetLastError = true, EntryPoint = "WinUsb_SetPipePolicy")]
internal static extern bool WinUsb_SetPipePolicy1(IntPtr interfaceHandle, byte pipeId, uint policyType, uint valueLength, ref uint Value);
[DllImport("winusb.dll", SetLastError = true)]
internal static extern bool WinUsb_WritePipe(IntPtr interfaceHandle, Byte pipeId, byte[] buffer, uint bufferLength, ref uint lengthTransferred, IntPtr overlapped);
}
}

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]