AcquisitionManager
AcquisitionManager is the object that drives a single Experiment
from the moment hardware initialization completes through the end of the
acquisition loop. It owns the in-progress experiment shared pointer, accumulates
FID waveforms and auxiliary sensor readings into the per-experiment storage tree,
and emits the lifecycle signals that coordinate the main window, the hardware
layer, and the batch layer. All acquisitions in Blackchirp — single-experiment
runs as well as multi-experiment batch sequences — pass through
AcquisitionManager. The user-facing acquisition workflow is described in
Experiment Setup.
The manager lives on a dedicated QThread ("AcquisitionManagerThread") created
in MainWindow. Its slots and signal emissions execute on that thread.
The GUI thread uses QMetaObject::invokeMethod to cross the thread boundary
when calling AcquisitionManager::beginExperiment(). Waveform
processing is further dispatched to the Qt thread pool via QtConcurrent::run;
the processing result is handed back to the AM thread through a
QFutureWatcher<FtmwProcessingResult> so that state mutations remain
thread-confined.
The immediate collaborators are:
Experiment — the in-progress experiment shared pointer; the AM writes FID data and aux readings into its storage objects and queries it for completion status.
HardwareManager (cross-thread) — receives
beginAcquisitionandendAcquisitionto start and stop hardware triggers; provides aux data via itsauxDatasignal; applies clock settings in response tonewClockSettings.FidStorageBase — the FID storage layer embedded in the experiment; waveform data accumulate here.
AuxDataStorage — the auxiliary sensor storage embedded in the experiment; each timed aux-data point is committed here.
BatchManager (GUI thread, queued connection) — receives
experimentCompleteafter every acquisition loop ends and decides whether to start the next experiment.LifStorage (LIF mode only) — the LIF storage object embedded in the experiment when a LIF scan is configured.
State machine
AcquisitionManager tracks its phase through the AcquisitionState enum.
State |
Meaning |
|---|---|
|
No experiment is running. The manager is ready for a new
|
|
An experiment is active. Waveform data, aux readings, and validation checks are processed as they arrive. |
|
Acquisition is suspended. Incoming data are dropped until |
The typical lifecycle of a single experiment is:
MainWindow::experimentInitializedreceivesHardwareManager::experimentInitialized, callsExperiment::initialize(), and invokesbeginExperiment(exp)on the AM thread.beginExperimenttransitions toAcquiring, emitsnewClockSettings(FTMW experiments), emitsbeginAcquisition, starts the aux-data interval timer, and starts the FTMW drain timer for buffered-waveform modes.During the loop, the aux-data timer fires periodically; each firing calls
auxDataTick, which collects FTMW shot counts (and optional phase/chirp metrics), callsprocessAuxData, and emitsauxDataSignalsoHardwareManagercan read sensor values.processAuxDatastores the readings inAuxDataStorageand re-emits them asauxData(map, timestamp)for plot widgets.processValidationDatachecks each incoming sensor value against its configured limit; a violation triggersabort.FTMW waveforms arrive through a
WaveformBufferpolled by the drain timer. Batches of entries are dispatched to a worker viaQtConcurrent::run; theQFutureWatcher<FtmwProcessingResult>delivers the result back to the AM thread. A processing failure callsabort.checkCompleteis called after each processing batch. IfExperiment::canBackupis true it launches a concurrent backup viaQtConcurrent::run(theQFutureWatcher<void>emitsbackupCompletewhen done). IfExperiment::isCompleteis true it callsfinishAcquisition.pauseandresumetoggle betweenAcquiringandPausedwithout stopping hardware. WhilePausedthe drain timer still fires but skips processing.abortmarks the experiment as aborted and callsfinishAcquisition.finishAcquisitionstops the drain timer, signals the worker to exit, waits for the worker to finish, emitsendAcquisition, transitions toIdle, callsExperiment::finalSave, and emitsexperimentComplete.
Note
AcquisitionManager::experimentComplete is a signal; the identically
named BatchManager::experimentComplete is a slot. The two are
connected via a queued connection that crosses the AM thread into the GUI
thread, and this signal-to-slot handoff is what advances a batch from one
experiment to the next.
Backups
The acquisition loop launches periodic backups of the in-progress experiment
on a worker thread via QtConcurrent::run. QFutureWatcher raises the
backupComplete signal on the AM thread when each backup finishes, and
FtmwViewWidget connects to it to refresh its list of available backups.
API Reference
-
struct FtmwProcessingResult
Result of a worker-thread waveform-processing batch.
Returned by the QtConcurrent worker to the AcquisitionManager event loop so that side-effect operations (advance, signals, abort) remain on the AM thread. The struct is the sole cross-thread data contract between the waveform-processing worker and the manager.
Public Members
-
int entriesProcessed = {0}
Number of waveform entries processed in this batch.
-
bool success = {true}
falseif a fatal processing error occurred.
-
QString errorString
Non-empty when
successisfalse; describes the error.
-
QString warningString
Non-empty when a non-fatal anomaly was detected.
-
int entriesProcessed = {0}
-
class AcquisitionManager : public QObject
Drives a single Experiment from hardware initialization through acquisition-loop completion.
AcquisitionManager owns the in-progress Experiment shared pointer, accumulates FID data and auxiliary sensor readings into the per-experiment storage tree, and emits the signals that notify the main window, HardwareManager, and BatchManager of lifecycle events.
The manager lives on a dedicated QThread (“AcquisitionManagerThread”) created in MainWindow. All public slots and signal emissions execute on that thread. Callers on other threads must use QMetaObject::invokeMethod or queued signal/slot connections — direct calls from the GUI thread are not safe.
Waveform processing is dispatched to the Qt thread pool via QtConcurrent::run; the result is returned to the AM thread through a QFutureWatcher so that all state mutations remain thread-confined.
See also
Public Types
-
enum AcquisitionState
Describes the current phase of the acquisition loop.
Values:
-
enumerator Idle
No experiment is running; the manager accepts a new beginExperiment call.
-
enumerator Acquiring
An experiment is active and data are being collected.
-
enumerator Paused
Acquisition is temporarily suspended; no new data are processed.
-
enumerator Idle
Public Functions
-
explicit AcquisitionManager(QObject *parent = nullptr)
Constructs an AcquisitionManager with the given parent.
-
~AcquisitionManager()
Destroys the manager, waiting for any in-flight waveform worker to finish.
Public Slots
Begins acquiring data for the given experiment.
Called by MainWindow::experimentInitialized() via QMetaObject::invokeMethod after hardware initialization succeeds. Sets the state to Acquiring, emits beginAcquisition(), starts the aux-data timer if configured, and starts the FTMW drain timer for buffered waveform modes.
- Parameters:
exp – Shared pointer to the fully initialized experiment. The manager holds this pointer for the duration of the acquisition loop.
-
void processAuxData(AuxDataStorage::AuxDataMap m)
Incorporates a map of aux-sensor readings into the current experiment.
Stores the readings in the experiment’s AuxDataStorage and forwards the data map via the auxData() signal. If storage fails, abort() is called. No-op when the state is not Acquiring.
- Parameters:
m – Map of sensor key to measured value returned by HardwareManager.
-
void processValidationData(AuxDataStorage::AuxDataMap m)
Validates a map of sensor readings against the experiment’s limit set.
Calls Experiment::validateItem() for each entry. If any value exceeds its configured limit, abort() is called. No-op when the state is not Acquiring.
- Parameters:
m – Map of sensor key to measured value returned by HardwareManager.
-
void clockSettingsComplete(const QHash<RfConfig::ClockType, RfConfig::ClockFreq> clocks)
Records the actual clock frequencies applied by hardware.
Called when HardwareManager emits allClocksReady. Stores the confirmed frequencies in the FTMW configuration and marks hardware as ready so waveform acquisition can proceed.
- Parameters:
clocks – Map from clock type to the frequency actually programmed by hardware.
-
void pause()
Suspends data processing without stopping hardware triggers.
Transitions from Acquiring to Paused. Incoming waveform data and aux readings are dropped until resume() is called. No-op if the state is not Acquiring.
-
void resume()
Resumes data processing after a pause.
Transitions from Paused back to Acquiring. No-op if the state is not Paused.
-
void abort()
Aborts the current experiment and ends the acquisition loop.
Marks the experiment as aborted, then calls finishAcquisition(). Safe to call from Acquiring or Paused. No-op from Idle.
-
void processLifDigitizerShot(const QVector<qint8> b)
Accumulates a raw LIF waveform shot into the current LIF scan point.
Adds the waveform to the LIF configuration, emits lifPointUpdate(), and advances to the next scan point if the current point is complete. Calls checkComplete() to detect overall experiment completion.
- Parameters:
b – Raw 8-bit waveform bytes from the LIF digitizer.
-
void lifHardwareReady(bool success)
Notifies the manager of the outcome of a LIF hardware configuration step.
If success is
false, the experiment is aborted. Iftrue, the LIF configuration is marked hardware-ready so shot acquisition can proceed.- Parameters:
success –
trueif the LIF delay and frequency were set successfully.
-
void requestBackup()
Requests an immediate backup of the current FID list.
Connected to FtmwViewWidget’s manual backup toolbar action via a queued signal/slot wire. The request is silently ignored if no experiment is active, if the FTMW mode does not support backups (only
Target_Shots,Target_Duration, andForeverdo), or if the experiment is in theIdlestate. If an automatic backup is already in flight, the request is folded into that backup — the in-flight write becomes the user’s manual snapshot for reporting purposes.
Signals
-
void logMessage(QString msg, LogHandler::MessageCode code = LogHandler::Normal)
Requests that a message be appended to the application log.
- Parameters:
msg – The text to log.
code – Severity classification; defaults to LogHandler::Normal.
-
void statusMessage(QString msg, int timeout = 0)
Requests that a transient status string be displayed in the status bar.
- Parameters:
msg – The status text.
timeout – Display duration in milliseconds; 0 means indefinite.
-
void experimentComplete()
Emitted when the acquisition loop for the current experiment has ended.
Emitted after endAcquisition(), after the experiment is saved to disk, and before the experiment shared pointer is released. BatchManager::experimentComplete() is connected to this signal so the batch can decide whether to advance.
-
void ftmwUpdateProgress(int perMil)
Reports FTMW acquisition progress to the progress bar.
- Parameters:
perMil – Progress in units of 1/1000 of completion (0–1000).
-
void newClockSettings(QHash<RfConfig::ClockType, RfConfig::ClockFreq> clocks)
Notifies HardwareManager that clock frequencies should be applied.
Emitted at experiment start and whenever an FTMW segment boundary is crossed.
- Parameters:
clocks – Map from clock type to target frequency.
-
void beginAcquisition()
Notifies HardwareManager that data collection should begin.
Connected to HardwareManager::beginAcquisition. Emitted after clock settings have been dispatched at the start of beginExperiment().
-
void endAcquisition()
Notifies HardwareManager that data collection has ended.
Emitted inside finishAcquisition() before the state transitions to Idle. HardwareManager uses this to stop hardware triggers.
-
void auxDataSignal()
Requests that HardwareManager read and return aux sensor data.
Emitted on each aux-data timer tick. HardwareManager responds by emitting its auxData signal, which is connected to processAuxData().
-
void auxData(AuxDataStorage::AuxDataMap data, QDateTime timestamp)
Delivers a completed aux-data point to observers such as the plot widget.
- Parameters:
data – Map of sensor key to measured value.
timestamp – Acquisition time of the point.
-
void backupComplete()
Emitted when a concurrent backup operation launched via QtConcurrent has finished.
Connected to the FtmwViewWidget so that the view can refresh its backup list.
-
void lifPointUpdate()
Notifies the LIF display that the current LIF point has new data.
-
void nextLifPoint(double delay, double frequency)
Requests that HardwareManager configure LIF hardware for the next scan point.
- Parameters:
delay – Delay value in seconds for the next LIF point.
frequency – Laser frequency in wavenumbers for the next LIF point.
-
void lifShotAcquired(int perMil)
Reports LIF acquisition progress to the LIF progress bar.
- Parameters:
perMil – Progress in units of 1/1000 of completion (0–1000).
Protected Functions
-
void timerEvent(QTimerEvent *event) override
Handles the periodic aux-data timer tick.
On each firing of the aux-data interval timer, reads FTMW shot counts and optional phase/chirp metrics, then calls processAuxData() and emits auxDataSignal().
- Parameters:
event – The timer event; accepted if it matches the aux-data timer ID.
Private Functions
-
void auxDataTick()
-
void checkComplete()
-
void finishAcquisition()
-
void drainFtmwBuffer()
-
void onProcessingComplete()
-
void dispatchBackup()
-
void onBackupFinished()
-
void temporaryStatusMessage(const QString &msg, int msecs)
Emits a timed status message and queues the persistent “Acquiring”/”Paused” label to be restored when it expires.
Use for transient notifications (e.g. backup completions) that should briefly replace the acquisition-state label without leaving the bar blank afterward.
-
bool ftmwModeSupportsBackup() const
Private Members
-
std::unique_ptr<QFutureWatcher<void>> pu_fw
-
std::unique_ptr<QFutureWatcher<FtmwProcessingResult>> pu_processingWatcher
-
std::shared_ptr<Experiment> ps_currentExperiment
-
AcquisitionState d_state
-
int d_auxTimerId
-
QTimer *p_drainTimer = {nullptr}
-
std::atomic<bool> d_abortProcessing = {false}
-
bool d_lastBackupWasManual = {false}
Set by
requestBackup()/dispatchBackup()soonBackupFinished()can pick the right log/status message.
-
enum AcquisitionState