| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Lab::Instrument::WR640; | 
| 2 |  |  |  |  |  |  | #ABSTRACT: LeCroy WaveRunner 640 digital oscilloscope | 
| 3 |  |  |  |  |  |  | $Lab::Instrument::WR640::VERSION = '3.880'; | 
| 4 | 1 |  |  | 1 |  | 1758 | use v5.20; | 
|  | 1 |  |  |  |  | 4 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 1 |  |  | 1 |  | 5 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 26 |  | 
| 7 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 8 | 1 |  |  | 1 |  | 8 | use Lab::Instrument; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 19 |  | 
| 9 | 1 |  |  | 1 |  | 4 | use Lab::SCPI; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 80 |  | 
| 10 | 1 |  |  | 1 |  | 7 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 57 |  | 
| 11 | 1 |  |  | 1 |  | 7 | use English; | 
|  | 1 |  |  |  |  | 11 |  | 
|  | 1 |  |  |  |  | 11 |  | 
| 12 | 1 |  |  | 1 |  | 428 | use Time::HiRes qw(sleep); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 13 | 1 |  |  | 1 |  | 95 | use Clone 'clone'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 74 |  | 
| 14 | 1 |  |  | 1 |  | 8 | use Data::Dumper; | 
|  | 1 |  |  |  |  | 5 |  | 
|  | 1 |  |  |  |  | 518 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our $DEBUG   = 0; | 
| 17 |  |  |  |  |  |  | our @ISA     = ("Lab::Instrument"); | 
| 18 |  |  |  |  |  |  | our %fields  = ( | 
| 19 |  |  |  |  |  |  | supported_connections => ['VICP'], | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | #default settings for connections | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | connection_settings => { | 
| 24 |  |  |  |  |  |  | connection_type => 'VICP', | 
| 25 |  |  |  |  |  |  | remote_address  => 'nulrs640', | 
| 26 |  |  |  |  |  |  | }, | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | device_settings => {}, | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | # too many characteristics can easily be "messed with" on the front | 
| 31 |  |  |  |  |  |  | # panel, so only allow changes when scope is "locked". | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | device_cache => {}, | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | chan_cache         => {}, | 
| 36 |  |  |  |  |  |  | default_chan_cache => { | 
| 37 |  |  |  |  |  |  | channel            => undef, | 
| 38 |  |  |  |  |  |  | chan_bwlimit       => undef, | 
| 39 |  |  |  |  |  |  | chan_coupling      => undef, | 
| 40 |  |  |  |  |  |  | chan_current_probe => undef, | 
| 41 |  |  |  |  |  |  | chan_invert        => undef, | 
| 42 |  |  |  |  |  |  | chan_position      => undef, | 
| 43 |  |  |  |  |  |  | chan_probe         => undef, | 
| 44 |  |  |  |  |  |  | chan_scale         => undef, | 
| 45 |  |  |  |  |  |  | chan_yunit         => undef, | 
| 46 |  |  |  |  |  |  | select             => undef, | 
| 47 |  |  |  |  |  |  | }, | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # non-front-panel cache items | 
| 50 |  |  |  |  |  |  | NFP => [ | 
| 51 |  |  |  |  |  |  | qw( | 
| 52 |  |  |  |  |  |  | ID | 
| 53 |  |  |  |  |  |  | HEADER | 
| 54 |  |  |  |  |  |  | VERBOSE | 
| 55 |  |  |  |  |  |  | LOCKED | 
| 56 |  |  |  |  |  |  | ) | 
| 57 |  |  |  |  |  |  | ], | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | shared_cache => { | 
| 60 |  |  |  |  |  |  | ID      => undef, | 
| 61 |  |  |  |  |  |  | HEADER  => undef, | 
| 62 |  |  |  |  |  |  | VERBOSE => undef, | 
| 63 |  |  |  |  |  |  | LOCKED  => undef, | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | }, | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | channel => undef, | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | # almost all of the WR640 command suite is non-SCPI | 
| 70 |  |  |  |  |  |  | scpi_override => { | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | }, | 
| 73 |  |  |  |  |  |  | ); | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | sub new { | 
| 77 | 0 |  |  | 0 | 1 |  | my $proto = shift; | 
| 78 | 0 |  | 0 |  |  |  | my $class = ref($proto) || $proto; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 0 |  |  |  |  |  | foreach my $k ( keys( %{ $fields{default_chan_cache} } ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 81 | 0 |  |  |  |  |  | $fields{device_cache}->{$k} = $fields{default_chan_cache}->{$k}; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 0 |  |  |  |  |  | foreach my $k ( keys( %{ $fields{shared_cache} } ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | $fields{device_cache}->{$k} = $fields{shared_cache}->{$k}; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 0 |  |  |  |  |  | my $self = $class->SUPER::new(@_); | 
| 89 | 0 |  |  |  |  |  | $self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__); | 
|  | 0 |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 |  |  |  |  |  | $self->{config}->{no_cache}          = 1; | 
| 92 | 0 |  |  |  |  |  | $self->{config}->{default_read_mode} = ''; | 
| 93 | 0 | 0 |  |  |  |  | $DEBUG = $self->{config}->{debug} if exists $self->{config}->{debug}; | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | # initialize channel caches | 
| 96 | 0 |  |  |  |  |  | foreach my $ch (qw(C1 C2 C3 C4)) { | 
| 97 | 0 |  |  |  |  |  | $self->{chan_cache}->{$ch} = {}; | 
| 98 | 0 |  |  |  |  |  | foreach my $k ( keys( %{ $self->{default_chan_cache} } ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | $self->{chan_cache}->{$ch}->{$k} | 
| 100 | 0 |  |  |  |  |  | = $self->{default_chan_cache}->{$k}; | 
| 101 |  |  |  |  |  |  | } | 
| 102 | 0 |  |  |  |  |  | $self->{chan_cache}->{$ch}->{channel} = $ch; | 
| 103 | 0 |  |  |  |  |  | foreach my $k ( keys( %{ $self->{shared_cache} } ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 104 | 0 |  |  |  |  |  | $self->{chan_cache}->{$ch}->{$k} = $self->{shared_cache}->{$k}; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 0 |  |  |  |  |  | $self->{device_cache} = $self->{chan_cache}->{C1}; | 
| 109 | 0 |  |  |  |  |  | $self->{channel}      = "C1"; | 
| 110 | 0 |  |  |  |  |  | return $self; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | #initialize scope.. this means setting up status bit masking | 
| 114 |  |  |  |  |  |  | #for non-destructive testing for device errors | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | sub _device_init { | 
| 117 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 118 | 0 |  |  |  |  |  | $self->write("*ESE 60") | 
| 119 |  |  |  |  |  |  | ;    # 0x3C -> CME+EXE+DDE+QYE to bit 5 of SBR (read with *STB?) | 
| 120 | 0 |  |  |  |  |  | $self->write("*CLS");    # clear status registers | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | {                            # keep perl from bitching about this stuff | 
| 124 | 1 |  |  | 1 |  | 8 | no warnings qw(redefine); | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 3889 |  | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | # calling argument parsing; this is an extension of the | 
| 127 |  |  |  |  |  |  | # _check_args and _check_args_strict routines in Instrument.pm, | 
| 128 |  |  |  |  |  |  | # allowing more flexibility in how routines are called. | 
| 129 |  |  |  |  |  |  | # In particular  routine(a=>1,b=>2,..) and | 
| 130 |  |  |  |  |  |  | # routine({a=>1,b=>2,..}) can both be used. | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | # note: if this code does not properly recognize the syntax, | 
| 133 |  |  |  |  |  |  | # then you have to use the {key=>value...} form. | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | # calling: | 
| 136 |  |  |  |  |  |  | #   ($par1,$par2,$par3,$tail) = $self->_Xcheck_args(\@_,qw(par1 par2 par3)); | 
| 137 |  |  |  |  |  |  | # or, for compatibility: | 
| 138 |  |  |  |  |  |  | #   ($par1,$par2,$par3,$tail) = $self->_Xcheck_args(\@_,[qw(par1 par2 par3)]); | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub Lab::Instrument::_check_args { | 
| 141 | 0 |  |  | 0 |  |  | my $self   = shift; | 
| 142 | 0 |  |  |  |  |  | my $args   = shift; | 
| 143 | 0 |  |  |  |  |  | my $params = [@_]; | 
| 144 | 0 | 0 |  |  |  |  | $params = $params->[0] if ref( $params->[0] ) eq 'ARRAY'; | 
| 145 | 0 |  |  |  |  |  | my $arguments = {}; | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 0 | 0 | 0 |  |  |  | if ( $#{$args} == 0 && ref( $args->[0] ) eq 'HASH' ) {    # case 3 | 
|  | 0 |  |  |  |  |  |  | 
| 148 | 0 |  |  |  |  |  | %{$arguments} = ( %{ $args->[0] } ); | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  | else { | 
| 151 | 0 |  |  |  |  |  | my $simple = 1; | 
| 152 | 0 | 0 |  |  |  |  | if ( $#{$args} & 1 == 1 ) {    # must have even # arguments | 
|  | 0 |  |  |  |  |  |  | 
| 153 | 0 |  |  |  |  |  | my $found = {}; | 
| 154 | 0 |  |  |  |  |  | for ( my $j = 0; $j <= $#{$args}; $j += 2 ) { | 
|  | 0 |  |  |  |  |  |  | 
| 155 | 0 | 0 |  |  |  |  | if ( ref( $args->[$j] ) ne '' ) {    # a ref for a key? no | 
| 156 | 0 |  |  |  |  |  | $simple = 1; | 
| 157 | 0 |  |  |  |  |  | last; | 
| 158 |  |  |  |  |  |  | } | 
| 159 | 0 |  |  |  |  |  | foreach my $p ( @{$params} ) {       # named param | 
|  | 0 |  |  |  |  |  |  | 
| 160 | 0 | 0 |  |  |  |  | $simple = 0 if $p eq $args->[$j]; | 
| 161 |  |  |  |  |  |  | } | 
| 162 | 0 | 0 |  |  |  |  | if ( exists( $found->{ $args->[$j] } ) ) | 
| 163 |  |  |  |  |  |  | {                                    # key used 2x? no | 
| 164 | 0 |  |  |  |  |  | $simple = 1; | 
| 165 | 0 |  |  |  |  |  | last; | 
| 166 |  |  |  |  |  |  | } | 
| 167 | 0 |  |  |  |  |  | $found->{ $args->[$j] } = 1; | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 | 0 | 0 |  |  |  |  | if ($simple) {                               # case 1 | 
| 172 | 0 |  |  |  |  |  | my $i = 0; | 
| 173 | 0 |  |  |  |  |  | foreach my $arg ( @{$args} ) { | 
|  | 0 |  |  |  |  |  |  | 
| 174 | 0 | 0 |  |  |  |  | if ( defined @{$params}[$i] ) { | 
|  | 0 |  |  |  |  |  |  | 
| 175 | 0 |  |  |  |  |  | $arguments->{ @{$params}[$i] } = $arg; | 
|  | 0 |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | } | 
| 177 | 0 |  |  |  |  |  | $i++; | 
| 178 |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  | else {                                       # case 2 | 
| 181 | 0 |  |  |  |  |  | %{$arguments} = ( @{$args} ); | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 0 |  |  |  |  |  | my @return_args = (); | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 0 |  |  |  |  |  | foreach my $param ( @{$params} ) { | 
|  | 0 |  |  |  |  |  |  | 
| 188 | 0 | 0 |  |  |  |  | if ( exists $arguments->{$param} ) { | 
| 189 | 0 |  |  |  |  |  | push( @return_args, $arguments->{$param} ); | 
| 190 | 0 |  |  |  |  |  | delete $arguments->{$param}; | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  | else { | 
| 193 | 0 |  |  |  |  |  | push( @return_args, undef ); | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 0 |  |  |  |  |  | push( @return_args, $arguments ); | 
| 198 |  |  |  |  |  |  |  | 
| 199 | 0 | 0 |  |  |  |  | if (wantarray) { | 
| 200 | 0 |  |  |  |  |  | return @return_args; | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  | else { | 
| 203 | 0 |  |  |  |  |  | return $return_args[0]; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub Lab::Instrument::_check_args_strict { | 
| 208 | 0 |  |  | 0 |  |  | my $self   = shift; | 
| 209 | 0 |  |  |  |  |  | my $args   = shift; | 
| 210 | 0 |  |  |  |  |  | my $params = [@_]; | 
| 211 | 0 | 0 |  |  |  |  | $params = $params->[0] if ref( $params->[0] ) eq 'ARRAY'; | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 0 |  |  |  |  |  | my @result = $self->_check_args( $args, $params ); | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 0 |  |  |  |  |  | my $num_params = @result - 1; | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 0 |  |  |  |  |  | for ( my $i = 0; $i < $num_params; ++$i ) { | 
| 218 | 0 | 0 |  |  |  |  | if ( not defined $result[$i] ) { | 
| 219 | 0 |  |  |  |  |  | croak("missing mandatory argument '$params->[$i]'"); | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 0 | 0 |  |  |  |  | if (wantarray) { | 
| 224 | 0 |  |  |  |  |  | return @result; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  | else { | 
| 227 | 0 |  |  |  |  |  | return $result[0]; | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  | # | 
| 233 |  |  |  |  |  |  | # utility function: check header/verbose and parse | 
| 234 |  |  |  |  |  |  | # query reply appropriately; remove quotes in present | 
| 235 |  |  |  |  |  |  | # ex:  $self->_parseReply('ACQ:MODE average',qw{AVE PEAK SAM}) | 
| 236 |  |  |  |  |  |  | #  gives AVE | 
| 237 |  |  |  |  |  |  | sub _parseReply { | 
| 238 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 239 | 0 |  |  |  |  |  | my $in   = shift; | 
| 240 |  |  |  |  |  |  |  | 
| 241 | 0 |  |  |  |  |  | my $h = $self->get_header(); | 
| 242 | 0 | 0 |  |  |  |  | if ($h) { | 
| 243 | 0 |  |  |  |  |  | my $c; | 
| 244 | 0 |  |  |  |  |  | ( $c, $in ) = split( /\s+/, $in ); | 
| 245 | 0 | 0 | 0 |  |  |  | return '' unless defined($in) && $in ne ''; | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | # remove quotes on strings | 
| 249 | 0 | 0 |  |  |  |  | if ( $in =~ /^\"(.*)\"$/ ) { | 
|  |  | 0 |  |  |  |  |  | 
| 250 | 0 |  |  |  |  |  | $in = $1; | 
| 251 | 0 |  |  |  |  |  | $in =~ s/\"\"/"/g; | 
| 252 |  |  |  |  |  |  | } | 
| 253 |  |  |  |  |  |  | elsif ( $in =~ /^\'(.*)\'$/ ) { | 
| 254 | 0 |  |  |  |  |  | $in = $1; | 
| 255 | 0 |  |  |  |  |  | $in =~ s/\'\'/'/g; | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 0 | 0 |  |  |  |  | return $in unless $#_ > -1; | 
| 259 | 0 |  |  |  |  |  | my $v = $self->get_verbose(); | 
| 260 | 0 | 0 |  |  |  |  | return $in unless $v; | 
| 261 | 0 |  |  |  |  |  | return _keyword( $in, @_ ); | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | # | 
| 265 |  |  |  |  |  |  | # select keyword | 
| 266 |  |  |  |  |  |  | #  example:  $got = _keyword('input', qw{ IN OUT EXT } ) | 
| 267 |  |  |  |  |  |  | #  returns $got = 'IN' | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | sub _keyword { | 
| 270 | 0 |  |  | 0 |  |  | my $in = shift; | 
| 271 | 0 | 0 |  |  |  |  | $in = shift if ref($in) eq 'HASH';    # dispose of $self->_keyword form... | 
| 272 | 0 |  |  |  |  |  | my $r; | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 0 |  |  |  |  |  | $in =~ s/^\s+//; | 
| 275 | 0 |  |  |  |  |  | foreach my $k (@_) { | 
| 276 | 0 | 0 |  |  |  |  | if ( $in =~ /^$k/i ) { | 
| 277 | 0 |  |  |  |  |  | return $k; | 
| 278 |  |  |  |  |  |  | } | 
| 279 |  |  |  |  |  |  | } | 
| 280 | 0 |  |  |  |  |  | Lab::Exception::CorruptParameter->throw("Invalid keyword input '$in'\n"); | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | # convert 'short form' keywords to long form | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | sub _bloat { | 
| 286 | 0 |  |  | 0 |  |  | my $in = shift; | 
| 287 | 0 | 0 |  |  |  |  | $in = shift if ref($in) eq 'HASH';    # dispose of $self->_bloat | 
| 288 | 0 |  |  |  |  |  | my $tr = shift;                       # hash of short=>long: | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 0 |  |  |  |  |  | $in =~ s/^\s+//; | 
| 291 | 0 |  |  |  |  |  | $in =~ s/\s+$//; | 
| 292 | 0 | 0 |  |  |  |  | return $in if $in eq ''; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 0 |  |  |  |  |  | foreach my $k ( keys( %{$tr} ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 295 | 0 | 0 |  |  |  |  | if ( $in =~ /^${k}/i ) { | 
| 296 | 0 |  |  |  |  |  | return $tr->{$k}; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 | 0 |  |  |  |  |  | return uc($in);                       # nothing matched | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | # parse a GPIB number with suffix, units | 
| 304 |  |  |  |  |  |  | # $result = _parseNRf($numberstring,$unit1[,$unit2,...]) | 
| 305 |  |  |  |  |  |  | # _parseNRf('maximum','foo) -> 'MAX' | 
| 306 |  |  |  |  |  |  | # _parseNRf('-3.7e+3kJ','j') -> -3.7e6 | 
| 307 |  |  |  |  |  |  | # _parseNRf('2.3ksec','s','sec') -> 2300   ('s' and 'sec' alternate units) | 
| 308 |  |  |  |  |  |  | # note special cases for suffixes: MHZ, MOHM, MA | 
| 309 |  |  |  |  |  |  | # also handling 'dB' -> (number)dB(magnitudesuffix)(unit V|W|etc) | 
| 310 |  |  |  |  |  |  | # | 
| 311 |  |  |  |  |  |  | # if problem, string returned starts 'ERR: ..message...' | 
| 312 |  |  |  |  |  |  | # see IEEE std 488-2 7.7.3 | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | sub _parseNRf { | 
| 315 | 0 |  |  | 0 |  |  | my $in = shift; | 
| 316 | 0 | 0 |  |  |  |  | $in = shift if ref($in) eq 'HASH';    # $self->_parseNRf handling... | 
| 317 | 0 |  |  |  |  |  | my $un = shift; | 
| 318 | 0 | 0 |  |  |  |  | $un = '' unless defined $un; | 
| 319 | 0 |  |  |  |  |  | my $us; | 
| 320 |  |  |  |  |  |  |  | 
| 321 | 0 | 0 |  |  |  |  | if ( ref($un) eq 'ARRAY' ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 322 | 0 |  |  |  |  |  | $us = $un; | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  | elsif ( ref($un) eq 'SCALAR' ) { | 
| 325 | 0 |  |  |  |  |  | $us = [ $$un, @_ ]; | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  | elsif ( ref($un) eq '' ) { | 
| 328 | 0 |  |  |  |  |  | $us = [ $un, @_ ]; | 
| 329 |  |  |  |  |  |  | } | 
| 330 | 0 |  |  |  |  |  | my $str = $in; | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 0 |  |  |  |  |  | $str =~ s/^\s+//; | 
| 333 | 0 |  |  |  |  |  | $str =~ s/\s+$//; | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 0 | 0 |  |  |  |  | if ( $str =~ /^MIN/i ) { | 
| 336 | 0 |  |  |  |  |  | return 'MIN'; | 
| 337 |  |  |  |  |  |  | } | 
| 338 | 0 | 0 |  |  |  |  | if ( $str =~ /^MAX/i ) { | 
| 339 | 0 |  |  |  |  |  | return 'MAX'; | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 0 |  |  |  |  |  | my $mant = 0; | 
| 343 | 0 |  |  |  |  |  | my $exp  = 0; | 
| 344 | 0 | 0 |  |  |  |  | if ( $str =~ /^([+\-]?(\d+\.\d*|\d+|\d*\.\d+))\s*/i ) { | 
| 345 | 0 |  |  |  |  |  | $mant = $1; | 
| 346 | 0 |  |  |  |  |  | $str  = $POSTMATCH; | 
| 347 | 0 | 0 |  |  |  |  | return $mant if $str eq ''; | 
| 348 | 0 | 0 |  |  |  |  | if ( $str =~ /^e\s*([+\-]?\d+)\s*/i ) { | 
| 349 | 0 |  |  |  |  |  | $exp = $1; | 
| 350 | 0 |  |  |  |  |  | $str = $POSTMATCH; | 
| 351 |  |  |  |  |  |  | } | 
| 352 | 0 | 0 |  |  |  |  | return $mant * ( 10**$exp ) if $str eq ''; | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 0 |  |  |  |  |  | my $kexp = $exp; | 
| 355 | 0 |  |  |  |  |  | my $kstr = $str; | 
| 356 | 0 |  |  |  |  |  | foreach my $u ( @{$us} ) { | 
|  | 0 |  |  |  |  |  |  | 
| 357 | 0 |  |  |  |  |  | $u =~ s/^\s+//; | 
| 358 | 0 |  |  |  |  |  | $u =~ s/\s+$//; | 
| 359 |  |  |  |  |  |  |  | 
| 360 | 0 |  |  |  |  |  | $str = $kstr; | 
| 361 | 0 |  |  |  |  |  | $exp = $kexp; | 
| 362 | 0 | 0 |  |  |  |  | if ( $u =~ /^db/i ) {    # db(magnitude_suffix)?(V|W|... unit)? | 
| 363 | 0 |  |  |  |  |  | my $dbt = $POSTMATCH; | 
| 364 | 0 | 0 |  |  |  |  | if ( $str =~ /^dBex(${dbt})?$/i ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 365 | 0 |  |  |  |  |  | $exp += 18; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  | elsif ( $str =~ /^dBpe(${dbt})?$/i ) { | 
| 368 | 0 |  |  |  |  |  | $exp += 15; | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  | elsif ( $str =~ /^dBt(${dbt})?$/i ) { | 
| 371 | 0 |  |  |  |  |  | $exp += 12; | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  | elsif ( $str =~ /^dBg(${dbt})?$/i ) { | 
| 374 | 0 |  |  |  |  |  | $exp += 9; | 
| 375 |  |  |  |  |  |  | } | 
| 376 |  |  |  |  |  |  | elsif ( $str =~ /^dBma(${dbt})$/i ) { | 
| 377 | 0 |  |  |  |  |  | $exp += 6; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  | elsif ( $str =~ /^dBk(${dbt})?$/i ) { | 
| 380 | 0 |  |  |  |  |  | $exp += 3; | 
| 381 |  |  |  |  |  |  | } | 
| 382 |  |  |  |  |  |  | elsif ( $str =~ /^dBm(${dbt})?$/i ) { | 
| 383 | 0 |  |  |  |  |  | $exp -= 3; | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  | elsif ( $str =~ /^dBu(${dbt})?$/i ) { | 
| 386 | 0 |  |  |  |  |  | $exp -= 6; | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  | elsif ( $str =~ /^dBn(${dbt})?$/i ) { | 
| 389 | 0 |  |  |  |  |  | $exp -= 9; | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  | elsif ( $str =~ /^dBp(${dbt})?$/i ) { | 
| 392 | 0 |  |  |  |  |  | $exp -= 12; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  | elsif ( $str =~ /^dBf(${dbt})?$/i ) { | 
| 395 | 0 |  |  |  |  |  | $exp -= 15; | 
| 396 |  |  |  |  |  |  | } | 
| 397 |  |  |  |  |  |  | elsif ( $str =~ /^dB${dbt}$/i ) { | 
| 398 | 0 |  |  |  |  |  | $exp += 0; | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  | else { | 
| 401 | 0 |  |  |  |  |  | next; | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  | else {    # regular units stuff: (magnitude_suffix)(unit)? | 
| 405 | 0 | 0 | 0 |  |  |  | if ( $str =~ /^ex(${u})?$/i ) { | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 406 | 0 |  |  |  |  |  | $exp += 18; | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  | elsif ( $str =~ /^pe(${u})?$/i ) { | 
| 409 | 0 |  |  |  |  |  | $exp += 15; | 
| 410 |  |  |  |  |  |  | } | 
| 411 |  |  |  |  |  |  | elsif ( $str =~ /^t(${u})?$/i ) { | 
| 412 | 0 |  |  |  |  |  | $exp += 12; | 
| 413 |  |  |  |  |  |  | } | 
| 414 |  |  |  |  |  |  | elsif ( $str =~ /^g(${u})?$/i ) { | 
| 415 | 0 |  |  |  |  |  | $exp += 9; | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  | elsif ( $u =~ /(HZ|OHM)/i && $str =~ /^ma?(${u})$/i ) { | 
| 418 | 0 |  |  |  |  |  | $exp += 6; | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  | elsif ( $u =~ /A/i && $str =~ /^ma$/i ) { | 
| 421 | 0 |  |  |  |  |  | $exp -= 3; | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  | elsif ( $u !~ /(HZ|OHM)/i && $str =~ /^ma(${u})?$/i ) { | 
| 424 | 0 |  |  |  |  |  | $exp += 6; | 
| 425 |  |  |  |  |  |  | } | 
| 426 |  |  |  |  |  |  | elsif ( $str =~ /^k(${u})?$/i ) { | 
| 427 | 0 |  |  |  |  |  | $exp += 3; | 
| 428 |  |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  | elsif ( $str =~ /^m(${u})?$/i ) { | 
| 430 | 0 |  |  |  |  |  | $exp -= 3; | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  | elsif ( $str =~ /^u(${u})?$/i ) { | 
| 433 | 0 |  |  |  |  |  | $exp -= 6; | 
| 434 |  |  |  |  |  |  | } | 
| 435 |  |  |  |  |  |  | elsif ( $str =~ /^n(${u})?$/i ) { | 
| 436 | 0 |  |  |  |  |  | $exp -= 9; | 
| 437 |  |  |  |  |  |  | } | 
| 438 |  |  |  |  |  |  | elsif ( $str =~ /^p(${u})?$/i ) { | 
| 439 | 0 |  |  |  |  |  | $exp -= 12; | 
| 440 |  |  |  |  |  |  | } | 
| 441 |  |  |  |  |  |  | elsif ( $str =~ /^f(${u})?$/i ) { | 
| 442 | 0 |  |  |  |  |  | $exp -= 15; | 
| 443 |  |  |  |  |  |  | } | 
| 444 |  |  |  |  |  |  | elsif ( $str =~ /^${u}$/i ) { | 
| 445 | 0 |  |  |  |  |  | $exp += 0; | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  | else { | 
| 448 | 0 |  |  |  |  |  | next; | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  | } | 
| 451 | 0 |  |  |  |  |  | return $mant * ( 10**$exp ); | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  | } | 
| 454 | 0 |  |  |  |  |  | return "ERR: '$str' number parsing problem"; | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | sub reset { | 
| 460 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 461 | 0 |  |  |  |  |  | $self->write("*RST"); | 
| 462 | 0 |  |  |  |  |  | $self->_debug(); | 
| 463 | 0 |  |  |  |  |  | $self->_reset_cache(); | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | our $_rst_state = { | 
| 467 |  |  |  |  |  |  | LOCKED  => 'NON', | 
| 468 |  |  |  |  |  |  | HEADER  => '1', | 
| 469 |  |  |  |  |  |  | VERBOSE => '1', | 
| 470 |  |  |  |  |  |  | }; | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | sub _reset_cache { | 
| 473 | 0 |  |  | 0 |  |  | my $self = shift; | 
| 474 |  |  |  |  |  |  |  | 
| 475 | 0 |  |  |  |  |  | for my $k ( keys( %{$_rst_state} ) ) { | 
|  | 0 |  |  |  |  |  |  | 
| 476 | 0 |  |  |  |  |  | $self->{device_cache}->{$k} = $_rst_state->{$k}; | 
| 477 | 0 |  |  |  |  |  | for ( my $ch = 1; $ch <= 4; $ch++ ) { | 
| 478 | 0 | 0 |  |  |  |  | $self->{chan_cache}->{"CH$ch"}->{select} = ( $ch == 1 ? 1 : 0 ); | 
| 479 | 0 | 0 |  |  |  |  | next if "CH$ch" eq $self->{channel}; | 
| 480 | 0 |  |  |  |  |  | $self->{chan_cache}->{"CH$ch"}->{$k} = $_rst_state->{$k}; | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  | } | 
| 483 | 0 | 0 |  |  |  |  | $self->{device_cache}->{select} = ( $self->{channel} eq 'CH1' ? 1 : 0 ); | 
| 484 | 0 |  |  |  |  |  | foreach my $wfm (qw(MATH REFA REFB REFC REFD)) { | 
| 485 | 0 |  |  |  |  |  | $self->{chan_cache}->{$wfm}->{select} = 0; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  | } | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | # print error queue; meant to be called at end of routine | 
| 490 |  |  |  |  |  |  | # so uses 'caller' info to label the subroutine | 
| 491 |  |  |  |  |  |  | sub _debug { | 
| 492 | 0 | 0 |  | 0 |  |  | return unless $DEBUG; | 
| 493 | 0 |  |  |  |  |  | my $self = shift; | 
| 494 | 0 |  |  |  |  |  | my ( $p, $f, $l, $subr ) = caller(1); | 
| 495 | 0 |  |  |  |  |  | while (1) { | 
| 496 | 0 |  |  |  |  |  | my ( $code, $msg ) = $self->get_error(); | 
| 497 | 0 | 0 |  |  |  |  | last if $code == 0; | 
| 498 | 0 |  |  |  |  |  | print "$subr\t$code: $msg\n"; | 
| 499 |  |  |  |  |  |  | } | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  |  | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | sub get_error { | 
| 504 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 505 |  |  |  |  |  |  |  | 
| 506 | 0 |  |  |  |  |  | my $err = $self->query("CHL? CLR"); | 
| 507 | 0 |  |  |  |  |  | $err =~ s/^(CHL\s*)?\"(.*)\"/$2/is; | 
| 508 | 0 |  |  |  |  |  | my (@lines) = split( /\n/, $err ); | 
| 509 | 0 |  |  |  |  |  | my (@elines) = (); | 
| 510 |  |  |  |  |  |  |  | 
| 511 | 0 |  |  |  |  |  | foreach my $x (@lines) { | 
| 512 | 0 |  |  |  |  |  | $x =~ s/^\s*(.*)\s*$/$1/; | 
| 513 | 0 | 0 |  |  |  |  | next if $x =~ /^connection\s/i; | 
| 514 | 0 | 0 |  |  |  |  | next if $x =~ /^disconnect/i; | 
| 515 | 0 |  |  |  |  |  | push( @elines, $x ); | 
| 516 |  |  |  |  |  |  | } | 
| 517 | 0 |  |  |  |  |  | return (@elines); | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | our $sbits = [qw(OPC RQC QYE DDE EXE CME URQ PON)]; | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | sub get_status { | 
| 525 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 526 | 0 |  |  |  |  |  | my $bit  = shift; | 
| 527 | 0 |  |  |  |  |  | my $s    = {}; | 
| 528 |  |  |  |  |  |  |  | 
| 529 | 0 |  |  |  |  |  | my $r = $self->query('*ESR?'); | 
| 530 | 0 |  |  |  |  |  | $self->_debug(); | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 0 |  |  |  |  |  | for ( my $j = 0; $j < 7; $j++ ) { | 
| 533 | 0 |  |  |  |  |  | $s->{ $sbits->[$j] } = ( $r >> $j ) & 0x01; | 
| 534 |  |  |  |  |  |  | } | 
| 535 | 0 |  |  |  |  |  | $s->{ERROR} = $s->{CME} | $s->{EXE} | $s->{DDE} | $s->{QYE}; | 
| 536 |  |  |  |  |  |  |  | 
| 537 | 0 | 0 |  |  |  |  | return $s->{ uc($bit) } if defined $bit; | 
| 538 | 0 |  |  |  |  |  | return $s; | 
| 539 |  |  |  |  |  |  | } | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | sub test_busy { | 
| 543 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 544 | 0 | 0 |  |  |  |  | return 1 if $self->query('BUSY?') =~ /^(:BUSY )?\s*1/i; | 
| 545 | 0 |  |  |  |  |  | return 0; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  |  | 
| 549 |  |  |  |  |  |  | sub get_id { | 
| 550 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 551 | 0 |  |  |  |  |  | my ($tail) = $self->_check_args( \@_ ); | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | $tail->{read_mode} = $self->{config}->{default_read_mode} | 
| 554 | 0 | 0 | 0 |  |  |  | unless exists( $tail->{read_mode} ) && defined( $tail->{read_mode} ); | 
| 555 |  |  |  |  |  |  |  | 
| 556 | 0 | 0 | 0 |  |  |  | if ( $tail->{read_mode} ne 'cache' | 
| 557 |  |  |  |  |  |  | || !defined( $self->{device_cache}->{ID} ) ) { | 
| 558 | 0 |  |  |  |  |  | $self->{device_cache}->{ID} = $self->query('*IDN?'); | 
| 559 | 0 |  |  |  |  |  | $self->_debug(); | 
| 560 |  |  |  |  |  |  | } | 
| 561 | 0 |  |  |  |  |  | return $self->{device_cache}->{ID}; | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | sub recall { | 
| 566 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 567 | 0 |  |  |  |  |  | my ( $mem, $tail ) = $self->_check_args( \@_, 'n' ); | 
| 568 |  |  |  |  |  |  |  | 
| 569 | 0 |  |  |  |  |  | my $n; | 
| 570 | 0 | 0 |  |  |  |  | if ( $mem =~ /^\s*([0-6])\s/ ) { | 
| 571 | 0 |  |  |  |  |  | $n = $1; | 
| 572 |  |  |  |  |  |  | } | 
| 573 |  |  |  |  |  |  | else { | 
| 574 | 0 |  |  |  |  |  | carp("recall memory n=$mem invalid, should be 0..6"); | 
| 575 | 0 |  |  |  |  |  | return; | 
| 576 |  |  |  |  |  |  | } | 
| 577 | 0 |  |  |  |  |  | $self->write("*RCL $n"); | 
| 578 |  |  |  |  |  |  | } | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | sub get_setup { | 
| 581 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 582 | 0 |  |  |  |  |  | my (@a) = (); | 
| 583 |  |  |  |  |  |  |  | 
| 584 | 0 |  |  |  |  |  | foreach my $ch (qw(C1 C2 C3 C4 EX EX10 ETM10 LINE)) { | 
| 585 | 0 | 0 |  |  |  |  | if ( $ch =~ /C\d/ ) { | 
| 586 | 0 |  |  |  |  |  | foreach my $q (qw(ATTN CPL OFST OFCT TRA TRCP VDIV)) { | 
| 587 | 0 |  |  |  |  |  | push( @a, $self->query( $ch . ':' . $q . '?' ) ); | 
| 588 |  |  |  |  |  |  | } | 
| 589 |  |  |  |  |  |  | } | 
| 590 | 0 | 0 |  |  |  |  | if ( $ch ne 'LINE' ) { | 
| 591 | 0 |  |  |  |  |  | push( @a, $self->query( $ch . ":TRLV?" ) ); | 
| 592 |  |  |  |  |  |  | } | 
| 593 | 0 |  |  |  |  |  | push( @a, $self->query( $ch . ":TRSL?" ) ); | 
| 594 |  |  |  |  |  |  | } | 
| 595 |  |  |  |  |  |  |  | 
| 596 | 0 |  |  |  |  |  | for ( my $j = 1; $j <= 8; $j++ ) { | 
| 597 | 0 |  |  |  |  |  | my $ch = "F$j"; | 
| 598 | 0 |  |  |  |  |  | foreach my $q (qw(TRA VMAG VPOS)) { | 
| 599 | 0 |  |  |  |  |  | push( @a, $self->query( $ch . ":" . $q . "?" ) ); | 
| 600 |  |  |  |  |  |  | } | 
| 601 |  |  |  |  |  |  | } | 
| 602 |  |  |  |  |  |  |  | 
| 603 | 0 |  |  |  |  |  | foreach my $ch (qw(M1 M2 M3 M4)) { | 
| 604 | 0 |  |  |  |  |  | push( @a, $self->query( $ch . ":VPOS?" ) ); | 
| 605 |  |  |  |  |  |  | } | 
| 606 |  |  |  |  |  |  |  | 
| 607 | 0 |  |  |  |  |  | foreach my $q ( | 
| 608 |  |  |  |  |  |  | qw(ALST BWL COUT CMR COMB CFMT CHDR CORD CRMS | 
| 609 |  |  |  |  |  |  | ILVD RCLK SCLK SEQ TDIV TRDL TRMD TRPA | 
| 610 |  |  |  |  |  |  | TRSE WFSU) | 
| 611 |  |  |  |  |  |  | ) { | 
| 612 | 0 |  |  |  |  |  | push( @a, $self->query( $q . '?' ) ); | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  |  | 
| 615 | 0 |  |  |  |  |  | return (@a); | 
| 616 |  |  |  |  |  |  | } | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | sub get_visible { | 
| 619 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 620 | 0 |  |  |  |  |  | my $ch   = shift; | 
| 621 |  |  |  |  |  |  |  | 
| 622 | 0 |  |  |  |  |  | my $r = $self->query("$ch:TRA?"); | 
| 623 | 0 |  |  |  |  |  | $r =~ s/^.*:TRA(ce)?\s+//i; | 
| 624 | 0 |  |  |  |  |  | $r = uc($r); | 
| 625 | 0 | 0 |  |  |  |  | return 1 if $r eq 'ON'; | 
| 626 | 0 |  |  |  |  |  | return 0; | 
| 627 |  |  |  |  |  |  | } | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | sub get_waveform { | 
| 630 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 631 | 0 |  |  |  |  |  | my $ch   = shift; | 
| 632 | 0 |  |  |  |  |  | return $self->query("$ch:WF?"); | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | 1; | 
| 636 |  |  |  |  |  |  |  | 
| 637 |  |  |  |  |  |  | __END__ | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | =pod | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | =encoding UTF-8 | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | =head1 NAME | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | Lab::Instrument::WR640 - LeCroy WaveRunner 640 digital oscilloscope | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | =head1 VERSION | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | version 3.880 | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 652 |  |  |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | =over 4 | 
| 654 |  |  |  |  |  |  |  | 
| 655 |  |  |  |  |  |  | use Lab::Instrument::WR640; | 
| 656 |  |  |  |  |  |  |  | 
| 657 |  |  |  |  |  |  | my $s = new Lab::Instrument::WR640 ( | 
| 658 |  |  |  |  |  |  | address => '192.168.1.1', | 
| 659 |  |  |  |  |  |  | ); | 
| 660 |  |  |  |  |  |  |  | 
| 661 |  |  |  |  |  |  | =back | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | Many of the 'quantities' passed to the code can use scientific | 
| 664 |  |  |  |  |  |  | notation, order of magnitude suffixes ('u', 'm', etc) and unit | 
| 665 |  |  |  |  |  |  | suffixes. The routines can be called using positional parameters | 
| 666 |  |  |  |  |  |  | (check the documentation for order), or with keyword parameters. | 
| 667 |  |  |  |  |  |  |  | 
| 668 |  |  |  |  |  |  | There are a few 'big' routines that let you set many parameters | 
| 669 |  |  |  |  |  |  | in one call, use keyword parameters for those. | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | In general, keywords passed TO these routines are case-independent, | 
| 672 |  |  |  |  |  |  | with only the first few characters being significant. So, in the | 
| 673 |  |  |  |  |  |  | example above: state=>'Run', state=>'running', both work. In cases | 
| 674 |  |  |  |  |  |  | where the keywords distinguish an "on/off" situation (RUN vs STOP | 
| 675 |  |  |  |  |  |  | for acquistion, for example) you can use a Boolean quantity, and | 
| 676 |  |  |  |  |  |  | again, the Boolean values are flexible: | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | =over | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | TRUE = 't' or 'y' or 'on' or number!=0 | 
| 681 |  |  |  |  |  |  |  | 
| 682 |  |  |  |  |  |  | FALSE = 'f' or 'n' or 'off' or number ==0 | 
| 683 |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  | (only the first part of these is checked, case independent) | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | =back | 
| 687 |  |  |  |  |  |  |  | 
| 688 |  |  |  |  |  |  | The oscilloscope input 'channels' are CH1..CH4, but | 
| 689 |  |  |  |  |  |  | there are also MATH, REFA..REFD that can be displayed | 
| 690 |  |  |  |  |  |  | or manipulated.  To perform operations on a channel, one | 
| 691 |  |  |  |  |  |  | should first $s->set_channel($chan);  Channel can be | 
| 692 |  |  |  |  |  |  | specified as 1..4 for the input channels, and it will | 
| 693 |  |  |  |  |  |  | be translated to 'CH1..CH4'. | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | The state of the TDS2024B scope is cached only when the | 
| 696 |  |  |  |  |  |  | front-panel is in a 'locked' state, so that it cannot be | 
| 697 |  |  |  |  |  |  | changed by users fiddling with knobs. | 
| 698 |  |  |  |  |  |  |  | 
| 699 |  |  |  |  |  |  | =head1 GENERAL/SYSTEM ROUTINES | 
| 700 |  |  |  |  |  |  |  | 
| 701 |  |  |  |  |  |  | =head2 new | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | my $s = new Lab::Instrument::TDS2024B( | 
| 704 |  |  |  |  |  |  | usb_serial => '...', | 
| 705 |  |  |  |  |  |  | ); | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | serial only needed if multiple TDS2024B scopes are attached, it | 
| 708 |  |  |  |  |  |  | defaults to '*', which selects the first TDS2024B found.  See | 
| 709 |  |  |  |  |  |  | Lab::Bus::USBtmc.pm documentation for more information. | 
| 710 |  |  |  |  |  |  |  | 
| 711 |  |  |  |  |  |  | =head2 reset | 
| 712 |  |  |  |  |  |  |  | 
| 713 |  |  |  |  |  |  | $s->reset() | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | Reset the oscilloscope (*RST) | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | =head2 get_error | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | ($code,$message) = $s->get_error(); | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | Fetch an error from the device error queue | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | =head2 get_status | 
| 724 |  |  |  |  |  |  |  | 
| 725 |  |  |  |  |  |  | $status = $s->get_status(['statusbit']); | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | Fetches the scope status, and returns either the requested | 
| 728 |  |  |  |  |  |  | status bit (if a 'statusbit' is supplied) or a reference to | 
| 729 |  |  |  |  |  |  | a hash of status information. Reading the status register | 
| 730 |  |  |  |  |  |  | causes it to be cleared.  A status bit 'ERROR' is combined | 
| 731 |  |  |  |  |  |  | from the other error bits. | 
| 732 |  |  |  |  |  |  |  | 
| 733 |  |  |  |  |  |  | Example: $s->get_status('OPC'); | 
| 734 |  |  |  |  |  |  |  | 
| 735 |  |  |  |  |  |  | Example: $s->get_status()->{'DDE'}; | 
| 736 |  |  |  |  |  |  |  | 
| 737 |  |  |  |  |  |  | Status bit names: | 
| 738 |  |  |  |  |  |  |  | 
| 739 |  |  |  |  |  |  | =over | 
| 740 |  |  |  |  |  |  |  | 
| 741 |  |  |  |  |  |  | B<PON>: Power on | 
| 742 |  |  |  |  |  |  |  | 
| 743 |  |  |  |  |  |  | B<URQ>: User Request (not used) | 
| 744 |  |  |  |  |  |  |  | 
| 745 |  |  |  |  |  |  | B<CME>: Command Error | 
| 746 |  |  |  |  |  |  |  | 
| 747 |  |  |  |  |  |  | B<EXE>: Execution Error | 
| 748 |  |  |  |  |  |  |  | 
| 749 |  |  |  |  |  |  | B<DDE>: Device Error | 
| 750 |  |  |  |  |  |  |  | 
| 751 |  |  |  |  |  |  | B<QYE>: Query Error | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | B<RQC>: Request Control (not used) | 
| 754 |  |  |  |  |  |  |  | 
| 755 |  |  |  |  |  |  | B<OPC>: Operation Complete | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | B<ERROR>: CME or EXE or DDE or QYE | 
| 758 |  |  |  |  |  |  |  | 
| 759 |  |  |  |  |  |  | =back | 
| 760 |  |  |  |  |  |  |  | 
| 761 |  |  |  |  |  |  | =head2 test_busy | 
| 762 |  |  |  |  |  |  |  | 
| 763 |  |  |  |  |  |  | $busy = $s->test_busy(); | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  | Returns 1 if busy (waiting for trigger, etc), 0 if not busy. | 
| 766 |  |  |  |  |  |  |  | 
| 767 |  |  |  |  |  |  | =head2 get_id | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | $s->get_id() | 
| 770 |  |  |  |  |  |  |  | 
| 771 |  |  |  |  |  |  | Fetch the *IDN? string from device | 
| 772 |  |  |  |  |  |  |  | 
| 773 |  |  |  |  |  |  | =head2 recall | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  | $s->recall($n); | 
| 776 |  |  |  |  |  |  |  | 
| 777 |  |  |  |  |  |  | $s->recall(n => $n); | 
| 778 |  |  |  |  |  |  |  | 
| 779 |  |  |  |  |  |  | Recall setup 0..6 | 
| 780 |  |  |  |  |  |  |  | 
| 781 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 782 |  |  |  |  |  |  |  | 
| 783 |  |  |  |  |  |  | This software is copyright (c) 2023 by the Lab::Measurement team; in detail: | 
| 784 |  |  |  |  |  |  |  | 
| 785 |  |  |  |  |  |  | Copyright 2016       Charles Lane | 
| 786 |  |  |  |  |  |  | 2017       Andreas K. Huettel | 
| 787 |  |  |  |  |  |  | 2020       Andreas K. Huettel | 
| 788 |  |  |  |  |  |  |  | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 791 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 792 |  |  |  |  |  |  |  | 
| 793 |  |  |  |  |  |  | =cut |