0
\$\begingroup\$

I am trying to read serial data from this OEM barcode scanner module: https://www.barcodescannermodule.com/sale-11330019-lv3085-mini-barcode-scanner-module-usb-ttl232-interface-for-pdas-tablets.html

and I am confused by the data formatting of the results: 8 bytes of data that fits my expectations, then 8 bytes of zeroes.

I am working under Linux. The device is connected via USB, and it appears as a HID Keyboard in the devices list: /dev/hidraw0.

According to the (very meager) documentation available for the device: "The default settings of the engine are 9600bps, no parity check, 8 data bits, 1 stop bit, and no flow control. The engine uses 8-bit registers.". This is also how I have tried to configure my read from the serial port.

Code used to read serially from the hidraw0 device:

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>

int main() {
  int fusb = open("/dev/hidraw0", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fusb < 0) {
    printf("\n Error in opening USB device");
  } else {
    printf("\n USB device opened successfully");

    /**
     * Set the data transmission options
     */ 
    struct termios options;
    // Get the current options for the port
    tcgetattr(fusb, &options);
    // Set R/W at 9600 baud
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
    // Set "no parity"
    options.c_cflag &= ~PARENB;
    // Set stop bits = 1, so we clear the CSTOPB bit.
    options.c_cflag &= ~CSTOPB;
    // Set data bits = 8
    options.c_cflag &= ~CSIZE;
    options.c_cflag |=  CS8;
    // Disable software flow control
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    // Set the modified options
    tcsetattr(fusb, TCSANOW, &options);

    // Start reading and printing out what we read
    fcntl(fusb, F_SETFL, 0);
    int step = 0;
    do {
      char read_buffer[64];
      int bytes_read = read(fusb, &read_buffer, sizeof(read_buffer) - 1);
      printf("\nBytes read in step %d: %d", step, bytes_read);
      for (int i = 0; i < bytes_read; i++) {
        printf("\nByte %d: %02X", i, read_buffer[i]);
      }
      step++;
    } while (1);
}

}

And this is what is printed out:

Bytes read in step 0: 8
Byte 0: 00
Byte 1: 00
Byte 2: 27
Byte 3: 00
Byte 4: 00
Byte 5: 00
Byte 6: 00
Byte 7: 00
Bytes read in step 1: 8
Byte 0: 00
Byte 1: 00
Byte 2: 00
Byte 3: 00
Byte 4: 00
Byte 5: 00
Byte 6: 00
Byte 7: 00
Bytes read in step 2: 8
Byte 0: 00
Byte 1: 00
Byte 2: 21
Byte 3: 00
Byte 4: 00
Byte 5: 00
Byte 6: 00
Byte 7: 00
Bytes read in step 3: 8
Byte 0: 00
Byte 1: 00
Byte 2: 00
Byte 3: 00
Byte 4: 00
Byte 5: 00
Byte 6: 00
Byte 7: 00   
...

The hex values printed in the even reading steps match my expectations: here, I was reading a QR code that started with "04", which matches the 27h, 21h read in steps 0 and 2, using hex -> decimal and then this mapping, according to the official USB HID usage tables for keyboards (see also here):

{ 4: 'a', 5: 'b', 6: 'c', 7: 'd', 8: 'e', 9: 'f', 10: 'g', 11: 'h', 12: 'i', 13: 'j', 14: 'k', 15: 'l', 16: 'm', 17: 'n', 18: 'o', 19: 'p', 20: 'q', 21: 'r', 22: 's', 23: 't', 24: 'u', 25: 'v', 26: 'w', 27: 'x', 28: 'y', 29: 'z', 30: '1', 31: '2', 32: '3', 33: '4', 34: '5', 35: '6', 36: '7', 37: '8', 38: '9', 39: '0', 44: ' ', 45: '-', 46: '=', 47: '[', 48: ']', 49: '\\', 51: ';' , 52: '\'', 53: '~', 54: ',', 55: '.', 56: '/'  }

