Start · Sprachen · JavaScript · Referenz · USBOutTransferResult

USBOutTransferResult

Schnittstelle

Enthält das Ergebnis eines ausgehenden USB-Transfers, der mit <code>USBDevice.transferOut()</code> oder <code>USBDevice.controlTransferOut()</code> ausgeführt wurde: Status und Anzahl der gesendeten Bytes.

seit JavaScript Experimentell: Chrome/Edge 61+, Opera; nicht in Fi Kategorie: webapi

Signatur

interface USBOutTransferResult

Beschreibung

USBOutTransferResult gehört zur WebUSB API. Instanzen erhält man als aufgelösten Wert der Promises, die USBDevice.prototype.transferOut() (Bulk- oder Interrupt-Transfer an einen OUT-Endpunkt) und USBDevice.prototype.controlTransferOut() (Steuertransfer an den Endpunkt 0) zurückgeben. Das Objekt meldet, ob der Transfer geklappt hat und wie viele Bytes das Gerät tatsächlich angenommen hat.

Das Interface hat zwei schreibgeschützte Eigenschaften:

  • bytesWritten – Anzahl der Bytes (number), die an das Gerät übertragen wurden. Sie kann kleiner als die Länge des gesendeten Puffers sein.
  • status – Status des Transfers als string: "ok" bei Erfolg oder "stall", wenn das Gerät den Endpunkt blockiert hat (STALL). Den Wert "babble" gibt es in der Aufzählung USBTransferStatus zwar auch, er kommt aber nur bei eingehenden Transfers vor.

In der Praxis prüft man nach jedem Schreibvorgang status und vergleicht bytesWritten mit der erwarteten Länge. Bei "stall" muss der Endpunkt meist mit USBDevice.clearHalt() wieder freigegeben werden, bevor weitere Transfers möglich sind. Schwere Fehler, etwa ein getrenntes Gerät oder ein nicht beanspruchtes Interface, führen dagegen dazu, dass das Promise mit einer DOMException zurückgewiesen wird. Sie tauchen also nicht im status auf.

Einen Konstruktor gibt es auch, man braucht ihn aber selten. Mit new USBOutTransferResult(status, bytesWritten) lassen sich zum Beispiel Testattrappen (Mocks) oder Polyfills bauen.

Parameter

Name Typ Default Beschreibung
$status Pflicht "ok" | "stall" | "babble" Nur beim Konstruktor: der Transferstatus, der später über status ausgelesen wird.
$bytesWritten number 0 Nur beim Konstruktor: die Anzahl der übertragenen Bytes, die später über bytesWritten ausgelesen wird.

Rückgabewert

Typ
USBOutTransferResult
Beschreibung
Ein Objekt mit den schreibgeschützten Eigenschaften status (string) und bytesWritten (number). Man bekommt es als aufgelösten Wert von transferOut() bzw. controlTransferOut() oder über den Konstruktor.

Beispiele

Daten per Bulk-Transfer senden und Ergebnis prüfen

// Muss durch eine Benutzeraktion ausgelöst werden (z. B. Klick)
const sendCommand = async () => {
  const device = await navigator.usb.requestDevice({
    filters: [{ vendorId: 0x2341 }]
  });
  await device.open();
  if (device.configuration === null) await device.selectConfiguration(1);
  await device.claimInterface(0);

  const data = new TextEncoder().encode('LED ON\n');
  const result = await device.transferOut(2, data); // Endpunkt 2 (OUT)

  console.log(result instanceof USBOutTransferResult);
  console.log(`Status: ${result.status}, gesendet: ${result.bytesWritten}/${data.byteLength}`);
};

document.querySelector('#send').addEventListener('click', sendCommand);
true Status: ok, gesendet: 7/7

Steuertransfer (controlTransferOut) an das Gerät

const setLineCoding = async (device, baudRate = 115200) => {
  // CDC-ACM: SET_LINE_CODING (Request 0x20)
  const buffer = new ArrayBuffer(7);
  const view = new DataView(buffer);
  view.setUint32(0, baudRate, true); // Baudrate
  view.setUint8(4, 0);               // 1 Stoppbit
  view.setUint8(5, 0);               // keine Parität
  view.setUint8(6, 8);               // 8 Datenbits

  const result = await device.controlTransferOut({
    requestType: 'class',
    recipient: 'interface',
    request: 0x20,
    value: 0x00,
    index: 0x00
  }, buffer);

  if (result.status !== 'ok') {
    throw new Error(`Steuertransfer fehlgeschlagen: ${result.status}`);
  }
  return result.bytesWritten;
};
7

STALL behandeln und unvollständige Übertragung erkennen

const writeAll = async (device, endpoint, data) => {
  let offset = 0;
  while (offset < data.byteLength) {
    const chunk = data.subarray(offset);
    const { status, bytesWritten } = await device.transferOut(endpoint, chunk);

    if (status === 'stall') {
      console.warn('Endpunkt blockiert – clearHalt() wird ausgeführt');
      await device.clearHalt('out', endpoint);
      continue; // erneut versuchen
    }
    offset += bytesWritten;
  }
  return offset;
};

Konstruktor für Unit-Tests (Mock-Gerät)

const mockDevice = {
  transferOut: async (endpoint, data) =>
    new USBOutTransferResult('ok', data.byteLength)
};

const result = await mockDevice.transferOut(1, new Uint8Array([1, 2, 3]));
console.log(result.status, result.bytesWritten);

const stalled = new USBOutTransferResult('stall');
console.log(stalled.status, stalled.bytesWritten);
ok 3 stall 0

// Wichtig · Fallstricke

  • Browser-Unterstützung: WebUSB ist experimentell und nur in Chromium-basierten Desktop-Browsern (Chrome, Edge, Opera) sowie in Chrome für Android verfügbar. Firefox und Safari unterstützen die API nicht. Prüfe deshalb vorab mit 'usb' in navigator, ob sie vorhanden ist.
  • Nur in sicheren Kontexten: Die API läuft nur über HTTPS oder auf localhost. navigator.usb.requestDevice() braucht eine Benutzeraktion und lässt sich per Permissions-Policy usb sperren, zum Beispiel in iframes.
  • status immer prüfen: Ein aufgelöstes Promise heißt nicht automatisch, dass der Transfer erfolgreich war. Ein "stall" wird nicht als Ausnahme geworfen, sondern steht nur im Ergebnisobjekt.
  • Teilweise Übertragung: bytesWritten kann kleiner als die Pufferlänge sein. Vergleiche die Werte und sende den Rest bei Bedarf erneut.
  • Ausnahmen statt Status: Ist das Gerät getrennt, das Interface nicht beansprucht (claimInterface()) oder die Endpunktnummer ungültig, wird das Promise mit einer DOMException (z. B. NotFoundError, InvalidStateError, NetworkError) zurückgewiesen. Nutze dafür try/catch.
  • Das Interface ist auch in Dedicated Workern verfügbar.