Linux in the Real World
A year ago I installed Linux at home on my 386-20 and fired up X11 on my Hercules monochrome graphics adapter. I edited a source file with GNU emacs and compiled it with gcc. A real “Unix” system at home! I was so thrilled I walked around grinning for days. “This is so cool!” I exclaimed. “That's nice, but what do you do with it?” was the reply. I didn't have much of an answer then—but I do now.
This article describes a real world Linux application. The requirement was for an unattended computer to gather data from three different fluid level measurement devices and relay that data to a remote location.
The site is a coal-fired power plant about 100km away from the computer. The three measurement devices are mounted on an upright cylindrical tank with a height and diameter of approximately 7m. The tank holds water which will be mixed with ash to produce a slurry that is easier to handle than dry ash. There is 120VAC power at the tank, but no telephone line. The environment is benign, other than the constant presence of a powder-fine dust that resembles a cross between Portland cement and cake flour.
The measurement devices all use different serial protocols and physical layers. Two protocols use printable ASCII with each frame terminated by CR/LF. The first of these (ASCII Modbus) resembles Intel hex records on an RS-232 physical layer. The second is a proprietary command interface that utilizes shell-like commands over an RS-485 physical layer.
The third protocol (RTU Modbus) consists of binary data with the end-of-frame marked by a gap larger than 3 byte times. The physical layer is half-duplex FSK. The interface to the computer is an RS-232 port connected to a proprietary FSK modem.
The hardware selected for the system is a rack-mounted, industrial 486 machine with 16M of RAM and a 500M IDE disk drive. The industrial PC chosen has several features useful for unattended operation:
Ability to boot without a keyboard.
Ability to boot without a video board.
A hardware watchdog timer that can reset the computer in case of system lockup.
Since no phone line was available to provide communications between the data gathering system and the central host, a cellular phone was used.
Cellular communication—all you need is money.
For this task I purchased a pair of Microcom DeskPort 14.4K modems that support the MNP-10 “cellular” feature set. Cellular telephone connections vary much more in quality from minute to minute than do land lines, and drop-outs are more frequent and longer. For reliable cellular communications, modems need the ability to re-equalize and adjust baud rates and packet sizes accordingly. With the MNP-10 features disabled, I was unable to maintain a reliable connection even at 300 and 600 baud. With the error correction enabled, the connection was usually maintained at 9.6K or 12K baud.
UUCP was chosen over SLIP due to UUCP's ability to queue work and to automatically redial and restart a transfer after a call is dropped.
The cellular telephone is a Motorola “Bag” style 3-watt cellular which was on hand and available for use. A “cellular connection” box had to be purchased for the phone. The cellular connection is a black box, about the size of a pack of cigarettes, that plugs between the handset and the radio. It provides an RJ-11 jack, generates dial tone, responds to the modem's switch-hook transitions and converts DTMF tones to handset key presses.
Since one of the ASCII interfaces runs on the RS-485 physical layer, a board from Opto-22 was chosen that had a standard 16450 UART with opto-isolated RS-485 drivers and receivers.
The system required unattended, remote operation and simultaneous communication on four serial ports. While all of this would be possible under MS-DOS it would require a significant amount of effort, while a Unix-type OS would support all of them right “out of the box”.
Copies of Coherent and ISC SVr2 were available for use, but I chose Linux for two reasons. First, I was (and still am) running Linux at home. More importantly, Linux source code was available in case something needed to be customized or fixed.
A borrowed Fall 1993 Yggdrasil CD provided the base system, although uucp and mail didn't work as installed. I downloaded new copies of smail and Taylor UUCP, and they installed and configured with no problems. getty-ps was installed to allow the modem to be used both as a dial-out device by uucp and as a dial-in device for remote logins.
The first job was a watchdog timer daemon. The watchdog daemon needed to do an I/O port write periodically to reset the hardware watchdog timer. In order to provide for orderly system shutdown, when the watchdog timer daemon receives a term signal, it disables the timer. Since the port address was above 0x400 the ioperm() and _outb() system calls wouldn't work.
(The kernel only maintains permission maps for ports below 0x400.) Instead, the daemon does an open() on /dev/port and uses the lseek() and write() system calls to do the port I/O. Since the I/O is small and infrequent, the system call overhead isn't a problem.
The next job was the software that gathers data via the three serial ports. Should it be a single, large program that talks to all three devices? This would be needlessly complex compared to writing three separate programs, each of which talks to a single device. This is especially true, since the three devices all used different protocols and provided different sets of data.
Each of the three programs gathers data (one sample every five seconds) and writes a line of text on stdout for each sample. Each line of output includes time stamp, status and data values. Each program has a command line option that specifies how long to gather data before terminating.
A simple ASCII output format with whitespace-separated columns allows easy manipulation and data reduction using familiar Unix tools, such as awk and gnuplot. A few lines of one of the data files is shown below:
94-01-28 18:52:41 OK 0 4.745400 998.4952 94-01-28 18:52:47 OK 0 4.745406 998.4937
It's like a cheap speaker phone—only one end can talk at a time.
The only unusual problem associated with the data gathering programs was the use of a half-duplex FSK modem. RTS must be asserted when the Linux host sending a command and then dropped to allow the device to respond. This can't be done easily from user level software, so the serial port driver was modified. Two lines of code were added to the driver so that it asserts RTS at the beginning of a transmission and drops it at the end. You don't often need source to the OS, but in this case, it saved a large amount of extra effort that would have been required to add custom hardware to control RTS.
Once the individual data acquisition programs were debugged, something was needed to execute the individual programs and coordinate the whole process. On Unix systems, that means a shell script: nothing complicated, just an infinite loop that does the following:
start each of the three data acquisition programs in the background with a command line switch set to run for six hours and with stdout redirected into a file.
wait for all three of the above to terminate.
compress the data files and uucp them to the destination.
This shellscript is started in the background by an entry in /etc/rc.local and runs forever shipping data files off four times a day.
It all sounds quite smooth after the fact, but the project was not without its little hiccups. The most embarrassing problem occurred while attempting to reboot the system remotely. I typed shutdown -fh instead of shutdown -fr so the system halted rather than rebooting. The system was down for a week before a trip could be made to the site to push the reset button.
The dial-in/dial-out port connected to the cellular modem would occasionally be permanently locked by getty. This prevented uucp from dialing out to transfer data. A crontab entry was added to periodically kill the getty on that port. There were two other instances where all communications were lost. After some experimentation, I determined that the cellular telephone had somehow been powered off.
Perusal of the user's manual and a call to the service provider revealed that the cellular phone shuts itself off if not used for eight hours. This happened twice—apparently the cellular connection doesn't always detect the modem off-hook condition, and this resulted in the cellular telephone turning itself off after eight hours of inactivity. UUCP should have retried several times before the eight hour timeout, so the exact sequence of events is still a bit of a mystery. The immediate solution was to configure a uucp crontab entry to make sure it will “phone home” once an hour even if there is not any work to be done. The eight hour timeout can be disabled and this will be done when it is convenient to take the phone in to the shop.
On a more mundane note, I managed to break my shared libraries the first time I attempted to upgrade them in order to run a newer version of the “man” utility. It was a simple task to boot using the bootdisk/CD-ROM and fix the libraries to the point where the system would again boot from the IDE drive. (When you upgrade your shared libraries, read the directions twice before you start and follow them exactly.)
Grant Edwards (firstname.lastname@example.org) is an electrical engineer for a manufacturer of process control equipment. He has been messing with Unix systems while doing product design work since the early 1980's.