oep-client-python 0.0.1__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.
@@ -0,0 +1,235 @@
1
+ """v1 messages (oep-spec docs/oep-core.ja.md §2-§5): the v0 request/result headers plus the session flag,
2
+ and the §0 rules for what follows a payload's fixed part.
3
+
4
+ request : role(0x01) corr(u16) fn(u16) op(u8) payload
5
+ role(0x81) corr(u16) fn(u16) op(u8) session_id(u32) payload role bit 7 = session_id present
6
+ result : role(0x02) corr(u16) resolution(u8) detail(u8) payload
7
+
8
+ §0 tails: after a result's fixed part (and any counted list) come TLVs (tag u8, len u8, value); the host skips tags it
9
+ does not know and never rejects a longer result. A request may end with TLVs too; tag bit 7 = critical (the probe
10
+ honours it or answers rejected unsupported with the tag), and the probe lists the non-critical tags it ignored in a
11
+ result TLV 0x7F. Numbers come from `registry` (generated from oep-spec registry/oep-v1.toml).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import struct
17
+ from dataclasses import dataclass, field
18
+
19
+ from . import registry as reg
20
+
21
+ ROLE_REQUEST, ROLE_RESULT = reg.ROLES["request"], reg.ROLES["result"]
22
+ ROLE_EVENT, ROLE_DATA = reg.ROLES["event"], reg.ROLES["data"]
23
+ ROLE_SESSION = reg.ROLE_SESSION_FLAG
24
+ REQUEST_HEADER, RESULT_HEADER, SESSION_BYTES = 6, 5, 4
25
+
26
+ REJECTED, COMPLETED, ACCEPTED = (reg.RESOLUTIONS[k] for k in ("rejected", "completed", "accepted"))
27
+ SUCCESS, FAILED, PARTIAL = (reg.OUTCOMES[k] for k in ("success", "failed", "partial"))
28
+
29
+ _R = reg.REJECT_REASONS
30
+ UNKNOWN_FUNCTION = _R["unknown_function"]
31
+ UNKNOWN_OPERATION = _R["unknown_operation"]
32
+ MALFORMED = _R["malformed"]
33
+ UNAVAILABLE = _R["unavailable"]
34
+ BUSY = _R["busy"] # a long operation is running: answered at once
35
+ WINDOW_EXCEEDED = _R["window_exceeded"]
36
+ NO_SESSION = _R["no_session"] # lock free, but this is not the last session id: open again
37
+ LOCKED = _R["locked"] # another session holds the lock; payload = remaining ms (u32)
38
+ SESSION_REQUIRED = _R["session_required"] # a state-changing request came without a session id
39
+ NO_CONNECTION = _R["no_connection"] # the probe does not know the request's connection: attach again
40
+ UNSUPPORTED = _R["unsupported"] # a critical TLV (payload: its tag) or a fixed-part value it cannot handle
41
+ RESULT_LOST = _R["result_lost"] # a request sent again whose result the probe did not keep: read the state again
42
+ CORR_REUSED = _R["corr_reused"] # a request sent again with the same corr but another fn, op or payload
43
+
44
+ REJECT_NAMES = {v: k.replace("_", " ") for k, v in _R.items()}
45
+ REJECT_NAMES[MALFORMED] = "malformed payload"
46
+
47
+ TAG_CRITICAL, TAG_IGNORED, TAG_INVALID = reg.TAG_CRITICAL, reg.TAG_IGNORED, reg.TAG_INVALID
48
+
49
+ # core (fn 0) operations
50
+ CORE_FN = 0
51
+ _OP = reg.CORE.op
52
+ OP_CONFIRM, OP_LIST, OP_DESCRIBE = _OP["confirm"], _OP["list"], _OP["describe"]
53
+ OP_PLAN_APPLY, OP_PLAN_RELEASE = _OP["plan_apply"], _OP["plan_release"]
54
+ OP_OPEN, OP_END, OP_KEEPALIVE, OP_LOCK_STATE = _OP["open"], _OP["end"], _OP["keepalive"], _OP["lock_state"]
55
+ OP_SUBSCRIBE, OP_UNSUBSCRIBE = _OP["subscribe"], _OP["unsubscribe"]
56
+ OP_LINK_SOURCE, OP_LINK_SINK = _OP["link_source"], _OP["link_sink"]
57
+
58
+ CONFIRM_REQUEST = reg.CONFIRM_REQUEST_MAGIC.encode()
59
+ CONFIRM_RESULT = reg.CONFIRM_RESULT_MAGIC.encode()
60
+
61
+
62
+ class OepError(Exception):
63
+ """Anything the probe or the link said no to."""
64
+
65
+
66
+ class ProtocolError(OepError, ValueError):
67
+ """A result that does not fit: wrong correlation, too short, a value this host does not know."""
68
+
69
+
70
+ class ShortPayload(ProtocolError):
71
+ """A payload shorter than its fixed part, or a truncated TLV (a broken result, §0)."""
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class Request:
76
+ corr: int
77
+ fn: int
78
+ op: int
79
+ payload: bytes = b""
80
+ session: int | None = None
81
+
82
+ def pack(self) -> bytes:
83
+ if self.session is None:
84
+ return struct.pack("<BHHB", ROLE_REQUEST, self.corr, self.fn, self.op) + self.payload
85
+ return (struct.pack("<BHHBI", ROLE_REQUEST | ROLE_SESSION, self.corr, self.fn, self.op, self.session)
86
+ + self.payload)
87
+
88
+ @classmethod
89
+ def unpack(cls, data: bytes) -> Request:
90
+ if len(data) < REQUEST_HEADER:
91
+ raise ValueError("request shorter than its header")
92
+ role, corr, fn, op = struct.unpack_from("<BHHB", data)
93
+ if role & ~ROLE_SESSION != ROLE_REQUEST:
94
+ raise ValueError(f"not a request: role 0x{role:02x}")
95
+ if role & ROLE_SESSION:
96
+ if len(data) < REQUEST_HEADER + SESSION_BYTES:
97
+ raise ValueError("session flag set but no session id")
98
+ (session,) = struct.unpack_from("<I", data, REQUEST_HEADER)
99
+ return cls(corr, fn, op, data[REQUEST_HEADER + SESSION_BYTES:], session)
100
+ return cls(corr, fn, op, data[REQUEST_HEADER:], None)
101
+
102
+
103
+ @dataclass(frozen=True)
104
+ class Result:
105
+ corr: int
106
+ resolution: int
107
+ detail: int
108
+ payload: bytes = b""
109
+
110
+ def pack(self) -> bytes:
111
+ return struct.pack("<BHBB", ROLE_RESULT, self.corr, self.resolution, self.detail) + self.payload
112
+
113
+ @classmethod
114
+ def unpack(cls, data: bytes) -> Result:
115
+ if len(data) < RESULT_HEADER:
116
+ raise ShortPayload("result shorter than its header")
117
+ role, corr, resolution, detail = struct.unpack_from("<BHBB", data)
118
+ if role != ROLE_RESULT:
119
+ raise ValueError(f"not a result: role 0x{role:02x}")
120
+ return cls(corr, resolution, detail, data[RESULT_HEADER:])
121
+
122
+ @property
123
+ def succeeded(self) -> bool:
124
+ return self.resolution == COMPLETED and self.detail == SUCCESS
125
+
126
+ @property
127
+ def ran(self) -> bool:
128
+ """Completed with a known outcome (success, failed, partial): the payload has the op's result shape. An unknown
129
+ resolution or outcome is a failure whose payload means nothing (§0)."""
130
+ return self.resolution == COMPLETED and self.detail in (SUCCESS, FAILED, PARTIAL)
131
+
132
+ def describe(self) -> str:
133
+ if self.resolution == REJECTED:
134
+ return f"rejected: {REJECT_NAMES.get(self.detail, f'reason 0x{self.detail:02x}')}"
135
+ if self.resolution == ACCEPTED:
136
+ return "accepted"
137
+ if self.resolution != COMPLETED:
138
+ return f"unknown resolution 0x{self.resolution:02x}"
139
+ return {SUCCESS: "completed", FAILED: "failed", PARTIAL: "partial"}.get(self.detail,
140
+ f"unknown outcome 0x{self.detail:02x}")
141
+
142
+
143
+ # ---- §0 TLV tails ------------------------------------------------------------------------------------------
144
+
145
+ def tlv(tag: int, value: bytes, critical: bool = False) -> bytes:
146
+ """One TLV; `critical` sets tag bit 7 (a request argument the probe must honour or refuse)."""
147
+ if len(value) > 255:
148
+ raise ValueError(f"TLV 0x{tag:02x}: value of {len(value)} bytes does not fit")
149
+ if tag & 0x7F == TAG_IGNORED:
150
+ raise ValueError("tag 0x7F is reserved for the ignored list")
151
+ return bytes((tag | (TAG_CRITICAL if critical else 0), len(value))) + value
152
+
153
+
154
+ def split_tlvs(data: bytes) -> list[tuple[int, bytes]]:
155
+ """TLVs in order. A truncated TLV raises ShortPayload (the result is broken)."""
156
+ pos, out = 0, []
157
+ while pos < len(data):
158
+ if pos + 2 > len(data):
159
+ raise ShortPayload("TLV: truncated header")
160
+ tag, n = data[pos], data[pos + 1]
161
+ if pos + 2 + n > len(data):
162
+ raise ShortPayload(f"TLV 0x{tag:02x}: truncated value")
163
+ out.append((tag, data[pos + 2:pos + 2 + n]))
164
+ pos += 2 + n
165
+ return out
166
+
167
+
168
+ @dataclass
169
+ class Tail:
170
+ """The TLVs after a result's known part: `tlvs` in order (unknown tags included, for whoever knows them), and
171
+ `ignored`, the non-critical request tags the probe said it ignored (TLV 0x7F)."""
172
+ tlvs: list[tuple[int, bytes]] = field(default_factory=list)
173
+ ignored: list[int] = field(default_factory=list)
174
+
175
+ def get(self, tag: int) -> bytes | None:
176
+ return next((v for t, v in self.tlvs if t == tag), None)
177
+
178
+ @classmethod
179
+ def parse(cls, data: bytes) -> Tail:
180
+ t = cls()
181
+ for tag, value in split_tlvs(data):
182
+ if tag == TAG_IGNORED:
183
+ t.ignored += list(value)
184
+ else:
185
+ t.tlvs.append((tag, value))
186
+ return t
187
+
188
+
189
+ class Reader:
190
+ """Reads a result payload's fixed part front to back; too short -> ShortPayload. `tail()` then reads the rest as
191
+ §0 TLVs; `rest()` takes the rest as bytes (a result ending with a list of unknown length: nothing may follow)."""
192
+
193
+ def __init__(self, payload: bytes):
194
+ self.data, self.at = payload, 0
195
+
196
+ def take(self, fmt: str):
197
+ size = struct.calcsize("<" + fmt)
198
+ if self.at + size > len(self.data):
199
+ raise ShortPayload(f"payload of {len(self.data)} bytes: needs {self.at + size} for its fixed part")
200
+ values = struct.unpack_from("<" + fmt, self.data, self.at)
201
+ self.at += size
202
+ return values if len(values) > 1 else values[0]
203
+
204
+ def u8(self) -> int:
205
+ return self.take("B")
206
+
207
+ def u16(self) -> int:
208
+ return self.take("H")
209
+
210
+ def u32(self) -> int:
211
+ return self.take("I")
212
+
213
+ def bytes(self, n: int) -> bytes:
214
+ if self.at + n > len(self.data):
215
+ raise ShortPayload(f"payload of {len(self.data)} bytes: needs {self.at + n}")
216
+ out = self.data[self.at:self.at + n]
217
+ self.at += n
218
+ return out
219
+
220
+ def words(self, n: int) -> list[int]:
221
+ return list(struct.unpack(f"<{n}I", self.bytes(4 * n)))
222
+
223
+ def rest(self) -> bytes:
224
+ out = self.data[self.at:]
225
+ self.at = len(self.data)
226
+ return out
227
+
228
+ def tail(self) -> Tail:
229
+ return Tail.parse(self.rest())
230
+
231
+
232
+ def serial_diff(a: int, b: int, bits: int = 32) -> int:
233
+ """a - b for values that wrap (positions u32, seq u16, µs u32): the difference as a signed number of `bits` (§0)."""
234
+ d = (a - b) & ((1 << bits) - 1)
235
+ return d - (1 << bits) if d >> (bits - 1) else d
oep_client/v1/names.py ADDED
@@ -0,0 +1,86 @@
1
+ """Interface names (oep-spec docs/capability-identification-comparison.ja.md, draft).
2
+
3
+ A name is dot-separated labels of lowercase ASCII letters, digits and '-', at most 48 bytes. The
4
+ first label says which kind of namespace it is:
5
+
6
+ oep. the OEP standard (reserved; `oep` is not a real top-level domain)
7
+ local. bench-only experiments, never published, no interoperability promise
8
+ uuid.<32 hex>. an author with no domain who still wants a unique namespace
9
+ <tld>.<domain>... reverse DNS of a domain the author owns, including hosting domains
10
+ such as io.github.<name> (GitHub gives <name>.github.io to one owner)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import re
16
+
17
+ MAX_NAME = 48
18
+ _LABEL = re.compile(r"[a-z0-9-]+\Z")
19
+ _TLD = re.compile(r"[a-z]{2,63}\Z")
20
+ _UUID = re.compile(r"[0-9a-f]{32}\Z")
21
+
22
+
23
+ class InvalidName(ValueError):
24
+ pass
25
+
26
+
27
+ def kind(name: str) -> str:
28
+ """'standard', 'local', 'uuid' or 'domain' - after validate()."""
29
+ first = name.split(".", 1)[0]
30
+ return {"oep": "standard", "local": "local", "uuid": "uuid"}.get(first, "domain")
31
+
32
+
33
+ def validate(name: str) -> str:
34
+ """Return the name, or raise InvalidName saying which rule it breaks."""
35
+ raw = name.encode("ascii", "strict") if name.isascii() else None
36
+ if raw is None:
37
+ raise InvalidName(f"{name!r}: not ASCII")
38
+ if len(raw) > MAX_NAME:
39
+ raise InvalidName(f"{name!r}: {len(raw)} bytes, the limit is {MAX_NAME}")
40
+ labels = name.split(".")
41
+ if len(labels) < 2:
42
+ raise InvalidName(f"{name!r}: needs a namespace and at least one more label")
43
+ for label in labels:
44
+ if not _LABEL.match(label):
45
+ raise InvalidName(f"{name!r}: label {label!r} is not [a-z0-9-]+")
46
+ first = labels[0]
47
+ if first == "uuid":
48
+ if len(labels) < 3 or not _UUID.match(labels[1]):
49
+ raise InvalidName(f"{name!r}: uuid. must be followed by 32 lowercase hex digits and a name")
50
+ elif first not in ("oep", "local"):
51
+ if not _TLD.match(first):
52
+ raise InvalidName(f"{name!r}: {first!r} is not a top-level domain (reverse DNS expected)")
53
+ if len(labels) < 3:
54
+ raise InvalidName(f"{name!r}: reverse DNS needs <tld>.<domain>.<name>")
55
+ return name
56
+
57
+
58
+ # Hosting services whose domain is often written wrongly as a top level. Whether a first label
59
+ # is a real top-level domain is not checked (that needs the IANA list); these are the common slips.
60
+ _HOSTING = {"github": "io.github", "gitlab": "io.gitlab", "codeberg": "page.codeberg",
61
+ "bitbucket": "io.bitbucket"}
62
+
63
+
64
+ def lint(name: str) -> list[str]:
65
+ """Warnings for names that are well-formed but break the namespace rules in spirit."""
66
+ labels = name.split(".")
67
+ out = []
68
+ if labels[0] in _HOSTING:
69
+ out.append(f"{labels[0]!r} is not a top-level domain; a {labels[0]} account's namespace is "
70
+ f"{_HOSTING[labels[0]]}.{labels[1] if len(labels) > 1 else '<name>'}")
71
+ if labels[0] == "com" and len(labels) > 1 and labels[1] in _HOSTING:
72
+ out.append(f"com.{labels[1]} is not given to accounts; use {_HOSTING[labels[1]]}.<name>")
73
+ return out
74
+
75
+
76
+ def matches(name: str, prefix: str, exact: bool) -> bool:
77
+ """List filtering: an empty prefix matches everything; otherwise match on label boundaries.
78
+
79
+ oep.fixture.uart matches oep.fixture.uart and oep.fixture.uart.stream, not oep.fixture.uart2;
80
+ with exact, only oep.fixture.uart itself.
81
+ """
82
+ if not prefix:
83
+ return not exact
84
+ if exact:
85
+ return name == prefix
86
+ return name == prefix or name.startswith(prefix + ".")
@@ -0,0 +1,59 @@
1
+ """Generated by oep-spec tools/oepgen1.py from registry/oep-v1.toml - do not edit."""
2
+
3
+ from types import SimpleNamespace as _NS
4
+
5
+ REGISTRY_HASH = "7ba704094c2898d2"
6
+ SCHEMA = 1
7
+ PROTOCOL_REVISION = 1
8
+ CONFIRM_REQUEST_MAGIC = 'OEP?'
9
+ CONFIRM_RESULT_MAGIC = 'OEP!'
10
+ ROLE_SESSION_FLAG = 0x80
11
+ TAG_CRITICAL = 0x80
12
+ TAG_IGNORED = 0x7F
13
+ TAG_INVALID = 0xFF
14
+ MIN_MAX_FRAME = 0x40
15
+ ROLES = {"request": 0x01, "result": 0x02, "event": 0x05, "data": 0x06}
16
+ RESOLUTIONS = {"rejected": 0x00, "completed": 0x01, "accepted": 0x02}
17
+ OUTCOMES = {"success": 0x00, "failed": 0x01, "partial": 0x02}
18
+ REJECT_REASONS = {"unknown_function": 0x01, "unknown_operation": 0x02, "malformed": 0x03, "unavailable": 0x04, "busy": 0x05, "window_exceeded": 0x06, "no_session": 0x07, "locked": 0x08, "session_required": 0x09, "no_connection": 0x0A, "unsupported": 0x0B, "result_lost": 0x0C, "corr_reused": 0x0D}
19
+ STATUS = {"ok": 0x00, "wait": 0x01, "line": 0x02, "fault": 0x03, "timeout": 0x04, "state": 0x05}
20
+ DESCRIBE_COMMON = {"role_channels": 0x01, "max_clock_hz": 0x02, "max_length": 0x03, "min_clock_hz": 0x05, "features": 0x06, "implementation": 0x07, "channel_group": 0x08}
21
+ TIMING = {"resync_quiet_ms": 0x32, "probe_frame_gap_ms": 0xC8, "host_frame_pause_max_ms": 0x64, "heartbeat_default_ms": 0x3E8}
22
+
23
+ INTERFACES = {}
24
+ CORE = _NS(name="oep.core", revision=1, op={"confirm": 0x01, "list": 0x02, "describe": 0x03, "plan_apply": 0x04, "plan_release": 0x05, "open": 0x10, "end": 0x11, "keepalive": 0x12, "lock_state": 0x13, "subscribe": 0x30, "unsubscribe": 0x32, "link_source": 0x40, "link_sink": 0x41}, lock_free={0x01, 0x02, 0x03, 0x10, 0x13, 0x40, 0x41},
25
+ closed_tail={0x40}, tlv={"plan_apply": {"role_assignment": 0x90}, "open": {"owner": 0x01}, "lock_state_answer": {"owner": 0x01}, "locked_payload": {"owner": 0x01}, "describe": {"firmware": 0x40, "model": 0x41, "unit_id": 0x42, "channels": 0x43, "reserved": 0x44, "profile": 0x45, "label": 0x46, "resets_on_open": 0x47, "transport": 0x49, "oep_pid": 0x4A}}, event={"heartbeat": 0x01}, enum={"transport_kind": {"uart_bridge": 0x01, "usb_cdc": 0x02, "usb_serial_jtag": 0x03, "vendor_bulk": 0x04, "hid": 0x05, "tcp": 0x06}}, own={})
26
+ INTERFACES["oep.core"] = CORE
27
+ WIRE_RVSWD = _NS(name="oep.wire.rvswd", revision=1, op={"scan": 0x01, "attach": 0x02, "detach": 0x03, "attach_under_reset": 0x04, "connections": 0x05}, lock_free={0x05},
28
+ closed_tail={}, tlv={"describe": {"max_connections": 0x40}, "detach": {"force": 0x01}, "attach": {"max_speed": 0x01, "pins": 0x03}, "attach_under_reset": {"max_speed": 0x01, "pins": 0x03}, "attach_answer": {"target_id": 0x10}}, event={}, enum={"connection_users": {"host_session": 0x01, "slot": 0x02}, "target_id_scheme": {"wch_dmi_7f": 0x01}, "attach_method": {"run": 0x00, "halt": 0x01}, "pin_role": {"swdio": 0x01, "swclk": 0x02}}, own={})
29
+ INTERFACES["oep.wire.rvswd"] = WIRE_RVSWD
30
+ WIRE_SWIO = _NS(name="oep.wire.swio", revision=1, op={"scan": 0x01, "attach": 0x02, "detach": 0x03, "attach_under_reset": 0x04, "connections": 0x05}, lock_free={0x05},
31
+ closed_tail={}, tlv={"describe": {"max_connections": 0x40}, "detach": {"force": 0x01}, "attach": {"max_speed": 0x01, "pins": 0x03}, "attach_under_reset": {"max_speed": 0x01, "pins": 0x03}, "attach_answer": {"target_id": 0x10}}, event={}, enum={"connection_users": {"host_session": 0x01, "slot": 0x02}, "target_id_scheme": {"wch_dmi_7f": 0x01}, "attach_method": {"run": 0x00, "halt": 0x01}, "pin_role": {"swdio": 0x01}}, own={})
32
+ INTERFACES["oep.wire.swio"] = WIRE_SWIO
33
+ WIRE_SWD = _NS(name="oep.wire.swd", revision=1, op={"scan": 0x01, "attach": 0x02, "detach": 0x03, "connections": 0x05}, lock_free={0x05},
34
+ closed_tail={}, tlv={"describe": {"max_connections": 0x40}, "detach": {"force": 0x01}, "attach": {"max_speed": 0x01, "targetsel": 0x02, "pins": 0x03}}, event={}, enum={"connection_users": {"host_session": 0x01, "slot": 0x02}, "pin_role": {"swdio": 0x01, "swclk": 0x02}}, own={})
35
+ INTERFACES["oep.wire.swd"] = WIRE_SWD
36
+ TARGET_RISCV_DM = _NS(name="oep.target.riscv-dm", revision=1, op={"dmi": 0x01, "halt": 0x02, "resume": 0x03, "reset": 0x04, "read_block": 0x05, "write_block": 0x06, "run": 0x07, "step": 0x08}, lock_free={},
37
+ closed_tail={}, tlv={"describe": {"clobbers": 0x40}, "reset": {"method": 0x01}}, event={}, enum={"dmi_step": {"write": 0x01, "read": 0x02, "poll_reads": 0x03, "wait_us": 0x04, "poll_us": 0x05}, "reset_mode": {"run": 0x00, "run_verified": 0x01, "halt_at_reset": 0x02}, "reset_method": {"probe_default": 0x00, "ndmreset": 0x01, "system_reset": 0x02}}, own={})
38
+ INTERFACES["oep.target.riscv-dm"] = TARGET_RISCV_DM
39
+ TARGET_ARM_ADI = _NS(name="oep.target.arm-adi", revision=1, op={"transfer": 0x01, "read_block": 0x02, "write_block": 0x03}, lock_free={},
40
+ closed_tail={}, tlv={}, event={}, enum={}, own={})
41
+ INTERFACES["oep.target.arm-adi"] = TARGET_ARM_ADI
42
+ TARGET_CONSOLE = _NS(name="oep.target.console", revision=1, op={"open": 0x01, "read": 0x02, "marks": 0x03, "clear": 0x04, "mark": 0x05, "write": 0x06, "close": 0x07}, lock_free={0x02, 0x03},
43
+ closed_tail={0x02}, tlv={"describe": {"mechanisms": 0x40}}, event={}, enum={"mechanism": {"sdi": 0x00, "dmdata": 0x01, "dmseq": 0x02}, "read_from": {"position": 0x00, "oldest": 0x01, "now": 0x02, "last_mark": 0x03}, "mark_kind": {"reset": 0x01, "restart": 0x02, "attach": 0x03, "detach": 0x04, "lost": 0x05, "clear": 0x06, "host": 0x07, "link_lost": 0x08}}, own={})
44
+ INTERFACES["oep.target.console"] = TARGET_CONSOLE
45
+ FIXTURE_GPIO = _NS(name="oep.fixture.gpio", revision=1, op={"set": 0x01, "read": 0x02}, lock_free={0x02},
46
+ closed_tail={}, tlv={"describe": {"modes": 0x40}}, event={}, enum={"role": {"line": 0x01}, "mode": {"input": 0x00, "input_pullup": 0x01, "input_pulldown": 0x02, "output_low": 0x03, "output_high": 0x04, "open_drain_low": 0x05, "open_drain_release": 0x06, "input_pullup_pulldown": 0x07}}, own={})
47
+ INTERFACES["oep.fixture.gpio"] = FIXTURE_GPIO
48
+ FIXTURE_UART = _NS(name="oep.fixture.uart", revision=1, op={"configure": 0x01, "read": 0x02, "marks": 0x03, "clear": 0x04, "mark": 0x05, "write": 0x06}, lock_free={0x02, 0x03},
49
+ closed_tail={0x02}, tlv={"configure": {"format": 0x01}, "describe": {"formats": 0x40}}, event={}, enum={"role": {"rx": 0x01, "tx": 0x02}}, own={})
50
+ INTERFACES["oep.fixture.uart"] = FIXTURE_UART
51
+ FIXTURE_CAPTURE = _NS(name="oep.fixture.capture", revision=1, op={"configure": 0x01, "start": 0x02, "stop": 0x03, "force": 0x04, "status": 0x05, "read": 0x06, "segments": 0x07, "release": 0x08, "query": 0x09}, lock_free={0x05, 0x06, 0x07, 0x09},
52
+ closed_tail={0x06}, tlv={"configure": {"mode": 0x40, "rate": 0x42, "samples": 0x43, "segments": 0x44, "trigger": 0x45, "pretrigger": 0x46, "frontend": 0x47}, "configure_answer": {"actual_rate": 0x50, "layout": 0x51, "actual_samples": 0x52, "actual_segments": 0x53, "timing": 0x54, "scale": 0x55, "blocking_ms": 0x56, "skew": 0x57}, "describe": {"mode": 0x40, "rate_range": 0x41, "rate_list": 0x42, "rate_limit": 0x43, "channels": 0x44, "trigger": 0x45, "frontend": 0x46, "max_read": 0x47, "segment_ring": 0x48, "frontend_shared": 0x49}}, event={"segment": 0x01, "stopped": 0x02, "triggered": 0x03}, enum={"mode": {"one_shot": 0x01, "repeat": 0x02, "streaming": 0x03}, "trigger": {"immediate": 0x00, "level": 0x01, "edge": 0x02, "cross_up": 0x03, "cross_down": 0x04}, "state": {"unconfigured": 0x00, "configured": 0x01, "waiting": 0x02, "capturing": 0x03, "done": 0x04, "paused": 0x05, "error": 0x06}, "stopped_reason": {"complete": 0x00, "host": 0x01, "no_free_segment": 0x02, "error": 0x03}, "segment_flag": {"gap": 0x01, "short": 0x02, "slipped": 0x04}}, own={})
53
+ INTERFACES["oep.fixture.capture"] = FIXTURE_CAPTURE
54
+ FIXTURE_ANALOG = _NS(name="oep.fixture.analog", revision=1, op={"configure": 0x01, "start": 0x02, "stop": 0x03, "force": 0x04, "status": 0x05, "read": 0x06, "segments": 0x07, "release": 0x08, "query": 0x09}, lock_free={0x05, 0x06, 0x07, 0x09},
55
+ closed_tail={0x06}, tlv={"configure": {"mode": 0x40, "rate": 0x42, "samples": 0x43, "segments": 0x44, "trigger": 0x45, "pretrigger": 0x46, "frontend": 0x47}, "configure_answer": {"actual_rate": 0x50, "layout": 0x51, "actual_samples": 0x52, "actual_segments": 0x53, "timing": 0x54, "scale": 0x55, "blocking_ms": 0x56, "skew": 0x57}, "describe": {"mode": 0x40, "rate_range": 0x41, "rate_list": 0x42, "rate_limit": 0x43, "channels": 0x44, "trigger": 0x45, "frontend": 0x46, "max_read": 0x47, "segment_ring": 0x48, "frontend_shared": 0x49}}, event={"segment": 0x01, "stopped": 0x02, "triggered": 0x03}, enum={"mode": {"one_shot": 0x01, "repeat": 0x02, "streaming": 0x03}, "trigger": {"immediate": 0x00, "level": 0x01, "edge": 0x02, "cross_up": 0x03, "cross_down": 0x04}, "state": {"unconfigured": 0x00, "configured": 0x01, "waiting": 0x02, "capturing": 0x03, "done": 0x04, "paused": 0x05, "error": 0x06}, "stopped_reason": {"complete": 0x00, "host": 0x01, "no_free_segment": 0x02, "error": 0x03}, "segment_flag": {"gap": 0x01, "short": 0x02, "slipped": 0x04}}, own={})
56
+ INTERFACES["oep.fixture.analog"] = FIXTURE_ANALOG
57
+ PROBE_CONFIG = _NS(name="oep.probe.config", revision=1, op={"get": 0x01, "set": 0x02, "save": 0x03, "erase": 0x04}, lock_free={0x01},
58
+ closed_tail={}, tlv={"item": {"plan": 0x01, "label": 0x02, "idle": 0x03, "slot": 0x04, "bind": 0x05}, "describe": {"storage": 0x40, "items": 0x41, "slots_max": 0x42, "bind_modes": 0x43, "slot_state": 0x44, "bind_state": 0x45}}, event={}, enum={"idle_mode": {"hi_z": 0x00, "pull_up": 0x01, "pull_down": 0x02}, "slot_attach": {"host": 0x00, "at_boot": 0x01}, "slot_state": {"connected": 0x00, "absent": 0x01, "lock_mismatch": 0x02, "no_target_id": 0x03}, "bind_mode": {"last_reset": 0x00, "manual": 0x01, "mixed": 0x02}, "bind_stream": {"slot_console": 0x01, "fixture_uart": 0x02}, "bind_flow": {"idle": 0x00, "streaming": 0x01, "held": 0x02}, "storage_state": {"none": 0x00, "applied": 0x01, "unreadable": 0x02}}, own={})
59
+ INTERFACES["oep.probe.config"] = PROBE_CONFIG