Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HidFastReadWrite classes #136

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/HidLibrary/HidDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public class HidDevice : IHidDevice
private bool _monitorDeviceEvents;
protected delegate HidDeviceData ReadDelegate(int timeout);
protected delegate HidReport ReadReportDelegate(int timeout);
private delegate bool WriteDelegate(byte[] data, int timeout);
private delegate bool WriteReportDelegate(HidReport report, int timeout);
protected delegate bool WriteDelegate(byte[] data, int timeout);
protected delegate bool WriteReportDelegate(HidReport report, int timeout);

internal HidDevice(string devicePath, string description = null)
{
Expand Down Expand Up @@ -485,7 +485,7 @@ protected static void EndReadReport(IAsyncResult ar)
if ((callbackDelegate != null)) callbackDelegate.Invoke(report);
}

private static void EndWrite(IAsyncResult ar)
protected static void EndWrite(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (WriteDelegate)hidAsyncState.CallerDelegate;
Expand All @@ -495,7 +495,7 @@ private static void EndWrite(IAsyncResult ar)
if ((callbackDelegate != null)) callbackDelegate.Invoke(result);
}

private static void EndWriteReport(IAsyncResult ar)
protected static void EndWriteReport(IAsyncResult ar)
{
var hidAsyncState = (HidAsyncState)ar.AsyncState;
var callerDelegate = (WriteReportDelegate)hidAsyncState.CallerDelegate;
Expand Down Expand Up @@ -548,7 +548,7 @@ private static HidDeviceCapabilities GetDeviceCapabilities(IntPtr hidHandle)
return new HidDeviceCapabilities(capabilities);
}

