9 #include "guideadaptor.h"
11 #include "ksmessagebox.h"
12 #include "ksnotification.h"
13 #include "kstarsdata.h"
14 #include "opscalibration.h"
16 #include "opsdither.h"
19 #include "indi/indiguider.h"
20 #include "indi/indiadaptiveoptics.h"
21 #include "auxiliary/QProgressIndicator.h"
22 #include "ekos/manager.h"
23 #include "ekos/auxiliary/darklibrary.h"
24 #include "externalguide/linguider.h"
25 #include "externalguide/phd2.h"
26 #include "fitsviewer/fitsdata.h"
27 #include "fitsviewer/fitsview.h"
28 #include "fitsviewer/fitsviewer.h"
29 #include "internalguide/internalguider.h"
30 #include "guideview.h"
31 #include "guidegraph.h"
33 #include <KConfigDialog>
35 #include <basedevice.h>
36 #include <ekos_guide_debug.h>
38 #include "ui_manualdither.h"
42 #define CAPTURE_TIMEOUT_THRESHOLD 30000
49 internalGuider =
new InternalGuider();
53 opsGuide =
new OpsGuide();
56 connect(opsGuide, &OpsGuide::settingsUpdated, [
this]()
58 onThresholdChanged(Options::guideAlgorithm());
59 configurePHD2Camera();
60 configSEPMultistarOptions();
63 opsCalibration =
new OpsCalibration(internalGuider);
64 page = dialog->
addPage(opsCalibration,
i18n(
"Calibration"));
67 opsDither =
new OpsDither();
71 opsGPG =
new OpsGPG(internalGuider);
72 page = dialog->
addPage(opsGPG,
i18n(
"GPG RA Guider"));
79 qRegisterMetaType<Ekos::GuideState>(
"Ekos::GuideState");
80 qDBusRegisterMetaType<Ekos::GuideState>();
81 new GuideAdaptor(
this);
89 internalGuider->setGuideView(m_GuideView);
99 controlLayout->addWidget(pi, 1, 2, 1, 1);
101 showFITSViewerB->setIcon(
106 guideAutoScaleGraphB->setIcon(
111 guideSaveDataB->setIcon(
116 guideDataClearB->setIcon(
123 guideZoomInXB->setText(
"+");
129 guideZoomOutXB->setText(
"-");
137 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
139 exposureIN->setRecommendedValues(exposureValues);
140 connect(exposureIN, &NonLinearDoubleSpinBox::editingFinished,
this, &Ekos::Guide::saveDefaultGuideExposure);
145 Options::setGuideDelay(GuideDelay->value());
152 if(guiderType == GUIDE_PHD2)
154 setExternalGuiderBLOBEnabled(!Options::guideSubframeEnabled());
159 opsDither->kcfg_DitherTimeout->setEnabled(
false);
160 opsDither->kcfg_DitherThreshold->setEnabled(
false);
161 opsDither->kcfg_DitherMaxIterations->setEnabled(!Options::ditherWithOnePulse());
165 resetNonGuidedDither();
170 for (
auto &button : qButtons)
171 button->setAutoDefault(
false);
175 m_DarkProcessor =
new DarkProcessor(
this);
176 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &Ekos::Guide::appendLogText);
177 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, [
this](
bool completed)
179 if (completed != darkFrameCheck->isChecked())
180 setDarkFrameEnabled(completed);
181 m_GuideView->setProperty(
"suspended",
false);
184 m_GuideView->rescale(ZOOM_KEEP_LEVEL);
185 m_GuideView->updateFrame();
187 m_GuideView->updateFrame();
188 setCaptureComplete();
194 delete m_GuiderInstance;
197 void Guide::handleHorizontalPlotSizeChange()
199 targetPlot->handleHorizontalPlotSizeChange();
200 calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0);
201 calibrationPlot->replot();
204 void Guide::handleVerticalPlotSizeChange()
206 targetPlot->handleVerticalPlotSizeChange();
207 calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0);
208 calibrationPlot->replot();
211 void Guide::guideAfterMeridianFlip()
215 m_GuideView->setTrackingBoxEnabled(
false);
218 if (Options::resetGuideCalibration())
222 if (Options::gPGEnabled())
223 m_GuiderInstance->resetGPG();
230 if (
event->oldSize().width() != -1)
232 if (
event->oldSize().width() != size().width())
233 handleHorizontalPlotSizeChange();
234 else if (
event->oldSize().height() != size().height())
235 handleVerticalPlotSizeChange();
243 void Guide::buildTarget()
245 double accuracyRadius = accuracyRadiusSpin->value();
246 Options::setGuiderAccuracyThreshold(accuracyRadius);
247 targetPlot->buildTarget(accuracyRadius);
250 void Guide::clearGuideGraphs()
256 void Guide::clearCalibrationGraphs()
258 calibrationPlot->graph(GuideGraph::G_RA)->data()->clear();
259 calibrationPlot->graph(GuideGraph::G_DEC)->data()->clear();
260 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear();
261 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear();
262 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->data()->clear();
263 calibrationPlot->replot();
266 void Guide::slotAutoScaleGraphs()
268 driftGraph->zoomX(defaultXZoomLevel);
270 driftGraph->autoScaleGraphs();
271 targetPlot->autoScaleGraphs(accuracyRadiusSpin->value());
273 calibrationPlot->rescaleAxes();
274 calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0);
275 calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0);
276 calibrationPlot->replot();
279 void Guide::guideHistory()
281 int sliderValue = guideSlider->value();
282 latestCheck->setChecked(sliderValue == guideSlider->maximum() - 1 || sliderValue == guideSlider->maximum());
283 double ra = driftGraph->graph(GuideGraph::G_RA)->dataMainValue(sliderValue);
284 double de = driftGraph->graph(GuideGraph::G_DEC)->dataMainValue(sliderValue);
285 driftGraph->guideHistory(sliderValue, graphOnLatestPt);
287 targetPlot->showPoint(ra, de);
290 void Guide::setLatestGuidePoint(
bool isChecked)
292 graphOnLatestPt = isChecked;
293 driftGraph->setLatestGuidePoint(isChecked);
294 targetPlot->setLatestGuidePoint(isChecked);
297 guideSlider->setValue(guideSlider->maximum());
302 exposureIN->setRecommendedValues(values);
303 return exposureIN->getRecommendedValuesString();
309 for (
auto &oneCamera : m_Cameras)
311 if (oneCamera->getDeviceName() == device->getDeviceName())
315 for (
auto &oneCamera : m_Cameras)
316 oneCamera->disconnect(
this);
319 m_Cameras.append(device);
321 if(guiderType != GUIDE_INTERNAL)
331 m_Camera->setBLOBEnabled(
false);
332 cameraCombo->clear();
333 cameraCombo->setEnabled(
false);
334 if (guiderType == GUIDE_PHD2)
335 cameraCombo->addItem(
"PHD2");
337 cameraCombo->addItem(
"LinGuider");
341 cameraCombo->setEnabled(
true);
342 cameraCombo->addItem(m_Camera->getDeviceName());
343 if (device->hasGuideHead())
344 addGuideHead(device);
353 configurePHD2Camera();
357 void Guide::configurePHD2Camera()
361 if(guiderType != GUIDE_PHD2)
368 if(!phd2Guider->isConnected())
372 if(phd2Guider->getCurrentCamera().isEmpty())
374 phd2Guider->requestCurrentEquipmentUpdate();
380 QString currentPHD2CameraName =
"None";
381 for(
auto &oneCamera : m_Cameras)
383 if(phd2Guider->getCurrentCamera().contains(oneCamera->getDeviceName()))
385 ccdMatch = oneCamera;
386 currentPHD2CameraName = (phd2Guider->getCurrentCamera());
394 if(lastPHD2CameraName == currentPHD2CameraName)
396 setExternalGuiderBLOBEnabled(!Options::guideSubframeEnabled());
402 setExternalGuiderBLOBEnabled(
false);
408 lastPHD2CameraName = currentPHD2CameraName;
411 phd2Guider->setCurrentCameraIsNotInEkos(m_Camera ==
nullptr);
413 if(phd2Guider->isCurrentCameraNotInEkos())
416 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.",
417 phd2Guider->getCurrentCamera()));
418 subFrameCheck->setEnabled(
false);
421 subFrameCheck->setChecked(
true);
426 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.",
427 phd2Guider->getCurrentCamera()));
428 subFrameCheck->setEnabled(
true);
430 subFrameCheck->setChecked(Options::guideSubframeEnabled());
435 if (guiderType != GUIDE_INTERNAL)
438 m_Cameras.append(device);
440 QString guiderName = device->getDeviceName() +
QString(
" Guider");
442 if (cameraCombo->findText(guiderName) == -1)
444 cameraCombo->addItem(guiderName);
453 for (
auto &oneMount : m_Mounts)
455 if (oneMount->getDeviceName() == device->getDeviceName())
459 for (
auto &oneMount : m_Mounts)
460 oneMount->disconnect(
this);
463 m_Mounts.append(device);
470 if (guiderType != GUIDE_INTERNAL)
473 for (
int i = 0; i < cameraCombo->count(); i++)
474 if (device == cameraCombo->itemText(i))
476 cameraCombo->setCurrentIndex(i);
479 updateCCDBin(guideBinIndex);
496 return m_Camera->getDeviceName();
501 void Guide::checkCamera(
int ccdNum)
505 if (guiderType != GUIDE_INTERNAL)
513 case GUIDE_CONNECTED:
514 case GUIDE_DISCONNECTED:
515 case GUIDE_CALIBRATION_ERROR:
523 case GUIDE_STAR_SELECT:
524 case GUIDE_CALIBRATING:
525 case GUIDE_CALIBRATION_SUCCESS:
527 case GUIDE_SUSPENDED:
528 case GUIDE_REACQUIRE:
529 case GUIDE_DITHERING:
530 case GUIDE_MANUAL_DITHERING:
531 case GUIDE_DITHERING_ERROR:
532 case GUIDE_DITHERING_SUCCESS:
533 case GUIDE_DITHERING_SETTLE:
539 ccdNum = cameraCombo->currentIndex();
545 if (ccdNum <= m_Cameras.count())
547 m_Camera = m_Cameras.at(ccdNum);
549 if (m_Camera->hasGuideHead() && cameraCombo->currentText().contains(
"Guider"))
552 useGuideHead =
false;
554 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
557 qCCritical(KSTARS_EKOS_GUIDE) <<
"Failed to retrieve active guide chip in camera";
561 if (targetChip->isCapturing())
564 if (guiderType != GUIDE_INTERNAL)
571 for (
auto &oneCamera : m_Cameras)
572 oneCamera->disconnect(
this);
581 void Guide::syncCameraInfo()
586 auto nvp = m_Camera->getNumber(useGuideHead ?
"GUIDER_INFO" :
"CCD_INFO");
590 auto np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_X");
592 ccdPixelSizeX = np->getValue();
594 np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_Y");
596 ccdPixelSizeY = np->getValue();
598 np = nvp->findWidgetByName(
"CCD_PIXEL_SIZE_Y");
600 ccdPixelSizeY = np->getValue();
606 void Guide::setTelescopeInfo(
double primaryFocalLength,
double primaryAperture,
double guideFocalLength,
607 double guideAperture)
609 if (primaryFocalLength > 0)
610 focal_length = primaryFocalLength;
611 if (primaryAperture > 0)
612 aperture = primaryAperture;
614 if (guideFocalLength > 0)
615 focal_length = guideFocalLength;
616 if (guideAperture > 0)
617 aperture = guideAperture;
622 void Guide::syncTelescopeInfo()
624 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
627 auto nvp = m_Mount->getNumber(
"TELESCOPE_INFO");
631 auto np = nvp->findWidgetByName(
"TELESCOPE_APERTURE");
633 if (np && np->getValue() > 0)
634 primaryAperture = np->getValue();
636 np = nvp->findWidgetByName(
"GUIDER_APERTURE");
637 if (np && np->getValue() > 0)
638 guideAperture = np->getValue();
640 aperture = primaryAperture;
643 if (FOVScopeCombo->currentIndex() == ISD::Camera::TELESCOPE_GUIDE)
644 aperture = guideAperture;
646 np = nvp->findWidgetByName(
"TELESCOPE_FOCAL_LENGTH");
647 if (np && np->getValue() > 0)
648 primaryFL = np->getValue();
650 np = nvp->findWidgetByName(
"GUIDER_FOCAL_LENGTH");
651 if (np && np->getValue() > 0)
652 guideFL = np->getValue();
654 focal_length = primaryFL;
657 if (FOVScopeCombo->currentIndex() == ISD::Camera::TELESCOPE_GUIDE)
658 focal_length = guideFL;
664 void Guide::updateGuideParams()
666 if (m_Camera ==
nullptr)
669 if (m_Camera->hasGuideHead() ==
false)
670 useGuideHead =
false;
672 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
674 if (targetChip ==
nullptr)
676 appendLogText(
i18n(
"Connection to the guide CCD is lost."));
680 if (targetChip->getFrameType() != FRAME_LIGHT)
683 if(guiderType == GUIDE_INTERNAL)
684 binningCombo->setEnabled(targetChip->canBin());
686 int subBinX = 1, subBinY = 1;
687 if (targetChip->canBin())
689 int maxBinX, maxBinY;
691 targetChip->getBinning(&subBinX, &subBinY);
692 targetChip->getMaxBin(&maxBinX, &maxBinY);
695 if( guideBinIndex >= 0 && guideBinIndex < maxBinX && guideBinIndex < maxBinY )
697 subBinX = guideBinIndex + 1;
698 subBinY = guideBinIndex + 1;
701 guideBinIndex = subBinX - 1;
703 binningCombo->blockSignals(
true);
705 binningCombo->clear();
706 for (
int i = 1; i <= maxBinX; i++)
707 binningCombo->addItem(
QString(
"%1x%2").arg(i).arg(i));
709 binningCombo->setCurrentIndex( guideBinIndex );
711 binningCombo->blockSignals(
false);
715 if (frameSettings.contains(targetChip) ==
false)
718 if (targetChip->getFrame(&x, &y, &w, &h))
722 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
723 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
725 QVariantMap settings;
727 settings[
"x"] = Options::guideSubframeEnabled() ? x : minX;
728 settings[
"y"] = Options::guideSubframeEnabled() ? y : minY;
729 settings[
"w"] = Options::guideSubframeEnabled() ? w : maxW;
730 settings[
"h"] = Options::guideSubframeEnabled() ? h : maxH;
731 settings[
"binx"] = subBinX;
732 settings[
"biny"] = subBinY;
734 frameSettings[targetChip] = settings;
741 QVariantMap settings = frameSettings[targetChip];
742 settings[
"binx"] = subBinX;
743 settings[
"biny"] = subBinY;
744 frameSettings[targetChip] = settings;
747 if (ccdPixelSizeX != -1 && ccdPixelSizeY != -1 && aperture != -1 && focal_length != -1)
749 FOVScopeCombo->setItemData(
750 ISD::Camera::TELESCOPE_PRIMARY,
751 i18nc(
"F-Number, Focal length, Aperture",
752 "<nobr>F<b>%1</b> Focal length: <b>%2</b> mm Aperture: <b>%3</b> mm<sup>2</sup></nobr>",
756 FOVScopeCombo->setItemData(
757 ISD::Camera::TELESCOPE_GUIDE,
758 i18nc(
"F-Number, Focal length, Aperture",
759 "<nobr>F<b>%1</b> Focal length: <b>%2</b> mm Aperture: <b>%3</b> mm<sup>2</sup></nobr>",
764 m_GuiderInstance->setGuiderParams(ccdPixelSizeX, ccdPixelSizeY, aperture, focal_length);
765 emit guideChipUpdated(targetChip);
768 if (targetChip->getFrame(&x, &y, &w, &h))
770 m_GuiderInstance->setFrameParams(x, y, w, h, subBinX, subBinY);
777 l_FbyD->setText(
"0");
786 pixScaleX = 206264.8062470963552 * ccdPixelSizeX / 1000.0 / focal_length;
787 pixScaleY = 206264.8062470963552 * ccdPixelSizeY / 1000.0 / focal_length;
791 double fov_w = (w * pixScaleX) / 60.0;
792 double fov_h = (h * pixScaleY) / 60.0;
798 bool Guide::addGuider(ISD::Guider *device)
800 if (guiderType != GUIDE_INTERNAL)
804 for (
auto &oneGuider : m_Guiders)
806 if (oneGuider->getDeviceName() == device->getDeviceName())
810 for (
auto &oneGuider : m_Guiders)
811 oneGuider->disconnect(
this);
814 m_Guiders.append(device);
815 guiderCombo->addItem(device->getDeviceName());
823 if (guiderType != GUIDE_INTERNAL)
827 for (
auto &oneAO : m_AdaptiveOptics)
829 if (oneAO->getDeviceName() == device->getDeviceName())
833 for (
auto &oneAO : m_AdaptiveOptics)
834 oneAO->disconnect(
this);
838 m_AdaptiveOptics.append(device);
844 if (guiderType != GUIDE_INTERNAL)
847 for (
int i = 0; i < m_Guiders.count(); i++)
848 if (m_Guiders.at(i)->getDeviceName() == device)
850 guiderCombo->setCurrentIndex(i);
860 if (guiderType != GUIDE_INTERNAL || guiderCombo->currentIndex() == -1)
863 return guiderCombo->currentText();
866 void Guide::setGuider(
int index)
868 if (m_Guiders.empty() || index >= m_Guiders.count() || guiderType != GUIDE_INTERNAL)
871 m_Guider = m_Guiders.at(index);
874 bool Guide::capture()
876 buildOperationStack(GUIDE_CAPTURE);
878 return executeOperationStack();
881 bool Guide::captureOneFrame()
883 captureTimeout.stop();
885 if (m_Camera ==
nullptr)
888 if (m_Camera->isConnected() ==
false)
890 appendLogText(
i18n(
"Error: lost connection to CCD."));
895 if (m_Camera->getTelescopeType() != FOVScopeCombo->currentIndex())
896 m_Camera->setTelescopeType(
static_cast<ISD::Camera::TelescopeType
>(FOVScopeCombo->currentIndex()));
898 double seqExpose = exposureIN->value();
900 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
902 prepareCapture(targetChip);
904 m_GuideView->setBaseSize(guideWidget->size());
908 if (frameSettings.contains(targetChip))
910 QVariantMap settings = frameSettings[targetChip];
911 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
912 settings[
"h"].toInt());
913 targetChip->setBinning(settings[
"binx"].toInt(), settings[
"biny"].toInt());
917 qCDebug(KSTARS_EKOS_GUIDE) <<
"Capturing frame...";
919 double finalExposure = seqExpose;
923 if (operationStack.contains(GUIDE_STAR_SELECT) && Options::guideAutoStarEnabled() &&
924 !((guiderType == GUIDE_INTERNAL) && internalGuider->SEPMultiStarEnabled()))
928 m_GuideView->setProperty(
"suspended", operationStack.contains(GUIDE_DARK));
931 captureTimeout.start(finalExposure * 1000 + CAPTURE_TIMEOUT_THRESHOLD);
933 targetChip->capture(finalExposure);
940 targetChip->setBatchMode(
false);
941 targetChip->setCaptureMode(FITS_GUIDE);
942 targetChip->setFrameType(FRAME_LIGHT);
943 targetChip->setCaptureFilter(FITS_NONE);
944 m_Camera->setEncodingFormat(
"FITS");
949 if (m_Camera && guiderType == GUIDE_INTERNAL)
951 captureTimeout.stop();
954 m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
955 if (targetChip->isCapturing())
956 targetChip->abortExposure();
959 manualDitherB->setEnabled(
false);
966 case GUIDE_CONNECTED:
967 case GUIDE_DISCONNECTED:
970 case GUIDE_CALIBRATING:
971 case GUIDE_DITHERING:
972 case GUIDE_STAR_SELECT:
976 m_GuiderInstance->abort();
986 void Guide::setBusy(
bool enable)
988 if (enable && pi->isAnimated())
990 else if (enable ==
false && pi->isAnimated() ==
false)
995 clearCalibrationB->setEnabled(
false);
996 guideB->setEnabled(
false);
997 captureB->setEnabled(
false);
998 loopB->setEnabled(
false);
1000 darkFrameCheck->setEnabled(
false);
1001 subFrameCheck->setEnabled(
false);
1002 autoStarCheck->setEnabled(
false);
1004 stopB->setEnabled(
true);
1006 pi->startAnimation();
1012 if(guiderType != GUIDE_LINGUIDER)
1014 captureB->setEnabled(
true);
1015 loopB->setEnabled(
true);
1016 autoStarCheck->setEnabled(!internalGuider->SEPMultiStarEnabled());
1018 subFrameCheck->setEnabled(!internalGuider->SEPMultiStarEnabled());
1020 if (guiderType == GUIDE_INTERNAL)
1021 darkFrameCheck->setEnabled(
true);
1023 if (calibrationComplete ||
1024 ((guiderType == GUIDE_INTERNAL) &&
1025 Options::reuseGuideCalibration() &&
1026 !Options::serializedCalibration().isEmpty()))
1027 clearCalibrationB->setEnabled(
true);
1028 guideB->setEnabled(
true);
1029 stopB->setEnabled(
false);
1030 pi->stopAnimation();
1036 void Guide::processCaptureTimeout()
1038 auto restartExposure = [&]()
1040 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
1041 m_Camera->setEncodingFormat(
"FITS");
1042 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1043 targetChip->abortExposure();
1044 prepareCapture(targetChip);
1045 targetChip->capture(exposureIN->value());
1046 captureTimeout.start(exposureIN->value() * 1000 + CAPTURE_TIMEOUT_THRESHOLD);
1049 m_CaptureTimeoutCounter++;
1051 if (m_Camera ==
nullptr)
1054 if (m_DeviceRestartCounter >= 3)
1056 m_CaptureTimeoutCounter = 0;
1057 m_DeviceRestartCounter = 0;
1058 if (m_State == GUIDE_GUIDING)
1059 appendLogText(
i18n(
"Exposure timeout. Aborting Autoguide."));
1060 else if (m_State == GUIDE_DITHERING)
1061 appendLogText(
i18n(
"Exposure timeout. Aborting Dithering."));
1062 else if (m_State == GUIDE_CALIBRATING)
1063 appendLogText(
i18n(
"Exposure timeout. Aborting Calibration."));
1065 captureTimeout.stop();
1070 if (m_CaptureTimeoutCounter > 1)
1072 QString camera = m_Camera->getDeviceName();
1073 QString via = m_Guider ? m_Guider->getDeviceName() :
"";
1074 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1075 QVariantMap settings = frameSettings[targetChip];
1076 emit driverTimedout(camera);
1079 m_DeviceRestartCounter++;
1080 reconnectDriver(camera, via, settings);
1089 void Guide::reconnectDriver(
const QString &camera,
const QString &via,
const QVariantMap &settings)
1091 for (
auto &oneCamera : m_Cameras)
1093 if (oneCamera->getDeviceName() == camera)
1096 cameraCombo->setCurrentIndex(cameraCombo->findText(camera));
1097 guiderCombo->setCurrentIndex(guiderCombo->findText(via));
1101 m_State = GUIDE_IDLE;
1106 if (guiderType == GUIDE_INTERNAL)
1109 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1110 frameSettings[targetChip] = settings;
1112 m_CaptureTimeoutCounter = 0;
1122 reconnectDriver(camera, via, settings);
1128 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1129 if (targetChip->getCaptureMode() != FITS_GUIDE)
1133 QString blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1134 .
arg(data->property(
"blobVector").toString())
1135 .
arg(data->property(
"blobElement").toString())
1136 .
arg(data->property(
"chip").toInt());
1138 qCWarning(KSTARS_EKOS_GUIDE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1139 targetChip->getCaptureMode();
1147 m_GuideView->loadData(data);
1151 m_ImageData.
reset();
1153 if (guiderType == GUIDE_INTERNAL)
1154 internalGuider->setImageData(m_ImageData);
1156 captureTimeout.stop();
1157 m_CaptureTimeoutCounter = 0;
1161 qCDebug(KSTARS_EKOS_GUIDE) <<
"Received guide frame.";
1163 int subBinX = 1, subBinY = 1;
1164 targetChip->getBinning(&subBinX, &subBinY);
1166 if (starCenter.x() == 0 && starCenter.y() == 0)
1168 int x = 0, y = 0, w = 0, h = 0;
1170 if (frameSettings.contains(targetChip))
1172 QVariantMap settings = frameSettings[targetChip];
1173 x = settings[
"x"].toInt();
1174 y = settings[
"y"].toInt();
1175 w = settings[
"w"].toInt();
1176 h = settings[
"h"].toInt();
1179 targetChip->getFrame(&x, &y, &w, &h);
1181 starCenter.setX(w / (2 * subBinX));
1182 starCenter.setY(h / (2 * subBinY));
1183 starCenter.setZ(subBinX);
1186 syncTrackingBoxPosition();
1188 setCaptureComplete();
1191 void Guide::setCaptureComplete()
1193 if (!m_GuideView.isNull())
1194 m_GuideView->clearNeighbors();
1196 DarkLibrary::Instance()->disconnect(
this);
1198 if (operationStack.isEmpty() ==
false)
1200 executeOperationStack();
1208 case GUIDE_CONNECTED:
1209 case GUIDE_DISCONNECTED:
1210 case GUIDE_CALIBRATION_SUCCESS:
1211 case GUIDE_CALIBRATION_ERROR:
1212 case GUIDE_DITHERING_ERROR:
1217 m_State = GUIDE_IDLE;
1218 emit newStatus(m_State);
1226 case GUIDE_CALIBRATING:
1227 m_GuiderInstance->calibrate();
1231 m_GuiderInstance->guide();
1234 case GUIDE_DITHERING:
1235 m_GuiderInstance->dither(Options::ditherPixels());
1239 case GUIDE_MANUAL_DITHERING:
1240 dynamic_cast<InternalGuider*
>(m_GuiderInstance)->processManualDithering();
1243 case GUIDE_REACQUIRE:
1244 m_GuiderInstance->reacquire();
1247 case GUIDE_DITHERING_SETTLE:
1248 if (Options::ditherNoGuiding())
1253 case GUIDE_SUSPENDED:
1254 if (Options::gPGEnabled())
1255 m_GuiderInstance->guide();
1262 emit newImage(m_GuideView);
1263 emit newStarPixmap(m_GuideView->getTrackingBoxPixmap(10));
1266 void Guide::appendLogText(
const QString &text)
1268 m_LogText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
1269 KStarsData::Instance()->lt().
toString(
"yyyy-MM-ddThh:mm:ss"), text));
1271 qCInfo(KSTARS_EKOS_GUIDE) << text;
1276 void Guide::clearLog()
1282 void Guide::setDECSwap(
bool enable)
1284 if (m_Guider ==
nullptr || m_GuiderInstance ==
nullptr)
1287 if (guiderType == GUIDE_INTERNAL)
1289 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setDECSwap(enable);
1290 m_Guider->setDECSwap(enable);
1294 bool Guide::sendMultiPulse(GuideDirection ra_dir,
int ra_msecs, GuideDirection dec_dir,
int dec_msecs)
1296 if (m_Guider ==
nullptr || (ra_dir == NO_DIR && dec_dir == NO_DIR))
1301 auto ms = std::max(ra_msecs, dec_msecs) + 100;
1302 auto delay = std::max(
static_cast<int>(Options::guideDelay() * 1000), ms);
1304 m_PulseTimer.start(delay);
1306 return m_Guider->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
1309 bool Guide::sendSinglePulse(GuideDirection dir,
int msecs)
1311 if (m_Guider ==
nullptr || dir == NO_DIR)
1316 auto ms = msecs + 100;
1317 auto delay = std::max(
static_cast<int>(Options::guideDelay() * 1000), ms);
1319 m_PulseTimer.start(delay);
1321 return m_Guider->doPulse(dir, msecs);
1328 for (
auto &oneGuider : m_Guiders)
1329 devices << oneGuider->getDeviceName();
1335 bool Guide::calibrate()
1338 m_State = GUIDE_IDLE;
1339 emit newStatus(m_State);
1341 if (guiderType == GUIDE_INTERNAL)
1343 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1345 if (frameSettings.contains(targetChip))
1347 targetChip->resetFrame();
1349 targetChip->getFrame(&x, &y, &w, &h);
1350 QVariantMap settings = frameSettings[targetChip];
1355 frameSettings[targetChip] = settings;
1363 buildOperationStack(GUIDE_CALIBRATING);
1365 executeOperationStack();
1367 qCDebug(KSTARS_EKOS_GUIDE) <<
"Starting calibration using CCD:" << m_Camera->getDeviceName() <<
"via" <<
1368 guiderCombo->currentText();
1375 auto executeGuide = [
this]()
1377 if(guiderType != GUIDE_PHD2)
1379 if (calibrationComplete ==
false)
1387 m_GuiderInstance->guide();
1393 if(!Options::guideAutoStarEnabled())
1395 if(guiderType == GUIDE_PHD2 && m_GuideView->isTrackingBoxEnabled())
1397 double x = starCenter.x();
1398 double y = starCenter.y();
1400 if(!m_ImageData.isNull())
1402 if(m_ImageData->width() > 50)
1404 guideConnect = connect(
this, &Guide::newStatus,
this, [
this, x, y](Ekos::GuideState newState)
1406 if(newState == GUIDE_GUIDING)
1408 phd2Guider->setLockPosition(x, y);
1409 disconnect(guideConnect);
1433 if (m_MountStatus == ISD::Mount::MOUNT_PARKED)
1435 KSMessageBox::Instance()->sorry(
i18n(
"The mount is parked. Unpark to start guiding."));
1443 bool Guide::dither()
1445 if (Options::ditherNoGuiding() && m_State == GUIDE_IDLE)
1451 if (m_State == GUIDE_DITHERING || m_State == GUIDE_DITHERING_SETTLE)
1455 double time = guideTimer.elapsed() / 1000.0;
1459 ditherLabel->position->
setCoords(time, 1.5);
1463 ditherLabel->
setText(
"Dither");
1466 if (guiderType == GUIDE_INTERNAL)
1468 if (m_State != GUIDE_GUIDING)
1471 setStatus(GUIDE_DITHERING);
1476 return m_GuiderInstance->dither(Options::ditherPixels());
1479 bool Guide::suspend()
1481 if (m_State == GUIDE_SUSPENDED)
1483 else if (m_State >= GUIDE_CAPTURE)
1484 return m_GuiderInstance->suspend();
1489 bool Guide::resume()
1491 if (m_State == GUIDE_GUIDING)
1493 else if (m_State == GUIDE_SUSPENDED)
1494 return m_GuiderInstance->resume();
1513 resetNonGuidedDither();
1520 void Guide::setPierSide(ISD::Mount::PierSide newSide)
1522 m_GuiderInstance->setPierSide(newSide);
1527 if (guiderType == GUIDE_INTERNAL &&
1528 m_State != GUIDE_GUIDING &&
1529 m_State != GUIDE_CALIBRATING &&
1530 calibrationComplete)
1533 if (Options::reuseGuideCalibration())
1534 calibrationComplete =
false;
1538 appendLogText(
i18n(
"Pier side change detected. Clearing calibration."));
1543 void Guide::setMountStatus(ISD::Mount::Status newState)
1545 m_MountStatus = newState;
1547 if (newState == ISD::Mount::MOUNT_PARKING || newState == ISD::Mount::MOUNT_SLEWING)
1550 if (Options::resetGuideCalibration())
1552 appendLogText(
i18n(
"Mount is moving. Resetting calibration..."));
1555 else if (Options::reuseGuideCalibration() && (guiderType == GUIDE_INTERNAL))
1558 calibrationComplete =
false;
1561 if (Options::gPGEnabled())
1562 m_GuiderInstance->resetGPG();
1565 if (m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1567 if (newState == ISD::Mount::MOUNT_PARKING)
1568 appendLogText(
i18n(
"Mount is parking. Aborting guide..."));
1570 appendLogText(
i18n(
"Mount is slewing. Aborting guide..."));
1576 if (guiderType != GUIDE_INTERNAL)
1581 case ISD::Mount::MOUNT_SLEWING:
1582 case ISD::Mount::MOUNT_PARKING:
1583 case ISD::Mount::MOUNT_MOVING:
1584 captureB->setEnabled(
false);
1585 loopB->setEnabled(
false);
1586 clearCalibrationB->setEnabled(
false);
1590 if (pi->isAnimated() ==
false)
1592 captureB->setEnabled(
true);
1593 loopB->setEnabled(
true);
1594 clearCalibrationB->setEnabled(
true);
1599 void Guide::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
1602 m_GuiderInstance->setMountCoords(position, pierSide);
1605 void Guide::setExposure(
double value)
1607 exposureIN->setValue(value);
1610 void Guide::setCalibrationTwoAxis(
bool enable)
1612 Options::setTwoAxisEnabled(enable);
1615 void Guide::setCalibrationAutoStar(
bool enable)
1617 autoStarCheck->setChecked(enable);
1620 void Guide::setCalibrationAutoSquareSize(
bool enable)
1622 Options::setGuideAutoSquareSizeEnabled(enable);
1625 void Guide::setCalibrationPulseDuration(
int pulseDuration)
1627 Options::setCalibrationPulseDuration(pulseDuration);
1630 void Guide::setGuideBoxSizeIndex(
int index)
1632 Options::setGuideSquareSizeIndex(index);
1635 void Guide::setGuideAlgorithmIndex(
int index)
1637 Options::setGuideAlgorithm(index);
1640 void Guide::setSubFrameEnabled(
bool enable)
1642 Options::setGuideSubframeEnabled(enable);
1643 if (subFrameCheck->isChecked() != enable)
1644 subFrameCheck->setChecked(enable);
1645 if(guiderType == GUIDE_PHD2)
1646 setExternalGuiderBLOBEnabled(!enable);
1650 void Guide::setDitherSettings(
bool enable,
double value)
1652 Options::setDitherEnabled(enable);
1653 Options::setDitherPixels(value);
1657 void Guide::clearCalibration()
1659 calibrationComplete =
false;
1661 m_GuiderInstance->clearCalibration();
1663 appendLogText(
i18n(
"Calibration is cleared."));
1666 void Guide::setStatus(Ekos::GuideState newState)
1668 if (newState == m_State)
1671 if (newState == GUIDE_ABORTED)
1672 emit newStatus(m_State);
1676 GuideState previousState = m_State;
1679 emit newStatus(m_State);
1683 case GUIDE_CONNECTED:
1684 appendLogText(
i18n(
"External guider connected."));
1685 externalConnectB->setEnabled(
false);
1686 externalDisconnectB->setEnabled(
true);
1687 clearCalibrationB->setEnabled(
true);
1688 guideB->setEnabled(
true);
1690 if(guiderType == GUIDE_PHD2)
1692 captureB->setEnabled(
true);
1693 loopB->setEnabled(
true);
1694 autoStarCheck->setEnabled(
true);
1695 configurePHD2Camera();
1696 setExternalGuiderBLOBEnabled(!Options::guideSubframeEnabled());
1697 boxSizeCombo->setEnabled(
true);
1701 case GUIDE_DISCONNECTED:
1702 appendLogText(
i18n(
"External guider disconnected."));
1704 externalConnectB->setEnabled(
true);
1705 externalDisconnectB->setEnabled(
false);
1706 clearCalibrationB->setEnabled(
false);
1707 guideB->setEnabled(
false);
1708 captureB->setEnabled(
false);
1709 loopB->setEnabled(
false);
1710 autoStarCheck->setEnabled(
false);
1711 boxSizeCombo->setEnabled(
false);
1718 case GUIDE_CALIBRATION_SUCCESS:
1719 appendLogText(
i18n(
"Calibration completed."));
1720 calibrationComplete =
true;
1728 case GUIDE_CALIBRATION_ERROR:
1730 manualDitherB->setEnabled(
false);
1733 case GUIDE_CALIBRATING:
1734 clearCalibrationGraphs();
1735 appendLogText(
i18n(
"Calibration started."));
1740 if (previousState == GUIDE_SUSPENDED || previousState == GUIDE_DITHERING_SUCCESS)
1741 appendLogText(
i18n(
"Guiding resumed."));
1744 appendLogText(
i18n(
"Autoguiding started."));
1749 driftGraph->resetTimer();
1750 driftGraph->refreshColorScheme();
1752 manualDitherB->setEnabled(
true);
1757 appendLogText(
i18n(
"Autoguiding aborted."));
1761 case GUIDE_SUSPENDED:
1762 appendLogText(
i18n(
"Guiding suspended."));
1765 case GUIDE_REACQUIRE:
1766 if (guiderType == GUIDE_INTERNAL)
1770 case GUIDE_MANUAL_DITHERING:
1771 appendLogText(
i18n(
"Manual dithering in progress."));
1774 case GUIDE_DITHERING:
1775 appendLogText(
i18n(
"Dithering in progress."));
1778 case GUIDE_DITHERING_SETTLE:
1779 appendLogText(
i18np(
"Post-dither settling for %1 second...",
"Post-dither settling for %1 seconds...",
1780 Options::ditherSettle()));
1783 case GUIDE_DITHERING_ERROR:
1784 appendLogText(
i18n(
"Dithering failed."));
1786 if (guiderType != GUIDE_LINGUIDER)
1789 m_State = GUIDE_ABORTED;
1794 case GUIDE_DITHERING_SUCCESS:
1795 appendLogText(
i18n(
"Dithering completed successfully."));
1797 if (Options::ditherNoGuiding() ==
false)
1799 setStatus(GUIDE_GUIDING);
1801 if (guiderType == GUIDE_INTERNAL)
1810 void Guide::updateCCDBin(
int index)
1812 if (m_Camera ==
nullptr || guiderType != GUIDE_INTERNAL)
1815 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1817 targetChip->setBinning(index + 1, index + 1);
1818 guideBinIndex = index;
1820 QVariantMap settings = frameSettings[targetChip];
1821 settings[
"binx"] = index + 1;
1822 settings[
"biny"] = index + 1;
1823 frameSettings[targetChip] = settings;
1825 m_GuiderInstance->setFrameParams(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(), settings[
"h"].toInt(),
1826 settings[
"binx"].toInt(), settings[
"biny"].toInt());
1831 void Guide::processCCDNumber(INumberVectorProperty *nvp)
1833 if (m_Camera ==
nullptr || (nvp->device != m_Camera->getDeviceName()) || guiderType != GUIDE_INTERNAL)
1836 if ((!strcmp(nvp->name,
"CCD_BINNING") && useGuideHead ==
false) ||
1837 (!strcmp(nvp->name,
"GUIDER_BINNING") && useGuideHead))
1839 binningCombo->disconnect();
1840 if (guideBinIndex > (nvp->np[0].value - 1))
1842 appendLogText(
i18n(
"%1x%1 guide binning is not supported.", guideBinIndex + 1));
1843 binningCombo->setCurrentIndex( nvp->np[0].value - 1 );
1847 binningCombo->setCurrentIndex(guideBinIndex);
1854 void Guide::checkExposureValue(
ISD::CameraChip *targetChip,
double exposure, IPState expState)
1857 if (guiderType != GUIDE_INTERNAL || targetChip->getCCD() != m_Camera)
1860 INDI_UNUSED(exposure);
1862 if (expState == IPS_ALERT &&
1863 ((m_State == GUIDE_GUIDING) || (m_State == GUIDE_DITHERING) || (m_State == GUIDE_CALIBRATING)))
1865 appendLogText(
i18n(
"Exposure failed. Restarting exposure..."));
1866 m_Camera->setEncodingFormat(
"FITS");
1867 targetChip->capture(exposureIN->value());
1871 void Guide::configSEPMultistarOptions()
1874 if (internalGuider->SEPMultiStarEnabled())
1876 subFrameCheck->setChecked(
false);
1877 subFrameCheck->setEnabled(
false);
1878 autoStarCheck->setChecked(
true);
1879 autoStarCheck->setEnabled(
false);
1883 subFrameCheck->setChecked(Options::guideSubframeEnabled());
1884 subFrameCheck->setEnabled(
true);
1885 autoStarCheck->setChecked(Options::guideAutoStarEnabled());
1886 autoStarCheck->setEnabled(
true);
1890 void Guide::setDarkFrameEnabled(
bool enable)
1892 Options::setGuideDarkFrameEnabled(enable);
1893 if (darkFrameCheck->isChecked() != enable)
1894 darkFrameCheck->setChecked(enable);
1897 void Guide::saveDefaultGuideExposure()
1899 Options::setGuideExposure(exposureIN->value());
1900 if(guiderType == GUIDE_PHD2)
1901 phd2Guider->requestSetExposureTime(exposureIN->value() * 1000);
1904 void Guide::setStarPosition(
const QVector3D &newCenter,
bool updateNow)
1906 starCenter.setX(newCenter.
x());
1907 starCenter.setY(newCenter.
y());
1908 if (newCenter.
z() > 0)
1909 starCenter.setZ(newCenter.
z());
1912 syncTrackingBoxPosition();
1915 void Guide::syncTrackingBoxPosition()
1917 if(!m_Camera || guiderType == GUIDE_LINGUIDER)
1920 if(guiderType == GUIDE_PHD2)
1923 if(!m_ImageData.isNull())
1925 if(m_ImageData->width() < 50)
1927 m_GuideView->setTrackingBoxEnabled(
false);
1933 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1934 Q_ASSERT(targetChip);
1936 int subBinX = 1, subBinY = 1;
1937 targetChip->getBinning(&subBinX, &subBinY);
1939 if (starCenter.isNull() ==
false)
1941 double boxSize = boxSizeCombo->currentText().toInt();
1943 targetChip->getFrame(&x, &y, &w, &h);
1945 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
1947 int newIndex = boxSizeCombo->currentIndex() - 1;
1949 boxSizeCombo->setCurrentIndex(newIndex);
1954 if (subBinX != starCenter.z())
1956 if (starCenter.z() > 0)
1958 starCenter.setX(starCenter.x() * (starCenter.z() / subBinX));
1959 starCenter.setY(starCenter.y() * (starCenter.z() / subBinY));
1962 starCenter.setZ(subBinX);
1965 QRect starRect =
QRect(starCenter.x() - boxSize / (2 * subBinX), starCenter.y() - boxSize / (2 * subBinY),
1966 boxSize / subBinX, boxSize / subBinY);
1967 m_GuideView->setTrackingBoxEnabled(
true);
1968 m_GuideView->setTrackingBox(starRect);
1972 bool Guide::setGuiderType(
int type)
1976 type = Options::guiderType();
1977 else if (type == guiderType)
1980 if (m_State == GUIDE_CALIBRATING || m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1982 appendLogText(
i18n(
"Cannot change guider type while active."));
1986 if (m_GuiderInstance !=
nullptr)
1989 if (m_GuiderInstance->isConnected())
1990 m_GuiderInstance->Disconnect();
1993 m_GuiderInstance->disconnect();
1996 guiderType =
static_cast<GuiderType
>(type);
2000 case GUIDE_INTERNAL:
2002 connect(internalGuider, &InternalGuider::newMultiPulse,
this, &Guide::sendMultiPulse);
2003 connect(internalGuider, &InternalGuider::newSinglePulse,
this, &Guide::sendSinglePulse);
2005 connect(internalGuider, &InternalGuider::newStarPixmap,
this, &Guide::newStarPixmap);
2007 m_GuiderInstance = internalGuider;
2009 internalGuider->setSquareAlgorithm(opsGuide->kcfg_GuideAlgorithm->currentIndex());
2011 clearCalibrationB->setEnabled(
true);
2012 guideB->setEnabled(
true);
2013 captureB->setEnabled(
true);
2014 loopB->setEnabled(
true);
2016 configSEPMultistarOptions();
2017 darkFrameCheck->setEnabled(
true);
2019 cameraCombo->setEnabled(
true);
2020 guiderCombo->setEnabled(
true);
2021 exposureIN->setEnabled(
true);
2022 binningCombo->setEnabled(
true);
2023 boxSizeCombo->setEnabled(
true);
2025 externalConnectB->setEnabled(
false);
2026 externalDisconnectB->setEnabled(
false);
2028 opsGuide->controlGroup->setEnabled(
true);
2029 infoGroup->setEnabled(
true);
2030 label_6->setEnabled(
true);
2031 FOVScopeCombo->setEnabled(
true);
2032 l_5->setEnabled(
true);
2033 l_6->setEnabled(
true);
2034 l_7->setEnabled(
true);
2035 l_8->setEnabled(
true);
2036 l_Aperture->setEnabled(
true);
2037 l_FOV->setEnabled(
true);
2038 l_FbyD->setEnabled(
true);
2039 l_Focal->setEnabled(
true);
2040 driftGraphicsGroup->setEnabled(
true);
2042 cameraCombo->setToolTip(
i18n(
"Select guide camera."));
2044 updateGuideParams();
2049 if (phd2Guider.isNull())
2050 phd2Guider =
new PHD2();
2052 m_GuiderInstance = phd2Guider;
2053 phd2Guider->setGuideView(m_GuideView);
2055 connect(phd2Guider, SIGNAL(newStarPixmap(
QPixmap &)),
this, SIGNAL(newStarPixmap(
QPixmap &)));
2057 clearCalibrationB->setEnabled(
true);
2058 captureB->setEnabled(
false);
2059 loopB->setEnabled(
false);
2060 darkFrameCheck->setEnabled(
false);
2061 subFrameCheck->setEnabled(
false);
2062 autoStarCheck->setEnabled(
false);
2063 guideB->setEnabled(
false);
2064 externalConnectB->setEnabled(
false);
2066 checkBox_DirRA->setEnabled(
false);
2067 eastControlCheck->setEnabled(
false);
2068 westControlCheck->setEnabled(
false);
2069 swapCheck->setEnabled(
false);
2072 opsGuide->controlGroup->setEnabled(
false);
2073 infoGroup->setEnabled(
true);
2074 label_6->setEnabled(
false);
2075 FOVScopeCombo->setEnabled(
false);
2076 l_5->setEnabled(
false);
2077 l_6->setEnabled(
false);
2078 l_7->setEnabled(
false);
2079 l_8->setEnabled(
false);
2080 l_Aperture->setEnabled(
false);
2081 l_FOV->setEnabled(
false);
2082 l_FbyD->setEnabled(
false);
2083 l_Focal->setEnabled(
false);
2084 driftGraphicsGroup->setEnabled(
true);
2086 guiderCombo->setEnabled(
false);
2087 exposureIN->setEnabled(
true);
2088 binningCombo->setEnabled(
false);
2089 boxSizeCombo->setEnabled(
false);
2090 cameraCombo->setEnabled(
false);
2092 if (Options::resetGuideCalibration())
2093 appendLogText(
i18n(
"Warning: Reset Guiding Calibration is enabled. It is recommended to turn this option off for PHD2."));
2095 updateGuideParams();
2098 case GUIDE_LINGUIDER:
2099 if (linGuider.isNull())
2102 m_GuiderInstance = linGuider;
2104 clearCalibrationB->setEnabled(
true);
2105 captureB->setEnabled(
false);
2106 loopB->setEnabled(
false);
2107 darkFrameCheck->setEnabled(
false);
2108 subFrameCheck->setEnabled(
false);
2109 autoStarCheck->setEnabled(
false);
2110 guideB->setEnabled(
true);
2111 externalConnectB->setEnabled(
true);
2113 opsGuide->controlGroup->setEnabled(
false);
2114 infoGroup->setEnabled(
false);
2115 driftGraphicsGroup->setEnabled(
false);
2117 guiderCombo->setEnabled(
false);
2118 exposureIN->setEnabled(
false);
2119 binningCombo->setEnabled(
false);
2120 boxSizeCombo->setEnabled(
false);
2122 cameraCombo->setEnabled(
false);
2124 updateGuideParams();
2129 if (m_GuiderInstance !=
nullptr)
2131 connect(m_GuiderInstance, &Ekos::GuideInterface::frameCaptureRequested,
this, &
Ekos::Guide::capture);
2132 connect(m_GuiderInstance, &Ekos::GuideInterface::newLog,
this, &Ekos::Guide::appendLogText);
2133 connect(m_GuiderInstance, &Ekos::GuideInterface::newStatus,
this, &Ekos::Guide::setStatus);
2134 connect(m_GuiderInstance, &Ekos::GuideInterface::newStarPosition,
this, &Ekos::Guide::setStarPosition);
2135 connect(m_GuiderInstance, &Ekos::GuideInterface::guideStats,
this, &Ekos::Guide::guideStats);
2137 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisDelta,
this, &Ekos::Guide::setAxisDelta);
2138 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisPulse,
this, &Ekos::Guide::setAxisPulse);
2139 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisSigma,
this, &Ekos::Guide::setAxisSigma);
2140 connect(m_GuiderInstance, &Ekos::GuideInterface::newSNR,
this, &Ekos::Guide::setSNR);
2142 driftGraph->connectGuider(m_GuiderInstance);
2143 targetPlot->connectGuider(m_GuiderInstance);
2145 connect(m_GuiderInstance, &Ekos::GuideInterface::calibrationUpdate,
this, &Ekos::Guide::calibrationUpdate);
2147 connect(m_GuiderInstance, &Ekos::GuideInterface::guideEquipmentUpdated,
this, &Ekos::Guide::configurePHD2Camera);
2150 externalConnectB->setEnabled(
false);
2151 externalDisconnectB->setEnabled(
false);
2153 if (m_GuiderInstance !=
nullptr && guiderType != GUIDE_INTERNAL)
2155 externalConnectB->setEnabled(!m_GuiderInstance->isConnected());
2156 externalDisconnectB->setEnabled(m_GuiderInstance->isConnected());
2159 if (m_GuiderInstance !=
nullptr)
2160 m_GuiderInstance->Connect();
2165 void Guide::updateTrackingBoxSize(
int currentIndex)
2167 if (currentIndex >= 0)
2169 Options::setGuideSquareSizeIndex(currentIndex);
2171 if (guiderType == GUIDE_INTERNAL)
2172 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setGuideBoxSize(boxSizeCombo->currentText().toInt());
2174 syncTrackingBoxPosition();
2178 void Guide::onThresholdChanged(
int index)
2182 case GUIDE_INTERNAL:
2183 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setSquareAlgorithm(index);
2191 void Guide::onEnableDirRA(
bool enable)
2194 if (Options::gPGEnabled())
2195 m_GuiderInstance->resetGPG();
2196 Options::setRAGuideEnabled(enable);
2199 void Guide::onEnableDirDEC(
bool enable)
2201 Options::setDECGuideEnabled(enable);
2202 updatePHD2Directions();
2205 void Guide::syncSettings()
2211 if ((pCB = qobject_cast<QCheckBox*>(obj)))
2213 if (pCB == autoStarCheck)
2214 Options::setGuideAutoStarEnabled(pCB->
isChecked());
2217 emit settingsUpdated(getSettings());
2220 void Guide::onControlDirectionChanged(
bool enable)
2224 if (northControlCheck ==
dynamic_cast<QCheckBox *
>(obj))
2226 Options::setNorthDECGuideEnabled(enable);
2227 updatePHD2Directions();
2229 else if (southControlCheck ==
dynamic_cast<QCheckBox *
>(obj))
2231 Options::setSouthDECGuideEnabled(enable);
2232 updatePHD2Directions();
2234 else if (westControlCheck ==
dynamic_cast<QCheckBox *
>(obj))
2236 Options::setWestRAGuideEnabled(enable);
2238 else if (eastControlCheck ==
dynamic_cast<QCheckBox *
>(obj))
2240 Options::setEastRAGuideEnabled(enable);
2243 void Guide::updatePHD2Directions()
2245 if(guiderType == GUIDE_PHD2)
2246 phd2Guider -> requestSetDEGuideMode(checkBox_DirDEC->isChecked(), northControlCheck->isChecked(),
2247 southControlCheck->isChecked());
2249 void Guide::updateDirectionsFromPHD2(
const QString &mode)
2252 disconnect(checkBox_DirDEC, &
QCheckBox::toggled,
this, &Ekos::Guide::onEnableDirDEC);
2253 disconnect(northControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
2254 disconnect(southControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
2258 checkBox_DirDEC->setChecked(
true);
2259 northControlCheck->setChecked(
true);
2260 southControlCheck->setChecked(
true);
2262 else if(mode ==
"North")
2264 checkBox_DirDEC->setChecked(
true);
2265 northControlCheck->setChecked(
true);
2266 southControlCheck->setChecked(
false);
2268 else if(mode ==
"South")
2270 checkBox_DirDEC->setChecked(
true);
2271 northControlCheck->setChecked(
false);
2272 southControlCheck->setChecked(
true);
2276 checkBox_DirDEC->setChecked(
false);
2277 northControlCheck->setChecked(
true);
2278 southControlCheck->setChecked(
true);
2283 connect(northControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
2284 connect(southControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
2288 void Guide::loadSettings()
2292 exposureIN->setValue(Options::guideExposure());
2294 GuideDelay->setValue(Options::guideDelay());
2296 guideBinIndex = Options::guideBinSizeIndex();
2298 boxSizeCombo->setCurrentIndex(Options::guideSquareSizeIndex());
2300 darkFrameCheck->setChecked(Options::guideDarkFrameEnabled());
2302 subFrameCheck->setChecked(Options::guideSubframeEnabled());
2304 checkBox_DirRA->setChecked(Options::rAGuideEnabled());
2305 checkBox_DirDEC->setChecked(Options::dECGuideEnabled());
2307 northControlCheck->setChecked(Options::northDECGuideEnabled());
2308 southControlCheck->setChecked(Options::southDECGuideEnabled());
2310 westControlCheck->setChecked(Options::westRAGuideEnabled());
2311 eastControlCheck->setChecked(Options::eastRAGuideEnabled());
2313 autoStarCheck->setChecked(Options::guideAutoStarEnabled());
2323 if (Options::rAProportionalGain() > 1.0)
2324 Options::setRAProportionalGain(0.75);
2325 if (Options::dECProportionalGain() > 1.0)
2326 Options::setDECProportionalGain(0.75);
2327 if (Options::rAIntegralGain() > 1.0)
2328 Options::setRAIntegralGain(0.75);
2329 if (Options::dECIntegralGain() > 1.0)
2330 Options::setDECIntegralGain(0.75);
2335 void Guide::saveSettings()
2339 Options::setGuideExposure(exposureIN->value());
2341 Options::setGuideDelay(GuideDelay->value());
2343 Options::setGuideBinSizeIndex(binningCombo->currentIndex());
2345 Options::setGuideSquareSizeIndex(boxSizeCombo->currentIndex());
2347 Options::setGuideDarkFrameEnabled(darkFrameCheck->isChecked());
2349 Options::setGuideSubframeEnabled(subFrameCheck->isChecked());
2351 Options::setRAGuideEnabled(checkBox_DirRA->isChecked());
2352 Options::setDECGuideEnabled(checkBox_DirDEC->isChecked());
2354 Options::setNorthDECGuideEnabled(northControlCheck->isChecked());
2355 Options::setSouthDECGuideEnabled(southControlCheck->isChecked());
2357 Options::setWestRAGuideEnabled(westControlCheck->isChecked());
2358 Options::setEastRAGuideEnabled(eastControlCheck->isChecked());
2367 void Guide::setTrackingStar(
int x,
int y)
2370 setStarPosition(newStarPosition,
true);
2372 if(guiderType == GUIDE_PHD2)
2375 if(!m_ImageData.isNull())
2377 if(m_ImageData->width() > 50)
2378 phd2Guider->setLockPosition(starCenter.x(), starCenter.y());
2382 if (operationStack.isEmpty() ==
false)
2383 executeOperationStack();
2386 void Guide::setAxisDelta(
double ra,
double de)
2396 int currentNumPoints = driftGraph->graph(GuideGraph::G_RA)->dataCount();
2397 guideSlider->setMaximum(currentNumPoints);
2400 guideSlider->setValue(currentNumPoints);
2405 emit newAxisDelta(ra, de);
2408 void Guide::calibrationUpdate(GuideInterface::CalibrationUpdateType type,
const QString &
message,
2409 double dx,
double dy)
2413 case GuideInterface::RA_OUT:
2414 calibrationPlot->graph(GuideGraph::G_RA)->addData(dx, dy);
2416 case GuideInterface::RA_IN:
2417 calibrationPlot->graph(GuideGraph::G_DEC)->addData(dx, dy);
2419 case GuideInterface::BACKLASH:
2420 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->addData(dx, dy);
2422 case GuideInterface::DEC_OUT:
2423 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(dx, dy);
2425 case GuideInterface::DEC_IN:
2426 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->addData(dx, dy);
2428 case GuideInterface::CALIBRATION_MESSAGE_ONLY:
2432 calibrationPlot->replot();
2435 void Guide::setAxisSigma(
double ra,
double de)
2439 const double total = std::hypot(ra, de);
2442 emit newAxisSigma(ra, de);
2449 delta << l_DeltaRA->text().toDouble() << l_DeltaDEC->text().toDouble();
2458 sigma << l_ErrRA->text().toDouble() << l_ErrDEC->text().toDouble();
2463 void Guide::setAxisPulse(
double ra,
double de)
2469 void Guide::setSNR(
double snr)
2474 void Guide::buildOperationStack(GuideState operation)
2476 operationStack.
clear();
2481 if (Options::guideDarkFrameEnabled())
2482 operationStack.push(GUIDE_DARK);
2484 operationStack.push(GUIDE_CAPTURE);
2485 operationStack.push(GUIDE_SUBFRAME);
2488 case GUIDE_CALIBRATING:
2489 operationStack.push(GUIDE_CALIBRATING);
2490 if (guiderType == GUIDE_INTERNAL)
2492 if (Options::guideDarkFrameEnabled())
2493 operationStack.push(GUIDE_DARK);
2496 if (Options::guideAutoStarEnabled() ||
2498 internalGuider->SEPMultiStarEnabled())
2502 if (subFramed ==
false && Options::guideSubframeEnabled())
2503 operationStack.push(GUIDE_CAPTURE);
2505 operationStack.push(GUIDE_SUBFRAME);
2506 operationStack.push(GUIDE_STAR_SELECT);
2509 operationStack.push(GUIDE_CAPTURE);
2512 if (subFramed ==
true && Options::guideSubframeEnabled() ==
false)
2513 operationStack.push(GUIDE_SUBFRAME);
2519 if (subFramed ==
false && Options::guideSubframeEnabled())
2520 operationStack.push(GUIDE_CAPTURE);
2523 operationStack.push(GUIDE_SUBFRAME);
2526 operationStack.push(GUIDE_CAPTURE);
2537 bool Guide::executeOperationStack()
2539 if (operationStack.isEmpty())
2542 GuideState nextOperation = operationStack.pop();
2544 bool actionRequired =
false;
2546 switch (nextOperation)
2548 case GUIDE_SUBFRAME:
2549 actionRequired = executeOneOperation(nextOperation);
2553 actionRequired = executeOneOperation(nextOperation);
2557 actionRequired = captureOneFrame();
2560 case GUIDE_STAR_SELECT:
2561 actionRequired = executeOneOperation(nextOperation);
2564 case GUIDE_CALIBRATING:
2565 if (guiderType == GUIDE_INTERNAL)
2567 m_GuiderInstance->setStarPosition(starCenter);
2570 if (m_Mount && m_Mount->canControlTrack() && m_Mount->isTracking() ==
false)
2571 m_Mount->setTrackEnabled(
true);
2574 if (m_GuiderInstance->calibrate())
2576 if (guiderType == GUIDE_INTERNAL)
2577 disconnect(m_GuideView.get(), &FITSView::trackingStarSelected,
this, &Guide::setTrackingStar);
2582 emit newStatus(GUIDE_CALIBRATION_ERROR);
2583 m_State = GUIDE_IDLE;
2584 appendLogText(
i18n(
"Calibration failed to start."));
2598 return executeOperationStack();
2601 bool Guide::executeOneOperation(GuideState operation)
2603 bool actionRequired =
false;
2605 if (m_Camera ==
nullptr)
2606 return actionRequired;
2608 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2609 if (targetChip ==
nullptr)
2612 int subBinX, subBinY;
2613 targetChip->getBinning(&subBinX, &subBinY);
2617 case GUIDE_SUBFRAME:
2620 if ((guiderType == GUIDE_INTERNAL) && internalGuider->SEPMultiStarEnabled())
2623 if (subFramed ==
false && Options::guideSubframeEnabled() ==
true && targetChip->canSubframe())
2625 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2626 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2628 int offset = boxSizeCombo->currentText().toInt() / subBinX;
2630 int x = starCenter.x();
2631 int y = starCenter.y();
2633 x = (x - offset * 2) * subBinX;
2634 y = (y - offset * 2) * subBinY;
2635 int w = offset * 4 * subBinX;
2636 int h = offset * 4 * subBinY;
2647 targetChip->setFrame(x, y, w, h);
2650 QVariantMap settings = frameSettings[targetChip];
2655 settings[
"binx"] = subBinX;
2656 settings[
"biny"] = subBinY;
2658 frameSettings[targetChip] = settings;
2660 starCenter.setX(w / (2 * subBinX));
2661 starCenter.setY(h / (2 * subBinX));
2667 else if (subFramed &&
2668 (Options::guideSubframeEnabled() ==
false ||
2669 m_State == GUIDE_REACQUIRE))
2671 targetChip->resetFrame();
2674 targetChip->getFrame(&x, &y, &w, &h);
2676 QVariantMap settings;
2681 settings[
"binx"] = subBinX;
2682 settings[
"biny"] = subBinY;
2683 frameSettings[targetChip] = settings;
2687 starCenter.setX(w / (2 * subBinX));
2688 starCenter.setY(h / (2 * subBinX));
2699 if (m_ImageData && Options::guideDarkFrameEnabled())
2701 QVariantMap settings = frameSettings[targetChip];
2702 uint16_t offsetX = 0;
2703 uint16_t offsetY = 0;
2705 if (settings[
"x"].
isValid() &&
2706 settings[
"y"].isValid() &&
2707 settings[
"binx"].isValid() &&
2708 settings[
"biny"].isValid())
2710 offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
2711 offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
2714 actionRequired =
true;
2715 targetChip->setCaptureFilter(FITS_NONE);
2716 m_DarkProcessor->denoise(targetChip, m_ImageData, exposureIN->value(), offsetX, offsetY);
2721 case GUIDE_STAR_SELECT:
2723 m_State = GUIDE_STAR_SELECT;
2724 emit newStatus(m_State);
2726 if (Options::guideAutoStarEnabled() ||
2728 ((guiderType == GUIDE_INTERNAL) &&
2729 internalGuider->SEPMultiStarEnabled()))
2731 bool autoStarCaptured = internalGuider->selectAutoStar();
2732 if (autoStarCaptured)
2734 appendLogText(
i18n(
"Auto star selected."));
2738 appendLogText(
i18n(
"Failed to select an auto star."));
2739 actionRequired =
true;
2740 m_State = GUIDE_CALIBRATION_ERROR;
2741 emit newStatus(m_State);
2747 appendLogText(
i18n(
"Select a guide star to calibrate."));
2748 actionRequired =
true;
2757 return actionRequired;
2760 void Guide::processGuideOptions()
2762 if (Options::guiderType() != guiderType)
2764 guiderType =
static_cast<GuiderType
>(Options::guiderType());
2765 setGuiderType(Options::guiderType());
2769 void Guide::showFITSViewer()
2771 static int lastFVTabID = -1;
2778 fv->loadData(m_ImageData, url, &lastFVTabID);
2780 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
2781 fv->loadData(m_ImageData, url, &lastFVTabID);
2787 void Guide::setExternalGuiderBLOBEnabled(
bool enable)
2790 if (guiderType == GUIDE_INTERNAL)
2796 m_Camera->setBLOBEnabled(enable);
2798 if(m_Camera->isBLOBEnabled())
2800 if (m_Camera->hasGuideHead() && cameraCombo->currentText().contains(
"Guider"))
2801 useGuideHead =
true;
2803 useGuideHead =
false;
2806 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2808 targetChip->setCaptureMode(FITS_GUIDE);
2814 void Guide::resetNonGuidedDither()
2817 nonGuidedDitherRaOffsetMsec = 0;
2818 nonGuidedDitherDecOffsetMsec = 0;
2819 qCDebug(KSTARS_EKOS_GUIDE) <<
"Reset non guiding dithering position";
2822 if (!isNonGuidedDitherInitialized)
2824 auto seed = std::chrono::system_clock::now().time_since_epoch().count();
2825 nonGuidedPulseGenerator.seed(seed);
2826 isNonGuidedDitherInitialized =
true;
2827 qCDebug(KSTARS_EKOS_GUIDE) <<
"Initialize non guiding dithering random generator";
2831 void Guide::nonGuidedDither()
2833 double ditherPulse = Options::ditherNoGuidingPulse();
2836 std::uniform_int_distribution<int> newPos(-ditherPulse, +ditherPulse);
2841 const int newRaOffsetMsec = newPos(nonGuidedPulseGenerator);
2842 const int raPulse = nonGuidedDitherRaOffsetMsec - newRaOffsetMsec;
2843 nonGuidedDitherRaOffsetMsec = newRaOffsetMsec;
2844 const int raMsec = std::abs(raPulse);
2845 const int raPolarity = (raPulse >= 0 ? 1 : -1);
2848 const int newDecOffsetMsec = newPos(nonGuidedPulseGenerator);
2849 const int decPulse = nonGuidedDitherDecOffsetMsec - newDecOffsetMsec;
2850 nonGuidedDitherDecOffsetMsec = newDecOffsetMsec;
2851 const int decMsec = std::abs(decPulse);
2852 const int decPolarity = (decPulse >= 0 ? 1 : -1);
2854 qCInfo(KSTARS_EKOS_GUIDE) <<
"Starting non-guiding dither...";
2855 qCDebug(KSTARS_EKOS_GUIDE) <<
"dither ra_msec:" << raMsec <<
"ra_polarity:" << raPolarity <<
"de_msec:" << decMsec <<
2856 "de_polarity:" << decPolarity;
2858 bool rc = sendMultiPulse(raPolarity > 0 ? RA_INC_DIR : RA_DEC_DIR, raMsec, decPolarity > 0 ? DEC_INC_DIR : DEC_DEC_DIR,
2863 qCInfo(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither successful.";
2864 QTimer::singleShot( (raMsec > decMsec ? raMsec : decMsec) + Options::ditherSettle() * 1000 + 100, [
this]()
2866 emit newStatus(GUIDE_DITHERING_SUCCESS);
2867 m_State = GUIDE_IDLE;
2872 qCWarning(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither failed.";
2873 emit newStatus(GUIDE_DITHERING_ERROR);
2874 m_State = GUIDE_IDLE;
2878 void Guide::updateTelescopeType(
int index)
2880 if (m_Camera ==
nullptr)
2883 focal_length = (index == ISD::Camera::TELESCOPE_PRIMARY) ? primaryFL : guideFL;
2884 aperture = (index == ISD::Camera::TELESCOPE_PRIMARY) ? primaryAperture : guideAperture;
2886 Options::setGuideScopeType(index);
2888 syncTelescopeInfo();
2891 void Guide::setDefaultGuider(
const QString &driver)
2893 Options::setDefaultGuideGuider(driver);
2896 void Guide::setDefaultCCD(
const QString &ccd)
2898 if (guiderType == GUIDE_INTERNAL)
2899 Options::setDefaultGuideCCD(ccd);
2902 void Guide::handleManualDither()
2904 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2905 if (targetChip ==
nullptr)
2908 Ui::ManualDither ditherDialog;
2910 ditherDialog.setupUi(&container);
2912 if (guiderType != GUIDE_INTERNAL)
2914 ditherDialog.coordinatesR->setEnabled(
false);
2915 ditherDialog.x->setEnabled(
false);
2916 ditherDialog.y->setEnabled(
false);
2919 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2920 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2922 ditherDialog.x->setMinimum(minX);
2923 ditherDialog.x->setMaximum(maxX);
2924 ditherDialog.y->setMinimum(minY);
2925 ditherDialog.y->setMaximum(maxY);
2927 ditherDialog.x->setValue(starCenter.x());
2928 ditherDialog.y->setValue(starCenter.y());
2932 if (ditherDialog.magnitudeR->isChecked())
2933 m_GuiderInstance->dither(ditherDialog.magnitude->value());
2936 InternalGuider *
const ig =
dynamic_cast<InternalGuider *
>(m_GuiderInstance);
2938 ig->ditherXY(ditherDialog.x->value(), ditherDialog.y->value());
2943 bool Guide::connectGuider()
2945 setStatus(GUIDE_IDLE);
2946 return m_GuiderInstance->Connect();
2949 bool Guide::disconnectGuider()
2951 return m_GuiderInstance->Disconnect();
2954 void Guide::initPlots()
2957 initCalibrationPlot();
2963 accuracyRadiusSpin->setValue(Options::guiderAccuracyThreshold());
2964 showRAPlotCheck->setChecked(Options::rADisplayedOnGuideGraph());
2965 showDECPlotCheck->setChecked(Options::dEDisplayedOnGuideGraph());
2966 showRACorrectionsCheck->setChecked(Options::rACorrDisplayedOnGuideGraph());
2967 showDECorrectionsCheck->setChecked(Options::dECorrDisplayedOnGuideGraph());
2968 showSNRPlotCheck->setChecked(Options::sNRDisplayedOnGuideGraph());
2969 showRMSPlotCheck->setChecked(Options::rMSDisplayedOnGuideGraph());
2974 void Guide::initDriftGraph()
2984 driftGraph->setCorrectionGraphScale(correctionSlider->value());
2992 correctionSlider->setValue(scale);
2995 void Guide::initCalibrationPlot()
2998 calibrationPlot->setSelectionTolerance(10);
3009 calibrationPlot->xAxis->setTickLabelColor(
Qt::white);
3010 calibrationPlot->yAxis->setTickLabelColor(
Qt::white);
3012 calibrationPlot->xAxis->setLabelColor(
Qt::white);
3013 calibrationPlot->yAxis->setLabelColor(
Qt::white);
3015 calibrationPlot->xAxis->setLabelFont(
QFont(font().family(), 10));
3016 calibrationPlot->yAxis->setLabelFont(
QFont(font().family(), 10));
3017 calibrationPlot->xAxis->setTickLabelFont(
QFont(font().family(), 9));
3018 calibrationPlot->yAxis->setTickLabelFont(
QFont(font().family(), 9));
3020 calibrationPlot->xAxis->setLabelPadding(2);
3021 calibrationPlot->yAxis->setLabelPadding(2);
3027 calibrationPlot->xAxis->grid()->setZeroLinePen(
QPen(
Qt::gray));
3028 calibrationPlot->yAxis->grid()->setZeroLinePen(
QPen(
Qt::gray));
3030 calibrationPlot->xAxis->setLabel(
i18n(
"x (pixels)"));
3031 calibrationPlot->yAxis->setLabel(
i18n(
"y (pixels)"));
3033 calibrationPlot->xAxis->setRange(-20, 20);
3034 calibrationPlot->yAxis->setRange(-20, 20);
3039 calibrationPlot->addGraph();
3042 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"RAGuideError"), 2),
QBrush(), 6));
3043 calibrationPlot->graph(GuideGraph::G_RA)->setName(
"RA out");
3045 calibrationPlot->addGraph();
3049 calibrationPlot->graph(GuideGraph::G_DEC)->setName(
"RA in");
3051 calibrationPlot->addGraph();
3052 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
3056 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setName(
"Backlash");
3058 calibrationPlot->addGraph();
3059 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
3061 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"DEGuideError"), 2),
QBrush(), 6));
3062 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setName(
"DEC out");
3064 calibrationPlot->addGraph();
3065 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setLineStyle(
QCPGraph::lsNone);
3069 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setName(
"DEC in");
3072 calLabel->setColor(
QColor(255, 255, 255));
3075 calLabel->position->setCoords(0.5, 0);
3076 calLabel->setText(
"");
3077 calLabel->setFont(
QFont(font().family(), 10));
3078 calLabel->setVisible(
true);
3080 calibrationPlot->resize(190, 190);
3081 calibrationPlot->replot();
3084 void Guide::initView()
3086 guideStateWidget =
new GuideStateWidget();
3087 guideInfoLayout->insertWidget(0, guideStateWidget);
3089 m_GuideView.reset(
new GuideView(guideWidget, FITS_GUIDE));
3091 m_GuideView->setBaseSize(guideWidget->size());
3092 m_GuideView->createFloatingToolBar();
3095 guideWidget->setLayout(vlayout);
3099 void Guide::initConnections()
3102 captureTimeout.setSingleShot(
true);
3103 connect(&captureTimeout, &
QTimer::timeout,
this, &Ekos::Guide::processCaptureTimeout);
3107 &Ekos::Guide::updateTrackingBoxSize);
3110 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3112 &Ekos::Guide::setDefaultCCD);
3115 &Ekos::Guide::setDefaultCCD);
3120 if (guiderType == GUIDE_INTERNAL)
3128 FOVScopeCombo->setCurrentIndex(Options::guideScopeType());
3130 &Ekos::Guide::updateTelescopeType);
3135 if(guiderType != GUIDE_PHD2)
3138 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3144 setDefaultGuider(text);
3150 &Ekos::Guide::updateCCDBin);
3157 connect(northControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
3158 connect(southControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
3159 connect(westControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
3160 connect(eastControlCheck, &
QCheckBox::toggled,
this, &Ekos::Guide::onControlDirectionChanged);
3171 m_State = GUIDE_CAPTURE;
3172 emit newStatus(m_State);
3174 if(guiderType == GUIDE_PHD2)
3176 configurePHD2Camera();
3177 if(phd2Guider->isCurrentCameraNotInEkos())
3179 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."));
3180 else if(Options::guideSubframeEnabled())
3183 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"));
3184 subFrameCheck->setChecked(
false);
3186 phd2Guider->captureSingleFrame();
3188 else if (guiderType == GUIDE_INTERNAL)
3209 m_GuiderInstance->Connect();
3214 m_GuiderInstance->Disconnect();
3218 m_PulseTimer.setSingleShot(
true);
3223 &Ekos::Guide::buildTarget);
3228 driftGraph->toggleShowPlot(GuideGraph::G_RA, isChecked);
3232 driftGraph->toggleShowPlot(GuideGraph::G_DEC, isChecked);
3236 driftGraph->toggleShowPlot(GuideGraph::G_RA_PULSE, isChecked);
3240 driftGraph->toggleShowPlot(GuideGraph::G_DEC_PULSE, isChecked);
3244 driftGraph->toggleShowPlot(GuideGraph::G_SNR, isChecked);
3248 driftGraph->toggleShowPlot(GuideGraph::G_RMS, isChecked);
3250 connect(correctionSlider, &
QSlider::sliderMoved, driftGraph, &GuideDriftGraph::setCorrectionGraphScale);
3254 connect(
this, &Ekos::Guide::newStatus, guideStateWidget, &Ekos::GuideStateWidget::updateGuideStatus);
3259 auto name = device->getDeviceName();
3264 for (
auto &oneMount : m_Mounts)
3266 if (oneMount->getDeviceName() == name)
3268 m_Mounts.removeOne(oneMount);
3269 if (m_Mount && (m_Mount->getDeviceName() == name))
3276 for (
auto &oneCamera : m_Cameras)
3278 if (oneCamera->getDeviceName() == name)
3280 m_Cameras.removeAll(oneCamera);
3281 cameraCombo->removeItem(cameraCombo->findText(name));
3282 cameraCombo->removeItem(cameraCombo->findText(name +
" Guider"));
3283 if (m_Cameras.empty())
3286 cameraCombo->setCurrentIndex(-1);
3290 m_Camera = m_Cameras[0];
3291 cameraCombo->setCurrentIndex(0);
3304 for (
auto &oneGuider : m_Guiders)
3306 if (oneGuider->getDeviceName() ==
name)
3308 m_Guiders.removeAll(oneGuider);
3309 guiderCombo->removeItem(guiderCombo->findText(name));
3310 if (m_Guiders.empty())
3313 setGuider(guiderCombo->currentText());
3320 for (
auto &oneAO : m_AdaptiveOptics)
3322 if (oneAO->getDeviceName() == name)
3324 m_AdaptiveOptics.removeAll(oneAO);
3335 settings.
insert(
"camera", cameraCombo->currentText());
3336 settings.
insert(
"via", guiderCombo->currentText());
3337 settings.
insert(
"exp", exposureIN->value());
3338 settings.
insert(
"bin", qMax(1, binningCombo->currentIndex() + 1));
3339 settings.
insert(
"dark", darkFrameCheck->isChecked());
3340 settings.
insert(
"box", boxSizeCombo->currentText());
3341 settings.
insert(
"ra_control", checkBox_DirRA->isChecked());
3342 settings.
insert(
"de_control", checkBox_DirDEC->isChecked());
3343 settings.
insert(
"east", eastControlCheck->isChecked());
3344 settings.
insert(
"west", westControlCheck->isChecked());
3345 settings.
insert(
"north", northControlCheck->isChecked());
3346 settings.
insert(
"south", southControlCheck->isChecked());
3347 settings.
insert(
"scope", qMax(0, FOVScopeCombo->currentIndex()));
3348 settings.
insert(
"swap", swapCheck->isChecked());
3349 settings.
insert(
"ra_gain", Options::rAProportionalGain());
3350 settings.
insert(
"de_gain", Options::dECProportionalGain());
3351 settings.
insert(
"dither_enabled", Options::ditherEnabled());
3352 settings.
insert(
"dither_pixels", Options::ditherPixels());
3353 settings.
insert(
"dither_frequency",
static_cast<int>(Options::ditherFrames()));
3354 settings.
insert(
"gpg_enabled", Options::gPGEnabled());
3359 void Guide::setSettings(
const QJsonObject &settings)
3361 static bool init =
false;
3363 auto syncControl = [settings](
const QString & key,
QWidget * widget)
3365 if (settings.
contains(key) ==
false)
3373 if ((pSB = qobject_cast<QSpinBox *>(widget)))
3375 const int value = settings[key].toInt(pSB->
value());
3376 if (value != pSB->
value())
3382 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
3384 const double value = settings[key].toDouble(pDSB->
value());
3385 if (value != pDSB->
value())
3391 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
3393 const bool value = settings[key].toBool(pCB->
isChecked());
3401 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
3415 if (syncControl(
"camera", cameraCombo) ||
init ==
false)
3418 syncControl(
"via", guiderCombo);
3420 syncControl(
"exp", exposureIN);
3422 const int bin = settings[
"bin"].toInt(binningCombo->currentIndex() + 1) - 1;
3423 if (bin != binningCombo->currentIndex())
3424 binningCombo->setCurrentIndex(bin);
3426 syncControl(
"dark", darkFrameCheck);
3428 syncControl(
"box", boxSizeCombo);
3430 syncControl(
"swap", swapCheck);
3432 syncControl(
"ra_control", checkBox_DirRA);
3434 syncControl(
"de_control", checkBox_DirDEC);
3436 syncControl(
"east", eastControlCheck);
3437 syncControl(
"west", westControlCheck);
3438 syncControl(
"north", northControlCheck);
3439 syncControl(
"south", southControlCheck);
3441 const int scope = settings[
"scope"].toInt(FOVScopeCombo->currentIndex());
3442 if (scope >= 0 && scope != FOVScopeCombo->currentIndex())
3443 FOVScopeCombo->setCurrentIndex(scope);
3445 syncControl(
"ra_gain", opsGuide->kcfg_RAProportionalGain);
3446 Options::setRAProportionalGain(opsGuide->kcfg_RAProportionalGain->value());
3448 syncControl(
"de_gain", opsGuide->kcfg_DECProportionalGain);
3449 Options::setDECProportionalGain(opsGuide->kcfg_DECProportionalGain->value());
3451 const bool ditherEnabled = settings[
"dither_enabled"].toBool(Options::ditherEnabled());
3452 Options::setDitherEnabled(ditherEnabled);
3453 const double ditherPixels = settings[
"dither_pixels"].toDouble(Options::ditherPixels());
3454 Options::setDitherPixels(ditherPixels);
3455 const int ditherFrequency = settings[
"dither_frequency"].toInt(Options::ditherFrames());
3456 Options::setDitherFrames(ditherFrequency);
3457 const bool gpg = settings[
"gpg_enabled"].toBool(Options::gPGEnabled());
3458 Options::setGPGEnabled(gpg);
3465 m_State = GUIDE_LOOPING;
3466 emit newStatus(m_State);
3468 if(guiderType == GUIDE_PHD2)
3470 configurePHD2Camera();
3471 if(phd2Guider->isCurrentCameraNotInEkos())
3473 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."));
3474 else if(Options::guideSubframeEnabled())
3477 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"));
3478 subFrameCheck->setChecked(
false);
3481 stopB->setEnabled(
true);
3483 else if (guiderType == GUIDE_INTERNAL)