Skip to content

Instantly share code, notes, and snippets.

@devanlai
Created December 3, 2019 04:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devanlai/4aba1c2d4000bdcfc5ec71584491e19f to your computer and use it in GitHub Desktop.
Save devanlai/4aba1c2d4000bdcfc5ec71584491e19f to your computer and use it in GitHub Desktop.
WebUSB descriptor read test
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebUSB Control Transfer Request to Device Endpoint while unconfigured</title>
<script>
async function readDeviceDescriptor(device) {
const GET_DESCRIPTOR = 0x06;
const DT_DEVICE = 0x01;
const wValue = (DT_DEVICE << 8);
let result = await device.controlTransferIn({
"requestType": "standard",
"recipient": "device",
"request": GET_DESCRIPTOR,
"value": wValue,
"index": 0
}, 18);
return result;
}
function parseDeviceDescriptor(data) {
return {
bLength: data.getUint8(0),
bDescriptorType: data.getUint8(1),
bcdUSB: data.getUint16(2, true),
bDeviceClass: data.getUint8(4),
bDeviceSubClass: data.getUint8(5),
bDeviceProtocol: data.getUint8(6),
bMaxPacketSize: data.getUint8(7),
idVendor: data.getUint16(8, true),
idProduct: data.getUint16(10, true),
bcdDevice: data.getUint16(12, true),
iManufacturer: data.getUint8(14),
iProduct: data.getUint8(15),
iSerialNumber: data.getUint8(16),
bNumConfigurations: data.getUint8(17),
};
}
document.addEventListener("DOMContentLoaded", function (event) {
let status = document.getElementById("status");
function log(msg) {
console.log(msg);
let div = document.createElement("div");
div.textContent = msg;
status.appendChild(div);
}
function logPreformatted(msg) {
console.log(msg);
let div = document.createElement("div");
div.textContent = msg;
div.style = "white-space: pre; font-family: monospace";
status.appendChild(div);
}
function displayDeviceDescriptor(desc) {
const names = "bLength bDescriptorType bcdUSB bDeviceClass bDeviceSubClass bDeviceProtocol bMaxPacketSize idVendor idProduct bcdDevice iManufacturer iProduct iSerialNumber bNumConfigurations".split(" ");
for (let name of names) {
logPreformatted((name + ':').padEnd(20) + desc[name]);
}
}
async function runTest(withConfiguration) {
const usb_options = { filters: [] };
let device = await navigator.usb.requestDevice(usb_options);
try {
await device.open();
} catch (err) {
log("Failed to open USB device: " + err);
if (err.toString().startsWith("NotFoundError")) {
log("Make sure you're running this test from a secure context (e.g. localhost or HTTPS, not a file:/// URI)");
}
return;
}
try {
if (withConfiguration !== undefined && withConfiguration !== null) {
log("Selecting configuration " + withConfiguration);
try {
await device.selectConfiguration(withConfiguration);
} catch (err) {
log("Failed to select configuration " + withConfiguration + ": " + err);
}
} else {
log("Proceeding without selecting configuration");
}
let result = await readDeviceDescriptor(device);
if (result.status == "ok") {
log("Successfully read device descriptor");
let desc = parseDeviceDescriptor(result.data);
displayDeviceDescriptor(desc);
} else {
log("Control transfer failed: " + result.status);
}
} catch (err) {
log("Failed to initiate control transfer: " + err);
}
}
document.getElementById("testButton").addEventListener("click", async function (event) {
// Test without setting the configuration explicitly
runTest(null);
});
document.getElementById("testWithConfigButton").addEventListener("click", async function (event) {
// Test explicitly setting configuration to 1
runTest(1);
});
});
</script>
</head>
<body>
<button id="testButton">Test w/o setting configuration</button>
<button id="testWithConfigButton">Test with setting configuration</button>
<div id="status"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment