File indexing completed on 2024-07-21 06:28:23

0001 /*
0002     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QDBusArgument>
0010 #include <QTimer>
0011 
0012 #include "indiconcretedevice.h"
0013 #include "skypoint.h"
0014 
0015 class SkyObject;
0016 
0017 namespace ISD
0018 {
0019 /**
0020  * @class Mount
0021  * device handle controlling Mounts. It can slew and sync to a specific sky point and supports all standard properties with INDI
0022  * telescope device.
0023  *
0024  * @author Jasem Mutlaq
0025  */
0026 class Mount : public ConcreteDevice
0027 {
0028         Q_OBJECT
0029 
0030     public:
0031         explicit Mount(GenericDevice *parent);
0032         virtual ~Mount() override = default;
0033 
0034         typedef enum { MOTION_NORTH, MOTION_SOUTH } VerticalMotion;
0035         typedef enum { MOTION_WEST, MOTION_EAST } HorizontalMotion;
0036         typedef enum { MOTION_START, MOTION_STOP } MotionCommand;
0037         typedef enum { PIER_UNKNOWN = -1, PIER_WEST = 0, PIER_EAST = 1 } PierSide;
0038         static QString pierSideStateString(PierSide ps)
0039         {
0040             switch (ps)
0041             {
0042             case ISD::Mount::PierSide::PIER_EAST:
0043                 return "Pier Side: East (pointing West)";
0044             case ISD::Mount::PierSide::PIER_WEST:
0045                 return "Pier Side: West (pointing East)";
0046             default:
0047                 return "Pier Side: Unknown";
0048             }
0049         }
0050 
0051         typedef enum
0052         {
0053             MOUNT_IDLE,
0054             MOUNT_MOVING,
0055             MOUNT_SLEWING,
0056             MOUNT_TRACKING,
0057             MOUNT_PARKING,
0058             MOUNT_PARKED,
0059             MOUNT_ERROR
0060         } Status;
0061         typedef enum { PARK_OPTION_CURRENT, PARK_OPTION_DEFAULT, PARK_OPTION_WRITE_DATA } ParkOptionCommand;
0062         typedef enum { TRACK_SIDEREAL, TRACK_SOLAR, TRACK_LUNAR, TRACK_CUSTOM } TrackModes;
0063 
0064 
0065         static const QList<const char *> mountStates;
0066 
0067         void registerProperty(INDI::Property prop) override;
0068         void processSwitch(INDI::Property prop) override;
0069         void processText(INDI::Property prop) override;
0070         void processNumber(INDI::Property prop) override;
0071 
0072         // Coordinates
0073         bool getEqCoords(double *ra, double *dec);
0074         bool isJ2000()
0075         {
0076             return m_isJ2000;
0077         }
0078 
0079         // Slew
0080         bool Slew(SkyPoint *ScopeTarget, bool flip=false);
0081         bool Slew(double ra, double dec, bool flip=false);
0082         bool canGoto()
0083         {
0084             return m_canGoto;
0085         }
0086         bool canFlip()
0087         {
0088             return m_canFlip;
0089         }
0090 
0091         // Sync
0092         bool Sync(SkyPoint *ScopeTarget);
0093         bool Sync(double ra, double dec);
0094         bool canSync()
0095         {
0096             return m_canSync;
0097         }
0098 
0099         // Tracking
0100         bool canControlTrack() const
0101         {
0102             return m_canControlTrack;
0103         }
0104         bool isTracking();
0105 
0106         // Track Mode
0107         bool hasTrackModes() const
0108         {
0109             return m_hasTrackModes;
0110         }
0111         bool getTrackMode(uint8_t &index);
0112 
0113         // Custom Track Rate
0114         bool hasCustomTrackRate() const
0115         {
0116             return m_hasTrackModes;
0117         }
0118         bool getCustomTrackRate(double &raRate, double &deRate);
0119 
0120         // Motion
0121         bool MoveNS(VerticalMotion dir, MotionCommand cmd);
0122         bool StopNS();
0123         bool MoveWE(HorizontalMotion dir, MotionCommand cmd);
0124         bool StopWE();
0125         bool isReversed(INDI_EQ_AXIS axis);
0126         bool setReversedEnabled(INDI_EQ_AXIS axis, bool enabled);
0127         bool isSlewing();
0128         bool isInMotion();
0129         bool canAbort()
0130         {
0131             return m_canAbort;
0132         }
0133         QString getManualMotionString() const;
0134 
0135         // Guiding
0136         bool canGuide();
0137         bool doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs);
0138         bool doPulse(GuideDirection dir, int msecs);
0139 
0140         // Parking
0141         bool canPark();
0142         bool isParked()
0143         {
0144             return m_ParkStatus == PARK_PARKED;
0145         }
0146         bool canCustomPark()
0147         {
0148             return m_hasCustomParking;
0149         }
0150         bool sendParkingOptionCommand(ParkOptionCommand command);
0151 
0152         // Status
0153         ParkStatus parkStatus()
0154         {
0155             return m_ParkStatus;
0156         }
0157 
0158         Status status(INumberVectorProperty *nvp);
0159         Status status();
0160         const QString statusString(Status status, bool translated = true) const;
0161 
0162         // Altitude Limits
0163         void setAltLimits(double minAltitude, double maxAltitude);
0164 
0165         // Alignment Model
0166         bool setAlignmentModelEnabled(bool enable);
0167         bool clearAlignmentModel();
0168         bool clearParking();
0169         bool hasAlignmentModel()
0170         {
0171             return m_hasAlignmentModel;
0172         }
0173 
0174         // Slew Rates
0175         bool hasSlewRates()
0176         {
0177             return m_hasSlewRates;
0178         }
0179         QStringList slewRates()
0180         {
0181             return m_slewRates;
0182         }
0183         int getSlewRate() const;
0184 
0185         // Pier side
0186         PierSide pierSide() const
0187         {
0188             return m_PierSide;
0189         }
0190 
0191         // Satellite tracking
0192         bool canTrackSatellite()
0193         {
0194             return m_canTrackSatellite;
0195         }
0196 
0197         /**
0198          * @short Tracks satellite on provided TLE, initial epoch for trajectory calculation and window in minutes
0199          *
0200          * This function needs a Two-Line-Element and a time window in the form of an initial point and a
0201          * number of minutes on which the trajectory should start. The function was developed wiht the lx200
0202          * in mind. If the trajectory has already started, the current time and a window of 1min are sufficient.
0203          *
0204          * @param tle Two-line-element.
0205          * @param satPassStart Start time of the trajectory calculation
0206          * @param satPassEnd End time of the trajectory calculation
0207          */
0208         bool setSatelliteTLEandTrack(QString tle, const KStarsDateTime satPassStart, const KStarsDateTime satPassEnd);
0209 
0210         /**
0211          * @brief Hour angle of the current coordinates
0212          */
0213         const dms hourAngle() const;
0214 
0215         const SkyPoint &currentCoordinates() const
0216         {
0217             return currentCoords;
0218         }
0219 
0220         /**
0221          * @brief stopTimers Stop timers to prevent timing race condition when device is unavailable
0222          * and timer is still invoked.
0223          */
0224         void stopTimers();
0225 
0226         void centerLock();
0227         void centerUnlock();
0228         void find();
0229         void setCustomParking(SkyPoint *coords = nullptr);
0230 
0231     protected:
0232         /**
0233          * @brief Send the coordinates to the mount's INDI driver. Due to the INDI implementation, this
0234          * function is shared for syncing, slewing and other (partly scope specific) functions like the
0235          * setting parking position. The interpretation of the coordinates depends in the setting of other
0236          * INDI switches for slewing, synching, tracking etc.
0237          * @param ScopeTarget target coordinates
0238          * @return true if sending the coordinates succeeded
0239          */
0240         bool sendCoords(SkyPoint *ScopeTarget);
0241 
0242         /**
0243          * @brief Check whether sending new coordinates will result into a slew
0244          */
0245         bool slewDefined();
0246 
0247         /**
0248          * @brief Helper function to update the J2000 coordinates of a sky point from its JNow coordinates
0249          * @param coords sky point with correct JNow values in RA and DEC
0250          */
0251         void updateJ2000Coordinates(SkyPoint *coords);
0252 
0253         /**
0254          * @brief updateParkStatus Updating parking status by checking the TELESCOPE_PARK property.
0255          */
0256         void updateParkStatus();
0257 
0258         /**
0259          * @brief updateTarget update target position from {@see currentPosition} and
0260          *       (if not pointing into the empty sky) also the target name.
0261          */
0262         void updateTarget();
0263 
0264     public slots:
0265         bool abort();
0266         bool park();
0267         bool unpark();
0268         bool setSlewRate(int index);
0269         bool setTrackEnabled(bool enable);
0270         bool setCustomTrackRate(double raRate, double deRate);
0271         bool setTrackMode(uint8_t index);
0272 
0273     signals:
0274         /**
0275          * @brief The mount has finished the slew to a new target.
0276          * @param currentCoords exact position where the mount is positioned
0277          */
0278         void newTarget(SkyPoint &currentCoords);
0279 
0280         /**
0281          * @brief The mount has finished the slew to a new target.
0282          * @param Name Name of object, if any, the mount is positioned at.
0283          */
0284         void newTargetName(const QString &name);
0285         /**
0286          * @brief Change in the mount status.
0287          */
0288         void newStatus(ISD::Mount::Status status);
0289         /**
0290          * @brief Update event with the current telescope position
0291          * @param position mount position. Independent from the mount type,
0292          * the EQ coordinates(both JNow and J2000) as well as the alt/az values are filled.
0293          * @param pierside for GEMs report the pier side the scope is currently (PierSide::PIER_WEST means
0294          * the mount is on the western side of the pier pointing east of the meridian).
0295          * @param ha current hour angle
0296          */
0297         void newCoords(const SkyPoint &position, const PierSide pierside, const dms &ha);
0298         void newParkStatus(ISD::ParkStatus status);
0299         void slewRateChanged(int rate);
0300         void pierSideChanged(PierSide side);
0301         void axisReversed(INDI_EQ_AXIS axis, bool reversed);
0302 
0303     private:
0304         SkyPoint currentCoords;
0305         double minAlt {0}, maxAlt = 90;
0306         ParkStatus m_ParkStatus = PARK_UNKNOWN;
0307         IPState EqCoordPreviousState {IPS_IDLE};
0308         QTimer centerLockTimer;
0309         QTimer updateCoordinatesTimer;
0310         SkyObject *currentObject = nullptr;
0311         bool inManualMotion      = false;
0312         bool inCustomParking     = false;
0313         IPState NSPreviousState  = IPS_IDLE;
0314         IPState WEPreviousState  = IPS_IDLE;
0315         PierSide m_PierSide = PIER_UNKNOWN;
0316 
0317         KStarsDateTime g_satPassStart;
0318         KStarsDateTime g_satPassEnd;
0319 
0320         QMap<TrackModes, uint8_t> TrackMap;
0321         TrackModes currentTrackMode { TRACK_SIDEREAL };
0322 
0323         bool m_hasAlignmentModel = { false };
0324         bool m_canControlTrack = { false };
0325         bool m_canGoto { false};
0326         bool m_canFlip { false};
0327         bool m_canSync { false};
0328         bool m_canAbort { false };
0329         bool m_canTrackSatellite { false };
0330         bool m_TLEIsSetForTracking { false };
0331         bool m_windowIsSetForTracking { false };
0332         bool m_hasTrackModes { false};
0333         bool m_hasCustomTrackRate { false};
0334         bool m_hasCustomParking { false };
0335         bool m_hasSlewRates { false };
0336         bool m_isJ2000 { false };
0337         bool m_hasEquatorialCoordProperty { false };
0338         QStringList m_slewRates;
0339 };
0340 }
0341 
0342 Q_DECLARE_METATYPE(ISD::Mount::Status)
0343 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Mount::Status &source);
0344 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Mount::Status &dest);
0345 
0346 Q_DECLARE_METATYPE(ISD::Mount::PierSide)
0347 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Mount::PierSide &source);
0348 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Mount::PierSide &dest);