Configuration of Honeywell Barcode Scanners

en

I had recently obtained an used USB barcode scanner: A Honeywell Hyperion 1300G. These scanners can be configured to use one of multiple USB operation modes:

  • USB Keyboard mode: The scanner emulates a keyboard and "types" the digits of scanned barcodes.
  • USB Serial mode: The scanner emulates a serial console to which it writes scanned barcodes.
  • USB HID mode: The scanner shows up as a a USB HID POS device to be used by applications.

For my use case, I needed the scanner to be in USB HID mode, however, when I obtained it, it was configured to USB Keyboard mode. Configuration of barcode scanners is usually done in-band, meaning by scanning special configuration barcodes. In the case of this scanner, these barcodes can be found in the user manual.

Unfortunately it seemed that in-band configuration had been disabled on this scanner, so that it could only be configured via USB. (The in-band configuration is usually disabled for security reasons in scenarios where potential adversaries might attempt to inject unexpected input via barcodes.)

Factory Reset & USB Traffic Logging

There is a Windows-only utility from Honeywell called «EZConfig» that can be used to configure, upgrade and factory-reset barcode scanners. So I set up a Windows VM, installed EZConfig in it and forwarded the host USB device to the VM. This way, the factory reset was only a matter of a few mouse clicks, and this is where this story could have ended.

Could have. However, since I had already set up the Windows VM and config utility, I wanted to see whether I could figure out how the configuration of these scanners actually worked. So I fired up Wireshark, set up USB capture and did another factory reset:

$ sudo modprobe usbmon
$ sudo setfacl -m u:s3lph:r /dev/usbmon*

With this, I was able to obtain a packet capture of the USB traffic between the EZConfig utility and the barcode scanner.

USB Traffic Analysis

From the user manual I knew that an in-band factory reset could be done by scanning the commands DEFOVR and DEFALT. The same was documented to be applicable out-of-band configuration of barcode scanners that are connected via RS232 instead of USB. So I hoped that the same could be assumed for USB configuration as well. And indeed, the packet capture contained a USB control transfer packet with the DEFALT command:

0000   fd 0a 16 4d 0d 44 45 46  41 4c 54 2e 00 00 00 00   |...M.DEFALT.....|
0010   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   |................|
0020   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   |................|
0030   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   |................|

So, let's try to break this down:

  • fd 0a 16 4d 0d: This appears to be a header of some sorts. It appears in all outgoing control transfer messages, however the second byte (0a) is changing with every message. Upon closer inspection, it appears to indicate the length of the payload, starting at the following byte.
  • The header is followed by the command, DEFALT. in this case. The . indicates termination of the command string.
  • The rest of the 64 bytes is filled with zeroes.

The respose to this control transfer was read from interrupt endpoint 0x83 and looked fairly similar:

0000   02 08 5d 58 30 44 45 46  41 4c 54 06 2e 00 00 00   |..]X0DEFALT.....|
0010   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   |................|
0020   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   |................|
0030   00 00 00 00 00 00 00 00  00 00 00 00 00 3f 00 00   |.............?..|

Here I could make a lot more sense from the headers, as the response appears to be similar to a USB HID «Scanned Data Report», which is emitted by USB HID POS barcode scanners when they scanned a barcode, and which is fairly well defined in the USB HID standard:

  • 02 again appears to be some kind of header.
  • 08 is the length of the barcode's payload.
  • ]X0 is an AIM ID, which indicates which type of barcode was scanned;]X0 corresponds to Code 39.
  • DEFALT is the command that was executed.
  • 06 (ASCII ACK) is the status report for this command, in this case a successful response.
  • . again terminates the message, and the rest is filled with zeroes.
  • There is a ? character at position 0x3d`. I couldn't figure out its purpose, and it seems to be there in every single response.

A few more things I learned from analyzing the packet dump:

  • The entire chapter Serial Programming Commands of the manual is applicable via USB as well, especially:
  • The documented concatenation of multiple commands with semicolons (e.g. DEFOVR;DEFALT.) is supported via USB as well.
  • The status code in the response is indicated through ASCII control characters ACK (0x06), NAK (0x15) and ENQ (0x05).
  • EZConfig uses some undocumented configuration commands. For example, it uses the P_INFO. command to retrieve detailed information such as software version numbers from the scanner.

Writing a Configuration Utility

With the things I had learned, I decided to attempt to write my own small configuration utility for these scanners. Since I had never worked with USB before, I approached this as a learning opportunity to gain a deeper understanding of the USB protocol.

However, the main challenge turned out to not be learning USB, but to make the config tool work independently from the device's configuration. Depending on the operation mode the barcode scanner was in, it presented itself differently to the host.

Here is an example in USB HID POS mode:

0c2e:0b07 Metrologic Instruments 1300 Linear Imager
- configuration 0: Default
  - interface 0
    - altsetting 0: interface=0, desc=HID POS class=3 subclass=0 protocol=0
      - endpoint 81: type=interrupt
  - interface 1
    - altsetting 0: interface=1, desc=REM class=3 subclass=0 protocol=0
      - endpoint 83: type=interrupt

Here is the same device, but in PC Keyboard mode:

0c2e:0b01 Metrologic Instruments 1300 Linear Imager
- configuration 0: Default
  - interface 0
    - altsetting 0: interface=0, desc=HID Keyboard Emulation class=3 subclass=1 protocol=1
      - endpoint 87: type=interrupt
  - interface 1
    - altsetting 0: interface=1, desc=REM class=3 subclass=0 protocol=0
      - endpoint 81: type=interrupt

There's two relevant differences in here:

  • The USB product ID changes depending on the configuration. In HID POS mode, it is 0b07, in PC Keyboard mode, it is 0b01.
  • The USB endpoint addresses change as well; in HID POS mode, endpoint 0x81 is the HID POS endpoint, and 0x83 is the configuration endpoint. In keyboard mode, endpoint 0x81 (the same address that was the HID POS endpoint before) becomes the configuration endpoint, whereas the keyboard endpoint is 0x87.

I solved the first issue by hard-coding all vendor and product IDs I had encountered with this device, and having the config tool try all known combinations until a device is found. In a future version I may choose to enumerate all devices on the USB bus and probe all of them for the configuration endpoint.

And this is where the second issue comes in: How to reliably identify the configuration endpoint if its address changes depending on the device's configuration? As it turned out, the description of the interface with this endpoint always was REM (after some digging, I assume this is an abbreviation for Honeywell's «Remote MasterMind» application), and only ever has a single endpoint. Through this description, I was able to correctly identify the configuration endpoint in all device configurations that I was able to try.

With these issues resolved, my configuration tool was now finally working reliably. With this tool, a factory reset (what I had originally set out to perform), as as easy as this:

$ honeywell-config DEFOVR DEFALT
DEFOVR.
DEFALT.

Apart from applying configuration, the tool can also be used to backup and restore the configuration of a barcode scanner:

$ honeywell-config -c -o backup.conf
$ honeywell-config -i backup.conf

The tool and instructions for compilation and usage can be found here.