Skip to content

Add config fields for Trigger mode for GenTL#78

Draft
C-Achard wants to merge 14 commits into
cy/gentl-cti-lock-fixfrom
cy/gentl-trigger-config
Draft

Add config fields for Trigger mode for GenTL#78
C-Achard wants to merge 14 commits into
cy/gentl-cti-lock-fixfrom
cy/gentl-trigger-config

Conversation

@C-Achard
Copy link
Copy Markdown
Contributor

Introduces a framework for hardware trigger support in the GenTL camera backend, along with related improvements to camera configuration management and GUI handling.
The main focus is on enabling configurable hardware trigger roles (off, external, master, follower), robust trigger configuration, and safe shutdown behavior.
It also introduces a new CameraTriggerSettings model, utilities for accessing and updating trigger settings, and ensures that configuration files include appropriate trigger defaults.

GenTL Camera Backend: Hardware Trigger Support and Configuration

  • Added support for hardware trigger roles (off, external, master, follower) in GenTL backend, with robust configuration and error handling using the new CameraTriggerSettings model. This includes methods for configuring trigger modes, input/output settings, and restoring safe states after acquisition. [1] [2] [3] [4] [5]
  • Improved GenTL backend capabilities reporting to indicate best-effort support for hardware triggers.
  • Added utility methods for working with GenICam nodes and trigger attributes, improving code robustness and maintainability.

Configuration Model and Utilities

  • Introduced CameraTriggerSettings as a pydantic model with validation and serialization utilities, supporting flexible trigger configuration in camera settings. Added methods to CameraSettings for accessing and updating trigger settings per backend.
  • Defined TriggerRole and TriggerActivation literals for type safety in trigger configuration.

GUI and Configuration Management

  • Ensured that saved configurations always include trigger defaults for GenTL cameras, and updated config serialization/deserialization to handle new trigger settings. [1] [2]
  • Improved error handling and flexibility in the GUI for model path validation and configuration saving, allowing saving without a model path if needed. [1] [2]

Other

  • Updated capability reporting in the base camera backend to include hardware_trigger as unsupported by default.
  • Added imports and type references for new trigger settings in relevant files.

C-Achard added 4 commits May 28, 2026 14:13
Add generic hardware-trigger support for GenTL cameras and expose trigger settings in CameraSettings.

- Introduce CameraTriggerSettings model (config.py) with role/input/output/timeout/strict and helpers to coerce and serialize.
- Allow CameraSettings to read/write backend-specific trigger options.
- GenTLCameraBackend: import and use trigger settings, apply trigger timeout override, persist actual trigger config, and mark hardware_trigger capability as BEST_EFFORT.
- Implement trigger configuration paths: off, external/follower (input), and master (output). Add helper methods (_set_enum_node, _node, _node_symbolics, _trigger_attr, _trigger_to_dict) to safely interact with GenICam nodes.
- Improve lifecycle handling: configure trigger after other settings, restore a safe non-triggering state on stop, and provide waits_for_hardware_trigger property and clearer timeout messages when waiting for hardware triggers.
- Add DEFAULT_CAPABILITIES entry for hardware_trigger in base defaults.

These changes enable safer and configurable hardware-trigger operation for GenTL backends and improve error reporting and shutdown behavior.
Populate gentl trigger defaults on save and allow saving configs with empty DLCLive model path. Add _with_camera_defaults_for_save to ensure CameraTriggerSettings are present for gentl cameras and thread through allow_empty_model_path in _dlc_settings_from_ui/_current_config so configs can be saved without a model while preserving existing DLC fields.

