BLE advert -- get the device display name - c#

It's pretty straightforward to listen for BLE advertisements and get the BluetoothAddress, signal strength etc from the advert. This page says
Once you have the address, you can call BluetoothLEDevice.FromBluetoothAddressAsync to get a reference to the device.
so I did and this gave me a BluetoothLEDevice object with a Name property. Unfortunately the name is frequently - but not always - an empty string.
When I interactively scan for Bluetooth devices, Windows shows me a list of names for devices it can see (excluding already paired devices). It does this very quickly and it shows a number of devices that don't ever show up in the names accumulated from advertising.
Is there a reliable strategy for quickly obtaining the name normally shown when computers and phones list unpaired devices?
I tried the suggestion from Emil, and while this simplifies my code by eliminating the need to obtain a BluetoothLEDevice object, the fundamental problem remains: advertisements cannot be relied upon to supply a name. They don't even contain meaningful manufacturer data.
The code currently looks like this
BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
...
watcher.Received += OnAdvertisementReceived;
watcher.Start();
...
private void BleAdvertHandlerAsync(BluetoothLEAdvertisementReceivedEventArgs args)
{
var localName = args.Advertisement.LocalName;
...
}
Fishing the local name into a variable sidesteps the fact that resolving the value entails a COM call which is not allowed in a breakpoint expression.
Playing with the switches on my mouse and keyboard, which can be paired with three different hosts and switched between them, I notice that when I tell them to connect to another host I immediately get advertisements containing names. If the host isn't present there is a steady stream of them that ceases when I switch back to my computer and a session is established.
This suggests that advertisements are not the way Windows populates its list of unpaired hosts.

If you use the advertisement watcher you can check the BluetoothLEAdvertisement.LocalName property.
For your second question, maybe your phone is discovered through Bluetooth Classic?

Related

unexplained sporadic repeat execution of code - looking for hypothesis

