Product Review: Pro-Lite Scrolling Message Signs

by Walter Stoneburner
  • Manufacturer: Pro-Lite

  • E-mail:

  • URL:

  • Price: $150 US

  • Author: Walt Stoneburner

The Pro-Lite Tru-Color II PL-M2014R is an affordable multi-color LED scrolling message board that is capable of being controlled by a standard RS-232 serial port. The sign is obtainable from Pro-Lite directly (, but can also be purchased at various discount warehouses for approximately $150. The serial cable and Windows software are sold separately.

This article is not just a review; it can serve as a primer for Pro-Lite's PL-M2014R with ROM release 5.24Q and 32K of memory with Trivia mode, basically your standard sign. Until now, not much developer information has been available to the public, meaning signs were usually configured with the included infrared remote control to display static messages. For very little money, it is possible to build your own serial cable and control the sign using Linux to display more than static text.

The business and personal applications for a highly visible sign are almost limitless: reporting days until software delivery, announcing traffic congestion, providing the weather, showing the date and time, sending public messages, reporting system load, announcing new mail, showing who's logged in, warning when disk space gets low, login information, announcing unexpected server outages as a watchdog, etc.

Communicating with the sign is almost as simple as beaming text out the serial port; however, a bit of text manipulation is necessary in order to get the sign to respond and do advanced tasks. Linux handles the serial port communication, so sending information to the sign appears as trivial as writing to a file.

Luckily, the majority of the work can be accomplished by simple scripts. All you need is a basic understanding of the shell, AWK, PERL or Python, and you can be running in almost no time. The first hurdle is to build a cable and configure Linux to talk out the serial port.

Cable Construction

Figure 1. Female DB9 Adapter

The first step is wiring an RJ12 to female DB9 adapter. It requires no tools, and an adapter kit can be purchased at most computer supply stores for about $2 US. The only other thing you need is a length of RJ12 cable with male adapters at each end. This means a standard telephone cord will do nicely. Your cable will most likely have the standard colors black, red, green and yellow, in that order.

Cables come in two flavors: straight-thru and reversed. You'll need to take the RJ12 cable and put it end to end (like a loop) to find out which kind of adapter you need to build.

Figure 2. RJ12 Adapter Diagram

One of two things will be noticeable: either the wires will match black to black, red to red and so on, or they will reverse their order showing black to yellow, red to green and so on.

If the cable is a straight-through, where the colors match, wire your RJ12 to a DB9 adapter using Pin 2 as green, Pin 3 as red and Pin 5 as yellow. If the cable is reversed, then where the colors reverse sequence, wire your RJ12 to a DB9 adapter using Pin 2 as red, Pin 3 as green and Pin 5 as black.

Figure 3. RJ12 to DB9 Wiring

Shove the unused adapter wires into the casing and snap the adapter shut. Take care not to let the exposed ends touch anything metal inside the adapter casing. You may want to clip the unused wires. Put an extension cable on your serial port and connect the adapter wires directly to the extension cable in order to test the wiring configuration before pushing the pins into the connector.

When all is said and done, one end of the RJ12 goes into the side of the LED sign, the other into the adapter you just made, and the adapter plugs into the computer.

Configuring Linux to Talk to the Sign

My sign is plugged into COM1, also known as /dev/ttyS0. I've elected to use a symbolic link to the sign, in the event I ever decide to change to another serial port in the future. To make the link, as root type:

ln -s /dev/ttyS0 /dev/prolite

I tend to shy away from doing development as root. Putting security issues aside for the moment, we can make the device world-writable by typing:

chmod a+rw /dev/prolite
The sign communicates using No Parity, 8 Bits, 1 Stop Bit; no handshaking of any kind (hardware or software) is used. Early versions of the sign work only at 300 baud, but they can be upgraded to 9600 baud. All signs I've encountered had the 9600 capability right out of the box. The bottom line is that all signs are capable of communication, and even at 300 baud you can outrun the sign. The only drawback is that the sign's baud rate has to be set by the remote control, according to the setup in the manual. This needs to be done only once.

In theory, the sign requires a 15ms delay between each character sent to the sign. I've found that Linux's device driver seems to work just fine without having to do anything special in the software.

stty speed 9600 cs8 -parenb -cstopb cread \
   -clocal -crtscts -ignpar -echo nl1 cr3 < \

Naturally, you can substitute any baud rate the sign will handle for the 9600. This command will work when you aren't root because it is world-writable.

The most important piece of information for communicating with the sign is that each command sent to the sign must end with a carriage return/newline pair. This is ctrl-M ctrl-J on the keyboard or 0x0C 0x0A in hexadecimal. C programmers will recognize it as \r\n. If you want Linux to handle the end-of-line sequence for you, type the command:

stty opost -ocrnl onlcr < /dev/prolite

When you send a newline, Linux will send both carriage return/newline automatically. Text can now be listed or redirected to /dev/prolite from the shell. If you want to send the carriage returns yourself, type:

stty -opost -ocrnl -onlcr < /dev/prolite
Where the options are defined as:
  • opost: postprocess the output stream.

  • -opost: do not postprocess the output stream.

  • -ocrnl: do not convert carriage returns into newlines.

  • -onlcr: do not translate each newline into a carriage return/newline pair.

  • onlcr: translate each newline into a carriage return/newline pair.

The stty command allows for a shorthand representation of all the termios structures that define the device characteristics. For 9600,N,8,1 with automatic carriage returns, type on one line:
stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:
12:f:17:16:0:0:73 < /dev/prolite
For 9600,N,8,1 with no automatic carriage returns, use the line:
stty 0:700:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:
12:f:17:16:0:0:73 < /dev/prolite
Command Syntax

Only a minimal understanding is needed in order to operate the sign. Mastery requires becoming familiar with the protocol and doing a little experimenting.

Multiple signs can be connected to a computer over the same serial port by using a simple telephone-line-splitting Y-connector. Each sign has an assignable logical address that allows you to send messages to particular signs. A logical address is represented in hexadecimal as a number between 01 and FF. Addresses may be shared enabling grouping; in this way, a message to ID01 goes to all signs with ID01.

Communication with the sign is always done with readable ASCII characters; thus, an arbitrary ID of 2F would be designated with the digit “2” and the capital letter “F”.

ID00 is reserved to mean “broadcast to all signs”. By default, a sign is preconfigured as ID01; this can be changed with the remote control. If you are addressing a single sign connected straight to the computer, it will respond with its ID number after each successful command. Messages sent to ID00 do not return a response, and neither does an individual sign when the line is shared via the Y-connector.

All messages to the sign, except for those setting the date and time, are sent in the following format followed by the carriage return/line feed: <IDxx>command, xx is 00 to FF. Any command longer than 1,023 bytes will be ignored by the sign.

To set the date and time, no ID is needed. The format is <TYYMMDDwhhmmss> where YY is the year, MM the month, DD the day, w the weekday (0=Sun, 1=Mon,...6=Sat), hh the hour, mm the minute and ss the seconds. This can be accomplished with the shell very easily. Set the date/time of all signs with the command:

ate "+<T%y%m%d%w%H%M%S>" te "+<T%y%m%d%w%H%M%S>" > /dev/prolite> /dev/prolite

The leading + sign tells the date command to build a string via substitution; see your man pages for details.

To signal a sign to start listening to responses, send it an empty command with the format <IDxx>; e.g., type:

echo "<ID01>" > /dev/prolite

The most fundamental concept of the sign is the idea of a page. A page consists of a message the sign is to display either now or some time in the future. Pages may contain text, numerics, symbols, font attribute tags, color tags, graphic tags and effect tags. There are 26 pages named, appropriately enough, A to Z. Case does matter when identifying a page.

Any given page can hold approximately 1,012 bytes of information. I say approximately because special tags (see sidebar) consume more than one byte, which means less space. Also, using some trickery by omitting the page directive completely and defaulting to page A squeezes out an additional two bytes, which means more space.

The command to set a page is <Px>, where x is the page name. Any text after this sequence is considered text for the sign. To set the message “Linux Rules” on page A, type the following command:

echo "<ID01><PA>Linux Rules" > /dev/prolite

It is important to leave extra space at the end so the end of the message is separated from the front of the message as it scrolls.

To delete a page, use <DPx>, where x is the page name. For example, to delete page B, type:

echo "<ID01><DPB>" > /dev/prolite
Displaying Pages

The sign is constantly displaying a page. If the default page A is scrolling by, then when its content is changed it will immediately start displaying the new message. Otherwise, we must tell the sign which page to run using the <RPx> command, where x is the page to display. Normally, the sign can run only one page at a time.

Once a page has been defined, it can be run. For example, to repeatedly display our message, type:

echo "<ID01><RPA>" > /dev/prolite

Running an undefined page will result in displaying the sign's demo.

Two points of interest for script writers:

  1. It is possible to update the contents of a page not being displayed, then switch to that page at a later time.

  2. It is possible to update the currently displayed message. The only problem is the display will be interrupted mid-message.

Sadly, you cannot ask the sign what the contents of a page are, what page it is currently displaying, or when it has started or ended a display sequence. Thus, techniques like double-buffering don't work for continuous messages.

I have received one terse message from Pro-Lite that alluded to a future version of the sign which is designed to address such needs explicitly for computer users.


In order to display one or more messages at a time, the sign includes ten timers named A to J. Each timer specifies a time and a series of 1 to 32 pages to sequence through. You may repeat pages in a sequence. The time a sequence is displayed consists of a weekday, an hour and a minute, any of which may be wildcarded (*) to match “all”.

When the first timer is defined, the sign is put into “timer” mode and will display that timer's messages immediately. Should two or more timers be defined, the sign seems to wait one minute, then checks each timer to see if one triggered based on the current time. If so, at the end of the displaying message, the new timer's sequence goes into effect. If no rule matches, no change is made.

Note the sign checks the rules for the immediate time. It will not go back to try to find a previous timer. So if you set a timer for 4:15PM and it is now 4:17PM, you've missed the moment when the sign would change.

Should two or more timers both be valid for the current time, the sign unpredictably selects one for display. This means you cannot set one timer to display at 4:15 and another timer to display at 15 minutes past any hour. Both rules would be triggered at 4:15 and it is a toss-up as to which message will be displayed.

The timer command is defined as <Tx>dhhmmABC..., where x is the timer, d is 0 (Sunday) to 6 (Saturday) for the day, hh is a two-digit hour and mm is the minute. “ABC...” is a list of 1 to 32 pages to display in the order specified. Note that Page-A and Timer-A are two different, unrelated entities. A timer set for “*****” will be triggered immediately.

The following sequence will display a series of messages at 8:00AM, noon, 1:00PM and 5:00PM:

$ cat > /dev/prolite
<ID01><PA>Good morning.
<ID01><PB>Have a nice lunch.
<ID01><PC>Get back to work.
<ID01><PD>Have a safe drive home.

In order to display a whole sequences of pages, just list more page letters. For instance, it is useful to make a scheme where you assign page letters to different message content. For example, page A could be hourly announcements, page R the runtime status of your machine, page M the message of the day, page T the time and so on. To display several pages right now (including repeats):

$ cat > /dev/prolite
Two interesting tidbits of information:
  • For some reason, the specific time of Sunday at midnight (00000 as a timer value) does not seem to work consistently. I suspect it confuses this value with unset timers.

  • If a run-page command (<ID01><RPA>) is issued, the sign is taken out of “timer” mode and displays the requested page. If you then issue the command <ID01><RP*>, the sign will go back into “timer” mode, displaying the last sequence of messages.

To delete a timer, use <DTx>, where x is the timer letter or * for all timers. For example, to delete timer D type:
echo "<ID01><DTx>" > /dev/prolite

There are 26 graphic blocks that can be redefined and are commonly used for graphics. Graphics are inserted into the text via the tag <Bx>, where x is a letter from A to Z. For example, this command will display a mug and a wine glass:

echo "<ID01><PA><BW> Party Tonight <BZ>"

Altering the graphics requires the <Gx> command followed by a string of 126 characters made up of R (for red), Y (for yellow), G (for green) and B (for black or unlit). A sequence of seven rows of eighteen LEDs is specified back to back on a single command line. (See Figure 4.)

Figure 4. A Graphics Block Specification

I know at least one user who loads a font into a sequence of graphic blocks, and in this way is able to display more characters than the sign technically allows by default—very clever.

To delete a graphic block, restoring it to the default, use <DGx>, where x is a letter A to Z; * is a wildcard indicating all are to be deleted.


One additional feature of the sign is to display in sequence a trivia question, your message, the answer to the question and your message again. It works its way though a canned list of questions and then starts over. The sign can be loaded with your own list, which does not have to be trivia. The list can be up to 16KB long, leaving 16KB for the pages. If no list is loaded (i.e., you deleted the trivia), the full 32KB of the sign is available for page content. To make your own list, do the following:

$ cat > /dev/prolite
<ID01>What operating system isn't a pig?
<ID01>What operating system is free?

To delete the trivia, just omit the lines between <Q+> and <Q->. If no messages are loaded, trivia mode is turned off. If they are, trivia is turned on.

Other Useful Commands and Tricks

To reset the sign, removing all timers and pages, use <D*> like this:

echo "<ID01><D*>" > /dev/prolite

Technically, there is no way to bring the sign to a halt. However, you can take advantage of a quirk in the software to do the same thing. If you use the <FX> tag in a message to control the speed of the sign, but don't supply a message, the old text isn't cleared and the sign stops scrolling until it gets a new message.

Function Tags

Additional tags are shown in “Function Tabs”. European tags are available for characters shown in Figure 5.

Figure 5. European Characters Available

Uses for the Sign

It doesn't take much to make the sign useful. For example, scripts that send commands to the sign can be executed every few minutes by editing your crontab file (crontab -e) to include:

*/5 * * * * /usr/local/bin/sign 1> /dev/null \
2> /dev/null

Every five minutes, the system will call /usr/local/bin/sign. In this script, we can place any number of tasks. To show our uptime, add these lines:

stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12\
:f:17:16:0:0:73 < /dev/prolite
echo "<ID01><PU>'uptime' " > /dev/prolite
echo "<ID01><TA>*****U" > /dev/prolite
If root wants to see the last line of the log file scroll by, this command will suffice:
tail -f -n 1 /var/log/messages |
   awk '{ print "<ID01><PA>" $0 " "; }' >
   /dev/prolite &
This job sits in the background, getting lines from the end of the log as they come in, prefixes a <ID01><PA> to it and sends it to the sign. The process then goes to sleep until another log entry is made. The only reason to run as root is to get access to the messages file.

The sign can also act as a watchdog for our system by setting up a timer to go off several minutes later. Ideally, the sign will get updated before the timer goes off and the timer will again be set for some time in the future. In the event the sign is not updated, the timer trips and an alternate alert message is displayed.

stty 0:705:bd:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12\
:f:17:16:0:0:73 < /dev/prolite
echo "<ID01><PU><FD>Server Up" > /dev/prolite
echo "<ID01><DTB>" > /dev/prolite
echo "<ID01><TA>00001U" > /dev/prolite
echo "<ID01><TD><FB><CC>Server Down" > \
date "+<ID01><TB>*%H%MD" -date "7 min" > \

To do this relies on some tricks. First, you cannot use a generic timer (<TA>*****) for running standard messages because it conflicts with our watchdog timer. Secondly, we cannot use timer <TA>00000 because it confuses the sign. Thus, we have to use one minute after midnight on Sunday (<TA>00001) in order to display our messages. When no timers are defined, the first timer defined shows our page.

Deleting timer B keeps us using timer A, which shows normal text. The sign ignores requests to delete timers and pages that don't exist. Once page A is defined and displaying, we define page B in the background and set up a time, again using the clever date command to output it seven minutes from now. Since our cron job is set to run this script every five minutes, the timer should never go off unless something is wrong.

If Linux suffers a power failure, the cron daemon is killed, or the sign becomes disconnected, it will display a warning message. The tag <FD> indicates the message should instantly appear instead of scrolling, where <FB> indicates the text should appear from the center—this will get your attention quickly.

More information about the protocol, cable and sign can be found at This site also includes source code for various applications that manipulate the sign.

Walt Stoneburner currently works as a software engineer for Downright Software, LLC. In his spare time, he enjoys working with Linux, playing non-computer games, reading and reviewing hardware and development software. Feel free to contact him at or ICQ# 5368391.
Load Disqus comments