I cannot account for the zeroes in the steps 1 and 3, however.

As a long-term StackOverflow user I am aware that my question is a bit nebulous, but I would like to know if this is a data formatting issue or something else I have overseen.

Bonus question: why are the expected values always in byte 2 of the read value?

\$\endgroup\$
  • \$\begingroup\$ The device is for 1D and 2D right? Did you test it with different barcode types? Maybe there is a way to setup the "expected bar code type", did you check for that? \$\endgroup\$ – Christian B. May 6 at 8:47
  • \$\begingroup\$ Yes, it's for 1D and 2D. It comes with a manual with 1D barcodes used for configuring the options, but none are usable (tried some of the obvious options, like changing the beep types or their loudness, but nothing changes). That's why I am trying to communicate with it serially and program it that way. Unfortunately, at the moment, I don't even know in what format I am reading, so I'm not sure what to write to it :-) Thanks for the idea, though, this is an aspect that I did not think about anymore. \$\endgroup\$ – ACEG May 6 at 8:58
  • \$\begingroup\$ could not find any information about the LV3085 but a rather big document about the LV3296. Not sure if it is any help: download.mikroe.com/documents/datasheets/… . Else you could try to get information via their webchat at rakinda. "Sunny" seems to be very eager to help... \$\endgroup\$ – Christian B. May 6 at 9:02
  • 1
    \$\begingroup\$ You are confusing two completely different interfaces. USB HID is not a "serial port" and would send what keyboard keystrokes do. While a serial mode would send ASCII. Typically you can switch modes by scanning a magic barcode and changing the wiring harness. \$\endgroup\$ – Chris Stratton May 6 at 9:04
  • \$\begingroup\$ @ChrisStratton Yeah, and that's exactly my problem -- "scanning a magic barcode" from the device's user manual does not do anything; it just beeps twice aka "cannot read". Ironically, I can correctly read any barcodes (random books, coke cans, etc.), except the device's own configuration codes. \$\endgroup\$ – ACEG May 6 at 9:07
4
\$\begingroup\$

It seems like the mystery data format is the official USB HID keypress format: https://wiki.osdev.org/USB_Human_Interface_Devices

The first eight bytes which are read correspond to a key press event (the value for a keypress is according to the USB HID usage tables for keyboards):

Offset  Size    Description
0       Byte    Modifier keys status.
1       Byte    Reserved field.
2       Byte    Keypress #1.
3       Byte    Keypress #2.
4       Byte    Keypress #3.
5       Byte    Keypress #4.
6       Byte    Keypress #5.
7       Byte    Keypress #6.

The next eight bytes correspond to the state after a key depress event; the barcode reader always "reads" one "pressed" key, so, after it was "depressed", nothing is pressed anymore and these eight bytes are all zero.

As an example that ties it together, I read a QR code based on the text 'abc'. From the USB HID usage tables for keyboards, we know that the hex value for 'a' is 04h, for 'b' it's 05h, and for 'c' it's 06h; sure enough, this is what the device outputs when reading this QR code:

$ sudo hexdump -C /dev/hidraw0
00000000  00 00 04 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 05 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 06 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 28 00 00 00 00 00  00 00 00 00 00 00 00 00  |..(.............|
00000040  00 00 51 00 00 00 00 00  00 00 00 00 00 00 00 00  |..Q.............|

The final two values 28h and 51h are the only part that I don't fully understand yet (in the USB HID usage table, 28h is 'Keyboard Return' and 51h is 'Keyboard DownArrow'). However, they seem to be sent at the end of any barcode/QR code read, so they don't pose any problems.

\$\endgroup\$
  • 1
    \$\begingroup\$ No real mystery about the endings, it is made so you can fill a table column in a spreadsheet or similar software that doesn't realize it is not a keyboard. \$\endgroup\$ – Chris Stratton May 6 at 14:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.