lc2csv.py 5.91 KB
Newer Older
1
2
#!/usr/bin/env python

3
import argparse
4
import labcomm
5
6
import sys
import time
7
8
9


class Reader(object):
10
11
    def __init__(self, file_):
        self._file = file_
12
13

    def read(self, count):
14
        data = self._file.read(count)
15
16
17
18
19
20
21
22
        if len(data) == 0:
            raise EOFError()
        return data

    def mark(self, value, decl):
        pass


23
24
25
26
27
class FollowingReader(Reader):
    def __init__(self, file_, interval, timeout):
        super(FollowingReader, self).__init__(file_)
        self._interval = interval
        self._timeout = timeout
28
29

    def read(self, count):
30
31
32
33
34
35
36
37
38
39
40
        data = ''
        t_start = time.time()
        while len(data) < count:
            tmp = self._file.read(count - len(data))
            if tmp:
                data += tmp
            else:
                time.sleep(self._interval)
                if self._timeout and time.time() - t_start > self._timeout:
                    raise EOFError()
        return data
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def flatten(sample, _type):
    if isinstance(_type, labcomm.sample):
        flatten(sample, _type.decl)
    elif isinstance(_type, labcomm.array):
        for e in sample:
            flatten(e, _type.decl)
    elif isinstance(_type, labcomm.struct):
        for name, decl in _type.field:
            flatten(sample[name], decl)
    elif isinstance(_type, labcomm.BOOLEAN):
        print "%d," % sample,
    elif isinstance(_type, labcomm.STRING):
        print "\"%s\"," % sample,
    elif isinstance(_type, labcomm.primitive):
        print "%s," % sample,
    else:
59
        raise Exception("Unhandled type.")
60
61


62
def flatten_labels(_type, prefix=""):
63
    if isinstance(_type, labcomm.sample):
64
        flatten_labels(_type.decl, _type.name)
65
66
67
    elif isinstance(_type, labcomm.array):
        if len(_type.indices) != 1:
            raise Exception("Fix multidimensional arrays")
68
        if len(_type.indices) == 0:
69
            raise Exception("We dont't handle dynamical sizes yet %s" % _type)
70
71
        for i in range(0, _type.indices[0]):
            flatten_labels(_type.decl, prefix + "[%d]" % i)
72
73
    elif isinstance(_type, labcomm.struct):
        for name, decl in _type.field:
74
            flatten_labels(decl,
75
76
77
78
                           prefix + "." + name)
    elif isinstance(_type, labcomm.primitive):
        print '"%s",' % prefix,
    else:
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
        raise Exception("Unhandled type.")


def default(type_):
    if isinstance(type_, labcomm.sample):
        return default(type_.decl)
    elif isinstance(type_, labcomm.array):
        if len(type_.indices) != 1:
            raise Exception("Fix multidimensional arrays")
        if len(type_.indices) == 0:
            raise Exception("We dont't handle dynamical sizes yet %s" % type_)
        for i in range(0, type_.indices[0]):
            return [default(type_.decl) for _ in range(type_.indices[0])]
    elif isinstance(type_, labcomm.struct):
        return {name: default(decl) for name, decl in type_.field}
    elif isinstance(type_, labcomm.STRING):
        return ''
    elif isinstance(type_, labcomm.BOOLEAN):
        return False
    elif (isinstance(type_, labcomm.FLOAT) or
          isinstance(type_, labcomm.DOUBLE)):
        return float('NaN')
    elif isinstance(type_, labcomm.primitive):
        # Must be int type.
        return 0
    else:
        raise Exception("Unhandled type. " + str(type(type_)) + " " + str(type_))
106
107
108
109
110
111
112
113


def dump(sample, _type):
    for k in sorted(_type.keys()):
        flatten(sample[k], _type[k])
    print


114
115
116
def dump_labels(type_):
    for k in sorted(type_.keys()):
        flatten_labels(type_[k])
117
118
119
    print


120
121
122
123
124
125
def defaults(current, type_):
    for k in sorted(type_.keys()):
        if k not in current:
            current[k] = default(type_[k])


126
def main(main_args):
127
128
129
    parser = argparse.ArgumentParser()
    parser.add_argument('elc', type=str, help="The log file.")
    parser.add_argument('-f', '--follow', action='store_true',
130
                        help="find all registrations that already "
131
132
133
                        "exist, then watch the file for changes. All "
                        "future registrations are ignored (because "
                        "the header has already been written).")
134
135
136
137
138
139
    parser.add_argument('-s', '--interval', action="store", type=float,
                        default=0.040,
                        help="time to sleep between failed reads. Requires -f.")
    parser.add_argument('-t', '--timeout', action="store", type=float,
                        help="timeout to terminate when no changes are detected. "
                        "Requires -f.")
140
141
142
143
    parser.add_argument('-d', '--default-columns', action="store_true",
                        help="Fill columns for which there has not come any "
                        "data with default values. Useful for getting output "
                        "even if not all registered types ara actually encoded.")
144
    args = parser.parse_args(main_args)
145
146
    seen = {}
    current = {}
147
    type_ = {}
148
    file_ = open(args.elc)
149
150
151
152
    if args.follow:
        reader = FollowingReader(file_, args.interval, args.timeout)
    else:
        reader = Reader(file_)
153
    d = labcomm.Decoder(reader)
154
155
    while True:
        try:
156
157
158
            o, t = d.decode()
            if o is None:
                seen[t.name] = 0
159
                type_[t.name] = t
160
161
            else:
                current[t.name] = o
162
                break
163
164
        except EOFError:
            break
165
166
167
    dump_labels(type_)
    if args.default_columns:
        defaults(current, type_)
168
    while True:
169
        try:
170
171
172
            o, t = d.decode()
            if o is not None:
                current[t.name] = o
173
174
                if len(current) == len(type_):
                    # TODO: Figure out what to trigger on...
175
176
177
                    # Assume that samples arrive at different rates.
                    # Trigger on everything once we have a value for
                    # each column.
178
                    dump(current, type_)
179
180
181
182
183
        except EOFError:
            break


if __name__ == "__main__":
184
    main(sys.argv[1:])