Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
3 | # Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com> | |
4 | # | |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | # of this software and associated documentation files (the "Software"), to deal | |
7 | # in the Software without restriction, including without limitation the rights | |
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | # copies of the Software, and to permit persons to whom the Software is | |
10 | # furnished to do so, subject to the following conditions: | |
11 | # | |
12 | # The above copyright notice and this permission notice shall be included in | |
13 | # all copies or substantial portions of the Software. | |
14 | # | |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
21 | # THE SOFTWARE. | |
22 | ||
23 | import enum | |
24 | import collections | |
25 | ||
26 | ||
27 | @enum.unique | |
28 | class ByteOrder(enum.Enum): | |
29 | LE = 0 | |
30 | BE = 1 | |
31 | ||
32 | ||
33 | @enum.unique | |
34 | class Encoding(enum.Enum): | |
35 | NONE = 0 | |
36 | UTF8 = 1 | |
37 | ASCII = 2 | |
38 | ||
39 | ||
40 | class Type: | |
41 | @property | |
42 | def align(self): | |
43 | raise NotImplementedError() | |
44 | ||
45 | @property | |
46 | def size(self): | |
47 | raise NotImplementedError() | |
48 | ||
49 | @size.setter | |
50 | def size(self, value): | |
51 | self._size = value | |
52 | ||
53 | ||
54 | class PropertyMapping: | |
55 | def __init__(self, object, prop): | |
56 | self._object = object | |
57 | self._prop = prop | |
58 | ||
59 | @property | |
60 | def object(self): | |
61 | return self._object | |
62 | ||
63 | @object.setter | |
64 | def object(self, value): | |
65 | self._object = value | |
66 | ||
67 | @property | |
68 | def prop(self): | |
69 | return self.prop | |
70 | ||
71 | @prop.setter | |
72 | def prop(self, value): | |
73 | self.prop = value | |
74 | ||
75 | ||
76 | class Integer(Type): | |
77 | def __init__(self): | |
78 | self._size = None | |
79 | self._align = None | |
80 | self._signed = False | |
81 | self._byte_order = None | |
82 | self._base = 10 | |
83 | self._encoding = Encoding.NONE | |
84 | self._property_mappings = [] | |
85 | ||
86 | @property | |
87 | def signed(self): | |
88 | return self._signed | |
89 | ||
90 | @signed.setter | |
91 | def signed(self, value): | |
92 | self._signed = value | |
93 | ||
94 | @property | |
95 | def byte_order(self): | |
96 | return self._byte_order | |
97 | ||
98 | @byte_order.setter | |
99 | def byte_order(self, value): | |
100 | self._byte_order = value | |
101 | ||
102 | @property | |
103 | def base(self): | |
104 | return self._base | |
105 | ||
106 | @base.setter | |
107 | def base(self, value): | |
108 | self._base = value | |
109 | ||
110 | @property | |
111 | def encoding(self): | |
112 | return self._encoding | |
113 | ||
114 | @encoding.setter | |
115 | def encoding(self, value): | |
116 | self._encoding = value | |
117 | ||
118 | @property | |
119 | def align(self): | |
120 | if self._align is None: | |
121 | if self._size is None: | |
122 | return None | |
123 | else: | |
124 | if self._size % 8 == 0: | |
125 | return 8 | |
126 | else: | |
127 | return 1 | |
128 | else: | |
129 | return self._align | |
130 | ||
131 | @align.setter | |
132 | def align(self, value): | |
133 | self._align = value | |
134 | ||
135 | @property | |
136 | def size(self): | |
137 | return self._size | |
138 | ||
139 | @size.setter | |
140 | def size(self, value): | |
141 | self._size = value | |
142 | ||
143 | @property | |
144 | def property_mappings(self): | |
145 | return self._property_mappings | |
146 | ||
147 | ||
148 | class FloatingPoint(Type): | |
149 | def __init__(self): | |
150 | self._exp_size = None | |
151 | self._mant_size = None | |
152 | self._align = 8 | |
153 | self._byte_order = None | |
154 | ||
155 | @property | |
156 | def exp_size(self): | |
157 | return self._exp_size | |
158 | ||
159 | @exp_size.setter | |
160 | def exp_size(self, value): | |
161 | self._exp_size = value | |
162 | ||
163 | @property | |
164 | def mant_size(self): | |
165 | return self._mant_size | |
166 | ||
167 | @mant_size.setter | |
168 | def mant_size(self, value): | |
169 | self._mant_size = value | |
170 | ||
171 | @property | |
172 | def size(self): | |
173 | return self._exp_size + self._mant_size | |
174 | ||
175 | @property | |
176 | def byte_order(self): | |
177 | return self._byte_order | |
178 | ||
179 | @byte_order.setter | |
180 | def byte_order(self, value): | |
181 | self._byte_order = value | |
182 | ||
183 | @property | |
184 | def align(self): | |
185 | return self._align | |
186 | ||
187 | @align.setter | |
188 | def align(self, value): | |
189 | self._align = value | |
190 | ||
191 | ||
192 | class Enum(Type): | |
193 | def __init__(self): | |
194 | self._value_type = None | |
195 | self._members = collections.OrderedDict() | |
196 | ||
197 | @property | |
198 | def align(self): | |
199 | return self._value_type.align | |
200 | ||
201 | @property | |
202 | def size(self): | |
203 | return self._value_type.size | |
204 | ||
205 | @property | |
206 | def value_type(self): | |
207 | return self._value_type | |
208 | ||
209 | @value_type.setter | |
210 | def value_type(self, value): | |
211 | self._value_type = value | |
212 | ||
213 | @property | |
214 | def members(self): | |
215 | return self._members | |
216 | ||
217 | def value_of(self, label): | |
218 | return self._members[label] | |
219 | ||
220 | def label_of(self, value): | |
221 | for label, vrange in self._members.items(): | |
222 | if value >= vrange[0] and value <= vrange[1]: | |
223 | return label | |
224 | ||
225 | def __getitem__(self, key): | |
226 | if type(key) is str: | |
227 | return self.value_of(key) | |
228 | elif type(key) is int: | |
229 | return self.label_of(key) | |
230 | ||
231 | raise TypeError('wrong subscript type') | |
232 | ||
233 | ||
234 | class String(Type): | |
235 | def __init__(self): | |
236 | self._encoding = Encoding.UTF8 | |
237 | ||
238 | @property | |
239 | def size(self): | |
240 | return None | |
241 | ||
242 | @property | |
243 | def align(self): | |
244 | return 8 | |
245 | ||
246 | @property | |
247 | def encoding(self): | |
248 | return self._encoding | |
249 | ||
250 | @encoding.setter | |
251 | def encoding(self, value): | |
252 | self._encoding = value | |
253 | ||
254 | ||
255 | class Array(Type): | |
256 | def __init__(self): | |
257 | self._element_type = None | |
258 | self._length = None | |
259 | ||
260 | @property | |
261 | def align(self): | |
262 | return self._element_type.align | |
263 | ||
264 | @property | |
265 | def element_type(self): | |
266 | return self._element_type | |
267 | ||
268 | @element_type.setter | |
269 | def element_type(self, value): | |
270 | self._element_type = value | |
271 | ||
272 | @property | |
273 | def length(self): | |
274 | return self._length | |
275 | ||
276 | @length.setter | |
277 | def length(self, value): | |
278 | self._length = value | |
279 | ||
280 | @property | |
281 | def is_static(self): | |
282 | return type(self._length) is int | |
283 | ||
284 | @property | |
285 | def size(self): | |
286 | if self.length == 0: | |
287 | return 0 | |
288 | ||
289 | element_sz = self.element_type.size | |
290 | ||
291 | if element_sz is None: | |
292 | return None | |
293 | ||
294 | # TODO: compute static size here | |
295 | return None | |
296 | ||
297 | ||
298 | class Struct(Type): | |
299 | def __init__(self): | |
300 | self._min_align = 1 | |
301 | self._fields = collections.OrderedDict() | |
302 | ||
303 | @property | |
304 | def min_align(self): | |
305 | return self._min_align | |
306 | ||
307 | @min_align.setter | |
308 | def min_align(self, value): | |
309 | self._min_align = value | |
310 | ||
311 | @property | |
312 | def align(self): | |
313 | fields_max = max([f.align for f in self.fields.values()] + [1]) | |
314 | ||
315 | return max(fields_max, self._min_align) | |
316 | ||
317 | @property | |
318 | def size(self): | |
319 | # TODO: compute static size here (if available) | |
320 | return None | |
321 | ||
322 | @property | |
323 | def fields(self): | |
324 | return self._fields | |
325 | ||
326 | def __getitem__(self, key): | |
327 | return self.fields[key] | |
328 | ||
329 | ||
330 | class Variant(Type): | |
331 | def __init__(self): | |
332 | self._tag = None | |
333 | self._types = collections.OrderedDict() | |
334 | ||
335 | @property | |
336 | def align(self): | |
337 | return 1 | |
338 | ||
339 | @property | |
340 | def size(self): | |
341 | if len(self.members) == 1: | |
342 | return list(self.members.values())[0].size | |
343 | ||
344 | return None | |
345 | ||
346 | @property | |
347 | def tag(self): | |
348 | return self._tag | |
349 | ||
350 | @tag.setter | |
351 | def tag(self, value): | |
352 | self._tag = value | |
353 | ||
354 | @property | |
355 | def types(self): | |
356 | return self._types | |
357 | ||
358 | def __getitem__(self, key): | |
359 | return self.types[key] | |
360 | ||
361 | ||
362 | class Trace: | |
363 | def __init__(self): | |
364 | self._byte_order = None | |
365 | self._packet_header_type = None | |
366 | self._uuid = None | |
367 | ||
368 | @property | |
369 | def uuid(self): | |
370 | return self._uuid | |
371 | ||
372 | @uuid.setter | |
373 | def uuid(self, value): | |
374 | self._uuid = value | |
375 | ||
376 | @property | |
377 | def byte_order(self): | |
378 | return self._byte_order | |
379 | ||
380 | @byte_order.setter | |
381 | def byte_order(self, value): | |
382 | self._byte_order = value | |
383 | ||
384 | @property | |
385 | def packet_header_type(self): | |
386 | return self._packet_header_type | |
387 | ||
388 | @packet_header_type.setter | |
389 | def packet_header_type(self, value): | |
390 | self._packet_header_type = value | |
391 | ||
392 | ||
393 | class Env(collections.OrderedDict): | |
394 | pass | |
395 | ||
396 | ||
397 | class Clock: | |
398 | def __init__(self): | |
399 | self._name = None | |
400 | self._uuid = None | |
401 | self._description = None | |
402 | self._freq = 1000000000 | |
403 | self._error_cycles = 0 | |
404 | self._offset_seconds = 0 | |
405 | self._offset_cycles = 0 | |
406 | self._absolute = False | |
407 | self._return_ctype = 'uint32_t' | |
408 | ||
409 | @property | |
410 | def name(self): | |
411 | return self._name | |
412 | ||
413 | @name.setter | |
414 | def name(self, value): | |
415 | self._name = value | |
416 | ||
417 | @property | |
418 | def uuid(self): | |
419 | return self._uuid | |
420 | ||
421 | @uuid.setter | |
422 | def uuid(self, value): | |
423 | self._uuid = value | |
424 | ||
425 | @property | |
426 | def description(self): | |
427 | return self._description | |
428 | ||
429 | @description.setter | |
430 | def description(self, value): | |
431 | self._description = value | |
432 | ||
433 | @property | |
434 | def error_cycles(self): | |
435 | return self._error_cycles | |
436 | ||
437 | @error_cycles.setter | |
438 | def error_cycles(self, value): | |
439 | self._error_cycles = value | |
440 | ||
441 | @property | |
442 | def freq(self): | |
443 | return self._freq | |
444 | ||
445 | @freq.setter | |
446 | def freq(self, value): | |
447 | self._freq = value | |
448 | ||
449 | @property | |
450 | def offset_seconds(self): | |
451 | return self._offset_seconds | |
452 | ||
453 | @offset_seconds.setter | |
454 | def offset_seconds(self, value): | |
455 | self._offset_seconds = value | |
456 | ||
457 | @property | |
458 | def offset_cycles(self): | |
459 | return self._offset_cycles | |
460 | ||
461 | @offset_cycles.setter | |
462 | def offset_cycles(self, value): | |
463 | self._offset_cycles = value | |
464 | ||
465 | @property | |
466 | def absolute(self): | |
467 | return self._absolute | |
468 | ||
469 | @absolute.setter | |
470 | def absolute(self, value): | |
471 | self._absolute = value | |
472 | ||
473 | ||
474 | class Event: | |
475 | def __init__(self): | |
476 | self._id = None | |
477 | self._name = None | |
478 | self._log_level = None | |
479 | self._context_type = None | |
480 | self._payload_type = None | |
481 | ||
482 | @property | |
483 | def id(self): | |
484 | return self._id | |
485 | ||
486 | @id.setter | |
487 | def id(self, value): | |
488 | self._id = value | |
489 | ||
490 | @property | |
491 | def name(self): | |
492 | return self._name | |
493 | ||
494 | @name.setter | |
495 | def name(self, value): | |
496 | self._name = value | |
497 | ||
498 | @property | |
499 | def log_level(self): | |
500 | return self._log_level | |
501 | ||
502 | @log_level.setter | |
503 | def log_level(self, value): | |
504 | self._log_level = value | |
505 | ||
506 | @property | |
507 | def context_type(self): | |
508 | return self._context_type | |
509 | ||
510 | @context_type.setter | |
511 | def context_type(self, value): | |
512 | self._context_type = value | |
513 | ||
514 | @property | |
515 | def payload_type(self): | |
516 | return self._payload_type | |
517 | ||
518 | @payload_type.setter | |
519 | def payload_type(self, value): | |
520 | self._payload_type = value | |
521 | ||
522 | def __getitem__(self, key): | |
523 | if type(self.payload_type) in [Struct, Variant]: | |
524 | return self.payload_type[key] | |
525 | ||
526 | raise TypeError('{} is not subscriptable') | |
527 | ||
528 | ||
529 | class Stream: | |
530 | def __init__(self): | |
531 | self._id = 0 | |
532 | self._name = None | |
533 | self._packet_context_type = None | |
534 | self._event_header_type = None | |
535 | self._event_context_type = None | |
536 | self._events = collections.OrderedDict() | |
537 | ||
538 | @property | |
539 | def name(self): | |
540 | return self._name | |
541 | ||
542 | @name.setter | |
543 | def name(self, value): | |
544 | self._name = value | |
545 | ||
546 | @property | |
547 | def id(self): | |
548 | return self._id | |
549 | ||
550 | @id.setter | |
551 | def id(self, value): | |
552 | self._id = value | |
553 | ||
554 | @property | |
555 | def packet_context_type(self): | |
556 | return self._packet_context_type | |
557 | ||
558 | @packet_context_type.setter | |
559 | def packet_context_type(self, value): | |
560 | self._packet_context_type = value | |
561 | ||
562 | @property | |
563 | def event_header_type(self): | |
564 | return self._event_header_type | |
565 | ||
566 | @event_header_type.setter | |
567 | def event_header_type(self, value): | |
568 | self._event_header_type = value | |
569 | ||
570 | @property | |
571 | def event_context_type(self): | |
572 | return self._event_context_type | |
573 | ||
574 | @event_context_type.setter | |
575 | def event_context_type(self, value): | |
576 | self._event_context_type = value | |
577 | ||
578 | @property | |
579 | def events(self): | |
580 | return self._events | |
581 | ||
582 | ||
583 | class Metadata: | |
584 | def __init__(self): | |
585 | self._trace = None | |
586 | self._env = collections.OrderedDict() | |
587 | self._clocks = collections.OrderedDict() | |
588 | self._streams = collections.OrderedDict() | |
589 | ||
590 | @property | |
591 | def trace(self): | |
592 | return self._trace | |
593 | ||
594 | @trace.setter | |
595 | def trace(self, value): | |
596 | self._trace = value | |
597 | ||
598 | @property | |
599 | def env(self): | |
600 | return self._env | |
601 | ||
602 | @env.setter | |
603 | def env(self, value): | |
604 | self._env = value | |
605 | ||
606 | @property | |
607 | def clocks(self): | |
608 | return self._clocks | |
609 | ||
610 | @clocks.setter | |
611 | def clocks(self, value): | |
612 | self._clocks = value | |
613 | ||
614 | @property | |
615 | def streams(self): | |
616 | return self._streams | |
617 | ||
618 | @streams.setter | |
619 | def streams(self, value): | |
620 | self._streams = value |