File Coverage

blib/lib/Lab/Moose/Instrument.pm
Criterion Covered Total %
statement 97 101 96.0
branch 11 18 61.1
condition n/a
subroutine 29 29 100.0
pod 13 17 76.4
total 150 165 90.9


line stmt bran cond sub pod time code
1             package Lab::Moose::Instrument;
2             $Lab::Moose::Instrument::VERSION = '3.881';
3             #ABSTRACT: Base class for instrument drivers
4              
5 30     30   109164 use v5.20;
  30         129  
6              
7 30     30   731 use Moose;
  30         468867  
  30         235  
8 30     30   221245 use MooseX::StrictConstructor;
  30         765270  
  30         177  
9 30     30   303964 use Moose::Util::TypeConstraints qw(enum duck_type);
  30         82  
  30         300  
10 30     30   18079 use MooseX::Params::Validate;
  30         89787  
  30         279  
11 30     30   16682 use Module::Load 'load';
  30         4000  
  30         308  
12 30     30   20707 use Data::Dumper;
  30         178657  
  30         2394  
13 30     30   277 use Exporter 'import';
  30         93  
  30         865  
14 30     30   172 use Carp;
  30         380  
  30         2910  
15              
16             our @EXPORT_OK = qw(
17             timeout_param
18             read_length_param
19             channel_param
20             precision_param
21             getter_params
22             setter_params
23             validated_getter
24             validated_setter
25             validated_no_param_setter
26             validated_channel_getter
27             validated_channel_setter
28             );
29              
30             # do not make imported functions available as methods.
31             use namespace::autoclean
32              
33             # Need this for Exporter.
34 30         322 -except => 'import',
35 30     30   231 -also => [@EXPORT_OK];
  30         90  
