7#include "meridianflipstate.h"
8#include "ekos/mount/mount.h"
11#include "kstarsdata.h"
14#include <ekos_capture_debug.h>
18MeridianFlipState::MeridianFlipState(
QObject *parent) :
QObject(parent)
22void MeridianFlipState::setResumeAlignmentAfterFlip(
bool resume)
24 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Setting resume alignment after flip to" << (resume ?
"true" :
"false");
25 m_resumeAlignmentAfterFlip = resume;
28QString MeridianFlipState::MFStageString(MFStage stage)
35 return "MF_REQUESTED";
39 return "MF_INITIATED";
43 return "MF_COMPLETED";
49 return "MFStage unknown.";
52void MeridianFlipState::setEnabled(
bool value)
56 if (m_enabled ==
false)
57 updateMFMountState(MOUNT_FLIP_NONE);
60void MeridianFlipState::connectMount(Mount *mount)
66void MeridianFlipState::updateMeridianFlipStage(
const MFStage &stage)
68 qCDebug(KSTARS_EKOS_CAPTURE) <<
"updateMeridianFlipStage: " << MeridianFlipState::MFStageString(stage);
70 if (meridianFlipStage != stage)
74 case MeridianFlipState::MF_NONE:
75 meridianFlipStage = stage;
78 case MeridianFlipState::MF_READY:
79 if (getMeridianFlipStage() == MeridianFlipState::MF_REQUESTED)
82 updateMFMountState(MeridianFlipState::MOUNT_FLIP_ACCEPTED);
84 else if (m_CaptureState == CAPTURE_PAUSED)
87 meridianFlipStage = stage;
88 updateMFMountState(MeridianFlipState::MOUNT_FLIP_ACCEPTED);
90 else if (!(checkMeridianFlipRunning()
91 || getMeridianFlipStage() == MeridianFlipState::MF_COMPLETED))
96 meridianFlipStage = MeridianFlipState::MF_NONE;
102 case MeridianFlipState::MF_INITIATED:
103 meridianFlipStage = MeridianFlipState::MF_INITIATED;
106 case MeridianFlipState::MF_REQUESTED:
107 if (m_CaptureState == CAPTURE_PAUSED)
109 updateMFMountState(MeridianFlipState::MOUNT_FLIP_ACCEPTED);
111 updateMFMountState(MeridianFlipState::MOUNT_FLIP_WAITING);
112 meridianFlipStage = stage;
115 case MeridianFlipState::MF_COMPLETED:
116 meridianFlipStage = MeridianFlipState::MF_COMPLETED;
120 meridianFlipStage = stage;
128bool MeridianFlipState::checkMeridianFlip(
dms lst)
131 if (m_hasMount ==
false)
133 publishMFMountStatusText(
i18n(
"Meridian flip inactive (no scope connected)"));
134 updateMFMountState(MOUNT_FLIP_NONE);
138 if (isEnabled() ==
false)
140 publishMFMountStatusText(
i18n(
"Meridian flip inactive (flip not requested)"));
145 if (m_MountParkStatus == ISD::PARK_PARKED)
147 publishMFMountStatusText(
i18n(
"Meridian flip inactive (parked)"));
151 if (targetPosition.valid ==
false || isEnabled() ==
false)
153 publishMFMountStatusText(
i18n(
"Meridian flip inactive (no target set)"));
158 double offset = rangeHA(m_offset / 15.0);
160 double hrsToFlip = 0;
162 double ha = currentPosition.ha.HoursHa();
173 static ISD::Mount::PierSide initialPierSide;
176 switch (currentPosition.pierSide)
178 case ISD::Mount::PierSide::PIER_WEST:
181 case ISD::Mount::PierSide::PIER_EAST:
184 ha = rangeHA(ha + 12);
190 if (initialPositionHA() >= 0)
192 publishMFMountStatusText(
i18n(
"Meridian flip inactive (slew after meridian)"));
193 if (getMeridianFlipMountState() == MOUNT_FLIP_NONE)
203 hrsToFlip = offset + getFlipDelayHrs() - ha;
205 int hh =
static_cast<int> (hrsToFlip);
206 int mm =
static_cast<int> ((hrsToFlip - hh) * 60);
207 int ss =
static_cast<int> ((hrsToFlip - hh - mm / 60.0) * 3600);
211 switch (getMeridianFlipMountState())
213 case MOUNT_FLIP_NONE:
214 publishMFMountStatusText(message);
219 qCInfo(KSTARS_EKOS_MOUNT) <<
"Meridian flip planned with LST=" <<
221 " scope RA=" << currentPosition.position.ra().toHMSString() <<
223 ", meridian diff=" << offset <<
224 ", hrstoFlip=" << hrsToFlip <<
225 ", flipDelayHrs=" << getFlipDelayHrs() <<
226 ", " << ISD::Mount::pierSideStateString(currentPosition.pierSide);
228 initialPierSide = currentPosition.pierSide;
229 updateMFMountState(MOUNT_FLIP_PLANNED);
233 case MOUNT_FLIP_PLANNED:
235 if (m_hasCaptureInterface ==
false)
237 qCDebug(KSTARS_EKOS_MOUNT) <<
"no capture interface, starting flip slew.";
238 updateMFMountState(MOUNT_FLIP_ACCEPTED);
243 case MOUNT_FLIP_ACCEPTED:
247 case MOUNT_FLIP_RUNNING:
248 if (m_MountStatus == ISD::Mount::MOUNT_TRACKING)
250 if (minMeridianFlipEndTime <= KStarsData::Instance()->clock()->utc())
254 bool flipFailed =
false;
257 if (currentPosition.pierSide == ISD::Mount::PIER_UNKNOWN)
259 appendLogText(
i18n(
"Assuming meridian flip completed, but pier side unknown."));
261 updateMFMountState(MOUNT_FLIP_COMPLETED);
264 else if (currentPosition.pierSide == initialPierSide)
267 qCWarning(KSTARS_EKOS_MOUNT) <<
"Meridian flip failed, pier side not changed";
272 if (getFlipDelayHrs() <= 1.0)
276 constexpr double delayHours = 4.0 / 60.0;
277 if (currentPosition.pierSide == ISD::Mount::PierSide::PIER_EAST)
278 setFlipDelayHrs(rangeHA(ha + 12 + delayHours) - offset);
280 setFlipDelayHrs(ha + delayHours - offset);
283 appendLogText(
i18n(
"meridian flip failed, retrying in 4 minutes"));
287 appendLogText(
i18n(
"No successful Meridian Flip done, delay too long"));
289 updateMFMountState(MOUNT_FLIP_COMPLETED);
294 appendLogText(
i18n(
"Meridian flip completed OK."));
296 updateMFMountState(MOUNT_FLIP_COMPLETED);
300 qCInfo(KSTARS_EKOS_MOUNT) <<
"Tracking state during meridian flip reached too early, ignored.";
304 case MOUNT_FLIP_COMPLETED:
305 updateMFMountState(MOUNT_FLIP_NONE);
314void MeridianFlipState::startMeridianFlip()
316 if ( targetPosition.valid ==
false)
319 qCDebug(KSTARS_EKOS_MOUNT) <<
"No meridian flip: no target defined";
323 if (m_MountStatus != ISD::Mount::MOUNT_TRACKING)
326 if (m_hasMount ==
false)
327 qCWarning(KSTARS_EKOS_MOUNT()) <<
"No mount connected!";
330 qCInfo(KSTARS_EKOS_MOUNT) <<
"No meridian flip: mount not tracking, current state:" <<
331 ISD::Mount::mountStates[m_MountStatus].untranslatedText();
335 dms lst = KStarsData::Instance()->
geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
336 double HA = rangeHA(lst.
Hours() - targetPosition.position.ra().Hours());
339 qCInfo(KSTARS_EKOS_MOUNT) <<
"Meridian flip: slewing to RA=" <<
340 targetPosition.position.ra().toHMSString() <<
341 "DEC=" << targetPosition.position.dec().toDMSString() <<
344 updateMinMeridianFlipEndTime();
345 updateMFMountState(MeridianFlipState::MOUNT_FLIP_RUNNING);
348 emit slewTelescope(targetPosition.position);
351bool MeridianFlipState::resetMeridianFlip()
355 if (meridianFlipMountState != MOUNT_FLIP_RUNNING)
357 updateMFMountState(MOUNT_FLIP_NONE);
359 qCDebug(KSTARS_EKOS_MOUNT) <<
"flipDelayHrs set to zero in slew, m_MFStatus=" <<
360 meridianFlipStatusString(meridianFlipMountState);
368void MeridianFlipState::processFlipCompleted()
370 appendLogText(
i18n(
"Telescope completed the meridian flip."));
371 if (m_CaptureState == CAPTURE_IDLE || m_CaptureState == CAPTURE_ABORTED || m_CaptureState == CAPTURE_COMPLETE)
375 updateMeridianFlipStage(MeridianFlipState::MF_NONE);
382void MeridianFlipState::setMeridianFlipMountState(MeridianFlipMountState newMeridianFlipMountState)
384 qCDebug (KSTARS_EKOS_MOUNT) <<
"Setting meridian flip status to " << meridianFlipStatusString(newMeridianFlipMountState);
385 publishMFMountStatus(newMeridianFlipMountState);
386 meridianFlipMountState = newMeridianFlipMountState;
389void MeridianFlipState::appendLogText(
QString message)
391 qCInfo(KSTARS_EKOS_MOUNT) << message;
392 emit newLog(message);
395void MeridianFlipState::updateMinMeridianFlipEndTime()
397 minMeridianFlipEndTime = KStarsData::Instance()->
clock()->
utc().addSecs(Options::minFlipDuration());
400void MeridianFlipState::updateMFMountState(MeridianFlipMountState status)
402 if (getMeridianFlipMountState() != status)
404 if (status == MOUNT_FLIP_ACCEPTED)
407 if (meridianFlipStage != MF_REQUESTED)
411 setMeridianFlipMountState(status);
412 emit newMountMFStatus(status);
416void MeridianFlipState::publishMFMountStatus(MeridianFlipMountState status)
419 if (status == meridianFlipMountState)
424 case MOUNT_FLIP_NONE:
425 publishMFMountStatusText(
i18n(
"Status: inactive"));
428 case MOUNT_FLIP_PLANNED:
429 publishMFMountStatusText(
i18n(
"Meridian flip planned..."));
432 case MOUNT_FLIP_WAITING:
433 publishMFMountStatusText(
i18n(
"Meridian flip waiting..."));
436 case MOUNT_FLIP_ACCEPTED:
437 publishMFMountStatusText(
i18n(
"Meridian flip ready to start..."));
440 case MOUNT_FLIP_RUNNING:
441 publishMFMountStatusText(
i18n(
"Meridian flip running..."));
444 case MOUNT_FLIP_COMPLETED:
445 publishMFMountStatusText(
i18n(
"Meridian flip completed."));
454void MeridianFlipState::publishMFMountStatusText(
QString text)
457 if (text != m_lastStatusText)
459 emit newMeridianFlipMountStatusText(text);
460 m_lastStatusText = text;
464QString MeridianFlipState::meridianFlipStatusString(MeridianFlipMountState status)
468 case MOUNT_FLIP_NONE:
469 return "MOUNT_FLIP_NONE";
470 case MOUNT_FLIP_PLANNED:
471 return "MOUNT_FLIP_PLANNED";
472 case MOUNT_FLIP_WAITING:
473 return "MOUNT_FLIP_WAITING";
474 case MOUNT_FLIP_ACCEPTED:
475 return "MOUNT_FLIP_ACCEPTED";
476 case MOUNT_FLIP_RUNNING:
477 return "MOUNT_FLIP_RUNNING";
478 case MOUNT_FLIP_COMPLETED:
479 return "MOUNT_FLIP_COMPLETED";
480 case MOUNT_FLIP_ERROR:
481 return "MOUNT_FLIP_ERROR";
483 return "not possible";
490void MeridianFlipState::setMountStatus(ISD::Mount::Status status)
492 qCDebug(KSTARS_EKOS_MOUNT) <<
"New mount state for MF:" << ISD::Mount::mountStates[
status].untranslatedText();
493 m_PrevMountStatus = m_MountStatus;
497void MeridianFlipState::setMountParkStatus(ISD::ParkStatus status)
500 if (status == ISD::PARK_PARKING || status == ISD::PARK_PARKED)
501 updateMFMountState(MOUNT_FLIP_NONE);
503 m_MountParkStatus =
status;
507void MeridianFlipState::updatePosition(MountPosition &pos,
const SkyPoint &position, ISD::Mount::PierSide pierSide,
508 const dms &ha,
const bool isValid)
510 pos.position = position;
511 pos.pierSide = pierSide;
516void MeridianFlipState::updateTelescopeCoord(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
518 updatePosition(currentPosition, position, pierSide, ha,
true);
522 if (m_MountStatus == ISD::Mount::MOUNT_TRACKING && m_PrevMountStatus == ISD::Mount::MOUNT_SLEWING
525 if (meridianFlipMountState == MOUNT_FLIP_NONE)
530 updatePosition(targetPosition, currentPosition.position, currentPosition.pierSide, currentPosition.ha,
true);
531 qCDebug(KSTARS_EKOS_MOUNT) <<
"Slew finished, MFStatus " <<
532 meridianFlipStatusString(meridianFlipMountState);
534 m_PrevMountStatus = m_MountStatus;
539 dms lst = KStarsData::Instance()->
geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
542 bool inMotion = (m_MountStatus == ISD::Mount::MOUNT_SLEWING || m_MountStatus == ISD::Mount::MOUNT_MOVING
543 || m_MountStatus == ISD::Mount::MOUNT_PARKING);
544 if ((inMotion ==
false) && checkMeridianFlip(lst))
548 const QString message(
i18n(
"Meridian flip inactive (parked)"));
549 if (m_MountParkStatus == ISD::PARK_PARKED )
551 publishMFMountStatusText(message);
556void MeridianFlipState::setTargetPosition(
SkyPoint *pos)
560 dms lst = KStarsData::Instance()->
geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
563 qCDebug(KSTARS_EKOS_MOUNT) <<
"Setting target RA=" << pos->
ra().toHMSString() <<
"DEC=" << pos->
dec().toDMSString();
564 updatePosition(targetPosition, *pos, ISD::Mount::PIER_UNKNOWN, ha,
true);
568 clearTargetPosition();
572double MeridianFlipState::initialPositionHA()
const
574 double HA = targetPosition.ha.HoursHa();
Q_INVOKABLE SimClock * clock()
const KStarsDateTime & utc() const
The sky coordinates of a point in the sky.
const CachingDms & dec() const
const CachingDms & ra() const
An angle, stored as degrees, but expressible in many ways.
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
const double & Degrees() const
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
bool isValid(QStringView ifopt)
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)