LifFreqConversionStage
LifFreqConversionStage is the hardware-type base class for one
crystal or compensator node in the LIF frequency-conversion topology —
a doubler, a sum-frequency mixer, a difference-frequency mixer. It is a
direct HardwareObject child, a sibling of
LifLaser rather than a subtype of it, registered like any
other hardware type (see Adding a New Hardware Type,
which uses this class as a worked example of a type whose
device-identity settings are pinned by concrete drivers). The base
class owns only the generic contract every conversion node shares: the
registered conversion operation (conversionOp()) and harmonic
order (harmonicOrder()) — both snapshot-visible via
SettingsStorage so a GUI or data-layer caller can read them
without touching a live threaded device — a verify flag/tolerance pair,
and the setPosition()/readPosition() dispatch slots
that move to and confirm a local input-beam wavenumber (cm⁻¹). The DAG
wiring itself (input references, the FINAL marker) is per-experiment
state owned by LifConversionSnapshot and
LifConfig, not by the stage — see Key invariants on
LIF Acquisition and Visualization for the full op/harmonic-versus-wiring
split.
A concrete driver such as SirahFcu pins conversionOp() to
a hardware-frozen constant (a doubler is NHG by device identity,
not a free choice) while leaving the registered op setting in
place, and overrides setHarmonicOrder() to route a harmonic
change through the device before persisting it — the canonical example
of the gated setting pattern described on
Hardware Configuration.
VirtualLifFreqConversionStage and FixedLifFreqConversionStage
are the uncontrolled/CI implementations.
Three free functions declared alongside the class join a
LifConversionSnapshot’s wiring with each stage’s
snapshot-read op/harmonic into an assembled
LifConversion, without ever touching a live threaded
device: lifConversionNodesFromSnapshot builds the joined node list,
assembleLifConversion assembles it, and
assembleCurrentLifConversion is the convenience wrapper that
resolves the current loadout’s current LifPreset,
falling back to the identity conversion when none is selected. These
are the building blocks behind the prep-time and connection-complete
assembly paths described on LIF Acquisition and Visualization
(Frequency conversion → Data flow by moment).
API Reference
-
class LifFreqConversionStage : public HardwareObject
Base class for a LIF frequency-conversion stage (FCU): a crystal or compensator node in the optical conversion topology between the tunable LifLaser fundamental and the FINAL output beam.
A direct child of HardwareObject (sibling of LifLaser), so it earns its own hwType. The base owns the generic contract shared by every conversion node: the registered device-identity settings (conversionOp(), harmonicOrder() — op/harmonic order, snapshot-visible so a GUI/data-layer caller can read them without touching the threaded device), a per-device verify flag, and the setPosition()/readPosition() dispatch slots that move to and confirm a local input-beam wavenumber (cm⁻¹). The DAG wiring (input refs, FINAL marker) is per-experiment state owned by LifConversionSnapshot/LifConfig, not by the stage. Structured calibration settings (crystal/compensator angle-vs-wavelength polynomials, mount addresses) differ by driver and are not declared here.
A stage emits no output-position update to the display; only LifLaser::laserPosUpdate drives the axis.
Subclassed by FixedLifFreqConversionStage, SirahFcu, VirtualLifFreqConversionStage
Public Functions
-
LifFreqConversionStage(const QString &impl, const QString &label, QObject *parent = nullptr)
-
~LifFreqConversionStage() override
-
virtual BC::LifConv::Op conversionOp() const
This stage’s conversion operation (NHG/SFG/DFG).
Base implementation reads the registered
opsetting. A doubler or mixer driver is that operation by device identity — not a free choice — so concrete drivers override this to a constant; the registered setting itself stays declared on the base for every stage (concrete drivers pin its default) so it remains snapshot-visible even where the driver treats it as fixed (see the C-6 assembly join, which reads settings snapshots rather than calling this virtual on a live threaded device).
-
inline int harmonicOrder() const
Harmonic order N for an NHG stage (the registered
harmonicsetting; ignored for SFG/DFG).
-
virtual bool setHarmonicOrder(int n)
Driver hook for a gated harmonic-order change.
Base implementation persists n to the registered
harmonicsetting and returnstrue. A unit that can retune its harmonic output in firmware overrides this to issue the hardware command (and update the setting on success), so a harmonic change always passes through the device rather than being a raw setting poke.- Returns:
Whether the change succeeded.
Public Slots
-
bool setPosition(double localCm1)
Dispatch target: move to this stage’s PRIMARY input-beam wavenumber (cm⁻¹).
localCm1 is already computed by the caller from the assembled conversion topology (LifConversion::stageInput); the stage itself needs no topology. Maps the requested wavenumber to a phase-match motor position via the driver’s calibration, moves, then verifies via readPos(). A negative readPos() is a hard communication-error sentinel, not a value the stage actually reported, so it always emits hardwareFailure() and returns false regardless of the verify flag. For an in-range readback that simply misses the requested wavenumber, the verify flag (BC::Key::LifConvStage::verify) decides the outcome: off logs a warning and returns true (best-effort); on emits hardwareFailure() and returns false.
- Returns:
Whether the move (and, if enabled, its verification) succeeded.
-
double readPosition()
Verify hook: this stage’s achieved local input-beam wavenumber (cm⁻¹), or <0 on error.
-
LifFreqConversionStage(const QString &impl, const QString &label, QObject *parent = nullptr)
-
std::vector<BC::LifConv::Node> lifConversionNodesFromSnapshot(const LifConversionSnapshot &snap)
Join snap’s wiring with op/n read from each stage’s active hardware settings snapshot into a node list, without touching any threaded device.
For every BC::LifConv::StageWiring entry, builds a SettingsStorage snapshot directly on the stage’s hardware key (never a live device) to read conversionOp()/harmonicOrder(). Shared by assembleLifConversion() and by callers that need the joined node list itself (e.g. the conversion table model, when seeding wiring from a preset snapshot).
- Returns:
The joined node list; empty when snap has no wiring.
-
LifConversion::AssemblyResult assembleLifConversion(const LifConversionSnapshot &snap)
Assemble a LIF frequency-conversion topology by joining snap’s wiring with op/n read from each stage’s active hardware settings snapshot, without touching any threaded device.
Builds the node list via lifConversionNodesFromSnapshot() and assembles it with LifConversion::assemble(). Snapshot-only, so it is safe to call from GUI or data-layer threads.
- Returns:
The assembly result:
okandconversionon success, orok== false anderrorStringon a malformed topology.
-
LifConversion::AssemblyResult assembleCurrentLifConversion()
Convenience wrapper: assemble the current LIF preset’s conversion wiring for the current loadout.
Resolves LoadoutManager::instance().currentLoadoutName() and that loadout’s current LIF preset. When no loadout or no LIF preset is selected, returns the identity AssemblyResult (
ok== true, identity LifConversion) rather than an error, matching the tolerant fallback used by GUI callers (config page, live laser widget) that need the active topology to compute display ranges but must stay responsive when the topology is not yet configured.- Returns:
The assembly result for the current preset, or the identity result when no preset is selected.