36              
37             has connection_type => (
38             is => 'ro',
39             isa => 'Str',
40             predicate => 'has_connection_type',
41             );
42              
43             has connection_options => (
44             is => 'ro',
45             isa => 'HashRef',
46             default => sub { {} },
47             );
48              
49             has connection => (
50             is => 'ro',
51             isa => duck_type( [qw/Write Read Query Clear/] ),
52              
53             handles => {
54             write => 'Write',
55             binary_read => 'Read',
56             binary_query => 'Query',
57             clear => 'Clear',
58             },
59             writer => '_connection',
60             predicate => 'has_connection',
61             );
62              
63             has endian => (
64             is => 'ro',
65             isa => enum( [qw/native big little/] ),
66             default => 'native',
67             );
68              
69             # Can be subclassed in drivers.
70             sub default_connection_options {
71             return {
72 31     31 0 354 any => {},
73             VXI11 => {},
74             USB => {},
75             LinuxGPIB => {},
76             'VISA::GPIB' => {},
77             'VISA::USB' => {},
78             Socket => {},
79             Zhinst => {},
80             WWW => {},
81             };
82             }
83              
84             sub _default_connection_options {
85 31     31   79 my $self = shift;
86              
87 31         157 my $options = $self->default_connection_options();
88 31         929 $options = $options->{ $self->connection_type() };
89 31 50       151 if ($options) {
90 0         0 return $options;
91             }
92             else {
93 31         117 return {};
94             }
95             }
96              
97             sub BUILD {
98 35     35 0 4289 my $self = shift;
99 35         162 my $error_msg
100             = "Give either ready connection or 'connection_type' argument to instrument constructor.";
101 35 100       1454 if ( $self->has_connection ) {
102 4 50       141 if ( $self->has_connection_type ) {
103 0         0 croak $error_msg ;
104             }
105 4         36 return;
106             }
107 31 50       1184 if ( not $self->has_connection_type ) {
108 0         0 croak $error_msg;
109             }
110 31         968 my $connection_type = $self->connection_type();
111 31         186 $connection_type = "Lab::Moose::Connection::$connection_type";
112              
113             my $connection_options = {
114 31         153 %{ $self->_default_connection_options() },
115 31         136 %{ $self->connection_options() }
  31         1087  
116             };
117 31         190 load $connection_type;
118 31         2223 my $connection = $connection_type->new( %{$connection_options} );
  31         1305  
119 31         1305 $self->_connection($connection);
120             }
121              
122             with 'Lab::Moose::Instrument::Log';
123              
124              
125              
126             my $ieee488_2_white_space_character = qr/[\x{00}-\x{09}\x{0b}-\x{20}]/;
127              
128             sub _trim_pmt {
129 236     236   2744 my ($retval) = pos_validated_list(
130             \@_,
131             { isa => 'Str' }
132             );
133              
134 236         43510 $retval =~ s/${ieee488_2_white_space_character}*\n?\Z//;
135              
136 236         1442 return $retval;
137             }
138              
139             sub read {
140 1     1 1 396 my $self = shift;
141 1 50       69 if ($self->connection_type ne 'HTTP') {
142 1         8 return _trim_pmt( $self->binary_read(@_) );
143             } else {
144 0         0 return $self->binary_read(@_);
145             }
146             }
147              
148             sub query {
149 235     235 1 481 my $self = shift;
150 235         862 return _trim_pmt( $self->binary_query(@_) );
151             }
152              
153              
154             sub timeout_param {
155 1306     1306 1 5319 return ( timeout => { isa => 'Num', optional => 1 } );
156             }
157              
158              
159             sub read_length_param {
160 539     539 1 1802 return ( read_length => { isa => 'Int', optional => 1 } );
161             }
162              
163              
164             sub channel_param {
165 125     125 1 546 return ( channel => { isa => 'Int', optional => 1 } );
166             }
167              
168              
169             sub precision_param {
170 36     36 1 9744 return ( precision =>
171             { isa => enum( [qw/single double/] ), default => 'single' } );
172             }
173              
174              
175             sub getter_params {
176 533     533 1 1145 return ( timeout_param(), read_length_param() );
177             }
178              
179              
180             sub setter_params {
181 754     754 1 1647 return ( timeout_param() );
182             }
183              
184             sub validated_hash_no_cache {
185 1111     1111 0 3778 return validated_hash( @_, MX_PARAMS_VALIDATE_NO_CACHE => 1 );
186             }
187              
188              
189             sub validated_getter {
190 405     405 1 14431 my $args_ref = shift;
191 405         817 my %additional_parameter_spec = @_;
192 405         858 return validated_hash_no_cache(
193             $args_ref, getter_params(),
194             %additional_parameter_spec
195             );
196             }
197              
198              
199             sub validated_setter {
200 537     537 1 51135 my $args_ref = shift;
201 537         1355 my %additional_parameter_spec = @_;
202 537         1169 my ( $self, %args ) = validated_hash_no_cache(
203             $args_ref, setter_params(),
204             value => { isa => 'Str' }, %additional_parameter_spec
205             );
206 537         330540 my $value = delete $args{value};
207 537         2508 return ( $self, $value, %args );
208             }
209              
210              
211             sub validated_no_param_setter {
212 44     44 1 104 my $args_ref = shift;
213 44         111 my %additional_parameter_spec = @_;
214 44         138 my ( $self, %args ) = validated_hash_no_cache(
215             $args_ref, setter_params(),
216             %additional_parameter_spec
217             );
218 44         15187 return ( $self, %args );
219             }
220              
221             sub get_default_channel {
222 125     125 0 219 my $self = shift;
223 125 100       540 if ( $self->can('instrument_nselect') ) {
224 65         200 my $channel = $self->cached_instrument_nselect();
225 65 50       235 return $channel == 1 ? '' : $channel;
226             }
227             else {
228 60         160 return '';
229             }
230             }
231              
232              
233             sub validated_channel_getter {
234 68     68 1 131 my $args_ref = shift;
235 68         148 my %additional_parameter_spec = @_;
236 68         138 my ( $self, %args ) = validated_hash_no_cache(
237             $args_ref, getter_params(),
238             channel_param(), %additional_parameter_spec
239             );
240              
241 68         50571 my $channel = delete $args{channel};
242 68 50       214 if ( not defined $channel ) {
243 68         303 $channel = $self->get_default_channel();
244             }
245 68         389 return ( $self, $channel, %args );
246             }
247              
248              
249             sub validated_channel_setter {
250 57     57 1 4825 my $args_ref = shift;
251 57         145 my %additional_parameter_spec = @_;
252 57         137 my ( $self, %args ) = validated_hash_no_cache(
253             $args_ref, getter_params(), channel_param(),
254             value => { isa => 'Str' },
255             %additional_parameter_spec,
256             );
257 57         63879 my $channel = delete $args{channel};
258 57 50       181 if ( not defined $channel ) {
259 57         177 $channel = $self->get_default_channel();
260             }
261 57         142 my $value = delete $args{value};
262 57         305 return ( $self, $channel, $value, %args );
263             }
264              
265             __PACKAGE__->meta->make_immutable();
266              
267             1;
268              
269             __END__
270              
271             =pod
272              
273             =encoding UTF-8
274              
275             =head1 NAME
276              
277             Lab::Moose::Instrument - Base class for instrument drivers
278              
279             =head1 VERSION
280              
281             version 3.881
282              
283             =head1 SYNOPSIS
284              
285             A complete device driver based on Lab::Moose::Instrument:
286              
287             package Lab::Moose::Instrument::FooBar;
288             use Moose;
289              
290             use Lab::Moose::Instrument qw/validated_getter validated_setter/;
291              
292             use namespace::autoclean;
293              
294             extends 'Lab::Moose::Instrument';
295              
296             sub get_foo {
297             my ($self, %args) = validated_getter(\@_);
298             return $self->query(command => "Foo?", %args);
299             }
300              
301             sub set_foo {
302             my ($self, $value, %args) = validated_setter(\@_);
303             return $self->write(command => "Foo $value", %args);
304             }
305              
306             __PACKAGE__->meta->make_immutable();
307              
308             =head1 DESCRIPTION
309              
310             The Lab::Moose::Instrument module is a thin wrapper around a connection object.
311             All other Lab::Moose::Instrument::* drivers inherit from this module.
312              
313             =head1 METHODS
314              
315             =head2 new
316              
317             The constructor requires a connection object, which provides
318             C<Read>, C<Write>, C<Query> and C<Clear> methods. You can provide any object,
319             which supports these methods.
320              
321             =head2 write
322              
323             $instrument->write(command => '*RST', timeout => 10);
324              
325             Call the connection's C<Write> method. The timeout parameter is optional.
326              
327             =head2 binary_read
328              
329             my $data = $instrument->binary_read(timeout => 10);
330              
331             Call the connection's C<Read> method. The timeout parameter is optional.
332              
333             =head2 read
334              
335             Like C<binary_read>, but trim trailing whitespace and newline from the result.
336              
337             More precisely, this removes the I<PROGRAM MESSAGE TERMINATOR> (IEEE 488.2
338             section 7.5).
339              
340             =head2 binary_query
341              
342             my $data = $instrument->binary_query(command => '*IDN?', timeout => 10)
343              
344             Call the connection's C<Query> method. The timeout parameter is optional.
345              
346             =head2 query
347              
348             Like C<binary_query>, but trim trailing whitespace and newline from the result.
349              
350             More precisely, this removes the I<PROGRAM MESSAGE TERMINATOR> (IEEE 488.2
351             section 7.5).
352              
353             =head2 clear
354              
355             $instrument->clear();
356              
357             Call the connection's C<Clear> method.
358              
359             =head1 Functions
360              
361             The following functions standardise and simplify the use of
362             L<MooseX::Params::Validate> in instrument drivers. They are only exported on
363             request.
364              
365             =head2 timeout_param
366              
367             Return mandatory validation parameter for timeout.
368              
369             =head2 read_length_param
370              
371             Return mandatory validation parameter for read_length.
372              
373             =head2 channel_param
374              
375             Return optional validation parameter for channel. A given argument has to be an
376             'Int'. The default value is the empty string ''.
377              
378             =head2 precision_param
379              
380             Return optional validation parameter for floating point precision. The
381             parameter has to be either 'single' (default) or 'double'.
382              
383             =head2 getter_params
384              
385             Return list of validation parameters which shell be used in all query
386             operations, eg. timeout, ....
387              
388             =head2 setter_params
389              
390             Return list of validation parameters which shell be used in all write
391             operations, eg. timeout, ....
392              
393             =head2 validated_getter
394              
395             my ($self, %args) = validated_getter(\@_, %additional_parameter_spec);
396              
397             Call C<validated_hash> with the getter_params.
398              
399             =head2 validated_setter
400              
401             my ($self, $value, %args) = validated_setter(\@_, %additional_parameter_spec);
402              
403             Call C<validated_hash> with the C<setter_params> and a mandatory 'value'
404             argument, which must be of 'Str' type.
405              
406             =head2 validated_no_param_setter
407              
408             my ($self, %args) = validated_no_param_setter(\@_, %additional_parameter_spec);
409              
410             Like C<validated_setter> without the 'value' argument.
411              
412             =head2 validated_channel_getter
413              
414             my ($self, $channel, %args) = validated_channel_getter(\@_);
415              
416             Like C<validated_getter> with an additional C<channel_param> argument. If the
417             no channel argument is given, try to call
418             C<$self->cached_instrument_nselect>. If this method is not available, return
419             the empty string for the channel.
420              
421             =head2 validated_channel_setter
422              
423             my ($self, $channel, $value, %args) = validated_channel_setter(\@_);
424              
425             Analog to C<validated_channel_getter>.
426              
427             =head1 COPYRIGHT AND LICENSE
428              
429             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
430              
431             Copyright 2016 Simon Reinhardt
432             2017 Andreas K. Huettel, Simon Reinhardt
433             2018 Simon Reinhardt
434             2020 Andreas K. Huettel, Sam Bingner
435             2021 Fabian Weinelt
436             2022-2023 Mia Schambeck
437              
438              
439             This is free software; you can redistribute it and/or modify it under
440             the same terms as the Perl 5 programming language system itself.
441              
442             =cut