Skip to content

feat: support DSLogic hardware trigger in capture - #13

Open
TreeNewbeer wants to merge 4 commits into
LISTENAI:masterfrom
TreeNewbeer:feat/hardware-trigger
Open

TreeNewbeer wants to merge 4 commits into
LISTENAI:masterfrom
TreeNewbeer:feat/hardware-trigger

Conversation

@TreeNewbeer

@TreeNewbeer TreeNewbeer commented Nov 10, 2026 •

Copy link
Copy Markdown

Summary

This PR lets capture arm the DSLogic Plus hardware trigger. It supports DSView's simple, stage, and serial trigger modes, and reports where the trigger fired. It implements the deferred TRIG-01 requirement from the v1.1 milestone. The DSView/ submodule is unchanged.

  • New capture flags, shown under a Trigger help heading:
    • --trigger CH=COND[,CH=COND...]: a simple trigger. Conditions are low, high, rising, falling, and edge; DSView letters 0, 1, R, F, C also work.
    • --trigger-config PATH: a version-1 JSON config in simple, stage, or serial mode.
    • --trigger-position PERCENT: the pre-trigger share. It can be 1-90 in buffer mode (default 1); stream mode allows only a simple trigger and fixes the position at 1, as the DSView GUI does.
  • The trigger is validated against the resolved device options before acquisition:
    • trigger channels must be enabled and within the channel-mode width
    • stream-mode limits apply, as above
    • a stage trigger has 1-16 stages and a counter of at least 1, and patterns that would always match or never match are rejected
    • each serial flag (start, stop, clock) needs an edge condition
  • The bridge resolves the exported ds_trigger_* setters and replays a fixed-size program that mirrors TriggerDock::commit_trigger and LogicSignal::commit_trig.
    • It rejects programs that would trip DSView asserts, and resets the native state if a setter fails part-way.
    • SR_DF_TRIGGER packets are recorded, so the CLI knows whether and where the trigger fired.
  • When a trigger is armed, the capture JSON and the metadata sidecar gain a trigger block with requested and observed (fired, sample_index, raw status). Without a trigger the output is unchanged, and the metadata schema_version stays 2.
  • New error codes:
    • capture_trigger_not_fired, for a timeout or a stopped stream capture that never saw a trigger hit
    • trigger_config_invalid and trigger_config_unreadable
    • trigger_channel_not_enabled and trigger_channel_unsupported
    • trigger_mode_unsupported and trigger_position_out_of_range
  • devices options lists the trigger capabilities in both JSON and text output.
  • A failed stream capture now deletes its partial *.vcd.streaming.tmp file. Before this change the file was left behind, and stream captures whose trigger never fires now hit this path routinely.
  • The Windows dsview_runtime.def exports the trigger setters and trigger DATA, which the state read-back uses.

Behaviour worth knowing

  • observed.sample_index is the exact trigger sample in the exported VCD.
  • The position is approximate. With real signals the trigger landed 0.03 to 0.30% of the capture after the requested share.
  • If the event comes before the pre-trigger share has been recorded, the capture starts early and sample_index is below the requested share. This is common with periodic signals. The README documents it.
  • Serial trigger:
    • it compares the first data_bits bits clocked after the start flag; there is no sliding window
    • the first-received bit is the leftmost, MSB, character of data_value
    • an empty or level-only start or stop flag never fires on the hardware, which is why validation requires edges

Test plan

  • cargo test --workspace: 315 passed, 0 failed. New tests:
    • dsview-sys/tests/trigger.rs: applies programs to the source-built runtime and reads the native struct ds_trigger back
    • core unit tests for parsing, validation, and program layout
    • dsview-cli/tests/trigger_cli.rs: flags, output shape, and error codes, using the debug fixture
  • DSLogic Plus internal-test counter (16 channels, 100 MHz), where each predicted trigger sample matched exactly:
    • simple edge and 16-channel level triggers
    • stage count, two-stage sequence, invert, OR, and contiguous
    • position 10% and 50%
    • serial with 4 and 8 data bits
    • triggers that must never fire
  • Idle real inputs:
    • buffer mode and stream mode (finite, --duration-ms, and --until-interrupt)
    • triggers that never fire, followed by checks that the device is still usable
  • Real signals (two 3.3 V GPIO lines from an FPGA board): 23 of 23 cases passed, covering simple, stage, serial, no-fire, stream, refusals, and position accuracy.
  • Windows and macOS builds. Only Linux x86_64 was built locally; CI covers the rest, including the .def change.

Known limitations

  • The 200 MHz x8 and 400 MHz x4 buffer channel modes fail at the enabled_channels apply step with SR_ERR_ARG, with or without a trigger. v1.2.4 has the same failure: set_enabled_channels walks all 16 channels, but these modes expose only 8 or 4. This PR does not fix it, so the halved and quartered trigger-mask paths are covered by validation only and were not tested on hardware.
  • Real-signal tests used two channels. Stage invert, contiguous, and or were checked on the internal-test counter only.

🤖 Generated with [Claude Code](https://claude.com/claude-code

@seasonyuu seasonyuu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review findings

  1. [P1] Stream captures can succeed even when the trigger never fires

    In crates/dsview-core/src/lib.rs:2795-2805, StoppedByDuration and StoppedByInterrupt are returned as successful captures without checking the trigger observation. The CLI remapping in crates/dsview-cli/src/main.rs:2319-2324 only handles Timeout and Incomplete errors. As a result, --duration-ms / --until-interrupt can stop before a requested trigger is hit, export a partial VCD, and exit successfully instead of returning the documented capture_trigger_not_fired error. Please check trigger.observation.fired() before treating these stopped completions as success, and discard the temporary streaming artifact on the error path.

  2. [P2] Trigger packet payload is read without validating its size or type

    crates/dsview-sys/bridge_runtime.c:3897-3919 casts every SR_DF_TRIGGER payload to struct ds_trigger_pos * and immediately reads all fields. A truncated or malformed packet from the runtime can therefore cause an out-of-bounds read and crash the process. Please validate the payload pointer, length, and packet format before dereferencing it.

Validation

I attempted cargo test --workspace, but the build stopped in crates/dsview-sys/build.rs:484 because this Windows environment does not have pkg-config / glib-2.0 available.

TreeNewbeer and others added 3 commits November 11, 2026 11:13
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TreeNewbeer
TreeNewbeer force-pushed the feat/hardware-trigger branch 2 times, most recently from 63d7b17 to fa2ea44 Compare November 11, 2026 05:37
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