diff --git a/kstars/ekos/capture/capture.h b/kstars/ekos/capture/capture.h --- a/kstars/ekos/capture/capture.h +++ b/kstars/ekos/capture/capture.h @@ -13,6 +13,7 @@ #include "customproperties.h" #include "oal/filter.h" #include "ekos/ekos.h" +#include "ekos/mount/mount.h" #include "indi/indiccd.h" #include "indi/indicap.h" #include "indi/indidome.h" @@ -90,7 +91,7 @@ Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) public: - typedef enum { MF_NONE, MF_INITIATED, MF_FLIPPING, MF_SLEWING, MF_ALIGNING, MF_GUIDING } MFStage; + typedef enum { MF_NONE, MF_REQUESTED, MF_INITIATED, MF_FLIPPING, MF_SLEWING, MF_ALIGNING, MF_GUIDING } MFStage; typedef enum { CAL_NONE, CAL_DUSTCAP_PARKING, @@ -512,6 +513,9 @@ // Clear Camera Configuration void clearCameraConfiguration(); + // Meridian flip + void meridianFlipStatusChanged(Mount::MeridianFlipStatus status); + private slots: /** @@ -540,10 +544,6 @@ void resetJobEdit(); void executeJob(); - // Meridian Flip - void checkMeridianFlipTimeout(); - //void checkAlignmentSlewComplete(); - // AutoGuide void checkGuideDeviationTimeout(); @@ -606,6 +606,7 @@ void newExposureProgress(Ekos::SequenceJob *job); void sequenceChanged(const QJsonArray &sequence); void settingsUpdated(const QJsonObject &settings); + void newMeridianFlipStatus(Mount::MeridianFlipStatus status); private: void setBusy(bool enable); @@ -633,17 +634,12 @@ /* Meridian Flip */ bool checkMeridianFlip(); void checkGuidingAfterFlip(); - double getCurrentHA(); - double getInitialHA(); // Remaining Time in seconds int getJobRemainingTime(SequenceJob *job); void resetFrameToZero(); - /* Slewing - true iff start slewing was successful */ - bool slew(const SkyPoint target); - /* Refocus */ void startRefocusTimer(bool forced = false); @@ -798,6 +794,6 @@ SchedulerJob::CapturedFramesMap capturedFramesMap; // Execute the meridian flip - bool executeMeridianFlip(); + void setMeridianFlipStage(MFStage status); }; } diff --git a/kstars/ekos/capture/capture.cpp b/kstars/ekos/capture/capture.cpp --- a/kstars/ekos/capture/capture.cpp +++ b/kstars/ekos/capture/capture.cpp @@ -376,11 +376,13 @@ void Capture::registerNewModule(const QString &name) { + qCDebug(KSTARS_EKOS_CAPTURE) << "Registering new Module (" << name << ")"; if (name == "Mount") { delete mountInterface; mountInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Mount", "org.kde.kstars.Ekos.Mount", QDBusConnection::sessionBus(), this); + } } @@ -461,7 +463,6 @@ // Refocus timer should not be reset on deviation error if (m_DeviationDetected == false && m_State != CAPTURE_SUSPENDED) { - meridianFlipStage = MF_NONE; // start timer to measure time until next forced refocus startRefocusEveryNTimer(); } @@ -612,6 +613,7 @@ seqTimer->stop(); activeJob = nullptr; + setMeridianFlipStage(MF_NONE); } void Capture::sendNewImage(const QString &filename, ISD::CCDChip *myChip) @@ -2863,7 +2865,7 @@ appendLogText(i18n("Post meridian flip calibration completed successfully.")); resumeSequence(); // N.B. Set meridian flip stage AFTER resumeSequence() always - meridianFlipStage = MF_NONE; + setMeridianFlipStage(MF_NONE); return; } } @@ -3090,17 +3092,72 @@ return point; } -bool Capture::executeMeridianFlip() { - QDBusReply const reply = mountInterface->call("executeMeridianFlip"); +void Capture::setMeridianFlipStage(MFStage status) +{ + if (meridianFlipStage != status) + { + switch (status) + { + case MF_NONE: + if (meridianFlipStage == MF_REQUESTED) + // we keep the stage on requested until the mount starts the meridian flip + emit newMeridianFlipStatus(Mount::MF_ACCEPTED); + else + { + secondsLabel->setText(""); + meridianFlipStage = status; + } + break; - if (reply.error().type() == QDBusError::NoError) - return reply.value(); + case MF_INITIATED: + meridianFlipStage = MF_INITIATED; + emit meridianFlipStarted(); + secondsLabel->setText(i18n("Meridian Flip...")); + KSNotification::event(QLatin1String("MeridianFlipStarted"), i18n("Meridian flip started"), KSNotification::EVENT_INFO); + break; - // error occured - qCCritical(KSTARS_EKOS_CAPTURE) << QString("Warning: execute meridian flip request received DBUS error: %1").arg(QDBusError::errorString(reply.error().type())); + case MF_REQUESTED: + meridianFlipStage = MF_REQUESTED; + emit newMeridianFlipStatus(Mount::MF_WAITING); + break; - return false; + default: + meridianFlipStage = status; + break; + } + } +} + + +void Capture::meridianFlipStatusChanged(Mount::MeridianFlipStatus status) { + switch (status) + { + case Mount::MF_IDLE: + setMeridianFlipStage(MF_NONE); + break; + + case Mount::MF_PLANNED: + // If we are autoguiding, we should resume autoguiding after flip + resumeGuidingAfterFlip = (guideState == GUIDE_GUIDING); + + if (m_State == CAPTURE_IDLE || m_State == CAPTURE_ABORTED || m_State == CAPTURE_COMPLETE) + { + setMeridianFlipStage(MF_INITIATED); + emit newMeridianFlipStatus(Mount::MF_ACCEPTED); + } + else + setMeridianFlipStage(MF_REQUESTED); + break; + + case Mount::MF_RUNNING: + setMeridianFlipStage(MF_INITIATED); + emit newStatus(Ekos::CAPTURE_MERIDIAN_FLIP); + break; + + default: + break; + } } int Capture::getTotalFramesCount(QString signature) @@ -3271,8 +3328,8 @@ } else if (!strcmp(tagXMLEle(ep), "MeridianFlip")) { - meridianCheck->setChecked(!strcmp(findXMLAttValu(ep, "enabled"), "true")); - meridianHours->setValue(cLocale.toDouble(pcdataXMLEle(ep))); + setMeridianFlip(!strcmp(findXMLAttValu(ep, "enabled"), "true")); + setMeridianFlipHour(cLocale.toDouble(pcdataXMLEle(ep))); } else if (!strcmp(tagXMLEle(ep), "CCD")) { @@ -4133,7 +4190,7 @@ case MF_INITIATED: { if (nvp->s == IPS_BUSY) - meridianFlipStage = MF_FLIPPING; + setMeridianFlipStage(MF_FLIPPING); } break; @@ -4149,7 +4206,7 @@ // Are there any mounts that do NOT change RA while flipping? i.e. do it silently? // Need to investigate that bit if (fabs(diffRA) > MF_RA_DIFF_LIMIT /* || nvp->s == IPS_OK*/) - meridianFlipStage = MF_SLEWING; + setMeridianFlipStage(MF_SLEWING); } break; @@ -4167,6 +4224,11 @@ //KNotification::event(QLatin1String("MeridianFlipCompleted"), i18n("Meridian flip is successfully completed")); KSNotification::event(QLatin1String("MeridianFlipCompleted"), i18n("Meridian flip is successfully completed"), KSNotification::EVENT_INFO); + + // resume only if capturing was running + if (m_State == CAPTURE_IDLE || m_State == CAPTURE_ABORTED || m_State == CAPTURE_COMPLETE) + break; + if (resumeAlignmentAfterFlip == true) { appendLogText(i18n("Performing post flip re-alignment...")); @@ -4176,7 +4238,7 @@ m_State = CAPTURE_ALIGNING; emit newStatus(Ekos::CAPTURE_ALIGNING); - meridianFlipStage = MF_ALIGNING; + setMeridianFlipStage(MF_ALIGNING); //QTimer::singleShot(Options::settlingTime(), [this]() {emit meridialFlipTracked();}); //emit meridialFlipTracked(); return; @@ -4198,7 +4260,7 @@ { resumeSequence(); // N.B. Set meridian flip stage AFTER resumeSequence() always - meridianFlipStage = MF_NONE; + setMeridianFlipStage(MF_NONE); } else { @@ -4208,119 +4270,37 @@ m_State = CAPTURE_CALIBRATING; emit newStatus(Ekos::CAPTURE_CALIBRATING); - meridianFlipStage = MF_GUIDING; + setMeridianFlipStage(MF_GUIDING); emit meridianFlipCompleted(); } } -double Capture::getCurrentHA() -{ - QVariant HA = mountInterface->property("hourAngle"); - return HA.toDouble(); -} - -double Capture::getInitialHA() -{ - QVariant HA = mountInterface->property("initialHA"); - return HA.toDouble(); -} - -bool Capture::slew(const SkyPoint target) -{ - QList telescopeSlew; - telescopeSlew.append(target.ra().Hours()); - telescopeSlew.append(target.dec().Degrees()); - - QDBusReply const slewModeReply = mountInterface->callWithArgumentList(QDBus::AutoDetect, "slew", telescopeSlew); - - if (slewModeReply.error().type() == QDBusError::NoError) - return true; - - // error occured - qCCritical(KSTARS_EKOS_CAPTURE) << QString("Warning: slew request received DBUS error: %1").arg(QDBusError::errorString(slewModeReply.error().type())); - return false; -} - bool Capture::checkMeridianFlip() { - if (currentTelescope == nullptr || meridianCheck->isChecked() == false || getInitialHA() > 0) + if (currentTelescope == nullptr || meridianCheck->isChecked() == false) return false; // If active job is taking flat field image at a wall source // then do not flip. if (activeJob && activeJob->getFrameType() == FRAME_FLAT && activeJob->getFlatFieldSource() == SOURCE_WALL) return false; - double currentHA = getCurrentHA(); - - //appendLogText(i18n("Current hour angle %1", currentHA)); - - if (currentHA == Ekos::INVALID_VALUE) + if (meridianFlipStage == MF_NONE) return false; - if (currentHA > meridianHours->value()) - { - //NOTE: DO NOT make the follow sentence PLURAL as the value is in double - appendLogText( - i18n("Current hour angle %1 hours exceeds meridian flip limit of %2 hours. Auto meridian flip is initiated.", - QString("%L1").arg(currentHA, 0, 'f', 2), QString("%L1").arg(meridianHours->value(), 0, 'f', 2))); - meridianFlipStage = MF_INITIATED; - - //KNotification::event(QLatin1String("MeridianFlipStarted"), i18n("Meridian flip started")); - KSNotification::event(QLatin1String("MeridianFlipStarted"), i18n("Meridian flip started"), KSNotification::EVENT_INFO); + // meridian flip requested or already in action - // Suspend guiding first before commanding a meridian flip - //if (isAutoGuiding && currentCCD->getChip(ISD::CCDChip::GUIDE_CCD) == guideChip) - // emit suspendGuiding(false); + // Reset frame if we need to do focusing later on + if (isInSequenceFocus || (refocusEveryNCheck->isChecked() && getRefocusEveryNTimerElapsedSec() > 0)) + emit resetFocus(); - // If we are autoguiding, we should resume autoguiding after flip - resumeGuidingAfterFlip = (guideState == GUIDE_GUIDING); + // signal that meridian flip may take place + if (meridianFlipStage == MF_REQUESTED) + setMeridianFlipStage(MF_NONE); - emit meridianFlipStarted(); - // Reset frame if we need to do focusing later on - if (isInSequenceFocus || (refocusEveryNCheck->isChecked() && getRefocusEveryNTimerElapsedSec() > 0)) - emit resetFocus(); - - if (executeMeridianFlip()) - { - secondsLabel->setText(i18n("Meridian Flip...")); - - retries = 0; - - m_State = CAPTURE_MERIDIAN_FLIP; - emit newStatus(Ekos::CAPTURE_MERIDIAN_FLIP); - - QTimer::singleShot(MF_TIMER_TIMEOUT, this, &Ekos::Capture::checkMeridianFlipTimeout); - return true; - } - } - - return false; -} - -void Capture::checkMeridianFlipTimeout() -{ - if (meridianFlipStage == MF_NONE) - return; - - if (meridianFlipStage < MF_ALIGNING) - { - appendLogText(i18n("Telescope meridian flip timed out. Please make sure your mount supports meridian flip.")); - - if (++retries == 3) - { - //KNotification::event(QLatin1String("MeridianFlipFailed"), i18n("Meridian flip failed")); - KSNotification::event(QLatin1String("MeridianFlipFailed"), i18n("Meridian flip failed"), KSNotification::EVENT_ALERT); - abort(); - } - else - { - if (executeMeridianFlip()) - appendLogText(i18n("Retrying meridian flip again...")); - } - } + return true; } void Capture::checkGuideDeviationTimeout() @@ -4373,7 +4353,7 @@ this->m_State = CAPTURE_ALIGNING; emit newStatus(Ekos::CAPTURE_ALIGNING); - meridianFlipStage = MF_ALIGNING; + setMeridianFlipStage(MF_ALIGNING); } } break; @@ -4612,11 +4592,20 @@ void Capture::setMeridianFlip(bool enable) { meridianCheck->setChecked(enable); + QDBusReply const reply = mountInterface->call("activateMeridianFlip", enable); + + if (reply.error().type() != QDBusError::NoError) + qCCritical(KSTARS_EKOS_CAPTURE) << QString("Warning: setting meridian flip request received DBUS error: %1").arg(QDBusError::errorString(reply.error().type())); } void Capture::setMeridianFlipHour(double hours) { meridianHours->setValue(hours); + + QDBusReply const reply = mountInterface->call("setMeridianFlipLimit", hours); + + if (reply.error().type() != QDBusError::NoError) + qCCritical(KSTARS_EKOS_CAPTURE) << QString("Warning: setting meridian flip time limit request received DBUS error: %1").arg(QDBusError::errorString(reply.error().type())); } bool Capture::hasCoolerControl() @@ -4805,8 +4794,11 @@ } } - // step 2: check if meridian flip is required - if (meridianFlipStage != MF_NONE || checkMeridianFlip()) + // step 2: check if meridian flip already is ongoing + if (meridianFlipStage != MF_NONE) + return IPS_BUSY; + // step 3: check if meridian flip is required + if (checkMeridianFlip()) return IPS_BUSY; calibrationStage = CAL_PRECAPTURE_COMPLETE; diff --git a/kstars/ekos/manager.cpp b/kstars/ekos/manager.cpp --- a/kstars/ekos/manager.cpp +++ b/kstars/ekos/manager.cpp @@ -2927,6 +2927,8 @@ // Meridian Flip states connect(captureProcess.get(), &Ekos::Capture::meridianFlipStarted, mountProcess.get(), &Ekos::Mount::disableAltLimits, Qt::UniqueConnection); connect(captureProcess.get(), &Ekos::Capture::meridianFlipCompleted, mountProcess.get(), &Ekos::Mount::enableAltLimits, Qt::UniqueConnection); + connect(captureProcess.get(), &Ekos::Capture::newMeridianFlipStatus, mountProcess.get(), &Ekos::Mount::meridianFlipStatusChanged, Qt::UniqueConnection); + connect(mountProcess.get(), &Ekos::Mount::newMeridianFlipStatus, captureProcess.get(), &Ekos::Capture::meridianFlipStatusChanged, Qt::UniqueConnection); // Mount Status connect(mountProcess.get(), &Ekos::Mount::newStatus, captureProcess.get(), &Ekos::Capture::setMountStatus, Qt::UniqueConnection); diff --git a/kstars/ekos/mount/mount.h b/kstars/ekos/mount/mount.h --- a/kstars/ekos/mount/mount.h +++ b/kstars/ekos/mount/mount.h @@ -56,6 +56,7 @@ //typedef enum { PARKING_IDLE, PARKING_OK, UNPARKING_OK, PARKING_BUSY, UNPARKING_BUSY, PARKING_ERROR } ParkingStatus; + typedef enum { MF_IDLE, MF_PLANNED, MF_WAITING, MF_ACCEPTED, MF_RUNNING, MF_COMPLETED, MF_ERROR } MeridianFlipStatus; /** * @brief setTelescope Sets the mount module telescope interface @@ -116,7 +117,7 @@ /** @brief Like above but RA and DEC are strings HH:MM:SS and DD:MM:SS */ - Q_INVOKABLE bool slew(const QString &RA, const QString &DEC); + Q_INVOKABLE bool slew(const QString &RA, const QString &DEC); /** DBUS interface function. * Slew the mount to the target. Target name must be valid in KStars. @@ -249,11 +250,30 @@ QJsonArray getScopes() const; /* + * @brief Check if a meridian flip if necessary. + * @param lst current local sideral time + * @return true if a meridian flip is necessary + */ + void checkMeridianFlip(dms lst); + + /* * @brief Execute a meridian flip if necessary. * @return true if a meridian flip was necessary */ Q_INVOKABLE bool executeMeridianFlip(); + /* + * @brief activate meridian flip function + * @param activate true iff the meridian flip function should be enabled + */ + Q_INVOKABLE Q_NOREPLY void activateMeridianFlip(bool activate); + + /* + * @brief set the time beyond the meridian when the meridian flip + * @param hours time limit + */ + Q_INVOKABLE Q_NOREPLY void setMeridianFlipLimit(double hours); + public slots: /** @@ -329,6 +349,8 @@ void toggleMountToolBox(); + void meridianFlipStatusChanged(MeridianFlipStatus status); + private slots: /** @@ -345,26 +367,30 @@ signals: void newLog(const QString &text); void newCoords(const QString &ra, const QString &dec, const QString &az, const QString &alt); - void newTarget(const QString &name); + void newTarget(const QString &name); void newStatus(ISD::Telescope::Status status); void newParkStatus(ISD::ParkStatus status); void pierSideChanged(ISD::Telescope::PierSide side); void slewRateChanged(int index); void ready(); + void newMeridianFlipStatus(MeridianFlipStatus status); - private: +private: void syncGPS(); + MeridianFlipStatus m_MFStatus = MF_IDLE; + void setMeridianFlipStatus(MeridianFlipStatus status); QPointer captureInterface { nullptr }; ISD::Telescope *currentTelescope = nullptr; ISD::GDInterface *currentGPS = nullptr; QStringList m_LogText; - SkyPoint currentTargetPosition; + SkyPoint *currentTargetPosition = nullptr; SkyPoint telescopeCoord; QString lastNotificationMessage; QTimer updateTimer; QTimer autoParkTimer; + QTimer meridianFlipTimer; double lastAlt; int abortDispatch; bool altLimitEnabled; @@ -380,7 +406,7 @@ QQuickItem *m_SpeedSlider = nullptr, *m_SpeedLabel = nullptr, *m_raValue = nullptr, *m_deValue = nullptr, *m_azValue = nullptr, *m_altValue = nullptr, *m_haValue = nullptr, *m_zaValue = nullptr, *m_targetText = nullptr, *m_targetRAText = nullptr, *m_targetDEText = nullptr, *m_Park = nullptr, - *m_Unpark = nullptr, *m_statusText = nullptr, *m_J2000Check = nullptr, *m_JNowCheck=nullptr; + *m_Unpark = nullptr, *m_statusText = nullptr, *m_J2000Check = nullptr, *m_JNowCheck=nullptr; }; } diff --git a/kstars/ekos/mount/mount.cpp b/kstars/ekos/mount/mount.cpp --- a/kstars/ekos/mount/mount.cpp +++ b/kstars/ekos/mount/mount.cpp @@ -43,6 +43,7 @@ #define UPDATE_DELAY 1000 #define ABORT_DISPATCH_LIMIT 3 +#define MF_DELAY 12000 namespace Ekos { @@ -87,6 +88,10 @@ updateTimer.setInterval(UPDATE_DELAY); connect(&updateTimer, SIGNAL(timeout()), this, SLOT(updateTelescopeCoords())); + meridianFlipTimer.setInterval(MF_DELAY); + meridianFlipTimer.setSingleShot(true); + connect(&meridianFlipTimer, SIGNAL(timeout()), this, SLOT(executeMeridianFlip())); + QDateTime now = KStarsData::Instance()->lt(); // Set seconds to zero now = now.addSecs(now.time().second()*-1); @@ -489,9 +494,14 @@ ISD::Telescope::Status currentStatus = currentTelescope->status(); if (m_Status != currentStatus) { - // If we just finished a slew, let's update initialHA - if (currentStatus == ISD::Telescope::MOUNT_TRACKING && m_Status == ISD::Telescope::MOUNT_SLEWING) - setInitialHA(ha.Hours()); + qCDebug(KSTARS_EKOS_MOUNT) << "Mount status changed from " << m_Status << " to " << currentStatus; + // If we just finished a slew, let's update initialHA and the current target's position + if (currentStatus == ISD::Telescope::MOUNT_TRACKING) + { + setInitialHA((sgn == '-' ? -1: 1) * ha.Hours()); + delete currentTargetPosition; + currentTargetPosition = new SkyPoint(telescopeCoord.ra(), telescopeCoord.dec()); + } m_Status = currentStatus; parkB->setEnabled(!currentTelescope->isParked()); @@ -528,6 +538,8 @@ remainingTime = remainingTime.addMSecs(autoParkTimer.remainingTime()); countdownLabel->setText(remainingTime.toString("hh:mm:ss")); } + + checkMeridianFlip(lst); } else updateTimer.stop(); @@ -574,6 +586,26 @@ return false; } +void Mount::activateMeridianFlip(bool activate) +{ + meridianFlipCheckBox->setChecked(activate); +} + +void Mount::setMeridianFlipLimit(double hours) +{ + meridianFlipTimeBox->setValue(hours); +} + +void Mount::setMeridianFlipStatus(MeridianFlipStatus status) +{ + if (m_MFStatus != status) + { + m_MFStatus = status; + meridianFlipStatusChanged(status); + emit newMeridianFlipStatus(status); + } +} + void Mount::updateSwitch(ISwitchVectorProperty *svp) { if (!strcmp(svp->name, "TELESCOPE_SLEW_RATE")) @@ -817,40 +849,145 @@ if (currentTelescope == nullptr || currentTelescope->isConnected() == false) return false; - // JM 2019-01-05: This is not required since the mount module monitors the mount status - // and sets the initialHA accordingly. -// dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst()); -// double HA = lst.Hours() - RA; -// if (HA > 12.0) -// HA -= 24.0; -// setInitialHA(HA); + dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst()); + double HA = lst.Hours() - RA; + if (HA > 12.0) + HA -= 24.0; + setInitialHA(HA); + // reset the meridian flip status if the slew is not the meridian flip itself + if (m_MFStatus != MF_RUNNING) + setMeridianFlipStatus(MF_IDLE); - currentTargetPosition.setRA(RA); - currentTargetPosition.setDec(DEC); + delete currentTargetPosition; + currentTargetPosition = new SkyPoint(RA, DEC); return currentTelescope->Slew(RA, DEC); } +void Mount::checkMeridianFlip(dms lst) +{ + + if (currentTelescope == nullptr || currentTelescope->isConnected() == false) + { + meridianFlipStatusText->setText("Status: inactive"); + setMeridianFlipStatus(MF_IDLE); + return; + } + + double deltaHA = meridianFlipTimeBox->value() - lst.Hours() + telescopeCoord.ra().Hours(); + int hh = (int) deltaHA; + int mm = (int) ((deltaHA - hh)*60); + int ss = (int) ((deltaHA - hh - mm/60.0)*3600); + + switch (m_MFStatus) + { + case MF_IDLE: + + if (initialHA() >= 0 || meridianFlipCheckBox->isChecked() == false) + { + meridianFlipStatusText->setText("Status: inactive"); + return; + } + + if (deltaHA > 0) + { + QString message = QString("Meridian flip in %1h:%2m:%3s") + .arg(hh, 2, 10, QChar('0')) + .arg(mm, 2, 10, QChar('0')) + .arg(ss, 2, 10, QChar('0')); + meridianFlipStatusText->setText(message); + return; + } + else if (initialHA() < 0) + { + setMeridianFlipStatus(MF_PLANNED); + } + break; + + case MF_PLANNED: + break; + + case MF_RUNNING: + if (currentTelescope->isTracking()) + { + // meridian flip completed + setMeridianFlipStatus(MF_COMPLETED); + } + break; + + case MF_COMPLETED: + setMeridianFlipStatus(MF_IDLE); + break; + + default: + // do nothing + break; + } + return; +} + bool Mount::executeMeridianFlip() { if (initialHA() > 0) // no meridian flip necessary return false; dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst()); - double HA = lst.Hours() - currentTargetPosition.ra().Hours(); + double HA = lst.Hours() - currentTargetPosition->ra().Hours(); if (HA > 12.0) // no meridian flip necessary return false; // execute meridian flip - slew(currentTargetPosition.ra().Hours(), currentTargetPosition.dec().Degrees()); + qCDebug(KSTARS_EKOS_MOUNT) << "Meridian flip: slewing to RA=" << + currentTargetPosition->ra().toHMSString() << + "DEC=" << currentTargetPosition->dec().toDMSString(); + setMeridianFlipStatus(MF_RUNNING); + slew(currentTargetPosition->ra().Hours(), currentTargetPosition->dec().Degrees()); return true; } +void Mount::meridianFlipStatusChanged(Mount::MeridianFlipStatus status) { + + m_MFStatus = status; + + switch (status) + { + case MF_IDLE: + meridianFlipStatusText->setText("Status: inactive"); + break; + + case MF_PLANNED: + meridianFlipStatusText->setText("Meridian flip planned..."); + meridianFlipTimer.start(); + break; + + case MF_WAITING: + meridianFlipStatusText->setText("Meridian flip waiting..."); + meridianFlipTimer.stop(); + break; + + case MF_ACCEPTED: + executeMeridianFlip(); + break; + + case MF_RUNNING: + meridianFlipStatusText->setText("Meridian flip running..."); + break; + + case MF_COMPLETED: + meridianFlipStatusText->setText("Meridian flip completed."); + break; + default: + break; + } + + +} + SkyPoint Mount::currentTarget() { - return currentTargetPosition; + return *currentTargetPosition; } diff --git a/kstars/ekos/mount/mount.ui b/kstars/ekos/mount/mount.ui --- a/kstars/ekos/mount/mount.ui +++ b/kstars/ekos/mount/mount.ui @@ -6,8 +6,8 @@ 0 0 - 498 - 319 + 703 + 464 @@ -348,46 +348,84 @@ - - - false - - - Park + + + Park Telescope + + + + + false + + + Park + + + + + + + false + + + UnPark + + + + - - - false - - - UnPark + + + Meridian Flip + + + + + + + + <html><head/><body><p>Request a meridian flip if the hour angle exceeds the specified value. Capture and Guiding will be suspended and resumed after the flip is complete.</p></body></html> + + + Flip if HA > + + + + + + + h + + + + + + + + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Reset mount alignment model - - - Clear Alignment Model + + + Alignment Model + + + + + Clear Model + + + + @@ -676,8 +714,8 @@ 3 - - + + false @@ -687,28 +725,34 @@ 0 - - Abort mount if it slews lower than this limit. - - - -10.000000000000000 - 90.000000000000000 + + 90.000000000000000 + - - - - <html><head/><body><p>Abort mount <span style=" font-weight:600;">slew/goto</span> motion if it falls outside the minimum and maximum altitude limits. This does not apply to tracking.</p></body></html> + + + + false - - Enable Limits + + + 0 + 0 + + + + -10.000000000000000 + + + 90.000000000000000 - + false @@ -721,42 +765,27 @@ - - - - false - - - <html><head/><body><p>Maximum telescope altitude limit. If the telescope is above this limit, it will be commanded to stop.</p></body></html> - + + - Max. Alt: + Enable Limits - - + + false - - - 0 - 0 - - - Abort mount if it slews higher than this limit. - - - 90.000000000000000 + <html><head/><body><p>Maximum telescope altitude limit. If the telescope is above this limit, it will be commanded to stop.</p></body></html> - - 90.000000000000000 + + Max. Alt: - + Qt::Vertical @@ -817,9 +846,6 @@ lstOUT minAltLimit maxAltLimit - parkB - unparkB - clearAlignmentModelB enableLimitsCheck 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 @@ -1316,10 +1316,7 @@ switch (job->getState()) { case SchedulerJob::JOB_SCHEDULED: - /* If job is scheduled, bypass if set to start later with a fixed time */ - if (SchedulerJob::START_AT == job->getFileStartupCondition()) - if (now < job->getStartupTime()) - continue; + /* If job is scheduled, keep it for evaluation against others */ break; case SchedulerJob::JOB_ERROR: @@ -1559,7 +1556,28 @@ break; } + // Check whether a previous job overlaps the current job + if (nullptr != previousJob && previousJob->getCompletionTime().isValid()) + { + // Calculate time we should be at after finishing the previous job + QDateTime const previousCompletionTime = previousJob->getCompletionTime().addSecs(static_cast (ceil(Options::leadTime()*60.0))); + + // Make this job invalid if startup time is not achievable because a START_AT job is non-movable + if (currentJob->getStartupTime() < previousCompletionTime) + { + currentJob->setState(SchedulerJob::JOB_INVALID); + + appendLogText(i18n("Warning: job '%1' has fixed startup time %2 unachievable due to the completion time of its previous sibling, marking invalid.", + currentJob->getName(), currentJob->getStartupTime().toString(currentJob->getDateTimeDisplayFormat()))); + + break; + } + + currentJob->setLeadTime(previousJob->getCompletionTime().secsTo(currentJob->getStartupTime())); + } + // This job is non-movable, we're done + currentJob->setScore(calculateJobScore(currentJob, now)); currentJob->setState(SchedulerJob::JOB_SCHEDULED); qCDebug(KSTARS_EKOS_SCHEDULER) << QString("Job '%1' is scheduled to start at %2, in compliance with fixed startup time requirement.") .arg(currentJob->getName()) diff --git a/kstars/kstars.notifyrc b/kstars/kstars.notifyrc --- a/kstars/kstars.notifyrc +++ b/kstars/kstars.notifyrc @@ -873,7 +873,7 @@ Comment[tr]=Kaide parkı devam ediyor Comment[uk]=Виконуємо паркування лафета Comment[x-test]=xxMount parking is in progressxx -Comment[zh_CN]=正在泊位赤道仪 +Comment[zh_CN]=正在归位赤道仪 Comment[zh_TW]=正在停止旋轉 Action=None [Event/MountParked] diff --git a/kstars/org.kde.kstars.Ekos.Mount.xml b/kstars/org.kde.kstars.Ekos.Mount.xml --- a/kstars/org.kde.kstars.Ekos.Mount.xml +++ b/kstars/org.kde.kstars.Ekos.Mount.xml @@ -60,6 +60,12 @@ + + + + + +