oep-client-python 0.0.32__py3-none-any.whl → 0.0.33__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.
oep_client/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.0.32"
5
+ __version__ = "0.0.33"
oep_client/__main__.py CHANGED
@@ -353,6 +353,12 @@ def _config_parser(sub) -> None:
353
353
  idle.add_argument("channel", type=int)
354
354
  idle.add_argument("mode", choices=sorted(config.IDLE))
355
355
  idle.add_argument("--save", action="store_true")
356
+ rest = cs.add_parser("rvswd-rest", help="how rvswd rests a port's SWCLK: auto (the probe decides from the target_id), "
357
+ "or high / low fixed (the automatic choice off; debug §3.1)")
358
+ rest.add_argument("probe")
359
+ rest.add_argument("channel", type=int, help="the port's SWCLK channel")
360
+ rest.add_argument("mode", choices=sorted(config.REST_MODE))
361
+ rest.add_argument("--save", action="store_true")
356
362
  dis = cs.add_parser("disable", help="channels the probe never drives or sets up (not on this board)")
357
363
  dis.add_argument("probe")
358
364
  dis.add_argument("channels", type=int, nargs="+")
@@ -435,6 +441,8 @@ def _config(args) -> int:
435
441
  _change(hst, cfg, [config.Label(channel=args.channel, text=args.text)], args.save)
436
442
  elif args.action == "idle":
437
443
  _change(hst, cfg, [config.Idle(channel=args.channel, mode=args.mode)], args.save)
444
+ elif args.action == "rvswd-rest":
445
+ _change(hst, cfg, [config.RvswdRest(channel=args.channel, mode=args.mode)], args.save)
438
446
  elif args.action == "disable":
439
447
  _change(hst, cfg, [config.Disable(channel=ch) for ch in args.channels], args.save)
440
448
  elif args.action == "remove":
oep_client/config.py CHANGED
@@ -36,6 +36,7 @@ NAMES = tuple(_CFG.names["setting"]) # the standard i
36
36
  ITEM = {k.replace("-", "_"): i + 1 for i, k in enumerate(NAMES)}
37
37
  DESCRIBE = _CFG.tlv["describe"]
38
38
  IDLE = {k.replace("_", "-"): v for k, v in _CFG.enum["idle_mode"].items()}
39
+ REST_MODE = dict(_CFG.enum["rvswd_rest_mode"]) # rvswd-rest: auto / high / low (debug §3.1)
39
40
  STORAGE_STATE = {v: k for k, v in _CFG.enum["storage_state"].items()}
40
41
  UNREADABLE = {v: k for k, v in _CFG.enum["storage_unreadable"].items()}
41
42
  FORM = _CFG.enum["setting_form"]
@@ -140,6 +141,27 @@ class Passthrough:
140
141
  return struct.pack("<HHIB", self.fn, self.rx, self.baud, self.format)
141
142
 
142
143
 
144
+ @dataclass
145
+ class RvswdRest:
146
+ """How an rvswd attach without idle_clock rests the SWCLK on `channel` (the port's SWCLK; debug §3.1): auto - the
147
+ probe's choice from the target_id it reads (also with no item) - or high / low fixed, the automatic choice off for
148
+ that port. An attach's idle_clock TLV still decides."""
149
+ channel: int
150
+ mode: str = "auto"
151
+ NAME = "rvswd-rest"
152
+
153
+ def key(self) -> int:
154
+ return self.channel
155
+
156
+ def value(self) -> bytes:
157
+ return struct.pack("<H", self.key()) + self.data()
158
+
159
+ def data(self) -> bytes:
160
+ if self.mode not in REST_MODE:
161
+ raise ValueError(f"rvswd-rest mode {self.mode!r}: one of {', '.join(REST_MODE)}")
162
+ return bytes([REST_MODE[self.mode]])
163
+
164
+
143
165
  @dataclass(kw_only=True)
144
166
  class ConsolePassthrough:
