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

descriptors.mddocs/

Descriptors and Metadata

Descriptors and metadata provide access to USB descriptors to understand device capabilities, configuration, and structure. This includes device descriptors, configuration descriptors, interface descriptors, endpoint descriptors, and Binary Object Store (BOS) descriptors.

Capabilities

Device Descriptors

Access device-level information and characteristics.

/**
 * USB Device Descriptor - describes device characteristics
 */
interface DeviceDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be LIBUSB_DT_DEVICE = 1) */
  bDescriptorType: number;
  
  /** USB specification release number in binary-coded decimal */
  bcdUSB: number;
  
  /** USB-IF class code for the device */
  bDeviceClass: number;
  
  /** USB-IF subclass code for the device, qualified by bDeviceClass */
  bDeviceSubClass: number;
  
  /** USB-IF protocol code for the device, qualified by bDeviceClass and bDeviceSubClass */
  bDeviceProtocol: number;
  
  /** Maximum packet size for endpoint 0 */
  bMaxPacketSize0: number;
  
  /** USB-IF vendor ID */
  idVendor: number;
  
  /** USB-IF product ID */
  idProduct: number;
  
  /** Device release number in binary-coded decimal */
  bcdDevice: number;
  
  /** Index of string descriptor describing manufacturer */
  iManufacturer: number;
  
  /** Index of string descriptor describing product */
  iProduct: number;
  
  /** Index of string descriptor containing device serial number */
  iSerialNumber: number;
  
  /** Number of possible configurations */
  bNumConfigurations: number;
}

Usage Examples:

import { getDeviceList } from 'usb';

// Analyze device descriptors
function analyzeDeviceDescriptors() {
  const devices = getDeviceList();
  
  devices.forEach((device, index) => {
    const desc = device.deviceDescriptor;
    
    console.log(`Device ${index}:`);
    console.log(`  Descriptor Length: ${desc.bLength}`);
    console.log(`  Descriptor Type: ${desc.bDescriptorType}`);
    
    // Decode USB version
    const usbMajor = (desc.bcdUSB >> 8) & 0xFF;
    const usbMinor = (desc.bcdUSB >> 4) & 0x0F;
    const usbSub = desc.bcdUSB & 0x0F;
    console.log(`  USB Version: ${usbMajor}.${usbMinor}.${usbSub}`);
    
    console.log(`  Device Class: ${desc.bDeviceClass} (${getDeviceClassName(desc.bDeviceClass)})`);
    console.log(`  Device Subclass: ${desc.bDeviceSubClass}`);
    console.log(`  Device Protocol: ${desc.bDeviceProtocol}`);
    console.log(`  Max Packet Size (EP0): ${desc.bMaxPacketSize0}`);
    
    console.log(`  Vendor ID: 0x${desc.idVendor.toString(16).padStart(4, '0')}`);
    console.log(`  Product ID: 0x${desc.idProduct.toString(16).padStart(4, '0')}`);
    
    // Decode device version
    const deviceMajor = (desc.bcdDevice >> 8) & 0xFF;
    const deviceMinor = (desc.bcdDevice >> 4) & 0x0F;
    const deviceSub = desc.bcdDevice & 0x0F;
    console.log(`  Device Version: ${deviceMajor}.${deviceMinor}.${deviceSub}`);
    
    console.log(`  Manufacturer String Index: ${desc.iManufacturer}`);
    console.log(`  Product String Index: ${desc.iProduct}`);
    console.log(`  Serial Number String Index: ${desc.iSerialNumber}`);
    console.log(`  Number of Configurations: ${desc.bNumConfigurations}`);
    console.log('');
  });
}

function getDeviceClassName(classCode: number): string {
  const classNames: { [key: number]: string } = {
    0: 'Per Interface',
    1: 'Audio',
    2: 'Communications',
    3: 'HID',
    5: 'Physical',
    6: 'Image',
    7: 'Printer',
    8: 'Mass Storage',
    9: 'Hub',
    10: 'CDC Data',
    11: 'Smart Card',
    13: 'Content Security',
    14: 'Video',
    15: 'Personal Healthcare',
    16: 'Audio/Video',
    17: 'Billboard',
    18: 'USB Type-C Bridge',
    220: 'Diagnostic',
    224: 'Wireless',
    239: 'Miscellaneous',
    254: 'Application Specific',
    255: 'Vendor Specific'
  };
  
  return classNames[classCode] || 'Unknown';
}

