9#include "guideadaptor.h"
11#include "ksmessagebox.h"
12#include "kstarsdata.h"
13#include "ksnotification.h"
14#include "opscalibration.h"
19#include "indi/indiguider.h"
20#include "indi/indiadaptiveoptics.h"
21#include "auxiliary/QProgressIndicator.h"
22#include "ekos/auxiliary/opticaltrainmanager.h"
23#include "ekos/auxiliary/profilesettings.h"
24#include "ekos/auxiliary/opticaltrainsettings.h"
25#include "ekos/auxiliary/darklibrary.h"
26#include "externalguide/linguider.h"
27#include "externalguide/phd2.h"
28#include "fitsviewer/fitsdata.h"
29#include "fitsviewer/fitsview.h"
30#include "fitsviewer/fitsviewer.h"
31#include "internalguide/internalguider.h"
33#include "guidegraph.h"
34#include "guidestatewidget.h"
35#include "manualpulse.h"
36#include "ekos/auxiliary/darkprocessor.h"
38#include <KConfigDialog>
40#include <basedevice.h>
41#include <ekos_guide_debug.h>
43#include "ui_manualdither.h"
47#define CAPTURE_TIMEOUT_THRESHOLD 30000
51Guide::Guide() : QWidget()
54 internalGuider =
new InternalGuider();
58 opsGuide =
new OpsGuide();
61 connect(opsGuide, &OpsGuide::settingsUpdated,
this, [
this]()
63 onThresholdChanged(Options::guideAlgorithm());
64 configurePHD2Camera();
65 configSEPMultistarOptions();
69 opsCalibration =
new OpsCalibration(internalGuider);
70 page = dialog->
addPage(opsCalibration,
i18n(
"Calibration"));
73 opsDither =
new OpsDither();
77 opsGPG =
new OpsGPG(internalGuider);
78 page = dialog->
addPage(opsGPG,
i18n(
"GPG RA Guider"));
85 qRegisterMetaType<Ekos::GuideState>(
"Ekos::GuideState");
86 qDBusRegisterMetaType<Ekos::GuideState>();
87 new GuideAdaptor(
this);
95 internalGuider->setGuideView(m_GuideView);
102 controlLayout->addWidget(pi, 1, 2, 1, 1);
104 showFITSViewerB->setIcon(
109 guideAutoScaleGraphB->setIcon(
114 guideSaveDataB->setIcon(
119 guideDataClearB->setIcon(
126 guideZoomInXB->setText(
"+");
132 guideZoomOutXB->setText(
"-");
137 focalLengthIcon->setPixmap(
QIcon::fromTheme(
"gnumeric-formulaguru").pixmap(32, 32));
139 reducerIcon->setPixmap(
QIcon::fromTheme(
"format-align-vertical-bottom").pixmap(32, 32));
140 FOVIcon->setPixmap(
QIcon::fromTheme(
"timeline-use-zone-on").pixmap(32, 32));
141 focalRatioIcon->setPixmap(
QIcon::fromTheme(
"node-type-symmetric").pixmap(32, 32));
146 exposureValues << 0.02 << 0.05 << 0.1 << 0.2 << 0.5 << 1 << 1.5 << 2 << 2.5 << 3 << 3.5 << 4 << 4.5 << 5 << 6 << 7 << 8 << 9
148 guideExposure->setRecommendedValues(exposureValues);
155 if(guiderType == GUIDE_PHD2)
157 setExternalGuiderBLOBEnabled(!Options::guideSubframe());
162 opsDither->kcfg_DitherTimeout->setEnabled(
false);
163 opsDither->kcfg_DitherThreshold->setEnabled(
false);
164 opsDither->kcfg_DitherMaxIterations->setEnabled(!Options::ditherWithOnePulse());
168 resetNonGuidedDither();
173 for (
auto &button : qButtons)
174 button->setAutoDefault(
false);
178 m_DarkProcessor =
new DarkProcessor(
this);
179 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &Ekos::Guide::appendLogText);
180 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, [
this](
bool completed)
182 if (completed != guideDarkFrame->isChecked())
183 setDarkFrameEnabled(completed);
184 m_GuideView->setProperty(
"suspended",
false);
187 m_GuideView->rescale(ZOOM_KEEP_LEVEL);
188 m_GuideView->updateFrame();
190 m_GuideView->updateFrame();
191 setCaptureComplete();
194 m_ManaulPulse =
new ManualPulse(
this);
195 connect(m_ManaulPulse, &ManualPulse::newSinglePulse,
this, &Guide::sendSinglePulse);
198 m_ManaulPulse->reset();
199 m_ManaulPulse->show();
202 loadGlobalSettings();
205 setupOpticalTrainManager();
210 delete m_GuiderInstance;
213void Guide::handleHorizontalPlotSizeChange()
215 targetPlot->handleHorizontalPlotSizeChange();
216 calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0);
217 calibrationPlot->replot();
220void Guide::handleVerticalPlotSizeChange()
222 targetPlot->handleVerticalPlotSizeChange();
223 calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0);
224 calibrationPlot->replot();
227void Guide::guideAfterMeridianFlip()
231 m_GuideView->setTrackingBoxEnabled(
false);
232 starCenter = QVector3D();
234 if (Options::resetGuideCalibration())
238 if (Options::gPGEnabled())
239 m_GuiderInstance->resetGPG();
246 if (
event->oldSize().width() != -1)
248 if (
event->oldSize().width() != size().width())
249 handleHorizontalPlotSizeChange();
250 else if (
event->oldSize().height() != size().height())
251 handleVerticalPlotSizeChange();
259void Guide::buildTarget()
261 targetPlot->buildTarget(guiderAccuracyThreshold->value());
264void Guide::clearGuideGraphs()
270void Guide::clearCalibrationGraphs()
272 calibrationPlot->graph(GuideGraph::G_RA)->data()->clear();
273 calibrationPlot->graph(GuideGraph::G_DEC)->data()->clear();
274 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear();
275 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear();
276 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->data()->clear();
277 calRALabel->setVisible(
false);
278 calRAArrow->setVisible(
false);
279 calDECLabel->setVisible(
false);
280 calDECArrow->setVisible(
false);
281 calibrationPlot->replot();
284void Guide::slotAutoScaleGraphs()
286 driftGraph->zoomX(defaultXZoomLevel);
288 driftGraph->autoScaleGraphs();
289 targetPlot->autoScaleGraphs(guiderAccuracyThreshold->value());
291 calibrationPlot->rescaleAxes();
292 calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0);
293 calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0);
294 calibrationPlot->replot();
297void Guide::guideHistory()
299 int sliderValue = guideSlider->value();
300 latestCheck->setChecked(sliderValue == guideSlider->maximum() - 1 || sliderValue == guideSlider->maximum());
301 double ra = driftGraph->graph(GuideGraph::G_RA)->dataMainValue(sliderValue);
302 double de = driftGraph->graph(GuideGraph::G_DEC)->dataMainValue(sliderValue);
303 driftGraph->guideHistory(sliderValue, graphOnLatestPt);
305 targetPlot->showPoint(ra, de);
308void Guide::setLatestGuidePoint(
bool isChecked)
310 graphOnLatestPt = isChecked;
311 driftGraph->setLatestGuidePoint(isChecked);
312 targetPlot->setLatestGuidePoint(isChecked);
315 guideSlider->setValue(guideSlider->maximum());
320 guideExposure->setRecommendedValues(values);
321 return guideExposure->getRecommendedValuesString();
326 if (m_Camera && device == m_Camera)
333 m_Camera->disconnect(
this);
339 connect(m_Camera, &ISD::Camera::Connected,
this, [
this]()
341 controlGroupBox->setEnabled(
true);
343 connect(m_Camera, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
345 controlGroupBox->setEnabled(
false);
349 controlGroupBox->setEnabled(m_Camera && m_Camera->isConnected());
355 if(guiderType != GUIDE_INTERNAL)
356 m_Camera->setBLOBEnabled(
false);
359 configurePHD2Camera();
362 if (captureTimeout.isActive() && m_State >= Ekos::GUIDE_CAPTURE)
368void Guide::configurePHD2Camera()
372 if(guiderType != GUIDE_PHD2)
379 if(!phd2Guider->isConnected())
383 if(phd2Guider->getCurrentCamera().isEmpty())
385 phd2Guider->requestCurrentEquipmentUpdate();
391 QString currentPHD2CameraName =
"None";
392 if(m_Camera && phd2Guider->getCurrentCamera().contains(m_Camera->getDeviceName()))
395 currentPHD2CameraName = (phd2Guider->getCurrentCamera());
401 if(m_LastPHD2CameraName == currentPHD2CameraName)
403 setExternalGuiderBLOBEnabled(!guideSubframe->isChecked());
409 setExternalGuiderBLOBEnabled(
false);
415 m_LastPHD2CameraName = currentPHD2CameraName;
417 m_LastPHD2MountName = phd2Guider->getCurrentMount();
420 phd2Guider->setCurrentCameraIsNotInEkos(m_Camera ==
nullptr);
422 if(phd2Guider->isCurrentCameraNotInEkos())
425 i18n(
"PHD2's current camera: %1, is not connected to Ekos. The PHD2 Guide Star Image will be received, but the full external guide frames cannot.",
426 phd2Guider->getCurrentCamera()));
427 guideSubframe->setEnabled(
false);
430 guideSubframe->setChecked(
true);
435 i18n(
"PHD2's current camera: %1, is connected to Ekos. You can select whether to use the full external guide frames or just receive the PHD2 Guide Star Image using the SubFrame checkbox.",
436 phd2Guider->getCurrentCamera()));
437 guideSubframe->setEnabled(
true);
439 guideSubframe->setChecked(guideSubframe->isChecked());
444 if (m_Mount && m_Mount == device)
451 m_Mount->disconnect(
this);
461 return m_Camera->getDeviceName();
470 if (!m_Camera || guiderType != GUIDE_INTERNAL)
478 case GUIDE_CONNECTED:
479 case GUIDE_DISCONNECTED:
480 case GUIDE_CALIBRATION_ERROR:
488 case GUIDE_STAR_SELECT:
489 case GUIDE_CALIBRATING:
490 case GUIDE_CALIBRATION_SUCCESS:
492 case GUIDE_SUSPENDED:
493 case GUIDE_REACQUIRE:
494 case GUIDE_DITHERING:
495 case GUIDE_MANUAL_DITHERING:
496 case GUIDE_DITHERING_ERROR:
497 case GUIDE_DITHERING_SUCCESS:
498 case GUIDE_DITHERING_SETTLE:
504 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
507 qCCritical(KSTARS_EKOS_GUIDE) <<
"Failed to retrieve active guide chip in camera";
511 if (targetChip->isCapturing())
514 if (guiderType != GUIDE_INTERNAL)
526void Ekos::Guide::checkUseGuideHead()
528 if (m_Camera ==
nullptr)
531 if (m_Camera->hasGuideHead() && Options::useGuideHead())
534 useGuideHead =
false;
536 opsGuide->kcfg_UseGuideHead->
setEnabled(m_Camera->hasGuideHead());
539void Guide::syncCameraInfo()
544 auto nvp = m_Camera->getNumber(useGuideHead ?
"GUIDER_INFO" :
"CCD_INFO");
548 auto np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_X");
550 ccdPixelSizeX = np->getValue();
552 np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_Y");
554 ccdPixelSizeY = np->getValue();
556 np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_Y");
558 ccdPixelSizeY = np->getValue();
564void Guide::syncTelescopeInfo()
566 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
572void Guide::updateGuideParams()
574 if (m_Camera ==
nullptr)
579 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
581 if (targetChip ==
nullptr)
583 appendLogText(
i18n(
"Connection to the guide CCD is lost."));
587 if (targetChip->getFrameType() != FRAME_LIGHT)
590 if(guiderType == GUIDE_INTERNAL)
591 guideBinning->setEnabled(targetChip->canBin());
593 int subBinX = 1, subBinY = 1;
594 if (targetChip->canBin())
596 int maxBinX, maxBinY;
598 targetChip->getBinning(&subBinX, &subBinY);
599 targetChip->getMaxBin(&maxBinX, &maxBinY);
602 if( guideBinIndex >= 0 && guideBinIndex < maxBinX && guideBinIndex < maxBinY )
604 subBinX = guideBinIndex + 1;
605 subBinY = guideBinIndex + 1;
608 guideBinIndex = subBinX - 1;
610 guideBinning->blockSignals(
true);
612 guideBinning->clear();
613 for (
int i = 1; i <= maxBinX; i++)
614 guideBinning->addItem(QString(
"%1x%2").arg(i).arg(i));
616 guideBinning->setCurrentIndex( guideBinIndex );
618 guideBinning->blockSignals(
false);
622 if (frameSettings.contains(targetChip) ==
false)
625 if (targetChip->getFrame(&
x, &
y, &w, &h))
629 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
630 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
631 auto subframed = guideSubframe->isChecked();
633 QVariantMap settings;
635 settings[
"x"] = subframed ?
x : minX;
636 settings[
"y"] = subframed ?
y : minY;
637 settings[
"w"] = subframed ? w : maxW;
638 settings[
"h"] = subframed ? h : maxH;
639 settings[
"binx"] = subBinX;
640 settings[
"biny"] = subBinY;
642 frameSettings[targetChip] = settings;
649 QVariantMap settings = frameSettings[targetChip];
650 settings[
"binx"] = subBinX;
651 settings[
"biny"] = subBinY;
652 frameSettings[targetChip] = settings;
655 if (ccdPixelSizeX != -1 && ccdPixelSizeY != -1 && m_FocalLength > 0)
657 auto effectiveFocaLength = m_Reducer * m_FocalLength;
658 m_GuiderInstance->setGuiderParams(ccdPixelSizeX, ccdPixelSizeY, m_Aperture, effectiveFocaLength);
659 emit guideChipUpdated(targetChip);
662 if (targetChip->getFrame(&
x, &
y, &w, &h))
664 m_GuiderInstance->setFrameParams(
x,
y, w, h, subBinX, subBinY);
667 l_Focal->setText(QString(
"%1mm").arg(m_FocalLength, 0,
'f', 0));
669 l_Aperture->setText(QString(
"%1mm").arg(m_Aperture, 0,
'f', 0));
672 l_Aperture->setText(
"DSLR");
673 l_Reducer->setText(QString(
"%1x").arg(
QString::number(m_Reducer,
'f', 2)));
675 if (m_FocalRatio > 0)
676 l_FbyD->setText(QString(
"F/%1").arg(m_FocalRatio, 0,
'f', 1));
677 else if (m_Aperture > 0)
678 l_FbyD->setText(QString(
"F/%1").arg(m_FocalLength / m_Aperture, 0,
'f', 1));
681 pixScaleX = 206264.8062470963552 * ccdPixelSizeX / 1000.0 / effectiveFocaLength;
682 pixScaleY = 206264.8062470963552 * ccdPixelSizeY / 1000.0 / effectiveFocaLength;
685 double fov_w = (w * pixScaleX) / 60.0;
686 double fov_h = (h * pixScaleY) / 60.0;
692 if (m_Camera->hasGain())
694 double min, max, step, value;
695 m_Camera->getGainMinMaxStep(&min, &max, &step);
698 guideGainSpecialValue = min - step;
699 guideGain->setRange(guideGainSpecialValue, max);
700 guideGain->setSpecialValueText(
i18n(
"--"));
701 guideGain->setEnabled(
true);
702 guideGain->setSingleStep(step);
703 m_Camera->getGain(&value);
705 auto gain = m_Settings[
"guideGain"];
709 TargetCustomGainValue = gain.toDouble();
710 if (TargetCustomGainValue > 0)
711 guideGain->setValue(TargetCustomGainValue);
713 guideGain->setValue(guideGainSpecialValue);
715 guideGain->setReadOnly(m_Camera->getGainPermission() == IP_RO);
719 if (guideGain->value() > guideGainSpecialValue)
720 TargetCustomGainValue = guideGain->value();
724 guideGain->setEnabled(
false);
729 if (guiderType != GUIDE_INTERNAL || (m_Guider && device == m_Guider))
733 m_Guider->disconnect(
this);
739 connect(m_Guider, &ISD::ConcreteDevice::Connected,
this, [
this]()
741 guideB->setEnabled(
true);
743 connect(m_Guider, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
745 guideB->setEnabled(
false);
749 guideB->setEnabled(m_Guider && m_Guider->isConnected());
755 if (guiderType != GUIDE_INTERNAL || (m_AO && device == m_AO))
759 m_AO->disconnect(
this);
768 if (guiderType != GUIDE_INTERNAL || m_Guider ==
nullptr)
771 return m_Guider->getDeviceName();
800 if (guiderType == GUIDE_INTERNAL && captureTimeout.isActive() && captureTimeout.remainingTime() > 0)
802 qCDebug(KSTARS_EKOS_GUIDE) <<
"Internal guider skipping capture, already running with remaining seconds =" <<
803 captureTimeout.remainingTime() / 1000.0;
807 buildOperationStack(GUIDE_CAPTURE);
809 return executeOperationStack();
812bool Guide::captureOneFrame()
814 captureTimeout.
stop();
816 if (m_Camera ==
nullptr)
819 if (m_Camera->isConnected() ==
false)
821 appendLogText(
i18n(
"Error: lost connection to CCD."));
825 double seqExpose = guideExposure->value();
827 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
829 prepareCapture(targetChip);
831 m_GuideView->setBaseSize(guideWidget->size());
835 if (frameSettings.
contains(targetChip))
837 QVariantMap settings = frameSettings[targetChip];
838 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
839 settings[
"h"].toInt());
840 targetChip->setBinning(settings[
"binx"].toInt(), settings[
"biny"].toInt());
844 qCDebug(KSTARS_EKOS_GUIDE) <<
"Capturing frame...";
846 double finalExposure = seqExpose;
850 if (operationStack.contains(GUIDE_STAR_SELECT) && guideAutoStar->isChecked() &&
851 !((guiderType == GUIDE_INTERNAL) && internalGuider->SEPMultiStarEnabled()))
855 m_GuideView->setProperty(
"suspended", operationStack.contains(GUIDE_DARK));
858 captureTimeout.start(finalExposure * 1000 + CAPTURE_TIMEOUT_THRESHOLD);
860 targetChip->capture(finalExposure);
865void Guide::prepareCapture(ISD::CameraChip * targetChip)
867 targetChip->setBatchMode(
false);
868 targetChip->setCaptureMode(FITS_GUIDE);
869 targetChip->setFrameType(FRAME_LIGHT);
870 targetChip->setCaptureFilter(FITS_NONE);
871 m_Camera->setEncodingFormat(
"FITS");
874 if (m_Camera->hasGain() && guideGain->isEnabled() && guideGain->value() > guideGainSpecialValue)
875 m_Camera->setGain(guideGain->value());
878void Guide::abortExposure()
880 if (m_Camera && guiderType == GUIDE_INTERNAL)
882 captureTimeout.stop();
884 ISD::CameraChip *targetChip =
885 m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
886 if (targetChip->isCapturing())
888 qCDebug(KSTARS_EKOS_GUIDE) <<
"Aborting guide capture";
889 targetChip->abortExposure();
896 if (m_Camera && guiderType == GUIDE_INTERNAL)
898 captureTimeout.stop();
901 m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
902 if (targetChip->isCapturing())
903 targetChip->abortExposure();
906 manualDitherB->setEnabled(
false);
913 case GUIDE_CONNECTED:
914 case GUIDE_DISCONNECTED:
917 case GUIDE_CALIBRATING:
918 case GUIDE_DITHERING:
919 case GUIDE_STAR_SELECT:
923 m_GuiderInstance->abort();
933void Guide::setBusy(
bool enable)
937 else if (enable ==
false && pi->
isAnimated() ==
false)
942 clearCalibrationB->setEnabled(
false);
943 guideB->setEnabled(
false);
944 captureB->setEnabled(
false);
945 loopB->setEnabled(
false);
946 guideDarkFrame->setEnabled(
false);
947 guideSubframe->setEnabled(
false);
948 guideAutoStar->setEnabled(
false);
949 stopB->setEnabled(
true);
951 opticalTrainCombo->setEnabled(
false);
952 trainB->setEnabled(
false);
958 if(guiderType != GUIDE_LINGUIDER)
960 captureB->setEnabled(
true);
961 loopB->setEnabled(
true);
962 guideAutoStar->setEnabled(!internalGuider->SEPMultiStarEnabled());
964 guideSubframe->setEnabled(!internalGuider->SEPMultiStarEnabled());
966 if (guiderType == GUIDE_INTERNAL)
967 guideDarkFrame->setEnabled(
true);
969 if (calibrationComplete ||
970 ((guiderType == GUIDE_INTERNAL) &&
971 Options::reuseGuideCalibration() &&
972 !Options::serializedCalibration().isEmpty()))
973 clearCalibrationB->setEnabled(
true);
974 guideB->setEnabled(
true);
975 stopB->setEnabled(
false);
979 opticalTrainCombo->setEnabled(
true);
980 trainB->setEnabled(
true);
986void Guide::processCaptureTimeout()
989 if (m_State == GUIDE_SUSPENDED)
991 appendLogText(
i18n(
"Exposure timeout, but suspended. Ignoring..."));
995 auto restartExposure = [&]()
997 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
998 m_Camera->setEncodingFormat(
"FITS");
999 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1000 targetChip->abortExposure();
1001 prepareCapture(targetChip);
1005 targetChip->capture(guideExposure->value());
1006 captureTimeout.start(guideExposure->value() * 1000 + CAPTURE_TIMEOUT_THRESHOLD);
1009 m_CaptureTimeoutCounter++;
1011 if (m_Camera ==
nullptr)
1014 if (m_DeviceRestartCounter >= 3)
1016 m_CaptureTimeoutCounter = 0;
1017 m_DeviceRestartCounter = 0;
1018 if (m_State == GUIDE_GUIDING)
1019 appendLogText(
i18n(
"Exposure timeout. Aborting Autoguide."));
1020 else if (m_State == GUIDE_DITHERING)
1021 appendLogText(
i18n(
"Exposure timeout. Aborting Dithering."));
1022 else if (m_State == GUIDE_CALIBRATING)
1023 appendLogText(
i18n(
"Exposure timeout. Aborting Calibration."));
1025 captureTimeout.stop();
1030 if (m_CaptureTimeoutCounter > 3)
1032 appendLogText(
i18n(
"Exposure timeout. Too many. Restarting driver."));
1033 QString camera = m_Camera->getDeviceName();
1034 QString via = m_Guider ? m_Guider->getDeviceName() :
"";
1035 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1036 QVariantMap settings = frameSettings[targetChip];
1037 emit driverTimedout(camera);
1040 m_DeviceRestartCounter++;
1041 reconnectDriver(camera, settings);
1049void Guide::reconnectDriver(
const QString &camera, QVariantMap settings)
1051 if (m_Camera && m_Camera->getDeviceName() == camera)
1054 Ekos::GuideState currentState = m_State;
1055 m_State = GUIDE_IDLE;
1058 m_State = currentState;
1060 if (guiderType == GUIDE_INTERNAL)
1063 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1064 frameSettings[targetChip] = settings;
1066 m_CaptureTimeoutCounter = 0;
1075 reconnectDriver(camera, settings);
1081 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1082 if (targetChip->getCaptureMode() != FITS_GUIDE)
1086 QString blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1087 .
arg(data->property(
"blobVector").toString())
1088 .
arg(data->property(
"blobElement").toString())
1089 .
arg(data->property(
"chip").toInt());
1091 qCWarning(KSTARS_EKOS_GUIDE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1092 targetChip->getCaptureMode();
1098 captureTimeout.stop();
1099 m_CaptureTimeoutCounter = 0;
1103 m_GuideView->loadData(data);
1107 m_ImageData.reset();
1109 if (guiderType == GUIDE_INTERNAL)
1110 internalGuider->setImageData(m_ImageData);
1116 int subBinX = 1, subBinY = 1;
1117 targetChip->getBinning(&subBinX, &subBinY);
1119 if (starCenter.x() == 0 && starCenter.y() == 0)
1121 int x = 0,
y = 0, w = 0, h = 0;
1123 if (frameSettings.contains(targetChip))
1125 QVariantMap settings = frameSettings[targetChip];
1126 x = settings[
"x"].toInt();
1127 y = settings[
"y"].toInt();
1128 w = settings[
"w"].toInt();
1129 h = settings[
"h"].toInt();
1132 targetChip->getFrame(&
x, &
y, &w, &h);
1134 starCenter.setX(w / (2 * subBinX));
1135 starCenter.setY(h / (2 * subBinY));
1136 starCenter.setZ(subBinX);
1139 syncTrackingBoxPosition();
1142 setCaptureComplete();
1147void Guide::setCaptureComplete()
1149 if (!m_GuideView.
isNull())
1150 m_GuideView->clearNeighbors();
1152 DarkLibrary::Instance()->disconnect(
this);
1154 if (operationStack.isEmpty() ==
false)
1156 executeOperationStack();
1160 qCDebug(KSTARS_EKOS_GUIDE) <<
"Capture complete, state=" << getGuideStatusString(m_State);
1165 case GUIDE_CONNECTED:
1166 case GUIDE_DISCONNECTED:
1167 case GUIDE_CALIBRATION_SUCCESS:
1168 case GUIDE_CALIBRATION_ERROR:
1169 case GUIDE_DITHERING_ERROR:
1174 qCDebug(KSTARS_EKOS_GUIDE) <<
"Guiding capture complete.";
1175 m_State = GUIDE_IDLE;
1176 emit newStatus(m_State);
1184 case GUIDE_CALIBRATING:
1185 m_GuiderInstance->calibrate();
1189 m_GuiderInstance->guide();
1192 case GUIDE_DITHERING:
1193 m_GuiderInstance->dither(Options::ditherPixels());
1197 case GUIDE_MANUAL_DITHERING:
1198 dynamic_cast<InternalGuider*
>(m_GuiderInstance)->processManualDithering();
1201 case GUIDE_REACQUIRE:
1202 m_GuiderInstance->reacquire();
1205 case GUIDE_DITHERING_SETTLE:
1206 if (Options::ditherNoGuiding())
1211 case GUIDE_SUSPENDED:
1212 if (Options::gPGEnabled())
1213 m_GuiderInstance->guide();
1220 emit newImage(m_GuideView);
1221 emit newStarPixmap(m_GuideView->getTrackingBoxPixmap(10));
1224void Guide::appendLogText(
const QString &text)
1226 m_LogText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
1227 KStarsData::Instance()->lt().
toString(
"yyyy-MM-ddThh:mm:ss"), text));
1229 qCInfo(KSTARS_EKOS_GUIDE) << text;
1242 if (m_Guider ==
nullptr || m_GuiderInstance ==
nullptr)
1245 if (guiderType == GUIDE_INTERNAL)
1247 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->
setDECSwap(enable);
1248 m_Guider->setDECSwap(enable);
1252bool Guide::sendMultiPulse(GuideDirection ra_dir,
int ra_msecs, GuideDirection dec_dir,
int dec_msecs,
1253 CaptureAfterPulses followWithCapture)
1255 if (m_Guider ==
nullptr || (ra_dir == NO_DIR && dec_dir == NO_DIR))
1258 if (followWithCapture == StartCaptureAfterPulses)
1262 auto ms = std::max(ra_msecs, dec_msecs) + 100;
1263 auto delay = std::max(
static_cast<int>(guideDelay->value() * 1000), ms);
1265 m_PulseTimer.
start(delay);
1267 return m_Guider->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
1270bool Guide::sendSinglePulse(GuideDirection dir,
int msecs, CaptureAfterPulses followWithCapture)
1272 if (m_Guider ==
nullptr || dir == NO_DIR)
1275 if (followWithCapture == StartCaptureAfterPulses)
1279 auto ms = msecs + 100;
1280 auto delay = std::max(
static_cast<int>(guideDelay->value() * 1000), ms);
1282 m_PulseTimer.start(delay);
1285 return m_Guider->doPulse(dir, msecs);
1291 m_State = GUIDE_IDLE;
1292 qCDebug(KSTARS_EKOS_GUIDE) <<
"Calibrating...";
1293 emit newStatus(m_State);
1295 if (guiderType == GUIDE_INTERNAL)
1299 KSNotification::error(
i18n(
"No camera detected. Check camera in optical trains."));
1305 KSNotification::error(
i18n(
"No guider detected. Check guide-via in optical trains."));
1309 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1311 if (frameSettings.contains(targetChip))
1313 targetChip->resetFrame();
1315 targetChip->getFrame(&
x, &
y, &w, &h);
1316 QVariantMap settings = frameSettings[targetChip];
1321 frameSettings[targetChip] = settings;
1327 buildOperationStack(GUIDE_CALIBRATING);
1329 executeOperationStack();
1331 if (m_Camera && m_Guider)
1333 qCDebug(KSTARS_EKOS_GUIDE) <<
"Starting calibration using camera:" << m_Camera->getDeviceName() <<
"via" <<
1334 m_Guider->getDeviceName();
1342 auto executeGuide = [
this]()
1344 if(guiderType != GUIDE_PHD2)
1346 if (calibrationComplete ==
false)
1353 m_GuiderInstance->guide();
1359 if(!guideAutoStar->isChecked())
1361 if(guiderType == GUIDE_PHD2 && m_GuideView->isTrackingBoxEnabled())
1363 double x = starCenter.x();
1364 double y = starCenter.y();
1366 if(!m_ImageData.isNull())
1368 if(m_ImageData->width() > 50)
1370 guideConnect =
connect(
this, &Guide::newStatus,
this, [
this,
x,
y](Ekos::GuideState newState)
1372 if(newState == GUIDE_GUIDING)
1374 phd2Guider->setLockPosition(
x,
y);
1384 if (m_MountStatus == ISD::Mount::MOUNT_PARKED)
1386 KSMessageBox::Instance()->sorry(
i18n(
"The mount is parked. Unpark to start guiding."));
1396 if (Options::ditherNoGuiding() && m_State == GUIDE_IDLE)
1402 if (m_State == GUIDE_DITHERING || m_State == GUIDE_DITHERING_SETTLE)
1406 double time = guideTimer.elapsed() / 1000.0;
1410 ditherLabel->position->
setCoords(time, 1.5);
1414 ditherLabel->
setText(
"Dither");
1417 if (guiderType == GUIDE_INTERNAL && !Options::ditherWithOnePulse())
1419 if (m_State != GUIDE_GUIDING)
1422 setStatus(GUIDE_DITHERING);
1427 return m_GuiderInstance->dither(Options::ditherPixels());
1432 if (m_State == GUIDE_SUSPENDED)
1434 else if (m_State >= GUIDE_CAPTURE)
1435 return m_GuiderInstance->suspend();
1442 if (m_State == GUIDE_GUIDING)
1444 else if (m_State == GUIDE_SUSPENDED)
1445 return m_GuiderInstance->resume();
1471void Guide::setPierSide(ISD::Mount::PierSide newSide)
1473 m_GuiderInstance->setPierSide(newSide);
1478 if (guiderType == GUIDE_INTERNAL &&
1479 m_State != GUIDE_GUIDING &&
1480 m_State != GUIDE_CALIBRATING &&
1481 calibrationComplete)
1484 if (Options::reuseGuideCalibration())
1485 calibrationComplete =
false;
1489 appendLogText(
i18n(
"Pier side change detected. Clearing calibration."));
1494void Guide::setMountStatus(ISD::Mount::Status newState)
1496 m_MountStatus = newState;
1498 if (newState == ISD::Mount::MOUNT_PARKING || newState == ISD::Mount::MOUNT_SLEWING)
1501 if (Options::resetGuideCalibration())
1503 appendLogText(
i18n(
"Mount is moving. Resetting calibration..."));
1506 else if (Options::reuseGuideCalibration() && (guiderType == GUIDE_INTERNAL))
1509 calibrationComplete =
false;
1512 if (Options::gPGEnabled())
1513 m_GuiderInstance->resetGPG();
1516 if (m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1518 if (newState == ISD::Mount::MOUNT_PARKING)
1519 appendLogText(
i18n(
"Mount is parking. Aborting guide..."));
1521 appendLogText(
i18n(
"Mount is slewing. Aborting guide..."));
1527 if (guiderType != GUIDE_INTERNAL)
1532 case ISD::Mount::MOUNT_SLEWING:
1533 case ISD::Mount::MOUNT_PARKING:
1534 case ISD::Mount::MOUNT_MOVING:
1535 captureB->setEnabled(
false);
1536 loopB->setEnabled(
false);
1537 clearCalibrationB->setEnabled(
false);
1538 manualPulseB->setEnabled(
false);
1542 if (pi->isAnimated() ==
false)
1544 captureB->setEnabled(
true);
1545 loopB->setEnabled(
true);
1546 clearCalibrationB->setEnabled(
true);
1547 manualPulseB->setEnabled(
true);
1552void Guide::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
1555 m_GuiderInstance->setMountCoords(position, pierSide);
1556 m_ManaulPulse->setMountCoords(position);
1561 guideExposure->setValue(value);
1566 if (guideSubframe->isChecked() != enable)
1567 guideSubframe->setChecked(enable);
1568 if(guiderType == GUIDE_PHD2)
1569 setExternalGuiderBLOBEnabled(!enable);
1574 if(guiderType == GUIDE_INTERNAL)
1575 guideAutoStar->setChecked(enable);
1580 calibrationComplete =
false;
1581 if (m_GuiderInstance->clearCalibration())
1583 clearCalibrationB->setEnabled(
false);
1584 appendLogText(
i18n(
"Calibration is cleared."));
1590void Guide::setStatus(Ekos::GuideState newState)
1592 if (newState == m_State)
1595 if (newState == GUIDE_ABORTED)
1596 emit newStatus(m_State);
1600 GuideState previousState = m_State;
1603 emit newStatus(m_State);
1607 case GUIDE_CONNECTED:
1608 appendLogText(
i18n(
"External guider connected."));
1609 externalConnectB->setEnabled(
false);
1610 externalDisconnectB->setEnabled(
true);
1611 clearCalibrationB->setEnabled(
true);
1612 guideB->setEnabled(
true);
1614 if(guiderType == GUIDE_PHD2)
1616 captureB->setEnabled(
true);
1617 loopB->setEnabled(
true);
1618 guideAutoStar->setEnabled(
true);
1619 configurePHD2Camera();
1620 setExternalGuiderBLOBEnabled(!guideSubframe->isChecked());
1621 guideSquareSize->setEnabled(
true);
1625 case GUIDE_DISCONNECTED:
1626 appendLogText(
i18n(
"External guider disconnected."));
1628 externalConnectB->setEnabled(
true);
1629 externalDisconnectB->setEnabled(
false);
1630 clearCalibrationB->setEnabled(
false);
1631 guideB->setEnabled(
false);
1632 captureB->setEnabled(
false);
1633 loopB->setEnabled(
false);
1634 guideAutoStar->setEnabled(
false);
1635 guideSquareSize->setEnabled(
false);
1642 case GUIDE_CALIBRATION_SUCCESS:
1643 appendLogText(
i18n(
"Calibration completed."));
1644 manualPulseB->setEnabled(
true);
1645 calibrationComplete =
true;
1653 case GUIDE_CALIBRATION_ERROR:
1655 manualDitherB->setEnabled(
false);
1656 manualPulseB->setEnabled(
true);
1659 case GUIDE_CALIBRATING:
1660 clearCalibrationGraphs();
1661 appendLogText(
i18n(
"Calibration started."));
1663 manualPulseB->setEnabled(
false);
1667 if (previousState == GUIDE_SUSPENDED || previousState == GUIDE_DITHERING_SUCCESS)
1668 appendLogText(
i18n(
"Guiding resumed."));
1671 appendLogText(
i18n(
"Autoguiding started."));
1676 driftGraph->resetTimer();
1677 driftGraph->refreshColorScheme();
1679 manualDitherB->setEnabled(
true);
1683 appendLogText(
i18n(
"Autoguiding aborted."));
1687 case GUIDE_SUSPENDED:
1688 appendLogText(
i18n(
"Guiding suspended."));
1691 case GUIDE_REACQUIRE:
1692 if (guiderType == GUIDE_INTERNAL)
1696 case GUIDE_MANUAL_DITHERING:
1697 appendLogText(
i18n(
"Manual dithering in progress."));
1700 case GUIDE_DITHERING:
1701 appendLogText(
i18n(
"Dithering in progress."));
1704 case GUIDE_DITHERING_SETTLE:
1705 appendLogText(
i18np(
"Post-dither settling for %1 second...",
"Post-dither settling for %1 seconds...",
1706 Options::ditherSettle()));
1709 case GUIDE_DITHERING_ERROR:
1710 appendLogText(
i18n(
"Dithering failed."));
1712 if (guiderType != GUIDE_LINGUIDER)
1715 m_State = GUIDE_ABORTED;
1720 case GUIDE_DITHERING_SUCCESS:
1721 appendLogText(
i18n(
"Dithering completed successfully."));
1723 if (Options::ditherNoGuiding() ==
false)
1725 setStatus(GUIDE_GUIDING);
1727 if (guiderType == GUIDE_INTERNAL)
1736void Guide::updateCCDBin(
int index)
1738 if (m_Camera ==
nullptr || guiderType != GUIDE_INTERNAL)
1741 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1743 targetChip->setBinning(index + 1, index + 1);
1744 guideBinIndex = index;
1746 QVariantMap settings = frameSettings[targetChip];
1747 settings[
"binx"] = index + 1;
1748 settings[
"biny"] = index + 1;
1749 frameSettings[targetChip] = settings;
1751 m_GuiderInstance->setFrameParams(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(), settings[
"h"].toInt(),
1752 settings[
"binx"].toInt(), settings[
"biny"].toInt());
1757 if (m_Camera ==
nullptr || (prop.getDeviceName() != m_Camera->getDeviceName()) || guiderType != GUIDE_INTERNAL)
1760 if ((prop.isNameMatch(
"CCD_BINNING") && useGuideHead ==
false) ||
1761 (prop.isNameMatch(
"GUIDER_BINNING") && useGuideHead))
1763 auto nvp = prop.getNumber();
1764 auto value = nvp->at(0)->getValue();
1765 if (guideBinIndex > (value - 1))
1767 appendLogText(
i18n(
"%1x%1 guide binning is not supported.", guideBinIndex + 1));
1768 guideBinning->setCurrentIndex( value - 1 );
1773 guideBinning->setCurrentIndex(guideBinIndex);
1781 if (guiderType != GUIDE_INTERNAL || targetChip->getCCD() != m_Camera)
1784 INDI_UNUSED(exposure);
1786 if (expState == IPS_ALERT &&
1787 ((m_State == GUIDE_GUIDING) || (m_State == GUIDE_DITHERING) || (m_State == GUIDE_CALIBRATING)))
1789 appendLogText(
i18n(
"Exposure failed. Restarting exposure..."));
1790 m_Camera->setEncodingFormat(
"FITS");
1791 targetChip->capture(guideExposure->value());
1795void Guide::configSEPMultistarOptions()
1798 if (internalGuider->SEPMultiStarEnabled())
1800 guideSubframe->setChecked(
false);
1801 guideSubframe->setEnabled(
false);
1802 guideAutoStar->setChecked(
true);
1803 guideAutoStar->setEnabled(
false);
1807 guideAutoStar->setEnabled(
true);
1808 guideSubframe->setEnabled(
true);
1810 auto subframed = m_Settings[
"guideSubframe"];
1811 if (subframed.isValid())
1812 guideSubframe->setChecked(subframed.toBool());
1814 auto autostar = m_Settings[
"guideAutoStar"];
1815 if (autostar.isValid())
1816 guideAutoStar->setChecked(autostar.toBool());
1822 if (guideDarkFrame->isChecked() != enable)
1823 guideDarkFrame->setChecked(enable);
1826void Guide::saveDefaultGuideExposure()
1828 if(guiderType == GUIDE_PHD2)
1830 phd2Guider->requestSetExposureTime(guideExposure->value() * 1000);
1831 else if (guiderType == GUIDE_INTERNAL)
1833 internalGuider->setExposureTime();
1837void Guide::setStarPosition(
const QVector3D &newCenter,
bool updateNow)
1839 starCenter.setX(newCenter.
x());
1840 starCenter.setY(newCenter.
y());
1841 if (newCenter.
z() > 0)
1842 starCenter.setZ(newCenter.
z());
1845 syncTrackingBoxPosition();
1848void Guide::syncTrackingBoxPosition()
1850 if(!m_Camera || guiderType == GUIDE_LINGUIDER)
1853 if(guiderType == GUIDE_PHD2)
1856 if(!m_ImageData.isNull())
1858 if(m_ImageData->width() < 50)
1860 m_GuideView->setTrackingBoxEnabled(
false);
1866 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1867 Q_ASSERT(targetChip);
1869 int subBinX = 1, subBinY = 1;
1870 targetChip->getBinning(&subBinX, &subBinY);
1872 if (starCenter.isNull() ==
false)
1874 double boxSize = guideSquareSize->currentText().toInt();
1876 targetChip->getFrame(&
x, &
y, &w, &h);
1878 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
1880 int newIndex = guideSquareSize->currentIndex() - 1;
1882 guideSquareSize->setCurrentIndex(newIndex);
1887 if (subBinX != starCenter.z())
1889 if (starCenter.z() > 0)
1891 starCenter.setX(starCenter.x() * (starCenter.z() / subBinX));
1892 starCenter.setY(starCenter.y() * (starCenter.z() / subBinY));
1895 starCenter.setZ(subBinX);
1898 QRect starRect = QRect(starCenter.x() - boxSize / (2 * subBinX), starCenter.y() - boxSize / (2 * subBinY),
1899 boxSize / subBinX, boxSize / subBinY);
1900 m_GuideView->setTrackingBoxEnabled(
true);
1901 m_GuideView->setTrackingBox(starRect);
1909 type = Options::guiderType();
1910 else if (type == guiderType)
1913 if (m_State == GUIDE_CALIBRATING || m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1915 appendLogText(
i18n(
"Cannot change guider type while active."));
1919 if (m_GuiderInstance !=
nullptr)
1922 if (m_GuiderInstance->isConnected())
1923 m_GuiderInstance->Disconnect();
1926 m_GuiderInstance->disconnect();
1929 guiderType =
static_cast<GuiderType
>(type);
1933 case GUIDE_INTERNAL:
1935 connect(internalGuider, &InternalGuider::newMultiPulse,
this, &Guide::sendMultiPulse);
1936 connect(internalGuider, &InternalGuider::newSinglePulse,
this, &Guide::sendSinglePulse);
1938 connect(internalGuider, &InternalGuider::newStarPixmap,
this, &Guide::newStarPixmap);
1940 m_GuiderInstance = internalGuider;
1942 internalGuider->setSquareAlgorithm(opsGuide->kcfg_GuideAlgorithm->currentIndex());
1944 clearCalibrationB->setEnabled(
true);
1945 guideB->setEnabled(
true);
1946 captureB->setEnabled(
true);
1947 loopB->setEnabled(
true);
1949 configSEPMultistarOptions();
1950 guideDarkFrame->setEnabled(
true);
1952 guideExposure->setEnabled(
true);
1953 guideBinning->setEnabled(
true);
1954 guideSquareSize->setEnabled(
true);
1956 externalConnectB->setEnabled(
false);
1957 externalDisconnectB->setEnabled(
false);
1959 opsGuide->controlGroup->setEnabled(
true);
1960 infoGroup->setEnabled(
true);
1961 l_Aperture->setEnabled(
true);
1962 l_FOV->setEnabled(
true);
1963 l_FbyD->setEnabled(
true);
1964 l_Focal->setEnabled(
true);
1965 driftGraphicsGroup->setEnabled(
true);
1967 updateGuideParams();
1972 if (phd2Guider.isNull())
1973 phd2Guider =
new PHD2();
1975 m_GuiderInstance = phd2Guider;
1976 phd2Guider->setGuideView(m_GuideView);
1980 clearCalibrationB->setEnabled(
true);
1981 captureB->setEnabled(
false);
1982 loopB->setEnabled(
false);
1983 guideDarkFrame->setEnabled(
false);
1984 guideSubframe->setEnabled(
false);
1985 guideAutoStar->setEnabled(
false);
1986 guideB->setEnabled(
false);
1987 externalConnectB->setEnabled(
false);
1989 rAGuideEnabled->setEnabled(
false);
1990 eastRAGuideEnabled->setEnabled(
false);
1991 westRAGuideEnabled->setEnabled(
false);
1993 opsGuide->controlGroup->setEnabled(
false);
1994 infoGroup->setEnabled(
true);
1995 l_Aperture->setEnabled(
false);
1996 l_FOV->setEnabled(
false);
1997 l_FbyD->setEnabled(
false);
1998 l_Focal->setEnabled(
false);
1999 driftGraphicsGroup->setEnabled(
true);
2001 guideExposure->setEnabled(
true);
2002 guideBinning->setEnabled(
false);
2003 guideSquareSize->setEnabled(
false);
2005 if (Options::resetGuideCalibration())
2006 appendLogText(
i18n(
"Warning: Reset Guiding Calibration is enabled. It is recommended to turn this option off for PHD2."));
2008 updateGuideParams();
2011 case GUIDE_LINGUIDER:
2012 if (linGuider.isNull())
2015 m_GuiderInstance = linGuider;
2017 clearCalibrationB->setEnabled(
true);
2018 captureB->setEnabled(
false);
2019 loopB->setEnabled(
false);
2020 guideDarkFrame->setEnabled(
false);
2021 guideSubframe->setEnabled(
false);
2022 guideAutoStar->setEnabled(
false);
2023 guideB->setEnabled(
true);
2024 externalConnectB->setEnabled(
true);
2026 opsGuide->controlGroup->setEnabled(
false);
2027 infoGroup->setEnabled(
false);
2028 driftGraphicsGroup->setEnabled(
false);
2030 guideExposure->setEnabled(
false);
2031 guideBinning->setEnabled(
false);
2032 guideSquareSize->setEnabled(
false);
2034 updateGuideParams();
2039 if (m_GuiderInstance !=
nullptr)
2042 connect(m_GuiderInstance, &Ekos::GuideInterface::newLog,
this, &Ekos::Guide::appendLogText);
2043 connect(m_GuiderInstance, &Ekos::GuideInterface::newStatus,
this, &Ekos::Guide::setStatus);
2044 connect(m_GuiderInstance, &Ekos::GuideInterface::newStarPosition,
this, &Ekos::Guide::setStarPosition);
2045 connect(m_GuiderInstance, &Ekos::GuideInterface::guideStats,
this, &Ekos::Guide::guideStats);
2047 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisDelta,
this, &Ekos::Guide::setAxisDelta);
2048 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisPulse,
this, &Ekos::Guide::setAxisPulse);
2049 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisSigma,
this, &Ekos::Guide::setAxisSigma);
2050 connect(m_GuiderInstance, &Ekos::GuideInterface::newSNR,
this, &Ekos::Guide::setSNR);
2051 connect(m_GuiderInstance, &Ekos::GuideInterface::guideInfo,
this, &Ekos::Guide::guideInfo);
2052 connect(m_GuiderInstance, &Ekos::GuideInterface::abortExposure,
this, &Ekos::Guide::abortExposure);
2054 driftGraph->connectGuider(m_GuiderInstance);
2055 targetPlot->connectGuider(m_GuiderInstance);
2057 connect(m_GuiderInstance, &Ekos::GuideInterface::calibrationUpdate,
this, &Ekos::Guide::calibrationUpdate);
2059 connect(m_GuiderInstance, &Ekos::GuideInterface::guideEquipmentUpdated,
this, &Ekos::Guide::configurePHD2Camera);
2062 externalConnectB->setEnabled(
false);
2063 externalDisconnectB->setEnabled(
false);
2065 if (m_GuiderInstance !=
nullptr && guiderType != GUIDE_INTERNAL)
2067 externalConnectB->setEnabled(!m_GuiderInstance->isConnected());
2068 externalDisconnectB->setEnabled(m_GuiderInstance->isConnected());
2071 if (m_GuiderInstance !=
nullptr)
2072 m_GuiderInstance->Connect();
2077void Guide::guideInfo(
const QString &info)
2079 if (info.size() == 0)
2081 guideInfoLabel->setVisible(
false);
2082 guideInfoText->setVisible(
false);
2085 guideInfoLabel->setVisible(
true);
2086 guideInfoLabel->setText(
"Detections");
2087 guideInfoText->setVisible(
true);
2088 guideInfoText->setText(info);
2091void Guide::updateTrackingBoxSize(
int currentIndex)
2093 if (currentIndex >= 0)
2095 if (guiderType == GUIDE_INTERNAL)
2096 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setGuideBoxSize(guideSquareSize->currentText().toInt());
2098 syncTrackingBoxPosition();
2102void Guide::onThresholdChanged(
int index)
2106 case GUIDE_INTERNAL:
2107 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setSquareAlgorithm(index);
2115void Guide::onEnableDirRA()
2118 if (Options::gPGEnabled())
2119 m_GuiderInstance->resetGPG();
2122void Guide::onEnableDirDEC()
2124 onControlDirectionChanged();
2127void Guide::onControlDirectionChanged()
2129 if(guiderType == GUIDE_PHD2)
2130 phd2Guider -> requestSetDEGuideMode(dECGuideEnabled->isChecked(), northDECGuideEnabled->isChecked(),
2131 southDECGuideEnabled->isChecked());
2134void Guide::updateDirectionsFromPHD2(
const QString &mode)
2143 dECGuideEnabled->setChecked(
true);
2144 northDECGuideEnabled->setChecked(
true);
2145 southDECGuideEnabled->setChecked(
true);
2147 else if(mode ==
"North")
2149 dECGuideEnabled->setChecked(
true);
2150 northDECGuideEnabled->setChecked(
true);
2151 southDECGuideEnabled->setChecked(
false);
2153 else if(mode ==
"South")
2155 dECGuideEnabled->setChecked(
true);
2156 northDECGuideEnabled->setChecked(
false);
2157 southDECGuideEnabled->setChecked(
true);
2161 dECGuideEnabled->setChecked(
false);
2162 northDECGuideEnabled->setChecked(
true);
2163 southDECGuideEnabled->setChecked(
true);
2175 setStarPosition(newStarPosition,
true);
2177 if(guiderType == GUIDE_PHD2)
2180 if(!m_ImageData.isNull())
2182 if(m_ImageData->width() > 50)
2183 phd2Guider->setLockPosition(starCenter.x(), starCenter.y());
2187 if (operationStack.isEmpty() ==
false)
2188 executeOperationStack();
2191void Guide::setAxisDelta(
double ra,
double de)
2199 int currentNumPoints = driftGraph->graph(GuideGraph::G_RA)->dataCount();
2200 guideSlider->setMaximum(currentNumPoints);
2203 guideSlider->setValue(currentNumPoints);
2208 emit newAxisDelta(ra, de);
2211void Guide::calibrationUpdate(GuideInterface::CalibrationUpdateType type,
const QString &message,
2212 double dx,
double dy)
2216 case GuideInterface::RA_OUT:
2217 calibrationPlot->graph(GuideGraph::G_RA)->addData(dx, dy);
2219 case GuideInterface::RA_OUT_OK:
2220 drawRADECAxis(calRALabel, calRAArrow, dx, dy);
2222 case GuideInterface::RA_IN:
2223 calibrationPlot->graph(GuideGraph::G_DEC)->addData(dx, dy);
2225 case GuideInterface::BACKLASH:
2226 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->addData(dx, dy);
2228 case GuideInterface::DEC_OUT:
2229 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(dx, dy);
2231 case GuideInterface::DEC_OUT_OK:
2232 drawRADECAxis(calDECLabel, calDECArrow, dx, dy);
2234 case GuideInterface::DEC_IN:
2235 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->addData(dx, dy);
2237 case GuideInterface::CALIBRATION_MESSAGE_ONLY:
2240 calLabel->setText(message);
2241 calibrationPlot->replot();
2244void Guide::drawRADECAxis(QCPItemText *Label, QCPItemLine *Arrow,
const double xEnd,
const double yEnd)
2250 Label->position->setCoords(xEnd, yEnd);
2255 Label->setVisible(
true);
2258void Guide::setAxisSigma(
double ra,
double de)
2262 const double total = std::hypot(ra, de);
2265 emit newAxisSigma(ra, de);
2268QList<double> Guide::axisDelta()
2270 QList<double> delta;
2272 delta << l_DeltaRA->text().toDouble() << l_DeltaDEC->text().toDouble();
2277QList<double> Guide::axisSigma()
2279 QList<double> sigma;
2281 sigma << l_ErrRA->text().toDouble() << l_ErrDEC->text().toDouble();
2286void Guide::setAxisPulse(
double ra,
double de)
2292void Guide::setSNR(
double snr)
2297void Guide::buildOperationStack(GuideState operation)
2299 operationStack.
clear();
2304 if (guideDarkFrame->isChecked())
2305 operationStack.push(GUIDE_DARK);
2307 operationStack.push(GUIDE_CAPTURE);
2308 operationStack.push(GUIDE_SUBFRAME);
2311 case GUIDE_CALIBRATING:
2312 operationStack.push(GUIDE_CALIBRATING);
2313 if (guiderType == GUIDE_INTERNAL)
2315 if (guideDarkFrame->isChecked())
2316 operationStack.push(GUIDE_DARK);
2319 if (guideAutoStar->isChecked() ||
2321 internalGuider->SEPMultiStarEnabled())
2325 if (subFramed ==
false && guideSubframe->isChecked())
2326 operationStack.push(GUIDE_CAPTURE);
2328 operationStack.push(GUIDE_SUBFRAME);
2329 operationStack.push(GUIDE_STAR_SELECT);
2332 operationStack.push(GUIDE_CAPTURE);
2335 if (subFramed ==
true && guideSubframe->isChecked() ==
false)
2336 operationStack.push(GUIDE_SUBFRAME);
2342 if (subFramed ==
false && guideSubframe->isChecked())
2343 operationStack.push(GUIDE_CAPTURE);
2346 operationStack.push(GUIDE_SUBFRAME);
2349 operationStack.push(GUIDE_CAPTURE);
2360bool Guide::executeOperationStack()
2362 if (operationStack.isEmpty())
2365 GuideState nextOperation = operationStack.pop();
2368 bool actionRequired =
false;
2370 switch (nextOperation)
2372 case GUIDE_SUBFRAME:
2373 actionRequired = executeOneOperation(nextOperation);
2377 actionRequired = executeOneOperation(nextOperation);
2381 actionRequired = captureOneFrame();
2384 case GUIDE_STAR_SELECT:
2385 actionRequired = executeOneOperation(nextOperation);
2388 case GUIDE_CALIBRATING:
2389 if (guiderType == GUIDE_INTERNAL)
2391 m_GuiderInstance->setStarPosition(starCenter);
2394 if (m_Mount && m_Mount->canControlTrack() && m_Mount->isTracking() ==
false)
2395 m_Mount->setTrackEnabled(
true);
2398 if (m_GuiderInstance->calibrate())
2400 if (guiderType == GUIDE_INTERNAL)
2406 emit newStatus(GUIDE_CALIBRATION_ERROR);
2407 m_State = GUIDE_IDLE;
2408 appendLogText(
i18n(
"Calibration failed to start."));
2422 return executeOperationStack();
2425bool Guide::executeOneOperation(GuideState operation)
2427 bool actionRequired =
false;
2429 if (m_Camera ==
nullptr)
2430 return actionRequired;
2432 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2433 if (targetChip ==
nullptr)
2436 int subBinX, subBinY;
2437 targetChip->getBinning(&subBinX, &subBinY);
2441 case GUIDE_SUBFRAME:
2444 if ((guiderType == GUIDE_INTERNAL) && internalGuider->SEPMultiStarEnabled())
2447 if (subFramed ==
false && guideSubframe->isChecked() ==
true && targetChip->canSubframe())
2449 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2450 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2452 int offset = guideSquareSize->currentText().toInt() / subBinX;
2454 int x = starCenter.x();
2455 int y = starCenter.y();
2457 x = (
x - offset * 2) * subBinX;
2458 y = (
y - offset * 2) * subBinY;
2459 int w = offset * 4 * subBinX;
2460 int h = offset * 4 * subBinY;
2471 targetChip->setFrame(
x,
y, w, h);
2474 QVariantMap settings = frameSettings[targetChip];
2479 settings[
"binx"] = subBinX;
2480 settings[
"biny"] = subBinY;
2482 frameSettings[targetChip] = settings;
2484 starCenter.setX(w / (2 * subBinX));
2485 starCenter.setY(h / (2 * subBinX));
2491 else if (subFramed &&
2492 (guideSubframe->isChecked() ==
false ||
2493 m_State == GUIDE_REACQUIRE))
2495 targetChip->resetFrame();
2498 targetChip->getFrame(&
x, &
y, &w, &h);
2500 QVariantMap settings;
2505 settings[
"binx"] = subBinX;
2506 settings[
"biny"] = subBinY;
2507 frameSettings[targetChip] = settings;
2511 starCenter.setX(w / (2 * subBinX));
2512 starCenter.setY(h / (2 * subBinX));
2523 if (m_ImageData && guideDarkFrame->isChecked())
2525 QVariantMap settings = frameSettings[targetChip];
2526 uint16_t offsetX = 0;
2527 uint16_t offsetY = 0;
2529 if (settings[
"x"].
isValid() &&
2534 offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
2535 offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
2538 actionRequired =
true;
2539 targetChip->setCaptureFilter(FITS_NONE);
2540 m_DarkProcessor->denoise(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()),
2541 targetChip, m_ImageData, guideExposure->value(), offsetX, offsetY);
2546 case GUIDE_STAR_SELECT:
2548 m_State = GUIDE_STAR_SELECT;
2549 emit newStatus(m_State);
2551 if (guideAutoStar->isChecked() ||
2553 ((guiderType == GUIDE_INTERNAL) &&
2554 internalGuider->SEPMultiStarEnabled()))
2556 bool autoStarCaptured = internalGuider->selectAutoStar();
2557 if (autoStarCaptured)
2559 appendLogText(
i18n(
"Auto star selected."));
2563 appendLogText(
i18n(
"Failed to select an auto star."));
2564 actionRequired =
true;
2565 m_State = GUIDE_CALIBRATION_ERROR;
2566 emit newStatus(m_State);
2572 appendLogText(
i18n(
"Select a guide star to calibrate."));
2573 actionRequired =
true;
2582 return actionRequired;
2585void Guide::processGuideOptions()
2587 if (Options::guiderType() != guiderType)
2589 guiderType =
static_cast<GuiderType
>(Options::guiderType());
2594void Guide::showFITSViewer()
2596 static int lastFVTabID = -1;
2603 fv->loadData(m_ImageData, url, &lastFVTabID);
2604 connect(fv.get(), &FITSViewer::terminated,
this, [
this]()
2609 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
2610 fv->loadData(m_ImageData, url, &lastFVTabID);
2616void Guide::setExternalGuiderBLOBEnabled(
bool enable)
2619 if (guiderType == GUIDE_INTERNAL)
2625 m_Camera->setBLOBEnabled(enable);
2627 if(m_Camera->isBLOBEnabled())
2629 checkUseGuideHead();
2631 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2633 targetChip->setCaptureMode(FITS_GUIDE);
2642 nonGuidedDitherRaOffsetMsec = 0;
2643 nonGuidedDitherDecOffsetMsec = 0;
2644 qCDebug(KSTARS_EKOS_GUIDE) <<
"Reset non guiding dithering position";
2647 if (!isNonGuidedDitherInitialized)
2649 auto seed = std::chrono::system_clock::now().time_since_epoch().count();
2650 nonGuidedPulseGenerator.seed(seed);
2651 isNonGuidedDitherInitialized =
true;
2652 qCDebug(KSTARS_EKOS_GUIDE) <<
"Initialize non guiding dithering random generator";
2656void Guide::nonGuidedDither()
2658 double ditherPulse = Options::ditherNoGuidingPulse();
2661 std::uniform_int_distribution<int> newPos(-ditherPulse, +ditherPulse);
2666 const int newRaOffsetMsec = newPos(nonGuidedPulseGenerator);
2667 const int raPulse = nonGuidedDitherRaOffsetMsec - newRaOffsetMsec;
2668 nonGuidedDitherRaOffsetMsec = newRaOffsetMsec;
2669 const int raMsec = std::abs(raPulse);
2670 const int raPolarity = (raPulse >= 0 ? 1 : -1);
2673 const int newDecOffsetMsec = newPos(nonGuidedPulseGenerator);
2674 const int decPulse = nonGuidedDitherDecOffsetMsec - newDecOffsetMsec;
2675 nonGuidedDitherDecOffsetMsec = newDecOffsetMsec;
2676 const int decMsec = std::abs(decPulse);
2677 const int decPolarity = (decPulse >= 0 ? 1 : -1);
2679 qCInfo(KSTARS_EKOS_GUIDE) <<
"Starting non-guiding dither...";
2680 qCDebug(KSTARS_EKOS_GUIDE) <<
"dither ra_msec:" << raMsec <<
"ra_polarity:" << raPolarity <<
"de_msec:" << decMsec <<
2681 "de_polarity:" << decPolarity;
2683 bool rc = sendMultiPulse(raPolarity > 0 ? RA_INC_DIR : RA_DEC_DIR, raMsec, decPolarity > 0 ? DEC_INC_DIR : DEC_DEC_DIR,
2684 decMsec, DontCaptureAfterPulses);
2688 qCInfo(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither successful.";
2689 QTimer::singleShot( (raMsec > decMsec ? raMsec : decMsec) + Options::ditherSettle() * 1000 + 100,
this, [
this]()
2691 emit newStatus(GUIDE_DITHERING_SUCCESS);
2692 m_State = GUIDE_IDLE;
2697 qCWarning(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither failed.";
2698 emit newStatus(GUIDE_DITHERING_ERROR);
2699 m_State = GUIDE_IDLE;
2703void Guide::handleManualDither()
2705 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2706 if (targetChip ==
nullptr)
2709 Ui::ManualDither ditherDialog;
2710 QDialog container(
this);
2711 ditherDialog.setupUi(&container);
2713 if (guiderType != GUIDE_INTERNAL)
2715 ditherDialog.coordinatesR->setEnabled(
false);
2716 ditherDialog.x->setEnabled(
false);
2717 ditherDialog.y->setEnabled(
false);
2720 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2721 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2723 ditherDialog.x->setMinimum(minX);
2724 ditherDialog.x->setMaximum(maxX);
2725 ditherDialog.y->setMinimum(minY);
2726 ditherDialog.y->setMaximum(maxY);
2728 ditherDialog.x->setValue(starCenter.x());
2729 ditherDialog.y->setValue(starCenter.y());
2733 if (ditherDialog.magnitudeR->isChecked())
2734 m_GuiderInstance->dither(ditherDialog.magnitude->value());
2737 InternalGuider *
const ig =
dynamic_cast<InternalGuider *
>(m_GuiderInstance);
2739 ig->ditherXY(ditherDialog.x->value(), ditherDialog.y->value());
2746 setStatus(GUIDE_IDLE);
2747 return m_GuiderInstance->Connect();
2752 return m_GuiderInstance->Disconnect();
2755void Guide::initPlots()
2758 initCalibrationPlot();
2766void Guide::initDriftGraph()
2776 driftGraph->setCorrectionGraphScale(correctionSlider->value());
2784 correctionSlider->setValue(scale);
2787void Guide::initCalibrationPlot()
2789 calibrationPlot->setBackground(QBrush(
Qt::black));
2790 calibrationPlot->setSelectionTolerance(10);
2792 calibrationPlot->xAxis->setBasePen(QPen(
Qt::white, 1));
2793 calibrationPlot->yAxis->setBasePen(QPen(
Qt::white, 1));
2795 calibrationPlot->xAxis->setTickPen(QPen(
Qt::white, 1));
2796 calibrationPlot->yAxis->setTickPen(QPen(
Qt::white, 1));
2798 calibrationPlot->xAxis->setSubTickPen(QPen(
Qt::white, 1));
2799 calibrationPlot->yAxis->setSubTickPen(QPen(
Qt::white, 1));
2801 calibrationPlot->xAxis->setTickLabelColor(
Qt::white);
2802 calibrationPlot->yAxis->setTickLabelColor(
Qt::white);
2804 calibrationPlot->xAxis->setLabelColor(
Qt::white);
2805 calibrationPlot->yAxis->setLabelColor(
Qt::white);
2807 calibrationPlot->xAxis->setLabelFont(QFont(
font().family(), 10));
2808 calibrationPlot->yAxis->setLabelFont(QFont(
font().family(), 10));
2809 calibrationPlot->xAxis->setTickLabelFont(QFont(
font().family(), 9));
2810 calibrationPlot->yAxis->setTickLabelFont(QFont(
font().family(), 9));
2812 calibrationPlot->xAxis->setLabelPadding(2);
2813 calibrationPlot->yAxis->setLabelPadding(2);
2815 calibrationPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1,
Qt::DotLine));
2816 calibrationPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1,
Qt::DotLine));
2817 calibrationPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1,
Qt::DotLine));
2818 calibrationPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1,
Qt::DotLine));
2819 calibrationPlot->xAxis->grid()->setZeroLinePen(QPen(
Qt::gray));
2820 calibrationPlot->yAxis->grid()->setZeroLinePen(QPen(
Qt::gray));
2822 calibrationPlot->xAxis->setLabel(
i18n(
"dx (pixels)"));
2823 calibrationPlot->yAxis->setLabel(
i18n(
"dy (pixels)"));
2825 calibrationPlot->xAxis->setRange(-20, 20);
2826 calibrationPlot->yAxis->setRange(-20, 20);
2831 calibrationPlot->addGraph();
2834 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"RAGuideError"), 2),
2836 calibrationPlot->graph(GuideGraph::G_RA)->setName(
"RA+");
2838 calibrationPlot->addGraph();
2843 calibrationPlot->graph(GuideGraph::G_DEC)->setName(
"RA-");
2845 calibrationPlot->addGraph();
2846 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
2850 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setName(
"Backlash");
2852 calibrationPlot->addGraph();
2853 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
2855 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"DEGuideError"), 2),
2857 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setName(
"DEC+");
2859 calibrationPlot->addGraph();
2860 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setLineStyle(
QCPGraph::lsNone);
2864 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setName(
"DEC-");
2866 calLabel =
new QCPItemText(calibrationPlot);
2867 calLabel->setColor(QColor(255, 255, 255));
2870 calLabel->position->setCoords(0.5, 0);
2871 calLabel->setText(
"");
2872 calLabel->setFont(QFont(
font().family(), 10));
2873 calLabel->setVisible(
true);
2875 calRALabel =
new QCPItemText(calibrationPlot);
2876 calRALabel->setText(
"RA");
2879 calRALabel->setVisible(
false);
2880 calRAArrow =
new QCPItemLine(calibrationPlot);
2883 calRAArrow->setVisible(
false);
2885 calDECLabel =
new QCPItemText(calibrationPlot);
2886 calDECLabel->setText(
"DEC");
2888 calDECLabel->setPen(QPen(
Qt::white, 1));
2889 calDECLabel->setVisible(
false);
2890 calDECArrow =
new QCPItemLine(calibrationPlot);
2891 calDECArrow->setPen(QPen(
Qt::white, 1));
2893 calDECArrow->setVisible(
false);
2895 calibrationPlot->resize(190, 190);
2896 calibrationPlot->replot();
2899void Guide::initView()
2901 guideStateWidget =
new GuideStateWidget();
2902 guideInfoLayout->insertWidget(-1, guideStateWidget);
2904 m_GuideView.reset(
new GuideView(guideWidget, FITS_GUIDE));
2906 m_GuideView->setBaseSize(guideWidget->size());
2907 m_GuideView->createFloatingToolBar();
2908 QVBoxLayout *vlayout =
new QVBoxLayout();
2910 guideWidget->setLayout(vlayout);
2912 guideInfoLabel->setVisible(
false);
2913 guideInfoText->setVisible(
false);
2916void Guide::initConnections()
2919 captureTimeout.setSingleShot(
true);
2923 m_DebounceTimer.setInterval(500);
2924 m_DebounceTimer.setSingleShot(
true);
2929 &Ekos::Guide::updateTrackingBoxSize);
2934 if(guiderType != GUIDE_PHD2)
2939 &Ekos::Guide::updateCCDBin);
2954 m_State = GUIDE_CAPTURE;
2955 emit newStatus(m_State);
2957 if(guiderType == GUIDE_PHD2)
2959 configurePHD2Camera();
2960 if(phd2Guider->isCurrentCameraNotInEkos())
2962 i18n(
"The PHD2 camera is not available to Ekos, so you cannot see the captured images. But you will still see the Guide Star Image when you guide."));
2963 else if(guideSubframe->isChecked())
2966 i18n(
"To receive PHD2 images other than the Guide Star Image, SubFrame must be unchecked. Unchecking it now to enable your image captures. You can re-enable it before Guiding"));
2967 guideSubframe->setChecked(
false);
2969 phd2Guider->captureSingleFrame();
2971 else if (guiderType == GUIDE_INTERNAL)
2992 m_GuiderInstance->Connect();
2997 m_GuiderInstance->Disconnect();
3001 m_PulseTimer.setSingleShot(
true);
3006 &Ekos::Guide::buildTarget);
3011 driftGraph->toggleShowPlot(GuideGraph::G_RA, isChecked);
3015 driftGraph->toggleShowPlot(GuideGraph::G_DEC, isChecked);
3019 driftGraph->toggleShowPlot(GuideGraph::G_RA_PULSE, isChecked);
3023 driftGraph->toggleShowPlot(GuideGraph::G_DEC_PULSE, isChecked);
3027 driftGraph->toggleShowPlot(GuideGraph::G_SNR, isChecked);
3031 driftGraph->toggleShowPlot(GuideGraph::G_RMS, isChecked);
3037 connect(
this, &Ekos::Guide::newStatus, guideStateWidget, &Ekos::GuideStateWidget::updateGuideStatus);
3040void Guide::removeDevice(
const QSharedPointer<ISD::GenericDevice> &device)
3042 auto name = device->getDeviceName();
3044 device->disconnect(
this);
3047 if (m_Mount && m_Mount->getDeviceName() == name)
3049 m_Mount->disconnect(
this);
3055 if (m_Camera && m_Camera->getDeviceName() == name)
3057 m_Camera->disconnect(
this);
3063 if (m_Guider && m_Guider->getDeviceName() == name)
3065 m_Guider->disconnect(
this);
3071 if (m_AO && m_AO->getDeviceName() == name)
3073 m_AO->disconnect(
this);
3080 m_State = GUIDE_LOOPING;
3081 emit newStatus(m_State);
3083 if(guiderType == GUIDE_PHD2)
3085 configurePHD2Camera();
3086 if(phd2Guider->isCurrentCameraNotInEkos())
3088 i18n(
"The PHD2 camera is not available to Ekos, so you cannot see the captured images. But you will still see the Guide Star Image when you guide."));
3089 else if(guideSubframe->isChecked())
3092 i18n(
"To receive PHD2 images other than the Guide Star Image, SubFrame must be unchecked. Unchecking it now to enable your image captures. You can re-enable it before Guiding"));
3093 guideSubframe->setChecked(
false);
3096 stopB->setEnabled(
true);
3098 else if (guiderType == GUIDE_INTERNAL)
3105QVariantMap Guide::getAllSettings()
const
3107 QVariantMap settings;
3111 settings.insert(oneWidget->objectName(), oneWidget->currentText());
3115 settings.insert(oneWidget->objectName(), oneWidget->value());
3119 settings.insert(oneWidget->objectName(), oneWidget->value());
3123 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
3131void Guide::setAllSettings(
const QVariantMap &settings)
3135 disconnectSettings();
3137 for (
auto &name : settings.keys())
3143 syncControl(settings, name, comboBox);
3151 syncControl(settings, name, doubleSpinBox);
3159 syncControl(settings, name, spinBox);
3167 syncControl(settings, name, checkbox);
3173 for (
auto &key : settings.keys())
3175 auto value = settings[key];
3177 Options::self()->setProperty(key.toLatin1(), value);
3179 m_Settings[key] = value;
3180 m_GlobalSettings[key] = value;
3183 emit settingsUpdated(getAllSettings());
3186 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
3187 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Guide, m_Settings);
3196bool Guide::syncControl(
const QVariantMap &settings,
const QString &key, QWidget * widget)
3198 QSpinBox *pSB =
nullptr;
3199 QDoubleSpinBox *pDSB =
nullptr;
3200 QCheckBox *pCB =
nullptr;
3201 QComboBox *pComboBox =
nullptr;
3202 QRadioButton *pRadioButton =
nullptr;
3207 const int value = settings[key].toInt(&ok);
3216 const double value = settings[key].toDouble(&ok);
3225 const bool value = settings[key].toBool();
3232 const bool value = settings[key].toBool();
3240 const QString value = settings[key].toString();
3248void Guide::setupOpticalTrainManager()
3250 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Guide::refreshOpticalTrain);
3253 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
3257 if (guiderType == GUIDE_PHD2 && m_GuiderInstance->isConnected())
3259 appendLogText(
i18n(
"Cannot change active optical train while PHD2 is connected"));
3263 ProfileSettings::Instance()->setOneSetting(ProfileSettings::GuideOpticalTrain,
3264 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
3265 refreshOpticalTrain();
3266 emit trainChanged();
3270void Guide::refreshOpticalTrain()
3272 opticalTrainCombo->blockSignals(
true);
3273 opticalTrainCombo->clear();
3274 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
3275 trainB->setEnabled(
true);
3277 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::GuideOpticalTrain);
3281 auto id = trainID.
toUInt();
3284 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
3286 qCWarning(KSTARS_EKOS_GUIDE) <<
"Optical train doesn't exist for id" << id;
3287 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
3290 auto name = OpticalTrainManager::Instance()->name(
id);
3292 opticalTrainCombo->setCurrentText(name);
3294 auto scope = OpticalTrainManager::Instance()->getScope(name);
3295 m_FocalLength = scope[
"focal_length"].
toDouble(-1);
3296 m_Aperture = scope[
"aperture"].toDouble(-1);
3297 m_FocalRatio = scope[
"focal_ratio"].toDouble(-1);
3298 m_Reducer = OpticalTrainManager::Instance()->getReducer(name);
3301 if (m_Aperture < 0 && m_FocalRatio > 0)
3302 m_Aperture = m_FocalLength / m_FocalRatio;
3304 auto mount = OpticalTrainManager::Instance()->getMount(name);
3307 auto camera = OpticalTrainManager::Instance()->getCamera(name);
3310 if (guiderType == GUIDE_INTERNAL)
3311 starCenter = QVector3D();
3313 camera->setScopeInfo(m_FocalLength * m_Reducer, m_Aperture);
3314 opticalTrainCombo->setToolTip(QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
3318 syncTelescopeInfo();
3320 auto guider = OpticalTrainManager::Instance()->getGuider(name);
3323 auto ao = OpticalTrainManager::Instance()->getAdaptiveOptics(name);
3327 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
3328 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Guide);
3329 if (settings.isValid())
3331 auto map = settings.toJsonObject().toVariantMap();
3332 if (map != m_Settings)
3335 setAllSettings(map);
3339 m_Settings = m_GlobalSettings;
3342 opticalTrainCombo->blockSignals(
false);
3345void Guide::loadGlobalSettings()
3350 QVariantMap settings;
3354 if (oneWidget->objectName() ==
"opticalTrainCombo")
3357 key = oneWidget->objectName();
3358 value = Options::self()->property(key.
toLatin1());
3359 if (value.
isValid() && oneWidget->count() > 0)
3361 oneWidget->setCurrentText(value.
toString());
3362 settings[key] = value;
3369 key = oneWidget->objectName();
3370 value = Options::self()->property(key.
toLatin1());
3373 oneWidget->setValue(value.
toDouble());
3374 settings[key] = value;
3381 key = oneWidget->objectName();
3382 value = Options::self()->property(key.
toLatin1());
3385 oneWidget->setValue(value.
toInt());
3386 settings[key] = value;
3393 key = oneWidget->objectName();
3394 value = Options::self()->property(key.
toLatin1());
3397 oneWidget->setChecked(value.
toBool());
3398 settings[key] = value;
3402 m_GlobalSettings = m_Settings = settings;
3405void Guide::connectSettings()
3431void Guide::disconnectSettings()
3458 Options::self()->setProperty(key.
toLatin1(), value);
3459 m_Settings[key] = value;
3460 m_GlobalSettings[key] = value;
3462 m_DebounceTimer.start();
3468void Guide::settleSettings()
3470 Options::self()->save();
3471 emit settingsUpdated(getAllSettings());
3473 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
3474 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Guide, m_Settings);
3477void Guide::syncSettings()
3491 value = dsb->
value();
3497 value = sb->
value();
3514 m_Settings.remove(key);
Q_SCRIPTABLE bool connectGuider()
DBUS interface function.
bool setMount(ISD::Mount *device)
Add new Mount.
Q_SCRIPTABLE bool calibrate()
DBUS interface function.
void updateProperty(INDI::Property prop)
processCCDNumber Process number properties arriving from CCD.
Q_SCRIPTABLE Q_NOREPLY void setAutoStarEnabled(bool enable)
DBUS interface function.
Q_SCRIPTABLE Q_NOREPLY void setDarkFrameEnabled(bool enable)
DBUS interface function.
void processData(const QSharedPointer< FITSData > &data)
newFITS is called by the INDI framework whenever there is a new BLOB arriving
Q_SCRIPTABLE bool resume()
DBUS interface function.
void setTrackingStar(int x, int y)
setTrackingStar Gets called when the user select a star in the guide frame
Q_SCRIPTABLE bool setGuiderType(int type)
DBUS interface function.
void checkExposureValue(ISD::CameraChip *targetChip, double exposure, IPState expState)
checkExposureValue This function is called by the INDI framework whenever there is a new exposure val...
void updateSetting(const QString &key, const QVariant &value)
updateSetting Update per-train and global setting
bool setGuider(ISD::Guider *device)
Add new Guider.
Q_SCRIPTABLE bool suspend()
DBUS interface function.
Q_SCRIPTABLE bool dither()
DBUS interface function.
void resetNonGuidedDither()
Reset non guided dithering properties and initialize the random generator seed if not already done.
Q_SCRIPTABLE Q_NOREPLY void setExposure(double value)
DBUS interface function.
Q_SCRIPTABLE Q_NOREPLY void setSubFrameEnabled(bool enable)
DBUS interface function.
void checkCamera()
checkCamera Check all CCD parameters and ensure all variables are updated to reflect the selected CCD
Q_SCRIPTABLE bool capture()
DBUS interface function.
Q_SCRIPTABLE Q_NOREPLY void clearCalibration()
DBUS interface function.
Q_SCRIPTABLE bool abort()
DBUS interface function.
Q_SCRIPTABLE bool disconnectGuider()
DBUS interface function.
bool setAdaptiveOptics(ISD::AdaptiveOptics *device)
Add new Adaptive Optics.
void setDECSwap(bool enable)
setDECSwap Change ST4 declination pulse direction.
Q_SCRIPTABLE void clearLog()
clearLog As the name suggests
Q_SCRIPTABLE Q_NOREPLY void loop()
DBUS interface function.
Q_SCRIPTABLE bool guide()
DBUS interface function.
bool setCamera(ISD::Camera *device)
Add new Camera.
Uses external LinGuider for guiding.
Uses external PHD2 for guiding.
AdaptiveOptics class handles control of INDI AdaptiveOptics devices.
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
device handle controlling Mounts.
KPageWidgetItem * addPage(QWidget *page, const QString &itemName, const QString &pixmapName=QString(), const QString &header=QString(), bool manage=true)
void setIcon(const QIcon &icon)
static KStars * Instance()
void colorSchemeChanged()
DBUS interface notification.
Manages a single axis inside a QCustomPlot.
void rangeChanged(const QCPRange &newRange)
Q_SLOT void setRange(const QCPRange &range)
@ lsNone
data points are not connected with any lines (e.g.
void setHead(const QCPLineEnding &head)
void setType(PositionType type)
void setCoords(double key, double value)
@ ptAxisRectRatio
Static positioning given by a fraction of the axis rect size (see setAxisRect).
@ ptPlotCoords
Dynamic positioning at a plot coordinate defined by two axes (see setAxes).
void setBrush(const QBrush &brush)
void setText(const QString &text)
void setPositionAlignment(Qt::Alignment alignment)
void setFont(const QFont &font)
void setPen(const QPen &pen)
void setColor(const QColor &color)
@ esSpikeArrow
A filled arrow head with an indented back.
Represents the range an axis is encompassing.
@ ssDisc
\enumimage{ssDisc.png} a circle which is filled with the pen's color (not the brush as with ssCircle)
@ ssPlus
\enumimage{ssPlus.png} a plus
@ ssCircle
\enumimage{ssCircle.png} a circle
void mouseMove(QMouseEvent *event)
void mousePress(QMouseEvent *event)
The QProgressIndicator class lets an application display a progress indicator to show that a long tas...
void startAnimation()
Starts the spin animation.
bool isAnimated() const
Returns a Boolean value indicating whether the component is currently animated.
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
CaptureState
Capture states.
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
bool isValid(QStringView ifopt)
QString name(StandardAction id)
@ iRangeDrag
0x001 Axis ranges are draggable (see QCPAxisRect::setRangeDrag, QCPAxisRect::setRangeDragAxes)
@ iRangeZoom
0x002 Axis ranges are zoomable with the mouse wheel (see QCPAxisRect::setRangeZoom,...
void sliderMoved(int value)
void activated(int index)
void currentIndexChanged(int index)
void setCurrentText(const QString &text)
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
void setValue(double val)
void valueChanged(double d)
QIcon fromTheme(const QString &name)
bool contains(const Key &key) 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
T qobject_cast(QObject *object)
QObject * sender() const const
bool isNull() const const
void splitterMoved(int pos, int index)
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
double toDouble(bool *ok) const const
QByteArray toLatin1() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
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