13#include <knotification.h>
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?"),
104 m_Mount->clearParking();
105 m_Mount->setConfig(PURGE_CONFIG);
116 m_AltitudeLimitEnabled = toggled;
125 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
129 connect(mf_state.
get(), &MeridianFlipState::newMeridianFlipMountStatusText, meridianFlipStatusWidget,
130 &MeridianFlipStatusWidget::setStatus);
141 stopTimerB->setEnabled(
false);
143 if (parkEveryDay->isChecked())
144 startTimerB->animateClick();
146 m_ControlPanel.
reset(
new MountControlPanel());
149 connect(m_ControlPanel.
get(), &MountControlPanel::newSlewRate,
this, &Mount::setSlewRate);
154 connect(m_ControlPanel.
get(), &MountControlPanel::updownReversed,
this, &Mount::setUpDownReversed);
155 connect(m_ControlPanel.
get(), &MountControlPanel::leftrightReversed,
this, &Mount::setLeftRightReversed);
156 connect(m_ControlPanel.
get(), &MountControlPanel::center,
this, &Mount::centerMount);
159 connect(mountMotion, &MountMotionWidget::newSlewRate,
this, &Mount::setSlewRate);
161 connect(mountMotion, &MountMotionWidget::updownReversed,
this, &Mount::setUpDownReversed);
162 connect(mountMotion, &MountMotionWidget::leftrightReversed,
this, &Mount::setLeftRightReversed);
165 connect(mountPosition, &MountPositionWidget::J2000Enabled, mountTarget, &MountTargetWidget::setJ2000Enabled);
174 for (
auto &button : qButtons)
175 button->setAutoDefault(
false);
177 loadGlobalSettings();
180 setupOpticalTrainManager();
185 autoParkTimer.
stop();
188void Mount::setupParkUI()
190 if (m_Mount ==
nullptr)
193 if (m_Mount->canPark())
195 switch(m_Mount->parkStatus())
197 case ISD::PARK_PARKED:
198 parkingLabel->setText(
"Parked");
200 case ISD::PARK_PARKING:
201 parkingLabel->setText(
"Parking");
203 case ISD::PARK_UNPARKING:
204 parkingLabel->setText(
"Unparking");
206 case ISD::PARK_UNPARKED:
207 parkingLabel->setText(
"Unparked");
209 case ISD::PARK_ERROR:
210 parkingLabel->setText(
"Park Error");
212 case ISD::PARK_UNKNOWN:
213 parkingLabel->setText(
"Park Status Unknown");
216 parkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_UNPARKED);
217 unparkB->setEnabled(m_Mount->parkStatus() == ISD::PARK_PARKED);
221 parkB->setEnabled(
false);
222 unparkB->setEnabled(
false);
223 parkingLabel->setText(
"");
229 if (device && device == m_Mount)
236 m_Mount->
disconnect(m_Mount,
nullptr,
this,
nullptr);
242 connect(m_Mount, &ISD::ConcreteDevice::Connected,
this, [
this]()
246 connect(m_Mount, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
249 opticalTrainCombo->setEnabled(
true);
250 trainLabel->setEnabled(
true);
256 mainLayout->setEnabled(
true);
259 mf_state->setMountConnected(device !=
nullptr);
266 connect(m_Mount, &ISD::Mount::slewRateChanged,
this, &Mount::slewRateChanged);
267 connect(m_Mount, &ISD::Mount::pierSideChanged,
this, &Mount::pierSideChanged);
269 connect(m_Mount, &ISD::Mount::Disconnected,
this, [
this]()
271 m_ControlPanel->hide();
273 connect(m_Mount, &ISD::Mount::newParkStatus,
this, [&](ISD::ParkStatus status)
275 m_ParkStatus = status;
276 emit newParkStatus(status);
282 if (status == ISD::PARK_UNPARKED && parkEveryDay->isChecked() && autoParkTimer.
isActive() ==
false)
283 startTimerB->animateClick();
287 if (m_Mount->isReady())
289 if (enableAltitudeLimits->isChecked())
290 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value(), enableAltitudeLimitsTrackingOnly->isChecked());
292 m_Mount->setAltLimits(-91, +91,
false);
297 m_Status = m_Mount->status();
300 m_ParkStatus = m_Mount->parkStatus();
301 emit newParkStatus(m_ParkStatus);
307 connect(m_Mount, &ISD::Mount::ready,
this, [
this]()
309 if (enableAltitudeLimits->isChecked())
310 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value(), enableAltitudeLimitsTrackingOnly->isChecked());
312 m_Mount->setAltLimits(-91, +91,
false);
317 m_Status = m_Mount->status();
320 m_ParkStatus = m_Mount->parkStatus();
321 emit newParkStatus(m_ParkStatus);
332 for (
auto &oneSource : m_TimeSources)
334 if (oneSource->getDeviceName() == device->getDeviceName())
338 m_TimeSources.append(device);
340 timeSource->blockSignals(
true);
342 timeSource->addItem(
"KStars");
344 m_TimeSourcesList.
clear();
345 m_TimeSourcesList.
append(
"KStars");
347 for (
auto &oneSource : m_TimeSources)
349 auto name = oneSource->getDeviceName();
351 m_TimeSourcesList.
append(name);
352 timeSource->addItem(name);
354 if (name == Options::timeSource())
357 auto refreshGPS = oneSource->getProperty(
"GPS_REFRESH");
360 auto sw = refreshGPS.getSwitch();
361 sw->at(0)->setState(ISS_ON);
362 oneSource->sendNewProperty(refreshGPS);
367 timeSource->setCurrentText(Options::timeSource());
368 timeSource->blockSignals(
false);
375 for (
auto &oneSource : m_LocationSources)
377 if (oneSource->getDeviceName() == device->getDeviceName())
381 m_LocationSources.append(device);
382 locationSource->blockSignals(
true);
383 locationSource->clear();
384 locationSource->addItem(
"KStars");
386 m_LocationSourcesList.
clear();
387 m_LocationSourcesList.
append(
"KStars");
389 for (
auto &oneSource : m_LocationSources)
391 auto name = oneSource->getDeviceName();
392 locationSource->addItem(name);
393 m_LocationSourcesList.
append(name);
395 if (name == Options::locationSource())
397 auto refreshGPS = oneSource->getProperty(
"GPS_REFRESH");
400 auto sw = refreshGPS.getSwitch();
401 sw->at(0)->setState(ISS_ON);
402 oneSource->sendNewProperty(refreshGPS);
407 locationSource->setCurrentText(Options::locationSource());
408 locationSource->blockSignals(
false);
414 if (m_Mount && m_Mount->getDeviceName() == device->getDeviceName())
417 m_ControlPanel->hide();
418 qCDebug(KSTARS_EKOS_MOUNT) <<
"Removing mount driver" << m_Mount->getDeviceName();
422 m_TimeSources.
erase(std::remove_if(m_TimeSources.
begin(), m_TimeSources.
end(), [device](
const auto & oneSource)
424 return device->getDeviceName() == oneSource->getDeviceName();
425 }), m_TimeSources.
end());
427 m_LocationSources.
erase(std::remove_if(m_LocationSources.
begin(), m_LocationSources.
end(), [device](
const auto & oneSource)
429 return device->getDeviceName() == oneSource->getDeviceName();
430 }), m_LocationSources.
end());
435 if (!m_Mount || m_Mount->isConnected() ==
false)
438 auto svp = m_Mount->
getSwitch(
"TELESCOPE_SLEW_RATE");
440 mountMotion->syncSpeedInfo(svp);
441 m_ControlPanel->mountMotion->syncSpeedInfo(svp);
443 if (m_Mount->canPark())
448 m_ControlPanel->parkButtonObject->setEnabled(!m_Mount->isParked());
449 m_ControlPanel->unparkButtonObject->setEnabled(m_Mount->isParked());
456 m_ControlPanel->parkButtonObject->setEnabled(
false);
457 m_ControlPanel->unparkButtonObject->setEnabled(
false);
460 m_ControlPanel->setProperty(
"isJ2000", m_Mount->isJ2000());
464 svp = m_Mount->
getSwitch(
"TELESCOPE_TRACK_STATE");
467 trackingLabel->setEnabled(
true);
468 trackOnB->setEnabled(
true);
469 trackOffB->setEnabled(
true);
470 trackOnB->disconnect();
471 trackOffB->disconnect();
474 m_Mount->setTrackEnabled(
true);
478#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0)
480 i18n(
"Are you sure you want to turn off mount tracking?"),
481 i18n(
"Mount Tracking"),
484 "turn_off_mount_tracking_dialog") == KMessageBox::ButtonCode::PrimaryAction)
485 m_Mount->setTrackEnabled(
false);
488 i18n(
"Are you sure you want to turn off mount tracking?"),
489 i18n(
"Mount Tracking"),
490 KStandardGuiItem::yes(),
491 KStandardGuiItem::no(),
492 "turn_off_mount_tracking_dialog") == KMessageBox::Yes)
493 m_Mount->setTrackEnabled(
false);
499 trackingLabel->setEnabled(
false);
500 trackOnB->setChecked(
false);
501 trackOnB->setEnabled(
false);
502 trackOffB->setChecked(
false);
503 trackOffB->setEnabled(
false);
506 m_ControlPanel->mountMotion->leftRightCheckObject->setProperty(
"checked", m_Mount->isReversed(AXIS_RA));
507 m_ControlPanel->mountMotion->upDownCheckObject->setProperty(
"checked", m_Mount->isReversed(AXIS_DE));
512 if (name ==
"Capture")
514 hasCaptureInterface =
true;
515 mf_state->setHasCaptureInterface(
true);
521 if (m_Mount ==
nullptr || !m_Mount->isConnected())
524 telescopeCoord = position;
527 mountPosition->updateTelescopeCoords(position, ha);
528 m_ControlPanel->mountPosition->updateTelescopeCoords(position, ha);
531 if (m_Status == ISD::Mount::MOUNT_PARKED && m_Status == m_Mount->status())
534 double currentAlt = telescopeCoord.altRefracted().Degrees();
536 if (minimumAltLimit->isEnabled() && (currentAlt < minimumAltLimit->value() || currentAlt > maximumAltLimit->value()) &&
537 (m_Mount->isTracking() || (!enableAltitudeLimitsTrackingOnly->isChecked() && m_Mount->isInMotion())))
539 if (currentAlt < minimumAltLimit->value())
542 if (currentAlt < m_LastAltitude && m_AbortAltDispatch == -1)
544 appendLogText(
i18n(
"Telescope altitude is below minimum altitude limit of %1. Aborting motion...",
547 m_Mount->setTrackEnabled(
false);
550 m_AbortAltDispatch++;
553 else if (currentAlt > m_LastAltitude && m_AbortAltDispatch == -1)
556 appendLogText(
i18n(
"Telescope altitude is above maximum altitude limit of %1. Aborting motion...",
559 m_Mount->setTrackEnabled(
false);
562 m_AbortAltDispatch++;
566 m_AbortAltDispatch = -1;
570 double haHours = rangeHA(ha.Hours());
576 if (maximumHaLimit->isEnabled())
579 double haLimit = maximumHaLimit->value();
580 bool haLimitReached =
false;
583 case ISD::Mount::PierSide::PIER_WEST:
584 haLimitReached = haHours > haLimit;
586 case ISD::Mount::PierSide::PIER_EAST:
587 haLimitReached = rangeHA(haHours + 12.0) > haLimit;
591 haLimitReached =
false;
595 qCDebug(KSTARS_EKOS_MOUNT) <<
"Ha: " << haHours <<
596 " haLimit " << haLimit <<
597 " " << ISD::Mount::pierSideStateString(m_Mount->pierSide()) <<
598 " haLimitReached " << (haLimitReached ?
"true" :
"false") <<
599 " lastHa " << m_LastHourAngle;
602 if (haLimitReached && (rangeHA(haHours - m_LastHourAngle) >= 0 ) &&
603 (m_AbortHADispatch == -1 ||
604 m_Mount->isInMotion()))
607 appendLogText(
i18n(
"Telescope hour angle is more than the maximum hour angle of %1. Aborting motion...",
610 m_Mount->setTrackEnabled(
false);
620 m_AbortHADispatch = -1;
622 m_LastAltitude = currentAlt;
623 m_LastHourAngle = haHours;
625 ISD::Mount::Status currentStatus = m_Mount->status();
626 if (m_Status != currentStatus)
628 qCDebug(KSTARS_EKOS_MOUNT) <<
"Mount status changed from " << m_Mount->statusString(m_Status)
629 <<
" to " << m_Mount->statusString(currentStatus);
633 m_ControlPanel->statusTextObject->setProperty(
"text", m_Mount->statusString(currentStatus));
634 m_Status = currentStatus;
639 m_ControlPanel->parkButtonObject->setEnabled(!m_Mount->isParked());
640 m_ControlPanel->unparkButtonObject->setEnabled(m_Mount->isParked());
644 a->
setChecked(currentStatus == ISD::Mount::MOUNT_TRACKING);
647 bool isTracking = (currentStatus == ISD::Mount::MOUNT_TRACKING);
648 if (trackOnB->isEnabled())
650 trackOnB->setChecked(isTracking);
651 trackOffB->setChecked(!isTracking);
655 pierSideLabel->setText(ISD::Mount::pierSideStateString(m_Mount->pierSide()));
660 QTime remainingTime(0, 0, 0);
662 countdownLabel->setText(remainingTime.
toString(
"hh:mm:ss"));
663 emit autoParkCountdownUpdated(countdownLabel->text());
669 if (prop.isNameMatch(
"EQUATORIAL_EOD_COORD") || prop.isNameMatch(
"EQUATORIAL_COORD"))
671 auto nvp = prop.getNumber();
679 case MeridianFlipState::MF_INITIATED:
680 if (nvp->s == IPS_BUSY && m_Mount !=
nullptr && m_Mount->isSlewing())
688 else if (prop.isNameMatch(
"TELESCOPE_SLEW_RATE"))
690 auto svp = prop.getSwitch();
691 mountMotion->updateSpeedInfo(svp);
692 m_ControlPanel->mountMotion->updateSpeedInfo(svp);
696bool Mount::setSlewRate(
int index)
699 return m_Mount->setSlewRate(index);
704void Mount::setUpDownReversed(
bool enabled)
706 Options::setUpDownReversed(
enabled);
708 m_Mount->setReversedEnabled(AXIS_DE,
enabled);
711void Mount::setLeftRightReversed(
bool enabled)
713 Options::setLeftRightReversed(
enabled);
715 m_Mount->setReversedEnabled(AXIS_RA,
enabled);
720 executeMeridianFlip->setChecked(activate);
721 meridianFlipOffsetDegrees->setValue(degrees);
732 if (stage != PolarAlignmentAssistant::PAH_IDLE)
733 mf_state->clearTargetPosition();
738 case PolarAlignmentAssistant::PAH_FIRST_CAPTURE:
739 case PolarAlignmentAssistant::PAH_FIRST_SOLVE:
740 if (mf_state->isEnabled())
742 appendLogText(
i18n(
"Meridian flip set inactive during polar alignment."));
743 mf_state->setEnabled(
false);
748 case PolarAlignmentAssistant::PAH_THIRD_CAPTURE:
749 case PolarAlignmentAssistant::PAH_THIRD_SOLVE:
750 case PolarAlignmentAssistant::PAH_STAR_SELECT:
751 case PolarAlignmentAssistant::PAH_REFRESH:
752 case PolarAlignmentAssistant::PAH_POST_REFRESH:
753 case PolarAlignmentAssistant::PAH_IDLE:
754 if (executeMeridianFlip->isChecked() && mf_state->isEnabled() ==
false)
756 appendLogText(
i18n(
"Polar alignment motions finished, meridian flip activated."));
757 mf_state->setEnabled(executeMeridianFlip->isChecked());
763void Mount::appendLogText(
const QString &text)
765 m_LogText.
insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
766 KStarsData::Instance()->lt().toString(
"yyyy-MM-ddThh:mm:ss"), text));
768 qCInfo(KSTARS_EKOS_MOUNT) << text;
775 if (m_Mount ==
nullptr)
778 auto message = m_Mount->getMessage(messageID);
779 m_LogText.
insert(0,
i18nc(
"Message shown in Ekos Mount module",
"%1", message));
781 emit newLog(message);
784void Mount::clearLog()
792 if (m_Mount ==
nullptr || !m_Mount->isConnected())
797 m_Mount->MoveNS(
static_cast<ISD::Mount::VerticalMotion
>(NS),
798 static_cast<ISD::Mount::MotionCommand
>(command));
803 m_Mount->MoveWE(
static_cast<ISD::Mount::HorizontalMotion
>(WE),
804 static_cast<ISD::Mount::MotionCommand
>(command));
809void Mount::doPulse(GuideDirection ra_dir,
int ra_msecs, GuideDirection dec_dir,
int dec_msecs)
811 if (m_Mount ==
nullptr || !m_Mount->isConnected())
814 m_Mount->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
819 if (m_Mount ==
nullptr)
822 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value(), enableAltitudeLimitsTrackingOnly->isChecked());
827 minAltLabel->setEnabled(enable);
828 maxAltLabel->setEnabled(enable);
830 minimumAltLimit->setEnabled(enable);
831 maximumAltLimit->setEnabled(enable);
833 enableAltitudeLimitsTrackingOnly->setEnabled(enable);
838 m_Mount->setAltLimits(minimumAltLimit->value(), maximumAltLimit->value(), enableAltitudeLimitsTrackingOnly->isChecked());
840 m_Mount->setAltLimits(-91, +91,
false);
848 if (m_AltitudeLimitEnabled && minimumAltLimit->isEnabled() ==
false)
855 m_AltitudeLimitEnabled = enableAltitudeLimits->isChecked();
861 maxHaLabel->setEnabled(enable);
862 maximumHaLimit->setEnabled(enable);
868 if (m_HourAngleLimitEnabled && maximumHaLimit->isEnabled() ==
false)
874 m_HourAngleLimitEnabled = enableHaLimit->isChecked();
883 limits.
append(minimumAltLimit->value());
884 limits.
append(maximumAltLimit->value());
891 minimumAltLimit->setValue(limits[0]);
892 maximumAltLimit->setValue(limits[1]);
897 enableAltitudeLimits->setChecked(enable);
900bool Mount::altitudeLimitsEnabled()
902 return enableAltitudeLimits->isChecked();
905double Mount::hourAngleLimit()
907 return maximumHaLimit->
value();
912 maximumHaLimit->setValue(limit);
917 enableHaLimit->setChecked(enable);
920bool Mount::hourAngleLimitEnabled()
922 return enableHaLimit->isChecked();
925void Mount::setJ2000Enabled(
bool enabled)
927 m_ControlPanel->setJ2000Enabled(
enabled);
928 mountPosition->setJ2000Enabled(
enabled);
935 if (
object !=
nullptr)
937 object->updateCoordsNow(KStarsData::Instance()->updateNum());
938 return slew(object->ra().Hours(), object->dec().Degrees());
946 return slew(target.ra().Hours(), target.dec().Degrees());
951 mountTarget->setTargetName(name);
952 m_ControlPanel->setTargetName(name);
959 if (
object !=
nullptr)
961 object->updateCoordsNow(KStarsData::Instance()->updateNum());
962 return sync(object->
ra().Hours(), object->
dec().Degrees());
970 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
974 targetPosition =
new SkyPoint(RA, DEC);
975 SkyPoint J2000Coord(targetPosition->ra(), targetPosition->dec());
976 J2000Coord.catalogueCoord(KStarsData::Instance()->ut().djd());
977 targetPosition->setRA0(J2000Coord.ra());
978 targetPosition->setDec0(J2000Coord.dec());
980 mf_state->setTargetPosition(targetPosition);
981 mf_state->resetMeridianFlip();
983 m_ControlPanel->setTargetPosition(
new SkyPoint(RA, DEC));
984 mountTarget->setTargetPosition(
new SkyPoint(RA, DEC));
986 qCDebug(KSTARS_EKOS_MOUNT) <<
"Slewing to RA=" <<
987 targetPosition->ra().toHMSString() <<
988 "DEC=" << targetPosition->dec().toDMSString();
989 qCDebug(KSTARS_EKOS_MOUNT) <<
"Initial HA " <<
initialHA() <<
", flipDelayHrs " << mf_state->getFlipDelayHrs() <<
990 "MFStatus " << MeridianFlipState::meridianFlipStatusString(mf_state->getMeridianFlipMountState());
993 return(m_Mount->Slew(targetPosition));
999 if (targetPosition !=
nullptr)
1000 return *targetPosition;
1002 qCWarning(KSTARS_EKOS_MOUNT) <<
"No target position defined!";
1004 return telescopeCoord;
1009 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
1012 return m_Mount->Sync(RA, DEC);
1017 if (m_Mount ==
nullptr)
1020 return m_Mount->abort();
1023IPState Mount::slewStatus()
1025 if (m_Mount ==
nullptr)
1028 return m_Mount->getState(
"EQUATORIAL_EOD_COORD");
1033 double ra {0},
dec {0};
1037 m_Mount->getEqCoords(&ra, &dec);
1048 coords.
append(telescopeCoord.az().Degrees());
1049 coords.
append(telescopeCoord.alt().Degrees());
1060 dms lst = KStarsData::Instance()->
geo()->GSTtoLST(KStarsData::Instance()->clock()->utc().gst());
1061 dms ha(lst.
Degrees() - telescopeCoord.ra().Degrees());
1062 return rangeHA(ha.Hours());
1065bool Mount::canPark()
1067 if (m_Mount ==
nullptr)
1070 return m_Mount->canPark();
1075 if (m_Mount ==
nullptr || m_Mount->canPark() ==
false)
1078 return m_Mount->park();
1083 if (m_Mount ==
nullptr || m_Mount->canPark() ==
false)
1086 return m_Mount->unpark();
1090void Mount::toggleMountToolBox()
1092 if (m_ControlPanel->isVisible())
1094 m_ControlPanel->hide();
1101 m_ControlPanel->show();
1112 return m_ControlPanel->mountTarget->raDecToAzAlt(qsRA, qsDec);
1115bool Mount::raDecToHaDec(
QString qsRA)
1117 return m_ControlPanel->mountTarget->raDecToHaDec(qsRA);
1122 return m_ControlPanel->mountTarget->azAltToRaDec(qsAz, qsAlt);
1127 return m_ControlPanel->mountTarget->azAltToHaDec(qsAz, qsAlt);
1130bool Mount::haDecToRaDec(
QString qsHA)
1132 return m_ControlPanel->mountTarget->haDecToRaDec(qsHA);
1137 return m_ControlPanel->mountTarget->haDecToAzAlt(qsHA, qsDec);
1142void Mount::centerMount()
1150 if (m_Mount ==
nullptr)
1153 if (m_Mount->hasAlignmentModel() ==
false)
1156 if (m_Mount->clearAlignmentModel())
1158 appendLogText(
i18n(
"Alignment Model cleared."));
1162 appendLogText(
i18n(
"Failed to clear Alignment Model."));
1167void Mount::setScopeStatus(ISD::Mount::Status status)
1169 if (m_Status != status)
1171 m_ControlPanel->statusTextObject->setProperty(
"text", m_Mount->statusString(status));
1188int Mount::slewRate()
1190 if (m_Mount ==
nullptr)
1193 return m_Mount->getSlewRate();
1225bool Mount::autoParkEnabled()
1240 parkEveryDay->setChecked(
enabled);
1245 autoParkTime->setTime(startup);
1248bool Mount::meridianFlipEnabled()
1250 return executeMeridianFlip->isChecked();
1253double Mount::meridianFlipValue()
1255 return meridianFlipOffsetDegrees->value();
1260 autoParkTimer.
stop();
1265void Mount::startParkTimer()
1267 if (m_Mount ==
nullptr || m_ParkStatus == ISD::PARK_UNKNOWN)
1270 if (m_Mount->isParked())
1272 appendLogText(
i18n(
"Mount already parked."));
1276 auto parkTime = autoParkTime->time();
1278 qCDebug(KSTARS_EKOS_MOUNT) <<
"Parking time is" << parkTime.toString();
1279 QDateTime currentDateTime = KStarsData::Instance()->
lt();
1280 QDateTime parkDateTime(currentDateTime);
1282 parkDateTime.setTime(parkTime);
1283 qint64 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1284 qCDebug(KSTARS_EKOS_MOUNT) <<
"Until parking time:" << parkMilliSeconds <<
"ms or" << parkMilliSeconds / (60 * 60 * 1000)
1286 if (parkMilliSeconds > 0)
1288 qCDebug(KSTARS_EKOS_MOUNT) <<
"Added a day to parking time...";
1289 parkDateTime = parkDateTime.addDays(1);
1290 parkMilliSeconds = parkDateTime.msecsTo(currentDateTime);
1292 int hours =
static_cast<int>(parkMilliSeconds / (1000 * 60 * 60));
1296 if (parkEveryDay->isChecked() ==
false)
1297 appendLogText(
i18n(
"Parking time cannot be in the past."));
1302 parkMilliSeconds = std::abs(parkMilliSeconds);
1304 if (parkMilliSeconds > 24 * 60 * 60 * 1000)
1306 appendLogText(
i18n(
"Parking time must be within 24 hours of current time."));
1310 if (parkMilliSeconds > 12 * 60 * 60 * 1000)
1311 appendLogText(
i18n(
"Warning! Parking time is more than 12 hours away."));
1313 appendLogText(
i18n(
"Caution: do not use Auto Park while scheduler is active."));
1315 autoParkTimer.
setInterval(
static_cast<int>(parkMilliSeconds));
1316 autoParkTimer.
start();
1318 startTimerB->setEnabled(
false);
1319 stopTimerB->setEnabled(
true);
1322void Mount::stopParkTimer()
1324 autoParkTimer.
stop();
1325 countdownLabel->setText(
"00:00:00");
1326 emit autoParkCountdownUpdated(
"00:00:00");
1327 stopTimerB->setEnabled(
false);
1328 startTimerB->setEnabled(
true);
1331void Mount::startAutoPark()
1333 appendLogText(
i18n(
"Parking timer is up."));
1334 autoParkTimer.
stop();
1335 startTimerB->setEnabled(
true);
1336 stopTimerB->setEnabled(
false);
1337 countdownLabel->setText(
"00:00:00");
1338 emit autoParkCountdownUpdated(
"00:00:00");
1341 if (m_Mount->isParked() ==
false)
1343 appendLogText(
i18n(
"Starting auto park..."));
1351 if (axis == AXIS_RA)
1352 m_ControlPanel->mountMotion->leftRightCheckObject->setProperty(
"checked", reversed);
1354 m_ControlPanel->mountMotion->upDownCheckObject->setProperty(
"checked", reversed);
1357void Mount::setupOpticalTrainManager()
1359 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Mount::refreshOpticalTrain);
1362 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
1366 ProfileSettings::Instance()->setOneSetting(ProfileSettings::MountOpticalTrain,
1367 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
1368 refreshOpticalTrain();
1369 emit trainChanged();
1373void Mount::refreshOpticalTrain()
1375 opticalTrainCombo->blockSignals(
true);
1376 opticalTrainCombo->clear();
1377 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
1378 trainB->setEnabled(
true);
1380 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::MountOpticalTrain);
1384 auto id = trainID.
toUInt();
1387 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
1389 qCWarning(KSTARS_EKOS_MOUNT) <<
"Optical train doesn't exist for id" << id;
1390 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
1393 auto name = OpticalTrainManager::Instance()->name(
id);
1395 opticalTrainCombo->setCurrentText(name);
1397 auto mount = OpticalTrainManager::Instance()->getMount(name);
1400 auto scope = OpticalTrainManager::Instance()->getScope(name);
1401 opticalTrainCombo->setToolTip(scope[
"name"].
toString());
1404 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
1405 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Mount);
1406 if (settings.isValid())
1408 auto map = settings.toJsonObject().toVariantMap();
1409 if (map != m_Settings)
1412 setAllSettings(map);
1416 m_Settings = m_GlobalSettings;
1419 opticalTrainCombo->blockSignals(
false);
1425QVariantMap Mount::getAllSettings()
const
1427 QVariantMap settings;
1431 settings.insert(oneWidget->objectName(), oneWidget->currentText());
1435 settings.insert(oneWidget->objectName(), oneWidget->value());
1439 settings.insert(oneWidget->objectName(), oneWidget->value());
1443 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
1447 settings.insert(oneWidget->objectName(), oneWidget->time().toString());
1455void Mount::setAllSettings(
const QVariantMap &settings)
1459 disconnectSyncSettings();
1461 for (
auto &name : settings.keys())
1467 syncControl(settings, name, comboBox);
1475 syncControl(settings, name, doubleSpinBox);
1483 syncControl(settings, name, spinBox);
1491 syncControl(settings, name, checkbox);
1499 syncControl(settings, name, timeEdit);
1505 for (
auto &key : settings.keys())
1507 auto value = settings[key];
1509 Options::self()->setProperty(key.toLatin1(), value);
1510 Options::self()->save();
1512 m_Settings[key] = value;
1513 m_GlobalSettings[key] = value;
1516 emit settingsUpdated(getAllSettings());
1519 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1520 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1523 connectSyncSettings();
1529bool Mount::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget * widget)
1541 const int value = settings[key].toInt(&ok);
1550 const double value = settings[key].toDouble(&ok);
1559 const bool value = settings[key].toBool();
1566 const bool value = settings[key].toBool();
1568 pRadioButton->
click();
1574 const QString value = settings[key].toString();
1580 const QString value = settings[key].toString();
1591void Mount::syncSettings()
1606 value = dsb->
value();
1612 value = sb->
value();
1624 m_Settings.remove(key);
1637 value = timeEdit->
time().toString();
1641 Options::self()->setProperty(key.
toLatin1(), value);
1642 m_Settings[key] = value;
1643 m_GlobalSettings[key] = value;
1645 m_DebounceTimer.
start();
1651void Mount::settleSettings()
1653 Options::self()->save();
1654 emit settingsUpdated(getAllSettings());
1656 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
1657 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Mount, m_Settings);
1663void Mount::loadGlobalSettings()
1668 QVariantMap settings;
1672 if (oneWidget->objectName() ==
"opticalTrainCombo")
1675 key = oneWidget->objectName();
1676 value = Options::self()->property(key.
toLatin1());
1677 if (value.
isValid() && oneWidget->count() > 0)
1679 oneWidget->setCurrentText(value.
toString());
1680 settings[key] = value;
1687 key = oneWidget->objectName();
1688 value = Options::self()->property(key.
toLatin1());
1691 oneWidget->setValue(value.
toDouble());
1692 settings[key] = value;
1699 key = oneWidget->objectName();
1700 value = Options::self()->property(key.
toLatin1());
1703 oneWidget->setValue(value.
toInt());
1704 settings[key] = value;
1711 key = oneWidget->objectName();
1712 value = Options::self()->property(key.
toLatin1());
1715 oneWidget->setChecked(value.
toBool());
1716 settings[key] = value;
1721 mf_state->setEnabled(Options::executeMeridianFlip());
1722 mf_state->setOffset(Options::meridianFlipOffsetDegrees());
1724 m_GlobalSettings = m_Settings = settings;
1730void Mount::connectSyncSettings()
1760void Mount::disconnectSyncSettings()
1789void Mount::connectSettings()
1791 connectSyncSettings();
1796 mf_state.
get(), &MeridianFlipState::setOffset);
1797 connect(
this, &Mount::newParkStatus, mf_state.
get(), &MeridianFlipState::setMountParkStatus);
1801 m_Mount->Slew(&pos, (m_Mount->canFlip() && Options::forcedFlip()));
1811void Mount::disconnectSettings()
1813 disconnectSyncSettings();
1818 mf_state.
get(), &MeridianFlipState::setOffset);
1819 disconnect(
this, &Mount::newParkStatus, mf_state.
get(), &MeridianFlipState::setMountParkStatus);
1820 disconnect(mf_state.
get(), &MeridianFlipState::slewTelescope,
nullptr,
nullptr);
1828 return mf_state->initialPositionHA();
1836 appendLogText(
i18n(
"Updating master time source to %1.", Options::locationSource()));
1844 auto name = Options::locationSource();
1845 auto it = std::find_if(m_LocationSources.
begin(), m_LocationSources.
end(), [name](
const auto & oneSource)
1847 return oneSource->getDeviceName() == name;
1849 if (it != m_LocationSources.
end())
1851 auto property = (*it)->getProperty(
"GPS_REFRESH");
1854 auto sw =
property.getSwitch();
1855 sw->at(0)->setState(ISS_ON);
1857 appendLogText(
i18n(
"Updating master location source to %1. Updating GPS...", name));
1861 property = (*it)->getProperty(
"GEOGRAPHIC_COORD");
1865 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
const CachingDms & ra() const
An angle, stored as degrees, but expressible in many ways.
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.
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
QString name(StandardAction id)
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
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