How to get device path using libusb in Linux - c#

I was looking for a cross platform way of getting usb arrival and removal events in C# and i found "LibUsbDotNet C# USB Library" (http://sourceforge.net/projects/libusbdotnet/?source=navbar).
It works as it should but in Linux it seems that i can't get device mount point (path). In Linux it uses "libusb" library which does not have a method for getting the device path.
Here is a simple code sample that detects the device events:
internal class DeviceNotification
{
public static IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private static void Main(string[] args)
{
// Hook the device notifier event
UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent;
// Exit on and key pressed.
Console.Clear();
Console.WriteLine();
Console.WriteLine("Waiting for system level device events..");
Console.Write("[Press any key to exit]");
while (!Console.KeyAvailable)
Application.DoEvents();
UsbDeviceNotifier.Enabled = false; // Disable the device notifier
// Unhook the device notifier event
UsbDeviceNotifier.OnDeviceNotify -= OnDeviceNotifyEvent;
}
private static void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
// A Device system-level event has occured
Console.SetCursorPosition(0,Console.CursorTop);
Console.WriteLine(e.ToString()); // Dump the event info to output.
Console.WriteLine();
Console.Write("[Press any key to exit]");
}
}
and here is a sample of the output:
[DeviceType:DeviceInterface] [EventType:DeviceArrival] Name:usbdev1.17
BusNumber:1 DeviceAddress:17 Length:18 DescriptorType:Device
BcdUsb:0x0200 Class:PerInterface SubClass:0x00 Protocol:0x00
MaxPacketSize0:64 VendorID:0x059F ProductID:0x1014 BcdDevice:0x0000
ManufacturerStringIndex:1 ProductStringIndex:2 SerialStringIndex:3
ConfigurationCount:1
[Press any key to exit][DeviceType:DeviceInterface]
[EventType:DeviceRemoveComplete] Name:usbdev1.17 BusNumber:1
DeviceAddress:17 Length:18 DescriptorType:Device BcdUsb:0x0200
Class:PerInterface SubClass:0x00 Protocol:0x00 MaxPacketSize0:64
VendorID:0x059F ProductID:0x1014 BcdDevice:0x0000
ManufacturerStringIndex:1 ProductStringIndex:2 SerialStringIndex:3
ConfigurationCount:1
My question is how can I get the path of the device attached or removed, or how can I bind the info returned by libusb with an actual device path?

You need to use UDev instead of libusb. Libusb merely tells you about what USB devices are on the system, but won't tell you anything about where they're mounted. UDev handles mounting them.
There is libudev and the documentation should be here: http://www.freedesktop.org/software/systemd/libudev/ but it appears to be down at the moment. Here's a tutorial on libudev: Tutorial: How to use libudev and SysFS in Linux
There is also a GLib based wrapper for libudev, docs here: http://ftp.osuosl.org/pub/linux/utils/kernel/hotplug/gudev/ and there appears to be a c# wrapper for libgudev.
But finally you may find using GLib's GIO easier than getting down to the udev level: Volumes and Drives API reference.

USB device files are usually stored in the path:
/dev/bus/usb
In that folder will be sub-directories that should match with your bus numbers above. Things will get complicated if the USB device isn't directly attached to the computer, for instance through a hub or other external device. Don't forget to convert from hex.

Related

Pairing Bluetooth device with InTheHand 32Feet shows as paired, but can't connect

