RDI_PD0_IO.pl
changeset 31 b6ca27a1d19c
parent 29 aeb26e966b71
child 32 7155adf61d77
--- a/RDI_PD0_IO.pl
+++ b/RDI_PD0_IO.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    R D I _ P D 0 _ I O . P L 
 #                    doc: Sat Jan 18 14:54:43 2003
-#                    dlm: Sat Jan  9 13:22:46 2016
+#                    dlm: Sat Jan  9 17:57:01 2016
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 70 34 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 73 64 NIL 0 0 72 10 2 4 NIL ofnI
 #======================================================================
 
 # Read RDI BroadBand Binary Data Files (*.[0-9][0-9][0-9])
@@ -66,8 +66,11 @@
 #	Oct  2, 2015: - added &skip_initial_trash()
 #	Dec 18, 2015: - added most data types to WBPofs()
 #				  - BUG: WBPens() requires round() for scaled values
-#	Jan  9, 2016: - BUG: WBRhdr() did not set DATA_SOURCE_ID
+#	Jan  9, 2016: - removed system() from writeData()
+#				  - BUG: WBRhdr() did not set DATA_SOURCE_ID
 #				  - added PRODUCER
+#				  - BUG: writeData() did not work correctly for ECOGIG OC26 moored data (spaces in filename?)
+#				  - added support for patching coordinate system
 
 # FIRMWARE VERSIONS:
 #	It appears that different firmware versions generate different file
@@ -92,7 +95,7 @@
 #			- PITCH & ROLL can be missing (0x8000 badval as in velocities)
 #			- HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading)
 #
-#	- DATA_SOURCE_ID = 0xB0 					produced by editPD0
+#	- DATA_SOURCE_ID = 0xE0 					produced by editPD0
 
 # NOTES:
 #	- RDI stores data in VAX/Intel byte order (little endian)
@@ -333,6 +336,8 @@
 		($dta) = unpack('C',$buf);
 		if ($dta == 0x7f) {
 			$found++;
+		} elsif ($found==1 && ($dta==0xE0 || ($dta&0xF0==0xA0 && $dta&0x0F<8))) {
+			$found++;
 		} elsif ($found == 0) {
 			$skipped++;
 		} else {
@@ -379,12 +384,12 @@
 	$dta->{DATA_SOURCE_ID} = $did;
 	if ($did == 0x7f) {
 		$dta->{PRODUCER} = 'TRDI ADCP';
-	} elsif ($did&0xF0 == 0xA0) {
-		$dta->{PRODUCER} = 'IMP+LADCP';
-	} elsif ($did&0xF0 == 0xB0) {
-		$dta->{PRODUCER} = 'editPD0';
+	} elsif (($did&0xF0) == 0xA0) {
+		$dta->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
+	} elsif (($did&0xF0) == 0xE0) {
+		$dta->{PRODUCER} = 'editPD0 (Thurnherr software)';
 	} else {
-		$dta->{PRODUCER} = 'unknown';
+		$dta->{PRODUCER} = sprintf('unknown (0x%02X)');
 	}
 
 	printf(STDERR "WARNING: unexpected number of data types (%d)\n",
@@ -652,7 +657,7 @@
 			${$E}[$ens]->{PRODUCER} = 'TRDI ADCP';
 		} elsif ($did&0xF0 == 0xA0) {
 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
-		} elsif ($did&0xF0 == 0xB0) {
+		} elsif ($did&0xF0 == 0xE0) {
 			${$E}[$ens]->{PRODUCER} = 'editPD0 (Thurnherr software)';
 		} else {
 			${$E}[$ens]->{PRODUCER} = 'unknown';
@@ -985,13 +990,24 @@
 	my($fn,$dta) = @_;
 
 	die("writeData() needs \$WBRcfn from previous readData()")
-		unless (-r $WBRcfn);
-	$WBPcfn = $fn;
-	system("cp $WBRcfn $WBPcfn");
+		unless (length($WBRcfn) > 0);
+
+    sysseek(WBRF,0,0) || die("$WBRcfn: $!");						# rewind input file
+	$WBPcfn = $fn;													# set patch file name for error messages
+	open(WBPF,"+>$WBPcfn") || die("$WBPcfn: $!");					# open patch file for r/w
 
-	open(WBPF,"+<$WBPcfn") || die("$WBPcfn: $!");
-    WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},
-	                   \@{$dta->{ENSEMBLE}});
+	while (1) {														# copy input file to patch file
+		my($buf);
+		my($nread) = sysread(WBRF,$buf,100*1024);
+		die("$WBRcfn: $!\n") if ($nread < 0);
+		last if ($nread == 0);
+		my($nwritten) = syswrite(WBPF,$buf,100*1024);
+		die("$WBPcfn: $! ($nwritten of $nread written)\n")
+			unless ($nwritten = $nread);
+	}
+    sysseek(WBPF,0,0) || die("$WBPcfn: $!");						# rewind patch file
+
+    WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta);
 }
 
 sub round(@)
@@ -1003,11 +1019,11 @@
 
 sub WBPens($$$)
 {
-	my($nbins,$fixed_leader_bytes,$E) = @_;
+	my($nbins,$fixed_leader_bytes,$dta) = @_;
 	my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs);
 	my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt);
 
