File indexing completed on 2024-04-28 15:09:55

0001 /*
0002     SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef MOUNT_H
0008 #define MOUNT_H
0009 
0010 #include <QQmlContext>
0011 #include "ui_mount.h"
0012 
0013 #include "indi/indistd.h"
0014 #include "indi/indifocuser.h"
0015 #include "indi/indimount.h"
0016 
0017 class QQuickView;
0018 class QQuickItem;
0019 
0020 namespace Ekos
0021 {
0022 /**
0023  *@class Mount
0024  *@short Supports controlling INDI telescope devices including setting/retrieving mount properties, slewing, motion and speed controls, in addition to enforcing altitude limits and parking/unparking.
0025  *@author Jasem Mutlaq
0026  *@version 1.5
0027  */
0028 
0029 class OpticalTrainManager;
0030 class MeridianFlipState;
0031 
0032 class Mount : public QWidget, public Ui::Mount
0033 {
0034         Q_OBJECT
0035         Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Mount")
0036         Q_PROPERTY(QString opticalTrain READ opticalTrain WRITE setOpticalTrain)
0037         Q_PROPERTY(ISD::Mount::Status status READ status NOTIFY newStatus)
0038         Q_PROPERTY(ISD::ParkStatus parkStatus READ parkStatus NOTIFY newParkStatus)
0039         Q_PROPERTY(QStringList logText READ logText NOTIFY newLog)
0040         Q_PROPERTY(QList<double> altitudeLimits READ altitudeLimits WRITE setAltitudeLimits)
0041         Q_PROPERTY(bool altitudeLimitsEnabled READ altitudeLimitsEnabled WRITE setAltitudeLimitsEnabled)
0042         Q_PROPERTY(double hourAngleLimit READ hourAngleLimit WRITE setHourAngleLimit)
0043         Q_PROPERTY(bool hourAngleLimitEnabled READ hourAngleLimitEnabled WRITE setHourAngleLimitEnabled)
0044         Q_PROPERTY(bool autoParkEnabled READ autoParkEnabled WRITE setAutoParkEnabled)
0045         Q_PROPERTY(QList<double> equatorialCoords READ equatorialCoords)
0046         Q_PROPERTY(QList<double> horizontalCoords READ horizontalCoords)
0047         Q_PROPERTY(double hourAngle READ hourAngle)
0048         Q_PROPERTY(int slewRate READ slewRate WRITE setSlewRate)
0049         Q_PROPERTY(int slewStatus READ slewStatus)
0050         Q_PROPERTY(bool canPark READ canPark)
0051         Q_PROPERTY(ISD::Mount::PierSide pierSide READ pierSide NOTIFY pierSideChanged)
0052 
0053     public:
0054         Mount();
0055         ~Mount() override;
0056 
0057         //typedef enum { PARKING_IDLE, PARKING_OK, UNPARKING_OK, PARKING_BUSY, UNPARKING_BUSY, PARKING_ERROR } ParkingStatus;
0058 
0059         /**
0060              * @brief addMount Add a new Mount device
0061              * @param device pointer to mount device
0062              * @return True if added successfully, false if duplicate or failed to add.
0063              */
0064         bool setMount(ISD::Mount *device);
0065 
0066         /**
0067              * @brief addGPS Add a new GPS device
0068              * @param device pointer to gps device
0069              * @return True if added successfully, false if duplicate or failed to add.
0070              */
0071         bool addGPS(ISD::GPS *device);
0072 
0073         void removeDevice(const QSharedPointer<ISD::GenericDevice> &device);
0074 
0075         void setupOpticalTrainManager();
0076         void refreshOpticalTrain();
0077         QString opticalTrain() const
0078         {
0079             return opticalTrainCombo->currentText();
0080         }
0081         void setOpticalTrain(const QString &value)
0082         {
0083             opticalTrainCombo->setCurrentText(value);
0084         }
0085 
0086         // Log functions
0087         void appendLogText(const QString &);
0088         void clearLog();
0089         QStringList logText()
0090         {
0091             return m_LogText;
0092         }
0093         QString getLogText() const
0094         {
0095             return m_LogText.join("\n");
0096         }
0097 
0098         ISD::Mount::Status status() const
0099         {
0100             return m_Status;
0101         }
0102         ISD::Mount *activeMount() const
0103         {
0104             return m_Mount;
0105         }
0106         QString statusString(bool translated = true) const
0107         {
0108             if (m_Mount)
0109                 return m_Mount->statusString(m_Status, translated);
0110             else
0111                 return "NA";
0112         }
0113         ISD::Mount::PierSide pierSide() const
0114         {
0115             if (m_Mount)
0116                 return m_Mount->pierSide();
0117             else
0118                 return ISD::Mount::PIER_UNKNOWN;
0119         }
0120         ISD::ParkStatus parkStatus() const
0121         {
0122             return m_ParkStatus;
0123         }
0124 
0125         /**
0126          * @brief getMeridianFlipState
0127          * @return
0128          */
0129         QSharedPointer<MeridianFlipState> getMeridianFlipState() const
0130         {
0131             return mf_state;
0132         }
0133 
0134         /** @defgroup MountDBusInterface Ekos Mount DBus Interface
0135              * Mount interface provides advanced scripting capabilities to control INDI mounts.
0136             */
0137 
0138         /*@{*/
0139 
0140         /** DBUS interface function.
0141              * Returns the mount altitude limits.
0142              * @return Returns array of doubles. First item is minimum altitude in degrees. Second item is maximum altitude limit in degrees.
0143              */
0144         Q_SCRIPTABLE QList<double> altitudeLimits();
0145 
0146         /** DBUS interface function.
0147              * Sets the mount altitude limits, and whether they are enabled or disabled.
0148              * @param limits is a list of double values. 2 values are expected: minAltitude & maxAltitude
0149              */
0150         Q_SCRIPTABLE Q_NOREPLY void setAltitudeLimits(QList<double> limits);
0151 
0152         /** DBUS interface function.
0153              * Enable or disable mount altitude limits.
0154              */
0155         Q_SCRIPTABLE void setAltitudeLimitsEnabled(bool enable);
0156 
0157         /** DBUS interface function.
0158              * Returns whether the mount limits are enabled or disabled.
0159              * @return True if enabled, false otherwise.
0160              */
0161         Q_SCRIPTABLE bool altitudeLimitsEnabled();
0162 
0163         /** DBUS interface function.
0164              * Returns the mount hour angle limit.
0165              * @return Returns hour angle limit in hours.
0166              */
0167         Q_SCRIPTABLE double hourAngleLimit();
0168 
0169         /** DBUS interface function.
0170              * Sets the mount altitude limits, and whether they are enabled or disabled.
0171              * @param limits is a list of double values. 2 values are expected: minAltitude & maxAltitude
0172              */
0173         Q_SCRIPTABLE Q_NOREPLY void setHourAngleLimit(double limit);
0174 
0175         /** DBUS interface function.
0176              * Enable or disable mount hour angle limit. Mount cannot slew and/or track past this
0177              * hour angle distance.
0178              */
0179         Q_SCRIPTABLE void setHourAngleLimitEnabled(bool enable);
0180 
0181         /** DBUS interface function.
0182              * Returns whether the mount limits are enabled or disabled.
0183              * @return True if enabled, false otherwise.
0184              */
0185         Q_SCRIPTABLE bool hourAngleLimitEnabled();
0186 
0187         /**
0188          * @brief autoParkEnabled Check if auto-park is enabled.
0189          * @return True if enabled.
0190          */
0191         Q_SCRIPTABLE bool autoParkEnabled();
0192 
0193         /**
0194          * @brief setAutoParkEnabled Toggle Auto Park
0195          * @param enable True to start, false to stop
0196          */
0197         Q_SCRIPTABLE void setAutoParkEnabled(bool enable);
0198 
0199         /**
0200          * @brief setAutoParkDailyEnabled toggles everyday Auto Park
0201          * @param enable true to activate, false to deactivate
0202          */
0203         Q_SCRIPTABLE void setAutoParkDailyEnabled(bool enabled);
0204 
0205         /**
0206          * @brief setAutoParkStartup Set time when automatic parking is activated.
0207          * @param startup Startup time. should not be more than 12 hours away.
0208          */
0209         Q_SCRIPTABLE void setAutoParkStartup(QTime startup);
0210 
0211         Q_SCRIPTABLE bool meridianFlipEnabled();
0212         Q_SCRIPTABLE double meridianFlipValue();
0213 
0214         /** DBUS interface function.
0215              * Slew the mount to the RA/DEC (JNow).
0216              * @param RA Right ascention is hours.
0217              * @param DEC Declination in degrees.
0218              * @return true if the command is sent successfully, false otherwise.
0219              */
0220         Q_INVOKABLE Q_SCRIPTABLE bool slew(double RA, double DEC);
0221 
0222         /**
0223               @brief Like above but RA and DEC are strings HH:MM:SS and DD:MM:SS
0224             */
0225         Q_INVOKABLE bool slew(const QString &RA, const QString &DEC);
0226 
0227         /** DBUS interface function.
0228              * Slew the mount to the target. Target name must be valid in KStars.
0229              * @param target name
0230              * @return true if the command is sent successfully, false otherwise.
0231              */
0232         Q_INVOKABLE Q_SCRIPTABLE bool gotoTarget(const QString &target);
0233 
0234         /** DBUS interface function.
0235              * Sync the mount to the RA/DEC (JNow).
0236              * @param RA Right ascention is hours.
0237              * @param DEC Declination in degrees.
0238              * @return true if the command is sent successfully, false otherwise.
0239              */
0240         Q_INVOKABLE Q_SCRIPTABLE bool sync(double RA, double DEC);
0241 
0242         /** DBUS interface function.
0243              * Sync the mount to the target. Target name must be valid in KStars.
0244              * @param target name
0245              * @return true if the command is sent successfully, false otherwise.
0246              */
0247         Q_INVOKABLE Q_SCRIPTABLE bool syncTarget(const QString &target);
0248 
0249         /**
0250               @brief Like above but RA and DEC are strings HH:MM:SS and DD:MM:SS
0251             */
0252         Q_INVOKABLE bool sync(const QString &RA, const QString &DEC);
0253 
0254         /** DBUS interface function.
0255              * Get equatorial coords (JNow). An array of doubles is returned. First element is RA in hours. Second elements is DEC in degrees.
0256              */
0257         Q_SCRIPTABLE QList<double> equatorialCoords();
0258 
0259         /** DBUS interface function.
0260              * Get Horizontal coords. An array of doubles is returned. First element is Azimuth in degrees. Second elements is Altitude in degrees.
0261              */
0262         Q_SCRIPTABLE QList<double> horizontalCoords();
0263 
0264         /** DBUS interface function.
0265              * Get Horizontal coords.
0266              */
0267         Q_SCRIPTABLE SkyPoint currentTarget();
0268 
0269         /** DBUS interface function.
0270              * Get mount hour angle in hours (-12 to +12).
0271              */
0272         Q_SCRIPTABLE double hourAngle();
0273 
0274         /** DBUS interface function.
0275              * Get the hour angle of that time the mount has slewed to the current position.
0276              * This is used to manage the meridian flip for mounts which do not report pier side.
0277              * only one attempt to flip is done.
0278              */
0279         Q_SCRIPTABLE double initialHA();
0280 
0281         /** DBUS interface function.
0282              * Aborts the mount motion
0283              * @return true if the command is sent successfully, false otherwise.
0284              */
0285         Q_INVOKABLE Q_SCRIPTABLE bool abort();
0286 
0287         /** DBUS interface function.
0288              * Get the mount slew status ("Idle","Complete", "Busy", "Error")
0289              */
0290         Q_INVOKABLE Q_SCRIPTABLE IPState slewStatus();
0291 
0292 
0293         /** DBUS interface function.
0294              * Get the mount slew rate index 0 to N-1, or -1 if slew rates are not supported.
0295              */
0296         Q_INVOKABLE Q_SCRIPTABLE int slewRate();
0297 
0298         Q_INVOKABLE Q_SCRIPTABLE bool setSlewRate(int index);
0299 
0300         /** DBUS interface function.
0301              * Reset mount model if supported by the mount.
0302              * @return true if the command is executed successfully, false otherwise.
0303              */
0304         Q_INVOKABLE Q_SCRIPTABLE bool resetModel();
0305 
0306         /** DBUS interface function.
0307              * Can mount park?
0308              */
0309         Q_INVOKABLE Q_SCRIPTABLE bool canPark();
0310 
0311         /** DBUS interface function.
0312              * Park mount
0313              */
0314         Q_INVOKABLE Q_SCRIPTABLE bool park();
0315 
0316         /** DBUS interface function.
0317              * Unpark mount
0318              */
0319         Q_INVOKABLE Q_SCRIPTABLE bool unpark();
0320 
0321         /** DBUS interface function.
0322              * Return parking status of the mount.
0323              */
0324         //Q_INVOKABLE Q_SCRIPTABLE ParkingStatus getParkingStatus();
0325 
0326         Q_INVOKABLE void setTrackEnabled(bool enabled);
0327 
0328         Q_INVOKABLE void setJ2000Enabled(bool enabled);
0329 
0330         /** @}*/
0331 
0332         Q_INVOKABLE void findTarget();
0333 
0334         // target coord conversions for displaying
0335         Q_INVOKABLE bool raDecToAzAlt(QString qsRA, QString qsDec);
0336         Q_INVOKABLE bool raDecToHaDec(QString qsRA);
0337         Q_INVOKABLE bool azAltToRaDec(QString qsAz, QString qsAlt);
0338         Q_INVOKABLE bool azAltToHaDec(QString qsAz, QString qsAlt);
0339         Q_INVOKABLE bool haDecToRaDec(QString qsHA);
0340         Q_INVOKABLE bool haDecToAzAlt(QString qsHA, QString qsDec);
0341 
0342         // Center mount in Sky Map
0343         Q_INVOKABLE void centerMount();
0344 
0345         Q_INVOKABLE void setUpDownReversed(bool enabled);
0346         Q_INVOKABLE void setLeftRightReversed(bool enabled);
0347 
0348         QString meridianFlipStatusDescription()
0349         {
0350             return meridianFlipStatusWidget->getStatus();
0351         }
0352 
0353         // Settings
0354         QVariantMap getAllSettings() const;
0355         void setAllSettings(const QVariantMap &settings);
0356 
0357     public slots:
0358 
0359         /**
0360              * @brief syncTelescopeInfo Update telescope information to reflect any property changes
0361              */
0362         void syncTelescopeInfo();
0363         /**
0364              * @brief updateProperty Update properties under watch in the mount module
0365              * @param prop INDI property
0366              */
0367         void updateProperty(INDI::Property prop);
0368 
0369         /**
0370              * @brief updateLog Update mount module log to include any messages arriving for the telescope driver
0371              * @param messageID ID of the new message
0372              */
0373         void updateLog(int messageID);
0374 
0375         /**
0376              * @brief updateTelescopeCoords is triggered by the ISD::Mount::newCoord() event and updates the displayed
0377              * coordinates of the mount and to ensure mount is within altitude limits if the altitude limits are enabled.
0378              * The frequency of this update depends on the REFRESH parameter of the INDI mount device.
0379              * @param position latest coordinates the mount reports it is pointing to
0380              * @param pierSide pierSide
0381              * @param ha hour angle of the latest coordinates
0382              */
0383         void updateTelescopeCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha);
0384 
0385         /**
0386              * @brief move Issues motion command to the mount to move in a particular direction based the request NS and WE values
0387              * @param command Either ISD::Mount::MOTION_START (0) or ISD::Mount::MOTION_STOP (1)
0388              * @param NS is either -1 for no direction, or ISD::Mount::MOTION_NORTH (0), or ISD::Mount::MOTION_SOUTH (1)
0389              * @param WE is either -1 for no direction, or ISD::Mount::MOTION_WEST (0), or ISD::Mount::MOTION_EAST (1)
0390              */
0391         void motionCommand(int command, int NS, int WE);
0392 
0393         /**
0394          * @brief Send a guide pulse to the telescope.
0395          * @param ra_dir RA guide direction
0396          * @param ra_msecs duration of the RA guiding pulse in milliseconds
0397          * @param dec_dir dec guide direction
0398          * @param dec_msecs duration of the DEC guiding pulse in milliseconds
0399          */
0400         void doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs);
0401 
0402         /**
0403              * @brief saveLimits Saves altitude limit to the user options and updates the INDI telescope driver limits
0404              */
0405         void saveLimits();
0406 
0407         /**
0408              * @brief Enable or disable altitude limits
0409              * @param enable True to enable, false to disable.
0410              */
0411         void setAltitudeLimits(bool enable);
0412 
0413         /**
0414              * @brief resumeAltLimits calls enableAltitudeLimits(true). This function is mostly used to enable altitude limit after a meridian flip is complete.
0415              */
0416         void resumeAltLimits();
0417 
0418         /**
0419              * @brief suspendAltLimits calls enableAltitudeLimits(false). This function is mostly used to disable altitude limit once a meridial flip process is started.
0420              */
0421         void suspendAltLimits();
0422 
0423         /**
0424              * @brief enableHourAngleLimits Enable or disable hour angle limits
0425              * @param enable True to enable, false to disable.
0426              */
0427         void enableHourAngleLimits(bool enable);
0428 
0429         /**
0430              * @brief enableHaLimits calls enableHourAngleLimits(true). This function is mostly used to enable hour angle limit after a meridian flip is complete.
0431              */
0432         void enableHaLimits();
0433 
0434         /**
0435              * @brief disableAltLimits calls enableHourAngleLimits(false). This function is mostly used to disable altitude limit once a meridial flip process is started.
0436              */
0437         void disableHaLimits();
0438 
0439         void toggleMountToolBox();
0440 
0441         /**
0442          * @brief set meridian flip activation and hours
0443          * @param activate true iff the meridian flip should be executed
0444          * @param degrees angle past the meridian when the flip should be delayed
0445          */
0446         void setMeridianFlipValues(bool activate, double degrees);
0447 
0448         /**
0449          * @brief React upon status changes of the polar alignment - mainly to
0450          *        avoid meridian flips happening during polar alignment.
0451          */
0452         void paaStageChanged(int stage);
0453 
0454         /**
0455          * @brief registerNewModule Register an Ekos module as it arrives via DBus
0456          * and create the appropriate DBus interface to communicate with it.
0457          * @param name of module
0458          */
0459         void registerNewModule(const QString &name);
0460 
0461         /**
0462          * @brief gotoTarget Slew to target coordinates.
0463          * @param target Target
0464          * @return True if slew successful, false otherwise.
0465          */
0466         bool gotoTarget(const SkyPoint &target);
0467 
0468         /**
0469          * @brief syncAxisReversed Update Mount Control GUI on the reverse motion toggled state.
0470          * @param axis RA (left/right) or DE (up/down)
0471          * @param reversed True if reversed, false otherwise.
0472          */
0473         void syncAxisReversed(INDI_EQ_AXIS axis, bool reversed);
0474 
0475         /**
0476          * @brief stopTimers Need to stop update timers when profile is disconnected
0477          * but due to timing and race conditions, the timers can trigger an invalid access
0478          * to INDI device.
0479          */
0480         void stopTimers();
0481 
0482     private slots:
0483         void startParkTimer();
0484         void stopParkTimer();
0485         void startAutoPark();
0486 
0487     signals:
0488         void newLog(const QString &text);
0489         /**
0490          * @brief Update event with the current telescope position
0491          * @param position mount position. Independent from the mount type,
0492          * the EQ coordinates(both JNow and J2000) as well as the alt/az values are filled.
0493          * @param pierside for GEMs report the pier side the scope is currently (PierSide::PIER_WEST means
0494          * the mount is on the western side of the pier pointing east of the meridian).
0495          * @param ha current hour angle
0496          */
0497         void newCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha);
0498         /**
0499          * @brief The mount has finished the slew to a new target.
0500          * @param currentCoords exact position where the mount is positioned
0501          */
0502         void newTarget(SkyPoint &currentCoord);
0503 
0504         /**
0505          * @brief The mount has finished the slew to a new target.
0506          * @param Name Name of object, if any, the mount is positioned at.
0507          */
0508         void newTargetName(const QString &name);
0509         /**
0510          * @brief Change in the mount status.
0511          */
0512         void newStatus(ISD::Mount::Status status);
0513         void newParkStatus(ISD::ParkStatus status);
0514         void pierSideChanged(ISD::Mount::PierSide side);
0515         void slewRateChanged(int index);
0516         void ready();
0517         void newMeridianFlipText(const QString &text);
0518         void autoParkCountdownUpdated(const QString &text);
0519 
0520         void settingsUpdated(const QVariantMap &settings);
0521         void trainChanged();
0522 
0523     private:
0524         ////////////////////////////////////////////////////////////////////
0525         /// Settings
0526         ////////////////////////////////////////////////////////////////////
0527 
0528         /**
0529          * @brief Connect GUI elements to sync settings once updated.
0530          */
0531         void connectSettings();
0532         /**
0533          * @brief Stop updating settings when GUI elements are updated.
0534          */
0535         void disconnectSettings();
0536         /**
0537          * @brief loadSettings Load setting from Options and set them accordingly.
0538          */
0539         void loadGlobalSettings();
0540 
0541         void connectSyncSettings();
0542         void disconnectSyncSettings();
0543 
0544         /**
0545          * @brief syncSettings When checkboxes, comboboxes, or spin boxes are updated, save their values in the
0546          * global and per-train settings.
0547          */
0548         void syncSettings();
0549 
0550         /**
0551          * @brief syncControl Sync setting to widget. The value depends on the widget type.
0552          * @param settings Map of all settings
0553          * @param key name of widget to sync
0554          * @param widget pointer of widget to set
0555          * @return True if sync successful, false otherwise
0556          */
0557         bool syncControl(const QVariantMap &settings, const QString &key, QWidget * widget);
0558 
0559         void syncGPS();
0560         void setScopeStatus(ISD::Mount::Status status);
0561         /* Meridian flip state handling */
0562         QSharedPointer<MeridianFlipState> mf_state;
0563         void setupParkUI();
0564 
0565         bool hasCaptureInterface { false };
0566 
0567         ISD::Mount *m_Mount {nullptr};
0568         ISD::GPS *m_GPS {nullptr};
0569         QList<ISD::GPS*> m_GPSes;
0570 
0571         QStringList m_LogText;
0572         SkyPoint telescopeCoord;
0573         SkyPoint *targetPosition {nullptr};
0574         QString lastNotificationMessage;
0575 
0576         // Auto Park
0577         QTimer autoParkTimer;
0578 
0579         // Limits
0580         int m_AbortAltDispatch {-1}, m_AbortHADispatch {-1};
0581         bool m_AltitudeLimitEnabled {false};
0582         double m_LastAltitude {0};
0583         bool m_HourAngleLimitEnabled {false};
0584         double m_LastHourAngle {0};
0585 
0586         // GPS
0587         bool GPSInitialized = {false};
0588 
0589         ISD::Mount::Status m_Status = ISD::Mount::MOUNT_IDLE;
0590         ISD::ParkStatus m_ParkStatus = ISD::PARK_UNKNOWN;
0591 
0592         // Settings
0593         QVariantMap m_Settings;
0594         QVariantMap m_GlobalSettings;
0595 
0596         QQuickView *m_BaseView = nullptr;
0597         QQuickItem *m_BaseObj  = nullptr;
0598         QQmlContext *m_Ctxt    = nullptr;
0599 
0600         QQuickItem *m_SpeedSlider = nullptr, *m_SpeedLabel = nullptr,
0601                     *m_raValue = nullptr, *m_deValue = nullptr, *m_azValue = nullptr,
0602                      *m_altValue = nullptr, *m_haValue = nullptr, *m_zaValue = nullptr,
0603                       *m_targetText = nullptr, *m_targetRAText = nullptr,
0604                        *m_targetDEText = nullptr, *m_Park = nullptr, *m_Unpark = nullptr,
0605                         *m_statusText = nullptr, *m_J2000Check = nullptr,
0606                          *m_JNowCheck = nullptr, *m_equatorialCheck = nullptr,
0607                           *m_horizontalCheck = nullptr, *m_haEquatorialCheck = nullptr,
0608                            *m_leftRightCheck = nullptr, *m_upDownCheck = nullptr;
0609 };
0610 }
0611 
0612 
0613 #endif // Mount