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 onSettingsUpdated(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(m_ProgressIndicator, 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 (guiderType == GUIDE_INTERNAL &&
239 (Options::rAGuidePulseAlgorithm() == OpsGuide::GPG_ALGORITHM))
240 m_GuiderInstance->resetGPG();
247 if (
event->oldSize().width() != -1)
249 if (
event->oldSize().width() != size().width())
250 handleHorizontalPlotSizeChange();
251 else if (
event->oldSize().height() != size().height())
252 handleVerticalPlotSizeChange();
260void Guide::buildTarget()
262 targetPlot->buildTarget(guiderAccuracyThreshold->value());
265void Guide::clearGuideGraphs()
271void Guide::clearCalibrationGraphs()
273 calibrationPlot->graph(GuideGraph::G_RA)->data()->clear();
274 calibrationPlot->graph(GuideGraph::G_DEC)->data()->clear();
275 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear();
276 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear();
277 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->data()->clear();
278 calRALabel->setVisible(
false);
279 calRAArrow->setVisible(
false);
280 calDECLabel->setVisible(
false);
281 calDECArrow->setVisible(
false);
282 calibrationPlot->replot();
285void Guide::slotAutoScaleGraphs()
287 driftGraph->zoomX(defaultXZoomLevel);
289 driftGraph->autoScaleGraphs();
290 targetPlot->autoScaleGraphs(guiderAccuracyThreshold->value());
292 calibrationPlot->rescaleAxes();
293 calibrationPlot->yAxis->setScaleRatio(calibrationPlot->xAxis, 1.0);
294 calibrationPlot->xAxis->setScaleRatio(calibrationPlot->yAxis, 1.0);
295 calibrationPlot->replot();
298void Guide::guideHistory()
300 int sliderValue = guideSlider->value();
301 latestCheck->setChecked(sliderValue == guideSlider->maximum() - 1 || sliderValue == guideSlider->maximum());
302 double ra = driftGraph->graph(GuideGraph::G_RA)->dataMainValue(sliderValue);
303 double de = driftGraph->graph(GuideGraph::G_DEC)->dataMainValue(sliderValue);
304 driftGraph->guideHistory(sliderValue, graphOnLatestPt);
306 targetPlot->showPoint(ra, de);
309void Guide::setLatestGuidePoint(
bool isChecked)
311 graphOnLatestPt = isChecked;
312 driftGraph->setLatestGuidePoint(isChecked);
313 targetPlot->setLatestGuidePoint(isChecked);
316 guideSlider->setValue(guideSlider->maximum());
321 guideExposure->setRecommendedValues(values);
322 return guideExposure->getRecommendedValuesString();
327 if (m_Camera && device == m_Camera)
334 m_Camera->disconnect(
this);
340 connect(m_Camera, &ISD::Camera::Connected,
this, [
this]()
342 controlGroupBox->setEnabled(
true);
344 connect(m_Camera, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
346 controlGroupBox->setEnabled(
false);
350 controlGroupBox->setEnabled(m_Camera && m_Camera->isConnected());
356 if(guiderType != GUIDE_INTERNAL)
357 m_Camera->setBLOBEnabled(
false);
360 configurePHD2Camera();
363 if (captureTimeout.isActive() && m_State >= Ekos::GUIDE_CAPTURE)
369void Guide::configurePHD2Camera()
373 if(guiderType != GUIDE_PHD2)
380 if(!phd2Guider->isConnected())
384 if(phd2Guider->getCurrentCamera().isEmpty())
386 phd2Guider->requestCurrentEquipmentUpdate();
392 QString currentPHD2CameraName =
"None";
393 if(m_Camera && phd2Guider->getCurrentCamera().contains(m_Camera->getDeviceName()))
396 currentPHD2CameraName = (phd2Guider->getCurrentCamera());
402 if(m_LastPHD2CameraName == currentPHD2CameraName)
404 setExternalGuiderBLOBEnabled(!guideSubframe->isChecked());
410 setExternalGuiderBLOBEnabled(
false);
416 m_LastPHD2CameraName = currentPHD2CameraName;
418 m_LastPHD2MountName = phd2Guider->getCurrentMount();
421 phd2Guider->setCurrentCameraIsNotInEkos(m_Camera ==
nullptr);
423 if(phd2Guider->isCurrentCameraNotInEkos())
426 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.",
427 phd2Guider->getCurrentCamera()));
428 guideSubframe->setEnabled(
false);
431 guideSubframe->setChecked(
true);
436 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.",
437 phd2Guider->getCurrentCamera()));
438 guideSubframe->setEnabled(
true);
440 guideSubframe->setChecked(guideSubframe->isChecked());
445 if (m_Mount && m_Mount == device)
452 m_Mount->disconnect(
this);
462 return m_Camera->getDeviceName();
471 if (!m_Camera || guiderType != GUIDE_INTERNAL)
479 case GUIDE_CONNECTED:
480 case GUIDE_DISCONNECTED:
481 case GUIDE_CALIBRATION_ERROR:
489 case GUIDE_STAR_SELECT:
490 case GUIDE_CALIBRATING:
491 case GUIDE_CALIBRATION_SUCCESS:
493 case GUIDE_SUSPENDED:
494 case GUIDE_REACQUIRE:
495 case GUIDE_DITHERING:
496 case GUIDE_MANUAL_DITHERING:
497 case GUIDE_DITHERING_ERROR:
498 case GUIDE_DITHERING_SUCCESS:
499 case GUIDE_DITHERING_SETTLE:
505 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
508 qCCritical(KSTARS_EKOS_GUIDE) <<
"Failed to retrieve active guide chip in camera";
512 if (targetChip->isCapturing())
515 if (guiderType != GUIDE_INTERNAL)
527void Ekos::Guide::checkUseGuideHead()
529 if (m_Camera ==
nullptr)
532 if (m_Camera->hasGuideHead() && Options::useGuideHead())
535 useGuideHead =
false;
537 opsGuide->kcfg_UseGuideHead->
setEnabled(m_Camera->hasGuideHead());
540void Guide::syncCameraInfo()
545 auto nvp = m_Camera->getNumber(useGuideHead ?
"GUIDER_INFO" :
"CCD_INFO");
549 auto np = nvp.findWidgetByName(
"CCD_PIXEL_SIZE_X");
551 ccdPixelSizeX = np->getValue();
553 np = nvp.findWidgetByName(
"CCD_PIXEL_SIZE_Y");
555 ccdPixelSizeY = np->getValue();
557 np = nvp.findWidgetByName(
"CCD_PIXEL_SIZE_Y");
559 ccdPixelSizeY = np->getValue();
565void Guide::syncTelescopeInfo()
567 if (m_Mount ==
nullptr || m_Mount->isConnected() ==
false)
573void Guide::updateGuideParams()
575 if (m_Camera ==
nullptr)
580 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
582 if (targetChip ==
nullptr)
584 appendLogText(
i18n(
"Connection to the guide CCD is lost."));
588 if (targetChip->getFrameType() != FRAME_LIGHT)
591 if(guiderType == GUIDE_INTERNAL)
592 guideBinning->setEnabled(targetChip->canBin());
594 int subBinX = 1, subBinY = 1;
595 if (targetChip->canBin())
597 int maxBinX, maxBinY;
599 targetChip->getBinning(&subBinX, &subBinY);
600 targetChip->getMaxBin(&maxBinX, &maxBinY);
603 if( guideBinIndex >= 0 && guideBinIndex < maxBinX && guideBinIndex < maxBinY )
605 subBinX = guideBinIndex + 1;
606 subBinY = guideBinIndex + 1;
609 guideBinIndex = subBinX - 1;
611 guideBinning->blockSignals(
true);
613 guideBinning->clear();
614 for (
int i = 1; i <= maxBinX; i++)
615 guideBinning->addItem(QString(
"%1x%2").arg(i).arg(i));
617 guideBinning->setCurrentIndex( guideBinIndex );
619 guideBinning->blockSignals(
false);
623 if (frameSettings.contains(targetChip) ==
false)
626 if (targetChip->getFrame(&
x, &
y, &w, &h))
630 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
631 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
632 auto subframed = guideSubframe->isChecked();
634 QVariantMap settings;
636 settings[
"x"] = subframed ?
x : minX;
637 settings[
"y"] = subframed ?
y : minY;
638 settings[
"w"] = subframed ? w : maxW;
639 settings[
"h"] = subframed ? h : maxH;
640 settings[
"binx"] = subBinX;
641 settings[
"biny"] = subBinY;
643 frameSettings[targetChip] = settings;
650 QVariantMap settings = frameSettings[targetChip];
651 settings[
"binx"] = subBinX;
652 settings[
"biny"] = subBinY;
653 frameSettings[targetChip] = settings;
656 if (ccdPixelSizeX != -1 && ccdPixelSizeY != -1 && m_FocalLength > 0)
658 auto effectiveFocaLength = m_Reducer * m_FocalLength;
659 m_GuiderInstance->setGuiderParams(ccdPixelSizeX, ccdPixelSizeY, m_Aperture, effectiveFocaLength);
660 emit guideChipUpdated(targetChip);
663 if (targetChip->getFrame(&
x, &
y, &w, &h))
665 m_GuiderInstance->setFrameParams(
x,
y, w, h, subBinX, subBinY);
668 l_Focal->setText(QString(
"%1mm").arg(m_FocalLength, 0,
'f', 0));
670 l_Aperture->setText(QString(
"%1mm").arg(m_Aperture, 0,
'f', 0));
673 l_Aperture->setText(
"DSLR");
674 l_Reducer->setText(QString(
"%1x").arg(
QString::number(m_Reducer,
'f', 2)));
676 if (m_FocalRatio > 0)
677 l_FbyD->setText(QString(
"F/%1").arg(m_FocalRatio, 0,
'f', 1));
678 else if (m_Aperture > 0)
679 l_FbyD->setText(QString(
"F/%1").arg(m_FocalLength / m_Aperture, 0,
'f', 1));
682 pixScaleX = 206264.8062470963552 * ccdPixelSizeX / 1000.0 / effectiveFocaLength;
683 pixScaleY = 206264.8062470963552 * ccdPixelSizeY / 1000.0 / effectiveFocaLength;
686 double fov_w = (w * pixScaleX) / 60.0;
687 double fov_h = (h * pixScaleY) / 60.0;
693 if (m_Camera->hasGain())
695 double min, max, step, value;
696 m_Camera->getGainMinMaxStep(&min, &max, &step);
699 guideGainSpecialValue = min - step;
700 guideGain->setRange(guideGainSpecialValue, max);
701 guideGain->setSpecialValueText(
i18n(
"--"));
702 guideGain->setEnabled(
true);
703 guideGain->setSingleStep(step);
704 m_Camera->getGain(&value);
706 auto gain = m_Settings[
"guideGain"];
710 TargetCustomGainValue = gain.toDouble();
711 if (TargetCustomGainValue > 0)
712 guideGain->setValue(TargetCustomGainValue);
714 guideGain->setValue(guideGainSpecialValue);
716 guideGain->setReadOnly(m_Camera->getGainPermission() == IP_RO);
720 if (guideGain->value() > guideGainSpecialValue)
721 TargetCustomGainValue = guideGain->value();
725 guideGain->setEnabled(
false);
730 if (guiderType != GUIDE_INTERNAL || (m_Guider && device == m_Guider))
734 m_Guider->disconnect(
this);
740 connect(m_Guider, &ISD::ConcreteDevice::Connected,
this, [
this]()
742 guideB->setEnabled(
true);
744 connect(m_Guider, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
746 guideB->setEnabled(
false);
750 guideB->setEnabled(m_Guider && m_Guider->isConnected());
756 if (guiderType != GUIDE_INTERNAL || (m_AO && device == m_AO))
760 m_AO->disconnect(
this);
769 if (guiderType != GUIDE_INTERNAL || m_Guider ==
nullptr)
772 return m_Guider->getDeviceName();
801 if (guiderType == GUIDE_INTERNAL && captureTimeout.isActive() && captureTimeout.remainingTime() > 0)
803 qCDebug(KSTARS_EKOS_GUIDE) <<
"Internal guider skipping capture, already running with remaining seconds =" <<
804 captureTimeout.remainingTime() / 1000.0;
808 buildOperationStack(GUIDE_CAPTURE);
810 return executeOperationStack();
813bool Guide::captureOneFrame()
815 captureTimeout.
stop();
817 if (m_Camera ==
nullptr)
820 if (m_Camera->isConnected() ==
false)
822 appendLogText(
i18n(
"Error: lost connection to CCD."));
826 double seqExpose = guideExposure->value();
828 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
830 prepareCapture(targetChip);
832 m_GuideView->setBaseSize(guideWidget->size());
836 if (frameSettings.
contains(targetChip))
838 QVariantMap settings = frameSettings[targetChip];
839 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
840 settings[
"h"].toInt());
841 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)
935 if (enable && m_ProgressIndicator->
isAnimated())
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);
967 guideDarkFrame->setEnabled(
true);
968 guideAutoStar->setEnabled(!internalGuider->SEPMultiStarEnabled());
970 guideSubframe->setEnabled(!internalGuider->SEPMultiStarEnabled());
973 guideSubframe->setEnabled(!phd2Guider->isCurrentCameraNotInEkos());
980 if (calibrationComplete ||
981 ((guiderType == GUIDE_INTERNAL) &&
982 Options::reuseGuideCalibration() &&
983 !Options::serializedCalibration().isEmpty()))
984 clearCalibrationB->setEnabled(
true);
985 guideB->setEnabled(
true);
986 stopB->setEnabled(
false);
987 m_ProgressIndicator->stopAnimation();
990 opticalTrainCombo->setEnabled(
true);
991 trainB->setEnabled(
true);
998void Guide::processCaptureTimeout()
1001 if (m_State == GUIDE_SUSPENDED)
1003 appendLogText(
i18n(
"Exposure timeout, but suspended. Ignoring..."));
1007 auto restartExposure = [&]()
1009 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
1010 m_Camera->setEncodingFormat(
"FITS");
1011 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1012 targetChip->abortExposure();
1013 prepareCapture(targetChip);
1017 targetChip->capture(guideExposure->value());
1018 captureTimeout.start(guideExposure->value() * 1000 + CAPTURE_TIMEOUT_THRESHOLD);
1021 m_CaptureTimeoutCounter++;
1023 if (m_Camera ==
nullptr)
1026 if (m_DeviceRestartCounter >= 3)
1028 m_CaptureTimeoutCounter = 0;
1029 m_DeviceRestartCounter = 0;
1030 if (m_State == GUIDE_GUIDING)
1031 appendLogText(
i18n(
"Exposure timeout. Aborting Autoguide."));
1032 else if (m_State == GUIDE_DITHERING)
1033 appendLogText(
i18n(
"Exposure timeout. Aborting Dithering."));
1034 else if (m_State == GUIDE_CALIBRATING)
1035 appendLogText(
i18n(
"Exposure timeout. Aborting Calibration."));
1037 captureTimeout.stop();
1042 if (m_CaptureTimeoutCounter > 3)
1044 appendLogText(
i18n(
"Exposure timeout. Too many. Restarting driver."));
1045 QString camera = m_Camera->getDeviceName();
1046 QString via = m_Guider ? m_Guider->getDeviceName() :
"";
1047 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1048 QVariantMap settings = frameSettings[targetChip];
1049 emit driverTimedout(camera);
1052 m_DeviceRestartCounter++;
1053 reconnectDriver(camera, settings);
1061void Guide::reconnectDriver(
const QString &camera, QVariantMap settings)
1063 if (m_Camera && m_Camera->getDeviceName() == camera)
1066 Ekos::GuideState currentState = m_State;
1067 m_State = GUIDE_IDLE;
1070 m_State = currentState;
1072 if (guiderType == GUIDE_INTERNAL)
1075 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1076 frameSettings[targetChip] = settings;
1078 m_CaptureTimeoutCounter = 0;
1087 reconnectDriver(camera, settings);
1093 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1094 if (targetChip->getCaptureMode() != FITS_GUIDE)
1098 QString blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1099 .
arg(data->property(
"blobVector").toString())
1100 .
arg(data->property(
"blobElement").toString())
1101 .
arg(data->property(
"chip").toInt());
1103 qCWarning(KSTARS_EKOS_GUIDE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1104 targetChip->getCaptureMode();
1110 captureTimeout.stop();
1111 m_CaptureTimeoutCounter = 0;
1113 if (data && (!guideShowFrame->isEnabled() || guideShowFrame->isChecked()))
1115 m_GuideView->loadData(data);
1119 m_ImageData.reset();
1121 if (guiderType == GUIDE_INTERNAL)
1122 internalGuider->setImageData(m_ImageData);
1126 int subBinX = 1, subBinY = 1;
1127 targetChip->getBinning(&subBinX, &subBinY);
1129 if (starCenter.x() == 0 && starCenter.y() == 0)
1131 int x = 0,
y = 0, w = 0, h = 0;
1133 if (frameSettings.contains(targetChip))
1135 QVariantMap settings = frameSettings[targetChip];
1136 x = settings[
"x"].toInt();
1137 y = settings[
"y"].toInt();
1138 w = settings[
"w"].toInt();
1139 h = settings[
"h"].toInt();
1142 targetChip->getFrame(&
x, &
y, &w, &h);
1144 starCenter.setX(w / (2 * subBinX));
1145 starCenter.setY(h / (2 * subBinY));
1146 starCenter.setZ(subBinX);
1149 syncTrackingBoxPosition();
1152 setCaptureComplete();
1157void Guide::setCaptureComplete()
1159 if (!m_GuideView.
isNull())
1160 m_GuideView->clearNeighbors();
1162 DarkLibrary::Instance()->disconnect(
this);
1164 if (operationStack.isEmpty() ==
false)
1166 executeOperationStack();
1170 qCDebug(KSTARS_EKOS_GUIDE) <<
"Capture complete, state=" << getGuideStatusString(m_State);
1175 case GUIDE_CONNECTED:
1176 case GUIDE_DISCONNECTED:
1177 case GUIDE_CALIBRATION_SUCCESS:
1178 case GUIDE_CALIBRATION_ERROR:
1179 case GUIDE_DITHERING_ERROR:
1184 qCDebug(KSTARS_EKOS_GUIDE) <<
"Guiding capture complete.";
1185 m_State = GUIDE_IDLE;
1186 emit newStatus(m_State);
1194 case GUIDE_CALIBRATING:
1195 m_GuiderInstance->calibrate();
1199 if (guiderType == GUIDE_INTERNAL)
1202 m_GuiderInstance->guide();
1206 case GUIDE_DITHERING:
1207 m_GuiderInstance->dither(Options::ditherPixels());
1211 case GUIDE_MANUAL_DITHERING:
1212 dynamic_cast<InternalGuider*
>(m_GuiderInstance)->processManualDithering();
1215 case GUIDE_REACQUIRE:
1216 m_GuiderInstance->reacquire();
1219 case GUIDE_DITHERING_SETTLE:
1220 if (Options::ditherNoGuiding())
1225 case GUIDE_SUSPENDED:
1226 if (guiderType == GUIDE_INTERNAL &&
1227 (Options::rAGuidePulseAlgorithm() == OpsGuide::GPG_ALGORITHM))
1228 m_GuiderInstance->guide();
1235 emit newImage(m_GuideView);
1236 emit newStarPixmap(m_GuideView->getTrackingBoxPixmap(10));
1239void Guide::appendLogText(
const QString &text)
1241 m_LogText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
1242 KStarsData::Instance()->lt().
toString(
"yyyy-MM-ddThh:mm:ss"), text));
1244 qCInfo(KSTARS_EKOS_GUIDE) << text;
1257 if (m_Guider ==
nullptr || m_GuiderInstance ==
nullptr)
1260 if (guiderType == GUIDE_INTERNAL)
1262 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->
setDECSwap(enable);
1263 m_Guider->setDECSwap(enable);
1267bool Guide::sendMultiPulse(GuideDirection ra_dir,
int ra_msecs, GuideDirection dec_dir,
int dec_msecs,
1268 CaptureAfterPulses followWithCapture)
1270 if (m_Guider ==
nullptr || (ra_dir == NO_DIR && dec_dir == NO_DIR))
1273 if (followWithCapture == StartCaptureAfterPulses)
1277 auto ms = std::max(ra_msecs, dec_msecs) + 100;
1278 auto delay = std::max(
static_cast<int>(guideDelay->value() * 1000), ms);
1280 m_PulseTimer.
start(delay);
1282 return m_Guider->doPulse(ra_dir, ra_msecs, dec_dir, dec_msecs);
1285bool Guide::sendSinglePulse(GuideDirection dir,
int msecs, CaptureAfterPulses followWithCapture)
1287 if (m_Guider ==
nullptr || dir == NO_DIR)
1290 if (followWithCapture == StartCaptureAfterPulses)
1294 auto ms = msecs + 100;
1295 auto delay = std::max(
static_cast<int>(guideDelay->value() * 1000), ms);
1297 m_PulseTimer.start(delay);
1300 return m_Guider->doPulse(dir, msecs);
1306 m_State = GUIDE_IDLE;
1307 qCDebug(KSTARS_EKOS_GUIDE) <<
"Calibrating...";
1308 emit newStatus(m_State);
1310 if (guiderType == GUIDE_INTERNAL)
1314 KSNotification::error(
i18n(
"No camera detected. Check camera in optical trains."));
1320 KSNotification::error(
i18n(
"No guider detected. Check guide-via in optical trains."));
1324 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1326 if (frameSettings.contains(targetChip))
1328 targetChip->resetFrame();
1330 targetChip->getFrame(&
x, &
y, &w, &h);
1331 QVariantMap settings = frameSettings[targetChip];
1336 frameSettings[targetChip] = settings;
1342 buildOperationStack(GUIDE_CALIBRATING);
1344 executeOperationStack();
1346 if (m_Camera && m_Guider)
1348 qCDebug(KSTARS_EKOS_GUIDE) <<
"Starting calibration using camera:" << m_Camera->getDeviceName() <<
"via" <<
1349 m_Guider->getDeviceName();
1357 auto executeGuide = [
this]()
1359 if(guiderType != GUIDE_PHD2)
1361 if (calibrationComplete ==
false)
1368 m_GuiderInstance->guide();
1374 if(!guideAutoStar->isChecked())
1376 if(guiderType == GUIDE_PHD2 && m_GuideView->isTrackingBoxEnabled())
1378 double x = starCenter.x();
1379 double y = starCenter.y();
1381 if(!m_ImageData.isNull())
1383 if(m_ImageData->width() > 50)
1385 guideConnect =
connect(
this, &Guide::newStatus,
this, [
this,
x,
y](Ekos::GuideState newState)
1387 if(newState == GUIDE_GUIDING)
1389 phd2Guider->setLockPosition(
x,
y);
1399 if (m_MountStatus == ISD::Mount::MOUNT_PARKED)
1401 KSMessageBox::Instance()->sorry(
i18n(
"The mount is parked. Unpark to start guiding."));
1411 if (Options::ditherNoGuiding() && m_State == GUIDE_IDLE)
1417 if (m_State == GUIDE_DITHERING || m_State == GUIDE_DITHERING_SETTLE)
1421 double time = guideTimer.elapsed() / 1000.0;
1425 ditherLabel->position->
setCoords(time, 1.5);
1429 ditherLabel->
setText(
"Dither");
1432 if (guiderType == GUIDE_INTERNAL && !Options::ditherWithOnePulse())
1434 if (m_State != GUIDE_GUIDING)
1437 setStatus(GUIDE_DITHERING);
1442 return m_GuiderInstance->dither(Options::ditherPixels());
1447 if (m_State == GUIDE_SUSPENDED)
1449 else if (m_State >= GUIDE_CAPTURE)
1450 return m_GuiderInstance->suspend();
1457 if (m_State == GUIDE_GUIDING)
1459 else if (m_State == GUIDE_SUSPENDED)
1460 return m_GuiderInstance->resume();
1486void Guide::setPierSide(ISD::Mount::PierSide newSide)
1488 m_GuiderInstance->setPierSide(newSide);
1493 if (guiderType == GUIDE_INTERNAL &&
1494 m_State != GUIDE_GUIDING &&
1495 m_State != GUIDE_CALIBRATING &&
1496 calibrationComplete)
1499 if (Options::reuseGuideCalibration())
1500 calibrationComplete =
false;
1504 appendLogText(
i18n(
"Pier side change detected. Clearing calibration."));
1509void Guide::setMountStatus(ISD::Mount::Status newState)
1511 m_MountStatus = newState;
1513 if (newState == ISD::Mount::MOUNT_PARKING || newState == ISD::Mount::MOUNT_SLEWING)
1516 if (Options::resetGuideCalibration())
1518 appendLogText(
i18n(
"Mount is moving. Resetting calibration..."));
1521 else if (Options::reuseGuideCalibration() && (guiderType == GUIDE_INTERNAL))
1524 calibrationComplete =
false;
1527 if (guiderType == GUIDE_INTERNAL &&
1528 (Options::rAGuidePulseAlgorithm() == OpsGuide::GPG_ALGORITHM))
1529 m_GuiderInstance->resetGPG();
1532 if (m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1534 if (newState == ISD::Mount::MOUNT_PARKING)
1535 appendLogText(
i18n(
"Mount is parking. Aborting guide..."));
1537 appendLogText(
i18n(
"Mount is slewing. Aborting guide..."));
1543 if (guiderType != GUIDE_INTERNAL)
1548 case ISD::Mount::MOUNT_SLEWING:
1549 case ISD::Mount::MOUNT_PARKING:
1550 case ISD::Mount::MOUNT_MOVING:
1551 captureB->setEnabled(
false);
1552 loopB->setEnabled(
false);
1553 clearCalibrationB->setEnabled(
false);
1554 manualPulseB->setEnabled(
false);
1558 if (m_ProgressIndicator->isAnimated() ==
false)
1560 captureB->setEnabled(
true);
1561 loopB->setEnabled(
true);
1562 clearCalibrationB->setEnabled(
true);
1563 manualPulseB->setEnabled(
true);
1568void Guide::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
1571 m_GuiderInstance->setMountCoords(position, pierSide);
1572 m_ManaulPulse->setMountCoords(position);
1577 guideExposure->setValue(value);
1582 if (guideSubframe->isChecked() != enable)
1583 guideSubframe->setChecked(enable);
1584 if(guiderType == GUIDE_PHD2)
1585 setExternalGuiderBLOBEnabled(!enable);
1590 if(guiderType == GUIDE_INTERNAL)
1591 guideAutoStar->setChecked(enable);
1596 calibrationComplete =
false;
1597 if (m_GuiderInstance->clearCalibration())
1599 clearCalibrationB->setEnabled(
false);
1600 appendLogText(
i18n(
"Calibration is cleared."));
1606void Guide::setStatus(Ekos::GuideState newState)
1608 if (newState == m_State)
1611 if (newState == GUIDE_ABORTED)
1612 emit newStatus(m_State);
1616 GuideState previousState = m_State;
1619 if (newState != GUIDE_CONNECTED && newState != GUIDE_DISCONNECTED)
1622 emit newStatus(m_State);
1627 case GUIDE_CONNECTED:
1628 appendLogText(
i18n(
"External guider connected."));
1629 externalConnectB->setEnabled(
false);
1630 externalDisconnectB->setEnabled(
true);
1631 clearCalibrationB->setEnabled(
true);
1633 if(guiderType == GUIDE_PHD2)
1635 configurePHD2Camera();
1636 setExternalGuiderBLOBEnabled(!guideSubframe->isChecked());
1637 setBusy(isGuiderActive(previousState));
1641 guideB->setEnabled(
true);
1645 case GUIDE_DISCONNECTED:
1646 appendLogText(
i18n(
"External guider disconnected."));
1648 externalConnectB->setEnabled(
true);
1649 externalDisconnectB->setEnabled(
false);
1650 clearCalibrationB->setEnabled(
false);
1651 guideB->setEnabled(
false);
1652 captureB->setEnabled(
false);
1653 loopB->setEnabled(
false);
1654 guideAutoStar->setEnabled(
false);
1655 guideSquareSize->setEnabled(
false);
1662 case GUIDE_CALIBRATION_SUCCESS:
1663 appendLogText(
i18n(
"Calibration completed."));
1664 manualPulseB->setEnabled(
true);
1665 calibrationComplete =
true;
1673 case GUIDE_CALIBRATION_ERROR:
1675 manualDitherB->setEnabled(
false);
1676 manualPulseB->setEnabled(
true);
1679 case GUIDE_CALIBRATING:
1680 clearCalibrationGraphs();
1681 appendLogText(
i18n(
"Calibration started."));
1683 manualPulseB->setEnabled(
false);
1687 if (previousState == GUIDE_SUSPENDED || previousState == GUIDE_DITHERING_SUCCESS)
1688 appendLogText(
i18n(
"Guiding resumed."));
1691 appendLogText(
i18n(
"Autoguiding running."));
1696 driftGraph->resetTimer();
1697 driftGraph->refreshColorScheme();
1699 manualDitherB->setEnabled(
true);
1703 appendLogText(
i18n(
"Autoguiding aborted."));
1707 case GUIDE_SUSPENDED:
1708 appendLogText(
i18n(
"Guiding suspended."));
1711 case GUIDE_REACQUIRE:
1712 if (guiderType == GUIDE_INTERNAL)
1716 case GUIDE_MANUAL_DITHERING:
1717 appendLogText(
i18n(
"Manual dithering in progress."));
1720 case GUIDE_DITHERING:
1721 appendLogText(
i18n(
"Dithering in progress."));
1724 case GUIDE_DITHERING_SETTLE:
1725 appendLogText(
i18np(
"Post-dither settling for %1 second...",
"Post-dither settling for %1 seconds...",
1726 Options::ditherSettle()));
1729 case GUIDE_DITHERING_ERROR:
1730 appendLogText(
i18n(
"Dithering failed."));
1732 if (guiderType != GUIDE_LINGUIDER)
1735 m_State = GUIDE_ABORTED;
1740 case GUIDE_DITHERING_SUCCESS:
1741 appendLogText(
i18n(
"Dithering completed successfully."));
1743 if (Options::ditherNoGuiding() ==
false)
1745 setStatus(GUIDE_GUIDING);
1747 if (guiderType == GUIDE_INTERNAL)
1759void Guide::updateCCDBin(
int index)
1761 if (m_Camera ==
nullptr || guiderType != GUIDE_INTERNAL)
1764 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1766 targetChip->setBinning(index + 1, index + 1);
1767 guideBinIndex = index;
1769 QVariantMap settings = frameSettings[targetChip];
1770 settings[
"binx"] = index + 1;
1771 settings[
"biny"] = index + 1;
1772 frameSettings[targetChip] = settings;
1774 m_GuiderInstance->setFrameParams(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(), settings[
"h"].toInt(),
1775 settings[
"binx"].toInt(), settings[
"biny"].toInt());
1780 if (m_Camera ==
nullptr || (prop.getDeviceName() != m_Camera->getDeviceName()) || guiderType != GUIDE_INTERNAL)
1783 if ((prop.isNameMatch(
"CCD_BINNING") && useGuideHead ==
false) ||
1784 (prop.isNameMatch(
"GUIDER_BINNING") && useGuideHead))
1786 auto nvp = prop.getNumber();
1787 auto value = nvp->at(0)->getValue();
1788 if (guideBinIndex > (value - 1))
1790 appendLogText(
i18n(
"%1x%1 guide binning is not supported.", guideBinIndex + 1));
1791 guideBinning->setCurrentIndex( value - 1 );
1796 guideBinning->setCurrentIndex(guideBinIndex);
1804 if (guiderType != GUIDE_INTERNAL || targetChip->getCCD() != m_Camera)
1807 INDI_UNUSED(exposure);
1809 if (expState == IPS_ALERT &&
1810 ((m_State == GUIDE_GUIDING) || (m_State == GUIDE_DITHERING) || (m_State == GUIDE_CALIBRATING)))
1812 appendLogText(
i18n(
"Exposure failed. Restarting exposure..."));
1813 m_Camera->setEncodingFormat(
"FITS");
1814 targetChip->capture(guideExposure->value());
1818void Guide::configSEPMultistarOptions()
1821 if (internalGuider->SEPMultiStarEnabled())
1823 guideSubframe->setChecked(
false);
1824 guideSubframe->setEnabled(
false);
1825 guideAutoStar->setChecked(
true);
1826 guideAutoStar->setEnabled(
false);
1830 guideAutoStar->setEnabled(
true);
1831 guideSubframe->setEnabled(
true);
1833 auto subframed = m_Settings[
"guideSubframe"];
1834 if (subframed.isValid())
1835 guideSubframe->setChecked(subframed.toBool());
1837 auto autostar = m_Settings[
"guideAutoStar"];
1838 if (autostar.isValid())
1839 guideAutoStar->setChecked(autostar.toBool());
1845 if (guideDarkFrame->isChecked() != enable)
1846 guideDarkFrame->setChecked(enable);
1849void Guide::saveDefaultGuideExposure()
1851 if(guiderType == GUIDE_PHD2)
1853 phd2Guider->requestSetExposureTime(guideExposure->value() * 1000);
1854 else if (guiderType == GUIDE_INTERNAL)
1856 internalGuider->setExposureTime();
1860void Guide::setStarPosition(
const QVector3D &newCenter,
bool updateNow)
1862 starCenter.setX(newCenter.
x());
1863 starCenter.setY(newCenter.
y());
1864 if (newCenter.
z() > 0)
1865 starCenter.setZ(newCenter.
z());
1868 syncTrackingBoxPosition();
1871void Guide::syncTrackingBoxPosition()
1873 if(!m_Camera || guiderType == GUIDE_LINGUIDER)
1876 if(guiderType == GUIDE_PHD2)
1879 if(!m_ImageData.isNull())
1881 if(m_ImageData->width() < 50)
1883 m_GuideView->setTrackingBoxEnabled(
false);
1889 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
1890 Q_ASSERT(targetChip);
1892 int subBinX = 1, subBinY = 1;
1893 targetChip->getBinning(&subBinX, &subBinY);
1895 if (starCenter.isNull() ==
false)
1897 double boxSize = guideSquareSize->currentText().toInt();
1899 targetChip->getFrame(&
x, &
y, &w, &h);
1901 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
1903 int newIndex = guideSquareSize->currentIndex() - 1;
1905 guideSquareSize->setCurrentIndex(newIndex);
1910 if (subBinX != starCenter.z())
1912 if (starCenter.z() > 0)
1914 starCenter.setX(starCenter.x() * (starCenter.z() / subBinX));
1915 starCenter.setY(starCenter.y() * (starCenter.z() / subBinY));
1918 starCenter.setZ(subBinX);
1921 QRect starRect = QRect(starCenter.x() - boxSize / (2 * subBinX), starCenter.y() - boxSize / (2 * subBinY),
1922 boxSize / subBinX, boxSize / subBinY);
1923 m_GuideView->setTrackingBoxEnabled(
true);
1924 m_GuideView->setTrackingBox(starRect);
1932 type = Options::guiderType();
1933 else if (type == guiderType)
1936 if (m_State == GUIDE_CALIBRATING || m_State == GUIDE_GUIDING || m_State == GUIDE_DITHERING)
1938 appendLogText(
i18n(
"Cannot change guider type while active."));
1942 if (m_GuiderInstance !=
nullptr)
1945 if (m_GuiderInstance->isConnected())
1946 m_GuiderInstance->Disconnect();
1949 m_GuiderInstance->disconnect();
1952 guiderType =
static_cast<GuiderType
>(type);
1956 case GUIDE_INTERNAL:
1958 connect(internalGuider, &InternalGuider::newMultiPulse,
this, &Guide::sendMultiPulse);
1959 connect(internalGuider, &InternalGuider::newSinglePulse,
this, &Guide::sendSinglePulse);
1961 connect(internalGuider, &InternalGuider::newStarPixmap,
this, &Guide::newStarPixmap);
1963 m_GuiderInstance = internalGuider;
1965 internalGuider->setStarDetectionAlgorithm(opsGuide->kcfg_GuideAlgorithm->currentIndex());
1967 clearCalibrationB->setEnabled(
true);
1968 guideB->setEnabled(
true);
1969 captureB->setEnabled(
true);
1970 loopB->setEnabled(
true);
1972 configSEPMultistarOptions();
1973 guideDarkFrame->setEnabled(
true);
1975 guideExposure->setEnabled(
true);
1976 guideBinning->setEnabled(
true);
1977 guideSquareSize->setEnabled(
true);
1979 externalConnectB->setEnabled(
false);
1980 externalDisconnectB->setEnabled(
false);
1982 opsGuide->controlGroup->setEnabled(
true);
1983 infoGroup->setEnabled(
true);
1984 l_Aperture->setEnabled(
true);
1985 l_FOV->setEnabled(
true);
1986 l_FbyD->setEnabled(
true);
1987 l_Focal->setEnabled(
true);
1988 driftGraphicsGroup->setEnabled(
true);
1990 updateGuideParams();
1995 if (phd2Guider.isNull())
1996 phd2Guider =
new PHD2();
1998 m_GuiderInstance = phd2Guider;
1999 phd2Guider->setGuideView(m_GuideView);
2003 clearCalibrationB->setEnabled(
true);
2004 captureB->setEnabled(
false);
2005 loopB->setEnabled(
false);
2006 guideDarkFrame->setEnabled(
false);
2007 guideSubframe->setEnabled(
false);
2008 guideAutoStar->setEnabled(
false);
2009 guideB->setEnabled(
false);
2010 externalConnectB->setEnabled(
false);
2012 guideShowFrame->setEnabled(
true);
2013 displayGuideView(guideShowFrame->isChecked());
2016 rAGuideEnabled->setEnabled(
false);
2017 eastRAGuideEnabled->setEnabled(
false);
2018 westRAGuideEnabled->setEnabled(
false);
2020 opsGuide->controlGroup->setEnabled(
false);
2021 infoGroup->setEnabled(
true);
2022 l_Aperture->setEnabled(
false);
2023 l_FOV->setEnabled(
false);
2024 l_FbyD->setEnabled(
false);
2025 l_Focal->setEnabled(
false);
2026 driftGraphicsGroup->setEnabled(
true);
2028 guideExposure->setEnabled(
true);
2029 guideBinning->setEnabled(
false);
2030 guideSquareSize->setEnabled(
false);
2032 if (Options::resetGuideCalibration())
2033 appendLogText(
i18n(
"Warning: Reset Guiding Calibration is enabled. It is recommended to turn this option off for PHD2."));
2035 updateGuideParams();
2038 case GUIDE_LINGUIDER:
2039 if (linGuider.isNull())
2042 m_GuiderInstance = linGuider;
2044 clearCalibrationB->setEnabled(
true);
2045 captureB->setEnabled(
false);
2046 loopB->setEnabled(
false);
2047 guideDarkFrame->setEnabled(
false);
2048 guideSubframe->setEnabled(
false);
2049 guideAutoStar->setEnabled(
false);
2050 guideB->setEnabled(
true);
2051 externalConnectB->setEnabled(
true);
2053 opsGuide->controlGroup->setEnabled(
false);
2054 infoGroup->setEnabled(
false);
2055 driftGraphicsGroup->setEnabled(
false);
2057 guideExposure->setEnabled(
false);
2058 guideBinning->setEnabled(
false);
2059 guideSquareSize->setEnabled(
false);
2061 updateGuideParams();
2066 if (m_GuiderInstance !=
nullptr)
2069 connect(m_GuiderInstance, &Ekos::GuideInterface::newLog,
this, &Ekos::Guide::appendLogText);
2070 connect(m_GuiderInstance, &Ekos::GuideInterface::newStatus,
this, &Ekos::Guide::setStatus);
2071 connect(m_GuiderInstance, &Ekos::GuideInterface::newStarPosition,
this, &Ekos::Guide::setStarPosition);
2072 connect(m_GuiderInstance, &Ekos::GuideInterface::guideStats,
this, &Ekos::Guide::guideStats);
2074 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisDelta,
this, &Ekos::Guide::setAxisDelta);
2075 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisPulse,
this, &Ekos::Guide::setAxisPulse);
2076 connect(m_GuiderInstance, &Ekos::GuideInterface::newAxisSigma,
this, &Ekos::Guide::setAxisSigma);
2077 connect(m_GuiderInstance, &Ekos::GuideInterface::newSNR,
this, &Ekos::Guide::setSNR);
2078 connect(m_GuiderInstance, &Ekos::GuideInterface::guideInfo,
this, &Ekos::Guide::guideInfo);
2079 connect(m_GuiderInstance, &Ekos::GuideInterface::abortExposure,
this, &Ekos::Guide::abortExposure);
2081 driftGraph->connectGuider(m_GuiderInstance);
2082 targetPlot->connectGuider(m_GuiderInstance);
2084 connect(m_GuiderInstance, &Ekos::GuideInterface::calibrationUpdate,
this, &Ekos::Guide::calibrationUpdate);
2086 connect(m_GuiderInstance, &Ekos::GuideInterface::guideEquipmentUpdated,
this, &Ekos::Guide::configurePHD2Camera);
2089 externalConnectB->setEnabled(
false);
2090 externalDisconnectB->setEnabled(
false);
2092 if (m_GuiderInstance !=
nullptr && guiderType != GUIDE_INTERNAL)
2094 externalConnectB->setEnabled(!m_GuiderInstance->isConnected());
2095 externalDisconnectB->setEnabled(m_GuiderInstance->isConnected());
2098 if (m_GuiderInstance !=
nullptr)
2099 m_GuiderInstance->Connect();
2104void Guide::guideInfo(
const QString &info)
2106 if (info.size() == 0)
2108 guideInfoLabel->setVisible(
false);
2109 guideInfoText->setVisible(
false);
2112 guideInfoLabel->setVisible(
true);
2113 guideInfoLabel->setText(
"Detections");
2114 guideInfoText->setVisible(
true);
2115 guideInfoText->setText(info);
2118void Guide::updateTrackingBoxSize(
int currentIndex)
2120 if (currentIndex >= 0)
2122 if (guiderType == GUIDE_INTERNAL)
2123 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setGuideBoxSize(guideSquareSize->currentText().toInt());
2125 syncTrackingBoxPosition();
2129void Guide::onSettingsUpdated(
int starDetectionIndex)
2133 case GUIDE_INTERNAL:
2134 dynamic_cast<InternalGuider *
>(m_GuiderInstance)->setStarDetectionAlgorithm(starDetectionIndex);
2142void Guide::onEnableDirRA()
2145 if (guiderType == GUIDE_INTERNAL &&
2146 (Options::rAGuidePulseAlgorithm() == Ekos::OpsGuide::GPG_ALGORITHM))
2147 m_GuiderInstance->resetGPG();
2150void Guide::onEnableDirDEC()
2152 onControlDirectionChanged();
2155void Guide::onControlDirectionChanged()
2157 if(guiderType == GUIDE_PHD2)
2158 phd2Guider -> requestSetDEGuideMode(dECGuideEnabled->isChecked(), northDECGuideEnabled->isChecked(),
2159 southDECGuideEnabled->isChecked());
2162void Guide::updateDirectionsFromPHD2(
const QString &mode)
2171 dECGuideEnabled->setChecked(
true);
2172 northDECGuideEnabled->setChecked(
true);
2173 southDECGuideEnabled->setChecked(
true);
2175 else if(mode ==
"North")
2177 dECGuideEnabled->setChecked(
true);
2178 northDECGuideEnabled->setChecked(
true);
2179 southDECGuideEnabled->setChecked(
false);
2181 else if(mode ==
"South")
2183 dECGuideEnabled->setChecked(
true);
2184 northDECGuideEnabled->setChecked(
false);
2185 southDECGuideEnabled->setChecked(
true);
2189 dECGuideEnabled->setChecked(
false);
2190 northDECGuideEnabled->setChecked(
true);
2191 southDECGuideEnabled->setChecked(
true);
2203 setStarPosition(newStarPosition,
true);
2205 if(guiderType == GUIDE_PHD2)
2208 if(!m_ImageData.isNull())
2210 if(m_ImageData->width() > 50)
2211 phd2Guider->setLockPosition(starCenter.x(), starCenter.y());
2215 if (operationStack.isEmpty() ==
false)
2216 executeOperationStack();
2219void Guide::setAxisDelta(
double ra,
double de)
2227 int currentNumPoints = driftGraph->graph(GuideGraph::G_RA)->dataCount();
2228 guideSlider->setMaximum(currentNumPoints);
2231 guideSlider->setValue(currentNumPoints);
2236 emit newAxisDelta(ra, de);
2239void Guide::calibrationUpdate(GuideInterface::CalibrationUpdateType type,
const QString &message,
2240 double dx,
double dy)
2244 case GuideInterface::RA_OUT:
2245 calibrationPlot->graph(GuideGraph::G_RA)->addData(dx, dy);
2247 case GuideInterface::RA_OUT_OK:
2248 drawRADECAxis(calRALabel, calRAArrow, dx, dy);
2250 case GuideInterface::RA_IN:
2251 calibrationPlot->graph(GuideGraph::G_DEC)->addData(dx, dy);
2252 calDecArrowStartX = dx;
2253 calDecArrowStartY = dy;
2255 case GuideInterface::BACKLASH:
2256 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->addData(dx, dy);
2257 calDecArrowStartX = dx;
2258 calDecArrowStartY = dy;
2260 case GuideInterface::DEC_OUT:
2261 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(dx, dy);
2263 case GuideInterface::DEC_OUT_OK:
2264 drawRADECAxis(calDECLabel, calDECArrow, dx - calDecArrowStartX, dy - calDecArrowStartY);
2266 case GuideInterface::DEC_IN:
2267 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->addData(dx, dy);
2269 case GuideInterface::CALIBRATION_MESSAGE_ONLY:
2272 calLabel->setText(message);
2273 calibrationPlot->replot();
2276void Guide::drawRADECAxis(QCPItemText *Label, QCPItemLine *Arrow,
const double xEnd,
const double yEnd)
2282 Label->position->setCoords(xEnd, yEnd);
2287 Label->setVisible(
true);
2290void Guide::setAxisSigma(
double ra,
double de)
2294 const double total = std::hypot(ra, de);
2297 emit newAxisSigma(ra, de);
2300QList<double> Guide::axisDelta()
2302 QList<double> delta;
2304 delta << l_DeltaRA->text().toDouble() << l_DeltaDEC->text().toDouble();
2309QList<double> Guide::axisSigma()
2311 QList<double> sigma;
2313 sigma << l_ErrRA->text().toDouble() << l_ErrDEC->text().toDouble();
2318void Guide::setAxisPulse(
double ra,
double de)
2324void Guide::setSNR(
double snr)
2329void Guide::buildOperationStack(GuideState operation)
2331 operationStack.
clear();
2336 if (guideDarkFrame->isChecked())
2337 operationStack.push(GUIDE_DARK);
2339 operationStack.push(GUIDE_CAPTURE);
2340 operationStack.push(GUIDE_SUBFRAME);
2343 case GUIDE_CALIBRATING:
2344 operationStack.push(GUIDE_CALIBRATING);
2345 if (guiderType == GUIDE_INTERNAL)
2347 if (guideDarkFrame->isChecked())
2348 operationStack.push(GUIDE_DARK);
2351 if (guideAutoStar->isChecked() ||
2353 internalGuider->SEPMultiStarEnabled())
2357 if (subFramed ==
false && guideSubframe->isChecked())
2358 operationStack.push(GUIDE_CAPTURE);
2360 operationStack.push(GUIDE_SUBFRAME);
2361 operationStack.push(GUIDE_STAR_SELECT);
2364 operationStack.push(GUIDE_CAPTURE);
2367 if (subFramed ==
true && guideSubframe->isChecked() ==
false)
2368 operationStack.push(GUIDE_SUBFRAME);
2374 if (subFramed ==
false && guideSubframe->isChecked())
2375 operationStack.push(GUIDE_CAPTURE);
2378 operationStack.push(GUIDE_SUBFRAME);
2381 operationStack.push(GUIDE_CAPTURE);
2392bool Guide::executeOperationStack()
2394 if (operationStack.isEmpty())
2397 GuideState nextOperation = operationStack.pop();
2400 bool actionRequired =
false;
2402 switch (nextOperation)
2404 case GUIDE_SUBFRAME:
2405 actionRequired = executeOneOperation(nextOperation);
2409 actionRequired = executeOneOperation(nextOperation);
2413 actionRequired = captureOneFrame();
2416 case GUIDE_STAR_SELECT:
2417 actionRequired = executeOneOperation(nextOperation);
2420 case GUIDE_CALIBRATING:
2421 if (guiderType == GUIDE_INTERNAL)
2423 m_GuiderInstance->setStarPosition(starCenter);
2426 if (m_Mount && m_Mount->canControlTrack() && m_Mount->isTracking() ==
false)
2427 m_Mount->setTrackEnabled(
true);
2430 if (m_GuiderInstance->calibrate())
2432 if (guiderType == GUIDE_INTERNAL)
2438 emit newStatus(GUIDE_CALIBRATION_ERROR);
2439 m_State = GUIDE_IDLE;
2440 appendLogText(
i18n(
"Calibration failed to start."));
2454 return executeOperationStack();
2457bool Guide::executeOneOperation(GuideState operation)
2459 bool actionRequired =
false;
2461 if (m_Camera ==
nullptr)
2462 return actionRequired;
2464 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2465 if (targetChip ==
nullptr)
2468 int subBinX, subBinY;
2469 targetChip->getBinning(&subBinX, &subBinY);
2473 case GUIDE_SUBFRAME:
2476 if ((guiderType == GUIDE_INTERNAL) && internalGuider->SEPMultiStarEnabled())
2479 if (subFramed ==
false && guideSubframe->isChecked() ==
true && targetChip->canSubframe())
2481 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2482 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2484 int offset = guideSquareSize->currentText().toInt() / subBinX;
2486 int x = starCenter.x();
2487 int y = starCenter.y();
2489 x = (
x - offset * 2) * subBinX;
2490 y = (
y - offset * 2) * subBinY;
2491 int w = offset * 4 * subBinX;
2492 int h = offset * 4 * subBinY;
2503 targetChip->setFrame(
x,
y, w, h);
2506 QVariantMap settings = frameSettings[targetChip];
2511 settings[
"binx"] = subBinX;
2512 settings[
"biny"] = subBinY;
2514 frameSettings[targetChip] = settings;
2516 starCenter.setX(w / (2 * subBinX));
2517 starCenter.setY(h / (2 * subBinX));
2523 else if (subFramed &&
2524 (guideSubframe->isChecked() ==
false ||
2525 m_State == GUIDE_REACQUIRE))
2527 targetChip->resetFrame();
2530 targetChip->getFrame(&
x, &
y, &w, &h);
2532 QVariantMap settings;
2537 settings[
"binx"] = subBinX;
2538 settings[
"biny"] = subBinY;
2539 frameSettings[targetChip] = settings;
2543 starCenter.setX(w / (2 * subBinX));
2544 starCenter.setY(h / (2 * subBinX));
2555 if (m_ImageData && guideDarkFrame->isChecked())
2557 QVariantMap settings = frameSettings[targetChip];
2558 uint16_t offsetX = 0;
2559 uint16_t offsetY = 0;
2561 if (settings[
"x"].
isValid() &&
2566 offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
2567 offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
2570 actionRequired =
true;
2571 targetChip->setCaptureFilter(FITS_NONE);
2572 m_DarkProcessor->denoise(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()),
2573 targetChip, m_ImageData, guideExposure->value(), offsetX, offsetY);
2578 case GUIDE_STAR_SELECT:
2580 m_State = GUIDE_STAR_SELECT;
2581 emit newStatus(m_State);
2583 if (guideAutoStar->isChecked() ||
2585 ((guiderType == GUIDE_INTERNAL) &&
2586 internalGuider->SEPMultiStarEnabled()))
2588 bool autoStarCaptured = internalGuider->selectAutoStar();
2589 if (autoStarCaptured)
2591 appendLogText(
i18n(
"Auto star selected."));
2595 appendLogText(
i18n(
"Failed to select an auto star."));
2596 actionRequired =
true;
2597 m_State = GUIDE_CALIBRATION_ERROR;
2598 emit newStatus(m_State);
2604 appendLogText(
i18n(
"Select a guide star to calibrate."));
2605 actionRequired =
true;
2614 return actionRequired;
2617void Guide::processGuideOptions()
2619 if (Options::guiderType() != guiderType)
2621 guiderType =
static_cast<GuiderType
>(Options::guiderType());
2626void Guide::showFITSViewer()
2628 static int lastFVTabID = -1;
2635 fv->loadData(m_ImageData, url, &lastFVTabID);
2636 connect(fv.get(), &FITSViewer::terminated,
this, [
this]()
2641 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
2642 fv->loadData(m_ImageData, url, &lastFVTabID);
2648void Guide::displayGuideView(
bool enabled)
2650 if (!m_GuideView.isNull() && !
enabled)
2651 m_GuideView->clearData();
2660void Guide::setExternalGuiderBLOBEnabled(
bool enable)
2663 if (guiderType == GUIDE_INTERNAL)
2669 m_Camera->setBLOBEnabled(enable);
2671 if(m_Camera->isBLOBEnabled())
2673 checkUseGuideHead();
2675 auto targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2677 targetChip->setCaptureMode(FITS_GUIDE);
2686 nonGuidedDitherRaOffsetMsec = 0;
2687 nonGuidedDitherDecOffsetMsec = 0;
2688 qCDebug(KSTARS_EKOS_GUIDE) <<
"Reset non guiding dithering position";
2691 if (!isNonGuidedDitherInitialized)
2693 auto seed = std::chrono::system_clock::now().time_since_epoch().count();
2694 nonGuidedPulseGenerator.seed(seed);
2695 isNonGuidedDitherInitialized =
true;
2696 qCDebug(KSTARS_EKOS_GUIDE) <<
"Initialize non guiding dithering random generator";
2700void Guide::nonGuidedDither()
2702 double ditherPulse = Options::ditherNoGuidingPulse();
2705 std::uniform_int_distribution<int> newPos(-ditherPulse, +ditherPulse);
2710 const int newRaOffsetMsec = newPos(nonGuidedPulseGenerator);
2711 const int raPulse = nonGuidedDitherRaOffsetMsec - newRaOffsetMsec;
2712 nonGuidedDitherRaOffsetMsec = newRaOffsetMsec;
2713 const int raMsec = std::abs(raPulse);
2714 const int raPolarity = (raPulse >= 0 ? 1 : -1);
2717 const int newDecOffsetMsec = newPos(nonGuidedPulseGenerator);
2718 const int decPulse = nonGuidedDitherDecOffsetMsec - newDecOffsetMsec;
2719 nonGuidedDitherDecOffsetMsec = newDecOffsetMsec;
2720 const int decMsec = std::abs(decPulse);
2721 const int decPolarity = (decPulse >= 0 ? 1 : -1);
2723 qCInfo(KSTARS_EKOS_GUIDE) <<
"Starting non-guiding dither...";
2724 qCDebug(KSTARS_EKOS_GUIDE) <<
"dither ra_msec:" << raMsec <<
"ra_polarity:" << raPolarity <<
"de_msec:" << decMsec <<
2725 "de_polarity:" << decPolarity;
2727 bool rc = sendMultiPulse(raPolarity > 0 ? RA_INC_DIR : RA_DEC_DIR, raMsec, decPolarity > 0 ? DEC_INC_DIR : DEC_DEC_DIR,
2728 decMsec, DontCaptureAfterPulses);
2732 qCInfo(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither successful.";
2733 QTimer::singleShot( (raMsec > decMsec ? raMsec : decMsec) + Options::ditherSettle() * 1000 + 100,
this, [
this]()
2735 emit newStatus(GUIDE_DITHERING_SUCCESS);
2736 m_State = GUIDE_IDLE;
2741 qCWarning(KSTARS_EKOS_GUIDE) <<
"Non-guiding dither failed.";
2742 emit newStatus(GUIDE_DITHERING_ERROR);
2743 m_State = GUIDE_IDLE;
2747void Guide::handleManualDither()
2749 ISD::CameraChip *targetChip = m_Camera->getChip(useGuideHead ? ISD::CameraChip::GUIDE_CCD : ISD::CameraChip::PRIMARY_CCD);
2750 if (targetChip ==
nullptr)
2753 Ui::ManualDither ditherDialog;
2754 QDialog container(
this);
2755 ditherDialog.setupUi(&container);
2757 if (guiderType != GUIDE_INTERNAL)
2759 ditherDialog.coordinatesR->setEnabled(
false);
2760 ditherDialog.x->setEnabled(
false);
2761 ditherDialog.y->setEnabled(
false);
2764 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2765 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2767 ditherDialog.x->setMinimum(minX);
2768 ditherDialog.x->setMaximum(maxX);
2769 ditherDialog.y->setMinimum(minY);
2770 ditherDialog.y->setMaximum(maxY);
2772 ditherDialog.x->setValue(starCenter.x());
2773 ditherDialog.y->setValue(starCenter.y());
2777 if (ditherDialog.magnitudeR->isChecked())
2778 m_GuiderInstance->dither(ditherDialog.magnitude->value());
2781 InternalGuider *
const ig =
dynamic_cast<InternalGuider *
>(m_GuiderInstance);
2783 ig->ditherXY(ditherDialog.x->value(), ditherDialog.y->value());
2790 setStatus(GUIDE_IDLE);
2791 return m_GuiderInstance->Connect();
2796 return m_GuiderInstance->Disconnect();
2799void Guide::initPlots()
2802 initCalibrationPlot();
2810void Guide::initDriftGraph()
2820 driftGraph->setCorrectionGraphScale(correctionSlider->value());
2828 correctionSlider->setValue(scale);
2831void Guide::initCalibrationPlot()
2833 calibrationPlot->setBackground(QBrush(
Qt::black));
2834 calibrationPlot->setSelectionTolerance(10);
2836 calibrationPlot->xAxis->setBasePen(QPen(
Qt::white, 1));
2837 calibrationPlot->yAxis->setBasePen(QPen(
Qt::white, 1));
2839 calibrationPlot->xAxis->setTickPen(QPen(
Qt::white, 1));
2840 calibrationPlot->yAxis->setTickPen(QPen(
Qt::white, 1));
2842 calibrationPlot->xAxis->setSubTickPen(QPen(
Qt::white, 1));
2843 calibrationPlot->yAxis->setSubTickPen(QPen(
Qt::white, 1));
2845 calibrationPlot->xAxis->setTickLabelColor(
Qt::white);
2846 calibrationPlot->yAxis->setTickLabelColor(
Qt::white);
2848 calibrationPlot->xAxis->setLabelColor(
Qt::white);
2849 calibrationPlot->yAxis->setLabelColor(
Qt::white);
2851 calibrationPlot->xAxis->setLabelFont(QFont(
font().family(), 10));
2852 calibrationPlot->yAxis->setLabelFont(QFont(
font().family(), 10));
2853 calibrationPlot->xAxis->setTickLabelFont(QFont(
font().family(), 9));
2854 calibrationPlot->yAxis->setTickLabelFont(QFont(
font().family(), 9));
2856 calibrationPlot->xAxis->setLabelPadding(2);
2857 calibrationPlot->yAxis->setLabelPadding(2);
2859 calibrationPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1,
Qt::DotLine));
2860 calibrationPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1,
Qt::DotLine));
2861 calibrationPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1,
Qt::DotLine));
2862 calibrationPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1,
Qt::DotLine));
2863 calibrationPlot->xAxis->grid()->setZeroLinePen(QPen(
Qt::gray));
2864 calibrationPlot->yAxis->grid()->setZeroLinePen(QPen(
Qt::gray));
2866 calibrationPlot->xAxis->setLabel(
i18n(
"dx (pixels)"));
2867 calibrationPlot->yAxis->setLabel(
i18n(
"dy (pixels)"));
2869 calibrationPlot->xAxis->setRange(-20, 20);
2870 calibrationPlot->yAxis->setRange(-20, 20);
2875 calibrationPlot->addGraph();
2878 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"RAGuideError"), 2),
2880 calibrationPlot->graph(GuideGraph::G_RA)->setName(
"RA+");
2882 calibrationPlot->addGraph();
2887 calibrationPlot->graph(GuideGraph::G_DEC)->setName(
"RA-");
2889 calibrationPlot->addGraph();
2890 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
2894 calibrationPlot->graph(GuideGraph::G_RA_HIGHLIGHT)->setName(
"Backlash");
2896 calibrationPlot->addGraph();
2897 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(
QCPGraph::lsNone);
2899 QPen(KStarsData::Instance()->colorScheme()->colorNamed(
"DEGuideError"), 2),
2901 calibrationPlot->graph(GuideGraph::G_DEC_HIGHLIGHT)->setName(
"DEC+");
2903 calibrationPlot->addGraph();
2904 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setLineStyle(
QCPGraph::lsNone);
2908 calibrationPlot->graph(GuideGraph::G_RA_PULSE)->setName(
"DEC-");
2910 calLabel =
new QCPItemText(calibrationPlot);
2911 calLabel->setColor(QColor(255, 255, 255));
2914 calLabel->position->setCoords(0.5, 0);
2915 calLabel->setText(
"");
2916 calLabel->setFont(QFont(
font().family(), 10));
2917 calLabel->setVisible(
true);
2919 calRALabel =
new QCPItemText(calibrationPlot);
2920 calRALabel->setText(
"RA");
2923 calRALabel->setVisible(
false);
2924 calRAArrow =
new QCPItemLine(calibrationPlot);
2927 calRAArrow->setVisible(
false);
2929 calDECLabel =
new QCPItemText(calibrationPlot);
2930 calDECLabel->setText(
"DEC");
2932 calDECLabel->setPen(QPen(
Qt::white, 1));
2933 calDECLabel->setVisible(
false);
2934 calDECArrow =
new QCPItemLine(calibrationPlot);
2935 calDECArrow->setPen(QPen(
Qt::white, 1));
2937 calDECArrow->setVisible(
false);
2939 calDecArrowStartX = 0;
2940 calDecArrowStartY = 0;
2942 calibrationPlot->resize(190, 190);
2943 calibrationPlot->replot();
2946void Guide::initView()
2948 guideStateWidget =
new GuideStateWidget();
2949 guideInfoLayout->insertWidget(-1, guideStateWidget);
2951 m_GuideView.reset(
new GuideView(guideWidget, FITS_GUIDE));
2953 m_GuideView->setBaseSize(guideWidget->size());
2954 m_GuideView->createFloatingToolBar();
2955 QVBoxLayout *vlayout =
new QVBoxLayout();
2957 guideWidget->setLayout(vlayout);
2959 guideInfoLabel->setVisible(
false);
2960 guideInfoText->setVisible(
false);
2963void Guide::initConnections()
2966 captureTimeout.setSingleShot(
true);
2970 m_DebounceTimer.setInterval(500);
2971 m_DebounceTimer.setSingleShot(
true);
2976 &Ekos::Guide::updateTrackingBoxSize);
2981 if(guiderType != GUIDE_PHD2)
2986 &Ekos::Guide::updateCCDBin);
3001 m_State = GUIDE_CAPTURE;
3002 emit newStatus(m_State);
3005 if(guiderType == GUIDE_PHD2)
3007 configurePHD2Camera();
3008 if(phd2Guider->isCurrentCameraNotInEkos())
3010 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."));
3011 else if(guideSubframe->isChecked())
3014 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"));
3015 guideSubframe->setChecked(
false);
3017 phd2Guider->captureSingleFrame();
3019 else if (guiderType == GUIDE_INTERNAL)
3040 m_GuiderInstance->Connect();
3045 m_GuiderInstance->Disconnect();
3049 m_PulseTimer.setSingleShot(
true);
3054 &Ekos::Guide::buildTarget);
3059 driftGraph->toggleShowPlot(GuideGraph::G_RA, isChecked);
3063 driftGraph->toggleShowPlot(GuideGraph::G_DEC, isChecked);
3067 driftGraph->toggleShowPlot(GuideGraph::G_RA_PULSE, isChecked);
3071 driftGraph->toggleShowPlot(GuideGraph::G_DEC_PULSE, isChecked);
3075 driftGraph->toggleShowPlot(GuideGraph::G_SNR, isChecked);
3079 driftGraph->toggleShowPlot(GuideGraph::G_RMS, isChecked);
3085 connect(
this, &Ekos::Guide::newStatus, guideStateWidget, &Ekos::GuideStateWidget::updateGuideStatus);
3088void Guide::removeDevice(
const QSharedPointer<ISD::GenericDevice> &device)
3090 auto name = device->getDeviceName();
3092 device->disconnect(
this);
3095 if (m_Mount && m_Mount->getDeviceName() == name)
3097 m_Mount->disconnect(
this);
3103 if (m_Camera && m_Camera->getDeviceName() == name)
3105 m_Camera->disconnect(
this);
3111 if (m_Guider && m_Guider->getDeviceName() == name)
3113 m_Guider->disconnect(
this);
3119 if (m_AO && m_AO->getDeviceName() == name)
3121 m_AO->disconnect(
this);
3128 m_State = GUIDE_LOOPING;
3129 emit newStatus(m_State);
3133 if(guiderType == GUIDE_PHD2)
3135 configurePHD2Camera();
3136 if(phd2Guider->isCurrentCameraNotInEkos())
3138 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."));
3139 else if(guideSubframe->isChecked())
3142 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"));
3143 guideSubframe->setChecked(
false);
3146 stopB->setEnabled(
true);
3148 else if (guiderType == GUIDE_INTERNAL)
3155QVariantMap Guide::getAllSettings()
const
3157 QVariantMap settings;
3161 settings.insert(oneWidget->objectName(), oneWidget->currentText());
3165 settings.insert(oneWidget->objectName(), oneWidget->value());
3169 settings.insert(oneWidget->objectName(), oneWidget->value());
3173 settings.insert(oneWidget->objectName(), oneWidget->isChecked());
3181void Guide::setAllSettings(
const QVariantMap &settings)
3185 disconnectSettings();
3187 for (
auto &name : settings.keys())
3193 syncControl(settings, name, comboBox);
3201 syncControl(settings, name, doubleSpinBox);
3209 syncControl(settings, name, spinBox);
3217 syncControl(settings, name, checkbox);
3223 for (
auto &key : settings.keys())
3225 auto value = settings[key];
3227 Options::self()->setProperty(key.toLatin1(), value);
3229 m_Settings[key] = value;
3230 m_GlobalSettings[key] = value;
3233 emit settingsUpdated(getAllSettings());
3236 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
3237 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Guide, m_Settings);
3246bool Guide::syncControl(
const QVariantMap &settings,
const QString &key, QWidget * widget)
3248 QSpinBox *pSB =
nullptr;
3249 QDoubleSpinBox *pDSB =
nullptr;
3250 QCheckBox *pCB =
nullptr;
3251 QComboBox *pComboBox =
nullptr;
3252 QRadioButton *pRadioButton =
nullptr;
3257 const int value = settings[key].toInt(&ok);
3266 const double value = settings[key].toDouble(&ok);
3275 const bool value = settings[key].toBool();
3282 const bool value = settings[key].toBool();
3290 const QString value = settings[key].toString();
3298void Guide::setupOpticalTrainManager()
3300 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Guide::refreshOpticalTrain);
3303 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
3307 if (guiderType == GUIDE_PHD2 && m_GuiderInstance->isConnected())
3309 appendLogText(
i18n(
"Cannot change active optical train while PHD2 is connected"));
3313 ProfileSettings::Instance()->setOneSetting(ProfileSettings::GuideOpticalTrain,
3314 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
3315 refreshOpticalTrain();
3316 emit trainChanged();
3320void Guide::refreshOpticalTrain()
3322 opticalTrainCombo->blockSignals(
true);
3323 opticalTrainCombo->clear();
3324 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
3325 trainB->setEnabled(
true);
3327 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::GuideOpticalTrain);
3331 auto id = trainID.
toUInt();
3334 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
3336 qCWarning(KSTARS_EKOS_GUIDE) <<
"Optical train doesn't exist for id" << id;
3337 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
3340 auto name = OpticalTrainManager::Instance()->name(
id);
3342 opticalTrainCombo->setCurrentText(name);
3344 auto scope = OpticalTrainManager::Instance()->getScope(name);
3345 m_FocalLength = scope[
"focal_length"].
toDouble(-1);
3346 m_Aperture = scope[
"aperture"].toDouble(-1);
3347 m_FocalRatio = scope[
"focal_ratio"].toDouble(-1);
3348 m_Reducer = OpticalTrainManager::Instance()->getReducer(name);
3351 if (m_Aperture < 0 && m_FocalRatio > 0)
3352 m_Aperture = m_FocalLength / m_FocalRatio;
3354 auto mount = OpticalTrainManager::Instance()->getMount(name);
3357 auto camera = OpticalTrainManager::Instance()->getCamera(name);
3360 if (guiderType == GUIDE_INTERNAL)
3361 starCenter = QVector3D();
3363 camera->setScopeInfo(m_FocalLength * m_Reducer, m_Aperture);
3364 opticalTrainCombo->setToolTip(QString(
"%1 @ %2").arg(camera->getDeviceName(), scope[
"name"].toString()));
3368 syncTelescopeInfo();
3370 auto guider = OpticalTrainManager::Instance()->getGuider(name);
3373 auto ao = OpticalTrainManager::Instance()->getAdaptiveOptics(name);
3377 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
3378 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Guide);
3379 if (settings.isValid())
3381 auto map = settings.toJsonObject().toVariantMap();
3382 if (map != m_Settings)
3385 setAllSettings(map);
3389 m_Settings = m_GlobalSettings;
3392 opticalTrainCombo->blockSignals(
false);
3395void Guide::loadGlobalSettings()
3400 QVariantMap settings;
3404 if (oneWidget->objectName() ==
"opticalTrainCombo")
3407 key = oneWidget->objectName();
3408 value = Options::self()->property(key.
toLatin1());
3409 if (value.
isValid() && oneWidget->count() > 0)
3411 oneWidget->setCurrentText(value.
toString());
3412 settings[key] = value;
3419 key = oneWidget->objectName();
3420 value = Options::self()->property(key.
toLatin1());
3423 oneWidget->setValue(value.
toDouble());
3424 settings[key] = value;
3431 key = oneWidget->objectName();
3432 value = Options::self()->property(key.
toLatin1());
3435 oneWidget->setValue(value.
toInt());
3436 settings[key] = value;
3443 key = oneWidget->objectName();
3444 value = Options::self()->property(key.
toLatin1());
3447 oneWidget->setChecked(value.
toBool());
3448 settings[key] = value;
3454 if (!oneWidget->isCheckable())
3457 key = oneWidget->objectName();
3458 value = Options::self()->property(key.
toLatin1());
3461 oneWidget->setChecked(value.
toBool());
3462 settings[key] = value;
3466 m_GlobalSettings = m_Settings = settings;
3469void Guide::connectSettings()
3493 if (oneWidget->isCheckable())
3500void Guide::disconnectSettings()
3524 if (oneWidget->isCheckable())
3531 Options::self()->setProperty(key.
toLatin1(), value);
3532 m_Settings[key] = value;
3533 m_GlobalSettings[key] = value;
3535 m_DebounceTimer.start();
3541void Guide::settleSettings()
3543 Options::self()->save();
3544 emit settingsUpdated(getAllSettings());
3546 OpticalTrainSettings::Instance()->setOpticalTrainID(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()));
3547 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Guide, m_Settings);
3550void Guide::syncSettings()
3565 value = dsb->
value();
3571 value = sb->
value();
3588 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