Barcode Reader with YUN

Folks,
The subject line of this post is probably all too familiar and I've been searching for far too long for my answer so I'm posting it as a new topic - hopefully someone can get me to the right info.....

Here is what I want to do:

  • Connect a barcode wand to my YUN Shield
  • Read my barcoded data
  • Decide from the data where I want it to position my cursor on a web-based javascript form
  • Move the cursor to the desired input cell and enter the data into that cell.

I hope you can see the potential in this to automate form filling using a barcode wand and Yun as a wedge. My biggest obstacle at this point is finding a simple solution to connect the barcode wand and read the data. I've read through much dialogue and some "solutions" but they all seem so complicated, I'm hoping not to have to go down that path. Has there been any recent development in the field of barcode interfacing that I should see?

FYI, the data I am reading is alpha-numeric but I would codify it with a special character at the beginning so I can read that character and decide what field I need to locate on the web-served input form. It should be a fairly simple matter then to run codes into the computer as a keyboard wedge to move my cursor around and input the data. I actually have access to the programmers who designed the input form so they can help me with that.

Is there a simple method out there to connect and use a barcode wand with the YUN Shield (as a keyboard wedge)?

Thanks :slight_smile:

BTW - to anticipate some questions - This is a USB scanner that I have. Its the Motorola STB4278. I do understand that certain criteria must be met for a barcode wand to work at all but I don't know how to determine if this one is applicable. Its an awesome scanner that works well at a distance and reads well from a computer monitor as well.

I’m doing something rather similar, but without the keyboard wedge output (my first version used a network socket to talk to an application on a PC, my current version does all of the processing locally on the Linux side and displays results on a character LCD driven by the sketch.)

It sounds like your first stumbling block is the barcode reader. I use a Symbol LS2104 scanner that has a USB interface and acts as a keyboard wedge. This is plugged into the Host USB port (the large Type A connector) for the Linux side. I found this thread to be very helpful in getting the reader recognized by Linux: Interface barcode scanner with arduino yun

Then, it was a matter of actually reading the barcodes. Using a few different resources, I was able to come up with the this Python script that processes individual low-level HID keyboard reports.

#!/usr/bin/python -u
# Note -u parameter above, which makes this script run in ubuffered mode.
# Without it, the serial output to the Process object that called it is
# buffered until a lot of data is queued up, and that is not tolerable here.

import struct
import time
import sys

# This script expects one argument, the event id number.

# default values
infile_path = "/dev/input/event0"
key = "0"

# Update the values if there is an argument
if len(sys.argv) > 1:
        key = sys.argv[1]
        infile_path = "/dev/input/event" + key

# Define the structure of the event record:
#     l = long int         Time value, seconds
#     l = long int         Time value, microseconds
#     H = unsigned short   Event type
#     H = unsigned short   Event code
#     I = unsigned int     Event value
FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)


# a lookup table to translate a key code to an ASCII character.
# Values that are a blank string are essentially ignored.
KeyLookup = [
   '',       #  0   KEY_RESERVED
   '',       #  1   KEY_ESC
   '1',      #  2   KEY_1
   '2',      #  3   KEY_2
   '3',      #  4   KEY_3
   '4',      #  5   KEY_4
   '5',      #  6   KEY_5
   '6',      #  7   KEY_6
   '7',      #  8   KEY_7
   '8',      #  9   KEY_8
   '9',      #  10  KEY_9
   '0',      #  11  KEY_0
   '',       #  12  KEY_MINUS
   '',       #  13  KEY_EQUAL
   '',       #  14  KEY_BACKSPACE
   '',       #  15  KEY_TAB
   'Q',      #  16  KEY_Q
   'W',      #  17  KEY_W
   'E',      #  18  KEY_E
   'R',      #  19  KEY_R
   'T',      #  20  KEY_T
   'Y',      #  21  KEY_Y
   'U',      #  22  KEY_U
   'I',      #  23  KEY_I
   'O',      #  24  KEY_O
   'P',      #  25  KEY_P
   '[',      #  26  KEY_LEFTBRACE
   ']',      #  27  KEY_RIGHTBRACE
   '',       #  28  KEY_ENTER
   '',       #  29  KEY_LEFTCTRL
   'A',      #  30  KEY_A
   'S',      #  31  KEY_S
   'D',      #  32  KEY_D
   'F',      #  33  KEY_F
   'G',      #  34  KEY_G
   'H',      #  35  KEY_H
   'J',      #  36  KEY_J
   'K',      #  37  KEY_K
   'L',      #  38  KEY_L
   '',       #  39  KEY_SEMICOLON
   '',       #  40  KEY_APOSTROPHE
   '',       #  41  KEY_GRAVE
   '',       #  42  KEY_LEFTSHIFT
   '\\',     #  43  KEY_BACKSLASH
   'Z',      #  44  KEY_Z
   'X',      #  45  KEY_X
   'C',      #  46  KEY_C
   'V',      #  47  KEY_V
   'B',      #  48  KEY_B
   'N',      #  49  KEY_N
   'M',      #  50  KEY_M
   '',       #  51  KEY_COMMA
   '.',      #  52  KEY_DOT
   '/' ]     #  53  KEY_SLASH

