oep-client-python 0.0.26__tar.gz → 0.0.28__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.26 → oep_client_python-0.0.28}/CHANGELOG.md +44 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/PKG-INFO +97 -25
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/README.ja.md +91 -20
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/README.md +96 -24
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/pyproject.toml +4 -1
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/__init__.py +1 -1
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/__main__.py +134 -10
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/arm.py +7 -6
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/ch32_flash.py +6 -7
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/cobs.py +5 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/config.py +57 -1
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/endpoint.py +355 -33
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/fake.py +55 -14
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/fixture.py +54 -5
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/link.py +508 -226
- oep_client_python-0.0.28/src/oep_client/linktest.py +184 -0
- oep_client_python-0.0.28/src/oep_client/pins.py +614 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/registry.py +5 -5
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/riscv.py +77 -10
- oep_client_python-0.0.28/src/oep_client/speed_record.py +104 -0
- oep_client_python-0.0.28/src/oep_client/targets.py +97 -0
- oep_client_python-0.0.28/tests/hw/README.ja.md +105 -0
- oep_client_python-0.0.28/tests/hw/README.md +107 -0
- oep_client_python-0.0.28/tests/hw/__init__.py +2 -0
- oep_client_python-0.0.28/tests/hw/boards.py +132 -0
- oep_client_python-0.0.28/tests/hw/conftest.py +91 -0
- oep_client_python-0.0.28/tests/hw/firmware.py +182 -0
- oep_client_python-0.0.28/tests/hw/flash.py +360 -0
- oep_client_python-0.0.28/tests/hw/record.py +293 -0
- oep_client_python-0.0.28/tests/hw/results/.gitignore +5 -0
- oep_client_python-0.0.28/tests/hw/results/9489dd2ae0953650-0.0.26+5bafb92-0.0.26.json +203 -0
- oep_client_python-0.0.28/tests/hw/results/9489dd2ae0953650-0.0.26+654b06a-0.0.26.json +203 -0
- oep_client_python-0.0.28/tests/hw/results/9489dd2ae0953650-0.0.27+ec1df99-0.0.27.json +337 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-d0wd-v3-0070070d9394-0.0.26+4fad559-0.0.26.json +526 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-d0wd-v3-0070070d9394-0.0.26+5bafb92-0.0.26.json +558 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.25-0.0.26.json +533 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.26+5bafb92-0.0.26.json +529 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.26+654b06a-0.0.26.json +529 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.26+e877631-0.0.26.json +528 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.27+ac80e07-0.0.27.json +1006 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.27+ec1df99-0.0.27.json +1009 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-0.0.27-0.0.27.json +1010 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-pico-d4-50029191fe34-unknown-0.0.26.json +99 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-series-30eda0e31108-0.0.26+5bafb92-0.0.26.json +256 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-series-30eda0e31108-0.0.26+654b06a-0.0.26.json +256 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-series-30eda0e343c6-0.0.26+5bafb92-0.0.26.json +224 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-series-30eda0e343c6-0.0.26+654b06a-0.0.26.json +224 -0
- oep_client_python-0.0.28/tests/hw/results/esp32-series-30eda0e343c6-0.0.27+ec1df99-0.0.27.json +492 -0
- oep_client_python-0.0.28/tests/hw/test_probe.py +923 -0
- oep_client_python-0.0.28/tests/test_config_idle.py +164 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_fake_spec.py +36 -5
- oep_client_python-0.0.28/tests/test_fake_targets.py +350 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_interfaces.py +1 -0
- oep_client_python-0.0.28/tests/test_linktest.py +55 -0
- oep_client_python-0.0.28/tests/test_pins.py +188 -0
- oep_client_python-0.0.28/tests/test_port_speed.py +724 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_session.py +7 -7
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_target_parts.py +101 -6
- oep_client_python-0.0.26/tests/test_port_speed.py +0 -490
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/.gitignore +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/LICENSE +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/capture.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/catalog.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/console.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/core.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/decode.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/dump.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/fake_capture.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/fake_serial.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/fake_serve.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/frames.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/hid_stream.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/host.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/interfaces.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/message.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/names.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/rp2350.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/uiapduino.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/src/oep_client/usb_stream.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_capabilities.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_capture.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_cobs.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_config.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_config_disable.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_fake_capture.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_fixture_targets.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_flash_console.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_hid_stream.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_link_host.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_link_serial.py +0 -0
- {oep_client_python-0.0.26 → oep_client_python-0.0.28}/tests/test_usb_stream.py +0 -0
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.0.28
|
|
6
|
+
- (EN) `oep pins` suggests the lines it found as probe.config labels (`<slot>.nrst`, `<slot>.power_hi`, host-development-guide §8.1) and an output idle for the power channel, instead of a slot reset_channel (not adopted: oep-spec v1-open-proposals §10); `--save` writes the slot and the labels.
|
|
7
|
+
- (JA) `oep pins` は見つけた線を probe.config の label(`<slot>.nrst`、`<slot>.power_hi`、host 開発ガイド §8.1)と、電源の channel の出力の idle として案内する(スロットの reset_channel は採らなかった: oep-spec v1-open-proposals §10)。`--save` はスロットと label を書く。
|
|
8
|
+
- (EN) Idle modes 3 / 4 (oep-spec 5013ffb / 7b3c319; registry synced, hash 050ffee525722713: idle_mode `output_low` 3, `output_high` 4). `config.Idle` takes `output-low` / `output-high` (`output_low` / `output_high` too, normalised to the hyphen form like `pull-up`), and `oep config idle <probe> <ch> output-high` offers them. `config.find_line(hst_or_items, name, slot=None)` finds a target's labelled line (`nrst`, `power_hi`, `power_lo`, `config.LINE_NAMES`; host-development-guide §8.1): `<slot>.<name>` first, then the bare name only while the settings hold at most one slot; with several slots and no slot given, or one label on two channels, it raises `config.AmbiguousLine` listing the candidates; None when there is none. The fake: an output idle drives its level while the channel is free, refused unsupported on `Endpoint.input_only` channels; every release (plan_release, a channel leaving a replaced plan - it used to keep the old channels' gpio modes - the lease lapse, force) goes to the idle state, and a gpio channel in both the old and the new plan keeps its state and drive; a gpio line a plan takes keeps that state until its first set (a read sees the idle level); at boot the idle states are applied before the plans and the at-boot attach (they came after the attach).
|
|
9
|
+
- (JA) idle の mode 3 / 4(oep-spec 5013ffb / 7b3c319。registry を写し直した、hash 050ffee525722713: idle_mode の `output_low` 3、`output_high` 4)。`config.Idle` が `output-low` / `output-high` を受ける(`output_low` / `output_high` も。`pull-up` と同じくハイフンの形にそろえる)。`oep config idle <probe> <ch> output-high` でも選べる。`config.find_line(hst_or_items, name, slot=None)` は target の label の付いた線(`nrst`、`power_hi`、`power_lo`、`config.LINE_NAMES`。host-development-guide §8.1)を探す: `<スロット>.<名前>` を先に、無ければ名前だけ(設定のスロットが 1 つ以下のときだけ)。スロットが 2 つ以上で slot を渡さないときと、1 つの label が 2 つの channel にあるときは、候補を並べた `config.AmbiguousLine` を上げる。無ければ None。fake: 出力の idle は channel が空いている間その level で駆動し、`Endpoint.input_only` の channel では unsupported で断る。解放はどの道でも(plan_release、置き換えた plan から外れる channel - これまでは古い channel の gpio の mode が残っていた - lease の失効、force)空きの状態に戻り、古い plan にも新しい plan にもある gpio の channel は状態と駆動を保つ。plan が取った gpio の線は最初の set までその状態を保つ(read は idle の level を見る)。起動では idle を plan と at boot の attach より先に掛ける(これまでは attach の後だった)。
|
|
10
|
+
- (EN) `oep pins <probe> [--power CH] [--exclude CH,...] [--wire swio|rvswd|swd] [--steps ...] [--save] [--json]` (module `pins`, `PinFinder`): finds where a target is wired on a probe whose pins the host chooses. Steps: classify every gpio channel from 16 reads under pull-up, both pulls, then pull-down (floating / pulled-up / driven-high / driven-low / active; with `--power` the target is read switched off first and the channels that read otherwise "follow power"); hold each floating / pulled-up channel low (open drain) while an active channel is watched (the watch lasts 3 x the longest lull of the running activity, 0.3-1 s); scan the wire over the floating / pulled-up channels only (rvswd / swd: pairs, at most 600); attach (halt), name the family by target_id and read a CH32V00x's option bytes (NRST on or off; read only); confirm the reset line by attach under reset (dpc = reset vector); print a suggested slot (`reset_channel` as a comment while `config.Slot` has none) and write it only with `--save`. Driven / active channels are never driven, scanned or held, the power channel is touched only with `--power`, every plan is released at the end, the run stays under 60 s. A new gpio plan lets every pin of the old one go first (the power channel too), so with `--power` each new plan is followed by a clean power cycle. On the ESP32-P4 with a CH32V003 (power GPIO5): SWIO 19 and NRST 4 found untold in 7-8 s, 6 runs of 6; the idle-high UART (22 / 23) is classified driven and left alone, the app's output 21 active.
|
|
11
|
+
- (JA) `oep pins <probe> [--power CH] [--exclude CH,...] [--wire swio|rvswd|swd] [--steps ...] [--save] [--json]`(モジュール `pins`、`PinFinder`): ピンを host が選ぶ probe で、target がどこにつながっているかを探す。段: gpio のすべての channel を pull-up、両方の pull、pull-down の順に 16 回ずつ読んで分ける(floating / pulled-up / driven-high / driven-low / active。`--power` では先に target の電源を切って読み、違って読めた channel を「電源に従う」とする)。floating / pulled-up の channel を 1 本ずつオープンドレインで low に保ち、active の channel を見る(見る長さは走っている時の最長の静かな間の 3 倍、0.3〜1 秒)。floating / pulled-up の channel だけで線を scan する(rvswd / swd は組で 600 組まで)。attach(halt)して target_id で系統を見て、CH32V00x なら option bytes で NRST の有無を読む(読むだけ)。リセットをかけながらの attach(dpc = リセットのベクタ)でリセットの線を確かめる。スロットの行を勧め(`config.Slot` に無い間 `reset_channel` はコメント)、`--save` のときだけ書く。driven / active の channel は駆動も scan も保持もしない、電源の channel は `--power` のときだけ触る、最後に plan をすべて解く、全体は 60 秒以内。gpio の plan を新しくすると前の plan のピンが(電源の channel も)いったん離れるので、`--power` では新しい plan のたびにきれいに電源を入れ直す。ESP32-P4 と CH32V003(電源 GPIO5)で、SWIO 19 と NRST 4 を指定なしで 7〜8 秒で見つけた(6 回中 6 回)。idle-high の UART(22 / 23)は driven として触らず、アプリの出力 21 は active。
|
|
12
|
+
- (EN) `targets`: what the host knows per target family in one table, `FAMILIES` (wire, target_id match on the WCH DMI 0x7F value, reset vector, an option-byte NRST reader, max_speed / idle_clock, notes): ch32v00x (swio, ids 0x002-0x007 in the top 12 bits, `v00x_nrst`: 0x1FFFF800 word0 USER bits[4:3] = RST_MODE, 11 = PD7 is a GPIO), ch32x035 (rvswd, 0x035, idle_clock high), ch32l103 (rvswd, 1 MHz, idle_clock low; id not recorded), ch32v203 (idle_clock low; id not recorded). `identify(target_id)`, `by_name()`, `describe_id()`. oep-spec docs/target-scan-notes.ja.md records the sources.
|
|
13
|
+
- (JA) `targets`: host が target の系統ごとに知っていることを 1 つの表 `FAMILIES` に(線、WCH DMI 0x7F の値での target_id の照合、リセットのベクタ、NRST を option で読む関数、max_speed / idle_clock、注): ch32v00x(swio、上位 12 ビットが 0x002〜0x007、`v00x_nrst`: 0x1FFFF800 の word0 の USER bits[4:3] = RST_MODE、11 = PD7 は GPIO)、ch32x035(rvswd、0x035、idle_clock high)、ch32l103(rvswd、1 MHz、idle_clock low。id は未記録)、ch32v203(idle_clock low。id は未記録)。`identify(target_id)`、`by_name()`、`describe_id()`。出典は oep-spec の docs/target-scan-notes.ja.md。
|
|
14
|
+
- (EN) `riscv.Wire.find_reset_line(..., pins=None)`: it returned [] on the ESP32-P4 with the CH32V003's real NRST among the candidates. Root cause: it attached without pins; on a wire whose pins the host chooses (role_channels) such an attach only joins the wire's one live connection, and the first try's detach closed that connection, so every later attach was rejected unavailable - and a rejection was taken for "not a reset line" and skipped. Now `pins` is passed to every attach (None: the pins of the wire's one live connection), a connection that was there before the search is left open, only unsupported or an unavailable naming the channel skips it, any other rejection is raised. On the P4: [4] over 48 candidates with tries=3 in 4.2 s, with and without a plain attach first. Hold time is not the cause: an attach under reset through 4 stopped at dpc 0 with 1, 2, 5, 10 and 20 ms holds, 3 of 3 each (RST_MODE 10, the 12 ms window).
|
|
15
|
+
- (JA) `riscv.Wire.find_reset_line(..., pins=None)`: ESP32-P4 と CH32V003 で、本物の NRST が候補にあるのに [] を返した。原因: pins を付けずに attach していた。ピンを host が選ぶ線(role_channels)では、pins の無い attach はその線の唯一の生きた接続に加わるだけで、1 回目の試しの detach がその接続を閉じた後は、どの attach も unavailable で断られ、断りを「リセットの線ではない」と読んで飛ばしていた。今は毎回の attach に `pins` を付け(None ならその線の唯一の生きた接続のピン)、探す前からあった接続は閉じない。飛ばすのは unsupported と、その channel を名指しした unavailable だけで、ほかの断りは例外にする。P4 で 48 候補、tries=3 で [4](4.2 秒)。先に普通の attach をしてあってもなくても同じ。保持時間は原因ではない: 4 でリセットをかけながらの attach は 1、2、5、10、20 ms の保持でどれも 3 回中 3 回 dpc 0(RST_MODE 10、12 ms の窓)。
|
|
16
|
+
- (EN) The fake: `Endpoint.gpio_world(channel, mode)` (a test hook: the level an input-mode read sees, from the lines outside) and `FakeTarget.reset_line` (an attach under reset through any other channel halts where the hart ran, off the vector). `tests/test_pins.py` runs `oep pins` against a P4-shaped profile with a V003-like world.
|
|
17
|
+
- (JA) fake: `Endpoint.gpio_world(channel, mode)`(試験の hook: 入力の mode の読みが見る外の線のレベル)と `FakeTarget.reset_line`(ほかの channel でリセットをかけながら attach すると、hart は走っていた所で止まり、ベクタに来ない)。`tests/test_pins.py` が P4 の形の profile と V003 らしい外の線で `oep pins` を動かす。
|
|
18
|
+
- (EN) Registry synced to oep-spec 75ca9ee (hash 3861100e11fb3b22): oep.fixture.i2c-target describe `max_stretch_us` (0x41, u32). The fake follows fixture §3 / §4 as 75ca9ee closed them: an i2c-target / spi-target plan holds each role exactly once on distinct channels (a missing role, a role twice or two roles on one channel -> malformed, before held_by_settings); the mode-1 wait survives a frame (armed stays 1 until the next arm_rx / reset / configure / plan release); an address-only write counts nothing in any mode; read_rx in state 0 is unavailable cause 6 on both targets; a 0-bit SPI transfer (`spi_transfer(..., bits=0)`, or empty MOSI) counts nothing and the arm keeps waiting, and the queued data is bits / 8 rounded up, capped at length. `p4-x035` declares max_stretch_us 100000 and stretch refuses more as unsupported (the fixed `endpoint.STRETCH_MAX_US` is gone); `esp32-v003` (no features bit1) declares none. `fixture.I2cTarget` gains `max_length`, `max_clock_hz`, `features`, `queue_depth` and `max_stretch_us` (None when not declared; features 0), `fixture.SpiTarget` the same but max_stretch_us, read once from describe. `tests/hw` i2c_target records `declared.max_stretch_us`.
|
|
19
|
+
- (JA) registry を oep-spec 75ca9ee に合わせた(hash 3861100e11fb3b22): oep.fixture.i2c-target の describe に `max_stretch_us`(0x41、u32)。fake を 75ca9ee で埋まった fixture §3 / §4 に合わせた: i2c-target / spi-target の plan は各 role をちょうど 1 つずつ別々の channel で持つ(role が欠ける、2 つある、2 つの role が同じ channel は malformed。held_by_settings より先)。mode 1 の待ちはフレームを受けても終わらない(次の arm_rx / reset / configure / plan を解くまで armed は 1)。アドレスだけの書き込みはどの mode でも何も数えない。state 0 の read_rx は両 target で unavailable cause 6。0 ビットの SPI 転送(`spi_transfer(..., bits=0)`、または MOSI が空)は何も数えず arm は待ち続ける。積む data は bits / 8 の切り上げで length で止める。`p4-x035` は max_stretch_us 100000 を宣言し、それを超える stretch は unsupported(固定の `endpoint.STRETCH_MAX_US` は無くした)。`esp32-v003`(features bit1 なし)は宣言しない。`fixture.I2cTarget` に `max_length`、`max_clock_hz`、`features`、`queue_depth`、`max_stretch_us`(宣言が無ければ None、features は 0)、`fixture.SpiTarget` に max_stretch_us 以外の同じものを足した(describe から 1 回読む)。`tests/hw` の i2c_target は `declared.max_stretch_us` を記録する。
|
|
20
|
+
- (EN) `tests/hw` spi_target: with no controller wired, an arm must stay armed (0 transactions, 0 errors) and a second arm is refused unavailable, as fixture §4 says. The check was loosened for phantom CS-edge transactions the probe counted; oep-probe-arduino a3dcabd stopped counting a CS edge without SCK. ATOM with the probe at ac80e07: 12 passed.
|
|
21
|
+
- (JA) `tests/hw` の spi_target: コントローラーをつないでいないとき、arm は armed のまま(transactions 0、errors 0)で、2 回目の arm は unavailable で断られること(fixture §4 のとおり)。probe が CS の縁だけで数えていた幻の転送のために緩めていた確かめを元に戻した(oep-probe-arduino a3dcabd で SCK の無い CS の縁を数えなくなった)。probe ac80e07 の ATOM で 12 passed。
|
|
22
|
+
- (EN) The fake probe runs `oep.fixture.i2c-target` and `oep.fixture.spi-target` (oep-spec oep-if-fixture §3 / §4); it only declared them before, so `tests/hw` `i2c_target` / `spi_target` failed on `fake-esp32-v003` and now pass. The plan takes SDA / SCL and SCK / MOSI / MISO / CS with the gpio / uart checks, plus role_channels per role and an exact channel_group (core §7.4); configure / arm_rx / arm / preload_tx / read_rx (TLV ns) / status (lock-free) / reset / stretch (features bit1 only, else unknown_operation) with the refusals in core §4.3's order; a plan change puts the target back to state 0. Declared: `p4-x035` i2c max_length 128, max_clock_hz 1 MHz, features 0b11, queue_depth 8; spi max_length 64, 3 MHz, features 0b1 (LSB first), queue_depth 8. `esp32-v003` i2c 16, 100 kHz, features 0b01, queue_depth 4; spi (two channel_groups) 32, 3 MHz, features 0, queue_depth 4. No bus controller: test hooks `Endpoint.i2c_write` / `i2c_read` / `spi_transfer` run one transaction (queued, consumed, overflow, not armed - transactions and errors counted). `fake.with_stand_in(probe)` adds the fn with the stand-in operations the session tests used the esp32-v003 i2c-target for.
|
|
23
|
+
- (JA) 偽の probe が `oep.fixture.i2c-target` と `oep.fixture.spi-target`(oep-spec oep-if-fixture §3 / §4)を動かす。これまでは宣言だけで、`fake-esp32-v003` の `tests/hw` の `i2c_target` / `spi_target` は落ちていた。今は通る。plan は SDA / SCL と SCK / MOSI / MISO / CS を、gpio / uart と同じ確かめに、role ごとの role_channels と channel_group の完全一致(core §7.4)を足して受ける。configure / arm_rx / arm / preload_tx / read_rx(TLV ns)/ status(ロック不要)/ reset / stretch(features bit1 のときだけ。ほかは unknown_operation)。断りは core §4.3 の順。plan が変わると target は state 0 に戻る。宣言: `p4-x035` の i2c は max_length 128、max_clock_hz 1 MHz、features 0b11、queue_depth 8。spi は 64、3 MHz、features 0b1(LSB 先)、queue_depth 8。`esp32-v003` の i2c は 16、100 kHz、features 0b01、queue_depth 4。spi(channel_group 2 つ)は 32、3 MHz、features 0、queue_depth 4。バスの controller は無い: 試験の hook `Endpoint.i2c_write` / `i2c_read` / `spi_transfer` が 1 回のトランザクションを起こす(積む、取り出す、あふれ、未 arm。transactions と errors を数える)。セッションの試験が esp32-v003 の i2c-target を代わりに使っていた仮の操作の fn は `fake.with_stand_in(probe)` が足す。
|
|
24
|
+
- (EN) `tests/hw` covers the interfaces it did not yet, each skipping when the probe does not list it, after `uart` and before `port_speed`: `capture` (oep.fixture.logic: a one-shot at the lowest declared rate over 10 ms on the two free channels, pulled up then down through fixture gpio planned on the same pins - all ones, then all zeros; sample count, timing within the declared uncertainty, generation +1 per start), `capture_analog` (one-shot on a free ADC channel, widest frontend; the pull bands are judged only when the probe lets gpio share the pin), `capture_group` (logic + analog bound and started together, both read back, the tracks' offsets from the group's start_ns), `i2c_target` / `spi_target` (configure, status, a preloaded queue / an armed transaction, reset, release - no bus controller, so floating-line glitches are recorded, not judged), `console` (with `OEP_HW_TARGET`: open with mechanism dmseq on the wire connection, read 1 s, close). `OEP_HW_ANALOG`, `OEP_HW_I2C`, `OEP_HW_SPI` name channels. ATOM, firmware 0.0.27: logic 400 kHz w 8, 4000 / 4000 ones then 0 / 4000 on both pins, done 24 ms after start for a 10 ms window, 4 KB read in 0.38 s; analog 20 kHz s 16 b 12, the floating pin at 2.8 / 4095; the group's tracks start 25 µs (logic) and 516 µs (analog) after the group; the analog refuses to share its pin with gpio (unavailable, as oep-if-capture §1.2 allows) and an idle pull-up on it reads only 137 mV mean once the ADC owns the pad; the SPI target counts 1-2 phantom transactions on its floating SCK / CS right after an arm.
|
|
25
|
+
- (JA) `tests/hw` に、まだ無かった interface の試験を足した(probe が list に出さなければ skip。`uart` の後、`port_speed` の前): `capture`(oep.fixture.logic: 空き 2 チャネルで、同じピンに plan した fixture gpio で pull-up → pull-down し、宣言の最低のレートで 10 ms のワンショット。全部 1、次に全部 0。サンプル数、宣言の不確かさの内の時間、start ごとに世代 +1)、`capture_analog`(空きの ADC チャネルでいちばん広い frontend のワンショット。pull の帯は probe が gpio とピンを共有させるときだけ判定)、`capture_group`(ロジックとアナログを bind して一緒に start、両方読み出し、組の start_ns からの各トラックのずれ)、`i2c_target` / `spi_target`(configure、status、preload の列 / arm した転送、reset、release。バスに controller は無いので浮いた線のグリッチは記録して判定しない)、`console`(`OEP_HW_TARGET` のとき: 線の connection に mechanism dmseq で open、1 秒読む、close)。`OEP_HW_ANALOG`、`OEP_HW_I2C`、`OEP_HW_SPI` でチャネルを指定できる。ATOM、firmware 0.0.27: ロジック 400 kHz w 8、両ピンとも 4000 / 4000 が 1、次に 0 / 4000、10 ms の窓に対し start の 24 ms 後に done、4 KB の読み出しに 0.38 秒。アナログ 20 kHz s 16 b 12、浮いたピンは 2.8 / 4095。組のトラックは組の 25 µs(ロジック)と 516 µs(アナログ)後に始まる。アナログは gpio とのピンの共有を断り(unavailable。oep-if-capture §1.2 が許す)、その上の idle の pull-up は ADC がパッドを持つと平均 137 mV しか読めない。SPI の target は arm の直後、浮いた SCK / CS で 1〜2 の幻の転送を数える。
|
|
26
|
+
- (EN) `tests/hw` port_speed: the run fails only when no candidate passes; a candidate that fails the guide's verdict is recorded (`passed_rates` / `failed_rates`). The ATOM's bridge puts 1500000 over the threshold in some runs (11-14 % on one flow against a 2-5 % baseline) while 500000 passes every time - a fact about that bridge, not about the probe or the client.
|
|
27
|
+
- (JA) `tests/hw` の port_speed: 通る候補が 1 つも無いときだけ落とす。ガイドの判定に落ちた候補は記録に残す(`passed_rates` / `failed_rates`)。ATOM の変換は 1500000 が回によって閾値を超え(基準 2〜5 % に対し 1 つの流し方で 11〜14 %)、500000 は毎回通る。probe や client ではなく変換の性質。
|
|
28
|
+
|
|
29
|
+
## 0.0.27
|
|
30
|
+
- (EN) `tests/hw` port_speed verdict follows the host guide §7.3.2: a one-at-a-time cell at a raised rate fails only when broken + lost ≥ 3 and its ratio is over max(2 × the boot-speed ratio of the same flow, 5 % `OEP_HW_ERROR_MAX`) - the absolute 1 % failed the CH340 jig on bursts the boot speed shows too. Results with the probe 5bafb92 (port_speed handshake per core §3.5, block length) on the ATOM, the V003 jig (SWIO) and the X035 jig (DFU, RVSWD): all pass.
|
|
31
|
+
- (JA) `tests/hw` の port_speed の判定を host 開発ガイド §7.3.2 に合わせた: 上げた速さの 1 つずつの条件で、broken + lost が 3 以上かつ割合が max(起動時の速さの同じ流し方の割合 × 2, 5 %(`OEP_HW_ERROR_MAX`)) を超えたときだけ落とす(絶対の 1 % は、起動時の速さにもある CH340 のまとまった落ちで治具を落としていた)。probe 5bafb92(core §3.5 の握手、block 長)での結果: ATOM、V003 治具(SWIO)、X035 治具(DFU、RVSWD)すべて pass。
|
|
32
|
+
- (EN) port_speed follows the host guide's reference procedure (oep-spec host-development-guide.ja.md §7; core §3.5 is the handshake). `raise_speed(hst, candidates=(500000,), *, flows=None, verify=None, baseline=None, frames=16, verify_ms=None, idle_ms=3000, port=None, record=False)` replaces the old `rates, verify_bytes, verify_s, duplex_s`. The minimal form (§7.2, the default; ~50 ms, no measurement): try -> switch to the requested baud -> settle 20 ms -> confirm (100 ms x3) -> commit. The full form (`verify=True`, or `flows` given; §7.3): a baseline at the boot speed per flow (this session's frames when 60+ and under 10 %, else 60 measured per flow, re-measured at n=1 when over 10 %), then per candidate every `flows` ("in"|"out"|"duplex", n; default all three at the most the link keeps) for `frames` (16) frames at max_frame-16, a flow failing on broken+lost >= 3 and a ratio over max(2x baseline, 5 %), re-run at n=1 (then n=1 is the link's cap), one failed flow failing the candidate. `SpeedTrial` now carries `actual`, `switched`, `flows` (`FlowResult`: flow, n, frames, broken, lost, kb_s, ratio, passed), `n_cap`, `in_kb_s`/`out_kb_s`/`duplex_kb_s`; `SpeedReport` adds `verified`, `baseline`, `baseline_flows`, `step_downs` (`StepDown`), `skipped`. In use: the frames of the last 3 s (none judged under 50) over max(2x baseline, 10 %) broken or lost step the link down (was 3 strikes in 5 s); a missed answer still falls back to the boot speed within port_speed_idle_max_ms + 1 s (a link error when no confirm comes, never back to the raised rate). The keepalive interval is set under half of idle_ms. `set_baud` switches to the requested baud and to the probe's answered baud only when the OS refuses it (obligation 6/2). `oep speed` keeps working and gains `--candidates`, `--flows`, `--verify`/`--minimal`, `--frames`, `--no-record`.
|
|
33
|
+
- (JA) port_speed を host 開発ガイドの参考手順に合わせた(oep-spec host-development-guide.ja.md §7。core §3.5 は握手だけ)。`raise_speed(hst, candidates=(500000,), *, flows=None, verify=None, baseline=None, frames=16, verify_ms=None, idle_ms=3000, port=None, record=False)` が旧 `rates, verify_bytes, verify_s, duplex_s` を置き換える。最小の形(§7.2、既定。約 50 ms、計測なし): 試す → 要求した baud に切り替え → 20 ms → confirm(100 ms×3)→ 決める。完全な形(`verify=True` か `flows` を渡す。§7.3): 起動時の速さの基準を流し方ごとに取り(このセッションの 60 フレーム以上かつ 10 % 未満、無ければ 60 フレーム。10 % 超は n=1 で測り直し)、候補ごとに `flows`(("in"|"out"|"duplex", n)。既定は link が出す最大で 3 つ)を `frames`(16)フレーム max_frame−16 で流し、壊れ+失われが 3 以上かつ割合が max(基準×2, 5 %) 超で流し方は通らず、n=1 で流し直し(通れば n=1 が上限)、1 つでも通らなければ候補は通らない。`SpeedTrial` は `actual`、`switched`、`flows`(`FlowResult`: flow, n, frames, broken, lost, kb_s, ratio, passed)、`n_cap`、`in_kb_s`/`out_kb_s`/`duplex_kb_s` を持つ。`SpeedReport` に `verified`、`baseline`、`baseline_flows`、`step_downs`(`StepDown`)、`skipped` を足した。使用中は直近 3 秒のフレーム(50 未満は判定しない)が max(基準×2, 10 %) 超で降りる(旧: 5 秒に 3 回)。応答が来ない要求は port_speed_idle_max_ms + 1 秒の内に起動時の速さへ戻る(confirm が通らなければリンクの失敗。上げた速さへは戻さない)。keepalive の間隔は idle_ms の半分未満にした。`set_baud` は要求した baud に切り替え、OS が断ったときだけ probe の応答の baud にする(義務 6/2)。`oep speed` は動いたまま `--candidates`、`--flows`、`--verify`/`--minimal`、`--frames`、`--no-record` を足した。
|
|
34
|
+
- (EN) port_speed record (host guide §7.4): `speed_record.SpeedRecord` keeps passed / failed rates per (port path, unit_id) in `~/.cache/oep-client/link-speed.json` (`$XDG_CACHE_HOME`), 30-day expiry; `raise_speed(record=True)` (a bool, a path, or a SpeedRecord) reorders candidates (passed first, failed skipped -> `report.skipped`) and writes this run's outcomes and step-downs. On by default for the `oep speed` CLI, off for the library (`open_host(..., record=)` passes it through). A file that cannot be read or written is a cache miss, not an error (`SpeedRecord.error`).
|
|
35
|
+
- (JA) port_speed の記録(host ガイド §7.4): `speed_record.SpeedRecord` は通った / 通らなかった速さを(口のパス、unit_id)ごとに `~/.cache/oep-client/link-speed.json`(`$XDG_CACHE_HOME`)に 30 日残す。`raise_speed(record=True)`(真偽値・パス・SpeedRecord)は候補を並べ替え(通った速さを先頭、通らなかった速さは外す → `report.skipped`)、この実行の結果と降りた事実を書く。`oep speed` CLI は既定で ON、ライブラリは OFF(`open_host(..., record=)` で渡す)。読めない / 書けないファイルはキャッシュミスで、エラーにしない(`SpeedRecord.error`)。
|
|
36
|
+
- (EN) riscv-dm / arm-adi `max_length` (bytes) and `max_words` from describe (oep-if-debug §4.5 / §6): `RiscvDm` and `ArmAdi` take their block size from the declared max_length only, never `(max_frame - 18) / 4` or the like - `ch32_flash._block_size` and `arm.MemAp.chunk` do too. A probe with block ops that declares no usable max_length raises `riscv.NoMaxLength` (the spec makes it mandatory there). The fake declares max_length = max_frame - 24 rounded to a word (so a read_block answer and a write_block request both fit): 40 at 64-byte frames (esp32-v003), 1000 at 1024 (the P4 / RP2350 profiles) - was a flat 1000 / 40. A block over max_length is now rejected unsupported with payload 0x00 (was malformed); an odd address stays malformed. A port_speed step above 2 is malformed (was unsupported), and a step that does not fit the port's state is unavailable cause 6.
|
|
37
|
+
- (JA) riscv-dm / arm-adi の `max_length`(byte)と `max_words` を describe から取る(oep-if-debug §4.5 / §6): `RiscvDm` と `ArmAdi` は block の長さを宣言された max_length だけから決め、`(max_frame - 18) / 4` などからは計算しない。`ch32_flash._block_size` と `arm.MemAp.chunk` も同じ。block op を持つのに使える max_length を宣言しない probe は `riscv.NoMaxLength`(spec で必須)。偽の probe は max_length = max_frame − 24 を語に丸めて宣言する(read_block の応答と write_block の要求がどちらも収まる): 64 byte フレーム(esp32-v003)で 40、1024(P4 / RP2350)で 1000 ― 旧は一律 1000 / 40。max_length を超える block は payload 0x00 の rejected unsupported(旧 malformed)、奇数番地は malformed のまま。port_speed の step が 2 より大きいと malformed(旧 unsupported)、口の状態に合わない step は unavailable cause 6。
|
|
38
|
+
- (EN) The committed probe's self-revert condition 4 is now 3 broken candidates in a row with no good frame between (was 3 within a 1 s window); condition 2 (trying) counts a broken candidate only after the first good frame at the new speed arrives (the switch-over's leftovers do not count); idle_ms (condition 3) is not counted while a request runs. The fake and its tests follow.
|
|
39
|
+
- (JA) 決めた probe の自己復帰の条件 4 を「正常を挟まず壊れた候補 3 つ連続」にした(旧: 1 秒の窓に 3 つ)。条件 2(試し)は新しい速さで最初の正常フレームが来た後の壊れた候補だけ数える(切り替えの直後の残りは数えない)。idle_ms(条件 3)は要求の実行中は数えない。偽の probe とそのテストも追随。
|
|
40
|
+
- (EN) `tests/hw` on the bench's jigs (2026-10-02, with the bench's leave): V003 jig (ESP32-D0WD + CH340, CH32V003 over SWIO) and X035 jig (ESP32-P4 over DFU, CH32X035 over RVSWD) - flash, identity, config, wire (50 halt / read_block / resume loops, registers unchanged), gpio, uart, session pass on both; the CH340's port_speed cells fail the 1 % verdict now and then (bursty probe->host loss at every rate, oep-spec docs/link-measurements.ja.md §1.4). Fixes found by running there: one arduino-cli build path per profile (the shared sketch cache linked another profile's objects), the wire lookup asks list for `oep.wire` (a trailing dot matched nothing), the uart test runs on a UART the probe's settings already planned (a jig's plan) instead of failing to plan it again. The Pro Micro RP2350 run found a firmware fault (a UART plan on pins its UART cannot use froze the probe; fixed in oep-probe-arduino 654b06a).
|
|
41
|
+
- (JA) `tests/hw` を bench の治具で(2026-10-02、bench の了解のもと): V003 治具(ESP32-D0WD + CH340、SWIO 越しの CH32V003)と X035 治具(DFU で焼く ESP32-P4、RVSWD 越しの CH32X035)。flash / identity / config / wire(halt → read_block → resume 50 往復、レジスタ不変)/ gpio / uart / session はどちらも pass。CH340 の port_speed は 1 % の判定にときどき掛かる(どの速さでも probe→host がまとまって落ちる。oep-spec docs/link-measurements.ja.md §1.4)。回して見つけた直し: arduino-cli の build path を profile ごとに分ける(共有の sketch cache が別 profile の object を link した)、線の検索は list に `oep.wire` を渡す(末尾の点では何も当たらない)、uart の試験は probe の設定が既に plan した UART(治具の plan)の上で行う(もう一度 plan して失敗しない)。Pro Micro RP2350 の一巡で firmware の不具合を見つけた(UART が使えないピンへの plan で probe が固まる。oep-probe-arduino 654b06a で修正)。
|
|
42
|
+
- (EN) Link: on a serial port (COBS framing) the answer bytes expected in flight are bounded by `SerialLink.ANSWER_BURST_MAX` (6 KiB; `answer_burst` per link, 0 = off) - at most 5 requests in flight for a 1024-byte frame. Linux cdc_acm silently lost 20-30 % of 8 x 1008-byte answers from an ESP32-P4's HS CDC, none below 8 KiB, and none when the same endpoint is read through libusb (oep-spec docs/link-measurements.ja.md §1.1, core §3.4). Not applied to vendor bulk / HID. `cobs.frame_max(message_len)`. `oep linktest --json` flushes each line.
|
|
43
|
+
- (JA) link: シリアルの口(COBS)では、未解決の応答の見込み量を `SerialLink.ANSWER_BURST_MAX`(6 KiB。link ごとの `answer_burst`、0 で無し)に抑える。1024 B のフレームなら同時 5 まで。ESP32-P4 の HS CDC で 8 × 1008 B の応答を Linux の cdc_acm が 20〜30 % 黙って落とし、8 KiB 未満なら 0、同じエンドポイントを libusb で読めば 8 本でも 0 だった(oep-spec docs/link-measurements.ja.md §1.1、core §3.4)。vendor bulk / HID には掛けない。`cobs.frame_max(message_len)`。`oep linktest --json` は 1 行ずつ flush する。
|
|
44
|
+
- (EN) `tests/hw`: the pre-release hardware test of oep-spec docs/release-testing.ja.md (pytest, marker `hw`, skipped without `OEP_HW_BOARDS`). Per board: flash the firmware (a local build with `OEP_PROBE_DIR`, or a GitHub release with `OEP_PROBE_VERSION`, sha256 checked; `OEP_HW_NOFLASH=1` tests what is on the board), then confirm / list / describe, probe.config set / get / save / state / unset with a disable item and a reboot, the wire (with `OEP_HW_TARGET`), fixture gpio and uart, port_speed through `linktest.matrix` (verdict: one at a time ≤ 1 % broken + lost), the session's lease / expired / resumed / force. Flashers: esptool (classic ESP32), USB DFU in pyusb (ESP32-P4), the 1200-baud touch and picotool (RP2040 / RP2350). Results in `tests/hw/results/<board>-<firmware>-<client>.json`. Run on an M5Stack ATOM with the 0.0.26 main build and release 0.0.25 (2026-10-01): everything passes but port_speed, where the ATOM's bridge (a CH552 posing as FTDI) loses 0-8 % of 496-byte answers one at a time at 115200 (COBS-broken frames) and 921600 gets no confirm while 1500000 and 500000 do.
|
|
45
|
+
- (JA) `tests/hw`: oep-spec docs/release-testing.ja.md のリリース前の実機試験(pytest、マーカー `hw`。`OEP_HW_BOARDS` が無ければ skip)。ボードごとに: firmware を焼き(`OEP_PROBE_DIR` でローカルのビルド、`OEP_PROBE_VERSION` で GitHub のリリース。sha256 を照合。`OEP_HW_NOFLASH=1` は入っているものを試す)、confirm / list / describe、probe.config の set / get / save / state / unset(disable を含む)と再起動、線(`OEP_HW_TARGET` のとき)、fixture の gpio と uart、`linktest.matrix` による port_speed(判定: 1 つずつで broken + lost が 1 % 以下)、セッションの lease / expired / resumed / force。焼き方: esptool(classic ESP32)、pyusb の USB DFU(ESP32-P4)、1200 baud のタッチと picotool(RP2040 / RP2350)。結果は `tests/hw/results/<board>-<firmware>-<client>.json`。M5Stack ATOM で main の 0.0.26 ビルドとリリース 0.0.25 を回した(2026-10-01): port_speed 以外は通る。ATOM の変換(CH552 の FTDI 互換)は 115200 で 1 つずつでも 496 バイトの答えの 0〜8 % を落とし(COBS の壊れたフレーム)、921600 は confirm が返らない(1500000 と 500000 は通る)。
|
|
46
|
+
- (EN) `oep linktest` and `oep_client.linktest`: measure a link under conditions the caller chooses - rates to switch to with port_speed (or the speed in force), patterns (in / out / duplex), in-flight counts, frame sizes, frames or seconds, the answer wait, the driver's low-latency mode - and count ok / broken / lost frames and KB/s per cell. No fixed numbers in the measurement. Found with it: an M5Stack ATOM's FTDI corrupts the probe's answer while the host is transmitting, at 115200 as at 1.5 Mbaud (5-9 % of pipelined frames), and is clean one request at a time (2026-10-01).
|
|
47
|
+
- (JA) `oep linktest` と `oep_client.linktest`: 呼ぶ側が条件を決めて線を測る。port_speed で切り替える速さ(または今の速さ)、流し方(in / out / duplex)、同時に出す要求の数、フレームの大きさ、回数か時間、答えの待ち、ドライバの low latency。条件ごとに ok / broken / lost と KB/s を数える。決め打ちの数値は持たない。これで分かったこと: M5Stack ATOM の FTDI は、host が送っている間に受けた probe の答えを壊す(115200 でも 1.5 Mbaud でも、重ねたフレームの 5〜9 %)。1 つずつなら壊れない(2026-10-01)。
|
|
48
|
+
|
|
5
49
|
## 0.0.26
|
|
6
50
|
- (EN) A request that may take long on the probe is waited for that long (core §6.1: the probe does not count the lease while it runs one): `Host.expecting(ms)` (and `request(..., expect_ms=)` / `call(..., expect_ms=)`) makes the link wait at least that and 0.5 s (`link.EXPECT_MARGIN_S`) for each answer, at any rate - so the raised-rate wait of a quarter of the lease applies to ordinary requests only. Passed down by riscv-dm run (`timeout_ms`), dmi (its wait_us and poll_us steps, `riscv.dmi_wait_ms`), attach with a reset (`hold_ms`, riscv and arm), capture start (the configured `blocking_ms`; a group's the longest of its tracks) and probe.config save (`config.SAVE_EXPECT_MS`, 2 s). Such a request that times out at a raised rate still falls back. The link's own confirms, keepalives, the step down's revert and `pump` never wait longer. Fix: the keepalive a raised link sends after 1 s of quiet now goes out before the request takes its corr (`Host.before_request`); it used to go out with a higher corr first, so the probe took the request for an old one (rejected result_lost).
|
|
7
51
|
- (JA) probe で長くかかりうる要求はその間待つ(core §6.1: probe は要求の実行中 lease を数えない): `Host.expecting(ms)`(と `request(..., expect_ms=)` / `call(..., expect_ms=)`)で、link はどの速さでも応答ごとに少なくともその時間と 0.5 秒(`link.EXPECT_MARGIN_S`)待つ。上げた速さでの lease の 4 分の 1 の待ちは普通の要求だけに掛かる。riscv-dm の run(`timeout_ms`)、dmi(wait_us と poll_us の step の和、`riscv.dmi_wait_ms`)、reset 付きの attach(`hold_ms`、riscv と arm)、capture の start(configure の `blocking_ms`。組はトラックの最長)、probe.config の save(`config.SAVE_EXPECT_MS`、2 秒)が渡す。そうした要求も上げた速さで時間切れなら戻る。link 自身の confirm・keepalive・降りるときの戻す・`pump` は長く待たない。修正: 上げた link が 1 秒黙った後に送る keepalive を、要求が corr を取る前に送るようにした(`Host.before_request`)。これまでは大きい corr で先に出ていたため、probe が要求を古いものとみなした(rejected result_lost)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: oep-client-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.28
|
|
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
|
|
@@ -36,7 +36,8 @@ here.
|
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
38
|
pip install oep-client-python # PyPI (import oep_client); a checkout: pip install -e <checkout>
|
|
39
|
-
uv run pytest # in a checkout
|
|
39
|
+
uv run pytest # in a checkout (the fake probe; no hardware)
|
|
40
|
+
OEP_HW_BOARDS=<board id> OEP_PROBE_DIR=<oep-probe-arduino checkout> uv run pytest tests/hw -m hw # a real probe: tests/hw/README.md
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
`import oep_client` is all it takes. The registry is copied from oep-spec with `tools/sync_registry.sh`. PyPI's
|
|
@@ -58,7 +59,9 @@ oep-client-python X.Y.Z (until the v1 freeze every release may break the wire; t
|
|
|
58
59
|
| `host` | requests and results, the session id and the lock, `call()` (raises unless it worked), pipelining, the errors (`OepError` / `Rejected` / `Failed`; `Expired` when the lease lapsed - the session is never re-opened behind the caller's back, `Host.epoch` moves) |
|
|
59
60
|
| `link` | transports: serial ports (always COBS + CRC as `0x00 <COBS> 0x00`, bytes outside frames skipped as noise, opened exclusively), USB vendor bulk / HID and TCP (length frames, the §5.1 resync); matching by corr and resending; `open_host(target)` |
|
|
60
61
|
| `core` | interfaces by name (cached), confirm (with the probe's `boot_id`), the probe's describe (declarations only, cached per boot: labels, the transport list, `max_op_ms`), taking the lock (`take`), the pin plan, the `Interface` base |
|
|
61
|
-
| `riscv` | `oep.wire.rvswd` / `oep.wire.swio` (scan, attach - `max_speed` always sent, `reset=(channel, hold_ms)` for an attach under reset -, detach, connections), `oep.target.riscv-dm` (answers count their values; `RunResult.not_halted`), finding the reset line, attach through GPIO |
|
|
62
|
+
| `riscv` | `oep.wire.rvswd` / `oep.wire.swio` (scan, attach - `max_speed` always sent, `reset=(channel, hold_ms)` for an attach under reset -, detach, connections), `oep.target.riscv-dm` (answers count their values; `RunResult.not_halted`), finding the reset line (`find_reset_line(candidates, pins=...)`), attach through GPIO |
|
|
63
|
+
| `targets` | what the host knows per target family, in one table (`FAMILIES`: wire, target_id match, reset vector, option-byte NRST reader, max_speed / idle_clock); `identify(target_id)` |
|
|
64
|
+
| `pins` | `oep pins`: classify the channels, hold-low search, scan, identify, confirm the reset line, suggest a slot (`PinFinder`) |
|
|
62
65
|
| `console` | `oep.target.console` (position streams: read answers carry their length, marks are `time_ns`, the lock-free `streams()` list) and `ConsoleIO`, read as bytes |
|
|
63
66
|
| `fixture` | `oep.fixture.gpio` / `uart` (its stream is the plan's; `status()`) / `i2c-target` / `spi-target` (revision 1) |
|
|
64
67
|
| `config` | `oep.probe.config` (slots, binds, plan / label / idle / uart items, get / set / unset / save / erase; `describe()` = the declarations, `state()` = the live storage / slot / bind state; `hash_of(items)` = the probe's hash) |
|
|
@@ -102,6 +105,7 @@ oep config bind <probe> --port 1 --mode last-reset --stream slot:x035
|
|
|
102
105
|
oep config uart <probe> oep.fixture.uart 115200 --format 8N1 # applied whenever that UART's plan has RX or TX
|
|
103
106
|
oep config save <probe> # kept over a restart (also: remove = unset, erase)
|
|
104
107
|
oep speed <probe> 1500000,921600,500000 # port_speed: try faster rates on a UART bridge, print the report (below)
|
|
108
|
+
oep pins <probe> --power 5 --wire swio # where the target is wired: debug pins, reset line, a slot (below)
|
|
105
109
|
```
|
|
106
110
|
|
|
107
111
|
`<probe>` is a serial port, `tcp://HOST:PORT` or `usb[:VID:PID[:SERIAL]]`. A change takes the lock (owner "oep config") and
|
|
@@ -109,39 +113,102 @@ ends the session after it; it takes effect at once and, after `save`, stays over
|
|
|
109
113
|
|
|
110
114
|
A run on hardware: ArduinoCore-CH32's `tests/manual/oep_smoke/` (`oep_smoke.py`, `oep_probe_checks.py`).
|
|
111
115
|
|
|
116
|
+
## Finding the pins (`oep pins`)
|
|
117
|
+
|
|
118
|
+
`oep pins <probe> [--power CH] [--exclude CH,...] [--wire swio|rvswd|swd] [--steps ...] [--save] [--json]` finds where a
|
|
119
|
+
target is wired to a probe whose pins the host chooses. Each step says what it did; the whole run stays under a minute and
|
|
120
|
+
every plan is released at the end. The procedure and its reasons are in oep-spec's host development guide (「ピンの探し方
|
|
121
|
+
(参考)」); what each target family needs is in one table, `targets.FAMILIES` (wire, reset vector, the option-byte reader
|
|
122
|
+
for the reset line, max_speed / idle_clock), which oep-spec `docs/target-scan-notes.ja.md` records the sources of.
|
|
123
|
+
|
|
124
|
+
1. **classify**: every channel `oep.fixture.gpio` allows is read 16 times under pull-up, both pulls, then pull-down:
|
|
125
|
+
floating, pulled-up (both pulls still read 1: a weak pull-up such as a reset line's), driven-high / driven-low (the same
|
|
126
|
+
level under both pulls: push-pull or a strong pull - an idle-high UART line looks like this), active (changes between
|
|
127
|
+
reads). With `--power CH` the target is first read switched off: the channels that read otherwise follow its power.
|
|
128
|
+
These are candidates only.
|
|
129
|
+
2. **hold**: each floating / pulled-up channel is held low (open drain) while an active channel is watched; a channel
|
|
130
|
+
that stops it is a reset-line candidate.
|
|
131
|
+
3. **scan**: the wire over the floating / pulled-up channels (rvswd / swd: pairs, at most 600) - never over a driven or
|
|
132
|
+
active channel, the power channel or `--exclude`.
|
|
133
|
+
4. **identify**: attach (halt) on what answered; the target_id names the family; a CH32V00x's option bytes say whether
|
|
134
|
+
NRST exists (read only, never written); then resume.
|
|
135
|
+
5. **reset**: attach under reset through each candidate - the real line stops the hart at the reset vector.
|
|
136
|
+
6. **slot**: a suggested `oep config slot` line (the reset channel as a comment while `config.Slot` has no
|
|
137
|
+
`reset_channel`); `--save` writes it (set + save). Nothing is written without `--save`.
|
|
138
|
+
|
|
139
|
+
Safety: a driven or active channel is never driven, scanned or held; the power channel is touched only with `--power`;
|
|
140
|
+
holding low is open drain only. A new gpio plan lets every pin of the old one go first - the power channel too - so with
|
|
141
|
+
`--power` each new plan is followed by a clean power cycle (`power_cycles` in the report).
|
|
142
|
+
|
|
143
|
+
ESP32-P4 with a CH32V003 (power on GPIO5), 2026-10-02:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
$ oep pins /run/board-identify/by-id/esp32-series-30eda0ea068b --power 5 --wire swio
|
|
147
|
+
power: channel 5 low 300 ms (target off: read), then high 400 ms before the reads
|
|
148
|
+
classify: 52 channels, 16 reads each under pull-up, both pulls, pull-down
|
|
149
|
+
floating 0-3,6,9-20,26-34,36-50,52-54
|
|
150
|
+
pulled-up 4
|
|
151
|
+
driven-high 7-8,22-23,35 (never scanned or held)
|
|
152
|
+
driven-low 51 (never scanned or held)
|
|
153
|
+
active 21 (21: 8 changes under pull-up)
|
|
154
|
+
follow power 4,6,9-11,13,15-16,19-23,32-33 (read otherwise with the target off: wired to it; candidates only)
|
|
155
|
+
reset line (hold low): 45 candidates, each held low (open drain) up to 390 ms while watching 21 (105 changes in 1.0 s running, longest lull 130 ms)
|
|
156
|
+
hold 4 low: 21 stopped
|
|
157
|
+
45 held in 3.4 s: stopped by 4
|
|
158
|
+
scan swio: 45 channels (0-4,6,9-20,26-34,36-50,52-54; not 7-8,21-23,35,51: driven / active) in 0.14 s -> 19
|
|
159
|
+
attach swio 19: target_id 00310510 (WCH DMI 0x7F) -> ch32v00x, halted at dpc 0x108
|
|
160
|
+
option bytes (read only): RST_MODE 10 (USER 0xf7): NRST on PD7, 12 ms ignore window
|
|
161
|
+
attach under reset through 4 (held 20 ms): dpc 0x0 -> the reset line
|
|
162
|
+
slot: oep config slot ... --name ch32v00x --wire swio --pins 19 (not written; --save writes it)
|
|
163
|
+
# reset_channel 4 (probe.config §1.1; this client's slot has no reset_channel yet: name it in the attach's reset TLV)
|
|
164
|
+
released every plan (channel 5 is back to its idle state: the target is powered only while something drives it)
|
|
165
|
+
done in 7.3 s
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
22 / 23 are the target's UART (idle high: driven, so neither scanned nor held); 21 is an output its app toggles.
|
|
169
|
+
|
|
112
170
|
## A faster UART bridge (port_speed, opt-in)
|
|
113
171
|
|
|
114
172
|
A probe whose describe declares `port_speed` (oep-core §3.5; the classic ESP32 reference firmware does) lets the host
|
|
115
173
|
run its UART bridge faster than the boot speed (115200) for one session. Nothing changes unless the host asks:
|
|
116
174
|
|
|
117
175
|
```python
|
|
118
|
-
hst = link.open_host("/dev/ttyUSB0", port_speed=[
|
|
119
|
-
print(hst.link.speed.to_text()) # every
|
|
120
|
-
#
|
|
176
|
+
hst = link.open_host("/dev/ttyUSB0", port_speed=[921600, 500000]) # takes the lock, keeps the session open
|
|
177
|
+
print(hst.link.speed.to_text()) # every candidate tried, the baseline, the flows, the one in force
|
|
178
|
+
# the full form (a baseline and the flows measured), in a session already taken:
|
|
179
|
+
report = link.raise_speed(hst, [921600, 500000], verify=True, flows=[("out", 2)], record=True)
|
|
121
180
|
```
|
|
122
181
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
(
|
|
182
|
+
The host's procedure is the oep-spec host guide §7 (core §3.5 is the handshake). The **minimal form** (the default, about
|
|
183
|
+
50 ms, no measurement): each candidate in order - `try` (answered at the speed now, then the probe switches) -> the host
|
|
184
|
+
switches to the requested baud -> 20 ms -> a `confirm` (100 ms, up to 3) -> `commit`. The **full form** (`verify=True`,
|
|
185
|
+
or `flows=` given): a baseline at the boot speed per flow (this session's frames, or 60 measured), then for each
|
|
186
|
+
candidate every flow the session will use - `flows` of `("in"|"out"|"duplex", n)` (in = link_source probe -> host, out =
|
|
187
|
+
link_sink host -> probe, duplex = both interleaved; `n` in flight, 0 = the most the link keeps) - 16 frames at
|
|
188
|
+
max_frame - 16, counting broken and lost and measuring KB/s; a flow fails on broken + lost >= 3 over max(2 x baseline,
|
|
189
|
+
5 %), runs once more at n = 1 first (then n = 1 is the link's cap), and one failed flow fails the candidate. A failed
|
|
190
|
+
candidate reverts (step 2) and goes back to the boot speed, confirmed there. The first candidate that passes is kept; a
|
|
191
|
+
rate the probe's UART cannot make is skipped. Which rates pass depends on the bridge chip and its driver (an FTDI took
|
|
192
|
+
only 3 MHz / n, a CH340 921600 but not 1500000 towards the host: oep-spec docs/uart-speed-negotiation.ja.md), so the
|
|
193
|
+
host chooses them. The report (`link.speed`: `base`, `rate`, `chosen`, `baseline`, `trials` of `SpeedTrial` with
|
|
194
|
+
`flows`, `in_kb_s` / `out_kb_s` / `duplex_kb_s`) is there to budget a capture or a write.
|
|
132
195
|
|
|
133
196
|
The probe goes back to the boot speed by itself when the session ends (`end`, a lapse, a force), when frames break or the
|
|
134
197
|
line goes quiet (`idle_ms`, at most `port_speed_idle_max_ms` = 3 s; a host that died leaves the rate no longer than
|
|
135
|
-
that): while raised the link sends a keepalive before a request when it has been quiet for
|
|
136
|
-
does the same for a caller that sits idle for long; opening a serial port retries its
|
|
137
|
-
wait out a rate left over. The link follows an `end` at once, and a request
|
|
138
|
-
resend too) takes the link back to the boot speed, confirmed, and goes once
|
|
139
|
-
each wait for an answer is at most a quarter of the lease, so this ends well
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
198
|
+
that): while raised the link sends a keepalive before a request when it has been quiet for less than half of `idle_ms`
|
|
199
|
+
(1 s), and `hst.link.keep_alive()` does the same for a caller that sits idle for long; opening a serial port retries its
|
|
200
|
+
first confirm for about 4 s to wait out a rate left over. The link follows an `end` or a revert at once, and a request
|
|
201
|
+
that goes unanswered at a raised rate (its resend too) takes the link back to the boot speed, confirmed, and goes once
|
|
202
|
+
more there - it never wedges; while raised each wait for an answer is at most a quarter of the lease, so this ends well
|
|
203
|
+
inside it. In use the link judges the frames of the last 3 s (none under 50): over max(2 x baseline, 10 %) broken or
|
|
204
|
+
lost steps the link down - port_speed revert at the raised rate, the boot speed, a confirm - and the rate is not raised
|
|
205
|
+
again in that session (`speed.stepped_down`, `speed.down_why`, `speed.step_downs`). `record=True` (a bool, a path, or a
|
|
206
|
+
`speed_record.SpeedRecord`; the `oep speed` CLI's default, off in the library) keeps passed / failed rates per (port,
|
|
207
|
+
unit_id) under `~/.cache/oep-client/link-speed.json` for 30 days, putting a passed rate first and leaving failed ones
|
|
208
|
+
out. A probe without the feature answers `not supported` and stays at its speed. Behind a broker (TCP) the broker does
|
|
209
|
+
this, not the client. Serial ports are also opened in the driver's low-latency mode where it has one (an FTDI's latency
|
|
210
|
+
timer 16 -> 1 ms tripled a UART bridge's throughput). `open_host(..., baud=)` names the boot speed when the board's
|
|
211
|
+
profile is not 115200.
|
|
145
212
|
|
|
146
213
|
## The fake probe (a working spec)
|
|
147
214
|
|
|
@@ -163,6 +230,11 @@ period 64 (k // 2 + 1) samples, 12-bit values in 16-bit slots; ESP32-style front
|
|
|
163
230
|
Vrefint) and `oep.fixture.capture-group` binding the logic and the analog: started together, the analog 5 us later
|
|
164
231
|
(+-2 us), the trigger of one marked on both. Times are ns on the probe's one clock.
|
|
165
232
|
|
|
233
|
+
`oep.fixture.i2c-target` and `oep.fixture.spi-target` (`p4-x035`, `esp32-v003`) take their roles from the plan (SDA / SCL;
|
|
234
|
+
SCK / MOSI / MISO / CS - on `esp32-v003` one of two fixed channel_groups exactly) and answer every op of fixture §3 / §4.
|
|
235
|
+
There is no bus controller: an arm stays armed and nothing is received until a test calls a hook on the endpoint
|
|
236
|
+
(`i2c_write` / `i2c_read` / `spi_transfer`: one transaction on the bus).
|
|
237
|
+
|
|
166
238
|
Other programs' tests run `fake_serve` as a child process:
|
|
167
239
|
|
|
168
240
|
```sh
|
|
@@ -11,7 +11,8 @@ target の知識は host にある、という OEP の分担に従う。probe
|
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
13
|
pip install oep-client-python # PyPI (import oep_client); a checkout: pip install -e <checkout>
|
|
14
|
-
uv run pytest # in a checkout
|
|
14
|
+
uv run pytest # in a checkout(偽の probe。実機なし)
|
|
15
|
+
OEP_HW_BOARDS=<board id> OEP_PROBE_DIR=<oep-probe-arduino の checkout> uv run pytest tests/hw -m hw # 実機: tests/hw/README.ja.md
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
`import oep_client` だけで使える(`sys.path` に `src/` を足す使い方は不要になった)。番号の表は `tools/sync_registry.sh` で
|
|
@@ -32,7 +33,9 @@ X.Y.Z(v1 の凍結までは、どのリリースも wire を壊しうるので
|
|
|
32
33
|
| `host` | 要求と結果、session_id とロック、`call()`(失敗なら例外)、pipeline、エラーの階層(`OepError` / `Rejected` / `Failed`。lease 切れなら `Expired`。黙って open し直さず、`Host.epoch` が進む) |
|
|
33
34
|
| `link` | transport: シリアルの口(常に COBS + CRC、`0x00 <COBS> 0x00`、フレームの外は雑音として捨てる、排他で開く)、USB vendor bulk / HID と TCP(長さつきフレーム、§5.1 の立て直し)、corr による照合と送り直し、`open_host(target)` |
|
|
34
35
|
| `core` | インターフェースを名前で探す(キャッシュつき)、confirm(probe の `boot_id` つき)、probe の describe(宣言だけ。起動の間 cache: ラベル、transport の一覧、`max_op_ms`)、ロックの取り方(`take`)、ピンの割り当て(plan)、`Interface` の土台 |
|
|
35
|
-
| `riscv` | `oep.wire.rvswd` / `oep.wire.swio`(scan、attach: `max_speed` は常に送る、`reset=(channel, hold_ms)` でリセットをかけながら attach、detach、connections)、`oep.target.riscv-dm`(応答は値の数を持つ。`RunResult.not_halted
|
|
36
|
+
| `riscv` | `oep.wire.rvswd` / `oep.wire.swio`(scan、attach: `max_speed` は常に送る、`reset=(channel, hold_ms)` でリセットをかけながら attach、detach、connections)、`oep.target.riscv-dm`(応答は値の数を持つ。`RunResult.not_halted`)、リセット線の探索(`find_reset_line(candidates, pins=...)`)、GPIO 経由の attach |
|
|
37
|
+
| `targets` | host が target の系統ごとに知っていることを 1 つの表に(`FAMILIES`: 線、target_id の照合、リセットのベクタ、NRST を option で読む関数、max_speed / idle_clock)。`identify(target_id)` |
|
|
38
|
+
| `pins` | `oep pins`: channel の分類、low に保つ探索、scan、識別、リセットの線の確かめ、スロットの提案(`PinFinder`) |
|
|
36
39
|
| `console` | `oep.target.console`(位置つきのストリーム: read の応答は長さを持ち、マークは `time_ns`、ロック不要の `streams()`)と、バイト列として読む `ConsoleIO` |
|
|
37
40
|
| `fixture` | `oep.fixture.gpio` / `uart`(ストリームは plan が作る。`status()`)/ `i2c-target` / `spi-target`(revision 1) |
|
|
38
41
|
| `config` | `oep.probe.config`(スロット、bind、plan / label / idle / uart の項目、get / set / unset / save / erase。`describe()` = 宣言、`state()` = 保存・スロット・bind の今の状態、`hash_of(items)` = probe と同じ hash) |
|
|
@@ -75,41 +78,105 @@ oep config slot <probe> --name x035 --wire rvswd --pins 2,54 --attach at-boot --
|
|
|
75
78
|
oep config bind <probe> --port 1 --mode last-reset --stream slot:x035
|
|
76
79
|
oep config uart <probe> oep.fixture.uart 115200 --format 8N1 # その UART の plan に RX / TX が付くたびに掛かる
|
|
77
80
|
oep config save <probe> # 再起動の後も残す(remove = unset、erase もある)
|
|
78
|
-
oep speed <probe>
|
|
81
|
+
oep speed <probe> [--candidates 921600,500000] [--verify [--flows out:2]] # port_speed: 速い速さを試し、結果を出す(下)
|
|
82
|
+
oep pins <probe> --power 5 --wire swio # target のつながり方: debug のピン、リセットの線、スロット(下)
|
|
79
83
|
```
|
|
80
84
|
|
|
81
85
|
`<probe>` はシリアルの口、`tcp://HOST:PORT`、`usb[:VID:PID[:SERIAL]]`。変更はロックを取り(owner "oep config")、終わったら
|
|
82
86
|
セッションを閉じる。変更はすぐ効き、`save` の後は再起動しても残る。
|
|
83
87
|
実機での一通りの確認は ArduinoCore-CH32 の `tests/manual/oep_smoke/`(`oep_smoke.py`、`oep_probe_checks.py`)。
|
|
84
88
|
|
|
89
|
+
## ピンを探す(`oep pins`)
|
|
90
|
+
|
|
91
|
+
`oep pins <probe> [--power CH] [--exclude CH,...] [--wire swio|rvswd|swd] [--steps ...] [--save] [--json]` は、ピンを host
|
|
92
|
+
が選ぶ probe で、target がどこにつながっているかを探します。各段は何をしたかを出し、全体は 1 分以内に終わり、最後に plan を
|
|
93
|
+
すべて解きます。手順とその理由は oep-spec の host 開発ガイド(「ピンの探し方(参考)」)にあります。target の系統ごとに要る
|
|
94
|
+
こと(線、リセットのベクタ、リセットの線の有無を読む option の読み方、max_speed / idle_clock)は 1 つの表 `targets.FAMILIES`
|
|
95
|
+
にまとめ、その出典は oep-spec の `docs/target-scan-notes.ja.md` に記録します。
|
|
96
|
+
|
|
97
|
+
1. **classify**: `oep.fixture.gpio` が許すすべての channel を、pull-up、両方の pull、pull-down の順に 16 回ずつ読む: floating、
|
|
98
|
+
pulled-up(両方の pull でも 1: リセットの線のような弱い pull-up)、driven-high / driven-low(どちらの pull でも同じレベル:
|
|
99
|
+
push-pull か強い pull。idle-high の UART の線はこう見える)、active(読むたびに変わる)。`--power CH` では先に target の
|
|
100
|
+
電源を切って読み、違って読めた channel が電源に従う。どれも候補を出すだけ。
|
|
101
|
+
2. **hold**: floating / pulled-up の channel を 1 本ずつオープンドレインで low に保ち、active の channel を見る。止まれば
|
|
102
|
+
リセットの線の候補。
|
|
103
|
+
3. **scan**: floating / pulled-up の channel で線を scan する(rvswd / swd は組で、600 組まで)。driven / active の channel、
|
|
104
|
+
電源の channel、`--exclude` は scan しない。
|
|
105
|
+
4. **identify**: 答えた線に attach(halt)し、target_id で系統を見る。CH32V00x は option bytes で NRST の有無を見る(読むだけ、
|
|
106
|
+
書かない)。その後 resume。
|
|
107
|
+
5. **reset**: 候補ごとにリセットをかけながら attach する。本物の線なら hart はリセットのベクタで止まる。
|
|
108
|
+
6. **slot**: `oep config slot` の行を勧める(`config.Slot` に `reset_channel` が無い間、リセットの channel はコメント)。
|
|
109
|
+
`--save` で書く(set + save)。`--save` が無ければ何も書かない。
|
|
110
|
+
|
|
111
|
+
安全: driven / active の channel は駆動も scan も保持もしない。電源の channel は `--power` のときだけ触る。low に保つのは
|
|
112
|
+
オープンドレインだけ。gpio の plan を新しくすると、probe は前の plan のピンを(電源の channel も)いったん離すので、`--power`
|
|
113
|
+
では新しい plan のたびにきれいに電源を入れ直す(報告の `power_cycles`)。
|
|
114
|
+
|
|
115
|
+
ESP32-P4 と CH32V003(電源は GPIO5)、2026-10-02:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
$ oep pins /run/board-identify/by-id/esp32-series-30eda0ea068b --power 5 --wire swio
|
|
119
|
+
power: channel 5 low 300 ms (target off: read), then high 400 ms before the reads
|
|
120
|
+
classify: 52 channels, 16 reads each under pull-up, both pulls, pull-down
|
|
121
|
+
floating 0-3,6,9-20,26-34,36-50,52-54
|
|
122
|
+
pulled-up 4
|
|
123
|
+
driven-high 7-8,22-23,35 (never scanned or held)
|
|
124
|
+
driven-low 51 (never scanned or held)
|
|
125
|
+
active 21 (21: 8 changes under pull-up)
|
|
126
|
+
follow power 4,6,9-11,13,15-16,19-23,32-33 (read otherwise with the target off: wired to it; candidates only)
|
|
127
|
+
reset line (hold low): 45 candidates, each held low (open drain) up to 390 ms while watching 21 (105 changes in 1.0 s running, longest lull 130 ms)
|
|
128
|
+
hold 4 low: 21 stopped
|
|
129
|
+
45 held in 3.4 s: stopped by 4
|
|
130
|
+
scan swio: 45 channels (0-4,6,9-20,26-34,36-50,52-54; not 7-8,21-23,35,51: driven / active) in 0.14 s -> 19
|
|
131
|
+
attach swio 19: target_id 00310510 (WCH DMI 0x7F) -> ch32v00x, halted at dpc 0x108
|
|
132
|
+
option bytes (read only): RST_MODE 10 (USER 0xf7): NRST on PD7, 12 ms ignore window
|
|
133
|
+
attach under reset through 4 (held 20 ms): dpc 0x0 -> the reset line
|
|
134
|
+
slot: oep config slot ... --name ch32v00x --wire swio --pins 19 (not written; --save writes it)
|
|
135
|
+
# reset_channel 4 (probe.config §1.1; this client's slot has no reset_channel yet: name it in the attach's reset TLV)
|
|
136
|
+
released every plan (channel 5 is back to its idle state: the target is powered only while something drives it)
|
|
137
|
+
done in 7.3 s
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
19 が SWIO、4 が NRST(hold で 21 が止まり、リセットをかけながらの attach で dpc 0)。22 / 23 は target の UART(idle high
|
|
141
|
+
なので driven として scan も保持もしない)、21 はアプリが動かす出力。
|
|
142
|
+
|
|
85
143
|
## UART bridge を速くする(port_speed、使うときだけ)
|
|
86
144
|
|
|
87
145
|
describe に `port_speed` を宣言する probe(oep-core §3.5。参照の classic ESP32 の firmware は宣言する)では、host は 1 つのセッションの
|
|
88
146
|
間、UART bridge を起動時の速さ(115200)より速くできます。host が頼まない限り何も変わりません:
|
|
89
147
|
|
|
90
148
|
```python
|
|
91
|
-
hst = link.open_host("/dev/ttyUSB0", port_speed=[
|
|
92
|
-
print(hst.link.speed.to_text()) #
|
|
93
|
-
#
|
|
149
|
+
hst = link.open_host("/dev/ttyUSB0", port_speed=[921600, 500000]) # ロックを取り、セッションを開いたままにする
|
|
150
|
+
print(hst.link.speed.to_text()) # 候補ごとに、基準、流し方、今の速さ
|
|
151
|
+
# 完全な形(基準と流し方を測る)を取ってあるセッションの中で:
|
|
152
|
+
report = link.raise_speed(hst, [921600, 500000], verify=True, flows=[("out", 2)], record=True)
|
|
94
153
|
```
|
|
95
154
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
155
|
+
手順は oep-spec の host 開発ガイド §7(core §3.5 は握手だけ)。**最小の形**(既定、約 50 ms、計測なし): 候補ごとに順に
|
|
156
|
+
`試す`(今の速さで応答してから probe が切り替える)→ host は要求した baud に切り替える → 20 ms → `confirm`(100 ms、3 回まで)→
|
|
157
|
+
`決める`。**完全な形**(`verify=True` か `flows=` を渡す): 起動時の速さの基準を流し方ごとに取り(このセッションのフレーム、
|
|
158
|
+
無ければ 60 フレーム)、候補ごとに使う流し方だけ流す。流し方 = `("in"|"out"|"duplex", n)`(in = link_source probe → host、
|
|
159
|
+
out = link_sink host → probe、duplex = 両方を交互。`n` は同時数、0 = link が出す最大)で、max_frame − 16 のフレームを 16 個流し、
|
|
160
|
+
壊れと失われを数え KB/s を測る。壊れ + 失われが 3 以上で割合が max(基準 × 2, 5 %) を超えたら流し方は通らず、n = 1 で流し直し
|
|
161
|
+
(通れば n = 1 が link の上限)、1 つでも通らなければ候補は通らない。通らない候補は戻して(step 2)起動時の速さに戻り confirm し直す。
|
|
162
|
+
最初に通った候補を使う。probe の UART が作れない速さは飛ばす。通る速さは変換チップとドライバで決まる(FTDI は 3 MHz ÷ n だけ、
|
|
163
|
+
CH340 は 921600 は通り 1500000 は probe → host が壊れた: oep-spec docs/uart-speed-negotiation.ja.md)ので、速さは host が選ぶ。
|
|
164
|
+
結果(`link.speed`: `base`、`rate`、`chosen`、`baseline`、`trials` = `flows` と `in_kb_s` / `out_kb_s` / `duplex_kb_s` を持つ
|
|
165
|
+
`SpeedTrial`)はキャプチャや書き込みの予算を立てるのに使う。
|
|
103
166
|
|
|
104
167
|
probe はセッションが終わったとき(`end`、lease の期限切れ、force)、フレームが壊れたとき、線が黙ったとき(`idle_ms`、最長
|
|
105
168
|
`port_speed_idle_max_ms` = 3 秒。落ちた host の速さもそれより長くは残らない)に自分で起動時の速さに戻る: 上げている間、link は
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
confirm し、そこでもう一度送る(固まらない)。上げている間は応答を待つ
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
169
|
+
`idle_ms` の半分より短く黙れば要求の前に keepalive を送り、長く黙る呼び出し側は `hst.link.keep_alive()` で同じことをする。
|
|
170
|
+
シリアルの口を開くと最初の confirm を約 4 秒繰り返して、残った速さが戻るのを待つ。link は `end` と戻すにはすぐ合わせ、上げた速さで
|
|
171
|
+
応答の来ない要求(送り直しも)があれば起動時の速さに戻って confirm し、そこでもう一度送る(固まらない)。上げている間は応答を待つ
|
|
172
|
+
1 回が lease の 4 分の 1 までなので、lease の内に十分収まる。使っている間は直近 3 秒のフレーム(50 未満なら判定しない)を見て、
|
|
173
|
+
max(基準 × 2, 10 %) を超えて壊れ・失われたら、上げた速さで port_speed の戻すを送り、起動時の速さに戻って confirm し、その速さは
|
|
174
|
+
そのセッションの間は使わない(`speed.stepped_down`、`speed.down_why`、`speed.step_downs`)。`record=True`(真偽値・パス・
|
|
175
|
+
`speed_record.SpeedRecord`。`oep speed` CLI は既定で ON、ライブラリは OFF)は、通った / 通らなかった速さを(口、unit_id)ごとに
|
|
176
|
+
`~/.cache/oep-client/link-speed.json` に 30 日残し、通った速さを先頭に、通らなかった速さを外す。機能の無い probe は `not supported`
|
|
177
|
+
で、速さは変わらない。ブローカー(TCP)の後ろでは client ではなくブローカーが行う。シリアルの口は、ドライバにあれば low-latency の
|
|
178
|
+
モードで開く(FTDI の latency timer 16 → 1 ms で UART bridge の速度が 3 倍になった)。ボードの起動時の速さが 115200 でなければ
|
|
179
|
+
`open_host(..., baud=)` で渡す。
|
|
113
180
|
|
|
114
181
|
## 偽の probe(動く spec)
|
|
115
182
|
|
|
@@ -128,6 +195,10 @@ PARLIO と同じ w 1〜16、3 本なら w 4。`esp32-v003`: classic ESP32 の sa
|
|
|
128
195
|
frontend、作り物の 2 点の較正と Vrefint)と、ロジックとアナログを束ねる `oep.fixture.capture-group` もある(一緒に始まり、
|
|
129
196
|
アナログは 5 µs 遅れ(±2 µs)、片方のトリガが両方に印される)。時刻は probe の 1 本の時計の ns。
|
|
130
197
|
|
|
198
|
+
`oep.fixture.i2c-target` と `oep.fixture.spi-target`(`p4-x035`、`esp32-v003`)は plan で役割を受け(SDA / SCL、SCK / MOSI / MISO / CS。
|
|
199
|
+
`esp32-v003` の SPI は 2 つの channel_group のどれかに完全に一致)、fixture §3 / §4 の op にすべて答える。バスの controller は無い:
|
|
200
|
+
試験が endpoint の hook(`i2c_write` / `i2c_read` / `spi_transfer`: バス上の 1 回のトランザクション)を呼ぶまで、arm は待ったままで何も受けない。
|
|
201
|
+
|
|
131
202
|
外のプログラムの試験には `fake_serve` を子プロセスで使う:
|
|
132
203
|
|
|
133
204
|
```sh
|