// Get device strings from descriptor indices
async function getDeviceStrings(device: Device) {
  const desc = device.deviceDescriptor;
  const strings: any = {};
  
  device.open();
  
  try {
    // Get manufacturer string
    if (desc.iManufacturer > 0) {
      strings.manufacturer = await new Promise<string>((resolve, reject) => {
        device.getStringDescriptor(desc.iManufacturer, (error, value) => {
          if (error) reject(error);
          else resolve(value || '');
        });
      });
    }
    
    // Get product string
    if (desc.iProduct > 0) {
      strings.product = await new Promise<string>((resolve, reject) => {
        device.getStringDescriptor(desc.iProduct, (error, value) => {
          if (error) reject(error);
          else resolve(value || '');
        });
      });
    }
    
    // Get serial number string
    if (desc.iSerialNumber > 0) {
      strings.serialNumber = await new Promise<string>((resolve, reject) => {
        device.getStringDescriptor(desc.iSerialNumber, (error, value) => {
          if (error) reject(error);
          else resolve(value || '');
        });
      });
    }
    
  } catch (error) {
    console.warn('Could not retrieve some string descriptors:', error);
  } finally {
    device.close();
  }
  
  return strings;
}

Configuration Descriptors

Access device configuration information and interface layout.

/**
 * USB Configuration Descriptor - describes device configuration
 */
interface ConfigDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be LIBUSB_DT_CONFIG = 2) */
  bDescriptorType: number;
  
  /** Total length of data returned for this configuration */
  wTotalLength: number;
  
  /** Number of interfaces supported by this configuration */
  bNumInterfaces: number;
  
  /** Identifier value for this configuration */
  bConfigurationValue: number;
  
  /** Index of string descriptor describing this configuration */
  iConfiguration: number;
  
  /** Configuration characteristics */
  bmAttributes: number;
  
  /** Maximum power consumption from bus in this configuration (in 2mA units) */
  bMaxPower: number;
  
  /** Extra descriptors */
  extra: Buffer;
  
  /** Array of interfaces supported by this configuration */
  interfaces: InterfaceDescriptor[][];
}

Usage Examples:

import { findByIds } from 'usb';

async function analyzeConfiguration() {
  const device = findByIds(0x1234, 0x5678);
  if (!device) return;
  
  device.open();
  
  try {
    // Get current configuration descriptor
    const configDesc = device.configDescriptor;
    if (configDesc) {
      console.log('Configuration Descriptor:');
      console.log(`  Length: ${configDesc.bLength}`);
      console.log(`  Type: ${configDesc.bDescriptorType}`);
      console.log(`  Total Length: ${configDesc.wTotalLength}`);
      console.log(`  Number of Interfaces: ${configDesc.bNumInterfaces}`);
      console.log(`  Configuration Value: ${configDesc.bConfigurationValue}`);
      console.log(`  Configuration String Index: ${configDesc.iConfiguration}`);
      
      // Decode attributes
      const attributes = configDesc.bmAttributes;
      console.log(`  Attributes: 0x${attributes.toString(16)}`);
      console.log(`    Self Powered: ${(attributes & 0x40) ? 'Yes' : 'No'}`);
      console.log(`    Remote Wakeup: ${(attributes & 0x20) ? 'Yes' : 'No'}`);
      
      console.log(`  Max Power: ${configDesc.bMaxPower * 2}mA`);
      console.log(`  Extra Descriptors: ${configDesc.extra.length} bytes`);
      
      // Analyze interfaces
      configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
        console.log(`  Interface Group ${groupIndex}:`);
        interfaceGroup.forEach((altSetting, altIndex) => {
          console.log(`    Alternate Setting ${altIndex}:`);
          console.log(`      Interface Number: ${altSetting.bInterfaceNumber}`);
          console.log(`      Alternate Setting: ${altSetting.bAlternateSetting}`);
          console.log(`      Interface Class: ${altSetting.bInterfaceClass}`);
          console.log(`      Interface Subclass: ${altSetting.bInterfaceSubClass}`);
          console.log(`      Interface Protocol: ${altSetting.bInterfaceProtocol}`);
          console.log(`      Number of Endpoints: ${altSetting.bNumEndpoints}`);
        });
      });
    }
    
    // Get all configuration descriptors
    const allConfigs = device.allConfigDescriptors;
    console.log(`\nDevice has ${allConfigs.length} configuration(s):`);
    
    allConfigs.forEach((config, index) => {
      console.log(`Configuration ${index}:`);
      console.log(`  Value: ${config.bConfigurationValue}`);
      console.log(`  Interfaces: ${config.bNumInterfaces}`);
      console.log(`  Power: ${config.bMaxPower * 2}mA`);
      
      if (config.iConfiguration > 0) {
        device.getStringDescriptor(config.iConfiguration, (error, configName) => {
          if (!error && configName) {
            console.log(`  Name: ${configName}`);
          }
        });
      }
    });
    
  } finally {
    device.close();
  }
}