I'm facing a very strange three-way headache. I'm using Unity Engine and a BrainLink Bluetooth device as a source of input. I connect to the BrainLink device automatically via code using a library called Neurosky.ThinkGear and so far these two work fine together, but that's assuming the device has been paired manually via Bluetooth & Other Devices window.
Now I've been asked to also PAIR the device automatically, and this is where I hit a snag. Because using Unity Engine I can't use the windows runtime stuff (like Windows.Enumeration.Devices), I've decided to use the InTheHand 32Feet solution for Bluetooth devices and it seems to kind of work. The device appears as listed in Bluetooth & Other Devices if it wasn't already and it's listed as Paired as well. The problem is that when paired via code and not manually, the library that handles connecting to the device (aforementioned Neurosky.ThinkGear) can't connect to the device. It only connects if the device is removed and paired again via Bluetooth & Oher Devices window.
The Code I'm currently testing is as follows:
private void Start()
{
Debug.Log("Operation Start");
//btClient is a class field
btClient = new BluetoothClient();
//Search for existing paired devices that contain "brainlink" in their name
BluetoothDeviceInfo btDevice = CheckExistingPairedDevices();
if (btDevice == null)
{
Debug.Log("No paired device found, trying to discover");
//Try to discover devices in range with "brainlink" in their name
btDevice = TryDiscoverDevice();
}
if(btDevice!= null)
{
Debug.Log("Found Device " + btDevice.DeviceName+", checking for pairing");
bool paired = AttemptPair(btDevice);
Debug.Log("Pair Status: " + paired);
}
else
{
Debug.Log("Could not discover device");
}
CloseClient();
}
This is the method that handles pairing. At the moment, I never pass a value to pin but it's there just in case I need to support other devices in the future.
private bool AttemptPair(BluetoothDeviceInfo btDevice, string pin = null)
{
//Check if this device has been paired before
if (btDevice.Authenticated)
return true;
bool result = BluetoothSecurity.PairRequest(btDevice.DeviceAddress, pin);
btDevice.Refresh();
return result;
}
I have zero knowledge about your devices/tools, but what I know is that to establish a Bluetooth connection, we need to discover devices first.
The reason is that such a discovery creates an object that is later used on Bluetooth actions (e.g., pairing, connecting).
The device appears as listed in Bluetooth & Other Devices if it wasn't
already and it's listed as Paired as well.
I think by this, what you mean is previously paired devices. The device appearing on the list might not mean that the device is currently discovered. I suggest change your code accordingly where you perform discovery first.

Can't receive data from c# hidlibrary and QR-Code Scanner

I have a QR-Code Scanner Device which is connected via USB with my Computer. The device itself is set to the HID Keyboard Interface. I tried to detect a new QR-Code with the hidlibrary, but unfortunately I can't get it to work. I am using WPF, C# and .NET Core. I tried something like this:
devices = HidDevices.Enumerate(0x05E0, 0x1200).ToList();
SelectedDevice = devices.FirstOrDefault();
SelectedDevice.OpenDevice();
SelectedDevice.Inserted += SelectedDevice_Inserted;
SelectedDevice.Removed += SelectedDevice_Removed;
SelectedDevice.ReadReport(OnReport);
private void OnReport(HidReport report)
{
if (!SelectedDevice.IsConnected) return;
var byteFromDevice = report.Data;
SelectedDevice.ReadReport(OnReport);
}
private void SelectedDevice_Removed()
{
logger.Info("Scanner device removed!");
}
private void SelectedDevice_Inserted()
{
logger.Info("Scanner device attached");
SelectedDevice.ReadReport(OnReport);
}
I am pretty sure that the VendorID(0x05E0) and the ProductID(0x1200) are correct. For safety I'll attach a screenshot of the device settings from windows. When I try to run this code I get this error message: Operation is not supported on this platform.
I searched a lot on google on how to get the scanned data from a QR-Code Scanner but can't find anything working. This hidlibrary was my last chance but somehow it does not work.
I saw things like getting the KeyDownEvent from the QR-Code Scanner, but the problem is, that the code where I receive the events is not in a Form or Window. Therefore I can't receive these events.
Change your device to "USB Serial" and then use SerialPort Class
See this post for how to read the data.

Why DeviceInformation.Name does not display correct name

I am developing custom HID device. I can see the name in device manager (MyCustomDevice). However when I find the device using DeviceWatcher, the DeviceInformation.Name property has value Unknown USB Device (Port Reset Failed). Other applications using WIN32 apis can get correct name of device without problem.
My code:
// Selector for enabled HID devices
string selector = "System.Devices.InterfaceClassGuid:=\"{4D1E55B2-F16F-11CF-88CB-001111000030}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True";
_watcher = DeviceInformation.CreateWatcher(selector, properties);
_watcher.Added += (s, deviceInformation) => {
Console.WriteLine(deviceInformation.Name); // prints "Unknown USB Device (Port Reset Failed)"
};
Device functions correctly, I can communicate with it - the only problem is this Name. Is there possibility to fix it other than going back to WIN32?
To clarify things:
The device uses standard hidusb.sys driver, and there are no yellow exclamation marks in device manager.

SerialPort.GetPortNames() creates System.StackOverflowException

