136 # setting (e.g. xducer orientation); I'v made an educated guess |
143 # setting (e.g. xducer orientation); I'v made an educated guess |
137 # as to which fields to move to the ENS array |
144 # as to which fields to move to the ENS array |
138 # - all units except pressure are SI, i.e. in m and m/s |
145 # - all units except pressure are SI, i.e. in m and m/s |
139 # - I don't understand the ERROR_STATUS_WORD; here's what 3 different |
146 # - I don't understand the ERROR_STATUS_WORD; here's what 3 different |
140 # instruments returned: |
147 # instruments returned: |
141 # 0x88000100 FSU instrument during A0304 (Firmware 16.12) |
148 # 0x88000100 FSU instrument during A0304 (Firmware 16.12) |
142 # 0x88008180 LDEO uplooker (slave) during NBP0402 (Firmware 16.21) |
149 # 0x88008180 LDEO uplooker (slave) during NBP0402 (Firmware 16.21) |
143 # 0x00008180 LDEO downlooker (master) during NBP0402 (Firmware 16.21) |
150 # 0x00008180 LDEO downlooker (master) during NBP0402 (Firmware 16.21) |
144 # According to the manual (January 2001 version) this would, for example, |
151 # According to the manual (January 2001 version) this would, for example, |
145 # indicate power failures on both FSU and LDEO slave instruments... |
152 # indicate power failures on both FSU and LDEO slave instruments... |
146 |
153 |
147 # &readData() returns perl obj (ref to anonymous hash) with the following |
154 # &readData() returns perl obj (ref to anonymous hash) with the following |
148 # structure: |
155 # structure: |
149 # |
156 # |
150 # DATA_SOURCE_ID scalar 0x7f (Workhorse, also DVL) |
157 # DATA_SOURCE_ID scalar 0x7f (Workhorse, also DVL) |
151 # NUMBER_OF_DATA_TYPES scalar 6 (no BT) or 7 |
158 # NUMBER_OF_DATA_TYPES scalar 6 (no BT) or 7 |
152 # ENSEMBLE_BYTES scalar ?, number of bytes w/o checksum |
159 # ENSEMBLE_BYTES scalar ?, number of bytes w/o checksum |
153 # HEADER_BYTES scalar ? |
160 # HEADER_BYTES scalar ? |
154 # FIXED_LEADER_BYTES scalar 42 for BB150; 53 for WH300, 58 for WH600, 59 for WH300(Nash) |
161 # FIXED_LEADER_BYTES scalar 42 for BB150; 53 for WH300, 58 for WH600, 59 for WH300(Nash) |
155 # VARIABLE_LEADER_BYTES scalar ? |
162 # VARIABLE_LEADER_BYTES scalar ? |
156 # VELOCITY_DATA_BYTES scalar ? |
163 # VELOCITY_DATA_BYTES scalar ? |
157 # CORRELATION_DATA_BYTES scalar ? |
164 # CORRELATION_DATA_BYTES scalar ? |
158 # ECHO_INTENSITY_DATA_BYTES scalar ? |
165 # ECHO_INTENSITY_DATA_BYTES scalar ? |
159 # PERCENT_GOOD_DATA_BYTES scalar ? |
166 # PERCENT_GOOD_DATA_BYTES scalar ? |
160 # BT_PRESENT bool NUMBER_OF_DATA_TYPES == 7 |
167 # BT_PRESENT bool NUMBER_OF_DATA_TYPES == 7 |
161 # BT_DATA_BYTES scalar undefined, ? if BT_PRESENT |
168 # BT_DATA_BYTES scalar undefined, ? if BT_PRESENT |
162 # CPU_FW_VER scalar 0--255 |
169 # CPU_FW_VER scalar 0--255 |
163 # CPU_FW_REV scalar 0--255 |
170 # CPU_FW_REV scalar 0--255 |
164 # BEAM_FREQUENCY scalar 75, 150, 300, 600, 1200, 2400 [kHz] |
171 # BEAM_FREQUENCY scalar 75, 150, 300, 600, 1200, 2400 [kHz] |
165 # CONVEX_BEAM_PATTERN bool undefined, 1 |
172 # LAG_LENGTH scalar ??? |
|
173 # CONVEX_BEAM_PATTERN bool undefined, 1 |
166 # CONCAVE_BEAM_PATTERN bool undefined, 1 |
174 # CONCAVE_BEAM_PATTERN bool undefined, 1 |
167 # SENSOR_CONFIG scalar 1--3 |
175 # SENSOR_CONFIG scalar 1--3 |
168 # XDUCER_HEAD_ATTACHED bool undefined, 1 |
176 # XDUCER_HEAD_ATTACHED bool undefined, 1 |
169 # BEAM_ANGLE scalar 15,20,30,undefined=other [deg] |
177 # BEAM_ANGLE scalar 15,20,30,undefined=other [deg] |
170 # N_BEAMS scalar 4--5 |
178 # N_BEAMS scalar 4--5 |
171 # N_DEMODS scalar 2--3(???),undefined=n/a |
179 # N_DEMODS scalar 2--3(???),undefined=n/a |
172 # N_BINS scalar 1--128 |
180 # N_BINS scalar 1--128 |
173 # PINGS_PER_ENSEMBLE scalar 0--16384 |
181 # PINGS_PER_ENSEMBLE scalar 0--16384 |
174 # BIN_LENGTH scalar 0.01--64 [m] |
182 # BIN_LENGTH scalar 0.01--64 [m] |
175 # BLANKING_DISTANCE scalar 0-99.99 [m] |
183 # BLANKING_DISTANCE scalar 0-99.99 [m] |
176 # MIN_CORRELATION scalar 0--255 |
184 # MIN_CORRELATION scalar 0--255 |
177 # N_CODE_REPETITIONS scalar 0--255 |
185 # N_CODE_REPETITIONS scalar 0--255 |
178 # MIN_PERCENT_GOOD scalar 1--100 [%] |
186 # MIN_PERCENT_GOOD scalar 1--100 [%] |
179 # MAX_ERROR_VELOCITY scalar 0--5 [m/s] |
187 # MAX_ERROR_VELOCITY scalar 0--5 [m/s] |
180 # TIME_BETWEEN_PINGS scalar 0--? [s] |
188 # TIME_BETWEEN_PINGS scalar 0--? [s] |
181 # BEAM_COORDINATES bool undefined,1 |
189 # BEAM_COORDINATES bool undefined,1 |
182 # INSTRUMENT_COORDINATES bool undefined,1 |
190 # INSTRUMENT_COORDINATES bool undefined,1 |
183 # SHIP_COORDINATES bool undefined,1 |
191 # SHIP_COORDINATES bool undefined,1 |
184 # EARTH_COORDINATES bool undefined,1 |
192 # EARTH_COORDINATES bool undefined,1 |
185 # PITCH_AND_ROLL_USED bool undefined,1 |
193 # PITCH_AND_ROLL_USED bool undefined,1 |
186 # USE_3_BEAM_ON_LOW_CORR bool undefined,1 |
194 # USE_3_BEAM_ON_LOW_CORR bool undefined,1 |
187 # BIN_MAPPING_ALLOWED bool undefined,1 |
195 # BIN_MAPPING_ALLOWED bool undefined,1 |
188 # HEADING_ALIGNMENT scalar -179.99..180 [deg] |
196 # HEADING_ALIGNMENT scalar -179.99..180 [deg] |
189 # HEADING_BIAS scalar -179.99..180 [deg] |
197 # HEADING_BIAS scalar -179.99..180 [deg] |
190 # CALCULATE_SPEED_OF_SOUND bool undefined,1 |
198 # CALCULATE_SPEED_OF_SOUND bool undefined,1 |
191 # USE_PRESSURE_SENSOR bool undefined,1 |
199 # USE_PRESSURE_SENSOR bool undefined,1 |
192 # USE_COMPASS bool undefined,1 |
200 # USE_COMPASS bool undefined,1 |
193 # USE_PITCH_SENSOR bool undefined,1 |
201 # USE_PITCH_SENSOR bool undefined,1 |
194 # USE_ROLL_SENSOR bool undefined,1 |
202 # USE_ROLL_SENSOR bool undefined,1 |
195 # USE_CONDUCTIVITY_SENSOR bool undefined,1 |
203 # USE_CONDUCTIVITY_SENSOR bool undefined,1 |
196 # USE_TEMPERATURE_SENSOR bool undefined,1 |
204 # USE_TEMPERATURE_SENSOR bool undefined,1 |
197 # SPEED_OF_SOUND_CALCULATED bool undefined,1 |
205 # SPEED_OF_SOUND_CALCULATED bool undefined,1 |
198 # PRESSURE_SENSOR_AVAILABLE bool undefined,1 |
206 # PRESSURE_SENSOR_AVAILABLE bool undefined,1 |
199 # COMPASS_AVAILABLE bool undefined,1 |
207 # COMPASS_AVAILABLE bool undefined,1 |
200 # PITCH_SENSOR_AVAILABLE bool undefined,1 |
208 # PITCH_SENSOR_AVAILABLE bool undefined,1 |
201 # ROLL_SENSOR_AVAILABLE bool undefined,1 |
209 # ROLL_SENSOR_AVAILABLE bool undefined,1 |
202 # CONDUCTIVITY_SENSOR_AVAILABLE bool undefined,1 |
210 # CONDUCTIVITY_SENSOR_AVAILABLE bool undefined,1 |
203 # TEMPERATURE_SENSOR_AVAILABLE bool undefined,1 |
211 # TEMPERATURE_SENSOR_AVAILABLE bool undefined,1 |
204 # DISTANCE_TO_BIN1_CENTER scalar 0--655.35 [m] |
212 # DISTANCE_TO_BIN1_CENTER scalar 0--655.35 [m] |
205 # TRANSMITTED_PULSE_LENGTH scalar 0--655.35 [m] |
213 # TRANSMITTED_PULSE_LENGTH scalar 0--655.35 [m] |
206 # RL_FIRST_BIN scalar 1--128 |
214 # RL_FIRST_BIN scalar 1--128 |
207 # RL_LAST_BIN scalar 1--128 |
215 # RL_LAST_BIN scalar 1--128 |
208 # FALSE_TARGET_THRESHOLD scalar 0--254, undefined=disabled |
216 # FALSE_TARGET_THRESHOLD scalar 0--254, undefined=disabled |
209 # LOW_LATENCY_SETTING scalar 0--5(???) |
217 # LOW_LATENCY_SETTING scalar 0--5(???) |
210 # TRANSMIT_LAG_DISTANCE scalar 0--655.35 [m] |
218 # TRANSMIT_LAG_DISTANCE scalar 0--655.35 [m] |
211 # CPU_SERIAL_NUMBER scalar undefined, 0--65535 if WH300 |
219 # CPU_SERIAL_NUMBER scalar undefined, 0--65535 if WH300 |
212 # NARROW_BANDWIDTH bool undefined,1 (only set if WH300) |
220 # NARROW_BANDWIDTH bool undefined,1 (only set if WH300) |
213 # WIDE_BANDWIDTH bool undefined,1 (only set if WH300) |
221 # WIDE_BANDWIDTH bool undefined,1 (only set if WH300) |
214 # TRANSMIT_POWER scalar undefined, 0--255(high) if WH300 |
222 # TRANSMIT_POWER scalar undefined, 0--255(high) if WH300 |
215 # TRANSMIT_POWER_HIGH bool undefined,1 (only set if WH300) |
223 # TRANSMIT_POWER_HIGH bool undefined,1 (only set if WH300) |
216 # BT_PINGS_PER_ENSEMBLE scalar 0--999 |
224 # BT_PINGS_PER_ENSEMBLE scalar 0--999 |
217 # BT_DELAY_BEFORE_REACQUIRE scalar 0--999 |
225 # BT_DELAY_BEFORE_REACQUIRE scalar 0--999 |
218 # BT_MIN_CORRELATION scalar 0--255 |
226 # BT_MIN_CORRELATION scalar 0--255 |
219 # BT_MIN_EVAL_AMPLITUDE scalar 0--255 |
227 # BT_MIN_EVAL_AMPLITUDE scalar 0--255 |
220 # BT_MIN_PERCENT_GOOD scalar 0--100 [%] |
228 # BT_MIN_PERCENT_GOOD scalar 0--100 [%] |
221 # BT_MODE scalar 4,5,6(?) |
229 # BT_MODE scalar 4,5,6(?) |
222 # BT_MAX_ERROR_VELOCITY scalar 0--5 [m/s], undef=not screened |
230 # BT_MAX_ERROR_VELOCITY scalar 0--5 [m/s], undef=not screened |
223 # BT_RL_MIN_SIZE scalar 0--99.9 [m] |
231 # BT_RL_MIN_SIZE scalar 0--99.9 [m] |
224 # BT_RL_NEAR scalar 0--999.9 [m] |
232 # BT_RL_NEAR scalar 0--999.9 [m] |
225 # BT_RL_FAR scalar 0--999.9 [m] |
233 # BT_RL_FAR scalar 0--999.9 [m] |
226 # BT_MAX_TRACKING_DEPTH scalar 8--999.9 [m] |
234 # BT_MAX_TRACKING_DEPTH scalar 8--999.9 [m] |
227 # ENSEMBLE[ensemble_no-1] array ensemble info |
235 # ENSEMBLE[ensemble_no-1] array ensemble info |
228 # XDUCER_FACING_UP bool undefined, 1 |
236 # XDUCER_FACING_UP bool undefined, 1 |
229 # XDUCER_FACING_DOWN bool undefined, 1 |
237 # XDUCER_FACING_DOWN bool undefined, 1 |
230 # N_BEAMS_USED scalar 3,4,5(?) |
238 # N_BEAMS_USED scalar 3,4,5(?) |
231 # NUMBER scalar 1--16777215 |
239 # NUMBER scalar 1--16777215 |
232 # BUILT_IN_TEST_ERROR scalar ?,undefined=none |
240 # BUILT_IN_TEST_ERROR scalar ?,undefined=none |
233 # SPEED_OF_SOUND scalar 1400--1600 [m/s] |
241 # SPEED_OF_SOUND scalar 1400--1600 [m/s] |
234 # XDUCER_DEPTH scalar 0.1--999.9 [m] |
242 # XDUCER_DEPTH scalar 0.1--999.9 [m] |
235 # HEADING scalar 0--359.99 [deg] --- IMP EXTENSION: undef |
243 # HEADING scalar 0--359.99 [deg] --- IMP EXTENSION: undef |
236 # PITCH scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef |
244 # PITCH scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef |
237 # ROLL scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef |
245 # ROLL scalar -20.00-20.00 [deg] --- IMP EXTENSION: undef |
238 # SALINITY scalar 0-40 [psu] |
246 # SALINITY scalar 0-40 [psu] |
239 # TEMPERATURE scalar -5.00--40.00 [deg] |
247 # TEMPERATURE scalar -5.00--40.00 [deg] |
240 # MIN_PRE_PING_WAIT_TIME scalar ? [s] |
248 # MIN_PRE_PING_WAIT_TIME scalar ? [s] |
241 # HEADING_STDDEV scalar 0-180 [deg] |
249 # HEADING_STDDEV scalar 0-180 [deg] |
242 # PITCH_STDDEV scalar 0.0-20.0 [deg] |
250 # PITCH_STDDEV scalar 0.0-20.0 [deg] |
243 # ROLL_STDDEV scalar 0.0-20.0 [deg] |
251 # ROLL_STDDEV scalar 0.0-20.0 [deg] |
244 # ADC_XMIT_CURRENT scalar 0--255 |
252 # ADC_XMIT_CURRENT scalar 0--255 |
245 # ADC_XMIT_VOLTAGE scalar 0--255 |
253 # ADC_XMIT_VOLTAGE scalar 0--255 |
246 # ADC_AMBIENT_TEMPERATURE scalar 0--255 |
254 # ADC_AMBIENT_TEMPERATURE scalar 0--255 |
247 # ADC_PRESSURE_PLUS scalar 0--255 |
255 # ADC_PRESSURE_PLUS scalar 0--255 |
248 # ADC_PRESSURE_MINUS scalar 0--255 |
256 # ADC_PRESSURE_MINUS scalar 0--255 |
249 # ADC_ATTITUDE_TEMPERATURE scalar 0--255 |
257 # ADC_ATTITUDE_TEMPERATURE scalar 0--255 |
250 # ADC_ATTITUDE scalar 0--255 |
258 # ADC_ATTITUDE scalar 0--255 |
251 # ADC_CONTAMINATION scalar 0--255 |
259 # ADC_CONTAMINATION scalar 0--255 |
252 # ERROR_STATUS_WORD scalar undefined, ? (only set if WH300) |
260 # ERROR_STATUS_WORD scalar undefined, ? (only set if WH300) |
253 # PRESSURE scalar undefined, ?-? [dbar] (only set if WH300) |
261 # PRESSURE scalar undefined, ?-? [dbar] (only set if WH300) |
254 # PRESSURE_STDDEV scalar undefined, ?-? [dbar] (only set if WH300) |
262 # PRESSURE_STDDEV scalar undefined, ?-? [dbar] (only set if WH300) |
255 # DATE string MM/DD/YYYY |
263 # DATE string MM/DD/YYYY |
256 # YEAR scalar ? |
264 # YEAR scalar ? |
257 # MONTH scalar 1--12 |
265 # MONTH scalar 1--12 |
258 # DAY scalar 1--31 |
266 # DAY scalar 1--31 |
259 # TIME string HH:MM:SS.hh |
267 # TIME string HH:MM:SS.hh |
260 # HOUR scalar 0--23 |
268 # HOUR scalar 0--23 |
261 # MINUTE scalar 0--59 |
269 # MINUTE scalar 0--59 |
262 # SECONDS scalar 0--59.99 |
270 # SECONDS scalar 0--59.99 |
263 # UNIX_TIME scalar 0--? |
271 # UNIX_TIME scalar 0--? |
264 # SECNO scalar 0--? (number of seconds since daystart) |
272 # SECNO scalar 0--? (number of seconds since daystart) |
265 # DAYNO double fractional day number since start of current year (1.0 is midnight Jan 1st) |
273 # DAYNO double fractional day number since start of current year (1.0 is midnight Jan 1st) |
266 # VELOCITY[bin][beam] scalars -32.767--32.768 [m/s], undef=bad |
274 # VELOCITY[bin][beam] scalars -32.767--32.768 [m/s], undef=bad |
267 # CORRELATION[bin][beam] scalars 1--255, undefined=bad |
275 # CORRELATION[bin][beam] scalars 1--255, undefined=bad |
268 # ECHO_AMPLITUDE[bin][beam] scalars 0--255 |
276 # ECHO_AMPLITUDE[bin][beam] scalars 0--255 |
269 # PERCENT_GOOD[bin][beam] scalars 0--255 |
277 # PERCENT_GOOD[bin][beam] scalars 0--255 |
270 # BT_RANGE[beam] scalars tons [m] |
278 # BT_RANGE[beam] scalars tons [m] |
271 # BT_VELOCITY[beam] scalars see VELOCITY |
279 # BT_VELOCITY[beam] scalars see VELOCITY |
272 # BT_CORRELATION[beam] scalars see CORRELATION |
280 # BT_CORRELATION[beam] scalars see CORRELATION |
273 # BT_EVAL_AMPLITUDE[beam] scalars 0--255 |
281 # BT_EVAL_AMPLITUDE[beam] scalars 0--255 |
274 # BT_PERCENT_GOOD[beam] scalars see PERCENT_GOOD |
282 # BT_PERCENT_GOOD[beam] scalars see PERCENT_GOOD |
275 # BT_RL_VELOCITY[beam] scalars see VELOCITY |
283 # BT_RL_VELOCITY[beam] scalars see VELOCITY |
276 # BT_RL_CORRELATION[beam] scalars see CORRELATION |
284 # BT_RL_CORRELATION[beam] scalars see CORRELATION |
277 # BT_RL_ECHO_AMPLITUDE[beam] scalars see ECHO_AMPLITUDE |
285 # BT_RL_ECHO_AMPLITUDE[beam] scalars see ECHO_AMPLITUDE |
278 # BT_RL_PERCENT_GOOD[beam] scalars see PERCENT_GOOD |
286 # BT_RL_PERCENT_GOOD[beam] scalars see PERCENT_GOOD |
279 # BT_SIGNAL_STRENGTH[beam] scalars 0--255 |
287 # BT_SIGNAL_STRENGTH[beam] scalars 0--255 |
280 # HIGH_GAIN bool 1, undefined |
288 # HIGH_GAIN bool 1, undefined |
281 # LOW_GAIN bool 1, undefined |
289 # LOW_GAIN bool 1, undefined |
282 |
290 |
283 use strict; |
291 use strict; |
284 use Time::Local; # timegm() |
292 use Time::Local; # timegm() |
285 |
293 |
286 #---------------------------------------------------------------------- |
294 #---------------------------------------------------------------------- |
287 # Time Conversion Subroutines |
295 # Time Conversion Subroutines |
288 #---------------------------------------------------------------------- |
296 #---------------------------------------------------------------------- |
289 |
297 |
290 sub monthLength($$) # of days in month |
298 sub monthLength($$) # of days in month |
291 { |
299 { |
292 my($Y,$M) = @_; |
300 my($Y,$M) = @_; |
293 |
301 |
294 return 31 if ($M==1 || $M==3 || $M==5 || $M==7 || |
302 return 31 if ($M==1 || $M==3 || $M==5 || $M==7 || |
295 $M==8 || $M==10 || $M==12); |
303 $M==8 || $M==10 || $M==12); |
296 return 30 if ($M==4 || $M==6 || $M==9 || $M==11); |
304 return 30 if ($M==4 || $M==6 || $M==9 || $M==11); |
297 return 28 if ($Y%4 != 0); |
305 return 28 if ($Y%4 != 0); |
298 return 29 if ($Y%100 != 0); |
306 return 29 if ($Y%100 != 0); |
299 return 28 if ($Y%400 > 0); |
307 return 28 if ($Y%400 > 0); |
300 return 29; |
308 return 29; |
301 } |
309 } |
302 |
310 |
303 { my($epoch,$lM,$lD,$lY,$ldn); # static scope |
311 { my($epoch,$lM,$lD,$lY,$ldn); # static scope |
304 |
312 |
305 sub dayNo($$$$$$) |
313 sub dayNo($$$$$$) |
306 { |
314 { |
307 my($Y,$M,$D,$h,$m,$s) = @_; |
315 my($Y,$M,$D,$h,$m,$s) = @_; |
308 my($dn); |
316 my($dn); |
309 |
317 |
310 if ($Y==$lY && $M==$lM && $D==$lD) { # same day as last samp |
318 if ($Y==$lY && $M==$lM && $D==$lD) { # same day as last samp |
311 $dn = $ldn; |
319 $dn = $ldn; |
312 } else { # new day |
320 } else { # new day |
313 $epoch = $Y unless defined($epoch); # 1st call |
321 $epoch = $Y unless defined($epoch); # 1st call |
314 $lY = $Y; $lM = $M; $lD = $D; # store |
322 $lY = $Y; $lM = $M; $lD = $D; # store |
315 |
323 |
316 for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) { # multiple years |
324 for ($dn=0,my($cY)=$epoch; $cY<$Y; $cY++) { # multiple years |
317 $dn += 337 + &monthLength($Y,$M); |
325 $dn += 337 + &monthLength($Y,$M); |
|
326 } |
|
327 |
|
328 $dn += $D; # day in month |
|
329 while (--$M > 0) { # preceding months |
|
330 $dn += &monthLength($Y,$M); |
|
331 } |
|
332 |
|
333 $ldn = $dn; # store |
318 } |
334 } |
319 |
335 return $dn + $h/24 + $m/24/60 + $s/24/3600; |
320 $dn += $D; # day in month |
|
321 while (--$M > 0) { # preceding months |
|
322 $dn += &monthLength($Y,$M); |
|
323 } |
|
324 |
|
325 $ldn = $dn; # store |
|
326 } |
336 } |
327 return $dn + $h/24 + $m/24/60 + $s/24/3600; |
337 |
328 } |
338 } # static scope |
329 |
339 |
330 } # static scope |
|
331 |
|
332 #---------------------------------------------------------------------- |
340 #---------------------------------------------------------------------- |
333 # Read Data |
341 # Read Data |
334 #---------------------------------------------------------------------- |
342 #---------------------------------------------------------------------- |
335 |
343 |
336 my($WBRcfn,$WBPcfn); # current file names for reading/patching |
344 my($WBRcfn,$WBPcfn); # current file names for reading/patching |
337 my($BIT_errors) = 0; # built-in-test errors |
345 my($BIT_errors) = 0; # built-in-test errors |
338 |
346 |
339 my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d"; |
347 my($FmtErr) = "%s: illegal %s Id 0x%04x at ensemble %d"; |
340 |
348 |
341 #---------------------------------------------------------------------- |
349 #---------------------------------------------------------------------- |
342 # skip to first valid ensemble (skip over initial garbage) |
350 # skip to first valid ensemble (skip over initial garbage) |
343 #---------------------------------------------------------------------- |
351 #---------------------------------------------------------------------- |
344 |
352 |
345 sub skip_initial_trash(@) |
353 sub skip_initial_trash(@) |
346 { |
354 { |
347 my($quiet) = @_; |
355 my($quiet) = @_; |
348 my($buf,$dta); |
356 my($buf,$dta); |
349 |
357 |
350 my($found) = 0; # zero consecutive 0x7f found |
358 my($found) = 0; # zero consecutive 0x7f found |
351 my($skipped) = 0; |
359 my($skipped) = 0; |
352 while ($found < 2) { |
360 while ($found < 2) { |
353 sysread(WBRF,$buf,1) == 1 || last; |
361 sysread(WBRF,$buf,1) == 1 || last; |
354 ($dta) = unpack('C',$buf); |
362 ($dta) = unpack('C',$buf); |
355 if ($dta == 0x7f) { |
363 if ($dta == 0x7f) { |
356 $found++; |
364 $found++; |
357 } elsif ($found==1 && ($dta==0xE0 || ($dta&0xF0==0xA0 && $dta&0x0F<8))) { |
365 } elsif ($found==1 && ($dta==0xE0 || ($dta&0xF0==0xA0 && $dta&0x0F<8))) { |
358 $found++; |
366 $found++; |
359 } elsif ($found == 0) { |
367 } elsif ($found == 0) { |
360 $skipped++; |
368 $skipped++; |
361 } else { |
369 } else { |
362 $skipped += $found; |
370 $skipped += $found; |
363 $found = 0; |
371 $found = 0; |
364 } |
372 } |
|
373 } |
|
374 die("$WBRcfn: no valid ensemble header found [$!]\n") |
|
375 if ($found < 2); |
|
376 printf(STDERR "WARNING: %d bytes of initial garbage\n",$skipped) |
|
377 if ($skipped > 0 && !$quiet); |
|
378 return sysseek(WBRF,-2,1); |
365 } |
379 } |
366 die("$WBRcfn: no valid ensemble header found [$!]\n") |
380 |
367 if ($found < 2); |
|
368 printf(STDERR "WARNING: %d bytes of initial garbage\n",$skipped) |
|
369 if ($skipped > 0 && !$quiet); |
|
370 return sysseek(WBRF,-2,1); |
|
371 } |
|
372 |
|
373 #---------------------------------------------------------------------- |
381 #---------------------------------------------------------------------- |
374 # readHeader(file_name,^dta) WBRhdr(^data) |
382 # readHeader(file_name,^dta) WBRhdr(^data) |
375 # - read header data |
383 # - read header data |
376 # - also includes some data from 1st ens |
384 # - also includes some data from 1st ens |
377 #---------------------------------------------------------------------- |
385 #---------------------------------------------------------------------- |
378 |
386 |
379 sub readHeader(@) |
387 sub readHeader(@) |
380 { |
388 { |
381 my($fn,$dta) = @_; |
389 my($fn,$dta) = @_; |
382 $WBRcfn = $fn; |
390 $WBRcfn = $fn; |
383 open(WBRF,$WBRcfn) || die("$WBRcfn: $!"); |
391 open(WBRF,$WBRcfn) || die("$WBRcfn: $!"); |
384 WBRhdr($dta) || die("$WBRcfn: Insufficient data\n"); |
392 WBRhdr($dta) || die("$WBRcfn: Insufficient data\n"); |
385 } |
393 } |
386 |
394 |
387 sub WBRhdr($) |
395 sub WBRhdr(@) |
388 { |
396 { |
389 my($dta) = @_; |
397 my($dta,$checkFmt) = @_; |
390 my($start_ens,$buf,$hid,$did,$Ndt,$B,$W,$i,$dummy,$id,@WBRofs); |
398 my($start_ens,$buf,$hid,$did,$Ndt,$B,$W,$i,$dummy,$id,@WBRofs); |
391 my($B1,$B2,$B3,$B4,$B5,$B6,$B7,$W1,$W2,$W3,$W4,$W5); |
399 my($B1,$B2,$B3,$B4,$B5,$B6,$B7,$W1,$W2,$W3,$W4,$W5); |
392 |
400 my($BT_dt); |
|
401 |
393 #-------------------- |
402 #-------------------- |
394 # HEADER |
403 # HEADER |
395 #-------------------- |
404 #-------------------- |
396 |
405 |
397 skip_initial_trash(); |
406 skip_initial_trash(); |
415 $dta->{PRODUCER} = 'editPD0 (Thurnherr software)'; |
424 $dta->{PRODUCER} = 'editPD0 (Thurnherr software)'; |
416 } else { |
425 } else { |
417 $dta->{PRODUCER} = sprintf('unknown (0x%02X)'); |
426 $dta->{PRODUCER} = sprintf('unknown (0x%02X)'); |
418 } |
427 } |
419 |
428 |
420 printf(STDERR "WARNING: unexpected number of data types (%d)\n", |
429 if ($checkFmt) { |
421 $dta->{NUMBER_OF_DATA_TYPES}) |
430 printf(STDERR "WARNING: unexpected number of data types (%d)\n", |
422 unless ($dta->{NUMBER_OF_DATA_TYPES} == 6 || |
431 $dta->{NUMBER_OF_DATA_TYPES}) |
423 $dta->{NUMBER_OF_DATA_TYPES} == 7); |
432 unless ($dta->{NUMBER_OF_DATA_TYPES} == 6 || |
424 ## $dta->{BT_PRESENT} = ($dta->{NUMBER_OF_DATA_TYPES} == 7); |
433 $dta->{NUMBER_OF_DATA_TYPES} == 7); |
425 $dta->{BT_PRESENT} = ($dta->{NUMBER_OF_DATA_TYPES} >= 7); |
434 $dta->{BT_PRESENT} = ($dta->{NUMBER_OF_DATA_TYPES} >= 7); |
|
435 } |
426 |
436 |
427 sysread(WBRF,$buf,2*$dta->{NUMBER_OF_DATA_TYPES}) |
437 sysread(WBRF,$buf,2*$dta->{NUMBER_OF_DATA_TYPES}) |
428 == 2*$dta->{NUMBER_OF_DATA_TYPES} |
438 == 2*$dta->{NUMBER_OF_DATA_TYPES} |
429 || die("$WBRcfn: $!"); |
439 || die("$WBRcfn: $!"); |
430 @WBRofs = unpack("v$dta->{NUMBER_OF_DATA_TYPES}",$buf); |
440 @WBRofs = unpack("v$dta->{NUMBER_OF_DATA_TYPES}",$buf); |
431 |
|
432 $dta->{HEADER_BYTES} = $WBRofs[0]; |
|
433 $dta->{FIXED_LEADER_BYTES} = $WBRofs[1] - $WBRofs[0]; |
|
434 $dta->{VARIABLE_LEADER_BYTES} = $WBRofs[2] - $WBRofs[1]; |
|
435 $dta->{VELOCITY_DATA_BYTES} = $WBRofs[3] - $WBRofs[2]; |
|
436 $dta->{CORRELATION_DATA_BYTES} = $WBRofs[4] - $WBRofs[3]; |
|
437 $dta->{ECHO_INTENSITY_DATA_BYTES} = $WBRofs[5] - $WBRofs[4]; |
|
438 if ($dta->{BT_PRESENT}) { |
|
439 $dta->{PERCENT_GOOD_DATA_BYTES} = $WBRofs[6] - $WBRofs[5]; |
|
440 $dta->{BT_DATA_BYTES} = $dta->{ENSEMBLE_BYTES} - 4 - $WBRofs[6]; |
|
441 } else { |
|
442 $dta->{PERCENT_GOOD_DATA_BYTES} = $dta->{ENSEMBLE_BYTES} - 4 - $WBRofs[5]; |
|
443 } |
|
444 |
|
445 if ($dta->{FIXED_LEADER_BYTES} == 42) { # Eric Firing's old instrument I used in 2004 |
|
446 $dta->{INSTRUMENT_TYPE} = 'BB150'; |
|
447 } elsif ($dta->{FIXED_LEADER_BYTES} == 53) { # old firmware: no serial numbers |
|
448 $dta->{INSTRUMENT_TYPE} = 'Workhorse'; |
|
449 } elsif ($dta->{FIXED_LEADER_BYTES} == 59) { # new firmware: with serial numbers |
|
450 $dta->{INSTRUMENT_TYPE} = 'Workhorse'; |
|
451 } elsif ($dta->{FIXED_LEADER_BYTES} == 58) { # DVL |
|
452 $dta->{INSTRUMENT_TYPE} = 'Explorer'; |
|
453 } |
|
454 |
|
455 # for ($i=0; $i<$dta->{NUMBER_OF_DATA_TYPES}; $i++) { |
441 # for ($i=0; $i<$dta->{NUMBER_OF_DATA_TYPES}; $i++) { |
456 # printf(STDERR "\nWBRofs[$i] = %d",$WBRofs[$i]); |
442 # printf(STDERR "\nWBRofs[$i] = %d",$WBRofs[$i]); |
457 # } |
443 # } |
458 |
444 |
|
445 |
|
446 $dta->{HEADER_BYTES} = $WBRofs[0]; |
|
447 $dta->{FIXED_LEADER_BYTES} = $WBRofs[1] - $WBRofs[0]; |
|
448 $dta->{VARIABLE_LEADER_BYTES} = $WBRofs[2] - $WBRofs[1]; |
|
449 if ($checkFmt) { |
|
450 $dta->{VELOCITY_DATA_BYTES} = $WBRofs[3] - $WBRofs[2]; |
|
451 $dta->{CORRELATION_DATA_BYTES} = $WBRofs[4] - $WBRofs[3]; |
|
452 $dta->{ECHO_INTENSITY_DATA_BYTES} = $WBRofs[5] - $WBRofs[4]; |
|
453 if ($dta->{BT_PRESENT}) { |
|
454 $dta->{PERCENT_GOOD_DATA_BYTES} = $WBRofs[6] - $WBRofs[5]; |
|
455 $dta->{BT_DATA_BYTES} = $dta->{ENSEMBLE_BYTES} - 4 - $WBRofs[6]; |
|
456 } else { |
|
457 $dta->{PERCENT_GOOD_DATA_BYTES} = $dta->{ENSEMBLE_BYTES} - 4 - $WBRofs[5]; |
|
458 } |
|
459 } |
|
460 |
|
461 if ($dta->{FIXED_LEADER_BYTES} == 42) { # Eric Firing's old instrument I used in 2004 |
|
462 $dta->{INSTRUMENT_TYPE} = 'BB150'; |
|
463 } elsif ($dta->{FIXED_LEADER_BYTES} == 53) { # old firmware: no serial numbers |
|
464 $dta->{INSTRUMENT_TYPE} = 'Workhorse'; |
|
465 } elsif ($dta->{FIXED_LEADER_BYTES} == 59) { # new firmware: with serial numbers |
|
466 $dta->{INSTRUMENT_TYPE} = 'Workhorse'; |
|
467 } elsif ($dta->{FIXED_LEADER_BYTES} == 58) { # DVL |
|
468 $dta->{INSTRUMENT_TYPE} = 'Explorer'; |
|
469 } elsif ($dta->{FIXED_LEADER_BYTES} == 60) { # OS75 |
|
470 $dta->{INSTRUMENT_TYPE} = 'Ocean Surveyor'; |
|
471 } else { |
|
472 $dta->{INSTRUMENT_TYPE} = 'unknown'; |
|
473 } |
|
474 |
|
475 #-------------------------------- |
|
476 # Variable Leader: SPEED_OF_SOUND |
|
477 #-------------------------------- |
|
478 |
|
479 sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!"); |
|
480 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
|
481 $id = unpack('v',$buf); |
|
482 if ($dta->{INSTRUMENT_TYPE} eq 'Ocean Surveyor') { |
|
483 $id == 0x0081 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1); |
|
484 } else { |
|
485 $id == 0x0080 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1); |
|
486 } |
|
487 sysseek(WBRF,12,1) || die("$WBRcfn: $!"); # skip up to speed of sound |
|
488 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
|
489 $dta->{SPEED_OF_SOUND} = unpack('v',$buf); |
|
490 |
459 #---------------------------------- |
491 #---------------------------------- |
460 # Check Data Format of 1st Ensemble |
492 # Check Data Format of 1st Ensemble |
461 #---------------------------------- |
493 #---------------------------------- |
462 |
494 |
463 sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!"); |
495 if ($checkFmt) { |
464 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
496 sysseek(WBRF,$start_ens+$WBRofs[2],0) || die("$WBRcfn: $!"); |
465 $id = unpack('v',$buf); |
497 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
466 $id == 0x0080 || printf(STDERR $FmtErr."\n",$WBRcfn,"Variable Leader",$id,1); |
498 $id = unpack('v',$buf); |
467 |
499 $id == 0x0100 || printf(STDERR $FmtErr."\n",$WBRcfn,"Velocity Data",$id,1); |
468 sysseek(WBRF,$start_ens+$WBRofs[2],0) || die("$WBRcfn: $!"); |
500 |
469 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
501 sysseek(WBRF,$start_ens+$WBRofs[3],0) || die("$WBRcfn: $!"); |
470 $id = unpack('v',$buf); |
502 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
471 $id == 0x0100 || printf(STDERR $FmtErr."\n",$WBRcfn,"Velocity Data",$id,1); |
503 $id = unpack('v',$buf); |
472 |
504 $id == 0x0200 || printf(STDERR $FmtErr."\n",$WBRcfn,"Correlation Data",$id,1); |
473 sysseek(WBRF,$start_ens+$WBRofs[3],0) || die("$WBRcfn: $!"); |
505 |
474 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
506 sysseek(WBRF,$start_ens+$WBRofs[4],0) || die("$WBRcfn: $!"); |
475 $id = unpack('v',$buf); |
507 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
476 $id == 0x0200 || printf(STDERR $FmtErr."\n",$WBRcfn,"Correlation Data",$id,1); |
508 $id = unpack('v',$buf); |
477 |
509 $id == 0x0300 || printf(STDERR $FmtErr."\n",$WBRcfn,"Echo Intensity",$id,1); |
478 sysseek(WBRF,$start_ens+$WBRofs[4],0) || die("$WBRcfn: $!"); |
510 |
479 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
511 sysseek(WBRF,$start_ens+$WBRofs[5],0) || die("$WBRcfn: $!"); |
480 $id = unpack('v',$buf); |
512 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
481 $id == 0x0300 || printf(STDERR $FmtErr."\n",$WBRcfn,"Echo Intensity",$id,1); |
513 $id = unpack('v',$buf); |
482 |
514 $id == 0x0400 || printf(STDERR $FmtErr."\n",$WBRcfn,"Percent-Good Data",$id,1); |
483 sysseek(WBRF,$start_ens+$WBRofs[5],0) || die("$WBRcfn: $!"); |
515 |
484 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
516 if ($dta->{BT_PRESENT}) { |
485 $id = unpack('v',$buf); |
517 for ($BT_dt=6; $BT_dt<$dta->{NUMBER_OF_DATA_TYPES}; $BT_dt++) { # scan until BT found |
486 $id == 0x0400 || printf(STDERR $FmtErr."\n",$WBRcfn,"Percent-Good Data",$id,1); |
518 sysseek(WBRF,$start_ens+$WBRofs[$BT_dt],0) || die("$WBRcfn: $!"); |
487 |
519 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
488 my($BT_dt); |
520 $id = unpack('v',$buf); |
489 if ($dta->{BT_PRESENT}) { |
521 last if ($id == 0x0600); |
490 for ($BT_dt=6; $BT_dt<$dta->{NUMBER_OF_DATA_TYPES}; $BT_dt++) { # scan until BT found |
522 } |
491 sysseek(WBRF,$start_ens+$WBRofs[$BT_dt],0) || die("$WBRcfn: $!"); |
523 |
492 sysread(WBRF,$buf,2) == 2 || die("$WBRcfn: $!"); |
524 if ($BT_dt == $dta->{NUMBER_OF_DATA_TYPES}) { |
493 $id = unpack('v',$buf); |
525 printf(STDERR "WARNING: no BT data found\n");die; |
494 last if ($id == 0x0600); |
526 undef($dta->{BT_PRESENT}); |
495 } |
527 } |
496 |
528 } |
497 if ($BT_dt == $dta->{NUMBER_OF_DATA_TYPES}) { |
|
498 printf(STDERR "WARNING: no BT data found\n");die; |
|
499 undef($dta->{BT_PRESENT}); |
|
500 } |
|
501 } |
529 } |
502 |
530 |
503 #-------------------- |
531 #-------------------- |
504 # FIXED LEADER |
532 # FIXED LEADER |
505 #-------------------- |
533 #-------------------- |
506 |
534 |
507 sysseek(WBRF,$start_ens+$WBRofs[0],0) || die("$WBRcfn: $!"); |
535 sysseek(WBRF,$start_ens+$WBRofs[0],0) || die("$WBRcfn: $!"); |
508 sysread(WBRF,$buf,42) == 42 || die("$WBRcfn: $!"); |
536 sysread(WBRF,$buf,42) == 42 || die("$WBRcfn: $!"); |
509 ($id,$dta->{CPU_FW_VER},$dta->{CPU_FW_REV},$B1,$B2,$dummy,$dummy,$dummy, |
537 ($id,$dta->{CPU_FW_VER},$dta->{CPU_FW_REV},$B1,$B2,$dummy, |
|
538 $dta->{LAG_LENGTH},$dummy, |
510 $dta->{N_BINS},$dta->{PINGS_PER_ENSEMBLE},$dta->{BIN_LENGTH}, |
539 $dta->{N_BINS},$dta->{PINGS_PER_ENSEMBLE},$dta->{BIN_LENGTH}, |
511 $dta->{BLANKING_DISTANCE},$dummy,$dta->{MIN_CORRELATION}, |
540 $dta->{BLANKING_DISTANCE},$dummy,$dta->{MIN_CORRELATION}, |
512 $dta->{N_CODE_REPETITIONS},$dta->{MIN_PERCENT_GOOD}, |
541 $dta->{N_CODE_REPETITIONS},$dta->{MIN_PERCENT_GOOD}, |
513 $dta->{MAX_ERROR_VELOCITY},$dta->{TIME_BETWEEN_PINGS},$B3,$B4,$B5, |
542 $dta->{MAX_ERROR_VELOCITY},$dta->{TIME_BETWEEN_PINGS},$B3,$B4,$B5, |
514 $dta->{HEADING_ALIGNMENT},$dta->{HEADING_BIAS},$B6,$B7, |
543 $dta->{HEADING_ALIGNMENT},$dta->{HEADING_BIAS},$B6,$B7, |