// Find devices with specific configuration characteristics
function findDevicesByPowerRequirement(maxPowerMa: number) {
  const devices = getDeviceList();
  const matchingDevices: Device[] = [];
  
  devices.forEach(device => {
    try {
      device.open();
      const configDesc = device.configDescriptor;
      
      if (configDesc && (configDesc.bMaxPower * 2) <= maxPowerMa) {
        matchingDevices.push(device);
        console.log(`Found low-power device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
        console.log(`  Power consumption: ${configDesc.bMaxPower * 2}mA`);
      }
      
      device.close();
    } catch (error) {
      // Skip devices that can't be opened
    }
  });
  
  return matchingDevices;
}

Interface Descriptors

Access interface-level information and endpoint configuration.

/**
 * USB Interface Descriptor - describes interface characteristics
 */
interface InterfaceDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be LIBUSB_DT_INTERFACE = 4) */
  bDescriptorType: number;
  
  /** Number of this interface */
  bInterfaceNumber: number;
  
  /** Value used to select this alternate setting for this interface */
  bAlternateSetting: number;
  
  /** Number of endpoints used by this interface (excluding control endpoint) */
  bNumEndpoints: number;
  
  /** USB-IF class code for this interface */
  bInterfaceClass: number;
  
  /** USB-IF subclass code for this interface, qualified by bInterfaceClass */
  bInterfaceSubClass: number;
  
  /** USB-IF protocol code for this interface, qualified by bInterfaceClass and bInterfaceSubClass */
  bInterfaceProtocol: number;
  
  /** Index of string descriptor describing this interface */
  iInterface: number;
  
  /** Extra descriptors */
  extra: Buffer;
  
  /** Array of endpoint descriptors */
  endpoints: EndpointDescriptor[];
}

Usage Examples:

import { findByIds } from 'usb';

function analyzeInterfaces() {
  const device = findByIds(0x1234, 0x5678);
  if (!device) return;
  
  device.open();
  
  try {
    const configDesc = device.configDescriptor;
    if (!configDesc) return;
    
    configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
      console.log(`Interface Group ${groupIndex}:`);
      
      interfaceGroup.forEach((ifaceDesc, altIndex) => {
        console.log(`  Alternate Setting ${altIndex}:`);
        console.log(`    Length: ${ifaceDesc.bLength}`);
        console.log(`    Type: ${ifaceDesc.bDescriptorType}`);
        console.log(`    Interface Number: ${ifaceDesc.bInterfaceNumber}`);
        console.log(`    Alternate Setting: ${ifaceDesc.bAlternateSetting}`);
        console.log(`    Number of Endpoints: ${ifaceDesc.bNumEndpoints}`);
        console.log(`    Interface Class: ${ifaceDesc.bInterfaceClass} (${getInterfaceClassName(ifaceDesc.bInterfaceClass)})`);
        console.log(`    Interface Subclass: ${ifaceDesc.bInterfaceSubClass}`);
        console.log(`    Interface Protocol: ${ifaceDesc.bInterfaceProtocol}`);
        console.log(`    Interface String Index: ${ifaceDesc.iInterface}`);
        console.log(`    Extra Descriptors: ${ifaceDesc.extra.length} bytes`);
        
        // Get interface string if available
        if (ifaceDesc.iInterface > 0) {
          device.getStringDescriptor(ifaceDesc.iInterface, (error, interfaceName) => {
            if (!error && interfaceName) {
              console.log(`    Interface Name: ${interfaceName}`);
            }
          });
        }
        
        // Analyze endpoints
        ifaceDesc.endpoints.forEach((endpoint, epIndex) => {
          console.log(`    Endpoint ${epIndex}:`);
          analyzeEndpointDescriptor(endpoint);
        });
        
        console.log('');
      });
    });
    
  } finally {
    device.close();
  }
}

function getInterfaceClassName(classCode: number): string {
  const classNames: { [key: number]: string } = {
    1: 'Audio',
    2: 'Communications',
    3: 'HID',
    5: 'Physical',
    6: 'Image', 
    7: 'Printer',
    8: 'Mass Storage',
    9: 'Hub',
    10: 'CDC Data',
    11: 'Smart Card',
    13: 'Content Security',
    14: 'Video',
    15: 'Personal Healthcare',
    255: 'Vendor Specific'
  };
  
  return classNames[classCode] || 'Unknown';
}

// Find interfaces by class
function findInterfacesByClass(targetClass: number) {
  const devices = getDeviceList();
  const matchingInterfaces: any[] = [];
  
  devices.forEach(device => {
    try {
      device.open();
      const configDesc = device.configDescriptor;
      
      if (configDesc) {
        configDesc.interfaces.forEach((interfaceGroup, groupIndex) => {
          interfaceGroup.forEach((ifaceDesc, altIndex) => {
            if (ifaceDesc.bInterfaceClass === targetClass) {
              matchingInterfaces.push({
                device: device,
                interfaceNumber: ifaceDesc.bInterfaceNumber,
                alternateSetting: ifaceDesc.bAlternateSetting,
                descriptor: ifaceDesc
              });
              
              console.log(`Found ${getInterfaceClassName(targetClass)} interface:`);
              console.log(`  Device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
              console.log(`  Interface: ${ifaceDesc.bInterfaceNumber}, Alt: ${ifaceDesc.bAlternateSetting}`);
            }
          });
        });
      }
      
      device.close();
    } catch (error) {
      // Skip devices that can't be opened
    }
  });
  
  return matchingInterfaces;
}

