The following example shows how Modbus I/O is done via a TCP/IP socket interface.
#!/usr/bin/env perl use strict; use Socket; use Fcntl; my ($remote, $port) = qw( hasa106bc01 502); my $iaddr = inet_aton( $remote) or die "no host $remote"; my $paddr = sockaddr_in( $port, $iaddr); my $proto = getprotobyname( 'tcp'); socket( SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket: $!"; connect( SOCK, $paddr) or die "connect: $!"; my $flags = fcntl( SOCK, F_GETFL(), 0); $flags &= ~O_NONBLOCK(); fcntl( SOCK, F_SETFL(), $flags); # # create PDU, protocol data unit # my $fc = 0x17; # read/write multiple registers my $countR = 12; # read count, in units of 2B my $adrR = 0x4000; # start address for read my $adrW = 0x4003; # start address for write my @values = qw( 14 17); # write values my $countW = scalar( @values); my $bc = $countW*2; # write count in B my $pdu = pack "CnnnnCn*", $fc, $adrR, $countR, $adrW, $countW, $bc, @values; # # create TCP header, 7B # my $tid = 1234; # Transaction identifier, 2B, recopied by the server my $pid = 0; # Protocol identifier, 2B, 0 = MB my $len = (length( $pdu) + 1); # Len, 2B, number of following bytes, including uid and data my $uid = 1; # Unit identifier, 1B, identification of a remote slave my $header = pack "nnnC", $tid, $pid, $len, $uid; # # append PDU to header # my $msg = $header . $pdu; syswrite( SOCK, $msg, length( $msg), 0); goto finish if( !fd_select( \*SOCK, 1.0)); my $response; my $exp = 7 + 2 + 2*$countR; my $len = sysread( SOCK, $response, $exp, 0); print " received $len/$exp \n"; $header = substr($response, 0, 6); my ($tid, $prid, $len) = unpack 'nnn', $header; #my ($tid, $prid, $hilen, $lolen) = unpack 'nnCC', $header; #print " tid $tid, prid $prid, hilen $hilen, lolen $lolen \n"; my ($unit, $fc, $bc) = unpack 'C*', substr($response, 6, 3); print sprintf " unit $unit, f 0x%x, bc $bc \n", $fc; my @data = unpack 'n*', substr($response, 9); print " data @data \n"; #my $len = 0x100 * $hilen + $lolen; print " len $len \n"; finish: close( SOCK); exit; # # select # sub fd_select { my ( $fd, $tmo) = @_; my $rin = my $win = my $ein = ""; vec( $rin, fileno( $fd), 1) = 1; $ein = $rin | $win; my ( $nfd, $remaining) = select( $rin, $win, $ein, $tmo); wantarray ? ( $nfd, $remaining) : $nfd; }