Improve multi-camera runtime robustness: treat TimeoutError from hardware-trigger backends as an expected 'no trigger' event (don't count as a camera failure) and add _trigger_role_from_settings/_camera_start_priority helpers. Start active cameras sorted by trigger role so trigger-waiting (external/follower) devices are armed before masters. Also extend DLCLive configuration error handling to include RuntimeError.
Enhance Qt app signal handling to support SIGTERM and SIGBREAK, and make Ctrl+C shutdown more robust. Adds a quitting flag and a two-stage interrupt: first interrupt triggers window close and schedules app.quit, second interrupt forces immediate exit (os._exit(130)). Parents the keepalive QTimer to the QApplication, sets a 100ms interval, and safely stops any previous timer to avoid duplicates. Adds logging and exception handling around window close and timer cleanup, and uses QTimer.singleShot to ensure Qt leaves its event loop even if closeEvent cleanup is asynchronous.
Add a comprehensive test suite for GenTL hardware trigger handling (tests/cameras/backends/test_gentl_trigger.py). Tests cover trigger roles (off/external/follower/master), selector/source/activation settings, strict vs non-strict behavior for invalid sources, master output configuration, alias mapping, timeout handling and error messaging, and persistence of trigger_actual for debugging. Update the test conftest fake node map (tests/cameras/backends/conftest.py) to include Trigger* and Line* nodes (AcquisitionMode, TriggerSelector, TriggerMode, TriggerSource, TriggerActivation, LineSelector, LineMode, LineSource) so the tests can exercise trigger and GPIO-related configuration.
@C-Achard C-Achard requested a review from Copilot May 28, 2026 12:32
@C-Achard C-Achard self-assigned this May 28, 2026
@C-Achard C-Achard added camera Related to cameras and camera backends config Related to user configs, oading, saving, etc labels May 28, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds GenTL hardware trigger configuration support and related GUI/configuration handling for saving trigger defaults and managing trigger-aware multi-camera startup/shutdown behavior.

Changes:

  • Introduces CameraTriggerSettings and trigger capability reporting.
  • Adds GenTL trigger configuration, timeout handling, and shutdown restore logic.
  • Updates GUI/config save behavior and multi-camera worker handling for hardware-triggered cameras.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
dlclivegui/config.py Adds trigger settings model and camera helpers.
dlclivegui/cameras/base.py Adds default hardware trigger capability flag.
dlclivegui/cameras/backends/gentl_backend.py Implements GenTL trigger roles, configuration, timeout messages, and restore behavior.
dlclivegui/services/multi_camera_controller.py Handles trigger timeouts and orders camera startup by trigger role.
dlclivegui/gui/main_window.py Adds GenTL trigger defaults during config save and relaxes save-time model path validation.
dlclivegui/main.py Improves signal handling for graceful/forced shutdown.
tests/cameras/backends/conftest.py Extends fake GenTL node map with trigger/GPIO nodes.
tests/cameras/backends/test_gentl_trigger.py Adds GenTL trigger behavior tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dlclivegui/gui/main_window.py Outdated
Comment thread dlclivegui/cameras/backends/gentl_backend.py
Comment thread dlclivegui/cameras/backends/gentl_backend.py Outdated
C-Achard added 6 commits May 28, 2026 15:01
Use the user-configured camera order for display/tiling and ensure tiling geometry matches displayed frames. Changes:

- GUI: populate the inference camera dropdown from active cameras in the configured order and only add entries for cameras that are actually running.
- MultiCameraController: store the user display order, derive startup order by sorting for trigger safety (followers/external first, master last), emit frames/timestamps in display order (with any unexpected IDs appended deterministically), clear display order on stop, and handle no-active-cameras early.
- Utils: compute_tiling_geometry now uses the frames' display order (insertion order) rather than sorted keys so tile dimensions and overlays align with the tiled frame; updated docstrings to reflect this.

These changes ensure consistent tiling, overlay transforms, and UI behavior that follow the user's configured ordering.
Update display tests to assert that tiling and tile computations preserve frame insertion/display order (no longer sorting by camera ID) and add coverage for tile offsets, scaling, and tiled frame content. Add a suite of unit tests for MultiCameraController utilities and behavior: get_camera_id, trigger role aliasing, camera start priority, preserving user display order on start, frame_ready emission order, clearing display order on stop, hardware trigger timeouts (non-fatal), and non-trigger timeouts (fatal). Also import newly-tested helper functions from multi_camera_controller.
Patch tests/gui/test_app_entrypoint.py to monkeypatch appmod._maybe_allow_keyboard_interrupt with a MagicMock in both test_main_with_splash and test_main_without_splash. This prevents the real interrupt-handling helper from running during GUI tests and avoids side effects on global keyboard/signal handling.
GenTLCameraBackend: add handling for a 'strict' flag when parsing GenTL trigger config so invalid configs raise in strict mode but fall back with a warning otherwise. Preserve the original exception when raising, and improve the warning text to mention strict mode. Return whether LineSelector was actually set and skip configuring trigger output if selection failed to avoid driving an unintended GPIO line.

DLCLiveMainWindow: introduce _with_camera_trigger_defaults_for_save to ensure gentl trigger defaults are stored per camera, refactor _with_camera_defaults_for_save to apply that per-camera, and adjust _current_config to use the first camera with defaults applied. This ensures trigger settings are persisted and validated consistently.
Add with_save_defaults helpers to CameraSettings and MultiCameraSettings and use them when serializing ApplicationSettings so gentl "trigger" defaults are applied to saved configs. Remove duplicated camera-default helper logic from DLCLiveMainWindow and simplify _current_config to rely on model methods. Add unit tests to verify gentl trigger defaults are included for top-level and multi-camera cases.
Remove sorting when building available_ids so the original frame key order is preserved. The DLC camera selection relies on the first active camera in frame_data.frames; using list(...) keeps the insertion/order semantics (dict order) instead of reordering keys with sorted(). This avoids unintended changes to camera priority caused by alphabetical/numeric sorting.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Comment thread dlclivegui/services/multi_camera_controller.py
Comment thread dlclivegui/gui/main_window.py Outdated
Initialize an existing DLC config (falling back to DEFAULT_CONFIG if unset) and use its model_copy(update=...) to return settings. This replaces explicit field-by-field construction so only model_path (and model_type when set) are changed, preserving other DLC options and avoiding duplication.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Comment thread dlclivegui/cameras/backends/gentl_backend.py Outdated
Comment on lines +125 to +127
trigger_timeout = self._positive_float(self._trigger_attr(self._trigger, "timeout", None))
if trigger_timeout is not None:
self._timeout = float(trigger_timeout)
Comment thread dlclivegui/config.py
C-Achard added 3 commits May 28, 2026 16:56
Add a warning log when setting GenTL TriggerMode to 'On' fails in non-strict mode. Previously the code only raised an exception in strict mode; now it emits a warning to inform users that the trigger mode may not be correctly configured when continuing without strict enforcement.
Make GenTLCameraBackend trigger configuration more robust and adjust tests.

- Use the waits_for_hardware_trigger property when converting GenTL timeouts to user-facing errors instead of inferring from the role string.
- Read and record the configured trigger role early in _configure_trigger_input.
- Check results when setting TriggerSelector, TriggerSource and TriggerActivation (selector_ok, source_ok, activation_ok). If selector/source routing fails in non-strict mode, disable the trigger, reset internal trigger state and log a warning to avoid arming the camera on a previous/default input line. If activation fails, warn and continue using the camera default.
- If enabling TriggerMode=On fails, disable the trigger and reset internal state instead of only warning.
- Validate LineMode and LineSource when configuring master output and log if configuration is incomplete.

Tests updated to reflect safety changes:
- Expect waits_for_hardware_trigger to be set for external input configuration.
- Rename and change a non-strict invalid-source test to assert the trigger is disabled, waits_for_hardware_trigger is False, and trigger_actual is persisted as off.
- Add a new test ensuring an invalid selector in non-strict mode disables the trigger and persists the off state.

These changes prevent the camera from being left armed on an unintended/default input if routing nodes could not be applied, improving safety and predictability.
Introduce a MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT and cap Harvester.fetch() timeouts when the trigger role waits for external hardware (roles: external, follower) to keep individual fetch calls short and allow prompt shutdown. Preserve legacy behavior for non-waiting roles (e.g. master). Remove a noisy Trigger input LOG.info call. Update tests to expect the capped fetch timeout, verify the original requested timeout is still persisted in trigger_actual, add a test that master mode is not capped, and make test resource cleanup more robust (use try/finally around open/close).
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Comment thread dlclivegui/config.py
Comment on lines +503 to +509
active_cameras = multi_camera.get_active_cameras()

if active_cameras:
camera = active_cameras[0].model_copy(deep=True)
else:
camera = self.camera.with_save_defaults()

Comment on lines +109 to +116
if bool(getattr(self._backend, "waits_for_hardware_trigger", False)):
LOGGER.debug(
"[Worker %s] waiting for hardware trigger: %s",
self._camera_id,
exc,
)
consecutive_errors = 0
continue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

camera Related to cameras and camera backends config Related to user configs, oading, saving, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Hardware-trigger mode to gentl/basler backends Allow users to specify ID:camera mapping

2 participants