Introduction

I wrote about this topic *SO* much before, but hey, I work with this a lot. Using the PC's serial (COM) port is very useful when working with embedded hardware & software. It's an excellent way to control the hardware from the PC, to gather and plot data, and to generally impress your EE co-workers who don't always have an intuitive understanding of how I turn relays on and off using "this Perl program".

One of my best creations in this area is a light-weight but powerful serial port monitor (that can monitor and log time-tagged data from several ports simultaneously), written in C++, following a prototype I wrote in Perl.

But receiving data is not always enough. It's great to be able to plot all my A2D samples from the FPGA in an Excel chart, but the other direction is also important - sending data from the PC to the custom hardware.

For that, on my PC I employ a nice Perl script which uses Win32::SerialPort. But since that module is difficult to install on other PC's, I came up with a solution to run scripts in a "hosted environment" created with PAR.

However, this method is also not completely satisfactory & flexible enough. Moreover, the PARed executable is a heavy 3 MB which is really inconvenient in some cases.

Solution

As I mentioned before, the awful Win32::SerialPort module makes it very difficult to work with serial ports in Perl. Until I find the time to write something better, I have real problems to solve at work, so I must pick the best tool for the job. And for this job, the best tool is C++, using the excellent CSerial library which is readily available on the web (LGPL).

On the other hand, general data munging is much nicer with Perl and complex binary data is especially easily managed with pack & unpack. Besides, Perl scripts are easier to change and need no compilation, thus making them generally more convenient to use for "quick tries", which is very important.

So today I finally decided to merge the good from the two worlds - C++'s ability to gracefully handle serial port communications, and Perl's general usability and productivity. The result is a very nice hack, which at its base is very simple.

The slave

The slave is a small C++ program that starts, receives the serial port's information (name, baudrate, parity, etc.) from the command line, dutifully opens a socket on port 14441 of the localhost (ip 127.0.0.1), using Win32's WinSock library, sends a notification that it's ready to receive data and waits. When it gets a data buffer, it transmits it to the serial port it's tied to.

The master

The master is a Perl script that runs the slave as a child process (using Win32::Process), and listens on port 14441 (using IO::Socket::INET), waiting for the slave to connect. When the slave connects and says it's ready, the master sends it a buffer of data to transmit to the serial port.

Conclusion

A happy couple - a 90 Kb executable (slave) + the master script now do anything the more bulky PARed script did, and with much area for future improvement and flexibility (because the C++ CSerial class is so nice to work with). It a good experience of mixing many things together (serial communications, processes, sockets), and I learned once again that sockets are a great IPC technique, even when no more than the local host is needed. But the main conclusion for today is:

Use the right tool for the job !

Update: I've finally packed the code of what I'm describing here for distribution. Here it is.