diff --git a/RDI_PD0_IO.pl b/RDI_PD0_IO.pl --- a/RDI_PD0_IO.pl +++ b/RDI_PD0_IO.pl @@ -1,13 +1,13 @@ #====================================================================== -# / D A T A / S R C / O C E A N O G R A P H Y / A D C P _ T O O L S / R D I _ B B _ R E A D . P L +# R D I _ P D 0 _ I O . P L # doc: Sat Jan 18 14:54:43 2003 -# dlm: Thu Feb 27 10:28:29 2020 +# dlm: Sun Apr 12 20:02:30 2020 # (c) 2003 A.M. Thurnherr -# uE-Info: 716 1 NIL 0 0 72 0 2 4 NIL ofnI +# uE-Info: 123 72 NIL 0 0 72 0 2 4 NIL ofnI #====================================================================== - + # Read RDI PD0 binary data files (*.[0-9][0-9][0-9]) - + # HISTORY: # Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS) # Jan 19, 2003: - continued @@ -117,8 +117,12 @@ # - removed old BT_PRESENT code # Jun 28, 2019: - renamed SECONDS to SECOND for consistency # Jun 30, 2019: - added dirty flag to prevent bad PD0 patching -# Feb 13, 2020: - added support for $readDataProgress +# - added $show_progress +# Feb 13, 2020: - added support for $readDataProgress (to Jun 13 version) +# Apr 12, 2020: - merged laptop and whoosher versions which both implemented +# progreass; not sure whether this merge is successful + # FIRMWARE VERSIONS: # It appears that different firmware versions generate different file # structures. Currently (Sep 2005) these routines have been tested @@ -130,7 +134,7 @@ # 16.12 WH300 (1) FSU A0304 53 # 16.21 WH300 (1) LDEO NBP0402 53 # 16.27 WH300 (2) Nash ? 59 - + # PD0 FILE FORMAT EXTENSIONS: # # - file creator encoded in DATA_SOURCE_ID @@ -148,7 +152,7 @@ # - HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading) # # - DATA_SOURCE_ID = 0xE0 produced by editPD0 - + # NOTES: # - RDI stores data in VAX/Intel byte order (little endian) # - the output data structure does not exactly mirror the file data @@ -180,7 +184,7 @@ # - defining the variable "$RDI_PD0_IO::IGNORE_Y2K_CLOCK" before calling &readData() # makes the code ignore the Y2K clock and use the old clock instead; this # is used for Dan Torres' KVH system - + # &readData() returns perl obj (ref to anonymous hash) with the following # structure: # @@ -315,70 +319,72 @@ # BT_SIGNAL_STRENGTH[beam] scalars 0--255 # HIGH_GAIN bool 1, undefined # LOW_GAIN bool 1, undefined - - use strict; - use Time::Local; # timegm() - + +use strict; +use Time::Local; # timegm() + +$RDI_PD0_IO::show_progress = 0; # when set, print . every 1000 ens read + #---------------------------------------------------------------------- # Time Conversion Subroutines # - prepended with _ to avoid conflicts with [libconv.pl] #---------------------------------------------------------------------- - - sub _monthLength($$) # of days in month - { - my($Y,$M) = @_; - - return 31 if ($M==1 || $M==3 || $M==5 || $M==7 || - $M==8 || $M==10 || $M==12); - return 30 if ($M==4 || $M==6 || $M==9 || $M==11); - return 28 if ($Y%4 != 0); - return 29 if ($Y%100 != 0); - return 28 if ($Y%400 > 0); - return 29; - } - - { my($epoch,$lM,$lD,$lY,$ldn); # static scope - - sub _dayNo($$$$$$) - { - my($Y,$M,$D,$h,$m,$s) = @_; - my($dn); - - if ($Y==$lY && $M==$lM && $D==$lD) { # same day as last samp - $dn = $ldn; - } else { # new day - $epoch = $Y unless defined($epoch); # 1st call - $lY = $Y; $lM = $M; $lD = $D; # store - - for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) { # multiple years - $dn += 337 + &_monthLength($Y,$M); - } - - $dn += $D; # day in month - while (--$M > 0) { # preceding months - $dn += &_monthLength($Y,$M); - } - - $ldn = $dn; # store + +sub _monthLength($$) # of days in month +{ + my($Y,$M) = @_; + + return 31 if ($M==1 || $M==3 || $M==5 || $M==7 || + $M==8 || $M==10 || $M==12); + return 30 if ($M==4 || $M==6 || $M==9 || $M==11); + return 28 if ($Y%4 != 0); + return 29 if ($Y%100 != 0); + return 28 if ($Y%400 > 0); + return 29; +} + +{ my($epoch,$lM,$lD,$lY,$ldn); # static scope + + sub _dayNo($$$$$$) + { + my($Y,$M,$D,$h,$m,$s) = @_; + my($dn); + + if ($Y==$lY && $M==$lM && $D==$lD) { # same day as last samp + $dn = $ldn; + } else { # new day + $epoch = $Y unless defined($epoch); # 1st call + $lY = $Y; $lM = $M; $lD = $D; # store + + for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) { # multiple years + $dn += 337 + &_monthLength($Y,$M); } - return $dn + $h/24 + $m/24/60 + $s/24/3600; + + $dn += $D; # day in month + while (--$M > 0) { # preceding months + $dn += &_monthLength($Y,$M); + } + + $ldn = $dn; # store } - - } # static scope - + return $dn + $h/24 + $m/24/60 + $s/24/3600; + } + +} # static scope + #---------------------------------------------------------------------- # Read Data #---------------------------------------------------------------------- - - my($WBRcfn,$WBPcfn); # current file names for reading/patching - my($BIT_errors) = 0; # built-in-test errors - - my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d"; - + +my($WBRcfn,$WBPcfn); # current file names for reading/patching +my($BIT_errors) = 0; # built-in-test errors + +my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d"; + #---------------------------------------------------------------------- # skip to next valid start of ensemble (skip over garbage) #---------------------------------------------------------------------- - + sub goto_next_ens(@) { my($fh,$return_skipped) = @_; # if return_skipped not set, return file pos @@ -392,7 +398,7 @@ if ($dta == 0x7f) { $found++; } elsif ($found==1 && - ($dta==0xE0 || # from editPD0 + ($dta==0xE0 || # from editPD0 (($dta&0xF0)==0xA0 && ($dta&0x0F)<8))) { # from IMP+LADCP or KVH+LADCP $found++; } elsif ($found == 0) { @@ -406,7 +412,7 @@ } my($fpos) = ($found < 2) ? undef : sysseek($fh,-2,1); return $skipped if ($return_skipped); - + if ($skipped) { if (eof($fh)) { # 04/18/18: disabled the following line of code because it is very common at @@ -419,16 +425,16 @@ print(STDERR "WARNING (RDI_PD0_IO): $skipped garbage bytes in PD0 file beginning at byte $garbage_start\n"); } } - + return $fpos; } - + #---------------------------------------------------------------------- # readHeader(file_name,^dta) WBRhdr(^data) # - read header data # - also includes some data from 1st ens #---------------------------------------------------------------------- - + sub readHeader(@) { my($fn,$dta,$suppress_error) = @_; @@ -436,11 +442,11 @@ open(WBRF,$WBRcfn) || die("$WBRcfn: $!"); if (WBRhdr($dta)) { return 1; - } elsif ($suppress_error) { + } elsif ($suppress_error) { return undef; - } else { + } else { die("$WBRcfn: Insufficient data\n"); - } + } } sub WBRhdr($) @@ -505,9 +511,9 @@ $dta->{INSTRUMENT_TYPE} = 'Explorer'; } elsif ($dta->{FIXED_LEADER_BYTES} == 60) { # OS75 $dta->{INSTRUMENT_TYPE} = 'Ocean Surveyor'; - } else { + } else { $dta->{INSTRUMENT_TYPE} = 'unknown'; - } + } #-------------------------------- # Variable Leader: SPEED_OF_SOUND @@ -518,13 +524,13 @@ $id = unpack('v',$buf); if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') { $id == 0x0081 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1); - } else { + } else { $id == 0x0080 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1); - } + } sysseek(WBRF,12,1) || die("$WBRcfn: $!"); # skip up to speed of sound sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); $dta->{SPEED_OF_SOUND} = unpack('v',$buf); - + #-------------------- # FIXED LEADER #-------------------- @@ -546,36 +552,36 @@ if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') { $id == 0x0001 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0); - } else { + } else { $id == 0x0000 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0); - } + } -# $dta->{BEAM_FREQUENCY} = 2**($B1 & 0x07) * 75; # nominal - if (($B1&0x07) == 0b000) { $dta->{BEAM_FREQUENCY} = 76.8; } # actual - elsif (($B1&0x07) == 0b001) { $dta->{BEAM_FREQUENCY} = 153.6; } - elsif (($B1&0x07) == 0b010) { $dta->{BEAM_FREQUENCY} = 307.2; } - elsif (($B1&0x07) == 0b011) { $dta->{BEAM_FREQUENCY} = 614.4; } +# $dta->{BEAM_FREQUENCY} = 2**($B1 & 0x07) * 75; # nominal + if (($B1&0x07) == 0b000) { $dta->{BEAM_FREQUENCY} = 76.8; } # actual + elsif (($B1&0x07) == 0b001) { $dta->{BEAM_FREQUENCY} = 153.6; } + elsif (($B1&0x07) == 0b010) { $dta->{BEAM_FREQUENCY} = 307.2; } + elsif (($B1&0x07) == 0b011) { $dta->{BEAM_FREQUENCY} = 614.4; } elsif (($B1&0x07) == 0b100) { $dta->{BEAM_FREQUENCY} = 1228.8; } elsif (($B1&0x07) == 0b101) { $dta->{BEAM_FREQUENCY} = 2457.6; } else { die(sprintf("$WBRcfn: cannot decode BEAM_FREQUENCY (%03b)\n",$B1&0x07)); } - $dta->{CONVEX_BEAM_PATTERN} = 1 if ($B1 & 0x08); - $dta->{CONCAVE_BEAM_PATTERN} = 1 if (!($B1 & 0x08)); - $dta->{SENSOR_CONFIG} = ($B1 & 0x30) >> 4; - $dta->{XDUCER_HEAD_ATTACHED} = 1 if ($B1 & 0x40); + $dta->{CONVEX_BEAM_PATTERN} = 1 if ($B1 & 0x08); + $dta->{CONCAVE_BEAM_PATTERN} = 1 if (!($B1 & 0x08)); + $dta->{SENSOR_CONFIG} = ($B1 & 0x30) >> 4; + $dta->{XDUCER_HEAD_ATTACHED} = 1 if ($B1 & 0x40); if (($B2 & 0x03) == 0x00) { $dta->{BEAM_ANGLE} = 15; } elsif (($B2 & 0x03) == 0x01) { $dta->{BEAM_ANGLE} = 20; } elsif (($B2 & 0x03) == 0x02) { $dta->{BEAM_ANGLE} = 30; } if (($B2 & 0xF0) == 0x40) { $dta->{N_BEAMS} = 4; } elsif (($B2 & 0xF0) == 0x50) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 3; } - elsif (($B2 & 0xF0) == 0xF0) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 2; } + elsif (($B2 & 0xF0) == 0xF0) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 2; } - $dta->{BIN_LENGTH} /= 100; - $dta->{BLANKING_DISTANCE} /= 100; + $dta->{BIN_LENGTH} /= 100; + $dta->{BLANKING_DISTANCE} /= 100; - $dta->{MAX_ERROR_VELOCITY} /= 1000; - $dta->{TIME_BETWEEN_PINGS} *= 60; + $dta->{MAX_ERROR_VELOCITY} /= 1000; + $dta->{TIME_BETWEEN_PINGS} *= 60; $dta->{TIME_BETWEEN_PINGS} += $B3 + $B4/100; $dta->{BEAM_COORDINATES} = 1 if (($B5 & 0x18) == 0x00); @@ -584,8 +590,8 @@ $dta->{EARTH_COORDINATES} = 1 if (($B5 & 0x18) == 0x18); $dta->{PITCH_AND_ROLL_USED} = 1 if ($B5 & 0x04); $dta->{USE_3_BEAM_ON_LOW_CORR} = 1 if ($B5 & 0x02); - $dta->{BIN_MAPPING_ALLOWED} = 1 if ($B5 & 0x01); - + $dta->{BIN_MAPPING_ALLOWED} = 1 if ($B5 & 0x01); + $dta->{HEADING_ALIGNMENT} = ($dta->{EARTH_COORDINATES} || $dta->{SHIP_COORDINATES}) ? $dta->{HEADING_ALIGNMENT} / 100 : undef; @@ -599,7 +605,7 @@ $dta->{USE_PITCH_SENSOR} = 1 if ($B6 & 0x08); $dta->{USE_ROLL_SENSOR} = 1 if ($B6 & 0x04); $dta->{USE_CONDUCTIVITY_SENSOR} = 1 if ($B6 & 0x02); - $dta->{USE_TEMPERATURE_SENSOR} = 1 if ($B6 & 0x01); + $dta->{USE_TEMPERATURE_SENSOR} = 1 if ($B6 & 0x01); $dta->{SPEED_OF_SOUND_CALCULATED} = 1 if ($B7 & 0x40); $dta->{PRESSURE_SENSOR_AVAILABLE} = 1 if ($B7 & 0x20); @@ -607,14 +613,14 @@ $dta->{PITCH_SENSOR_AVAILABLE} = 1 if ($B7 & 0x08); $dta->{ROLL_SENSOR_AVAILABLE} = 1 if ($B7 & 0x04); $dta->{CONDUCTIVITY_SENSOR_AVAILABLE} = 1 if ($B7 & 0x02); - $dta->{TEMPERATURE_SENSOR_AVAILABLE} = 1 if ($B7 & 0x01); + $dta->{TEMPERATURE_SENSOR_AVAILABLE} = 1 if ($B7 & 0x01); - $dta->{DISTANCE_TO_BIN1_CENTER} /= 100; - $dta->{TRANSMITTED_PULSE_LENGTH} /= 100; + $dta->{DISTANCE_TO_BIN1_CENTER} /= 100; + $dta->{TRANSMITTED_PULSE_LENGTH} /= 100; - $dta->{FALSE_TARGET_THRESHOLD} = undef + $dta->{FALSE_TARGET_THRESHOLD} = undef if ($dta->{FALSE_TARGET_THRESHOLD} == 255); - $dta->{TRANSMIT_LAG_DISTANCE} /= 100; + $dta->{TRANSMIT_LAG_DISTANCE} /= 100; if ($dta->{INSTRUMENT_TYPE} eq 'Workhorse') { sysread(WBRF,$buf,11) == 11 || die("$WBRcfn: $!"); @@ -622,17 +628,17 @@ unpack('vvvvvC',$buf); $dta->{CPU_SERIAL_NUMBER} = sprintf("%04X%04X%04X%04X",$W1,$W2,$W3,$W4); - + $dta->{NARROW_BANDWIDTH} = ($W5 == 1); $dta->{WIDE_BANDWIDTH} = ($W5 == 0); - $dta->{TRANSMIT_POWER_HIGH} = ($dta->{TRANSMIT_POWER} == 255); + $dta->{TRANSMIT_POWER_HIGH} = ($dta->{TRANSMIT_POWER} == 255); - if ($dta->{FIXED_LEADER_BYTES} == 59) { # new style with serial number + if ($dta->{FIXED_LEADER_BYTES} == 59) { # new style with serial number sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!"); - ($dummy,$dta->{SERIAL_NUMBER},$dummy) = # last bytes is beam angle, but that info has - unpack('CVC',$buf); # already been provided above + ($dummy,$dta->{SERIAL_NUMBER},$dummy) = # last bytes is beam angle, but that info has + unpack('CVC',$buf); # already been provided above } - } + } if ($dta->{INSTRUMENT_TYPE} eq 'Explorer') { sysread(WBRF,$buf,16) == 16 || die("$WBRcfn: $!"); @@ -640,13 +646,13 @@ unpack('VVvvV',$buf); $dta->{NARROW_BANDWIDTH} = ($W5 == 1); $dta->{WIDE_BANDWIDTH} = ($W5 == 0); - } + } #----------------------- # 1st ENSEMBLE, BT Setup #----------------------- -# CODE DISABLED BECAUSE BT_PRESENT FLAG WAS REMOVED. WITHOUT THIS CODE, +# CODE DISABLED BECAUSE BT_PRESENT FLAG WAS REMOVED. WITHOUT THIS CODE, # [listHdr] DOES NOT LIST ANY BT INFO # # if ($dta->{BT_PRESENT}) { @@ -659,44 +665,43 @@ # # $id == 0x0600 || # printf(STDERR $FmtErr."\n",$WBRcfn,"Bottom Track",$id,0,tell(WBRF)); -# +# # $dta->{BT_MAX_ERROR_VELOCITY} = # $dta->{BT_MAX_ERROR_VELOCITY} ? $dta->{BT_MAX_ERROR_VELOCITY} / 1000 # : undef; -# +# # sysseek(WBRF,28,1) || die("$WBRcfn: $!"); # sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!"); # ($dta->{BT_RL_MIN_SIZE},$dta->{BT_RL_NEAR},$dta->{BT_RL_FAR}) # = unpack('vvv',$buf); -# +# # $dta->{BT_RL_MIN_SIZE} /= 10; # $dta->{BT_RL_NEAR} /= 10; # $dta->{BT_RL_FAR} /= 10; # # sysseek(WBRF,20,1) || die("$WBRcfn: $!"); # skip data # sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); -# $dta->{BT_MAX_TRACKING_DEPTH} = unpack('v',$buf) / 10; -# } +# $dta->{BT_MAX_TRACKING_DEPTH} = unpack('v',$buf) / 10; +# } - return $dta; + return $dta; } #---------------------------------------------------------------------- # readData(file_name,^data[,first_ens,last_ens[,last_bin]]) -# - read ensembles +# - read ensembles # - read all ensembles unless first_ens and last_ens are given # - read all bins unless last_bin is given -# - if global var $readDataProgress > 0, a . is printed -# every $readaDataProgress ensembles +# - NB: CODE GETS PROGRESSIVELY SLOWER => HUGE PAIN FOR LARGE FILES #---------------------------------------------------------------------- sub readData(@) { my($fn,$dta,$fe,$le,$lb) = @_; $WBRcfn = $fn; - open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n"); - WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n"); - $lb = $dta->{N_BINS} + open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n"); + WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n"); + $lb = $dta->{N_BINS} unless (numberp($lb) && $lb>=1 && $lb<=$dta->{N_BINS}); WBRens($lb,$dta->{FIXED_LEADER_BYTES},\@{$dta->{ENSEMBLE}},$fe,$le); print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n") @@ -710,11 +715,10 @@ my($ens,$ensNo,$dayStart,$ens_length,$hid,$did,$el); local our($ndt,$buf,$id,$start_ens,@WBRofs); - sysseek(WBRF,0,0) || die("$WBRcfn: $!"); + sysseek(WBRF,0,0) || die("$WBRcfn: $!"); ENSEMBLE: for ($ens=0; 1; $ens++) { -# die unless defined($global::readDataProgress); - print(STDERR '.') if ($global::readDataProgress>0 && ($ens%$global::readDataProgress)==0); + print(STDERR '.') if ($RDI_PD0_IO::show_progress && $ens % 1000 == 0); $start_ens = goto_next_ens(\*WBRF); last unless defined($start_ens); @@ -748,7 +752,7 @@ ${$E}[$ens]->{PRODUCER} = 'editPD0 (Thurnherr software)'; } else { ${$E}[$ens]->{PRODUCER} = 'unknown'; - } + } if (defined($ens_length) && ($el != $ens_length)) { $RDI_PD0_IO::File_Dirty = 1; @@ -757,7 +761,7 @@ $ens--; next; } - + $ens_length = $el; ## printf(STDERR "$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last @@ -773,7 +777,7 @@ @WBRofs = unpack("v$ndt",$buf); $fixed_leader_bytes = $WBRofs[1] - $WBRofs[0]; # print(STDERR "@WBRofs\n"); - + #------------------------------- # Make Sure Ensemble is Complete #------------------------------- @@ -794,12 +798,12 @@ # print(STDERR "BAD CHECKSUM\n"); pop(@{$E}); $ens--; next; - } + } #------------------------------ # Variable Leader #------------------------------ - + my($lastEns) = $ensNo; sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!"); @@ -808,10 +812,10 @@ if (${$E}[$ens]->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') { $id == 0x0081 || die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF)))); - } else { + } else { $id == 0x0080 || die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF)))); - } + } # if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) { # BB150 & Explorer DVL (if DISABLED!) sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!"); # always read pre-Y2K clock @@ -836,9 +840,9 @@ next ENSEMBLE; } } - + ${$E}[$ens]->{NUMBER} = $ensNo; - + sysread(WBRF,$buf,30) == 30 || die("$WBRcfn: $!"); (${$E}[$ens]->{BUILT_IN_TEST_ERROR},${$E}[$ens]->{SPEED_OF_SOUND}, ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING}, @@ -862,7 +866,7 @@ #------------------------------------------------- # IMP EXTENSION: PITCH/ROLL/HEADING CAN BE MISSING #------------------------------------------------- - + ${$E}[$ens]->{HEADING} = (${$E}[$ens]->{HEADING} == 0xF000) ? undef : ${$E}[$ens]->{HEADING} / 100; @@ -870,9 +874,9 @@ ? undef : unpack('s',pack('S',${$E}[$ens]->{PITCH})) / 100; ${$E}[$ens]->{ROLL} = (${$E}[$ens]->{ROLL} == 0x8000) - ? undef - : unpack('s',pack('S',${$E}[$ens]->{ROLL})) / 100; - + ? undef + : unpack('s',pack('S',${$E}[$ens]->{ROLL})) / 100; + ${$E}[$ens]->{TEMPERATURE} = unpack('s',pack('S',${$E}[$ens]->{TEMPERATURE})) / 100; ${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} *= 60; ${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} += $B1 + $B2/100; @@ -883,7 +887,7 @@ !defined($RDI_PD0_IO::IGNORE_Y2K_CLOCK)) { sysread(WBRF,$buf,23) == 23 || die("$WBRcfn: $!"); (${$E}[$ens]->{ERROR_STATUS_WORD}, - $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}, + $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}, $dummy,${$E}[$ens]->{YEAR},$B3,${$E}[$ens]->{MONTH}, ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, ${$E}[$ens]->{SECOND},$B4) @@ -895,7 +899,7 @@ ${$E}[$ens]->{SECOND} += $B4/100; } -# THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP +# THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP # TO THE last STATEMENT ABOVE (INCOMPLETE ENSEMBLE) # THE LINE WAS RE-ENABLED ON 12/23/2017 BECAUSE OTHERWISE THE # ANSLOPE II PROFILES IN THE HOWTO CANNOT BE READ. @@ -904,12 +908,12 @@ if ($fixed_leader_bytes == 58) { # Explorer DVL sysread(WBRF,$buf,14) == 14 || die("$WBRcfn: $!"); (${$E}[$ens]->{ERROR_STATUS_WORD}, - $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}) + $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}) = unpack('VvVV',$buf); ${$E}[$ens]->{PRESSURE} /= 1000; ${$E}[$ens]->{PRESSURE_STDDEV} /= 1000; } - + ${$E}[$ens]->{DATE} = sprintf("%02d/%02d/%d",${$E}[$ens]->{MONTH}, ${$E}[$ens]->{DAY}, @@ -928,7 +932,7 @@ if (${$E}[$ens]->{MONTH} == 0) { # no time info ${$E}[$ens]->{UNIX_TIME} = 0; ${$E}[$ens]->{SECNO} = 0; - } else { + } else { # print(STDERR "[$ens]->${$E}[$ens]->{MINUTE}:${$E}[$ens]->{HOUR},${$E}[$ens]->{DAY},${$E}[$ens]->{MONTH},${$E}[$ens]->{YEAR}-<\n"); ${$E}[$ens]->{UNIX_TIME} = timegm(0,${$E}[$ens]->{MINUTE}, @@ -942,16 +946,16 @@ ${$E}[$ens]->{MONTH}-1, ${$E}[$ens]->{YEAR}) unless defined($dayStart); - ${$E}[$ens]->{SECNO} = ${$E}[$ens]->{UNIX_TIME} - $dayStart; - } + ${$E}[$ens]->{SECNO} = ${$E}[$ens]->{UNIX_TIME} - $dayStart; + } - sysseek(WBRF,$start_ens+$WBRofs[0]+4,0) # System Config / Fixed Leader + sysseek(WBRF,$start_ens+$WBRofs[0]+4,0) # System Config / Fixed Leader || die("$WBRcfn: $!"); sysread(WBRF,$buf,5) == 5 || die("$WBRcfn: $!"); ($B1,$dummy,$dummy,$dummy,${$E}[$ens]->{N_BEAMS_USED}) - = unpack('CCCCC',$buf); - ${$E}[$ens]->{XDUCER_FACING_UP} = 1 if ($B1 & 0x80); + = unpack('CCCCC',$buf); + ${$E}[$ens]->{XDUCER_FACING_UP} = 1 if ($B1 & 0x80); ${$E}[$ens]->{XDUCER_FACING_DOWN} = 1 unless ($B1 & 0x80); #-------------------- @@ -963,7 +967,7 @@ my($vel_di) = WBRdtaIndex(0x0100); die("no velocity data in ensemble #$ensNo\n") unless defined($vel_di); - + sysseek(WBRF,$start_ens+$WBRofs[$vel_di],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,2+$ndata*2) == 2+$ndata*2 || die("$WBRcfn: $!"); ($id,@dta) = unpack("vv$ndata",$buf); @@ -983,7 +987,7 @@ my($corr_di) = WBRdtaIndex(0x0200); die("no correlation data in ensemble #$ensNo\n") unless defined($corr_di); - + sysseek(WBRF,$start_ens+$WBRofs[$corr_di],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!"); ($id,@dta) = unpack("vC$ndata",$buf); @@ -1002,7 +1006,7 @@ my($echo_di) = WBRdtaIndex(0x0300); die("no echo intensity data in ensemble #$ensNo\n") unless defined($echo_di); - + sysseek(WBRF,$start_ens+$WBRofs[$echo_di],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!"); ($id,@dta) = unpack("vC$ndata",$buf); @@ -1023,7 +1027,7 @@ my($pctg_di) = WBRdtaIndex(0x0400); die("no percent good data in ensemble #$ensNo\n") unless defined($pctg_di); - + sysseek(WBRF,$start_ens+$WBRofs[$pctg_di],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!"); ($id,@dta) = unpack("vC$ndata",$buf); @@ -1046,7 +1050,7 @@ unless (defined($pctg_di)) { # no BT found => next ens sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!"); next; - } + } sysseek(WBRF,14,1) || die("$WBRcfn: $!"); # BT range, velocity, corr, %-good, ... sysread(WBRF,$buf,28) == 28 || die("$WBRcfn: $!"); @@ -1072,7 +1076,10 @@ } sysseek(WBRF,6,1) || die("$WBRcfn: $!"); # BT ref level stuff - sysread(WBRF,$buf,20) == 20 || die("$WBRcfn: $!"); + if (sysread(WBRF,$buf,20) != 20) { # EN642/PITA1 + pop(@{$E}); + last; + } @dta = unpack('v4C4C4C4',$buf); for ($beam=0; $beam<4; $beam++) { ${$E}[$ens]->{BT_RL_VELOCITY}[$beam] = @@ -1107,8 +1114,8 @@ } sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!"); } # ens loop + print(STDERR "\n") if ($RDI_PD0_IO::show_progress); } -print(STDERR "\n") if ($global::readDataProgress > 0); sub WBRdtaIndex($) {