Start · Sprachen · JavaScript · Referenz · USBDevice.controlTransferIn()

USBDevice.controlTransferIn()

Methode

Sendet eine Control-Anfrage an ein USB-Gerät und liest die Antwortdaten (Richtung Gerät → Host). Das Promise wird mit einem <code>USBInTransferResult</code> erfüllt.

seit JavaScript WebUSB API – Chromium-Browser (Chrome/Edge 61+, Op Kategorie: webapi

Signatur

USBDevice.prototype.controlTransferIn(setup, length)

Beschreibung

controlTransferIn() führt einen Control-Transfer über den Default-Endpunkt 0 aus, bei dem Daten vom Gerät zum Host fließen. Mit solchen Transfers liest man Deskriptoren, fragt Status- oder Konfigurationswerte ab oder ruft herstellerspezifische Befehle auf, die eine Antwort liefern. Welche Anfrage gesendet wird, legt das Objekt im Parameter setup fest (Request-Typ, Empfänger, Request-Code, value und index). Diese Werte entsprechen dem Setup-Paket aus der USB-Spezifikation.

Das Gerät muss vorher mit open() geöffnet werden. Ist der Empfänger "interface" oder "endpoint", muss außerdem das betreffende Interface per claimInterface() beansprucht sein. Der Parameter length gibt an, wie viele Bytes höchstens erwartet werden. Das Gerät darf weniger senden.

Das zurückgegebene Promise wird mit einem USBInTransferResult erfüllt. Dessen Eigenschaft data ist ein DataView mit den empfangenen Bytes. status ist "ok", "stall" (das Gerät hat die Anfrage abgelehnt) oder "babble" (das Gerät hat mehr Daten gesendet als angefordert). Das Promise wird nur bei echten Fehlern verworfen, etwa wenn das Gerät nicht geöffnet ist oder die Übertragung fehlschlägt. Ein Stall führt dagegen nicht zum Verwerfen.

Parameter

Name Typ Default Beschreibung
$setup Pflicht USBControlTransferParameters Objekt, das das Setup-Paket beschreibt:
  • requestType: "standard", "class" oder "vendor"
  • recipient: "device", "interface", "endpoint" oder "other"
  • request: Request-Code (Zahl von 0 bis 255, entspricht bRequest)
  • value: 16-Bit-Wert (wValue)
  • index: 16-Bit-Wert (wIndex). Beim Empfänger "interface" oder "endpoint" steht im niederwertigen Byte die Interface- bzw. Endpunktnummer.
$length Pflicht number Maximale Anzahl Bytes, die vom Gerät gelesen werden sollen (wLength, 0 bis 65535).

Rückgabewert

Typ
Promise<USBInTransferResult>
Beschreibung
Promise, das mit einem USBInTransferResult erfüllt wird. Es enthält data (DataView, die empfangenen Bytes) und status ("ok", "stall" oder "babble").

Beispiele

Geräte-Deskriptor lesen (Standard-Request GET_DESCRIPTOR)

const readDeviceDescriptor = async () => {
  // Muss durch eine Nutzeraktion ausgelöst werden (z. B. Klick)
  const device = await navigator.usb.requestDevice({ filters: [] });
  await device.open();

  const result = await device.controlTransferIn({
    requestType: 'standard',
    recipient: 'device',
    request: 0x06,        // GET_DESCRIPTOR
    value: 0x0100,        // Deskriptortyp 1 (Gerät), Index 0
    index: 0x0000
  }, 18);                 // Geräte-Deskriptor ist 18 Byte lang

  if (result.status === 'ok') {
    const view = result.data;
    const vendorId = view.getUint16(8, true);
    const productId = view.getUint16(10, true);
    console.log(`VID: 0x${vendorId.toString(16)}, PID: 0x${productId.toString(16)}`);
  }
  await device.close();
};

document.querySelector('#connect').addEventListener('click', readDeviceDescriptor);
VID: 0x2341, PID: 0x43

Herstellerspezifischen Status über ein Interface abfragen

const readVendorStatus = async (device) => {
  await device.open();
  if (device.configuration === null) {
    await device.selectConfiguration(1);
  }
  await device.claimInterface(0);

  const { status, data } = await device.controlTransferIn({
    requestType: 'vendor',
    recipient: 'interface',
    request: 0x01,   // gerätespezifischer Befehl "Status lesen"
    value: 0x0000,
    index: 0x0000    // Interface-Nummer 0
  }, 64);

  if (status === 'stall') {
    console.warn('Gerät hat die Anfrage abgelehnt');
    return null;
  }
  // Empfangene Bytes als Uint8Array auslesen
  const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
  console.log('Empfangen:', bytes.length, 'Bytes', bytes);
  return bytes;
};
Empfangen: 4 Bytes Uint8Array(4) [1, 0, 42, 255]

Fehlerbehandlung mit try/catch und Stall-Behandlung

const safeControlIn = async (device, setup, length) => {
  try {
    const result = await device.controlTransferIn(setup, length);
    if (result.status === 'stall') {
      // Bei Control-Transfers setzt sich der Stall mit dem nächsten Setup-Paket
      // automatisch zurück, clearHalt() ist hier nicht nötig
      throw new Error('Request vom Gerät nicht unterstützt (STALL)');
    }
    if (result.status === 'babble') {
      throw new Error('Gerät hat mehr Daten gesendet als erwartet');
    }
    return result.data;
  } catch (err) {
    // z. B. InvalidStateError (Gerät nicht geöffnet) oder NetworkError
    console.error(`${err.name}: ${err.message}`);
    return null;
  }
};
InvalidStateError: The device must be opened first.

// Wichtig · Fallstricke

  • Browser-Unterstützung: WebUSB gibt es nur in Chromium-Browsern (Chrome, Edge, Opera) auf dem Desktop und unter Android. Firefox und Safari unterstützen es nicht. Vor der Nutzung mit 'usb' in navigator prüfen.
  • Sicherer Kontext: Die API ist nur über HTTPS (oder localhost) verfügbar. requestDevice() braucht eine Nutzeraktion. In iframes muss die Permissions-Policy usb erlaubt sein.
  • Stall führt nicht zum Verwerfen: Lehnt das Gerät die Anfrage ab, wird das Promise trotzdem erfüllt, nur mit status: "stall". Den Status also immer prüfen.
  • Interface beanspruchen: Beim Empfänger "interface" oder "endpoint" ohne vorheriges claimInterface() wird das Promise mit InvalidStateError verworfen.
  • Gesperrte Geräteklassen: Geräte, die das Betriebssystem bereits beansprucht (z. B. HID-Tastaturen, Massenspeicher), und Geräte auf der Sperrliste sind nicht zugänglich. Unter Windows ist oft der WinUSB-Treiber nötig.
  • Byte-Reihenfolge: USB-Deskriptoren sind Little-Endian, daher bei DataView.getUint16() das zweite Argument true übergeben. data.byteLength kann kleiner sein als length.