1 /*
2     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include <QDBusArgument>
10 #include <QTimer>
11 
12 #include "indistd.h"
13 #include "skypoint.h"
14 
15 class SkyObject;
16 
17 namespace ISD
18 {
19 /**
20  * @class Telescope
21  * device handle controlling telescope. It can slew and sync to a specific sky point and supports all standard properties with INDI
22  * telescope device.
23  *
24  * @author Jasem Mutlaq
25  */
26 class Telescope : public DeviceDecorator
27 {
28         Q_OBJECT
29 
30     public:
31         explicit Telescope(GDInterface *iPtr);
32         virtual ~Telescope() override = default;
33 
34         typedef enum { MOTION_NORTH, MOTION_SOUTH } TelescopeMotionNS;
35         typedef enum { MOTION_WEST, MOTION_EAST } TelescopeMotionWE;
36         typedef enum { MOTION_START, MOTION_STOP } TelescopeMotionCommand;
37         typedef enum { PIER_UNKNOWN = -1, PIER_WEST = 0, PIER_EAST = 1 } PierSide;
38         typedef enum
39         {
40             MOUNT_IDLE,
41             MOUNT_MOVING,
42             MOUNT_SLEWING,
43             MOUNT_TRACKING,
44             MOUNT_PARKING,
45             MOUNT_PARKED,
46             MOUNT_ERROR
47         } Status;
48         typedef enum { PARK_OPTION_CURRENT, PARK_OPTION_DEFAULT, PARK_OPTION_WRITE_DATA } ParkOptionCommand;
49         typedef enum { TRACK_SIDEREAL, TRACK_SOLAR, TRACK_LUNAR, TRACK_CUSTOM } TrackModes;
50 
51         void registerProperty(INDI::Property prop) override;
52         void processSwitch(ISwitchVectorProperty *svp) override;
53         void processText(ITextVectorProperty *tvp) override;
54         void processNumber(INumberVectorProperty *nvp) override;
55 
getType()56         DeviceFamily getType() override
57         {
58             return dType;
59         }
60 
61         // Coordinates
62         bool getEqCoords(double *ra, double *dec);
isJ2000()63         bool isJ2000()
64         {
65             return m_isJ2000;
66         }
67 
68         // Slew
69         bool Slew(SkyPoint *ScopeTarget);
70         bool Slew(double ra, double dec);
canGoto()71         bool canGoto()
72         {
73             return m_canGoto;
74         }
75 
76         // Sync
77         bool Sync(SkyPoint *ScopeTarget);
78         bool Sync(double ra, double dec);
canSync()79         bool canSync()
80         {
81             return m_canSync;
82         }
83 
84         // Tracking
canControlTrack()85         bool canControlTrack() const
86         {
87             return m_canControlTrack;
88         }
89         bool isTracking();
90 
91         // Track Mode
hasTrackModes()92         bool hasTrackModes() const
93         {
94             return m_hasTrackModes;
95         }
96         bool getTrackMode(uint8_t &index);
97 
98         // Custom Track Rate
hasCustomTrackRate()99         bool hasCustomTrackRate() const
100         {
101             return m_hasTrackModes;
102         }
103         bool getCustomTrackRate(double &raRate, double &deRate);
104 
105         // Motion
106         bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand cmd);
107         bool StopNS();
108         bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand cmd);
109         bool StopWE();
110         bool isSlewing();
111         bool isInMotion();
canAbort()112         bool canAbort()
113         {
114             return m_canAbort;
115         }
116         QString getManualMotionString() const;
117 
118         // Guiding
119         bool canGuide();
120         bool doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs);
121         bool doPulse(GuideDirection dir, int msecs);
122 
123         // Parking
124         bool canPark();
isParked()125         bool isParked()
126         {
127             return m_ParkStatus == PARK_PARKED;
128         }
canCustomPark()129         bool canCustomPark()
130         {
131             return m_hasCustomParking;
132         }
133         bool sendParkingOptionCommand(ParkOptionCommand command);
134 
135         // Status
parkStatus()136         ParkStatus parkStatus()
137         {
138             return m_ParkStatus;
139         }
140 
141         Status status(INumberVectorProperty *nvp);
142         Status status();
143         const QString getStatusString(Status status);
144 
145         // Altitude Limits
146         void setAltLimits(double minAltitude, double maxAltitude);
147 
148         // Alignment Model
149         bool setAlignmentModelEnabled(bool enable);
150         bool clearAlignmentModel();
151         bool clearParking();
hasAlignmentModel()152         bool hasAlignmentModel()
153         {
154             return m_hasAlignmentModel;
155         }
156 
157         // Slew Rates
hasSlewRates()158         bool hasSlewRates()
159         {
160             return m_hasSlewRates;
161         }
slewRates()162         QStringList slewRates()
163         {
164             return m_slewRates;
165         }
166         int getSlewRate() const;
167 
168         // Pier side
pierSide()169         PierSide pierSide() const
170         {
171             return m_PierSide;
172         }
173 
174         // Satellite tracking
canTrackSatellite()175         bool canTrackSatellite()
176         {
177             return m_canTrackSatellite;
178         }
179 
180         /**
181          * @short Tracks satellite on provided TLE, initial epoch for trajectory calculation and window in minutes
182          *
183          * This function needs a Two-Line-Element and a time window in the form of an initial point and a
184          * number of minutes on which the trajectory should start. The function was developed wiht the lx200
185          * in mind. If the trajectory has already started, the current time and a window of 1min are sufficient.
186          *
187          * @param tle Two-line-element.
188          * @param satPassStart Start time of the trajectory calculation
189          * @param satPassEnd End time of the trajectory calculation
190          */
191         bool setSatelliteTLEandTrack(QString tle, const KStarsDateTime satPassStart, const KStarsDateTime satPassEnd);
192 
193         /**
194          * @brief Hour angle of the current coordinates
195          */
196         const dms hourAngle() const;
197 
currentCoordinates()198         const SkyPoint &currentCoordinates() const
199         {
200             return currentCoords;
201         }
202 
203 
204     protected:
205         /**
206          * @brief Send the coordinates to the mount's INDI driver. Due to the INDI implementation, this
207          * function is shared for syncing, slewing and other (partly scope specific) functions like the
208          * setting parking position. The interpretation of the coordinates depends in the setting of other
209          * INDI switches for slewing, synching, tracking etc.
210          * @param ScopeTarget target coordinates
211          * @return true if sending the coordinates succeeded
212          */
213         bool sendCoords(SkyPoint *ScopeTarget);
214 
215         /**
216          * @brief Check whether sending new coordinates will result into a slew
217          */
218         bool slewDefined();
219 
220         /**
221          * @brief Helper function to update the J2000 coordinates of a sky point from its JNow coordinates
222          * @param coords sky point with correct JNow values in RA and DEC
223          */
224         void updateJ2000Coordinates(SkyPoint *coords);
225 
226 public slots:
227         virtual bool runCommand(int command, void *ptr = nullptr) override;
228         bool Abort();
229         bool Park();
230         bool UnPark();
231         bool setSlewRate(int index);
232         bool setTrackEnabled(bool enable);
233         bool setCustomTrackRate(double raRate, double deRate);
234         bool setTrackMode(uint8_t index);
235 
236     signals:
237         /**
238          * @brief The mount has finished the slew to a new target.
239          * @param currentObject object close to the position the mount is pointing to
240          * @param currentCoords exact position where the mount is positioned
241          */
242         void newTarget(SkyObject &currentObject, SkyPoint &currentCoords);
243         /**
244          * @brief Change in the mount status.
245          */
246         void newStatus(ISD::Telescope::Status status);
247         /**
248          * @brief Update event with the current telescope position
249          * @param position mount position. Independent from the mount type,
250          * the EQ coordinates(both JNow and J2000) as well as the alt/az values are filled.
251          * @param pierside for GEMs report the pier side the scope is currently (PierSide::PIER_WEST means
252          * the mount is on the western side of the pier pointing east of the meridian).
253          * @param ha current hour angle
254          */
255         void newCoords(const SkyPoint &position, const PierSide pierside, const dms &ha);
256         void newParkStatus(ISD::ParkStatus status);
257         void slewRateChanged(int rate);
258         void pierSideChanged(PierSide side);
259         void ready();
260 
261     private:
262         SkyPoint currentCoords;
263         double minAlt = 0, maxAlt = 90;
264         ParkStatus m_ParkStatus = PARK_UNKNOWN;
265         IPState EqCoordPreviousState;
266         QTimer centerLockTimer;
267         QTimer readyTimer;
268         SkyObject *currentObject = nullptr;
269         bool inManualMotion      = false;
270         bool inCustomParking     = false;
271         IPState NSPreviousState  = IPS_IDLE;
272         IPState WEPreviousState  = IPS_IDLE;
273         PierSide m_PierSide = PIER_UNKNOWN;
274 
275         KStarsDateTime g_satPassStart;
276         KStarsDateTime g_satPassEnd;
277 
278         QMap<TrackModes, uint8_t> TrackMap;
279         TrackModes currentTrackMode { TRACK_SIDEREAL };
280 
281         bool m_hasAlignmentModel = { false };
282         bool m_canControlTrack = { false };
283         bool m_canGoto { false};
284         bool m_canSync { false};
285         bool m_canAbort { false };
286         bool m_canTrackSatellite { false };
287         bool m_TLEIsSetForTracking { false };
288         bool m_windowIsSetForTracking { false };
289         bool m_hasTrackModes { false};
290         bool m_hasCustomTrackRate { false};
291         bool m_hasCustomParking { false };
292         bool m_hasSlewRates { false };
293         bool m_isJ2000 { false };
294         QStringList m_slewRates;
295 };
296 }
297 
298 Q_DECLARE_METATYPE(ISD::Telescope::Status)
299 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Telescope::Status &source);
300 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Telescope::Status &dest);
301 
302 Q_DECLARE_METATYPE(ISD::Telescope::PierSide)
303 QDBusArgument &operator<<(QDBusArgument &argument, const ISD::Telescope::PierSide &source);
304 const QDBusArgument &operator>>(const QDBusArgument &argument, ISD::Telescope::PierSide &dest);
305