64 # incomplete ensemble at the end, which seems to imply that there is |
64 # incomplete ensemble at the end, which seems to imply that there is |
65 # a garbage final ensemble that passes the checksum test??? |
65 # a garbage final ensemble that passes the checksum test??? |
66 # Oct 2, 2015: - added &skip_initial_trash() |
66 # Oct 2, 2015: - added &skip_initial_trash() |
67 # Dec 18, 2015: - added most data types to WBPofs() |
67 # Dec 18, 2015: - added most data types to WBPofs() |
68 # - BUG: WBPens() requires round() for scaled values |
68 # - BUG: WBPens() requires round() for scaled values |
69 # Jan 9, 2016: - BUG: WBRhdr() did not set DATA_SOURCE_ID |
69 # Jan 9, 2016: - removed system() from writeData() |
|
70 # - BUG: WBRhdr() did not set DATA_SOURCE_ID |
70 # - added PRODUCER |
71 # - added PRODUCER |
|
72 # - BUG: writeData() did not work correctly for ECOGIG OC26 moored data (spaces in filename?) |
|
73 # - added support for patching coordinate system |
71 |
74 |
72 # FIRMWARE VERSIONS: |
75 # FIRMWARE VERSIONS: |
73 # It appears that different firmware versions generate different file |
76 # It appears that different firmware versions generate different file |
74 # structures. Currently (Sep 2005) these routines have been tested |
77 # structures. Currently (Sep 2005) these routines have been tested |
75 # with the following firmware versions (as reported by [listHdr]): |
78 # with the following firmware versions (as reported by [listHdr]): |
377 = unpack('CCvCC',$buf); |
382 = unpack('CCvCC',$buf); |
378 $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0)); |
383 $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0)); |
379 $dta->{DATA_SOURCE_ID} = $did; |
384 $dta->{DATA_SOURCE_ID} = $did; |
380 if ($did == 0x7f) { |
385 if ($did == 0x7f) { |
381 $dta->{PRODUCER} = 'TRDI ADCP'; |
386 $dta->{PRODUCER} = 'TRDI ADCP'; |
382 } elsif ($did&0xF0 == 0xA0) { |
387 } elsif (($did&0xF0) == 0xA0) { |
383 $dta->{PRODUCER} = 'IMP+LADCP'; |
388 $dta->{PRODUCER} = 'IMP+LADCP (Thurnherr software)'; |
384 } elsif ($did&0xF0 == 0xB0) { |
389 } elsif (($did&0xF0) == 0xE0) { |
385 $dta->{PRODUCER} = 'editPD0'; |
390 $dta->{PRODUCER} = 'editPD0 (Thurnherr software)'; |
386 } else { |
391 } else { |
387 $dta->{PRODUCER} = 'unknown'; |
392 $dta->{PRODUCER} = sprintf('unknown (0x%02X)'); |
388 } |
393 } |
389 |
394 |
390 printf(STDERR "WARNING: unexpected number of data types (%d)\n", |
395 printf(STDERR "WARNING: unexpected number of data types (%d)\n", |
391 $dta->{NUMBER_OF_DATA_TYPES}) |
396 $dta->{NUMBER_OF_DATA_TYPES}) |
392 unless ($dta->{NUMBER_OF_DATA_TYPES} == 6 || |
397 unless ($dta->{NUMBER_OF_DATA_TYPES} == 6 || |
983 sub writeData(@) |
988 sub writeData(@) |
984 { |
989 { |
985 my($fn,$dta) = @_; |
990 my($fn,$dta) = @_; |
986 |
991 |
987 die("writeData() needs \$WBRcfn from previous readData()") |
992 die("writeData() needs \$WBRcfn from previous readData()") |
988 unless (-r $WBRcfn); |
993 unless (length($WBRcfn) > 0); |
989 $WBPcfn = $fn; |
994 |
990 system("cp $WBRcfn $WBPcfn"); |
995 sysseek(WBRF,0,0) || die("$WBRcfn: $!"); # rewind input file |
991 |
996 $WBPcfn = $fn; # set patch file name for error messages |
992 open(WBPF,"+<$WBPcfn") || die("$WBPcfn: $!"); |
997 open(WBPF,"+>$WBPcfn") || die("$WBPcfn: $!"); # open patch file for r/w |
993 WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES}, |
998 |
994 \@{$dta->{ENSEMBLE}}); |
999 while (1) { # copy input file to patch file |
|
1000 my($buf); |
|
1001 my($nread) = sysread(WBRF,$buf,100*1024); |
|
1002 die("$WBRcfn: $!\n") if ($nread < 0); |
|
1003 last if ($nread == 0); |
|
1004 my($nwritten) = syswrite(WBPF,$buf,100*1024); |
|
1005 die("$WBPcfn: $! ($nwritten of $nread written)\n") |
|
1006 unless ($nwritten = $nread); |
|
1007 } |
|
1008 sysseek(WBPF,0,0) || die("$WBPcfn: $!"); # rewind patch file |
|
1009 |
|
1010 WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta); |
995 } |
1011 } |
996 |
1012 |
997 sub round(@) |
1013 sub round(@) |
998 { |
1014 { |
999 return $_[0] >= 0 ? int($_[0] + 0.5) |
1015 return $_[0] >= 0 ? int($_[0] + 0.5) |
1001 } |
1017 } |
1002 |
1018 |
1003 |
1019 |
1004 sub WBPens($$$) |
1020 sub WBPens($$$) |
1005 { |
1021 { |
1006 my($nbins,$fixed_leader_bytes,$E) = @_; |
1022 my($nbins,$fixed_leader_bytes,$dta) = @_; |
1007 my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs); |
1023 my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs); |
1008 my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt); |
1024 my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt); |
1009 |
1025 |
1010 for ($ens=$start_ens=0; $ens<=$#{$E}; $ens++,$start_ens+=$ens_length+2) { |
1026 for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) { |
1011 |
1027 |
1012 #------------------------------ |
1028 #------------------------------ |
1013 # Patch Header (Data Source Id) |
1029 # Patch Header (Data Source Id) |
1014 #------------------------------ |
1030 #------------------------------ |
1015 |
1031 |
1016 sysseek(WBPF,$start_ens,0) || die("$WBPcfn: $!"); |
1032 sysseek(WBPF,$start_ens,0) || die("$WBPcfn: $!"); |
1017 sysread(WBPF,$buf,1) || die("$WBPcfn: unexpected EOF"); |
1033 sysread(WBPF,$buf,1) || die("$WBPcfn: unexpected EOF"); |
1018 ($hid) = unpack('C',$buf); |
1034 ($hid) = unpack('C',$buf); |
1019 $hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,$ens)); |
1035 $hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,$ens)); |
1020 |
1036 |
1021 $buf = pack('C',${$E}[$ens]->{DATA_SOURCE_ID}); |
1037 $buf = pack('C',$dta->{ENSEMBLE}[$ens]->{DATA_SOURCE_ID}); |
1022 my($nw) = syswrite(WBPF,$buf,1); |
1038 my($nw) = syswrite(WBPF,$buf,1); |
1023 $nw == 1 || die("$WBPcfn: $nw bytes written ($!)"); |
1039 $nw == 1 || die("$WBPcfn: $nw bytes written ($!)"); |
1024 |
1040 |
1025 sysread(WBPF,$buf,4) == 4 || die("$WBPcfn: unexpected EOF"); |
1041 sysread(WBPF,$buf,4) == 4 || die("$WBPcfn: unexpected EOF"); |
1026 ($ens_length,$dummy,$ndt) = unpack('vCC',$buf); |
1042 ($ens_length,$dummy,$ndt) = unpack('vCC',$buf); |
1028 unless ($ndt == 6 || $ndt == 7); |
1044 unless ($ndt == 6 || $ndt == 7); |
1029 |
1045 |
1030 sysread(WBPF,$buf,2*$ndt) == 2*$ndt || die("$WBPcfn: $!"); |
1046 sysread(WBPF,$buf,2*$ndt) == 2*$ndt || die("$WBPcfn: $!"); |
1031 @WBPofs = unpack("v$ndt",$buf); |
1047 @WBPofs = unpack("v$ndt",$buf); |
1032 $fixed_leader_bytes = $WBPofs[1] - $WBPofs[0]; |
1048 $fixed_leader_bytes = $WBPofs[1] - $WBPofs[0]; |
|
1049 |
|
1050 #-------------------- |
|
1051 # Fixed Leader |
|
1052 #-------------------- |
1033 |
1053 |
|
1054 sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!"); # jump to EX/Coord-Transform |
|
1055 sysread(WBPF,$buf,1) == 1 || die("$WBPcfn: $!"); |
|
1056 my($EX) = unpack('C',$buf); |
|
1057 if ($dta->{BEAM_COORDINATES}) { |
|
1058 $EX &= ~0x18; |
|
1059 } elsif ($dta->{EARTH_COORDINATES}) { |
|
1060 $EX |= 0x18; |
|
1061 } else { |
|
1062 die("$WBPcfn: only beam- and earth coordinates are supported (implementation restriction)\n"); |
|
1063 } |
|
1064 $buf = pack('C',$EX); |
|
1065 sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!"); |
|
1066 syswrite(WBPF,$buf,1) == 1 || die("$WBPcfn: $!"); |
|
1067 |
1034 #------------------------------ |
1068 #------------------------------ |
1035 # Variable Leader |
1069 # Variable Leader |
1036 #------------------------------ |
1070 #------------------------------ |
1037 |
1071 |
1038 sysseek(WBPF,$start_ens+$WBPofs[1]+12,0) || die("$WBPcfn: $!"); |
1072 sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!"); # jump to SPEED_OF_SOUND |
1039 |
1073 |
1040 ${$E}[$ens]->{XDUCER_DEPTH} = round(${$E}[$ens]->{XDUCER_DEPTH}*10); |
1074 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10); |
1041 |
1075 |
1042 #----------------------------- |
1076 #----------------------------- |
1043 # IMP allows for missing value |
1077 # IMP allows for missing value |
1044 #----------------------------- |
1078 #----------------------------- |
1045 |
1079 |
1046 ${$E}[$ens]->{HEADING} = defined(${$E}[$ens]->{HEADING}) |
1080 $dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING}) |
1047 ? round(${$E}[$ens]->{HEADING}*100) |
1081 ? round($dta->{ENSEMBLE}[$ens]->{HEADING}*100) |
1048 : 0xF000; |
1082 : 0xF000; |
1049 ${$E}[$ens]->{PITCH} = defined(${$E}[$ens]->{PITCH}) |
1083 $dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH}) |
1050 ? unpack('S',pack('s',round(${$E}[$ens]->{PITCH}*100))) |
1084 ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{PITCH}*100))) |
1051 : 0x8000; |
1085 : 0x8000; |
1052 ${$E}[$ens]->{ROLL} = defined(${$E}[$ens]->{ROLL}) |
1086 $dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL}) |
1053 ? unpack('S',pack('s',round(${$E}[$ens]->{ROLL}*100))) |
1087 ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{ROLL}*100))) |
1054 : 0x8000; |
1088 : 0x8000; |
1055 |
1089 |
1056 ${$E}[$ens]->{TEMPERATURE} = |
1090 $dta->{ENSEMBLE}[$ens]->{TEMPERATURE} = |
1057 unpack('S',pack('s',round(${$E}[$ens]->{TEMPERATURE}*100))); |
1091 unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100))); |
1058 |
|
1059 sysseek(WBPF,2,1); # skip built-in test which reads as 0 but is usually undef |
|
1060 # this was found not to matter, but there is no reason to edit |
|
1061 # my($b1); # this field |
|
1062 # sysread(WBPF,$b1,14); |
|
1063 # sysseek(WBPF,-14,1); |
|
1064 # my($sos,$xd,$hdg,$pit,$rol,$sal,$tem) = unpack('vvvvvvv',$b1); |
|
1065 |
1092 |
1066 $buf = pack('vvvvvvv', |
1093 $buf = pack('vvvvvvv', |
1067 ${$E}[$ens]->{SPEED_OF_SOUND}, |
1094 $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND}, |
1068 ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING}, |
1095 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH},$dta->{ENSEMBLE}[$ens]->{HEADING}, |
1069 ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL}, |
1096 $dta->{ENSEMBLE}[$ens]->{PITCH},$dta->{ENSEMBLE}[$ens]->{ROLL}, |
1070 ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE}); |
1097 $dta->{ENSEMBLE}[$ens]->{SALINITY},$dta->{ENSEMBLE}[$ens]->{TEMPERATURE}); |
1071 |
1098 |
1072 my($nw) = syswrite(WBPF,$buf,14); |
1099 my($nw) = syswrite(WBPF,$buf,14); |
1073 $nw == 14 || die("$WBPcfn: $nw bytes written ($!)"); |
1100 $nw == 14 || die("$WBPcfn: $nw bytes written ($!)"); |
1074 |
1101 |
1075 |
1102 |
1078 #-------------------- |
1105 #-------------------- |
1079 |
1106 |
1080 sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBRcfn: $!"); # skip velocity data id (assume it is correct) |
1107 sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBRcfn: $!"); # skip velocity data id (assume it is correct) |
1081 for ($bin=0; $bin<$nbins; $bin++) { |
1108 for ($bin=0; $bin<$nbins; $bin++) { |
1082 for ($beam=0; $beam<4; $beam++) { |
1109 for ($beam=0; $beam<4; $beam++) { |
1083 ${$E}[$ens]->{VELOCITY}[$bin][$beam] = defined(${$E}[$ens]->{VELOCITY}[$bin][$beam]) |
1110 $dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]) |
1084 ? round(${$E}[$ens]->{VELOCITY}[$bin][$beam]*1000) |
1111 ? round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000) |
1085 : 0x8000; |
1112 : 0x8000; |
1086 $buf = pack('v',unpack('S',pack('s',${$E}[$ens]->{VELOCITY}[$bin][$beam]))); |
1113 $buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]))); |
1087 my($nw) = syswrite(WBPF,$buf,2); |
1114 my($nw) = syswrite(WBPF,$buf,2); |
1088 $nw == 2 || die("$WBPcfn: $nw bytes written ($!)"); |
1115 $nw == 2 || die("$WBPcfn: $nw bytes written ($!)"); |
1089 } |
1116 } |
1090 } |
1117 } |
1091 |
1118 |