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

Anyone got any examples using Device::SerialPort?
I'm having problems talking to this nifty external modem and making it dial numbers ;). There's not that much documentation on it and it would be cool if someone could atleast get me started..

if not, no sweat.. C-Kermit and Expect.pm will have to do.

thanks

-brad..

Replies are listed 'Best First'.
(jcwren) Re: Device::SerialPort Examples..
by jcwren (Prior) on Feb 22, 2001 at 22:51 UTC

    This should get you started. It's a script I use to read my weather station. And, it will run either *nix, or Win32 platforms.

    #!/usr/bin/perl -w # # What we use # use strict; require 5.005; use vars qw($OS_win); my $debugGlobal = 0; my $portName = 0; my $logPath = 0; # # Run early to determine whether to load Win32::SerialPort (Win32) or + Device::SerialPort (Linux) # BEGIN { $OS_win = ($^O eq "MSWin32") ? 1 : 0; # print "Perl version: $]\n"; # print "OS version: $^O\n"; # # This must be in a BEGIN in order for the 'use' to be conditional # if ($OS_win) { eval "use Win32::SerialPort 0.14"; die "$@\n" if ($@); } else { eval "use Device::SerialPort"; die "$@\n" if ($@); } } # # Main entry point. If "action" is not defined, we default to login. # { my $data = 0; # # Enable flushing, && if debugging, kick out the content type # $| = 1; if (OS_Linux ()) { $logPath = "/home/system/weather/runlog.log"; $portName = '/dev/ttyS0'; } else { $logPath = "c:/perl/scripts/weather/runlog.log"; $portName = 'COM1'; } $debugGlobal && (open (LOG, ">>$logPath") || die "runlog.log: $!"); $debugGlobal && LOG->autoflush (1); runlog ('Starting run'); $data = read_wx_station (); runlog ("Exiting...\n"); exit; } # # Return 0 if running Windows, 1 if running anything else (Linux) # sub OS_Linux { return ($^O eq 'MSWin32' ? 0 : 1); } # # # sub read_wx_station { my $ob = 0; my $c = 0; my $record = ""; my $errcnt = 0; my $totalinbytes = 0; my $starttime = 0; if (OS_Linux ()) { $ob = new Device::SerialPort ($portName, 1); } else { $ob = new Win32::SerialPort ($portName, 1); } runlog ("Can't open serial port $portName: $^E\n") unless ($ob); die unless ($ob); runlog ('Setting serial port conditions'); $ob->baudrate (2400); $ob->parity ('none'); $ob->databits (8); $ob->stopbits (1); $ob->handshake ('none'); $ob->stty_icrnl (1); $ob->stty_ocrnl (1); $ob->stty_onlcr (1); $ob->stty_opost (1); $ob->write_settings (); runlog ('Waiting for a full weather record'); $starttime = time; for (;;) { my $blockingflags = 0; my $inbytes = 0; my $outbytes = 0; my $errflags = 0; # # See if we can read anything from the port # ($blockingflags, $inbytes, $outbytes, $errflags) = $ob->status o +r warn "could not get port status\n"; # # Did we get an 8250 error? # if (!OS_Linux ()) { if ($errflags & ($ob->CE_RXOVER | $ob->CE_OVERRUN | $ob->CE_R +XPARITY | $ob->CE_FRAME)) { if ($errcnt++ == 10) { runlog ("Aborted due to more than 10 errors\n"); die; } runlog ('Purging port'); $ob->purge_rx; $record = ""; } } # # Add the number of bytes read to the running total. Die if to +o many bytes without a record. Just for # grins, if we get too many, try shifting the baud rate and set +ting back so the UART will re-sync. # $totalinbytes += $inbytes; if ($totalinbytes > 1000) { if ($errcnt++ == 3) { runlog ("1000+ bytes read with no good data (wrong mode?)\ +n"); runlog ($record); die; } else { runlog ("purge for 1000+ bytes read with no good data"); $ob->baudrate (4800); $ob->write_settings (); $ob->baudrate (2400); $ob->write_settings (); $totalinbytes = 0; $starttime = time; } } # # If input is present in the buffer, read it, and add it to our + cumulative string # if ($c = $ob->input) { $c =~ s/\r//g; $c =~ s/\n//g; $record .= $c; if ($record =~ m/(!!)/) { runlog ("U2000 is in datalogging mode!\n"); die; } elsif ($record =~ m/(\$ULTW)/i) { runlog ("U2000 is in packet mode!\n"); die; } last if $record =~ /(&CR&).*(&CR&)/; } # # See if we've been doing this serial thing for too long. # if ((time - $starttime) > 30) { runlog ("Over 30 seconds with no good data (U2000 connected?) +\n"); die; } # # Basically sleep for .2 seconds # select undef, undef, undef, 0.2; } runlog ('Port read complete'); $ob->close or die "Close failed: $!\n"; undef $ob; runlog ('Starting weather data parsing'); $record =~ s/^.*?(&CR&)//; $record =~ s/(&CR&).*//; $record =~ s/^/&CR&/; runlog ('Returning 1 complete weather record'); return ($record); } # # # sub runlog { my $text = shift; $debugGlobal && print LOG scalar (localtime ()), ": $text\n"; }
    --Chris

    e-mail jcwren
      Very nice.. There's one thing I did notice about your example that doesn't apply to what I'm doing.. I need to read and write to/from a serial device.. I tried a few things to no avail.. I'm working on my third try now and will post my code for criticism and possibly help if it dosen't work..
      Thanks much jcwren, beautiful code I wish I could ++ it more than once. ;)

      -brad..
