Skip to content

Commit

Permalink
Merge branch 'develop' into #9-AndroidRefactor
Browse files Browse the repository at this point in the history
  • Loading branch information
MelbourneDeveloper committed Dec 31, 2018
2 parents 6dd961a + 1ee698e commit 8597992
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 62 deletions.
47 changes: 18 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

This library provides a common Task based Async interface across platforms and device types. This allows for dependency injection so that different types of devices can be used on any platform with the same code. The supported device types are Hid, and USB. Other device types such as Bluetooth and so on may be added in future. Hid.Net is specifically for Hid devices that may be Usb devices. Usb.Net is specifically for Usb devices that don't have a Hid interface.

Please visit the [documentation page](https://github.com/MelbourneDeveloper/Device.Net/wiki).

### Currently supports:

| Platform | Device Types |
Expand All @@ -16,12 +18,11 @@ This library provides a common Task based Async interface across platforms and d
| UWP | Hid, USB |
| Linux* | USB (Via LibUsbDotNet) |

*See the Trezor repo for the LibUsbDotNet example

## Quick Start
*See [Linux and MacOS Support](https://github.com/MelbourneDeveloper/Device.Net/wiki/Linux-and-MacOS-Support)

Please download one of the samples in 'Samples & Unit Tests', or add the NuGet packages you need to a fresh project. This is UWP code. The only difference for Windows is that you would call WindowsHidDeviceFactory.Register().
## [Quick Start](https://github.com/MelbourneDeveloper/Device.Net/wiki/Quick-Start)

Example Code:
```cs
private static async Task InitializeTrezor()
{
Expand Down Expand Up @@ -69,39 +70,17 @@ Ethereum: 0x7ba0ea9975ac0efb5319886a287dcf5eecd3038e

Litecoin: MVAbLaNPq7meGXvZMU4TwypUsDEuU6stpY

## Samples & Unit Tests

This repos have implementations of Hid.Net and Usb.Net. These should help you to understand how the libraries can be used to connect to various devices. The libraries are for cryptocurrency hardwarewallets

[Trezor.Net](https://github.com/MelbourneDeveloper/Trezor.Net) (UWP, Android, Console - .NET Framework)

[Ledger.Net](https://github.com/MelbourneDeveloper/Ledger.Net) (UWP, Console - .NET Core)

[Ledger .NET API](https://github.com/LedgerHQ/ledger-dotnet-api) (Console - .NET Core)

[KeepKey.Net](https://github.com/MelbourneDeveloper/KeepKey.Net) (UWP, .NET Framework)
## [Samples & Unit Tests](https://github.com/MelbourneDeveloper/Device.Net/wiki/Samples-and-Unit-Tests)

## Store App Production Usage

**Hardfolio** - Cryptocurrency portfolio app for hardwarewallets
**Hardfolio** - Cryptocurrency portfolio app for hardwarewallets. Hid.Net started its life as a project inside the Hardfolio app codebase. The original aim of this app was to support multiple hardwarewallets across multiple platforms. It turned out that Hid.Net and Usb.Net were warranted as libraries in their own right because there really is not other library on the internet that supports all the platforms that were needed for Hardfolio.

[Google Play](https://play.google.com/store/apps/details?id=com.Hardfolio)

[Windows Store](https://www.microsoft.com/en-au/p/hardfolio/9p8xx70n5d2j)

## NuGet

For Hid Devices:

**Install-Package Hid.Net**

For Usb Devices:

**Install-Package Usb.Net**

Device.Net only provides the base interface. This would allow you to create a provider for a new device type like Bluetooth for example.

**Install-Package Device.Net**
## [NuGet](https://github.com/MelbourneDeveloper/Device.Net/wiki/NuGet)

## Contact

Expand All @@ -118,3 +97,13 @@ I welcome feedback, and pull requests. If there's something that you need to cha
### Pull Requests

Please break pull requests up in to their smallest possible parts. If you have a small feature of refactor that other code depends on, try submitting that first. Please try to reference an issue so that I understand the context of the pull request. If there is no issue, I don't know what the code is about. If you need help, please jump on Slack here: https://hardwarewallets.slack.com

### See Also

[Human Interface Device Wikipedia Page](https://en.wikipedia.org/wiki/Human_interface_device) - Good for understanding the difference between the meaning of the two terms: USB and Hid.

[USB human interface device class Wikipedia Page](https://en.wikipedia.org/wiki/USB_human_interface_device_class) - as above

[USB Wikipedia Page](https://en.wikipedia.org/wiki/USB) - as above

Jax Axelson's [USB Page](http://janaxelson.com/usb.htm) - General C# USB Programming
2 changes: 1 addition & 1 deletion src/Device.Net/DeviceDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class DeviceDefinition
/// <summary>
/// The name of the device product according to the Manufacturer
/// </summary>
public string Product { get; set; }
public string ProductName { get; set; }

/// <summary>
/// Name of the device's manufacturer
Expand Down
6 changes: 3 additions & 3 deletions src/Device.Net/Windows/WindowsDeviceDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace Device.Net.Windows
{
public class WindowsDeviceDefinition : DeviceDefinition
{
public ushort Usage { get; set; }
public ushort UsagePage { get; set; }
public ushort VersionNumber { get; set; }
public ushort? Usage { get; set; }
public ushort? UsagePage { get; set; }
public ushort? VersionNumber { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Hid.Net/Windows/WindowsHidDeviceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static WindowsDeviceDefinition GetDeviceDefinition(string deviceId, SafeF
WriteBufferSize = hidCollectionCapabilities.OutputReportByteLength,
ReadBufferSize = hidCollectionCapabilities.InputReportByteLength,
Manufacturer = manufacturer,
Product = product,
ProductName = product,
ProductId = (ushort)hidAttributes.ProductId,
SerialNumber = serialNumber,
Usage = hidCollectionCapabilities.Usage,
Expand Down
20 changes: 19 additions & 1 deletion src/Usb.Net/Windows/WinUsbApiCalls.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using Microsoft.Win32.SafeHandles;
using Device.Net.Windows;
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Usb.Net.Windows
{
public static partial class WinUsbApiCalls
{
#region Constants
public const int EnglishLanguageID = 1033;
public const uint DEVICE_SPEED = 1;
public const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
public const int WritePipeId = 0x80;
Expand All @@ -15,7 +19,9 @@ public static partial class WinUsbApiCalls
/// </summary>
public const int DEFAULT_DESCRIPTOR_TYPE = 0x01;
public const int USB_STRING_DESCRIPTOR_TYPE = 0x03;
#endregion

#region API Calls
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, byte[] Buffer, uint BufferLength, ref uint LengthTransferred, IntPtr Overlapped);

Expand Down Expand Up @@ -51,5 +57,17 @@ public static partial class WinUsbApiCalls

[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_WritePipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
#endregion

#region Public Methods
public static string GetDescriptor(SafeFileHandle defaultInterfaceHandle, byte index, string errorMessage)
{
var buffer = new byte[256];
var isSuccess = WinUsb_GetDescriptor(defaultInterfaceHandle, USB_STRING_DESCRIPTOR_TYPE, index, EnglishLanguageID, buffer, (uint)buffer.Length, out var transfered);
WindowsDeviceBase.HandleError(isSuccess, errorMessage);
var descriptor = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
return descriptor.Substring(0, descriptor.Length - 1);
}
#endregion
}
}
70 changes: 43 additions & 27 deletions src/Usb.Net/Windows/WindowsUsbDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,21 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Usb.Net.Windows
{
public class WindowsUsbDevice : WindowsDeviceBase
{
#region Fields
private const int EnglishLanguageID = 1033;
private SafeFileHandle _DeviceHandle;
private readonly List<UsbInterface> _UsbInterfaces = new List<UsbInterface>();
private UsbInterface _DefaultUsbInterface => _UsbInterfaces.FirstOrDefault();
private USB_DEVICE_DESCRIPTOR _UsbDeviceDescriptor;
#endregion

#region Public Properties
public string Product { get; private set; }
#endregion

#region Public Overrride Properties
public override ushort WriteBufferSize => IsInitialized ? _UsbDeviceDescriptor.bMaxPacketSize0 : throw new Exception("Device has not been initialized");
public override ushort ReadBufferSize => IsInitialized ? _UsbDeviceDescriptor.bMaxPacketSize0 : throw new Exception("Device has not been initialized");
public override ushort WriteBufferSize => IsInitialized ? (ushort)DeviceDefinition.WriteBufferSize : throw new Exception("Device has not been initialized");
public override ushort ReadBufferSize => IsInitialized ? (ushort)DeviceDefinition.ReadBufferSize : throw new Exception("Device has not been initialized");
#endregion

#region Constructor
Expand All @@ -35,8 +28,8 @@ public WindowsUsbDevice(string deviceId) : base(deviceId)
}
#endregion

#region Public Methods
public override Task InitializeAsync()
#region Private Methods
private void Initialize()
{
Dispose();

Expand All @@ -49,6 +42,7 @@ public override Task InitializeAsync()

_DeviceHandle = APICalls.CreateFile(DeviceId, (APICalls.GenericWrite | APICalls.GenericRead), APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);


if (_DeviceHandle.IsInvalid)
{
//TODO: is error code useful here?
Expand All @@ -59,20 +53,7 @@ public override Task InitializeAsync()
var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var defaultInterfaceHandle);
HandleError(isSuccess, "Couldn't initialize device");

var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, EnglishLanguageID, out _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
HandleError(isSuccess, "Couldn't get device descriptor");

if (_UsbDeviceDescriptor.iProduct > 0)
{
//Get the product name
var buffer = new byte[256];
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.USB_STRING_DESCRIPTOR_TYPE, _UsbDeviceDescriptor.iProduct, 1033, buffer, (uint)buffer.Length, out var transfered);
HandleError(isSuccess, "Couldn't get product name");

Product = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
Product = Product.Substring(0, Product.Length - 1);
}
DeviceDefinition = GetDeviceDefinition(defaultInterfaceHandle, DeviceId);

byte i = 0;

Expand Down Expand Up @@ -100,10 +81,14 @@ public override Task InitializeAsync()
}

IsInitialized = true;
}
#endregion

#region Public Methods
public override async Task InitializeAsync()
{
await Task.Run(Initialize);
RaiseConnected();

return Task.CompletedTask;
}

public override async Task<byte[]> ReadAsync()
Expand Down Expand Up @@ -152,6 +137,37 @@ public override void Dispose()
#endregion

#region Private Static Methods
private static WindowsDeviceDefinition GetDeviceDefinition(SafeFileHandle defaultInterfaceHandle, string deviceId)
{
var deviceDefinition = new WindowsDeviceDefinition { DeviceType = DeviceType.Usb, DeviceId = deviceId };

var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
var isSuccess2 = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, WinUsbApiCalls.EnglishLanguageID, out var _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
HandleError(isSuccess2, "Couldn't get device descriptor");

if (_UsbDeviceDescriptor.iProduct > 0)
{
deviceDefinition.ProductName = WinUsbApiCalls.GetDescriptor(defaultInterfaceHandle, _UsbDeviceDescriptor.iProduct, "Couldn't get product name");
}

if (_UsbDeviceDescriptor.iSerialNumber > 0)
{
deviceDefinition.SerialNumber = WinUsbApiCalls.GetDescriptor(defaultInterfaceHandle, _UsbDeviceDescriptor.iSerialNumber, "Couldn't get serial number");
}

if (_UsbDeviceDescriptor.iManufacturer > 0)
{
deviceDefinition.Manufacturer = WinUsbApiCalls.GetDescriptor(defaultInterfaceHandle, _UsbDeviceDescriptor.iManufacturer, "Couldn't get manufacturer");
}

deviceDefinition.VendorId = _UsbDeviceDescriptor.idVendor;
deviceDefinition.ProductId = _UsbDeviceDescriptor.idProduct;
deviceDefinition.WriteBufferSize = _UsbDeviceDescriptor.bMaxPacketSize0;
deviceDefinition.ReadBufferSize = _UsbDeviceDescriptor.bMaxPacketSize0;

return deviceDefinition;
}

private static UsbInterface GetInterface(SafeFileHandle interfaceHandle)
{
var retVal = new UsbInterface { Handle = interfaceHandle };
Expand Down

0 comments on commit 8597992

Please sign in to comment.