|Perl: the Markov chain saw|
Empowered by Perlby liverpole (Monsignor)
|on Oct 15, 2007 at 01:05 UTC||Need Help??|
Did you ever notice how Perl gives you that feeling that you can solve any programming task?
I know it does for me; more than any other programming language. There may be obstacles, but when Perl is the tool, there's ALWAYS a solution to be found, even if the first 2 or 3 don't succeed.
This weekend, my friend described a work assignment his manager had given him. He was supposed to produce a demo, where any time an RFID card came into range, it could be detected by an antenna plugged into his laptop.
There was a catch. It relied on a C program to read the COM1 port, and the software dated back to 1999, and would no longer compile with a recent version of Borland (the libraries were not backwards compatible). So even though the executable would work, and the source code was there to peruse, he couldn't modify the C program.
He needed to get it done over the weekend, since the boss wanted to have the demo presentable on Monday.
And although the C program seemed to work fine writing to STDOUT, all attempts to write to a logfile and detect the RFID card by reading that logfile had failed. Now STDERR was also being written too as well, so even though it was a single '.' to STDERR at a time, my friend assured me he only needed to detect that the card was in range, not identify it. So reading STDERR was another option.
At Perlmonks, of course, we often refer to this problem as "Suffering from Buffering".
Now as I said, if I can use Perl, my instinct tells me the problem will be solvable, no matter what the obstacles. I offered to take a shot at it, and my friend said it'd be fine to install Perl on his laptop.
Ten minutes or so later, Perl was installed, as was gvim.
Windows-based programming is not my forte (I much prefer Linux), so I wasn't sure whether Windows would buffer the program's output it I tried to create a pipe from it, and read the tail end. But writing a little test program is quick, and after a minute or two, we knew that it wouldn't work.
"Not a problem", I thought, "I'll just go get the Expect module from CPAN and good-ol' pseudo-terminals will help me force the output to be line-buffered, the way I want it. Unfortunately, the "cl" compiler wasn't installed, so relying on modules to solve the problem was out.
Next, I tried redirecting STDERR, but the semantics of doing that in Windows thwarted me, so I put that approach aside as well.
Then, while reading through some Windows-specific documentation, I came across a paragraph about reading the COM port in the ActivePerl-Winfaq8:
I asked my friend if we could discard the C program altogether, just reading from the COM port ourselves, and he said "Sure!" -- so the next try resulted in opening the COM1 port as described in the documentation. It wasn't immediately successful, but then he remembered something about needing to initialize the COM port by writing a backslash '\' to it, so after doing that, success! The program started getting COM1 output each time the card was in range!
To be sure the Perl program could now write data to a logfile (unbuffered, of course), and read it from another process at the same time, we inserted a fork in the program, and called another simple Perl script to announce lines as soon as they appeared in the logfile. This program would keep track of the offset of the logfile each time it read a line, so as to skip lines it had already processed.
My friend was very happy; the whole solution was done in about an hour, and he confessed that he'd been expecting to spend two full days on it using C++. Instead of using an out-of-date hundreds-of-lines-long C program which we couldn't even change, we did it with about a dozen lines of Perl. We can still figure out later how to exactly interpret the COM port results, to give the exact RFID information, either by decoding the output bytes, or by visually inspecting the C program sourcecode.
There was never a sense of "this is impossible", only "here's another roadblock, but there's GOT to be a way to do it with Perl!"