A Python driver for the Symbol CS 1504 bar code scanner

One of my cousins works for Symbol, the world’s largest bar code reader manufacturer. The fashionable action today is in RFID, but the humble bar code is relatively untapped at the consumer level. The unexpected success of Delicious Library shows people want to manage their collection of books, CDs and DVDs, and as with businesses, scanning bar codes is the fastest and least error-prone way to do so. Delicious Library supports scanning bar codes with an Apple iSight camera, but you have to wonder how reliable that is.

If you want something more reliable, you need a dedicated bar code scanner. They come in a bewildering array of sizes and shapes, from thin wands to pistol-like models or flat ones like those used at your supermarket checkout counter. For some reason, the bar code scanner world seems stuck in the era of serial ports (or worse, PS/2 keyboard wedges), but USB models are available, starting at $70 or so. They emulate a keyboard – when you scan a bar code, they will type in the code (as printed on the label), character by character so as to not overwhelm the application, and follow with a carriage return, which means they can work with almost anything from terminal-based applications to web pages. Ingeniously, most will allow you to program the reader’s settings using a booklet of special bar codes that perform changes like enabling or disabling ISBN decoding, and so on.

The problem with tethered bar code readers is, they are not very convenient if you are trying to catalog items on a bookshelf or read in UPC codes in a supermarket. Symbol has a unit buried deep inside its product catalog, the CS 1504 consumer scanner. This tiny unit (shown below with a canister of 35mm film for size comparison) can be worn on a key chain, although I would worry about damaging the plastic window. Most bar code readers are hulking beasts in comparison. It has a laser bar code scanner: just align the line it projects with the bar code and it will chirp once it has read and memorized the code. The memory capacity is up to 150 bar code scans with timestamps, or 300 without timestamps. The 4 silver button batteries (included) are rated for 5000 scans — AAA would have been preferable, but I guess the unit wouldn’t be so compact, but it is clear this scanner was not intended for heavy-duty commercial inventory tracking purposes.

I bought one to simplify the process of listing books with BookCrossing (even though their site is not optimized for bar code readers), but you have other interesting uses like finding out more about your daily purchases such as nutritional information or whether the company behind them engages in objectionable business practices. I can also imagine sticking preprinted bar-coded asset tracking tags on inventory (e.g. computers in the case of an IT department), and keeping track of them with this gizmo. People who sell a lot of books or used records through Amazon.com can also benefit as Amazon has a bulk listing service to which you can upload a file with barcodes. An interesting related service is the free UPC database.

Symbol CS 1504
You can order the scanner in either serial ($100) or USB ($110) versions, significantly cheaper than the competition like Intelliscanner (and much smaller to boot). I highly recommend the USB version, even if you have a serial port today — serial ports seem to be going the way of the dodo and your next computer may not have one. The USB version costs slightly more, but that’s because they include a USB-Serial adapter, and you can’t get one retailing for a mere $10. The one shipped with my unit is the newer PN50 cable which uses a Prolific 2303 chipset rather than the older Digi adapter. Wonder of wonders, they even have a Mac OS X driver available.

The scanner ships without any software. Symbol mostly sells through integrators to corporations that buy hundreds or thousands of bar code scanners for inventory or point of sale purposes, and they are not really geared to be a direct to consumer business with all the customer support hassles that entails. There are a number of programs available, mostly for Windows, but they don’t seem to have that much by way of functionality to justify their high prices, often as expensive as the scanner itself.

Symbol does make available a SDK to access the scanner, including complete documentation of the protocol used for the device. While you do have to register, they do not make you go through the ridiculous hoops you have to pass to access to the Photoshop plug-in SDK or the Canon RAW decoding SDK. The supplied libraries are Windows-only, however, so I wrote a Python script that works on both Windows and Mac OS X (and probably most UNIX implementations as well, although you will have to use a serial port). The only dependency is the pySerial module.

By default, it will set the clock on the scanner, retrieve the recorded bar codes, correct the timestamps for any drift between the CS 1504’s internal clock and that of the host computer, and if successful clear the unit’s memory and dump the acquired bar codes in CSV format to standard output. The script will also decode ISBN codes (the CS 1504 does not appear to do this by itself in its default configuration). As it is written in Python, it can easily be extended, although it is probably easier to work off the CSV file.

The only configuration you have to do is set the serial port to use at the top of the script (it should do the right thing on a Mac using the Prolific driver, and the Windows driver seems to always use COM8 but I have no way of knowing if this is by design or coincidence). The program is still very rough, specially as concerns error recovery, and I appreciate any feedback.

A sample session follows:

