I am working on a project that involves connecting to a Zebra Technologies printer (Model: ZEBRA ZQ620) via WebUSB. My ultimate goal is to send ZPL print commands to this device using the WebUSB API.
What’s Happening:
I successfully request a device and open a session.
I claim an interface (Claimed interface: 0 on configuration: 1).
I send a control transfer (Successfully sent control transfer).
I attempt to send a print command.
Issue:
Despite these seemingly successful operations, the printer doesn’t execute the print command. The code reaches the point where it tries to send data to the printer but fails to print.
Driver Context:
Initially, I was encountering a “USB Access Denied” issue when using the printer’s original drivers. I resolved this by using Zadig to replace the current driver with WinUSB. I’m not sure if this could be causing any problems.
Code:
<!DOCTYPE html>
<html>
<head>
<title>WebUSB Example</title>
</head>
<body>
<h1>WebUSB Zebra Technologies Device Connection</h1>
<button id="connect">Connect to Device</button>
<script>
let device;
// Helper method to test all possible interface options
async function tryAllInterfaces(device) {
const configCount = device.configurations.length;
for (let configIndex = 0; configIndex < configCount; configIndex++) {
await device.selectConfiguration(configIndex + 1); // Configurations are 1-indexed
for (let interfaceIndex = 0; interfaceIndex < device.configuration.interfaces.length; interfaceIndex++) {
try {
await device.claimInterface(interfaceIndex);
console.log(`Claimed interface: ${interfaceIndex} on configuration: ${configIndex + 1}`);
return { configIndex, interfaceIndex }; // If successful, return the indices
} catch (err) {
console.error(`Failed to claim interface ${interfaceIndex} on configuration ${configIndex + 1}: ${err}`);
}
}
}
throw new Error('Could not claim any interface');
}
// Systematically try all the possible controlTransferOut configurations
async function testControlTransfer(interfaceIndex) {
const requestTypes = ['standard', 'class', 'vendor'];
const recipients = ['device', 'interface', 'endpoint', 'other'];
const requests = [0x00, 0x01, 0x09, 0x21];
const values = [0x00, 0x01, 0x02];
const indices = [0x00, 0x01, 0x02, interfaceIndex]; // Include the claimed interface index
for (const requestType of requestTypes) {
for (const recipient of recipients) {
for (const request of requests) {
for (const value of values) {
for (const index of indices) {
try {
await device.controlTransferOut({
requestType: 'standard',
recipient: 'other',
request: 9,
value: 0,
index: 0 // Replace with the index that was successful in your tests
});
console.log('Successfully sent control transfer');
} catch (error) {
console.error('Detailed error:', JSON.stringify(error, null, 2));
}
}
}
}
}
}
}
// Function to try all possible endpoints and send a test print
// Function to try all possible endpoints and send a test print
async function tryAllEndpointsAndSendTestPrint() {
if (!device) {
console.error('No device connected.');
return;
}
console.log('Attempting to send a test print on all possible endpoints.');
const zplData = '^XA^FO50,50^A0N,50,50^FDHellodddddd, World!^FS^XZ';
const buffer = new TextEncoder().encode(zplData);
const claimedInterface = device.configuration.interfaces[0];
const endpoints = claimedInterface.alternate.endpoints;
console.log(`Number of endpoints: ${endpoints.length}`);
for (const endpoint of endpoints) {
console.log(`Trying endpoint number: ${endpoint.endpointNumber}, direction: ${endpoint.direction}`);
if (endpoint.direction === 'out') {
try {
const result = await new Promise((resolve, reject) => {
// Set a timeout to reject the promise if it takes too long
const timeout = setTimeout(() => {
console.log(`Timeout on endpoint ${endpoint.endpointNumber}`);
reject(new Error('Operation timed out'));
}, 5000); // 5 seconds
device.transferOut(endpoint.endpointNumber, buffer)
.then(result => {
clearTimeout(timeout);
console.log(`Successfully transferred out on endpoint ${endpoint.endpointNumber}.`);
resolve(result);
})
.catch(err => {
clearTimeout(timeout);
console.log(`Error during transfer out on endpoint ${endpoint.endpointNumber}.`);
reject(err);
});
});
console.log(`Transfer result: ${JSON.stringify(result)}`);
return;
} catch (err) {
console.error(`Failed to transfer out on endpoint ${endpoint.endpointNumber}: ${err}`);
}
}
}
console.error('Failed to transfer out on all endpoints.');
}
// Function to send a test print
async function connectDevice() {
try {
device = await navigator.usb.requestDevice({
filters: [{ vendorId: 0x0A5F, productId: 0x014C }]
});
await device.open();
const { configIndex, interfaceIndex } = await tryAllInterfaces(device);
await testControlTransfer(interfaceIndex);
// After successfully testing control transfer, attempt to send a test print.
await tryAllEndpointsAndSendTestPrint(); // Use this instead of sendTestPrint()
} catch (error) {
console.error('An error occurred:', error);
}
}
async function connectDevice() {
try {
device = await navigator.usb.requestDevice({
filters: [{ vendorId: 0x0A5F, productId: 0x014C }]
});
await device.open();
const { configIndex, interfaceIndex } = await tryAllInterfaces(device);
await testControlTransfer(interfaceIndex);
// After successfully testing control transfer, attempt to send a test print.
await tryAllEndpointsAndSendTestPrint(); // Use this instead of sendTestPrint()
} catch (error) {
console.error('An error occurred:', error);
}
}
document.getElementById('connect').addEventListener('click', connectDevice);
</script>
</body>
</html>
What I’ve Tried:
I’ve looked for examples and guides that might shed light on how to interface with this specific Zebra model, but to no avail.
I’ve tried multiple endpoint numbers for transferOut.
I’ve checked for driver compatibility issues.
I’ve verified that the ZPL commands are correct.
Logs:
Claimed interface: 0 on configuration: 1
Successfully sent control transfer
Attempting to send a test print on all possible endpoints.
Number of endpoints: 2
Question:
What could be the reason for the printer not executing the print command despite claiming the interface and sending control transfers successfully? Is there something I’m missing in my code or approach? Could the driver change be causing any issues?