0
votes

I have a c# application that can open a cash drawer with the Windows Driver Installed. Pretty simple as the driver makes the USB device appears as a serial port:

 SerialPort rsPort = new SerialPort(textBox1.Text);
 byte[] openCmd = new byte[5];
 openCmd[0] = 27;
 openCmd[1] = 112;
 openCmd[2] = 0;
 openCmd[3] = 60;
 openCmd[4] = 255;
 rsPort.Open();
 Thread.Sleep(100);
 rsPort.Write(openCmd, 0, 5);
 Thread.Sleep(100);
 rsPort.Close();

I'm now trying to open the same USB cash Drawer via WebUSB. I've used ZaDig to install a generic USB drive and Chrome can see the USB device; can open the device; however, i'm struggling to send the correct commands.

Here is an image of the config:

enter image description here

Here is my current code:

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript WebUSB</h2>

<button id="myBtn">Try it</button>

<script>
document.getElementById("myBtn").addEventListener("click", talkToDrawer);

async function talkToDrawer() {
  try {
    let device = await navigator.usb.requestDevice({ filters: [{ vendorId: 1659 }] });
    console.log(device);
    await device.open(); // Begin a session.
    await device.selectConfiguration(1); // Select configuration #1 for the device.
    await device.claimInterface(0); // Request exclusive control over interface #2.
    result = await device.controlTransferOut({
        requestType: 'standard', // tried all combinations: standard / class / vendor
        recipient: 'endpoint', // tried all combinations: device / interface / endpoint / other
        request: 0x27,
        value: 0,
        index: 1
     });
     result = await device.controlTransferOut({
        requestType: 'standard', // tried all combinations: standard / class / vendor
        recipient: 'endpoint', // tried all combinations: device / interface / endpoint / other
        request: 0x112,
        value: 0,
        index: 1
     });
     result = await device.controlTransferOut({
        requestType: 'standard', // tried all combinations: standard / class / vendor
        recipient: 'endpoint', // tried all combinations: device / interface / endpoint / other
        request: 0x0,
        value: 0,
        index: 1
     });
     result = await device.controlTransferOut({
        requestType: 'standard', // tried all combinations: standard / class / vendor
        recipient: 'endpoint', // tried all combinations: device / interface / endpoint / other
        request: 0x60,
        value: 0,
        index: 1
     });
         result = await device.controlTransferOut({
        requestType: 'standard', // tried all combinations: standard / class / vendor
        recipient: 'endpoint', // tried all combinations: device / interface / endpoint / other
        request: 0x255,
        value: 0,
        index: 1
     });

  } catch (error) {
    console.log(error);
  }
}


</script>

</body>
</html> 
1
DO NOT post images of code, data, error messages, etc. - copy or type the text into the question. How to Ask - Rob

1 Answers

1
votes

Without knowing more about the device there are two errors I see in the code,

  1. In the C# example the command is [27, 112, 0, 60, 255] with the values given in decimal while in the Javascript example the values are given as hexadecimal constants. The appropriate code for constructing the command buffer in Javascript is,
const cmd = new Uint8Array([27, 112, 0, 60, 255]);
  1. Rather than using controlTransferOut() to send the data it is most likely correct to use transferOut() and select endpoint number 3. The Prolific USB-to-serial converter chips implement a protocol similar to the standard USB serial class, which uses a pair of bulk IN and OUT endpoints for the serial data stream,
result = await device.transferOut(3, cmd);

The remaining open question is whether you need to perform any control transfers before you can send this command. Control transfers are used to configure the device and for a USB-to-serial chip this usually involves things like setting baud rate or setting the DCE bit high. When reverse-engineering how to communicate with a USB device I recommend using Wireshark to view the USB traffic from a working driver.

Note, that if you are working with a serial device you should take a the Serial API. There is an experimental implementation available in Chrome behind the chrome://flags/#enable-experimental-web-platform-features flag. This API is designed for applications specifically targeting serial devices and avoids having to re-implement the driver for the USB-to-serial chip.