RDI_PD0_IO.pl
changeset 51 148c092b3a09
parent 50 6bfec705d25e
child 52 5b07a9b89aee
equal deleted inserted replaced
50:6bfec705d25e 51:148c092b3a09
     1 #======================================================================
     1 #======================================================================
     2 #                    / 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 
     2 #                    R D I _ P D 0 _ I O . P L 
     3 #                    doc: Sat Jan 18 14:54:43 2003
     3 #                    doc: Sat Jan 18 14:54:43 2003
     4 #                    dlm: Thu Feb 27 10:28:29 2020
     4 #                    dlm: Sun Apr 12 20:02:30 2020
     5 #                    (c) 2003 A.M. Thurnherr
     5 #                    (c) 2003 A.M. Thurnherr
     6 #					 uE-Info: 716 1 NIL 0 0 72 0 2 4 NIL ofnI
     6 #					 uE-Info: 123 72 NIL 0 0 72 0 2 4 NIL ofnI
     7 #======================================================================
     7 #======================================================================
     8 	
     8     
     9 # Read RDI PD0 binary data files (*.[0-9][0-9][0-9])
     9 # Read RDI PD0 binary data files (*.[0-9][0-9][0-9])
    10 	
    10     
    11 # HISTORY:
    11 # HISTORY:
    12 #	Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS)
    12 #	Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS)
    13 #	Jan 19, 2003: - continued
    13 #	Jan 19, 2003: - continued
    14 #	Jan 20, 2003: - replaced INTENSITY by AMPLITUDE
    14 #	Jan 20, 2003: - replaced INTENSITY by AMPLITUDE
    15 #	Jan 21, 2003: - changed heading-correction field names
    15 #	Jan 21, 2003: - changed heading-correction field names
   115 #	Jun 12, 2018: - BUG: IMPed files did not pass the garbage detection
   115 #	Jun 12, 2018: - BUG: IMPed files did not pass the garbage detection
   116 #	Jun 13, 2019: - adapted reading routines to RTI files (free order of data types)
   116 #	Jun 13, 2019: - adapted reading routines to RTI files (free order of data types)
   117 #				  - removed old BT_PRESENT code
   117 #				  - removed old BT_PRESENT code
   118 #	Jun 28, 2019: - renamed SECONDS to SECOND for consistency
   118 #	Jun 28, 2019: - renamed SECONDS to SECOND for consistency
   119 #	Jun 30, 2019: - added dirty flag to prevent bad PD0 patching
   119 #	Jun 30, 2019: - added dirty flag to prevent bad PD0 patching
   120 #	Feb 13, 2020: - added support for $readDataProgress
   120 #				  - added $show_progress
       
   121 #	Feb 13, 2020: - added support for $readDataProgress (to Jun 13 version)
       
   122 #	Apr 12, 2020: - merged laptop and whoosher versions which both implemented
       
   123 #					progreass; not sure whether this merge is successful
   121 	
   124 	
       
   125     
   122 # FIRMWARE VERSIONS:
   126 # FIRMWARE VERSIONS:
   123 #	It appears that different firmware versions generate different file
   127 #	It appears that different firmware versions generate different file
   124 #	structures. Currently (Sep 2005) these routines have been tested
   128 #	structures. Currently (Sep 2005) these routines have been tested
   125 #	with the following firmware versions (as reported by [listHdr]):
   129 #	with the following firmware versions (as reported by [listHdr]):
   126 #
   130 #
   128 #------------------------------------------------------------
   132 #------------------------------------------------------------
   129 #	05.52	BB150 (1)				UH		CLIVAR/P16S 42
   133 #	05.52	BB150 (1)				UH		CLIVAR/P16S 42
   130 #	16.12	WH300 (1)				FSU 	A0304		53
   134 #	16.12	WH300 (1)				FSU 	A0304		53
   131 #	16.21	WH300 (1)				LDEO	NBP0402 	53
   135 #	16.21	WH300 (1)				LDEO	NBP0402 	53
   132 #	16.27	WH300 (2)				Nash	?			59
   136 #	16.27	WH300 (2)				Nash	?			59
   133 	
   137     
   134 # PD0 FILE FORMAT EXTENSIONS:
   138 # PD0 FILE FORMAT EXTENSIONS:
   135 #
   139 #
   136 #	- file creator encoded in DATA_SOURCE_ID
   140 #	- file creator encoded in DATA_SOURCE_ID
   137 #
   141 #
   138 #	- first ensemble uses default RDI DATA_SOURCE_ID because the LDEO_IX
   142 #	- first ensemble uses default RDI DATA_SOURCE_ID because the LDEO_IX
   146 #		PATCHED_MASK & 0x01:						heading value has been patched
   150 #		PATCHED_MASK & 0x01:						heading value has been patched
   147 #			- PITCH & ROLL can be missing (0x8000 badval as in velocities)
   151 #			- PITCH & ROLL can be missing (0x8000 badval as in velocities)
   148 #			- HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading)
   152 #			- HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading)
   149 #
   153 #
   150 #	- DATA_SOURCE_ID = 0xE0 					produced by editPD0
   154 #	- DATA_SOURCE_ID = 0xE0 					produced by editPD0
   151 	
   155     
   152 # NOTES:
   156 # NOTES:
   153 #	- RDI stores data in VAX/Intel byte order (little endian)
   157 #	- RDI stores data in VAX/Intel byte order (little endian)
   154 #	- the output data structure does not exactly mirror the file data
   158 #	- the output data structure does not exactly mirror the file data
   155 #	  structure; the header is not stored at all and the fixed leader
   159 #	  structure; the header is not stored at all and the fixed leader
   156 #	  data are not duplicated in every ensemble
   160 #	  data are not duplicated in every ensemble
   178 #	  According to the manual (January 2001 version) this would, for example,
   182 #	  According to the manual (January 2001 version) this would, for example,
   179 #	  indicate power failures on both FSU and LDEO slave instruments...
   183 #	  indicate power failures on both FSU and LDEO slave instruments...
   180 #	- defining the variable "$RDI_PD0_IO::IGNORE_Y2K_CLOCK" before calling &readData()
   184 #	- defining the variable "$RDI_PD0_IO::IGNORE_Y2K_CLOCK" before calling &readData()
   181 #	  makes the code ignore the Y2K clock and use the old clock instead; this 
   185 #	  makes the code ignore the Y2K clock and use the old clock instead; this 
   182 #	  is used for Dan Torres' KVH system
   186 #	  is used for Dan Torres' KVH system
   183 	
   187     
   184 # &readData() returns perl obj (ref to anonymous hash) with the following
   188 # &readData() returns perl obj (ref to anonymous hash) with the following
   185 # structure:
   189 # structure:
   186 #
   190 #
   187 #	DATA_SOURCE_ID					scalar		0x7f (Workhorse, also DVL)
   191 #	DATA_SOURCE_ID					scalar		0x7f (Workhorse, also DVL)
   188 #	NUMBER_OF_DATA_TYPES			scalar		6 (no BT) or 7
   192 #	NUMBER_OF_DATA_TYPES			scalar		6 (no BT) or 7
   313 #		BT_RL_ECHO_AMPLITUDE[beam]	scalars 	see ECHO_AMPLITUDE
   317 #		BT_RL_ECHO_AMPLITUDE[beam]	scalars 	see ECHO_AMPLITUDE
   314 #		BT_RL_PERCENT_GOOD[beam]	scalars 	see PERCENT_GOOD
   318 #		BT_RL_PERCENT_GOOD[beam]	scalars 	see PERCENT_GOOD
   315 #		BT_SIGNAL_STRENGTH[beam]	scalars 	0--255
   319 #		BT_SIGNAL_STRENGTH[beam]	scalars 	0--255
   316 #		HIGH_GAIN					bool		1, undefined
   320 #		HIGH_GAIN					bool		1, undefined
   317 #		LOW_GAIN					bool		1, undefined
   321 #		LOW_GAIN					bool		1, undefined
   318 	
   322     
   319 	use strict;
   323 use strict;
   320 	use Time::Local;						# timegm()
   324 use Time::Local;										# timegm()
   321 	
   325 
       
   326 $RDI_PD0_IO::show_progress = 0;							# when set, print . every 1000 ens read
       
   327     
   322 #----------------------------------------------------------------------
   328 #----------------------------------------------------------------------
   323 # Time Conversion Subroutines
   329 # Time Conversion Subroutines
   324 #	- prepended with _ to avoid conflicts with [libconv.pl]
   330 #	- prepended with _ to avoid conflicts with [libconv.pl]
   325 #----------------------------------------------------------------------
   331 #----------------------------------------------------------------------
   326 	
   332     
   327 	sub _monthLength($$) 									# of days in month
   333 sub _monthLength($$)									# of days in month
   328 	{
   334 {
   329 		my($Y,$M) = @_;
   335 	my($Y,$M) = @_;
   330 	
   336 
   331 		return 31 if ($M==1 || $M==3 || $M==5 || $M==7 ||
   337 	return 31 if ($M==1 || $M==3 || $M==5 || $M==7 ||
   332 					  $M==8 || $M==10 || $M==12);
   338 				  $M==8 || $M==10 || $M==12);
   333 		return 30 if ($M==4 || $M==6 || $M==9 || $M==11);
   339 	return 30 if ($M==4 || $M==6 || $M==9 || $M==11);
   334 		return 28 if ($Y%4 != 0);
   340 	return 28 if ($Y%4 != 0);
   335 		return 29 if ($Y%100 != 0);
   341 	return 29 if ($Y%100 != 0);
   336 		return 28 if ($Y%400 > 0);
   342 	return 28 if ($Y%400 > 0);
   337 		return 29;
   343 	return 29;
   338 	}
   344 }
   339 	
   345 
   340 	{ my($epoch,$lM,$lD,$lY,$ldn);							# static scope
   346 { my($epoch,$lM,$lD,$lY,$ldn);							# static scope
   341 	
   347 
   342 	  sub _dayNo($$$$$$)
   348   sub _dayNo($$$$$$)
   343 	  {
   349   {
   344 		  my($Y,$M,$D,$h,$m,$s) = @_;
   350 	  my($Y,$M,$D,$h,$m,$s) = @_;
   345 		  my($dn);
   351 	  my($dn);
   346 	  
   352   
   347 		  if ($Y==$lY && $M==$lM && $D==$lD) {				# same day as last samp
   353 	  if ($Y==$lY && $M==$lM && $D==$lD) {				# same day as last samp
   348 			  $dn = $ldn;
   354 		  $dn = $ldn;
   349 		  } else {											# new day
   355 	  } else {											# new day
   350 			  $epoch = $Y unless defined($epoch);			# 1st call
   356 		  $epoch = $Y unless defined($epoch);			# 1st call
   351 			  $lY = $Y; $lM = $M; $lD = $D; 				# store
   357 		  $lY = $Y; $lM = $M; $lD = $D; 				# store
   352 	  
   358   
   353 			  for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) {	# multiple years
   359 		  for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) {	# multiple years
   354 				  $dn += 337 + &_monthLength($Y,$M);
   360 			  $dn += 337 + &_monthLength($Y,$M);
   355 			  }
       
   356 	  
       
   357 			  $dn += $D;									# day in month
       
   358 			  while (--$M > 0) {							# preceding months
       
   359 				  $dn += &_monthLength($Y,$M);
       
   360 			  }
       
   361 	
       
   362 			  $ldn = $dn;									# store
       
   363 		  }
   361 		  }
   364 		  return $dn + $h/24 + $m/24/60 + $s/24/3600;
   362   
       
   363 		  $dn += $D;									# day in month
       
   364 		  while (--$M > 0) {							# preceding months
       
   365 			  $dn += &_monthLength($Y,$M);
       
   366 		  }
       
   367 
       
   368 		  $ldn = $dn;									# store
   365 	  }
   369 	  }
   366 	
   370 	  return $dn + $h/24 + $m/24/60 + $s/24/3600;
   367 	} # static scope
   371   }
   368 	
   372 
       
   373 } # static scope
       
   374 
   369 #----------------------------------------------------------------------
   375 #----------------------------------------------------------------------
   370 # Read Data
   376 # Read Data
   371 #----------------------------------------------------------------------
   377 #----------------------------------------------------------------------
   372 	
   378 
   373 	my($WBRcfn,$WBPcfn);									# current file names for reading/patching
   379 my($WBRcfn,$WBPcfn);									# current file names for reading/patching
   374 	my($BIT_errors) = 0;									# built-in-test errors
   380 my($BIT_errors) = 0;									# built-in-test errors
   375 	
   381 
   376 	my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d";
   382 my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d";
   377 	
   383     
   378 #----------------------------------------------------------------------
   384 #----------------------------------------------------------------------
   379 # skip to next valid start of ensemble (skip over garbage)
   385 # skip to next valid start of ensemble (skip over garbage)
   380 #----------------------------------------------------------------------
   386 #----------------------------------------------------------------------
   381 	
   387     
   382 sub goto_next_ens(@)
   388 sub goto_next_ens(@)
   383 {
   389 {
   384 	my($fh,$return_skipped) = @_;							# if return_skipped not set, return file pos
   390 	my($fh,$return_skipped) = @_;							# if return_skipped not set, return file pos
   385 	my($buf,$dta);
   391 	my($buf,$dta);
   386 
   392 
   390 		sysread($fh,$buf,1) == 1 || last; 
   396 		sysread($fh,$buf,1) == 1 || last; 
   391 		($dta) = unpack('C',$buf);
   397 		($dta) = unpack('C',$buf);
   392 		if ($dta == 0x7f) {
   398 		if ($dta == 0x7f) {
   393 			$found++;
   399 			$found++;
   394 		} elsif ($found==1 &&
   400 		} elsif ($found==1 &&
   395 					($dta==0xE0	||									# from editPD0
   401 					($dta==0xE0 ||									# from editPD0
   396 					 (($dta&0xF0)==0xA0 && ($dta&0x0F)<8))) {		# from IMP+LADCP or KVH+LADCP
   402 					 (($dta&0xF0)==0xA0 && ($dta&0x0F)<8))) {		# from IMP+LADCP or KVH+LADCP
   397 			$found++;
   403 			$found++;
   398 		} elsif ($found == 0) {
   404 		} elsif ($found == 0) {
   399 			$garbage_start = sysseek($fh,0,1)-1 unless defined($garbage_start);
   405 			$garbage_start = sysseek($fh,0,1)-1 unless defined($garbage_start);
   400 			$skipped++;
   406 			$skipped++;
   404 			$found = 0;
   410 			$found = 0;
   405 		}
   411 		}
   406 	}
   412 	}
   407 	my($fpos) = ($found < 2) ? undef : sysseek($fh,-2,1);
   413 	my($fpos) = ($found < 2) ? undef : sysseek($fh,-2,1);
   408 	return $skipped if ($return_skipped);
   414 	return $skipped if ($return_skipped);
   409 	
   415     
   410 	if ($skipped) {
   416 	if ($skipped) {
   411 		if (eof($fh)) {
   417 		if (eof($fh)) {
   412 #				04/18/18: disabled the following line of code because it is very common at
   418 #				04/18/18: disabled the following line of code because it is very common at
   413 #						  least with the older RDI instruments I am looking at in the context
   419 #						  least with the older RDI instruments I am looking at in the context
   414 #						  of the SR1b repeat section analysis
   420 #						  of the SR1b repeat section analysis
   417 			print(STDERR "WARNING (RDI_PD0_IO): PD0 file starts with $skipped garbage bytes\n");
   423 			print(STDERR "WARNING (RDI_PD0_IO): PD0 file starts with $skipped garbage bytes\n");
   418 		} else {
   424 		} else {
   419 			print(STDERR "WARNING (RDI_PD0_IO): $skipped garbage bytes in PD0 file beginning at byte $garbage_start\n");
   425 			print(STDERR "WARNING (RDI_PD0_IO): $skipped garbage bytes in PD0 file beginning at byte $garbage_start\n");
   420 		}
   426 		}
   421 	}
   427 	}
   422 	
   428     
   423 	return $fpos;
   429 	return $fpos;
   424 }
   430 }
   425 	
   431     
   426 #----------------------------------------------------------------------
   432 #----------------------------------------------------------------------
   427 # readHeader(file_name,^dta) WBRhdr(^data)
   433 # readHeader(file_name,^dta) WBRhdr(^data)
   428 #	- read header data
   434 #	- read header data
   429 #	- also includes some data from 1st ens
   435 #	- also includes some data from 1st ens
   430 #----------------------------------------------------------------------
   436 #----------------------------------------------------------------------
   431 	
   437     
   432 sub readHeader(@)
   438 sub readHeader(@)
   433 {
   439 {
   434 	my($fn,$dta,$suppress_error) = @_;
   440 	my($fn,$dta,$suppress_error) = @_;
   435 	$WBRcfn = $fn;
   441 	$WBRcfn = $fn;
   436 	open(WBRF,$WBRcfn) || die("$WBRcfn: $!");
   442 	open(WBRF,$WBRcfn) || die("$WBRcfn: $!");
   437 	if (WBRhdr($dta)) {
   443 	if (WBRhdr($dta)) {
   438 		return 1;
   444 		return 1;
   439     } elsif ($suppress_error) {
   445 	} elsif ($suppress_error) {
   440 		return undef;
   446 		return undef;
   441     } else {
   447 	} else {
   442 		die("$WBRcfn: Insufficient data\n");
   448 		die("$WBRcfn: Insufficient data\n");
   443     }
   449 	}
   444 }
   450 }
   445 
   451 
   446 sub WBRhdr($)
   452 sub WBRhdr($)
   447 {
   453 {
   448 	my($dta) = @_;
   454 	my($dta) = @_;
   503 		$dta->{INSTRUMENT_TYPE} = 'Workhorse';
   509 		$dta->{INSTRUMENT_TYPE} = 'Workhorse';
   504 	} elsif ($dta->{FIXED_LEADER_BYTES} == 58) {		# DVL
   510 	} elsif ($dta->{FIXED_LEADER_BYTES} == 58) {		# DVL
   505 		$dta->{INSTRUMENT_TYPE} = 'Explorer';
   511 		$dta->{INSTRUMENT_TYPE} = 'Explorer';
   506 	} elsif ($dta->{FIXED_LEADER_BYTES} == 60) {		# OS75
   512 	} elsif ($dta->{FIXED_LEADER_BYTES} == 60) {		# OS75
   507 		$dta->{INSTRUMENT_TYPE} = 'Ocean Surveyor';
   513 		$dta->{INSTRUMENT_TYPE} = 'Ocean Surveyor';
   508     } else {
   514 	} else {
   509 		$dta->{INSTRUMENT_TYPE} = 'unknown';
   515 		$dta->{INSTRUMENT_TYPE} = 'unknown';
   510     }
   516 	}
   511 
   517 
   512 	#--------------------------------
   518 	#--------------------------------
   513 	# Variable Leader: SPEED_OF_SOUND
   519 	# Variable Leader: SPEED_OF_SOUND
   514 	#--------------------------------
   520 	#--------------------------------
   515 
   521 
   516 	sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   522 	sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   517 	sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   523 	sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   518 	$id = unpack('v',$buf);
   524 	$id = unpack('v',$buf);
   519 	if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   525 	if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   520 		$id == 0x0081 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1);
   526 		$id == 0x0081 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1);
   521     } else {
   527 	} else {
   522 		$id == 0x0080 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1);
   528 		$id == 0x0080 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1);
   523     }
   529 	}
   524 	sysseek(WBRF,12,1) || die("$WBRcfn: $!");							# skip up to speed of sound
   530 	sysseek(WBRF,12,1) || die("$WBRcfn: $!");							# skip up to speed of sound
   525 	sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   531 	sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   526 	$dta->{SPEED_OF_SOUND} = unpack('v',$buf);
   532 	$dta->{SPEED_OF_SOUND} = unpack('v',$buf);
   527 	
   533     
   528 	#--------------------
   534 	#--------------------
   529 	# FIXED LEADER
   535 	# FIXED LEADER
   530 	#--------------------
   536 	#--------------------
   531 
   537 
   532 	sysseek(WBRF,$start_ens+$WBRofs[0],0) || die("$WBRcfn: $!");
   538 	sysseek(WBRF,$start_ens+$WBRofs[0],0) || die("$WBRcfn: $!");
   544 	 $dta->{TRANSMIT_LAG_DISTANCE}) =
   550 	 $dta->{TRANSMIT_LAG_DISTANCE}) =
   545 		unpack('vCCCCC3CvvvCCCCvCCCCvvCCvvCCCCv',$buf);
   551 		unpack('vCCCCC3CvvvCCCCvCCCCvvCCvvCCCCv',$buf);
   546 
   552 
   547 	if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   553 	if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   548 		$id == 0x0001 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0);
   554 		$id == 0x0001 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0);
   549     } else {
   555 	} else {
   550 		$id == 0x0000 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0);
   556 		$id == 0x0000 || printf(STDERR $FmtErr."\n",$WBRcfn,"Fixed Leader",$id,0);
   551     }
   557 	}
   552 
   558 
   553 #   $dta->{BEAM_FREQUENCY} = 2**($B1 & 0x07) * 75;						# nominal
   559 #	$dta->{BEAM_FREQUENCY} = 2**($B1 & 0x07) * 75;						# nominal
   554 	if    (($B1&0x07) == 0b000) { $dta->{BEAM_FREQUENCY} =   76.8; }		# actual
   560 	if	  (($B1&0x07) == 0b000) { $dta->{BEAM_FREQUENCY} =	 76.8; }		# actual
   555 	elsif (($B1&0x07) == 0b001) { $dta->{BEAM_FREQUENCY} =  153.6; }
   561 	elsif (($B1&0x07) == 0b001) { $dta->{BEAM_FREQUENCY} =	153.6; }
   556 	elsif (($B1&0x07) == 0b010) { $dta->{BEAM_FREQUENCY} =  307.2; }
   562 	elsif (($B1&0x07) == 0b010) { $dta->{BEAM_FREQUENCY} =	307.2; }
   557 	elsif (($B1&0x07) == 0b011) { $dta->{BEAM_FREQUENCY} =  614.4; }
   563 	elsif (($B1&0x07) == 0b011) { $dta->{BEAM_FREQUENCY} =	614.4; }
   558 	elsif (($B1&0x07) == 0b100) { $dta->{BEAM_FREQUENCY} = 1228.8; }
   564 	elsif (($B1&0x07) == 0b100) { $dta->{BEAM_FREQUENCY} = 1228.8; }
   559 	elsif (($B1&0x07) == 0b101) { $dta->{BEAM_FREQUENCY} = 2457.6; }
   565 	elsif (($B1&0x07) == 0b101) { $dta->{BEAM_FREQUENCY} = 2457.6; }
   560 	else { die(sprintf("$WBRcfn: cannot decode BEAM_FREQUENCY (%03b)\n",$B1&0x07)); }
   566 	else { die(sprintf("$WBRcfn: cannot decode BEAM_FREQUENCY (%03b)\n",$B1&0x07)); }
   561 
   567 
   562     $dta->{CONVEX_BEAM_PATTERN} = 1 if ($B1 & 0x08);
   568 	$dta->{CONVEX_BEAM_PATTERN} = 1 if ($B1 & 0x08);
   563     $dta->{CONCAVE_BEAM_PATTERN} = 1 if (!($B1 & 0x08));
   569 	$dta->{CONCAVE_BEAM_PATTERN} = 1 if (!($B1 & 0x08));
   564     $dta->{SENSOR_CONFIG} = ($B1 & 0x30) >> 4;
   570 	$dta->{SENSOR_CONFIG} = ($B1 & 0x30) >> 4;
   565     $dta->{XDUCER_HEAD_ATTACHED} = 1 if ($B1 & 0x40);
   571 	$dta->{XDUCER_HEAD_ATTACHED} = 1 if ($B1 & 0x40);
   566 
   572 
   567 	if	  (($B2 & 0x03) == 0x00) { $dta->{BEAM_ANGLE} = 15; }
   573 	if	  (($B2 & 0x03) == 0x00) { $dta->{BEAM_ANGLE} = 15; }
   568 	elsif (($B2 & 0x03) == 0x01) { $dta->{BEAM_ANGLE} = 20; }
   574 	elsif (($B2 & 0x03) == 0x01) { $dta->{BEAM_ANGLE} = 20; }
   569 	elsif (($B2 & 0x03) == 0x02) { $dta->{BEAM_ANGLE} = 30; }
   575 	elsif (($B2 & 0x03) == 0x02) { $dta->{BEAM_ANGLE} = 30; }
   570 	if	  (($B2 & 0xF0) == 0x40) { $dta->{N_BEAMS} = 4; }
   576 	if	  (($B2 & 0xF0) == 0x40) { $dta->{N_BEAMS} = 4; }
   571 	elsif (($B2 & 0xF0) == 0x50) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 3; }
   577 	elsif (($B2 & 0xF0) == 0x50) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 3; }
   572     elsif (($B2 & 0xF0) == 0xF0) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 2; }
   578 	elsif (($B2 & 0xF0) == 0xF0) { $dta->{N_BEAMS} = 5; $dta->{N_DEMODS} = 2; }
   573     
   579     
   574     $dta->{BIN_LENGTH} /= 100;
   580 	$dta->{BIN_LENGTH} /= 100;
   575     $dta->{BLANKING_DISTANCE} /= 100;
   581 	$dta->{BLANKING_DISTANCE} /= 100;
   576 
   582 
   577     $dta->{MAX_ERROR_VELOCITY} /= 1000;
   583 	$dta->{MAX_ERROR_VELOCITY} /= 1000;
   578     $dta->{TIME_BETWEEN_PINGS} *= 60;
   584 	$dta->{TIME_BETWEEN_PINGS} *= 60;
   579 	$dta->{TIME_BETWEEN_PINGS} += $B3 + $B4/100;
   585 	$dta->{TIME_BETWEEN_PINGS} += $B3 + $B4/100;
   580 
   586 
   581 	$dta->{BEAM_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x00);
   587 	$dta->{BEAM_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x00);
   582 	$dta->{INSTRUMENT_COORDINATES}	  = 1 if (($B5 & 0x18) == 0x08);
   588 	$dta->{INSTRUMENT_COORDINATES}	  = 1 if (($B5 & 0x18) == 0x08);
   583 	$dta->{SHIP_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x10);
   589 	$dta->{SHIP_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x10);
   584 	$dta->{EARTH_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x18);
   590 	$dta->{EARTH_COORDINATES}		  = 1 if (($B5 & 0x18) == 0x18);
   585 	$dta->{PITCH_AND_ROLL_USED} 	  = 1 if ($B5 & 0x04);
   591 	$dta->{PITCH_AND_ROLL_USED} 	  = 1 if ($B5 & 0x04);
   586 	$dta->{USE_3_BEAM_ON_LOW_CORR}	  = 1 if ($B5 & 0x02);
   592 	$dta->{USE_3_BEAM_ON_LOW_CORR}	  = 1 if ($B5 & 0x02);
   587     $dta->{BIN_MAPPING_ALLOWED}       = 1 if ($B5 & 0x01);
   593 	$dta->{BIN_MAPPING_ALLOWED} 	  = 1 if ($B5 & 0x01);
   588         
   594 	    
   589 	$dta->{HEADING_ALIGNMENT} =
   595 	$dta->{HEADING_ALIGNMENT} =
   590 		($dta->{EARTH_COORDINATES} || $dta->{SHIP_COORDINATES}) ?
   596 		($dta->{EARTH_COORDINATES} || $dta->{SHIP_COORDINATES}) ?
   591 			$dta->{HEADING_ALIGNMENT} / 100 : undef;
   597 			$dta->{HEADING_ALIGNMENT} / 100 : undef;
   592 	$dta->{HEADING_BIAS} =
   598 	$dta->{HEADING_BIAS} =
   593 		($dta->{EARTH_COORDINATES} || $dta->{SHIP_COORDINATES}) ?
   599 		($dta->{EARTH_COORDINATES} || $dta->{SHIP_COORDINATES}) ?
   597 	$dta->{USE_PRESSURE_SENSOR} 	  = 1 if ($B6 & 0x20); 
   603 	$dta->{USE_PRESSURE_SENSOR} 	  = 1 if ($B6 & 0x20); 
   598 	$dta->{USE_COMPASS} 			  = 1 if ($B6 & 0x10); 
   604 	$dta->{USE_COMPASS} 			  = 1 if ($B6 & 0x10); 
   599 	$dta->{USE_PITCH_SENSOR}		  = 1 if ($B6 & 0x08); 
   605 	$dta->{USE_PITCH_SENSOR}		  = 1 if ($B6 & 0x08); 
   600 	$dta->{USE_ROLL_SENSOR} 		  = 1 if ($B6 & 0x04); 
   606 	$dta->{USE_ROLL_SENSOR} 		  = 1 if ($B6 & 0x04); 
   601 	$dta->{USE_CONDUCTIVITY_SENSOR}   = 1 if ($B6 & 0x02); 
   607 	$dta->{USE_CONDUCTIVITY_SENSOR}   = 1 if ($B6 & 0x02); 
   602     $dta->{USE_TEMPERATURE_SENSOR}    = 1 if ($B6 & 0x01); 
   608 	$dta->{USE_TEMPERATURE_SENSOR}	  = 1 if ($B6 & 0x01); 
   603 
   609 
   604 	$dta->{SPEED_OF_SOUND_CALCULATED}	  = 1 if ($B7 & 0x40); 
   610 	$dta->{SPEED_OF_SOUND_CALCULATED}	  = 1 if ($B7 & 0x40); 
   605 	$dta->{PRESSURE_SENSOR_AVAILABLE}	  = 1 if ($B7 & 0x20); 
   611 	$dta->{PRESSURE_SENSOR_AVAILABLE}	  = 1 if ($B7 & 0x20); 
   606 	$dta->{COMPASS_AVAILABLE}			  = 1 if ($B7 & 0x10); 
   612 	$dta->{COMPASS_AVAILABLE}			  = 1 if ($B7 & 0x10); 
   607 	$dta->{PITCH_SENSOR_AVAILABLE}		  = 1 if ($B7 & 0x08); 
   613 	$dta->{PITCH_SENSOR_AVAILABLE}		  = 1 if ($B7 & 0x08); 
   608 	$dta->{ROLL_SENSOR_AVAILABLE}		  = 1 if ($B7 & 0x04); 
   614 	$dta->{ROLL_SENSOR_AVAILABLE}		  = 1 if ($B7 & 0x04); 
   609 	$dta->{CONDUCTIVITY_SENSOR_AVAILABLE} = 1 if ($B7 & 0x02); 
   615 	$dta->{CONDUCTIVITY_SENSOR_AVAILABLE} = 1 if ($B7 & 0x02); 
   610     $dta->{TEMPERATURE_SENSOR_AVAILABLE}  = 1 if ($B7 & 0x01); 
   616 	$dta->{TEMPERATURE_SENSOR_AVAILABLE}  = 1 if ($B7 & 0x01); 
   611 
   617 
   612     $dta->{DISTANCE_TO_BIN1_CENTER}  /= 100;
   618 	$dta->{DISTANCE_TO_BIN1_CENTER}  /= 100;
   613     $dta->{TRANSMITTED_PULSE_LENGTH} /= 100;
   619 	$dta->{TRANSMITTED_PULSE_LENGTH} /= 100;
   614 
   620 
   615     $dta->{FALSE_TARGET_THRESHOLD} = undef
   621 	$dta->{FALSE_TARGET_THRESHOLD} = undef
   616 		if ($dta->{FALSE_TARGET_THRESHOLD} == 255);
   622 		if ($dta->{FALSE_TARGET_THRESHOLD} == 255);
   617     $dta->{TRANSMIT_LAG_DISTANCE} /= 100;
   623 	$dta->{TRANSMIT_LAG_DISTANCE} /= 100;
   618 
   624 
   619 	if ($dta->{INSTRUMENT_TYPE} eq 'Workhorse') {
   625 	if ($dta->{INSTRUMENT_TYPE} eq 'Workhorse') {
   620 		sysread(WBRF,$buf,11) == 11 || die("$WBRcfn: $!");
   626 		sysread(WBRF,$buf,11) == 11 || die("$WBRcfn: $!");
   621 		($W1,$W2,$W3,$W4,$W5,$dta->{TRANSMIT_POWER}) = 
   627 		($W1,$W2,$W3,$W4,$W5,$dta->{TRANSMIT_POWER}) = 
   622 			unpack('vvvvvC',$buf);
   628 			unpack('vvvvvC',$buf);
   623 
   629 
   624 		$dta->{CPU_SERIAL_NUMBER} = sprintf("%04X%04X%04X%04X",$W1,$W2,$W3,$W4);
   630 		$dta->{CPU_SERIAL_NUMBER} = sprintf("%04X%04X%04X%04X",$W1,$W2,$W3,$W4);
   625 	
   631     
   626 		$dta->{NARROW_BANDWIDTH} = ($W5 == 1);
   632 		$dta->{NARROW_BANDWIDTH} = ($W5 == 1);
   627 		$dta->{WIDE_BANDWIDTH}	 = ($W5 == 0);
   633 		$dta->{WIDE_BANDWIDTH}	 = ($W5 == 0);
   628 	    $dta->{TRANSMIT_POWER_HIGH} = ($dta->{TRANSMIT_POWER} == 255);
   634 		$dta->{TRANSMIT_POWER_HIGH} = ($dta->{TRANSMIT_POWER} == 255);
   629 
   635 
   630 		if ($dta->{FIXED_LEADER_BYTES} == 59) {					# new style with serial number
   636 		if ($dta->{FIXED_LEADER_BYTES} == 59) { 				# new style with serial number
   631 			sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   637 			sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   632 			($dummy,$dta->{SERIAL_NUMBER},$dummy) =				# last bytes is beam angle, but that info has
   638 			($dummy,$dta->{SERIAL_NUMBER},$dummy) = 			# last bytes is beam angle, but that info has
   633 				unpack('CVC',$buf);								# already been provided above
   639 				unpack('CVC',$buf); 							# already been provided above
   634 		}
   640 		}
   635     }
   641 	}
   636 
   642 
   637 	if ($dta->{INSTRUMENT_TYPE} eq 'Explorer') {
   643 	if ($dta->{INSTRUMENT_TYPE} eq 'Explorer') {
   638 		sysread(WBRF,$buf,16) == 16 || die("$WBRcfn: $!");
   644 		sysread(WBRF,$buf,16) == 16 || die("$WBRcfn: $!");
   639 		($dummy,$dummy,$W5,$dummy,$dta->{SERIAL_NUMBER}) = 
   645 		($dummy,$dummy,$W5,$dummy,$dta->{SERIAL_NUMBER}) = 
   640 			unpack('VVvvV',$buf);
   646 			unpack('VVvvV',$buf);
   641 		$dta->{NARROW_BANDWIDTH} = ($W5 == 1);
   647 		$dta->{NARROW_BANDWIDTH} = ($W5 == 1);
   642 		$dta->{WIDE_BANDWIDTH}	 = ($W5 == 0);
   648 		$dta->{WIDE_BANDWIDTH}	 = ($W5 == 0);
   643     }
   649 	}
   644 
   650 
   645 	#-----------------------
   651 	#-----------------------
   646 	# 1st ENSEMBLE, BT Setup
   652 	# 1st ENSEMBLE, BT Setup
   647 	#-----------------------
   653 	#-----------------------
   648 
   654 
   649 # 	CODE DISABLED BECAUSE BT_PRESENT FLAG WAS REMOVED. WITHOUT THIS CODE,
   655 #	CODE DISABLED BECAUSE BT_PRESENT FLAG WAS REMOVED. WITHOUT THIS CODE,
   650 #	[listHdr] DOES NOT LIST ANY BT INFO
   656 #	[listHdr] DOES NOT LIST ANY BT INFO
   651 #
   657 #
   652 #	if ($dta->{BT_PRESENT}) {
   658 #	if ($dta->{BT_PRESENT}) {
   653 #		sysseek(WBRF,$start_ens+$WBRofs[$BT_dt],0) || die("$WBRcfn: $!");
   659 #		sysseek(WBRF,$start_ens+$WBRofs[$BT_dt],0) || die("$WBRcfn: $!");
   654 #		sysread(WBRF,$buf,12) == 12 || die("$WBRcfn: $!");
   660 #		sysread(WBRF,$buf,12) == 12 || die("$WBRcfn: $!");
   657 #		 $dta->{BT_MIN_PERCENT_GOOD},$dta->{BT_MODE},
   663 #		 $dta->{BT_MIN_PERCENT_GOOD},$dta->{BT_MODE},
   658 #		 $dta->{BT_MAX_ERROR_VELOCITY}) = unpack('vvvCCCCv',$buf);
   664 #		 $dta->{BT_MAX_ERROR_VELOCITY}) = unpack('vvvCCCCv',$buf);
   659 #		 
   665 #		 
   660 #		$id == 0x0600 ||
   666 #		$id == 0x0600 ||
   661 #			printf(STDERR $FmtErr."\n",$WBRcfn,"Bottom Track",$id,0,tell(WBRF));
   667 #			printf(STDERR $FmtErr."\n",$WBRcfn,"Bottom Track",$id,0,tell(WBRF));
   662 #	
   668 #   
   663 #		$dta->{BT_MAX_ERROR_VELOCITY} =
   669 #		$dta->{BT_MAX_ERROR_VELOCITY} =
   664 #			$dta->{BT_MAX_ERROR_VELOCITY} ? $dta->{BT_MAX_ERROR_VELOCITY} / 1000
   670 #			$dta->{BT_MAX_ERROR_VELOCITY} ? $dta->{BT_MAX_ERROR_VELOCITY} / 1000
   665 #										  : undef;
   671 #										  : undef;
   666 #	
   672 #   
   667 #		sysseek(WBRF,28,1) || die("$WBRcfn: $!");
   673 #		sysseek(WBRF,28,1) || die("$WBRcfn: $!");
   668 #		sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   674 #		sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   669 #		($dta->{BT_RL_MIN_SIZE},$dta->{BT_RL_NEAR},$dta->{BT_RL_FAR})
   675 #		($dta->{BT_RL_MIN_SIZE},$dta->{BT_RL_NEAR},$dta->{BT_RL_FAR})
   670 #			= unpack('vvv',$buf);
   676 #			= unpack('vvv',$buf);
   671 #	
   677 #   
   672 #		$dta->{BT_RL_MIN_SIZE} /= 10;
   678 #		$dta->{BT_RL_MIN_SIZE} /= 10;
   673 #		$dta->{BT_RL_NEAR} /= 10;
   679 #		$dta->{BT_RL_NEAR} /= 10;
   674 #		$dta->{BT_RL_FAR} /= 10;
   680 #		$dta->{BT_RL_FAR} /= 10;
   675 #	    
   681 #	    
   676 #		sysseek(WBRF,20,1) || die("$WBRcfn: $!");		# skip data
   682 #		sysseek(WBRF,20,1) || die("$WBRcfn: $!");		# skip data
   677 #		sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   683 #		sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!");
   678 #	    $dta->{BT_MAX_TRACKING_DEPTH} = unpack('v',$buf) / 10;
   684 #		$dta->{BT_MAX_TRACKING_DEPTH} = unpack('v',$buf) / 10;
   679 #    }
   685 #	 }
   680     
   686     
   681     return $dta;
   687 	return $dta;
   682 }
   688 }
   683 
   689 
   684 #----------------------------------------------------------------------
   690 #----------------------------------------------------------------------
   685 # readData(file_name,^data[,first_ens,last_ens[,last_bin]]) 
   691 # readData(file_name,^data[,first_ens,last_ens[,last_bin]]) 
   686 # 	- read ensembles
   692 #	- read ensembles
   687 #	- read all ensembles unless first_ens and last_ens are given
   693 #	- read all ensembles unless first_ens and last_ens are given
   688 #	- read all bins unless last_bin is given
   694 #	- read all bins unless last_bin is given
   689 #	- if global var $readDataProgress > 0, a . is printed
   695 #	- NB: CODE GETS PROGRESSIVELY SLOWER => HUGE PAIN FOR LARGE FILES
   690 #	  every $readaDataProgress ensembles
       
   691 #----------------------------------------------------------------------
   696 #----------------------------------------------------------------------
   692 
   697 
   693 sub readData(@)
   698 sub readData(@)
   694 {
   699 {
   695 	my($fn,$dta,$fe,$le,$lb) = @_;
   700 	my($fn,$dta,$fe,$le,$lb) = @_;
   696 	$WBRcfn = $fn;
   701 	$WBRcfn = $fn;
   697     open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n");
   702 	open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n");
   698     WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n");
   703 	WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n");
   699     $lb = $dta->{N_BINS}
   704 	$lb = $dta->{N_BINS}
   700 		unless (numberp($lb) && $lb>=1 && $lb<=$dta->{N_BINS});
   705 		unless (numberp($lb) && $lb>=1 && $lb<=$dta->{N_BINS});
   701 	WBRens($lb,$dta->{FIXED_LEADER_BYTES},\@{$dta->{ENSEMBLE}},$fe,$le);
   706 	WBRens($lb,$dta->{FIXED_LEADER_BYTES},\@{$dta->{ENSEMBLE}},$fe,$le);
   702 	print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n")
   707 	print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n")
   703 		if ($BIT_errors);
   708 		if ($BIT_errors);
   704 }
   709 }
   708 	my($nbins,$fixed_leader_bytes,$E,$fe,$le) = @_;
   713 	my($nbins,$fixed_leader_bytes,$E,$fe,$le) = @_;
   709 	my($B1,$B2,$B3,$B4,$I,$bin,$beam,$dummy,@dta,$i,$cs);
   714 	my($B1,$B2,$B3,$B4,$I,$bin,$beam,$dummy,@dta,$i,$cs);
   710 	my($ens,$ensNo,$dayStart,$ens_length,$hid,$did,$el);
   715 	my($ens,$ensNo,$dayStart,$ens_length,$hid,$did,$el);
   711 	local our($ndt,$buf,$id,$start_ens,@WBRofs);
   716 	local our($ndt,$buf,$id,$start_ens,@WBRofs);
   712 
   717 
   713     sysseek(WBRF,0,0) || die("$WBRcfn: $!");
   718 	sysseek(WBRF,0,0) || die("$WBRcfn: $!");
   714 ENSEMBLE:
   719 ENSEMBLE:
   715 	for ($ens=0; 1; $ens++) {
   720 	for ($ens=0; 1; $ens++) {
   716 #		die unless defined($global::readDataProgress);
   721 		print(STDERR '.') if ($RDI_PD0_IO::show_progress && $ens % 1000 == 0);
   717 		print(STDERR '.') if ($global::readDataProgress>0 && ($ens%$global::readDataProgress)==0);
       
   718 		$start_ens = goto_next_ens(\*WBRF);
   722 		$start_ens = goto_next_ens(\*WBRF);
   719 		last unless defined($start_ens);
   723 		last unless defined($start_ens);
   720 
   724 
   721 		#----------------------------------------
   725 		#----------------------------------------
   722 		# Handle first_ens and last_ens
   726 		# Handle first_ens and last_ens
   746 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
   750 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
   747 		} elsif ($did&0xF0 == 0xE0) {
   751 		} elsif ($did&0xF0 == 0xE0) {
   748 			${$E}[$ens]->{PRODUCER} = 'editPD0 (Thurnherr software)';
   752 			${$E}[$ens]->{PRODUCER} = 'editPD0 (Thurnherr software)';
   749 		} else {
   753 		} else {
   750 			${$E}[$ens]->{PRODUCER} = 'unknown';
   754 			${$E}[$ens]->{PRODUCER} = 'unknown';
   751 	    }
   755 		}
   752 
   756 
   753 		if (defined($ens_length) && ($el != $ens_length)) {
   757 		if (defined($ens_length) && ($el != $ens_length)) {
   754 			$RDI_PD0_IO::File_Dirty = 1;
   758 			$RDI_PD0_IO::File_Dirty = 1;
   755 			print(STDERR "WARNING (RDI_PD0_IO): ensemble ${$E}[$#{$E}]->{NUMBER} skipped (unexpected length)\n");
   759 			print(STDERR "WARNING (RDI_PD0_IO): ensemble ${$E}[$#{$E}]->{NUMBER} skipped (unexpected length)\n");
   756 			pop(@{$E});
   760 			pop(@{$E});
   757 			$ens--;
   761 			$ens--;
   758 			next;
   762 			next;
   759 		}
   763 		}
   760 		
   764 	    
   761 		$ens_length = $el;
   765 		$ens_length = $el;
   762 
   766 
   763 ##		printf(STDERR "$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last
   767 ##		printf(STDERR "$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last
   764 ##				unless ($ndt == 6 || $ndt == 7);
   768 ##				unless ($ndt == 6 || $ndt == 7);
   765 		my($nread) = sysread(WBRF,$buf,2*$ndt);						# 2019 EPR test
   769 		my($nread) = sysread(WBRF,$buf,2*$ndt);						# 2019 EPR test
   771 
   775 
   772 
   776 
   773 		@WBRofs = unpack("v$ndt",$buf);
   777 		@WBRofs = unpack("v$ndt",$buf);
   774 		$fixed_leader_bytes = $WBRofs[1] - $WBRofs[0];
   778 		$fixed_leader_bytes = $WBRofs[1] - $WBRofs[0];
   775 #		print(STDERR "@WBRofs\n");
   779 #		print(STDERR "@WBRofs\n");
   776 	
   780     
   777 		#-------------------------------
   781 		#-------------------------------
   778 		# Make Sure Ensemble is Complete
   782 		# Make Sure Ensemble is Complete
   779 		#-------------------------------
   783 		#-------------------------------
   780 
   784 
   781 		# UH BB150 writes incomplete ensembles (i.e. short read
   785 		# UH BB150 writes incomplete ensembles (i.e. short read
   792 
   796 
   793 		unless (unpack('%16C*',$buf) == unpack('v',$cs)) {						# bad checksum
   797 		unless (unpack('%16C*',$buf) == unpack('v',$cs)) {						# bad checksum
   794 #			print(STDERR "BAD CHECKSUM\n");
   798 #			print(STDERR "BAD CHECKSUM\n");
   795 			pop(@{$E}); $ens--;
   799 			pop(@{$E}); $ens--;
   796 			next;
   800 			next;
   797 		}		
   801 		}	    
   798 
   802 
   799 		#------------------------------
   803 		#------------------------------
   800 		# Variable Leader
   804 		# Variable Leader
   801 		#------------------------------
   805 		#------------------------------
   802 	
   806     
   803 		my($lastEns) = $ensNo;
   807 		my($lastEns) = $ensNo;
   804 		sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   808 		sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   805 		sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!");
   809 		sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!");
   806 		($id,$ensNo) = unpack("vv",$buf);										# only lower two bytes!!!
   810 		($id,$ensNo) = unpack("vv",$buf);										# only lower two bytes!!!
   807 
   811 
   808 		if (${$E}[$ens]->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   812 		if (${$E}[$ens]->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') {
   809 			$id == 0x0081 ||
   813 			$id == 0x0081 ||
   810 				die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF))));
   814 				die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF))));
   811         } else {
   815 		} else {
   812 			$id == 0x0080 ||
   816 			$id == 0x0080 ||
   813 				die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF))));
   817 				die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF))));
   814         }
   818 		}
   815 
   819 
   816 #		if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) {				# BB150 & Explorer DVL (if DISABLED!)
   820 #		if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) {				# BB150 & Explorer DVL (if DISABLED!)
   817 			sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!");					# always read pre-Y2K clock
   821 			sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!");					# always read pre-Y2K clock
   818 			(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},
   822 			(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},
   819 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   823 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   834 				pop(@{$E});
   838 				pop(@{$E});
   835 				$ens--;
   839 				$ens--;
   836 				next ENSEMBLE;
   840 				next ENSEMBLE;
   837 			}
   841 			}
   838 		}
   842 		}
   839 			
   843 		    
   840 		${$E}[$ens]->{NUMBER} = $ensNo;
   844 		${$E}[$ens]->{NUMBER} = $ensNo;
   841 		
   845 	    
   842 		sysread(WBRF,$buf,30) == 30 || die("$WBRcfn: $!");
   846 		sysread(WBRF,$buf,30) == 30 || die("$WBRcfn: $!");
   843 		(${$E}[$ens]->{BUILT_IN_TEST_ERROR},${$E}[$ens]->{SPEED_OF_SOUND},
   847 		(${$E}[$ens]->{BUILT_IN_TEST_ERROR},${$E}[$ens]->{SPEED_OF_SOUND},
   844 		 ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING},
   848 		 ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING},
   845 		 ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL},
   849 		 ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL},
   846 		 ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE},
   850 		 ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE},
   860 		${$E}[$ens]->{XDUCER_DEPTH} /= 10;
   864 		${$E}[$ens]->{XDUCER_DEPTH} /= 10;
   861 
   865 
   862 		#-------------------------------------------------
   866 		#-------------------------------------------------
   863 		# IMP EXTENSION: PITCH/ROLL/HEADING CAN BE MISSING
   867 		# IMP EXTENSION: PITCH/ROLL/HEADING CAN BE MISSING
   864 		#-------------------------------------------------
   868 		#-------------------------------------------------
   865 		
   869 	    
   866 		${$E}[$ens]->{HEADING} = (${$E}[$ens]->{HEADING} == 0xF000)
   870 		${$E}[$ens]->{HEADING} = (${$E}[$ens]->{HEADING} == 0xF000)
   867 							   ? undef
   871 							   ? undef
   868 							   : ${$E}[$ens]->{HEADING} / 100;
   872 							   : ${$E}[$ens]->{HEADING} / 100;
   869 		${$E}[$ens]->{PITCH} = (${$E}[$ens]->{PITCH} == 0x8000)
   873 		${$E}[$ens]->{PITCH} = (${$E}[$ens]->{PITCH} == 0x8000)
   870 							 ? undef
   874 							 ? undef
   871 							 : unpack('s',pack('S',${$E}[$ens]->{PITCH})) / 100;
   875 							 : unpack('s',pack('S',${$E}[$ens]->{PITCH})) / 100;
   872 		${$E}[$ens]->{ROLL}  = (${$E}[$ens]->{ROLL} == 0x8000)
   876 		${$E}[$ens]->{ROLL}  = (${$E}[$ens]->{ROLL} == 0x8000)
   873                              ? undef
   877 							 ? undef
   874                              : unpack('s',pack('S',${$E}[$ens]->{ROLL})) / 100;
   878 							 : unpack('s',pack('S',${$E}[$ens]->{ROLL})) / 100;
   875                              
   879 							 
   876 		${$E}[$ens]->{TEMPERATURE} = unpack('s',pack('S',${$E}[$ens]->{TEMPERATURE})) / 100;
   880 		${$E}[$ens]->{TEMPERATURE} = unpack('s',pack('S',${$E}[$ens]->{TEMPERATURE})) / 100;
   877 		${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} *= 60;
   881 		${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} *= 60;
   878 		${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} += $B1 + $B2/100;
   882 		${$E}[$ens]->{MIN_PRE_PING_WAIT_TIME} += $B1 + $B2/100;
   879 		${$E}[$ens]->{PITCH_STDDEV} /= 10;
   883 		${$E}[$ens]->{PITCH_STDDEV} /= 10;
   880 		${$E}[$ens]->{ROLL_STDDEV} /= 10;
   884 		${$E}[$ens]->{ROLL_STDDEV} /= 10;
   881 
   885 
   882 		if (($fixed_leader_bytes==53 || $fixed_leader_bytes==59) && 		# Workhorse instruments
   886 		if (($fixed_leader_bytes==53 || $fixed_leader_bytes==59) && 		# Workhorse instruments
   883 			!defined($RDI_PD0_IO::IGNORE_Y2K_CLOCK)) {
   887 			!defined($RDI_PD0_IO::IGNORE_Y2K_CLOCK)) {
   884 			sysread(WBRF,$buf,23) == 23 || die("$WBRcfn: $!");
   888 			sysread(WBRF,$buf,23) == 23 || die("$WBRcfn: $!");
   885 			(${$E}[$ens]->{ERROR_STATUS_WORD},
   889 			(${$E}[$ens]->{ERROR_STATUS_WORD},
   886 		 	 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV},
   890 			 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV},
   887 			 $dummy,${$E}[$ens]->{YEAR},$B3,${$E}[$ens]->{MONTH},
   891 			 $dummy,${$E}[$ens]->{YEAR},$B3,${$E}[$ens]->{MONTH},
   888 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   892 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   889 			 ${$E}[$ens]->{SECOND},$B4)
   893 			 ${$E}[$ens]->{SECOND},$B4)
   890 				= unpack('VvVVCCCCCCCCC',$buf);
   894 				= unpack('VvVVCCCCCCCCC',$buf);
   891 
   895 
   893 			${$E}[$ens]->{PRESSURE_STDDEV} /= 1000;
   897 			${$E}[$ens]->{PRESSURE_STDDEV} /= 1000;
   894 			${$E}[$ens]->{YEAR} *= 100; ${$E}[$ens]->{YEAR} += $B3;
   898 			${$E}[$ens]->{YEAR} *= 100; ${$E}[$ens]->{YEAR} += $B3;
   895 			${$E}[$ens]->{SECOND} += $B4/100;
   899 			${$E}[$ens]->{SECOND} += $B4/100;
   896 		}
   900 		}
   897 
   901 
   898 # 		THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP
   902 #		THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP
   899 #		TO THE last STATEMENT ABOVE (INCOMPLETE ENSEMBLE)
   903 #		TO THE last STATEMENT ABOVE (INCOMPLETE ENSEMBLE)
   900 #		THE LINE WAS RE-ENABLED ON 12/23/2017 BECAUSE OTHERWISE THE
   904 #		THE LINE WAS RE-ENABLED ON 12/23/2017 BECAUSE OTHERWISE THE
   901 #		ANSLOPE II PROFILES IN THE HOWTO CANNOT BE READ.
   905 #		ANSLOPE II PROFILES IN THE HOWTO CANNOT BE READ.
   902 		pop(@{$E}),last if (${$E}[$ens]->{MONTH}>12);						# 10/15/2014; IWISE#145 UL ???
   906 		pop(@{$E}),last if (${$E}[$ens]->{MONTH}>12);						# 10/15/2014; IWISE#145 UL ???
   903 
   907 
   904 		if ($fixed_leader_bytes == 58) {									# Explorer DVL
   908 		if ($fixed_leader_bytes == 58) {									# Explorer DVL
   905 			sysread(WBRF,$buf,14) == 14 || die("$WBRcfn: $!");
   909 			sysread(WBRF,$buf,14) == 14 || die("$WBRcfn: $!");
   906 			(${$E}[$ens]->{ERROR_STATUS_WORD},
   910 			(${$E}[$ens]->{ERROR_STATUS_WORD},
   907 		 	 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV})
   911 			 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV})
   908 				= unpack('VvVV',$buf);
   912 				= unpack('VvVV',$buf);
   909 			${$E}[$ens]->{PRESSURE} /= 1000;
   913 			${$E}[$ens]->{PRESSURE} /= 1000;
   910 			${$E}[$ens]->{PRESSURE_STDDEV} /= 1000;
   914 			${$E}[$ens]->{PRESSURE_STDDEV} /= 1000;
   911 		}
   915 		}
   912 		
   916 	    
   913 		${$E}[$ens]->{DATE}
   917 		${$E}[$ens]->{DATE}
   914 			= sprintf("%02d/%02d/%d",${$E}[$ens]->{MONTH},
   918 			= sprintf("%02d/%02d/%d",${$E}[$ens]->{MONTH},
   915 									 ${$E}[$ens]->{DAY},
   919 									 ${$E}[$ens]->{DAY},
   916 									 ${$E}[$ens]->{YEAR});
   920 									 ${$E}[$ens]->{YEAR});
   917 		${$E}[$ens]->{TIME}
   921 		${$E}[$ens]->{TIME}
   926 		# I noticed that there is no time information. This causes
   930 		# I noticed that there is no time information. This causes
   927 		# timegm to bomb. 
   931 		# timegm to bomb. 
   928 		if (${$E}[$ens]->{MONTH} == 0) {					# no time info
   932 		if (${$E}[$ens]->{MONTH} == 0) {					# no time info
   929 			${$E}[$ens]->{UNIX_TIME} = 0;
   933 			${$E}[$ens]->{UNIX_TIME} = 0;
   930 			${$E}[$ens]->{SECNO} = 0;
   934 			${$E}[$ens]->{SECNO} = 0;
   931         } else {
   935 		} else {
   932 #			print(STDERR "[$ens]->${$E}[$ens]->{MINUTE}:${$E}[$ens]->{HOUR},${$E}[$ens]->{DAY},${$E}[$ens]->{MONTH},${$E}[$ens]->{YEAR}-<\n");
   936 #			print(STDERR "[$ens]->${$E}[$ens]->{MINUTE}:${$E}[$ens]->{HOUR},${$E}[$ens]->{DAY},${$E}[$ens]->{MONTH},${$E}[$ens]->{YEAR}-<\n");
   933 			${$E}[$ens]->{UNIX_TIME}
   937 			${$E}[$ens]->{UNIX_TIME}
   934 				= timegm(0,${$E}[$ens]->{MINUTE},
   938 				= timegm(0,${$E}[$ens]->{MINUTE},
   935 						   ${$E}[$ens]->{HOUR},
   939 						   ${$E}[$ens]->{HOUR},
   936 						   ${$E}[$ens]->{DAY},
   940 						   ${$E}[$ens]->{DAY},
   940 	
   944 	
   941 			$dayStart = timegm(0,0,0,${$E}[$ens]->{DAY},
   945 			$dayStart = timegm(0,0,0,${$E}[$ens]->{DAY},
   942 									 ${$E}[$ens]->{MONTH}-1,
   946 									 ${$E}[$ens]->{MONTH}-1,
   943 									 ${$E}[$ens]->{YEAR})
   947 									 ${$E}[$ens]->{YEAR})
   944 				unless defined($dayStart);
   948 				unless defined($dayStart);
   945 	        ${$E}[$ens]->{SECNO} = ${$E}[$ens]->{UNIX_TIME} - $dayStart;
   949 			${$E}[$ens]->{SECNO} = ${$E}[$ens]->{UNIX_TIME} - $dayStart;
   946         }
   950 		}
   947 
   951 
   948 		sysseek(WBRF,$start_ens+$WBRofs[0]+4,0)		# System Config / Fixed Leader
   952 		sysseek(WBRF,$start_ens+$WBRofs[0]+4,0) 	# System Config / Fixed Leader
   949 			|| die("$WBRcfn: $!");
   953 			|| die("$WBRcfn: $!");
   950 
   954 
   951 		sysread(WBRF,$buf,5) == 5 || die("$WBRcfn: $!");
   955 		sysread(WBRF,$buf,5) == 5 || die("$WBRcfn: $!");
   952 		($B1,$dummy,$dummy,$dummy,${$E}[$ens]->{N_BEAMS_USED})
   956 		($B1,$dummy,$dummy,$dummy,${$E}[$ens]->{N_BEAMS_USED})
   953 			= unpack('CCCCC',$buf);		
   957 			= unpack('CCCCC',$buf);     
   954 		${$E}[$ens]->{XDUCER_FACING_UP}   = 1 if     ($B1 & 0x80);
   958 		${$E}[$ens]->{XDUCER_FACING_UP}   = 1 if	 ($B1 & 0x80);
   955 		${$E}[$ens]->{XDUCER_FACING_DOWN} = 1 unless ($B1 & 0x80);
   959 		${$E}[$ens]->{XDUCER_FACING_DOWN} = 1 unless ($B1 & 0x80);
   956 
   960 
   957 		#--------------------
   961 		#--------------------
   958 		# Velocity Data
   962 		# Velocity Data
   959 		#--------------------
   963 		#--------------------
   961 		my($ndata) = $nbins * 4;
   965 		my($ndata) = $nbins * 4;
   962 
   966 
   963 		my($vel_di) = WBRdtaIndex(0x0100);
   967 		my($vel_di) = WBRdtaIndex(0x0100);
   964 		die("no velocity data in ensemble #$ensNo\n")
   968 		die("no velocity data in ensemble #$ensNo\n")
   965 			unless defined($vel_di);
   969 			unless defined($vel_di);
   966 		
   970 	    
   967 		sysseek(WBRF,$start_ens+$WBRofs[$vel_di],0) || die("$WBRcfn: $!");
   971 		sysseek(WBRF,$start_ens+$WBRofs[$vel_di],0) || die("$WBRcfn: $!");
   968 		sysread(WBRF,$buf,2+$ndata*2) == 2+$ndata*2 || die("$WBRcfn: $!");
   972 		sysread(WBRF,$buf,2+$ndata*2) == 2+$ndata*2 || die("$WBRcfn: $!");
   969 		($id,@dta) = unpack("vv$ndata",$buf);
   973 		($id,@dta) = unpack("vv$ndata",$buf);
   970 
   974 
   971 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   975 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   981 		#--------------------
   985 		#--------------------
   982 
   986 
   983 		my($corr_di) = WBRdtaIndex(0x0200);
   987 		my($corr_di) = WBRdtaIndex(0x0200);
   984 		die("no correlation data in ensemble #$ensNo\n")
   988 		die("no correlation data in ensemble #$ensNo\n")
   985 			unless defined($corr_di);
   989 			unless defined($corr_di);
   986 		
   990 	    
   987 		sysseek(WBRF,$start_ens+$WBRofs[$corr_di],0) || die("$WBRcfn: $!");
   991 		sysseek(WBRF,$start_ens+$WBRofs[$corr_di],0) || die("$WBRcfn: $!");
   988 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   992 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   989 		($id,@dta) = unpack("vC$ndata",$buf);
   993 		($id,@dta) = unpack("vC$ndata",$buf);
   990 
   994 
   991 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   995 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
  1000 		#--------------------
  1004 		#--------------------
  1001 
  1005 
  1002 		my($echo_di) = WBRdtaIndex(0x0300);
  1006 		my($echo_di) = WBRdtaIndex(0x0300);
  1003 		die("no echo intensity data in ensemble #$ensNo\n")
  1007 		die("no echo intensity data in ensemble #$ensNo\n")
  1004 			unless defined($echo_di);
  1008 			unless defined($echo_di);
  1005 		
  1009 	    
  1006 		sysseek(WBRF,$start_ens+$WBRofs[$echo_di],0) || die("$WBRcfn: $!");
  1010 		sysseek(WBRF,$start_ens+$WBRofs[$echo_di],0) || die("$WBRcfn: $!");
  1007 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
  1011 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
  1008 		($id,@dta) = unpack("vC$ndata",$buf);
  1012 		($id,@dta) = unpack("vC$ndata",$buf);
  1009 
  1013 
  1010 		$id == 0x0300 ||
  1014 		$id == 0x0300 ||
  1021 		#--------------------
  1025 		#--------------------
  1022 
  1026 
  1023 		my($pctg_di) = WBRdtaIndex(0x0400);
  1027 		my($pctg_di) = WBRdtaIndex(0x0400);
  1024 		die("no percent good data in ensemble #$ensNo\n")
  1028 		die("no percent good data in ensemble #$ensNo\n")
  1025 			unless defined($pctg_di);
  1029 			unless defined($pctg_di);
  1026 		
  1030 	    
  1027 		sysseek(WBRF,$start_ens+$WBRofs[$pctg_di],0) || die("$WBRcfn: $!");
  1031 		sysseek(WBRF,$start_ens+$WBRofs[$pctg_di],0) || die("$WBRcfn: $!");
  1028 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
  1032 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
  1029 		($id,@dta) = unpack("vC$ndata",$buf);
  1033 		($id,@dta) = unpack("vC$ndata",$buf);
  1030 
  1034 
  1031 		$id == 0x0400 ||
  1035 		$id == 0x0400 ||
  1044 
  1048 
  1045 		my($bt_di) = WBRdtaIndex(0x0600);
  1049 		my($bt_di) = WBRdtaIndex(0x0600);
  1046 		unless (defined($pctg_di)) {											# no BT found => next ens
  1050 		unless (defined($pctg_di)) {											# no BT found => next ens
  1047 			sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!");
  1051 			sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!");
  1048 			next;
  1052 			next;
  1049         }		
  1053 		}	    
  1050 
  1054 
  1051 		sysseek(WBRF,14,1) || die("$WBRcfn: $!");								# BT range, velocity, corr, %-good, ...
  1055 		sysseek(WBRF,14,1) || die("$WBRcfn: $!");								# BT range, velocity, corr, %-good, ...
  1052 		sysread(WBRF,$buf,28) == 28 || die("$WBRcfn: $!");
  1056 		sysread(WBRF,$buf,28) == 28 || die("$WBRcfn: $!");
  1053 		@dta = unpack('v4v4C4C4C4',$buf);
  1057 		@dta = unpack('v4v4C4C4C4',$buf);
  1054 		for ($beam=0; $beam<4; $beam++) {
  1058 		for ($beam=0; $beam<4; $beam++) {
  1070 		for ($beam=0; $beam<4; $beam++) {
  1074 		for ($beam=0; $beam<4; $beam++) {
  1071 			${$E}[$ens]->{BT_PERCENT_GOOD}[$beam] = $dta[16+$beam];
  1075 			${$E}[$ens]->{BT_PERCENT_GOOD}[$beam] = $dta[16+$beam];
  1072 		}
  1076 		}
  1073 
  1077 
  1074 		sysseek(WBRF,6,1) || die("$WBRcfn: $!");								# BT ref level stuff
  1078 		sysseek(WBRF,6,1) || die("$WBRcfn: $!");								# BT ref level stuff
  1075 		sysread(WBRF,$buf,20) == 20 || die("$WBRcfn: $!");
  1079 		if (sysread(WBRF,$buf,20) != 20) {										# EN642/PITA1
       
  1080 			pop(@{$E});
       
  1081 			last;
       
  1082 		}
  1076 		@dta = unpack('v4C4C4C4',$buf);
  1083 		@dta = unpack('v4C4C4C4',$buf);
  1077 		for ($beam=0; $beam<4; $beam++) {
  1084 		for ($beam=0; $beam<4; $beam++) {
  1078 			${$E}[$ens]->{BT_RL_VELOCITY}[$beam] =
  1085 			${$E}[$ens]->{BT_RL_VELOCITY}[$beam] =
  1079 				unpack('s',pack('S',$dta[$beam])) / 1000
  1086 				unpack('s',pack('S',$dta[$beam])) / 1000
  1080 					if ($dta[$beam] != 0x8000);
  1087 					if ($dta[$beam] != 0x8000);
  1105 			}
  1112 			}
  1106 #			sysseek(WBRF,8,1) || die("$WBRcfn: $!");							# remainder of ensemble
  1113 #			sysseek(WBRF,8,1) || die("$WBRcfn: $!");							# remainder of ensemble
  1107         }
  1114         }
  1108         sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!");
  1115         sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!");
  1109 	} # ens loop
  1116 	} # ens loop
       
  1117 	print(STDERR "\n") if ($RDI_PD0_IO::show_progress);
  1110 }
  1118 }
  1111 print(STDERR "\n") if ($global::readDataProgress > 0);
       
  1112 
  1119 
  1113 sub WBRdtaIndex($)
  1120 sub WBRdtaIndex($)
  1114 {
  1121 {
  1115 	my($trgid) = @_;
  1122 	my($trgid) = @_;
  1116 	our($ndt,$buf,$id,$start_ens,@WBRofs);
  1123 	our($ndt,$buf,$id,$start_ens,@WBRofs);