# This is the Python tracebuf2 class, courtesy of ISTI # # It will keep track of Tracebuf header variables, and # pack them into a binary string. # # $Id: tracebuf2.py 213 2010-06-03 15:40:04Z paulf $ # (Enable keyword substitution on this file with this command: # svn propset svn:keywords "Id" *.py # ) # # ====================================================================== # Copyright (C) 2000-2009 Instrumental Software Technologies, Inc. (ISTI) # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. If modifications are performed to this code, please enter your own # copyright, name and organisation after that of ISTI. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # 3. All advertising materials mentioning features or use of this # software must display the following acknowledgement: # "This product includes software developed by Instrumental # Software Technologies, Inc. (http://www.isti.com)" # 4. If the software is provided with, or as part of a commercial # product, or is used in other commercial software products the # customer must be informed that "This product includes software # developed by Instrumental Software Technologies, Inc. # (http://www.isti.com)" # 5. The names "Instrumental Software Technologies, Inc." and "ISTI" # must not be used to endorse or promote products derived from # this software without prior written permission. For written # permission, please contact "info@isti.com". # 6. Products derived from this software may not be called "ISTI" # nor may "ISTI" appear in their names without prior written # permission of Instrumental Software Technologies, Inc. # 7. Redistributions of any form whatsoever must retain the following # acknowledgement: # "This product includes software developed by Instrumental # Software Technologies, Inc. (http://www.isti.com/)." # 8. Redistributions of source code, or portions of this source code, # must retain the above copyright notice, this list of conditions # and the following disclaimer. # THIS SOFTWARE IS PROVIDED BY INSTRUMENTAL SOFTWARE # TECHNOLOGIES, INC. "AS IS" AND ANY EXPRESSED OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL INSTRUMENTAL SOFTWARE TECHNOLOGIES, # INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # ====================================================================== # # All of the comments below extracted from C header files are simply for reference, # Natually Python doesn't recognize any #defines! # # From earthworm/include/tracebuf.h: # ##define TRACE2_STA_LEN 7 /* SEED: 5 chars plus terminating NULL */ ##define TRACE2_NET_LEN 9 /* SEED: 2 chars plus terminating NULL */ ##define TRACE2_CHAN_LEN 4 /* SEED: 3 chars plus terminating NULL */ ##define TRACE2_LOC_LEN 3 /* SEED: 2 chars plus terminating NULL */ # ##define TRACE2_VERSION0 '2' /* version[0] for TYPE_TRACEBUF2 */ ##define TRACE2_VERSION1 '0' /* version[1] for TYPE_TRACEBUF2 */ # ##define LOC_NULL_STRING "--" /* NULL string for location code field */ # #typedef struct { # int pinno; /* Pin number */ # int nsamp; /* Number of samples in packet */ # double starttime; /* time of first sample in epoch seconds # (seconds since midnight 1/1/1970) */ # double endtime; /* Time of last sample in epoch seconds */ # double samprate; /* Sample rate; nominal */ # char sta[TRACE2_STA_LEN]; /* Site name (NULL-terminated) */ # char net[TRACE2_NET_LEN]; /* Network name (NULL-terminated) */ # char chan[TRACE2_CHAN_LEN]; /* Component/channel code (NULL-terminated)*/ # char loc[TRACE2_LOC_LEN]; /* Location code (NULL-terminated) */ # char version[2]; /* version field */ # char datatype[3]; /* Data format code (NULL-terminated) */ # char quality[2]; /* Data-quality field */ # char pad[2]; /* padding */ #} TRACE2_HEADER; # # #/*-----------------------------------------* # * Definition of a generic TraceBuf Packet * # *-----------------------------------------*/ # ##define MAX_TRACEBUF_SIZ 4096 /* define maximum size of tracebuf message */ # #typedef union { # char msg[MAX_TRACEBUF_SIZ]; # TRACE_HEADER trh; # TRACE2_HEADER trh2; # int i; #} TracePacket; # # #/* CSS datatype codes # ******************/ #/* # t4 SUN IEEE single precision real # t8 SUN IEEE double precision real # s4 SUN IEEE integer # s2 SUN IEEE short integer # f4 VAX/Intel IEEE single precision real # f8 VAX/Intel IEEE double precision real # i4 VAX/Intel IEEE integer # i2 VAX/Intel IEEE short integer # g2 NORESS gain-ranged #*/ # #/* Byte 0 of data quality flags, as in SEED format # ***********************************************/ ##define AMPLIFIER_SATURATED 0x01 ##define DIGITIZER_CLIPPED 0x02 ##define SPIKES_DETECTED 0x04 ##define GLITCHES_DETECTED 0x08 ##define MISSING_DATA_PRESENT 0x10 ##define TELEMETRY_SYNCH_ERROR 0x20 ##define FILTER_CHARGING 0x40 ##define TIME_TAG_QUESTIONABLE 0x80 from struct import pack import array, re class tracebuf2: """ The base class for any other classes that use TRACEBUF2 It will keep track of Tracebuf header variables, and pack them into a binary string. """ def __init__(self): self.setPinno(0); self.setNsamp("undefined"); self.setStarttime("undefined"); self.setEndtime(0); self.setSamprate("undefined"); self.setSta(""); self.setNet(""); self.setChan(""); self.setLoc("--"); self.setVersion("20"); self.setDatatype("undefined"); self.setQuality(""); self.setPad("\x00\x00"); def getPinno(self): return self.pinno def setPinno(self, newPinno): self.pinno = newPinno def getNsamp(self): return self.nsamp def setNsamp(self, newNsamp): self.nsamp = newNsamp def getStarttime(self): return self.starttime def setStarttime(self, newStarttime): self.starttime = newStarttime def getEndtime(self): return self.endtime def setEndtime(self, newEndtime): if (newEndtime == "auto"): # you can only use "auto" if you've already set start time, sample rate, and number of samples die = 0; if self.starttime == "undefined": print ("can't calculate an end time for an undefined start time.") die = 1 if self.samprate == "undefined": print ("can't calculate an end time for an undefined start time.") die = 1 if self.samprate == 0: print ("can't calculate an end time for sample rate of zero.") die = 1 if self.nsamp == "undefined": print ("can't calculate an end time for an undefined number of samples.") die = 1 if die == 1: exit(2) self.endtime = self.starttime + (self.nsamp-1)/float(self.samprate) else: self.endtime = newEndtime def getSamprate(self): return self.samprate def setSamprate(self, newSamprate): self.samprate = newSamprate def getSta(self): return self.sta def setSta(self, newSta): self.sta = newSta def getNet(self): return self.net def setNet(self, newNet): self.net = newNet def getChan(self): return self.chan def setChan(self, newChan): self.chan = newChan def getLoc(self): return self.loc def setLoc(self, newLoc): self.loc = newLoc def getVersion(self): return self.version def setVersion(self, newVersion): self.version = newVersion def getDatatype(self): return self.datatype def setDatatype(self, newDatatype): self.datatype = newDatatype def getQuality(self): return self.quality def setQuality(self, newQuality): self.quality = newQuality def getPad(self): return self.pad def setPad(self, newPad): self.pad = newPad def getTheader(self): return self.theader def setTheader(self): # Note that packed strings fill extra space with nulls, so you don't need to # add special null termination # < is little endian (intel) # # From the Python struct module man page: (CAPS=unsigned) # h/H short is 2 bytes # i/I int and l/L long are 4 bytes # q/Q long long (__int64 on Windows) is 8 bytes # f float is a 32-bit [4 byte] IEEE floating point number # d double is a 64-bit [8 byte] IEEE floating point number # c = 1 byte char, s=char[]/string packstring = "2i3d7s9s4s3s2s3s2s2s"; if ((re.search('f', self.getDatatype(), re.IGNORECASE)) or (re.search('i', self.getDatatype(), re.IGNORECASE))): # little endian packstring = "<" + packstring else: # Assuming big-endian if not little endian. packstring = ">" + packstring self.theader = pack(packstring, self.pinno, self.nsamp, self.starttime, self.endtime, self.samprate, self.sta, self.net, self.chan, self.loc, self.version, self.datatype, self.quality, self.pad); # Return 'true' if the current platform is little endian # We assume big-endian if not little endian. def getLittleEndian(self): # Thanks Nick Mathewson, author of Mixminion where this "not substantial" portion of code came from: num = struct.pack("@I", 0x01020304) return (num=="\x04\x03\x02\x01") def needToByteswap(self): if (((re.search('f', self.getDatatype(), re.IGNORECASE)) or (re.search('i', self.getDatatype(), re.IGNORECASE))) and (not(getLittleEndian()))) : return True if (((re.search('t', self.getDatatype(), re.IGNORECASE)) or (re.search('s', self.getDatatype(), re.IGNORECASE))) and (getLittleEndian())) : return True if (re.search('g', self.getDatatype(), re.IGNORECASE)): print "Unknown byte order 'NORESS gain-ranged.' Not byte swapping." return False def byteSwapInt(self, inint): a=array.array('i', [inint]) a.byteswap() return (a[0]) def byteSwapDouble(self, indouble): a=array.array('d', [indouble]) a.byteswap() return (a[0])