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,128 @@
1
+ """The tgen command: generate telemetry records from a command file.
2
+
3
+ tgen [ options ] command_file [ nframes [ firstframe ] ] > telemetry.dat
4
+ tgen --convert old_perl_command_file > new_command_file
5
+
6
+ Run ``tgen -help`` for help.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import sys
12
+ from typing import BinaryIO, TextIO
13
+
14
+ from .. import __version__
15
+ from .._cli import broken_pipe
16
+ from .._getopt import OptionError, getoptions
17
+ from .._perl import numify, truthy
18
+ from . import cmdfile
19
+ from .convert import convert
20
+ from .runtime import Generator, TgenError
21
+
22
+ SPECS = ["h|help|man", "r|random|random_fill", "f|fill=i", "n|notify=i", "q|quiet",
23
+ "v|version", "seed=i", "convert"] # fmt: skip
24
+
25
+ USAGE = """\
26
+ Usage:
27
+ tgen [ options ] command_file [ nframes [ firstframe ] ] > telemetry.dat
28
+ tgen --convert perl_command_file > python_command_file
29
+ tgen -help
30
+ """
31
+
32
+ HELP = (
33
+ USAGE
34
+ + """
35
+ tgen reads a command file and writes records (frames) laid out as it says:
36
+ nframes of them (default 1), numbering them from firstframe (default 0).
37
+
38
+ Options:
39
+ -r, -random fill unspecified bytes with random values
40
+ -f, -fill=n fill unspecified bytes with the byte n (default 0)
41
+ -n, -notify=n report progress on stderr every n frames (default 100)
42
+ -q, -quiet no progress reports
43
+ -seed=n seed the random numbers (rand and -r), for repeatable output
44
+ -convert translate a Perl tgen command file to the Python form
45
+ -v, -version show the version
46
+ -h, -help show this help
47
+
48
+ A command file holds item specifications, one per line:
49
+
50
+ name # offset # trigger # type # value
51
+
52
+ Each field is Python code, evaluated for every frame. The value is packed
53
+ with the type (a Perl pack template such as 'C', 'L', 'a10' or f"C{n}") and
54
+ written at the byte offset, if the trigger is true. A negative offset means
55
+ "evaluate the value but don't write it". Other lines are Python statements,
56
+ run once at the start; lines starting with #, ! or ; are comments.
57
+
58
+ In the code, I is the frame number, F the fill byte, and P.name.value an
59
+ item's value. The full manual, with examples, is at
60
+ https://github.com/donalgrant/telemetry-cli/blob/main/docs/tgen.md
61
+ """
62
+ )
63
+
64
+
65
+ def main(
66
+ argv: list[str] | None = None,
67
+ *,
68
+ stdin: BinaryIO | None = None,
69
+ stdout: BinaryIO | None = None,
70
+ stderr: TextIO | None = None,
71
+ ) -> int:
72
+ argv = sys.argv[1:] if argv is None else list(argv)
73
+ stdout = stdout if stdout is not None else sys.stdout.buffer
74
+ stderr = stderr if stderr is not None else sys.stderr
75
+
76
+ def error(message: str, status: int = 1) -> int:
77
+ print(f"tgen: {message}", file=stderr)
78
+ return status
79
+
80
+ try:
81
+ o, args = getoptions(argv, SPECS)
82
+ except OptionError as e:
83
+ return error(f"{e} (see 'tgen -help')", 2)
84
+ if o.get("v"):
85
+ print(f"tgen (Python), from telemetry-cli {__version__}", file=stderr)
86
+ return 0
87
+ if o.get("h"):
88
+ stdout.write(HELP.encode())
89
+ return 0
90
+ if not args:
91
+ stderr.write(USAGE)
92
+ return 2
93
+ try:
94
+ with open(args[0], encoding="latin-1") as f:
95
+ text = f.read()
96
+ except OSError as e:
97
+ return error(f"Can't read {args[0]}: {e.strerror}")
98
+ if o.get("convert"):
99
+ stdout.write(convert(text).encode("latin-1"))
100
+ return 0
101
+
102
+ def count(i, default):
103
+ if len(args) <= i:
104
+ return default
105
+ v = numify(args[i])
106
+ return int(v) if truthy(args[i]) and v else default # Perl: shift || default
107
+
108
+ nframes, first = count(1, 1), count(2, 0)
109
+ fill = "random" if o.get("r") else o.get("f", 0)
110
+ try:
111
+ items, statements = cmdfile.parse(text)
112
+ gen = Generator(
113
+ items, statements, fill=fill, seed=o.get("seed"), stderr=stderr, source=args[0]
114
+ )
115
+ gen.run(
116
+ stdout,
117
+ nframes,
118
+ first,
119
+ notify=o.get("n") or 100,
120
+ quiet=bool(o.get("q")),
121
+ progress=lambda m: print(m, file=stderr),
122
+ )
123
+ except TgenError as e:
124
+ return error(str(e))
125
+ except BrokenPipeError:
126
+ return broken_pipe(stdout)
127
+ stdout.flush()
128
+ return 0
@@ -0,0 +1,68 @@
1
+ """Reading tgen command files.
2
+
3
+ A command file has three kinds of lines:
4
+
5
+ - comments: lines starting with ``#``, ``!`` or ``;`` in the first column;
6
+ - item specifications, with at least four `` # `` separators (a ``#`` with
7
+ white space on both sides)::
8
+
9
+ name # offset # trigger # type # value
10
+
11
+ - statements, run once before any record is generated.
12
+
13
+ A line ending in a backslash continues on the next line.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ from dataclasses import dataclass
20
+
21
+ SEPARATOR = re.compile(r"\s+[#]\s+")
22
+
23
+
24
+ @dataclass
25
+ class Item:
26
+ name: str
27
+ offset: str
28
+ trigger: str
29
+ type: str
30
+ value: str
31
+ line: int # where the specification starts in the file
32
+
33
+
34
+ @dataclass
35
+ class Statement:
36
+ code: str
37
+ line: int
38
+
39
+
40
+ def logical_lines(text: str):
41
+ """(line number, text) of each logical line, with continuations joined."""
42
+ lines = text.split("\n")
43
+ if lines and lines[-1] == "":
44
+ lines.pop()
45
+ i = 0
46
+ while i < len(lines):
47
+ start = i + 1
48
+ line = lines[i]
49
+ i += 1
50
+ while line.endswith("\\"):
51
+ line = line[:-1]
52
+ if i < len(lines):
53
+ line += lines[i]
54
+ i += 1
55
+ yield start, line
56
+
57
+
58
+ def parse(text: str) -> tuple[list[Item], list[Statement]]:
59
+ items, statements = [], []
60
+ for n, line in logical_lines(text):
61
+ if line[:1] in ("#", "!", ";"):
62
+ continue
63
+ if len(SEPARATOR.findall(line)) >= 4:
64
+ fields = [f.strip() for f in SEPARATOR.split(line)]
65
+ items.append(Item(*fields[:5], line=n)) # further fields are ignored
66
+ elif line.strip():
67
+ statements.append(Statement(line.strip(), n))
68
+ return items, statements
@@ -0,0 +1,278 @@
1
+ """Translate a Perl tgen command file into the Python form (``tgen --convert``).
2
+
3
+ The translation is pattern-based. It handles what tgen command files usually
4
+ contain: ``$::name`` variables, ``$P{item}{field}``, arithmetic, string
5
+ concatenation, interpolated strings, ``map { ... } (a..b)``, ``++``/``--``,
6
+ and statement modifiers (``x if y``). Anything else that looks like Perl is
7
+ left as it is, with a ``# TODO(convert)`` comment line above it, so that
8
+ running the result fails loudly rather than doing something different.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import ast
14
+ import re
15
+
16
+ from .cmdfile import SEPARATOR, logical_lines
17
+
18
+ _PERLISH = re.compile(
19
+ r"\$|@|->|\bsub\b|=~|\bmy\b|\bprint\b(?!\()|\?|\blast\b|\bnext\b|\beq\b|\bne\b"
20
+ )
21
+
22
+
23
+ def convert(text: str) -> str:
24
+ out = []
25
+ for _, line in logical_lines(text):
26
+ if line[:1] in ("#", "!", ";") or not line.strip():
27
+ out.append(line)
28
+ continue
29
+ if len(SEPARATOR.findall(line)) >= 4:
30
+ parts = SEPARATOR.split(line)
31
+ seps = SEPARATOR.findall(line)
32
+ fields = [parts[0].strip()] + [expr(p.strip()) for p in parts[1:5]]
33
+ todo = [f for f in fields[1:] if _PERLISH.search(_strip_strings(f))]
34
+ rest = "".join(s + p for s, p in zip(seps[4:], parts[5:], strict=False))
35
+ new = fields[0] + "".join(s + f for s, f in zip(seps, fields[1:], strict=False)) + rest
36
+ else:
37
+ new = statement(line.strip())
38
+ todo = [new] if _PERLISH.search(_strip_strings(new)) else []
39
+ if todo:
40
+ out.append("# TODO(convert): this line still contains Perl")
41
+ out.append(new)
42
+ return "\n".join(out) + "\n"
43
+
44
+
45
+ # --- pieces --------------------------------------------------------------------
46
+
47
+ _STRING = re.compile(r"""("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')""")
48
+
49
+
50
+ def _strip_strings(s: str) -> str:
51
+ return _STRING.sub('""', s)
52
+
53
+
54
+ def _split_code(s: str):
55
+ """Alternating (code, string literal) pieces of s."""
56
+ pos = 0
57
+ for m in _STRING.finditer(s):
58
+ yield s[pos : m.start()], False
59
+ yield m.group(0), True
60
+ pos = m.end()
61
+ yield s[pos:], False
62
+
63
+
64
+ def _variables(code: str) -> str:
65
+ code = re.sub(r"\$P\{\s*(\w+)\s*\}\s*\{\s*(\w+)\s*\}", r"P.\1.\2", code)
66
+ code = re.sub(r"[$@]::(\w+)", r"\1", code)
67
+ code = re.sub(r"\bmy\s+[$@](\w+)", r"\1", code)
68
+ code = re.sub(r"\$_\b", "_", code)
69
+ code = re.sub(r"[$@](\w+)", r"\1", code)
70
+ return code
71
+
72
+
73
+ def _string(lit: str) -> str:
74
+ """A Perl string literal as Python: double-quoted strings interpolate."""
75
+ if lit.startswith("'"):
76
+ if "$" in lit: # code in a string, for seek_file's offset and condition
77
+ return "'" + _code(lit[1:-1]) + "'"
78
+ return lit
79
+ body = lit[1:-1]
80
+ if not re.search(r"[$@]", body.replace("\\$", "").replace("\\@", "")):
81
+ return lit
82
+ body = body.replace("{", "{{").replace("}", "}}")
83
+ body = re.sub(r"\$(?:::)?(\w+)", r"{\1}", body)
84
+ return 'f"' + body + '"'
85
+
86
+
87
+ def _ranges(code: str) -> str:
88
+ return re.sub(r"\(\s*([^()]+?|\([^()]*\))\s*\.\.\s*(\([^()]*\)|[^()]+?)\s*\)",
89
+ r"range(\1, \2 + 1)", code) # fmt: skip
90
+
91
+
92
+ def _maps(code: str) -> str:
93
+ # [ map { EXPR } (LIST) ] and map { EXPR } (LIST)
94
+ code = re.sub(r"\[\s*map\s*\{(.*)\}\s*(range\(.*\)|\(.*\))\s*\]", r"[\1 for _ in \2]", code)
95
+ code = re.sub(r"\bmap\s*\{(.*)\}\s*(range\(.*\)|\(.*\))", r"[\1 for _ in \2]", code)
96
+ return code
97
+
98
+
99
+ def _operators(code: str) -> str:
100
+ code = re.sub(r"&&", " and ", code)
101
+ code = re.sub(r"\|\|", " or ", code)
102
+ code = re.sub(r"!(?!=)", " not ", code)
103
+ code = re.sub(r"\beq\b", "==", code)
104
+ code = re.sub(r"\bne\b", "!=", code)
105
+ return code
106
+
107
+
108
+ # Perl operators whose operands are integers, and the helpers that do the same
109
+ _INTEGER_OPS = {ast.Mod: "pmod", ast.BitAnd: "pand", ast.BitOr: "por", ast.BitXor: "pxor",
110
+ ast.LShift: "pshl", ast.RShift: "pshr"} # fmt: skip
111
+
112
+
113
+ def _integer_ops(code: str) -> str:
114
+ """Rewrite %, &, |, ^, << and >> as calls to helpers with Perl's integer semantics.
115
+
116
+ Only those expressions change; the rest of the text is kept as written.
117
+ """
118
+ if not re.search(r"%|&|\||\^|<<|>>", _strip_strings(code)) or "\n" in code:
119
+ return code
120
+ try:
121
+ tree = ast.parse(code)
122
+ except SyntaxError:
123
+ return code # still Perl; it will be marked for review
124
+ src = code.encode()
125
+
126
+ def needs(node) -> bool:
127
+ return any(isinstance(n, ast.BinOp) and type(n.op) in _INTEGER_OPS for n in ast.walk(node))
128
+
129
+ def span(node) -> tuple[int, int]:
130
+ return node.col_offset, node.end_col_offset
131
+
132
+ def render(node) -> bytes:
133
+ if isinstance(node, ast.BinOp) and type(node.op) in _INTEGER_OPS:
134
+ fn = _INTEGER_OPS[type(node.op)].encode()
135
+ return fn + b"(" + render(node.left) + b", " + render(node.right) + b")"
136
+ start, end = span(node)
137
+ text = src[start:end]
138
+ for child in sorted(
139
+ (c for c in ast.iter_child_nodes(node) if hasattr(c, "col_offset") and needs(c)),
140
+ key=lambda c: c.col_offset,
141
+ reverse=True,
142
+ ):
143
+ cs, ce = span(child)
144
+ text = text[: cs - start] + render(child) + text[ce - start :]
145
+ return text
146
+
147
+ out = src
148
+ for stmt in sorted(tree.body, key=lambda n: n.col_offset, reverse=True):
149
+ if needs(stmt):
150
+ s0, e0 = span(stmt)
151
+ out = out[:s0] + render(stmt) + out[e0:]
152
+ return out.decode()
153
+
154
+
155
+ def _code(code: str) -> str:
156
+ return _operators(_maps(_ranges(_variables(code))))
157
+
158
+
159
+ def _finish(code: str) -> str:
160
+ return _integer_ops(code)
161
+
162
+
163
+ def _concat_pieces(s: str) -> list[str]:
164
+ """s split at Perl's string-concatenation operator (.), outside strings and brackets.
165
+
166
+ A dot next to a digit is part of a number, and ".." is a range.
167
+ """
168
+ pieces, depth, start, i, quote = [], 0, 0, 0, None
169
+ while i < len(s):
170
+ ch = s[i]
171
+ if quote:
172
+ if ch == "\\":
173
+ i += 1
174
+ elif ch == quote:
175
+ quote = None
176
+ elif ch in "'\"":
177
+ quote = ch
178
+ elif ch in "([{":
179
+ depth += 1
180
+ elif ch in ")]}":
181
+ depth -= 1
182
+ elif ch == "." and depth == 0:
183
+ before, after = s[i - 1 : i], s[i + 1 : i + 2]
184
+ if "." not in (before, after) and not (before.isdigit() or after.isdigit()):
185
+ pieces.append(s[start:i])
186
+ start = i + 1
187
+ i += 1
188
+ pieces.append(s[start:])
189
+ return pieces
190
+
191
+
192
+ def _translate(s: str) -> str:
193
+ pieces = _concat_pieces(s)
194
+ if len(pieces) > 1: # Perl's . joins strings, and numbers as text
195
+ return "cat(" + ", ".join(_translate(p.strip()) for p in pieces) + ")"
196
+ out = []
197
+ for piece, is_string in _split_code(s):
198
+ out.append(_string(piece) if is_string else _code(piece))
199
+ return "".join(out)
200
+
201
+
202
+ def _increments(stmt: str) -> str:
203
+ """x++ / ++x / x-- / --x as assignments."""
204
+ m = re.fullmatch(r"\s*(?:(\+\+|--)\s*(\S+?)|(\S+?)\s*(\+\+|--))\s*", stmt)
205
+ if not m:
206
+ return stmt
207
+ op = m.group(1) or m.group(4)
208
+ target = m.group(2) or m.group(3)
209
+ return f"{target} = {target} {'+' if op == '++' else '-'} 1"
210
+
211
+
212
+ def _statements(s: str) -> list[str]:
213
+ parts, depth, cur, quote = [], 0, "", None
214
+ for ch in s:
215
+ if quote:
216
+ cur += ch
217
+ if ch == quote:
218
+ quote = None
219
+ continue
220
+ if ch in "'\"":
221
+ quote = ch
222
+ elif ch in "([{":
223
+ depth += 1
224
+ elif ch in ")]}":
225
+ depth -= 1
226
+ elif ch == ";" and depth == 0:
227
+ parts.append(cur)
228
+ cur = ""
229
+ continue
230
+ cur += ch
231
+ parts.append(cur)
232
+ return [p.strip() for p in parts if p.strip()]
233
+
234
+
235
+ def _modifier(stmt: str, *, as_expression: bool) -> str:
236
+ """Perl's `STATEMENT if CONDITION`."""
237
+ m = re.fullmatch(r"(.+?)\s+if\s+(.+)", stmt)
238
+ if not m or " else " in stmt:
239
+ return _increments(stmt)
240
+ body, cond = _increments(m.group(1)), m.group(2)
241
+ if not as_expression:
242
+ return f"if {cond}: {body}"
243
+ a = re.fullmatch(r"(\w+(?:\.\w+)*)\s*=\s*(.+)", body)
244
+ if a:
245
+ return f"{a.group(1)} = {a.group(2)} if {cond} else {a.group(1)}"
246
+ return f"({body}) if ({cond}) else None"
247
+
248
+
249
+ def _print(stmt: str) -> str:
250
+ m = re.fullmatch(r"print\s+STDERR\s+(.+?)((?:\s+if\s+.+)?)", stmt)
251
+ if not m:
252
+ return stmt
253
+ return f'print({m.group(1)}, file=stderr, end=""){m.group(2)}'
254
+
255
+
256
+ def expr(field: str) -> str:
257
+ """A Perl item field (an expression, or statements whose last value counts)."""
258
+ stmts = [_translate(_print(s)) for s in _statements(field)]
259
+ return _finish("; ".join(_modifier(s, as_expression=True) for s in stmts))
260
+
261
+
262
+ def statement(line: str) -> str:
263
+ """A Perl statement line (run once)."""
264
+ code, comment = _split_comment(line)
265
+ stmts = [_translate(_print(s)) for s in _statements(code)]
266
+ new = _finish("; ".join(_modifier(s, as_expression=False) for s in stmts))
267
+ return new + (f" {comment}" if comment else "")
268
+
269
+
270
+ def _split_comment(line: str) -> tuple[str, str]:
271
+ """Code and a trailing # comment (outside strings)."""
272
+ pos = 0
273
+ for piece, is_string in _split_code(line):
274
+ if not is_string and "#" in piece:
275
+ i = pos + piece.index("#")
276
+ return line[:i].rstrip(), line[i:]
277
+ pos += len(piece)
278
+ return line, ""
@@ -0,0 +1,15 @@
1
+ #
2
+ # Arbitrarily-filled data file -- generates 1024-byte records
3
+ #
4
+
5
+ # this following item specification gives only the value of the
6
+ # final byte (byte 1023, with is the 1024th zero-offset byte);
7
+ # the bytes at all earlier byte offsets are padded automatically.
8
+ # $::F is a special variable in tgen which contains the value
9
+ # of the fill byte. The value is zero by default, but can
10
+ # be specified on the command line as any other byte value using
11
+ # the -f flag, or can be made random using the -r flag.
12
+
13
+ data # 1023 # 1 # 'C' # F
14
+
15
+ # end of command file
@@ -0,0 +1,32 @@
1
+ #
2
+ # Generate a binary data file
3
+ #
4
+
5
+ # some parameters to define a digital system
6
+
7
+ pi=3.141592654 # the (approx) value of pi
8
+ nf=10 # number of caltones to generate
9
+ f0=5.0e6 # minimum caltone frequency
10
+ f_max=35.0e6 # maximum caltone frequency
11
+ df=(f_max-f0)/(nf-1) # frequency step
12
+
13
+ f = [ f0+_*df for _ in range(1, nf + 1)] # array of frequencies
14
+
15
+ fs=90.0e6 # sampling rate
16
+ a=2.0*pi/fs # convenience coefficient
17
+
18
+ ns=256 # number of samples to generate
19
+
20
+ # below we have two item specifications:
21
+ # 'calfreq' calculates which caltone frequency
22
+ # we should use for the current pulse, and
23
+ # data actually generates the sample values
24
+ # to be written for the current pulse, using
25
+ # the caltone frequency calculated previously.
26
+
27
+ calfreq # -1 # 1 # X # pmod(I/32, nf) # 32 pulses per caltone
28
+
29
+ data # 0 # 1 # f"C{ns}" # [ 128+int(128.0*cos(a*_*f[P.calfreq.value])) for _ in range(1, (ns-1) + 1)]
30
+
31
+ # end of command file
32
+
@@ -0,0 +1,17 @@
1
+ #
2
+ # Change fill behavior on every third pulse
3
+ #
4
+
5
+ zero_fill # -1 # (pmod(I, 3))==0 # X # F=0
6
+ rail_fill # -1 # (pmod(I, 3))==1 # X # F=255
7
+ rand_fill # -1 # (pmod(I, 3))==2 # X # F="random"
8
+
9
+ pulse_number # 0 # 1 # 'C' # I
10
+ last_byte # 9 # 1 # 'C' # F
11
+
12
+ # Note that the -1 offset for the first three item specs
13
+ # means that the fields are only evaluated when the trigger field is true,
14
+ # but not written. The pack-type is ignored in this case.
15
+
16
+ # end of command file
17
+
@@ -0,0 +1,11 @@
1
+ #
2
+ # Generate different counters
3
+ #
4
+
5
+ every_pulse_byte # 0 # 1 # 'C' # pmod(I, 256)
6
+ every_other_pulse_byte # 1 # 1 # 'C' # pmod(I/2, 256)
7
+ count_to_4 # 2 # 1 # 'C' # (pmod(I, 4)) + 1
8
+ every_pulse_long # 3 # 1 # 'L' # I
9
+
10
+ # end of command file
11
+
@@ -0,0 +1,11 @@
1
+ #
2
+ # Null data file -- generates 1024-byte null-valued data items.
3
+ #
4
+
5
+ # this following item specification gives only the value of the
6
+ # final byte (byte 1023, with is the 1024th zero-offset byte).
7
+ # the bytes at all earlier byte offsets are null-padded automatically.
8
+
9
+ data # 1023 # 1 # 'C' # 0
10
+
11
+ # end of command file
@@ -0,0 +1,20 @@
1
+ #
2
+ # random record lengths
3
+ #
4
+
5
+ # we make use of the fact that the byte-offset is actually
6
+ # a Perl-evaluated statement for each pulse, so that it
7
+ # can vary from one pulse to the next. We'll write random
8
+ # or fixed value data (using the -r or -f flag on the command line)
9
+ # but have a fixed "PN-Sequence" for the start of the records.
10
+
11
+ pn # 0 # 1 # 'L' # 0x03915ed3
12
+
13
+ # the following item gives a random byte offset between 4
14
+ # (so that we don't try to over-write the pn-sequence)
15
+ # and 255 (maximum 256-byte record length). The value
16
+ # is the same as the fill byte value.
17
+
18
+ data # int(rand()*252)+4 # 1 # 'C' # F
19
+
20
+ # end of command file
@@ -0,0 +1,14 @@
1
+ #
2
+ # Generate a "subcommutated header" -- use this command file
3
+ #
4
+
5
+ SUB_LENGTH=500 # size (bytes) of subcom data record
6
+ SUB_BYTES=10 # number of subcom bytes per record
7
+ FILE='subcom.tgen' # use this file for example subcom data (run from its directory)
8
+
9
+ counter # 0 # 1 # 'L' # I
10
+ sub_index # 4 # 1 # 'S' # pmod(I * SUB_BYTES, SUB_LENGTH)
11
+ sub_data # 6 # 1 # 'a10' # subcom_file(FILE,P.sub_index.value,10)
12
+
13
+ # end of command file
14
+
@@ -0,0 +1,20 @@
1
+ #
2
+ # Contrast the value and _value $P{}{} fields
3
+ #
4
+
5
+ random_number # 0 # 1 # 'f' # rand(1.0)
6
+
7
+ COUNT1=0 # this does a count on the rand(1.0) function
8
+ COUNT2=0 # this one will be what we were probably wanting
9
+
10
+ value_1 # 4 # 1 # 'S' # COUNT1 = COUNT1 + 1 if P.random_number._value>0.5 else COUNT1; COUNT1
11
+
12
+ value_2 # 6 # 1 # 'S' # COUNT2 = COUNT2 + 1 if P.random_number.value>0.5 else COUNT2; COUNT2
13
+
14
+ # The difference between the two is that _value does an 'eval' on the
15
+ # content of the value field (in this case, the rand(1.0) function),
16
+ # while value gives the result of the eval when the item was generated
17
+ # for this record.
18
+
19
+ # end of command file
20
+