Endpoint Descriptors

Access endpoint-level information for data transfer configuration.

/**
 * USB Endpoint Descriptor - describes endpoint characteristics
 */
interface EndpointDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be LIBUSB_DT_ENDPOINT = 5) */
  bDescriptorType: number;
  
  /** The address of the endpoint described by this descriptor */
  bEndpointAddress: number;
  
  /** Attributes which apply to the endpoint when configured using bConfigurationValue */
  bmAttributes: number;
  
  /** Maximum packet size this endpoint is capable of sending/receiving */
  wMaxPacketSize: number;
  
  /** Interval for polling endpoint for data transfers */
  bInterval: number;
  
  /** For audio devices only: the rate at which synchronization feedback is provided */
  bRefresh: number;
  
  /** For audio devices only: the address of the synch endpoint */
  bSynchAddress: number;
  
  /** Extra descriptors */
  extra: Buffer;
}

Usage Examples:

import { findByIds, LIBUSB_ENDPOINT_IN } from 'usb';

function analyzeEndpointDescriptor(endpointDesc: EndpointDescriptor) {
  console.log(`      Length: ${endpointDesc.bLength}`);
  console.log(`      Type: ${endpointDesc.bDescriptorType}`);
  console.log(`      Address: 0x${endpointDesc.bEndpointAddress.toString(16)}`);
  
  // Decode endpoint address
  const endpointNumber = endpointDesc.bEndpointAddress & 0x7F;
  const direction = (endpointDesc.bEndpointAddress & LIBUSB_ENDPOINT_IN) ? 'IN' : 'OUT';
  console.log(`        Endpoint Number: ${endpointNumber}`);
  console.log(`        Direction: ${direction}`);
  
  // Decode attributes
  const transferType = endpointDesc.bmAttributes & 0x03;
  const syncType = (endpointDesc.bmAttributes >> 2) & 0x03;
  const usageType = (endpointDesc.bmAttributes >> 4) & 0x03;
  
  const transferTypes = ['Control', 'Isochronous', 'Bulk', 'Interrupt'];
  const syncTypes = ['No Sync', 'Asynchronous', 'Adaptive', 'Synchronous'];
  const usageTypes = ['Data', 'Feedback', 'Implicit Feedback', 'Reserved'];
  
  console.log(`        Transfer Type: ${transferTypes[transferType] || 'Unknown'}`);
  if (transferType === 1) { // Isochronous
    console.log(`        Sync Type: ${syncTypes[syncType] || 'Unknown'}`);
    console.log(`        Usage Type: ${usageTypes[usageType] || 'Unknown'}`);
  }
  
  console.log(`        Max Packet Size: ${endpointDesc.wMaxPacketSize}`);
  console.log(`        Polling Interval: ${endpointDesc.bInterval}`);
  
  if (endpointDesc.bRefresh > 0) {
    console.log(`        Refresh: ${endpointDesc.bRefresh}`);
  }
  
  if (endpointDesc.bSynchAddress > 0) {
    console.log(`        Synch Address: 0x${endpointDesc.bSynchAddress.toString(16)}`);
  }
  
  console.log(`        Extra Descriptors: ${endpointDesc.extra.length} bytes`);
}

