File Coverage

blib/lib/Lab/Moose/Connection/Socket.pm
Criterion Covered Total %
statement 68 71 95.7
branch 11 20 55.0
condition 1 2 50.0
subroutine 12 13 92.3
pod 1 4 25.0
total 93 110 84.5


line stmt bran cond sub pod time code
1             package Lab::Moose::Connection::Socket;
2             $Lab::Moose::Connection::Socket::VERSION = '3.881';
3             #ABSTRACT: Transfer IEEE 488.2 / SCPI messages over TCP
4              
5 3     3   213966 use v5.20;
  3         28  
6              
7 3     3   1202 use Moose;
  3         964460  
  3         21  
8 3     3   24679 use MooseX::Params::Validate;
  3         181402  
  3         22  
9 3     3   2875 use Socket qw(IPPROTO_TCP TCP_NODELAY);
  3         7883  
  3         398  
10 3     3   1054 use IO::Socket::INET;
  3         35917  
  3         23  
11 3     3   2667 use IO::Select;
  3         3263  
  3         145  
12 3     3   23 use Carp;
  3         9  
  3         186  
13              
14 3     3   1172 use Lab::Moose::Instrument qw/timeout_param read_length_param/;
  3         18  
  3         361  
15              
16 3     3   25 use namespace::autoclean;
  3         9  
  3         28  
