oep-client-python 0.0.22__tar.gz → 0.0.23__tar.gz

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 (52) hide show
  1. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/CHANGELOG.md +4 -0
  2. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/PKG-INFO +1 -1
  3. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/pyproject.toml +1 -1
  4. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/__init__.py +1 -1
  5. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/link.py +19 -6
  6. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/.gitignore +0 -0
  7. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/LICENSE +0 -0
  8. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/README.ja.md +0 -0
  9. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/README.md +0 -0
  10. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/__main__.py +0 -0
  11. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/arm.py +0 -0
  12. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/capture.py +0 -0
  13. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/catalog.py +0 -0
  14. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/ch32_flash.py +0 -0
  15. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/cobs.py +0 -0
  16. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/config.py +0 -0
  17. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/console.py +0 -0
  18. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/core.py +0 -0
  19. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/decode.py +0 -0
  20. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/dump.py +0 -0
  21. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/endpoint.py +0 -0
  22. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/fake.py +0 -0
  23. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/fake_capture.py +0 -0
  24. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/fake_serial.py +0 -0
  25. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/fake_serve.py +0 -0
  26. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/fixture.py +0 -0
  27. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/frames.py +0 -0
  28. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/hid_stream.py +0 -0
  29. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/host.py +0 -0
  30. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/interfaces.py +0 -0
  31. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/message.py +0 -0
  32. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/names.py +0 -0
  33. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/registry.py +0 -0
  34. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/riscv.py +0 -0
  35. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/rp2350.py +0 -0
  36. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/uiapduino.py +0 -0
  37. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/src/oep_client/usb_stream.py +0 -0
  38. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_capabilities.py +0 -0
  39. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_capture.py +0 -0
  40. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_cobs.py +0 -0
  41. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_config.py +0 -0
  42. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_fake_capture.py +0 -0
  43. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_fake_spec.py +0 -0
  44. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_fixture_targets.py +0 -0
  45. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_flash_console.py +0 -0
  46. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_hid_stream.py +0 -0
  47. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_interfaces.py +0 -0
  48. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_link_host.py +0 -0
  49. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_link_serial.py +0 -0
  50. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_session.py +0 -0
  51. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_target_parts.py +0 -0
  52. {oep_client_python-0.0.22 → oep_client_python-0.0.23}/tests/test_usb_stream.py +0 -0
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.0.23
6
+ - (EN) `link.open_host("tcp://…")` waits 15 s for a reply and does not send a request again by itself (`resend=False`): behind ch32rv's broker, the broker retries towards the probe, and a second copy from the client only raced it (V003 jig, 2026-10-01). `open_host(..., timeout=, resend=)` set both explicitly; serial and USB keep 3 s and one resend.
7
+ - (JA) `link.open_host("tcp://…")` は応答を 15 秒待ち、自分では送り直さない(`resend=False`)。ch32rv のブローカーの後ろでは、ブローカーが probe に送り直すので、client からの 2 通目は競合するだけだった(V003 ジグ、2026-10-01)。`open_host(..., timeout=, resend=)` で明示できる。シリアルと USB は 3 秒と 1 回の送り直しのまま。
8
+
5
9
  ## 0.0.22
6
10
  - (EN) Breaking: the wire follows oep-spec's zero-base rewrite of 2026-10-01 (docs/v1-zero-base-proposal.ja.md §3 / §7; registry synced). Every answer that ended in data or a list now carries its length and may be followed by TLVs: read answers `start flags len data [TLV]` (console, fixture UART; capture `len` u32), gpio read `n n×level`, dmi `done status nvals values`, arm-adi transfer `done status ack nvals values`, run `status stopped dpc elapsed_us nvals values` (stopped 2 = the hart could not be halted: `RunResult.not_halted`), data frames `position len data [TLV]`, events `kind fixed-part [TLV]`. TLVs have a long form (`tag 0xFF len(u16) value` for 255 bytes and more; `message.tlv` / `split_tlvs`, the long form with a short value is `message.BadTlv`). confirm answers the probe's `boot_id`; subscribe's `max_delay_ms` is u32; `rejected unsupported` is always `tag [TLV]` (0x00 = a fixed-part value: `Unsupported.tag` None, `.tlvs`).
7
11
  - (JA) 破壊的変更: wire を oep-spec の 2026-10-01 のゼロベース見直し(docs/v1-zero-base-proposal.ja.md §3 / §7。registry を写し直した)に揃えた。データや並びで終わっていた応答はすべて長さを持ち、後ろに TLV を置ける: read の応答 `start flags len data [TLV]`(console、fixture UART。capture の `len` は u32)、gpio read `n n×level`、dmi `done status nvals values`、arm-adi transfer `done status ack nvals values`、run `status stopped dpc elapsed_us nvals values`(stopped 2 = hart を止められなかった: `RunResult.not_halted`)、データフレーム `position len data [TLV]`、出来事 `kind 固定部 [TLV]`。TLV に長い形(255 byte 以上は `tag 0xFF len(u16) value`。`message.tlv` / `split_tlvs`、短い値の長い形は `message.BadTlv`)。confirm は probe の `boot_id` を返す。subscribe の `max_delay_ms` は u32。`rejected unsupported` は常に `tag [TLV]`(0x00 = 固定部の値: `Unsupported.tag` は None、`.tlvs`)。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: oep-client-python
