Source code for obspy.clients.seedlink.slpacket

# -*- coding: utf-8 -*-
"""
Module to hold and decode a SeedLink packet.

Part of Python implementation of libslink of Chad Trabant and
JSeedLink of Anthony Lomax

:copyright:
    The ObsPy Development Team (devs@obspy.org) & Anthony Lomax
:license:
    GNU Lesser General Public License, Version 3
    (https://www.gnu.org/copyleft/lesser.html)
"""
import ctypes as C  # NOQA

import numpy as np

from obspy.core.compatibility import from_buffer
from obspy.core.trace import Trace
from obspy.io.mseed.headers import clibmseed
from obspy.io.mseed.util import (_convert_msr_to_dict,
                                 _ctypes_array_2_numpy_array,
                                 _convert_mstime_to_datetime)
from .seedlinkexception import SeedLinkException


[docs]class SLPacket(object): """ Class to hold and decode a SeedLink packet. :var TYPE_SLINFT: Packet type is terminated info packet. :type TYPE_SLINFT: int :var TYPE_SLINF: Packet type is non-terminated info packet. :type TYPE_SLINF: int :var SLTERMINATE: Terminate flag - connection was closed by the server or the termination sequence completed. :type SLTERMINATE: str :var SLNOPACKET: No packet flag - indicates no data available. :type SLNOPACKET: bytes :var SLERROR: Error flag - indicates server reported an error. :type SLERROR: str :var SLHEADSIZE: SeedLink packet header size. :type SLHEADSIZE: int :var SLRECSIZE: Mini-SEED record size. :type SLRECSIZE: int :var SIGNATURE: SeedLink header signature. :type SIGNATURE: str :var INFOSIGNATURE: SeedLink INFO packet signature. :type INFOSIGNATURE: str :var ERRORSIGNATURE: SeedLink ERROR signature. :type ERRORSIGNATURE: str :var ENDSIGNATURE: SeedLink END signature. :type ENDSIGNATURE: str :var slhead: The SeedLink header. :type slhead: bytes :var msrecord: The MiniSEED record. :type msrecord: bytes """ TYPE_SLINFT = -101 TYPE_SLINF = -102 SLTERMINATE = b"SLTERMINATE" SLNOPACKET = b"SLNOPACKET" SLERROR = b"SLERROR" SLHEADSIZE = 8 SLRECSIZE = 512 SIGNATURE = b"SL" INFOSIGNATURE = b"SLINFO" ERRORSIGNATURE = b"ERROR\r\n" ENDSIGNATURE = b"END"
[docs] def __init__(self, data=None, offset=None): if data is None or offset is None: return if len(data) - offset < self.SLHEADSIZE + self.SLRECSIZE: msg = "not enough bytes in sub array to construct a new SLPacket" raise SeedLinkException(msg) self.slhead = data[offset: offset + self.SLHEADSIZE] self.msrecord = data[offset + self.SLHEADSIZE: offset + self.SLHEADSIZE + self.SLRECSIZE] self.trace = None
[docs] def get_sequence_number(self): # print "DEBUG: repr(self.slhead):", repr(self.slhead) # print "DEBUG: self.slhead[0 : len(self.INFOSIGNATURE)].lower():", # print self.slhead[0 : len(self.INFOSIGNATURE)].lower() # print "DEBUG: self.INFOSIGNATURE.lower():", # self.INFOSIGNATURE.lower() if self.slhead[0: len(self.INFOSIGNATURE)].lower() == \ self.INFOSIGNATURE.lower(): return 0 # print "DEBUG: self.slhead[0 : len(self.SIGNATURE)].lower():", # print self.slhead[0 : len(self.SIGNATURE)].lower() # print "DEBUG: self.SIGNATURE.lower():", self.SIGNATURE.lower() if not self.slhead[0: len(self.SIGNATURE)].lower() == \ self.SIGNATURE.lower(): return -1 seqbytes = bytes(self.slhead[2:8]) # print "DEBUG: seqbytes:", seqbytes,", int(seqbytes, 16):", \ # int(seqbytes, 16) seqnum = -1 try: seqnum = int(seqbytes, 16) except Exception: msg = "SLPacket.get_sequence_number(): bad packet sequence number:" print(msg, seqbytes) return -1 return seqnum
[docs] def get_ms_record(self): # following from obspy.io.mseed.tests.test_libmseed.py -> test_msrParse msr = clibmseed.msr_init(None) pyobj = from_buffer(self.msrecord, dtype=np.int8) errcode = \ clibmseed.msr_parse(pyobj, len(pyobj), C.pointer(msr), -1, 1, 1) if errcode != 0: msg = "failed to decode mini-seed record: msr_parse errcode: %s" raise SeedLinkException(msg % (errcode)) # print "DEBUG: msr:", msr msrecord_py = msr.contents # print "DEBUG: msrecord_py:", msrecord_py return msr, msrecord_py
[docs] def free_ms_record(self, msr, msrecord_py): clibmseed.msr_free(msr)
[docs] def get_trace(self): if self.trace is not None: return self.trace msr, msrecord_py = self.get_ms_record() try: header = _convert_msr_to_dict(msrecord_py) # XXX Workaround: in Python 3 msrecord_py.sampletype is a byte # (e.g. b'i'), while keys of mseed.headers.SAMPLESIZES are # unicode ('i') (see above) sampletype = msrecord_py.sampletype if not isinstance(sampletype, str): sampletype = sampletype.decode() data = _ctypes_array_2_numpy_array(msrecord_py.datasamples, msrecord_py.numsamples, sampletype) finally: self.free_ms_record(msr, msrecord_py) # XXX Workaround: the fields in the returned struct of type # obspy.io.mseed.header.MsrecordS have byte values in Python 3, while # the rest of the code still expects them to be string (see #770) # -> convert convert = ('network', 'station', 'location', 'channel', 'dataquality', 'sampletype') for key, value in header.items(): if key in convert and not isinstance(value, str): header[key] = value.decode() # 20111201 AJL - bug fix? header['starttime'] = _convert_mstime_to_datetime(header['starttime']) # 20111205 AJL - bug fix? if 'samprate' in header: header['sampling_rate'] = header['samprate'] del header['samprate'] # Access data directly as NumPy array. self.trace = Trace(data, header) return self.trace
[docs] def get_string_payload(self): """ Get the MiniSEED payload, parsed as string. """ msr, msrecord_py = self.get_ms_record() try: # This is the same data buffer that is accessed by # _ctypes_array_2_numpy_array in get_trace above. payload = C.string_at(msrecord_py.datasamples, msrecord_py.samplecnt) finally: self.free_ms_record(msr, msrecord_py) return payload
[docs] def get_type(self): # print "DEBUG: self.slhead:", repr(self.slhead) if self.slhead[0: len(SLPacket.INFOSIGNATURE)].lower() == \ SLPacket.INFOSIGNATURE.lower(): if (chr(self.slhead[self.SLHEADSIZE - 1]) != '*'): return self.TYPE_SLINFT else: return self.TYPE_SLINF msr, msrecord_py = self.get_ms_record() try: ret = msrecord_py.blkts.contents.blkt_type finally: self.free_ms_record(msr, msrecord_py) return ret