File Coverage

blib/lib/Lab/Instrument.pm
Criterion Covered Total %
statement 363 489 74.2
branch 128 236 54.2
condition 35 83 42.1
subroutine 51 61 83.6
pod 7 25 28.0
total 584 894 65.3


line stmt bran cond sub pod time code
1             package Lab::Instrument;
2             $Lab::Instrument::VERSION = '3.880';
3             #ABSTRACT: Instrument base class
4              
5 9     9   258568 use v5.20;
  9         38  
6              
7 9     9   53 use strict;
  9         33  
  9         179  
8 9     9   96 use warnings;
  9         21  
  9         293  
9              
10             #use POSIX; # added for int() function
11 9     9   1032 use Lab::Generic;
  9         26  
  9         288  
12 9     9   977 use Lab::Exception;
  9         22  
  9         268  
13 9     9   4093 use Lab::Connection;
  9         27  
  9         316  
14 9     9   63 use Carp qw(cluck croak);
  9         34  
  9         502  
15 9     9   69 use Data::Dumper;
  9         40  
  9         446  
16 9     9   3686 use Clone qw(clone);
  9         20044  
  9         581  
17 9     9   4315 use Class::ISA qw(self_and_super_path);
  9         16301  
  9         308  
18 9     9   4355 use Hook::LexWrap;
  9         12265  
  9         59  
19              
20 9     9   367 use Time::HiRes qw (usleep sleep);
  9         20  
  9         61  
21              
22             our @ISA = ('Lab::Generic');
23              
24             our $AUTOLOAD;
25              
26             our %fields = (
27              
28             device_name => undef,
29             device_comment => undef,
30              
31             ins_debug => 0, # do we need additional output?
32              
33             connection => undef,
34             supported_connections => ['ALL'],
35              
36             # for connection default settings/user supplied settings. see accessor method.
37             connection_settings => { timeout => 1 },
38              
39             # default device settings/user supplied settings. see accessor method.
40             device_settings => {
41             name => undef,
42             wait_status => 10e-6, # sec
43             wait_query => 10e-6, # sec
44             query_length => 300, # bytes
45             query_long_length => 10240, # bytes
46             },
47              
48             device_cache => {
49              
50             },
51              
52             device_cache_order => [],
53              
54             config => {},
55             );
56              
57             sub new {
58 10     10 1 21 my $proto = shift;
59 10   33     42 my $class = ref($proto) || $proto;
60 10         22 my $config = undef;
61 10 50       35 if ( ref $_[0] eq 'HASH' ) { $config = shift }
  10         23  
62 0         0 else { $config = {@_} }
63              
64 10         79 my $self = $class->SUPER::new(@_);
65 10         21 $self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__);
  10         51  
66              
67             # wrap additional code for automatic cache-handling aroung all paramter set- and get-functions defined in %fields->{device_cache}
68 10         45 my @isa = Class::ISA::self_and_super_path($class);
69 10         755 my $flag = 0;
70 10         38 while (@isa) {
71 38         69 my $isa = pop @isa;
72 38 100       90 if ( $flag == 1 ) {
73 18         85 $self->_init_cache_handling($isa);
74             }
75 38 100       141 if ( $isa eq 'Lab::Instrument' ) {
76 10         26 $flag = 1;
77             }
78              
79             }
80              
81 10         53 $self->config($config);
82              
83             #
84             # In most inherited classes, configure() is run through _construct()
85             #
86 10         28 $self->${ \( __PACKAGE__ . '::configure' ) }( $self->config() )
  10         48  
