Serial communication in Perl

| 1 Comment | No TrackBacks

João Gabriel asked in cascavel-pm:

Is there a possibility of using a Perl script (in a Linux environment) to send and receive data from a parallel port (/dev/ttyS0)? Did someone do that with Perl already? Should I adventure myself in Perl or should I jump to C?

Well, you just listed the most evident case of when programming for Linux is easier that when programming to Windows. In summary, the serial port is a file you read from and write to.

It's worth to mention that /dev/ttyS0 is a serial port, not parallel. The parallel port is usually /dev/lp. They are fundamentally different, as one implements the RS232 protocol to encode a given stream of information, while the parallel port is just a set of pins you can manipulate.

Well, that being said, let's go to the interesting part...

First of all, you need to open the port, and to do that:

  use IO::Handle; # so you can use OO API with filehandles
  open my $fh, '+<', '/dev/ttyS0' or die $!;

The '+<' open mode means that you're openning it for both reading and writing (perldoc -f open is your friend). After that, you probably want non-blocking IO, except if your protocol os considerably predictable (it never is). To do that:
  $fh->blocking(0);

It might be necessary to configure the serial port, since the device might not be using the same default configuration as you are. In oreder to do that you need access to the POSIX API, specifically termios.h. So, the first thing you need is:
  use POSIX qw(:termios_h);

Then, to configure the port you can do something like:
    my $term = POSIX::Termios->new;
  $term->getattr(fileno($fh)) or die $!;
    $term->setiflag( $term->getiflag &
      ( &POSIX::IGNBRK | &POSIX::IGNPAR &
        ~&POSIX::INPCK & ~ &POSIX::IXON &
        ~ &POSIX::IXOFF));
    $term->setlflag( $term->getlflag &
     ~( &POSIX::ICANON | &POSIX::ECHO |
        &POSIX::ECHONL | &POSIX::ISIG |
       &POSIX::IEXTEN ));
    $term->setcflag( $term->getcflag &
      ( &POSIX::CSIZE | &POSIX::CS8 & ~&POSIX::PARENB));
    $term->setospeed(&POSIX::B1200);
    $term->setispeed(&POSIX::B1200);
    $term->setattr(fileno($fh), &POSIX::TCSANOW) or die $!;

perldoc POSIX and man termios (install manpages-dev) help you understand what it does.

Now you're ready to read and write from/to the serial port, but unless you have a very controlled environment, you don't want to do that in a synchronous way. And for that I recommend using the EV module, which will give you all the tools you need to do the async communication.

No TrackBacks

TrackBack URL: http://daniel.ruoso.com/cgi-bin/mt/mt-tb.cgi/138

1 Comment

The question that you answer here says "Parallel port" but you answered with "Serial port". To answer the question on the parallel front you can use Device::ParallelPort.

Leave a comment

About this Entry

This page contains a single entry by Daniel Ruoso published on June 17, 2009 6:51 PM.

A plan for module loading in mildew was the previous entry in this blog.

Ninar -- Lullaby is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.