Skip to content
Open
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
11 changes: 11 additions & 0 deletions acamd/acam_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5577,6 +5577,17 @@ logwrite( function, message.str() );
return ERROR;
}

// Lock out user-initiated moves while actively acquiring (converging on the
// target); a manual move would disrupt the acquisition. Allowed while
// guiding or stopped.
//
if ( this->target.acquire_mode == Acam::TARGET_ACQUIRE ||
this->target.acquire_mode == Acam::TARGET_ACQUIRE_HERE ) {
logwrite( function, "ERROR cannot move while ACAM is acquiring" );
retstring="acquiring";
return ERROR;
}

std::vector<std::string> tokens;
Tokenize( args, tokens, " " );

Expand Down
47 changes: 28 additions & 19 deletions sequencerd/sequence_acquisition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,26 +178,35 @@ namespace Sequencer {
// before slicecamd's first telemetry publish arrives.
//
bool was_running = false;
std::unique_lock<std::mutex> lock(this->fineacquire_mtx);
this->fineacquire_cv.wait(lock, [&]() {
if ( this->is_fineacquire_running.load() ) was_running = true;
return this->is_fineacquire_locked.load() || this->cancel_flag.load() ||
( was_running && !this->is_fineacquire_running.load() ) ||
(use_timeout && std::chrono::steady_clock::now() > timeout_time);
});

if (this->cancel_flag.load()) return ABORT;

// Determine outcome by reading state. If not locked, then this is a
// failure of some kind; distinguish a true timeout from slicecamd
// stopping without locking by consulting the clock. This ordering
// ensures that a failure publish arriving at or near the timeout
// boundary is still reported as a failure (not mis-labeled as a
// timeout).
bool cancelled, locked, timed_out;
{
std::unique_lock<std::mutex> lock(this->fineacquire_mtx);
this->fineacquire_cv.wait(lock, [&]() {
if ( this->is_fineacquire_running.load() ) was_running = true;
return this->is_fineacquire_locked.load() || this->cancel_flag.load() ||
( was_running && !this->is_fineacquire_running.load() ) ||
(use_timeout && std::chrono::steady_clock::now() > timeout_time);
});
// Classify the outcome while still holding the mutex. is_fineacquire_*
// are written under this mutex by handletopic_slicecamd(); releasing
// first would let a late publish flip them between here and the checks
// (e.g. a stale "locked" arriving after a timeout wake, making a
// timed-out run look successful and skipping the stop).
cancelled = this->cancel_flag.load();
locked = this->is_fineacquire_locked.load();
timed_out = use_timeout && std::chrono::steady_clock::now() >= timeout_time;
} // release fineacquire_mtx before do_slicecam_stop() below (it locks the same mutex)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep fine-acquire outcome under the mutex

This unlock lets handletopic_slicecamd() change is_fineacquire_locked/is_fineacquire_running before the outcome checks below, even though those values are deliberately written under fineacquire_mtx for waiters. If a forced slicecamd status publish wakes this wait because the deadline expired, and then a late lock publish is handled before line 200 runs, this function can return success without issuing the stop even though the acquisition already timed out; the previous code held the mutex until the outcome was classified. Capture the wake reason/state while the lock is still held, then release it only before calling do_slicecam_stop().

Useful? React with 👍 / 👎.


if (cancelled) return ABORT;

// If not locked this is a failure of some kind; distinguish a true timeout
// from slicecamd stopping without locking. A failure at/near the timeout
// boundary is still reported as a failure, not mis-labeled as a timeout.
//
if (!this->is_fineacquire_locked.load()) {
if (use_timeout && std::chrono::steady_clock::now() >= timeout_time) {
logwrite( function, "ERROR slicecam fine acquisition timed out!" );
if (!locked) {
if (timed_out) {
logwrite( function, "ERROR slicecam fine acquisition timed out; aborting" );
this->do_slicecam_stop(); // stop the running loop so it can't perturb the exposure
return TIMEOUT;
}
logwrite( function, "ERROR slicecam fine acquisition stopped without locking" );
Expand Down
16 changes: 16 additions & 0 deletions slicecamd/slicecam_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2589,6 +2589,22 @@ namespace Slicecam {
return ERROR;
}

// Lock out user-initiated moves while ACAM is acquiring (converging on the
// target). Jog (LEFT/RIGHT/UP/DOWN), put-on-slit and put-on-guider on both
// GUIs all arrive here via "scam putonslit"; a manual move mid-acquisition
// would disrupt it. Ask acamd for its mode directly; moves are allowed
// while guiding or stopped, only blocked while actively acquiring.
//
{
std::string acam_mode;
if ( this->acamd.command( ACAMD_ACQUIRE, acam_mode ) == NO_ERROR &&
acam_mode.find("acquiring") != std::string::npos ) {
logwrite( function, "ERROR cannot move while ACAM is acquiring" );
retstring="acquiring";
return ERROR;
}
}

// outputs: result from solve_offset in degrees
//
double ra_off, dec_off;
Expand Down
Loading