diff --git a/RDI_PD0_IO.pl b/RDI_PD0_IO.pl --- 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 ($!)"); }