17              
18             has client => (
19             is => 'ro',
20             isa => 'IO::Socket::INET',
21             writer => '_client',
22             init_arg => undef,
23             );
24              
25             has select => (
26             is => 'ro',
27             isa => 'IO::Select',
28             writer => '_select',
29             init_arg => undef,
30             );
31              
32             has host => (
33             is => 'ro',
34             isa => 'Str',
35             required => 1,
36             );
37              
38             has port => (
39             is => 'ro',
40             isa => 'Int',
41             required => 1,
42             );
43              
44             has write_termchar => (
45             is => 'ro',
46             isa => 'Maybe[Str]',
47             default => "\n",
48             );
49              
50             sub BUILD {
51 1     1 0 19 my $self = shift;
52 1         77 my $host = $self->host();
53 1         36 my $port = $self->port();
54 1         46 my $timeout = $self->timeout();
55 1 50       37 my $client = IO::Socket::INET->new(
56             PeerAddr => $host,
57             PeerPort => $port,
58             Proto => 'tcp',
59             Timeout => $timeout,
60              
61             # enable use of orphaned connection after a script was killed by user
62             ReuseAddr => 1,
63             ) or croak "cannot open connection with $host on port $port: $!";
64              
65 1 50       2287 $client->setsockopt( IPPROTO_TCP, TCP_NODELAY, 1 )
66             or croak "setsockopt: cannot enable TCP_NODELAY";
67              
68 1 50       21 my $select = IO::Select->new($client)
69             or croak "cannot create IO::Select object: $!";
70              
71 1         118 $self->_client($client);
72 1         52 $self->_select($select);
73             }
74              
75             sub Write {
76 3     3 0 12 my ( $self, %args ) = validated_hash(
77             \@_,
78             timeout_param,
79             command => { isa => 'Str' },
80             );
81              
82 3   50     1111 my $write_termchar = $self->write_termchar() // '';
83 3         10 my $command = $args{command} . $write_termchar;
84 3         25 my $timeout = $self->_timeout_arg(%args);
85 3         87 my $host = $self->host();
86 3         84 my $port = $self->port();
87              
88 3         100 my $client = $self->client();
89              
90 3         6 my $length = length($command);
91 3         6 my $written = 0;
92 3         103 my $select = $self->select();
93 3         9 while ($length) {
94 3 50       23 if ( !$select->can_write($timeout) ) {
95 0         0 croak "timeout in Socket connection Write, host $host on port $port";
96             }
97 3 50       185 my $bytes_written = $client->syswrite( $command, $length, $written )
98             or croak("Write: syswrite to host $host on port $port failed: $!");
99 3         232 $written += $bytes_written;
100 3         19 $length -= $bytes_written;
101             }
102             }
103              
104             sub Read {
105 3     3 1 12 my ( $self, %args ) = validated_hash(
106             \@_,
107             timeout_param(),
108             read_length_param(),
109             );
110 3         922 my $timeout = $self->_timeout_arg(%args);
111 3         13 my $read_length = $self->_read_length_arg(%args);
112 3         98 my $client = $self->client();
113 3         86 my $select = $self->select();
114 3         83 my $host = $self->host();
115 3         110 my $port = $self->port();
116              
117 3         5 my $string;
118 3         9 my $length = 0;
119 3 100       13 if ( $args{read_length} ) {
120              
121             # explicit read_length arg:
122             # Keep reading until we have $read_length bytes.
123 2         6 while ($read_length) {
124 4 50       17 if ( !$select->can_read($timeout) ) {
125 0         0 croak "timeout in connection Read, host $host on port $port";
126             }
127 4 50       170 my $read_bytes
128             = $client->sysread( $string, $read_length, $length )
129             or croak "socket read error, host $host on port $port: $!";
130 4         393 $read_length -= $read_bytes;
131 4         23 $length += $read_bytes;
132             }
133             }
134             else {
135 1 50       19 if ( !$select->can_read($timeout) ) {
136 0         0 croak "timeout in connection Read, host $host on port $port";
137             }
138 1 50       75 $client->sysread( $string, $read_length )
139             or croak "socket read error: $!";
140             }
141              
142 3         103 return $string;
143             }
144              
145       0 0   sub Clear {
146              
147             # Some instruments provide an additional control port.
148             }
149              
150             with qw/
151             Lab::Moose::Connection
152             /;
153              
154             __PACKAGE__->meta->make_immutable();
155              
156             1;
157              
158             __END__
159              
160             =pod
161              
162             =encoding UTF-8
163              
164             =head1 NAME
165              
166             Lab::Moose::Connection::Socket - Transfer IEEE 488.2 / SCPI messages over TCP
167              
168             =head1 VERSION
169              
170             version 3.881
171              
172             =head1 SYNOPSIS
173              
174             use Lab::Moose;
175              
176             my $instrument = instrument(
177             type => 'random_instrument',
178             connection_type => 'Socket',
179             connection_options => {
180             host => '132.199.11.2',
181             port => 5025
182             },
183             );
184              
185             =head1 DESCRIPTION
186              
187             This connection uses L<IO::Socket::INET> to interface with the operating
188             system's TCP stack. This works on most operating systems without installing any
189             additional software.
190              
191             Without knowing the syntax of the used command-messages there is no way for the
192             connection to determine when C<Read> is finished. This is unlike GPIB, USBTMC,
193             or VXI-11 which have explicit End of Message indicators. To deal with this, the
194             C<read_length> parameter has the following semantics:
195              
196             =over
197              
198             =item C<Read> is given an explicit C<read_length> parameter
199              
200             Keep calling sysread until C<read_length> bytes are read.
201              
202             =item C<Read> is not given an explicit C<read_length> parameter
203              
204             Do a single sysread with the connections default C<read_length>.
205              
206             =back
207              
208             For SCPI definite length blocks you will have to give the exact block length
209             with the C<read_length> parameter.
210              
211             =head2 CONNECTION OPTIONS
212              
213             =over
214              
215             =item host
216              
217             Host address.
218              
219             =item port
220              
221             Host port.
222              
223             =item write_termchar
224              
225             Append this to each write command. Default: C<"\n">.
226              
227             =back
228              
229             =head1 COPYRIGHT AND LICENSE
230              
231             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
232              
233             Copyright 2017 Andreas K. Huettel, Simon Reinhardt
234             2020 Andreas K. Huettel
235             2021 Andreas K. Huettel, Simon Reinhardt
236              
237              
238             This is free software; you can redistribute it and/or modify it under
239             the same terms as the Perl 5 programming language system itself.
240              
241             =cut