Signatur
Beschreibung
Ein Endpunkt ist bei USB der eigentliche Datenkanal zwischen Host und Gerät. Das Interface USBEndpoint der WebUSB API liefert die Metadaten eines solchen Endpunkts. Instanzen bekommt man in der Regel über USBAlternateInterface.endpoints, also z. B. über device.configuration.interfaces[i].alternate.endpoints.
Alle Eigenschaften sind schreibgeschützt:
endpointNumber– Nummer des Endpunkts (1–15). Diesen Wert übergibt man anUSBDevice.transferIn(),transferOut(),isochronousTransferIn()/Out()undclearHalt().direction–"in"(Gerät → Host) oder"out"(Host → Gerät).type– Übertragungsart:"bulk","interrupt"oder"isochronous".packetSize– maximale Paketgröße in Byte, die der Endpunkt pro Paket übertragen kann.
Typischer Einsatz: Nach claimInterface() sucht man die passenden IN- und OUT-Endpunkte heraus, statt Endpunktnummern hart zu kodieren. So funktioniert der Code auch mit Geräte-Revisionen, deren Deskriptoren leicht abweichen. Der Kontrollendpunkt 0 taucht dabei nicht in der Liste auf – er wird über controlTransferIn()/controlTransferOut() angesprochen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $alternate Pflicht | USBAlternateInterface | Nur beim Konstruktor new USBEndpoint(alternate, endpointNumber, direction): die alternative Schnittstelle, zu der der Endpunkt gehört. |
|
| $endpointNumber Pflicht | number | Nur beim Konstruktor: Nummer des Endpunkts, der in der alternativen Schnittstelle existieren muss. | |
| $direction Pflicht | "in" | "out" | Nur beim Konstruktor: Übertragungsrichtung des gesuchten Endpunkts. |
Rückgabewert
endpointNumber, direction, type und packetSize. Existiert der Endpunkt beim Konstruktor-Aufruf nicht, wird ein RangeError geworfen.Beispiele
Alle Endpunkte eines Geräts auflisten
// Muss durch eine Nutzergeste (z. B. Klick) ausgelöst werden
const button = document.querySelector('#connect');
button.addEventListener('click', async () => {
const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x2341 }] });
await device.open();
if (device.configuration === null) await device.selectConfiguration(1);
for (const iface of device.configuration.interfaces) {
for (const ep of iface.alternate.endpoints) {
console.log(`Interface ${iface.interfaceNumber}: EP ${ep.endpointNumber} ${ep.direction} ${ep.type} (${ep.packetSize} Byte)`);
}
}
});
Bulk-Endpunkte dynamisch finden und nutzen
const findBulkEndpoints = (iface) => {
const eps = iface.alternate.endpoints;
const inEp = eps.find((ep) => ep.type === 'bulk' && ep.direction === 'in');
const outEp = eps.find((ep) => ep.type === 'bulk' && ep.direction === 'out');
if (!inEp || !outEp) throw new Error('Keine Bulk-Endpunkte gefunden');
return { inEp, outEp };
};
const sendCommand = async (device, ifaceNumber, text) => {
await device.claimInterface(ifaceNumber);
const iface = device.configuration.interfaces.find((i) => i.interfaceNumber === ifaceNumber);
const { inEp, outEp } = findBulkEndpoints(iface);
await device.transferOut(outEp.endpointNumber, new TextEncoder().encode(text));
// Mindestens packetSize anfordern, sonst droht ein Babble-Fehler
const result = await device.transferIn(inEp.endpointNumber, inEp.packetSize);
return new TextDecoder().decode(result.data);
};
Endpunkt per Konstruktor abfragen
const getEndpoint = (device, ifaceIndex, number, direction) => {
const alternate = device.configuration.interfaces[ifaceIndex].alternate;
try {
return new USBEndpoint(alternate, number, direction);
} catch (err) {
console.warn(`Endpunkt ${number}/${direction} existiert nicht:`, err.name);
return null;
}
};
// const ep = getEndpoint(device, 1, 2, 'out');
// console.log(ep?.type, ep?.packetSize);
// Wichtig · Fallstricke
Browser-Kompatibilität: WebUSB ist experimentell und nur in Chromium-Browsern (Chrome, Edge, Opera) auf dem Desktop sowie Chrome für Android verfügbar. Firefox und Safari unterstützen die API nicht. Per Feature-Erkennung mit 'usb' in navigator prüfen.
- Nur in einem sicheren Kontext (HTTPS oder
localhost) verfügbar. Zudem lässt sich die API perPermissions-Policy: usbeinschränken; in Web Workern gibt es sie nur in Chromium ab Version 96 und nur eingeschränkt. - Die Endpunktliste hängt von der aktuell gewählten alternativen Einstellung ab. Nach
selectAlternateInterface()können sich Endpunkte ändern, deshalb danach neu auslesen. - Bei
transferIn()sollte die angeforderte Länge ein Vielfaches vonpacketSizesein. Kleinere Puffer können zum Status"babble"führen. - Endpunkte zu Klassen, die das Betriebssystem schützt (z. B. HID-Tastaturen, Massenspeicher), sind gesperrt.
claimInterface()schlägt dann fehl. - Bei Status
"stall"muss man den Endpunkt mitdevice.clearHalt(direction, endpointNumber)zurücksetzen.