Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ set(SOURCES_LIST
capture/src/waveform_parser.cpp
capture/src/waveform_ring_buffer.cpp
core/src/waveform_scaling.cpp
core/src/waveform_trigger.cpp
core/src/instrument_scaling_profile.cpp
${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_draw.cpp
Expand All @@ -65,6 +66,7 @@ set(HEADERS_LIST
capture/inc/waveform_parser.h
capture/inc/waveform_ring_buffer.h
core/inc/waveform_scaling.h
core/inc/waveform_trigger.h
core/inc/instrument_model.h
core/inc/instrument_scaling_profile.h
)
Expand All @@ -85,6 +87,10 @@ set(WAVEFORM_SCALING_TEST_SOURCES_LIST
tests/waveform_scaling_test.cpp
)

set(WAVEFORM_TRIGGER_TEST_SOURCES_LIST
tests/waveform_trigger_test.cpp
)

set(INSTRUMENT_SCALING_PROFILE_TEST_SOURCES_LIST
tests/instrument_scaling_profile_test.cpp
)
Expand Down Expand Up @@ -177,6 +183,16 @@ if(BUILD_TESTING)
enable_project_warnings(waveform_scaling_tests)
add_test(NAME waveform_scaling COMMAND waveform_scaling_tests)
add_dependencies(${APP_NAME} waveform_scaling_tests)
add_executable(waveform_trigger_tests
${WAVEFORM_TRIGGER_TEST_SOURCES_LIST}
core/src/waveform_trigger.cpp
)
target_include_directories(waveform_trigger_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/core/inc
)
enable_project_warnings(waveform_trigger_tests)
add_test(NAME waveform_trigger COMMAND waveform_trigger_tests)
add_dependencies(${APP_NAME} waveform_trigger_tests)
add_executable(instrument_scaling_profile_tests
${INSTRUMENT_SCALING_PROFILE_TEST_SOURCES_LIST}
core/src/instrument_scaling_profile.cpp
Expand Down
66 changes: 66 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,4 +553,70 @@ Records key decisions, structural changes, and completed development stages.
headroom is deferred to a later stage. The software zero reference already
yields a correct 0 V reading.

### Stage 4 - Added edge trigger detection

- Added a new `oscilloscope::core` trigger module (`core/inc/waveform_trigger.h`,
`core/src/waveform_trigger.cpp`) with an `ETriggerSlope` enum and
`findEdgeTrigger`, which scans a sample buffer for the first rising or
falling crossing of a level starting at a given index.
- Added `tests/waveform_trigger_test.cpp` covering rising and falling edges,
the no-crossing case, the start-index skip, and the null/short-buffer guards,
and registered the `waveform_trigger` test in `CMakeLists.txt`.
- Wired the trigger into `app/main.cpp`: added a Trigger panel with a source
selector (CH1, CH2, ALT, EXT, EXT/10), a slope selector (Rising/Falling), a
level slider, and a mode selector (Auto, Normal, Single). Drew a horizontal
level line and a vertical trigger-position marker over the waveform, and used
the detected trigger sample as the readout reference. Software edge detection
runs on CH1/CH2 (ALT falls back to CH1; EXT and EXT/10 have no in-software
signal). Auto free-runs, Normal draws only when a trigger is found, and
Single freezes the first triggered frame until the Rearm button is pressed.
- Modelled the trigger controls as `ETriggerMode`, `ETriggerSource`, and
`ETriggerSlope` enumerations with option tables that keep each value next to
its label (mirroring the scaling-profile step tables), so the combo labels
cannot drift from the enumerators.

### Stage 4 - Held triggered frames and a trigger reference marker

- Fixed Normal mode to hold the last triggered frame until the next trigger
instead of blanking the display when a frame contained no edge. Normal and
Single now share one held-frame path: Single captures once per arm, Normal
refreshes the held frame on every new trigger, and Auto free-runs live.
- Added a "T" reference marker at the top of the display marking the sweep
trigger point, alongside the existing vertical trigger line.

### Stage 4 - Aligned the trace to a movable trigger point

- Reworked the trigger point so it is a fixed, user-movable horizontal
reference: added a Position control and shifted the displayed trace so the
triggering edge lands exactly under the "T" marker, with pre-trigger samples
to its left and post-trigger samples to its right.
- Added a `horizontalOffset` parameter to `drawChannelWaveform` and drew the
vertical reference and "T" marker at the fixed trigger position instead of at
the raw sample index of the detected edge.
- Armed the trigger only past a pre-trigger window sized by the Position
control, so the aligned trace keeps enough history to fill the display left
of the "T" marker instead of leaving an empty region.

### Stage 4 - Windowed the record under a fixed trigger marker

- Displayed only a fraction of the captured record (a window) so the surplus
samples act as pre/post-trigger reserve, letting the trace fill the whole
display under the fixed "T" marker without an empty region on either side.
- Slid the window so the trigger sample sits under the marker, clamping the
window to the record bounds; at the reserve limit the marker drifts slightly
rather than exposing an empty edge.
- Replaced the pixel-shift parameter of `drawChannelWaveform` with a window
start and length, and added `computeDisplayWindow` to size the window.
- Verified on a physical Hantek DSO-2250 with a noise signal, the trigger
centered, and Normal sweep: the trace reaches the right edge and starts at
the left edge with no gaps. Confirmed at Position 0 and Position 90 as well.

### Next windowing tasks

- Phase 2: derive the display window length from the Timebase control using the
device's real sample period, so the Timebase combo drives the horizontal
span. Requires confirming the true sample period from the reference USB
captures before wiring it to the window length.



23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ The application currently provides:
- supported Hantek device discovery and connection through libusb;
- FX2 firmware upload and operational-device re-enumeration;
- Start/Stop-controlled endpoint polling;
- bounded USB error recovery and safe device-loss handling.
- bounded USB error recovery and safe device-loss handling;
- live two-channel waveform rendering with edge triggering.

Capture-state responses and sample buffers are decoded by deterministic,
hardware-independent parser functions. Each supported-device entry supplies its
Expand All @@ -25,8 +26,10 @@ worker reads and queues the complete profile-defined sample buffer, then starts
the next capture. A processing worker decodes complete captures and publishes
the latest frame and trigger point safely for rendering. Deterministic
functions convert raw capture samples into volts and elapsed capture time from
the selected voltage-scale and timebase settings. Live waveform rendering is
not yet implemented.
the selected voltage-scale and timebase settings. Both channels are plotted on
the display grid with Auto, Normal, and Single edge triggering, a movable
trigger Position with a fixed "T" reference marker, and a display window that
keeps the trace filling the full width with pre/post-trigger reserve.

## Planned Stack

Expand Down Expand Up @@ -217,18 +220,14 @@ CI can update only the version metadata by passing `--skip-build`.

## Known Issues

- Live capture on a physical Hantek DSO-2250 never reports a waveform:
`GetCaptureState` polling stays at the empty-buffer state, so no channel
data is read. Demo mode and the full CTest suite are unaffected. See
`HISTORY.md` ("Known issue - live capture on real DSO-2250 hardware
reports no waveform") for the investigation and ruled-out causes.
- None currently tracked.

## Next Steps

1. Diagnose the live-capture-never-completes issue on real DSO-2250
hardware.
2. Render live and demo waveforms on the display grid.
3. Implement the two-channel model, timebase, and instrument controls.
1. Drive the horizontal display window length from the Timebase control using
the device's real sample period.
2. Add a vertical Level slider and per-channel zero-position controls.
3. Implement cursor-based measurements.

The full goals, constraints, and architecture are documented in
`WorkingDocs/TECHNICAL_SPECIFICATION.md`.
Expand Down
Loading
Loading