87             ; # use local configure, not possibly overwritten one
88              
89 10 50       32 if ( $class eq __PACKAGE__ ) {
90              
91             # _setconnection after providing $config - needed for direct instantiation of Lab::Instrument
92 0         0 $self->_setconnection();
93             }
94              
95             # digest parameters
96 10 50       35 $self->device_name( $self->config('device_name') )
97             if defined $self->config('device_name');
98 10 50       33 $self->device_comment( $self->config('device_comment') )
99             if defined $self->config('device_comment');
100              
101 10         77 $self->register_instrument();
102              
103 10         34 return $self;
104             }
105              
106             #
107             # Call this in inheriting class's constructors to conveniently initialize the %fields object data.
108             #
109             sub _construct { # _construct(__PACKAGE__);
110 28     28   67 ( my $self, my $package ) = ( shift, shift );
111              
112 28         50 my $class = ref($self);
113 28         50 my $fields = undef;
114             {
115 9     9   4258 no strict 'refs';
  9         40  
  9         3286  
  28         42  
116 28         42 $fields = *${ \( $package . '::fields' ) }{HASH};
  28         134  
117             }
118              
119 28         65 foreach my $element ( keys %{$fields} ) {
  28         122  
120              
121             # handle special subarrays
122 215 100       431 if ( $element eq 'device_settings' ) {
    100          
123              
124             # don't overwrite filled hash from ancestor
125             $self->{device_settings} = {}
126 26 100       80 if !exists( $self->{device_settings} );
127 26         38 for my $s_key ( keys %{ $fields->{'device_settings'} } ) {
  26         98  
128             $self->{device_settings}->{$s_key}
129 162         561 = clone( $fields->{device_settings}->{$s_key} );
130             }
131             }
132             elsif ( $element eq 'connection_settings' ) {
133              
134             # don't overwrite filled hash from ancestor
135             $self->{connection_settings} = {}
136 18 100       61 if !exists( $self->{connection_settings} );
137 18         29 for my $s_key ( keys %{ $fields->{connection_settings} } ) {
  18         86  
138             $self->{connection_settings}->{$s_key}
139 28         104 = clone( $fields->{connection_settings}->{$s_key} );
140             }
141             }
142             else {
143             # handle the normal fields - can also be hash refs etc, so use clone to get a deep copy
144 171         890 $self->{$element} = clone( $fields->{$element} );
145              
146             #warn "here comes\n" if($element eq 'device_cache');
147             #warn Dumper($Lab::Instrument::DummySource::fields) if($element eq 'device_cache');
148             }
149 215         439 $self->{_permitted}->{$element} = 1;
150              
151             }
152              
153             # @{$self}{keys %{$fields}} = values %{$fields};
154              
155             #
156             # run configure() of the calling package on the supplied config hash.
157             # this parses the whole config hash on every heritance level (and with every version of configure())
158             # For Lab::Instrument itself it does not make sense, as $self->config() is not set yet. Instead it's run from the new() method, see there.
159             #
160 28 50       137 $self->${ \( $package . '::configure' ) }( $self->config() )
  28         172  
161             if $class ne 'Lab::Instrument'
162             ; # use configure() of calling package, not possibly overwritten one
163              
164             #
165             # Check and parse the connection data OR the connection object in $self->config(), but only if
166             # _construct() has been called from the instantiated class (and not from somewhere up the heritance hierarchy)
167             # That's because child classes can add new entrys to $self->supported_connections(), so delay checking to the top class.
168             # Also, don't run _setconnection() for Lab::Instrument, as in this case the needed fields in $self->config() are not set yet.
169             # It's run in Lab::Instrument::new() instead if needed.
170             #
171             # Also, other stuff that should only happen in the top level class instantiation can go here.
172             #
173              
174 28 100 66     146 if ( $class eq $package && $class ne 'Lab::Instrument' ) {
175              
176 10         62 $self->_setconnection();
177              
178             # Match the device hash with the device
179             # The cache carries the default values set above and was possibly modified with user
180             # defined values through configure() before the connection was set. These settings are now transferred
181             # to the device.
182 10         50 $self->_device_init(); # enable device communication if necessary
183 10         49 $self->_set_config_parameters(); # transfer configuration to device
184              
185             }
186              
187             }
188              
189             # this methode implements the cache-handling:
190             #
191             # It will wrap all get- and set-functions for parameters initialized in $fields->{device_cache} with additional pre- and post-processing code.
192             # If a get-function is called and read_mode == cache, the $self->{device_cache}->{parameter} will be returned immediately. The original get-function won't be executed in this case.
193             # This behaviour can be disabled by setting the parmeter $self->{config}->{no_cache} = 1.
194             # The return-value of the get-function will be cached in $self->{device_cache}in any case.
195             #
196             # Set-functions will automatically call the corresponding get-function in the post-processing section, in order to keep the cache up to date.
197             #
198             # If a requestID has been set, only the get-function, which placed the request will be executed, while all others return the cache-value. Set-functions won't be executed at all.
199             #
200              
201 0         0 sub _init_cache_handling {
202 18     18   43 my $self = shift;
203 18         29 my $class = shift;
204              
205 9     9   85 no strict 'refs';
  9         56  
  9         7694  
206              
207             # avoid to redefine the subs twice
208 18 100       32 if ( defined ${ $class . '::MODIFIED' } ) {
  18         135  
209 3         5 return;
210             }
211              
212 15         32 my $fields = *${ \( $class . '::fields' ) }{HASH};
  15         64  
213 15         33 my @cache_params = keys %{ $fields->{device_cache} };
  15         84  
214              
215             # wrap parameter function defined in %fields->{device_cache}:
216 15         37 foreach my $cache_param (@cache_params) {
217 38         864 my $set_sub = "set_" . $cache_param;
218 38         89 my $get_sub = "get_" . $cache_param;
219              
220 38         51 my $get_methode = *{ $class . "::" . $get_sub };
  38         185  
221 38         65 my $set_methode = *{ $class . "::" . $set_sub };
  38         157  
222              
223 38 100 100     348 if ( $class->can( "set_" . $cache_param ) and exists &$set_methode ) {
224              
225             # Change STDERR to undef, in order to avoid warnings from Hook::LexWrap and
226             # and save original STDERR stream in SAVEERR to be able to restore original
227             # behavior
228 29         65 local (*SAVEERR);
229              
230             #open SAVEERR, ">&STDERR";
231             #open(STDERR, '>', undef);
232              
233             # wrap set-function:
234             wrap(
235             $class . "::" . $set_sub,
236              
237             # before set-functions is executed:
238             pre => sub {
239 75     75   21405 my $self = shift;
240              
241 75         176 ${__PACKAGE__::SELF} = $self;
242 75         145 ${__PACKAGE__::SELF}->{fast_cache_value} = $_[0];
243              
244             # read_mode handling: do not execute if request is set:
245 75 50 33     517 if ( defined $self->{requestID}
246             or $self->connection()->is_blocked() ) {
247 0         0 $_[-1] = 'connection blocked';
248             }
249             },
250              
251             # after set-functions is executed:
252             post => sub {
253              
254 75 50   75   448 if ( not defined ${__PACKAGE__::SELF} ) {
255 0         0 return;
256             }
257              
258             # skip get_sub if $self->{config}->{fast_cache} is set.
259 75 50 33     210 if ( defined ${__PACKAGE__::SELF}->{config}->{fast_cache}
260             and ${__PACKAGE__::SELF}->{config}->{fast_cache} > 0 )
261             {
262             ${__PACKAGE__::SELF}->device_cache(
263             {
264             $cache_param =>
265             ${__PACKAGE__::SELF}->{fast_cache_value}
266             }
267 0         0 );
268 0         0 return;
269             }
270              
271             # call coresponding get-function in order to keep the cache up to date, if available
272              
273 75 50 33     506 if ( ${__PACKAGE__::SELF}->can($get_sub)
274             and not ${__PACKAGE__::SELF}->{config}->{no_cache} ) {
275 75         210 my $var = ${__PACKAGE__::SELF}->$get_sub();
276             }
277              
278             }
279 29         285 );
280              
281             # Restore Warnings:
282             #open STDERR, ">&SAVEERR";
283              
284             }
285              
286 38 100 66     1428 if ( $class->can( "get_" . $cache_param ) and exists &$get_methode ) {
287              
288             # Change STDERR to undef, in order to avoid warnings from Hook::LexWrap and
289             # and save original STDERR stream in SAVEERR to be able to restore original
290             # behavior
291 34         77 local (*SAVEERR);
292              
293             #open SAVEERR, ">&STDERR";
294             #open(STDERR, '>', undef);
295              
296 34         74 my $parameter = $cache_param;
297              
298             # wrap get-function:
299             wrap(
300             $class . "::" . $get_sub,
301              
302             # before get-functions is executed:
303             pre => sub {
304 294     294   6428 my $self = shift;
305              
306 294         487 ${__PACKAGE__::SELF} = $self;
307              
308             # read_mode handling:
309 294         616 my @args = @_;
310 294         440 pop @args;
311 294         872 my ( $read_mode, $tail )
312             = $self->_check_args( \@args, ['read_mode'] );
313              
314             # do not read if request has been set. set read_mode to cache if cache is available
315             $read_mode = $self->{config}->{default_read_mode}
316             if !defined($read_mode)
317 294 50 66     1108 and exists( $self->{config}->{default_read_mode} );
318              
319 294 50       1311 if ( $self->connection()->is_blocked() == 1 ) {
320 0 0       0 if ( defined $self->device_cache($parameter) ) {
321 0         0 $read_mode = 'cache';
322             }
323             else {
324 0         0 $_[-1] = 'connection_blocked';
325             }
326             }
327              
328 294 50       753 if ( defined $self->{requestID} ) {
329             my ( $package, $filename, $subroutine, $line )
330 0         0 = split( / /, $self->{requestID} );
331              
332 0 0       0 if ( $subroutine ne $class . "::" . $get_sub ) {
333 0 0       0 if ( defined $self->device_cache($parameter) ) {
334              
335 0         0 $read_mode = 'cache';
336             }
337             else {
338 0         0 $_[-1] = 'connection_blocked';
339             }
340             }
341             else {
342 0         0 $read_mode = undef;
343 0         0 pop @_;
344             }
345              
346             }
347              
348             # return cache value if read_mode is set to cache
349 294 100 100     1254 if ( defined $read_mode
      100        
      66        
350             and $read_mode eq 'cache'
351             and defined $self->device_cache($parameter)
352             and not $self->{config}->{no_cache} ) {
353 98         200 $_[-1] = $self->device_cache($parameter);
354             }
355              
356             },
357              
358             # after get-functions is executed:
359             post => sub {
360              
361 196 50   196   2279 if ( not defined ${__PACKAGE__::SELF} ) {
362 0         0 return;
363             }
364 196         302 my $retval = $_[-1];
365              
366             # refresh cache value
367 196 50 33     756 if ( not defined $retval
368             or ref($retval) eq 'Hook::LexWrap::Cleanup' ) {
369 0         0 return;
370             }
371             else {
372 196 100       430 my $cache_value = wantarray ? $retval->[0] : $retval;
373 196         664 ${__PACKAGE__::SELF}
374             ->device_cache( { $parameter => $cache_value } );
375             }
376             }
377 34         424 );
378              
379             # Restore Warnings:
380             #open STDERR, ">&SAVEERR";
381             }
382              
383             }
384              
385             # remeber that we have allready redefined the functions
386 15         514 ${ $class . '::MODIFIED' } = 1;
  15         79  
387              
388 9     9   83 use strict 'refs';
  9         17  
  9         8329  
389              
390             }
391              
392             sub register_instrument {
393 10     10 0 18 my $self = shift;
394              
395 10         27 push( @{Lab::Instrument::REGISTERED_INSTRUMENTS}, $self );
396              
397             }
398              
399             sub unregister_instrument {
400 0     0 0 0 my $self = shift;
401              
402             @{Lab::Instrument::REGISTERED_INSTRUMENTS}
403 0         0 = grep { $_ ne $self } @{Lab::Instrument::REGISTERED_INSTRUMENTS};
  0         0  
404              
405             }
406              
407             sub sprint_config {
408 2     2 0 6 my $self = shift;
409              
410 2         5 $Data::Dumper::Varname = "device_cache_";
411 2         7 my $config = Dumper $self->device_cache();
412              
413 2         275 $config .= "\n";
414              
415 2         4 $Data::Dumper::Maxdepth = 1;
416 2         4 $Data::Dumper::Varname = "connection_settings_";
417 2 50       13 if ( defined $self->connection() ) {
418 2         20 $config .= Dumper $self->connection()->config();
419             }
420 2         129 return $config;
421              
422             }
423              
424             sub _set_config_parameters {
425 10     10   21 my $self = shift;
426              
427 10         15 my @order = @{ $self->device_cache_order() };
  10         58  
428 10         25 my @keys = keys %{ $self->config() };
  10         37  
429              
430 10         28 foreach my $ckey (@order) {
431 16         37 my $subname = 'set_' . $ckey;
432 16 50 33     38 if ( defined $self->config($ckey) and $self->can($subname) ) {
433 0         0 my $result = $self->$subname( $self->config($ckey) );
434 0         0 @keys = grep { $_ ne $ckey } @keys;
  0         0  
435             }
436             }
437              
438 10         29 foreach my $ckey (@keys) {
439 49         98 my $subname = 'set_' . $ckey;
440 49 50       322 if ( $self->can($subname) ) {
441 0         0 my $result = $self->$subname( $self->config($ckey) );
442             }
443             }
444              
445             }
446              
447             # old; replaced by _refresh_cache and _set_config_parameters
448             sub _getset_key {
449 0     0   0 my $self = shift;
450 0         0 my $ckey = shift;
451              
452             #print Dumper $self->device_cache();
453              
454             Lab::Exception::CorruptParameter->throw(
455             "No field with name $ckey in device_cache!\n")
456 0 0       0 if !exists $self->device_cache()->{$ckey};
457 0 0 0     0 if ( !defined $self->device_cache()->{$ckey}
458             and !defined $self->config()->{$ckey} ) {
459 0         0 my $subname = 'get_' . $ckey;
460 0 0       0 Lab::Exception::CorruptParameter->throw(
461             "No get method defined for device_cache field $ckey! \n")
462             if !$self->can($subname);
463 0         0 my $result = $self->$subname();
464             }
465             else {
466 0         0 my $subname = 'set_' . $ckey;
467 0 0       0 print Dumper $self->device_cache() if !$self->can($subname);
468 0 0       0 Lab::Exception::CorruptParameter->throw(
469             "No set method defined for device_cache field $ckey!\n")
470             if !$self->can($subname);
471 0         0 my $result = $self->$subname( $self->device_cache()->{$ckey} );
472             }
473              
474             }
475              
476             #
477             # Sync the field set in $self->device_cache with the device.
478             # Undefined fields are filled in from the device, existing values in device_cache are written to the device.
479             # Without parameter, parses the whole $self->device_cache. Else, the parameter list is parsed as a list of
480             # field names. Contained fields for which have no corresponding getter/setter/device_cache entry exists will result in an exception thrown.
481             #
482             # old; replaced by _refresh_cache and _set_config_parameters
483             # still used in Yokogawa7651 and SignalRecovery726x
484             sub _cache_init {
485 0     0   0 my $self = shift;
486 0         0 my $subname = shift;
487 0 0       0 my @ckeys = scalar(@_) > 0 ? @_ : keys %{ $self->device_cache() };
  0         0  
488              
489             #print Dumper $self->config();
490              
491 0         0 print "ckeys: @ckeys\n";
492              
493             # a key hash, to search for given keys quickly
494 0         0 my %ckeyhash;
495             my %orderhash;
496 0         0 @ckeyhash{@ckeys} = ();
497              
498 0         0 my @order = @{ $self->device_cache_order() };
  0         0  
499              
500 0 0 0     0 if ( $self->device_cache() && $self->connection() ) {
501              
502             # do we have a preferred order for device cache settings?
503 0 0       0 if (@order) {
504 0         0 @orderhash{@order} = ();
505 0         0 foreach my $ckey (@order) {
506 0 0       0 $self->_getset_key($ckey) if exists $ckeyhash{$ckey};
507             }
508              
509             # initialize all values not in device_cache_order
510             #for my $ckey (@ckeys){
511             # $self->_getset_key($ckey) if not exists $orderhash{$ckey};
512             #}
513             }
514              
515             # no ordering requestd
516             else {
517 0         0 foreach my $ckey (@ckeys) {
518 0         0 $self->_getset_key($ckey);
519             }
520             }
521             }
522             }
523              
524             #
525             # Fill $self->device_settings() from config parameters
526             #
527             sub configure {
528 40     40 0 71 my $self = shift;
529 40         56 my $config = shift;
530              
531 40 50       89 if ( ref($config) ne 'HASH' ) {
532 0         0 Lab::Exception::CorruptParameter->throw(
533             error => 'Given Configuration is not a hash.' );
534             }
535             else {
536             #
537             # fill matching fields defined in %fields from the configuration hash ($self->config )
538             # this will also catch an explicitly given device_settings, default_device_settings (see Source.pm) or connection_settings hash ( overwritten default config )
539             #
540 40         58 for my $fields_key ( keys %{ $self->{_permitted} } ) {
  40         199  
541             { # restrict scope of "no strict"
542 9     9   89 no strict 'refs';
  9         48  
  9         1332  
  505         616  
543             $self->$fields_key( $config->{$fields_key} )
544 505 100       944 if exists $config->{$fields_key};
545             }
546             }
547              
548             #
549             # fill fields $self->device_settings and $self->device_cache from entries given in configuration hash (this is usually the same as $self->config )
550             #
551 40         180 $self->device_settings($config);
552              
553             #$self->device_cache($config);
554             }
555             }
556              
557             sub _checkconnection
558             { # Connection object or connection_type string (as in Lab::Connections::<connection_type>)
559 10     10   21 my $self = shift;
560 10   50     35 my $connection = shift || undef;
561 10         18 my $found = 0;
562              
563 10   66     50 $connection = ref($connection) || $connection;
564              
565 10 50       35 return 0 if !defined $connection;
566              
567 9     9   72 no strict 'refs';
  9         42  
  9         4438  
568 10 50 66     19 if ( grep( /^ALL$/, @{ $self->supported_connections() } ) == 1 ) {
  10 50       103  
569 0         0 return $connection;
570             }
571             elsif ($connection->isa('Lab::Connection::DEBUG')
572             or $connection->isa('Lab::Connection::Mock') ) {
573 10         50 return $connection;
574             }
575             else {
576 0         0 for my $conn_supp ( @{ $self->supported_connections() } ) {
  0         0  
577 0 0       0 return $conn_supp
578             if ( $connection->isa( 'Lab::Connection::' . $conn_supp ) );
579             }
580             }
581              
582 0         0 return undef;
583             }
584              
585             sub _setconnection
586             { # $self->setconnection() create new or use existing connection
587 10     10   17 my $self = shift;
588              
589             #
590             # fill in unset connection parameters with the defaults from $self->connections_settings to $self->config
591             #
592 10         30 my $config = $self->config();
593 10         25 my $connection_type = undef;
594 10         16 my $full_connection = undef;
595              
596 10         20 for my $setting_key ( keys %{ $self->connection_settings() } ) {
  10         90  
597             $config->{$setting_key} = $self->connection_settings($setting_key)
598 24 100       99 if !defined $config->{$setting_key};
599             }
600              
601             # check the configuration hash for a valid connection object or connection type, and set the connection
602 10 100       29 if ( defined( $self->config('connection') ) ) {
    50          
603              
604 4 50       8 if ( $self->_checkconnection( $self->config('connection') ) ) {
605 4         8 $self->connection( $self->config('connection') );
606              
607             }
608             else {
609 0         0 Lab::Exception::CorruptParameter->throw(
610             error => "Received invalid connection object!\n" );
611             }
612             }
613              
614             # else {
615             # Lab::Exception::CorruptParameter->throw( error => 'Received no connection object!\n' );
616             # }
617             elsif ( defined $self->config('connection_type') ) {
618              
619 6         34 $connection_type = $self->config('connection_type');
620              
621 6 50       61 if ( $connection_type !~ /^[A-Za-z0-9_\-\:]*$/ ) {
622 0         0 Lab::Exception::CorruptParameter->throw( error =>
623             "Given connection type is does not look like a valid module name.\n"
624             );
625             }
626              
627 6 50       23 if ( $connection_type eq 'none' ) {
628 0 0       0 if ( grep( /^none$/, @{ $self->supported_connections() } ) == 1 )
  0         0  
629             {
630 0         0 return;
631             }
632             else {
633 0         0 Lab::Exception::Error->throw( error =>
634             "Sorry, this instrument cannot work without a connection.\n"
635             );
636             }
637             }
638              
639 6         21 $full_connection = "Lab::Connection::" . $connection_type;
640 6         506 eval("require ${full_connection};");
641 6 50       38 if ($@) {
642 0         0 Lab::Exception::Error->throw( error =>
643             "Sorry, I was not able to load the connection ${full_connection}.\n"
644             . "The error received from the connections was\n===\n$@\n===\n"
645             );
646             }
647              
648 6 50       91 if ( $self->_checkconnection( "Lab::Connection::" . $connection_type )
649 0         0 ) {
650              
651             # let's get creative
652 9     9   84 no strict 'refs';
  9         23  
  9         812  
653              
654             # yep - pass all the parameters on to the connection, it will take the ones it needs.
655             # This way connection setup can be handled generically. Conflicting parameter names? Let's try it.
656 6 50       125 $self->connection( $full_connection->new($config) )
657             || Lab::Exception::Error->throw(
658             error => "Failed to create connection $full_connection!\n" );
659              
660 9     9   64 use strict;
  9         25  
  9         29611  
661             }
662             else {
663 0         0 Lab::Exception::CorruptParameter->throw(
664             error => "Given Connection not supported!\n" );
665             }
666             }
667             else {
668 0         0 Lab::Exception::CorruptParameter->throw( error =>
669             "Neither a connection nor a connection type was supplied.\n"
670             );
671             }
672              
673             # add predefined connection settings to connection config:
674             # no overwriting of user defined connection settings
675 10         71 my $new_config = $self->connection()->config();
676 10         26 for my $key ( keys %{ $self->connection_settings() } ) {
  10         41  
677 24 100       83 if ( not defined $self->connection()->config($key) ) {
678 2         5 $new_config->{$key} = $self->connection_settings($key);
679             }
680             }
681 10         67 $self->connection()->config($new_config);
682 10         44 $self->connection()->_configurebus();
683             }
684              
685             sub _checkconfig {
686 0     0   0 my $self = shift;
687 0         0 my $config = $self->config();
688              
689 0         0 return 1;
690             }
691              
692             #
693             # To be overwritten...
694             # Returned $errcode has to be 0 for "no error"
695             #
696             sub get_error {
697 0     0 1 0 my $self = shift;
698              
699             # overwrite with device specific error retrieval...
700 0         0 warn( "There was an error on the device "
701             . ref($self)
702             . ", but the driver is not able to supply more details.\n" );
703              
704 0         0 return ( -1, undef ); # ( $errcode, $message )
705             }
706              
707             #
708             # Optionally implement this to return a hash with device specific named status bits for this device, e.g. from the status byte/serial poll for GPIB
709             # return { ERROR => 1, READY => 1, DATA => 0, ... }
710             #
711             sub get_status {
712 0     0 1 0 my $self = shift;
713 0         0 Lab::Exception::Unimplemented->throw(
714             "get_status() not implemented for " . ref($self) . ".\n" );
715 0         0 return undef;
716             }
717              
718             sub check_errors {
719 6     6 1 8 my $self = shift;
720 6         9 my $command = shift;
721 6         9 my @errors = ();
722              
723 6 50       23 if ( $self->get_status()->{'ERROR'} ) {
724 0         0 my ( $code, $message ) = $self->get_error();
725 0   0     0 while ( $code != 0 && $code != -1 ) {
726 0         0 push @errors, [ $code, $message ];
727 0         0 warn
728             "\nReceived device error with code $code\nMessage: $message\n";
729 0         0 ( $code, $message ) = $self->get_error();
730             }
731              
732 0 0 0     0 if ( @errors || $code == -1 ) {
733 0         0 Lab::Exception::DeviceError->throw(
734             error =>
735             "An Error occured in the device while executing the command: $command \n",
736             device_class => ref $self,
737             command => $command,
738             error_list => \@errors,
739             );
740             }
741             }
742 6         17 return 0;
743             }
744              
745             #
746             # Generic utility methods for string based connections (most common, SCPI etc.).
747             # For connections not based on command strings these should probably be overwritten/disabled!
748             #
749              
750             #
751             # passing through generic write, read and query from the connection.
752             #
753              
754             sub set_name {
755 0     0 0 0 my $self = shift;
756 0         0 my ($name) = $self->_check_args( \@_, ['name'] );
757 0         0 $self->device_settings( { 'name' => $name } );
758              
759             }
760              
761             sub get_name {
762 2     2 0 5 my $self = shift;
763 2         7 return $self->device_settings('name');
764             }
765              
766             sub get_id {
767 2     2 0 8 my $self = shift;
768 2         9 my @name = split( /::/, ref($self) );
769 2         30 return pop(@name);
770             }
771              
772       0 0   sub set_id {
773              
774             }
775              
776             sub write {
777 83     83 1 143 my $self = shift;
778 83 50 66     302 my $command
779             = scalar(@_) % 2 == 0 && ref $_[1] ne 'HASH'
780             ? undef
781             : shift
782             ; # even sized parameter list and second parm no hashref? => Assume parameter hash
783 83 50       229 my $args
    100          
784             = scalar(@_) % 2 == 0
785             ? {@_}
786             : ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef );
787 83 50       179 Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n")
788             if !defined($args);
789              
790 83 50       224 $args->{'command'} = $command if defined $command;
791              
792 83         377 my $result = $self->connection()->Write($args);
793              
794 83 100       244 $self->check_errors( $args->{'command'} ) if $args->{error_check};
795              
796 83         231 return $result;
797             }
798              
799             sub read {
800 4     4 1 9 my $self = shift;
801 4 0       14 my $args
    50          
802             = scalar(@_) % 2 == 0
803             ? {@_}
804             : ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef );
805 4 50       9 Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n")
806             if !defined($args);
807              
808 4         15 my $result = $self->connection()->Read($args);
809             $self->check_errors('Just a plain and simple read.')
810 4 50       11 if $args->{error_check};
811              
812 4         5 $result =~ s/^[\r\t\n]+|[\r\t\n]+$//g;
813 4         18 return $result;
814             }
815              
816             sub clear {
817 1     1 0 4 my $self = shift;
818 1         5 $self->connection()->Clear();
819             }
820              
821             sub request {
822 18     18 0 30 my $self = shift;
823 18         44 my ( $command, $args ) = $self->parse_optional(@_);
824             my $read_mode
825 18 100       47 = ( defined $args->{'read_mode'} ) ? $args->{'read_mode'} : 'device';
826              
827             # generate requestID from caller:
828 18         34 my ( $package, $filename, $line, $subroutine );
829 18         52 ( $package, $filename, $line, $subroutine ) = caller(1);
830 18         939 ( $package, $filename, $line ) = caller(0);
831 18         494 my $requestID
832             = $package . " " . $filename . " " . $subroutine . " " . $line;
833              
834             # # avoid to return an undef value:
835 18 50 33     94 if ( $read_mode eq 'request' and not defined $self->{requestID} ) {
    50 33        
836 0         0 $self->write(@_);
837 0         0 $self->connection()->block_connection();
838 0         0 $self->{requestID} = $requestID;
839 0         0 return undef;
840             }
841             elsif ( defined $self->{requestID} and $self->{requestID} eq $requestID )
842             {
843 0         0 $self->connection()->unblock_connection();
844 0         0 $self->{requestID} = undef;
845 0         0 return $self->read(@_);
846             }
847             else {
848 18         48 return $self->query(@_);
849             }
850              
851             }
852              
853             sub query {
854 166     166 1 353 my $self = shift;
855 166         373 my ( $command, $args ) = $self->parse_optional(@_);
856             my $read_mode
857 166 100       421 = ( defined $args->{'read_mode'} ) ? $args->{'read_mode'} : 'device';
858 166 50       449 $args->{'command'} = $command if defined $command;
859              
860 166 50       346 if ( not defined $args->{'command'} ) {
861 0         0 Lab::Exception::CorruptParameter->throw("No 'command' given!\n");
862             }
863              
864 166         713 my $result = $self->connection()->Query($args);
865 166 50       522 $self->check_errors( $args->{'command'} ) if $args->{error_check};
866              
867 166         676 $result =~ s/^[\r\t\n]+|[\r\t\n]+$//g;
868 166         546 return $result;
869              
870             }
871              
872             #
873             # infrastructure stuff below
874             #
875              
876             #
877             # tool function to safely handle an optional scalar parameter in presence with a parameter hash/list
878             # only one optional scalar parameter can be handled, and its value must not be a hashref!
879             #
880             sub parse_optional {
881 184     184 0 258 my $self = shift;
882              
883 184 50 66     759 my $optional
884             = scalar(@_) % 2 == 0 && ref $_[1] ne 'HASH'
885             ? undef
886             : shift
887             ; # even sized parameter list and second parm no hashref? => Assume parameter hash
888 184 50       501 my $args
    100          
889             = scalar(@_) % 2 == 0
890             ? {@_}
891             : ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef );
892 184 50       372 Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n")
893             if !defined($args);
894              
895 184         411 return $optional, $args;
896             }
897              
898             #
899             # accessor for device_settings
900             #
901             sub device_settings {
902 479     479 0 700 my $self = shift;
903 479         627 my $value = undef;
904              
905             #warn "device_settings got this:\n" . Dumper(@_) . "\n";
906              
907 479 100 0     941 if ( scalar(@_) == 0 )
    50          
    0          
908             { # empty parameters - return whole device_settings hash
909 302         1105 return $self->{'device_settings'};
910             }
911             elsif ( scalar(@_) == 1 )
912             { # one parm - either a scalar (key) or a hashref (try to merge)
913 177         259 $value = shift;
914             }
915             elsif ( scalar(@_) > 1 && scalar(@_) % 2 == 0 )
916             { # even sized list - assume it's keys and values and try to merge it
917 0         0 $value = {@_};
918             }
919             else { # uneven sized list - don't know what to do with that one
920 0         0 Lab::Exception::CorruptParameter->throw(
921             error => "Corrupt parameters given to "
922             . __PACKAGE__
923             . "::device_settings().\n" );
924             }
925              
926             #warn "Keys present: \n" . Dumper($self->{device_settings}) . "\n";
927              
928 177 100       369 if ( ref($value) =~ /HASH/ ) { # it's a hash - merge into current settings
929 40         62 for my $ext_key ( keys %{$value} ) {
  40         112  
930             $self->{'device_settings'}->{$ext_key} = $value->{$ext_key}
931 95 100       235 if ( exists( $self->device_settings()->{$ext_key} ) );
932             }
933 40         97 return $self->{'device_settings'};
934             }
935             else { # it's a key - return the corresponding value
936 137         622 return $self->{'device_settings'}->{$value};
937             }
938             }
939              
940             #
941             # Accessor for device_cache settings
942             #
943              
944             sub device_cache {
945 604     604 0 873 my $self = shift;
946 604         854 my $value = undef;
947              
948             #warn "device_cache got this:\n" . Dumper(@_) . "\n";
949              
950 604 100 33     1253 if ( scalar(@_) == 0 )
    100          
    50          
951             { # empty parameters - return whole device_settings hash
952 204         776 return $self->{'device_cache'};
953             }
954             elsif ( scalar(@_) == 1 )
955             { # one parm - either a scalar (key) or a hashref (try to merge)
956 394         588 $value = shift;
957             }
958             elsif ( scalar(@_) > 1 && scalar(@_) % 2 == 0 )
959             { # even sized list - assume it's keys and values and try to merge it
960 6         15 $value = {@_};
961             }
962             else { # uneven sized list - don't know what to do with that one
963 0         0 Lab::Exception::CorruptParameter->throw(
964             error => "Corrupt parameters given to "
965             . __PACKAGE__
966             . "::device_cache().\n" );
967             }
968              
969             #warn "Keys present: \n" . Dumper($self->{device_settings}) . "\n";
970              
971 400 100       961 if ( ref($value) =~ /HASH/ ) { # it's a hash - merge into current settings
972 202         421 for my $ext_key ( keys %{$value} ) {
  202         617  
973             $self->{'device_cache'}->{$ext_key} = $value->{$ext_key}
974 202 50       454 if ( exists( $self->device_cache()->{$ext_key} ) );
975             }
976 202         725 return $self->{'device_cache'};
977             }
978             else { # it's a key - return the corresponding value
979 198         1016 return $self->{'device_cache'}->{$value};
980             }
981             }
982              
983             sub reset_device_cache {
984 1     1 0 3 my $self = shift;
985 1         75 my @cache_params = keys %{ $self->{'device_cache'} };
  1         11  
986 1         4 for my $param (@cache_params) {
987 6         14 $self->device_cache( $param => undef );
988             }
989             }
990              
991             #
992             # accessor for connection_settings
993             #
994             sub connection_settings {
995 42     42 0 69 my $self = shift;
996 42         56 my $value = undef;
997              
998 42 100 0     119 if ( scalar(@_) == 0 )
    50          
    0          
999             { # empty parameters - return whole device_settings hash
1000 20         103 return $self->{'connection_settings'};
1001             }
1002             elsif ( scalar(@_) == 1 )
1003             { # one parm - either a scalar (key) or a hashref (try to merge)
1004 22         46 $value = shift;
1005             }
1006             elsif ( scalar(@_) > 1 && scalar(@_) % 2 == 0 )
1007             { # even sized list - assume it's keys and values and try to merge it
1008 0         0 $value = {@_};
1009             }
1010             else { # uneven sized list - don't know what to do with that one
1011 0         0 Lab::Exception::CorruptParameter->throw(
1012             error => "Corrupt parameters given to "
1013             . __PACKAGE__
1014             . "::connection_settings().\n" );
1015             }
1016              
1017 22 50       58 if ( ref($value) =~ /HASH/ ) { # it's a hash - merge into current settings
1018 0         0 for my $ext_key ( keys %{$value} ) {
  0         0  
1019             $self->{'connection_settings'}->{$ext_key} = $value->{$ext_key}
1020 0 0       0 if ( exists( $self->{'connection_settings'}->{$ext_key} ) );
1021              
1022             # warn "merge: set $ext_key to " . $value->{$ext_key} . "\n";
1023             }
1024 0         0 return $self->{'connection_settings'};
1025             }
1026             else { # it's a key - return the corresponding value
1027 22         79 return $self->{'connection_settings'}->{$value};
1028             }
1029             }
1030              
1031             sub _check_args {
1032 609     609   903 my $self = shift;
1033 609         759 my $args = shift;
1034 609         796 my $params = shift;
1035              
1036 609         900 my $arguments = {};
1037              
1038 609         837 my $i = 0;
1039 609         842 foreach my $arg ( @{$args} ) {
  609         1222  
1040 284 100       584 if ( ref($arg) ne "HASH" ) {
1041 131 100       212 if ( defined @{$params}[$i] ) {
  131         303  
1042 113         174 $arguments->{ @{$params}[$i] } = $arg;
  113         326  
1043             }
1044 131         272 $i++;
1045             }
1046             else {
1047 153         226 %{$arguments} = ( %{$arguments}, %{$arg} );
  153         322  
  153         348  
  153         303  
1048 153         308 $i++;
1049             }
1050             }
1051              
1052 609         973 my @return_args = ();
1053              
1054 609         786 foreach my $param ( @{$params} ) {
  609         917  
1055 476 100       874 if ( exists $arguments->{$param} ) {
1056 214         388 push( @return_args, $arguments->{$param} );
1057 214         446 delete $arguments->{$param};
1058             }
1059             else {
1060 262         486 push( @return_args, undef );
1061             }
1062             }
1063              
1064 609         959 foreach my $param ( 'from_device', 'from_cache'
1065             ) # Delete Standard option parameters from $arguments hash if not defined in device driver function
1066             {
1067 1218 50       2372 if ( exists $arguments->{$param} ) {
1068 0         0 delete $arguments->{$param};
1069             }
1070             }
1071              
1072 609         865 push( @return_args, $arguments );
1073              
1074 609 50       1023 if (wantarray) {
1075 609         1674 return @return_args;
1076             }
1077             else {
1078 0         0 return $return_args[0];
1079             }
1080              
1081             }
1082              
1083             sub _check_args_strict {
1084 19     19   29 my $self = shift;
1085 19         27 my $args = shift;
1086 19         26 my $params = shift;
1087              
1088 19         48 my @result = $self->_check_args( $args, $params );
1089              
1090 19         34 my $num_params = @result - 1;
1091              
1092 19         48 for ( my $i = 0; $i < $num_params; ++$i ) {
1093 19 50       55 if ( not defined $result[$i] ) {
1094 0         0 croak("missing mandatory argument '$params->[$i]'");
1095             }
1096             }
1097              
1098 19 50       38 if (wantarray) {
1099 19         68 return @result;
1100             }
1101             else {
1102 0           return $result[0];
1103             }
1104             }
1105              
1106             #
1107             # config gets it's own accessor - convenient access like $self->config('GPIB_Paddress') instead of $self->config()->{'GPIB_Paddress'}
1108             # with a hashref as argument, set $self->{'config'} to the given hashref.
1109             # without an argument it returns a reference to $self->config (just like AUTOLOAD would)
1110             #
1111             sub config { # $value = self->config($key);
1112 143     143 0 284 ( my $self, my $key ) = ( shift, shift );
1113              
1114 143 100       326 if ( !defined $key ) {
    100          
1115 60         156 return $self->{'config'};
1116             }
1117             elsif ( ref($key) =~ /HASH/ ) {
1118 10         64 return $self->{'config'} = $key;
1119             }
1120             else {
1121 73         281 return $self->{'config'}->{$key};
1122             }
1123             }
1124              
1125             # sub device_cache { # $value = $self->{'device_cache'}($key);
1126             # (my $self, my $key) = (shift, shift);
1127              
1128             # if(!defined $key) {
1129             # return $self->{'device_cache'};
1130             # }
1131             # elsif(ref($key) =~ /HASH/) {
1132             # return $self->{'device_cache'} = ($self->{'device_cache'}, $key);
1133             # }
1134             # else {
1135             # return $self->{'device_cache'}->{$key};
1136             # }
1137             # }
1138              
1139             #
1140             # provides generic accessor methods to the fields defined in %fields and to the elements of $self->device_settings
1141             #
1142             sub AUTOLOAD {
1143              
1144 1232     1232   2066 my $self = shift;
1145 1232 50       2469 my $type = ref($self) or croak "\$self is not an object";
1146 1232         1685 my $value = undef;
1147              
1148 1232         1741 my $name = $AUTOLOAD;
1149 1232         4635 $name =~ s/.*://; # strip fully qualified portion
1150              
1151 1232 100       2943 if ( exists $self->{_permitted}->{$name} ) {
    50          
    0          
1152 1226 100       2062 if (@_) {
1153 31         106 return $self->{$name} = shift;
1154             }
1155             else {
1156 1195         17592 return $self->{$name};
1157             }
1158             }
1159             elsif ( $name =~ qr/^(get_|set_)(.*)$/ ) {
1160 6 50       20 if ( exists $self->device_settings()->{$2} ) {
    0          
1161 6         25 return $self->getset( $1, $2, "device_settings", @_ );
1162             }
1163             elsif ( exists $self->device_cache()->{$2} ) {
1164 0         0 return $self->getset( $1, $2, "device_cache", @_ );
1165             }
1166             else {
1167 0         0 Lab::Exception::Warning->throw( error =>
1168             "AUTOLOAD could not find var for getter/setter: $name \n"
1169             );
1170             }
1171             }
1172             elsif ( exists $self->{'device_settings'}->{$name} ) {
1173 0 0       0 if (@_) {
1174 0         0 return $self->{'device_settings'}->{$name} = shift;
1175             }
1176             else {
1177 0         0 return $self->{'device_settings'}->{$name};
1178             }
1179             }
1180             else {
1181 0         0 Lab::Exception::Warning->throw( error => "AUTOLOAD in "
1182             . __PACKAGE__
1183             . " couldn't access field '${name}'.\n" );
1184             }
1185             }
1186              
1187             # needed so AUTOLOAD doesn't try to call DESTROY on cleanup and prevent the inherited DESTROY
1188             sub DESTROY {
1189 0     0   0 my $self = shift;
1190              
1191             #$self->connection()->DESTROY();
1192 0 0       0 $self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
1193             }
1194              
1195             sub getset {
1196 6     6 0 17 my $self = shift;
1197 6         14 my $gs = shift;
1198 6         17 my $varname = shift;
1199 6         13 my $subfield = shift;
1200 6 50       15 if ( $gs eq 'set_' ) {
1201 0         0 my $value = shift;
1202 0 0 0     0 if ( !defined $value || ref($value) ne "" ) {
1203 0         0 Lab::Exception::CorruptParameter->throw( error =>
1204             "No or no scalar value given to generic set function $AUTOLOAD in "
1205             . __PACKAGE__
1206             . "::AUTOLOAD().\n" );
1207             }
1208 0 0       0 if ( @_ > 0 ) {
1209 0         0 Lab::Exception::CorruptParameter->throw( error =>
1210             "Too many values given to generic set function $AUTOLOAD "
1211             . __PACKAGE__
1212             . "::AUTOLOAD().\n" );
1213             }
1214 0         0 return $self->{$subfield}->{$varname} = $value;
1215             }
1216             else {
1217 6 50       15 if ( @_ > 0 ) {
1218 0         0 Lab::Exception::CorruptParameter->throw( error =>
1219             "Too many values given to generic get function $AUTOLOAD "
1220             . __PACKAGE__
1221             . "::AUTOLOAD().\n" );
1222             }
1223 6         30 return $self->{$subfield}->{$varname};
1224             }
1225             }
1226              
1227             #
1228             # This is a hook which is called after connection initialization and before the device cache is synced (see _construct).
1229             # Necessary for some devices to put them into e.g. remote control mode or otherwise enable communication.
1230             # Overwrite this if needed.
1231             #
1232       7     sub _device_init {
1233             }
1234              
1235             #
1236             # This tool just returns the index of the element in the provided list
1237             #
1238              
1239             sub function_list_index {
1240 0     0 0 0 1 while $_[0] ne pop;
1241 0         0 $#_;
1242             }
1243              
1244             # sub WriteConfig {
1245             # my $self = shift;
1246             #
1247             # my %config = @_;
1248             # %config = %{$_[0]} if (ref($_[0]));
1249             #
1250             # my $command = "";
1251             # # function characters init
1252             # my $inCommand = "";
1253             # my $betweenCmdAndData = "";
1254             # my $postData = "";
1255             # # config data
1256             # if (exists $self->{'CommandRules'}) {
1257             # # write stating value by default to command
1258             # $command = $self->{'CommandRules'}->{'preCommand'}
1259             # if (exists $self->{'CommandRules'}->{'preCommand'});
1260             # $inCommand = $self->{'CommandRules'}->{'inCommand'}
1261             # if (exists $self->{'CommandRules'}->{'inCommand'});
1262             # $betweenCmdAndData = $self->{'CommandRules'}->{'betweenCmdAndData'}
1263             # if (exists $self->{'CommandRules'}->{'betweenCmdAndData'});
1264             # $postData = $self->{'CommandRules'}->{'postData'}
1265             # if (exists $self->{'CommandRules'}->{'postData'});
1266             # }
1267             # # get command if sub call from itself
1268             # $command = $_[1] if (ref($_[0]));
1269             #
1270             # # build up commands buffer
1271             # foreach my $key (keys %config) {
1272             # my $value = $config{$key};
1273             #
1274             # # reference again?
1275             # if (ref($value)) {
1276             # $self->WriteConfig($value,$command.$key.$inCommand);
1277             # } else {
1278             # # end of search
1279             # $self->Write($command.$key.$betweenCmdAndData.$value.$postData);
1280             # }
1281             # }
1282             #
1283             # }
1284              
1285             # =head2 WriteConfig
1286             #
1287             # this is NOT YET IMPLEMENTED in this base class so far
1288             #
1289             # $instrument->WriteConfig( 'TRIGGER' => { 'SOURCE' => 'CHANNEL1',
1290             # 'EDGE' => 'RISE' },
1291             # 'AQUIRE' => 'HRES',
1292             # 'MEASURE' => { 'VRISE' => 'ON' });
1293             #
1294             # Builds up the commands and sends them to the instrument. To get the correct
1295             # format a
1296             # command rules hash has to be set up by the driver package
1297             #
1298             # e.g. for SCPI commands
1299             # $instrument->{'CommandRules'} = {
1300             # 'preCommand' => ':',
1301             # 'inCommand' => ':',
1302             # 'betweenCmdAndData' => ' ',
1303             # 'postData' => '' # empty entries can be skipped
1304             # };
1305             #
1306             #
1307             #
1308              
1309              
1310             1;
1311              
1312             __END__
1313              
1314             =pod
1315              
1316             =encoding utf-8
1317              
1318             =head1 NAME
1319              
1320             Lab::Instrument - Instrument base class
1321              
1322             =head1 VERSION
1323              
1324             version 3.880
1325              
1326             =head1 SYNOPSIS
1327              
1328             Lab::Instrument is meant to be used as a base class for inheriting instruments.
1329             For very simple applications it can also be used directly, like
1330              
1331             $generic_instrument = new Lab::Instrument ( connection_type => VISA_GPIB, gpib_address => 14 );
1332             my $idn = $generic_instrument->query('*IDN?');
1333              
1334             Every inheriting class constructor should start as follows:
1335              
1336             sub new {
1337             my $proto = shift;
1338             my $class = ref($proto) || $proto;
1339             my $self = $class->SUPER::new(@_);
1340             $self->${\(__PACKAGE__.'::_construct')}(__PACKAGE__); # check for supported connections, initialize fields etc.
1341             ...
1342             }
1343              
1344             Beware that only the first set of parameters specific to an individual GPIB
1345             board or any other bus hardware gets used. Settings for EOI assertion for
1346             example.
1347              
1348             If you know what you're doing or you have an exotic scenario you can use the
1349             connection parameter "ignore_twins => 1" to force the creation of a new bus
1350             object, but this is discouraged - it will kill bus management and you might run
1351             into hardware/resource sharing issues.
1352              
1353             =head1 DESCRIPTION
1354              
1355             C<Lab::Instrument> is the base class for Instruments. It doesn't do much by
1356             itself, but is meant to be inherited in specific instrument drivers. It provides
1357             general C<read>, C<write> and C<query> methods and basic connection handling
1358             (internally, C<_set_connection>, C<_check_connection>).
1359              
1360             =head1 CONSTRUCTOR
1361              
1362             =head2 new
1363              
1364             This blesses $self (don't do it yourself in an inheriting class!), initializes
1365             the basic "fields" to be accessed via AUTOLOAD and puts the configuration hash
1366             in $self->config to be accessed in methods and inherited classes.
1367              
1368             Arguments: just the configuration hash (or even-sized list) passed along from a
1369             child class constructor.
1370              
1371             =head1 METHODS
1372              
1373             =head2 write
1374              
1375             $instrument->write($command <, {optional hashref/hash}> );
1376              
1377             Sends the command C<$command> to the instrument. An option hash can be supplied
1378             as second or also as only argument. Generally, all options are passed to the
1379             connection/bus, so additional named options may be supported based on the
1380             connection and bus and can be passed as a hashref or hash. See
1381             L<Lab::Connection>.
1382              
1383             Optional named parameters for hash:
1384              
1385             error_check => 1/0
1386              
1387             Invoke $instrument->check_errors after write. Defaults to off.
1388              
1389             =head2 read
1390              
1391             $result=$instrument->read({ read_length => <max length>, brutal => <1/0>);
1392              
1393             Reads a result of C<ReadLength> from the instrument and returns it. Returns an
1394             exception on error.
1395              
1396             If the parameter C<brutal> is set, a timeout in the connection will not result
1397             in an Exception thrown, but will return the data obtained until the timeout
1398             without further comment. Be aware that this data is also contained in the the
1399             timeout exception object (see C<Lab::Exception>).
1400              
1401             Generally, all options are passed to the connection/bus, so additional named
1402             options may be supported based on the connection and bus and can be passed as a
1403             hashref or hash. See L<Lab::Connection>.
1404              
1405             =head2 query
1406              
1407             $result=$instrument->query({ command => $command,
1408             wait_query => $wait_query,
1409             read_length => $read_length);
1410              
1411             Sends the command C<$command> to the instrument and reads a result from the
1412             instrument and returns it. The length of the read buffer is set to
1413             C<read_length> or to the default set in the connection.
1414              
1415             Waits for C<wait_query> microseconds before trying to read the answer.
1416              
1417             Generally, all options are passed to the connection/bus, so additional named
1418             options may be supported based on the connection and bus and can be passed as a
1419             hashref or hash. See L<Lab::Connection>.
1420              
1421             =head2 get_error
1422              
1423             ($errcode, $errmsg) = $instrument->get_error();
1424              
1425             Method stub to be overwritten. Implementations read one error (and message, if
1426             available) from the device.
1427              
1428             =head2 get_status
1429              
1430             $status = $instrument->get_status();
1431             if( $instrument->get_status('ERROR') ) {...}
1432              
1433             Method stub to be overwritten. This returns the status reported by the device
1434             (e.g. the status byte retrieved via serial poll from GPIB devices). When
1435             implementing, use only information which can be retrieved very fast from the
1436             device, as this may be used often.
1437              
1438             Without parameters, has to return a hashref with named status bits, e.g.
1439              
1440             $status => {
1441             ERROR => 1,
1442             DATA => 0,
1443             READY => 1
1444             }
1445              
1446             If present, the first argument is interpreted as a key and the corresponding
1447             value of the hash above is returned directly.
1448              
1449             The 'ERROR'-key has to be implemented in every device driver!
1450              
1451             =head2 check_errors
1452              
1453             $instrument->check_errors($last_command);
1454            
1455             # try
1456             eval { $instrument->check_errors($last_command) };
1457             # catch
1458             if ( my $e = Exception::Class->caught('Lab::Exception::DeviceError')) {
1459             warn "Errors from device!";
1460             @errors = $e->error_list();
1461             @devtype = $e->device_class();
1462             $command = $e->command();
1463             }
1464              
1465             Uses get_error() to check the device for occured errors. Reads all present
1466             errors and throws a Lab::Exception::DeviceError. The list of errors, the device
1467             class and the last issued command(s) (if the script provided them) are enclosed.
1468              
1469             =head2 _check_args
1470              
1471             Parse the arguments given to a method. The typical use is like this:
1472              
1473             sub my_method () {
1474             my $self = shift;
1475             my ($arg_1, $arg_2, $tail) = $self->_check_args(\@_, ['arg1', 'arg2']);
1476             ...
1477             }
1478              
1479             There are now two ways, how a user can give arguments to C<my_method>. Both of
1480             the following calls will assign C<$value1> to C<$arg1> and C<$value2> to C<$arg2>.
1481              
1482             =over
1483              
1484             =item old style:
1485              
1486             $instrument->my_method($value1, $value2, $tail);
1487              
1488             =item new style:
1489              
1490             $instrument->my_method({arg1 => $value1, arg2 => $value2});
1491              
1492             Remaining key-value pairs will be consumed by C<$tail>. For example, after
1493              
1494             $instrument->my_method({arg1 => $value1, arg2 => $value2, x => $value_x});
1495              
1496             C<$tail> will hold the hashref C<< {x => $value_x} >>.
1497              
1498             Multiple hashrefs given to C<my_method> are concatenated.
1499              
1500             For a method without named arguments, you can either use
1501              
1502             my ($tail) = $self->_check_args(\@_, []);
1503              
1504             or
1505              
1506             my ($tail) = $self->_check_args(\@);
1507              
1508             =back
1509              
1510             =head2 _check_args_strict
1511              
1512             Like C<_check_args>, but makes all declared arguments mandatory.
1513              
1514             If an argument does not
1515             receive a non-undef value, this will throw an exception. Thus, the returned
1516             array will never contain undefined values.
1517              
1518             =head1 CAVEATS/BUGS
1519              
1520             Probably many, with all the porting. This will get better.
1521              
1522             =head1 SEE ALSO
1523              
1524             =over 4
1525              
1526             =item * L<Lab::Bus>
1527              
1528             =item * L<Lab::Connection>
1529              
1530             =item * L<Lab::Instrument::HP34401A>
1531              
1532             =item * L<Lab::Instrument::HP34970A>
1533              
1534             =item * L<Lab::Instrument::Source>
1535              
1536             =item * L<Lab::Instrument::Yokogawa7651>
1537              
1538             =item * and many more...
1539              
1540             =back
1541              
1542             =head1 COPYRIGHT AND LICENSE
1543              
1544             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
1545              
1546             Copyright 2005-2006 Daniel Schroeer
1547             2009 Andreas K. Huettel
1548             2010 Andreas K. Huettel, Daniel Schroeer, Florian Olbrich, Matthias Voelker
1549             2011 Andreas K. Huettel, Florian Olbrich
1550             2012 Alois Dirnaichner, Andreas K. Huettel, Christian Butschkow, Florian Olbrich, Stefan Geissler
1551             2013 Alois Dirnaichner, Andreas K. Huettel, Christian Butschkow, Stefan Geissler
1552             2014 Alexei Iankilevitch, Christian Butschkow
1553             2016 Charles Lane, Simon Reinhardt
1554             2017 Andreas K. Huettel
1555             2019 Simon Reinhardt
1556             2020 Andreas K. Huettel
1557              
1558              
1559             This is free software; you can redistribute it and/or modify it under
1560             the same terms as the Perl 5 programming language system itself.
1561              
1562             =cut