13#include <KNotifications/KNotification>
14#include <KLocalizedContext>
15#include <KActionCollection>
17#include <kio_version.h>
21#include "ksmessagebox.h"
22#include "indi/driverinfo.h"
23#include "indi/indicommon.h"
24#include "indi/clientmanager.h"
25#include "indi/indigps.h"
28#include "mountadaptor.h"
29#include "mountcontrolpanel.h"
31#include "ekos/manager.h"
32#include "ekos/auxiliary/opticaltrainmanager.h"
33#include "ekos/auxiliary/profilesettings.h"
34#include "ekos/auxiliary/opticaltrainsettings.h"
35#include "ekos/manager/meridianflipstate.h"
36#include "ekos/align/polaralignmentassistant.h"
39#include "skymapcomposite.h"
40#include "dialogs/finddialog.h"
41#include "kstarsdata.h"
43#include <basedevice.h>
45#include <ekos_mount_debug.h>
47extern const char *libindi_strings_context;
49#define ABORT_DISPATCH_LIMIT 3
58 new MountAdaptor(
this);
63 qDBusRegisterMetaType<SkyPoint>();
72 mf_state.
reset(
new MeridianFlipState());
77 connect(mf_state.
get(), &MeridianFlipState::newMeridianFlipMountStatusText, [&](
const QString & text)
79 meridianFlipStatusWidget->setStatus(text);
80 if (mf_state->getMeridianFlipMountState() != MeridianFlipState::MOUNT_FLIP_NONE &&
81 mf_state->getMeridianFlipMountState() != MeridianFlipState::MOUNT_FLIP_PLANNED)
91 m_Mount->clearParking();
100 i18n(
"Are you sure you want to clear all mount configurations?"),
101 i18n(
"Mount Configuration"), KStandardGuiItem::yes(), KStandardGuiItem::no(),
102 "purge_mount_settings_dialog") == KMessageBox::Yes)
105 m_Mount->clearParking();
106 m_Mount->setConfig(PURGE_CONFIG);
117 m_AltitudeLimitEnabled = toggled;
121 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
125 connect(mf_state.
get(), &MeridianFlipState::newMeridianFlipMountStatusText, meridianFlipStatusWidget,
126 &MeridianFlipStatusWidget::setStatus);
137 stopTimerB->setEnabled(
false);
139 if (parkEveryDay->isChecked())
140 startTimerB->animateClick();
145 connect(m_ControlPanel.
get(), &MountControlPanel::newSlewRate,
this, &Mount::setSlewRate);
150 connect(m_ControlPanel.
get(), &MountControlPanel::updownReversed,
this, &Mount::setUpDownReversed);
151 connect(m_ControlPanel.
get(), &MountControlPanel::leftrightReversed,
this, &Mount::setLeftRightReversed);
152 connect(m_ControlPanel.
get(), &MountControlPanel::center,
this, &Mount::centerMount);
155 connect(mountMotion, &MountMotionWidget::newSlewRate,
this, &Mount::setSlewRate);
157 connect(mountMotion, &MountMotionWidget::updownReversed,
this, &Mount::setUpDownReversed);
158 connect(mountMotion, &MountMotionWidget::leftrightReversed,
this, &Mount::setLeftRightReversed);
161 connect(mountPosition, &MountPositionWidget::J2000Enabled, mountTarget, &MountTargetWidget::setJ2000Enabled);
170 for (
auto &button : qButtons)
171 button->setAutoDefault(false);
173 loadGlobalSettings();
176 setupOpticalTrainManager();
181 autoParkTimer.
stop();
184void Mount::setupParkUI()
186 if (m_Mount ==
nullptr)
189 if (m_Mount->canPark())
191 switch(m_Mount->parkStatus())
193 case ISD::PARK_PARKED:
194 parkingLabel->setText(
"Parked");
196 case ISD::PARK_PARKING:
197 parkingLabel->setText(
"Parking");
199 case ISD::PARK_UNPARKING:
200 parkingLabel->setText(
"Unparking");
202 case ISD::PARK_UNPARKED:
203 parkingLabel->setText(
"Unparked");
205 case ISD::PARK_ERROR:
206 parkingLabel->setText(
"Park Error");
208 case ISD::PARK_UNKNOWN:
209 parkingLabel->setText(
"Park Status Unknown");
212 parkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_UNPARKED);
213 unparkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_PARKED);
217 parkB->setEnabled(
false);
218 unparkB->setEnabled(
false);
219 parkingLabel->setText(
"");
225 if (device && device == m_Mount)
232 m_Mount->
disconnect(m_Mount,
nullptr,
this,
nullptr);
238 connect(m_Mount, &ISD::ConcreteDevice::Connected,
this, [
this]()
242 connect(m_Mount, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
245 opticalTrainCombo->setEnabled(
true);
246 trainLabel->setEnabled(
true);
252 mainLayout->setEnabled(
true);
255 mf_state->setMountConnected(device !=
nullptr);
262 connect(m_Mount, &ISD::Mount::slewRateChanged,
this, &Mount::slewRateChanged);
263 connect(m_Mount, &ISD::Mount::pierSideChanged,
this, &Mount::pierSideChanged);
265 connect(m_Mount, &ISD::Mount::Disconnected,
this, [
this]()
267 m_ControlPanel->hide();
269 connect(m_Mount, &ISD::Mount::newParkStatus,
this, [&](ISD::ParkStatus status)
271 m_ParkStatus = status;
272 emit newParkStatus(status);
278 if (status == ISD::PARK_UNPARKED && parkEveryDay->isChecked() && autoParkTimer.
isActive() ==
false)
279 startTimerB->animateClick();
283 if (m_Mount->isReady())
285 if (enableAltitudeLimits->isChecked())
286 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
288 m_Mount->setAltLimits(-91, +91);
293 m_Status = m_Mount->status();
296 m_ParkStatus = m_Mount->parkStatus();
297 emit newParkStatus(m_ParkStatus);
303 connect(m_Mount, &ISD::Mount::ready,
this, [
this]()
305 if (enableAltitudeLimits->isChecked())
306 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
308 m_Mount->setAltLimits(-91, +91);
313 m_Status = m_Mount->status();
316 m_ParkStatus = m_Mount->parkStatus();
317 emit newParkStatus(m_ParkStatus);
328 for (
auto &oneSource : m_TimeSources)
330 if (oneSource->getDeviceName() == device->getDeviceName())
334 m_TimeSources.
append(device);
336 timeSource->blockSignals(
true);
338 timeSource->addItem(
"KStars");
340 m_TimeSourcesList.
clear();
341 m_TimeSourcesList.
append(
"KStars");
343 for (
auto &oneSource : m_TimeSources)
345 auto name = oneSource->getDeviceName();
347 m_TimeSourcesList.
append(name);
348 timeSource->addItem(name);
350 if (name == Options::timeSource())
353 auto refreshGPS = oneSource->getProperty(
"GPS_REFRESH");
356 auto sw = refreshGPS.getSwitch();
357 sw->at(0)->setState(ISS_ON);
358 oneSource->sendNewProperty(refreshGPS);
363 timeSource->setCurrentText(Options::timeSource());
364 timeSource->blockSignals(
false);
371 for (
auto &oneSource : m_LocationSources)
373 if (oneSource->getDeviceName() == device->getDeviceName())
377 m_LocationSources.
append(device);
378 locationSource->blockSignals(
true);
379 locationSource->clear();
380 locationSource->addItem(
"KStars");
382 m_LocationSourcesList.
clear();
383 m_LocationSourcesList.
append(
"KStars");
385 for (
auto &oneSource : m_LocationSources)
387 auto name = oneSource->getDeviceName();
388 locationSource->addItem(name);
389 m_LocationSourcesList.
append(name);
391 if (name == Options::locationSource())
393 auto refreshGPS = oneSource->getProperty(
"GPS_REFRESH");
396 auto sw = refreshGPS.getSwitch();
397 sw->at(0)->setState(ISS_ON);
398 oneSource->sendNewProperty(refreshGPS);
403 locationSource->setCurrentText(Options::locationSource());
404 locationSource->blockSignals(
false);
410 if (m_Mount && m_Mount->getDeviceName() == device->getDeviceName())
413 m_ControlPanel->hide();
414 qCDebug(KSTARS_EKOS_MOUNT) <<
"Removing mount driver" << m_Mount->getDeviceName();
418 m_TimeSources.
erase(std::remove_if(m_TimeSources.
begin(), m_TimeSources.
end(), [device](
const auto & oneSource)
420 return device->getDeviceName() == oneSource->getDeviceName();
421 }), m_TimeSources.
end());
423 m_LocationSources.
erase(std::remove_if(m_LocationSources.
begin(), m_LocationSources.
end(), [device](
const auto & oneSource)
425 return device->getDeviceName() == oneSource->getDeviceName();
426 }), m_LocationSources.
end());
431 if (!m_Mount || m_Mount->isConnected() ==
false)
434 auto svp = m_Mount->
getSwitch(
"TELESCOPE_SLEW_RATE");
436 mountMotion->syncSpeedInfo(svp);
437 m_ControlPanel->mountMotion->syncSpeedInfo(svp);
439 if (m_Mount->canPark())
444 m_ControlPanel->parkButtonObject->setEnabled(!m_Mount->isParked());
445 m_ControlPanel->unparkButtonObject->setEnabled(m_Mount->isParked());
452 m_ControlPanel->parkButtonObject->setEnabled(
false);
453 m_ControlPanel->unparkButtonObject->setEnabled(
false);
456 m_ControlPanel->setProperty(
"isJ2000", m_Mount->isJ2000());
460 svp = m_Mount->
getSwitch(
"TELESCOPE_TRACK_STATE");
463 trackingLabel->setEnabled(
true);
464 trackOnB->setEnabled(
true);
465 trackOffB->setEnabled(
true);
466 trackOnB->disconnect();
467 trackOffB->disconnect();
470 m_Mount->setTrackEnabled(
true);
474#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0)
476 i18n(
"Are you sure you want to turn off mount tracking?"),
477 i18n(
"Mount Tracking"),
480 "turn_off_mount_tracking_dialog") == KMessageBox::ButtonCode::PrimaryAction)
481 m_Mount->setTrackEnabled(
false);
484 i18n(
"Are you sure you want to turn off mount tracking?"),
485 i18n(
"Mount Tracking"),
486 KStandardGuiItem::yes(),
487 KStandardGuiItem::no(),
488 "turn_off_mount_tracking_dialog") == KMessageBox::Yes)
489 m_Mount->setTrackEnabled(
false);
495 trackingLabel->setEnabled(
false);
496 trackOnB->setChecked(
false);
497 trackOnB->setEnabled(
false);
498 trackOffB->setChecked(
false);
499 trackOffB->setEnabled(
false);
502 m_ControlPanel->mountMotion->leftRightCheckObject->setProperty(
"checked", m_Mount->isReversed(AXIS_RA));
503 m_ControlPanel->mountMotion->upDownCheckObject->setProperty(
"checked", m_Mount->isReversed(AXIS_DE));
508 if (name ==
"Capture")
510 hasCaptureInterface =
true;
511 mf_state->setHasCaptureInterface(
true);
517 if (m_Mount ==
nullptr || !m_Mount->isConnected())
520 telescopeCoord = position;
523 mountPosition->updateTelescopeCoords(position, ha);
524 m_ControlPanel->mountPosition->updateTelescopeCoords(position, ha);
527 if (m_Status == ISD::Mount::MOUNT_PARKED && m_Status == m_Mount->status())
532 if (minimumAltLimit->isEnabled() && (currentAlt < minimumAltLimit->value() || currentAlt > maximumAltLimit->value()))
534 if (currentAlt < minimumAltLimit->value())
537 if (currentAlt < m_LastAltitude &&
538 (m_AbortAltDispatch == -1 ||
539 (m_Mount->isInMotion() )))
541 appendLogText(
i18n(
"Telescope altitude is below minimum altitude limit of %1. Aborting motion...",
544 m_Mount->setTrackEnabled(
false);
547 m_AbortAltDispatch++;
553 if (currentAlt > m_LastAltitude &&
554 (m_AbortAltDispatch == -1 ||
555 (m_Mount->isInMotion() )))
557 appendLogText(
i18n(
"Telescope altitude is above maximum altitude limit of %1. Aborting motion...",
560 m_Mount->setTrackEnabled(
false);
563 m_AbortAltDispatch++;
568 m_AbortAltDispatch = -1;
572 double haHours = rangeHA(ha.
Hours());
578 if (maximumHaLimit->isEnabled())
581 double haLimit = maximumHaLimit->value();
582 bool haLimitReached =
false;
585 case ISD::Mount::PierSide::PIER_WEST:
586 haLimitReached = haHours > haLimit;
588 case ISD::Mount::PierSide::PIER_EAST:
589 haLimitReached = rangeHA(haHours + 12.0) > haLimit;
593 haLimitReached =
false;
597 qCDebug(KSTARS_EKOS_MOUNT) <<
"Ha: " << haHours <<
598 " haLimit " << haLimit <<
599 " " << ISD::Mount::pierSideStateString(m_Mount->pierSide()) <<
600 " haLimitReached " << (haLimitReached ?
"true" :
"false") <<
601 " lastHa " << m_LastHourAngle;
604 if (haLimitReached && (rangeHA(haHours - m_LastHourAngle) >= 0 ) &&
605 (m_AbortHADispatch == -1 ||
606 m_Mount->isInMotion()))
609 appendLogText(
i18n(
"Telescope hour angle is more than the maximum hour angle of %1. Aborting motion...",
612 m_Mount->setTrackEnabled(
false);
622 m_AbortHADispatch = -1;
624 m_LastAltitude = currentAlt;
625 m_LastHourAngle = haHours;
627 ISD::Mount::Status currentStatus = m_Mount->status();
628 if (m_Status != currentStatus)
630 qCDebug(KSTARS_EKOS_MOUNT) <<
"Mount status changed from " << m_Mount->statusString(m_Status)
631 <<
" to " << m_Mount->statusString(currentStatus);
635 m_ControlPanel->statusTextObject->setProperty(
"text", m_Mount->statusString(currentStatus));
636 m_Status = currentStatus;
641 m_ControlPanel->parkButtonObject->setEnabled(!m_Mount->isParked());
642 m_ControlPanel->unparkButtonObject->setEnabled(m_Mount->isParked());
646 a->
setChecked(currentStatus == ISD::Mount::MOUNT_TRACKING);
649 bool isTracking = (currentStatus == ISD::Mount::MOUNT_TRACKING);
650 if (trackOnB->isEnabled())
652 trackOnB->setChecked(isTracking);
653 trackOffB->setChecked(!isTracking);
657 pierSideLabel->setText(ISD::Mount::pierSideStateString(m_Mount->pierSide()));
662 QTime remainingTime(0, 0, 0);
664 countdownLabel->setText(remainingTime.
toString(
"hh:mm:ss"));
665 emit autoParkCountdownUpdated(countdownLabel->text());
671 if (prop.isNameMatch(
"EQUATORIAL_EOD_COORD") || prop.isNameMatch(
"EQUATORIAL_COORD"))
673 auto nvp = prop.getNumber();
681 case MeridianFlipState::MF_INITIATED:
682 if (nvp->s == IPS_BUSY && m_Mount !=
nullptr && m_Mount->isSlewing())
690 else if (prop.isNameMatch(
"TELESCOPE_SLEW_RATE"))
692 auto svp = prop.getSwitch();
693 mountMotion->updateSpeedInfo(svp);
694 m_ControlPanel->mountMotion->updateSpeedInfo(svp);
698bool Mount::setSlewRate(
int index)
701 return m_Mount->setSlewRate(index);
706void Mount::setUpDownReversed(
bool enabled)
708 Options::setUpDownReversed(
enabled);
710 m_Mount->setReversedEnabled(AXIS_DE,
enabled);
713void Mount::setLeftRightReversed(
bool enabled)
715 Options::setLeftRightReversed(
enabled);
717 m_Mount->setReversedEnabled(AXIS_RA,
enabled);
722 executeMeridianFlip->setChecked(activate);
723 meridianFlipOffsetDegrees->setValue(degrees);
734 if (stage != PolarAlignmentAssistant::PAH_IDLE)
735 mf_state->clearTargetPosition();
740 case PolarAlignmentAssistant::PAH_FIRST_CAPTURE:
741 case PolarAlignmentAssistant::PAH_FIRST_SOLVE:
742 if (mf_state->isEnabled())
744 appendLogText(
i18n(
"Meridian flip set inactive during polar alignment."));
745 mf_state->setEnabled(
false);
750 case PolarAlignmentAssistant::PAH_THIRD_CAPTURE:
751 case PolarAlignmentAssistant::PAH_THIRD_SOLVE:
752 case PolarAlignmentAssistant::PAH_STAR_SELECT:
753 case PolarAlignmentAssistant::PAH_REFRESH:
754 case PolarAlignmentAssistant::PAH_POST_REFRESH:
755 case PolarAlignmentAssistant::PAH_IDLE:
756 if (executeMeridianFlip->isChecked() && mf_state->isEnabled() ==
false)
758 appendLogText(
i18n(
"Polar alignment motions finished, meridian flip activated."));
759 mf_state->setEnabled(executeMeridianFlip->isChecked());
765void Mount::appendLogText(
const QString &text)
767 m_LogText.
insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
768 KStarsData::Instance()->lt().toString(
"yyyy-MM-ddThh:mm:ss"), text));
770 qCInfo(KSTARS_EKOS_MOUNT) << text;
777 if (m_Mount ==
nullptr)
780 auto message = m_Mount->getMessage(messageID);
781 m_LogText.
insert(0,
i18nc(
"Message shown in Ekos Mount module",
"%1", message));
783 emit newLog(message);
786void Mount::clearLog()
794 if (m_Mount ==
nullptr || !m_Mount->isConnected())
799 m_Mount->MoveNS(
static_cast<ISD::Mount::VerticalMotion
>(NS),
800 static_cast<ISD::Mount::MotionCommand
>(command));
805 m_Mount->MoveWE(
static_cast<ISD::Mount::HorizontalMotion
>(WE),
806 static_cast<ISD::Mount::MotionCommand
>(command));
811void Mount::doPulse(GuideDirection ra_dir,
int ra_msecs, GuideDirection dec_dir,
int dec_msecs)
813 if (m_Mount ==
nullptr || !m_Mount->isConnected())
816 m_Mount->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
821 if (m_Mount ==
nullptr)
824 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
831 minAltLabel->setEnabled(
true);
832 maxAltLabel->setEnabled(
true);
834 minimumAltLimit->setEnabled(
true);
835 maximumAltLimit->setEnabled(
true);
838 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value());
842 minAltLabel->setEnabled(
false);
843 maxAltLabel->setEnabled(
false);
845 minimumAltLimit->setEnabled(
false);
846 maximumAltLimit->setEnabled(
false);
849 m_Mount->setAltLimits(-91, +91);
857 if (m_AltitudeLimitEnabled && minimumAltLimit->isEnabled() ==
false)
864 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
870 maxHaLabel->setEnabled(enable);
871 maximumHaLimit->setEnabled(enable);
877 if (m_HourAngleLimitEnabled && maximumHaLimit->isEnabled() ==
false)
883 m_HourAngleLimitEnabled = enableHaLimit->isChecked();
892 limits.
append(minimumAltLimit->value());
893 limits.
append(maximumAltLimit->value());
900 minimumAltLimit->setValue(limits[0]);
901 maximumAltLimit->setValue(limits[1]);
906 enableAltitudeLimits->setChecked(enable);
909bool Mount::altitudeLimitsEnabled()
911 return enableAltitudeLimits->isChecked();
914double Mount::hourAngleLimit()
916 return maximumHaLimit->
value();
921 maximumHaLimit->setValue(limit);
926 enableHaLimit->setChecked(enable);
929bool Mount::hourAngleLimitEnabled()
931 return enableHaLimit->isChecked();
934void Mount::setJ2000Enabled(
bool enabled)
936 m_ControlPanel->setJ2000Enabled(
enabled);
937 mountPosition->setJ2000Enabled(
enabled);
944 if (
object !=
nullptr)
947 return slew(object->ra().Hours(), object->dec().Degrees());
960 mountTarget->setTargetName(name);
961 m_ControlPanel->setTargetName(name);
968 if (
object !=
nullptr)
979 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
983 targetPosition =
new SkyPoint(RA, DEC);
984 SkyPoint J2000Coord(targetPosition->
ra(), targetPosition->
dec());
986 targetPosition->
setRA0(J2000Coord.
ra());
989 mf_state->setTargetPosition(targetPosition);
990 mf_state->resetMeridianFlip();
992 m_ControlPanel->setTargetPosition(
new SkyPoint(RA, DEC));
993 mountTarget->setTargetPosition(
new SkyPoint(RA, DEC));
995 qCDebug(KSTARS_EKOS_MOUNT) <<
"Slewing to RA=" <<
998 qCDebug(KSTARS_EKOS_MOUNT) <<
"Initial HA " <<
initialHA() <<
", flipDelayHrs " << mf_state->getFlipDelayHrs() <<
999 "MFStatus " << MeridianFlipState::meridianFlipStatusString(mf_state->getMeridianFlipMountState());
1002 return(m_Mount->Slew(targetPosition));
1008 if (targetPosition !=
nullptr)
1009 return *targetPosition;
1011 qCWarning(KSTARS_EKOS_MOUNT) <<
"No target position defined!";
1013 return telescopeCoord;
1018 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
1021 return m_Mount->Sync(RA, DEC);
1026 if (m_Mount ==
nullptr)
1029 return m_Mount->abort();
1032IPState Mount::slewStatus()
1034 if (m_Mount ==
nullptr)
1037 return m_Mount->getState(
"EQUATORIAL_EOD_COORD");
1042 double ra {0},
dec {0};
1046 m_Mount->getEqCoords(&ra, &dec);
1069 dms lst = KStarsData::Instance()->
geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1071 return rangeHA(ha.Hours());
1074bool Mount::canPark()
1076 if (m_Mount ==
nullptr)
1079 return m_Mount->canPark();
1084 if (m_Mount ==
nullptr || m_Mount->canPark() ==
false)
1087 return m_Mount->park();
1092 if (m_Mount ==
nullptr || m_Mount->canPark() ==
false)
1095 return m_Mount->unpark();
1099void Mount::toggleMountToolBox()
1101 if (m_ControlPanel->isVisible())
1103 m_ControlPanel->hide();
1110 m_ControlPanel->show();
1121 return m_ControlPanel->mountTarget->raDecToAzAlt(qsRA, qsDec);
1124bool Mount::raDecToHaDec(
QString qsRA)
1126 return m_ControlPanel->mountTarget->raDecToHaDec(qsRA);
1131 return m_ControlPanel->mountTarget->azAltToRaDec(qsAz, qsAlt);
1136 return m_ControlPanel->mountTarget->azAltToHaDec(qsAz, qsAlt);
1139bool Mount::haDecToRaDec(
QString qsHA)
1141 return m_ControlPanel->mountTarget->haDecToRaDec(qsHA);
1146 return m_ControlPanel->mountTarget->haDecToAzAlt(qsHA, qsDec);
1151void Mount::centerMount()
1159 if (m_Mount ==
nullptr)
1162 if (m_Mount->hasAlignmentModel() ==
false)
1165 if (m_Mount->clearAlignmentModel())
1167 appendLogText(
i18n(
"Alignment Model cleared."));
1171 appendLogText(
i18n(
"Failed to clear Alignment Model."));
1176void Mount::setScopeStatus(ISD::Mount::Status status)
1178 if (m_Status != status)
1180 m_ControlPanel->statusTextObject->setProperty(
"text", m_Mount->statusString(status));
1197int Mount::slewRate()
1199 if (m_Mount ==
nullptr)
1202 return m_Mount->getSlewRate();
1234bool Mount::autoParkEnabled()
1249 parkEveryDay->setChecked(
enabled);
1254 autoParkTime->setTime(startup);
1257bool Mount::meridianFlipEnabled()
1259 return executeMeridianFlip->isChecked();
1262double Mount::meridianFlipValue()
1264 return meridianFlipOffsetDegrees->value();
1269 autoParkTimer.
stop();
1274void Mount::startParkTimer()
1276 if (m_Mount ==
nullptr || m_ParkStatus == ISD::PARK_UNKNOWN)
1279 if (m_Mount->isParked())
1281 appendLogText(
i18n(
"Mount already parked."));
1285 auto parkTime = autoParkTime->time();
1287 qCDebug(KSTARS_EKOS_MOUNT) <<
"Parking time is" << parkTime.toString();
1288 QDateTime currentDateTime = KStarsData::Instance()->
lt();
1289 QDateTime parkDateTime(currentDateTime);
1291 parkDateTime.setTime(parkTime);
1292 qint64 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1293 qCDebug(KSTARS_EKOS_MOUNT) <<
"Until parking time:" << parkMilliSeconds <<
"ms or" << parkMilliSeconds / (60 * 60 * 1000)
1295 if (parkMilliSeconds > 0)
1297 qCDebug(KSTARS_EKOS_MOUNT) <<
"Added a day to parking time...";
1298 parkDateTime = parkDateTime.addDays(1);
1299 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1301 int hours =
static_cast<int>(parkMilliSeconds / (1000 * 60 * 60));
1305 if (parkEveryDay->isChecked() ==
false)
1306 appendLogText(
i18n(
"Parking time cannot be in the past."));
1311 parkMilliSeconds = std::abs(parkMilliSeconds);
1313 if (parkMilliSeconds > 24 * 60 * 60 * 1000)
1315 appendLogText(
i18n(
"Parking time must be within 24 hours of current time."));
1319 if (parkMilliSeconds > 12 * 60 * 60 * 1000)
1320 appendLogText(
i18n(
"Warning! Parking time is more than 12 hours away."));
1322 appendLogText(
i18n(
"Caution: do not use Auto Park while scheduler is active."));
1324 autoParkTimer.
setInterval(
static_cast<int>(parkMilliSeconds));
1325 autoParkTimer.
start();
1327 startTimerB->setEnabled(
false);
1328 stopTimerB->setEnabled(
true);
1331void Mount::stopParkTimer()
1333 autoParkTimer.
stop();
1334 countdownLabel->setText(
"00:00:00");
1335 emit autoParkCountdownUpdated(
"00:00:00");
1336 stopTimerB->setEnabled(
false);
1337 startTimerB->setEnabled(
true);
1340void Mount::startAutoPark()
1342 appendLogText(
i18n(
"Parking timer is up."));
1343 autoParkTimer.
stop();
1344 startTimerB->setEnabled(
true);
1345 stopTimerB->setEnabled(
false);
1346 countdownLabel->setText(
"00:00:00");
1347 emit autoParkCountdownUpdated(
"00:00:00");
1350 if (m_Mount->isParked() ==
false)
1352 appendLogText(
i18n(
"Starting auto park..."));
1360 if (axis == AXIS_RA)
1361 m_ControlPanel->mountMotion->leftRightCheckObject->setProperty(
"checked", reversed);
1363 m_ControlPanel->mountMotion->upDownCheckObject->setProperty(
"checked", reversed);
1366void Mount::setupOpticalTrainManager()
1368 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Mount::refreshOpticalTrain);
1371 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1375 ProfileSettings::Instance()->setOneSetting(ProfileSettings::MountOpticalTrain,
1376 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
1377 refreshOpticalTrain();
1378 emit trainChanged();
1382void Mount::refreshOpticalTrain()
1384 opticalTrainCombo->blockSignals(
true);
1385 opticalTrainCombo->clear();
1386 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1387 trainB->setEnabled(
true);
1389 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::MountOpticalTrain);
1393 auto id = trainID.
toUInt();
1396 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
1398 qCWarning(KSTARS_EKOS_MOUNT) <<
"Optical train doesn't exist for id" << id;
1399 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1402 auto name = OpticalTrainManager::Instance()->name(
id);
1404 opticalTrainCombo->setCurrentText(name);
1406 auto mount = OpticalTrainManager::Instance()->getMount(name);
1409 auto scope = OpticalTrainManager::Instance()->getScope(name);
1410 opticalTrainCombo->setToolTip(scope[
"name"].
toString());
1413 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
1414 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Mount);
1415 if (settings.isValid())
1417 auto map = settings.toJsonObject().toVariantMap();
1418 if (map != m_Settings)
1421 setAllSettings(map);
1425 m_Settings = m_GlobalSettings;
1428 opticalTrainCombo->blockSignals(
false);
1434QVariantMap Mount::getAllSettings()
const
1436 QVariantMap settings;
1464void Mount::setAllSettings(
const QVariantMap &settings)
1468 disconnectSyncSettings();
1470 for (
auto &name : settings.keys())
1476 syncControl(settings, name, comboBox);
1484 syncControl(settings, name, doubleSpinBox);
1492 syncControl(settings, name, spinBox);
1500 syncControl(settings, name, checkbox);
1508 syncControl(settings, name, timeEdit);
1514 for (
auto &key : settings.keys())
1516 auto value = settings[key];
1518 Options::self()->setProperty(key.toLatin1(), value);
1519 Options::self()->save();
1521 m_Settings[key] = value;
1522 m_GlobalSettings[key] = value;
1525 emit settingsUpdated(getAllSettings());
1528 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1529 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1532 connectSyncSettings();
1538bool Mount::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
1550 const int value = settings[key].toInt(&ok);
1559 const double value = settings[key].toDouble(&ok);
1568 const bool value = settings[key].toBool();
1575 const bool value = settings[key].toBool();
1577 pRadioButton->
click();
1583 const QString value = settings[key].toString();
1589 const QString value = settings[key].toString();
1600void Mount::syncSettings()
1615 value = dsb->
value();
1621 value = sb->
value();
1633 m_Settings.remove(key);
1646 value = timeEdit->
time().toString();
1650 Options::self()->setProperty(key.
toLatin1(), value);
1651 m_Settings[key] = value;
1652 m_GlobalSettings[key] = value;
1654 m_DebounceTimer.
start();
1660void Mount::settleSettings()
1662 Options::self()->save();
1663 emit settingsUpdated(getAllSettings());
1665 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1666 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1672void Mount::loadGlobalSettings()
1677 QVariantMap settings;
1681 if (oneWidget->objectName() ==
"opticalTrainCombo")
1684 key = oneWidget->objectName();
1685 value = Options::self()->property(key.
toLatin1());
1686 if (value.
isValid() && oneWidget->count() > 0)
1688 oneWidget->setCurrentText(value.
toString());
1689 settings[key] = value;
1696 key = oneWidget->objectName();
1697 value = Options::self()->property(key.
toLatin1());
1701 settings[key] = value;
1708 key = oneWidget->objectName();
1709 value = Options::self()->property(key.
toLatin1());
1713 settings[key] = value;
1720 key = oneWidget->objectName();
1721 value = Options::self()->property(key.
toLatin1());
1724 oneWidget->setChecked(value.
toBool());
1725 settings[key] = value;
1730 mf_state->setEnabled(Options::executeMeridianFlip());
1731 mf_state->setOffset(Options::meridianFlipOffsetDegrees());
1733 m_GlobalSettings = m_Settings = settings;
1739void Mount::connectSyncSettings()
1743 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated), this, &
Ekos::Mount::syncSettings);
1769void Mount::disconnectSyncSettings()
1798void Mount::connectSettings()
1800 connectSyncSettings();
1805 mf_state.
get(), &MeridianFlipState::setOffset);
1806 connect(
this, &Mount::newParkStatus, mf_state.
get(), &MeridianFlipState::setMountParkStatus);
1810 m_Mount->Slew(&pos, (m_Mount->canFlip() && Options::forcedFlip()));
1820void Mount::disconnectSettings()
1822 disconnectSyncSettings();
1827 mf_state.
get(), &MeridianFlipState::setOffset);
1828 disconnect(
this, &Mount::newParkStatus, mf_state.
get(), &MeridianFlipState::setMountParkStatus);
1829 disconnect(mf_state.
get(), &MeridianFlipState::slewTelescope,
nullptr,
nullptr);
1837 return mf_state->initialPositionHA();
1845 appendLogText(
i18n(
"Updating master time source to %1.", Options::locationSource()));
1853 auto name = Options::locationSource();
1854 auto it = std::find_if(m_LocationSources.
begin(), m_LocationSources.
end(), [name](
const auto & oneSource)
1856 return oneSource->getDeviceName() == name;
1858 if (it != m_LocationSources.
end())
1860 auto property = (*it)->getProperty(
"GPS_REFRESH");
1863 auto sw =
property.getSwitch();
1864 sw->at(0)->setState(ISS_ON);
1866 appendLogText(
i18n(
"Updating master location source to %1. Updating GPS...", name));
1870 property = (*it)->getProperty(
"GEOGRAPHIC_COORD");
1874 appendLogText(
i18n(
"Updating master location source to %1.", name));
void newTarget(SkyPoint ¤tCoord)
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
Q_SCRIPTABLE void setAutoParkDailyEnabled(bool enabled)
setAutoParkDailyEnabled toggles everyday Auto Park
Q_SCRIPTABLE void setAltitudeLimitsEnabled(bool enable)
DBUS interface function.
void enableHaLimits()
enableHaLimits calls enableHourAngleLimits(true).
Q_INVOKABLE Q_SCRIPTABLE bool park()
DBUS interface function.
Q_INVOKABLE Q_SCRIPTABLE bool sync(double RA, double DEC)
DBUS interface function.
bool addLocationSource(const QSharedPointer< ISD::GenericDevice > &device)
addLocationSource Add an INDI driver that can be used for a master location source
void syncLocationSource()
syncLocationSource When location source changes, update all INDI drivers to this location source
void updateProperty(INDI::Property prop)
updateProperty Update properties under watch in the mount module
void doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs)
Send a guide pulse to the telescope.
Q_INVOKABLE Q_SCRIPTABLE bool resetModel()
DBUS interface function.
Q_INVOKABLE Q_SCRIPTABLE bool gotoTarget(const QString &target)
DBUS interface function.
void syncTimeSource()
syncTimeSource When time source changes, update all INDI drivers to this time source
void setTargetName(const QString &name)
setTargetName Set the name of the current target
Q_INVOKABLE void setTrackEnabled(bool enabled)
DBUS interface function.
void disableHaLimits()
disableAltLimits calls enableHourAngleLimits(false).
Q_SCRIPTABLE double initialHA()
DBUS interface function.
Q_SCRIPTABLE void setAutoParkStartup(QTime startup)
setAutoParkStartup Set time when automatic parking is activated.
void paaStageChanged(int stage)
React upon status changes of the polar alignment - mainly to avoid meridian flips happening during po...
void setMeridianFlipValues(bool activate, double degrees)
set meridian flip activation and hours
void syncTelescopeInfo()
syncTelescopeInfo Update telescope information to reflect any property changes
void syncAxisReversed(INDI_EQ_AXIS axis, bool reversed)
syncAxisReversed Update Mount Control GUI on the reverse motion toggled state.
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...
void registerNewModule(const QString &name)
registerNewModule Register an Ekos module as it arrives via DBus and create the appropriate DBus inte...
Q_INVOKABLE Q_SCRIPTABLE bool unpark()
DBUS interface function.
double hourAngle
Mount::hourAngle.
bool addTimeSource(const QSharedPointer< ISD::GenericDevice > &device)
addTimeSource Add an INDI driver that can be used for a master time source
void newTargetName(const QString &name)
The mount has finished the slew to a new target.
Q_INVOKABLE Q_SCRIPTABLE bool syncTarget(const QString &target)
DBUS interface function.
void stopTimers()
stopTimers Need to stop update timers when profile is disconnected but due to timing and race conditi...
Q_SCRIPTABLE Q_NOREPLY void setHourAngleLimit(double limit)
DBUS interface function.
void newStatus(ISD::Mount::Status status)
Change in the mount status.
Q_INVOKABLE Q_SCRIPTABLE bool abort()
DBUS interface function.
Q_SCRIPTABLE SkyPoint currentTarget()
DBUS interface function.
void updateLog(int messageID)
updateLog Update mount module log to include any messages arriving for the telescope driver
bool setMount(ISD::Mount *device)
addMount Add a new Mount device
QSharedPointer< MeridianFlipState > getMeridianFlipState() const
getMeridianFlipState
Q_SCRIPTABLE Q_NOREPLY void setAltitudeLimits(QList< double > limits)
DBUS interface function.
Q_SCRIPTABLE void setHourAngleLimitEnabled(bool enable)
DBUS interface function.
void enableHourAngleLimits(bool enable)
enableHourAngleLimits Enable or disable hour angle limits
void suspendAltLimits()
suspendAltLimits calls enableAltitudeLimits(false).
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...
Q_INVOKABLE Q_SCRIPTABLE bool slew(double RA, double DEC)
DBUS interface function.
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).
Q_SCRIPTABLE void setAutoParkEnabled(bool enable)
setAutoParkEnabled Toggle Auto Park
INDI::PropertyView< ISwitch > * getSwitch(const QString &name) const
device handle controlling Mounts.
void stopTimers()
stopTimers Stop timers to prevent timing race condition when device is unavailable and timer is still...
void newTarget(SkyPoint ¤tCoords)
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.
Q_INVOKABLE QAction * action(const QString &name) const
static void beep(const QString &reason=QString())
const KStarsDateTime & lt() const
SkyMapComposite * skyComposite()
static KStars * Instance()
virtual KActionCollection * actionCollection() const
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
The sky coordinates of a point in the sky.
const CachingDms & dec() const
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
const CachingDms & ra() const
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
void setDec0(dms d)
Sets Dec0, the catalog Declination.
SkyPoint catalogueCoord(long double jdf)
Computes the J2000.0 catalogue coordinates for this SkyPoint using the epoch removing aberration,...
An angle, stored as degrees, but expressible in many ways.
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
const double & Degrees() const
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.
QString name(GameStandardAction id)
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
void activated(int index)
void currentIndexChanged(int index)
void setCurrentText(const QString &text)
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 setValue(double val)
void valueChanged(double d)
void append(QList< T > &&value)
iterator erase(const_iterator begin, const_iterator end)
iterator insert(const_iterator before, parameter_type value)
T value(qsizetype i) const const
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
T qobject_cast(QObject *object)
QObject * sender() const const
QString number(double n, char format, int precision)
QByteArray toLatin1() const const
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)
bool isValid() const const
void setValue(QVariant &&value)
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