File Coverage

blib/lib/Lab/Instrument/U2000.pm
Criterion Covered Total %
statement 8 115 6.9
branch 0 52 0.0
condition 0 35 0.0
subroutine 3 15 20.0
pod 7 12 58.3
total 18 229 7.8


line stmt bran cond sub pod time code
1             package Lab::Instrument::U2000;
2             #ABSTRACT: Agilent U2000 series USB Power Sensor
3             $Lab::Instrument::U2000::VERSION = '3.881';
4 1     1   1671 use v5.20;
  1         4  
5              
6 1     1   7 use strict;
  1         2  
  1         21  
7 1     1   6 use Lab::Instrument;
  1         2  
  1         1330  
8              
9             our @ISA = ("Lab::Instrument");
10              
11             our %fields = (
12             supported_connections => ['USBtmc'],
13              
14             connection_settings => {
15             usb_vendor => "0957",
16             usb_product => "2a18"
17             },
18              
19             device_settings => {
20             frequency => 10e6,
21             },
22              
23             );
24              
25             sub new {
26 0     0 1   my $proto = shift;
27 0   0       my $class = ref($proto) || $proto;
28 0           my $self = $class->SUPER::new(@_);
29 0           $self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__);
  0            
30 0           $self->clear();
31              
32             #TODO: Device clear
33 0           $self->write("SYST:PRES"); # Load presets
34 0           $self->{trigger_mode} = "AUTO";
35 0           $self->{average_on} = "1";
36 0           return $self;
37             }
38              
39             # template functions for inheriting classes
40              
41             sub id {
42 0     0 1   my $self = shift;
43 0           return $self->query('*IDN?');
44             }
45              
46             sub selftest {
47 0     0 0   my $self = shift;
48 0           return $self->query("*TST");
49             }
50              
51             #TODO: EXT mode not tested
52             sub set_trigger {
53 0     0 0   my $self = shift;
54 0   0       my $type = shift || "AUTO"; #AUTO, BUS, INT, EXT, IMM
55 0           my $args;
56 0 0         if ( ref $_[0] eq 'HASH' ) { $args = shift }
  0            
57 0           else { $args = {@_} }
58 0           my $delay = $args->{'delay'}; #AUTO, MIN, MAX, DEF, -0.15s to +0.15s
59 0           my $level = $args->{'level'}; #DEF, MIN, MAX, sensor dependent range in dB
60 0           my $hysteresis = $args->{'hysteresis'}; #DEF, MIN, MAX, 0 to 3dB
61 0           my $holdoff = $args->{'holdoff'}; #DEF, MIN, MAX, 1µs to 400ms
62 0           my $slope = $args->{'edge'}; #POS, NEG
63              
64 0 0         if ( $type eq "AUTO" ) {
65 0           $self->write("INIT:CONT ON");
66             }
67             else {
68 0           $self->write("INIT:CONT OFF");
69             }
70              
71 0 0 0       if ( $self->{average_on} && ( $type eq "INT" || $type eq "EXT" ) ) {
      0        
72 0           Lab::Exception::CorruptParameter->throw( error =>
73             "Can't switch to internal or external trigger while average mode is on. Change mode using set_mode(\"NORM\"). Error in U2000::set_trigger(). \n"
74             );
75             }
76 0 0 0       if ( $type eq "INT" || $type eq "EXT" || $type eq "IMM" ) {
    0 0        
    0          
77 0           $self->write("TRIG:SOUR $type");
78 0           $self->{trigger_mode} = $type;
79             }
80             elsif ( $type eq "BUS" ) {
81 0           Lab::Exception::CorruptParameter->throw( error =>
82             "'BUS' trigger mode is not supported by this library in U2000::set_trigger()\n"
83             );
84             }
85             elsif ( $type ne "AUTO" ) {
86 0           Lab::Exception::CorruptParameter->throw(
87             error => "Unknown trigger mode in HP34401A::set_trigger()\n" );
88             }
89              
90 0 0         if ( defined($delay) ) {
91 0 0         if ( $delay eq "AUTO" ) {
92 0           $self->write("TRIG:DEL:AUTO ON");
93             }
94             else {
95 0           $self->write("TRIG:DEL:AUTO OFF");
96 0           $self->write("TRIG:DEL $delay");
97             }
98             }
99              
100 0 0         if ( defined($holdoff) ) {
101 0           $self->write("TRIG:HOLD $holdoff");
102             }
103              
104 0 0         if ( defined($level) ) {
105 0           $self->write("TRIG:LEV $level");
106             }
107              
108 0 0         if ( defined($hysteresis) ) {
109 0           $self->write("TRIG:HYST $hysteresis");
110             }
111              
112 0 0         if ( defined($slope) ) {
113 0           $self->write("TRIG:SLOP $slope");
114             }
115             }
116              
117             sub set_power_unit {
118 0     0 0   my $self = shift;
119 0   0       my $unit = shift || "DBM"; #DBM, W
120 0           $self->write("UNIT:POW $unit");
121             }
122              
123             sub set_average {
124 0     0 0   my $self = shift;
125 0   0       my $count = shift || "AUTO"; #OFF, AUTO, DEF, MIN, MAX, 1 to 1024
126              
127 0 0         if ( $count eq "OFF" ) {
128 0           $self->write("AVER OFF");
129 0           $self->set_mode("NORM");
130 0           return;
131             }
132             else {
133 0           $self->write("AVER ON");
134 0           $self->set_mode("AVER");
135             }
136              
137 0 0         if ( $count eq "AUTO" ) {
138 0           $self->write("AVER:COUN:AUTO ON");
139             }
140             else {
141             #Automatic averaging is disabled by this command
142 0           $self->write("AVER:COUN $count");
143             }
144             }
145              
146             sub set_mode {
147 0     0 0   my $self = shift;
148 0   0       my $mode = shift || "AVER";
149              
150 0 0         if ( $mode eq "AVER" ) {
    0          
151 0           $self->{trigger_mode} = "AUTO";
152             }
153             elsif ( $mode eq "NORM" ) {
154 0 0         if ( $self->{trigger_mode} eq "IMM" ) {
155 0           $self->{trigger_mode} = "INT";
156             }
157             }
158             else {
159 0           Lab::Exception::CorruptParameter->throw(
160             error => "Unknown mode in HP34401A::set_mode()\n" );
161             }
162 0           $self->{average_on} = $mode eq "AVER";
163 0           $self->write("DET:FUNC $mode");
164             }
165              
166             sub set_step_detect {
167 0     0 1   my $self = shift;
168 0   0       my $state = shift || "ON"; # ON, OFF
169 0           $self->write("AVER:SDET $state");
170             }
171              
172             sub set_frequency {
173 0     0 1   my $self = shift;
174 0   0       my $freq = shift || "DEF"; # DEF, MIN, MAX, 1kHz to 1000GHz
175 0           $self->write("FREQ $freq");
176             }
177              
178             sub set_sample_rate {
179 0     0 1   my $self = shift;
180 0   0       my $rate = shift || "NORM"; # MIN, MAX, NORM, DOUBLE, FAST, 1-110
181 0 0 0       if ( $rate =~ /(NORM,DOUB, FAST)/ ) {
    0 0        
    0          
    0          
182 0           $self->write("MRAT $rate");
183             }
184             elsif ( $rate eq "MIN" || $rate <= 20 ) {
185 0           $self->write("MRAT NORM");
186             }
187             elsif ( $rate <= 40 ) {
188 0           $self->write("MRAT DOUB");
189             }
190             elsif ( $rate eq "MAX" || $rate <= 110 ) {
191 0           $self->write("MRAT FAST");
192             }
193             else {
194 0           Lab::Exception::CorruptParameter->throw( error =>
195             "Unsuppoerted sample rate in HP34401A::set_sample_rate()\n" );
196             }
197             }
198              
199             #TODO: Device hangs after a read has timed out and a new read was
200             # issued during which the trigger condition is satisifed.
201             # (in INT trigger mode and possibly others as well)
202             sub read {
203 0     0 1   my $self = shift;
204 0 0         if ( $self->{trigger_mode} eq "AUTO" ) {
    0          
205              
206             #No trigger needed for AUTO MODE
207 0           return $self->query("FETC?");
208             }
209             elsif ( $self->{trigger_mode} eq "IMM" ) {
210              
211             #Automatically send trigger for immediate mode
212 0           return $self->query("READ?");
213             }
214              
215             #TODO: Check other modes
216 0           return $self->query("READ?");
217              
218             }
219              
220             sub get_error {
221 0     0 1   my $self = shift;
222 0           my $current_error = "";
223 0           my $all_errors = "";
224 0           my $max_errors = 5;
225 0           while ( $max_errors-- ) {
226 0           $current_error = $self->query('SYST:ERR?');
227 0 0         if ( $current_error eq "" ) {
228 0           $all_errors .= "Could not read error message!\n";
229 0           last;
230             }
231 0 0         if ( $current_error =~ m/^\+?0,/ ) { last; }
  0            
232 0           $all_errors .= $current_error . "\n";
233             }
234 0 0         if ( !$max_errors ) { $all_errors .= "Maximum Error count reached!\n"; }
  0            
235 0           $self->write("*CLS"); #Clear errors
236 0           chomp($all_errors);
237 0           return $all_errors;
238             }
239              
240             1;
241              
242             __END__
243              
244             =pod
245              
246             =encoding utf-8
247              
248             =head1 NAME
249              
250             Lab::Instrument::U2000 - Agilent U2000 series USB Power Sensor
251              
252             =head1 VERSION
253              
254             version 3.881
255              
256             =head1 DESCRIPTION
257              
258             The Lab::Instrument::U2000 class implements an interface to the U2000 series
259             power sensors from Agilent.
260              
261             =head1 CONSTRUCTOR
262              
263             my $power=new(\%options);
264              
265             =head1 METHODS
266              
267             =head2 get_value
268              
269             $value=$power->read();
270              
271             Read out the current measurement value, for whatever type of measurement
272             the sensor is currently configured. Waits for trigger.
273              
274             =head2 id
275              
276             $id=$power->id();
277              
278             Returns the instruments ID string.
279              
280             =head2 set_sample_rate
281             $power->set_sample_rate(string);
282              
283             Valid values are MIN, MAX, NORM, DOUBLE, FAST and 1-110 (rate in Hz).
284              
285             =head2 set_step_detect
286             $power->set_step_detect(string);
287              
288             Valid values are ON and OFF.
289              
290             =head2 set_frequency
291             $power->set_frequency(string or number)
292              
293             Sets frequency for internal frequency correction (in Hz).
294             Valid values are DEF, MIN, MAX and 1kHz to 1000GHz.
295              
296             =head1 CAVEATS/BUGS
297              
298             Sometimes the sensor hangs for a short amount of time. Very seldom it
299             completely stops working. This is probably either a bug in the firmware or
300             in the kernel driver as not even a reset of the USB port reenable communication.
301              
302             Error handling needs to be improved. Neither timeouts nor errors are handled correctly.
303             Error reporting from the kernel driver is bad.
304              
305             =head1 COPYRIGHT AND LICENSE
306              
307             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
308              
309             Copyright 2012 Hermann Kraus
310             2016 Simon Reinhardt
311             2017 Andreas K. Huettel
312             2020 Andreas K. Huettel
313              
314              
315             This is free software; you can redistribute it and/or modify it under
316             the same terms as the Perl 5 programming language system itself.
317              
318             =cut