#!/usr/bin/perl -w # Perl Modbus Client use Socket; use Getopt::Std; use vars qw($opt_u $opt_r $opt_c $opt_g $opt_t $opt_h $opt_s $opt_p); my ($remote, $port, $iaddr, $paddr, $proto, $line, $ans); my ($ta_id, $prot_id, $unit_id, $mb_fc, $ref, $count, @data); # Der Client wird flexibel durch Optionen, die es erlauben, # ihn wie ein klassisches Unix-Tool mit vielen Parametern # aufzurufen $unit_id = $opt_u = 1; # SPS-Station $ref = $opt_r = 0; # Register darauf $count = $opt_c = 16; # Anzahl übertragener Register $opt_g = 0; # Anforderung zum Lesen $opt_t = 0; # Anforderung zum Schreiben $opt_h = 0; # Anforderung der Hilfe $remote = $opt_s = 'server'; # IP-Name des Servers $port = $opt_p = 502; # Port-Nummer getopts('u:r:c:gths:p:'); # Abfrage der Parameter if ($opt_h) { # Netterweise eine Gebrauchsanweisung print "\n usage: $0 [-u unit(1)] [-r register(0)] [-c count(16)]\n", " [(-g et)|-t ransmit] [-h elp]\n", " [-s server(yak)] [-p port(502)]\n\n"; exit; } # Welche Optionen sind eingegeben worden? $unit_id = $opt_u; $ref = $opt_r; $count = $opt_c; $remote = $opt_s; $port = $opt_p; $mb_fc = 3; if ($opt_t) { unless ($opt_g) { # wenn nicht lesen, dann schreiben $mb_fc = 16; @data = @ARGV; $count = $#data + 1; } } $ta_id = 1234; # beliebig $prot_id = 502; # " - aber in Anlehung an die Portnummer # Verbindungsdaten festlegen if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') } die "No Port" unless $port; $iaddr = inet_aton($remote) or die "No Host: $remote"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); while ( 1 ) { # dieser Client hält eine dauernde Verbindung zum Server # dies erlaubt die kontinuierliche Beobachtung der Simulation socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket: $!"; connect(SOCK, $paddr) or die "connect: $!"; # Netzwerkverbindung und Terminalausgabe ungepuffert. select SOCK; $| = 1; select STDOUT; $| = 1; # Request formulieren (binär!) $line = pack "nnnCCnn", $ta_id, $prot_id, 6, $unit_id, $mb_fc, $ref, $count; if ( $mb_fc == 0x10 ) { # binär kodieren - Big Endian $line .= pack 'Cn*', 2*$count, @data; } # und absenden send SOCK, $line, 0; # ein wenig Geduld zeigen - hier 100 msec select(undef, undef, undef, 0.1); # und auf Antwort warten next unless defined(recv SOCK, $ans, 6+3+2*$count, 0); # Wenn der Server die Verbindung nicht schließt, dann tun wir das close (SOCK); # und bereiten die Ausgabe vor my $header = substr($ans, 0, 6); my ($tid, $prid, $hilen, $lolen) = unpack 'nnCC', $header; my ($unit, $fc, $bc) = unpack 'C*', substr($ans, 6, 3); # binär dekodieren @data = unpack 'n*', substr($ans, 9); my $len = 0x100 * $hilen + $lolen; print "Unit $unit(Ref $ref): "; foreach (@data) { printf "%5d ", $_; } print "\n"; if ( $mb_fc == 0x10 ) { # wenn wir nur geschrieben haben, Schluß exit; } } exit; # That's it