Kstars

meridianflipstate.h
1/* Ekos state machine for the meridian flip
2 SPDX-FileCopyrightText: Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include <QObject>
10#include "skypoint.h"
11
12#include <ekos_mount_debug.h>
13#include "ekos/ekos.h"
14
15#include "indi/indistd.h"
16#include "indi/indimount.h"
17
18/**
19 * @brief A meridian flip is executed by issueing a scope motion to the target.
20 *
21 * Essentially, the meridian flip relies upon that the mount hardware selects the
22 * pier side of the scope on the appropriate side depending whether the scope points east
23 * or west of the meridian.
24 *
25 * While tracking a certain object a pier side change is necessary as soon as the position
26 * crosses the meridian. As soon as this is detected, the meridian flip works as follows:
27 * - A meridian flip request is sent to Capture so that a currently running capture can
28 * be completed before the flip starts.
29 * - Capture completes the currently running capture, stops capturing and sends a confirmation
30 * so that the flip may start.
31 * - Now a slew command is issued to the current target (i.e. the last position where a slew has
32 * been executed). This will force the mount hardware to reconsider the pier side and slews
33 * to the same position but changing the pier side.
34 * - As soon as the slew has been completed alignment is executed, guiding restarted and Capture
35 * informed that capturing may continue.
36 */
37
38namespace Ekos
39{
40
41class Mount;
42
43class MeridianFlipState : public QObject
44{
46public:
47 explicit MeridianFlipState(QObject *parent = nullptr);
48
49
50 // Meridian flip state of the mount
51 typedef enum
52 {
53 MOUNT_FLIP_NONE, // this is the default state, comparing the hour angle with the next flip position
54 // it moves to MOUNT_FLIP_PLANNED when a flip is needed
55 MOUNT_FLIP_PLANNED, // a meridian flip is ready to be started due to the target position and the
56 // configured offsets and signals to the Capture class that a flip is required
57 MOUNT_FLIP_WAITING, // step after FLUP_PLANNED waiting until Capture completes a running exposure
58 MOUNT_FLIP_ACCEPTED, // Capture is idle or has completed the exposure and will wait until the flip
59 // is completed.
60 MOUNT_FLIP_RUNNING, // this signals that a flip slew is in progress, when the slew is completed
61 // the state is set to MOUNT_FLIP_COMPLETED
62 MOUNT_FLIP_COMPLETED, // this checks that the flip was completed successfully or not and after tidying up
63 // moves to MOUNT_FLIP_NONE to wait for the next flip requirement.
64 // Capture sees this and resumes.
65 MOUNT_FLIP_ERROR // errors in the flip process should end up here
66 } MeridianFlipMountState;
67
68 // overall meridian flip stage
69 typedef enum {
70 MF_NONE, /* no meridian flip planned */
71 MF_REQUESTED, /* meridian flip necessary, confirmation requested to start the flip */
72 MF_READY, /* confirmations received, the meridian flip may start */
73 MF_INITIATED, /* meridian flip started */
74 MF_FLIPPING, /* slew started to the target position */
75 MF_COMPLETED, /* meridian flip completed, re-calibration required */
76 MF_ALIGNING, /* alignment running after a successful flip */
77 MF_GUIDING /* guiding started after a successful flip */
78 } MFStage;
79
80 // mount position
81 typedef struct MountPosition {
82 SkyPoint position;
83 ISD::Mount::PierSide pierSide;
84 dms ha;
85 bool valid = false;
86 } MountPosition;
87
88 // flag if alignment should be executed after the meridian flip
89 bool resumeAlignmentAfterFlip() { return m_resumeAlignmentAfterFlip; }
90 void setResumeAlignmentAfterFlip(bool resume) { m_resumeAlignmentAfterFlip = resume; }
91
92 // flag if guiding should be resetarted after the meridian flip
93 bool resumeGuidingAfterFlip() { return m_resumeGuidingAfterFlip; }
94 void setResumeGuidingAfterFlip(bool resume) { m_resumeGuidingAfterFlip = resume; }
95
96 /**
97 * @brief Translate the state to a string value.
98 */
99 static QString MFStageString(MFStage stage);
100
101 // Is the meridian flip enabled?
102 bool isEnabled() const { return m_enabled; }
103 void setEnabled(bool value);
104 // offset past the meridian
105 double getOffset() const { return m_offset; }
106 void setOffset(double newOffset) { m_offset = newOffset; }
107
108 /**
109 * @brief connectMount Establish the connection to the mount
110 */
111 void connectMount(Mount *mount);
112
113 MeridianFlipState::MFStage getMeridianFlipStage() const { return meridianFlipStage; };
114 const QString &getMeridianStatusText()
115 {
116 return m_lastStatusText;
117 }
118
119 /**
120 * @brief Update the meridian flip stage
121 */
122 void updateMeridianFlipStage(const MFStage &stage);
123
124 /**
125 * @brief Stop a meridian flip if necessary.
126 * @return true if a meridian flip was running
127 */
128 bool resetMeridianFlip();
129
130 /**
131 * @brief Execute actions after the flipping slew has completed.
132 */
133 void processFlipCompleted();
134
135 /**
136 * @brief Check if a meridian flip has already been started
137 * @return true iff the scope has started the meridian flip
138 */
139 inline bool checkMeridianFlipRunning()
140 {
141 return meridianFlipStage == MF_INITIATED || meridianFlipStage == MF_FLIPPING;
142 }
143
144 /**
145 * @brief Check if a meridian flip is ready to start, running or some post flip actions are not comleted.
146 */
147 inline bool checkMeridianFlipActive()
148 {
149 return meridianFlipStage != MF_NONE && meridianFlipStage != MF_REQUESTED;
150 }
151
152 /**
153 * @brief Update the current target position
154 * @param pos new target (may be null if no target is set)
155 */
156 void setTargetPosition(SkyPoint *pos);
157
158 /**
159 * @brief Make current target position invalid
160 */
161 void clearTargetPosition() { targetPosition.valid = false; }
162
163 /**
164 * @brief Get the hour angle of that time the mount has slewed to the current position.
165 * his is used to manage the meridian flip for mounts which do not report pier side.
166 * (-12.0 < HA <= 12.0)
167 */
168 double initialPositionHA() const;
169
170 /**
171 * @brief access to the meridian flip mount state
172 */
173 MeridianFlipMountState getMeridianFlipMountState() const { return meridianFlipMountState; }
174
175 double getFlipDelayHrs() const { return flipDelayHrs; }
176 void setFlipDelayHrs(double value) { flipDelayHrs = value; }
177
178 /**
179 * @brief Change the meridian flip mount state
180 */
181 void updateMFMountState(MeridianFlipState::MeridianFlipMountState status);
182
183 /**
184 * @brief return the string for the status
185 */
186 static QString meridianFlipStatusString(MeridianFlipMountState status);
187
188 // Access to the current mount device
189 void setMountConnected(bool connected) { m_hasMount = connected; }
190
191 // Access to the capture device
192 void setHasCaptureInterface(bool present) { m_hasCaptureInterface = present; }
193
194public slots:
195 /**
196 * @brief Slot for receiving an update of the capture status
197 */
198 void setCaptureState(CaptureState state) { m_CaptureState = state; }
199 /**
200 * @brief Slot for receiving an update to the mount status
201 */
202 void setMountStatus(ISD::Mount::Status status);
203 /**
204 * @brief Slot for receiving an update to the mount park status
205 */
206 void setMountParkStatus(ISD::ParkStatus status);
207 /**
208 * @brief Slot for receiving a new telescope position
209 * @param position new position
210 * @param pierSide current pier side
211 * @param ha current hour angle
212 */
213 void updateTelescopeCoord(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha);
214
215signals:
216 // mount meridian flip status update event
217 void newMountMFStatus(MeridianFlipMountState status);
218 // Communicate a new meridian flip mount status message
219 void newMeridianFlipMountStatusText(const QString &text);
220 // slew the telescope to a target
221 void slewTelescope(SkyPoint &target);
222 // new log text for the module log window
223 void newLog(const QString &text);
224
225private:
226 // flag if meridian flip is enabled
227 bool m_enabled = false;
228 // offset post meridian (in degrees)
229 double m_offset;
230 // flag if alignment should be executed after the meridian flip
231 bool m_resumeAlignmentAfterFlip { false };
232 // flag if guiding should be resetarted after the meridian flip
233 bool m_resumeGuidingAfterFlip { false };
234
235 // the mount device
236 bool m_hasMount { false };
237 // capture interface
238 bool m_hasCaptureInterface { false };
239 // the current capture status
240 CaptureState m_CaptureState { CAPTURE_IDLE };
241 // the current mount status
242 ISD::Mount::Status m_MountStatus = ISD::Mount::MOUNT_IDLE;
243 // the previous mount status
244 ISD::Mount::Status m_PrevMountStatus = ISD::Mount::MOUNT_IDLE;
245 // mount park status
246 ISD::ParkStatus m_MountParkStatus = ISD::PARK_UNKNOWN;
247 // current overall meridian flip state
248 MFStage meridianFlipStage { MF_NONE };
249
250 // current mount meridian flip state
251 MeridianFlipMountState meridianFlipMountState { MOUNT_FLIP_NONE };
252 // last message published to avoid double entries
253 QString m_lastStatusText = "";
254
255 SkyPoint initialMountCoords;
256
257 // current position of the mount
258 MountPosition currentPosition;
259 // current target position (might be different from current position!)
260 MountPosition targetPosition;
261
262 static void updatePosition(MountPosition &pos, const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha, const bool isValid);
263
264 // A meridian flip requires a slew of 180 degrees in the hour angle axis so will take a certain
265 // amount of time. Within this time, a slewing state change will be ignored for pier side change checks.
266 QDateTime minMeridianFlipEndTime;
267
268 double flipDelayHrs = 0.0; // delays the next flip attempt if it fails
269
270 /**
271 * @brief Internal method for changing the mount meridian flip state. From extermal, use {@see updateMFMountState()}
272 */
273 void setMeridianFlipMountState(MeridianFlipMountState newMeridianFlipMountState);
274
275 /**
276 * @brief Check if a meridian flip if necessary.
277 * @param lst local sideral time
278 */
279 bool checkMeridianFlip(dms lst);
280
281 /**
282 * @brief Start a meridian flip if necessary.
283 * @return true if a meridian flip was started
284 */
285 void startMeridianFlip();
286
287 /**
288 * @brief Calculate the minimal end time from now plus {@see minMeridianFlipEndTime}
289 */
290 void updateMinMeridianFlipEndTime();
291
292 /**
293 * @brief React upon a meridian flip status change of the mount.
294 */
295 void publishMFMountStatus(MeridianFlipMountState status);
296
297 /**
298 * @brief publish a new meridian flip mount status text
299 */
300 void publishMFMountStatusText(QString text);
301
302 /**
303 * @brief Add log message
304 */
305 void appendLogText(QString message);
306
307};
308} // namespace
The sky coordinates of a point in the sky.
Definition skypoint.h:45
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
@ CAPTURE_IDLE
Definition ekos.h:93
Q_OBJECTQ_OBJECT
QObject * parent() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.