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 @@ -311,7 +311,9 @@ */ void setSettings(const QJsonObject &settings); - public slots: + SkyPoint getInitialMountCoords() const; + +public slots: /** \addtogroup CaptureDBusInterface * @{ @@ -580,6 +582,13 @@ // Cooler void setCoolerToggled(bool enabled); + /** + * @brief registerNewModule Register an Ekos module as it arrives via DBus + * and create the appropriate DBus interface to communicate with it. + * @param name of module + */ + void registerNewModule(const QString &name); + signals: Q_SCRIPTABLE void newLog(const QString &text); Q_SCRIPTABLE void meridianFlipStarted(); @@ -625,12 +634,16 @@ 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); @@ -693,6 +706,8 @@ ISD::LightBox *lightBox { nullptr }; ISD::Dome *dome { nullptr }; + QPointer mountInterface { nullptr }; + QStringList m_LogText; QUrl m_SequenceURL; bool m_Dirty { false }; @@ -723,9 +738,7 @@ int refocusEveryNMinutesValue { 0 }; // number of minutes between forced refocus QElapsedTimer refocusEveryNTimer; // used to determine when next force refocus should occur - // Meridian flip - double initialHA { 0 }; - //double initialRA { 0 }; + // Meridan flip SkyPoint initialMountCoords; bool resumeAlignmentAfterFlip { false }; bool resumeGuidingAfterFlip { false }; @@ -783,5 +796,8 @@ // Captured Frames Map SchedulerJob::CapturedFramesMap capturedFramesMap; + + // Execute the meridian flip + bool executeMeridianFlip(); }; } 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 @@ -56,6 +56,15 @@ new CaptureAdaptor(this); QDBusConnection::sessionBus().registerObject("/KStars/Ekos/Capture", this); + QPointer ekosInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos", "org.kde.kstars.Ekos", + QDBusConnection::sessionBus(), this); + + // Connecting DBus signals + connect(ekosInterface, SIGNAL(newModule(QString)), this, SLOT(registerNewModule(QString))); + + // ensure that the mount interface is present + registerNewModule("Mount"); + KStarsData::Instance()->userdb()->GetAllDSLRInfos(DSLRInfos); @@ -365,6 +374,21 @@ } } + +void Capture::registerNewModule(const QString &name) +{ + if (name == "Mount") + { + if (mountInterface != nullptr) + delete mountInterface; + mountInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Mount", "org.kde.kstars.Ekos.Mount", + QDBusConnection::sessionBus(), this); + } + +} + + + void Capture::start() { if (darkSubCheck->isChecked()) @@ -439,35 +463,10 @@ job->resetStatus(); } - // Record initialHA and initialMount position when we are starting fresh - // If recovering from deviation error, these values should not be recorded. // Refocus timer should not be reset on deviation error if (m_DeviationDetected == false && m_State != CAPTURE_SUSPENDED) { - initialHA = getCurrentHA(); - qCDebug(KSTARS_EKOS_CAPTURE) << "Initial hour angle:" << initialHA; meridianFlipStage = MF_NONE; - // Record initial mount coordinates that we may use later to perform a meridian flip - if (currentTelescope) - { - double initialRA, initialDE; - currentTelescope->getEqCoords(&initialRA, &initialDE); - if (currentTelescope->isJ2000()) - { - initialMountCoords.setRA0(initialRA); - initialMountCoords.setDec0(initialDE); - initialMountCoords.apparentCoord(static_cast(J2000), KStars::Instance()->data()->ut().djd()); - } - else - { - initialMountCoords.setRA(initialRA); - initialMountCoords.setDec(initialDE); - } - - qCDebug(KSTARS_EKOS_CAPTURE) << "Initial mount coordinates RA:" << initialMountCoords.ra().toHMSString() - << "DE:" << initialMountCoords.dec().toDMSString(); - } - // start timer to measure time until next forced refocus startRefocusEveryNTimer(); } @@ -2866,7 +2865,6 @@ // otherwise we can for deviation RMS if (guideDeviationCheck->isChecked() == false || deviation_rms < guideDeviation->value()) { - initialHA = getCurrentHA(); appendLogText(i18n("Post meridian flip calibration completed successfully.")); resumeSequence(); // N.B. Set meridian flip stage AFTER resumeSequence() always @@ -3090,6 +3088,26 @@ HFRPixels->setValue(median + (median * (Options::hFRThresholdPercentage() / 100.0))); } +SkyPoint Capture::getInitialMountCoords() const +{ + QVariant const result = mountInterface->property("currentTarget"); + SkyPoint point = result.value(); + return point; +} + +bool Capture::executeMeridianFlip() { + + QDBusReply const reply = mountInterface->call("executeMeridianFlip"); + + if (reply.error().type() == QDBusError::NoError) + return reply.value(); + + // error occured + qCCritical(KSTARS_EKOS_CAPTURE) << QString("Warning: execute meridian flip request received DBUS error: %1").arg(QDBusError::errorString(reply.error().type())); + + return false; +} + int Capture::getTotalFramesCount(QString signature) { int result = 0; @@ -4128,7 +4146,7 @@ { double ra, dec; currentTelescope->getEqCoords(&ra, &dec); - double diffRA = initialMountCoords.ra().Hours() - ra; + double diffRA = getInitialMountCoords().ra().Hours() - ra; // If the mount is actually flipping then we should see a difference in RA // which if it exceeded MF_RA_DIFF_LIMIT (4 hours) then we consider it to be // undertaking the flip. Otherwise, it's not flipping and let timeout takes care of @@ -4149,9 +4167,6 @@ if (dome && dome->isMoving()) break; - // We are at a new initialHA - initialHA = getCurrentHA(); - appendLogText(i18n("Telescope completed the meridian flip.")); //KNotification::event(QLatin1String("MeridianFlipCompleted"), i18n("Meridian flip is successfully completed")); @@ -4205,33 +4220,36 @@ double Capture::getCurrentHA() { - double currentRA, currentDEC; + QVariant HA = mountInterface->property("hourAngle"); + return HA.toDouble(); +} - if (currentTelescope == nullptr) - return Ekos::INVALID_VALUE; +double Capture::getInitialHA() +{ + QVariant HA = mountInterface->property("initialHA"); + return HA.toDouble(); +} - if (currentTelescope->getEqCoords(¤tRA, ¤tDEC) == false) - { - appendLogText(i18n("Failed to retrieve telescope coordinates. Unable to calculate telescope's hour angle.")); - return Ekos::INVALID_VALUE; - } +bool Capture::slew(const SkyPoint target) +{ + QList telescopeSlew; + telescopeSlew.append(target.ra().Hours()); + telescopeSlew.append(target.dec().Degrees()); - /* Edge case: undefined HA at poles */ - if (90.0f == currentDEC || -90.0f == currentDEC) - return Ekos::INVALID_VALUE; + QDBusReply const slewModeReply = mountInterface->callWithArgumentList(QDBus::AutoDetect, "slew", telescopeSlew); - dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst()); + if (slewModeReply.error().type() == QDBusError::NoError) + return true; - dms ha = (lst - dms(currentRA * 15.0)); - double HA = ha.Hours(); - if (HA > 12) - HA -= 24; - return HA; + // 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 || initialHA > 0) + if (currentTelescope == nullptr || meridianCheck->isChecked() == false || getInitialHA() > 0) return false; // If active job is taking flat field image at a wall source @@ -4270,18 +4288,18 @@ if (isInSequenceFocus || (refocusEveryNCheck->isChecked() && getRefocusEveryNTimerElapsedSec() > 0)) emit resetFocus(); - //double dec; - //currentTelescope->getEqCoords(&initialRA, &dec); - currentTelescope->Slew(&initialMountCoords); - secondsLabel->setText(i18n("Meridian Flip...")); + if (executeMeridianFlip()) + { + secondsLabel->setText(i18n("Meridian Flip...")); - retries = 0; + retries = 0; - m_State = CAPTURE_MERIDIAN_FLIP; - emit newStatus(Ekos::CAPTURE_MERIDIAN_FLIP); + m_State = CAPTURE_MERIDIAN_FLIP; + emit newStatus(Ekos::CAPTURE_MERIDIAN_FLIP); - QTimer::singleShot(MF_TIMER_TIMEOUT, this, &Ekos::Capture::checkMeridianFlipTimeout); - return true; + QTimer::singleShot(MF_TIMER_TIMEOUT, this, &Ekos::Capture::checkMeridianFlipTimeout); + return true; + } } return false; @@ -4304,11 +4322,8 @@ } else { - //double dec; - //currentTelescope->getEqCoords(&initialRA, &dec); - //currentTelescope->Slew(initialRA, dec); - currentTelescope->Slew(&initialMountCoords); - appendLogText(i18n("Retrying meridian flip again...")); + if (executeMeridianFlip()) + appendLogText(i18n("Retrying meridian flip again...")); } } } @@ -4755,43 +4770,50 @@ IPState Capture::processPreCaptureCalibrationStage() { // Unpark dust cap if we have to take light images. - if (activeJob->getFrameType() == FRAME_LIGHT && dustCap) + if (activeJob->getFrameType() == FRAME_LIGHT) { - if (dustCap->isLightOn() == true) - { - dustCapLightEnabled = false; - dustCap->SetLightEnabled(false); - } - - // If cap is not unparked, unpark it - if (calibrationStage < CAL_DUSTCAP_UNPARKING && dustCap->isParked()) - { - if (dustCap->UnPark()) + // step 1: unpark dust cap + if (dustCap != nullptr) { + if (dustCap->isLightOn() == true) { - calibrationStage = CAL_DUSTCAP_UNPARKING; - appendLogText(i18n("Unparking dust cap...")); - return IPS_BUSY; + dustCapLightEnabled = false; + dustCap->SetLightEnabled(false); } - else + + // If cap is not unparked, unpark it + if (calibrationStage < CAL_DUSTCAP_UNPARKING && dustCap->isParked()) { - appendLogText(i18n("Unparking dust cap failed, aborting...")); - abort(); - return IPS_ALERT; + if (dustCap->UnPark()) + { + calibrationStage = CAL_DUSTCAP_UNPARKING; + appendLogText(i18n("Unparking dust cap...")); + return IPS_BUSY; + } + else + { + appendLogText(i18n("Unparking dust cap failed, aborting...")); + abort(); + return IPS_ALERT; + } } - } - // Wait until cap is unparked - if (calibrationStage == CAL_DUSTCAP_UNPARKING) - { - if (dustCap->isUnParked() == false) - return IPS_BUSY; - else + // Wait until cap is unparked + if (calibrationStage == CAL_DUSTCAP_UNPARKING) { - calibrationStage = CAL_DUSTCAP_UNPARKED; - appendLogText(i18n("Dust cap unparked.")); + if (dustCap->isUnParked() == false) + return IPS_BUSY; + else + { + calibrationStage = CAL_DUSTCAP_UNPARKED; + appendLogText(i18n("Dust cap unparked.")); + } } } + // step 2: check if meridian flip is required + if (meridianFlipStage != MF_NONE || checkMeridianFlip()) + return IPS_BUSY; + calibrationStage = CAL_PRECAPTURE_COMPLETE; if (guideState == GUIDE_SUSPENDED) 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 @@ -29,6 +29,7 @@ *@author Jasem Mutlaq *@version 1.3 */ + class Mount : public QWidget, public Ui::Mount { Q_OBJECT @@ -41,7 +42,9 @@ Q_PROPERTY(QList equatorialCoords READ equatorialCoords) Q_PROPERTY(QList horizontalCoords READ horizontalCoords) Q_PROPERTY(QList telescopeInfo READ telescopeInfo WRITE setTelescopeInfo) + Q_PROPERTY(SkyPoint currentTarget READ currentTarget) Q_PROPERTY(double hourAngle READ hourAngle) + Q_PROPERTY(double initialHA READ initialHA) Q_PROPERTY(int slewRate READ slewRate WRITE setSlewRate) Q_PROPERTY(int slewStatus READ slewStatus) Q_PROPERTY(bool canPark READ canPark) @@ -152,11 +155,24 @@ */ Q_SCRIPTABLE QList horizontalCoords(); + /** DBUS interface function. + * Get Horizontal coords. + */ + Q_SCRIPTABLE SkyPoint currentTarget(); + /** DBUS interface function. * Get mount hour angle in hours (-12 to +12). */ Q_SCRIPTABLE double hourAngle(); + double initialPositionHA; + /** DBUS interface function. + * Get the hour angle of that time the mount has slewed to the current position. + */ + Q_SCRIPTABLE double initialHA() {return initialPositionHA; } + + Q_SCRIPTABLE void setInitialHA(double ha) { initialPositionHA = ha; } + /** DBUS interface function. * Aborts the mount motion * @return true if the command is sent successfully, false otherwise. @@ -232,7 +248,13 @@ // Get list of scopes QJsonArray getScopes() const; - public slots: + /* + * @brief Execute a meridian flip if necessary. + * @return true if a meridian flip was necessary + */ + Q_INVOKABLE bool executeMeridianFlip(); + +public slots: /** * @brief syncTelescopeInfo Update telescope information to reflect any property changes @@ -309,6 +331,13 @@ private slots: + /** + * @brief registerNewModule Register an Ekos module as it arrives via DBus + * and create the appropriate DBus interface to communicate with it. + * @param name of module + */ + void registerNewModule(const QString &name); + void startParkTimer(); void stopParkTimer(); void startAutoPark(); @@ -326,9 +355,12 @@ private: void syncGPS(); + QPointer captureInterface { nullptr }; + ISD::Telescope *currentTelescope = nullptr; ISD::GDInterface *currentGPS = nullptr; QStringList m_LogText; + SkyPoint currentTargetPosition; SkyPoint telescopeCoord; QString lastNotificationMessage; QTimer updateTimer; @@ -352,4 +384,5 @@ }; } + #endif // Mount 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 @@ -46,12 +46,20 @@ namespace Ekos { + Mount::Mount() { setupUi(this); new MountAdaptor(this); QDBusConnection::sessionBus().registerObject("/KStars/Ekos/Mount", this); + // Set up DBus interfaces + QPointer ekosInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos", "org.kde.kstars.Ekos", + QDBusConnection::sessionBus(), this); + qDBusRegisterMetaType(); + + // Connecting DBus signals + connect(ekosInterface, SIGNAL(newModule(QString)), this, SLOT(registerNewModule(QString))); currentTelescope = nullptr; @@ -331,6 +339,17 @@ scopeConfigNameEdit->setText(tvp->tp[0].text); } +void Mount::registerNewModule(const QString &name) +{ + if (name == "Capture") + { + captureInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Capture", "org.kde.kstars.Ekos.Capture", + QDBusConnection::sessionBus(), this); + } + +} + + void Mount::updateText(ITextVectorProperty *tvp) { if (!strcmp(tvp->name, "SCOPE_CONFIG_NAME")) @@ -794,9 +813,43 @@ if (currentTelescope == nullptr || currentTelescope->isConnected() == false) return false; + 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); + + currentTargetPosition.setRA(RA); + currentTargetPosition.setDec(DEC); + return currentTelescope->Slew(RA, DEC); } +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(); + if (HA > 12.0) + // no meridian flip necessary + return false; + + // execute meridian flip + slew(currentTargetPosition.ra().Hours(), currentTargetPosition.dec().Degrees()); + return true; + +} + +SkyPoint Mount::currentTarget() +{ + return currentTargetPosition; +} + + + bool Mount::sync(const QString &RA, const QString &DEC) { dms ra, de; @@ -869,7 +922,7 @@ double HA = ha.Hours(); if (HA > 12.0) - return (24 - HA); + return (HA - 24.0); else return HA; } 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 @@ -7,6 +7,9 @@ + + + @@ -19,6 +22,7 @@ + @@ -53,6 +57,9 @@ + + + diff --git a/kstars/skyobjects/skypoint.h b/kstars/skyobjects/skypoint.h --- a/kstars/skyobjects/skypoint.h +++ b/kstars/skyobjects/skypoint.h @@ -23,6 +23,9 @@ #include "kstarsdatetime.h" #include +#ifndef KSTARS_LITE +#include +#endif //#define PROFILE_COORDINATE_CONVERSION @@ -648,3 +651,9 @@ protected: double lastPrecessJD { 0 }; // JD at which the last coordinate (see updateCoords) for this SkyPoint was done }; + +#ifndef KSTARS_LITE +Q_DECLARE_METATYPE(SkyPoint) +QDBusArgument &operator<<(QDBusArgument &argument, const SkyPoint &source); +const QDBusArgument &operator>>(const QDBusArgument &argument, SkyPoint &dest); +#endif diff --git a/kstars/skyobjects/skypoint.cpp b/kstars/skyobjects/skypoint.cpp --- a/kstars/skyobjects/skypoint.cpp +++ b/kstars/skyobjects/skypoint.cpp @@ -936,3 +936,24 @@ retval = 180. + retval; return retval; } + +#ifndef KSTARS_LITE +QDBusArgument &operator<<(QDBusArgument &argument, const SkyPoint &source) +{ + argument.beginStructure(); + argument << source.ra().Hours() << source.dec().Degrees(); + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, SkyPoint &dest) +{ + double ra, dec; + argument.beginStructure(); + argument >> ra >> dec; + argument.endStructure(); + dest = SkyPoint(ra, dec); + return argument; +} +#endif +