Please bear with me, this question is not going to be perfectly formed and/or may not have enough data for you to pin-point a cause. I am simply looking for ideas to continue solving this problem. Read as a horror story.
Problem Description
I have a C# program that interacts with an operator through button clicks, TCP/IP with a set of 4 barcode scanners, and some SQL. This is used in an somewhat-automated manufacturing setting. The barcode scanners come with a communications library to trigger barcode reading, as well as aggregate the data from 4 (or more) scanners into a single data stream to a client (my c# program). Each scanner provides the scanner ID as well as the scanned data, for example: 001:111111;004:444444;003:333333;002:222222.... 001, 004, 003 being the scanner's ID, while 111111, 222222, 333333, 444444 being the barcode data at those associated scanners.
I must apologize, you must be wondering why all these details but they come in play.
We run this program about 1000 times a day, mostly successfully. But at about 0.2% of the times, something unexpected happens.
Normal program flow (99.8%):
SQL Connection Open
User button press
Scanner trigger
Scanner returns data
SQL Operations (New code Registered)
Abnormal program flow (0.2%)
SQL Connection Open
User button press
Scanner trigger
Scanner returns incorrect data
SQL Operations
**Program rewinds back to start
SQL Connection Open
User button press bypassed
Scanner trigger bypassed
Scanner returns GOOD data
SQL Operations
Here is a captured sequence of events in log with bold comments:
SQL Connection Open.
K-----e Scanner LF Connect success? True
K-----e Scanner RF Connect success? True
K-----e Scanner LB Connect success? True
K-----e Scanner RB Connect success? True
New code Registered: 785889<=>819345 wrong data
New code Registered: 917890<=>481899 wrong data
New code Registered: 249447<=>999731 wrong data
New code Registered: 967082<=>386511 wrong data
New code Registered: 794079<=>772860 wrong data
New code Registered: 349467<=>421658 wrong data
New code Registered: 810132<=>525941 wrong data
New code Registered: 879309<=>105578 wrong data
SQL Connection Open. Rewind back to start of cycle, all without any user interaction
K-----e Scanner LF Connect success? True
K-----e Scanner RF Connect success? True
K-----e Scanner LB Connect success? True
K-----e Scanner RB Connect success? True
785889 is not unique. Data is good now, DB ops correctly since all scanned data was already inserted into DB
Already Exist 785889
819345 is not unique.
Already Exist 819345
917890 is not unique.
Already Exist 917890
525941 is not unique.
Already Exist 525941
249447 is not unique.
Already Exist 249447
105578 is not unique.
Already Exist 105578
967082 is not unique.
Already Exist 967082
481899 is not unique.
Already Exist 481899
794079 is not unique.
Already Exist 794079
421658 is not unique.
Already Exist 421658
349467 is not unique.
Already Exist 349467
772860 is not unique.
Already Exist 772860
810132 is not unique.
Already Exist 810132
386511 is not unique.
Already Exist 386511
879309 is not unique.
Already Exist 879309
999731 is not unique.
Already Exist 999731
Known Issues
After debugging (which is difficult due to the 0.2% occurrence), the scanner communications library is implicated for the wrong (scrambled) data 001:222222;004:111111;003:222222;002:333333, etc. I am concerned that the data is bad, but I am much more concerned about the program rewind.
Question
What mechanism(s) or conditions could result in repeated code execution, triggered by an external library in C# windows form? How can I detect and trap such events?
Conclusion
My apologies for the long and incomplete description of this problem, I have included the information that I could gather in this question. It is certainly beyond normal to see this happen, and repeatedly. I hope to gather some information from your replies to help me further diagnose or fix this problem.
I have discussed this problem with my local scanner rep, but software libraries are provided as-is. These scanners are $10K each, but this is now a problem that I have to solve.
Here's one idea: The barcode scans are probably event-driven. If the events occur too closely to each other there's no guarantee that one will complete its query before the next event triggers a different query. There's an easy way to make the thread wait for an action to complete using a basic sychronization object in System.Threading.SemaphoreSlim.
public void DoSomeSqlOperations()
{
try
{
_ssEnforceSingleOperation.Wait();
using(var cnx = new SQLite.SQLiteConnection(ConnectionString))
{
// Perform the query
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
finally
{
// Ensure the semaphore releases even if an error occurs.
_ssEnforceSingleOperation.Release();
}
}
SemaphoreSlim _ssEnforceSingleOperation = new SemaphoreSlim(1, 1);
If an operation is already in progress, the new one won't begin until the first one completes and releases the semaphore. My suggestion would be to protect your critical sections in this manner and see it it helps.

C# how to detect which keyboard is pressed? [duplicate]

I have a barcode scanner (which acts like a keyboard) and of course I have a keyboard too hooked up to a computer. The software is accepting input from both the scanner and the keyboard. I need to accept only the scanner's input. The code is written in C#. Is there a way to "disable" input from the keyboard and only accept input from the scanner?
Note:
Keyboard is part of a laptop...so it cannot be unplugged. Also, I tried putting the following code
protected override Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData)
{
return true;
}
But then along with ignoring the keystrokes from the keyboard, the barcode scanner input is also ignored.
I cannot have the scanner send sentinal characters as, the scanner is being used by other applications and adding a sentinal character stream would mean modifying other code.
Also, I cannot use the timing method of determining if the input came from a barcode scanner (if its a bunch of characters followed by a pause) since the barcodes scanned could potentially be single character barcodes.
Yes, I am reading data from a stream.
I am trying to follow along with the article: Distinguishing Barcode Scanners from the Keyboard in WinForms. However I have the following questions:
I get an error NativeMethods is inaccessible due to its protection level. It seems as though I need to import a dll; is this correct? If so, how do I do it?
Which protected override void WndProc(ref Message m) definition should I use, there are two implementations in the article?
Am getting an error related to [SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] error CS0246: The type or namespace name 'SecurityPermission' could not be found (are you missing a using directive or an assembly reference?). How do I resolve this error?
There is also an error on the line containing: if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Error is error CS1026: ) expected.
Should I be placing all the code in the article in one .cs file called BarcodeScannerListener.cs?
Followup questions about C# solution source code posted by Nicholas Piasecki on http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:
I was not able to open the solution in VS 2005, so I downloaded Visual C# 2008 Express Edition, and the code ran. However, after hooking up my barcode scanner and scanning a barcode, the program did not recognize the scan. I put a break point in OnBarcodeScanned method but it never got hit. I did change the App.config with the id of my Barcode scanner obtained using Device Manager. There seems to be 2 deviceNames with HID#Vid_0536&Pid_01c1 (which is obtained from Device Manager when the scanner is hooked up). I don't know if this is causing the scanning not to work. When iterating over the deviceNames, here is the list of devices I found (using the debugger):
"\??\HID#Vid_0536&Pid_01c1&MI_01#9&25ca5370&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
"\??\HID#Vid_0536&Pid_01c1&MI_00#9&38e10b9&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\HID#Vid_413c&Pid_2101&MI_00#8&1966e83d&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\HID#Vid_413c&Pid_3012#7&960fae0&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
"\??\Root#RDP_KBD#0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\ACPI#PNP0303#4&2f94427b&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
"\??\ACPI#PNP0F13#4&2f94427b&0#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
So there are 2 entries for HID#Vid_0536&Pid_01c1; could that be causing the scanning not to work?
OK so it seems that I had to figure out a way to not depend on the ASCII 0x04 character being sent by the scanner...since my scanner does not send that character. After that, the barcode scanned event is fired and the popup with the barcode is shown. So thanks Nicholas for your help.
You could use the Raw Input API to distinguish between the keyboard and the scanner like I did recently. It doesn't matter how many keyboard or keyboard-like devices you have hooked up; you will see a WM_INPUT before the keystroke is mapped to a device-independent virtual key that you typically see in a KeyDown event.
Far easier is to do what others have recommended and configure the scanner to send sentinel characters before and after the barcode. (You usually do this by scanning special barcodes in the back of the scanner's user manual.) Then, your main form's KeyPreview event can watch those roll end and swallow the key events for any child control if it's in the middle of a barcode read. Or, if you wanted to be fancier, you could use a low-level keyboard hook with SetWindowsHookEx() to watch for those sentinels and swallow them there (advantage of this is you could still get the event even if your app didn't have focus).
I couldn't change the sentinel values on our barcode scanners among other things so I had to go the complicated route. Was definitely painful. Keep it simple if you can!
--
Your update, seven years later: If your use case is reading from a USB barcode scanner, Windows 10 has a nice, friendly API for this built-in in Windows.Devices.PointOfService.BarcodeScanner. It's a UWP/WinRT API, but you can use it from a regular desktop app as well; that's what I'm doing now. Here's some example code for it, straight from my app, to give you the gist:
{
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Windows.Devices.Enumeration;
using Windows.Devices.PointOfService;
using Windows.Storage.Streams;
using PosBarcodeScanner = Windows.Devices.PointOfService.BarcodeScanner;
public class BarcodeScanner : IBarcodeScanner, IDisposable
{
private ClaimedBarcodeScanner scanner;
public event EventHandler<BarcodeScannedEventArgs> BarcodeScanned;
~BarcodeScanner()
{
this.Dispose(false);
}
public bool Exists
{
get
{
return this.scanner != null;
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public async Task StartAsync()
{
if (this.scanner == null)
{
var collection = await DeviceInformation.FindAllAsync(PosBarcodeScanner.GetDeviceSelector());
if (collection != null && collection.Count > 0)
{
var identity = collection.First().Id;
var device = await PosBarcodeScanner.FromIdAsync(identity);
if (device != null)
{
this.scanner = await device.ClaimScannerAsync();
if (this.scanner != null)
{
this.scanner.IsDecodeDataEnabled = true;
this.scanner.ReleaseDeviceRequested += WhenScannerReleaseDeviceRequested;
this.scanner.DataReceived += WhenScannerDataReceived;
await this.scanner.EnableAsync();
}
}
}
}
}
private void WhenScannerDataReceived(object sender, BarcodeScannerDataReceivedEventArgs args)
{
var data = args.Report.ScanDataLabel;
using (var reader = DataReader.FromBuffer(data))
{
var text = reader.ReadString(data.Length);
var bsea = new BarcodeScannedEventArgs(text);
this.BarcodeScanned?.Invoke(this, bsea);
}
}
private void WhenScannerReleaseDeviceRequested(object sender, ClaimedBarcodeScanner args)
{
args.RetainDevice();
}
private void Dispose(bool disposing)
{
if (disposing)
{
this.scanner = null;
}
}
}
}
Granted, you'll need a barcode scanner that supports the USB HID POS and isn't just a keyboard wedge. If your scanner is just a keyboard wedge, I recommend picking up something like a used Honeywell 4600G off eBay for like $25. Trust me, your sanity will be worth it.
What I did in a similar situation is distinguish between a scan and a user typing by looking at the speed of the input.
Lots of characters very close together then a pause is a scan. Anything else is keyboard input.
I don't know exactly your requirements, so maybe that won't do for you, but it's the best I've got :)
It depends on the way you are interacting with the device. Anyway it wont be a C# solution, it will be some other library. Are you reading data from a stream? If you are just taking keystrokes, there may be nothing you can do about it.
I know this is an old thread, found it by searching barcode scanning in WIN10.
Just a few notes in case someone needs it.
These scanners from Honeywell have several USB interfaces.
One is a keyboard + Hid Point of sales (composite device).
Also there are CDC-ACM (ComPort emulation) and Hid Point of sales (alone) + more.
By default the scanners expose a serial number, so the host can distinguish between many devices (I had once +20 connected). There is a command to disable the serial number though!
The newer models behave the same in this regard.
If you want to see it live, try my terminal program yat3 (free on my site).
It can open all the interfaces mentioned above and is tailored for such devices.
A word to use keyboard interfaces:
Only use them as a last resort. They are slow, less reliable when it comes to exotic characters. The only good use is if you want to enter data into existing applications. If you code anyway, then reading from ComPort/HidPos-Device is easier.
look at this: http://nate.dynalias.net/dev/keyboardredirector.rails (NOT AVAILABLE ANYMORE) works great!
Specify the keyboard and the keys you want to block, and it works like a charm!
Also take a look at this: http://www.oblita.com/interception.html
You can create a C# wrapper for it - it also works like a charm..
I think you might be able to distinguish multiple keyboards through DirectX API, or if that doesn't work, through raw input API.
I have successfully accomplished what you folks are looking for here. I have an application that receives all barcode character data from a Honeywell/Metrologic barcode scanner. No other application on the system receives the data from the scanner, and the keyboard continues to function normally.
My application uses a combination of raw input and the dreaded low-level keyboard hook system. Contrary to what is written here, I found that the wm_input message is received before the keyboard hook function is called. My code to process the wm_input message basically sets a boolean variable to specify whether or not the received character is from the scanner. The keyboard hook function, called immediately after the wm_input is processed, swallows the scanner’s pseudo-keyboard data, preventing the data from being received by other applications.
The keyboard hook function has to be placed in an dll since you want to intercept all system keyboard messages. Also, a memory mapped file has to be used for the wm_input processing code to communicate with the dll.

Problems with serial device communication in UWP

I have a peculiar problem.
I am trying to communicate with a peripheral unit that requires serial communication in a UWP project. I am using Windows.Devices.SerialCommunication.
For purpose of demonstration, I made a new page that has two buttons, with two different click handlers. One for opening the port, and the other for sending messages to the peripheral.
One handler is:
SerialDevice device;
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
string selector = SerialDevice.GetDeviceSelector("COM7");
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector);
if (devices.Any())
{
DeviceInformation deviceInfo = devices.First();
device = await SerialDevice.FromIdAsync(deviceInfo.Id);
//*********************
device.BaudRate = 9600;
device.DataBits = 8;
device.Parity = SerialParity.None;
device.StopBits = SerialStopBitCount.One;
device.ReadTimeout = device.WriteTimeout = TimeSpan.FromMilliseconds(1000);
device.Handshake = SerialHandshake.None;
}
_dataReader = new DataReader(device.InputStream);
_dataWriter = new DataWriter(device.OutputStream);
}
Peripheral has a red light on it when I enable the power supply. When the line above //********* is executed, the light is switched off. The peripheral doesn't respond to any messages then. When I stop the program, the light switches back on.
I made a .NET Framework app that works perfectly. It is fully functional. I used System.IO.Ports there. I noticed something:
If I extract and run only this part of the code in .NET Framework app:
SerialPort comPort = new SerialPort();
_ComPort.PortName = PortName;
_ComPort.BaudRate = BaudRate;
_ComPort.DataBits = 8;
_ComPort.Parity = Parity.None;
_ComPort.StopBits = StopBits.One;
_ComPort.DataReceived += new SerialDataReceivedEventHandler(_ComPort_DataReceived);
_ComPort.Open();
Nothing more.
And run the UWP app again, the port opens perfectly, the lamp is red, and the device responds to messages. I can switch off the device, and initialize it from the UWP app as many times as I want to. When I restart my computer, I can't initialize the device from the UWP app again, (until I run the said block of code from .NET Framework app).
If you want to know, the peripheral is Bill to Bill unit made by Suzo Happ.
I didn't make any mistakes regarding property initialization in UWP.
I think this is the same issue I'm having.
I repost here a description of the cause and a possible solution:
The UWP SerialDevice class currently only allows you to set "ReadTimeout", which under the hood, sets the "ReadIntervalTimeout" of the actual serial device (https://learn.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_commtimeouts). There are two other timeout values which dramatically affect the read operations behavior: 1) ReadTotalTimeoutMultiplier and 2) ReadTotalTimeoutConstant.
The UWP SerialDevice class does not allow the user to set these two other read timeout values, and even worse, the UWP SerialDevice class does not set these two other timeout values to known values when the serial device is opened. This means that the two other timeout values will be whatever default value the serial driver uses, or worse still, whatever value some serial port application happened to set these two values to be when the other application was last executed.
The overall effect of this is that your UWP application's serial device read behavior is undefined and cannot reliably be used. For example, if these two other timeout values happen to be set one way, then a read operation may block forever waiting on the first byte of data to be read, but if the other timeout values happen to be set a different way, then the read operation may return immediately, with no data read at all. Currently, a UWP application cannot control this behavior, and the behavior will be different across different serial ports, and even perhaps different every time the UWP application is executed.
The UWP SerialDevice class either needs to
1)Allow the user to set these two other read timeout values (preferred), OR
2)Initialize these two other timeout values to known values when the serial device is opened.