145
167
  """Serial port `port` carries the target's debug console - read by the probe itself over `wire_fn` on (swdio, swclk)
@@ -293,6 +315,8 @@ def decode(name: str, key: int, d: bytes, setting: Setting | None = None, netifs
293
315
  try:
294
316
  if name == "label":
295
317
  return Label(channel=key, text=d.decode("utf-8", "replace"))
318
+ if name == "rvswd-rest" and len(d) == 1 and d[0] in REST_MODE.values():
319
+ return RvswdRest(channel=key, mode={v: k for k, v in REST_MODE.items()}[d[0]])
296
320
  if name == "idle" and len(d) == 1:
297
321
  return Idle(channel=key, mode=_name(IDLE, d[0]))
298
322
  if name == "disable" and not d:
oep_client/endpoint.py CHANGED
@@ -117,7 +117,8 @@ RESET_MODE = _RV.enum["reset_mode"]
117
117
  READ_FROM = reg.COMMON.enum["read_from"] # position, oldest, now, last_mark (common §1.2)
118
118
  STEP_LEFT = _RV.tlv["step_answer"]["step_left"] # step's answer: the hart could not be halted again (§4.2)
119
119
  ITEM = {k.replace("-", "_"): k for k in cfgmod.NAMES} # the standard items by name (probe.config §1, core §7.7)
120
- CHANNEL_ITEMS = (ITEM["label"], ITEM["idle"], ITEM["disable"]) # items keyed by a channel (probe.config §1)
120
+ CHANNEL_ITEMS = (ITEM["label"], ITEM["idle"], ITEM["disable"], ITEM["rvswd_rest"]) # keyed by a channel (probe.config §1)
121
+ REST_MODE = cfgmod.REST_MODE
121
122
  IDLE_MODE = _CFG.enum["idle_mode"]
122
123
  CFG_DESCRIBE = cfgmod.DESCRIBE
123
124
  SETTING_FORM = _CFG.enum["setting_form"]
@@ -137,7 +138,18 @@ I2C_FEATURES, SPI_FEATURES = _I2C.enum["features"], _SPI.enum["features"]
137
138
  TARGET_ROLES = {"oep.fixture.gpio": {1}, "oep.fixture.uart": {1, 2}, _I2C.name: set(_I2C.enum["role"].values()),
138
139
  _SPI.name: set(_SPI.enum["role"].values())} # the plan roles each fixture takes
139
140
  UART_FORMAT_MASK = 0x1F # the defined format bits (fixture §2)
140
- _T_SCAN, _T_ATTACH, _T_ATTACH_ANSWER = (reg.WIRE_RVSWD.tlv[k] for k in ("scan", "attach", "attach_answer"))
141
+ _T_SCAN, _T_ATTACH, _T_ATTACH_ANSWER, _T_CONNECTIONS_ANSWER = (
142
+ reg.WIRE_RVSWD.tlv[k] for k in ("scan", "attach", "attach_answer", "connections_answer"))
143
+ _IDLE_CLOCK = reg.WIRE_RVSWD.enum["idle_clock"]
144
+
145
+
146
+ def rvswd_rest(target_id: int | None) -> int:
147
+ """The rest an rvswd attach without idle_clock uses (debug §3.1): low for a family in the registry's
148
+ idle_low_family (target_id >> target_id_family.shift), high otherwise and when no target_id was read."""
149
+ if target_id is None:
150
+ return _IDLE_CLOCK["high"]
151
+ family = target_id >> reg.WIRE_RVSWD.enum["target_id_family"]["shift"]
152
+ return _IDLE_CLOCK["low"] if family in reg.WIRE_RVSWD.enum["idle_low_family"].values() else _IDLE_CLOCK["high"]
141
153
  _WIRE_INDEX = reg.WIRE_RVSWD.tlv["unsupported_payload"]["index"] # scan's candidate index (debug §1)
142
154
  ATTACH_METHOD = reg.WIRE_RVSWD.enum["attach_method"]
143
155
  GPIO_MODE_MAX = max(_GPIO.enum["mode"].values()) # 6: the modes revision 1 defines are 0-6 (fixture §1)
@@ -542,7 +554,7 @@ class Connection:
542
554
 
543
555
 
544
556
  ITEM_SIZES = {ITEM["idle"]: 1, ITEM["disable"]: 0, ITEM["passthrough"]: 9, # the data of a fixed length (probe.config §1)
545
- ITEM["console_passthrough"]: 13, ITEM["ipv4"]: 14}
557
+ ITEM["console_passthrough"]: 13, ITEM["ipv4"]: 14, ITEM["rvswd_rest"]: 1}
546
558
  PASSTHROUGHS = (ITEM["passthrough"], ITEM["console_passthrough"])
547
559
 
548
560
 
@@ -2293,8 +2305,11 @@ class Endpoint:
2293
2305
  if tg.havereset:
2294
2306
  tg.havereset, flags = False, flags | ATTACH_FLAGS["havereset_acked"]
2295
2307
  c = self.conns[cid]
2296
- if idle_clock is not None:
2297
- c.idle_clock = idle_clock
2308
+ if rvswd: # the host's TLV, the setting, else from target_id (§3.1)
2309
+ setting = self.config.get((ITEM["rvswd_rest"], pair[1]), bytes([REST_MODE["auto"]]))[0]
2310
+ c.idle_clock = (idle_clock if idle_clock is not None
2311
+ else _IDLE_CLOCK["high"] if setting == REST_MODE["high"]
2312
+ else _IDLE_CLOCK["low"] if setting == REST_MODE["low"] else rvswd_rest(c.tid))
2298
2313
  if reset is not None and tg.reset_line not in (None, channel):
2299
2314
  if method == 1: # a line that resets nothing: halted where it ran
2300
2315
  tg.halted, tg.dpc = True, tg.reset_vector + 0x2f8
@@ -2308,6 +2323,8 @@ class Endpoint:
2308
2323
  if tg.halted and method == 1: # bit3: the probe saw hart 0 halted (§3)
2309
2324
  flags |= ATTACH_FLAGS["halted"]
2310
2325
  tail += m.tlv(_T_ATTACH_ANSWER["dpc"], struct.pack("<I", tg.dpc))
2326
+ if rvswd: # the rest in use, always (§3.1)
2327
+ tail += m.tlv(_T_ATTACH_ANSWER["idle_clock"], bytes([c.idle_clock]))
2311
2328
  return self._answer(struct.pack("<IIBI", cid, tg.dmstatus(), flags, c.speed) + tail)
2312
2329
  if op == O["detach"]:
2313
2330
  cid = t.take("I")
@@ -2321,24 +2338,31 @@ class Endpoint:
2321
2338
  first = t.take("B")
2322
2339
  t.tail()
2323
2340
  mine = sorted((c.order, cid) for cid, c in self.conns.items() if c.fn == fn)
2324
- rows = []
2341
+ rows, rests = [], []
2325
2342
  for _, cid in mine:
2326
2343
  c = self.conns[cid]
2327
2344
  tid = b"" if c.tid is None else struct.pack("<I", c.tid)
2328
2345
  scheme = TARGET_ID_SCHEME["dmi_7f"] if tid else 0
2329
2346
  rows.append(struct.pack("<IHHIBB", cid, *c.pair, c.speed, scheme, len(tid)) + tid)
2330
- return m.COMPLETED, m.SUCCESS, self._paged(rows, first)
2347
+ rests.append(c.idle_clock)
2348
+ # rvswd: TLV idle_clock (entry_index, rest) for every entry of the page (§2.1, §3.1)
2349
+ return m.COMPLETED, m.SUCCESS, self._paged(rows, first, rests if rvswd else None)
2331
2350
  return m.REJECTED, m.UNKNOWN_OPERATION, b""
2332
2351
 
2333
- def _paged(self, rows: list[bytes], first: int) -> bytes:
2334
- """more(u8) count(u8) the rows from `first` that fit the frame (connections, streams: core §2.3's lists)."""
2352
+ def _paged(self, rows: list[bytes], first: int, rests: list[int] | None = None) -> bytes:
2353
+ """more(u8) count(u8) the rows from `first` that fit the frame (connections, streams: core §2.3's lists);
2354
+ with `rests` (rvswd's connections), each row's TLV idle_clock (entry_index, rest) after them, counted in."""
2335
2355
  budget = self.probe.max_frame - m.RESULT_HEADER - 2
2336
2356
  out: list[bytes] = []
2337
- for row in rows[first:]:
2338
- if out and sum(map(len, out)) + len(row) > budget:
2357
+ tail: list[bytes] = []
2358
+ for i, row in enumerate(rows[first:]):
2359
+ extra = b"" if rests is None else m.tlv(_T_CONNECTIONS_ANSWER["idle_clock"], bytes([len(out), rests[first + i]]))
2360
+ if out and sum(map(len, out + tail)) + len(row) + len(extra) > budget:
2339
2361
  break
2340
2362
  out.append(row)
2341
- return bytes([int(first + len(out) < len(rows)), len(out)]) + b"".join(out)
2363
+ if extra:
2364
+ tail.append(extra)
2365
+ return bytes([int(first + len(out) < len(rows)), len(out)]) + b"".join(out) + b"".join(tail)
2342
2366
 
2343
2367
  def _attach_methods(self, fn: int) -> set[int]:
2344
2368
  """method 0, and 1 when the wire declares features bit0 attach_halt (debug §3)."""
@@ -3275,6 +3299,8 @@ class Endpoint:
3275
3299
  return True
3276
3300
  if mode in (IDLE_MODE["pull_up"], IDLE_MODE["pull_down"]) and mode in self.no_pull.get(key, ()):
3277
3301
  return True
3302
+ if name == ITEM["rvswd_rest"] and d[0] not in REST_MODE.values():
3303
+ return True # a mode the definition leaves unused (§1)
3278
3304
  return False
3279
3305
 
3280
3306
  def _shown(self, name: str, d: bytes) -> bytes:
oep_client/registry.py CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  from types import SimpleNamespace as _NS
5
5
 
6
- REGISTRY_HASH = "0aaae1a1afbb5b02"
6
+ REGISTRY_HASH = "66b19f04290391f3"
7
7
  SCHEMA = 1
8
8
  PROTOCOL_REVISION = 1
9
9
  CONFIRM_REQUEST_MAGIC = 'OEP?'
@@ -42,7 +42,7 @@ PROBE_LINK = _NS(name="oep.probe.link", revision=1, target=None, op={"source": 0
42
42
  line_names={}, names={})
43
43
  INTERFACES["oep.probe.link"] = PROBE_LINK
44
44
  WIRE_RVSWD = _NS(name="oep.wire.rvswd", revision=1, target="RISC-V targets whose debug module is reached over the two-wire RVSWD line", op={"scan": 0x10, "attach": 0x11, "detach": 0x12, "connections": 0x13}, lock_free={0x13},
45
- tlv={"describe": {"max_connections": 0x40}, "scan": {"max_speed": 0x01, "idle_clock": 0x03}, "attach": {"idle_clock": 0x03, "reset": 0x04}, "attach_answer": {"target_id": 0x01, "dpc": 0x02}, "unavailable_payload": {"index": 0x40}, "unsupported_payload": {"index": 0x40}}, event={}, enum={"scan_kind": {"riscv_dm": 0x01}, "attach_flags": {"havereset_acked": 0x01, "halted": 0x08}, "features": {"attach_halt": 0x01}, "attach_method": {"run": 0x00, "halt": 0x01}, "pin_role": {"swdio": 0x01, "swclk": 0x02, "reset": 0x03}, "idle_clock": {"high": 0x00, "low": 0x01}}, own={},
45
+ tlv={"describe": {"max_connections": 0x40}, "scan": {"max_speed": 0x01, "idle_clock": 0x03}, "attach": {"idle_clock": 0x03, "reset": 0x04}, "attach_answer": {"target_id": 0x01, "dpc": 0x02, "idle_clock": 0x03}, "connections_answer": {"idle_clock": 0x02}, "unavailable_payload": {"index": 0x40}, "unsupported_payload": {"index": 0x40}}, event={}, enum={"scan_kind": {"riscv_dm": 0x01}, "attach_flags": {"havereset_acked": 0x01, "halted": 0x08}, "features": {"attach_halt": 0x01}, "attach_method": {"run": 0x00, "halt": 0x01}, "pin_role": {"swdio": 0x01, "swclk": 0x02, "reset": 0x03}, "idle_clock": {"high": 0x00, "low": 0x01}, "target_id_family": {"shift": 0x14}, "idle_low_family": {"ch32l103": 0x103}}, own={},
46
46
  line_names={}, names={})
47
47
  INTERFACES["oep.wire.rvswd"] = WIRE_RVSWD
48
48
  WIRE_SWIO = _NS(name="oep.wire.swio", revision=1, target="RISC-V targets whose debug module is reached over the one-wire SWIO line", op={"scan": 0x10, "attach": 0x11, "detach": 0x12, "connections": 0x13}, lock_free={0x13},
@@ -94,6 +94,6 @@ FIXTURE_CAPTURE_GROUP = _NS(name="oep.fixture.capture-group", revision=1, target
94
94
  line_names={}, names={})
95
95
  INTERFACES["oep.fixture.capture-group"] = FIXTURE_CAPTURE_GROUP
96
96
  PROBE_CONFIG = _NS(name="oep.probe.config", revision=1, target=None, op={"get": 0x10, "set": 0x11, "save": 0x12, "erase": 0x13, "unset": 0x14, "state": 0x15, "network": 0x16}, lock_free={0x10, 0x15, 0x16},
97
- tlv={"describe": {"storage": 0x40, "setting": 0x41, "netif": 0x42}}, event={}, enum={"idle_mode": {"hi_z": 0x00, "pull_up": 0x01, "pull_down": 0x02, "output_low": 0x03, "output_high": 0x04}, "ipv4_mode": {"dhcp": 0x00, "static": 0x01}, "network_state": {"off": 0x00, "connecting": 0x01, "up": 0x02, "waiting": 0x03}, "network_reason": {"none": 0x00, "not_found": 0x01, "auth": 0x02, "no_address": 0x03, "other": 0x04}, "setting_form": {"named": 0x00, "bytes": 0x01, "text": 0x02, "u32": 0x03, "ipv4": 0x04, "bool": 0x05}, "setting_flag": {"secret": 0x01, "restart": 0x02}, "storage_state": {"none": 0x00, "applied": 0x01, "unreadable": 0x02, "partial": 0x03}, "storage_unreadable": {"none": 0x00, "form": 0x01, "item": 0x02, "capacity": 0x03}}, own={},
98
- line_names={'nrst': 'the target reset line (Host only)', 'power_hi': 'target power on when high (Host only)', 'power_lo': 'target power on when low (Host only)'}, names={'setting': {'label': 'key channel; text 1-32 bytes', 'idle': 'key channel; mode(u8)', 'disable': 'key channel; no data', 'passthrough': 'key port; fn(u16) rx(u16) baud(u32) format(u8)', 'console-passthrough': 'key port; wire_fn(u16) swdio(u16) swclk(u16) max_speed(u32) console_fn(u16) mechanism(u8)', 'wifi': 'key entry; ssid_len(u8) ssid pass_len(u8) passphrase; passphrase write-only', 'ipv4': 'key netif; mode(u8) address(4) prefix(u8) gateway(4) dns(4)'}, 'netif': {'wifi': 'Wi-Fi station', 'ethernet': 'wired Ethernet'}})
97
+ tlv={"describe": {"storage": 0x40, "setting": 0x41, "netif": 0x42}}, event={}, enum={"idle_mode": {"hi_z": 0x00, "pull_up": 0x01, "pull_down": 0x02, "output_low": 0x03, "output_high": 0x04}, "rvswd_rest_mode": {"auto": 0x00, "high": 0x01, "low": 0x02}, "ipv4_mode": {"dhcp": 0x00, "static": 0x01}, "network_state": {"off": 0x00, "connecting": 0x01, "up": 0x02, "waiting": 0x03}, "network_reason": {"none": 0x00, "not_found": 0x01, "auth": 0x02, "no_address": 0x03, "other": 0x04}, "setting_form": {"named": 0x00, "bytes": 0x01, "text": 0x02, "u32": 0x03, "ipv4": 0x04, "bool": 0x05}, "setting_flag": {"secret": 0x01, "restart": 0x02}, "storage_state": {"none": 0x00, "applied": 0x01, "unreadable": 0x02, "partial": 0x03}, "storage_unreadable": {"none": 0x00, "form": 0x01, "item": 0x02, "capacity": 0x03}}, own={},
98
+ line_names={'swdio': 'the debug data line (2 wires: rvswd, swd) (Host only)', 'swclk': 'the debug clock line (2 wires: rvswd, swd) (Host only)', 'swio': 'the one debug wire (swio) (Host only)', 'rx': 'the fixture UART receive, wired to the target TX (Host only)', 'tx': 'the fixture UART transmit, wired to the target RX (Host only)', 'nrst': 'the target reset line (Host only)', 'power_hi': 'target power on when high (Host only)', 'power_lo': 'target power on when low (Host only)'}, names={'setting': {'label': 'key channel; text 1-32 bytes', 'idle': 'key channel; mode(u8)', 'disable': 'key channel; no data', 'passthrough': 'key port; fn(u16) rx(u16) baud(u32) format(u8)', 'console-passthrough': 'key port; wire_fn(u16) swdio(u16) swclk(u16) max_speed(u32) console_fn(u16) mechanism(u8)', 'wifi': 'key entry; ssid_len(u8) ssid pass_len(u8) passphrase; passphrase write-only', 'ipv4': 'key netif; mode(u8) address(4) prefix(u8) gateway(4) dns(4)', 'rvswd-rest': "key channel (the port's SWCLK); mode(u8): rvswd_rest_mode"}, 'netif': {'wifi': 'Wi-Fi station', 'ethernet': 'wired Ethernet'}})
99
99
  INTERFACES["oep.probe.config"] = PROBE_CONFIG
oep_client/riscv.py CHANGED
@@ -197,6 +197,10 @@ class WireBase(Interface):
197
197
  ONE_WIRE = False # swio: swclk is 0xFFFF (§3)
198
198
  DEFAULT_MAX_SPEED = 1_000_000 # when the wire declares no max_clock_hz either
199
199
 
200
+ def _is_rvswd(self) -> bool:
201
+ """The rest TLVs are rvswd's (debug §3.1); the name as opened, else the class's."""
202
+ return getattr(self, "name", self.NAME) == "oep.wire.rvswd"
203
+
200
204
  def _description(self) -> catalog.Description:
201
205
  return catalog.decode_description(b"".join(catalog.tlv(t, v) for t, v in describe(self.host, self.fn)))
202
206
 
@@ -307,17 +311,22 @@ class WireBase(Interface):
307
311
  for _ in range(count):
308
312
  conn, swdio, swclk, speed, scheme, n = rd.take("IHHIBB")
309
313
  tid = rd.bytes(n)
310
- page.append([conn, (swdio, swclk), speed, (scheme, tid) if scheme else None, None])
314
+ page.append([conn, (swdio, swclk), speed, (scheme, tid) if scheme else None, None, None])
311
315
  for tag, value in m.split_tlvs(rd.rest()):
312
316
  # entry_index(u8) targetsel(u32), repeatable; bit 7 in an answer: an unknown tag (core §2.2, §2.3)
313
317
  if tag == _SELECTED_TARGET and len(value) == 5 and value[0] < len(page):
314
318
  page[value[0]][4] = struct.unpack_from("<I", value, 1)[0]
319
+ # rvswd: entry_index(u8) idle_clock(u8) for every entry (debug §2.1, §3.1)
320
+ if self._is_rvswd() and tag == _REST and len(value) == 2 and value[0] < len(page):
321
+ page[value[0]][5] = _REST_NAMES.get(value[1])
315
322
  out += [ConnectionInfo(*row) for row in page]
316
323
  if not more or not count or len(out) > 0xFF:
317
324
  return out
318
325
 
319
326
 
320
327
  _SELECTED_TARGET = reg.WIRE_SWD.tlv["connections_answer"]["selected_target"]
328
+ _REST = reg.WIRE_RVSWD.tlv["connections_answer"]["idle_clock"]
329
+ _REST_NAMES = {v: k for k, v in reg.WIRE_RVSWD.enum["idle_clock"].items()}
321
330
 
322
331
 
323
332
  @dataclass(frozen=True)
@@ -329,6 +338,7 @@ class ConnectionInfo:
329
338
  speed_hz: int
330
339
  target_id: tuple[int, bytes] | None
331
340
  targetsel: int | None = None
341
+ idle_clock: str | None = None # rvswd: "high" / "low", the rest the connection uses (debug §3.1)
332
342
 
333
343
 
334
344
  class Wire(WireBase):
@@ -342,6 +352,7 @@ class Wire(WireBase):
342
352
  SCHEME_DMI_7F = reg.COMMON.enum["target_id_scheme"]["dmi_7f"] # the u32 at DMI 0x7F (oep-if-debug §3)
343
353
 
344
354
  TAG_DPC = reg.WIRE_RVSWD.tlv["attach_answer"]["dpc"]
355
+ TAG_REST = reg.WIRE_RVSWD.tlv["attach_answer"]["idle_clock"]
345
356
 
346
357
  def __init__(self, hst: h.Host, name: str = "oep.wire.rvswd"):
347
358
  super().__init__(hst, name)
@@ -397,6 +408,10 @@ class Wire(WireBase):
397
408
  dpc = tail.get(self.TAG_DPC)
398
409
  # dpc is a u32: a value of another length is broken, not used (core §2.3)
399
410
  self.dpc = struct.unpack("<I", dpc)[0] if self.halted and dpc is not None and len(dpc) == 4 else None
411
+ # rvswd: the rest the connection uses, the host's or the probe's choice from target_id (debug §3.1)
412
+ rest = tail.get(self.TAG_REST) if self._is_rvswd() else None
413
+ names = {v: k for k, v in self.IDLE_CLOCK.items()}
414
+ self.idle_clock = names.get(rest[0]) if rest is not None and len(rest) == 1 else None
400
415
  return conn, status
401
416
 
402
417
  def attach_under_reset(self, channel: int, hold_ms: int = 20, max_speed: int | None = None,
@@ -262,7 +262,7 @@ def _setting(name: str, keys: int, form: int = 0, max_len: int = 0, flags: int =
262
262
 
263
263
 
264
264
  def _config(fn: int, instance: int, storage: int = 4096, *, channels: int = 64, ports: int = 4, netifs=(), wifi_entries: int = 4,
265
- own=()) -> Offered:
265
+ own=(), rvswd: bool = False) -> Offered:
266
266
  """oep.probe.config's declarations (probe.config §4): the standard items label / idle / disable (keys: the
267
267
  channels), passthrough / console-passthrough (keys: the transports), with `netifs` (names) wifi / ipv4 and the
268
268
  network op; `own`: the probe's own items as (name, form, keys, max_len, flags) (§1.6). storage 0 = none - no storage
@@ -274,6 +274,8 @@ def _config(fn: int, instance: int, storage: int = 4096, *, channels: int = 64,
274
274
  if "wifi" in netifs:
275
275
  settings.append(_setting("wifi", wifi_entries))
276
276
  settings.append(_setting("ipv4", len(netifs) + 1))
277
+ if rvswd: # its automatic rest can be turned off per port (debug §3.1)
278
+ settings.append(_setting("rvswd-rest", channels))
277
279
  settings += [_setting(name, keys, form, max_len, flags) for name, form, keys, max_len, flags in own]
278
280
  return Offered(fn, instance, "oep.probe.config", ops_of("oep.probe.config", *drop)
279
281
  + ((catalog.u32(_CFG["storage"], storage),) if storage else ()) + tuple(settings)
@@ -388,7 +390,7 @@ def p4_x035() -> VirtualProbe:
388
390
  max_stretch_us=100_000), # stretch
389
391
  Offered(9, 0, "oep.fixture.spi-target", _roles({1: pins, 2: pins, 3: pins, 4: pins})
390
392
  + _spi_decl(max_length=64, max_hz=3_000_000, features=0b1, queue_depth=8)), # LSB first
391
- _config(10, 0, channels=55, ports=4, netifs=("ethernet",)),
393
+ _config(10, 0, channels=55, ports=4, netifs=("ethernet",), rvswd=True),
392
394
  # the P4's ADC1 (GPIO16-23): one ADC for all its channels, 611 Hz - 83.3 kHz in all; ESP32-style attenuations
393
395
  Offered(11, 0, "oep.fixture.analog", _roles({k: list(range(16, 24)) for k in range(4)})
394
396
  + _analog_decl([(0, 0, 950), (1, 0, 1250), (2, 0, 1750), (3, 0, 3100)], 65536, 611, 83_333),
@@ -465,7 +467,7 @@ def p4_bench() -> VirtualProbe:
465
467
  _console(3),
466
468
  _gpio(4, pins),
467
469
  _uart(5, 0, pins, 3_000_000),
468
- _config(6, 0, channels=55, ports=4),
470
+ _config(6, 0, channels=55, ports=4, rvswd=True),
469
471
  _link(7),
470
472
  _plan(8),
471
473
  _restart(9),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: oep-client-python
3
- Version: 0.0.32
3
+ Version: 0.0.33
4
4
  Summary: Open Embedded Probe (OEP) v1 host: serial / USB / TCP transports, the session rules, the standard interfaces, and a virtual bench
5
5
  Project-URL: Homepage, https://github.com/Open-Embedded-Probe/oep-client-python
6
6
  Project-URL: Repository, https://github.com/Open-Embedded-Probe/oep-client-python
@@ -1,11 +1,11 @@
1
- oep_client/__init__.py,sha256=dc5KhNc3OoDo3NHuTBh3x0xUq6ZK5r7OI8zmMek5fqI,164
2
- oep_client/__main__.py,sha256=si0Jx0Shjgg9cZka73sWmBuRObcrIQs3GHHoJ8bKruE,32277
1
+ oep_client/__init__.py,sha256=i55a89BxR1hu3ff6BPlfP_aEJn4skTGl0cJphRFGQdo,164
2
+ oep_client/__main__.py,sha256=l7KIG3-55GovEmb9dboeA-gInoNBwCXziCERHbBQCyY,32873
3
3
  oep_client/arm.py,sha256=SszSLae8zErD4T-a1uQ6s6o3Lz7pe2SR8d3Qy-wi5rY,15633
4
4
  oep_client/capture.py,sha256=AFyJ-_DRb3ztYlvmFCDh9siNaKrwChOx8xvoNH6CKsI,48884
5
5
  oep_client/catalog.py,sha256=WkaksNn9cFvkTRnvtX4I9g1AvkFoldEiNQaKiyPQ7_E,10772
6
6
  oep_client/ch32_flash.py,sha256=lY_HKxf2foSfhNda91lcWefgRnY9ebTljsg4zJEj-Ks,12885
7
7
  oep_client/cobs.py,sha256=RbdPrqgzD3SukxOIXX9m2dZpVTud8xAYYEhm3rcW2nA,2513
8
- oep_client/config.py,sha256=JS0aFHo3oZuCxTV1d1q4hFEEwCXtHTlcD_RLGwxQxb4,28557
8
+ oep_client/config.py,sha256=OTePLd-X1QC7xOk36BmhqfF8M7WwBXaDvuz_jiBmrIM,29575
9
9
  oep_client/conformance.py,sha256=phKkP_vT_8b9MyQiJU0p7JoCnkrPbPdkolcEqaD61TI,62859
10
10
  oep_client/conformance_allocator.py,sha256=83xXiJ7c-6-M86615Kvq6yDD0sf0Z6lIOKDtbYcKeyM,6274
11
11
  oep_client/conformance_allocator_sample.py,sha256=GGv43xbDNSPjQ8_flNXe-QbkLOr-NCbPpWPOfbD_wH8,879
@@ -178,7 +178,7 @@ oep_client/core.py,sha256=VPtgaVe2K5-HJMi72DDbIpIirATAXjcJSKautKUFgOM,22677
178
178
  oep_client/decode.py,sha256=6pTFVBT0MLAKedZLVKyd5yT8hjrRw4fdDjnoDiE9XRs,2380
179
179
  oep_client/discovery.py,sha256=OS6c4Qa8N32zbOHmw75e1y6ff3SQrL0uLtyPi7BWKUA,20187
180
180
  oep_client/dump.py,sha256=31v4Hg27Het3cu3joCm6ttTWxQHSvvNryyGo8pwHXO4,12788
181
- oep_client/endpoint.py,sha256=_19u04VavT4-Pim-BnLQpIQ2-eGPulSHznQcU9EB8TM,224395
181
+ oep_client/endpoint.py,sha256=DmKqB_uLHQnvUBuv5q_jcofD_9spbWjCJ1_1tieFJMo,226457
182
182
  oep_client/fixture.py,sha256=GbAPXAk9GQ0qG6STL-rY4-EqXftmKfNKVI2xZZUiFzA,18108
183
183
  oep_client/frames.py,sha256=OrvoNugGB4ewfmILhwBiJfI9sQ09i-RzO47LESVbWXw,4800
184
184
  oep_client/hardware.py,sha256=RboxkRxkQJ3DbNJEXyyiOFYlLFKGxrlcSwHho8zFC1U,30256
@@ -192,8 +192,8 @@ oep_client/message.py,sha256=-WgnHcmnhJ6pozYvZP_FS8dr0ZMg2Wp9rTdRReGvogU,13116
192
192
  oep_client/names.py,sha256=ohrRvQNURraYyJ-BtjHRwxGt_GLq-t8IO0aOji9Dhe0,3531
193
193
  oep_client/pins.py,sha256=YVM0JXjCKcMMMWChtWsQoSKU4-OTOnDbZjo_mo_5hD0,32574
194
194
  oep_client/pytest_conformance.py,sha256=-bcJU2E1UE4xjQ7HZjaIgtp0l65cIibBTNFnaW2tews,2929
195
- oep_client/registry.py,sha256=zHcPM0y8w-4omwn-Htj2wgSl72gzGDTxn2Nq2JEAMGI,16087
196
- oep_client/riscv.py,sha256=S9nJR5GGE4mmG36r-4878iSJFfTnHrnwlv3oq66fll8,58101
195
+ oep_client/registry.py,sha256=eeUL7cquyunsaSQYofRNXH0y8sAFkX8sRtmwc7-GZjA,16688
196
+ oep_client/riscv.py,sha256=J0HHHrI-xrIt46zob3RpmOqy9XV12-futGeU1SC-xjY,59201
197
197
  oep_client/rp2350.py,sha256=7OMyj270k3AY1e3-ljicPwOjf9jOlokbT6QNkA0b0yY,4227
198
198
  oep_client/speed_record.py,sha256=6THUKbN7gQKpfIdUO2551P8mXiAFqbFDky72Xbki7L0,7229
199
199
  oep_client/targets.py,sha256=zFekSr76NVO7tzdgyQsLDHLWRvkgylfwvGNTz_hQGf8,5041
@@ -203,7 +203,7 @@ oep_client/virtual_allocator_model.py,sha256=XBrbjG2Zupf0P28gjUhQVDw6UzO2jQXsYZ1
203
203
  oep_client/virtual_analog_model.py,sha256=iV5pyJ1sy37D6VMy4qVmgzsmq4gLwEPMcdOGXPIin1Q,13872
204
204
  oep_client/virtual_arm_adi_model.py,sha256=xlqhjr_QCF6MNVOnVelTanlNWpmaCJ5uWXf6V9WkqUM,8121
205
205
  oep_client/virtual_attach_model.py,sha256=11UfEicbmTKcjps8JPzw99J59Dl_QGVbyyuFb0ixzso,10288
206
- oep_client/virtual_bench.py,sha256=V7gW6QELn9g9CC6Y1zc4qifH5v04kBPaa_2obH1lYeg,35720
206
+ oep_client/virtual_bench.py,sha256=WXLJICEhaTo5kapOujCcH-CEfIgtudlzanrUv_tVIss,35944
207
207
  oep_client/virtual_bench_capture.py,sha256=hIIOUOqKcSxBnsCb9rcyzYFqSsBmuic7sAkF7zsBAIs,52208
208
208
  oep_client/virtual_bench_mdns.py,sha256=cnJNBKg5zTduXUcH-wqN_ZBDGl7DyL-tL3CBn2jro0E,13305
209
209
  oep_client/virtual_bench_serial.py,sha256=EvbdOYeGrM6CRti2b90I0PzpmmherfoJRaAg4v7Iq9Y,13205
@@ -261,8 +261,8 @@ oep_client/virtual_tlv_request_model.py,sha256=gp-eiN784NnloQBANG_4TnM6oUCmrj046
261
261
  oep_client/virtual_uart_model.py,sha256=Sd_MWLjl1-6_bemsCuI2at9zpVJRBehFQgZ6By97PdQ,9386
262
262
  oep_client/virtual_wire_options_model.py,sha256=1QNF16hRWmdFt0J7Zd1WKZdEc07vns6osMQLetMBlXw,9206
263
263
  oep_client/virtual_writer_lease_model.py,sha256=E1MAQsGuShqONVdIeLubun7Cop0URNUSk8wicPicbt4,1728
264
- oep_client_python-0.0.32.dist-info/METADATA,sha256=GhnCD1t2bz0YgyBVnXFJC91foKBuFdu2o0Gr0cuRgNI,52711
265
- oep_client_python-0.0.32.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
266
- oep_client_python-0.0.32.dist-info/entry_points.txt,sha256=XEt39Jz7oQyU9Hfg_tV6eDGofNxWYrjSfslxKP-fh70,135
267
- oep_client_python-0.0.32.dist-info/licenses/LICENSE,sha256=ntlalztb3L1OaNAxmQdHlubu5fVhjMc9oRZi3PeQhXg,1076
268
- oep_client_python-0.0.32.dist-info/RECORD,,
264
+ oep_client_python-0.0.33.dist-info/METADATA,sha256=ruHISiMjzQOjtZv3t2Bcyo3LxM8292-_CCUMc0NUXLk,52711
265
+ oep_client_python-0.0.33.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
266
+ oep_client_python-0.0.33.dist-info/entry_points.txt,sha256=XEt39Jz7oQyU9Hfg_tV6eDGofNxWYrjSfslxKP-fh70,135
267
+ oep_client_python-0.0.33.dist-info/licenses/LICENSE,sha256=ntlalztb3L1OaNAxmQdHlubu5fVhjMc9oRZi3PeQhXg,1076
268
+ oep_client_python-0.0.33.dist-info/RECORD,,