TERMINATOR = 51 # key code for end of barcode (KEY_COMMA)

barcode = ""

#open event input device file in binary mode
in_file = open(infile_path, "rb")

# read the first event
event = in_file.read(EVENT_SIZE)

# keep looping as long as there are events read
while event:

    # decode the event using the defined structure format
    (tv_sec, tv_usec, type, code, value) = struct.unpack(FORMAT, event)

    if type == 1 and value == 1:          # Check whether this is a simulated key press.
        if code == TERMINATOR:            # Is this the barcode terminator character?
            print barcode                 # Got the end of the barcode. Print it so it's received by the sketch.
            barcode = ""                  # Clear out the buffer, ready for the next code.
        else:
            if code < len(KeyLookup):     # Not the end. If the code is in range of the lookup tabke, add the chracter to the buffer.
                barcode = barcode +  KeyLookup[code]

    event = in_file.read(EVENT_SIZE)      # Wait for another event

in_file.close()                           # No event read, close file and exit.

I’m using very simple Code39 barcodes, that just use digits, upper case letters, and a few special symbols, so the Python script is only set up for those few characters. Of course, it could be expanded to handle more. To make parsing easier, I set up the scanner to add a prefix and suffix to every code that it reports, using characters that are not part of the regular barcode alphabet - in my case, I chose ‘[’ as the prefix, and ‘]’ as the suffix.

If you just run the Python code from the command line, it will echo any barcodes scanned to the terminal. The way I use it in my system is that my sketch uses a Process object to run the Python script asynchronously. Then in loop(), it calls Process.available() to see if the script has returned any data, and if so, it reads the data from the process into a character array. If it sees a ‘[’ character, it resets the character array index to zero, so that it starts looking for a new code. When it sees a ‘]’ character, it knows it has a complete code and processes it as needed.

An instance of a Process object named EventProcess is declared globally, and this code in setup() starts the process:

   EventProcess.begin("/mnt/sda1/barcode.py");
   EventProcess.addParameter(String(EventID));
   EventProcess.runAsynchronously();

This is called from within loop(), where Barcode is a globally defined character array, and Index is a globally defined byte variable:

   while (EventProcess.available())
   {
      // Read the character
      char ch = EventProcess.read();

      // Is this the beginning of a barcode?
      if (ch == '[')
         Index = 0; // Reset the buffer

      // Store the character in the buffer
      Barcode[Index] = ch;

      // Bump the index
      Index++;

      // Don't overflow the buffer, and make sure there is room for the NULL terminator.
      if (Index >= sizeof(Barcode))
         Index = sizeof(Barcode) - 1;

      // Is this the end of a barcode?
      if (ch == ']')
      {
         // Null terminate the barcode string
         Barcode[Index+1] = '\0';
         
         // Process the barcode string as needed here.

         // Reset the buffer
         Index = 0;
      }
   }

Is this anything like what you are looking to do?

Where do you declare String [eventID] ??

ERIKMONHUI:
Where do you declare String [eventID] ??

You don’t.

Are you referring to this bit of code?

ShapeShifter:
An instance of a Process object named EventProcess is declared globally, and this code in setup() starts the process:

   EventProcess.begin("/mnt/sda1/barcode.py");

EventProcess.addParameter(String(EventID));
  EventProcess.runAsynchronously();

Note that this usage of String is followed by round parenthesis, not the square brackets you used in your post. Square brackets are used to access or define an array, String here is not an array, it is a type name.

With parenthesis, the construct String([i]<something>[/i]) is calling the String type constructor to convert the argument into a string (a sequence of characters.) In this case, EventID is an integer, and String(EventID) is converting that integer to a string to match the expected data type for arguments to addParameter().

EventID is either an integer type variable or constant defined somewhere in your code. Or, you could replace EventID with a literal constant such as 0. Of course, if you are going to hard code a value like that, it makes more sense to just start with a string in the first case, rather then using a conversion: instead of EventProcess.addParameter(String(0))l it would be more efficient to just use EventProcess.addParameter("0");

This is passed as a parameter to the Python script described above, and is used to specify which device the script should be processing. For example, if EventID has the value 1, the Python script will be reading from /dev/input/event1/