0

GOAL

I am interested in a USB PDF417 scanner that will automatically a PDF417 barcode, decode the data and send it through USB to the target platform (raspberry pi, PC, etc). Ideally it would send it serial over USB at 9600-8-N-1 and be powered by the USB port (no wall wart), however, I am open to other ideas.

QUESTION

When searching for such a device, what search keywords would be effective to identify suitable candidates to perform the task described above? Ideally, I would be able to configure it to present as either a HID or serial-over-usb device.

STATUS UPDATE

Configured rPi to read HID events from HID scanner: mission-completed. Thank you to all participants: your comments and support are the foundation to my success.

3

Common barcode/2D scanners emulate an USB keyboard and are powered through USB. Ask a POS dealer for a 2D scanner which can read PDF417. All scanners I know of decode the raw data read by default. Raw output died out >30 years ago. (Though there may be scanners which have that as an optional setting.)

RS232 is an option for a lot of devices, but you have to purchase a special cable for roughly 20..50% the price of the scanner, and that one needs an additional external supply when connected to the Pi, because the POS standard is having 12V at some pins of the DB9/RJ45 RS232 port, and the Pi doesn't need 12V and doesn't have that anywhere.

I've never encountered a scanner which does USB-RS232 (e.g FTDI or PL2303 based).

So I recommend to stick to the USB connection and live with the keyboard emulation. You can read out /dev/input/eventX to sample the event codes. Here's a small Tcl script which does that

#!/usr/bin/tclsh

## Open /dev/input/eventX in non-buffered, no-translation mode.
set fd [open [lindex $::argv 0] r]
fconfigure $fd -translation binary -buffering none


## Dictionary holding pressed keys.
set keys [dict create]

## Keycode combination to ASCII dictionary.
set keycodes [dict create 2 1 {42 2} !  3 2 {42 3} @ 4 3 {42 4} # 5 4 {42 5} $ 6 5 {42 6} % 7 6 {42 7} ^ 8 7 {42 8} & 9 8 {42 9} * 10 9 {42 10} ( 11 0 {42 11} ) 12 - {42 12} _ 13 = {42 13} + 16 q {42 16} Q 17 w {42 17} W 18 e {42 18} E 19 r {42 19} R 20 t {42 20} T 21 y {42 21} Y 22 u {42 22} U 23 i {42 23} I 24 o {42 24} O 25 p {42 25} P 26 "\[" {42 26} "\{" 27 "\]" {42 27} "\}" 30 a {42 30} A 31 s {42 31} S 32 d {42 32} D 33 f {42 33} F 34 g {42 34} G 35 h {42 35} H 36 j {42 36} J 37 k {42 37} K 38 l {42 38} L 39 "\;" {42 39} : 40 ' {42 40} \\" 44 z {42 44} Z 45 x {42 45} X 46 c {42 46} C 47 v {42 47} V 48 b {42 48} B 49 n {42 49} N 50 m {42 50} M 51 , {42 51}  53 / {42 53} ?  55 * {42 55} * 57 { } {42 57} { } 28 "\n" 96 "\n"]


## Process the latest event from /dev/input/eventX.
proc sampleEvent {} {
    ## Exit program when device fails (scanner pulled from USB.)
    if {[eof $::fd]} exit

    ## Read event record from kernel driver.
    ## Skip both timestamps, decode type, code, value fields.
    binary scan \
        [read $::fd [expr {2*$::tcl_platform(wordSize)+8}]] \
        x[expr {2*$::tcl_platform(wordSize)}]ssi \
        type code value

    ## Process event by type.
    switch -- $type {
        0 {processSyncEvent [dict keys $::keys]}
        1 {processKeyEvent $code $value}
    }
}


## Key event. Remember key state.
proc processKeyEvent {code value} {
    if {$value} {dict set ::keys $code {}} {dict unset ::keys $code}
}


## Sync event: add keypress to line.
proc processSyncEvent {keys} {
    ## Skip event when the pressed keycode combination has no ASCII equivalent e.g shift only.
    if {![dict exists $::keycodes $keys]} return

    ## Check for return keycode
    if {$keys ne 28} {
        ## No. Append ASCII char to line buffer.
        append ::line [dict get $::keycodes $keys]
    } {
        ## Yes. Output line and clear buffer.
        puts $::line
        set ::line {}
    }
}


## Sample event whenever the device node becomes readable.
fileevent $fd readable sampleEvent

## Start Tcl event loop.
vwait endless

The problem you still have is the scanner is recognized as a keyboard. You can work around that by advising X not to use the stardard VT keyboard driver but /dev/input/eventY (eventY the driver node of the real keyboard) but that has the drawback you cannot easily pull/plug the keyboard or use more than one without playing with xorg.conf or the xinput utility. Plus, this is only about X. In the console, you will still see the scanner input as keypresses.

Because that bothered me, I've made a small kernel patch to make the kernel's VT subsystem to ignore "keyboards" from a blacklist. They are still available through /dev/input/eventX of course.

--- linux-3.9.4.orig/drivers/tty/vt/keyboard.c  2013-05-24 20:45:59.000000000 +0200
+++ linux-3.9.4/drivers/tty/vt/keyboard.c   2014-01-16 18:15:26.941819341 +0100
@@ -1398,9 +1398,49 @@
    schedule_console_callback();
 }

+
+/* Blacklist for "keyboards" not to use as vt input. Barcode scanners, chipcard readers, keylocks and the PS/2 input on some machines. */
+static const struct input_id kbd_match_blacklist[] = {
+   {
+       /* PS/2 keyboard (e.g. keyboard wedge barcode scanners) */
+       .bustype = BUS_I8042,
+       .vendor  = 0x0001, /* PS/2 keyboard vendor id */
+       .product = 0x0001, /* PS/2 keyboard product id */
+       .version = 0xffff, /* don't care */
+   },
+   {
+       /* USB-TMU barcode scanner */
+       .bustype = BUS_USB,
+       .vendor  = 0x1130,
+       .product = 0x0001,
+       .version = 0xffff, /* don't care */
+   },
+   {
+       /* MagTek Mini Swipe Reader */
+       .bustype = BUS_USB,
+       .vendor  = 0x0801,
+       .product = 0x0001,
+       .version = 0xffff, /* don't care */
+   },
+   { .bustype = 0 } /* Terminating entry. */
+};
+
 static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
 {
    int i;
+   const struct input_id *id;
+
+   for (id = kbd_match_blacklist; id->bustype != 0; id++) {
+       if ((id->bustype == dev->id.bustype)
+           && ((id->vendor == dev->id.vendor) || (id->vendor == 0xffff))
+           && ((id->product == dev->id.product) || (id->product == 0xffff)) 
+           && ((id->version == dev->id.version) || (id->version == 0xffff))) {
+               pr_warning("Ignoring blacklisted bustype=0x%04x vendor=0x%04x product=0x%04x version=0x%04x\n",
+                   dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
+               return false;
+           
+       }
+   }

    if (test_bit(EV_SND, dev->evbit))
        return true;

You can find out the correct vendor and product ids from

lsusb
or
udevadm info -a -n /dev/input/event…

Happy patching. And of course, you should make a custom udev rule for getting the correct permissions and a nice, stable symlink.

SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTR{../name}=="USB-TMU" \
    GROUP="users", MODE="640", SYMLINK+="barcodescanner"

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.