Signatur
Beschreibung
Die Methode clearHalt() des USBDevice-Interfaces sendet eine Standardanfrage CLEAR_FEATURE(ENDPOINT_HALT) an das Gerät. Dadurch wird ein Bulk- oder Interrupt-Endpunkt aus dem Halt-Zustand geholt. In diesen Zustand gerät ein Endpunkt, wenn das Gerät eine Übertragung mit einem STALL-Handshake ablehnt, z. B. nach einem Protokollfehler oder einem ungültigen Befehl.
Ob ein Endpunkt blockiert ist, erkennen Sie an einem USBInTransferResult oder USBOutTransferResult mit status === "stall", den Sie von transferIn() bzw. transferOut() erhalten. Solange Sie clearHalt() nicht aufrufen, schlagen alle weiteren Übertragungen auf diesem Endpunkt fehl. Rufen Sie die Methode also als Teil Ihrer Fehlerbehandlung auf, bevor Sie es erneut versuchen.
Voraussetzung: Das Gerät muss mit open() geöffnet sein, eine Konfiguration muss aktiv sein, und die Schnittstelle, zu der der Endpunkt gehört, muss mit claimInterface() belegt sein. Bei Control-Transfers (Endpunkt 0) brauchen Sie clearHalt() nicht, denn ein Stall dort wird beim nächsten Setup-Paket automatisch aufgehoben.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $direction Pflicht | "in" | "out" | Richtung des Endpunkts: "in" (Gerät → Host) oder "out" (Host → Gerät). |
|
| $endpointNumber Pflicht | number | Nummer des Endpunkts (1–15) ohne Richtungsbit, also z. B. 1 statt 0x81. Sie entspricht USBEndpoint.endpointNumber. |
Rückgabewert
Promise, das ohne Wert erfüllt wird, sobald der Halt-Zustand aufgehoben ist. Es wird mit einer DOMException abgelehnt, z. B. mit InvalidStateError (Gerät nicht geöffnet oder Schnittstelle nicht belegt), NotFoundError (Endpunkt existiert nicht) oder NetworkError (Gerät getrennt oder Übertragung fehlgeschlagen).Beispiele
Stall beim Lesen erkennen und aufheben
const readWithRecovery = async (device, endpoint = 1, length = 64) => {
let result = await device.transferIn(endpoint, length);
if (result.status === 'stall') {
console.warn('Endpunkt blockiert – hebe Halt auf …');
await device.clearHalt('in', endpoint);
// Zweiter Versuch nach dem Zurücksetzen
result = await device.transferIn(endpoint, length);
}
return result;
};
const [device] = await navigator.usb.getDevices();
await device.open();
if (device.configuration === null) await device.selectConfiguration(1);
await device.claimInterface(0);
const res = await readWithRecovery(device);
console.log(res.status, res.data?.byteLength);
Endpunkte aus dem Deskriptor ermitteln und alle zurücksetzen
const resetAllEndpoints = async (device, interfaceNumber = 0) => {
const iface = device.configuration.interfaces
.find((i) => i.interfaceNumber === interfaceNumber);
for (const ep of iface.alternate.endpoints) {
if (ep.type === 'bulk' || ep.type === 'interrupt') {
await device.clearHalt(ep.direction, ep.endpointNumber);
console.log(`Endpunkt ${ep.endpointNumber} (${ep.direction}) freigegeben`);
}
}
};
const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] });
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);
await resetAllEndpoints(device, 0);
Schreiben mit Fehlerbehandlung
const sendCommand = async (device, endpoint, bytes) => {
try {
const result = await device.transferOut(endpoint, new Uint8Array(bytes));
if (result.status === 'stall') {
await device.clearHalt('out', endpoint);
throw new Error('Gerät hat den Befehl abgelehnt (STALL)');
}
return result.bytesWritten;
} catch (err) {
console.error('USB-Fehler:', err.name ?? '', err.message);
return 0;
}
};
const written = await sendCommand(device, 2, [0x01, 0xff]);
console.log('Geschrieben:', written);
// Wichtig · Fallstricke
- Browser-Kompatibilität: WebUSB gibt es nur in Chromium-basierten Browsern (Chrome, Edge, Opera), und das nur auf Desktop und Android. Firefox und Safari unterstützen es nicht. Prüfen Sie die Unterstützung vorher mit
'usb' in navigator. - Die API steht nur in einem sicheren Kontext (HTTPS oder
localhost) zur Verfügung. In iframes kann die Permissions Policyusbsie sperren. - Häufiger Fehler: Wer als
endpointNumberdie Endpunktadresse mit Richtungsbit übergibt (z. B.0x81), bekommt einen Fehler. Übergeben Sie nur die Nummer und die Richtung getrennt. - Nach
clearHalt()setzt das Gerät das Data-Toggle-Bit des Endpunkts zurück. Manche Geräte verlangen zusätzlich einen protokollspezifischen Reset, z. B. Bulk-Only Mass Storage Reset, bevor der Endpunkt wieder zuverlässig funktioniert. - Rufen Sie
clearHalt()nicht in einer Endlosschleife auf. Wenn der Stall immer wieder auftritt, liegt meist ein Protokollfehler vor, z. B. ein ungültiger Befehl oder eine falsche Paketgröße.