Kstars

mount.cpp
1/*
2 SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "mount.h"
8
9#include <QQuickView>
10#include <QQuickItem>
11#include <indicom.h>
12
13#include <KNotifications/KNotification>
14#include <KLocalizedContext>
15#include <KActionCollection>
16
17#include "Options.h"
18
19#include "ksmessagebox.h"
20#include "indi/driverinfo.h"
21#include "indi/indicommon.h"
22#include "indi/clientmanager.h"
23#include "indi/indigps.h"
24
25
26#include "mountadaptor.h"
27
28#include "ekos/manager.h"
29#include "ekos/auxiliary/opticaltrainmanager.h"
30#include "ekos/auxiliary/profilesettings.h"
31#include "ekos/auxiliary/opticaltrainsettings.h"
32#include "ekos/manager/meridianflipstate.h"
33#include "ekos/align/polaralignmentassistant.h"
34
35#include "kstars.h"
36#include "skymapcomposite.h"
37#include "dialogs/finddialog.h"
38#include "kstarsdata.h"
39
40#include <basedevice.h>
41
42#include <ekos_mount_debug.h>
43
44extern const char *libindi_strings_context;
45
46#define ABORT_DISPATCH_LIMIT 3
47
48namespace Ekos
49{
50
52{
53 setupUi(this);
54
55 new MountAdaptor(this);
56 QDBusConnection::sessionBus().registerObject("/KStars/Ekos/Mount", this);
57 // Set up DBus interfaces
58 QPointer<QDBusInterface> ekosInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos", "org.kde.kstars.Ekos",
61
62 // Connecting DBus signals
63 QDBusConnection::sessionBus().connect("org.kde.kstars", "/KStars/Ekos", "org.kde.kstars.Ekos", "newModule", this,
65
66 m_Mount = nullptr;
67
68 // initialize the state machine
69 mf_state.reset(new MeridianFlipState());
70 // connect to the MF state maichine
71 getMeridianFlipState()->connectMount(this);
72
73 // set the status message in the mount tab and write it to the log
74 connect(mf_state.get(), &MeridianFlipState::newMeridianFlipMountStatusText, [&](const QString & text)
75 {
76 meridianFlipStatusWidget->setStatus(text);
77 if (mf_state->getMeridianFlipMountState() != MeridianFlipState::MOUNT_FLIP_NONE &&
78 mf_state->getMeridianFlipMountState() != MeridianFlipState::MOUNT_FLIP_PLANNED)
79 appendLogText(text);
80 });
81 connect(mountToolBoxB, &QPushButton::clicked, this, &Mount::toggleMountToolBox);
82
84
86 {
87 if (m_Mount)
88 m_Mount->clearParking();
89
90 });
91
93 {
94 if (m_Mount)
95 {
96 if (KMessageBox::questionYesNo(KStars::Instance(),
97 i18n("Are you sure you want to clear all mount configurations?"),
98 i18n("Mount Configuration"), KStandardGuiItem::yes(), KStandardGuiItem::no(),
99 "purge_mount_settings_dialog") == KMessageBox::Yes)
100 {
101 resetModel();
102 m_Mount->clearParking();
103 m_Mount->setConfig(PURGE_CONFIG);
104 }
105 }
106 });
107
108 connect(enableAltitudeLimits, &QCheckBox::toggled, this, [this](bool toggled)
109 {
110 m_AltitudeLimitEnabled = toggled;
111 setAltitudeLimits(toggled);
112
113 });
114 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
116
117 // meridian flip
118 connect(mf_state.get(), &MeridianFlipState::newMeridianFlipMountStatusText, meridianFlipStatusWidget,
119 &MeridianFlipStatusWidget::setStatus);
120
121 connect(&autoParkTimer, &QTimer::timeout, this, &Mount::startAutoPark);
122 connect(startTimerB, &QPushButton::clicked, this, &Mount::startParkTimer);
123 connect(stopTimerB, &QPushButton::clicked, this, &Mount::stopParkTimer);
124
125 stopTimerB->setEnabled(false);
126
127 if (parkEveryDay->isChecked())
128 startTimerB->animateClick();
129
130 // QML Stuff
131 m_BaseView = new QQuickView();
132
133 // Must set context *before* loading the QML file.
134 m_Ctxt = m_BaseView->rootContext();
135 ///Use instead of KDeclarative
136 m_Ctxt->setContextObject(new KLocalizedContext(m_BaseView));
137
138 m_Ctxt->setContextProperty("mount", this);
139
140 // Load QML file after setting context
141 m_BaseView->setSource(QUrl("qrc:/qml/mount/mountbox.qml"));
142
143 m_BaseView->setTitle(i18n("Mount Control"));
144#ifdef Q_OS_OSX
146#else
148#endif
149
150 // Theming?
151 m_BaseView->setColor(Qt::black);
152
153 m_BaseObj = m_BaseView->rootObject();
154
156
157 m_SpeedSlider = m_BaseObj->findChild<QQuickItem *>("speedSliderObject");
158 m_SpeedLabel = m_BaseObj->findChild<QQuickItem *>("speedLabelObject");
159 m_raValue = m_BaseObj->findChild<QQuickItem *>("raValueObject");
160 m_deValue = m_BaseObj->findChild<QQuickItem *>("deValueObject");
161 m_azValue = m_BaseObj->findChild<QQuickItem *>("azValueObject");
162 m_altValue = m_BaseObj->findChild<QQuickItem *>("altValueObject");
163 m_haValue = m_BaseObj->findChild<QQuickItem *>("haValueObject");
164 m_zaValue = m_BaseObj->findChild<QQuickItem *>("zaValueObject");
165 m_targetText = m_BaseObj->findChild<QQuickItem *>("targetTextObject");
166 m_targetRAText = m_BaseObj->findChild<QQuickItem *>("targetRATextObject");
167 m_targetDEText = m_BaseObj->findChild<QQuickItem *>("targetDETextObject");
168 m_J2000Check = m_BaseObj->findChild<QQuickItem *>("j2000CheckObject");
169 m_JNowCheck = m_BaseObj->findChild<QQuickItem *>("jnowCheckObject");
170 m_Park = m_BaseObj->findChild<QQuickItem *>("parkButtonObject");
171 m_Unpark = m_BaseObj->findChild<QQuickItem *>("unparkButtonObject");
172 m_statusText = m_BaseObj->findChild<QQuickItem *>("statusTextObject");
173 m_equatorialCheck = m_BaseObj->findChild<QQuickItem *>("equatorialCheckObject");
174 m_horizontalCheck = m_BaseObj->findChild<QQuickItem *>("horizontalCheckObject");
175 m_haEquatorialCheck = m_BaseObj->findChild<QQuickItem *>("haEquatorialCheckObject");
176 m_leftRightCheck = m_BaseObj->findChild<QQuickItem *>("leftRightCheckObject");
177 m_upDownCheck = m_BaseObj->findChild<QQuickItem *>("upDownCheckObject");
178
179 m_leftRightCheck->setProperty("checked", Options::leftRightReversed());
180 m_upDownCheck->setProperty("checked", Options::upDownReversed());
181
182 //Note: This is to prevent a button from being called the default button
183 //and then executing when the user hits the enter key such as when on a Text Box
185 for (auto &button : qButtons)
186 button->setAutoDefault(false);
187
188 loadGlobalSettings();
189 connectSettings();
190
191 setupOpticalTrainManager();
192}
193
194Mount::~Mount()
195{
196 autoParkTimer.stop();
197 delete(m_Ctxt);
198 delete(m_BaseObj);
199}
200
201void Mount::setupParkUI()
202{
203 if (m_Mount == nullptr)
204 return;
205
206 if (m_Mount->canPark())
207 {
208 switch(m_Mount->parkStatus())
209 {
210 case ISD::PARK_PARKED:
211 parkingTitle->setTitle("Parked");
212 break;
213 case ISD::PARK_PARKING:
214 parkingTitle->setTitle("Parking");
215 break;
216 case ISD::PARK_UNPARKING:
217 parkingTitle->setTitle("Unparking");
218 break;
219 case ISD::PARK_UNPARKED:
220 parkingTitle->setTitle("Unparked");
221 break;
222 case ISD::PARK_ERROR:
223 parkingTitle->setTitle("Park Error");
224 break;
225 case ISD::PARK_UNKNOWN:
226 parkingTitle->setTitle("Park Status Unknown");
227 break;
228 }
229 parkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_UNPARKED);
230 unparkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_PARKED);
231 }
232 else
233 {
234 parkB->setEnabled(false);
235 unparkB->setEnabled(false);
236 parkingTitle->setTitle("");
237 }
238}
239
241{
242 if (device && device == m_Mount)
243 {
245 return false;
246 }
247
248 if (m_Mount)
249 m_Mount->disconnect(m_Mount, nullptr, this, nullptr);
250
251 m_Mount = device;
252
253 if (m_Mount)
254 {
255 connect(m_Mount, &ISD::ConcreteDevice::Connected, this, [this]()
256 {
257 setEnabled(true);
258 });
259 connect(m_Mount, &ISD::ConcreteDevice::Disconnected, this, [this]()
260 {
261 setEnabled(false);
262 opticalTrainCombo->setEnabled(true);
263 trainLabel->setEnabled(true);
264 });
265 }
266 else
267 return false;
268
269 mainLayout->setEnabled(true);
270
271 // forward the new mount to the meridian flip state machine
272 mf_state->setMountConnected(device != nullptr);
273
274 if (m_GPS != nullptr)
275 syncGPS();
276
277 connect(m_Mount, &ISD::Mount::propertyUpdated, this, &Mount::updateProperty);
282 connect(m_Mount, &ISD::Mount::slewRateChanged, this, &Mount::slewRateChanged);
283 connect(m_Mount, &ISD::Mount::pierSideChanged, this, &Mount::pierSideChanged);
284 connect(m_Mount, &ISD::Mount::axisReversed, this, &Mount::syncAxisReversed);
285 connect(m_Mount, &ISD::Mount::Disconnected, this, [this]()
286 {
287 m_BaseView->hide();
288 });
289 connect(m_Mount, &ISD::Mount::newParkStatus, this, [&](ISD::ParkStatus status)
290 {
291 m_ParkStatus = status;
292 emit newParkStatus(status);
293
294 setupParkUI();
295
296 // If mount is unparked AND every day auto-paro check is ON
297 // AND auto park timer is not yet started, we try to initiate it.
298 if (status == ISD::PARK_UNPARKED && parkEveryDay->isChecked() && autoParkTimer.isActive() == false)
299 startTimerB->animateClick();
300 });
301
302 // If mount is ready then let's set it up.
303 if (m_Mount->isReady())
304 {
305 if (enableAltitudeLimits->isChecked())
306 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
307 else
308 m_Mount->setAltLimits(-91, +91);
309
311
312 // Send initial status
313 m_Status = m_Mount->status();
314 emit newStatus(m_Status);
315
316 m_ParkStatus = m_Mount->parkStatus();
317 emit newParkStatus(m_ParkStatus);
318 emit ready();
319 }
320 // Otherwise, let's wait for mount to be ready
321 else
322 {
323 connect(m_Mount, &ISD::Mount::ready, this, [this]()
324 {
325 if (enableAltitudeLimits->isChecked())
326 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
327 else
328 m_Mount->setAltLimits(-91, +91);
329
331
332 // Send initial status
333 m_Status = m_Mount->status();
334 emit newStatus(m_Status);
335
336 m_ParkStatus = m_Mount->parkStatus();
337 emit newParkStatus(m_ParkStatus);
338 emit ready();
339 });
340 }
341
342 return true;
343}
344
345bool Mount::addGPS(ISD::GPS * device)
346{
347 // No duplicates
348 for (auto &oneGPS : m_GPSes)
349 {
350 if (oneGPS->getDeviceName() == device->getDeviceName())
351 return false;
352 }
353
354 for (auto &oneGPS : m_GPSes)
355 oneGPS->disconnect(this);
356
357 m_GPSes.append(device);
358
359 auto executeSetGPS = [this, device]()
360 {
361 m_GPS = device;
362 connect(m_GPS, &ISD::GPS::propertyUpdated, this, &Ekos::Mount::updateProperty, Qt::UniqueConnection);
363 appendLogText(i18n("GPS driver detected. KStars and mount time and location settings are now synced to the GPS driver."));
364 syncGPS();
365 };
366
367 if (Options::useGPSSource() == false)
368 {
369 connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this, executeSetGPS]()
370 {
371 KSMessageBox::Instance()->disconnect(this);
372 Options::setUseKStarsSource(false);
373 Options::setUseMountSource(false);
374 Options::setUseGPSSource(true);
376 });
377
378 KSMessageBox::Instance()->questionYesNo(i18n("GPS is detected. Do you want to switch time and location source to GPS?"),
379 i18n("GPS Settings"), 10);
380 }
381 else
383
384 return true;
385}
386
387void Mount::syncGPS()
388{
389 // We only update when location is OK
390 auto location = m_GPS->getNumber("GEOGRAPHIC_COORD");
391 if (!location || location->getState() != IPS_OK)
392 return;
393
394 // Sync name
395 if (m_Mount)
396 {
397 auto activeDevices = m_Mount->getText("ACTIVE_DEVICES");
398 if (activeDevices)
399 {
400 auto activeGPS = activeDevices->findWidgetByName("ACTIVE_GPS");
401 if (activeGPS)
402 {
403 if (activeGPS->getText() != m_GPS->getDeviceName())
404 {
405 activeGPS->setText(m_GPS->getDeviceName().toLatin1().constData());
407 }
408 }
409 }
410 }
411
412 // GPS Refresh should only be called once automatically.
413 if (GPSInitialized == false)
414 {
415 auto refreshGPS = m_GPS->getSwitch("GPS_REFRESH");
416 if (refreshGPS)
417 {
418 refreshGPS->at(0)->setState(ISS_ON);
420 GPSInitialized = true;
421 }
422 }
423}
424
425void Mount::removeDevice(const QSharedPointer<ISD::GenericDevice> &device)
426{
427 if (m_Mount && m_Mount->getDeviceName() == device->getDeviceName())
428 {
429 m_Mount->disconnect(this);
430 m_BaseView->hide();
431 qCDebug(KSTARS_EKOS_MOUNT) << "Removing mount driver" << m_Mount->getDeviceName();
432 m_Mount = nullptr;
433 }
434
435 for (auto &oneGPS : m_GPSes)
436 {
437 if (oneGPS->getDeviceName() == device->getDeviceName())
438 {
439 oneGPS->disconnect(this);
440 m_GPSes.removeOne(oneGPS);
441 m_GPS = nullptr;
442 break;
443 }
444 }
445}
446
448{
449 if (!m_Mount || m_Mount->isConnected() == false)
450 return;
451
452 auto svp = m_Mount->getSwitch("TELESCOPE_SLEW_RATE");
453
454 if (svp)
455 {
456 int index = svp->findOnSwitchIndex();
457
458 // QtQuick
459 m_SpeedSlider->setEnabled(true);
460 m_SpeedSlider->setProperty("maximumValue", svp->count() - 1);
461 m_SpeedSlider->setProperty("value", index);
462
463 m_SpeedLabel->setProperty("text", i18nc(libindi_strings_context, svp->at(index)->getLabel()));
464 m_SpeedLabel->setEnabled(true);
465 }
466 else
467 {
468 // QtQuick
469 m_SpeedSlider->setEnabled(false);
470 m_SpeedLabel->setEnabled(false);
471 }
472
473 if (m_Mount->canPark())
474 {
475 connect(parkB, &QPushButton::clicked, m_Mount, &ISD::Mount::park, Qt::UniqueConnection);
476 connect(unparkB, &QPushButton::clicked, m_Mount, &ISD::Mount::unpark, Qt::UniqueConnection);
477
478 // QtQuick
479 m_Park->setEnabled(!m_Mount->isParked());
480 m_Unpark->setEnabled(m_Mount->isParked());
481 }
482 else
483 {
484 disconnect(parkB, &QPushButton::clicked, m_Mount, &ISD::Mount::park);
485 disconnect(unparkB, &QPushButton::clicked, m_Mount, &ISD::Mount::unpark);
486
487 // QtQuick
488 m_Park->setEnabled(false);
489 m_Unpark->setEnabled(false);
490 }
491 setupParkUI();
492
493 // Tracking State
494 svp = m_Mount->getSwitch("TELESCOPE_TRACK_STATE");
495 if (svp)
496 {
497 trackingGroup->setEnabled(true);
498 trackOnB->disconnect();
499 trackOffB->disconnect();
501 {
502 m_Mount->setTrackEnabled(true);
503 });
505 {
506 if (KMessageBox::questionYesNo(KStars::Instance(),
507 i18n("Are you sure you want to turn off mount tracking?"),
508 i18n("Mount Tracking"), KStandardGuiItem::yes(), KStandardGuiItem::no(),
509 "turn_off_mount_tracking_dialog") == KMessageBox::Yes)
510 m_Mount->setTrackEnabled(false);
511 });
512 }
513 else
514 {
515 trackOnB->setChecked(false);
516 trackOffB->setChecked(false);
517 trackingGroup->setEnabled(false);
518 }
519
520 m_leftRightCheck->setProperty("checked", m_Mount->isReversed(AXIS_RA));
521 m_upDownCheck->setProperty("checked", m_Mount->isReversed(AXIS_DE));
522}
523
525{
526 if (name == "Capture")
527 {
528 hasCaptureInterface = true;
529 mf_state->setHasCaptureInterface(true);
530 }
531
532}
533
534void Mount::updateTelescopeCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha)
535{
536 if (m_Mount == nullptr || !m_Mount->isConnected())
537 return;
538
539 telescopeCoord = position;
540
541 // No need to update coords if we are still parked.
542 if (m_Status == ISD::Mount::MOUNT_PARKED && m_Status == m_Mount->status())
543 return;
544
545 // Ekos Mount Tab coords are always in JNow
546 raOUT->setText(telescopeCoord.ra().toHMSString());
547 decOUT->setText(telescopeCoord.dec().toDMSString());
548
549 // Mount Control Panel coords depend on the switch
550 if (m_JNowCheck->property("checked").toBool())
551 {
552 m_raValue->setProperty("text", telescopeCoord.ra().toHMSString());
553 m_deValue->setProperty("text", telescopeCoord.dec().toDMSString());
554 }
555 else
556 {
557 m_raValue->setProperty("text", telescopeCoord.ra0().toHMSString());
558 m_deValue->setProperty("text", telescopeCoord.dec0().toDMSString());
559 }
560
561 // Get horizontal coords
562 azOUT->setText(telescopeCoord.az().toDMSString());
563 m_azValue->setProperty("text", telescopeCoord.az().toDMSString());
564 altOUT->setText(telescopeCoord.alt().toDMSString());
565 m_altValue->setProperty("text", telescopeCoord.alt().toDMSString());
566
567 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
568 dms haSigned(ha);
569 QChar sgn('+');
570
571 if (haSigned.Hours() > 12.0)
572 {
573 haSigned.setH(24.0 - haSigned.Hours());
574 sgn = '-';
575 }
576
577 haOUT->setText(QString("%1%2").arg(sgn).arg(haSigned.toHMSString()));
578
579 m_haValue->setProperty("text", haOUT->text());
580 lstOUT->setText(lst.toHMSString());
581
582 double currentAlt = telescopeCoord.altRefracted().Degrees();
583
584 m_zaValue->setProperty("text", dms(90 - currentAlt).toDMSString());
585
586 if (minimumAltLimit->isEnabled() && (currentAlt < minimumAltLimit->value() || currentAlt > maximumAltLimit->value()))
587 {
589 {
590 // Only stop if current altitude is less than last altitude indicate worse situation
591 if (currentAlt < m_LastAltitude &&
592 (m_AbortAltDispatch == -1 ||
593 (m_Mount->isInMotion() /* && ++abortDispatch > ABORT_DISPATCH_LIMIT*/)))
594 {
595 appendLogText(i18n("Telescope altitude is below minimum altitude limit of %1. Aborting motion...",
596 QString::number(minimumAltLimit->value(), 'g', 3)));
597 m_Mount->abort();
598 m_Mount->setTrackEnabled(false);
599 //KNotification::event( QLatin1String( "OperationFailed" ));
601 m_AbortAltDispatch++;
602 }
603 }
604 else
605 {
606 // Only stop if current altitude is higher than last altitude indicate worse situation
607 if (currentAlt > m_LastAltitude &&
608 (m_AbortAltDispatch == -1 ||
609 (m_Mount->isInMotion() /* && ++abortDispatch > ABORT_DISPATCH_LIMIT*/)))
610 {
611 appendLogText(i18n("Telescope altitude is above maximum altitude limit of %1. Aborting motion...",
612 QString::number(maximumAltLimit->value(), 'g', 3)));
613 m_Mount->abort();
614 m_Mount->setTrackEnabled(false);
615 //KNotification::event( QLatin1String( "OperationFailed" ));
617 m_AbortAltDispatch++;
618 }
619 }
620 }
621 else
622 m_AbortAltDispatch = -1;
623
624 //qCDebug(KSTARS_EKOS_MOUNT) << "MaximumHaLimit " << MaximumHaLimit->isEnabled() << " value " << MaximumHaLimit->value();
625
626 double haHours = rangeHA(ha.Hours());
627 // handle Ha limit:
628 // Telescope must report Pier Side
629 // MaximumHaLimit must be enabled
630 // for PierSide West -> East if Ha > MaximumHaLimit stop tracking
631 // for PierSide East -> West if Ha > MaximumHaLimit - 12 stop Tracking
632 if (maximumHaLimit->isEnabled())
633 {
634 // get hour angle limit
635 double haLimit = maximumHaLimit->value();
636 bool haLimitReached = false;
637 switch(pierSide)
638 {
639 case ISD::Mount::PierSide::PIER_WEST:
641 break;
642 case ISD::Mount::PierSide::PIER_EAST:
644 break;
645 default:
646 // can't tell so always false
647 haLimitReached = false;
648 break;
649 }
650
651 qCDebug(KSTARS_EKOS_MOUNT) << "Ha: " << haHours <<
652 " haLimit " << haLimit <<
653 " " << ISD::Mount::pierSideStateString(m_Mount->pierSide()) <<
654 " haLimitReached " << (haLimitReached ? "true" : "false") <<
655 " lastHa " << m_LastHourAngle;
656
657 // compare with last ha to avoid multiple calls
658 if (haLimitReached && (rangeHA(haHours - m_LastHourAngle) >= 0 ) &&
659 (m_AbortHADispatch == -1 ||
660 m_Mount->isInMotion()))
661 {
662 // moved past the limit, so stop
663 appendLogText(i18n("Telescope hour angle is more than the maximum hour angle of %1. Aborting motion...",
664 QString::number(maximumHaLimit->value(), 'g', 3)));
665 m_Mount->abort();
666 m_Mount->setTrackEnabled(false);
667 //KNotification::event( QLatin1String( "OperationFailed" ));
669 m_AbortHADispatch++;
670 // ideally we pause and wait until we have passed the pier flip limit,
671 // then do a pier flip and try to resume
672 // this will need changing to use a target position because the current HA has stopped.
673 }
674 }
675 else
676 m_AbortHADispatch = -1;
677
678 m_LastAltitude = currentAlt;
679 m_LastHourAngle = haHours;
680
681 ISD::Mount::Status currentStatus = m_Mount->status();
682 if (m_Status != currentStatus)
683 {
684 qCDebug(KSTARS_EKOS_MOUNT) << "Mount status changed from " << m_Mount->statusString(m_Status)
685 << " to " << m_Mount->statusString(currentStatus);
686
687 //setScopeStatus(currentStatus);
688
689 m_statusText->setProperty("text", m_Mount->statusString(currentStatus));
690 m_Status = currentStatus;
691 // forward
692 emit newStatus(m_Status);
693
694 setupParkUI();
695 m_Park->setEnabled(!m_Mount->isParked());
696 m_Unpark->setEnabled(m_Mount->isParked());
697
698 QAction *a = KStars::Instance()->actionCollection()->action("telescope_track");
699 if (a != nullptr)
700 a->setChecked(currentStatus == ISD::Mount::MOUNT_TRACKING);
701 }
702
703 bool isTracking = (currentStatus == ISD::Mount::MOUNT_TRACKING);
704 if (trackingGroup->isEnabled())
705 {
706 trackOnB->setChecked(isTracking);
707 trackOffB->setChecked(!isTracking);
708 }
709
710 // handle pier side display
711 pierSideLabel->setText(ISD::Mount::pierSideStateString(m_Mount->pierSide()));
712
713 // Auto Park Timer
714 if (autoParkTimer.isActive())
715 {
716 QTime remainingTime(0, 0, 0);
717 remainingTime = remainingTime.addMSecs(autoParkTimer.remainingTime());
718 countdownLabel->setText(remainingTime.toString("hh:mm:ss"));
719 emit autoParkCountdownUpdated(countdownLabel->text());
720 }
721}
722
723void Mount::updateProperty(INDI::Property prop)
724{
725 if (prop.isNameMatch("GEOGRAPHIC_COORD") &&
726 m_GPS != nullptr &&
727 (prop.getDeviceName() == m_GPS->getDeviceName()) &&
728 prop.getState() == IPS_OK)
729 {
730 syncGPS();
731 }
732 else if (prop.isNameMatch("EQUATORIAL_EOD_COORD") || prop.isNameMatch("EQUATORIAL_COORD"))
733 {
734 auto nvp = prop.getNumber();
735
736 // if the meridian flip state machine is not initialized, return
737 if (getMeridianFlipState().isNull())
738 return;
739
740 switch (getMeridianFlipState()->getMeridianFlipStage())
741 {
742 case MeridianFlipState::MF_INITIATED:
743 if (nvp->s == IPS_BUSY && m_Mount != nullptr && m_Mount->isSlewing())
744 getMeridianFlipState()->updateMeridianFlipStage(MeridianFlipState::MF_FLIPPING);
745 break;
746
747 default:
748 break;
749 }
750 }
751 else if (prop.isNameMatch("TELESCOPE_SLEW_RATE"))
752 {
753 auto svp = prop.getSwitch();
754 auto index = svp->findOnSwitchIndex();
755 m_SpeedSlider->setProperty("value", index);
756 m_SpeedLabel->setProperty("text", i18nc(libindi_strings_context, svp->at(index)->getLabel()));
757 }
758}
759
760bool Mount::setSlewRate(int index)
761{
762 if (m_Mount)
763 return m_Mount->setSlewRate(index);
764
765 return false;
766}
767
768void Mount::setUpDownReversed(bool enabled)
769{
770 Options::setUpDownReversed(enabled);
771 if (m_Mount)
772 m_Mount->setReversedEnabled(AXIS_DE, enabled);
773}
774
775void Mount::setLeftRightReversed(bool enabled)
776{
777 Options::setLeftRightReversed(enabled);
778 if (m_Mount)
779 m_Mount->setReversedEnabled(AXIS_RA, enabled);
780}
781
782void Mount::setMeridianFlipValues(bool activate, double degrees)
783{
784 executeMeridianFlip->setChecked(activate);
786}
787
789{
790 // Clear the current target position is necessary due to a bug in some mount drivers
791 // which report a mount slew instead of a mount motion. For these mounts, ending a slew
792 // leads to setting the current target position, which is necessary for meridian flips
793 // Since we want to avoid meridian flips during and after finishing PAA, it needs to
794 // be set to nullptr.
795
796 if (stage != PolarAlignmentAssistant::PAH_IDLE)
797 mf_state->clearTargetPosition();
798
799 switch (stage)
800 {
801 // deactivate the meridian flip when the first capture is taken
802 case PolarAlignmentAssistant::PAH_FIRST_CAPTURE:
803 case PolarAlignmentAssistant::PAH_FIRST_SOLVE:
804 if (mf_state->isEnabled())
805 {
806 appendLogText(i18n("Meridian flip set inactive during polar alignment."));
807 mf_state->setEnabled(false);
808 }
809 break;
810 // activate it when the last rotation is finished or stopped
811 // for safety reasons, we add all stages after the last rotation
812 case PolarAlignmentAssistant::PAH_THIRD_CAPTURE:
813 case PolarAlignmentAssistant::PAH_THIRD_SOLVE:
814 case PolarAlignmentAssistant::PAH_STAR_SELECT:
815 case PolarAlignmentAssistant::PAH_REFRESH:
816 case PolarAlignmentAssistant::PAH_POST_REFRESH:
817 case PolarAlignmentAssistant::PAH_IDLE:
818 if (executeMeridianFlip->isChecked() && mf_state->isEnabled() == false)
819 {
820 appendLogText(i18n("Polar alignment motions finished, meridian flip activated."));
821 mf_state->setEnabled(executeMeridianFlip->isChecked());
822 }
823 break;
824 }
825}
826
827void Mount::appendLogText(const QString &text)
828{
829 m_LogText.insert(0, i18nc("log entry; %1 is the date, %2 is the text", "%1 %2",
830 KStarsData::Instance()->lt().toString("yyyy-MM-ddThh:mm:ss"), text));
831
832 qCInfo(KSTARS_EKOS_MOUNT) << text;
833
834 emit newLog(text);
835}
836
837void Mount::updateLog(int messageID)
838{
839 if (m_Mount == nullptr)
840 return;
841
842 auto message = m_Mount->getMessage(messageID);
843 m_LogText.insert(0, i18nc("Message shown in Ekos Mount module", "%1", message));
844
845 emit newLog(message);
846}
847
848void Mount::clearLog()
849{
850 m_LogText.clear();
851 emit newLog(QString());
852}
853
854void Mount::motionCommand(int command, int NS, int WE)
855{
856 if (m_Mount == nullptr || !m_Mount->isConnected())
857 return;
858
859 if (NS != -1)
860 {
861 m_Mount->MoveNS(static_cast<ISD::Mount::VerticalMotion>(NS),
862 static_cast<ISD::Mount::MotionCommand>(command));
863 }
864
865 if (WE != -1)
866 {
867 m_Mount->MoveWE(static_cast<ISD::Mount::HorizontalMotion>(WE),
868 static_cast<ISD::Mount::MotionCommand>(command));
869 }
870}
871
872
873void Mount::doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs)
874{
875 if (m_Mount == nullptr || !m_Mount->isConnected())
876 return;
877
878 m_Mount->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
879}
880
882{
883 if (m_Mount == nullptr)
884 return;
885
886 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
887}
888
890{
891 if (enable)
892 {
893 minAltLabel->setEnabled(true);
894 maxAltLabel->setEnabled(true);
895
896 minimumAltLimit->setEnabled(true);
897 maximumAltLimit->setEnabled(true);
898
899 if (m_Mount)
900 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
901 }
902 else
903 {
904 minAltLabel->setEnabled(false);
905 maxAltLabel->setEnabled(false);
906
907 minimumAltLimit->setEnabled(false);
908 maximumAltLimit->setEnabled(false);
909
910 if (m_Mount)
911 m_Mount->setAltLimits(-91, +91);
912 }
913}
914
915// Used for meridian flip
917{
918 //Only enable if it was already enabled before and the MinimumAltLimit is currently disabled.
919 if (m_AltitudeLimitEnabled && minimumAltLimit->isEnabled() == false)
920 setAltitudeLimits(true);
921}
922
923// Used for meridian flip
925{
926 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
927 setAltitudeLimits(false);
928}
929
931{
932 maxHaLabel->setEnabled(enable);
933 maximumHaLimit->setEnabled(enable);
934}
935
937{
938 //Only enable if it was already enabled before and the minHaLimit is currently disabled.
939 if (m_HourAngleLimitEnabled && maximumHaLimit->isEnabled() == false)
941}
942
944{
945 m_HourAngleLimitEnabled = enableHaLimit->isChecked();
946
948}
949
950QList<double> Mount::altitudeLimits()
951{
953
954 limits.append(minimumAltLimit->value());
955 limits.append(maximumAltLimit->value());
956
957 return limits;
958}
959
961{
962 minimumAltLimit->setValue(limits[0]);
963 maximumAltLimit->setValue(limits[1]);
964}
965
967{
968 enableAltitudeLimits->setChecked(enable);
969}
970
971bool Mount::altitudeLimitsEnabled()
972{
973 return enableAltitudeLimits->isChecked();
974}
975
976double Mount::hourAngleLimit()
977{
978 return maximumHaLimit->value();
979}
980
981void Mount::setHourAngleLimit(double limit)
982{
983 maximumHaLimit->setValue(limit);
984}
985
987{
988 enableHaLimit->setChecked(enable);
989}
990
991bool Mount::hourAngleLimitEnabled()
992{
993 return enableHaLimit->isChecked();
994}
995
996void Mount::setJ2000Enabled(bool enabled)
997{
998 m_J2000Check->setProperty("checked", enabled);
999}
1000
1001bool Mount::gotoTarget(const QString &target)
1002{
1003 SkyObject *object = KStarsData::Instance()->skyComposite()->findByName(target, false);
1004
1005 if (object != nullptr)
1006 {
1007 object->updateCoordsNow(KStarsData::Instance()->updateNum());
1008 return slew(object->ra().Hours(), object->dec().Degrees());
1009 }
1010
1011 return false;
1012}
1013
1014bool Mount::gotoTarget(const SkyPoint &target)
1015{
1016 return slew(target.ra().Hours(), target.dec().Degrees());
1017}
1018
1019bool Mount::syncTarget(const QString &target)
1020{
1021 SkyObject *object = KStarsData::Instance()->skyComposite()->findByName(target, false);
1022
1023 if (object != nullptr)
1024 {
1025 object->updateCoordsNow(KStarsData::Instance()->updateNum());
1026 return sync(object->ra().Hours(), object->dec().Degrees());
1027 }
1028
1029 return false;
1030}
1031
1032bool Mount::slew(const QString &RA, const QString &DEC)
1033{
1034 dms ra, de;
1035
1036 if (m_equatorialCheck->property("checked").toBool())
1037 {
1038 ra = dms::fromString(RA, false);
1039 de = dms::fromString(DEC, true);
1040 }
1041
1042 if (m_horizontalCheck->property("checked").toBool())
1043 {
1044 dms az = dms::fromString(RA, true);
1045 dms at = dms::fromString(DEC, true);
1046 SkyPoint target;
1047 target.setAz(az);
1048 target.setAlt(at);
1049 target.HorizontalToEquatorial(KStars::Instance()->data()->lst(), KStars::Instance()->data()->geo()->lat());
1050 ra = target.ra();
1051 de = target.dec();
1052 }
1053
1054 if (m_haEquatorialCheck->property("checked").toBool())
1055 {
1056 dms ha = dms::fromString(RA, false);
1057 de = dms::fromString(DEC, true);
1058 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1059 ra = (lst - ha + dms(360.0)).reduce();
1060 }
1061
1062 // If J2000 was checked and the Mount is _not_ already using native J2000 coordinates
1063 // then we need to convert J2000 to JNow. Otherwise, we send J2000 as is.
1064 if (m_J2000Check->property("checked").toBool() && m_Mount && m_Mount->isJ2000() == false)
1065 {
1066 // J2000 ---> JNow
1067 SkyPoint J2000Coord(ra, de);
1068 J2000Coord.setRA0(ra);
1069 J2000Coord.setDec0(de);
1070 J2000Coord.apparentCoord(static_cast<long double>(J2000), KStars::Instance()->data()->ut().djd());
1071
1072 ra = J2000Coord.ra();
1073 de = J2000Coord.dec();
1074 }
1075
1076 return slew(ra.Hours(), de.Degrees());
1077}
1078
1079bool Mount::slew(double RA, double DEC)
1080{
1081 if (m_Mount == nullptr || m_Mount->isConnected() == false)
1082 return false;
1083
1084 // calculate the new target
1085 targetPosition = new SkyPoint(RA, DEC);
1086 SkyPoint J2000Coord(targetPosition->ra(), targetPosition->dec());
1087 J2000Coord.catalogueCoord(KStarsData::Instance()->ut().djd());
1088 targetPosition->setRA0(J2000Coord.ra());
1089 targetPosition->setDec0(J2000Coord.dec());
1090
1091 mf_state->setTargetPosition(targetPosition);
1092 mf_state->resetMeridianFlip();
1093
1094 qCDebug(KSTARS_EKOS_MOUNT) << "Slewing to RA=" <<
1095 targetPosition->ra().toHMSString() <<
1096 "DEC=" << targetPosition->dec().toDMSString();
1097 qCDebug(KSTARS_EKOS_MOUNT) << "Initial HA " << initialHA() << ", flipDelayHrs " << mf_state->getFlipDelayHrs() <<
1098 "MFStatus " << MeridianFlipState::meridianFlipStatusString(mf_state->getMeridianFlipMountState());
1099
1100 // start the slew
1101 return(m_Mount->Slew(targetPosition));
1102}
1103
1104
1106{
1107 if (targetPosition != nullptr)
1108 return *targetPosition;
1109
1110 qCWarning(KSTARS_EKOS_MOUNT) << "No target position defined!";
1111 // since we need to answer something, we take the current mount position
1112 return telescopeCoord;
1113}
1114
1115
1116bool Mount::sync(const QString &RA, const QString &DEC)
1117{
1118 dms ra, de;
1119
1120 if (m_equatorialCheck->property("checked").toBool())
1121 {
1122 ra = dms::fromString(RA, false);
1123 de = dms::fromString(DEC, true);
1124 }
1125
1126 if (m_horizontalCheck->property("checked").toBool())
1127 {
1128 dms az = dms::fromString(RA, true);
1129 dms at = dms::fromString(DEC, true);
1130 SkyPoint target;
1131 target.setAz(az);
1132 target.setAlt(at);
1133 target.HorizontalToEquatorial(KStars::Instance()->data()->lst(), KStars::Instance()->data()->geo()->lat());
1134 ra = target.ra();
1135 de = target.dec();
1136 }
1137
1138 if (m_haEquatorialCheck->property("checked").toBool())
1139 {
1140 dms ha = dms::fromString(RA, false);
1141 de = dms::fromString(DEC, true);
1142 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1143 ra = (lst - ha + dms(360.0)).reduce();
1144 }
1145
1146 if (m_J2000Check->property("checked").toBool())
1147 {
1148 // J2000 ---> JNow
1149 SkyPoint J2000Coord(ra, de);
1150 J2000Coord.setRA0(ra);
1151 J2000Coord.setDec0(de);
1152 J2000Coord.updateCoordsNow(KStarsData::Instance()->updateNum());
1153
1154 ra = J2000Coord.ra();
1155 de = J2000Coord.dec();
1156 }
1157
1158 return sync(ra.Hours(), de.Degrees());
1159}
1160
1161bool Mount::sync(double RA, double DEC)
1162{
1163 if (m_Mount == nullptr || m_Mount->isConnected() == false)
1164 return false;
1165
1166 return m_Mount->Sync(RA, DEC);
1167}
1168
1170{
1171 if (m_Mount == nullptr)
1172 return false;
1173
1174 return m_Mount->abort();
1175}
1176
1177IPState Mount::slewStatus()
1178{
1179 if (m_Mount == nullptr)
1180 return IPS_ALERT;
1181
1182 return m_Mount->getState("EQUATORIAL_EOD_COORD");
1183}
1184
1185QList<double> Mount::equatorialCoords()
1186{
1187 double ra {0}, dec {0};
1188 QList<double> coords;
1189
1190 if (m_Mount)
1191 m_Mount->getEqCoords(&ra, &dec);
1192 coords.append(ra);
1193 coords.append(dec);
1194
1195 return coords;
1196}
1197
1198QList<double> Mount::horizontalCoords()
1199{
1200 QList<double> coords;
1201
1202 coords.append(telescopeCoord.az().Degrees());
1203 coords.append(telescopeCoord.alt().Degrees());
1204
1205 return coords;
1206}
1207
1208///
1209/// \brief Mount::hourAngle
1210/// \return returns the current mount hour angle in hours in the range -12 to +12
1211///
1212double Mount::hourAngle()
1213{
1214 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1215 dms ha(lst.Degrees() - telescopeCoord.ra().Degrees());
1216 return rangeHA(ha.Hours());
1217}
1218
1219bool Mount::canPark()
1220{
1221 if (m_Mount == nullptr)
1222 return false;
1223
1224 return m_Mount->canPark();
1225}
1226
1228{
1229 if (m_Mount == nullptr || m_Mount->canPark() == false)
1230 return false;
1231
1232 return m_Mount->park();
1233}
1234
1236{
1237 if (m_Mount == nullptr || m_Mount->canPark() == false)
1238 return false;
1239
1240 return m_Mount->unpark();
1241}
1242
1243
1244void Mount::toggleMountToolBox()
1245{
1246 if (m_BaseView->isVisible())
1247 {
1248 m_BaseView->hide();
1249 QAction *a = KStars::Instance()->actionCollection()->action("show_mount_box");
1250 if (a)
1251 a->setChecked(false);
1252 }
1253 else
1254 {
1255 m_BaseView->show();
1256 QAction *a = KStars::Instance()->actionCollection()->action("show_mount_box");
1257 if (a)
1258 a->setChecked(true);
1259 }
1260}
1261
1262void Mount::findTarget()
1263{
1264 if (FindDialog::Instance()->execWithParent(Ekos::Manager::Instance()) == QDialog::Accepted)
1265 {
1266 SkyObject *object = FindDialog::Instance()->targetObject();
1267 if (object != nullptr)
1268 {
1269 KStarsData * const data = KStarsData::Instance();
1270
1271 SkyObject *o = object->clone();
1272 o->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false);
1273
1274 m_equatorialCheck->setProperty("checked", true);
1275
1276 m_targetText->setProperty("text", o->name());
1277
1278 if (m_JNowCheck->property("checked").toBool())
1279 {
1280 m_targetRAText->setProperty("text", o->ra().toHMSString());
1281 m_targetDEText->setProperty("text", o->dec().toDMSString());
1282 }
1283 else
1284 {
1285 m_targetRAText->setProperty("text", o->ra0().toHMSString());
1286 m_targetDEText->setProperty("text", o->dec0().toDMSString());
1287 }
1288 }
1289 }
1290}
1291
1292//++++ converters for target coordinate display in Mount Control box
1293
1294bool Mount::raDecToAzAlt(QString qsRA, QString qsDec)
1295{
1296 dms RA, Dec;
1297
1298 if (!RA.setFromString(qsRA, false) || !Dec.setFromString(qsDec, true))
1299 return false;
1300
1301 SkyPoint targetCoord(RA, Dec);
1302
1303 targetCoord.EquatorialToHorizontal(KStarsData::Instance()->lst(),
1304 KStarsData::Instance()->geo()->lat());
1305
1306 m_targetRAText->setProperty("text", targetCoord.az().toDMSString());
1307 m_targetDEText->setProperty("text", targetCoord.alt().toDMSString());
1308
1309 return true;
1310}
1311
1312bool Mount::raDecToHaDec(QString qsRA)
1313{
1314 dms RA;
1315
1316 if (!RA.setFromString(qsRA, false))
1317 return false;
1318
1319 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1320
1321 dms HA = (lst - RA + dms(360.0)).reduce();
1322
1323 QChar sgn('+');
1324 if (HA.Hours() > 12.0)
1325 {
1326 HA.setH(24.0 - HA.Hours());
1327 sgn = '-';
1328 }
1329
1330 m_targetRAText->setProperty("text", QString("%1%2").arg(sgn).arg(HA.toHMSString()));
1331
1332 return true;
1333}
1334
1335bool Mount::azAltToRaDec(QString qsAz, QString qsAlt)
1336{
1337 dms Az, Alt;
1338
1339 if (!Az.setFromString(qsAz, true) || !Alt.setFromString(qsAlt, true))
1340 return false;
1341
1343 targetCoord.setAz(Az);
1344 targetCoord.setAlt(Alt);
1345
1346 targetCoord.HorizontalToEquatorial(KStars::Instance()->data()->lst(),
1347 KStars::Instance()->data()->geo()->lat());
1348
1349 m_targetRAText->setProperty("text", targetCoord.ra().toHMSString());
1350 m_targetDEText->setProperty("text", targetCoord.dec().toDMSString());
1351
1352 return true;
1353}
1354
1355bool Mount::azAltToHaDec(QString qsAz, QString qsAlt)
1356{
1357 dms Az, Alt;
1358
1359 if (!Az.setFromString(qsAz, true) || !Alt.setFromString(qsAlt, true))
1360 return false;
1361
1363 targetCoord.setAz(Az);
1364 targetCoord.setAlt(Alt);
1365
1366 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1367
1368 targetCoord.HorizontalToEquatorial(&lst, KStars::Instance()->data()->geo()->lat());
1369
1370 dms HA = (lst - targetCoord.ra() + dms(360.0)).reduce();
1371
1372 QChar sgn('+');
1373 if (HA.Hours() > 12.0)
1374 {
1375 HA.setH(24.0 - HA.Hours());
1376 sgn = '-';
1377 }
1378
1379 m_targetRAText->setProperty("text", QString("%1%2").arg(sgn).arg(HA.toHMSString()));
1380 m_targetDEText->setProperty("text", targetCoord.dec().toDMSString());
1381
1382
1383 return true;
1384}
1385
1386bool Mount::haDecToRaDec(QString qsHA)
1387{
1388 dms HA;
1389
1390 if (!HA.setFromString(qsHA, false))
1391 return false;
1392
1393 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1394 dms RA = (lst - HA + dms(360.0)).reduce();
1395
1396 m_targetRAText->setProperty("text", RA.toHMSString());
1397
1398 return true;
1399}
1400
1401bool Mount::haDecToAzAlt(QString qsHA, QString qsDec)
1402{
1403 dms HA, Dec;
1404
1405 if (!HA.setFromString(qsHA, false) || !Dec.setFromString(qsDec, true))
1406 return false;
1407
1408 dms lst = KStarsData::Instance()->geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1409 dms RA = (lst - HA + dms(360.0)).reduce();
1410
1412 targetCoord.setRA(RA);
1413 targetCoord.setDec(Dec);
1414
1415 targetCoord.EquatorialToHorizontal(&lst, KStars::Instance()->data()->geo()->lat());
1416
1417 m_targetRAText->setProperty("text", targetCoord.az().toDMSString());
1418 m_targetDEText->setProperty("text", targetCoord.alt().toDMSString());
1419
1420 return true;
1421}
1422
1423//---- end: converters for target coordinate display in Mount Control box
1424
1425void Mount::centerMount()
1426{
1427 if (m_Mount)
1428 m_Mount->find();
1429}
1430
1432{
1433 if (m_Mount == nullptr)
1434 return false;
1435
1436 if (m_Mount->hasAlignmentModel() == false)
1437 return false;
1438
1439 if (m_Mount->clearAlignmentModel())
1440 {
1441 appendLogText(i18n("Alignment Model cleared."));
1442 return true;
1443 }
1444
1445 appendLogText(i18n("Failed to clear Alignment Model."));
1446 return false;
1447}
1448
1449
1450void Mount::setScopeStatus(ISD::Mount::Status status)
1451{
1452 if (m_Status != status)
1453 {
1454 m_statusText->setProperty("text", m_Mount->statusString(status));
1455 m_Status = status;
1456 // forward
1457 emit newStatus(status);
1458 }
1459}
1460
1461
1462
1463void Mount::setTrackEnabled(bool enabled)
1464{
1465 if (enabled)
1466 trackOnB->click();
1467 else
1468 trackOffB->click();
1469}
1470
1471int Mount::slewRate()
1472{
1473 if (m_Mount == nullptr)
1474 return -1;
1475
1476 return m_Mount->getSlewRate();
1477}
1478
1479//QJsonArray Mount::getScopes() const
1480//{
1481// QJsonArray scopes;
1482// if (currentTelescope == nullptr)
1483// return scopes;
1484
1485// QJsonObject primary =
1486// {
1487// {"name", "Primary"},
1488// {"mount", currentTelescope->getDeviceName()},
1489// {"aperture", primaryScopeApertureIN->value()},
1490// {"focalLength", primaryScopeFocalIN->value()},
1491// };
1492
1493// scopes.append(primary);
1494
1495// QJsonObject guide =
1496// {
1497// {"name", "Guide"},
1498// {"mount", currentTelescope->getDeviceName()},
1499// {"aperture", primaryScopeApertureIN->value()},
1500// {"focalLength", primaryScopeFocalIN->value()},
1501// };
1502
1503// scopes.append(guide);
1504
1505// return scopes;
1506//}
1507
1508bool Mount::autoParkEnabled()
1509{
1510 return autoParkTimer.isActive();
1511}
1512
1514{
1515 if (enable)
1516 startParkTimer();
1517 else
1518 stopParkTimer();
1519}
1520
1522{
1523 parkEveryDay->setChecked(enabled);
1524}
1525
1527{
1528 autoParkTime->setTime(startup);
1529}
1530
1531bool Mount::meridianFlipEnabled()
1532{
1533 return executeMeridianFlip->isChecked();
1534}
1535
1536double Mount::meridianFlipValue()
1537{
1538 return meridianFlipOffsetDegrees->value();
1539}
1540
1542{
1543 autoParkTimer.stop();
1544 if (m_Mount)
1545 m_Mount->stopTimers();
1546}
1547
1548void Mount::startParkTimer()
1549{
1550 if (m_Mount == nullptr || m_ParkStatus == ISD::PARK_UNKNOWN)
1551 return;
1552
1553 if (m_Mount->isParked())
1554 {
1555 appendLogText(i18n("Mount already parked."));
1556 return;
1557 }
1558
1559 auto parkTime = autoParkTime->time();
1560
1561 qCDebug(KSTARS_EKOS_MOUNT) << "Parking time is" << parkTime.toString();
1562 QDateTime currentDateTime = KStarsData::Instance()->lt();
1563 QDateTime parkDateTime(currentDateTime);
1564
1565 parkDateTime.setTime(parkTime);
1566 qint64 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1567 qCDebug(KSTARS_EKOS_MOUNT) << "Until parking time:" << parkMilliSeconds << "ms or" << parkMilliSeconds / (60 * 60 * 1000)
1568 << "hours";
1569 if (parkMilliSeconds > 0)
1570 {
1571 qCDebug(KSTARS_EKOS_MOUNT) << "Added a day to parking time...";
1572 parkDateTime = parkDateTime.addDays(1);
1573 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1574
1575 int hours = static_cast<int>(parkMilliSeconds / (1000 * 60 * 60));
1576 if (hours > 0)
1577 {
1578 // No need to display warning for every day check
1579 if (parkEveryDay->isChecked() == false)
1580 appendLogText(i18n("Parking time cannot be in the past."));
1581 return;
1582 }
1583 }
1584
1586
1587 if (parkMilliSeconds > 24 * 60 * 60 * 1000)
1588 {
1589 appendLogText(i18n("Parking time must be within 24 hours of current time."));
1590 return;
1591 }
1592
1593 if (parkMilliSeconds > 12 * 60 * 60 * 1000)
1594 appendLogText(i18n("Warning! Parking time is more than 12 hours away."));
1595
1596 appendLogText(i18n("Caution: do not use Auto Park while scheduler is active."));
1597
1598 autoParkTimer.setInterval(static_cast<int>(parkMilliSeconds));
1599 autoParkTimer.start();
1600
1601 startTimerB->setEnabled(false);
1602 stopTimerB->setEnabled(true);
1603}
1604
1605void Mount::stopParkTimer()
1606{
1607 autoParkTimer.stop();
1608 countdownLabel->setText("00:00:00");
1609 emit autoParkCountdownUpdated("00:00:00");
1610 stopTimerB->setEnabled(false);
1611 startTimerB->setEnabled(true);
1612}
1613
1614void Mount::startAutoPark()
1615{
1616 appendLogText(i18n("Parking timer is up."));
1617 autoParkTimer.stop();
1618 startTimerB->setEnabled(true);
1619 stopTimerB->setEnabled(false);
1620 countdownLabel->setText("00:00:00");
1621 emit autoParkCountdownUpdated("00:00:00");
1622 if (m_Mount)
1623 {
1624 if (m_Mount->isParked() == false)
1625 {
1626 appendLogText(i18n("Starting auto park..."));
1627 park();
1628 }
1629 }
1630}
1631
1633{
1634 if (axis == AXIS_RA)
1635 m_leftRightCheck->setProperty("checked", reversed);
1636 else
1637 m_upDownCheck->setProperty("checked", reversed);
1638}
1639
1640void Mount::setupOpticalTrainManager()
1641{
1642 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated, this, &Mount::refreshOpticalTrain);
1643 connect(trainB, &QPushButton::clicked, this, [this]()
1644 {
1645 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1646 });
1648 {
1649 ProfileSettings::Instance()->setOneSetting(ProfileSettings::MountOpticalTrain,
1650 OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(index)));
1651 refreshOpticalTrain();
1652 emit trainChanged();
1653 });
1654}
1655
1656void Mount::refreshOpticalTrain()
1657{
1658 opticalTrainCombo->blockSignals(true);
1659 opticalTrainCombo->clear();
1660 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1661 trainB->setEnabled(true);
1662
1663 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::MountOpticalTrain);
1664
1665 if (trainID.isValid())
1666 {
1667 auto id = trainID.toUInt();
1668
1669 // If train not found, select the first one available.
1670 if (OpticalTrainManager::Instance()->exists(id) == false)
1671 {
1672 qCWarning(KSTARS_EKOS_MOUNT) << "Optical train doesn't exist for id" << id;
1673 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1674 }
1675
1676 auto name = OpticalTrainManager::Instance()->name(id);
1677
1678 opticalTrainCombo->setCurrentText(name);
1679
1680 auto mount = OpticalTrainManager::Instance()->getMount(name);
1681 setMount(mount);
1682
1683 auto scope = OpticalTrainManager::Instance()->getScope(name);
1684 opticalTrainCombo->setToolTip(scope["name"].toString());
1685
1686 // Load train settings
1687 OpticalTrainSettings::Instance()->setOpticalTrainID(id);
1688 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Mount);
1689 if (settings.isValid())
1690 setAllSettings(settings.toJsonObject().toVariantMap());
1691 else
1692 m_Settings = m_GlobalSettings;
1693 }
1694
1695 opticalTrainCombo->blockSignals(false);
1696}
1697
1698///////////////////////////////////////////////////////////////////////////////////////////
1699///
1700///////////////////////////////////////////////////////////////////////////////////////////
1701QVariantMap Mount::getAllSettings() const
1702{
1703 QVariantMap settings;
1704
1705 // All Combo Boxes
1706 for (auto &oneWidget : findChildren<QComboBox*>())
1707 settings.insert(oneWidget->objectName(), oneWidget->currentText());
1708
1709 // All Double Spin Boxes
1710 for (auto &oneWidget : findChildren<QDoubleSpinBox*>())
1711 settings.insert(oneWidget->objectName(), oneWidget->value());
1712
1713 // All Spin Boxes
1714 for (auto &oneWidget : findChildren<QSpinBox*>())
1715 settings.insert(oneWidget->objectName(), oneWidget->value());
1716
1717 // All Checkboxes
1718 for (auto &oneWidget : findChildren<QCheckBox*>())
1719 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
1720
1721 // All Time
1722 for (auto &oneWidget : findChildren<QTimeEdit*>())
1723 settings.insert(oneWidget->objectName(), oneWidget->time().toString());
1724
1725 return settings;
1726}
1727
1728///////////////////////////////////////////////////////////////////////////////////////////
1729///
1730///////////////////////////////////////////////////////////////////////////////////////////
1731void Mount::setAllSettings(const QVariantMap &settings)
1732{
1733 // Disconnect settings that we don't end up calling syncSettings while
1734 // performing the changes.
1735 disconnectSyncSettings();
1736
1737 for (auto &name : settings.keys())
1738 {
1739 // Combo
1740 auto comboBox = findChild<QComboBox*>(name);
1741 if (comboBox)
1742 {
1743 syncControl(settings, name, comboBox);
1744 continue;
1745 }
1746
1747 // Double spinbox
1748 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
1749 if (doubleSpinBox)
1750 {
1751 syncControl(settings, name, doubleSpinBox);
1752 continue;
1753 }
1754
1755 // spinbox
1756 auto spinBox = findChild<QSpinBox*>(name);
1757 if (spinBox)
1758 {
1759 syncControl(settings, name, spinBox);
1760 continue;
1761 }
1762
1763 // checkbox
1764 auto checkbox = findChild<QCheckBox*>(name);
1765 if (checkbox)
1766 {
1767 syncControl(settings, name, checkbox);
1768 continue;
1769 }
1770
1771 // timeEdit
1772 auto timeEdit = findChild<QTimeEdit*>(name);
1773 if (timeEdit)
1774 {
1775 syncControl(settings, name, timeEdit);
1776 continue;
1777 }
1778 }
1779
1780 // Sync to options
1781 for (auto &key : settings.keys())
1782 {
1783 auto value = settings[key];
1784 // Save immediately
1785 Options::self()->setProperty(key.toLatin1(), value);
1786 Options::self()->save();
1787
1788 m_Settings[key] = value;
1789 m_GlobalSettings[key] = value;
1790 }
1791
1792 emit settingsUpdated(getAllSettings());
1793
1794 // Save to optical train specific settings as well
1795 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->id(opticalTrainCombo->currentText()));
1796 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1797
1798 // Restablish connections
1799 connectSyncSettings();
1800}
1801
1802///////////////////////////////////////////////////////////////////////////////////////////
1803///
1804///////////////////////////////////////////////////////////////////////////////////////////
1805bool Mount::syncControl(const QVariantMap &settings, const QString &key, QWidget * widget)
1806{
1807 QSpinBox *pSB = nullptr;
1808 QDoubleSpinBox *pDSB = nullptr;
1809 QCheckBox *pCB = nullptr;
1810 QComboBox *pComboBox = nullptr;
1811 QTimeEdit *pTimeEdit = nullptr;
1812 bool ok = false;
1813
1814 if ((pSB = qobject_cast<QSpinBox *>(widget)))
1815 {
1816 const int value = settings[key].toInt(&ok);
1817 if (ok)
1818 {
1819 pSB->setValue(value);
1820 return true;
1821 }
1822 }
1823 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
1824 {
1825 const double value = settings[key].toDouble(&ok);
1826 if (ok)
1827 {
1828 pDSB->setValue(value);
1829 return true;
1830 }
1831 }
1832 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
1833 {
1834 const bool value = settings[key].toBool();
1835 pCB->setChecked(value);
1836 return true;
1837 }
1838 // ONLY FOR STRINGS, not INDEX
1839 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
1840 {
1841 const QString value = settings[key].toString();
1842 pComboBox->setCurrentText(value);
1843 return true;
1844 }
1845 else if ((pTimeEdit = qobject_cast<QTimeEdit *>(widget)))
1846 {
1847 const QString value = settings[key].toString();
1848 pTimeEdit->setTime(QTime::fromString(value));
1849 return true;
1850 }
1851
1852 return false;
1853};
1854
1855///////////////////////////////////////////////////////////////////////////////////////////
1856///
1857///////////////////////////////////////////////////////////////////////////////////////////
1858void Mount::syncSettings()
1859{
1860 QDoubleSpinBox *dsb = nullptr;
1861 QSpinBox *sb = nullptr;
1862 QCheckBox *cb = nullptr;
1863 QComboBox *cbox = nullptr;
1864 QTimeEdit *timeEdit = nullptr;
1865
1866 QString key;
1867 QVariant value;
1868
1870 {
1871 key = dsb->objectName();
1872 value = dsb->value();
1873
1874 }
1875 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
1876 {
1877 key = sb->objectName();
1878 value = sb->value();
1879 }
1880 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
1881 {
1882 key = cb->objectName();
1883 value = cb->isChecked();
1884 }
1885 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
1886 {
1887 key = cbox->objectName();
1888 value = cbox->currentText();
1889 }
1890 else if ( (timeEdit = qobject_cast<QTimeEdit*>(sender())))
1891 {
1892 key = timeEdit->objectName();
1893 value = timeEdit->time().toString();
1894 }
1895
1896 // Save immediately
1897 Options::self()->setProperty(key.toLatin1(), value);
1898 Options::self()->save();
1899
1900 m_Settings[key] = value;
1901 m_GlobalSettings[key] = value;
1902
1903 emit settingsUpdated(getAllSettings());
1904
1905 // Save to optical train specific settings as well
1906 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->id(opticalTrainCombo->currentText()));
1907 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1908}
1909
1910///////////////////////////////////////////////////////////////////////////////////////////
1911///
1912///////////////////////////////////////////////////////////////////////////////////////////
1913void Mount::loadGlobalSettings()
1914{
1915 QString key;
1916 QVariant value;
1917
1918 QVariantMap settings;
1919 // All Combo Boxes
1920 for (auto &oneWidget : findChildren<QComboBox*>())
1921 {
1922 if (oneWidget->objectName() == "opticalTrainCombo")
1923 continue;
1924
1925 key = oneWidget->objectName();
1926 value = Options::self()->property(key.toLatin1());
1927 if (value.isValid())
1928 {
1929 oneWidget->setCurrentText(value.toString());
1930 settings[key] = value;
1931 }
1932 }
1933
1934 // All Double Spin Boxes
1935 for (auto &oneWidget : findChildren<QDoubleSpinBox*>())
1936 {
1937 key = oneWidget->objectName();
1938 value = Options::self()->property(key.toLatin1());
1939 if (value.isValid())
1940 {
1941 oneWidget->setValue(value.toDouble());
1942 settings[key] = value;
1943 }
1944 }
1945
1946 // All Spin Boxes
1947 for (auto &oneWidget : findChildren<QSpinBox*>())
1948 {
1949 key = oneWidget->objectName();
1950 value = Options::self()->property(key.toLatin1());
1951 if (value.isValid())
1952 {
1953 oneWidget->setValue(value.toInt());
1954 settings[key] = value;
1955 }
1956 }
1957
1958 // All Checkboxes
1959 for (auto &oneWidget : findChildren<QCheckBox*>())
1960 {
1961 key = oneWidget->objectName();
1962 value = Options::self()->property(key.toLatin1());
1963 if (value.isValid())
1964 {
1965 oneWidget->setChecked(value.toBool());
1966 settings[key] = value;
1967 }
1968 }
1969
1970 // initialize meridian flip state machine values
1971 mf_state->setEnabled(Options::executeMeridianFlip());
1972 mf_state->setOffset(Options::meridianFlipOffsetDegrees());
1973
1974 m_GlobalSettings = m_Settings = settings;
1975}
1976
1977///////////////////////////////////////////////////////////////////////////////////////////
1978///
1979///////////////////////////////////////////////////////////////////////////////////////////
1980void Mount::connectSyncSettings()
1981{
1982 // All Combo Boxes
1983 for (auto &oneWidget : findChildren<QComboBox*>())
1984 connect(oneWidget, QOverload<int>::of(&QComboBox::activated), this, &Ekos::Mount::syncSettings);
1985
1986 // All Double Spin Boxes
1987 for (auto &oneWidget : findChildren<QDoubleSpinBox*>())
1988 connect(oneWidget, &QDoubleSpinBox::editingFinished, this, &Ekos::Mount::syncSettings);
1989
1990 // All Spin Boxes
1991 for (auto &oneWidget : findChildren<QSpinBox*>())
1992 connect(oneWidget, &QSpinBox::editingFinished, this, &Ekos::Mount::syncSettings);
1993
1994 // All Checkboxes
1995 for (auto &oneWidget : findChildren<QCheckBox*>())
1996 connect(oneWidget, &QCheckBox::toggled, this, &Ekos::Mount::syncSettings);
1997
1998 // All QDateTimeEdit
1999 for (auto &oneWidget : findChildren<QDateTimeEdit*>())
2000 connect(oneWidget, &QDateTimeEdit::editingFinished, this, &Ekos::Mount::syncSettings);
2001}
2002
2003///////////////////////////////////////////////////////////////////////////////////////////
2004///
2005///////////////////////////////////////////////////////////////////////////////////////////
2006void Mount::disconnectSyncSettings()
2007{
2008 // All Combo Boxes
2009 for (auto &oneWidget : findChildren<QComboBox*>())
2010 disconnect(oneWidget, QOverload<int>::of(&QComboBox::activated), this, &Ekos::Mount::syncSettings);
2011
2012 // All Double Spin Boxes
2013 for (auto &oneWidget : findChildren<QDoubleSpinBox*>())
2014 disconnect(oneWidget, &QDoubleSpinBox::editingFinished, this, &Ekos::Mount::syncSettings);
2015
2016 // All Spin Boxes
2017 for (auto &oneWidget : findChildren<QSpinBox*>())
2018 disconnect(oneWidget, &QSpinBox::editingFinished, this, &Ekos::Mount::syncSettings);
2019
2020 // All Checkboxes
2021 for (auto &oneWidget : findChildren<QCheckBox*>())
2022 disconnect(oneWidget, &QCheckBox::toggled, this, &Ekos::Mount::syncSettings);
2023
2024 for (auto &oneWidget : findChildren<QDateTimeEdit*>())
2025 disconnect(oneWidget, &QDateTimeEdit::editingFinished, this, &Ekos::Mount::syncSettings);
2026}
2027
2028///////////////////////////////////////////////////////////////////////////////////////////
2029///
2030///////////////////////////////////////////////////////////////////////////////////////////
2031void Mount::connectSettings()
2032{
2033 connectSyncSettings();
2034
2035 // connections to the meridian flip state machine
2036 connect(executeMeridianFlip, &QCheckBox::toggled, mf_state.get(), &MeridianFlipState::setEnabled);
2038 mf_state.get(), &MeridianFlipState::setOffset);
2039 connect(this, &Mount::newParkStatus, mf_state.get(), &MeridianFlipState::setMountParkStatus);
2040 connect(mf_state.get(), &MeridianFlipState::slewTelescope, [&](SkyPoint pos)
2041 {
2042 if (m_Mount)
2043 m_Mount->Slew(&pos, (m_Mount->canFlip() && Options::forcedFlip()));
2044 });
2045
2046 // Train combo box should NOT be synced.
2047 disconnect(opticalTrainCombo, QOverload<int>::of(&QComboBox::activated), this, &Ekos::Mount::syncSettings);
2048}
2049
2050///////////////////////////////////////////////////////////////////////////////////////////
2051///
2052///////////////////////////////////////////////////////////////////////////////////////////
2053void Mount::disconnectSettings()
2054{
2055 disconnectSyncSettings();
2056
2057 // cut connections to the meridian flip state machine
2058 disconnect(executeMeridianFlip, &QCheckBox::toggled, mf_state.get(), &MeridianFlipState::setEnabled);
2060 mf_state.get(), &MeridianFlipState::setOffset);
2061 disconnect(this, &Mount::newParkStatus, mf_state.get(), &MeridianFlipState::setMountParkStatus);
2062 disconnect(mf_state.get(), &MeridianFlipState::slewTelescope, nullptr, nullptr);
2063}
2064
2066{
2067 return mf_state->initialPositionHA();
2068}
2069}
void newTarget(SkyPoint &currentCoord)
The mount has finished the slew to a new target.
void saveLimits()
saveLimits Saves altitude limit to the user options and updates the INDI telescope driver limits
Definition mount.cpp:881
Q_SCRIPTABLE void setAutoParkDailyEnabled(bool enabled)
setAutoParkDailyEnabled toggles everyday Auto Park
Definition mount.cpp:1521
Q_SCRIPTABLE void setAltitudeLimitsEnabled(bool enable)
DBUS interface function.
Definition mount.cpp:966
void enableHaLimits()
enableHaLimits calls enableHourAngleLimits(true).
Definition mount.cpp:936
Q_INVOKABLE Q_SCRIPTABLE bool park()
DBUS interface function.
Definition mount.cpp:1227
Q_INVOKABLE Q_SCRIPTABLE bool sync(double RA, double DEC)
DBUS interface function.
Definition mount.cpp:1161
void updateProperty(INDI::Property prop)
updateProperty Update properties under watch in the mount module
Definition mount.cpp:723
void doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs)
Send a guide pulse to the telescope.
Definition mount.cpp:873
Q_INVOKABLE Q_SCRIPTABLE bool resetModel()
DBUS interface function.
Definition mount.cpp:1431
Q_INVOKABLE Q_SCRIPTABLE bool gotoTarget(const QString &target)
DBUS interface function.
Definition mount.cpp:1001
Q_INVOKABLE void setTrackEnabled(bool enabled)
DBUS interface function.
Definition mount.cpp:1463
void disableHaLimits()
disableAltLimits calls enableHourAngleLimits(false).
Definition mount.cpp:943
Q_SCRIPTABLE double initialHA()
DBUS interface function.
Definition mount.cpp:2065
Q_SCRIPTABLE void setAutoParkStartup(QTime startup)
setAutoParkStartup Set time when automatic parking is activated.
Definition mount.cpp:1526
void paaStageChanged(int stage)
React upon status changes of the polar alignment - mainly to avoid meridian flips happening during po...
Definition mount.cpp:788
void setMeridianFlipValues(bool activate, double degrees)
set meridian flip activation and hours
Definition mount.cpp:782
void syncTelescopeInfo()
syncTelescopeInfo Update telescope information to reflect any property changes
Definition mount.cpp:447
void syncAxisReversed(INDI_EQ_AXIS axis, bool reversed)
syncAxisReversed Update Mount Control GUI on the reverse motion toggled state.
Definition mount.cpp:1632
void motionCommand(int command, int NS, int WE)
move Issues motion command to the mount to move in a particular direction based the request NS and WE...
Definition mount.cpp:854
void registerNewModule(const QString &name)
registerNewModule Register an Ekos module as it arrives via DBus and create the appropriate DBus inte...
Definition mount.cpp:524
Q_INVOKABLE Q_SCRIPTABLE bool unpark()
DBUS interface function.
Definition mount.cpp:1235
double hourAngle
Mount::hourAngle.
Definition mount.h:47
void newTargetName(const QString &name)
The mount has finished the slew to a new target.
bool addGPS(ISD::GPS *device)
addGPS Add a new GPS device
Definition mount.cpp:345
Q_INVOKABLE Q_SCRIPTABLE bool syncTarget(const QString &target)
DBUS interface function.
Definition mount.cpp:1019
void stopTimers()
stopTimers Need to stop update timers when profile is disconnected but due to timing and race conditi...
Definition mount.cpp:1541
Q_SCRIPTABLE Q_NOREPLY void setHourAngleLimit(double limit)
DBUS interface function.
Definition mount.cpp:981
void newStatus(ISD::Mount::Status status)
Change in the mount status.
Q_INVOKABLE Q_SCRIPTABLE bool abort()
DBUS interface function.
Definition mount.cpp:1169
Q_SCRIPTABLE SkyPoint currentTarget()
DBUS interface function.
Definition mount.cpp:1105
void updateLog(int messageID)
updateLog Update mount module log to include any messages arriving for the telescope driver
Definition mount.cpp:837
bool setMount(ISD::Mount *device)
addMount Add a new Mount device
Definition mount.cpp:240
QSharedPointer< MeridianFlipState > getMeridianFlipState() const
getMeridianFlipState
Definition mount.h:129
Q_SCRIPTABLE Q_NOREPLY void setAltitudeLimits(QList< double > limits)
DBUS interface function.
Definition mount.cpp:960
Q_SCRIPTABLE void setHourAngleLimitEnabled(bool enable)
DBUS interface function.
Definition mount.cpp:986
void enableHourAngleLimits(bool enable)
enableHourAngleLimits Enable or disable hour angle limits
Definition mount.cpp:930
void suspendAltLimits()
suspendAltLimits calls enableAltitudeLimits(false).
Definition mount.cpp:924
void updateTelescopeCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha)
updateTelescopeCoords is triggered by the ISD::Mount::newCoord() event and updates the displayed coor...
Definition mount.cpp:534
Q_INVOKABLE Q_SCRIPTABLE bool slew(double RA, double DEC)
DBUS interface function.
Definition mount.cpp:1079
void newCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha)
Update event with the current telescope position.
void resumeAltLimits()
resumeAltLimits calls enableAltitudeLimits(true).
Definition mount.cpp:916
Q_SCRIPTABLE void setAutoParkEnabled(bool enable)
setAutoParkEnabled Toggle Auto Park
Definition mount.cpp:1513
const CachingDms * lat() const
Definition geolocation.h:70
void sendNewProperty(INDI::Property prop)
Send new property command to server.
INDI::PropertyView< IText > * getText(const QString &name) const
INDI::PropertyView< ISwitch > * getSwitch(const QString &name) const
device handle controlling Mounts.
Definition indimount.h:27
void stopTimers()
stopTimers Stop timers to prevent timing race condition when device is unavailable and timer is still...
void newTarget(SkyPoint &currentCoords)
The mount has finished the slew to a new target.
void newCoords(const SkyPoint &position, const PierSide pierside, const dms &ha)
Update event with the current telescope position.
void newTargetName(const QString &name)
The mount has finished the slew to a new target.
static void beep(const QString &reason=QString())
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
CachingDms * lst()
Definition kstarsdata.h:224
GeoLocation * geo()
Definition kstarsdata.h:230
static KStars * Instance()
Definition kstars.h:123
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual SkyObject * clone() const
Create copy of object.
Definition skyobject.cpp:50
virtual QString name(void) const
Definition skyobject.h:145
The sky coordinates of a point in the sky.
Definition skypoint.h:45
const CachingDms & dec() const
Definition skypoint.h:269
const CachingDms & ra0() const
Definition skypoint.h:251
const CachingDms & ra() const
Definition skypoint.h:263
dms altRefracted() const
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
Definition skypoint.h:94
const dms & az() const
Definition skypoint.h:275
virtual void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false)
Determine the current coordinates (RA, Dec) from the catalog coordinates (RA0, Dec0),...
Definition skypoint.cpp:582
void setAlt(dms alt)
Sets Alt, the Altitude.
Definition skypoint.h:194
const dms & alt() const
Definition skypoint.h:281
void HorizontalToEquatorial(const dms *LST, const dms *lat)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates,...
Definition skypoint.cpp:143
void setAz(dms az)
Sets Az, the Azimuth.
Definition skypoint.h:230
const CachingDms & dec0() const
Definition skypoint.h:257
void setDec0(dms d)
Sets Dec0, the catalog Declination.
Definition skypoint.h:119
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
static dms fromString(const QString &s, bool deg)
Static function to create a DMS object from a QString.
Definition dms.cpp:421
double Hours() const
Definition dms.h:168
virtual void setH(const double &x)
Sets floating-point value of angle, in hours.
Definition dms.h:210
virtual bool setFromString(const QString &s, bool isDeg=true)
Attempt to parse the string argument as a dms value, and set the dms object accordingly.
Definition dms.cpp:48
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
Definition dms.cpp:370
const double & Degrees() const
Definition dms.h:141
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
KGuiItem insert()
QString name(StandardShortcut id)
bool isChecked() const const
void clicked(bool checked)
void toggled(bool checked)
void setChecked(bool)
void activated(int index)
void currentIndexChanged(int index)
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
bool registerObject(const QString &path, QObject *object, QDBusConnection::RegisterOptions options)
QDBusConnection sessionBus()
void accepted()
void valueChanged(double d)
void append(const T &value)
void clear()
void insert(int i, const T &value)
bool removeOne(const T &value)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
T findChild(const QString &name, Qt::FindChildOptions options) const const
QList< T > findChildren(const QString &name, Qt::FindChildOptions options) const const
QVariant property(const char *name) const const
QObject * sender() const const
bool setProperty(const char *name, const QVariant &value)
void setContextObject(QObject *object)
void setContextProperty(const QString &name, QObject *value)
void setEnabled(bool)
void setResizeMode(QQuickView::ResizeMode)
QQmlContext * rootContext() const const
QQuickItem * rootObject() const const
void setSource(const QUrl &url)
void setColor(const QColor &color)
T * get() const const
QString number(int n, int base)
QByteArray toLatin1() const const
UniqueConnection
QTextStream & dec(QTextStream &stream)
QTime addMSecs(int ms) const const
QTime fromString(const QString &string, Qt::DateFormat format)
QString toString(Qt::DateFormat format) const const
void setInterval(int msec)
bool isActive() const const
void start(int msec)
void stop()
void timeout()
bool isValid() const const
bool toBool() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const
void setEnabled(bool)
void setupUi(QWidget *widget)
void setFlags(Qt::WindowFlags flags)
void hide()
void show()
void setTitle(const QString &)
bool isVisible() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:45:34 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.