| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Lab::Instrument; |
|
2
|
|
|
|
|
|
|
$Lab::Instrument::VERSION = '3.881'; |
|
3
|
|
|
|
|
|
|
#ABSTRACT: Instrument base class |
|
4
|
|
|
|
|
|
|
|
|
5
|
9
|
|
|
9
|
|
256921
|
use v5.20; |
|
|
9
|
|
|
|
|
39
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
9
|
|
|
9
|
|
49
|
use strict; |
|
|
9
|
|
|
|
|
20
|
|
|
|
9
|
|
|
|
|
188
|
|
|
8
|
9
|
|
|
9
|
|
44
|
use warnings; |
|
|
9
|
|
|
|
|
20
|
|
|
|
9
|
|
|
|
|
222
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#use POSIX; # added for int() function |
|
11
|
9
|
|
|
9
|
|
1010
|
use Lab::Generic; |
|
|
9
|
|
|
|
|
19
|
|
|
|
9
|
|
|
|
|
251
|
|
|
12
|
9
|
|
|
9
|
|
928
|
use Lab::Exception; |
|
|
9
|
|
|
|
|
22
|
|
|
|
9
|
|
|
|
|
246
|
|
|
13
|
9
|
|
|
9
|
|
4126
|
use Lab::Connection; |
|
|
9
|
|
|
|
|
30
|
|
|
|
9
|
|
|
|
|
305
|
|
|
14
|
9
|
|
|
9
|
|
58
|
use Carp qw(cluck croak); |
|
|
9
|
|
|
|
|
19
|
|
|
|
9
|
|
|
|
|
474
|
|
|
15
|
9
|
|
|
9
|
|
67
|
use Data::Dumper; |
|
|
9
|
|
|
|
|
33
|
|
|
|
9
|
|
|
|
|
398
|
|
|
16
|
9
|
|
|
9
|
|
3582
|
use Clone qw(clone); |
|
|
9
|
|
|
|
|
19825
|
|
|
|
9
|
|
|
|
|
523
|
|
|
17
|
9
|
|
|
9
|
|
4113
|
use Class::ISA qw(self_and_super_path); |
|
|
9
|
|
|
|
|
15811
|
|
|
|
9
|
|
|
|
|
367
|
|
|
18
|
9
|
|
|
9
|
|
4337
|
use Hook::LexWrap; |
|
|
9
|
|
|
|
|
11911
|
|
|
|
9
|
|
|
|
|
87
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
9
|
|
|
9
|
|
340
|
use Time::HiRes qw (usleep sleep); |
|
|
9
|
|
|
|
|
24
|
|
|
|
9
|
|
|
|
|
64
|
|
|
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
|
20
|
my $proto = shift; |
|
59
|
10
|
|
33
|
|
|
42
|
my $class = ref($proto) || $proto; |
|
60
|
10
|
|
|
|
|
23
|
my $config = undef; |
|
61
|
10
|
50
|
|
|
|
38
|
if ( ref $_[0] eq 'HASH' ) { $config = shift } |
|
|
10
|
|
|
|
|
19
|
|
|
62
|
0
|
|
|
|
|
0
|
else { $config = {@_} } |
|
63
|
|
|
|
|
|
|
|
|
64
|
10
|
|
|
|
|
70
|
my $self = $class->SUPER::new(@_); |
|
65
|
10
|
|
|
|
|
27
|
$self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__); |
|
|
10
|
|
|
|
|
56
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# wrap additional code for automatic cache-handling aroung all paramter set- and get-functions defined in %fields->{device_cache} |
|
68
|
10
|
|
|
|
|
48
|
my @isa = Class::ISA::self_and_super_path($class); |
|
69
|
10
|
|
|
|
|
768
|
my $flag = 0; |
|
70
|
10
|
|
|
|
|
44
|
while (@isa) { |
|
71
|
38
|
|
|
|
|
71
|
my $isa = pop @isa; |
|
72
|
38
|
100
|
|
|
|
92
|
if ( $flag == 1 ) { |
|
73
|
18
|
|
|
|
|
92
|
$self->_init_cache_handling($isa); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
38
|
100
|
|
|
|
146
|
if ( $isa eq 'Lab::Instrument' ) { |
|
76
|
10
|
|
|
|
|
24
|
$flag = 1; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
10
|
|
|
|
|
55
|
$self->config($config); |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# |
|
84
|
|
|
|
|
|
|
# In most inherited classes, configure() is run through _construct() |
|
85
|
|
|
|
|
|
|
# |
|
86
|
10
|
|
|
|
|
35
|
$self->${ \( __PACKAGE__ . '::configure' ) }( $self->config() ) |
|
|
10
|
|
|
|
|
52
|
|
|
87
|
|
|
|
|
|
|
; # use local configure, not possibly overwritten one |
|
88
|
|
|
|
|
|
|
|
|
89
|
10
|
50
|
|
|
|
34
|
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
|
|
|
|
46
|
$self->device_name( $self->config('device_name') ) |
|
97
|
|
|
|
|
|
|
if defined $self->config('device_name'); |
|
98
|
10
|
50
|
|
|
|
34
|
$self->device_comment( $self->config('device_comment') ) |
|
99
|
|
|
|
|
|
|
if defined $self->config('device_comment'); |
|
100
|
|
|
|
|
|
|
|
|
101
|
10
|
|
|
|
|
80
|
$self->register_instrument(); |
|
102
|
|
|
|
|
|
|
|
|
103
|
10
|
|
|
|
|
33
|
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
|
|
66
|
( my $self, my $package ) = ( shift, shift ); |
|
111
|
|
|
|
|
|
|
|
|
112
|
28
|
|
|
|
|
52
|
my $class = ref($self); |
|
113
|
28
|
|
|
|
|
42
|
my $fields = undef; |
|
114
|
|
|
|
|
|
|
{ |
|
115
|
9
|
|
|
9
|
|
4045
|
no strict 'refs'; |
|
|
9
|
|
|
|
|
33
|
|
|
|
9
|
|
|
|
|
3160
|
|
|
|
28
|
|
|
|
|
47
|
|
|
116
|
28
|
|
|
|
|
39
|
$fields = *${ \( $package . '::fields' ) }{HASH}; |
|
|
28
|
|
|
|
|
142
|
|
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
28
|
|
|
|
|
63
|
foreach my $element ( keys %{$fields} ) { |
|
|
28
|
|
|
|
|
123
|
|
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# handle special subarrays |
|
122
|
215
|
100
|
|
|
|
442
|
if ( $element eq 'device_settings' ) { |
|
|
|
100
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# don't overwrite filled hash from ancestor |
|
125
|
|
|
|
|
|
|
$self->{device_settings} = {} |
|
126
|
26
|
100
|
|
|
|
86
|
if !exists( $self->{device_settings} ); |
|
127
|
26
|
|
|
|
|
37
|
for my $s_key ( keys %{ $fields->{'device_settings'} } ) { |
|
|
26
|
|
|
|
|
95
|
|
|
128
|
|
|
|
|
|
|
$self->{device_settings}->{$s_key} |
|
129
|
162
|
|
|
|
|
565
|
= 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
|
|
|
|
60
|
if !exists( $self->{connection_settings} ); |
|
137
|
18
|
|
|
|
|
31
|
for my $s_key ( keys %{ $fields->{connection_settings} } ) { |
|
|
18
|
|
|
|
|
55
|
|
|
138
|
|
|
|
|
|
|
$self->{connection_settings}->{$s_key} |
|
139
|
28
|
|
|
|
|
120
|
= 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
|
|
|
|
|
851
|
$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
|
|
|
|
|
423
|
$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
|
|
|
|
134
|
$self->${ \( $package . '::configure' ) }( $self->config() ) |
|
|
28
|
|
|
|
|
187
|
|
|
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
|
|
|
143
|
if ( $class eq $package && $class ne 'Lab::Instrument' ) { |
|
175
|
|
|
|
|
|
|
|
|
176
|
10
|
|
|
|
|
61
|
$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
|
|
|
|
|
52
|
$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
|
|
46
|
my $self = shift; |
|
203
|
18
|
|
|
|
|
32
|
my $class = shift; |
|
204
|
|
|
|
|
|
|
|
|
205
|
9
|
|
|
9
|
|
72
|
no strict 'refs'; |
|
|
9
|
|
|
|
|
33
|
|
|
|
9
|
|
|
|
|
7555
|
|
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# avoid to redefine the subs twice |
|
208
|
18
|
100
|
|
|
|
28
|
if ( defined ${ $class . '::MODIFIED' } ) { |
|
|
18
|
|
|
|
|
140
|
|
|
209
|
3
|
|
|
|
|
7
|
return; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
15
|
|
|
|
|
37
|
my $fields = *${ \( $class . '::fields' ) }{HASH}; |
|
|
15
|
|
|
|
|
81
|
|
|
213
|
15
|
|
|
|
|
35
|
my @cache_params = keys %{ $fields->{device_cache} }; |
|
|
15
|
|
|
|
|
83
|
|
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# wrap parameter function defined in %fields->{device_cache}: |
|
216
|
15
|
|
|
|
|
37
|
foreach my $cache_param (@cache_params) { |
|
217
|
38
|
|
|
|
|
941
|
my $set_sub = "set_" . $cache_param; |
|
218
|
38
|
|
|
|
|
87
|
my $get_sub = "get_" . $cache_param; |
|
219
|
|
|
|
|
|
|
|
|
220
|
38
|
|
|
|
|
58
|
my $get_methode = *{ $class . "::" . $get_sub }; |
|
|
38
|
|
|
|
|
160
|
|
|
221
|
38
|
|
|
|
|
81
|
my $set_methode = *{ $class . "::" . $set_sub }; |
|
|
38
|
|
|
|
|
161
|
|
|
222
|
|
|
|
|
|
|
|
|
223
|
38
|
100
|
100
|
|
|
349
|
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
|
|
|
|
|
67
|
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
|
|
23943
|
my $self = shift; |
|
240
|
|
|
|
|
|
|
|
|
241
|
75
|
|
|
|
|
139
|
${__PACKAGE__::SELF} = $self; |
|
242
|
75
|
|
|
|
|
157
|
${__PACKAGE__::SELF}->{fast_cache_value} = $_[0]; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# read_mode handling: do not execute if request is set: |
|
245
|
75
|
50
|
33
|
|
|
558
|
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
|
|
467
|
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
|
|
|
230
|
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
|
|
|
487
|
if ( ${__PACKAGE__::SELF}->can($get_sub) |
|
274
|
|
|
|
|
|
|
and not ${__PACKAGE__::SELF}->{config}->{no_cache} ) { |
|
275
|
75
|
|
|
|
|
228
|
my $var = ${__PACKAGE__::SELF}->$get_sub(); |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
|
279
|
29
|
|
|
|
|
252
|
); |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Restore Warnings: |
|
282
|
|
|
|
|
|
|
#open STDERR, ">&SAVEERR"; |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
38
|
100
|
66
|
|
|
1429
|
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
|
|
|
|
|
87
|
local (*SAVEERR); |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
#open SAVEERR, ">&STDERR"; |
|
294
|
|
|
|
|
|
|
#open(STDERR, '>', undef); |
|
295
|
|
|
|
|
|
|
|
|
296
|
34
|
|
|
|
|
69
|
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
|
|
6476
|
my $self = shift; |
|
305
|
|
|
|
|
|
|
|
|
306
|
294
|
|
|
|
|
483
|
${__PACKAGE__::SELF} = $self; |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# read_mode handling: |
|
309
|
294
|
|
|
|
|
591
|
my @args = @_; |
|
310
|
294
|
|
|
|
|
424
|
pop @args; |
|
311
|
294
|
|
|
|
|
903
|
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
|
|
|
1132
|
and exists( $self->{config}->{default_read_mode} ); |
|
318
|
|
|
|
|
|
|
|
|
319
|
294
|
50
|
|
|
|
1339
|
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
|
|
|
|
732
|
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
|
|
|
1248
|
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
|
|
|
|
|
211
|
$_[-1] = $self->device_cache($parameter); |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
}, |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# after get-functions is executed: |
|
359
|
|
|
|
|
|
|
post => sub { |
|
360
|
|
|
|
|
|
|
|
|
361
|
196
|
50
|
|
196
|
|
2199
|
if ( not defined ${__PACKAGE__::SELF} ) { |
|
362
|
0
|
|
|
|
|
0
|
return; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
196
|
|
|
|
|
310
|
my $retval = $_[-1]; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# refresh cache value |
|
367
|
196
|
50
|
33
|
|
|
724
|
if ( not defined $retval |
|
368
|
|
|
|
|
|
|
or ref($retval) eq 'Hook::LexWrap::Cleanup' ) { |
|
369
|
0
|
|
|
|
|
0
|
return; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
else { |
|
372
|
196
|
100
|
|
|
|
435
|
my $cache_value = wantarray ? $retval->[0] : $retval; |
|
373
|
196
|
|
|
|
|
649
|
${__PACKAGE__::SELF} |
|
374
|
|
|
|
|
|
|
->device_cache( { $parameter => $cache_value } ); |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
} |
|
377
|
34
|
|
|
|
|
382
|
); |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Restore Warnings: |
|
380
|
|
|
|
|
|
|
#open STDERR, ">&SAVEERR"; |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
# remeber that we have allready redefined the functions |
|
386
|
15
|
|
|
|
|
515
|
${ $class . '::MODIFIED' } = 1; |
|
|
15
|
|
|
|
|
92
|
|
|
387
|
|
|
|
|
|
|
|
|
388
|
9
|
|
|
9
|
|
81
|
use strict 'refs'; |
|
|
9
|
|
|
|
|
37
|
|
|
|
9
|
|
|
|
|
8160
|
|
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
} |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub register_instrument { |
|
393
|
10
|
|
|
10
|
0
|
17
|
my $self = shift; |
|
394
|
|
|
|
|
|
|
|
|
395
|
10
|
|
|
|
|
24
|
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
|
|
|
|
|
6
|
$Data::Dumper::Varname = "device_cache_"; |
|
411
|
2
|
|
|
|
|
7
|
my $config = Dumper $self->device_cache(); |
|
412
|
|
|
|
|
|
|
|
|
413
|
2
|
|
|
|
|
240
|
$config .= "\n"; |
|
414
|
|
|
|
|
|
|
|
|
415
|
2
|
|
|
|
|
5
|
$Data::Dumper::Maxdepth = 1; |
|
416
|
2
|
|
|
|
|
6
|
$Data::Dumper::Varname = "connection_settings_"; |
|
417
|
2
|
50
|
|
|
|
13
|
if ( defined $self->connection() ) { |
|
418
|
2
|
|
|
|
|
9
|
$config .= Dumper $self->connection()->config(); |
|
419
|
|
|
|
|
|
|
} |
|
420
|
2
|
|
|
|
|
129
|
return $config; |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
} |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub _set_config_parameters { |
|
425
|
10
|
|
|
10
|
|
23
|
my $self = shift; |
|
426
|
|
|
|
|
|
|
|
|
427
|
10
|
|
|
|
|
20
|
my @order = @{ $self->device_cache_order() }; |
|
|
10
|
|
|
|
|
62
|
|
|
428
|
10
|
|
|
|
|
24
|
my @keys = keys %{ $self->config() }; |
|
|
10
|
|
|
|
|
40
|
|
|
429
|
|
|
|
|
|
|
|
|
430
|
10
|
|
|
|
|
29
|
foreach my $ckey (@order) { |
|
431
|
16
|
|
|
|
|
40
|
my $subname = 'set_' . $ckey; |
|
432
|
16
|
50
|
33
|
|
|
37
|
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
|
|
|
|
|
35
|
foreach my $ckey (@keys) { |
|
439
|
49
|
|
|
|
|
104
|
my $subname = 'set_' . $ckey; |
|
440
|
49
|
50
|
|
|
|
307
|
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
|
67
|
my $self = shift; |
|
529
|
40
|
|
|
|
|
61
|
my $config = shift; |
|
530
|
|
|
|
|
|
|
|
|
531
|
40
|
50
|
|
|
|
90
|
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
|
|
|
|
|
61
|
for my $fields_key ( keys %{ $self->{_permitted} } ) { |
|
|
40
|
|
|
|
|
216
|
|
|
541
|
|
|
|
|
|
|
{ # restrict scope of "no strict" |
|
542
|
9
|
|
|
9
|
|
77
|
no strict 'refs'; |
|
|
9
|
|
|
|
|
21
|
|
|
|
9
|
|
|
|
|
1220
|
|
|
|
505
|
|
|
|
|
622
|
|
|
543
|
|
|
|
|
|
|
$self->$fields_key( $config->{$fields_key} ) |
|
544
|
505
|
100
|
|
|
|
991
|
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
|
|
|
|
|
158
|
$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
|
|
24
|
my $self = shift; |
|
560
|
10
|
|
50
|
|
|
39
|
my $connection = shift || undef; |
|
561
|
10
|
|
|
|
|
20
|
my $found = 0; |
|
562
|
|
|
|
|
|
|
|
|
563
|
10
|
|
66
|
|
|
53
|
$connection = ref($connection) || $connection; |
|
564
|
|
|
|
|
|
|
|
|
565
|
10
|
50
|
|
|
|
39
|
return 0 if !defined $connection; |
|
566
|
|
|
|
|
|
|
|
|
567
|
9
|
|
|
9
|
|
68
|
no strict 'refs'; |
|
|
9
|
|
|
|
|
21
|
|
|
|
9
|
|
|
|
|
5621
|
|
|
568
|
10
|
50
|
66
|
|
|
20
|
if ( grep( /^ALL$/, @{ $self->supported_connections() } ) == 1 ) { |
|
|
10
|
50
|
|
|
|
113
|
|
|
569
|
0
|
|
|
|
|
0
|
return $connection; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
elsif ($connection->isa('Lab::Connection::DEBUG') |
|
572
|
|
|
|
|
|
|
or $connection->isa('Lab::Connection::Mock') ) { |
|
573
|
10
|
|
|
|
|
60
|
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
|
|
32
|
my $self = shift; |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
# |
|
590
|
|
|
|
|
|
|
# fill in unset connection parameters with the defaults from $self->connections_settings to $self->config |
|
591
|
|
|
|
|
|
|
# |
|
592
|
10
|
|
|
|
|
31
|
my $config = $self->config(); |
|
593
|
10
|
|
|
|
|
23
|
my $connection_type = undef; |
|
594
|
10
|
|
|
|
|
27
|
my $full_connection = undef; |
|
595
|
|
|
|
|
|
|
|
|
596
|
10
|
|
|
|
|
18
|
for my $setting_key ( keys %{ $self->connection_settings() } ) { |
|
|
10
|
|
|
|
|
78
|
|
|
597
|
|
|
|
|
|
|
$config->{$setting_key} = $self->connection_settings($setting_key) |
|
598
|
24
|
100
|
|
|
|
94
|
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
|
|
|
|
30
|
if ( defined( $self->config('connection') ) ) { |
|
|
|
50
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
|
|
604
|
4
|
50
|
|
|
|
9
|
if ( $self->_checkconnection( $self->config('connection') ) ) { |
|
605
|
4
|
|
|
|
|
10
|
$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
|
|
|
|
|
17
|
$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
|
|
|
|
26
|
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
|
|
|
|
|
18
|
$full_connection = "Lab::Connection::" . $connection_type; |
|
640
|
6
|
|
|
|
|
503
|
eval("require ${full_connection};"); |
|
641
|
6
|
50
|
|
|
|
43
|
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
|
|
|
|
95
|
if ( $self->_checkconnection( "Lab::Connection::" . $connection_type ) |
|
649
|
0
|
|
|
|
|
0
|
) { |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# let's get creative |
|
652
|
9
|
|
|
9
|
|
78
|
no strict 'refs'; |
|
|
9
|
|
|
|
|
21
|
|
|
|
9
|
|
|
|
|
785
|
|
|
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
|
|
|
|
122
|
$self->connection( $full_connection->new($config) ) |
|
657
|
|
|
|
|
|
|
|| Lab::Exception::Error->throw( |
|
658
|
|
|
|
|
|
|
error => "Failed to create connection $full_connection!\n" ); |
|
659
|
|
|
|
|
|
|
|
|
660
|
9
|
|
|
9
|
|
63
|
use strict; |
|
|
9
|
|
|
|
|
31
|
|
|
|
9
|
|
|
|
|
30871
|
|
|
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
|
|
|
|
|
51
|
my $new_config = $self->connection()->config(); |
|
676
|
10
|
|
|
|
|
24
|
for my $key ( keys %{ $self->connection_settings() } ) { |
|
|
10
|
|
|
|
|
40
|
|
|
677
|
24
|
100
|
|
|
|
93
|
if ( not defined $self->connection()->config($key) ) { |
|
678
|
2
|
|
|
|
|
4
|
$new_config->{$key} = $self->connection_settings($key); |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
} |
|
681
|
10
|
|
|
|
|
429
|
$self->connection()->config($new_config); |
|
682
|
10
|
|
|
|
|
49
|
$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
|
9
|
my $self = shift; |
|
720
|
6
|
|
|
|
|
11
|
my $command = shift; |
|
721
|
6
|
|
|
|
|
12
|
my @errors = (); |
|
722
|
|
|
|
|
|
|
|
|
723
|
6
|
50
|
|
|
|
19
|
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
|
4
|
my $self = shift; |
|
763
|
2
|
|
|
|
|
6
|
return $self->device_settings('name'); |
|
764
|
|
|
|
|
|
|
} |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
sub get_id { |
|
767
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
|
768
|
2
|
|
|
|
|
13
|
my @name = split( /::/, ref($self) ); |
|
769
|
2
|
|
|
|
|
19
|
return pop(@name); |
|
770
|
|
|
|
|
|
|
} |
|
771
|
|
|
|
|
|
|
|
|
772
|
|
|
|
0
|
0
|
|
sub set_id { |
|
773
|
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
} |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
sub write { |
|
777
|
83
|
|
|
83
|
1
|
134
|
my $self = shift; |
|
778
|
83
|
50
|
66
|
|
|
315
|
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
|
|
|
|
299
|
my $args |
|
|
|
100
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
= scalar(@_) % 2 == 0 |
|
785
|
|
|
|
|
|
|
? {@_} |
|
786
|
|
|
|
|
|
|
: ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef ); |
|
787
|
83
|
50
|
|
|
|
195
|
Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n") |
|
788
|
|
|
|
|
|
|
if !defined($args); |
|
789
|
|
|
|
|
|
|
|
|
790
|
83
|
50
|
|
|
|
240
|
$args->{'command'} = $command if defined $command; |
|
791
|
|
|
|
|
|
|
|
|
792
|
83
|
|
|
|
|
415
|
my $result = $self->connection()->Write($args); |
|
793
|
|
|
|
|
|
|
|
|
794
|
83
|
100
|
|
|
|
236
|
$self->check_errors( $args->{'command'} ) if $args->{error_check}; |
|
795
|
|
|
|
|
|
|
|
|
796
|
83
|
|
|
|
|
229
|
return $result; |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
sub read { |
|
800
|
4
|
|
|
4
|
1
|
8
|
my $self = shift; |
|
801
|
4
|
0
|
|
|
|
17
|
my $args |
|
|
|
50
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
= scalar(@_) % 2 == 0 |
|
803
|
|
|
|
|
|
|
? {@_} |
|
804
|
|
|
|
|
|
|
: ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef ); |
|
805
|
4
|
50
|
|
|
|
10
|
Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n") |
|
806
|
|
|
|
|
|
|
if !defined($args); |
|
807
|
|
|
|
|
|
|
|
|
808
|
4
|
|
|
|
|
16
|
my $result = $self->connection()->Read($args); |
|
809
|
|
|
|
|
|
|
$self->check_errors('Just a plain and simple read.') |
|
810
|
4
|
50
|
|
|
|
12
|
if $args->{error_check}; |
|
811
|
|
|
|
|
|
|
|
|
812
|
4
|
|
|
|
|
9
|
$result =~ s/^[\r\t\n]+|[\r\t\n]+$//g; |
|
813
|
4
|
|
|
|
|
18
|
return $result; |
|
814
|
|
|
|
|
|
|
} |
|
815
|
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
sub clear { |
|
817
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
|
818
|
1
|
|
|
|
|
5
|
$self->connection()->Clear(); |
|
819
|
|
|
|
|
|
|
} |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
sub request { |
|
822
|
18
|
|
|
18
|
0
|
27
|
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
|
|
|
|
|
33
|
my ( $package, $filename, $line, $subroutine ); |
|
829
|
18
|
|
|
|
|
46
|
( $package, $filename, $line, $subroutine ) = caller(1); |
|
830
|
18
|
|
|
|
|
1012
|
( $package, $filename, $line ) = caller(0); |
|
831
|
18
|
|
|
|
|
470
|
my $requestID |
|
832
|
|
|
|
|
|
|
= $package . " " . $filename . " " . $subroutine . " " . $line; |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# # avoid to return an undef value: |
|
835
|
18
|
50
|
33
|
|
|
88
|
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
|
259
|
my $self = shift; |
|
855
|
166
|
|
|
|
|
364
|
my ( $command, $args ) = $self->parse_optional(@_); |
|
856
|
|
|
|
|
|
|
my $read_mode |
|
857
|
166
|
100
|
|
|
|
425
|
= ( defined $args->{'read_mode'} ) ? $args->{'read_mode'} : 'device'; |
|
858
|
166
|
50
|
|
|
|
470
|
$args->{'command'} = $command if defined $command; |
|
859
|
|
|
|
|
|
|
|
|
860
|
166
|
50
|
|
|
|
341
|
if ( not defined $args->{'command'} ) { |
|
861
|
0
|
|
|
|
|
0
|
Lab::Exception::CorruptParameter->throw("No 'command' given!\n"); |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
|
|
864
|
166
|
|
|
|
|
687
|
my $result = $self->connection()->Query($args); |
|
865
|
166
|
50
|
|
|
|
554
|
$self->check_errors( $args->{'command'} ) if $args->{error_check}; |
|
866
|
|
|
|
|
|
|
|
|
867
|
166
|
|
|
|
|
616
|
$result =~ s/^[\r\t\n]+|[\r\t\n]+$//g; |
|
868
|
166
|
|
|
|
|
536
|
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
|
295
|
my $self = shift; |
|
882
|
|
|
|
|
|
|
|
|
883
|
184
|
50
|
66
|
|
|
779
|
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
|
|
|
|
483
|
my $args |
|
|
|
100
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
= scalar(@_) % 2 == 0 |
|
890
|
|
|
|
|
|
|
? {@_} |
|
891
|
|
|
|
|
|
|
: ( ref( $_[0] ) eq 'HASH' ? $_[0] : undef ); |
|
892
|
184
|
50
|
|
|
|
370
|
Lab::Exception::CorruptParameter->throw("Illegal parameter hash given!\n") |
|
893
|
|
|
|
|
|
|
if !defined($args); |
|
894
|
|
|
|
|
|
|
|
|
895
|
184
|
|
|
|
|
474
|
return $optional, $args; |
|
896
|
|
|
|
|
|
|
} |
|
897
|
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
# |
|
899
|
|
|
|
|
|
|
# accessor for device_settings |
|
900
|
|
|
|
|
|
|
# |
|
901
|
|
|
|
|
|
|
sub device_settings { |
|
902
|
479
|
|
|
479
|
0
|
706
|
my $self = shift; |
|
903
|
479
|
|
|
|
|
629
|
my $value = undef; |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
#warn "device_settings got this:\n" . Dumper(@_) . "\n"; |
|
906
|
|
|
|
|
|
|
|
|
907
|
479
|
100
|
0
|
|
|
937
|
if ( scalar(@_) == 0 ) |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
{ # empty parameters - return whole device_settings hash |
|
909
|
302
|
|
|
|
|
1220
|
return $self->{'device_settings'}; |
|
910
|
|
|
|
|
|
|
} |
|
911
|
|
|
|
|
|
|
elsif ( scalar(@_) == 1 ) |
|
912
|
|
|
|
|
|
|
{ # one parm - either a scalar (key) or a hashref (try to merge) |
|
913
|
177
|
|
|
|
|
242
|
$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
|
|
|
|
429
|
if ( ref($value) =~ /HASH/ ) { # it's a hash - merge into current settings |
|
929
|
40
|
|
|
|
|
68
|
for my $ext_key ( keys %{$value} ) { |
|
|
40
|
|
|
|
|
105
|
|
|
930
|
|
|
|
|
|
|
$self->{'device_settings'}->{$ext_key} = $value->{$ext_key} |
|
931
|
95
|
100
|
|
|
|
215
|
if ( exists( $self->device_settings()->{$ext_key} ) ); |
|
932
|
|
|
|
|
|
|
} |
|
933
|
40
|
|
|
|
|
94
|
return $self->{'device_settings'}; |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
else { # it's a key - return the corresponding value |
|
936
|
137
|
|
|
|
|
612
|
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
|
835
|
my $self = shift; |
|
946
|
604
|
|
|
|
|
845
|
my $value = undef; |
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
#warn "device_cache got this:\n" . Dumper(@_) . "\n"; |
|
949
|
|
|
|
|
|
|
|
|
950
|
604
|
100
|
33
|
|
|
1287
|
if ( scalar(@_) == 0 ) |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
{ # empty parameters - return whole device_settings hash |
|
952
|
204
|
|
|
|
|
780
|
return $self->{'device_cache'}; |
|
953
|
|
|
|
|
|
|
} |
|
954
|
|
|
|
|
|
|
elsif ( scalar(@_) == 1 ) |
|
955
|
|
|
|
|
|
|
{ # one parm - either a scalar (key) or a hashref (try to merge) |
|
956
|
394
|
|
|
|
|
571
|
$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
|
|
|
|
|
13
|
$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
|
|
|
|
967
|
if ( ref($value) =~ /HASH/ ) { # it's a hash - merge into current settings |
|
972
|
202
|
|
|
|
|
383
|
for my $ext_key ( keys %{$value} ) { |
|
|
202
|
|
|
|
|
659
|
|
|
973
|
|
|
|
|
|
|
$self->{'device_cache'}->{$ext_key} = $value->{$ext_key} |
|
974
|
202
|
50
|
|
|
|
469
|
if ( exists( $self->device_cache()->{$ext_key} ) ); |
|
975
|
|
|
|
|
|
|
} |
|
976
|
202
|
|
|
|
|
856
|
return $self->{'device_cache'}; |
|
977
|
|
|
|
|
|
|
} |
|
978
|
|
|
|
|
|
|
else { # it's a key - return the corresponding value |
|
979
|
198
|
|
|
|
|
1033
|
return $self->{'device_cache'}->{$value}; |
|
980
|
|
|
|
|
|
|
} |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
sub reset_device_cache { |
|
984
|
1
|
|
|
1
|
0
|
4
|
my $self = shift; |
|
985
|
1
|
|
|
|
|
76
|
my @cache_params = keys %{ $self->{'device_cache'} }; |
|
|
1
|
|
|
|
|
10
|
|
|
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
|
71
|
my $self = shift; |
|
996
|
42
|
|
|
|
|
69
|
my $value = undef; |
|
997
|
|
|
|
|
|
|
|
|
998
|
42
|
100
|
0
|
|
|
118
|
if ( scalar(@_) == 0 ) |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
{ # empty parameters - return whole device_settings hash |
|
1000
|
20
|
|
|
|
|
104
|
return $self->{'connection_settings'}; |
|
1001
|
|
|
|
|
|
|
} |
|
1002
|
|
|
|
|
|
|
elsif ( scalar(@_) == 1 ) |
|
1003
|
|
|
|
|
|
|
{ # one parm - either a scalar (key) or a hashref (try to merge) |
|
1004
|
22
|
|
|
|
|
40
|
$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
|
|
|
|
54
|
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
|
|
|
|
|
86
|
return $self->{'connection_settings'}->{$value}; |
|
1028
|
|
|
|
|
|
|
} |
|
1029
|
|
|
|
|
|
|
} |
|
1030
|
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
sub _check_args { |
|
1032
|
609
|
|
|
609
|
|
934
|
my $self = shift; |
|
1033
|
609
|
|
|
|
|
847
|
my $args = shift; |
|
1034
|
609
|
|
|
|
|
777
|
my $params = shift; |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
609
|
|
|
|
|
899
|
my $arguments = {}; |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
609
|
|
|
|
|
846
|
my $i = 0; |
|
1039
|
609
|
|
|
|
|
836
|
foreach my $arg ( @{$args} ) { |
|
|
609
|
|
|
|
|
1137
|
|
|
1040
|
284
|
100
|
|
|
|
591
|
if ( ref($arg) ne "HASH" ) { |
|
1041
|
131
|
100
|
|
|
|
204
|
if ( defined @{$params}[$i] ) { |
|
|
131
|
|
|
|
|
286
|
|
|
1042
|
113
|
|
|
|
|
186
|
$arguments->{ @{$params}[$i] } = $arg; |
|
|
113
|
|
|
|
|
309
|
|
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
131
|
|
|
|
|
237
|
$i++; |
|
1045
|
|
|
|
|
|
|
} |
|
1046
|
|
|
|
|
|
|
else { |
|
1047
|
153
|
|
|
|
|
229
|
%{$arguments} = ( %{$arguments}, %{$arg} ); |
|
|
153
|
|
|
|
|
333
|
|
|
|
153
|
|
|
|
|
331
|
|
|
|
153
|
|
|
|
|
296
|
|
|
1048
|
153
|
|
|
|
|
287
|
$i++; |
|
1049
|
|
|
|
|
|
|
} |
|
1050
|
|
|
|
|
|
|
} |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
609
|
|
|
|
|
983
|
my @return_args = (); |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
609
|
|
|
|
|
815
|
foreach my $param ( @{$params} ) { |
|
|
609
|
|
|
|
|
944
|
|
|
1055
|
476
|
100
|
|
|
|
897
|
if ( exists $arguments->{$param} ) { |
|
1056
|
214
|
|
|
|
|
393
|
push( @return_args, $arguments->{$param} ); |
|
1057
|
214
|
|
|
|
|
453
|
delete $arguments->{$param}; |
|
1058
|
|
|
|
|
|
|
} |
|
1059
|
|
|
|
|
|
|
else { |
|
1060
|
262
|
|
|
|
|
493
|
push( @return_args, undef ); |
|
1061
|
|
|
|
|
|
|
} |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
609
|
|
|
|
|
932
|
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
|
|
|
|
2408
|
if ( exists $arguments->{$param} ) { |
|
1068
|
0
|
|
|
|
|
0
|
delete $arguments->{$param}; |
|
1069
|
|
|
|
|
|
|
} |
|
1070
|
|
|
|
|
|
|
} |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
609
|
|
|
|
|
904
|
push( @return_args, $arguments ); |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
609
|
50
|
|
|
|
1057
|
if (wantarray) { |
|
1075
|
609
|
|
|
|
|
1687
|
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
|
|
|
|
|
29
|
my $args = shift; |
|
1086
|
19
|
|
|
|
|
29
|
my $params = shift; |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
19
|
|
|
|
|
51
|
my @result = $self->_check_args( $args, $params ); |
|
1089
|
|
|
|
|
|
|
|
|
1090
|
19
|
|
|
|
|
38
|
my $num_params = @result - 1; |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
19
|
|
|
|
|
46
|
for ( my $i = 0; $i < $num_params; ++$i ) { |
|
1093
|
19
|
50
|
|
|
|
59
|
if ( not defined $result[$i] ) { |
|
1094
|
0
|
|
|
|
|
0
|
croak("missing mandatory argument '$params->[$i]'"); |
|
1095
|
|
|
|
|
|
|
} |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
19
|
50
|
|
|
|
35
|
if (wantarray) { |
|
1099
|
19
|
|
|
|
|
63
|
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
|
313
|
( my $self, my $key ) = ( shift, shift ); |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
143
|
100
|
|
|
|
319
|
if ( !defined $key ) { |
|
|
|
100
|
|
|
|
|
|
|
1115
|
60
|
|
|
|
|
207
|
return $self->{'config'}; |
|
1116
|
|
|
|
|
|
|
} |
|
1117
|
|
|
|
|
|
|
elsif ( ref($key) =~ /HASH/ ) { |
|
1118
|
10
|
|
|
|
|
71
|
return $self->{'config'} = $key; |
|
1119
|
|
|
|
|
|
|
} |
|
1120
|
|
|
|
|
|
|
else { |
|
1121
|
73
|
|
|
|
|
317
|
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
|
|
2035
|
my $self = shift; |
|
1145
|
1232
|
50
|
|
|
|
2589
|
my $type = ref($self) or croak "\$self is not an object"; |
|
1146
|
1232
|
|
|
|
|
1734
|
my $value = undef; |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
1232
|
|
|
|
|
1839
|
my $name = $AUTOLOAD; |
|
1149
|
1232
|
|
|
|
|
4666
|
$name =~ s/.*://; # strip fully qualified portion |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
1232
|
100
|
|
|
|
2959
|
if ( exists $self->{_permitted}->{$name} ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1152
|
1226
|
100
|
|
|
|
2060
|
if (@_) { |
|
1153
|
31
|
|
|
|
|
98
|
return $self->{$name} = shift; |
|
1154
|
|
|
|
|
|
|
} |
|
1155
|
|
|
|
|
|
|
else { |
|
1156
|
1195
|
|
|
|
|
17908
|
return $self->{$name}; |
|
1157
|
|
|
|
|
|
|
} |
|
1158
|
|
|
|
|
|
|
} |
|
1159
|
|
|
|
|
|
|
elsif ( $name =~ qr/^(get_|set_)(.*)$/ ) { |
|
1160
|
6
|
50
|
|
|
|
16
|
if ( exists $self->device_settings()->{$2} ) { |
|
|
|
0
|
|
|
|
|
|
|
1161
|
6
|
|
|
|
|
24
|
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
|
9
|
my $self = shift; |
|
1197
|
6
|
|
|
|
|
24
|
my $gs = shift; |
|
1198
|
6
|
|
|
|
|
11
|
my $varname = shift; |
|
1199
|
6
|
|
|
|
|
11
|
my $subfield = shift; |
|
1200
|
6
|
50
|
|
|
|
13
|
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
|
|
|
|
26
|
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
|
|
|
|
|
32
|
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.881 |
|
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 |