I have been working on an website that uses WebUSB. The WebUSB library works 100% on Linux and Android. Unfortunately on Windows the promise returned by .claimInterface never returns anything, ever. And when I, for interest sake, run the claimInterface again the returned promise returns the error "An operation that changes state is in progress", confirming that the first claimInterface function is still busy.
The problem only occurs when claiming interface 1, claiming interface 0 works, but this interface is of no use to me. The USB device is not standard (descriptor dieplayed below) so it might be something about the device configuration, but it is really hard to tell with the lack of logs.
I did try and look at chrome://device-log?refresh=1 for additional logs, but only the plug events are dislpayed. I also enabled the new USB backend at chrome://flags/#new-usb-backend to no avail. I also tried running chrome with the --enable-loging --v1
, but the only error that seemed relevant is: ERROR:device_event_log_impl.cc(211)] [01:32:33.170] USB: usb_device_handle_win.cc:1020 Failed to read descriptor from node connection: A device attached to the system is not functioning. (0x1F)
.
But this error is logged before I have even connected a device, also discussed here, so I do not even know if it is relevant.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0xXXXX XXX
idProduct 0xXXXX
bcdDevice 1.01
iManufacturer 1 XXX
iProduct 2 XXX
iSerial 3 XXX
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0030
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x40
(Missing must-be-set bit!)
Self Powered
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 1
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 32
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 1
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 32
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status: 0x0001
Self Powered
The driver installation is almost identical to the WinUSB predescribed method.
[Version]
DriverVer=XX/XX/XXXX,X.X.X.X
Signature = "$Windows NT$"
Class = USBDevice
ClassGuid = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider = %ManufacturerName%
CatalogFile = XXX.cat
[ClassInstall32]
AddReg = ClassInstall_AddReg
[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2
[WinUSBDeviceClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-20
[Manufacturer]
%ManufacturerName% = Standard,NTx86,NTamd64
[Standard.NTx86]
%DeviceName% = USB_Install, USB\%VendorID%&%ProductID%
[Standard.NTamd64]
%DeviceName% = USB_Install, USB\%VendorID%&%ProductID%
[USB_Install]
Include=winusb.inf
Needs=WINUSB.NT
[USB_Install.Services]
Include=winusb.inf
Needs=WINUSB.NT.Services
[USB_Install.HW]
AddReg=Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
[Strings]
ManufacturerName = "XXX"
ClassName="Universal Serial Bus devices"
DeviceName = "XXX"
VendorID = "VID_XXX"
ProductID = "PID_XXX"
As well as a React App I used to test the library.
import { useEffect, useState } from 'react';
export default function App() {
const [devices, setDevices] = useState([]);
useEffect(function () {
update()
navigator.usb.addEventListener("connect", update);
navigator.usb.addEventListener("disconnect", update);
}, [])
return (
<div className="App">
<button onClick={refresh}>
<div>Refresh</div>
</button>
<button onClick={connect}>
<div>Connect</div>
</button>
</div>
);
function connect() {
let _device = devices[0]
if (_device) {
_device
.open()
.then(function () {
_device
.selectConfiguration(1)
.then(function () {
console.log("Connecting to interface")
_device
.claimInterface(1)
.then(function () {
console.log("Success");
})
.catch(console.error);
})
.catch(console.error);
})
.catch(console.error);
}
}
function update() {
navigator.usb.getDevices().then(function (_devices) {
setDevices(_devices)
});
}
function refresh() {
navigator.usb
?.requestDevice({
filters: [{ vendorId: 0xXXXX, productId: 0xXXXX }],
})
.then(update)
.catch(console.error);
}
}