CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-usb

Cross-platform Node.js library for USB device communication with both legacy and WebUSB-compatible APIs.

Pending
Overview
Eval results
Files

device-communication.mddocs/

Device Communication

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.

Capabilities

Device Opening and Closing

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();
}

Device Configuration

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();
      });
    }
  });
}

Control Transfers

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();
}

String Descriptor Access

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();
}

Kernel Driver Management

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();
    });
  }
}

Device Reset

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);
  });
}

Timeout Configuration

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();
}

BOS Descriptor Access

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

docs

constants-errors.md

data-transfers.md

descriptors.md

device-communication.md

device-management.md

event-handling.md

index.md

interfaces-endpoints.md

webusb-api.md

tile.json