Menu

Serial Ports for Ruby

One of my biggest frustrations with scripting languages is dealing with serial ports. In Particular, when I want it to work across multiple Operating Systems when not all are UNIX based. Ruby seems to be especially lacking in a good serial port library; the only one I've found was ruby-serialport, but it's rather out of date, nor could I even get the Windows version to respond. I am working on my own version of a serial port library for ruby from scratch.

I am taking a different approach than ruby-serialport took in that it's implemented entirely in ruby for portability. Ruby-serialport is entirely written in C and it compiled for each environment. I am accomplishing this by using system() to call various command-line programs for setting the serial parameters then opening up the serial port in append+read mode. On most UNIX systems the stty command is available to set up the parameters, but on DOS/Windows they have a command called MODE. The other big difference is which files to open. UNIX systems have some file under /dev for such a purpose and DOS/Windows just request a file called COM1 through COM256. With this in mind, it should be possible to make a portable serial port written in ruby, but requiring no C code to be compiled.

The other problem with serial ports in ruby is setting timeouts on reads. Normal file I/O is not a problem because there will always data to return or an EOF. Serial ports, however, do not have an EOF, and if the connection is severred or the remote device stops sending data, the call to read can hang forever. In perl, the recommended procedure was to call the read from an eval statement block which setup a SIGALRM handler and started alarm() before the read. The alarm handler just set a global variable to 1 which should of been initialized to 0 before the eval block. This way you could determine if an alarm happened. I have never like this approach, especially since it means you can't see what the partial read might have returned. The proper way to write this program in c is to call select() and when there is data to be read, either call read() for 1 byte or do a non-blocking read. High-level buffered I/O should not be intermixed like called to fopen(), fgets() and similar because data might have been read into a buffer which select would not know about.

Valid XHTML 1.0 Transitional Valid CSS! Created with Vim