1 #====================================================================== |
1 #====================================================================== |
2 # R D I _ P D 0 _ I O . P L |
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 |
3 # doc: Sat Jan 18 14:54:43 2003 |
3 # doc: Sat Jan 18 14:54:43 2003 |
4 # dlm: Wed Jun 26 09:27:46 2019 |
4 # dlm: Thu Feb 27 10:28:29 2020 |
5 # (c) 2003 A.M. Thurnherr |
5 # (c) 2003 A.M. Thurnherr |
6 # uE-Info: 645 39 NIL 0 0 72 2 2 4 NIL ofnI |
6 # uE-Info: 716 1 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: |
113 # - added warning on wrong ensemble length |
113 # - added warning on wrong ensemble length |
114 # Jun 9, 2018: - removed double \n from warnings |
114 # Jun 9, 2018: - removed double \n from warnings |
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 |
|
119 # Jun 30, 2019: - added dirty flag to prevent bad PD0 patching |
|
120 # Feb 13, 2020: - added support for $readDataProgress |
118 |
121 |
119 # FIRMWARE VERSIONS: |
122 # FIRMWARE VERSIONS: |
120 # It appears that different firmware versions generate different file |
123 # It appears that different firmware versions generate different file |
121 # structures. Currently (Sep 2005) these routines have been tested |
124 # structures. Currently (Sep 2005) these routines have been tested |
122 # with the following firmware versions (as reported by [listHdr]): |
125 # with the following firmware versions (as reported by [listHdr]): |
290 # MONTH scalar 1--12 |
293 # MONTH scalar 1--12 |
291 # DAY scalar 1--31 |
294 # DAY scalar 1--31 |
292 # TIME string HH:MM:SS.hh |
295 # TIME string HH:MM:SS.hh |
293 # HOUR scalar 0--23 |
296 # HOUR scalar 0--23 |
294 # MINUTE scalar 0--59 |
297 # MINUTE scalar 0--59 |
295 # SECONDS scalar 0--59.99 |
298 # SECOND scalar 0--59.99 |
296 # UNIX_TIME scalar 0--? |
299 # UNIX_TIME scalar 0--? |
297 # SECNO scalar 0--? (number of seconds since daystart) |
300 # SECNO scalar 0--? (number of seconds since daystart) |
298 # DAYNO double fractional day number since start of current year (1.0 is midnight Jan 1st) |
301 # DAYNO double fractional day number since start of current year (1.0 is midnight Jan 1st) |
299 # VELOCITY[bin][beam] scalars -32.767--32.768 [m/s], undef=bad |
302 # VELOCITY[bin][beam] scalars -32.767--32.768 [m/s], undef=bad |
300 # CORRELATION[bin][beam] scalars 1--255, undefined=bad |
303 # CORRELATION[bin][beam] scalars 1--255, undefined=bad |
450 #-------------------- |
453 #-------------------- |
451 # HEADER |
454 # HEADER |
452 #-------------------- |
455 #-------------------- |
453 |
456 |
454 my($skipped) = goto_next_ens(\*WBRF,1); |
457 my($skipped) = goto_next_ens(\*WBRF,1); |
455 printf(STDERR "WARNING: %d bytes of initial garbage\n",$skipped) |
458 if ($skipped > 0) { |
456 if ($skipped > 0); |
459 $RDI_PD0_IO::File_Dirty = 1; |
|
460 printf(STDERR "WARNING: %d bytes of initial garbage\n",$skipped); |
|
461 } |
457 |
462 |
458 sysread(WBRF,$buf,6) == 6 || return undef; |
463 sysread(WBRF,$buf,6) == 6 || return undef; |
459 ($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES}) |
464 ($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES}) |
460 = unpack('CCvCC',$buf); |
465 = unpack('CCvCC',$buf); |
461 $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid)",$hid,0)); |
466 $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid)",$hid,0)); |
679 #---------------------------------------------------------------------- |
684 #---------------------------------------------------------------------- |
680 # readData(file_name,^data[,first_ens,last_ens[,last_bin]]) |
685 # readData(file_name,^data[,first_ens,last_ens[,last_bin]]) |
681 # - read ensembles |
686 # - read ensembles |
682 # - read all ensembles unless first_ens and last_ens are given |
687 # - read all ensembles unless first_ens and last_ens are given |
683 # - read all bins unless last_bin is given |
688 # - read all bins unless last_bin is given |
|
689 # - if global var $readDataProgress > 0, a . is printed |
|
690 # every $readaDataProgress ensembles |
684 #---------------------------------------------------------------------- |
691 #---------------------------------------------------------------------- |
685 |
692 |
686 sub readData(@) |
693 sub readData(@) |
687 { |
694 { |
688 my($fn,$dta,$fe,$le,$lb) = @_; |
695 my($fn,$dta,$fe,$le,$lb) = @_; |
704 local our($ndt,$buf,$id,$start_ens,@WBRofs); |
711 local our($ndt,$buf,$id,$start_ens,@WBRofs); |
705 |
712 |
706 sysseek(WBRF,0,0) || die("$WBRcfn: $!"); |
713 sysseek(WBRF,0,0) || die("$WBRcfn: $!"); |
707 ENSEMBLE: |
714 ENSEMBLE: |
708 for ($ens=0; 1; $ens++) { |
715 for ($ens=0; 1; $ens++) { |
|
716 # die unless defined($global::readDataProgress); |
|
717 print(STDERR '.') if ($global::readDataProgress>0 && ($ens%$global::readDataProgress)==0); |
709 $start_ens = goto_next_ens(\*WBRF); |
718 $start_ens = goto_next_ens(\*WBRF); |
710 last unless defined($start_ens); |
719 last unless defined($start_ens); |
711 |
720 |
712 #---------------------------------------- |
721 #---------------------------------------- |
713 # Handle first_ens and last_ens |
722 # Handle first_ens and last_ens |
740 } else { |
749 } else { |
741 ${$E}[$ens]->{PRODUCER} = 'unknown'; |
750 ${$E}[$ens]->{PRODUCER} = 'unknown'; |
742 } |
751 } |
743 |
752 |
744 if (defined($ens_length) && ($el != $ens_length)) { |
753 if (defined($ens_length) && ($el != $ens_length)) { |
|
754 $RDI_PD0_IO::File_Dirty = 1; |
745 print(STDERR "WARNING (RDI_PD0_IO): ensemble ${$E}[$#{$E}]->{NUMBER} skipped (unexpected length)\n"); |
755 print(STDERR "WARNING (RDI_PD0_IO): ensemble ${$E}[$#{$E}]->{NUMBER} skipped (unexpected length)\n"); |
746 pop(@{$E}); |
756 pop(@{$E}); |
747 $ens--; |
757 $ens--; |
748 next; |
758 next; |
749 } |
759 } |
750 |
760 |
751 $ens_length = $el; |
761 $ens_length = $el; |
752 |
762 |
753 ## printf(STDERR "$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last |
763 ## printf(STDERR "$WBRcfn: WARNING: unexpected number of data types (%d, ens=$ens)\n",$ndt),last |
754 ## unless ($ndt == 6 || $ndt == 7); |
764 ## unless ($ndt == 6 || $ndt == 7); |
755 sysread(WBRF,$buf,2*$ndt) == 2*$ndt || die("$WBRcfn: $!"); |
765 my($nread) = sysread(WBRF,$buf,2*$ndt); # 2019 EPR test |
|
766 if ($nread != 2*$ndt) { |
|
767 printf(STDERR "$WBRcfn: WARNING: expected to read %d bytes, got only %d in ensemble %d\n", |
|
768 2*$ndt,$nread,${$E}[$ens]->{NUMBER}); |
|
769 last; |
|
770 } |
|
771 |
|
772 |
756 @WBRofs = unpack("v$ndt",$buf); |
773 @WBRofs = unpack("v$ndt",$buf); |
757 $fixed_leader_bytes = $WBRofs[1] - $WBRofs[0]; |
774 $fixed_leader_bytes = $WBRofs[1] - $WBRofs[0]; |
758 # print(STDERR "@WBRofs\n"); |
775 # print(STDERR "@WBRofs\n"); |
759 |
776 |
760 #------------------------------- |
777 #------------------------------- |
798 |
815 |
799 # if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) { # BB150 & Explorer DVL (if DISABLED!) |
816 # if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) { # BB150 & Explorer DVL (if DISABLED!) |
800 sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!"); # always read pre-Y2K clock |
817 sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!"); # always read pre-Y2K clock |
801 (${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH}, |
818 (${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH}, |
802 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, |
819 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, |
803 ${$E}[$ens]->{SECONDS},$B4) = unpack('CCCCCCC',$buf); |
820 ${$E}[$ens]->{SECOND},$B4) = unpack('CCCCCCC',$buf); |
804 ${$E}[$ens]->{SECONDS} += $B4/100; |
821 ${$E}[$ens]->{SECOND} += $B4/100; |
805 ${$E}[$ens]->{YEAR} += (${$E}[$ens]->{YEAR} > 80) ? 1900 : 2000; |
822 ${$E}[$ens]->{YEAR} += (${$E}[$ens]->{YEAR} > 80) ? 1900 : 2000; |
806 # } else { |
823 # } else { |
807 # sysseek(WBRF,7,1) || die("$WBRcfn: $!"); # use Y2K RTC instead |
824 # sysseek(WBRF,7,1) || die("$WBRcfn: $!"); # use Y2K RTC instead |
808 # } |
825 # } |
809 |
826 |
810 sysread(WBRF,$buf,1) == 1 || die("$WBRcfn: $!"); |
827 sysread(WBRF,$buf,1) == 1 || die("$WBRcfn: $!"); |
811 $ensNo += unpack('C',$buf) << 16; |
828 $ensNo += unpack('C',$buf) << 16; |
812 |
829 |
813 for (my($i)=$ens; $i>0; $i--) { # check for duplicate ens; e.g. 2018 S4P 24UL |
830 for (my($i)=$ens; $i>0; $i--) { # check for duplicate ens; e.g. 2018 S4P 24UL |
814 if (${$E}[$i]->{NUMBER} == $ensNo) { |
831 if (${$E}[$i]->{NUMBER} == $ensNo) { |
|
832 $RDI_PD0_IO::File_Dirty = 1; |
815 print(STDERR "WARNING (RDI_PD0_IO): duplicate ensemble $ensNo skipped\n"); |
833 print(STDERR "WARNING (RDI_PD0_IO): duplicate ensemble $ensNo skipped\n"); |
816 pop(@{$E}); |
834 pop(@{$E}); |
817 $ens--; |
835 $ens--; |
818 next ENSEMBLE; |
836 next ENSEMBLE; |
819 } |
837 } |
866 sysread(WBRF,$buf,23) == 23 || die("$WBRcfn: $!"); |
884 sysread(WBRF,$buf,23) == 23 || die("$WBRcfn: $!"); |
867 (${$E}[$ens]->{ERROR_STATUS_WORD}, |
885 (${$E}[$ens]->{ERROR_STATUS_WORD}, |
868 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}, |
886 $dummy,${$E}[$ens]->{PRESSURE},${$E}[$ens]->{PRESSURE_STDDEV}, |
869 $dummy,${$E}[$ens]->{YEAR},$B3,${$E}[$ens]->{MONTH}, |
887 $dummy,${$E}[$ens]->{YEAR},$B3,${$E}[$ens]->{MONTH}, |
870 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, |
888 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, |
871 ${$E}[$ens]->{SECONDS},$B4) |
889 ${$E}[$ens]->{SECOND},$B4) |
872 = unpack('VvVVCCCCCCCCC',$buf); |
890 = unpack('VvVVCCCCCCCCC',$buf); |
873 |
891 |
874 ${$E}[$ens]->{PRESSURE} /= 1000; |
892 ${$E}[$ens]->{PRESSURE} /= 1000; |
875 ${$E}[$ens]->{PRESSURE_STDDEV} /= 1000; |
893 ${$E}[$ens]->{PRESSURE_STDDEV} /= 1000; |
876 ${$E}[$ens]->{YEAR} *= 100; ${$E}[$ens]->{YEAR} += $B3; |
894 ${$E}[$ens]->{YEAR} *= 100; ${$E}[$ens]->{YEAR} += $B3; |
877 ${$E}[$ens]->{SECONDS} += $B4/100; |
895 ${$E}[$ens]->{SECOND} += $B4/100; |
878 } |
896 } |
879 |
897 |
880 # THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP |
898 # THE FOLLOWING LINE OF CODE WAS REMOVED 7/30/2016 WHEN I ADDED A POP |
881 # TO THE last STATEMENT ABOVE (INCOMPLETE ENSEMBLE) |
899 # TO THE last STATEMENT ABOVE (INCOMPLETE ENSEMBLE) |
882 # THE LINE WAS RE-ENABLED ON 12/23/2017 BECAUSE OTHERWISE THE |
900 # THE LINE WAS RE-ENABLED ON 12/23/2017 BECAUSE OTHERWISE THE |
897 ${$E}[$ens]->{DAY}, |
915 ${$E}[$ens]->{DAY}, |
898 ${$E}[$ens]->{YEAR}); |
916 ${$E}[$ens]->{YEAR}); |
899 ${$E}[$ens]->{TIME} |
917 ${$E}[$ens]->{TIME} |
900 = sprintf("%02d:%02d:%05.02f",${$E}[$ens]->{HOUR}, |
918 = sprintf("%02d:%02d:%05.02f",${$E}[$ens]->{HOUR}, |
901 ${$E}[$ens]->{MINUTE}, |
919 ${$E}[$ens]->{MINUTE}, |
902 ${$E}[$ens]->{SECONDS}); |
920 ${$E}[$ens]->{SECOND}); |
903 ${$E}[$ens]->{DAYNO} |
921 ${$E}[$ens]->{DAYNO} |
904 = &_dayNo(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},${$E}[$ens]->{DAY}, |
922 = &_dayNo(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},${$E}[$ens]->{DAY}, |
905 ${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},${$E}[$ens]->{SECONDS}); |
923 ${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},${$E}[$ens]->{SECOND}); |
906 |
924 |
907 # when analyzing an STA file from an OS75 SADCP (Poseidon), |
925 # when analyzing an STA file from an OS75 SADCP (Poseidon), |
908 # I noticed that there is no time information. This causes |
926 # I noticed that there is no time information. This causes |
909 # timegm to bomb. |
927 # timegm to bomb. |
910 if (${$E}[$ens]->{MONTH} == 0) { # no time info |
928 if (${$E}[$ens]->{MONTH} == 0) { # no time info |
916 = timegm(0,${$E}[$ens]->{MINUTE}, |
934 = timegm(0,${$E}[$ens]->{MINUTE}, |
917 ${$E}[$ens]->{HOUR}, |
935 ${$E}[$ens]->{HOUR}, |
918 ${$E}[$ens]->{DAY}, |
936 ${$E}[$ens]->{DAY}, |
919 ${$E}[$ens]->{MONTH}-1, # timegm jan==0!!! |
937 ${$E}[$ens]->{MONTH}-1, # timegm jan==0!!! |
920 ${$E}[$ens]->{YEAR}) |
938 ${$E}[$ens]->{YEAR}) |
921 + ${$E}[$ens]->{SECONDS}; |
939 + ${$E}[$ens]->{SECOND}; |
922 |
940 |
923 $dayStart = timegm(0,0,0,${$E}[$ens]->{DAY}, |
941 $dayStart = timegm(0,0,0,${$E}[$ens]->{DAY}, |
924 ${$E}[$ens]->{MONTH}-1, |
942 ${$E}[$ens]->{MONTH}-1, |
925 ${$E}[$ens]->{YEAR}) |
943 ${$E}[$ens]->{YEAR}) |
926 unless defined($dayStart); |
944 unless defined($dayStart); |
1088 # sysseek(WBRF,8,1) || die("$WBRcfn: $!"); # remainder of ensemble |
1106 # sysseek(WBRF,8,1) || die("$WBRcfn: $!"); # remainder of ensemble |
1089 } |
1107 } |
1090 sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!"); |
1108 sysseek(WBRF,$start_ens+$ens_length+2,0) || die("$WBRcfn: $!"); |
1091 } # ens loop |
1109 } # ens loop |
1092 } |
1110 } |
|
1111 print(STDERR "\n") if ($global::readDataProgress > 0); |
1093 |
1112 |
1094 sub WBRdtaIndex($) |
1113 sub WBRdtaIndex($) |
1095 { |
1114 { |
1096 my($trgid) = @_; |
1115 my($trgid) = @_; |
1097 our($ndt,$buf,$id,$start_ens,@WBRofs); |
1116 our($ndt,$buf,$id,$start_ens,@WBRofs); |
1119 |
1138 |
1120 sub writeData(@) |
1139 sub writeData(@) |
1121 { |
1140 { |
1122 my($fn,$dta) = @_; |
1141 my($fn,$dta) = @_; |
1123 |
1142 |
1124 die("writeData() needs \$WBRcfn from previous readData()") |
1143 die("writeData() needs \$WBRcfn from previous readData()\n") |
1125 unless (length($WBRcfn) > 0); |
1144 unless (length($WBRcfn) > 0); |
|
1145 die("writeData() only works with clean PD0 files\n") |
|
1146 if ($RDI_PD0_IO::File_Dirty); |
1126 |
1147 |
1127 sysseek(WBRF,0,0) || die("$WBRcfn: $!"); # rewind input file |
1148 sysseek(WBRF,0,0) || die("$WBRcfn: $!"); # rewind input file |
1128 $WBPcfn = $fn; # set patch file name for error messages |
1149 $WBPcfn = $fn; # set patch file name for error messages |
1129 open(WBPF,"+>$WBPcfn") || die("$WBPcfn: $!"); # open patch file for r/w |
1150 open(WBPF,"+>$WBPcfn") || die("$WBPcfn: $!"); # open patch file for r/w |
1130 |
1151 |
1242 ($dta->{ENSEMBLE}[$ens]->{YEAR}, |
1263 ($dta->{ENSEMBLE}[$ens]->{YEAR}, |
1243 $dta->{ENSEMBLE}[$ens]->{MONTH}, |
1264 $dta->{ENSEMBLE}[$ens]->{MONTH}, |
1244 $dta->{ENSEMBLE}[$ens]->{DAY}, |
1265 $dta->{ENSEMBLE}[$ens]->{DAY}, |
1245 $dta->{ENSEMBLE}[$ens]->{HOUR}, |
1266 $dta->{ENSEMBLE}[$ens]->{HOUR}, |
1246 $dta->{ENSEMBLE}[$ens]->{MINUTE}, |
1267 $dta->{ENSEMBLE}[$ens]->{MINUTE}, |
1247 $dta->{ENSEMBLE}[$ens]->{SECONDS},$B4) = |
1268 $dta->{ENSEMBLE}[$ens]->{SECOND},$B4) = |
1248 unpack('CCCCCCC',$buf); |
1269 unpack('CCCCCCC',$buf); |
1249 $dta->{ENSEMBLE}[$ens]->{SECONDS} += $B4/100; |
1270 $dta->{ENSEMBLE}[$ens]->{SECOND} += $B4/100; |
1250 $dta->{ENSEMBLE}[$ens]->{YEAR} += ($dta->{ENSEMBLE}[$ens]->{YEAR} > 80) ? 1900 : 2000; |
1271 $dta->{ENSEMBLE}[$ens]->{YEAR} += ($dta->{ENSEMBLE}[$ens]->{YEAR} > 80) ? 1900 : 2000; |
1251 } |
1272 } |
1252 |
1273 |
1253 #---------------------------------------------------------------------- |
1274 #---------------------------------------------------------------------- |
1254 # Variable Leader #2 |
1275 # Variable Leader #2 |
1297 |
1318 |
1298 sysseek(WBPF,$start_ens+$WBPofs[1]+57,0) || die("$WBPcfn: $!"); # jump to RTC_CENTURY |
1319 sysseek(WBPF,$start_ens+$WBPofs[1]+57,0) || die("$WBPcfn: $!"); # jump to RTC_CENTURY |
1299 |
1320 |
1300 my($century) = int($dta->{ENSEMBLE}[$ens]->{YEAR} / 100); |
1321 my($century) = int($dta->{ENSEMBLE}[$ens]->{YEAR} / 100); |
1301 my($year) = $dta->{ENSEMBLE}[$ens]->{YEAR} % 100; |
1322 my($year) = $dta->{ENSEMBLE}[$ens]->{YEAR} % 100; |
1302 my($seconds) = int($dta->{ENSEMBLE}[$ens]->{SECONDS}); |
1323 my($seconds) = int($dta->{ENSEMBLE}[$ens]->{SECOND}); |
1303 my($hundredths) = 100 * ($dta->{ENSEMBLE}[$ens]->{SECONDS} - $seconds); |
1324 my($hundredths) = 100 * ($dta->{ENSEMBLE}[$ens]->{SECOND} - $seconds); |
1304 $buf = pack('CCCCCCCC',$century,$year,$dta->{ENSEMBLE}[$ens]->{MONTH}, |
1325 $buf = pack('CCCCCCCC',$century,$year,$dta->{ENSEMBLE}[$ens]->{MONTH}, |
1305 $dta->{ENSEMBLE}[$ens]->{DAY},$dta->{ENSEMBLE}[$ens]->{HOUR}, |
1326 $dta->{ENSEMBLE}[$ens]->{DAY},$dta->{ENSEMBLE}[$ens]->{HOUR}, |
1306 $dta->{ENSEMBLE}[$ens]->{MINUTE},$seconds,$hundredths); |
1327 $dta->{ENSEMBLE}[$ens]->{MINUTE},$seconds,$hundredths); |
1307 my($nw) = syswrite(WBPF,$buf,8); |
1328 my($nw) = syswrite(WBPF,$buf,8); |
1308 $nw == 8 || die("$WBPcfn: $nw bytes written ($!)"); |
1329 $nw == 8 || die("$WBPcfn: $nw bytes written ($!)"); |