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 |