diff --git a/src/Device.Net - All.sln b/src/Device.Net - All.sln index 314122a3..a1aeedb4 100644 --- a/src/Device.Net - All.sln +++ b/src/Device.Net - All.sln @@ -72,6 +72,8 @@ Global {8E29E247-78B7-4FC8-AF1C-DA273050978C}.Release|Any CPU.ActiveCfg = Release|Any CPU {8E29E247-78B7-4FC8-AF1C-DA273050978C}.Release|Any CPU.Build.0 = Release|Any CPU {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Debug|Any CPU.ActiveCfg = Debug|x86 + {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Debug|Any CPU.Build.0 = Debug|x86 + {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Debug|Any CPU.Deploy.0 = Debug|x86 {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Release|Any CPU.ActiveCfg = Release|x86 {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Release|Any CPU.Build.0 = Release|x86 {63695F84-3EC6-4F6A-8C8C-5219D75EDB68}.Release|Any CPU.Deploy.0 = Release|x86 diff --git a/src/Device.Net.LibUsb/LibUsbDevice.cs b/src/Device.Net.LibUsb/LibUsbDevice.cs index ad0c9712..03c779b8 100644 --- a/src/Device.Net.LibUsb/LibUsbDevice.cs +++ b/src/Device.Net.LibUsb/LibUsbDevice.cs @@ -3,12 +3,13 @@ using LibUsbDotNet.Main; using LibUsbDotNet.WinUsb; using System; +using System.IO; using System.Threading; using System.Threading.Tasks; namespace Device.Net.LibUsb { - public class LibUsbDevice : IDevice + public class LibUsbDevice : DeviceBase, IDevice { #region Fields private UsbEndpointReader _UsbEndpointReader; @@ -16,6 +17,7 @@ public class LibUsbDevice : IDevice private int ReadPacketSize; private SemaphoreSlim _WriteAndReadLock = new SemaphoreSlim(1, 1); private bool disposed; + private bool _IsInitialized; #endregion #region Public Properties @@ -23,10 +25,11 @@ public class LibUsbDevice : IDevice public int VendorId => GetVendorId(UsbDevice); public int ProductId => GetProductId(UsbDevice); public int Timeout { get; } - public bool IsInitialized { get; private set; } - public ConnectedDeviceDefinitionBase ConnectedDeviceDefinition => throw new NotImplementedException(); + public override bool IsInitialized => _IsInitialized; public string DeviceId => UsbDevice.DevicePath; public ILogger Logger { get; set; } + public override ushort WriteBufferSize => throw new NotImplementedException(); + public override ushort ReadBufferSize => throw new NotImplementedException(); #endregion #region Events @@ -35,7 +38,11 @@ public class LibUsbDevice : IDevice #endregion #region Constructor - public LibUsbDevice(UsbDevice usbDevice, int timeout) + public LibUsbDevice(UsbDevice usbDevice, int timeout) : this(usbDevice, timeout, null, null) + { + } + + public LibUsbDevice(UsbDevice usbDevice, int timeout, ILogger logger, ITracer tracer) : base(logger, tracer) { UsbDevice = usbDevice; Timeout = timeout; @@ -86,11 +93,11 @@ public async Task InitializeAsync() _UsbEndpointReader = UsbDevice.OpenEndpointReader(ReadEndpointID.Ep01); ReadPacketSize = _UsbEndpointReader.EndpointInfo.Descriptor.MaxPacketSize; - IsInitialized = true; + _IsInitialized = true; }); } - public async Task ReadAsync() + public override async Task ReadAsync() { await _WriteAndReadLock.WaitAsync(); @@ -98,11 +105,13 @@ public async Task ReadAsync() { return await Task.Run(() => { - var buffer = new byte[ReadPacketSize]; + var data = new byte[ReadPacketSize]; - _UsbEndpointReader.Read(buffer, Timeout, out var bytesRead); + _UsbEndpointReader.Read(data, Timeout, out var bytesRead); - return buffer; + Tracer?.Trace(false, data); + + return data; }); } finally @@ -111,7 +120,7 @@ public async Task ReadAsync() } } - public async Task WriteAsync(byte[] data) + public override async Task WriteAsync(byte[] data) { await _WriteAndReadLock.WaitAsync(); @@ -119,7 +128,17 @@ public async Task WriteAsync(byte[] data) { await Task.Run(() => { - _UsbEndpointWriter.Write(data, Timeout, out var bytesWritten); + var errorCode = _UsbEndpointWriter.Write(data, Timeout, out var bytesWritten); + if (errorCode == ErrorCode.Ok || errorCode == ErrorCode.Success) + { + Tracer?.Trace(true, data); + } + else + { + var message = $"Error. Write error code: {errorCode}"; + Logger?.Log(message, GetType().Name, null, LogLevel.Error); + throw new IOException(message); + } }); } finally @@ -128,11 +147,6 @@ public async Task WriteAsync(byte[] data) } } - public async Task WriteAndReadAsync(byte[] writeBuffer) - { - await WriteAsync(writeBuffer); - return await ReadAsync(); - } #endregion #region Public Static Methods diff --git a/src/Device.Net.LibUsb/LibUsbDeviceFactoryBase.cs b/src/Device.Net.LibUsb/LibUsbDeviceFactoryBase.cs index cce9b530..b584da80 100644 --- a/src/Device.Net.LibUsb/LibUsbDeviceFactoryBase.cs +++ b/src/Device.Net.LibUsb/LibUsbDeviceFactoryBase.cs @@ -9,7 +9,8 @@ namespace Device.Net.LibUsb public abstract class LibUsbDeviceFactoryBase : IDeviceFactory { #region Public Properties - public ILogger Logger { get; set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } #endregion #region Public Abstraction Properties @@ -56,7 +57,15 @@ public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { var usbDeviceFinder = new UsbDeviceFinder((int)deviceDefinition.VendorId.Value, (int)deviceDefinition.ProductId.Value); var usbDevice = UsbDevice.OpenUsbDevice(usbDeviceFinder); - return usbDevice != null ? new LibUsbDevice(usbDevice, 3000) { Logger = Logger } : null; + return usbDevice != null ? new LibUsbDevice(usbDevice, 3000, Logger, Tracer) : null; + } + #endregion + + #region Constructor + protected LibUsbDeviceFactoryBase(ILogger logger, ITracer tracer) + { + Logger = logger; + Tracer = tracer; } #endregion } diff --git a/src/Device.Net.LibUsb/LibUsbUsbDeviceFactory.cs b/src/Device.Net.LibUsb/LibUsbUsbDeviceFactory.cs index 933e5686..2296806d 100644 --- a/src/Device.Net.LibUsb/LibUsbUsbDeviceFactory.cs +++ b/src/Device.Net.LibUsb/LibUsbUsbDeviceFactory.cs @@ -2,16 +2,18 @@ { public class LibUsbUsbDeviceFactory : LibUsbDeviceFactoryBase { - public override DeviceType DeviceType => DeviceType.Usb; - - public static void Register() + public LibUsbUsbDeviceFactory(ILogger logger, ITracer tracer) : base(logger, tracer) { - Register(null); } - public static void Register(ILogger logger) + public override DeviceType DeviceType => DeviceType.Usb; + + /// + /// Register the factory for enumerating USB devices. + /// + public static void Register(ILogger logger, ITracer tracer) { - DeviceManager.Current.DeviceFactories.Add(new LibUsbUsbDeviceFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new LibUsbUsbDeviceFactory(logger, tracer)); } } } diff --git a/src/Device.Net.UWP/UWPDeviceBase - Generic.cs b/src/Device.Net.UWP/UWPDeviceBase - Generic.cs index f111e36d..b697416b 100644 --- a/src/Device.Net.UWP/UWPDeviceBase - Generic.cs +++ b/src/Device.Net.UWP/UWPDeviceBase - Generic.cs @@ -16,12 +16,7 @@ public abstract class UWPDeviceBase : UWPDeviceBase, IDevice #endregion #region Constructor - protected UWPDeviceBase() - { - - } - - protected UWPDeviceBase(string deviceId) + protected UWPDeviceBase(string deviceId, ILogger logger, ITracer tracer) : base(logger, tracer) { DeviceId = deviceId; } @@ -53,16 +48,19 @@ public override async Task ReadAsync() { if (Chunks.Count > 0) { - var retVal = Chunks[0]; - Tracer?.Trace(false, retVal); + var data2 = Chunks[0]; + Logger?.Log("Received data from device", GetType().Name, null, LogLevel.Information); Chunks.RemoveAt(0); - return retVal; + Tracer?.Trace(false, data2); + return data2; } } IsReading = true; ReadChunkTaskCompletionSource = new TaskCompletionSource(); - return await ReadChunkTaskCompletionSource.Task; + var data = await ReadChunkTaskCompletionSource.Task; + Tracer?.Trace(false, data); + return data; } #endregion diff --git a/src/Device.Net.UWP/UWPDeviceBase.cs b/src/Device.Net.UWP/UWPDeviceBase.cs index 03f66396..5e3863bb 100644 --- a/src/Device.Net.UWP/UWPDeviceBase.cs +++ b/src/Device.Net.UWP/UWPDeviceBase.cs @@ -35,5 +35,11 @@ protected void HandleDataReceived(byte[] bytes) #region Public Abstract Methods public abstract Task InitializeAsync(); #endregion + + #region Constructor + protected UWPDeviceBase(ILogger logger, ITracer tracer) : base(logger, tracer) + { + } + #endregion } } diff --git a/src/Device.Net.UWP/UWPDeviceFactoryBase.cs b/src/Device.Net.UWP/UWPDeviceFactoryBase.cs index 46ce9f4e..458671ad 100644 --- a/src/Device.Net.UWP/UWPDeviceFactoryBase.cs +++ b/src/Device.Net.UWP/UWPDeviceFactoryBase.cs @@ -23,7 +23,8 @@ public abstract class UWPDeviceFactoryBase #endregion #region Public Properties - public ILogger Logger { get; set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } #endregion #region Public Abstract Properties @@ -34,6 +35,14 @@ public abstract class UWPDeviceFactoryBase protected abstract string GetAqsFilter(uint? vendorId, uint? productId); #endregion + #region Constructor + protected UWPDeviceFactoryBase(ILogger logger, ITracer tracer) + { + Logger = logger; + Tracer = tracer; + } + #endregion + #region Abstraction Methods protected string GetVendorPart(uint? vendorId) { diff --git a/src/Device.Net.UnitTests/MockDeviceBase.cs b/src/Device.Net.UnitTests/MockDeviceBase.cs index e41b4680..4a9a448e 100644 --- a/src/Device.Net.UnitTests/MockDeviceBase.cs +++ b/src/Device.Net.UnitTests/MockDeviceBase.cs @@ -11,6 +11,11 @@ public abstract class MockDeviceBase : DeviceBase, IDevice public override bool IsInitialized => _IsInitialized; + protected MockDeviceBase(ILogger logger, ITracer tracer) : base(logger, tracer) + { + + } + public void Close() { } @@ -23,16 +28,22 @@ public Task InitializeAsync() private byte[] LastWrittenBuffer; - public async override Task ReadAsync() + public override async Task ReadAsync() { - if (LastWrittenBuffer != null) return LastWrittenBuffer; - - return await Task.FromResult(new byte[64] { 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); + if (LastWrittenBuffer != null) + { + Tracer.Trace(false, LastWrittenBuffer); + return LastWrittenBuffer; + } + var data = new byte[64] { 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + Tracer.Trace(false, data); + return await Task.FromResult(data); } public override Task WriteAsync(byte[] data) { LastWrittenBuffer = data; + Tracer.Trace(true, data); return Task.FromResult(true); } } diff --git a/src/Device.Net.UnitTests/MockFactoryBase.cs b/src/Device.Net.UnitTests/MockFactoryBase.cs index 47b79f5b..dba649c2 100644 --- a/src/Device.Net.UnitTests/MockFactoryBase.cs +++ b/src/Device.Net.UnitTests/MockFactoryBase.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Device.Net.UnitTests @@ -12,7 +11,14 @@ public abstract class MockFactoryBase : IDeviceFactory public abstract DeviceType DeviceType { get; } - public ILogger Logger { get; protected set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } + + protected MockFactoryBase(ILogger logger, ITracer tracer) + { + Logger = logger; + Tracer = tracer; + } public abstract uint ProductId { get; } public abstract uint VendorId { get; } @@ -23,6 +29,15 @@ public Task> GetConnectedDeviceDefinition var mockConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId) { ProductId = ProductId, VendorId = VendorId }; + if (this is MockHidFactory mockHidFactory) + { + mockConnectedDeviceDefinition.DeviceType = DeviceType.Hid; + } + else + { + mockConnectedDeviceDefinition.DeviceType = DeviceType.Usb; + } + if (IsConnected) { if (DeviceManager.IsDefinitionMatch(deviceDefinition, mockConnectedDeviceDefinition)) diff --git a/src/Device.Net.UnitTests/MockHidDevice.cs b/src/Device.Net.UnitTests/MockHidDevice.cs index 0331988f..f988a32d 100644 --- a/src/Device.Net.UnitTests/MockHidDevice.cs +++ b/src/Device.Net.UnitTests/MockHidDevice.cs @@ -6,11 +6,10 @@ public class MockHidDevice : MockDeviceBase, IDevice public const uint VendorId = 1; public const string MockedDeviceId = "123"; - public MockHidDevice() + public MockHidDevice(ILogger logger, ITracer tracer) : base(logger, tracer) { DeviceId = MockedDeviceId; - ConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId) { ProductId = ProductId, VendorId = VendorId }; - Logger = new DebugLogger { LogToConsole = true }; + ConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId) { ProductId = ProductId, VendorId = VendorId, DeviceType = DeviceType.Hid }; } } } diff --git a/src/Device.Net.UnitTests/MockHidFactory.cs b/src/Device.Net.UnitTests/MockHidFactory.cs index 02438ada..8b1f1892 100644 --- a/src/Device.Net.UnitTests/MockHidFactory.cs +++ b/src/Device.Net.UnitTests/MockHidFactory.cs @@ -4,9 +4,10 @@ namespace Device.Net.UnitTests { public class MockHidFactory : MockFactoryBase, IDeviceFactory { - public MockHidFactory() + public const string FoundMessage = "Found device {0}"; + + public MockHidFactory(ILogger logger, ITracer tracer) : base(logger, tracer) { - Logger = new DebugLogger { LogToConsole = true }; } public override string DeviceId => MockHidDevice.MockedDeviceId; @@ -21,9 +22,9 @@ public MockHidFactory() public override uint VendorId => MockHidDevice.VendorId; - public static void Register(ILogger logger) + public static void Register(ILogger logger, ITracer tracer) { - DeviceManager.Current.DeviceFactories.Add(new MockHidFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new MockHidFactory(logger, tracer)); } public override IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) @@ -32,11 +33,16 @@ public override IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { if (deviceDefinition.DeviceId == DeviceId) { - if (!deviceDefinition.DeviceType.HasValue || deviceDefinition.DeviceType == DeviceType.Hid) return new MockHidDevice(); + if (!deviceDefinition.DeviceType.HasValue || deviceDefinition.DeviceType == DeviceType.Hid) + { + Logger?.Log(string.Format(FoundMessage, DeviceId), nameof(MockHidFactory), null, LogLevel.Information); + + return new MockHidDevice(Logger, Tracer); + } } } - throw new Exception("Couldn't get a device"); + return null; } } } diff --git a/src/Device.Net.UnitTests/MockLogger.cs b/src/Device.Net.UnitTests/MockLogger.cs new file mode 100644 index 00000000..1cf5f8ff --- /dev/null +++ b/src/Device.Net.UnitTests/MockLogger.cs @@ -0,0 +1,17 @@ +using System; +using System.Text; + +namespace Device.Net.UnitTests +{ + internal class MockLogger : ILogger + { + StringBuilder _stringBuilder = new StringBuilder(); + + public string LogText => _stringBuilder.ToString(); + + public void Log(string message, string region, Exception ex, LogLevel logLevel) + { + _stringBuilder.Append(message); + } + } +} \ No newline at end of file diff --git a/src/Device.Net.UnitTests/MockTracer.cs b/src/Device.Net.UnitTests/MockTracer.cs new file mode 100644 index 00000000..ff4e471d --- /dev/null +++ b/src/Device.Net.UnitTests/MockTracer.cs @@ -0,0 +1,17 @@ +using System; + +namespace Device.Net.UnitTests +{ + public class MockTracer : ITracer + { + public int WriteCount { get; private set; } + public int ReadCount { get; private set; } + + public void Trace(bool isWrite, byte[] data) + { + if (data == null) throw new Exception("data must not be null"); + if (isWrite) WriteCount++; + if (!isWrite) ReadCount++; + } + } +} diff --git a/src/Device.Net.UnitTests/MockUsbDevice.cs b/src/Device.Net.UnitTests/MockUsbDevice.cs index 0623e60c..4d71ef98 100644 --- a/src/Device.Net.UnitTests/MockUsbDevice.cs +++ b/src/Device.Net.UnitTests/MockUsbDevice.cs @@ -6,11 +6,10 @@ public class MockUsbDevice : MockDeviceBase, IDevice public const uint VendorId = 2; public const string MockedDeviceId = "321"; - public MockUsbDevice() + public MockUsbDevice(ILogger logger, ITracer tracer) : base(logger, tracer) { DeviceId = MockedDeviceId; - ConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId) { ProductId = ProductId, VendorId = VendorId }; - Logger = new DebugLogger { LogToConsole = true }; + ConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId) { ProductId = ProductId, VendorId = VendorId, DeviceType = DeviceType.Usb }; } } } diff --git a/src/Device.Net.UnitTests/MockUsbFactory.cs b/src/Device.Net.UnitTests/MockUsbFactory.cs index ffec9a99..68242af4 100644 --- a/src/Device.Net.UnitTests/MockUsbFactory.cs +++ b/src/Device.Net.UnitTests/MockUsbFactory.cs @@ -4,9 +4,8 @@ namespace Device.Net.UnitTests { public class MockUsbFactory : MockFactoryBase, IDeviceFactory { - public MockUsbFactory() + public MockUsbFactory(ILogger logger, ITracer tracer) : base(logger, tracer) { - Logger = new DebugLogger { LogToConsole = true }; } public override string DeviceId => MockUsbDevice.MockedDeviceId; @@ -21,9 +20,11 @@ public MockUsbFactory() public override uint VendorId => MockUsbDevice.VendorId; - public static void Register(ILogger logger) + public const string FoundMessage = "Found device {0}"; + + public static void Register(ILogger logger, ITracer tracer) { - DeviceManager.Current.DeviceFactories.Add(new MockUsbFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new MockUsbFactory(logger, tracer)); } public override IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) @@ -32,7 +33,12 @@ public override IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { if (deviceDefinition.DeviceId == DeviceId) { - if (!deviceDefinition.DeviceType.HasValue || deviceDefinition.DeviceType == DeviceType.Usb) return new MockUsbDevice() ; + if (!deviceDefinition.DeviceType.HasValue || deviceDefinition.DeviceType == DeviceType.Usb) + { + Logger?.Log(string.Format(FoundMessage, DeviceId), nameof(MockUsbFactory), null, LogLevel.Information); + + return new MockUsbDevice(Logger, Tracer); + } } } diff --git a/src/Device.Net.UnitTests/UnitTests.cs b/src/Device.Net.UnitTests/UnitTests.cs index bf29560a..2f2f2563 100644 --- a/src/Device.Net.UnitTests/UnitTests.cs +++ b/src/Device.Net.UnitTests/UnitTests.cs @@ -10,12 +10,15 @@ namespace Device.Net.UnitTests [TestClass] public class UnitTests { + private static MockLogger logger = new MockLogger(); + private static MockTracer tracer = new MockTracer(); + #region Tests [TestInitialize] public void Startup() { - MockHidFactory.Register(null); - MockUsbFactory.Register(null); + MockHidFactory.Register(logger, tracer); + MockUsbFactory.Register(logger, tracer); } [TestMethod] @@ -33,6 +36,25 @@ public async Task TestWithMatchedFilterAsync(bool isHidConnected, bool isUsbConn MockHidFactory.IsConnectedStatic = isHidConnected; MockUsbFactory.IsConnectedStatic = isUsbConnected; var connectedDeviceDefinitions = (await DeviceManager.Current.GetConnectedDeviceDefinitionsAsync(new FilterDeviceDefinition { ProductId = pid, VendorId = vid })).ToList(); + + if (connectedDeviceDefinitions.Count > 0) + { + foreach (var connectedDeviceDefinition in connectedDeviceDefinitions) + { + var device = DeviceManager.Current.GetDevice(connectedDeviceDefinition); + + if (device != null && connectedDeviceDefinition.DeviceType == DeviceType.Hid) + { + Assert.IsTrue(logger.LogText.Contains(string.Format(MockHidFactory.FoundMessage, connectedDeviceDefinition.DeviceId))); + } + + if (device != null && connectedDeviceDefinition.DeviceType == DeviceType.Usb) + { + Assert.IsTrue(logger.LogText.Contains(string.Format(MockUsbFactory.FoundMessage, connectedDeviceDefinition.DeviceId))); + } + } + } + Assert.IsNotNull(connectedDeviceDefinitions); Assert.AreEqual(expectedCount, connectedDeviceDefinitions.Count); } @@ -40,20 +62,25 @@ public async Task TestWithMatchedFilterAsync(bool isHidConnected, bool isUsbConn [TestMethod] [DataRow(true, true, MockHidDevice.VendorId, MockHidDevice.ProductId)] [DataRow(true, false, MockHidDevice.VendorId, MockHidDevice.ProductId)] - //[DataRow(true, true, MockUsbDevice.VendorId, MockUsbDevice.ProductId)] - //[DataRow(false, true, MockUsbDevice.VendorId, MockUsbDevice.ProductId)] public async Task TestWriteAndReadThreadSafety(bool isHidConnected, bool isUsbConnected, uint vid, uint pid) { + var readtraceCount = tracer.ReadCount; + var writetraceCount = tracer.WriteCount; + MockHidFactory.IsConnectedStatic = isHidConnected; MockUsbFactory.IsConnectedStatic = isUsbConnected; var connectedDeviceDefinition = (await DeviceManager.Current.GetConnectedDeviceDefinitionsAsync(new FilterDeviceDefinition { ProductId = pid, VendorId = vid })).ToList().First(); - var mockHidDevice = new MockHidDevice() { DeviceId = connectedDeviceDefinition.DeviceId }; + + + var mockHidDevice = new MockHidDevice(logger, tracer) { DeviceId = connectedDeviceDefinition.DeviceId }; var writeAndReadTasks = new List>(); //TODO: Does this properly test thread safety? - for (byte i = 0; i < 10; i++) + const int count = 10; + + for (byte i = 0; i < count; i++) { writeAndReadTasks.Add(mockHidDevice.WriteAndReadAsync(new byte[64] { i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); } @@ -65,6 +92,11 @@ public async Task TestWriteAndReadThreadSafety(bool isHidConnected, bool isUsbCo var result = results[i]; Assert.IsTrue(result[0] == i); } + + Assert.AreEqual(readtraceCount + count, tracer.ReadCount); + Assert.AreEqual(writetraceCount + count, tracer.WriteCount); + + Assert.IsTrue(logger.LogText.Contains(Messages.SuccessMessageWriteAndReadCalled)); } [TestMethod] diff --git a/src/Device.Net/DebugTracer.cs b/src/Device.Net/DebugTracer.cs index 0f8f242d..b5f4b261 100644 --- a/src/Device.Net/DebugTracer.cs +++ b/src/Device.Net/DebugTracer.cs @@ -6,7 +6,7 @@ public class DebugTracer : ITracer { public void Trace(bool isWrite, byte[] data) { - Debug.WriteLine($"({string.Join(",", data)}) - {(isWrite ? "Write" : "Read")} ({data.Length})"); + Debug.WriteLine($"{(isWrite ? "Write" : "Read")}: ({string.Join(",", data)}) ({data.Length})"); } } } diff --git a/src/Device.Net/DeviceBase.cs b/src/Device.Net/DeviceBase.cs index 7876bf6d..58f9c8ed 100644 --- a/src/Device.Net/DeviceBase.cs +++ b/src/Device.Net/DeviceBase.cs @@ -21,10 +21,18 @@ public abstract class DeviceBase : IDisposable #endregion #region Public Properties - public ITracer Tracer { get; set; } public ConnectedDeviceDefinitionBase ConnectedDeviceDefinition { get; set; } public string DeviceId { get; set; } - public ILogger Logger { get; set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } + #endregion + + #region Constructor + protected DeviceBase(ILogger logger, ITracer tracer) + { + Tracer = tracer; + Logger = logger; + } #endregion #region Private Methods @@ -75,7 +83,7 @@ public async Task WriteAndReadAsync(byte[] writeBuffer) { await WriteAsync(writeBuffer); var retVal = await ReadAsync(); - Log($"Successfully called {nameof(WriteAndReadAsync)}"); + Log(Messages.SuccessMessageWriteAndReadCalled); return retVal; } catch (Exception ex) diff --git a/src/Device.Net/Messages.cs b/src/Device.Net/Messages.cs new file mode 100644 index 00000000..7cd35bc2 --- /dev/null +++ b/src/Device.Net/Messages.cs @@ -0,0 +1,14 @@ +namespace Device.Net +{ + public static class Messages + { + public const string ErrorMessageNotInitialized = "The device has not been initialized."; + + public static string SuccessMessageWriteAndReadCalled => $"Successfully called {nameof(DeviceBase.WriteAndReadAsync)}"; + + public static string GetErrorMessageInvalidWriteLength(int length, uint count) + { + return $"Write failure. {length} bytes were sent to the device but it claims that {count} were sent."; + } + } +} diff --git a/src/Device.Net/Windows/WindowsDeviceBase.cs b/src/Device.Net/Windows/WindowsDeviceBase.cs index 3947b7f5..ffd83c9c 100644 --- a/src/Device.Net/Windows/WindowsDeviceBase.cs +++ b/src/Device.Net/Windows/WindowsDeviceBase.cs @@ -14,7 +14,7 @@ public abstract class WindowsDeviceBase : DeviceBase #endregion #region Constructor - protected WindowsDeviceBase(string deviceId) + protected WindowsDeviceBase(string deviceId, ILogger logger, ITracer tracer) : base(logger, tracer) { DeviceId = deviceId; } diff --git a/src/Device.Net/Windows/WindowsDeviceFactoryBase.cs b/src/Device.Net/Windows/WindowsDeviceFactoryBase.cs index 93fcde8c..2fa31942 100644 --- a/src/Device.Net/Windows/WindowsDeviceFactoryBase.cs +++ b/src/Device.Net/Windows/WindowsDeviceFactoryBase.cs @@ -14,8 +14,8 @@ namespace Device.Net.Windows public abstract class WindowsDeviceFactoryBase { #region Public Properties - public ILogger Logger { get; set; } - public ITracer Tracer { get; set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } #endregion #region Public Abstract Properties @@ -27,6 +27,14 @@ public abstract class WindowsDeviceFactoryBase protected abstract Guid GetClassGuid(); #endregion + #region Constructor + protected WindowsDeviceFactoryBase(ILogger logger, ITracer tracer) + { + Logger = logger; + Tracer = tracer; + } + #endregion + #region Public Methods public async Task> GetConnectedDeviceDefinitionsAsync(FilterDeviceDefinition filterDeviceDefinition) { diff --git a/src/Hid.Net.UWP/UWPHidDevice.cs b/src/Hid.Net.UWP/UWPHidDevice.cs index 21d67df1..465f4b1c 100644 --- a/src/Hid.Net.UWP/UWPHidDevice.cs +++ b/src/Hid.Net.UWP/UWPHidDevice.cs @@ -1,5 +1,7 @@ -using Device.Net.UWP; +using Device.Net; +using Device.Net.UWP; using System; +using System.IO; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using Windows.Devices.HumanInterfaceDevice; @@ -34,11 +36,15 @@ private void _HidDevice_InputReportReceived(HidDevice sender, HidInputReportRece #endregion #region Constructors - public UWPHidDevice() + public UWPHidDevice(ILogger logger, ITracer tracer) : this(null, logger, tracer) { } - public UWPHidDevice(string deviceId) : base(deviceId) + public UWPHidDevice(string deviceId) : this(deviceId, null, null) + { + } + + public UWPHidDevice(string deviceId, ILogger logger, ITracer tracer) : base(deviceId, logger, tracer) { } #endregion @@ -111,8 +117,17 @@ public async Task WriteReportAsync(byte[] data, byte? reportId) try { var operation = ConnectedDevice.SendOutputReportAsync(outReport); - await operation.AsTask(); - Tracer?.Trace(false, bytes); + var count = await operation.AsTask(); + if (count == bytes.Length) + { + Tracer?.Trace(true, bytes); + } + else + { + var message = Messages.GetErrorMessageInvalidWriteLength(bytes.Length, count); + Logger?.Log(message, GetType().Name, null, LogLevel.Error); + throw new IOException(message); + } } catch (ArgumentException ex) { @@ -124,6 +139,8 @@ public async Task WriteReportAsync(byte[] data, byte? reportId) throw; } } + + #endregion #region Public Overrides @@ -143,7 +160,9 @@ public async Task ReadReportAsync() public override async Task ReadAsync() { - return (await ReadReportAsync()).Data; + var data = (await ReadReportAsync()).Data; + Tracer?.Trace(false, data); + return data; } #endregion diff --git a/src/Hid.Net.UWP/UWPHidDeviceFactory.cs b/src/Hid.Net.UWP/UWPHidDeviceFactory.cs index c4ac8c29..37a159da 100644 --- a/src/Hid.Net.UWP/UWPHidDeviceFactory.cs +++ b/src/Hid.Net.UWP/UWPHidDeviceFactory.cs @@ -64,10 +64,17 @@ public override async Task TestConnection(string deviceId) } #endregion + #region Constructor + public UWPHidDeviceFactory(ILogger logger, ITracer tracer) : base(logger, tracer) + { + + } + #endregion + #region Public Methods public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { - return deviceDefinition.DeviceType == DeviceType.Usb ? null : new UWPHidDevice(deviceDefinition.DeviceId) { Logger = Logger }; + return deviceDefinition.DeviceType == DeviceType.Usb ? null : new UWPHidDevice(deviceDefinition.DeviceId, Logger, Tracer); } public void Dispose() @@ -82,19 +89,17 @@ public void Dispose() #endregion #region Public Static Methods - public static void Register() - { - Register(null); - } - - public static void Register(ILogger logger) + /// + /// Register the factory for enumerating Hid devices on UWP. + /// + public static void Register(ILogger logger, ITracer tracer) { foreach (var deviceFactory in DeviceManager.Current.DeviceFactories) { if (deviceFactory is UWPHidDeviceFactory) return; } - DeviceManager.Current.DeviceFactories.Add(new UWPHidDeviceFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new UWPHidDeviceFactory(logger, tracer)); } #endregion diff --git a/src/Hid.Net/Windows/WindowsHIDDevice.cs b/src/Hid.Net/Windows/WindowsHIDDevice.cs index 4c4c57ca..039f13a9 100644 --- a/src/Hid.Net/Windows/WindowsHIDDevice.cs +++ b/src/Hid.Net/Windows/WindowsHIDDevice.cs @@ -41,11 +41,15 @@ public sealed class WindowsHidDevice : WindowsDeviceBase, IHidDevice #endregion #region Constructor - public WindowsHidDevice(string deviceId) : this(deviceId, null, null) + public WindowsHidDevice(string deviceId) : this(deviceId, null, null, null, null) { } - public WindowsHidDevice(string deviceId, ushort? writeBufferSize, ushort? readBufferSize) : base(deviceId) + public WindowsHidDevice(string deviceId, ILogger logger, ITracer tracer) : this(deviceId, null, null, logger, tracer) + { + } + + public WindowsHidDevice(string deviceId, ushort? writeBufferSize, ushort? readBufferSize, ILogger logger, ITracer tracer) : base(deviceId, logger, tracer) { _WriteBufferSize = writeBufferSize; _ReadBufferSize = readBufferSize; @@ -162,7 +166,9 @@ public override async Task InitializeAsync() public override async Task ReadAsync() { - return (await ReadReportAsync()).Data; + var data = (await ReadReportAsync()).Data; + Tracer?.Trace(false, data); + return data; } public async Task ReadReportAsync() @@ -190,8 +196,6 @@ public async Task ReadReportAsync() var retVal = ReadBufferHasReportId ? RemoveFirstByte(bytes) : bytes; - Tracer?.Trace(false, retVal); - return new ReadReport(reportId, retVal); } @@ -234,14 +238,13 @@ public async Task WriteReportAsync(byte[] data, byte? reportId) try { await _WriteFileStream.WriteAsync(bytes, 0, bytes.Length); + Tracer?.Trace(true, bytes); } catch (Exception ex) { Log(Helpers.WriteErrorMessage, ex); throw new IOException(Helpers.WriteErrorMessage, ex); } - - Tracer?.Trace(true, bytes); } else { diff --git a/src/Hid.Net/Windows/WindowsHidDeviceFactory.cs b/src/Hid.Net/Windows/WindowsHidDeviceFactory.cs index b856148c..ec30a681 100644 --- a/src/Hid.Net/Windows/WindowsHidDeviceFactory.cs +++ b/src/Hid.Net/Windows/WindowsHidDeviceFactory.cs @@ -36,10 +36,17 @@ protected override Guid GetClassGuid() #endregion + #region Constructor + public WindowsHidDeviceFactory(ILogger logger, ITracer tracer) : base(logger, tracer) + { + + } + #endregion + #region Public Methods public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { - return deviceDefinition.DeviceType != DeviceType ? null : new WindowsHidDevice(deviceDefinition.DeviceId) { Logger = Logger }; + return deviceDefinition.DeviceType != DeviceType ? null : new WindowsHidDevice(deviceDefinition.DeviceId, Logger, Tracer); } #endregion @@ -70,14 +77,12 @@ public static ConnectedDeviceDefinition GetDeviceDefinition(string deviceId, Saf #endregion #region Public Static Methods - public static void Register() - { - Register(null); - } - - public static void Register(ILogger logger) + /// + /// Register the factory for enumerating Hid devices on UWP. + /// + public static void Register(ILogger logger, ITracer tracer) { - DeviceManager.Current.DeviceFactories.Add(new WindowsHidDeviceFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new WindowsHidDeviceFactory(logger, tracer)); } #endregion } diff --git a/src/Usb.Net.Android/AndroidUsbDeviceFactory.cs b/src/Usb.Net.Android/AndroidUsbDeviceFactory.cs index 0d77b320..0aa317d0 100644 --- a/src/Usb.Net.Android/AndroidUsbDeviceFactory.cs +++ b/src/Usb.Net.Android/AndroidUsbDeviceFactory.cs @@ -16,8 +16,8 @@ public class AndroidUsbDeviceFactory : IDeviceFactory #region Public Properties public UsbManager UsbManager { get; } public Context Context { get; } - public ILogger Logger { get; set; } - public ITracer Tracer { get; set; } + public ILogger Logger { get; } + public ITracer Tracer { get; } public ushort? ReadBufferSize { get; set; } public ushort? WriteBufferSize { get; set; } #endregion @@ -27,10 +27,12 @@ public class AndroidUsbDeviceFactory : IDeviceFactory #endregion #region Constructor - public AndroidUsbDeviceFactory(UsbManager usbManager, Context context) + public AndroidUsbDeviceFactory(UsbManager usbManager, Context context, ILogger logger, ITracer tracer) { UsbManager = usbManager; Context = context; + Logger = logger; + Tracer = tracer; } #endregion @@ -77,14 +79,12 @@ public static ConnectedDeviceDefinition GetAndroidDeviceDefinition(UsbDevice usb }; } - public static void Register(UsbManager usbManager, Context context) + /// + /// Register the factory for enumerating USB devices on Android. + /// + public static void Register(UsbManager usbManager, Context context, ILogger logger, ITracer tracer) { - Register(usbManager, context, null); - } - - public static void Register(UsbManager usbManager, Context context, ILogger logger) - { - DeviceManager.Current.DeviceFactories.Add(new AndroidUsbDeviceFactory(usbManager, context) { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new AndroidUsbDeviceFactory(usbManager, context, logger, tracer)); } #endregion } diff --git a/src/Usb.Net.AndroidSample/MainActivity.cs b/src/Usb.Net.AndroidSample/MainActivity.cs index 73a4379c..50b52cb2 100644 --- a/src/Usb.Net.AndroidSample/MainActivity.cs +++ b/src/Usb.Net.AndroidSample/MainActivity.cs @@ -1,5 +1,4 @@ using Android.App; -using Android.Content; using Android.Hardware.Usb; using Android.OS; using Android.Support.Design.Widget; @@ -8,7 +7,6 @@ using Android.Views; using Device.Net; using System; -using Usb.Net.Android; using Usb.Net.Sample; namespace Usb.Net.AndroidSample @@ -69,7 +67,7 @@ private void FabOnClick(object sender, EventArgs eventArgs) if (usbManager == null) throw new Exception("UsbManager is null"); //Register the factory for creating Usb devices. This only needs to be done once. - AndroidUsbDeviceFactory.Register(usbManager, base.ApplicationContext); + AndroidUsbDeviceFactory.Register(usbManager, base.ApplicationContext, new DebugLogger(), new DebugTracer()); _TrezorExample.TrezorDisconnected += _TrezorExample_TrezorDisconnected; _TrezorExample.TrezorInitialized += _TrezorExample_TrezorInitialized; @@ -82,7 +80,7 @@ private void FabOnClick(object sender, EventArgs eventArgs) DisplayMessage("Waiting for device..."); } - catch(Exception ex) + catch (Exception ex) { DisplayMessage("Failed to start listener..." + ex.Message); } diff --git a/src/Usb.Net.UWP.Sample/MainPage.xaml.cs b/src/Usb.Net.UWP.Sample/MainPage.xaml.cs index d9d84b57..cc90b862 100644 --- a/src/Usb.Net.UWP.Sample/MainPage.xaml.cs +++ b/src/Usb.Net.UWP.Sample/MainPage.xaml.cs @@ -29,12 +29,13 @@ public MainPage() _DeviceConnectionExample.TrezorDisconnected += _DeviceConnectionExample_TrezorDisconnected; var logger = new DebugLogger(); + var tracer = new DebugTracer(); //Register the factory for creating Usb devices. This only needs to be done once. - UWPUsbDeviceFactory.Register(logger); + UWPUsbDeviceFactory.Register(logger, tracer); //Register the factory for creating Usb devices. This only needs to be done once. - UWPHidDeviceFactory.Register(logger); + UWPHidDeviceFactory.Register(logger, tracer); } #endregion diff --git a/src/Usb.Net.UWP/UWPUsbDevice.cs b/src/Usb.Net.UWP/UWPUsbDevice.cs index d30766db..0e2d1517 100644 --- a/src/Usb.Net.UWP/UWPUsbDevice.cs +++ b/src/Usb.Net.UWP/UWPUsbDevice.cs @@ -1,6 +1,7 @@ using Device.Net; using Device.Net.UWP; using System; +using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; @@ -26,11 +27,15 @@ public class UWPUsbDevice : UWPDeviceBase #endregion #region Constructors - public UWPUsbDevice() : base() + public UWPUsbDevice(ILogger logger, ITracer tracer) : this(null, logger, tracer) { } - public UWPUsbDevice(ConnectedDeviceDefinition deviceDefinition) : base(deviceDefinition.DeviceId) + public UWPUsbDevice(ConnectedDeviceDefinition deviceDefinition) : this(deviceDefinition, null, null) + { + } + + public UWPUsbDevice(ConnectedDeviceDefinition deviceDefinition, ILogger logger, ITracer tracer) : base(deviceDefinition.DeviceId, logger, tracer) { ConnectedDeviceDefinition = deviceDefinition; } @@ -102,12 +107,21 @@ private void InterruptPipe_DataReceived(UsbInterruptInPipe sender, UsbInterruptI #region Public Methods public override async Task WriteAsync(byte[] data) { - if (_DefaultOutPipe == null) throw new Exception("The device has not been initialized."); + if (_DefaultOutPipe == null) throw new Exception(Messages.ErrorMessageNotInitialized); if (data.Length > WriteBufferSize) throw new Exception("The buffer size is too large"); - await _DefaultOutPipe.OutputStream.WriteAsync(data.AsBuffer()); + var count = await _DefaultOutPipe.OutputStream.WriteAsync(data.AsBuffer()); - Tracer?.Trace(false, data); + if (count == data.Length) + { + Tracer?.Trace(true, data); + } + else + { + var message = Messages.GetErrorMessageInvalidWriteLength(data.Length, count); + Logger?.Log(message, GetType().Name, null, LogLevel.Error); + throw new IOException(message); + } } #endregion } diff --git a/src/Usb.Net.UWP/UWPUsbDeviceFactory.cs b/src/Usb.Net.UWP/UWPUsbDeviceFactory.cs index 1e3fcd17..a0bfdad3 100644 --- a/src/Usb.Net.UWP/UWPUsbDeviceFactory.cs +++ b/src/Usb.Net.UWP/UWPUsbDeviceFactory.cs @@ -22,33 +22,36 @@ protected override string GetAqsFilter(uint? vendorId, uint? productId) } #endregion - #region Public Methods - public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) + #region Constructur + public UWPUsbDeviceFactory(ILogger logger, ITracer tracer) : base(logger, tracer) { - if (deviceDefinition.DeviceType == DeviceType.Hid) return null; - return new UWPUsbDevice(deviceDefinition) { Logger = Logger }; } #endregion - #region Public Static Methods - public static void Register() + #region Public Methods + public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { - Register(null); + return deviceDefinition.DeviceType == DeviceType.Hid ? null : new UWPUsbDevice(deviceDefinition, Logger, Tracer); } + #endregion - public static void Register(ILogger logger) + #region Public Static Methods + /// + /// Register the factory for enumerating USB devices on UWP. + /// + public static void Register(ILogger logger, ITracer tracer) { foreach (var deviceFactory in DeviceManager.Current.DeviceFactories) { if (deviceFactory is UWPUsbDeviceFactory) return; } - DeviceManager.Current.DeviceFactories.Add(new UWPUsbDeviceFactory() { Logger = logger }); + DeviceManager.Current.DeviceFactories.Add(new UWPUsbDeviceFactory(logger, tracer)); } #endregion #region Public Overrides - public override Task TestConnection(string Id) => Task.FromResult(new ConnectionInfo {CanConnect=true }); + public override Task TestConnection(string Id) => Task.FromResult(new ConnectionInfo { CanConnect = true }); #endregion } } diff --git a/src/Usb.Net.WindowsSample/Program.cs b/src/Usb.Net.WindowsSample/Program.cs index 64b1ed3d..ed45c4e9 100644 --- a/src/Usb.Net.WindowsSample/Program.cs +++ b/src/Usb.Net.WindowsSample/Program.cs @@ -17,7 +17,11 @@ internal class Program { #region Fields private static TrezorExample _DeviceConnectionExample = new TrezorExample(); + /// + /// TODO: Test these! + /// private static DebugLogger Logger = new DebugLogger(); + private static DebugTracer Tracer = new DebugTracer(); #endregion #region Main @@ -25,10 +29,10 @@ private static void Main(string[] args) { //Register the factory for creating Usb devices. This only needs to be done once. #if (LIBUSB) - LibUsbUsbDeviceFactory.Register(Logger); + LibUsbUsbDeviceFactory.Register(Logger, Tracer); #else - WindowsUsbDeviceFactory.Register(Logger); - WindowsHidDeviceFactory.Register(Logger); + WindowsUsbDeviceFactory.Register(Logger, Tracer); + WindowsHidDeviceFactory.Register(Logger, Tracer); #endif _DeviceConnectionExample.TrezorInitialized += _DeviceConnectionExample_TrezorInitialized; diff --git a/src/Usb.Net/Windows/WindowsUsbDeviceFactory.cs b/src/Usb.Net/Windows/WindowsUsbDeviceFactory.cs index e3b3fe52..c4e22296 100644 --- a/src/Usb.Net/Windows/WindowsUsbDeviceFactory.cs +++ b/src/Usb.Net/Windows/WindowsUsbDeviceFactory.cs @@ -23,6 +23,12 @@ public class WindowsUsbDeviceFactory : WindowsDeviceFactoryBase, IDeviceFactory protected override Guid GetClassGuid() => WindowsDeviceConstants.WinUSBGuid; #endregion + #region Constructor + public WindowsUsbDeviceFactory(ILogger logger, ITracer tracer) : base(logger, tracer) + { + } + #endregion + #region Public Methods public IDevice GetDevice(ConnectedDeviceDefinition deviceDefinition) { @@ -38,9 +44,12 @@ protected override ConnectedDeviceDefinition GetDeviceDefinition(string deviceId #endregion #region Public Static Methods - public static void Register() + /// + /// Register the factory for enumerating USB devices in Windows. + /// + public static void Register(ILogger logger, ITracer tracer) { - Register(null); + DeviceManager.Current.DeviceFactories.Add(new WindowsUsbDeviceFactory(logger, tracer)); } public static void Register(ILogger logger)