telemetry-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. telemetry_cli/__init__.py +8 -0
  2. telemetry_cli/_cli.py +18 -0
  3. telemetry_cli/_getopt.py +114 -0
  4. telemetry_cli/_msg.py +39 -0
  5. telemetry_cli/_pack.py +183 -0
  6. telemetry_cli/_perl.py +183 -0
  7. telemetry_cli/pick/__init__.py +1 -0
  8. telemetry_cli/pick/__main__.py +7 -0
  9. telemetry_cli/pick/cli.py +157 -0
  10. telemetry_cli/pick/commandline.py +219 -0
  11. telemetry_cli/pick/fields.py +166 -0
  12. telemetry_cli/pick/formats.py +191 -0
  13. telemetry_cli/pick/help.py +536 -0
  14. telemetry_cli/pick/symbols/airmoc +24 -0
  15. telemetry_cli/pick/symbols/aux +28 -0
  16. telemetry_cli/pick/symbols/corr +31 -0
  17. telemetry_cli/pick/symbols/corrOld +29 -0
  18. telemetry_cli/pick/symbols/hw +16 -0
  19. telemetry_cli/pick/symbols/moc +42 -0
  20. telemetry_cli/pick/symbols/subcom +83 -0
  21. telemetry_cli/pick/symbols/subcom_2002 +111 -0
  22. telemetry_cli/recl/__init__.py +1 -0
  23. telemetry_cli/recl/__main__.py +7 -0
  24. telemetry_cli/recl/cli.py +214 -0
  25. telemetry_cli/recl/corr.py +83 -0
  26. telemetry_cli/recs/__init__.py +1 -0
  27. telemetry_cli/recs/__main__.py +7 -0
  28. telemetry_cli/recs/cli.py +182 -0
  29. telemetry_cli/recs/extract.py +399 -0
  30. telemetry_cli/tgen/__init__.py +1 -0
  31. telemetry_cli/tgen/__main__.py +7 -0
  32. telemetry_cli/tgen/cli.py +128 -0
  33. telemetry_cli/tgen/cmdfile.py +68 -0
  34. telemetry_cli/tgen/convert.py +278 -0
  35. telemetry_cli/tgen/examples/arb_data.tgen +15 -0
  36. telemetry_cli/tgen/examples/calsweep.tgen +32 -0
  37. telemetry_cli/tgen/examples/cond_fill.tgen +17 -0
  38. telemetry_cli/tgen/examples/counter.tgen +11 -0
  39. telemetry_cli/tgen/examples/null_data.tgen +11 -0
  40. telemetry_cli/tgen/examples/random_size.tgen +20 -0
  41. telemetry_cli/tgen/examples/subcom.tgen +14 -0
  42. telemetry_cli/tgen/examples/valueV_value.tgen +20 -0
  43. telemetry_cli/tgen/runtime.py +390 -0
  44. telemetry_cli-1.0.0.dist-info/METADATA +106 -0
  45. telemetry_cli-1.0.0.dist-info/RECORD +48 -0
  46. telemetry_cli-1.0.0.dist-info/WHEEL +4 -0
  47. telemetry_cli-1.0.0.dist-info/entry_points.txt +5 -0
  48. telemetry_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,191 @@
