Skip to content

Add explicit scope display and focus controls - #3

Open
Epslion404 wants to merge 2 commits into
Scaxlibur:masterfrom
Epslion404:split/scope-display-focus
Open

Add explicit scope display and focus controls#3
Epslion404 wants to merge 2 commits into
Scaxlibur:masterfrom
Epslion404:split/scope-display-focus

Conversation

@Epslion404

Copy link
Copy Markdown
Collaborator

Summary

  • add explicit wavebench scope display --channel N on|off
  • add explicit wavebench scope focus --channel N with time range, vertical scale, and hide-other-channel options
  • return mutation manifests for display/focus operations
  • implement DS1104Z and RTM2032 driver support
  • skip DS1000Z socket *OPC? during autoscale to avoid response desync

Safety

  • these are explicit CLI actions only
  • they only adjust scope display/acquisition view state
  • they do not control sources, power outputs, or DUT state

Validation

  • git diff --cached --check
  • pytest -q tests/test_cli.py tests/test_ds1104.py tests/test_instrument_models.py tests/test_scope_snapshot.py tests/test_waveform.py: 132 passed, 1 warning, 5 subtests passed

Split context

This is split out from the original AI-agent scope PR so scope state-changing controls can be reviewed separately from MCP/agent read APIs.

@Scaxlibur

Copy link
Copy Markdown
Owner

感谢把 scope display / scope focus 从 agent/MCP 功能中拆出来。我们认可“显式操作、明确声明会改变仪器状态”的方向,但这个 PR 目前同时混合了:

  1. WaveBench 主仓库的通用控制面和能力契约;
  2. DS1000Z、RTM2000/RTM2032 的具体驱动实现和 SCPI 行为。

项目已经有独立的仪器插件仓库,并且其中已有:

  • wavebench-rigol-ds1000z
  • wavebench-rohde-schwarz-rtm2000

因此希望在合并前调整 PR 边界,并修复下面的状态安全问题。当前结论是 Request changes / 暂不按现状合并

1. 请拆分通用控制面与具体仪器实现

这个 PR 在 WaveBench 主仓库中可以保留以下通用部分:

  • scope.channel_display / scope.focus_channel 公共 capability 和 driver contract;
  • scope display / scope focus CLI;
  • ScopeService 的通用调度、参数验证和 mutation manifest;
  • 不依赖具体型号的 fake-driver/service/CLI 测试。

以下内容请迁移到仪器插件仓库对应的包中:

  • DS1000Z/DS1104 的具体 SCPI 和驱动实现;
  • RTM2000/RTM2032 的具体 SCPI 和驱动实现;
  • 型号通道数量和型号能力声明;
  • autoscale 的型号/传输相关完成机制;
  • 型号级命令序列、错误恢复和零写入测试。

主仓库里的内建兼容驱动可以继续保留现有基线,但在没有完成同等安全实现和验证前,不应提前声明新的 display/focus capability。增强能力可以先通过外置插件的 canonical driver ID 提供。

2. wait_opc=True 不能被静默忽略

当前 DS1104 修改在 autoscale 时不再执行完成等待,而只记录 telemetry。这样会改变 wait_opc=True 的既有语义:调用者可能收到成功结果时,示波器仍在异步调整显示和采集参数。

查询错误队列不能证明 autoscale 已经完成。

如果 DS1000Z 的 socket 连接上 *OPC? 存在响应失步风险,请在对应插件驱动中实现安全、可验证的替代完成机制。如果暂时没有可靠机制,则在请求 wait_opc=True 时应明确 fail closed,而不是将“跳过等待”当作操作完成。

同时请增加测试,证明:

  • wait_opc=True 不会在没有完成证据时返回成功;
  • wait_opc=False 的行为是显式且有记录的;
  • 完成等待失败不会被误报为成功。

3. 所有参数必须在第一次仪器写入前完成验证

当前 time_range <= 0vertical_scale <= 0 的检查无法拒绝 nan 和正无穷。

例如:

wavebench scope focus --channel 1 --time-range nan --hide-other-channels

可能先关闭其他通道、打开目标通道,然后才发送无效的时基命令。这样一个无效请求也会造成部分仪器状态改变。

请在 service/driver 边界使用有限数校验,例如 math.isfinite(),并保证以下输入在任何 SCPI 写入前被拒绝:

  • nan
  • inf
  • -inf
  • 零和负数
  • 超出具体型号支持范围的值
  • 不存在的通道

对应测试应断言 invalid input 产生 零条仪器写入,而不只是断言最终抛出异常。

4. RTM2032 必须在写入前拒绝 CH3 及以上通道

RTM2032 是两通道型号,但当前驱动只检查 channel >= 1

这意味着:

wavebench scope focus --channel 3 --hide-other-channels

可能先关闭 CH1、CH2,再尝试打开不存在的 CH3。如果最后一条命令失败,两个有效通道已经被留在关闭状态;如果关闭了错误检查,还可能输出成功 manifest。

请将型号通道上限放在具体插件 descriptor/driver 中,并在任何写入前完成校验。至少增加以下回归测试:

  • RTM2032 的 CH3/CH4 被拒绝;
  • 无效通道产生零条写入;
  • 无效目标通道不会关闭任何有效通道;
  • scope.check_errors=false 也不能使无效通道被报告为成功。

5. Mutation manifest 必须来自实际型号和实际执行结果

当前 service 在 hide_other_channels=true 时固定把 CH1–CH4 都列为受影响设置,但 RTM2032 实际只有 CH1–CH2。

这会让审计记录声明修改了不存在的 CH3/CH4,也无法准确表达部分失败时究竟执行了哪些操作。

建议不要在通用 service 中硬编码四通道。可以选择:

  • 从 descriptor 获取模拟通道数量;
  • 或由 driver 返回实际 affected_settings / applied_settings
  • 或使用公共的型号 channel profile 构造 manifest。

请分别覆盖 DS1000Z 四通道和 RTM2032 两通道的 manifest 测试。

6. 请定义并测试部分写入失败的处理策略

focus 是多条 SCPI 写入组成的复合操作,例如:

  1. 关闭其他通道;
  2. 打开目标通道;
  3. 修改时基;
  4. 修改垂直档位;
  5. 某些驱动还会重置 offset;
  6. 最后检查错误队列。

任意中间步骤失败时,当前实现可能留下部分改变,但没有恢复,也没有准确报告部分状态。

请在具体插件驱动中明确采用一种安全策略:

  • 写入前读取完整相关状态,失败后恢复并验证;
  • 或在无法安全恢复时 fail closed,并返回明确的 partial/unknown-state 结果;
  • 不应在部分执行后仍返回普通成功 manifest。

测试至少应注入每个中间写入点的失败,并验证:

  • 恢复成功时,显示、时基、垂直档位和 offset 均恢复;
  • 恢复失败时,不会宣称操作成功;
  • 返回的 manifest 与实际执行或恢复结果一致。

建议的 PR 拆分方式

建议将本 PR 调整为:

WaveBench 主仓库 PR

  • 公共 capability/contract;
  • CLI 和 service;
  • 有限数及通用参数预验证;
  • 通用 mutation-result 模型;
  • fake driver 测试;
  • 不修改 DS1104/RTM2032 的具体 SCPI 实现,也暂不为内建 descriptor 宣称未完成的能力。

仪器插件仓库 PR

分别修改:

  • wavebench-rigol-ds1000z
  • wavebench-rohde-schwarz-rtm2000

每个插件独立实现并测试:

  • 通道显示;
  • focus 操作;
  • 型号范围和通道上限;
  • autoscale 完成机制;
  • 错误检查、恢复和状态不明处理;
  • 准确的 mutation manifest。

完成上述拆分和安全修复后,我们再复审主仓库控制面与两个插件实现。

@Epslion404
Epslion404 force-pushed the split/scope-display-focus branch from 218cd07 to de78947 Compare July 29, 2026 15:22
@Epslion404

Copy link
Copy Markdown
Collaborator Author

Thanks for the detailed boundary and safety review. I updated this PR to make it a main-repo shared control-surface PR only:

  • Removed DS1000Z/DS1104 and RTM2000/RTM2032 concrete SCPI implementations from this PR.
  • Removed the new display/focus capability declarations from the built-in DS/RTM descriptors.
  • Removed model-specific command-sequence/autoscale tests from the main repo PR.
  • Kept only the public capability/contract, CLI, ScopeService dispatch, CLI output, and fake-driver/service tests.
  • Added service-side pre-validation before opening the instrument/session:
    • channel must be a positive integer;
    • time_range_s and vertical_scale_v_per_div must be finite and > 0;
    • invalid values are rejected before driver calls.
  • Changed the service so concrete drivers may return the actual mutation manifest. The service no longer hardcodes CH1-CH4 when hide_other_channels=true; its fallback uses generic other_channels.display unless a driver/plugin returns precise affected settings.

Validation after rebasing onto current origin/master:

git diff --check origin/master...HEAD
.\.venv-device\Scripts\python.exe -m pytest -q tests/test_cli.py tests/test_instrument_models.py tests/test_scope_snapshot.py tests/test_ds1104.py tests/test_waveform.py
226 passed, 5 subtests passed

The DS1000Z and RTM2000/RTM2032 concrete implementations are now left for the instrument plugin repo as requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants