File Coverage

blib/lib/Lab/Moose/Instrument/Lakeshore340.pm
Criterion Covered Total %
statement 23 112 20.5
branch 0 2 0.0
condition 0 51 0.0
subroutine 8 33 24.2
pod 24 25 96.0
total 55 223 24.6


line stmt bran cond sub pod time code
1             package Lab::Moose::Instrument::Lakeshore340;
2             $Lab::Moose::Instrument::Lakeshore340::VERSION = '3.880';
3             #ABSTRACT: Lakeshore Model 340 Temperature Controller
4              
5 1     1   2238 use v5.20;
  1         4  
6              
7 1     1   9 use Moose;
  1         4  
  1         14  
8 1     1   7634 use Moose::Util::TypeConstraints qw/enum/;
  1         4  
  1         8  
9 1     1   551 use MooseX::Params::Validate;
  1         2  
  1         10  
10 1         87 use Lab::Moose::Instrument qw/
11 1     1   612 validated_getter validated_setter setter_params /;
  1         3  
12 1     1   15 use Lab::Moose::Instrument::Cache;
  1         3  
  1         10  
13 1     1   773 use Carp;
  1         3  
  1         71  
14 1     1   8 use namespace::autoclean;
  1         2  
  1         9  
15              
16             #use POSIX qw/log10 ceil floor/;
17              
18             extends 'Lab::Moose::Instrument';
19              
20             with qw(
21             Lab::Moose::Instrument::Common
22             );
23              
24             has input_channel => (
25             is => 'ro',
26             isa => enum( [qw/A B C D/] ),
27             default => 'A',
28             );
29              
30             has default_loop => (
31             is => 'ro',
32             isa => enum( [ 1 .. 2 ] ),
33             default => 1,
34             );
35              
36             sub BUILD {
37 0     0 0   my $self = shift;
38 0           $self->clear();
39 0           $self->cls();
40             }
41              
42             my %channel_arg
43             = ( channel => { isa => enum( [qw/A B C D/] ), optional => 1 } );
44             my %loop_arg = ( loop => { isa => enum( [qw/1 2/] ), optional => 1 } );
45              
46              
47             sub get_T {
48 0     0 1   my ( $self, %args ) = validated_getter(
49             \@_,
50             %channel_arg
51             );
52 0   0       my $channel = delete $args{channel} // $self->input_channel();
53 0           return $self->query( command => "KRDG? $channel", %args );
54             }
55              
56             sub get_value {
57 0     0 1   my $self = shift;
58 0           return $self->get_T(@_);
59             }
60              
61              
62             sub get_sensor_units_reading {
63 0     0 1   my ( $self, %args ) = validated_getter(
64             \@_,
65             %channel_arg
66             );
67 0   0       my $channel = delete $args{channel} // $self->input_channel();
68 0           return $self->query( command => "SRDG? $channel", %args );
69             }
70              
71              
72             sub get_setpoint {
73 0     0 1   my ( $self, %args ) = validated_getter(
74             \@_,
75             %loop_arg
76             );
77 0   0       my $loop = delete $args{loop} // $self->default_loop;
78 0           return $self->query( command => "SETP? $loop", %args );
79             }
80              
81             sub set_setpoint {
82 0     0 1   my ( $self, $value, %args ) = validated_setter(
83             \@_,
84             %loop_arg
85             );
86 0   0       my $loop = delete $args{loop} // $self->default_loop;
87              
88             # Device bug. The 340 cannot parse values with too many digits.
89 0           $value = sprintf( "%.6G", $value );
90 0           $self->write( command => "SETP $loop,$value", %args );
91             }
92              
93              
94             sub set_T {
95 0     0 1   my $self = shift;
96 0           $self->set_setpoint(@_);
97             }
98              
99              
100             sub set_heater_range {
101 0     0 1   my ( $self, $value, %args ) = validated_setter(
102             \@_,
103             value => { isa => enum( [qw/0 1 2 3 4 5/] ) }
104             );
105 0           $self->write( command => "RANGE $value", %args );
106             }
107              
108             sub get_heater_range {
109 0     0 1   my ( $self, %args ) = validated_getter( \@_ );
110 0           return $self->query( command => "RANGE?", %args );
111             }
112              
113              
114             sub set_control_mode {
115 0     0 1   my ( $self, $value, %args ) = validated_setter(
116             \@_,
117             value => { isa => enum( [ ( 1 .. 6 ) ] ) },
118             %loop_arg
119             );
120 0   0       my $loop = delete $args{loop} // $self->default_loop;
121 0           return $self->write( command => "CMODE $loop,$value", %args );
122             }
123              
124             sub get_control_mode {
125 0     0 1   my ( $self, %args ) = validated_getter(
126             \@_,
127             %loop_arg
128             );
129 0   0       my $loop = delete $args{loop} // $self->default_loop;
130 0           return $self->query( command => "CMODE? $loop", %args );
131             }
132              
133              
134             sub set_mout {
135 0     0 1   my ( $self, $value, %args ) = validated_setter(
136             \@_,
137             value => { isa => 'Num' },
138             %loop_arg
139             );
140 0   0       my $loop = delete $args{loop} // $self->default_loop;
141 0           return $self->write( command => "MOUT $loop,$value", %args );
142             }
143              
144             sub get_mout {
145 0     0 1   my ( $self, %args ) = validated_getter(
146             \@_,
147             %loop_arg
148             );
149 0   0       my $loop = delete $args{loop} // $self->default_loop;
150 0           return $self->query( command => "MOUT? $loop", %args );
151             }
152              
153              
154             sub set_control_parameters {
155 0     0 1   my ( $self, %args ) = validated_getter(
156             \@_,
157             %loop_arg,
158             %channel_arg,
159             units => { isa => enum( [qw/1 2 3/] ) },
160             state => { isa => enum( [qw/0 1/] ) },
161             powerup_enable => { isa => enum( [qw/0 1/] ), default => 1 },
162             );
163 0   0       my $channel = delete $args{channel} // $self->input_channel();
164              
165             my ( $loop, $units, $state, $powerup_enable )
166 0           = delete @args{qw/loop units state powerup_enable/};
167 0   0       $loop = $loop // $self->default_loop;
168 0           $self->write( command => "CSET $loop, $channel, $units, $state,"
169             . "$powerup_enable", %args );
170             }
171              
172             sub get_control_parameters {
173 0     0 1   my ( $self, %args ) = validated_getter(
174             \@_,
175             %loop_arg
176             );
177 0   0       my $loop = delete $args{loop} // $self->default_loop();
178 0           my $rv = $self->query( command => "CSET? $loop", %args );
179 0           my @rv = split /,/, $rv;
180             return (
181 0           channel => $rv[0], units => $rv[1], state => $rv[2],
182             powerup_enable => $rv[3]
183             );
184             }
185              
186              
187             sub set_input_curve {
188 0     0 1   my ( $self, $value, %args ) = validated_setter(
189             \@_,
190             %channel_arg,
191             value => { isa => enum( [ 0 .. 60 ] ) },
192             );
193 0   0       my $channel = delete $args{channel} // $self->input_channel();
194 0           $self->write( command => "INCRV $channel,$value", %args );
195             }
196              
197             sub get_input_curve {
198 0     0 1   my ( $self, %args ) = validated_getter(
199             \@_,
200             %channel_arg,
201             );
202 0   0       my $channel = delete $args{channel} // $self->input_channel();
203 0           return $self->query( command => "INCRV $channel", %args );
204             }
205              
206              
207             sub set_remote_mode {
208 0     0 1   my ( $self, $value, %args )
209             = validated_setter( \@_, value => { isa => enum( [ 1 .. 3 ] ) } );
210 0           $self->write( command => "MODE $value", %args );
211             }
212              
213             sub get_remote_mode {
214 0     0 1   my ( $self, %args ) = validated_getter( \@_ );
215 0           return $self->query( command => "MODE?", %args );
216             }
217              
218              
219             sub set_pid {
220 0     0 1   my ( $self, %args ) = validated_getter(
221             \@_,
222             %loop_arg,
223             P => { isa => 'Lab::Moose::PosNum' },
224             I => { isa => 'Lab::Moose::PosNum' },
225             D => { isa => 'Lab::Moose::PosNum' }
226             );
227 0           my ( $loop, $P, $I, $D ) = delete @args{qw/loop P I D/};
228 0   0       $loop = $loop // $self->default_loop();
229 0           $self->write(
230             command => sprintf( "PID $loop, %.1f, %.1f, %d", $P, $I, $D ),
231             %args
232             );
233             }
234              
235             sub get_pid {
236 0     0 1   my ( $self, %args ) = validated_getter(
237             \@_,
238             %loop_arg
239             );
240 0   0       my $loop = delete $args{loop} // $self->default_loop;
241 0           my $pid = $self->query( command => "PID? $loop", %args );
242 0           my %pid;
243 0           @pid{qw/P I D/} = split /,/, $pid;
244 0           return %pid;
245             }
246              
247              
248             sub set_zone {
249 0     0 1   my ( $self, %args ) = validated_getter(
250             \@_,
251             %loop_arg,
252             zone => { isa => enum( [ 1 .. 10 ] ) },
253             top => { isa => 'Lab::Moose::PosNum' },
254             P => { isa => 'Lab::Moose::PosNum' },
255             I => { isa => 'Lab::Moose::PosNum' },
256             D => { isa => 'Lab::Moose::PosNum' },
257             mout => { isa => 'Lab::Moose::PosNum', optional => 1 },
258             range => { isa => enum( [ 0 .. 5 ] ) },
259             );
260             my ( $loop, $zone, $top, $P, $I, $D, $mout, $range )
261 0           = delete @args{qw/loop zone top P I D mout range/};
262 0   0       $loop = $loop // $self->default_loop;
263 0 0         if ( defined $mout ) {
264 0           $mout = sprintf( "%.1f", $mout );
265             }
266             else {
267 0           $mout = ' ';
268             }
269              
270 0           $self->write(
271             command => sprintf(
272             "ZONE $loop, $zone, %.6G, %.1f, %.1f, %d, $mout, $range", $top,
273             $P, $I, $D
274             ),
275             %args
276             );
277             }
278              
279             sub get_zone {
280 0     0 1   my ( $self, %args ) = validated_getter(
281             \@_,
282             %loop_arg,
283             zone => { isa => enum( [ 1 .. 10 ] ) }
284             );
285 0           my ( $loop, $zone ) = delete @args{qw/loop zone/};
286 0   0       $loop = $loop // $self->default_loop;
287 0           my $result = $self->query( command => "ZONE? $loop, $zone", %args );
288 0           my %zone;
289 0           @zone{qw/top P I D mout range/} = split /,/, $result;
290 0           return %zone;
291             }
292              
293              
294             sub set_analog_out {
295 0     0 1   my ( $self, %args ) = validated_getter(
296             \@_,
297             output => { isa => enum( [ 1, 2 ] ) },
298             bipolar_enable => { isa => enum( [ 0, 1 ] ), default => 0 },
299             mode => { isa => enum( [ 0, 1, 2, 3 ] ) },
300             input => { isa => enum( [qw/A B C D/] ), default => '' },
301             source => { isa => enum( [ 1, 2, 3, 4 ] ), default => '' },
302             high_value => { isa => 'Num', default => '' },
303             low_value => { isa => 'Num', default => '' },
304             manual_value => { isa => 'Num', default => '' },
305             );
306              
307             my (
308             $output, $bipolar_enable, $mode, $input, $source, $high_value,
309             $low_value, $manual_value
310             )
311             = delete @args{
312 0           qw/output bipolar_enable mode input source high_value low_value manual_value/
313             };
314              
315 0           $self->write(
316             command =>
317             "ANALOG $output, $bipolar_enable, $mode, $input, $source, $high_value, $low_value, $manual_value",
318             %args
319             );
320              
321             }
322              
323             sub get_analog_out {
324 0     0 1   my ( $self, %args ) = validated_getter(
325             \@_,
326             output => { isa => enum( [ 1, 2 ] ) },
327             );
328              
329 0           my $output = delete $args{'output'};
330 0           my $result = $self->query( command => "ANALOG? $output", %args );
331 0           my %analog_out;
332             @analog_out{
333 0           qw/output bipolar_enable mode input source high_value low_value manual_value/
334             } = split /,/, $result;
335 0           return %analog_out;
336             }
337              
338              
339             __PACKAGE__->meta()->make_immutable();
340              
341             1;
342              
343             __END__
344              
345             =pod
346              
347             =encoding UTF-8
348              
349             =head1 NAME
350              
351             Lab::Moose::Instrument::Lakeshore340 - Lakeshore Model 340 Temperature Controller
352              
353             =head1 VERSION
354              
355             version 3.880
356              
357             =head1 SYNOPSIS
358              
359             use Lab::Moose;
360              
361             # Constructor
362             my $lakeshore = instrument(
363             type => 'Lakeshore340',
364             connection_type => 'LinuxGPIB',
365             connection_options => {pad => 22},
366            
367             input_channel => 'B', # set default input channel for all method calls
368             );
369              
370             my $temp_B = $lakeshore->get_T(); # Get temp for input 'B' set as default in constructor.
371              
372             my $temp_A = $lakeshore->get_T(channel => 'A'); # Get temp for input 'A'.
373              
374             =head1 METHODS
375              
376             =head2 get_T
377              
378             my $temp = $lakeshore->get_T(channel => $channel);
379              
380             C<$channel> can be 'A' or 'B'. The default can be set in the constructor.
381              
382             =head2 get_value
383              
384             alias for C<get_T>.
385              
386             =head2 get_sensor_units_reading
387              
388             my $reading = $lakeshore->get_sensor_units_reading(channel => $channel);
389              
390             Get sensor units reading (like resistance) of an input channel.
391              
392             =head2 set_setpoint/get_setpoint
393              
394             Set/get setpoint for loop 1 in whatever units the setpoint is using
395              
396             $lakeshore->set_setpoint(value => 10, loop => 1);
397             my $setpoint1 = $lakeshore->get_setpoint(loop => 1);
398              
399             =head2 set_T
400              
401             alias for C<set_setpoint>
402              
403             =head2 set_heater_range/get_heater_range
404              
405             $lakeshore->set_heater_range(value => 1);
406             my $range = $lakeshore->get_heater_range();
407              
408             Value is one of 0 (OFF),1,...,5 (MAX)
409              
410             =head2 set_control_mode/get_control_mode
411              
412             Specifies the control mode. Valid entries: 1 = Manual PID, 2 = Zone,
413             3 = Open Loop 4 = AutoTune PID, 5 = AutoTune PI, 6 = AutoTune P.
414              
415             # Set loop 1 to manual PID
416             $lakeshore->set_control_mode(value => 1, loop => 1);
417             my $cmode = $lakeshore->get_control_mode(loop => 1);
418              
419             =head2 set_mout/get_mout
420              
421             $lakeshore->set_mout(
422             loop => 1,
423             value => 22.45, # percent of range
424             );
425             my $mout = $lakeshore->get_mout(loop => 1);
426              
427             Set/get manual output. Only works if output is configured for open
428             loop control.
429              
430             =head2 set_control_parameters/get_control_parameters
431              
432             $lakeshore->set_control_parameters(
433             loop => 1,
434             input => 'A',
435             units => 1, # 1 = Kelvin, 2 = Celsius, 3 = sensor units
436             state => 1, # 0 = off, 1 = on
437             powerup_enable => 1, # 0 = off, 1 = on, optional with default = off
438             );
439             my %args = $lakeshore->get_control_parameters(loop => 1);
440              
441             =head2 set_input_curve/get_input_curve
442              
443             # Set channel 'B' to use curve 25
444             $lakeshore->set_input_curve(channel => 'B', value => 25);
445             my $curve = $lakeshore->get_input_curve(channel => 'B');
446              
447             =head2 set_remote_mode/get_remote_mode
448              
449             $lakeshore->set_remote_mode(value => 1);
450             my $mode = $lakeshore->get_remote_mode();
451              
452             Valid entries: 1 = local, 2 = remote, 3 = remote with local lockout.
453              
454             =head2 set_pid/get_pid
455              
456             $lakeshore->set_pid(loop => 1, P => 1, I => 50, D => 50)
457             my %PID = $lakeshore->get_pid(loop => 1);
458             # %PID = (P => $P, I => $I, D => $D);
459              
460             =head2 set_zone/get_zone
461              
462             $lakeshore->set_zone(
463             loop => 1,
464             zone => 1,
465             top => 10,
466             P => 25,
467             I => 10,
468             D => 20,
469             range => 1
470             );
471              
472             my %zone = $lakeshore->get_zone(loop => 1, zone => 1);
473              
474             =head2 set_analog_out/get_analog_out
475              
476             $lakeshore->set_analog_out
477             output => 1,
478             bipolar_enable => 1, # default: 0
479             mode => 2, # 0 = off, 1 = input, 2 = manual, 3 = loop. Loop is only valid for output 2
480             manual_value => -30, # -30 percent output (-3V)
481             );
482              
483             my %analog_out = $lakeshore->get_analog_out();
484              
485             =head2 Consumed Roles
486              
487             This driver consumes the following roles:
488              
489             =over
490              
491             =item L<Lab::Moose::Instrument::Common>
492              
493             =back
494              
495             =head1 COPYRIGHT AND LICENSE
496              
497             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
498              
499             Copyright 2018 Simon Reinhardt
500             2020 Andreas K. Huettel, Simon Reinhardt
501             2021-2022 Simon Reinhardt
502              
503              
504             This is free software; you can redistribute it and/or modify it under
505             the same terms as the Perl 5 programming language system itself.
506              
507             =cut