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
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ public interface AcquisitionManager {
*/
Future<?> requestRun(boolean speedTest);

/**
* Request that a test acquisition is run.
*
* <p>A test acquisition runs a single time point and does not save anything to disk. The
* settings shown in the user interface are left unchanged.
*
* @return a future that completes when the acquisition finishes
*/
Future<?> requestTestAcquisition();

/**
* Request the running acquisition to stop.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ private void createUserInterface() {
swapTimingSettingsPanels(isUsingAdvancedTiming);

btnRunOverviewAcq_.setEnabled(false); // TODO: re-enable when these features are put in
btnTestAcquisition_.setEnabled(false);

// set ui sizes, should match the MigLayout constraints
pnlChannelTable_.setAbsoluteSize(280, 400);
Expand Down Expand Up @@ -257,6 +256,7 @@ private void createEventHandlers() {
btnOpenPlaylist_.setEnabled(false); // TODO: enable when playlist is implemented

btnSpeedTest_.registerListener(() -> runAcquisition(true));
btnTestAcquisition_.registerListener(this::runTestAcquisition);
btnRunOverviewAcq_.registerListener(() -> {
// TODO: run the overview acq
});
Expand Down Expand Up @@ -326,6 +326,7 @@ private void acqFinishedCallback() {
btnRunAcquisition_.setState(false);
btnPauseAcquisition_.setEnabled(false);
btnSpeedTest_.setEnabled(true);
btnTestAcquisition_.setEnabled(true);
});
} catch (InterruptedException e) {
model_.studio().logs().logError("Acquisition was interrupted!");
Expand All @@ -337,7 +338,21 @@ private void acqFinishedCallback() {
private void runAcquisition(boolean speedTest) {
btnPauseAcquisition_.setEnabled(true);
btnSpeedTest_.setEnabled(false);
Future<?> acqFinished = model_.acquisitions().requestRun(speedTest);
btnTestAcquisition_.setEnabled(false);
waitForAcquisition(model_.acquisitions().requestRun(speedTest));
}

private void runTestAcquisition() {
// this run is started from a button that is not the toggle, so select the toggle here
// or it reads "Start Acquisition" for as long as the test acquisition is running
btnRunAcquisition_.setState(true);
btnPauseAcquisition_.setEnabled(true);
btnSpeedTest_.setEnabled(false);
btnTestAcquisition_.setEnabled(false);
waitForAcquisition(model_.acquisitions().requestTestAcquisition());
}

private void waitForAcquisition(final Future<?> acqFinished) {
// Launch new thread to update the button when the acquisition is complete
new Thread(() -> {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,21 @@ public void loadFromJson(final String json, final boolean notify) {
* Save user settings.
*/
public void save() {
// make settings current before saving
model_.acquisitions().updateSettings();

// settings key based on geometry type
final GeometryType geometryType = model_.devices().adapter().geometry();
final String key = SETTINGS_PREFIX + geometryType.toString().toUpperCase();

// Build from the builder, which holds what the user set in the user interface. The
// acquisition settings can carry run scoped overrides, for example a test acquisition
// turning saving off, and writing one of those to the profile would change the user's
// settings for every later session. Building here also means saving no longer rebuilds
// the settings a running acquisition is reading.
final ScapeAcquisitionSettings settings = model_.acquisitions().settingsBuilder().build();

// save acquisition settings
settings_.putString(key, model_.acquisitions().settings().toJson());
settings_.putString(key, settings.toJson());
model_.studio().logs().logDebugMessage("saved JSON to " + key + ": "
+ model_.acquisitions().settings().toPrettyJson());
+ settings.toPrettyJson());

// save plugin settings
settings_.putString(SETTINGS_PLUGIN, model_.pluginSettings().toJson());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ public abstract class AcquisitionEngine implements AcquisitionManager, MMAcquist
// cannot answer "is a run in flight?": the engines only assign it partway through run(), so it
// stays null across all of setup() and the arming that follows.
private volatile boolean acquisitionRequested_ = false;
// true while a test acquisition is in flight, read by updateSettings()
private volatile boolean testAcquisition_;

// a stop asked for before the acquisition was started, acted on by the checks in requestRun()
// and in each engine's run()
private volatile boolean stopRequested_ = false;
Expand Down Expand Up @@ -282,7 +285,20 @@ public void updateSettings(final ScapeAcquisitionSettings acqSettings) {
* Build the {@code DefaultAcquisitionSettingsSCAPE} with the builder and update settings.
*/
public void updateSettings() {
acqSettings_ = asb_.build();
// Build fully before assigning: acqSettings_ is read from other threads, and a second
// assignment here would briefly publish the user's settings during a test acquisition.
ScapeAcquisitionSettings settings = asb_.build();
// Re-apply here and not at the call site: acqSettings_ is rebuilt from the builder at
// several points during a run, and the builder holds the user's settings, so an override
// applied once is discarded by the next rebuild.
if (testAcquisition_) {
settings = settings.copyBuilder()
.saveImagesDuringAcquisition(false)
.useTimePoints(false)
.numTimePoints(1)
.build();
}
acqSettings_ = settings;
}

public Future<?> requestRun() {
Expand All @@ -291,6 +307,15 @@ public Future<?> requestRun() {

@Override
public Future<?> requestRun(boolean speedTest) {
return requestRun(speedTest, false);
}

@Override
public Future<?> requestTestAcquisition() {
return requestRun(false, true);
}

private Future<?> requestRun(boolean speedTest, boolean testAcquisition) {
// set here and not inside the task: a Stop clicked while the task is still queued, or
// anywhere inside setup(), must find a run in flight
acquisitionRequested_ = true;
Expand All @@ -308,6 +333,12 @@ public Future<?> requestRun(boolean speedTest) {
long startNs = 0; // set alongside runId at START

try {
// set inside the task and not at request time: the executor runs one task at a
// time, so this cannot reach a run that is already in flight, and the finally
// below only ever clears the request it belongs to. Set before updateSettings()
// so the first rebuild already carries the override.
testAcquisition_ = testAcquisition;

updateSettings(); // make sure settings are current

if (speedTest) {
Expand Down Expand Up @@ -363,6 +394,8 @@ public Future<?> requestRun(boolean speedTest) {
// cleared last of the run-state flags: while it is set, requestStop() treats
// a stop as something to act on rather than an error
acquisitionRequested_ = false;
// cleared here so the next run rebuilds from the user's own settings
testAcquisition_ = false;
// free the datastore so a large store isn't kept in memory (matches MM's
// AcqEngJAdapter.onAcquisitionEnded); also what the save guard checks to skip aborted/empty runs
datastore_ = null;
Expand Down
Loading