diff --git a/acamd/acam_interface.cpp b/acamd/acam_interface.cpp index cce50353..a2d8ca76 100644 --- a/acamd/acam_interface.cpp +++ b/acamd/acam_interface.cpp @@ -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 tokens; Tokenize( args, tokens, " " ); diff --git a/sequencerd/sequence_acquisition.cpp b/sequencerd/sequence_acquisition.cpp index 057d2063..c0d01444 100644 --- a/sequencerd/sequence_acquisition.cpp +++ b/sequencerd/sequence_acquisition.cpp @@ -178,26 +178,35 @@ namespace Sequencer { // before slicecamd's first telemetry publish arrives. // bool was_running = false; - std::unique_lock 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 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) + + 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" ); diff --git a/slicecamd/slicecam_interface.cpp b/slicecamd/slicecam_interface.cpp index 01604a4b..91f1dde0 100644 --- a/slicecamd/slicecam_interface.cpp +++ b/slicecamd/slicecam_interface.cpp @@ -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;