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: Tue Nov 26 01:29:26 2013 +# dlm: Wed May 7 10:41:18 2014 # (c) 2003 A.M. Thurnherr -# uE-Info: 873 10 NIL 0 0 72 74 2 4 NIL ofnI +# uE-Info: 827 0 NIL 0 0 72 74 2 4 NIL ofnI #====================================================================== # Read RDI BroadBand Binary Data Files (*.[0-9][0-9][0-9]) @@ -54,6 +54,11 @@ # Nov 25, 2013: - renamed from [RDI_BB_Read.pl] # - begin implementing WBWens() # - checkEnsemble() expunged +# Mar 3, 2014: - BUG: WBPens() did not handle incomple ensembles at EOF correctly +# Mar 4, 2014: - added support for DATA_SOURCE_ID +# Apr 24, 2014: - added debug statements to log %-GOOD values +# May 6, 2014: - loosened input format checks +# May 7, 2014: - removed BT_present flag # FIRMWARE VERSIONS: # It appears that different firmware versions generate different file @@ -67,6 +72,14 @@ # 16.21 WH300 (1) LDEO NBP0402 53 # 16.27 WH300 (2) Nash ? 59 +# PD0 IMP FILE FORMAT EXTENSIONS: +# - DATA_SOURCE_ID = 0xA0 | PATCHED_MASK (vs. 0x7F for TRDI PD0 files) +# PATCHED_MASK & 0x04: pitch value has been patched +# PATCHED_MASK & 0x02: roll value has been patched +# PATCHED_MASK & 0x01: heading value has been patched +# - PITCH & ROLL can be missing (0x8000 badval as in velocities) +# - HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading) + # NOTES: # - RDI stores data in VAX/Intel byte order (little endian) # - the output data structure does not exactly mirror the file data @@ -99,6 +112,7 @@ # &readData() returns perl obj (ref to anonymous hash) with the following # structure: # +# DATA_SOURCE_ID scalar 0x7f (Workhorse, also DVL) # NUMBER_OF_DATA_TYPES scalar 6 (no BT) or 7 # ENSEMBLE_BYTES scalar ?, number of bytes w/o checksum # HEADER_BYTES scalar ? @@ -183,9 +197,9 @@ # BUILT_IN_TEST_ERROR scalar ?,undefined=none # SPEED_OF_SOUND scalar 1400--1600 [m/s] # XDUCER_DEPTH scalar 0.1--999.9 [m] -# HEADING scalar 0--359.99 [deg] -# PITCH scalar -20.00-20.00 [deg] -# ROLL scalar -20.00-20.00 [deg] +# HEADING scalar 0--359.99 [deg] --- IMP EXTENSION: undef +# PITCH scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef +# ROLL scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef # SALINITY scalar 0-40 [psu] # TEMPERATURE scalar -5.00--40.00 [deg] # MIN_PRE_PING_WAIT_TIME scalar ? [s] @@ -317,7 +331,7 @@ ($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES}) = unpack('CCvCC',$buf); $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0)); - $did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Data Source",$did,0)); +## $did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Data Source",$did,0)); printf(STDERR "\n$WBRcfn: WARNING: unexpected number of data types (%d)\n", $dta->{NUMBER_OF_DATA_TYPES}) unless ($dta->{NUMBER_OF_DATA_TYPES} == 6 || @@ -553,7 +567,7 @@ { my($nbins,$fixed_leader_bytes,$E) = @_; my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBRofs); - my($ens,$ensNo,$dayStart,$ens_length,$BT_present,$hid,$did,$ndt); + my($ens,$ensNo,$dayStart,$ens_length,$hid,$did,$ndt); for ($ens=$start_ens=0; 1; $ens++,$start_ens+=$ens_length+2) { # print(STDERR "ens = $ens\n"); @@ -567,10 +581,9 @@ sysread(WBRF,$buf,6) == 6 || last; ($hid,$did,$ens_length,$dummy,$ndt) = unpack('CCvCC',$buf); $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0)); - $did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Data Source",$did,0)); - printf(STDERR "\n$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last - unless ($ndt == 6 || $ndt == 7); - $BT_present = ($ndt == 7); +## $did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Data Source",$did,0)); +## printf(STDERR "\n$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last +## unless ($ndt == 6 || $ndt == 7); sysread(WBRF,$buf,2*$ndt) == 2*$ndt || die("$WBRcfn: $!"); @WBRofs = unpack("v$ndt",$buf); $fixed_leader_bytes = $WBRofs[1] - $WBRofs[0]; @@ -594,6 +607,8 @@ # Variable Leader #------------------------------ + ${$E}[$ens]->{DATA_SOURCE_ID} = $did; # IMP extension + sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!"); ($id,$ensNo) = unpack("vv",$buf); @@ -635,11 +650,22 @@ $BIT_errors++ if (${$E}[$ens]->{BUILT_IN_TEST_ERROR}); ${$E}[$ens]->{XDUCER_DEPTH} /= 10; - ${$E}[$ens]->{HEADING} /= 100; - ${$E}[$ens]->{PITCH} = unpack('s',pack('S',${$E}[$ens]->{PITCH})) / 100; - ${$E}[$ens]->{ROLL} = unpack('s',pack('S',${$E}[$ens]->{ROLL})) / 100; - ${$E}[$ens]->{TEMPERATURE} = - unpack('s',pack('S',${$E}[$ens]->{TEMPERATURE})) / 100; + + #------------------------------------------------- + # IMP EXTENSION: PITCH/ROLL/HEADING CAN BE MISSING + #------------------------------------------------- + + ${$E}[$ens]->{HEADING} = (${$E}[$ens]->{HEADING} == 0xF000) + ? undef + : ${$E}[$ens]->{HEADING} / 100; + ${$E}[$ens]->{PITCH} = (${$E}[$ens]->{PITCH} == 0x8000) + ? 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; + + ${$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; ${$E}[$ens]->{PITCH_STDDEV} /= 10; @@ -780,84 +806,90 @@ die(sprintf($FmtErr,$WBRcfn,"Percent-Good Data",$id,$ens)); for ($i=0,$bin=0; $bin<$nbins; $bin++) { +# printf(STDERR "%-GOOD($bin): "); for ($beam=0; $beam<4; $beam++,$i++) { +# printf(STDERR "$dta[$i] "); ${$E}[$ens]->{PERCENT_GOOD}[$bin][$beam] = $dta[$i]; } +# printf(STDERR "\n"); } - #-------------------- + #----------------------------------------- # Bottom-Track Data - #-------------------- + # - scan through remaining data types + #----------------------------------------- - if ($BT_present) { - sysseek(WBRF,$start_ens+$WBRofs[6],0) || die("$WBRcfn: $!"); + my($nxt); + for ($nxt=6; $nxt<$ndt; $nxt++) { # scan until BT found + sysseek(WBRF,$start_ens+$WBRofs[$nxt],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); $id = unpack('v',$buf); - - $id == 0x0600 || - die(sprintf($FmtErr,$WBRcfn,"Bottom Track",$id,$ens)); - - sysseek(WBRF,14,1) || die("$WBRcfn: $!"); # BT config - - sysread(WBRF,$buf,28) == 28 || die("$WBRcfn: $!"); - @dta = unpack('v4v4C4C4C4',$buf); - - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RANGE}[$beam] = $dta[$beam] / 100 - if ($dta[$beam]); - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_VELOCITY}[$beam] = - unpack('s',pack('S',$dta[4+$beam])) / 1000 - if ($dta[4+$beam] != 0x8000); - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_CORRELATION}[$beam] = $dta[8+$beam] - if ($dta[8+$beam]); - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_EVAL_AMPLITUDE}[$beam] = $dta[12+$beam]; - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_PERCENT_GOOD}[$beam] = $dta[16+$beam]; - } - - sysseek(WBRF,6,1) || die("$WBRcfn: $!"); # BT config - - sysread(WBRF,$buf,20) == 20 || die("$WBRcfn: $!"); - @dta = unpack('v4C4C4C4',$buf); - - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RL_VELOCITY}[$beam] = - unpack('s',pack('S',$dta[$beam])) / 1000 - if ($dta[$beam] != 0x8000); - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RL_CORRELATION}[$beam] = $dta[4+$beam] - if ($dta[4+$beam]); - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RL_ECHO_AMPLITUDE}[$beam] = $dta[8+$beam]; - } - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RL_PERCENT_GOOD}[$beam] = $dta[12+$beam]; - } - - sysseek(WBRF,2,1) || die("$WBRcfn: $!"); # BT config - - sysread(WBRF,$buf,9) == 9 || die("$WBRcfn: $!"); - @dta = unpack('C4CC4',$buf); - - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_SIGNAL_STRENGTH}[$beam] = $dta[$beam]; - } - ${$E}[$ens]->{HIGH_GAIN} if ($dta[4]); - ${$E}[$ens]->{LOW_GAIN} unless ($dta[4]); - for ($beam=0; $beam<4; $beam++) { - ${$E}[$ens]->{BT_RANGE}[$beam] += $dta[5+$beam] * 655.36 - if ($dta[5+$beam]); - } - } # BT present + last if ($id == 0x0600); + } + + next if ($nxt == $ndt); # no BT found => next ens + + + sysseek(WBRF,14,1) || die("$WBRcfn: $!"); # BT config + + sysread(WBRF,$buf,28) == 28 || die("$WBRcfn: $!"); + @dta = unpack('v4v4C4C4C4',$buf); + + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RANGE}[$beam] = $dta[$beam] / 100 + if ($dta[$beam]); + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_VELOCITY}[$beam] = + unpack('s',pack('S',$dta[4+$beam])) / 1000 + if ($dta[4+$beam] != 0x8000); + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_CORRELATION}[$beam] = $dta[8+$beam] + if ($dta[8+$beam]); + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_EVAL_AMPLITUDE}[$beam] = $dta[12+$beam]; + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_PERCENT_GOOD}[$beam] = $dta[16+$beam]; + } + + sysseek(WBRF,6,1) || die("$WBRcfn: $!"); # BT config + + sysread(WBRF,$buf,20) == 20 || die("$WBRcfn: $!"); + @dta = unpack('v4C4C4C4',$buf); + + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RL_VELOCITY}[$beam] = + unpack('s',pack('S',$dta[$beam])) / 1000 + if ($dta[$beam] != 0x8000); + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RL_CORRELATION}[$beam] = $dta[4+$beam] + if ($dta[4+$beam]); + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RL_ECHO_AMPLITUDE}[$beam] = $dta[8+$beam]; + } + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RL_PERCENT_GOOD}[$beam] = $dta[12+$beam]; + } + + sysseek(WBRF,2,1) || die("$WBRcfn: $!"); # BT config + + sysread(WBRF,$buf,9) == 9 || die("$WBRcfn: $!"); + @dta = unpack('C4CC4',$buf); + + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_SIGNAL_STRENGTH}[$beam] = $dta[$beam]; + } + ${$E}[$ens]->{HIGH_GAIN} if ($dta[4]); + ${$E}[$ens]->{LOW_GAIN} unless ($dta[4]); + for ($beam=0; $beam<4; $beam++) { + ${$E}[$ens]->{BT_RANGE}[$beam] += $dta[5+$beam] * 655.36 + if ($dta[5+$beam]); + } } # ens loop } @@ -886,22 +918,28 @@ { my($nbins,$fixed_leader_bytes,$E) = @_; my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs); - my($ens,$ensNo,$dayStart,$ens_length,$BT_present,$hid,$did,$ndt); + my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt); - for ($ens=$start_ens=0; 1; $ens++,$start_ens+=$ens_length+2) { + for ($ens=$start_ens=0; $ens<=$#{$E}; $ens++,$start_ens+=$ens_length+2) { - #---------------------------------------- - # Get ensemble length and # of data types - #---------------------------------------- + #------------------------------ + # Patch Header (Data Source Id) + #------------------------------ sysseek(WBPF,$start_ens,0) || die("$WBPcfn: $!"); - sysread(WBPF,$buf,6) == 6 || last; - ($hid,$did,$ens_length,$dummy,$ndt) = unpack('CCvCC',$buf); - $hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,0)); - $did == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Data Source",$did,0)); + sysread(WBPF,$buf,1) || die("$WBPcfn: unexpected EOF"); + ($hid) = unpack('C',$buf); + $hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,$ens)); + + $buf = pack('C',${$E}[$ens]->{DATA_SOURCE_ID}); + my($nw) = syswrite(WBPF,$buf,1); + $nw == 1 || die("$WBPcfn: $nw bytes written ($!)"); + + sysread(WBPF,$buf,4) == 4 || die("$WBPcfn: unexpected EOF"); + ($ens_length,$dummy,$ndt) = unpack('vCC',$buf); printf(STDERR "\n$WBPcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last unless ($ndt == 6 || $ndt == 7); - $BT_present = ($ndt == 7); + sysread(WBPF,$buf,2*$ndt) == 2*$ndt || die("$WBPcfn: $!"); @WBPofs = unpack("v$ndt",$buf); $fixed_leader_bytes = $WBPofs[1] - $WBPofs[0]; @@ -913,10 +951,19 @@ sysseek(WBPF,$start_ens+$WBPofs[1]+12,0) || die("$WBPcfn: $!"); ${$E}[$ens]->{XDUCER_DEPTH} *= 10; - ${$E}[$ens]->{HEADING} *= 100; - - ${$E}[$ens]->{PITCH} = unpack('S',pack('s',${$E}[$ens]->{PITCH}*100)); - ${$E}[$ens]->{ROLL} = unpack('S',pack('s',${$E}[$ens]->{ROLL} *100)); + + # IMP EXTENSIONS + #--------------- + ${$E}[$ens]->{HEADING} = defined(${$E}[$ens]->{HEADING}) + ? ${$E}[$ens]->{HEADING} * 100 + : 0xF000; + ${$E}[$ens]->{PITCH} = defined(${$E}[$ens]->{PITCH}) + ? unpack('S',pack('s',${$E}[$ens]->{PITCH}*100)) + : 0x8000; + ${$E}[$ens]->{ROLL} = defined(${$E}[$ens]->{ROLL}) + ? unpack('S',pack('s',${$E}[$ens]->{ROLL}*100)) + : 0x8000; + ${$E}[$ens]->{TEMPERATURE} = unpack('S',pack('s',${$E}[$ens]->{TEMPERATURE}*100)); @@ -933,20 +980,6 @@ ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL}, ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE}); -# unless ($b1 eq $buf) { -# printf(STDERR "ens = $ens\n"); -# printf(STDERR "hdg: $hdg, ${$E}[$ens]->{HEADING}\n"); -# printf(STDERR "xd: $xd, ${$E}[$ens]->{XDUCER_DEPTH}\n"); -# printf(STDERR "pit: $pit, ${$E}[$ens]->{PITCH}\n"); -# printf(STDERR "rol: $rol, ${$E}[$ens]->{ROLL}\n"); -# printf(STDERR "sal: $sal, ${$E}[$ens]->{SALINITY}\n"); -# printf(STDERR "tem: $tem, ${$E}[$ens]->{TEMPERATURE}\n"); -# -# printf(STDERR "read: %04X %04X %04X %04X %04X %04X %04X written: %04X %04X %04X %04X %04X %04X %04X\n",unpack('v7',$b1),unpack('v7',$buf)); -# -# die; -# } - my($nw) = syswrite(WBPF,$buf,14); $nw == 14 || die("$WBPcfn: $nw bytes written ($!)");