3
- Version: 0.0.22
3
+ Version: 0.0.23
4
4
  Summary: Open Embedded Probe (OEP) v1 host: serial / USB / TCP transports, the session rules, the standard interfaces, and a fake probe
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oep-client-python"
7
- version = "0.0.22"
7
+ version = "0.0.23"
8
8
  description = "Open Embedded Probe (OEP) v1 host: serial / USB / TCP transports, the session rules, the standard interfaces, and a fake probe"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.0.22"
5
+ __version__ = "0.0.23"
@@ -122,6 +122,7 @@ class SerialLink:
122
122
  self.stream = stream
123
123
  self.framing = framing
124
124
  self.timeout = timeout
125
+ self.resend = True # a lost reply: the request once more with the same corr (core §5.2)
125
126
  self.retries = 0
126
127
  self.corrupt = 0
127
128
  self.stale = 0 # replies that answered another request
@@ -284,7 +285,7 @@ class SerialLink:
284
285
  if isinstance(e, cobs.CorruptFrame):
285
286
  self.corrupt += 1
286
287
  self._recover()
287
- if attempt or (message[0] & m.ROLE_SESSION and self.ended_blind):
288
+ if attempt or not self.resend or (message[0] & m.ROLE_SESSION and self.ended_blind):
288
289
  raise
289
290
  # sent once more with the same corr, state-changing ones too: the probe keeps the lock holder's recent
290
291
  # results and answers a repeat from them instead of running it twice (v1-open-proposals §4). A result
@@ -303,7 +304,7 @@ class SerialLink:
303
304
  try:
304
305
  return self._exchange_once(messages, max_inflight, window_bytes, replies)
305
306
  except (cobs.CorruptFrame, TimeoutError, FramingLost):
306
- if self.ended_blind:
307
+ if self.ended_blind or not self.resend:
307
308
  raise
308
309
  self.retries += 1
309
310
  rest = messages[len(replies):]
@@ -433,19 +434,29 @@ def _open_usb_stream(kind: str, vid: int, pid: int, serial: str | None):
433
434
  return UsbBulkStream.open(vid, pid, serial)
434
435
 
435
436
 
436
- def open_host(target: str, timeout: float = 3.0):
437
+ TCP_TIMEOUT = 15.0 # behind a broker: outlast its own 3 s retry towards the probe, and never send again ourselves
438
+
439
+
440
+ def open_host(target: str, timeout: float | None = None, resend: bool | None = None):
437
441
  """A Host on `target`, with the link's pipelining bound to the probe's limits (core confirm): Host.pipeline and
438
442
  everything built on it (flash, capture reads) then keep several requests in flight.
439
443
 
440
444
  target: a serial port path (COM3 on Windows); tcp://HOST:PORT for a local broker (length frames); usb[:VID:PID[:SERIAL]]
441
445
  (hex) for the probe's USB device, vendor bulk then HID (oep-core §3.3); usb:UNIT_ID for the OEP probe whose USB
442
- serial is that unit id, whatever its VID:PID."""
446
+ serial is that unit id, whatever its VID:PID.
447
+
448
+ timeout: seconds to wait for a reply (default 3; TCP 15). resend: send a request once more with the same corr when
449
+ its reply was lost (default on; off for TCP, where a broker retries towards the probe itself and a second copy from
450
+ here would only race it - a lost reply is then raised to the caller)."""
443
451
  from . import host
444
452
  if target.startswith("tcp://"):
445
453
  addr, _, port = target[len("tcp://"):].rpartition(":")
446
- lk = SerialLink.on_stream(TcpStream(addr or "127.0.0.1", int(port)), "length", timeout)
454
+ lk = SerialLink.on_stream(TcpStream(addr or "127.0.0.1", int(port)), "length",
455
+ TCP_TIMEOUT if timeout is None else timeout)
456
+ lk.resend = False if resend is None else resend
447
457
  lk.transport = "tcp"
448
458
  elif target == "usb" or target.startswith("usb:"):
459
+ timeout = 3.0 if timeout is None else timeout
449
460
  parts = target.split(":")[1:]
450
461
  if len(parts) == 1: # usb:UNIT_ID (any length: a VID comes with its PID)
451
462
  vid, pid = find_usb(parts[0])
@@ -454,8 +465,10 @@ def open_host(target: str, timeout: float = 3.0):
454
465
  pid = int(parts[1], 16) if len(parts) > 1 else USB_PID
455
466
  return open_usb_host(vid, pid, parts[2] if len(parts) > 2 else None, timeout)
456
467
  else:
457
- lk = SerialLink(target, timeout)
468
+ lk = SerialLink(target, 3.0 if timeout is None else timeout)
458
469
  lk.transport = "serial"
470
+ if resend is not None:
471
+ lk.resend = resend
459
472
  hst = host.Host(lk.send)
460
473
  lk.attach_host(hst)
461
474
  return hst