1 /***************************************************************************
3 * Routines to parse Mini-SEED.
5 * Written by Chad Trabant
6 * IRIS Data Management Center
9 ***************************************************************************/
20 /**********************************************************************
23 * This routine will attempt to parse (detect and unpack) a Mini-SEED
24 * record from a specified memory buffer and populate a supplied
27 * If reclen is less than or equal to 0 the length of record is
28 * automatically detected otherwise reclen should be the correct
31 * For auto detection of record length the record should include a
32 * 1000 blockette or be followed by another record header in the
35 * dataflag will be passed directly to msr_unpack().
38 * 0 : Success, populates the supplied MSRecord.
39 * >0 : Data record detected but not enough data is present, the
40 * return value is a hint of how many more bytes are needed.
41 * <0 : libmseed error code (listed in libmseed.h) is returned.
42 *********************************************************************/
44 msr_parse ( char *record
, int recbuflen
, MSRecord
**ppmsr
, int reclen
,
45 flag dataflag
, flag verbose
)
56 /* Sanity check: record length cannot be larger than buffer */
57 if ( reclen
> 0 && reclen
> recbuflen
)
59 ms_log (2, "ms_parse() Record length (%d) cannot be larger than buffer (%d)\n",
64 /* Autodetect the record length */
67 detlen
= ms_detect (record
, recbuflen
);
69 /* No data record detected */
75 /* Found record but could not determine length */
83 ms_log (1, "Detected record length of %d bytes\n", detlen
);
89 /* Check that record length is in supported range */
90 if ( reclen
< MINRECLEN
|| reclen
> MAXRECLEN
)
92 ms_log (2, "Record length is out of range: %d (allowed: %d to %d)\n",
93 reclen
, MINRECLEN
, MAXRECLEN
);
98 /* Check if more data is required, return hint */
99 if ( reclen
> recbuflen
)
102 ms_log (1, "Detected %d byte record, need %d more bytes\n",
103 reclen
, (reclen
- recbuflen
));
105 return (reclen
- recbuflen
);
109 if ( (retcode
= msr_unpack (record
, reclen
, ppmsr
, dataflag
, verbose
)) != MS_NOERROR
)
117 } /* End of msr_parse() */
120 /**********************************************************************
121 * msr_parse_selection:
123 * This routine wraps msr_parse() to parse and return the first record
124 * from a memory buffer that matches optional Selections. If the
125 * selections pointer is NULL the effect is to search the buffer for
126 * the first parsable record.
128 * The offset value specifies the starting offset in the buffer and,
129 * on success, the offset in the buffer to record parsed.
131 * The caller should manage the value of the offset in two ways:
133 * 1) on subsequent calls after a record has been parsed the caller
134 * should increment the offset by the record length returned or
135 * properly manipulate the record buffer pointer, buffer length and
136 * offset to the same effect.
138 * 2) when the end of the buffer is reached MS_GENERROR (-1) is
139 * returned, the caller should check the offset value against the
140 * record buffer length to determine when the entire buffer has been
143 * Return values: same as msr_parse() except that MS_GENERROR is
144 * returned when end-of-buffer is reached.
145 *********************************************************************/
147 msr_parse_selection ( char *recbuf
, int recbuflen
, int64_t *offset
,
148 MSRecord
**ppmsr
, int reclen
,
149 Selections
*selections
, flag dataflag
, flag verbose
)
151 int retval
= MS_GENERROR
;
153 flag dataswapflag
= 0;
154 flag bigendianhost
= ms_bigendianhost();
165 while ( *offset
< recbuflen
)
167 retval
= msr_parse (recbuf
+*offset
, (int)(recbuflen
-*offset
), ppmsr
, reclen
, 0, verbose
);
172 ms_log (2, "Error parsing record at offset %"PRId64
"\n", *offset
);
174 *offset
+= MINRECLEN
;
178 if ( selections
&& ! msr_matchselect (selections
, *ppmsr
, NULL
) )
180 *offset
+= (*ppmsr
)->reclen
;
181 retval
= MS_GENERROR
;
187 /* If BE host and LE data need swapping */
188 if ( bigendianhost
&& (*ppmsr
)->byteorder
== 0 )
190 /* If LE host and BE data (or bad byte order value) need swapping */
191 else if ( !bigendianhost
&& (*ppmsr
)->byteorder
> 0 )
194 unpackretval
= msr_unpack_data (*ppmsr
, dataswapflag
, verbose
);
196 if ( unpackretval
< 0 )
199 (*ppmsr
)->numsamples
= unpackretval
;
208 } /* End of msr_parse_selection() */
211 /********************************************************************
214 * Determine SEED data record length with the following steps:
216 * 1) determine that the buffer contains a SEED data record by
217 * verifying known signatures (fields with known limited values)
219 * 2) search the record up to recbuflen bytes for a 1000 blockette.
221 * 3) If no blockette 1000 is found search at MINRECLEN-byte offsets
222 * for the fixed section of the next header or blank/noise record,
223 * thereby implying the record length.
226 * -1 : data record not detected or error
227 * 0 : data record detected but could not determine length
228 * >0 : size of the record in bytes
229 *********************************************************************/
231 ms_detect ( const char *record
, int recbuflen
)
233 uint16_t blkt_offset
; /* Byte offset for next blockette */
234 uint8_t swapflag
= 0; /* Byte swapping flag */
235 uint8_t foundlen
= 0; /* Found record length */
236 int32_t reclen
= -1; /* Size of record in bytes */
242 struct blkt_1000_s
*blkt_1000
;
243 const char *nextfsdh
;
245 /* Buffer must be at least 48 bytes (the fixed section) */
246 if ( recbuflen
< 48 )
249 /* Check for valid fixed section of header */
250 if ( ! MS_ISVALIDHEADER(record
) )
253 fsdh
= (struct fsdh_s
*) record
;
255 /* Check to see if byte swapping is needed by checking for sane year and day */
256 if ( ! MS_ISVALIDYEARDAY(fsdh
->start_time
.year
, fsdh
->start_time
.day
) )
259 blkt_offset
= fsdh
->blockette_offset
;
261 /* Swap order of blkt_offset if needed */
262 if ( swapflag
) ms_gswap2 (&blkt_offset
);
264 /* Loop through blockettes as long as number is non-zero and viable */
265 while ( blkt_offset
!= 0 &&
266 blkt_offset
<= recbuflen
)
268 memcpy (&blkt_type
, record
+ blkt_offset
, 2);
269 memcpy (&next_blkt
, record
+ blkt_offset
+ 2, 2);
273 ms_gswap2 (&blkt_type
);
274 ms_gswap2 (&next_blkt
);
277 /* Found a 1000 blockette, not truncated */
278 if ( blkt_type
== 1000 &&
279 (int)(blkt_offset
+ 4 + sizeof(struct blkt_1000_s
)) <= recbuflen
)
281 blkt_1000
= (struct blkt_1000_s
*) (record
+ blkt_offset
+ 4);
285 /* Calculate record size in bytes as 2^(blkt_1000->reclen) */
286 reclen
= (unsigned int) 1 << blkt_1000
->reclen
;
291 /* Safety check for invalid offset */
292 if ( next_blkt
!= 0 && ( next_blkt
< 4 || (next_blkt
- 4) <= blkt_offset
) )
294 ms_log (2, "Invalid blockette offset (%d) less than or equal to current offset (%d)\n",
295 next_blkt
, blkt_offset
);
299 blkt_offset
= next_blkt
;
302 /* If record length was not determined by a 1000 blockette scan the buffer
303 * and search for the next record */
306 nextfsdh
= record
+ MINRECLEN
;
308 /* Check for record header or blank/noise record at MINRECLEN byte offsets */
309 while ( ((nextfsdh
- record
) + 48) < recbuflen
)
311 if ( MS_ISVALIDHEADER(nextfsdh
) || MS_ISVALIDBLANK(nextfsdh
) )
314 reclen
= nextfsdh
- record
;
318 nextfsdh
+= MINRECLEN
;
326 } /* End of ms_detect() */
329 /***************************************************************************
332 * Parse and verify a SEED data record header (fixed section and
333 * blockettes) at the lowest level, printing error messages for
334 * invalid header values and optionally print raw header values. The
335 * memory at 'record' is assumed to be a Mini-SEED record. Not every
336 * possible test is performed, common errors and those causing
337 * libmseed parsing to fail should be detected.
339 * The 'details' argument is interpreted as follows:
342 * 0 = only print error messages for invalid header fields
343 * 1 = print basic fields in addition to invalid field errors
344 * 2 = print all fields in addition to invalid field errors
346 * The 'swapflag' argument is interpreted as follows:
349 * 1 = swap multibyte quantities
351 * -1 = autodetect byte order using year test, swap if needed
353 * Any byte swapping performed by this routine is applied directly to
354 * the memory reference by the record pointer.
356 * This routine is primarily intended to diagnose invalid Mini-SEED headers.
358 * Returns 0 when no errors were detected or a positive count of
360 ***************************************************************************/
362 ms_parse_raw ( char *record
, int maxreclen
, flag details
, flag swapflag
)
370 int b1000encoding
= -1;
371 int b1000reclen
= -1;
372 int endofblockettes
= -1;
378 /* Generate a source name string */
380 ms_recsrcname (record
, srcname
, 1);
382 fsdh
= (struct fsdh_s
*) record
;
384 /* Check to see if byte swapping is needed by testing the year and day */
385 if ( swapflag
== -1 && ! MS_ISVALIDYEARDAY(fsdh
->start_time
.year
, fsdh
->start_time
.day
) )
393 ms_log (0, "Swapping multi-byte quantities in header\n");
395 ms_log (0, "Not swapping multi-byte quantities in header\n");
398 /* Swap byte order */
401 MS_SWAPBTIME (&fsdh
->start_time
);
402 ms_gswap2a (&fsdh
->numsamples
);
403 ms_gswap2a (&fsdh
->samprate_fact
);
404 ms_gswap2a (&fsdh
->samprate_mult
);
405 ms_gswap4a (&fsdh
->time_correct
);
406 ms_gswap2a (&fsdh
->data_offset
);
407 ms_gswap2a (&fsdh
->blockette_offset
);
410 /* Validate fixed section header fields */
411 X
= record
; /* Pointer of convenience */
413 /* Check record sequence number, 6 ASCII digits */
414 if ( ! isdigit((int) *(X
)) || ! isdigit ((int) *(X
+1)) ||
415 ! isdigit((int) *(X
+2)) || ! isdigit ((int) *(X
+3)) ||
416 ! isdigit((int) *(X
+4)) || ! isdigit ((int) *(X
+5)) )
418 ms_log (2, "%s: Invalid sequence number: '%c%c%c%c%c%c'\n", srcname
, X
, X
+1, X
+2, X
+3, X
+4, X
+5);
422 /* Check header/quality indicator */
423 if ( ! MS_ISDATAINDICATOR(*(X
+6)) )
425 ms_log (2, "%s: Invalid header indicator (DRQM): '%c'\n", srcname
, X
+6);
429 /* Check reserved byte, space or NULL */
430 if ( ! (*(X
+7) == ' ' || *(X
+7) == '\0') )
432 ms_log (2, "%s: Invalid fixed section reserved byte (Space): '%c'\n", srcname
, X
+7);
436 /* Check station code, 5 alphanumerics or spaces */
437 if ( ! (isalnum((unsigned char) *(X
+8)) || *(X
+8) == ' ') ||
438 ! (isalnum((unsigned char) *(X
+9)) || *(X
+9) == ' ') ||
439 ! (isalnum((unsigned char) *(X
+10)) || *(X
+10) == ' ') ||
440 ! (isalnum((unsigned char) *(X
+11)) || *(X
+11) == ' ') ||
441 ! (isalnum((unsigned char) *(X
+12)) || *(X
+12) == ' ') )
443 ms_log (2, "%s: Invalid station code: '%c%c%c%c%c'\n", srcname
, X
+8, X
+9, X
+10, X
+11, X
+12);
447 /* Check location ID, 2 alphanumerics or spaces */
448 if ( ! (isalnum((unsigned char) *(X
+13)) || *(X
+13) == ' ') ||
449 ! (isalnum((unsigned char) *(X
+14)) || *(X
+14) == ' ') )
451 ms_log (2, "%s: Invalid location ID: '%c%c'\n", srcname
, X
+13, X
+14);
455 /* Check channel codes, 3 alphanumerics or spaces */
456 if ( ! (isalnum((unsigned char) *(X
+15)) || *(X
+15) == ' ') ||
457 ! (isalnum((unsigned char) *(X
+16)) || *(X
+16) == ' ') ||
458 ! (isalnum((unsigned char) *(X
+17)) || *(X
+17) == ' ') )
460 ms_log (2, "%s: Invalid channel codes: '%c%c%c'\n", srcname
, X
+15, X
+16, X
+17);
464 /* Check network code, 2 alphanumerics or spaces */
465 if ( ! (isalnum((unsigned char) *(X
+18)) || *(X
+18) == ' ') ||
466 ! (isalnum((unsigned char) *(X
+19)) || *(X
+19) == ' ') )
468 ms_log (2, "%s: Invalid network code: '%c%c'\n", srcname
, X
+18, X
+19);
472 /* Check start time fields */
473 if ( fsdh
->start_time
.year
< 1900 || fsdh
->start_time
.year
> 2100 )
475 ms_log (2, "%s: Unlikely start year (1900-2100): '%d'\n", srcname
, fsdh
->start_time
.year
);
478 if ( fsdh
->start_time
.day
< 1 || fsdh
->start_time
.day
> 366 )
480 ms_log (2, "%s: Invalid start day (1-366): '%d'\n", srcname
, fsdh
->start_time
.day
);
483 if ( fsdh
->start_time
.hour
> 23 )
485 ms_log (2, "%s: Invalid start hour (0-23): '%d'\n", srcname
, fsdh
->start_time
.hour
);
488 if ( fsdh
->start_time
.min
> 59 )
490 ms_log (2, "%s: Invalid start minute (0-59): '%d'\n", srcname
, fsdh
->start_time
.min
);
493 if ( fsdh
->start_time
.sec
> 60 )
495 ms_log (2, "%s: Invalid start second (0-60): '%d'\n", srcname
, fsdh
->start_time
.sec
);
498 if ( fsdh
->start_time
.fract
> 9999 )
500 ms_log (2, "%s: Invalid start fractional seconds (0-9999): '%d'\n", srcname
, fsdh
->start_time
.fract
);
504 /* Check number of samples, max samples in 4096-byte Steim-2 encoded record: 6601 */
505 if ( fsdh
->numsamples
> 20000 )
507 ms_log (2, "%s: Unlikely number of samples (>20000): '%d'\n", srcname
, fsdh
->numsamples
);
511 /* Sanity check that there is space for blockettes when both data and blockettes are present */
512 if ( fsdh
->numsamples
> 0 && fsdh
->numblockettes
> 0 && fsdh
->data_offset
<= fsdh
->blockette_offset
)
514 ms_log (2, "%s: No space for %d blockettes, data offset: %d, blockette offset: %d\n", srcname
,
515 fsdh
->numblockettes
, fsdh
->data_offset
, fsdh
->blockette_offset
);
520 /* Print raw header details */
523 /* Determine nominal sample rate */
524 nomsamprate
= ms_nomsamprate (fsdh
->samprate_fact
, fsdh
->samprate_mult
);
526 /* Print header values */
527 ms_log (0, "RECORD -- %s\n", srcname
);
528 ms_log (0, " sequence number: '%c%c%c%c%c%c'\n", fsdh
->sequence_number
[0], fsdh
->sequence_number
[1], fsdh
->sequence_number
[2],
529 fsdh
->sequence_number
[3], fsdh
->sequence_number
[4], fsdh
->sequence_number
[5]);
530 ms_log (0, " data quality indicator: '%c'\n", fsdh
->dataquality
);
532 ms_log (0, " reserved: '%c'\n", fsdh
->reserved
);
533 ms_log (0, " station code: '%c%c%c%c%c'\n", fsdh
->station
[0], fsdh
->station
[1], fsdh
->station
[2], fsdh
->station
[3], fsdh
->station
[4]);
534 ms_log (0, " location ID: '%c%c'\n", fsdh
->location
[0], fsdh
->location
[1]);
535 ms_log (0, " channel codes: '%c%c%c'\n", fsdh
->channel
[0], fsdh
->channel
[1], fsdh
->channel
[2]);
536 ms_log (0, " network code: '%c%c'\n", fsdh
->network
[0], fsdh
->network
[1]);
537 ms_log (0, " start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", fsdh
->start_time
.year
, fsdh
->start_time
.day
,
538 fsdh
->start_time
.hour
, fsdh
->start_time
.min
, fsdh
->start_time
.sec
, fsdh
->start_time
.fract
, fsdh
->start_time
.unused
);
539 ms_log (0, " number of samples: %d\n", fsdh
->numsamples
);
540 ms_log (0, " sample rate factor: %d (%.10g samples per second)\n",
541 fsdh
->samprate_fact
, nomsamprate
);
542 ms_log (0, " sample rate multiplier: %d\n", fsdh
->samprate_mult
);
544 /* Print flag details if requested */
549 ms_log (0, " activity flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
550 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
551 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
552 if ( b
& 0x01 ) ms_log (0, " [Bit 0] Calibration signals present\n");
553 if ( b
& 0x02 ) ms_log (0, " [Bit 1] Time correction applied\n");
554 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Beginning of an event, station trigger\n");
555 if ( b
& 0x08 ) ms_log (0, " [Bit 3] End of an event, station detrigger\n");
556 if ( b
& 0x10 ) ms_log (0, " [Bit 4] A positive leap second happened in this record\n");
557 if ( b
& 0x20 ) ms_log (0, " [Bit 5] A negative leap second happened in this record\n");
558 if ( b
& 0x40 ) ms_log (0, " [Bit 6] Event in progress\n");
559 if ( b
& 0x80 ) ms_log (0, " [Bit 7] Undefined bit set\n");
561 /* I/O and clock flags */
563 ms_log (0, " I/O and clock flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
564 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
565 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
566 if ( b
& 0x01 ) ms_log (0, " [Bit 0] Station volume parity error possibly present\n");
567 if ( b
& 0x02 ) ms_log (0, " [Bit 1] Long record read (possibly no problem)\n");
568 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Short record read (record padded)\n");
569 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Start of time series\n");
570 if ( b
& 0x10 ) ms_log (0, " [Bit 4] End of time series\n");
571 if ( b
& 0x20 ) ms_log (0, " [Bit 5] Clock locked\n");
572 if ( b
& 0x40 ) ms_log (0, " [Bit 6] Undefined bit set\n");
573 if ( b
& 0x80 ) ms_log (0, " [Bit 7] Undefined bit set\n");
575 /* Data quality flags */
577 ms_log (0, " data quality flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
578 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
579 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
580 if ( b
& 0x01 ) ms_log (0, " [Bit 0] Amplifier saturation detected\n");
581 if ( b
& 0x02 ) ms_log (0, " [Bit 1] Digitizer clipping detected\n");
582 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Spikes detected\n");
583 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Glitches detected\n");
584 if ( b
& 0x10 ) ms_log (0, " [Bit 4] Missing/padded data present\n");
585 if ( b
& 0x20 ) ms_log (0, " [Bit 5] Telemetry synchronization error\n");
586 if ( b
& 0x40 ) ms_log (0, " [Bit 6] A digital filter may be charging\n");
587 if ( b
& 0x80 ) ms_log (0, " [Bit 7] Time tag is questionable\n");
590 ms_log (0, " number of blockettes: %d\n", fsdh
->numblockettes
);
591 ms_log (0, " time correction: %ld\n", (long int) fsdh
->time_correct
);
592 ms_log (0, " data offset: %d\n", fsdh
->data_offset
);
593 ms_log (0, " first blockette offset: %d\n", fsdh
->blockette_offset
);
594 } /* Done printing raw header details */
597 /* Validate and report information in the blockette chain */
598 if ( fsdh
->blockette_offset
> 46 && fsdh
->blockette_offset
< maxreclen
)
600 int blkt_offset
= fsdh
->blockette_offset
;
607 /* Traverse blockette chain */
608 while ( blkt_offset
!= 0 && blkt_offset
< maxreclen
)
610 /* Every blockette has a similar 4 byte header: type and next */
611 memcpy (&blkt_type
, record
+ blkt_offset
, 2);
612 memcpy (&next_blkt
, record
+ blkt_offset
+2, 2);
616 ms_gswap2 (&blkt_type
);
617 ms_gswap2 (&next_blkt
);
620 /* Print common header fields */
623 blkt_desc
= ms_blktdesc(blkt_type
);
624 ms_log (0, " BLOCKETTE %u: (%s)\n", blkt_type
, (blkt_desc
) ? blkt_desc
: "Unknown");
625 ms_log (0, " next blockette: %u\n", next_blkt
);
628 blkt_length
= ms_blktlen (blkt_type
, record
+ blkt_offset
, swapflag
);
629 if ( blkt_length
== 0 )
631 ms_log (2, "%s: Unknown blockette length for type %d\n", srcname
, blkt_type
);
635 /* Track end of blockette chain */
636 endofblockettes
= blkt_offset
+ blkt_length
- 1;
638 /* Sanity check that the blockette is contained in the record */
639 if ( endofblockettes
> maxreclen
)
641 ms_log (2, "%s: Blockette type %d at offset %d with length %d does not fix in record (%d)\n",
642 srcname
, blkt_type
, blkt_offset
, blkt_length
, maxreclen
);
647 if ( blkt_type
== 100 )
649 struct blkt_100_s
*blkt_100
= (struct blkt_100_s
*) (record
+ blkt_offset
+ 4);
652 ms_gswap4 (&blkt_100
->samprate
);
656 ms_log (0, " actual sample rate: %.10g\n", blkt_100
->samprate
);
661 ms_log (0, " undefined flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
662 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
663 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
665 ms_log (0, " reserved bytes (3): %u,%u,%u\n",
666 blkt_100
->reserved
[0], blkt_100
->reserved
[1], blkt_100
->reserved
[2]);
671 else if ( blkt_type
== 200 )
673 struct blkt_200_s
*blkt_200
= (struct blkt_200_s
*) (record
+ blkt_offset
+ 4);
677 ms_gswap4 (&blkt_200
->amplitude
);
678 ms_gswap4 (&blkt_200
->period
);
679 ms_gswap4 (&blkt_200
->background_estimate
);
680 MS_SWAPBTIME (&blkt_200
->time
);
685 ms_log (0, " signal amplitude: %g\n", blkt_200
->amplitude
);
686 ms_log (0, " signal period: %g\n", blkt_200
->period
);
687 ms_log (0, " background estimate: %g\n", blkt_200
->background_estimate
);
692 ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
693 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
694 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
695 if ( b
& 0x01 ) ms_log (0, " [Bit 0] 1: Dilatation wave\n");
696 else ms_log (0, " [Bit 0] 0: Compression wave\n");
697 if ( b
& 0x02 ) ms_log (0, " [Bit 1] 1: Units after deconvolution\n");
698 else ms_log (0, " [Bit 1] 0: Units are digital counts\n");
699 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Bit 0 is undetermined\n");
700 ms_log (0, " reserved byte: %u\n", blkt_200
->reserved
);
703 ms_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_200
->time
.year
, blkt_200
->time
.day
,
704 blkt_200
->time
.hour
, blkt_200
->time
.min
, blkt_200
->time
.sec
, blkt_200
->time
.fract
, blkt_200
->time
.unused
);
705 ms_log (0, " detector name: %.24s\n", blkt_200
->detector
);
709 else if ( blkt_type
== 201 )
711 struct blkt_201_s
*blkt_201
= (struct blkt_201_s
*) (record
+ blkt_offset
+ 4);
715 ms_gswap4 (&blkt_201
->amplitude
);
716 ms_gswap4 (&blkt_201
->period
);
717 ms_gswap4 (&blkt_201
->background_estimate
);
718 MS_SWAPBTIME (&blkt_201
->time
);
723 ms_log (0, " signal amplitude: %g\n", blkt_201
->amplitude
);
724 ms_log (0, " signal period: %g\n", blkt_201
->period
);
725 ms_log (0, " background estimate: %g\n", blkt_201
->background_estimate
);
728 ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
729 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
730 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
731 if ( b
& 0x01 ) ms_log (0, " [Bit 0] 1: Dilation wave\n");
732 else ms_log (0, " [Bit 0] 0: Compression wave\n");
735 ms_log (0, " reserved byte: %u\n", blkt_201
->reserved
);
736 ms_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_201
->time
.year
, blkt_201
->time
.day
,
737 blkt_201
->time
.hour
, blkt_201
->time
.min
, blkt_201
->time
.sec
, blkt_201
->time
.fract
, blkt_201
->time
.unused
);
738 ms_log (0, " SNR values: ");
739 for (idx
=0; idx
< 6; idx
++) ms_log (0, "%u ", blkt_201
->snr_values
[idx
]);
741 ms_log (0, " loopback value: %u\n", blkt_201
->loopback
);
742 ms_log (0, " pick algorithm: %u\n", blkt_201
->pick_algorithm
);
743 ms_log (0, " detector name: %.24s\n", blkt_201
->detector
);
747 else if ( blkt_type
== 300 )
749 struct blkt_300_s
*blkt_300
= (struct blkt_300_s
*) (record
+ blkt_offset
+ 4);
753 MS_SWAPBTIME (&blkt_300
->time
);
754 ms_gswap4 (&blkt_300
->step_duration
);
755 ms_gswap4 (&blkt_300
->interval_duration
);
756 ms_gswap4 (&blkt_300
->amplitude
);
757 ms_gswap4 (&blkt_300
->reference_amplitude
);
762 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_300
->time
.year
, blkt_300
->time
.day
,
763 blkt_300
->time
.hour
, blkt_300
->time
.min
, blkt_300
->time
.sec
, blkt_300
->time
.fract
, blkt_300
->time
.unused
);
764 ms_log (0, " number of calibrations: %u\n", blkt_300
->numcalibrations
);
767 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
768 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
769 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
770 if ( b
& 0x01 ) ms_log (0, " [Bit 0] First pulse is positive\n");
771 if ( b
& 0x02 ) ms_log (0, " [Bit 1] Calibration's alternate sign\n");
772 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
773 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
775 ms_log (0, " step duration: %u\n", blkt_300
->step_duration
);
776 ms_log (0, " interval duration: %u\n", blkt_300
->interval_duration
);
777 ms_log (0, " signal amplitude: %g\n", blkt_300
->amplitude
);
778 ms_log (0, " input signal channel: %.3s", blkt_300
->input_channel
);
780 ms_log (0, " reserved byte: %u\n", blkt_300
->reserved
);
781 ms_log (0, " reference amplitude: %u\n", blkt_300
->reference_amplitude
);
782 ms_log (0, " coupling: %.12s\n", blkt_300
->coupling
);
783 ms_log (0, " rolloff: %.12s\n", blkt_300
->rolloff
);
787 else if ( blkt_type
== 310 )
789 struct blkt_310_s
*blkt_310
= (struct blkt_310_s
*) (record
+ blkt_offset
+ 4);
793 MS_SWAPBTIME (&blkt_310
->time
);
794 ms_gswap4 (&blkt_310
->duration
);
795 ms_gswap4 (&blkt_310
->period
);
796 ms_gswap4 (&blkt_310
->amplitude
);
797 ms_gswap4 (&blkt_310
->reference_amplitude
);
802 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_310
->time
.year
, blkt_310
->time
.day
,
803 blkt_310
->time
.hour
, blkt_310
->time
.min
, blkt_310
->time
.sec
, blkt_310
->time
.fract
, blkt_310
->time
.unused
);
805 ms_log (0, " reserved byte: %u\n", blkt_310
->reserved1
);
808 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
809 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
810 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
811 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
812 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
813 if ( b
& 0x10 ) ms_log (0, " [Bit 4] Peak-to-peak amplitude\n");
814 if ( b
& 0x20 ) ms_log (0, " [Bit 5] Zero-to-peak amplitude\n");
815 if ( b
& 0x40 ) ms_log (0, " [Bit 6] RMS amplitude\n");
817 ms_log (0, " calibration duration: %u\n", blkt_310
->duration
);
818 ms_log (0, " signal period: %g\n", blkt_310
->period
);
819 ms_log (0, " signal amplitude: %g\n", blkt_310
->amplitude
);
820 ms_log (0, " input signal channel: %.3s", blkt_310
->input_channel
);
822 ms_log (0, " reserved byte: %u\n", blkt_310
->reserved2
);
823 ms_log (0, " reference amplitude: %u\n", blkt_310
->reference_amplitude
);
824 ms_log (0, " coupling: %.12s\n", blkt_310
->coupling
);
825 ms_log (0, " rolloff: %.12s\n", blkt_310
->rolloff
);
829 else if ( blkt_type
== 320 )
831 struct blkt_320_s
*blkt_320
= (struct blkt_320_s
*) (record
+ blkt_offset
+ 4);
835 MS_SWAPBTIME (&blkt_320
->time
);
836 ms_gswap4 (&blkt_320
->duration
);
837 ms_gswap4 (&blkt_320
->ptp_amplitude
);
838 ms_gswap4 (&blkt_320
->reference_amplitude
);
843 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_320
->time
.year
, blkt_320
->time
.day
,
844 blkt_320
->time
.hour
, blkt_320
->time
.min
, blkt_320
->time
.sec
, blkt_320
->time
.fract
, blkt_320
->time
.unused
);
846 ms_log (0, " reserved byte: %u\n", blkt_320
->reserved1
);
849 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
850 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
851 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
852 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
853 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
854 if ( b
& 0x10 ) ms_log (0, " [Bit 4] Random amplitudes\n");
856 ms_log (0, " calibration duration: %u\n", blkt_320
->duration
);
857 ms_log (0, " peak-to-peak amplitude: %g\n", blkt_320
->ptp_amplitude
);
858 ms_log (0, " input signal channel: %.3s", blkt_320
->input_channel
);
860 ms_log (0, " reserved byte: %u\n", blkt_320
->reserved2
);
861 ms_log (0, " reference amplitude: %u\n", blkt_320
->reference_amplitude
);
862 ms_log (0, " coupling: %.12s\n", blkt_320
->coupling
);
863 ms_log (0, " rolloff: %.12s\n", blkt_320
->rolloff
);
864 ms_log (0, " noise type: %.8s\n", blkt_320
->noise_type
);
868 else if ( blkt_type
== 390 )
870 struct blkt_390_s
*blkt_390
= (struct blkt_390_s
*) (record
+ blkt_offset
+ 4);
874 MS_SWAPBTIME (&blkt_390
->time
);
875 ms_gswap4 (&blkt_390
->duration
);
876 ms_gswap4 (&blkt_390
->amplitude
);
881 ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_390
->time
.year
, blkt_390
->time
.day
,
882 blkt_390
->time
.hour
, blkt_390
->time
.min
, blkt_390
->time
.sec
, blkt_390
->time
.fract
, blkt_390
->time
.unused
);
884 ms_log (0, " reserved byte: %u\n", blkt_390
->reserved1
);
887 ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
888 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
889 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
890 if ( b
& 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
891 if ( b
& 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
893 ms_log (0, " calibration duration: %u\n", blkt_390
->duration
);
894 ms_log (0, " signal amplitude: %g\n", blkt_390
->amplitude
);
895 ms_log (0, " input signal channel: %.3s", blkt_390
->input_channel
);
897 ms_log (0, " reserved byte: %u\n", blkt_390
->reserved2
);
901 else if ( blkt_type
== 395 )
903 struct blkt_395_s
*blkt_395
= (struct blkt_395_s
*) (record
+ blkt_offset
+ 4);
906 MS_SWAPBTIME (&blkt_395
->time
);
910 ms_log (0, " calibration end time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_395
->time
.year
, blkt_395
->time
.day
,
911 blkt_395
->time
.hour
, blkt_395
->time
.min
, blkt_395
->time
.sec
, blkt_395
->time
.fract
, blkt_395
->time
.unused
);
913 ms_log (0, " reserved bytes (2): %u,%u\n",
914 blkt_395
->reserved
[0], blkt_395
->reserved
[1]);
918 else if ( blkt_type
== 400 )
920 struct blkt_400_s
*blkt_400
= (struct blkt_400_s
*) (record
+ blkt_offset
+ 4);
924 ms_gswap4 (&blkt_400
->azimuth
);
925 ms_gswap4 (&blkt_400
->slowness
);
926 ms_gswap4 (&blkt_400
->configuration
);
931 ms_log (0, " beam azimuth (degrees): %g\n", blkt_400
->azimuth
);
932 ms_log (0, " beam slowness (sec/degree): %g\n", blkt_400
->slowness
);
933 ms_log (0, " configuration: %u\n", blkt_400
->configuration
);
935 ms_log (0, " reserved bytes (2): %u,%u\n",
936 blkt_400
->reserved
[0], blkt_400
->reserved
[1]);
940 else if ( blkt_type
== 405 )
942 struct blkt_405_s
*blkt_405
= (struct blkt_405_s
*) (record
+ blkt_offset
+ 4);
943 uint16_t firstvalue
= blkt_405
->delay_values
[0]; /* Work on a private copy */
946 ms_gswap2 (&firstvalue
);
949 ms_log (0, " first delay value: %u\n", firstvalue
);
952 else if ( blkt_type
== 500 )
954 struct blkt_500_s
*blkt_500
= (struct blkt_500_s
*) (record
+ blkt_offset
+ 4);
958 ms_gswap4 (&blkt_500
->vco_correction
);
959 MS_SWAPBTIME (&blkt_500
->time
);
960 ms_gswap4 (&blkt_500
->exception_count
);
965 ms_log (0, " VCO correction: %g%%\n", blkt_500
->vco_correction
);
966 ms_log (0, " time of exception: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_500
->time
.year
, blkt_500
->time
.day
,
967 blkt_500
->time
.hour
, blkt_500
->time
.min
, blkt_500
->time
.sec
, blkt_500
->time
.fract
, blkt_500
->time
.unused
);
968 ms_log (0, " usec: %d\n", blkt_500
->usec
);
969 ms_log (0, " reception quality: %u%%\n", blkt_500
->reception_qual
);
970 ms_log (0, " exception count: %u\n", blkt_500
->exception_count
);
971 ms_log (0, " exception type: %.16s\n", blkt_500
->exception_type
);
972 ms_log (0, " clock model: %.32s\n", blkt_500
->clock_model
);
973 ms_log (0, " clock status: %.128s\n", blkt_500
->clock_status
);
977 else if ( blkt_type
== 1000 )
979 struct blkt_1000_s
*blkt_1000
= (struct blkt_1000_s
*) (record
+ blkt_offset
+ 4);
982 /* Calculate record size in bytes as 2^(blkt_1000->rec_len) */
983 b1000reclen
= (unsigned int) 1 << blkt_1000
->reclen
;
985 /* Big or little endian? */
986 if (blkt_1000
->byteorder
== 0)
987 strncpy (order
, "Little endian", sizeof(order
)-1);
988 else if (blkt_1000
->byteorder
== 1)
989 strncpy (order
, "Big endian", sizeof(order
)-1);
991 strncpy (order
, "Unknown value", sizeof(order
)-1);
995 ms_log (0, " encoding: %s (val:%u)\n",
996 (char *) ms_encodingstr (blkt_1000
->encoding
), blkt_1000
->encoding
);
997 ms_log (0, " byte order: %s (val:%u)\n",
998 order
, blkt_1000
->byteorder
);
999 ms_log (0, " record length: %d (val:%u)\n",
1000 b1000reclen
, blkt_1000
->reclen
);
1003 ms_log (0, " reserved byte: %u\n", blkt_1000
->reserved
);
1006 /* Save encoding format */
1007 b1000encoding
= blkt_1000
->encoding
;
1009 /* Sanity check encoding format */
1010 if ( ! (b1000encoding
>= 0 && b1000encoding
<= 5) &&
1011 ! (b1000encoding
>= 10 && b1000encoding
<= 19) &&
1012 ! (b1000encoding
>= 30 && b1000encoding
<= 33) )
1014 ms_log (2, "%s: Blockette 1000 encoding format invalid (0-5,10-19,30-33): %d\n", srcname
, b1000encoding
);
1018 /* Sanity check byte order flag */
1019 if ( blkt_1000
->byteorder
!= 0 && blkt_1000
->byteorder
!= 1 )
1021 ms_log (2, "%s: Blockette 1000 byte order flag invalid (0 or 1): %d\n", srcname
, blkt_1000
->byteorder
);
1026 else if ( blkt_type
== 1001 )
1028 struct blkt_1001_s
*blkt_1001
= (struct blkt_1001_s
*) (record
+ blkt_offset
+ 4);
1032 ms_log (0, " timing quality: %u%%\n", blkt_1001
->timing_qual
);
1033 ms_log (0, " micro second: %d\n", blkt_1001
->usec
);
1036 ms_log (0, " reserved byte: %u\n", blkt_1001
->reserved
);
1038 ms_log (0, " frame count: %u\n", blkt_1001
->framecnt
);
1042 else if ( blkt_type
== 2000 )
1044 struct blkt_2000_s
*blkt_2000
= (struct blkt_2000_s
*) (record
+ blkt_offset
+ 4);
1049 ms_gswap2 (&blkt_2000
->length
);
1050 ms_gswap2 (&blkt_2000
->data_offset
);
1051 ms_gswap4 (&blkt_2000
->recnum
);
1054 /* Big or little endian? */
1055 if (blkt_2000
->byteorder
== 0)
1056 strncpy (order
, "Little endian", sizeof(order
)-1);
1057 else if (blkt_2000
->byteorder
== 1)
1058 strncpy (order
, "Big endian", sizeof(order
)-1);
1060 strncpy (order
, "Unknown value", sizeof(order
)-1);
1064 ms_log (0, " blockette length: %u\n", blkt_2000
->length
);
1065 ms_log (0, " data offset: %u\n", blkt_2000
->data_offset
);
1066 ms_log (0, " record number: %u\n", blkt_2000
->recnum
);
1067 ms_log (0, " byte order: %s (val:%u)\n",
1068 order
, blkt_2000
->byteorder
);
1069 b
= blkt_2000
->flags
;
1070 ms_log (0, " data flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
1071 bit(b
,0x01), bit(b
,0x02), bit(b
,0x04), bit(b
,0x08),
1072 bit(b
,0x10), bit(b
,0x20), bit(b
,0x40), bit(b
,0x80));
1076 if ( b
& 0x01 ) ms_log (0, " [Bit 0] 1: Stream oriented\n");
1077 else ms_log (0, " [Bit 0] 0: Record oriented\n");
1078 if ( b
& 0x02 ) ms_log (0, " [Bit 1] 1: Blockette 2000s may NOT be packaged\n");
1079 else ms_log (0, " [Bit 1] 0: Blockette 2000s may be packaged\n");
1080 if ( ! (b
& 0x04) && ! (b
& 0x08) )
1081 ms_log (0, " [Bits 2-3] 00: Complete blockette\n");
1082 else if ( ! (b
& 0x04) && (b
& 0x08) )
1083 ms_log (0, " [Bits 2-3] 01: First blockette in span\n");
1084 else if ( (b
& 0x04) && (b
& 0x08) )
1085 ms_log (0, " [Bits 2-3] 11: Continuation blockette in span\n");
1086 else if ( (b
& 0x04) && ! (b
& 0x08) )
1087 ms_log (0, " [Bits 2-3] 10: Final blockette in span\n");
1088 if ( ! (b
& 0x10) && ! (b
& 0x20) )
1089 ms_log (0, " [Bits 4-5] 00: Not file oriented\n");
1090 else if ( ! (b
& 0x10) && (b
& 0x20) )
1091 ms_log (0, " [Bits 4-5] 01: First blockette of file\n");
1092 else if ( (b
& 0x10) && ! (b
& 0x20) )
1093 ms_log (0, " [Bits 4-5] 10: Continuation of file\n");
1094 else if ( (b
& 0x10) && (b
& 0x20) )
1095 ms_log (0, " [Bits 4-5] 11: Last blockette of file\n");
1098 ms_log (0, " number of headers: %u\n", blkt_2000
->numheaders
);
1100 /* Crude display of the opaque data headers */
1102 ms_log (0, " headers: %.*s\n",
1103 (blkt_2000
->data_offset
- 15), blkt_2000
->payload
);
1109 ms_log (2, "%s: Unrecognized blockette type: %d\n", srcname
, blkt_type
);
1113 /* Sanity check the next blockette offset */
1114 if ( next_blkt
&& next_blkt
<= endofblockettes
)
1116 ms_log (2, "%s: Next blockette offset (%d) is within current blockette ending at byte %d\n",
1117 srcname
, next_blkt
, endofblockettes
);
1122 blkt_offset
= next_blkt
;
1126 } /* End of looping through blockettes */
1128 /* Check that the blockette offset is within the maximum record size */
1129 if ( blkt_offset
> maxreclen
)
1131 ms_log (2, "%s: Blockette offset (%d) beyond maximum record length (%d)\n", srcname
, blkt_offset
, maxreclen
);
1135 /* Check that the data and blockette offsets are within the record */
1136 if ( b1000reclen
&& fsdh
->data_offset
> b1000reclen
)
1138 ms_log (2, "%s: Data offset (%d) beyond record length (%d)\n", srcname
, fsdh
->data_offset
, b1000reclen
);
1141 if ( b1000reclen
&& fsdh
->blockette_offset
> b1000reclen
)
1143 ms_log (2, "%s: Blockette offset (%d) beyond record length (%d)\n", srcname
, fsdh
->blockette_offset
, b1000reclen
);
1147 /* Check that the data offset is beyond the end of the blockettes */
1148 if ( fsdh
->numsamples
&& fsdh
->data_offset
<= endofblockettes
)
1150 ms_log (2, "%s: Data offset (%d) is within blockette chain (end of blockettes: %d)\n", srcname
, fsdh
->data_offset
, endofblockettes
);
1154 /* Check that the correct number of blockettes were parsed */
1155 if ( fsdh
->numblockettes
!= blkt_count
)
1157 ms_log (2, "%s: Specified number of blockettes (%d) not equal to those parsed (%d)\n", srcname
, fsdh
->numblockettes
, blkt_count
);
1163 } /* End of ms_parse_raw() */