1
+ """Printing pick's fields: the print formats (``pick ?f``).
2
+
3
+ The output matches the Perl original's, including its spacing: most formats
4
+ are followed by a space, and x, o, d and u on byte types print another space
5
+ after each byte.
6
+
7
+ Byte order: each item is first put into big-endian order (each half separately
8
+ for complex types), and then printed the way the Perl printed on the
9
+ big-endian machines it was written for. So the output doesn't depend on the
10
+ machine pick runs on, only on the data's byte order.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import math
16
+ import struct
17
+
18
+ from .._perl import multiply, sprintf, substr
19
+ from .fields import STRUCT, Field
20
+
21
+ PI = 3.14159265359 # the Perl original's value, used for the D format
22
+
23
+ FORMAT = {"u": "%u", "d": "%d", "x": "%02x", "o": "%03o", "g": "%g", "G": "%25.18g"}
24
+ FORMAT |= {"M": "%g", "P": "%g", "R": "%g", "I": "%g", "D": "%g"}
25
+
26
+ # names of the ASCII control characters, 0..31
27
+ ASCII_NAMES = ( # noqa: SIM905 (a list literal would take 32 lines)
28
+ "nul soh stx etx eot enq ack bel bs ht nl vt np cr so si "
29
+ "dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us"
30
+ ).split()
31
+
32
+
33
+ class FormatError(ValueError):
34
+ """A print format that can't be used with a field's data type."""
35
+
36
+
37
+ def reversed_order(t: str, nb: int) -> list[int]:
38
+ """Byte indices that reverse an item's byte order (each half, for complex)."""
39
+ if t in "zZ":
40
+ half = nb // 2
41
+ return [*range(half - 1, -1, -1), *range(nb - 1, half - 1, -1)]
42
+ return list(range(nb - 1, -1, -1))
43
+
44
+
45
+ def reorder(data: bytes, order: list[int]) -> bytes:
46
+ """data rearranged by index; missing bytes become zero (as in the Perl)."""
47
+ return bytes(data[i] if i < len(data) else 0 for i in order)
48
+
49
+
50
+ def _index(seq, i):
51
+ """Perl's $array[i]: negative indices count from the end; out of range is undef."""
52
+ if -len(seq) <= i < len(seq):
53
+ return seq[i]
54
+ return None
55
+
56
+
57
+ def _value(d: bytes, t: str):
58
+ """The first item of type t in d (big-endian), as Perl's unpack gave it."""
59
+ if t in "cSA": # unpacked as a one-character string
60
+ return d[:1].decode("latin-1")
61
+ code = STRUCT[t]
62
+ size = struct.calcsize(code)
63
+ return struct.unpack(">" + code, d[:size])[0] if len(d) >= size else None
64
+
65
+
66
+ def _bit_field(d0: bytes, f: Field) -> bytes:
67
+ """Apply a field's bit offset and mask, as the Perl's "slow" path did."""
68
+ nb, out = f.nb, f.out_bytes
69
+ r = [d0[j] if j < len(d0) else 0 for j in range(nb)]
70
+ if nb > 4: # bit fields aren't available for these types
71
+ return bytes(r[j] if j < nb else 0 for j in range(out))
72
+ u = 0
73
+ for x in r:
74
+ u = (u << 8) | x
75
+ u = (u >> f.first_bit) & f.mask
76
+ d = []
77
+ for _ in range(out):
78
+ d.append(u & 0xFF)
79
+ u >>= 8
80
+ d += [0] * (nb - out)
81
+ return bytes(reversed(d))
82
+
83
+
84
+ def render(data: bytes, fields: list[Field], *, order: str, host: str, fast_binary: bool) -> bytes:
85
+ """The output for one record."""
86
+ out = bytearray()
87
+ for f in fields:
88
+ if fast_binary: # -b: the bytes as they are
89
+ out += substr(data, f.pos, f.nb * f.m)
90
+ continue
91
+ rev = reversed_order(f.t, f.nb)
92
+ for i in range(f.m):
93
+ d0 = substr(data, f.pos + i * f.nb, f.nb * f.m)
94
+ item = d0[: f.nb]
95
+ full = len(item) == f.nb
96
+ # big-endian view of the item
97
+ canon = reorder(item, rev) if order == "little" and full else d0
98
+ nbytes = f.out_bytes
99
+ for p in f.formats:
100
+ d = _bit_field(canon, f) if f.bits else canon
101
+ if p == "U":
102
+ out += _unformatted(d, d0, f, order=order, host=host)
103
+ elif f.t in "zZ":
104
+ out += _complex(d, f, p).encode()
105
+ else:
106
+ out += _scalar(d, f, p, nbytes).encode("latin-1")
107
+ if p not in "SAUn":
108
+ out += b" "
109
+ return bytes(out)
110
+
111
+
112
+ def _unformatted(d: bytes, d0: bytes, f: Field, *, order: str, host: str) -> bytes:
113
+ """The 'U' format: the item's bytes, in the host's byte order."""
114
+ nbytes = f.out_bytes
115
+ if f.bits and f.nb <= 4:
116
+ # the masked value's low bytes (the Perl wrote the wrong end of them)
117
+ value = d[len(d) - nbytes :]
118
+ return value[::-1] if host == "little" else value
119
+ if f.bits:
120
+ return d[:nbytes][::-1] if host == "little" and nbytes == f.nb else d[:nbytes]
121
+ if order == host:
122
+ return d0[:nbytes]
123
+ return reorder(d0[: f.nb], reversed_order(f.t, f.nb))[:nbytes]
124
+
125
+
126
+ def _complex(d: bytes, f: Field, p: str) -> str:
127
+ code = STRUCT[f.t]
128
+ size = struct.calcsize(code)
129
+ parts = [struct.unpack_from(">" + code, d, k * size)[0] for k in range(min(2, len(d) // size))]
130
+ re_, im = (parts + [0.0, 0.0])[:2]
131
+ if p == "R":
132
+ return sprintf("%g", re_)
133
+ if p == "I":
134
+ return sprintf("%g", im)
135
+ if p == "g": # documented as RI; the Perl rejected it
136
+ return sprintf("%g", re_) + " " + sprintf("%g", im)
137
+ if p == "M":
138
+ return sprintf("%g", math.sqrt(re_ * re_ + im * im))
139
+ if p == "P":
140
+ return sprintf("%g", math.atan2(im, re_))
141
+ if p == "D":
142
+ return sprintf("%g", multiply(180.0, math.atan2(im, re_)) / PI)
143
+ raise FormatError(f"Unrecognized print format for complex type: {p}")
144
+
145
+
146
+ def _scalar(d: bytes, f: Field, p: str, nbytes: int) -> str:
147
+ t, nb = f.t, f.nb
148
+ if p in "cSA":
149
+ text = []
150
+ for k in range(nb):
151
+ ch = d[k : k + 1]
152
+ o = ch[0] if ch else 0
153
+ if ch and 0x20 <= o <= 0x7E:
154
+ text.append(chr(o))
155
+ elif o < 128:
156
+ if p == "c":
157
+ text.append(ASCII_NAMES[o] if o < 32 else "del")
158
+ elif p == "S":
159
+ text.append(f"({ASCII_NAMES[o] if o < 32 else 'del'})")
160
+ elif p == "c":
161
+ text.append(f"{o:o}")
162
+ elif p == "S":
163
+ text.append(f"({o:o})")
164
+ return "".join(text)
165
+ if p in "udgG" and t not in "cb":
166
+ return sprintf(FORMAT[p], _value(d, t))
167
+ if p == "D":
168
+ return sprintf("%g", multiply(_value(d, t), 180.0) / PI)
169
+ if p == "n":
170
+ return "\n"
171
+ if p == "s":
172
+ return ""
173
+ if p in "xodu":
174
+ k = list(d[:nb])
175
+ return "".join(sprintf(FORMAT[p], _index(k, j)) + " " for j in range(nb - nbytes, nb))
176
+ if p == "b":
177
+ k = list(reversed(d[:nb]))
178
+ bout: list[int] = []
179
+ for j in range(nbytes):
180
+ x = _index(k, j) or 0
181
+ for _ in range(8):
182
+ bout.insert(0, x & 1)
183
+ x >>= 1
184
+ n = len(bout)
185
+ text = []
186
+ for bb in range(n - f.nbits, n):
187
+ text.append(str(_index(bout, bb) or 0))
188
+ if (n - (bb + 1)) % 4 == 0:
189
+ text.append(" ")
190
+ return "".join(text)
191
+ raise FormatError(f"unrecognized print format-->{p}<--")