-	for ($ens=$start_ens=0; $ens<=$#{$E}; $ens++,$start_ens+=$ens_length+2) {
+	for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) {
 
 		#------------------------------
 		# Patch Header (Data Source Id)
@@ -1018,7 +1034,7 @@
 		($hid) = unpack('C',$buf);
 		$hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,$ens));
 
-		$buf = pack('C',${$E}[$ens]->{DATA_SOURCE_ID});
+		$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{DATA_SOURCE_ID});
 		my($nw) = syswrite(WBPF,$buf,1);
 		$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 
@@ -1030,44 +1046,55 @@
 		sysread(WBPF,$buf,2*$ndt) == 2*$ndt || die("$WBPcfn: $!");
 		@WBPofs = unpack("v$ndt",$buf);
 		$fixed_leader_bytes = $WBPofs[1] - $WBPofs[0];
+
+		#--------------------
+		# Fixed Leader
+		#--------------------
 	
+		sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!");		# jump to EX/Coord-Transform
+		sysread(WBPF,$buf,1) == 1 || die("$WBPcfn: $!");
+		my($EX) = unpack('C',$buf);
+		if ($dta->{BEAM_COORDINATES}) {
+			$EX &= ~0x18;
+		} elsif ($dta->{EARTH_COORDINATES}) {
+			$EX |= 0x18;
+		} else {
+			die("$WBPcfn: only beam- and earth coordinates are supported (implementation restriction)\n");
+		}
+		$buf = pack('C',$EX);		
+		sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!");
+		syswrite(WBPF,$buf,1) == 1 || die("$WBPcfn: $!");
+
 		#------------------------------
 		# Variable Leader
 		#------------------------------
-	
-		sysseek(WBPF,$start_ens+$WBPofs[1]+12,0) || die("$WBPcfn: $!");
+
+		sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!");		# jump to SPEED_OF_SOUND
 		
-		${$E}[$ens]->{XDUCER_DEPTH} = round(${$E}[$ens]->{XDUCER_DEPTH}*10);
+		$dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10);
 
 		#-----------------------------
 		# IMP allows for missing value
 		#-----------------------------
 
-		${$E}[$ens]->{HEADING} = defined(${$E}[$ens]->{HEADING})
-							   ? round(${$E}[$ens]->{HEADING}*100)
+		$dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING})
+							   ? round($dta->{ENSEMBLE}[$ens]->{HEADING}*100)
 							   : 0xF000;
-		${$E}[$ens]->{PITCH} = defined(${$E}[$ens]->{PITCH})
-							 ? unpack('S',pack('s',round(${$E}[$ens]->{PITCH}*100)))
+		$dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH})
+							 ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{PITCH}*100)))
 							 : 0x8000;
-		${$E}[$ens]->{ROLL} = defined(${$E}[$ens]->{ROLL})
-						    ? unpack('S',pack('s',round(${$E}[$ens]->{ROLL}*100)))
+		$dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL})
+						    ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{ROLL}*100)))
 						    : 0x8000;
 
-		${$E}[$ens]->{TEMPERATURE} =
-			unpack('S',pack('s',round(${$E}[$ens]->{TEMPERATURE}*100)));
-
-		sysseek(WBPF,2,1);			# skip built-in test which reads as 0 but is usually undef		
-									# this was found not to matter, but there is no reason to edit
-#		my($b1);					# this field
-#		sysread(WBPF,$b1,14);
-#		sysseek(WBPF,-14,1);
-#		my($sos,$xd,$hdg,$pit,$rol,$sal,$tem) = unpack('vvvvvvv',$b1);
+		$dta->{ENSEMBLE}[$ens]->{TEMPERATURE} =
+			unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100)));
 
 		$buf = pack('vvvvvvv',
-			 ${$E}[$ens]->{SPEED_OF_SOUND},
-			 ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING},
-			 ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL},
-			 ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE});
+			 $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND},
+			 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH},$dta->{ENSEMBLE}[$ens]->{HEADING},
+			 $dta->{ENSEMBLE}[$ens]->{PITCH},$dta->{ENSEMBLE}[$ens]->{ROLL},
+			 $dta->{ENSEMBLE}[$ens]->{SALINITY},$dta->{ENSEMBLE}[$ens]->{TEMPERATURE});
 
 		my($nw) = syswrite(WBPF,$buf,14);
 		$nw == 14 || die("$WBPcfn: $nw bytes written ($!)");
@@ -1080,10 +1107,10 @@
 		sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBRcfn: $!");	# skip velocity data id (assume it is correct)
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				${$E}[$ens]->{VELOCITY}[$bin][$beam] = defined(${$E}[$ens]->{VELOCITY}[$bin][$beam])
-							   						 ? round(${$E}[$ens]->{VELOCITY}[$bin][$beam]*1000)
+				$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])
+							   						 ? round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000)
 							   						 : 0x8000;
-				$buf = pack('v',unpack('S',pack('s',${$E}[$ens]->{VELOCITY}[$bin][$beam])));
+				$buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])));
 				my($nw) = syswrite(WBPF,$buf,2);
 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1096,7 +1123,7 @@
 		sysseek(WBPF,$start_ens+$WBPofs[3]+2,0) || die("$WBRcfn: $!");
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				$buf = pack('C',${$E}[$ens]->{CORRELATION}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{CORRELATION}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1110,7 +1137,7 @@
 
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				$buf = pack('C',${$E}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1124,7 +1151,7 @@
 
 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++,$i++) {
-				$buf = pack('C',${$E}[$ens]->{PERCENT_GOOD}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{PERCENT_GOOD}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}