I've made a Bootloader implementation in a SAMD21J18A mcu, based on a
Atmel example. I can connect to the bootloader via USB CDC and it is recognized in windows as a COM port with the name: AT91 USB to Serial Converter, not showing any problems.
The COM-port works fine, I've made a working Windows Form C# program to download code to the bootloader. In the working program I've just manually set the PortName.
Now, I want to make the program more user friendly and want to make a ComboBoxto enable the user to pick the COM-port to use. Therefore I'm calling the GetPortNames function:
string[] Ports = null;
Ports = SerialPort.GetPortNames();
This works fine, as long as I don't plugin my bootloader.
If I attach eg. a FTDI device, it detects the device and adds it to the list, but if I attach the Bootloader("AT91 USB to Serial Converter"), then I get a System.StackOverflowException on the SerialPort.GetPortNames() function.
Does anyone know what is wrong with GetPortNames or the USB CDC driver?
Thanks for your help mjwills :-)
The complete program were too large to show here, so I decided to make a short program showing the problem. However, the new short program didn't have this problem. So, found out the problem didn't directly originate from the line refered to by visual studio.
Anyway, here's the function which created the problem:
// Update comport pull-down list:
private void UpdateComPortList()
{
string[] Ports = null;
Ports = SerialPort.GetPortNames();
int index = -1;
string ComPortName = null;
comboBoxComPort.Items.Clear();
do
{
index += 1;
comboBoxComPort.Items.Add(Ports[index]);
//if(Properties.Settings.Default.comPort == Ports[index]) comboBoxComPort.SelectedIndex = index;
}
while (!((Ports[index] == ComPortName) || (index == Ports.GetUpperBound(0))));
comboBoxComPort.Items.Add("update list...");
}
If I remove the line which I've now commented, the program works.
I think the problem is that, I try to select an item while at the same time adding items...

LibUsbDotNet No devices found when calling UsbDevice.AllDevices

I am executing the example code of LibUsbDotNet which will return me the information of all connected usb devices. You can find this code below.
using System;
using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
using System.Collections.ObjectModel;
namespace Examples
{
internal class ShowInfo
{
public static UsbDevice MyUsbDevice;
public static void Main(string[] args)
{
// Dump all devices and descriptor information to console output.
UsbRegDeviceList allDevices = UsbDevice.AllDevices;
foreach (UsbRegistry usbRegistry in allDevices)
{
if (usbRegistry.Open(out MyUsbDevice))
{
Console.WriteLine(MyUsbDevice.Info.ToString());
for (int iConfig = 0; iConfig < MyUsbDevice.Configs.Count; iConfig++)
{
UsbConfigInfo configInfo = MyUsbDevice.Configs[iConfig];
Console.WriteLine(configInfo.ToString());
ReadOnlyCollection<UsbInterfaceInfo> interfaceList = configInfo.InterfaceInfoList;
for (int iInterface = 0; iInterface < interfaceList.Count; iInterface++)
{
UsbInterfaceInfo interfaceInfo = interfaceList[iInterface];
Console.WriteLine(interfaceInfo.ToString());
ReadOnlyCollection<UsbEndpointInfo> endpointList = interfaceInfo.EndpointInfoList;
for (int iEndpoint = 0; iEndpoint < endpointList.Count; iEndpoint++)
{
Console.WriteLine(endpointList[iEndpoint].ToString());
}
}
}
}
}
// Free usb resources.
// This is necessary for libusb-1.0 and Linux compatibility.
UsbDevice.Exit();
// Wait for user input..
Console.ReadKey();
}
}
}
My problem is that the second line executed in the code:
UsbRegDeviceList allDevices = UsbDevice.AllDevices;
does not not return any device at all, while I do have the device I want to find connected, my keyboard and mouse.
Has anyone encountered this problem before? And/or does anyone know how to solve it?
Thanks in Advance!
Milan van Dijck
Does libusb support HID devices?
On Windows, the native Windows HID driver is supported by libusb, but there are some limitations, such as not being able to access HID mice and keyboards, as they are system reserved, as well as getting a direct read of HID report descriptors. Apart from that, you should be communicate with an HID device as you would with any other USB device.
If your application will revolve around HID access, you are encouraged to try to use the ​HIDAPI library by Signal 11 Software, which is also cross-platform. It uses native HID API under Windows and Mac OS X and can use libusb or hidraw as the backend under Linux.
The documentation says that
Gets a list of all available USB devices (WinUsb, LibUsb, Linux LibUsb v1.x).
and
Use this property to get a list of USB device that can be accessed by LibUsbDotNet.
If you are using the standard HID driver for your mouse and keyboard and haven't replaced that with the libusb.sys driver, then LibUsbDotNet can't access those devices and therefore doesn't list them.

Categories