oep-client-python 0.0.1__tar.gz → 0.0.2__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.
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/CHANGELOG.md +6 -0
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/PKG-INFO +7 -7
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/README.ja.md +6 -6
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/pyproject.toml +2 -2
- oep_client_python-0.0.2/src/oep_client/__init__.py +5 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/__main__.py +4 -4
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake_serve.py +54 -12
- oep_client_python-0.0.1/tests/test_v1_capabilities.py → oep_client_python-0.0.2/tests/test_capabilities.py +1 -1
- oep_client_python-0.0.1/tests/test_v1_capture.py → oep_client_python-0.0.2/tests/test_capture.py +3 -3
- oep_client_python-0.0.1/tests/test_v1_cobs.py → oep_client_python-0.0.2/tests/test_cobs.py +1 -1
- oep_client_python-0.0.1/tests/test_v1_esp32_targets.py → oep_client_python-0.0.2/tests/test_esp32_targets.py +2 -2
- oep_client_python-0.0.1/tests/test_v1_fake_spec.py → oep_client_python-0.0.2/tests/test_fake_spec.py +30 -4
- oep_client_python-0.0.1/tests/test_v1_flash_console.py → oep_client_python-0.0.2/tests/test_flash_console.py +2 -2
- oep_client_python-0.0.1/tests/test_v1_hid_stream.py → oep_client_python-0.0.2/tests/test_hid_stream.py +1 -1
- oep_client_python-0.0.1/tests/test_v1_interfaces.py → oep_client_python-0.0.2/tests/test_interfaces.py +3 -3
- oep_client_python-0.0.1/tests/test_v1_link_host.py → oep_client_python-0.0.2/tests/test_link_host.py +1 -1
- oep_client_python-0.0.1/tests/test_v1_link_serial.py → oep_client_python-0.0.2/tests/test_link_serial.py +2 -2
- oep_client_python-0.0.1/tests/test_v1_session.py → oep_client_python-0.0.2/tests/test_session.py +3 -3
- oep_client_python-0.0.1/tests/test_v1_target_parts.py → oep_client_python-0.0.2/tests/test_target_parts.py +2 -2
- oep_client_python-0.0.1/src/oep_client/__init__.py +0 -5
- oep_client_python-0.0.1/src/oep_client/v1/__init__.py +0 -1
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/.gitignore +0 -0
- {oep_client_python-0.0.1 → oep_client_python-0.0.2}/LICENSE +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/arm.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/capture.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/catalog.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/ch32_flash.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/cobs.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/console.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/core.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/decode.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/dump.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/endpoint.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/esp32_targets.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake_serial.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fixture.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/frames.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/hid_stream.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/host.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/interfaces.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/link.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/message.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/names.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/registry.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/riscv.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/rp2350.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/target.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/uiapduino.py +0 -0
- {oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/usb_stream.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.0.2
|
|
6
|
+
- (EN) Breaking: the modules move from `oep_client.v1.*` to `oep_client.*` (`from oep_client import link`, `python -m oep_client`, `python -m oep_client.fake_serve`). The protocol revision stays in the registry and confirm.
|
|
7
|
+
- (JA) 破壊的変更: モジュールを `oep_client.v1.*` から `oep_client.*` に移した(`from oep_client import link`、`python -m oep_client`、`python -m oep_client.fake_serve`)。プロトコルの revision は registry と confirm が持つ。
|
|
8
|
+
- (EN) `fake_serve --uart-plan` puts the first fixture UART's RX / TX plan in at boot (as a saved config), and `--uart-rx TEXT` feeds its RX every `--every` ms once configured.
|
|
9
|
+
- (JA) `fake_serve --uart-plan` で最初の fixture UART の RX / TX の plan を起動時に入れる(保存した設定として)。`--uart-rx TEXT` で、configure の後、その RX に `--every` ms ごとに文字を入れる。
|
|
10
|
+
|
|
5
11
|
## 0.0.1
|
|
6
12
|
- (EN) First beta on PyPI (`pip install oep-client-python`, imported as `oep_client`). OEP v1 host: serial ports always COBS with the probe's raw bytes skipped as noise and opened exclusively (TIOCEXCL), USB vendor bulk / HID and TCP (a broker) with length frames, all under one `Host` (`link.open_host(target)`); the session rules (owner, resend with the same corr, `core.take` for the lock); the standard interfaces; `Host.on_capture` for run recorders; a fake probe (`oep_client.v1.endpoint`) and `python -m oep_client.v1.fake_serve` (pty / TCP) as the working spec for other hosts' tests.
|
|
7
13
|
- (JA) PyPI での最初のβ版(`pip install oep-client-python`、import は `oep_client`)。OEP v1 の host: シリアルの口は常に COBS(probe の生のバイトは雑音として捨てる、排他で開く TIOCEXCL)、USB の vendor bulk / HID と TCP(ブローカー)は長さつきのフレームで、どれも同じ `Host`(`link.open_host(target)`)。セッションの規則(owner、同じ corr での送り直し、ロックの取り方 `core.take`)、標準インターフェース、記録の受け口 `Host.on_capture`。ほかの host の試験のための「動く spec」として、偽の probe(`oep_client.v1.endpoint`)と `python -m oep_client.v1.fake_serve`(pty / TCP)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: oep-client-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
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
|
|
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
# OEP Python client
|
|
24
24
|
|
|
25
25
|
Open Embedded Probe の host 側。v1(oep-spec の `docs/oep-core.ja.md` と `docs/oep-if-*.ja.md`、固める候補の形)を話す。番号は oep-spec の
|
|
26
|
-
`generated/oep-v1/oep_v1_registry.py` をそのまま写した `oep_client.
|
|
26
|
+
`generated/oep-v1/oep_v1_registry.py` をそのまま写した `oep_client.registry` から取る。破壊的変更を前提とする
|
|
27
27
|
実験段階で、互換 API は約束しない。OEP を初めて読む人は oep-spec の `docs/review-guide.ja.md`(どこに何が書いてあるか)から。
|
|
28
28
|
|
|
29
29
|
target の知識は host にある、という OEP の分担に従う。probe は線と DMI / DP・AP の転送しか知らず、CH32 の flash
|
|
@@ -34,14 +34,14 @@ pip install oep-client-python # PyPI (import oep_client); a checkout: pip in
|
|
|
34
34
|
uv run pytest # in a checkout
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
`import oep_client
|
|
37
|
+
`import oep_client` だけで使える(`sys.path` に `src/` を足す使い方は不要になった)。番号の表は `tools/sync_registry.sh` で
|
|
38
38
|
oep-spec から写す。PyPI の `oep-client` は別のプロジェクトなので、配布名は `oep-client-python`。
|
|
39
39
|
|
|
40
40
|
リリースは GitHub Actions の Release(workflow_dispatch、version = X.Y.Z か X.Y.ZbN): `tools/prepare_release.py` が
|
|
41
41
|
pyproject.toml と `oep_client.__version__` を書き換え、CHANGELOG.md の Unreleased をその版にし、試験と build の後に commit と tag、
|
|
42
42
|
GitHub Release、PyPI(Trusted Publishing)へ出す。変更は CHANGELOG.md の Unreleased に (EN) / (JA) で書き足しておく。
|
|
43
43
|
|
|
44
|
-
## モジュール(`oep_client
|
|
44
|
+
## モジュール(`oep_client`)
|
|
45
45
|
|
|
46
46
|
| モジュール | 中身 |
|
|
47
47
|
|---|---|
|
|
@@ -66,7 +66,7 @@ GitHub Release、PyPI(Trusted Publishing)へ出す。変更は CHANGELOG.md
|
|
|
66
66
|
## 使い方の例
|
|
67
67
|
|
|
68
68
|
```python
|
|
69
|
-
from oep_client
|
|
69
|
+
from oep_client import core, link, riscv, ch32_flash
|
|
70
70
|
|
|
71
71
|
hst = link.open_host("/run/board-identify/by-id/esp32-series-30eda0e31108") # pipelining つき
|
|
72
72
|
# a serial port (always COBS), "tcp://127.0.0.1:PORT" (a broker), "usb" / "usb:303a:0002[:SERIAL]" (vendor, then HID)
|
|
@@ -81,7 +81,7 @@ wire.detach(conn)
|
|
|
81
81
|
hst.end()
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
能力の一覧は `uv run python -m oep_client
|
|
84
|
+
能力の一覧は `uv run python -m oep_client dump --port <probe>`(`--fake p4-x035` でハードウェアなし)。
|
|
85
85
|
実機での一通りの確認は ArduinoCore-CH32 の `tests/manual/oep_smoke/`(`oep_smoke.py`、`oep_probe_checks.py`)。
|
|
86
86
|
|
|
87
87
|
## 偽の probe(動く spec)
|
|
@@ -94,7 +94,7 @@ hst.end()
|
|
|
94
94
|
外のプログラムの試験には `fake_serve` を子プロセスで使う:
|
|
95
95
|
|
|
96
96
|
```sh
|
|
97
|
-
uv run python -m oep_client.
|
|
97
|
+
uv run python -m oep_client.fake_serve --pty --profile p4-bench --slot x035 --bind last-reset \
|
|
98
98
|
--console 'uptime %d\r\n' --every 100
|
|
99
99
|
# 最初の行: PTY /dev/pts/N(--tcp 0 なら PORT n)。stdin を閉じると終わる
|
|
100
100
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# OEP Python client
|
|
2
2
|
|
|
3
3
|
Open Embedded Probe の host 側。v1(oep-spec の `docs/oep-core.ja.md` と `docs/oep-if-*.ja.md`、固める候補の形)を話す。番号は oep-spec の
|
|
4
|
-
`generated/oep-v1/oep_v1_registry.py` をそのまま写した `oep_client.
|
|
4
|
+
`generated/oep-v1/oep_v1_registry.py` をそのまま写した `oep_client.registry` から取る。破壊的変更を前提とする
|
|
5
5
|
実験段階で、互換 API は約束しない。OEP を初めて読む人は oep-spec の `docs/review-guide.ja.md`(どこに何が書いてあるか)から。
|
|
6
6
|
|
|
7
7
|
target の知識は host にある、という OEP の分担に従う。probe は線と DMI / DP・AP の転送しか知らず、CH32 の flash
|
|
@@ -12,14 +12,14 @@ pip install oep-client-python # PyPI (import oep_client); a checkout: pip in
|
|
|
12
12
|
uv run pytest # in a checkout
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
`import oep_client
|
|
15
|
+
`import oep_client` だけで使える(`sys.path` に `src/` を足す使い方は不要になった)。番号の表は `tools/sync_registry.sh` で
|
|
16
16
|
oep-spec から写す。PyPI の `oep-client` は別のプロジェクトなので、配布名は `oep-client-python`。
|
|
17
17
|
|
|
18
18
|
リリースは GitHub Actions の Release(workflow_dispatch、version = X.Y.Z か X.Y.ZbN): `tools/prepare_release.py` が
|
|
19
19
|
pyproject.toml と `oep_client.__version__` を書き換え、CHANGELOG.md の Unreleased をその版にし、試験と build の後に commit と tag、
|
|
20
20
|
GitHub Release、PyPI(Trusted Publishing)へ出す。変更は CHANGELOG.md の Unreleased に (EN) / (JA) で書き足しておく。
|
|
21
21
|
|
|
22
|
-
## モジュール(`oep_client
|
|
22
|
+
## モジュール(`oep_client`)
|
|
23
23
|
|
|
24
24
|
| モジュール | 中身 |
|
|
25
25
|
|---|---|
|
|
@@ -44,7 +44,7 @@ GitHub Release、PyPI(Trusted Publishing)へ出す。変更は CHANGELOG.md
|
|
|
44
44
|
## 使い方の例
|
|
45
45
|
|
|
46
46
|
```python
|
|
47
|
-
from oep_client
|
|
47
|
+
from oep_client import core, link, riscv, ch32_flash
|
|
48
48
|
|
|
49
49
|
hst = link.open_host("/run/board-identify/by-id/esp32-series-30eda0e31108") # pipelining つき
|
|
50
50
|
# a serial port (always COBS), "tcp://127.0.0.1:PORT" (a broker), "usb" / "usb:303a:0002[:SERIAL]" (vendor, then HID)
|
|
@@ -59,7 +59,7 @@ wire.detach(conn)
|
|
|
59
59
|
hst.end()
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
能力の一覧は `uv run python -m oep_client
|
|
62
|
+
能力の一覧は `uv run python -m oep_client dump --port <probe>`(`--fake p4-x035` でハードウェアなし)。
|
|
63
63
|
実機での一通りの確認は ArduinoCore-CH32 の `tests/manual/oep_smoke/`(`oep_smoke.py`、`oep_probe_checks.py`)。
|
|
64
64
|
|
|
65
65
|
## 偽の probe(動く spec)
|
|
@@ -72,7 +72,7 @@ hst.end()
|
|
|
72
72
|
外のプログラムの試験には `fake_serve` を子プロセスで使う:
|
|
73
73
|
|
|
74
74
|
```sh
|
|
75
|
-
uv run python -m oep_client.
|
|
75
|
+
uv run python -m oep_client.fake_serve --pty --profile p4-bench --slot x035 --bind last-reset \
|
|
76
76
|
--console 'uptime %d\r\n' --every 100
|
|
77
77
|
# 最初の行: PTY /dev/pts/N(--tcp 0 なら PORT n)。stdin を閉じると終わる
|
|
78
78
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oep-client-python"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.2"
|
|
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.ja.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -25,7 +25,7 @@ usb-async = ["libusb1>=3"] # queued asynchronous IN transfers: streaming near
|
|
|
25
25
|
hid = ["hidapi>=0.14"] # the vendor HID way in through the OS HID driver (Windows without WinUSB, Linux hidraw)
|
|
26
26
|
|
|
27
27
|
[project.scripts]
|
|
28
|
-
oep = "oep_client.
|
|
28
|
+
oep = "oep_client.__main__:main"
|
|
29
29
|
|
|
30
30
|
[project.urls]
|
|
31
31
|
Homepage = "https://github.com/Open-Embedded-Probe/oep-client-python"
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/__main__.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Draft OEP capability discovery by name, on an in-process fake or a v1 draft probe.
|
|
2
2
|
|
|
3
|
-
uv run python -m oep_client
|
|
4
|
-
uv run python -m oep_client
|
|
5
|
-
uv run python -m oep_client
|
|
6
|
-
uv run python -m oep_client
|
|
3
|
+
uv run python -m oep_client dump --port /run/board-identify/by-id/<probe>
|
|
4
|
+
uv run python -m oep_client dump --fake p4-x035
|
|
5
|
+
uv run python -m oep_client dump --fake esp32-v003 --prefix oep.fixture
|
|
6
|
+
uv run python -m oep_client dump --fake p4-x035 --prefix oep.target --json
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake_serve.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Serve a fake probe (`endpoint.Endpoint`) on a pty or a TCP port, for other programs' tests.
|
|
2
2
|
|
|
3
|
-
python -m oep_client.
|
|
3
|
+
python -m oep_client.fake_serve [--pty | --tcp PORT] [options]
|
|
4
4
|
|
|
5
5
|
--pty (the default) opens a pseudo terminal that is the probe's serial port (oep-core §3.4): COBS frames
|
|
6
6
|
0x00 <COBS> 0x00 and the raw bytes of the port's bind on one line. The host opens the printed path itself (and
|
|
@@ -25,6 +25,9 @@ Options:
|
|
|
25
25
|
--bind MODE bind the serial port to every --slot: last-reset, manual or mixed
|
|
26
26
|
--target-id HEX the target_id every target's attach reports (wch_dmi_7f)
|
|
27
27
|
--absent N the N-th pin pair of the first wire has no target (repeatable)
|
|
28
|
+
--uart-plan the first oep.fixture.uart gets its RX / TX plan at boot, as if saved (the jig's "DUT TX" /
|
|
29
|
+
"DUT RX" labels when the profile has them, else the first free channels); configure then works
|
|
30
|
+
--uart-rx TEXT what arrives on that UART's RX every --every ms once it is configured (%d = a counter)
|
|
28
31
|
--run-hook SPEC what riscv-dm run does on every target: SPEC is module:function or path/file.py:function,
|
|
29
32
|
called as function(target, pc, regs) -> (stopped, dpc, elapsed_us). `target` is the
|
|
30
33
|
endpoint.FakeTarget (mem = word address -> value, regs = regno -> value, halted, dpc), so a
|
|
@@ -45,7 +48,7 @@ import sys
|
|
|
45
48
|
import time
|
|
46
49
|
import tty
|
|
47
50
|
|
|
48
|
-
from . import endpoint, fake, fake_serial, registry as reg
|
|
51
|
+
from . import catalog, endpoint, fake, fake_serial, registry as reg
|
|
49
52
|
|
|
50
53
|
_ITEM = reg.PROBE_CONFIG.tlv["item"]
|
|
51
54
|
_MODES = reg.PROBE_CONFIG.enum["bind_mode"]
|
|
@@ -82,11 +85,40 @@ def build(a: argparse.Namespace) -> endpoint.Endpoint:
|
|
|
82
85
|
for n in range(len(a.slot)))
|
|
83
86
|
value = struct.pack("<BBBB", a.port_index, _MODES[a.bind.replace("-", "_")], 0, len(a.slot)) + streams
|
|
84
87
|
items.append(bytes([_ITEM["bind"], len(value)]) + value)
|
|
88
|
+
if a.uart_plan:
|
|
89
|
+
fn = uart_fn(ep)
|
|
90
|
+
rx, tx = _uart_channels(ep, fn)
|
|
91
|
+
for role, ch in ((1, rx), (2, tx)):
|
|
92
|
+
items.append(bytes([_ITEM["plan"], 5]) + struct.pack("<HBH", fn, role, ch))
|
|
85
93
|
if items:
|
|
86
94
|
ep.load_config(items, saved=True)
|
|
87
95
|
return ep
|
|
88
96
|
|
|
89
97
|
|
|
98
|
+
def uart_fn(ep: endpoint.Endpoint) -> int:
|
|
99
|
+
fn = ep.fns.get("oep.fixture.uart")
|
|
100
|
+
if fn is None:
|
|
101
|
+
raise SystemExit("this profile offers no oep.fixture.uart")
|
|
102
|
+
return fn
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _uart_channels(ep: endpoint.Endpoint, fn: int) -> tuple[int, int]:
|
|
106
|
+
"""RX, TX for the UART's plan: the jig's DUT TX (probe RX) / DUT RX (probe TX) labels, else the first two free."""
|
|
107
|
+
labels = {name: ch for ch, name in ep.static_labels.items()}
|
|
108
|
+
if "DUT TX" in labels and "DUT RX" in labels:
|
|
109
|
+
return labels["DUT TX"], labels["DUT RX"]
|
|
110
|
+
allowed = []
|
|
111
|
+
for t in ep.static[fn]:
|
|
112
|
+
if t[0] == catalog.ROLE_CHANNELS and t[2] == 1:
|
|
113
|
+
base = struct.unpack_from("<H", t, 3)[0]
|
|
114
|
+
allowed = catalog.bitmap_to_channels(base, t[5:2 + t[1]])
|
|
115
|
+
taken = {p for s in ep.slots.values() for p in s.pair} | {a[2] for a in ep.plan}
|
|
116
|
+
free = [ch for ch in allowed if ch not in taken]
|
|
117
|
+
if len(free) < 2:
|
|
118
|
+
raise SystemExit("no two free channels for the UART's plan")
|
|
119
|
+
return free[0], free[1]
|
|
120
|
+
|
|
121
|
+
|
|
90
122
|
def _load_hook(spec: str):
|
|
91
123
|
where, _, name = spec.rpartition(":")
|
|
92
124
|
if not where or not name:
|
|
@@ -118,20 +150,28 @@ def _filter(a: argparse.Namespace):
|
|
|
118
150
|
return answer
|
|
119
151
|
|
|
120
152
|
|
|
153
|
+
def _text(fmt: str, count: int) -> bytes:
|
|
154
|
+
text = fmt.replace("%d", str(count)) if "%d" in fmt else fmt
|
|
155
|
+
return text.encode().decode("unicode_escape").encode("latin-1")
|
|
156
|
+
|
|
157
|
+
|
|
121
158
|
class Console:
|
|
122
|
-
|
|
123
|
-
|
|
159
|
+
"""Every `every_ms`: the targets write `fmt` to their consoles, and `uart_rx` arrives on the UART's RX (fn
|
|
160
|
+
`uart`) while it runs (configured)."""
|
|
161
|
+
|
|
162
|
+
def __init__(self, ep: endpoint.Endpoint, fmt: str | None, every_ms: int, uart_rx: str | None = None,
|
|
163
|
+
uart: int | None = None):
|
|
164
|
+
self.ep, self.fmt, self.every, self.uart_rx, self.uart = ep, fmt, every_ms, uart_rx, uart
|
|
124
165
|
self.next_ms, self.count = 0, 0
|
|
125
166
|
|
|
126
167
|
def tick(self) -> None:
|
|
127
|
-
if not self.fmt or self.ep.now() < self.next_ms:
|
|
168
|
+
if not (self.fmt or self.uart_rx) or self.ep.now() < self.next_ms:
|
|
128
169
|
return
|
|
129
170
|
self.next_ms = self.ep.now() + self.every
|
|
130
|
-
for i, tg in enumerate(self.ep.targets.values()):
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
self.ep.target_says(text.encode().decode("unicode_escape").encode("latin-1"), tg)
|
|
171
|
+
for i, tg in enumerate(self.ep.targets.values()) if self.fmt else ():
|
|
172
|
+
self.ep.target_says(_text(self.fmt.replace("{t}", str(i)), self.count), tg)
|
|
173
|
+
if self.uart_rx and self.uart in self.ep.uarts:
|
|
174
|
+
self.ep.uart_rx(self.uart, _text(self.uart_rx, self.count))
|
|
135
175
|
self.count += 1
|
|
136
176
|
|
|
137
177
|
|
|
@@ -257,7 +297,7 @@ def _serve_conn(a, ep, console, conn, watch_stdin) -> bool:
|
|
|
257
297
|
|
|
258
298
|
|
|
259
299
|
def main(argv: list[str] | None = None) -> None:
|
|
260
|
-
ap = argparse.ArgumentParser(prog="python -m oep_client.
|
|
300
|
+
ap = argparse.ArgumentParser(prog="python -m oep_client.fake_serve", description=__doc__.split("\n\n")[0])
|
|
261
301
|
where = ap.add_mutually_exclusive_group()
|
|
262
302
|
where.add_argument("--pty", action="store_true")
|
|
263
303
|
where.add_argument("--tcp", type=int, metavar="PORT")
|
|
@@ -273,6 +313,8 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
273
313
|
ap.add_argument("--bind", choices=["last-reset", "manual", "mixed"])
|
|
274
314
|
ap.add_argument("--target-id")
|
|
275
315
|
ap.add_argument("--absent", type=int, action="append", default=[])
|
|
316
|
+
ap.add_argument("--uart-plan", action="store_true")
|
|
317
|
+
ap.add_argument("--uart-rx")
|
|
276
318
|
ap.add_argument("--run-hook")
|
|
277
319
|
ap.add_argument("--once", action="store_true")
|
|
278
320
|
a = ap.parse_args(argv)
|
|
@@ -285,7 +327,7 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
285
327
|
probe_ep = endpoint.Endpoint(profile(), lambda: 0)
|
|
286
328
|
a.port_index = min(probe_ep.serial_ports) if probe_ep.serial_ports else 0
|
|
287
329
|
ep = build(a)
|
|
288
|
-
console = Console(ep, a.console, _ms(a.every))
|
|
330
|
+
console = Console(ep, a.console, _ms(a.every), a.uart_rx, uart_fn(ep) if a.uart_rx else None)
|
|
289
331
|
try:
|
|
290
332
|
if a.tcp is None:
|
|
291
333
|
serve_pty(a, ep, console)
|
oep_client_python-0.0.1/tests/test_v1_capture.py → oep_client_python-0.0.2/tests/test_capture.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""oep_client.
|
|
1
|
+
"""oep_client.capture: the configure answer and the §3.0 logic layout (oep-spec logic-capture.ja.md)."""
|
|
2
2
|
|
|
3
3
|
import struct
|
|
4
4
|
from fractions import Fraction
|
|
5
5
|
|
|
6
|
-
from oep_client
|
|
6
|
+
from oep_client import capture as c
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def answer(*items):
|
|
@@ -92,7 +92,7 @@ def test_stream_does_not_count_the_fns_events_as_lost():
|
|
|
92
92
|
|
|
93
93
|
def test_read_spans_frames_without_the_header_leaking_into_the_data():
|
|
94
94
|
"""read() splits a long read into frame-sized ones; each answer is position(u64) flags(u8) data."""
|
|
95
|
-
from
|
|
95
|
+
from test_target_parts import ScriptedHost, ok
|
|
96
96
|
stream = bytes(range(256)) * 12 # 3072 bytes: more than one 1024-byte frame
|
|
97
97
|
def read(p):
|
|
98
98
|
pos, n = struct.unpack("<QI", p[:12])
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import struct
|
|
4
4
|
|
|
5
|
-
from oep_client
|
|
6
|
-
from
|
|
5
|
+
from oep_client import decode, esp32_targets as et, message as m
|
|
6
|
+
from test_target_parts import ScriptedHost, ok
|
|
7
7
|
|
|
8
8
|
I2C, SPI = 11, 12
|
|
9
9
|
|
oep_client_python-0.0.1/tests/test_v1_fake_spec.py → oep_client_python-0.0.2/tests/test_fake_spec.py
RENAMED
|
@@ -11,7 +11,7 @@ import time
|
|
|
11
11
|
|
|
12
12
|
import pytest
|
|
13
13
|
|
|
14
|
-
from oep_client
|
|
14
|
+
from oep_client import cobs, endpoint, fake, fake_serial, message as m, registry as reg
|
|
15
15
|
|
|
16
16
|
CFG = reg.PROBE_CONFIG
|
|
17
17
|
ITEM, ATTACH, MODE, KIND = CFG.tlv["item"], CFG.enum["slot_attach"], CFG.enum["bind_mode"], CFG.enum["bind_stream"]
|
|
@@ -289,7 +289,7 @@ def test_last_reset_follows_the_target_the_host_reset():
|
|
|
289
289
|
|
|
290
290
|
@pytest.mark.skipif(sys.platform != "linux", reason="pty and TIOCEXCL as on Linux")
|
|
291
291
|
def test_fake_serve_pty_speaks_cobs_with_console_bytes_and_honours_tiocexcl():
|
|
292
|
-
proc = subprocess.Popen([sys.executable, "-m", "oep_client.
|
|
292
|
+
proc = subprocess.Popen([sys.executable, "-m", "oep_client.fake_serve", "--pty", "--profile", "p4-bench",
|
|
293
293
|
"--slot", "x035", "--bind", "last-reset", "--console", "tick %d\\n", "--every", "20"],
|
|
294
294
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
|
295
295
|
try:
|
|
@@ -320,11 +320,12 @@ def test_fake_serve_pty_speaks_cobs_with_console_bytes_and_honours_tiocexcl():
|
|
|
320
320
|
|
|
321
321
|
|
|
322
322
|
def test_fake_serve_run_hook_from_a_file(tmp_path):
|
|
323
|
-
from oep_client
|
|
323
|
+
from oep_client import fake_serve
|
|
324
324
|
hook = tmp_path / "loader.py"
|
|
325
325
|
hook.write_text("def run(target, pc, regs):\n target.mem[0x100] = regs.get(0x100A, 0)\n return True, pc + 4, 7\n")
|
|
326
326
|
a = fake_serve.main.__globals__["argparse"].Namespace(
|
|
327
|
-
profile="p4-x035", target_id=None, absent=[], slot=[], bind=None, port_index=0, run_hook=f"{hook}:run"
|
|
327
|
+
profile="p4-x035", target_id=None, absent=[], slot=[], bind=None, port_index=0, run_hook=f"{hook}:run",
|
|
328
|
+
uart_plan=False)
|
|
328
329
|
ep = fake_serve.build(a)
|
|
329
330
|
assert ep.target.run_hook(0x2000, {0x100A: 5}) == (True, 0x2004, 7) and ep.target.mem[0x100] == 5
|
|
330
331
|
|
|
@@ -344,3 +345,28 @@ def test_a_closed_console_stays_readable_until_the_same_place_opens_again():
|
|
|
344
345
|
a2 = attach(p[0])
|
|
345
346
|
h.ok(3, 0x01, struct.pack("<HB", a2, 2)) # the same place again: the old one goes
|
|
346
347
|
assert h.raw(3, 0x02, struct.pack("<HBQH", sa, 1, 0, 16), session=False).detail == m.UNAVAILABLE
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def test_fake_serve_uart_plan_and_rx():
|
|
351
|
+
import time
|
|
352
|
+
from oep_client import fixture, link
|
|
353
|
+
proc = subprocess.Popen([sys.executable, "-m", "oep_client.fake_serve", "--tcp", "0", "--framing", "length",
|
|
354
|
+
"--profile", "esp32-v003", "--uart-plan", "--uart-rx", "rx %d\\n", "--every", "10"],
|
|
355
|
+
stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
|
356
|
+
try:
|
|
357
|
+
port = proc.stdout.readline().split()[1]
|
|
358
|
+
hst = link.open_host(f"tcp://127.0.0.1:{port}", timeout=1.0)
|
|
359
|
+
hst.open(3000)
|
|
360
|
+
uart = fixture.FixtureUartIO(hst)
|
|
361
|
+
assert uart.configure(115200) > 0 # the saved plan: configure works
|
|
362
|
+
assert uart.configure(9600) > 0 # and again, while it runs
|
|
363
|
+
got, deadline = b"", time.monotonic() + 2
|
|
364
|
+
while b"\n" not in got and time.monotonic() < deadline:
|
|
365
|
+
got += uart.read()
|
|
366
|
+
assert got.startswith(b"rx ") # the RX side, from the configure on
|
|
367
|
+
uart.write(b"to the DUT") # out on TX
|
|
368
|
+
hst.end()
|
|
369
|
+
hst.link.close()
|
|
370
|
+
finally:
|
|
371
|
+
proc.stdin.close()
|
|
372
|
+
proc.wait(timeout=5)
|
|
@@ -6,8 +6,8 @@ import struct
|
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
|
|
9
|
-
from oep_client
|
|
10
|
-
from
|
|
9
|
+
from oep_client import ch32_flash as cf, console, fixture, host as h, message as m, riscv, uiapduino
|
|
10
|
+
from test_target_parts import FNS, ScriptedHost, ok
|
|
11
11
|
|
|
12
12
|
WIRE, DM, GPIO = FNS["oep.wire.rvswd"], FNS["oep.target.riscv-dm"], FNS["oep.fixture.gpio"]
|
|
13
13
|
CONSOLE, UART = 6, 7
|
|
@@ -7,7 +7,7 @@ import struct
|
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from oep_client
|
|
10
|
+
from oep_client import capture, console, core, endpoint, fake, fixture, host, message as m, riscv
|
|
11
11
|
|
|
12
12
|
WIRE, DM, CONSOLE, GPIO, UART = 1, 2, 3, 4, 5 # p4_x035
|
|
13
13
|
|
|
@@ -259,7 +259,7 @@ def test_uart_configure_format_and_reads_that_do_not_consume(bench):
|
|
|
259
259
|
|
|
260
260
|
|
|
261
261
|
def test_capture_critical_tag_it_cannot_honour_is_unsupported():
|
|
262
|
-
from
|
|
262
|
+
from test_target_parts import ScriptedHost
|
|
263
263
|
|
|
264
264
|
def configure(p):
|
|
265
265
|
for tag, _ in m.split_tlvs(p):
|
|
@@ -351,7 +351,7 @@ def test_a_plan_replaces_only_the_fns_it_names_and_release_takes_a_list(bench):
|
|
|
351
351
|
|
|
352
352
|
|
|
353
353
|
def test_ch32_resume_asks_again_while_dpc_has_not_moved(dm):
|
|
354
|
-
from oep_client
|
|
354
|
+
from oep_client import ch32_flash
|
|
355
355
|
ep, hst, d = dm
|
|
356
356
|
assert d.read_register(d.DPC) == ep.target.dpc
|
|
357
357
|
ep.target.resume_misses = 2 # two requests that do not take, then it goes
|
|
@@ -9,7 +9,7 @@ import sys
|
|
|
9
9
|
|
|
10
10
|
import pytest
|
|
11
11
|
|
|
12
|
-
from oep_client
|
|
12
|
+
from oep_client import capture, cobs, core, host as h, link, message as m
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class Scripted:
|
|
@@ -67,7 +67,7 @@ def test_a_missing_answer_goes_once_more_with_the_same_corr():
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
def serve(*args):
|
|
70
|
-
proc = subprocess.Popen([sys.executable, "-m", "oep_client.
|
|
70
|
+
proc = subprocess.Popen([sys.executable, "-m", "oep_client.fake_serve", *args],
|
|
71
71
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
|
|
72
72
|
return proc, proc.stdout.readline().split()
|
|
73
73
|
|
oep_client_python-0.0.1/tests/test_v1_session.py → oep_client_python-0.0.2/tests/test_session.py
RENAMED
|
@@ -4,7 +4,7 @@ import struct
|
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
-
from oep_client
|
|
7
|
+
from oep_client import endpoint, fake, host, message as m
|
|
8
8
|
|
|
9
9
|
TOY = 7 # a fn the fake does not simulate (esp32_v003: the i2c-target) has the stand-in operations
|
|
10
10
|
|
|
@@ -53,7 +53,7 @@ def test_a_48_byte_name_fits_a_64_byte_frame():
|
|
|
53
53
|
assert len(name) == 48
|
|
54
54
|
probe = fake.FakeProbe("tiny", 64, [fake.Offered(0, 0, "oep.core"), fake.Offered(1, 1, name)])
|
|
55
55
|
ep = endpoint.Endpoint(probe, Clock())
|
|
56
|
-
from oep_client
|
|
56
|
+
from oep_client import catalog
|
|
57
57
|
result = ep.handle(m.Request(1, 0, m.OP_LIST, catalog.pack_list_request(name, True, 0)).pack())
|
|
58
58
|
assert len(result) == 63 and catalog.unpack_list_result(result[5:])[1][0].name == name # oep-v1 frame budget (v1-core-wire-delta §6)
|
|
59
59
|
|
|
@@ -228,7 +228,7 @@ def test_the_host_skips_tlvs_it_does_not_know_after_every_result(bench):
|
|
|
228
228
|
assert opened.lease_ms == 1000 and not opened.resumed
|
|
229
229
|
write(a, 9)
|
|
230
230
|
assert read(a) == 9 and a.lock_state() == (True, 1000)
|
|
231
|
-
from oep_client
|
|
231
|
+
from oep_client import riscv
|
|
232
232
|
wire = riscv.Wire(a, "oep.wire.swio")
|
|
233
233
|
conn, _ = wire.attach()
|
|
234
234
|
riscv.RiscvDm(a, conn).halt()
|
|
@@ -5,7 +5,7 @@ import struct
|
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
|
-
from oep_client
|
|
8
|
+
from oep_client import arm, host as h, message as m, target
|
|
9
9
|
|
|
10
10
|
FNS = {"oep.wire.rvswd": 1, "oep.target.riscv-dm": 2, "oep.fixture.gpio": 3, "oep.wire.swd": 4,
|
|
11
11
|
"oep.target.arm-adi": 5}
|
|
@@ -302,7 +302,7 @@ def test_cortexm_call_returns_r0_and_clears_maskints():
|
|
|
302
302
|
|
|
303
303
|
|
|
304
304
|
def test_rp2350_flash_program_runs_the_sdk_sequence_and_verifies():
|
|
305
|
-
from oep_client
|
|
305
|
+
from oep_client import rp2350
|
|
306
306
|
fake = FakeCortexM()
|
|
307
307
|
core = arm.CortexM(fake, bkpt_at=rp2350.BKPT_AT, stack_top=rp2350.STACK_TOP)
|
|
308
308
|
core.halt()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""Draft: capability discovery by name (oep-spec capability-*.ja.md). No hardware yet."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/capture.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/catalog.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/ch32_flash.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/cobs.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/console.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/core.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/decode.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/dump.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/endpoint.py
RENAMED
|
File without changes
|
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fake_serial.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/fixture.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/frames.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/hid_stream.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/host.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/interfaces.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/link.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/message.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/names.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/registry.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/riscv.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/rp2350.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/target.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/uiapduino.py
RENAMED
|
File without changes
|
{oep_client_python-0.0.1/src/oep_client/v1 → oep_client_python-0.0.2/src/oep_client}/usb_stream.py
RENAMED
|
File without changes
|