Cross-platform Node.js library for USB device communication with both legacy and WebUSB-compatible APIs.
—
Device communication provides methods to open USB devices and perform control transfers for device configuration and data exchange. This includes device initialization, configuration management, and low-level control operations.
Open and close USB devices for communication.
/**
* Open the device for communication
* @param defaultConfig - Whether to automatically configure the device with the default configuration (default: true)
*/
open(defaultConfig?: boolean): void;
/**
* Close the device
* The device must be open to use other methods
*/
close(): void;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
// Open with default configuration
device.open();
console.log('Device opened with default configuration');
// Access interfaces after opening
console.log(`Device has ${device.interfaces?.length || 0} interfaces`);
// Close when done
device.close();
console.log('Device closed');
}
// Open without default configuration (for manual configuration)
if (device) {
device.open(false);
console.log('Device opened without auto-configuration');
// You can now manually set configuration before using interfaces
device.setConfiguration(1, (error) => {
if (!error) {
console.log('Configuration set successfully');
// Now interfaces are available
}
});
device.close();
}Set the device configuration to something other than the default.
/**
* Set the device configuration
* To use this, first call .open(false), then before claiming an interface, call this method
* @param desired - Configuration value to set
* @param callback - Optional callback called when complete
*/
setConfiguration(desired: number, callback?: (error?: LibUSBException) => void): void;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
// Open without default configuration
device.open(false);
// Set specific configuration
device.setConfiguration(2, (error) => {
if (error) {
console.error('Failed to set configuration:', error.message);
return;
}
console.log('Configuration 2 set successfully');
console.log(`Device now has ${device.interfaces?.length || 0} interfaces`);
// Now you can claim interfaces and use endpoints
if (device.interfaces && device.interfaces.length > 0) {
const interface0 = device.interfaces[0];
interface0.claim();
console.log('Interface 0 claimed');
// Use interface...
interface0.release((error) => {
if (!error) console.log('Interface released');
device.close();
});
}
});
}Perform control transfers for device configuration and vendor-specific commands.
/**
* Perform a control transfer with libusb_control_transfer
* Parameter data_or_length can be an integer length for an IN transfer, or a Buffer for an OUT transfer
* The type must match the direction specified in the MSB of bmRequestType
* @param bmRequestType - Request type (direction, type, recipient)
* @param bRequest - Specific request
* @param wValue - Request-specific value
* @param wIndex - Request-specific index
* @param data_or_length - Buffer for OUT transfer or length for IN transfer
* @param callback - Completion callback
* @returns Device instance for chaining
*/
controlTransfer(
bmRequestType: number,
bRequest: number,
wValue: number,
wIndex: number,
data_or_length: number | Buffer,
callback?: (error?: LibUSBException, buffer?: Buffer | number) => void
): Device;Usage Examples:
import { findByIds, LIBUSB_ENDPOINT_IN, LIBUSB_ENDPOINT_OUT, LIBUSB_REQUEST_TYPE_VENDOR, LIBUSB_RECIPIENT_DEVICE } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
// Vendor-specific IN control transfer
const bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
device.controlTransfer(bmRequestType, 0x01, 0x0000, 0x0000, 64, (error, data) => {
if (error) {
console.error('Control transfer failed:', error.message);
return;
}
console.log('Received data:', data);
if (data instanceof Buffer) {
console.log('Data length:', data.length);
console.log('Data hex:', data.toString('hex'));
}
});
// Vendor-specific OUT control transfer
const outData = Buffer.from([0x01, 0x02, 0x03, 0x04]);
const bmRequestTypeOut = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
device.controlTransfer(bmRequestTypeOut, 0x02, 0x1234, 0x0000, outData, (error, bytesWritten) => {
if (error) {
console.error('Control transfer failed:', error.message);
return;
}
console.log('Bytes written:', bytesWritten);
});
device.close();
}Retrieve string descriptors from the device.
/**
* Perform a control transfer to retrieve a string descriptor
* @param desc_index - String descriptor index
* @param callback - Callback with error and string value
*/
getStringDescriptor(desc_index: number, callback: (error?: LibUSBException, value?: string) => void): void;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
const descriptor = device.deviceDescriptor;
// Get manufacturer string
if (descriptor.iManufacturer > 0) {
device.getStringDescriptor(descriptor.iManufacturer, (error, manufacturer) => {
if (!error && manufacturer) {
console.log('Manufacturer:', manufacturer);
}
});
}
// Get product string
if (descriptor.iProduct > 0) {
device.getStringDescriptor(descriptor.iProduct, (error, product) => {
if (!error && product) {
console.log('Product:', product);
}
});
}
// Get serial number string
if (descriptor.iSerialNumber > 0) {
device.getStringDescriptor(descriptor.iSerialNumber, (error, serial) => {
if (!error && serial) {
console.log('Serial Number:', serial);
}
});
}
device.close();
}Manage automatic kernel driver detachment for device access.
/**
* Enable/disable libusb's automatic kernel driver detachment
* When enabled, libusb will automatically detach the kernel driver on an interface
* when claiming the interface, and attach it when releasing the interface
* @param enable - Whether to enable automatic detachment
*/
setAutoDetachKernelDriver(enable: boolean): void;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
// Enable automatic kernel driver detachment
device.setAutoDetachKernelDriver(true);
console.log('Auto kernel driver detach enabled');
// Now when you claim an interface, the kernel driver will be automatically detached
if (device.interfaces && device.interfaces.length > 0) {
const interface0 = device.interfaces[0];
// This will automatically detach kernel driver if needed
interface0.claim();
console.log('Interface claimed (kernel driver automatically detached if needed)');
// Use interface...
// This will automatically reattach kernel driver
interface0.release((error) => {
if (!error) {
console.log('Interface released (kernel driver automatically reattached)');
}
device.close();
});
}
}
// Disable automatic detachment for manual control
const device2 = findByIds(0x5678, 0x1234);
if (device2) {
device2.open();
device2.setAutoDetachKernelDriver(false);
if (device2.interfaces && device2.interfaces.length > 0) {
const interface0 = device2.interfaces[0];
// Manually check and detach kernel driver if needed
if (interface0.isKernelDriverActive()) {
console.log('Kernel driver is active, detaching...');
interface0.detachKernelDriver();
}
interface0.claim();
// Use interface...
// Manually reattach kernel driver
interface0.release((error) => {
if (!error) {
interface0.attachKernelDriver();
console.log('Kernel driver reattached');
}
device2.close();
});
}
}Reset the USB device.
/**
* Performs a reset of the device. Callback is called when complete.
* The device must be open to use this method.
* @param callback - Completion callback
*/
reset(callback: (error?: LibUSBException) => void): void;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
// Reset the device
device.reset((error) => {
if (error) {
console.error('Device reset failed:', error.message);
return;
}
console.log('Device reset successfully');
// Note: After reset, you may need to re-open the device
// as the device may re-enumerate with new addresses
device.close();
// Wait a moment for re-enumeration
setTimeout(() => {
// Find device again (it may have new bus/address)
const resetDevice = findByIds(0x1234, 0x5678);
if (resetDevice) {
resetDevice.open();
console.log('Device reconnected after reset');
resetDevice.close();
}
}, 1000);
});
}Configure timeout for control transfers.
/**
* Device timeout property
* Timeout in milliseconds to use for control transfers (default: 1000)
*/
timeout: number;Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
// Set custom timeout (5 seconds)
device.timeout = 5000;
console.log(`Device timeout set to ${device.timeout}ms`);
// Control transfers will now use the 5-second timeout
device.controlTransfer(0x80, 0x06, 0x0100, 0x0000, 18, (error, data) => {
if (error) {
console.error('Control transfer timed out or failed:', error.message);
} else {
console.log('Control transfer completed within timeout');
}
});
device.close();
}Retrieve Binary Object Store (BOS) descriptors for USB 2.0.1+ devices.
/**
* Perform a control transfer to retrieve BOS descriptor
* BOS is only supported from USB 2.0.1
* @param callback - Callback with error and BOS descriptor
*/
getBosDescriptor(callback: (error?: LibUSBException, descriptor?: BosDescriptor) => void): void;
/**
* Retrieve array of Capability objects for BOS capabilities
* @param callback - Callback with error and capabilities array
*/
getCapabilities(callback: (error?: LibUSBException, capabilities?: Capability[]) => void): void;
/**
* Binary Object Store (BOS) Descriptor
*/
interface BosDescriptor {
/** Size of this descriptor (in bytes) */
bLength: number;
/** Descriptor type */
bDescriptorType: number;
/** Length of this descriptor and all sub descriptors */
wTotalLength: number;
/** Number of separate device capability descriptors */
bNumDeviceCaps: number;
/** Device Capability Descriptors */
capabilities: CapabilityDescriptor[];
}
/**
* Device Capability Descriptor
*/
interface CapabilityDescriptor {
/** Size of this descriptor (in bytes) */
bLength: number;
/** Descriptor type */
bDescriptorType: number;
/** Device Capability type */
bDevCapabilityType: number;
/** Device Capability data */
dev_capability_data: Buffer;
}
/**
* Capability class for device capabilities
*/
class Capability {
/** Capability type */
readonly type: number;
/** Capability data buffer */
readonly data: Buffer;
/** Capability descriptor */
readonly descriptor: CapabilityDescriptor;
}Usage Examples:
import { findByIds } from 'usb';
const device = findByIds(0x1234, 0x5678);
if (device) {
device.open();
// Check USB version before attempting BOS
const usbVersion = device.deviceDescriptor.bcdUSB;
console.log(`USB Version: ${(usbVersion >> 8).toString(16)}.${((usbVersion & 0xFF) >> 4).toString(16)}.${(usbVersion & 0x0F).toString(16)}`);
if (usbVersion >= 0x0201) { // USB 2.0.1 or higher
// Get BOS descriptor
device.getBosDescriptor((error, bosDescriptor) => {
if (error) {
console.error('Failed to get BOS descriptor:', error.message);
device.close();
return;
}
if (!bosDescriptor) {
console.log('Device does not support BOS descriptor');
device.close();
return;
}
console.log('BOS Descriptor:');
console.log(` Total Length: ${bosDescriptor.wTotalLength}`);
console.log(` Number of Capabilities: ${bosDescriptor.bNumDeviceCaps}`);
// List capability types
bosDescriptor.capabilities.forEach((cap, index) => {
console.log(` Capability ${index}:`);
console.log(` Type: ${cap.bDevCapabilityType}`);
console.log(` Length: ${cap.bLength}`);
console.log(` Data: ${cap.dev_capability_data.toString('hex')}`);
});
device.close();
});
// Get device capabilities
device.getCapabilities((error, capabilities) => {
if (error) {
console.error('Failed to get capabilities:', error.message);
return;
}
if (capabilities && capabilities.length > 0) {
console.log(`Device has ${capabilities.length} capabilities:`);
capabilities.forEach((capability, index) => {
console.log(` Capability ${index}:`);
console.log(` Type: ${capability.type}`);
console.log(` Data Length: ${capability.data.length}`);
console.log(` Descriptor Type: ${capability.descriptor.bDevCapabilityType}`);
});
} else {
console.log('Device has no BOS capabilities');
}
});
} else {
console.log('Device USB version is below 2.0.1, BOS not supported');
device.close();
}
}Install with Tessl CLI
npx tessl i tessl/npm-usb