1#! /usr/bin/env python
2# -*- coding: utf-8 -*-
3from __future__ import (absolute_import, division, print_function,
4                        unicode_literals)
5from future.builtins import *  # NOQA
6
7import locale
8import os
9import struct
10import sys
11import time
12
13
14locale.setlocale(locale.LC_ALL, 'C')
15
16formats = (str, str, float, int, int, int, float, int, float, float, float,
17           str, str, str, str, str, str, int, int, str)
18
19
20def main(wfdisc):
21    # read wfdisc file line by line
22    for line in wfdisc:
23        # split line into separate fields
24        parts = line.split()
25
26        i = 0
27        for data in parts:
28            # convert each field to desired format (string, float, int)
29            parts[i] = formats[i](data)
30            i += 1
31
32        # build destination name
33        destname = "%s-%s-%s-%s.ASC" % \
34            (os.path.splitext(parts[16])[0], parts[0], parts[1],
35             time.strftime("%Y%m%d-%H%M%S", time.gmtime(parts[2])))
36        print("station %s, component %s, %u samples" % (parts[0], parts[1],
37                                                        parts[7]))
38        print("=> %s ..." % destname)
39
40        # check if already there
41        if os.path.exists(destname):
42            print("I won't overwrite existing file \"%s\", skipping..." %
43                  os.path.split(destname)[1])
44            continue
45
46        # read unnormalized data
47        datatonorm = convert(parts)
48
49        # normalize data
50        normalized = []
51        for i in datatonorm:
52            normalized.append(i * parts[9])
53
54        # write ASCII file
55        out = open(destname, "w")
56        # write headers
57        for header in buildheader(parts):
58            out.write("%s\n" % header)
59        # write data
60        for value in normalized:
61            out.write("%e\n" % value)
62        out.close()
63
64
65def convert(parts):
66    # open binary data file
67    datafile = open(parts[16], "rb")
68
69    fmt, size = calcfmt(format=parts[13], samples=parts[7])
70
71    try:
72        datafile.seek(parts[17])
73        values = struct.unpack(fmt, datafile.read(size))
74    except Exception:
75        print("error reading binary packed data from \"%s\"" %
76              os.path.split(parts[16])[1])
77        return False
78
79    datafile.close()
80
81    # if its 4 byte format, we are done
82    if parts[13].lower() in ["t4", "s4"]:
83        return values
84    # 3 byte format
85
86    return False
87
88
89def calcfmt(format, samples):
90    # four byte floats
91    if format.lower() == "s4":
92        fmt = ">" + "i" * samples
93        return (fmt, struct.calcsize(fmt))
94    # 4 byte integer
95    elif format.lower() == "t4":
96        fmt = ">" + "f" * samples
97        return (fmt, struct.calcsize(fmt))
98    # 3 byte floats
99    elif format.lower() == "s3":
100        return (False, False)
101    else:
102        return (False, False)
103
104
105def buildheader(parts):
106    headers = []
107
108    headers.append("DELTA: %e" % (1.0 / parts[8]))
109    headers.append("LENGTH: %u" % parts[7])
110    headers.append("STATION: %s" % parts[0])
111    if len(parts[1]) == 3:
112        comp = parts[1][2]
113    else:
114        comp = parts[1]
115    headers.append("COMP: %s" % comp.upper())
116    headers.append("START: %s" % time.strftime("%Y-%b-%d_%H:%M:%S",
117                                               time.gmtime(parts[2])))
118
119    return headers
120
121
122if __name__ == '__main__':
123    try:
124        wfdisc = open(sys.argv[1])
125    except IndexError:
126        print("""
127        Usage: css2asc wfdisc-file
128
129        All traces referenced by the given wfdisc file will be converted
130        to ASCII
131        """)
132    except IOError:
133        print("Cannot access file \"%s\"!" % sys.argv[1])
134
135    main(wfdisc)
136
137    # close file
138    try:
139        wfdisc.close()
140    except Exception:
141        pass
142