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