Re: Device::SerialPort Examples..
by reyjrar (Hermit) on Feb 23, 2001 at 06:11 UTC
    Here's what I came up with.. its VERY primitive at this point, and I'll be developing it more so, much thanks to jcwren for his example.. I hope this helps someone out there..
    #!/usr/bin/perl # # Purpose: Dial the OOB on a cisco router # and determine the OOB if the # OOB line is up and functioning # properly # # Code by Brad Lhotsky <brad@divisionbyzero.net> # Based off code by jcwren on http://perlmonks.org # $|++; use strict; use Device::SerialPort; ################### # configs. my $DEVICE = '/dev/cua1'; # serial port ext. modem is on my $QUIETDIAL = 0; # Turn on/off the modem speake +r my $USERNAME = 'username' . "\n"; # username for the router my $PASSWORD = 'password' . "\n"; # password for the router my $NUMBER = '912345678'; # routers number my $MAX_RETRY = 3; # number of times we retry my $DEBUG = 1; # print a whole buncha crap? ################### # Globals. my $DONE = 0; my $TOTALIN = 0; my $TOTALOUT = 0; my $SUCCESS = 0; my $ERROR = ""; my $ob = new Device::SerialPort ($DEVICE, 1); die "Couldn't access $DEVICE: $!\n" unless $ob; ################### # setup device print "configuring ... "; sleep(1); $ob->baudrate(9600); $ob->parity('none'); $ob->databits(8); $ob->stopbits(1); $ob->handshake('none'); $ob->stty_icrnl(1); $ob->stty_ocrnl(1); $ob->stty_onlcr(1); $ob->stty_opost(1); $ob->write_settings; print "done.\n"; #################### # Now we need to do # some modem dialing # stuff.. my $init = "ATH0\n"; # modem hangup, clear the line +. my $silence = "ATM0\n"; # silence the speaker my $dial = "ATDT $NUMBER\n"; # dial the number my $count = $ob->write($init); warn "WRITE FAILED!\n" unless $count; warn "WRITE INCOMPLETE!\n" if $count != length($init); select undef, undef, undef, 2.5; # sleep 2.5 seconds. if($QUIETDIAL) { $count = $ob->write($silence); warn "WRITE FAILED!\n" unless $count; warn "WRITE INCOMPLETE!\n" if $count != length($silence); select undef, undef, undef, 2.5; # sleep 2.5 seconds. } $count = $ob->write($dial); warn "WRITE FAILED!\n" unless $count; warn "WRITE INCOMPLETE!\n" if $count != length($dial); #################### # trap ctrl+c here. $SIG{'INT'} = sub { $DONE++; $ob->close; undef $ob; }; my $RETRY = 0; while(!$DONE) { my ($inbytes,$outbytes) = (0,0); (undef, $inbytes, $outbytes, undef) = $ob->status or warn "could not get port status!\n"; $TOTALIN += $inbytes; $TOTALOUT += $outbytes; if(my $line = $ob->input) { if($line =~ /CONNECT\s+(\d+)/i) { # Standard baudrate should be 9600, # but in case its not, we need to # reconfigure our modem. $ob->baudrate($1); $ob->write_settings; sleep(1); # After this point we need ot push "enter" a f +ew times. $ob->write("\n\n"); } elsif($line =~ /sername\:/) { $ob->write($USERNAME); } elsif($line =~ /assword\:/) { $ob->write($PASSWORD); } elsif($line =~ /NO CARRIER/i) { end(\$ob, \$DONE) if ($RETRY >= $MAX_RETRY); $RETRY++; $ob->write($init); select undef, undef, undef, 1.5; $ob->write($dial); } elsif($line =~ /[\w().-]*[\$#>]/) { # prompt # which is all we were looking for! # we're done! and successfully! $DONE++; $SUCCESS++; last; } print $line; } select undef, undef, undef, 0.5; # sleep for half a second. } print "Total bytes: $TOTALIN (in), $TOTALOUT (out)\n"; if($SUCCESS) { end(\$ob); print "successful!\n"; } sub end { my $obref = shift; my $checkref = shift; ref($checkref) && $$checkref++; $ob->write("ATH0\n"); $ob->close; undef $ob; }

    welp thats about it.. look for it to go up in its finalized state on http://www.otrics.com where me and my friend (cleen here) are assembling a suite of network monitoring/auditing/configuration/trouble shooting tools for all you network admins out there.. wish us luck.. ;)

    -brad..