diff --git a/kstars/ekos/guide/externalguide/phd2.cpp b/kstars/ekos/guide/externalguide/phd2.cpp --- a/kstars/ekos/guide/externalguide/phd2.cpp +++ b/kstars/ekos/guide/externalguide/phd2.cpp @@ -366,11 +366,16 @@ } else { - // settle completed after "guide" command - - if (!error) + if (error) + { + emit newLog(i18n("PHD2: Settling failed, aborted.")); + emit newStatus(GUIDE_ABORTED); + } + else { + // settle completed after "guide" command emit newLog(i18n("PHD2: Settling complete, Guiding Started.")); + emit newStatus(GUIDE_GUIDING); } } } @@ -655,6 +660,7 @@ //shutdown case STOP_CAPTURE_COMMAND_RECEIVED: //stop_capture + emit newStatus(GUIDE_ABORTED); break; } diff --git a/kstars/ekos/guide/guide.cpp b/kstars/ekos/guide/guide.cpp --- a/kstars/ekos/guide/guide.cpp +++ b/kstars/ekos/guide/guide.cpp @@ -1604,7 +1604,12 @@ void Guide::setStatus(Ekos::GuideState newState) { if (newState == state) + { + // pass through the aborted state + if (newState == GUIDE_ABORTED) + emit newStatus(state); return; + } GuideState previousState = state; diff --git a/kstars/ekos/scheduler/scheduler.h b/kstars/ekos/scheduler/scheduler.h --- a/kstars/ekos/scheduler/scheduler.h +++ b/kstars/ekos/scheduler/scheduler.h @@ -651,6 +651,10 @@ bool &hasAutoFocus); int getCompletedFiles(const QString &path, const QString &seqPrefix); + // retrieve the guiding status + GuideState getGuidingStatus(); + + Ekos::Scheduler *ui { nullptr }; //DBus interfaces QPointer focusInterface { nullptr }; @@ -739,6 +743,8 @@ QTimer schedulerTimer; /// To call checkJobStage QTimer jobTimer; + /// Delay for restarting the guider + QTimer restartGuidingTimer; /// Generic time to track timeout of current operation in progress QTime currentOperationTime; diff --git a/kstars/ekos/scheduler/scheduler.cpp b/kstars/ekos/scheduler/scheduler.cpp --- a/kstars/ekos/scheduler/scheduler.cpp +++ b/kstars/ekos/scheduler/scheduler.cpp @@ -31,9 +31,10 @@ #include -#define BAD_SCORE -1000 -#define MAX_FAILURE_ATTEMPTS 5 -#define UPDATE_PERIOD_MS 1000 +#define BAD_SCORE -1000 +#define MAX_FAILURE_ATTEMPTS 5 +#define UPDATE_PERIOD_MS 1000 +#define RESTART_GUIDING_DELAY_MS 5000 #define DEFAULT_CULMINATION_TIME -60 #define DEFAULT_MIN_ALTITUDE 15 @@ -87,6 +88,13 @@ connect(&schedulerTimer, &QTimer::timeout, this, &Scheduler::checkStatus); connect(&jobTimer, &QTimer::timeout, this, &Scheduler::checkJobStage); + restartGuidingTimer.setSingleShot(true); + restartGuidingTimer.setInterval(RESTART_GUIDING_DELAY_MS); + connect(&restartGuidingTimer, &QTimer::timeout, this, [this]() + { + startGuiding(true); + }); + pi = new QProgressIndicator(this); bottomLayout->addWidget(pi, 0, nullptr); @@ -1165,6 +1173,7 @@ schedulerTimer.stop(); jobTimer.stop(); + restartGuidingTimer.stop(); state = SCHEDULER_IDLE; emit newStatus(state); @@ -3235,8 +3244,7 @@ // Let's make sure guide module does not become unresponsive if (currentOperationTime.elapsed() > GUIDE_INACTIVITY_TIMEOUT) { - QVariant const status = guideInterface->property("status"); - Ekos::GuideState guideStatus = static_cast(status.toInt()); + GuideState guideStatus = getGuidingStatus(); if (guideStatus == Ekos::GUIDE_IDLE || guideStatus == Ekos::GUIDE_CONNECTED || guideStatus == Ekos::GUIDE_DISCONNECTED) { @@ -3565,7 +3573,13 @@ else if (currentJob->getStepPipeline() & SchedulerJob::USE_ALIGN) startAstrometry(); else if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) - startGuiding(); + if (getGuidingStatus() == GUIDE_GUIDING) + { + appendLogText(i18n("Guiding already running, directly start capturing.")); + startCapture(); + } + else + startGuiding(); else startCapture(); } @@ -4552,6 +4566,15 @@ void Scheduler::startGuiding(bool resetCalibration) { + // avoid starting the guider twice + if (resetCalibration == false && getGuidingStatus() == GUIDE_GUIDING) + { + appendLogText(i18n("Guiding already running for %1 ...", currentJob->getName())); + currentJob->setStage(SchedulerJob::STAGE_GUIDING); + currentOperationTime.restart(); + return; + } + // Connect Guider guideInterface->call(QDBus::AutoDetect, "connectGuider"); @@ -6612,6 +6635,8 @@ { appendLogText(i18n("Job '%1' guiding is in progress.", currentJob->getName())); guideFailureCount = 0; + // if guiding recovered while we are waiting, abort the restart + restartGuidingTimer.stop(); currentJob->setStage(SchedulerJob::STAGE_GUIDING_COMPLETE); getNextAction(); @@ -6624,6 +6649,13 @@ else appendLogText(i18n("Warning: job '%1' calibration failed.", currentJob->getName())); + // if the timer for restarting the guiding is already running, we do nothing and + // wait for the action triggered by the timer. This way we avoid that a small guiding problem + // abort the scheduler job + + if (restartGuidingTimer.isActive()) + return; + if (guideFailureCount++ < MAX_FAILURE_ATTEMPTS) { if (status == Ekos::GUIDE_CALIBRATION_ERROR && @@ -6638,8 +6670,8 @@ } else { - appendLogText(i18n("Job '%1' is guiding, and is restarting its guiding procedure.", currentJob->getName())); - startGuiding(true); + appendLogText(i18n("Job '%1' is guiding, guiding procedure will be restarted in %2 seconds.", currentJob->getName(), (RESTART_GUIDING_DELAY_MS * guideFailureCount)/1000)); + restartGuidingTimer.start(RESTART_GUIDING_DELAY_MS * guideFailureCount); } } else @@ -6653,6 +6685,14 @@ } } +GuideState Scheduler::getGuidingStatus() +{ + QVariant guideStatus = guideInterface->property("status"); + Ekos::GuideState gStatus = static_cast(guideStatus.toInt()); + + return gStatus; +} + void Scheduler::setCaptureStatus(Ekos::CaptureState status) { if (state == SCHEDULER_PAUSED || currentJob == nullptr) @@ -6680,8 +6720,7 @@ if (currentJob->getStepPipeline() & SchedulerJob::USE_GUIDE) { // Check if it is guiding related. - QVariant guideStatus = guideInterface->property("status"); - Ekos::GuideState gStatus = static_cast(guideStatus.toInt()); + Ekos::GuideState gStatus = getGuidingStatus(); if (gStatus == Ekos::GUIDE_ABORTED || gStatus == Ekos::GUIDE_CALIBRATION_ERROR || gStatus == GUIDE_DITHERING_ERROR)