private bool WriteData(byte[] data, int timeout)
protected bool WriteData(byte[] data, int timeout)
{
if (_deviceCapabilities.OutputReportByteLength <= 0) return false;

Expand Down
83 changes: 83 additions & 0 deletions src/HidLibrary/HidFastReadWriteDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Threading.Tasks;

namespace HidLibrary
{
public class HidFastReadWriteDevice : HidFastReadDevice
{
internal HidFastReadWriteDevice(string devicePath, string description = null)
: base(devicePath, description) { }

// FastWrite assumes that the device is connected,
// which could cause stability issues if hardware is
// disconnected during a write
public bool FastWrite(byte[] data)
{
return FastWrite(data, 0);
}

public bool FastWrite(byte[] data, int timeout)
{
try
{
return WriteData(data, timeout);
}
catch
{
return false;
}
}

public void FastWrite(byte[] data, WriteCallback callback)
{
FastWrite(data, callback, 0);
}

public void FastWrite(byte[] data, WriteCallback callback, int timeout)
{
var writeDelegate = new WriteDelegate(WriteData);
var asyncState = new HidAsyncState(writeDelegate, callback);
writeDelegate.BeginInvoke(data, timeout, EndWrite, asyncState);
}

public async Task<bool> FastWriteAsync(byte[] data, int timeout = 0)
{
var writeDelegate = new WriteDelegate(FastWrite);
#if NET20 || NET35 || NET5_0_OR_GREATER
return await Task<bool>.Factory.StartNew(() => writeDelegate.Invoke(data, timeout));
#else
return await Task<bool>.Factory.FromAsync(writeDelegate.BeginInvoke, writeDelegate.EndInvoke, data, timeout, null);
#endif
}

public bool FastWriteReport(HidReport report)
{
return FastWriteReport(report, 0);
}

public bool FastWriteReport(HidReport report, int timeout)
{
return FastWrite(report.GetBytes(), timeout);
}

public void FastWriteReport(HidReport report, WriteCallback callback)
{
FastWriteReport(report, callback, 0);
}

public void FastWriteReport(HidReport report, WriteCallback callback, int timeout)
{
var writeReportDelegate = new WriteReportDelegate(FastWriteReport);
var asyncState = new HidAsyncState(writeReportDelegate, callback);
writeReportDelegate.BeginInvoke(report, timeout, EndWriteReport, asyncState);
}

public async Task<bool> FastWriteReportAsync(HidReport report, int timeout = 0)
{
var writeReportDelegate = new WriteReportDelegate(FastWriteReport);
#if NET20 || NET35 || NET5_0_OR_GREATER
return await Task<bool>.Factory.StartNew(() => writeReportDelegate.Invoke(report, timeout));
#else
return await Task<bool>.Factory.FromAsync(writeReportDelegate.BeginInvoke, writeReportDelegate.EndInvoke, report, timeout, null);
#endif
} }
}
44 changes: 44 additions & 0 deletions src/HidLibrary/HidFastReadWriteEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Linq;

namespace HidLibrary
{
public class HidFastReadWriteEnumerator : IHidEnumerator
{
public bool IsConnected(string devicePath)
{
return HidDevices.IsConnected(devicePath);
}

public IHidDevice GetDevice(string devicePath)
{
return Enumerate(devicePath).FirstOrDefault() as IHidDevice;
}

public IEnumerable<IHidDevice> Enumerate()
{
return HidDevices.EnumerateDevices().
Select(d => new HidFastReadWriteDevice(d.Path, d.Description) as IHidDevice);
}

public IEnumerable<IHidDevice> Enumerate(string devicePath)
{
return HidDevices.EnumerateDevices().Where(x => x.Path == devicePath).
Select(d => new HidFastReadWriteDevice(d.Path, d.Description) as IHidDevice);
}

public IEnumerable<IHidDevice> Enumerate(int vendorId, params int[] productIds)
{
return HidDevices.EnumerateDevices().Select(d => new HidFastReadWriteDevice(d.Path, d.Description)).
Where(f => f.Attributes.VendorId == vendorId && productIds.Contains(f.Attributes.ProductId)).
Select(d => d as IHidDevice);
}

public IEnumerable<IHidDevice> Enumerate(int vendorId)
{
return HidDevices.EnumerateDevices().Select(d => new HidFastReadWriteDevice(d.Path, d.Description)).
Where(f => f.Attributes.VendorId == vendorId).
Select(d => d as IHidDevice);
}
}
}
176 changes: 176 additions & 0 deletions src/Tests/HidFastReadWriteEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
namespace HidLibrary.Tests
{
using Xunit;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Should;

namespace Tests
{
public class HidFastReadWriteEnumeratorTests
{
private HidFastReadWriteEnumerator enumerator;
private string devicePath;

private void BeforeEach()
{
enumerator = new HidFastReadWriteEnumerator();
var firstDevice = enumerator.Enumerate().FirstOrDefault();

if (firstDevice != null)
{
devicePath = firstDevice.DevicePath;
}
else
{
devicePath = "";
}
}

[Fact]
public void CanConstruct()
{
BeforeEach();
enumerator.ShouldBeType(typeof(HidFastReadWriteEnumerator));
}

[Fact]
public void WrapsIsConnected()
{
BeforeEach();
bool enumIsConnected = enumerator.IsConnected(devicePath);
bool hidIsConnected = HidDevices.IsConnected(devicePath);
enumIsConnected.ShouldEqual(hidIsConnected);
}

[Fact]
public void WrapsGetDevice()
{
BeforeEach();
IHidDevice enumDevice = enumerator.GetDevice(devicePath);
IHidDevice hidDevice = HidDevices.GetDevice(devicePath);
enumDevice.DevicePath.ShouldEqual(hidDevice.DevicePath);
}

[Fact]
public void WrapsEnumerateDefault()
{
BeforeEach();
IEnumerable<IHidDevice> enumDevices = enumerator.Enumerate();
IEnumerable<IHidDevice> hidDevices = HidDevices.Enumerate().
Select(d => d as IHidDevice);


AllDevicesTheSame(enumDevices, hidDevices).ShouldBeTrue();
}

[Fact]
public void WrapsEnumerateDevicePath()
{
BeforeEach();
IEnumerable<IHidDevice> enumDevices =
enumerator.Enumerate(devicePath);
IEnumerable<IHidDevice> hidDevices =
HidDevices.Enumerate(devicePath).
Select(d => d as IHidDevice);


AllDevicesTheSame(enumDevices, hidDevices).ShouldBeTrue();
}

[Fact]
public void WrapsEnumerateVendorId()
{
BeforeEach();
int vid = GetVid();

IEnumerable<IHidDevice> enumDevices =
enumerator.Enumerate(vid);
IEnumerable<IHidDevice> hidDevices =
HidDevices.Enumerate(vid).
Select(d => d as IHidDevice);


AllDevicesTheSame(enumDevices, hidDevices).ShouldBeTrue();
}

[Fact]
public void WrapsEnumerateVendorIdProductId()
{
BeforeEach();
int vid = GetVid();
int pid = GetPid();

IEnumerable<IHidDevice> enumDevices =
enumerator.Enumerate(vid, pid);
IEnumerable<IHidDevice> hidDevices =
HidDevices.Enumerate(vid, pid).
Select(d => d as IHidDevice);


AllDevicesTheSame(enumDevices, hidDevices).ShouldBeTrue();
}

[Fact]
public void DevicesAreFastRead()
{
BeforeEach();
HidFastReadWriteDevice device = enumerator.GetDevice(devicePath) as HidFastReadWriteDevice;
device.ShouldNotBeNull();
}

private bool AllDevicesTheSame(IEnumerable<IHidDevice> a,
IEnumerable<IHidDevice> b)
{
if (a.Count() != b.Count())
return false;

bool allSame = true;

var aList = a.ToList();
var bList = b.ToList();

int numDevices = aList.Count;

for (int i = 0; i < numDevices; i++)
{
if (aList[i].DevicePath !=
bList[i].DevicePath)
{
allSame = false;
break;
}
}

return allSame;
}

private int GetVid()
{
return GetNumberFromRegex("vid_([0-9a-f]{4})");
}

private int GetPid()
{
return GetNumberFromRegex("pid_([0-9a-f]{3,4})");
}

private int GetNumberFromRegex(string pattern)
{
var match = Regex.Match(devicePath, pattern,
RegexOptions.IgnoreCase);

int num = 0;

if (match.Success)
{
num = int.Parse(match.Groups[1].Value,
System.Globalization.NumberStyles.HexNumber);
}

return num;
}
}
}
}