1# -*- coding: utf-8 -*- 2""" 3Defines the libmseed structures and blockettes. 4""" 5from __future__ import (absolute_import, division, print_function, 6 unicode_literals) 7from future.builtins import * # NOQA 8from future.utils import native_str 9 10import ctypes as C # NOQA 11import warnings 12 13import numpy as np 14 15from . import InternalMSEEDError, InternalMSEEDWarning 16from obspy.core.util.libnames import _load_cdll 17 18 19# Load the shared library. Later on it is wrapped into another object that 20# correctly set's up error and warning handles - but information from the 21# library is already required at an earlier point. 22__clibmseed = _load_cdll("mseed") 23 24 25# Size of the off_t type. 26sizeoff_off_t = C.c_int.in_dll(__clibmseed, "LM_SIZEOF_OFF_T").value 27for _c in [C.c_long, C.c_longlong, C.c_int]: 28 if C.sizeof(_c) == sizeoff_off_t: 29 off_t_type = _c 30 break 31else: # pragma: no cover 32 raise InternalMSEEDError("Could not determine corresponding ctypes " 33 "datatype for off_t.") 34 35 36HPTERROR = -2145916800000000 37 38ENDIAN = {0: '<', 1: '>'} 39 40 41# XXX: Do we still support Python 2.4 ???? 42# Figure out Py_ssize_t (PEP 353). 43# 44# Py_ssize_t is only defined for Python 2.5 and above, so it defaults to 45# ctypes.c_int for earlier versions. 46# 47# https://svn.python.org/projects/ctypes/trunk/ 48# ctypeslib/ctypeslib/contrib/pythonhdr.py 49if hasattr(C.pythonapi, 'Py_InitModule4'): 50 Py_ssize_t = C.c_int 51elif hasattr(C.pythonapi, 'Py_InitModule4_64'): 52 Py_ssize_t = C.c_int64 53else: 54 # XXX: just hard code it for now 55 Py_ssize_t = C.c_int64 56 # raise TypeError("Cannot determine type of Py_ssize_t") 57 58# Valid control headers in ASCII numbers. 59SEED_CONTROL_HEADERS = [ord('V'), ord('A'), ord('S'), ord('T')] 60MINI_SEED_CONTROL_HEADERS = [ord('D'), ord('R'), ord('Q'), ord('M')] 61VALID_CONTROL_HEADERS = SEED_CONTROL_HEADERS + MINI_SEED_CONTROL_HEADERS + \ 62 [ord(' ')] 63 64# expected data types for libmseed id: (numpy, ctypes) 65DATATYPES = {b"a": C.c_char, b"i": C.c_int32, b"f": C.c_float, 66 b"d": C.c_double} 67SAMPLESIZES = {'a': 1, 'i': 4, 'f': 4, 'd': 8} 68 69# Valid record lengths for Mini-SEED files. 70VALID_RECORD_LENGTHS = [256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 71 131072, 262144, 524288, 1048576] 72 73# allowed encodings: 74# id: (name, sampletype a/i/f/d, default NumPy type, write support) 75ENCODINGS = {0: ("ASCII", "a", np.dtype(native_str("|S1")).type, True), 76 1: ("INT16", "i", np.dtype(np.int16), True), 77 3: ("INT32", "i", np.dtype(np.int32), True), 78 4: ("FLOAT32", "f", np.dtype(np.float32), True), 79 5: ("FLOAT64", "d", np.dtype(np.float64), True), 80 10: ("STEIM1", "i", np.dtype(np.int32), True), 81 11: ("STEIM2", "i", np.dtype(np.int32), True), 82 12: ("GEOSCOPE24", "f", np.dtype(np.float32), False), 83 13: ("GEOSCOPE16_3", "f", np.dtype(np.float32), False), 84 14: ("GEOSCOPE16_4", "f", np.dtype(np.float32), False), 85 16: ("CDSN", "i", np.dtype(np.int32), False), 86 30: ("SRO", "i", np.dtype(np.int32), False), 87 32: ("DWWSSN", "i", np.dtype(np.int32), False)} 88 89# Encodings not supported by libmseed and consequently ObsPy. 90UNSUPPORTED_ENCODINGS = { 91 2: "INT24", 92 15: "US National Network compression", 93 17: "Graefenberg 16 bit gain ranged", 94 18: "IPG - Strasbourg 16 bit gain ranged", 95 19: "STEIM (3) Comprssion", 96 31: "HGLP Format", 97 33: "RSTN 16 bit gain ranged" 98} 99 100# Maps fixed header activity flags bit number and the matching expected key in 101# the flags_value 102FIXED_HEADER_ACTIVITY_FLAGS = {0: 'calib_signal', 103 1: 'time_correction', 104 2: 'begin_event', 105 3: 'end_event', 106 4: 'positive_leap', 107 5: 'negative_leap', 108 6: 'event_in_progress'} 109 110# Maps fixed header I/O and clock flags bit number and the matching expected 111# key in the flags_value 112FIXED_HEADER_IO_CLOCK_FLAGS = {0: 'sta_vol_parity_error_possible', 113 1: 'long_record_read', 114 2: 'short_record_read', 115 3: 'start_of_time_series', 116 4: 'end_of_time_series', 117 5: 'clock_locked'} 118 119# Maps fixed header data quality flags bit number and the matching expected 120# key in the flags_value 121FIXED_HEADER_DATA_QUAL_FLAGS = {0: 'amplifier_sat_detected', 122 1: 'digitizer_clipping_detected', 123 2: 'spikes_detected', 124 3: 'glitches_detected', 125 4: 'missing_padded_data_present', 126 5: 'telemetry_sync_error', 127 6: 'digital_filter_maybe_charging', 128 7: 'time_tag_questionable'} 129 130# Map the dtype to the samplecode. Redundant information but it is hard coded 131# for performance reasons. 132SAMPLETYPE = {"|S1": "a", 133 "int16": "i", 134 "int32": "i", 135 "float32": "f", 136 "float64": "d", 137 np.dtype(native_str("|S1")).type: "a", 138 np.dtype(np.int16).type: "i", 139 np.dtype(np.int32).type: "i", 140 np.dtype(np.float32).type: "f", 141 np.dtype(np.float64).type: "d"} 142# as defined in libmseed.h 143MS_ENDOFFILE = 1 144MS_NOERROR = 0 145 146 147# SEED binary time 148class BTime(C.Structure): 149 _fields_ = [ 150 ('year', C.c_ushort), 151 ('day', C.c_ushort), 152 ('hour', C.c_ubyte), 153 ('min', C.c_ubyte), 154 ('sec', C.c_ubyte), 155 ('unused', C.c_ubyte), 156 ('fract', C.c_ushort), 157 ] 158 159 160# Fixed section data of header 161class FSDHS(C.Structure): 162 _fields_ = [ 163 ('sequence_number', C.c_char * 6), 164 ('dataquality', C.c_char), 165 ('reserved', C.c_char), 166 ('station', C.c_char * 5), 167 ('location', C.c_char * 2), 168 ('channel', C.c_char * 3), 169 ('network', C.c_char * 2), 170 ('start_time', BTime), 171 ('numsamples', C.c_ushort), 172 ('samprate_fact', C.c_short), 173 ('samprate_mult', C.c_short), 174 ('act_flags', C.c_ubyte), 175 ('io_flags', C.c_ubyte), 176 ('dq_flags', C.c_ubyte), 177 ('numblockettes', C.c_ubyte), 178 ('time_correct', C.c_int), 179 ('data_offset', C.c_ushort), 180 ('blockette_offset', C.c_ushort), 181 ] 182 183 184# Blockette 100, Sample Rate (without header) 185class Blkt100S(C.Structure): 186 _fields_ = [ 187 ('samprate', C.c_float), 188 ('flags', C.c_byte), 189 ('reserved', C.c_ubyte * 3), 190 ] 191blkt_100 = Blkt100S # noqa 192 193 194# Blockette 200, Generic Event Detection (without header) 195class Blkt200S(C.Structure): 196 _fields_ = [ 197 ('amplitude', C.c_float), 198 ('period', C.c_float), 199 ('background_estimate', C.c_float), 200 ('flags', C.c_ubyte), 201 ('reserved', C.c_ubyte), 202 ('time', BTime), 203 ('detector', C.c_char * 24), 204 ] 205 206 207# Blockette 201, Murdock Event Detection (without header) 208class Blkt201S(C.Structure): 209 _fields_ = [ 210 ('amplitude', C.c_float), 211 ('period', C.c_float), 212 ('background_estimate', C.c_float), 213 ('flags', C.c_ubyte), 214 ('reserved', C.c_ubyte), 215 ('time', BTime), 216 ('snr_values', C.c_ubyte * 6), 217 ('loopback', C.c_ubyte), 218 ('pick_algorithm', C.c_ubyte), 219 ('detector', C.c_char * 24), 220 ] 221 222 223# Blockette 300, Step Calibration (without header) 224class Blkt300S(C.Structure): 225 _fields_ = [ 226 ('time', BTime), 227 ('numcalibrations', C.c_ubyte), 228 ('flags', C.c_ubyte), 229 ('step_duration', C.c_uint), 230 ('interval_duration', C.c_uint), 231 ('amplitude', C.c_float), 232 ('input_channel', C.c_char * 3), 233 ('reserved', C.c_ubyte), 234 ('reference_amplitude', C.c_uint), 235 ('coupling', C.c_char * 12), 236 ('rolloff', C.c_char * 12), 237 ] 238 239 240# Blockette 310, Sine Calibration (without header) 241class Blkt310S(C.Structure): 242 _fields_ = [ 243 ('time', BTime), 244 ('reserved1', C.c_ubyte), 245 ('flags', C.c_ubyte), 246 ('duration', C.c_uint), 247 ('period', C.c_float), 248 ('amplitude', C.c_float), 249 ('input_channel', C.c_char * 3), 250 ('reserved2', C.c_ubyte), 251 ('reference_amplitude', C.c_uint), 252 ('coupling', C.c_char * 12), 253 ('rolloff', C.c_char * 12), 254 ] 255 256 257# Blockette 320, Pseudo-random Calibration (without header) 258class Blkt320S(C.Structure): 259 _fields_ = [ 260 ('time', BTime), 261 ('reserved1', C.c_ubyte), 262 ('flags', C.c_ubyte), 263 ('duration', C.c_uint), 264 ('ptp_amplitude', C.c_float), 265 ('input_channel', C.c_char * 3), 266 ('reserved2', C.c_ubyte), 267 ('reference_amplitude', C.c_uint), 268 ('coupling', C.c_char * 12), 269 ('rolloff', C.c_char * 12), 270 ('noise_type', C.c_char * 8), 271 ] 272 273 274# Blockette 390, Generic Calibration (without header) 275class Blkt390S(C.Structure): 276 _fields_ = [ 277 ('time', BTime), 278 ('reserved1', C.c_ubyte), 279 ('flags', C.c_ubyte), 280 ('duration', C.c_uint), 281 ('amplitude', C.c_float), 282 ('input_channel', C.c_char * 3), 283 ('reserved2', C.c_ubyte), 284 ] 285 286 287# Blockette 395, Calibration Abort (without header) 288class Blkt395S(C.Structure): 289 _fields_ = [ 290 ('time', BTime), 291 ('reserved', C.c_ubyte * 2), 292 ] 293 294 295# Blockette 400, Beam (without header) 296class Blkt400S(C.Structure): 297 _fields_ = [ 298 ('azimuth', C.c_float), 299 ('slowness', C.c_float), 300 ('configuration', C.c_ushort), 301 ('reserved', C.c_ubyte * 2), 302 ] 303 304 305# Blockette 405, Beam Delay (without header) 306class Blkt405S(C.Structure): 307 _fields_ = [ 308 ('delay_values', C.c_ushort * 1), 309 ] 310 311 312# Blockette 500, Timing (without header) 313class Blkt500S(C.Structure): 314 _fields_ = [ 315 ('vco_correction', C.c_float), 316 ('time', BTime), 317 ('usec', C.c_byte), 318 ('reception_qual', C.c_ubyte), 319 ('exception_count', C.c_uint), 320 ('exception_type', C.c_char * 16), 321 ('clock_model', C.c_char * 32), 322 ('clock_status', C.c_char * 128), 323 ] 324 325 326# Blockette 1000, Data Only SEED (without header) 327class Blkt1000S(C.Structure): 328 _fields_ = [ 329 ('encoding', C.c_ubyte), 330 ('byteorder', C.c_ubyte), 331 ('reclen', C.c_ubyte), 332 ('reserved', C.c_ubyte), 333 ] 334 335 336# Blockette 1001, Data Extension (without header) 337class Blkt1001S(C.Structure): 338 _fields_ = [ 339 ('timing_qual', C.c_ubyte), 340 ('usec', C.c_byte), 341 ('reserved', C.c_ubyte), 342 ('framecnt', C.c_ubyte), 343 ] 344blkt_1001 = Blkt1001S # noqa 345 346 347# Blockette 2000, Opaque Data (without header) 348class Blkt2000S(C.Structure): 349 _fields_ = [ 350 ('length', C.c_ushort), 351 ('data_offset', C.c_ushort), 352 ('recnum', C.c_uint), 353 ('byteorder', C.c_ubyte), 354 ('flags', C.c_ubyte), 355 ('numheaders', C.c_ubyte), 356 ('payload', C.c_char * 1), 357 ] 358 359 360# Blockette chain link, generic linkable blockette index 361class BlktLinkS(C.Structure): 362 pass 363 364 365BlktLinkS._fields_ = [ 366 ('blktoffset', C.c_ushort), # Blockette offset 367 ('blkt_type', C.c_ushort), # Blockette type 368 ('next_blkt', C.c_ushort), # Offset to next blockette 369 ('blktdata', C.POINTER(None)), # Blockette data 370 ('blktdatalen', C.c_ushort), # Length of blockette data in bytes 371 ('next', C.POINTER(BlktLinkS))] 372BlktLink = BlktLinkS # noqa 373 374 375class StreamstateS(C.Structure): 376 _fields_ = [ 377 ('packedrecords', C.c_longlong), # Count of packed records 378 ('packedsamples', C.c_longlong), # Count of packed samples 379 ('lastintsample', C.c_int), # Value of last integer sample packed 380 ('comphistory', C.c_byte), # Control use of lastintsample for 381 # compression history 382 ] 383StreamState = StreamstateS # noqa 384 385 386class MsrecordS(C.Structure): 387 pass 388 389 390MsrecordS._fields_ = [ 391 ('record', C.POINTER(C.c_char)), # Mini-SEED record 392 ('reclen', C.c_int), # Length of Mini-SEED record in bytes 393 # Pointers to SEED data record structures 394 ('fsdh', C.POINTER(FSDHS)), # Fixed Section of Data Header 395 ('blkts', C.POINTER(BlktLink)), # Root of blockette chain 396 ('Blkt100', 397 C.POINTER(Blkt100S)), # Blockette 100, if present 398 ('Blkt1000', 399 C.POINTER(Blkt1000S)), # Blockette 1000, if present 400 ('Blkt1001', 401 C.POINTER(Blkt1001S)), # Blockette 1001, if present 402 # Common header fields in accessible form 403 ('sequence_number', C.c_int), # SEED record sequence number 404 ('network', C.c_char * 11), # Network designation, NULL terminated 405 ('station', C.c_char * 11), # Station designation, NULL terminated 406 ('location', C.c_char * 11), # Location designation, NULL terminated 407 ('channel', C.c_char * 11), # Channel designation, NULL terminated 408 ('dataquality', C.c_char), # Data quality indicator 409 ('starttime', C.c_longlong), # Record start time, corrected (first 410 # sample) 411 ('samprate', C.c_double), # Nominal sample rate (Hz) 412 ('samplecnt', C.c_int64), # Number of samples in record 413 ('encoding', C.c_byte), # Data encoding format 414 ('byteorder', C.c_byte), # Byte order of record 415 # Data sample fields 416 ('datasamples', C.c_void_p), # Data samples, 'numsamples' of type 417 # 'sampletype' 418 ('numsamples', C.c_int64), # Number of data samples in datasamples 419 ('sampletype', C.c_char), # Sample type code: a, i, f, d 420 # Stream oriented state information 421 ('ststate', 422 C.POINTER(StreamState)), # Stream processing state information 423] 424MSRecord = MsrecordS # noqa 425 426 427class MstraceS(C.Structure): 428 pass 429 430 431MstraceS._fields_ = [ 432 ('network', C.c_char * 11), # Network designation, NULL terminated 433 ('station', C.c_char * 11), # Station designation, NULL terminated 434 ('location', C.c_char * 11), # Location designation, NULL terminated 435 ('channel', C.c_char * 11), # Channel designation, NULL terminated 436 ('dataquality', C.c_char), # Data quality indicator 437 ('type', C.c_char), # MSTrace type code 438 ('starttime', C.c_longlong), # Time of first sample 439 ('endtime', C.c_longlong), # Time of last sample 440 ('samprate', C.c_double), # Nominal sample rate (Hz) 441 ('samplecnt', C.c_int64), # Number of samples in trace coverage 442 ('datasamples', C.c_void_p), # Data samples, 'numsamples' of type 443 # 'sampletype' 444 ('numsamples', C.c_int64), # Number of data samples in datasamples 445 ('sampletype', C.c_char), # Sample type code: a, i, f, d 446 ('prvtptr', C.c_void_p), # Private pointer for general use 447 ('ststate', 448 C.POINTER(StreamState)), # Stream processing state information 449 ('next', C.POINTER(MstraceS)), # Pointer to next trace 450] 451MSTrace = MstraceS # noqa 452 453 454class MstracegroupS(C.Structure): 455 pass 456 457 458MstracegroupS._fields_ = [ 459 ('numtraces', C.c_int), # Number of MSTraces in the trace chain 460 ('traces', C.POINTER(MstraceS)), # Root of the trace chain 461] 462MSTraceGroup = MstracegroupS # noqa 463 464 465# Define the high precision time tick interval as 1/modulus seconds */ 466# Default modulus of 1000000 defines tick interval as a microsecond */ 467HPTMODULUS = 1000000.0 468 469 470# Reading Mini-SEED records from files 471class MsfileparamS(C.Structure): 472 pass 473 474 475MsfileparamS._fields_ = [ 476 ('fp', C.POINTER(Py_ssize_t)), 477 ('filename', C.c_char * 512), 478 ('rawrec', C.c_char_p), 479 ('readlen', C.c_int), 480 ('readoffset', C.c_int), 481 ('packtype', C.c_int), 482 ('packhdroffset', off_t_type), 483 ('filepos', off_t_type), 484 ('filesize', off_t_type), 485 ('recordcount', C.c_int), 486] 487MSFileParam = MsfileparamS # noqa 488 489 490class UDIFF(C.Union): 491 """ 492 Union for Steim objects. 493 """ 494 _fields_ = [ 495 ("byte", C.c_int8 * 4), # 4 1-byte differences. 496 ("hw", C.c_int16 * 2), # 2 halfword differences. 497 ("fw", C.c_int32), # 1 fullword difference. 498 ] 499 500 501##################################### 502# Define the C structures. 503##################################### 504 505 506# Container for a continuous trace segment, linkable 507class MSTraceSeg(C.Structure): 508 pass 509 510 511MSTraceSeg._fields_ = [ 512 ('starttime', C.c_longlong), # Time of first sample 513 ('endtime', C.c_longlong), # Time of last sample 514 ('samprate', C.c_double), # Nominal sample rate (Hz) 515 ('samplecnt', C.c_int64), # Number of samples in trace coverage 516 ('datasamples', C.c_void_p), # Data samples, 'numsamples' of type 517 # 'sampletype' 518 ('numsamples', C.c_int64), # Number of data samples in datasamples 519 ('sampletype', C.c_char), # Sample type code: a, i, f, d 520 ('prvtptr', C.c_void_p), # Private pointer for general use, unused 521 # by libmseed 522 ('prev', C.POINTER(MSTraceSeg)), # Pointer to previous segment 523 ('next', C.POINTER(MSTraceSeg)) # Pointer to next segment 524] 525 526 527# Container for a trace ID, linkable 528class MSTraceID(C.Structure): 529 pass 530 531 532MSTraceID._fields_ = [ 533 ('network', C.c_char * 11), # Network designation, NULL terminated 534 ('station', C.c_char * 11), # Station designation, NULL terminated 535 ('location', C.c_char * 11), # Location designation, NULL terminated 536 ('channel', C.c_char * 11), # Channel designation, NULL terminated 537 ('dataquality', C.c_char), # Data quality indicator 538 ('srcname', C.c_char * 45), # Source name (Net_Sta_Loc_Chan_Qual), 539 # NULL terminated 540 ('type', C.c_char), # Trace type code 541 ('earliest', C.c_longlong), # Time of earliest sample 542 ('latest', C.c_longlong), # Time of latest sample 543 ('prvtptr', C.c_void_p), # Private pointer for general use, unused 544 # by libmseed 545 ('numsegments', C.c_int), # Number of segments for this ID 546 ('first', 547 C.POINTER(MSTraceSeg)), # Pointer to first of list of segments 548 ('last', C.POINTER(MSTraceSeg)), # Pointer to last of list of segments 549 ('next', C.POINTER(MSTraceID)) # Pointer to next trace 550] 551 552 553# Container for a continuous trace segment, linkable 554class MSTraceList(C.Structure): 555 pass 556 557 558MSTraceList._fields_ = [ 559 ('numtraces', C.c_int), # Number of traces in list 560 ('traces', C.POINTER(MSTraceID)), # Pointer to list of traces 561 ('last', C.POINTER(MSTraceID)) # Pointer to last used trace in list 562] 563 564 565# Data selection structure time window definition containers 566class SelectTime(C.Structure): 567 pass 568 569 570SelectTime._fields_ = [ 571 ('starttime', C.c_longlong), # Earliest data for matching channels 572 ('endtime', C.c_longlong), # Latest data for matching channels 573 ('next', C.POINTER(SelectTime)) 574] 575 576 577# Data selection structure definition containers 578class Selections(C.Structure): 579 pass 580 581 582Selections._fields_ = [ 583 ('srcname', C.c_char * 100), # Matching (globbing) source name: 584 # Net_Sta_Loc_Chan_Qual 585 ('timewindows', C.POINTER(SelectTime)), 586 ('next', C.POINTER(Selections)) 587] 588 589 590# Container for a continuous linked list of records. 591class ContinuousSegment(C.Structure): 592 pass 593 594 595ContinuousSegment._fields_ = [ 596 ('starttime', C.c_longlong), 597 ('endtime', C.c_longlong), 598 ('samprate', C.c_double), 599 ('sampletype', C.c_char), 600 ('hpdelta', C.c_longlong), 601 ('recordcnt', C.c_int64), 602 ('samplecnt', C.c_int64), 603 ('encoding', C.c_byte), 604 ('byteorder', C.c_byte), 605 ('reclen', C.c_int), 606 ('timing_quality', C.c_uint8), 607 ('calibration_type', C.c_int8), 608 ('datasamples', C.c_void_p), # Data samples, 'numsamples' of type 609 # 'sampletype' 610 ('firstRecord', C.c_void_p), 611 ('lastRecord', C.c_void_p), 612 ('next', C.POINTER(ContinuousSegment)), 613 ('previous', C.POINTER(ContinuousSegment)) 614] 615 616 617# A container for continuous segments with the same id 618class LinkedIDList(C.Structure): 619 pass 620 621 622LinkedIDList._fields_ = [ 623 ('network', C.c_char * 11), # Network designation, NULL terminated 624 ('station', C.c_char * 11), # Station designation, NULL terminated 625 ('location', C.c_char * 11), # Location designation, NULL terminated 626 ('channel', C.c_char * 11), # Channel designation, NULL terminated 627 ('dataquality', C.c_char), # Data quality indicator 628 ('firstSegment', 629 C.POINTER(ContinuousSegment)), # Pointer to first of list of segments 630 ('lastSegment', 631 C.POINTER(ContinuousSegment)), # Pointer to last of list of segments 632 ('next', 633 C.POINTER(LinkedIDList)), # Pointer to next id 634 ('previous', 635 C.POINTER(LinkedIDList)), # Pointer to previous id 636] 637 638 639########################################################################## 640# Define the argument and return types of all the used libmseed functions. 641########################################################################## 642 643# Declare function of libmseed library, argument parsing 644__clibmseed.mst_init.argtypes = [C.POINTER(MSTrace)] 645__clibmseed.mst_init.restype = C.POINTER(MSTrace) 646 647__clibmseed.mst_free.argtypes = [C.POINTER(C.POINTER(MSTrace))] 648__clibmseed.mst_free.restype = None 649 650__clibmseed.mst_initgroup.argtypes = [C.POINTER(MSTraceGroup)] 651__clibmseed.mst_initgroup.restype = C.POINTER(MSTraceGroup) 652 653__clibmseed.mst_freegroup.argtypes = [C.POINTER(C.POINTER(MSTraceGroup))] 654__clibmseed.mst_freegroup.restype = None 655 656__clibmseed.msr_init.argtypes = [C.POINTER(MSRecord)] 657__clibmseed.msr_init.restype = C.POINTER(MSRecord) 658 659__clibmseed.ms_readmsr_r.argtypes = [ 660 C.POINTER(C.POINTER(MSFileParam)), C.POINTER(C.POINTER(MSRecord)), 661 C.c_char_p, C.c_int, C.POINTER(off_t_type), C.POINTER(C.c_int), C.c_short, 662 C.c_short, C.c_short] 663__clibmseed.ms_readmsr_r.restypes = C.c_int 664 665__clibmseed.ms_readtraces.argtypes = [ 666 C.POINTER(C.POINTER(MSTraceGroup)), C.c_char_p, C.c_int, C.c_double, 667 C.c_double, C.c_short, C.c_short, C.c_short, C.c_short] 668__clibmseed.ms_readtraces.restype = C.c_int 669 670__clibmseed.ms_readtraces_timewin.argtypes = [ 671 C.POINTER(C.POINTER(MSTraceGroup)), C.c_char_p, C.c_int, C.c_double, 672 C.c_double, C.c_int64, C.c_int64, C.c_short, C.c_short, C.c_short, 673 C.c_short] 674__clibmseed.ms_readtraces_timewin.restype = C.c_int 675 676__clibmseed.msr_starttime.argtypes = [C.POINTER(MSRecord)] 677__clibmseed.msr_starttime.restype = C.c_int64 678 679__clibmseed.msr_endtime.argtypes = [C.POINTER(MSRecord)] 680__clibmseed.msr_endtime.restype = C.c_int64 681 682__clibmseed.ms_detect.argtypes = [ 683 np.ctypeslib.ndpointer(dtype=np.int8, ndim=1, 684 flags=native_str('C_CONTIGUOUS')), 685 C.c_int] 686__clibmseed.ms_detect.restype = C.c_int 687 688__clibmseed.msr_decode_steim2.argtypes = [ 689 C.c_void_p, 690 C.c_int, 691 C.c_int, 692 np.ctypeslib.ndpointer(dtype=np.int32, ndim=1, 693 flags=native_str('C_CONTIGUOUS')), 694 C.c_int, C.c_char_p, C.c_int] 695__clibmseed.msr_decode_steim2.restype = C.c_int 696 697__clibmseed.msr_decode_steim1.argtypes = [ 698 C.c_void_p, 699 C.c_int, 700 C.c_int, 701 np.ctypeslib.ndpointer(dtype=np.int32, ndim=1, 702 flags=native_str('C_CONTIGUOUS')), 703 C.c_int, C.c_char_p, C.c_int] 704__clibmseed.msr_decode_steim1.restype = C.c_int 705 706# tricky, C.POINTER(C.c_char) is a pointer to single character fields 707# this is completely different to C.c_char_p which is a string 708__clibmseed.mst_packgroup.argtypes = [ 709 C.POINTER(MSTraceGroup), C.CFUNCTYPE( 710 None, C.POINTER(C.c_char), C.c_int, C.c_void_p), 711 C.c_void_p, C.c_int, C.c_short, C.c_short, C.POINTER(C.c_int64), C.c_short, 712 C.c_short, C.POINTER(MSRecord)] 713__clibmseed.mst_packgroup.restype = C.c_int 714 715__clibmseed.msr_addblockette.argtypes = [C.POINTER(MSRecord), 716 C.POINTER(C.c_char), 717 C.c_int, C.c_int, C.c_int] 718__clibmseed.msr_addblockette.restype = C.POINTER(BlktLink) 719 720__clibmseed.msr_parse.argtypes = [ 721 np.ctypeslib.ndpointer(dtype=np.int8, ndim=1), C.c_int, 722 C.POINTER(C.POINTER(MSRecord)), 723 C.c_int, C.c_int, C.c_int] 724__clibmseed.msr_parse.restype = C.c_int 725 726 727# Set the necessary arg- and restypes. 728__clibmseed.readMSEEDBuffer.argtypes = [ 729 np.ctypeslib.ndpointer(dtype=np.int8, ndim=1, 730 flags=native_str('C_CONTIGUOUS')), 731 C.c_int, 732 C.POINTER(Selections), 733 C.c_int8, 734 C.c_int, 735 C.c_int8, 736 C.c_int8, 737 C.c_int, 738 C.CFUNCTYPE(C.c_longlong, C.c_int, C.c_char) 739] 740__clibmseed.readMSEEDBuffer.restype = C.POINTER(LinkedIDList) 741 742 743__clibmseed.setupLogging.argtpyes = [ 744 C.c_int8, 745 C.CFUNCTYPE(C.c_void_p, C.c_char_p), 746 C.CFUNCTYPE(C.c_void_p, C.c_char_p)] 747__clibmseed.setupLogging.restype = None 748 749 750__clibmseed.msr_free.argtypes = [C.POINTER(C.POINTER(MSRecord))] 751__clibmseed.msr_free.restype = None 752 753 754__clibmseed.mstl_init.restype = C.POINTER(MSTraceList) 755__clibmseed.mstl_free.argtypes = [C.POINTER(C.POINTER(MSTraceList)), C.c_int] 756 757 758__clibmseed.lil_free.argtypes = [C.POINTER(LinkedIDList)] 759__clibmseed.lil_free.restype = None 760 761 762__clibmseed.allocate_bytes.argtypes = (C.c_int,) 763__clibmseed.allocate_bytes.restype = C.c_void_p 764 765 766__clibmseed.ms_genfactmult.argtypes = [ 767 C.c_double, 768 C.POINTER(C.c_int16), 769 C.POINTER(C.c_int16) 770] 771__clibmseed.ms_genfactmult.restype = C.c_int 772 773 774__clibmseed.ms_nomsamprate.argtypes = [ 775 C.c_int, 776 C.c_int 777] 778__clibmseed.ms_nomsamprate.restype = C.c_double 779 780 781class _LibmseedWrapper(object): 782 """ 783 Wrapper object around libmseed that tries to guarantee that all warnings 784 and errors within libmseed are properly converted to their Python 785 counterparts. 786 787 Might be a bit overengineered but it does the trick and is completely 788 transparent to the user. 789 """ 790 def __init__(self, lib): 791 self.lib = lib 792 self.verbose = True 793 794 def __getattr__(self, item): 795 func = getattr(self.lib, item) 796 797 def _wrapper(*args): 798 # Collect exceptions. They cannot be raised in the callback as 799 # they could never be caught then. They are collected and raised 800 # later on. 801 _errs = [] 802 _warns = [] 803 804 def log_error_or_warning(msg): 805 msg = msg.decode() 806 if msg.startswith("ERROR: "): 807 msg = msg[7:].strip() 808 _errs.append(msg) 809 if msg.startswith("INFO: "): 810 msg = msg[6:].strip() 811 _warns.append(msg) 812 813 diag_print = \ 814 C.CFUNCTYPE(None, C.c_char_p)(log_error_or_warning) 815 816 def log_message(msg): 817 if self.verbose: 818 print(msg[6:].strip()) 819 log_print = C.CFUNCTYPE(None, C.c_char_p)(log_message) 820 821 # Hookup libmseed's logging facilities to it's Python callbacks. 822 self.lib.setupLogging(diag_print, log_print) 823 824 try: 825 return func(*args) 826 finally: 827 for _w in _warns: 828 warnings.warn(_w, InternalMSEEDWarning) 829 if _errs: 830 msg = ("Encountered %i error(s) during a call to " 831 "%s():\n%s" % ( 832 len(_errs), item, "\n".join(_errs))) 833 raise InternalMSEEDError(msg) 834 return _wrapper 835 836 837clibmseed = _LibmseedWrapper(lib=__clibmseed) 838