Description
This is kind of a follow-up of #1220.
I'm using serialport
v6.0.4 (latest available as of 2018-01-28) on nodejs 8.9. I have a Linux (debian sid) box, and a win32 (Windows 10 v1607 build 14393.2007) box.
The serial port device I'm working with is a nRF52840 preview development kit, loaded with firmware implementing USB CDC ACM for serialport-like communications. It's basically a beefed-up arduino-like board with wireless stuff and its own fully-configurable USB stack.
Summary of Problem
In my case, the serial number of the USB device is set up when compiling the firmware, and is used by the USB stack to populate the iSerial
field of the USB descriptor. This is how the serial number looks over the wire (wireshark screenshot):
And this is how a lsusb -v
looks like in my linux box (relevant part):
Device Descriptor:
idVendor 0x1915 Nordic Semiconductor ASA
idProduct 0x521f
bcdDevice 1.00
iManufacturer 1 Nordic Semiconductor
iProduct 2 nRF52 USB CDC Demo
iSerial 3 bf8f64cd7b5be46c
And this is how node-serialport/bin/list.js -f jsonline
looks like in linux (with extra line breaks for reading pleasure):
{
"manufacturer":"Nordic Semiconductor",
"serialNumber":"bf8f64cd7b5be46c",
"pnpId":"usb-Nordic_Semiconductor_nRF52_USB_CDC_Demo_bf8f64cd7b5be46c-if00",
"vendorId":"1915",
"productId":"521f",
"comName":"/dev/ttyACM0"
}
So in Linux, I get to see the serial number of the USB device as the serial number. This is good. This is expected.
Now I switch to win32.
The output of node-serialport/bin/list.js -f jsonline
in win32 looks like:
{
"comName":"COM5",
"manufacturer":"Microsoft",
"serialNumber":"7&307B223F&1&0000",
"pnpId":"USB\\VID_1915&PID_521F&MI_00\\7&307B223F&1&0000",
"locationId":"0000.0014.0000.005.002.000.000.000.000",
"vendorId":"1915",
"productId":"521F"}
Win32 reports the serial number as 7&307B223F&1&0000
, but it should be bf8f64cd7b5be46c
... so where does that come from?
The answer is in how win32 handles composite USB devices. If I open up win's device manager, it looks like:
If I fire up regedit.exe
to see details of those two devices (under HKEY_LOCAL_MACHINE/System/CurrentControlSet/Enum/USB
, I can see...
Well, that makes sense. One of the devices maps to the USB device as a whole, and the other maps to the CDC ACM interface. And the naming makes sense according to https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/enumeration-of-interfaces-not-grouped-in-collections .
Digging a bit deeper, I can see how the drivers are bound to "devices":
So my guess is that serialport
is interacting with the usbser.sys
kernel driver, fetching information from it - but the right serial number is not available at that level.
The question is: How can serialport
check if a serial port is part of a USB composite device, and if so how can it fetch the parent's serial number?
Steps and Code to Reproduce the Issue
Get a hold of a USB composite device with a CDC ACM interface, play around with it with the windows device manager as shown above :-)
Addendum: It is possible to force win32 to bind the usbser.sys
to the USB device as a whole: run Zadig, show all devices, choose the composite device, replace usbccgp.sys
with usbser.sys
(AKA USB Serial (CDC)
)". In this case, things will look like:
...and serialport
will be able to fetch the right serial number. However, this prevents other interfaces in the device from working (e.g. a device with CDC ACM and mass storage at the same time), and requires manual user intervention with scary messages, so it's just a stopgap measure.