BatchManager
BatchManager is the abstract base class that controls the lifecycle of an
acquisition run from the main window’s perspective. Every acquisition in
Blackchirp — whether it consists of a single experiment or a timed sequence of
experiments — is represented by a concrete BatchManager subclass and
submitted to MainWindow::startBatch. The main window connects the batch’s
signals to AcquisitionManager and the UI, then triggers the first
experiment via HardwareManager. The user-facing workflow for
starting experiments and batch sequences is described in
Experiment Setup.
BatchManager lives on the main (GUI) thread. Its signals reach
AcquisitionManager (which lives on a dedicated background thread) via queued
connections. Slots on BatchManager are called from the GUI thread by the
main window or by AcquisitionManager’s experimentComplete signal.
The immediate collaborators are:
Experiment — each experiment in the batch is a shared pointer that
currentExperiment()returns to the caller.AcquisitionManager — drives the hardware acquisition loop for each experiment; its
experimentCompletesignal is connected toBatchManager::experimentCompletefor the duration of the batch.
The two built-in concrete subclasses are BatchSingle (wraps a single
experiment; BatchType::SingleExperiment) and BatchSequence (repeats an
experiment template on a configurable interval; BatchType::Sequence). The
batch type in use is identified by the BatchType enum stored in d_type.
State machine
The iterate-over-experiments loop proceeds as follows:
MainWindow::startBatchconnects signals, then callsHardwareManager::initializeExperiment(currentExperiment())to start the first experiment.BatchManageremitsbeginExperiment()for subsequent experiments (see step 5).HardwareManagerconfigures hardware and emitsexperimentInitialized. The main window callsExperiment::initialize()on success, then invokesAcquisitionManager::beginExperiment(exp)on the AM thread.AcquisitionManagerruns the acquisition loop and, when it ends (normally or via abort), emits itsexperimentCompletesignal.That signal is connected to
BatchManager::experimentComplete(the slot). The slot:Logs the experiment result via
Experiment::d_endLogMessage.Calls
processExperiment()if hardware and software initialization both succeeded.Evaluates
isComplete()and whether the experiment was aborted.
If initialization succeeded, the experiment was not aborted, and
isComplete()returnsfalse, the slot callsbeginNextExperiment(), which by default emitsbeginExperiment()immediately. The main window responds by invokingHardwareManager::initializeExperiment(currentExperiment())for the next experiment (go to step 2).If the batch is complete, or if the experiment was aborted, or if initialization failed:
abort()is called when the experiment was aborted or init failed.writeReport()is called unconditionally.batchComplete(aborted)is emitted, whereabortedreflectsExperiment::isAborted().
The connection between AcquisitionManager::experimentComplete (signal) and
BatchManager::experimentComplete (slot) is the central handoff between the
two managers. The signal fires on the AM thread and is delivered to the BM slot
on the GUI thread via a queued connection.
Subclassing guide
A new batch type inherits BatchManager and implements the following pure-virtual
methods:
currentExperiment()Return the experiment that is either in progress or about to be acquired. Called by the main window each time
beginExperiment()is emitted, and byexperimentComplete()to inspect the result. Must never return a null pointer while the batch is active.isComplete()Return
truewhen no further experiments remain. Evaluated byexperimentComplete()afterprocessExperiment()returns.abort()Mark the batch as complete so
isComplete()returnstrueand release any pending timers or queued work. Called when the user clicks the abort button or when hardware initialization fails.processExperiment()Perform any post-acquisition analysis or bookkeeping for the most recently completed experiment. Called only when initialization succeeded. May be a no-op.
writeReport()Write a summary report for the batch (file, log entry, or nothing). Called unconditionally after the last experiment ends, before
batchCompleteis emitted.
The optional override beginNextExperiment() is available when the default
behavior — emit beginExperiment() immediately — is not appropriate. For
example, BatchSequence overrides this method to start a QTimer and emit
beginExperiment() only after the configured inter-experiment interval has
elapsed.
To register a new batch type with the main window, add a BatchType enumerator,
construct the concrete subclass in the appropriate MainWindow action handler,
and pass it to MainWindow::startBatch.
API Reference
-
class BatchManager : public QObject
Abstract base class that iterates one or more experiments through AcquisitionManager and signals completion to the main window.
BatchManager coordinates the lifecycle of an acquisition run, whether it consists of a single experiment (BatchSingle) or a timed sequence (BatchSequence). The main window constructs a concrete subclass and passes it to MainWindow::startBatch(), which connects the batch’s signals to AcquisitionManager and the UI, then triggers the first experiment via HardwareManager::initializeExperiment().
BatchManager lives on the main (GUI) thread. Its signals cross into the AcquisitionManager thread via queued connections; its slots are called from the GUI thread by the main window or by AcquisitionManager’s experimentComplete() signal.
Subclass authors must implement the five pure-virtual hooks described below. The optional beginNextExperiment() override is available when the default behavior — emit beginExperiment() immediately — is not appropriate (for example, BatchSequence delays the next experiment by a configurable interval).
See also
AcquisitionManager, BatchSingle, BatchSequence
Subclassed by BatchSequence, BatchSingle
Public Types
Public Functions
-
virtual std::shared_ptr<Experiment> currentExperiment() = 0
Returns the experiment that is in progress or about to be acquired.
Called by the main window inside the beginExperiment() signal handler to pass the experiment to HardwareManager::initializeExperiment(). Also called by experimentComplete() to inspect the result of the last acquisition.
- Returns:
Shared pointer to the active experiment. Must never be null while the batch is in progress.
-
explicit BatchManager(BatchType b)
Constructs the base with the given batch type.
- Parameters:
b – The BatchType that identifies the concrete subclass.
-
virtual ~BatchManager()
Destroys the batch manager.
-
virtual bool isComplete() = 0
Returns
truewhen no further experiments remain to be acquired.Evaluated inside experimentComplete() after processExperiment() returns. If
true, the batch writes its report and emits batchComplete().- Returns:
trueif the batch sequence has finished all configured experiments.
Public Slots
-
void experimentComplete()
Responds to AcquisitionManager::experimentComplete().
Logs the experiment result, calls processExperiment() if initialization succeeded, then either advances to the next experiment via beginNextExperiment() or ends the batch by calling writeReport() and emitting batchComplete().
The decision tree is:
If init succeeded and batch is not complete: call beginNextExperiment().
If init succeeded and batch is complete: write report, emit batchComplete(false).
If the experiment was aborted or init failed: call abort(), write report, emit batchComplete(true).
Note
This slot and AcquisitionManager::experimentComplete() share the same name but are different entities: the AM signal triggers this BM slot.
-
virtual void beginNextExperiment()
Advances to the next experiment in the batch.
The default implementation emits beginExperiment() immediately. Subclasses may override to insert a delay or other inter-experiment logic (see BatchSequence).
Note
Called by experimentComplete() when the batch is not yet complete and initialization of the previous experiment succeeded.
-
virtual void abort() = 0
Aborts the batch unconditionally.
Implementations must mark the batch as complete so that isComplete() returns
trueand no further experiments are started. They must also ensure that any pending timers or resources are released.Note
Called by experimentComplete() when the experiment was aborted or hardware initialization failed, and by the main window abort button.
Signals
-
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 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 beginExperiment()
Signals that the next experiment in the batch should begin.
The main window connects this signal to a lambda that calls HardwareManager::initializeExperiment(currentExperiment()). Emitted by beginNextExperiment() (or by an overriding subclass after a delay).
-
void batchComplete(bool aborted)
Emitted when the batch has finished, either normally or by abort.
Connected to MainWindow::batchComplete(). After this signal, the batch manager is no longer active and will be deleted on the next batch start.
- Parameters:
aborted –
trueif the last experiment was aborted;falsefor normal completion.
Protected Functions
-
virtual void writeReport() = 0
Writes a summary report for the completed batch.
Called by experimentComplete() after the last experiment finishes (either normally or by abort) and before batchComplete() is emitted. Implementations may write a file, log a summary, or take no action.
-
virtual void processExperiment() = 0
Performs any post-acquisition processing for the most recently completed experiment.
Called by experimentComplete() after a successful initialization/acquisition cycle, before isComplete() is evaluated. Implementations may re-analyze data, update state, or do nothing.
-
virtual std::shared_ptr<Experiment> currentExperiment() = 0