BluetoothAdapter ActionDiscoveryFinished

I just started to take a look at xamarin and now I want to scan for bluetooth-devices. Therefor I use the following code:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.DefaultAdapter;
bluetoothAdapter.StartDiscovery();
And I have the following class for getting the result:
[BroadcastReceiver]
[IntentFilter(new [] {BluetoothAdapter.ActionDiscoveryFinished})]
public class BluetoothReceiver : BroadcastReceiver
{
public BluetoothReceiver()
{
}
public override void OnReceive(Context context, Intent intent)
{
if (BluetoothAdapter.ActionDiscoveryFinished.Equals(intent.Action))
{
}
}
}
I've also set the permissions for my app to BLUETOOTH and BLUETOOTH_ADMIN. Everything just works fine and the OnReceive-Method is called correctly. My problem now is: How do I get the found devices from the parameters of the OnReceive-Method?
ACTION_DISCOVERY_FINISHED doesn't tell you anything other than the discovery action has finished. https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#ACTION_DISCOVERY_FINISHED
If you wanted to grab devices from the scan, you should read what startDiscovery() has to say regarding finding devices:
The discovery process usually involves an inquiry scan of about 12 seconds, followed by a page scan of each new device to retrieve its Bluetooth name.
This is an asynchronous call, it will return immediately. Register for ACTION_DISCOVERY_STARTED and ACTION_DISCOVERY_FINISHED intents to determine exactly when the discovery starts and completes. Register for ACTION_FOUND to be notified as remote Bluetooth devices are found.
https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
Thus you should use ACTION_FOUND and parse the EXTRA_DEVICE for devices:
Broadcast Action: Remote device discovered.
Sent when a remote device is found during discovery.
Always contains the extra fields EXTRA_DEVICE and EXTRA_CLASS. Can contain the extra fields EXTRA_NAME and/or EXTRA_RSSI if they are available.
https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND
In sequence of events, you would do the following:
ACTION_DISCOVERY_STARTED - Which will start discovery
ACTION_FOUND - Which will find a device
ACTION_DISCOVERY_FINISHED - Which will end discovery
As for beginner, I would recommend looking into cross-platform libraries, e.g. https://github.com/xabre/xamarin-bluetooth-le, https://github.com/aritchie/bluetoothle
This not only abstracts the platform-specific stuff, offers a simple interface to work with, but also give you multi-platform support out of the box.
I understand that this might be not the answer you're looking for, but in the end, this is what the main advantage of Xamarin is about - write once, run anywhere, etc.

