http://www.perlmonks.org?node_id=88726

senget has asked for the wisdom of the Perl Monks concerning the following question:

Hai I need suggestion on how to read or send data through serial port.. I am not sure how to start using perl 5 i have tried using Borland C++ (using dos.h).. not that easy and I am half retarded already.. thanks

Replies are listed 'Best First'.
Re: sending to & reading from serial port
by rob_au (Abbot) on Jun 15, 2001 at 12:51 UTC
    I have found two modules which implement some very nice methods for handling serial port communications - These are:
     
    • Device::SerialPort - which implements its calls through termios library for *nix systems - I have used this module for some IVRS-type applications with little difficulty; and
    • Win32::SerialPort - which implements its calls through Win32 APIs for Windows systems

       
      It may be worth your while to have a look at these modules and some of the example code included in the module PODs to get a better idea about how you can implement your write and read calls to and from the serial port through Perl.
       
      Ooohhh, Rob no beer function well without!
    Re: sending to & reading from serial port
    by Aighearach (Initiate) on Jun 15, 2001 at 16:27 UTC

      Here is an ugly real world example of doing it raw, using POSIX.pm to set things up. This code is rough, but it works. Note that I set the termios settings for non-blocking... I'm using a polling interval instead, which is different depending on what was just sent. IO::Select is used for the timeout. I had to kludge IO::Select to get it to work right, by adding STDOUT (which shouldn't ever be ready to read!) to the IO::Select object. (it returns right away without any handles)

      What it does is, on new() it instantiates a new object, on get_ad_flags() and get_d_flags() it writes a command to the serial port, and reads a binary response, parses it into an array, and returns the array. Also there are three methods to toggle digital outputs. Handy if you have an SDA 10 from B&B :) (nice for adding extra buttons and LEDs to your computer, about $50. It can read thermometers and such also)

      Who says Perl is no good for device drivers?! bah! it doesn't create any load at all to poll three analog to digital channels with only a .03 second delay.

      # sda10.pm # (C)2001 Paris Sinclair <pariss@efn.org> # Control library for data acquisition module 232SDA10 # from B&B Electronics http://www.bb-elec.com package sda10; use strict; use warnings; use POSIX; use Fcntl; use IO::Select; use IO::Handle; #public data our $TIMEOUT_AD = .03; our $TIMEOUT_D = .26; our $TIMEOUT_SO = 1; our $BUFFER_SIZE = 1024; # private data my $_select = new IO::Select; $_select->add( \*STDOUT ); #put in something that will never be ready +to read :) sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; bless $self, $class; $self->{dev} = shift || '/dev/ttyS1'; $self->{baud} = B9600; sysopen( $self->{fh}, $self->{dev}, O_RDWR | O_NOCTTY ) or die "fa +iled opening serial device ".$self->{dev}.": $!"; $self->{termios_old} = POSIX::Termios->new(); $self->{termios_old}->getattr( $self->{fh} ); $self->{termios} = POSIX::Termios->new(); $self->{termios}->setispeed( $self->{baud} ); $self->{termios}->setcflag( CS8 | CLOCAL | CREAD ); $self->{termios}->setiflag( IGNPAR ); $self->{termios}->setattr( $self->{fh} ); $self->{flags} = chr(0); $self->{fh}->blocking( 0 ); return $self; } sub get_ad_flags { no warnings; my $self = shift or return undef; my $n_channels = (shift @_) - 1; $n_channels = 0 unless defined $n_channels and $n_channels <= 13; return undef unless $self->send_read_ad( $n_channels ) == 5; ($_select->can_read( $TIMEOUT_AD * ($n_channels + 1) )); my $flags = $self->read_sda; my @channels = (); for ( my $i = 0; $i < length $flags; $i += 2 ) { my $msb = ord( substr $flags, $i, 1 ); my $lsb = ord( substr $flags, $i+1, 1); unshift @channels, "$msb$lsb"; } if ( (+length $flags) * .5 < $n_channels ) { $channels[((length $flags)*.5)..$n_channels] = 0; } return @channels; } sub send_read_ad { my $self = shift; defined( my $n_channels = +shift ) or return undef; my $bytes = syswrite( $self->{fh}, '!0RA'.chr($n_channels) ); return $bytes; } sub get_d_flags { my $self = shift or return undef; unless ( $self->send_read_d( $self->{fh} ) == 4 ) { return undef; } return $self->read_sda; } sub send_read_d { my $self = shift or return undef; my $bytes = syswrite( $self->{fh}, '!0RD' ); ($_select->can_read( $TIMEOUT_D )); return $bytes; } sub read_sda { my $self = shift or return undef; my $data = ""; defined( my $bytes = $self->{fh}->sysread( $data, $BUFFER_SIZE ) ) + or warn "error reading from ".$self->{dev}.": $!"; $self->{flags} = $data; return $data; } sub toggle_out1 { my $self = shift; my $flag = vec( $self->{flags}, 0, 1 ); vec( $self->{flags}, 0, 1 ) = !($flag); my $bytes = syswrite( $self->{fh}, '!0SO'.$self->{flags} ); ($_select->can_read( $TIMEOUT_SO )); } sub toggle_out2 { my $self = shift; my $flag = vec( $self->{flags}, 1, 1 ); vec( $self->{flags}, 1, 1 ) = !($flag); my $bytes = syswrite( $self->{fh}, '!0SO'.$self->{flags} ); ($_select->can_read( $TIMEOUT_SO )); } sub toggle_out3 { my $self = shift; my $flag = vec( $self->{flags}, 2, 1 ); vec( $self->{flags}, 2, 1 ) = !($flag); my $bytes = syswrite( $self->{fh}, '!0SO'.$self->{flags} ); ($_select->can_read( $TIMEOUT_SO * 2)); } 1;
      --Paris
      
    Re: sending to & reading from serial port
    by Anonymous Monk on Jun 18, 2001 at 21:17 UTC
      I'm having a little trouble (as a PERL newbie) reading my serial output (using the linux serial port PERL mod)...input from my script works great. What command and syntax would I use to parse the stuff I see in my minicom window? Right now I am being cheesy and using a minicom flag to write to a file for manual review.
        <Hi, Can anyone please tell how to send and receive the data using perl script in CAN???>
    Re: sending to & reading from serial port
    by Skunk-A-Roo (Initiate) on Jan 18, 2013 at 22:01 UTC
      I tried using Win32::Serial in a Windows 7 64 bit environment. I pilfered this line from one of the examples, and it isn't working for me: my $ob = Win32::SerialPort->new ("COM1") || die "Can't open port COM1: $!\n"; The error I get is: Access is denied. can't open device: COM1 Do you have any idea how to correct that?