ormag ~>python cs1504.py > barcodes.csv
Using device /dev/cu.usbserial...  connected
serial# 000100000003be95
reading clock for drift
clock drift 0:00:01.309451
resetting scanner clock... done
reading barcodes... done (2 read)
clearing barcodes... done
powering down... done

ormag ~>cat barcodes.csv
UPCA,034571575179,2006-03-27 01:08:48
ISBN,1892391198,2006-03-27 01:08:52

Update (2006-07-21):

At the prompting of some Windows users, I made a slightly modified version, win_cs1504.py, that will copy the barcodes to the clipboard, and also insert the symbology, barcode and timestamp starting on the first free line in the active Excel spreadsheet (creating one if necessary).

Update (2007-01-20):

Just to make it clear: I hereby place this code in the public domain.

Update (2009-11-06):

For Windows users, I have put up videos describing how to install the Prolific USB to serial driver, Python and requisite extensions, and how to use the program itself.

Update (2012-07-05):

I moved the script over to GitHub. Please file bug reports and enhancement requests there. Fatherhood and a startup don’t leave me much time to maintain this, so I make no promises, but this should allow people who make fixes to contribute them back (or fork).

This entry was posted in Mac, Python and tagged . Bookmark the permalink.

29 Responses to A Python driver for the Symbol CS 1504 bar code scanner

  1. Enrique says:

    Hi, as you have been programming on this device. Let me ask you something. Is there any way that I can use it as a regular serial barcode scanner? So, every time I scan a barcode it is send to the serial port and NOT to the memory? Because I’m interested to add this to a bluetooth device and convert it to bluetooth. Let me know what do you think about it. And in the case it is possible is there anyway to make Windows mobile to receibe the data? Thanks.-

    • majid says:

      The CS1504 protocol manual mentions the possibility of using a polling mode by asserting the HOST_IN serial line, but recommends against it because the batteries will be quickly depleted. Keep in mind it is really a RS-232C serial scanner, and unlike USB or PS/2 wedges, the host interface cannot provide power to it. If that’s what you want, a simple USB wand scanner would be a better option – no batteries to mess around with, and quite cheaper to boot.

      • Juri Munkki says:

        First of all: thanks for the work on the Python code. Having some working reference code helped us get our Lua version working.

        I managed to get our Lua test version to work sort of like a normal scanner, but it has to poll the reader regularly. After the initial interrogate/upload/clear cycle, the reader is shut down and then regularly interrogated. What happens then is that the reader doesn’t respond to the interrogate unless it actually has some stored bar codes. If the interrogate succeeds, the Lua program uploads the bar codes, clears the memory and shuts down the reader again.

        Battery life is probably affected, but I don’t know by how much.

  2. Nick says:

    Do you know if you can use it only with a micro USB cable? Or do I need to use the usb to serial cable, and then connect it serial to the CS1504.

    • majid says:

      On the scanner side it is strictly serial, even if the socket used is a mini USB type connector. You cannot connect it directly to USB on your computer, only to a serial port of the computer using the supplied cable, or to the serial port of a USB Serial adapter.

  3. Nick says:

    Hi Majid,

    Thanks for your response about the USB cable. I now have the CS1504 working with some library software, and would like to explore using the scanner to import into excel. I have read your post, and watched the video. I installed Python 2.6 and downloaded the windows py script. Also, the “virtual” (USB to Serial) is COM9. However, when I run the script I do not get anything in Excel (2007). Any suggestions? I am using Windows Vista 64bit.

  4. Jo says:

    Many thanks for this script.

    I have some problems using it with a german Win XP. I always have to delete the clipboard to read the scanner.
    Also there is a problem to write the data to excel. I get an error in line 358 and an error in dynamic.py in line 512.
    Maybe anyone can help me to fix this?

    • majid says:

      Unfortunately, as I founded a new startup, I barely have the time to sleep, let alone help. If this function is a must-have for you, you could try to find a local Python developers’ group and ask them for assistance.

  5. Jo says:

    I found the problem: I still use Office 2000.
    I skipped your excel-import an used xlwt (www.python-excel.org) to write a xls-file.

  6. dingus9 says:

    So in python 2.6> you can fix the “DeprecationWarning: ‘H’ format requires 0 <= number H’, (~value) & 0xFFFF) #mask off extra bits with an & 0xFFFF

    Linux ttyS0 vs ttyUSB0

    In Linux, depending of which connection you are using, you must manually set the serial connection for this script to work. Pretty straight forward though.

    • dingus9 says:

      The fix should be:

      return struct.pack(‘>H’, (~value) & 0xFFFF) #mask off extra bits with an & 0xFFFF

  7. Auke Huisman says:

    Every script I run has the same problem:

    print ‘%s,%s,%s’ % (symbology, code, str(timestamp).split(‘.’)[0])

    SyntaxError: invalid syntax

    What is wrong?

    Thanks for your help

    • majid says:

      It looks like regular quotes ‘%s’ have been converted into “smart quotes” ‘%s’ (note how they are angled differently), presumably by an over-zealous word processor. Unfortunately, what is typographically correct is not syntactically correct. You should use a plain text editor that does not try to rewrite your quotes, e.g. TextEdit on the Mac, Notepad on Windows or Emacs on Linux/UNIX.

    • jumperpunk says:

      You’re quotes are probably fine. It is the comment system that changed it from your copy/paste.

      You are probably using Python 3 instead of Python 2. Change the first line to
      #!/usr/bin/env python2

  8. Pingback: bar-code scanners, serial-to-usb and python « The Legend, The Machine, Corrie

  9. fraymel says:

    This code works great!. Thanks for all of the effort!

  10. Rob says:

    Code works great, thank you!

    I see it advertised on the CS1504 the ability to turn off timestamp in order to store more data. Do you have any idea how to accomplish this? I’m assuming it has to be scripted as a command to the device, but I am not familiar with it or the SDK.

  11. Lock4key says:

    Using the python cs1504.py code for a OPN2001? Use parity=serial.PARITY_NONE instead of parity=serial.PARITY_ODD.

  12. RMFlagg says:

    I am trying to run this under Ubuntu 12.04 but I get the following error:

    Traceback (most recent call last):
    File “cs1504.py”, line 318, in
    assert crc16(‘\x01\x02\x00’) == ‘\x9f\xde’, \
    File “cs1504.py”, line 302, in crc16
    return struct.pack(‘>H’, ~value)
    struct.error: integer out of range for ‘H’ format code

    I don’t have the programming chops to get this fixed. Can anybody help?

  13. Fred says:

    Thanks for this script.
    I’m using it on Mac OSX 10.6.8 for some time now and its working fine !
    But I just tried it on mac OSX 10.8.2 and I have a problem. CS1504 led blink, then the script stop at “Using device /dev/cu.usbserial” for about 1 min then I get “IOError”
    Any ideas ?

  14. Tamas says:

    You are a lifesaver man!


  15. Sri says:

    Thanks for the Python script, which helped me to solve my problem using rxtxSerial and Java.

  16. Larry says:

    Fred: A touch too late but I determined that, for some reason, the current OS X driver from Prolific is not honoring the parity setting. I am on Mavericks.
    I finallly got things working by using the open source driver (http://sourceforge.net/projects/osx-pl2303/) but even there I had problems which I solved by adding self.ser.setDTR(1) to the init sequence. Also, the name of the driver is ‘/dev/tty.NoZAP-PL2303-0000105D’ rather than ‘/dev/cu.usbserial’.
    I ran into additional problems after changing the battery and had to muck with the script (one time) to ensure scanner.set_time() and scanner.clear_barcodes() get called.

    • Jun says:

      What kinds of cable do you use? I tried cheap PL2303 based USB-to-Serial converter and just connect GND, TX, and RX. But it did not respond when I called interrogate(). Any tips and information will be appreciated. Thanks in advance.

  17. Patrik Karisch says:

    Thanks to your phyton script (and the linux opticon serial driver) I made an Opticon OPN-2001 work directly with the android USB-Host API and can get now barcodes in my android application. In the next week I’ll publish this as an Open Source Library 🙂

  18. Yiorgos says:


    I am interested in retrieving some (possibly) deleted data and I was wondering whether there is a code to basically do a memory dump from the scanner.


  19. Are Egner-Kaupang says:

    Thanks for this script!
    I am using it to read barcodes from the Opticon OPN 2001. The first read after connecting the device to USB goes whithout problems, but all subesecuent tries results in errors like:

    sudo python barcode.py
    Traceback (most recent call last):
    File "barcode.py", line 323, in
    scanner = CS1504(serial_port)
    File "barcode.py", line 135, in __init__
    File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line 261, in __init__
    File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 282, in open
    File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 413, in _reconfigurePort
    termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
    termios.error: (22, 'Invalid argument')
    Exception AttributeError: "CS1504 instance has no attribute 'ser'" in <bound method CS1504.__del__ of > ignored

    Do you have at tip as to what I need to change to make it possible to read several times?

  20. Are Egner-Kaupang says:

    please remove my comment. I went to the GitHub page and found my answer. Thanks again for the great work!!

Comments are closed.