How get the serial port name of an Arduino

I'm trying to figure out which serial port belongs to an Arduino.
Since the SerialPort class does not reveal any information about
the underlying hardware, I'm trying to use LibUsbDotNet instead.
Using the following code to get a list of all devices:
UsbDevice.ForceLibUsbWinBack = true;
var devices = UsbDevice.AllDevices;
I can then either iterate over all of them or search for the Arduino specifically:
var deviceFinder = new UsbDeviceFinder(0x2341, 0x8036);
var arduino = devices.Find(deviceFinder);
This actually works and I get an instance of UsbRegistry,
but I'm unable to open the device or determine through which serial port it is exposed.
USBDevice arduinoUsbDevice;
usbRegistry.Open(out arduinoUsbDevice);
Since this doesn't work arduinoUsbDevice remains null.
I then tried using the DeviceNotifier class which raises an event whenever
a device is added or removed from the system:
var notifier = DeviceNotifier.OpenDeviceNotifier();
notifier.OnDeviceNotify += (s, e) =>
{
WriteLine(e.Device?.Name ?? "no device");
WriteLine(e.Device?.IdProduct ?? 0);
WriteLine(e.Device?.IdVendor ?? 0);
WriteLine(e.EventType);
WriteLine(e.Object);
WriteLine(e.Port?.Name ?? "");
};
Now whenever I connect the Arduino to the computer, the event is raised twice.
As if two separate devices are being connected,
but only one of them is ever returned by UsbDevice.AllDevices:
` \\?\USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
32822
9025
DeviceArrival
FullName:USB#VID_2341&PID_8036#7&533912d&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Vid:0x2341
Pid:0x8036
SerialNumber:7&533912d&0&2
ClassGuid:a5dcbf10-6530-11d2-901f-00c04fb951ed
no device
0
0
DeviceArrival
[Port Name:COM5]
COM5
The first time the event is raised for the device we could find before as well.
The second time it is raised with e.Device set to null but
with e.Port set to COM5, which is the information I'm after.
So the problem is I can only get this information when the Arduino is connected
after the software has been started and even then linking the two events is
kind of a guessing game.
Is there any way of getting the information without having to rely
on the events raised by the DeviceNotifier class?
I'm aware I could use System.Management and WMI queries, but
these are not available on Linux and MacOS, which is why I'm using
LibUsbDotNet instead.
The native library I'm using is libusb-1.0

Categories

Resources