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

Dear Monks,

I need to communicate with an appliance, the consolle port of which is linked to my RedHat 7.2 system's serial port.

I started writing a Perl programs that uses the basic filehandle syntax

open(PORTA, "+</dev/ttyS0"); ... print PORTA $stringout; ... $answer = <PORTA>;

I tested it connecting my serial port to a Windows workstation running Hyperterminal, and it worked out ok!

Sadly, when I tried it on the needed connection, I got absolutely no response from the appliance.

I blamed it on the different serial port configuration requested by the appliance (9600 bps, 8-bit, 1-stop, no parity, ?flow control? = none), and so I turned to the more sophisticated "Device::SerialPort" module, which should provide the right tools to set the port parameters.

I tested it again using Hyperterminal but this time, though I managed to get my strings sent, the replies I sent from the Windows hyperterminal never reached my Linux PC...naturally, it didn't work with the appliance either.

I must certainly be going wrong somewhere, but I have no clue at all.

Could you please help?

I attach hereby the two versions of the program (both of which read the strings that must be sent from an input text file) and the script I used to set the port parameters.

Thank you very much in advance.

Best regards
Bruno

serial_old.pl - The first version of the program ================================================ #!/usr/bin/perl -w # Routines # comunicate: adds a customary terminator to the string, which is then + sent to # the serial port, the standard output and the logfile; finally it rea +ds the # reply coming from the serial port and prints it on the standard outp +ut and # the logfile sub comunicate{ $terminator = "\n"; $stringout = $_[0].$terminator; print PORTA $stringout; print "Sent: $stringout\n"; print FOUT "Sent: $stringout\n"; ascspell($stringout); $answer = <PORTA>; print "Received: $answer\n"; print FOUT "Received: $answer\n"; ascspell($answer); } # ascspell: displays the ASCII codes for each character in a given str +ing sub ascspell{ @array = unpack("C*", $_[0]); print "["; foreach $ch (@array) { print "$ch "; print FOUT "$ch "; } print "]\n"; } # Main open(FIN,$ARGV[0]) or die ("error opening input file because: $!"); @inner = <FIN>; close(FIN); open(FOUT, "+>serial_old.log"); open(PORTA, "+</dev/ttyS0"); foreach $riga (@inner) { chomp($riga); comunicate($riga); } close(PORTA); close(FOUT); ============ serconf.pl - The script that sets the port parameters and writes them +to a config file ====================================================================== +================ #!/usr/bin/perl -w use Device::SerialPort; # Initialisation $PortName="/dev/ttyS0"; $ConfigurationFileName="./ttyS0.conf"; $quiet=1; $lockfile="./lock"; $PortObj = new Device::SerialPort ($PortName, $quiet, $lockfile) || die "Can't open $PortName: $!\n"; $PortObj->user_msg(ON); $PortObj->databits(8); $PortObj->baudrate(9600); $PortObj->parity("none"); $PortObj->stopbits(1); $PortObj->handshake("rts"); print "Given configuration\n\n"; print "Port Name: $PortName\n"; $baud = $PortObj->baudrate; $parity = $PortObj->parity; $data = $PortObj->databits; $stop = $PortObj->stopbits; $hshake = $PortObj->handshake; print "B = $baud, D = $data, S = $stop, P = $parity, H = $hshake\n"; $PortObj->write_settings; $PortObj->save($ConfigurationFileName) || warn "Can't save $Configurat +ionFileName: $!\n"; ====================================================================== +=================== serial.pl - The Device::SerialPort version ========================================== #!/usr/bin/perl -w use Device::SerialPort; # Routines # comunicate: adds a customary terminator to the string, which is then + sent to # the serial port, the standard output and the logfile; finally it rea +ds the # reply coming from the serial port and prints it on the standard outp +ut and # the logfile sub comunicate{ $terminator = "\n"; $stringout = $_[0].$terminator; print PORTA $stringout; print "Sent: $stringout\n"; print FOUT "Sent: $stringout\n"; ascspell($stringout); $answer = <PORTA>; print "Received: $answer\n"; print FOUT "Received: $answer\n"; ascspell($answer); } # ascspell: displays the ASCII codes for each character in a given str +ing sub ascspell{ @array = unpack("C*", $_[0]); print "["; foreach $ch (@array) { print "$ch "; print FOUT "$ch "; } print "]\n"; } # Initialisation $cfgfile="./ttyS0.conf"; # created by serco +nf.pl $PortObj= tie(*PORTA,'Device::SerialPort', $cfgfile) || die "Can't start $cfgfile\n"; my $name= $PortObj->alias; my $baud = $PortObj->baudrate; my $parity = $PortObj->parity; my $data = $PortObj->databits; my $stop = $PortObj->stopbits; my $hshake = $PortObj->handshake; print "Port: $name\nB = $baud, D = $data, S = $stop, P = $parity, H = +$hshake\n"; # Main open(FIN,$ARGV[0]) or die ("error opening input file because: $!"); @inner = <FIN>; close FIN; open(FOUT, "+>serial.log"); foreach $riga (@inner) { chomp($riga); comunicate($riga); } close PORTA || print "port close failed\n"; undef $PortObj; untie *PORTA; close FOUT;

Edited by Chady -- fixed formatting, added code tags.

Replies are listed 'Best First'.
Re: Sending commands and viewing replies from a serial-attached appliance
by bschmer (Friar) on Jan 16, 2004 at 12:41 UTC
    I don't have Device::SerialPort on my machine, but did you try different values for flow control? You said that the appliance expected no flow control, but you set the serial port in your script to RTS. Hopefully it's as simple as setting flow control in your script to "none".

    Update: I installed Device::SerialPort and ran your script with minicom running on the other end of the cable and it worked as expected, so I'm going to stick with my guess that you have one of the communication parameters mismatched.

      You are certainly right: the software version I posted contained "rts" in order to match the Hyperterminal settings, but when I connected to the appliance I set the parameter to "none". And naturally it didn't work.

      I forgot to mention: I tried minicom to connect to the windows PC...it stays stuck to "Offline"

      Bruno

Re: Sending commands and viewing replies from a serial-attached appliance
by duff (Parson) on Jan 16, 2004 at 14:52 UTC
    I blamed it on the different serial port configuration requested by the appliance (9600 bps, 8-bit, 1-stop, no parity, ?flow control? = none), and so I turned to the more sophisticated "Device::SerialPort" module, which should provide the right tools to set the port parameters.

    Alternatively you could've used something you probably already have installed to accomplish the same task: stty. The code would look something like this:

    my $dev = "/dev/ttyS0"; open(DEV,"+<$dev") or die; system("/bin/stty <$dev 9600 cs8 -parenb -cstopb -crtscts clocal raw") +; # talk to DEV here close DEV;