Introduction: Arduino and CueCat Barcode Scanner
I've had a cuecat barcode scanner sitting around for over 10 years. Basically it connects to a PS2 port (apparently there is a USB version) like a keyboard and spits out a barcode when scanned. Nice!. The annoying thing is that it is "encrypted". What I set out to do is;
- unencrypt the barcode in software on the arduino
- i didn't want to cut into the Cuecat in case I broke it, not hard to replace, but that's not the point ;-)
- get it to write only the bar code to the serial port, and I can use some terminal emulator (TeraTerm,Putty or SecureCRT) to write the data to a file as I furiously scan like a boss all items with a barcode in the house.
Step 1: Connecting the CueCat to Arduino
The cable connected to the CueCat is a Y cable that connected to a PC PS/2 port. The connection to the PC is a male adapter. There is also a female, that allows the PC's keyboard to share the port.
There is no continuous path between the 2 ports (Except Power and GND) as a multimeter and continuity test confirmed. So using the female port as a way to access the cuecat signal did not work.
PS2 female connectors are hard to find these days, so I cut the female connector from the cuecat and used that to break out the wires...
The Cue cat cable has 6 wires, marked on the board as 1-6
1. Brown (+5V)
2. Red (DATA Female connector)
3. Black (Clock Female Connector)
4. Orange (DATA Male connector)
5. Yellow (Clock Male Connector)
6. Black - Cable is thicker than other black (Ground)
When cut, the female adapter, has the following which will map to the connector inside the Cuecat as follows
1. Brown (+5V)
2. Red (DATA Female connector) to Orange(pin4)
3. Black (Clock Female Connector) to Yellow (pin5)
4. Bare wire (GND)
I tinned the wires with flux and solder to make them a little more durable, and wired them to a terminal shield on the Arduino.
Step 2: Getting the First Code
Since the Cuecat emulates the PS2 Keyboard, I used the Arduino PS2 library and examples to get a look at the first bar-codes.
The only thing to watch out for is;
- The CLK is used as interrupt, and so ensure you connect to a pin that supports interrupts
e.g. on the Mega 2560 http://arduino.cc/en/Main/ArduinoBoardMega2560
External Interrupts: 2 (interrupt 0), 3 (interrupt 1), 18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), and 21 (interrupt 2).
I used Pin 3... Which is a bit annoying as now all the pins are not on same side of the board :-( (first world problems)
And a few swipes, check all wires are connected right and ...
TIP: Look at ASCII codes, NOT printable characters...
You can see I played with the code a little, as when looking at output there are always non printable characters, so I wrote the code to show the ASCII code.
OUTPUT ASCII value -> printed Character
International Keyboard Test:
[deleted for brevity...]
Note that there does not seem to be anything strange at the start, but the end is /13 which is a Carriage return, ie, end of the code
I did expect to see ALT-F10 being sent as on my linux box it kept minimising and expanding the window on each scan, and that is the keystroke that does that... if the Arduino doesn't see it, then I am OK with that...
Step 3: Decoding the Barcode
<SERIAL> is the unique serial number that each cuecat has. The idea being that the company distributing them can track what you scan. I don't see a need for this, so will ignore it.
<CODE> is the BarCode type. I dont have an exhaustive list but I have seen "E13", "IB5" etc. I would think this may help decide where to look up the bar code, as I imagine that there are many sources of barcode data. I imagine that books, food products and teh barcodes you print may be in different formats. I know that some barcodes are numbers only, some are a mix of letters and numbers
<BARCODE> the interesting bit :-)
OK so how to decode...
I trolled the internet and found lots of example code in various (non processing/arduino) format with little explanation. So I grabbed a reliable version that worked well on my Linux Box that was written in PERL.
Here is the amazingly terse PERL script by Larry Wall
To describe it, and understand it, I did it in excel as follows... the file is attached to play with.
1) Break the code and break into the 2 pieces described above, and decrypt one at a time as described
2) Each set of 4 characters is "unencrypted" into 3. So the length of the final output is 3/4 of the input string, Round down if necessary. (encryption going the other way clearly needs to pad out characters to ensure no information is lost)
3) Take the 4 characters and map to ASCII
- effectively "a-zA-Z0-9+-" maps to ASCII characters 32-96 (ie SPACE ' ' to '_')
- so E, N, b, X map to >, G, !, X respectively
I found it a problem to keep converting back and forth between ASCII characters and Codes (E.g. E<-> 69) as some non printable characters were hard to troubleshoot and working out which non printable character was being printed is tough. So in the final code I worked exclusively in ASCII codes until the last step. IE the yellow lines were useful while reverse engineering this, but are not part of the final code...
4) Subtract 32 from the ASCII code
- >, G, !, X has teh ASCII code of 62,71,33,81
- Subtracting 32 gives us 30,39,1,49
5) Treat the above characters and ASCII codes as 6 bit numbers (4 x 6 = 24 bits)
- 30 gives us 01110, so
- 30,39,1,49 gives us 0 1 1 1 1 0 1 0 0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 1
6) Treat the binary string as a string of 8 bit characters, this is how it becomes 3/4 of the size! (3 x 8 = 24 bits)
- 0 1 1 1 1 0 1 0 0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 1
- 122, 112,113 which is z,p,q in ASCII format
7) Take each of the 3 codes and Exclusive OR it with 67 = 01000011
- 122 XOR 67 = 57
122 = 01111010
67 = 01000011
00111001 = 57
- 122, 112,113 becomes 57,51,50
8) Convert to ASCII
- 57,51,50 becomes 932, which is the first 3 digits of my barcode!!!!
9) repeat for each 4 digits until you get a '.' :-)
Step 4: Putting It All Together
I made the format CSV style so I can cut and paste into EXCEL or upload easily...
I tried to make it into a library, but it is buggy and I ran out of time :-(
I will add the library later if I get it done...
Step 5: Last Points
As I was finalizing I noticed some errors crept in. the cucat seemed to scan in some incorrect characters. the deencryption is working reliably, but characters read in were bad. not sure If I broke something poking around inside it.
If you try it and it works, let me know.