function findEndpointsByType(transferType: number) {
  const devices = getDeviceList();
  const matchingEndpoints: any[] = [];
  
  devices.forEach(device => {
    try {
      device.open();
      const configDesc = device.configDescriptor;
      
      if (configDesc) {
        configDesc.interfaces.forEach((interfaceGroup) => {
          interfaceGroup.forEach((ifaceDesc) => {
            ifaceDesc.endpoints.forEach((endpoint) => {
              if ((endpoint.bmAttributes & 0x03) === transferType) {
                matchingEndpoints.push({
                  device: device,
                  interfaceNumber: ifaceDesc.bInterfaceNumber,
                  endpoint: endpoint
                });
                
                const transferTypes = ['Control', 'Isochronous', 'Bulk', 'Interrupt'];
                console.log(`Found ${transferTypes[transferType]} endpoint:`);
                console.log(`  Device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
                console.log(`  Interface: ${ifaceDesc.bInterfaceNumber}`);
                console.log(`  Endpoint: 0x${endpoint.bEndpointAddress.toString(16)}`);
                console.log(`  Max Packet Size: ${endpoint.wMaxPacketSize}`);
              }
            });
          });
        });
      }
      
      device.close();
    } catch (error) {
      // Skip devices that can't be opened
    }
  });
  
  return matchingEndpoints;
}

// Analyze endpoint capabilities for optimal transfer settings
function analyzeEndpointCapabilities(device: Device, interfaceNumber: number) {
  device.open();
  
  try {
    const interface0 = device.interface(interfaceNumber);
    const ifaceDesc = interface0.descriptor;
    
    console.log(`Interface ${interfaceNumber} Endpoint Analysis:`);
    
    interface0.endpoints.forEach((endpoint, index) => {
      const desc = endpoint.descriptor;
      console.log(`  Endpoint ${index} (0x${desc.bEndpointAddress.toString(16)}):`);
      console.log(`    Max Packet Size: ${desc.wMaxPacketSize}`);
      console.log(`    Transfer Type: ${endpoint.transferType}`);
      console.log(`    Direction: ${endpoint.direction}`);
      
      // Calculate optimal transfer settings
      if (endpoint.direction === 'in') {
        console.log(`    Recommended read size: ${desc.wMaxPacketSize * 8} bytes`);
        console.log(`    Polling interval: ${desc.bInterval}ms`);
      } else {
        console.log(`    Recommended write chunk: ${desc.wMaxPacketSize} bytes`);
      }
      
      // Check for high-speed capabilities
      if (desc.wMaxPacketSize > 64) {
        console.log(`    High-speed capable (packet size > 64)`);
      }
      
      // Isochronous-specific analysis
      if ((desc.bmAttributes & 0x03) === 1) {
        const packetsPerFrame = ((desc.wMaxPacketSize >> 11) & 0x03) + 1;
        const actualPacketSize = desc.wMaxPacketSize & 0x7FF;
        console.log(`    Packets per microframe: ${packetsPerFrame}`);
        console.log(`    Actual packet size: ${actualPacketSize}`);
        console.log(`    Max bandwidth: ${actualPacketSize * packetsPerFrame * 8000} bytes/sec`);
      }
    });
    
  } finally {
    device.close();
  }
}

Binary Object Store (BOS) Descriptors

Access advanced device capabilities through BOS descriptors.

/**
 * Binary Object Store (BOS) Descriptor - describes device capabilities
 */
interface BosDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be LIBUSB_DT_BOS = 15) */
  bDescriptorType: number;
  
  /** Length of this descriptor and all of its sub descriptors */
  wTotalLength: number;
  
  /** The number of separate device capability descriptors in the BOS */
  bNumDeviceCaps: number;
  
  /** Device Capability Descriptors */
  capabilities: CapabilityDescriptor[];
}

/**
 * Generic representation of a BOS Device Capability descriptor
 */
interface CapabilityDescriptor {
  /** Size of this descriptor (in bytes) */
  bLength: number;
  
  /** Descriptor type (should be DEVICE_CAPABILITY = 16) */
  bDescriptorType: number;
  
  /** Device Capability type */
  bDevCapabilityType: number;
  
  /** Device Capability data (bLength - 3 bytes) */
  dev_capability_data: Buffer;
}

/**
 * Capability class for accessing BOS capabilities
 */
interface Capability {
  /** Object with fields from the capability descriptor */
  descriptor: CapabilityDescriptor;
  
  /** Integer capability type */
  type: number;
  
  /** Buffer capability data */
  data: Buffer;
}

Usage Examples:

import { findByIds } from 'usb';

async function analyzeBOSDescriptor() {
  const device = findByIds(0x1234, 0x5678);
  if (!device) return;
  
  device.open();
  
  try {
    // Get BOS descriptor
    const bosDescriptor = await new Promise<BosDescriptor | undefined>((resolve, reject) => {
      device.getBosDescriptor((error, descriptor) => {
        if (error) reject(error);
        else resolve(descriptor);
      });
    });
    
    if (bosDescriptor) {
      console.log('BOS Descriptor:');
      console.log(`  Length: ${bosDescriptor.bLength}`);
      console.log(`  Type: ${bosDescriptor.bDescriptorType}`);
      console.log(`  Total Length: ${bosDescriptor.wTotalLength}`);
      console.log(`  Number of Capabilities: ${bosDescriptor.bNumDeviceCaps}`);
      
      // Analyze each capability
      bosDescriptor.capabilities.forEach((capability, index) => {
        console.log(`  Capability ${index}:`);
        console.log(`    Length: ${capability.bLength}`);
        console.log(`    Type: ${capability.bDescriptorType}`);
        console.log(`    Capability Type: ${capability.bDevCapabilityType} (${getCapabilityTypeName(capability.bDevCapabilityType)})`);
        console.log(`    Data Length: ${capability.dev_capability_data.length} bytes`);
        
        if (capability.dev_capability_data.length > 0) {
          console.log(`    Data: ${capability.dev_capability_data.toString('hex')}`);
        }
      });
    } else {
      console.log('Device does not have BOS descriptor (USB 2.0 or earlier)');
    }
    
    // Get capabilities using Capability class
    const capabilities = await new Promise<Capability[]>((resolve, reject) => {
      device.getCapabilities((error, capabilities) => {
        if (error) reject(error);
        else resolve(capabilities || []);
      });
    });
    
    console.log(`\nFound ${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(`  Data: ${capability.data.toString('hex')}`);
    });
    
  } catch (error) {
    console.log('Could not retrieve BOS descriptor:', error.message);
  } finally {
    device.close();
  }
}

function getCapabilityTypeName(capabilityType: number): string {
  const capabilityTypes: { [key: number]: string } = {
    1: 'Wireless USB',
    2: 'USB 2.0 Extension',
    3: 'SuperSpeed USB',
    4: 'Container ID',
    5: 'Platform',
    6: 'Power Delivery Capability',
    7: 'Battery Info Capability',
    8: 'PD Consumer Port Capability',
    9: 'PD Provider Port Capability',
    10: 'SuperSpeed Plus',
    11: 'Precision Time Measurement',
    12: 'Wireless USB Ext'
  };
  
  return capabilityTypes[capabilityType] || 'Unknown';
}

// Analyze USB 3.0 SuperSpeed capabilities
function analyzeSuperspeedCapabilities(capability: Capability) {
  if (capability.type === 3) { // SuperSpeed USB capability
    const data = capability.data;
    
    if (data.length >= 6) {
      const bmAttributes = data.readUInt8(0);
      const wSpeedsSupported = data.readUInt16LE(1);
      const bFunctionalitySupport = data.readUInt8(3);
      const bU1DevExitLat = data.readUInt8(4);
      const bU2DevExitLat = data.readUInt16LE(5);
      
      console.log('SuperSpeed USB Capability:');
      console.log(`  Attributes: 0x${bmAttributes.toString(16)}`);
      console.log(`    LTM Capable: ${(bmAttributes & 0x02) ? 'Yes' : 'No'}`);
      console.log(`  Speeds Supported: 0x${wSpeedsSupported.toString(16)}`);
      console.log(`    Low Speed: ${(wSpeedsSupported & 0x01) ? 'Yes' : 'No'}`);
      console.log(`    Full Speed: ${(wSpeedsSupported & 0x02) ? 'Yes' : 'No'}`);
      console.log(`    High Speed: ${(wSpeedsSupported & 0x04) ? 'Yes' : 'No'}`);
      console.log(`    SuperSpeed: ${(wSpeedsSupported & 0x08) ? 'Yes' : 'No'}`);
      console.log(`  Functionality Support: ${bFunctionalitySupport}`);
      console.log(`  U1 Device Exit Latency: ${bU1DevExitLat}μs`);
      console.log(`  U2 Device Exit Latency: ${bU2DevExitLat}μs`);
    }
  }
}

// Find USB 3.0 capable devices
async function findUSB3Devices() {
  const devices = getDeviceList();
  const usb3Devices: Device[] = [];
  
  for (const device of devices) {
    try {
      device.open();
      
      const capabilities = await new Promise<Capability[]>((resolve, reject) => {
        device.getCapabilities((error, capabilities) => {
          if (error) reject(error);
          else resolve(capabilities || []);
        });
      });
      
      const hasSuperspeed = capabilities.some(cap => cap.type === 3);
      if (hasSuperspeed) {
        usb3Devices.push(device);
        console.log(`USB 3.0 device: VID:PID = ${device.deviceDescriptor.idVendor.toString(16)}:${device.deviceDescriptor.idProduct.toString(16)}`);
        
        // Analyze SuperSpeed capability
        const sspeedCap = capabilities.find(cap => cap.type === 3);
        if (sspeedCap) {
          analyzeSuperspeedCapabilities(sspeedCap);
        }
      }
      
      device.close();
    } catch (error) {
      // Skip devices that can't be opened or don't have BOS
      try { device.close(); } catch {}
    }
  }
  
  return usb3Devices;
}

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