0

I'm currently trying to write a service that should programmatically intercepts the output of a barcode scanner. I managed to get pyusb to work on Windows (has to install libusb-1.0 as a backend) and I can enumerate all connected USB devices along with the hierarchy of descriptors. So far so good.

Next step was to get data from the end point. I couldn't quite figure out how pyusb is supposed to work in that specific instance and even after reading the device's user manual (it's a HHP 3800g if it could help), I couldn't come with any wisdow on how to achieve this. pyusb read doesn't work.

Seeing both interface are HID ifaces, I attempted to use hidapi to access the device input. I manage to open the device using the path descriptor but read operation doesn't work.

iface 0 is HDI Keyboard emulation (usage=2)
iface 1 is HDI POS (usage=6)

I even tried to sniff USB traffic with Wireshark/USBPcap, not to avail. I can see USB traffic from the mouse (wee!) but no frames from the barcode scanner.

I should add that the scanner works properly being seen as a darn keyboard and behaving accordingly.

Here below is the entire descriptor of the device extracted by pyusb. The snippet of code comes after.

DEVICE ID 0536:02e1 on Bus 001 Address 002 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x110 USB 1.1
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :   0x20 (32 bytes)
 idVendor               : 0x0536
 idProduct              : 0x02e1
 bcdDevice              :    0x0 Device 0.0
 iManufacturer          :    0x1 Hand Held Products
 iProduct               :    0x2 3800G
 iSerialNumber          :    0x8 08011D1080
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 250 mA ==================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x49 (73 bytes)
   bNumInterfaces       :    0x2
   bConfigurationValue  :    0x1
   iConfiguration       :    0x3 Default
   bmAttributes         :   0xa0 Bus Powered, Remote Wakeup
   bMaxPower            :   0x7d (250 mA)
    INTERFACE 0: Human Interface Device ====================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x2
     bInterfaceClass    :    0x3 Human Interface Device
     bInterfaceSubClass :    0x1
     bInterfaceProtocol :    0x1
     iInterface         :    0x4 HID Keyboard Emulation
      ENDPOINT 0x83: Interrupt IN ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x83 IN
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :    0x8 (8 bytes)
       bInterval        :    0x8
      ENDPOINT 0x4: Interrupt OUT ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x4 OUT
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :    0x8 (8 bytes)
       bInterval        :    0x8
      ENDPOINT 0x2: Interrupt OUT ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x2 OUT
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :   0x40 (64 bytes)
       bInterval        :    0x1

HIDAPI python code

device_list = hid.enumerate(DEVICE_ID[0], DEVICE_ID[1])  # got 2 devices (2 ifaces)
device_desc = next(dev for dev in device_list if dev['usage'] == 2)  # alternately tried 2/6
device = hid.device()
device.open_path(device_desc['path'])
device.set_nonblocking(1)  # tried with 0, no difference
while True:
    d = device.read(64)
    if d:
        print(d)
    times.sleep(0.05)

Caveats

  • pyusb could work only with a proper backend, doesn't run natively on Windows. Was easy to fix
  • USBPcap installs its own driver to capture USB traffic rendering pyusb unable to work (I didn't try to manually set the backend argument though)

Final notes

I have to say that using input/raw_input to get the scanned barcode is not an option. It works but I need to discriminate between legitimate keyboard input and barcode scanner input hence my aim to access the second HID iface.

I tried also to access the USB ports using Windows Linux Subsystem not to avail. I'm on Windows 10 and USB related stuff is disabled (no 'lsusb' for short)

I'm kind of desperate to have it to work, maybe I'm missing something trivial but I'm not a well-seasoned USB specialist as I've only read 'USB in a nutshell' and looked at some code samples that interface with non HID devices.

Any help and insights fairly appreciated.

slouchart
  • 72
  • 6

1 Answers1

1

I somehow managed to get this to work.

Intercepting the barcode scanner input on Linux was straightforward: open the device, detach it from the kernel driver and you're good to go. It's pyusb tutorial 'by the book'

On windows, it's a bit of a mess. I had to configure the scanner as a serial device that gets recognized as such by Windows and mapped onto a virtual COM port. Then, using pyserial, I could effortlessly access the scanner input, decode it as the expected string.

I'll post the complete solution as a link to my github repo as soon as I can.

slouchart
  • 72
  • 6