9 #include "focusadaptor.h"
10 #include "focusalgorithms.h"
11 #include "polynomialfit.h"
13 #include "kstarsdata.h"
15 #include "auxiliary/kspaths.h"
16 #include "auxiliary/ksmessagebox.h"
17 #include "ekos/manager.h"
18 #include "ekos/auxiliary/darklibrary.h"
19 #include "fitsviewer/fitsdata.h"
20 #include "fitsviewer/fitstab.h"
21 #include "fitsviewer/fitsview.h"
22 #include "indi/indifilterwheel.h"
23 #include "ksnotification.h"
24 #include "kconfigdialog.h"
26 #include <basedevice.h>
28 #include <gsl/gsl_fit.h>
29 #include <gsl/gsl_vector.h>
30 #include <gsl/gsl_min.h>
32 #include <ekos_focus_debug.h>
36 #define MAXIMUM_ABS_ITERATIONS 30
37 #define MAXIMUM_RESET_ITERATIONS 3
38 #define AUTO_STAR_TIMEOUT 45000
39 #define MINIMUM_PULSE_TIMER 32
40 #define MAX_RECAPTURE_RETRIES 3
41 #define MINIMUM_POLY_SOLUTIONS 2
51 qRegisterMetaType<Ekos::FocusState>(
"Ekos::FocusState");
52 qDBusRegisterMetaType<Ekos::FocusState>();
53 new FocusAdaptor(
this);
69 filterCombo->addItems(FITSViewer::filterTypes);
73 if (Options::focusEffect() < (uint) FITSViewer::filterTypes.count() + 1)
74 filterCombo->setCurrentIndex(Options::focusEffect());
76 defaultScale =
static_cast<FITSScale
>(Options::focusEffect());
82 initSettingsConnections();
89 for (
auto &button : qButtons)
90 button->setAutoDefault(
false);
92 appendLogText(
i18n(
"Idle."));
95 m_FocusMotionTimer.
setInterval(Options::focusMotionTimeout() * 1000);
109 optionsProfileEditor =
new StellarSolverProfileEditor(
this, Ekos::FocusProfiles, optionsEditor);
116 optionsProfileEditor->loadProfile(focusOptionsProfiles->currentIndex());
117 optionsEditor->
show();
135 m_DarkProcessor =
new DarkProcessor(
this);
136 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &Ekos::Focus::appendLogText);
137 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, [
this](
bool completed)
139 darkFrameCheck->setChecked(completed);
140 m_FocusView->setProperty(
"suspended",
false);
143 m_FocusView->rescale(ZOOM_KEEP_LEVEL);
144 m_FocusView->updateFrame();
146 setCaptureComplete();
153 QString savedOptionsProfiles =
QDir(KSPaths::writableLocation(
155 if(
QFile(savedOptionsProfiles).exists())
156 m_StellarSolverProfiles = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles);
158 m_StellarSolverProfiles = getDefaultFocusOptionsProfiles();
159 focusOptionsProfiles->clear();
160 for(
auto param : m_StellarSolverProfiles)
161 focusOptionsProfiles->addItem(param.listName);
162 focusOptionsProfiles->setCurrentIndex(Options::focusOptionsProfile());
168 for (
auto param : m_StellarSolverProfiles)
169 profiles << param.listName;
177 if (focusingWidget->parent() ==
nullptr)
178 toggleFocusingWidgetFullScreen();
180 m_FocusLogFile.
close();
185 if (m_Camera && m_Camera->isConnected())
187 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
192 targetChip->resetFrame();
195 targetChip->getFrame(&
x, &
y, &w, &h);
197 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is reset. X:" <<
x <<
"Y:" <<
y <<
"W:" << w <<
"H:" << h <<
"binX:" << 1 <<
"binY:" <<
200 QVariantMap settings;
205 settings[
"binx"] = 1;
206 settings[
"biny"] = 1;
207 frameSettings[targetChip] = settings;
209 starSelected =
false;
213 m_FocusView->setTrackingBox(
QRect());
220 for (
int i = 0; i < CCDCaptureCombo->count(); i++)
221 if (device == CCDCaptureCombo->itemText(i))
223 CCDCaptureCombo->setCurrentIndex(i);
234 return m_Camera->getDeviceName();
256 case FOCUS_CHANGING_FILTER:
262 ccdNum = CCDCaptureCombo->currentIndex();
268 if (ccdNum >= 0 && ccdNum < m_Cameras.
count())
270 m_Camera = m_Cameras.
at(ccdNum);
272 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
273 if (targetChip && targetChip->isCapturing())
278 if (oneCCD == m_Camera)
280 if (captureInProgress ==
false)
281 oneCCD->disconnect(
this);
286 binningCombo->setEnabled(targetChip->canBin());
287 useSubFrame->setEnabled(targetChip->canSubframe());
288 if (targetChip->canBin())
290 int subBinX = 1, subBinY = 1;
291 binningCombo->clear();
292 targetChip->getMaxBin(&subBinX, &subBinY);
293 for (
int i = 1; i <= subBinX; i++)
294 binningCombo->addItem(
QString(
"%1x%2").arg(i).arg(i));
296 activeBin = Options::focusXBin();
297 binningCombo->setCurrentIndex(activeBin - 1);
303 liveVideoB->setEnabled(m_Camera->hasVideoStream());
304 if (m_Camera->hasVideoStream())
305 setVideoStreamEnabled(m_Camera->isStreamingEnabled());
318 if (m_Camera ==
nullptr)
321 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
322 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
325 auto isoList = targetChip->getISOList();
328 if (isoList.isEmpty())
330 ISOCombo->setEnabled(
false);
331 ISOLabel->setEnabled(
false);
335 ISOCombo->setEnabled(
true);
336 ISOLabel->setEnabled(
true);
337 ISOCombo->addItems(isoList);
338 ISOCombo->setCurrentIndex(targetChip->getISOIndex());
341 bool hasGain = m_Camera->hasGain();
342 gainLabel->setEnabled(hasGain);
343 gainIN->setEnabled(hasGain && m_Camera->getGainPermission() != IP_RO);
346 double gain = 0, min = 0, max = 0, step = 1;
347 m_Camera->getGainMinMaxStep(&min, &max, &step);
348 if (m_Camera->getGain(&gain))
350 gainIN->setMinimum(min);
351 gainIN->setMaximum(max);
353 gainIN->setSingleStep(step);
355 double defaultGain = Options::focusGain();
357 gainIN->setValue(defaultGain);
359 gainIN->setValue(gain);
368 if (m_Camera ==
nullptr)
371 auto targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
372 if (targetChip ==
nullptr || (targetChip && targetChip->isCapturing()))
375 useSubFrame->setEnabled(targetChip->canSubframe());
377 if (frameSettings.
contains(targetChip) ==
false)
380 if (targetChip->getFrame(&
x, &
y, &w, &h))
382 int binx = 1, biny = 1;
383 targetChip->getBinning(&binx, &biny);
386 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
387 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
389 QVariantMap settings;
391 settings[
"x"] = useSubFrame->isChecked() ?
x : minX;
392 settings[
"y"] = useSubFrame->isChecked() ?
y : minY;
393 settings[
"w"] = useSubFrame->isChecked() ? w : maxW;
394 settings[
"h"] = useSubFrame->isChecked() ? h : maxH;
395 settings[
"binx"] = binx;
396 settings[
"biny"] = biny;
398 frameSettings[targetChip] = settings;
406 for (
auto &oneFilter : m_FilterWheels)
408 if (oneFilter->getDeviceName() == device->getDeviceName())
412 FilterCaptureLabel->setEnabled(
true);
413 FilterDevicesCombo->setEnabled(
true);
414 FilterPosLabel->setEnabled(
true);
415 FilterPosCombo->setEnabled(
true);
416 filterManagerB->setEnabled(
true);
418 FilterDevicesCombo->addItem(device->getDeviceName());
420 m_FilterWheels.append(device);
422 int filterWheelIndex = 1;
423 if (Options::defaultFocusFilterWheel().isEmpty() ==
false)
424 filterWheelIndex = FilterDevicesCombo->findText(Options::defaultFocusFilterWheel());
426 if (filterWheelIndex < 1)
427 filterWheelIndex = 1;
430 FilterDevicesCombo->setCurrentIndex(filterWheelIndex);
432 emit settingsUpdated(getSettings());
441 for (
auto &oneSource : m_TemperatureSources)
443 if (oneSource->getDeviceName() == device->getDeviceName())
447 m_TemperatureSources.append(device);
448 temperatureSourceCombo->addItem(device->getDeviceName());
450 int temperatureSourceIndex = temperatureSourceCombo->currentIndex();
451 if (Options::defaultFocusTemperatureSource().isEmpty())
452 Options::setDefaultFocusTemperatureSource(device->getDeviceName());
454 temperatureSourceIndex = temperatureSourceCombo->findText(Options::defaultFocusTemperatureSource());
455 if (temperatureSourceIndex < 0)
456 temperatureSourceIndex = 0;
466 index = temperatureSourceCombo->currentIndex();
472 if (index < m_TemperatureSources.
count())
473 deviceName = temperatureSourceCombo->itemText(index);
477 for (
auto &oneSource : m_TemperatureSources)
479 if (oneSource->getDeviceName() == deviceName)
481 currentSource = oneSource;
492 for (
const auto &oneSource : m_TemperatureSources)
494 deviceNames << oneSource->getDeviceName();
498 if (findTemperatureElement(currentSource))
500 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement->value;
501 absoluteTemperatureLabel->setText(
QString(
"%1 °C").arg(currentTemperatureSourceElement->value, 0,
'f', 2));
502 deltaTemperatureLabel->setText(
QString(
"%1 °C").arg(0.0, 0,
'f', 2));
505 m_LastSourceAutofocusTemperature = INVALID_VALUE;
508 temperatureSourceCombo->clear();
509 temperatureSourceCombo->addItems(deviceNames);
510 temperatureSourceCombo->setCurrentIndex(index);
515 INDI::Property *temperatureProperty = device->getProperty(
"FOCUS_TEMPERATURE");
516 if (!temperatureProperty)
517 temperatureProperty = device->getProperty(
"CCD_TEMPERATURE");
518 if (temperatureProperty)
520 currentTemperatureSourceElement = temperatureProperty->getNumber()->at(0);
524 temperatureProperty = device->getProperty(
"WEATHER_PARAMETERS");
525 if (temperatureProperty)
527 for (
int i = 0; i < temperatureProperty->getNumber()->count(); i++)
529 if (strstr(temperatureProperty->getNumber()->at(i)->getName(),
"_TEMPERATURE"))
531 currentTemperatureSourceElement = temperatureProperty->getNumber()->at(i);
542 bool deviceFound =
false;
544 for (
int i = 1; i < FilterDevicesCombo->count(); i++)
545 if (device == FilterDevicesCombo->itemText(i))
552 if (deviceFound ==
false)
560 if (FilterDevicesCombo->currentIndex() >= 1)
561 return FilterDevicesCombo->currentText();
568 if (FilterDevicesCombo->currentIndex() >= 1)
570 FilterPosCombo->setCurrentText(filter);
579 return FilterPosCombo->currentText();
586 filterNum = FilterDevicesCombo->currentIndex();
594 m_FilterWheel =
nullptr;
595 currentFilterPosition = -1;
596 FilterPosCombo->clear();
600 if (filterNum <= m_FilterWheels.
count())
601 m_FilterWheel = m_FilterWheels.
at(filterNum - 1);
603 m_FilterManager->setCurrentFilterWheel(m_FilterWheel);
605 FilterPosCombo->
clear();
607 FilterPosCombo->addItems(m_FilterManager->getFilterLabels());
609 currentFilterPosition = m_FilterManager->getFilterPosition();
611 FilterPosCombo->setCurrentIndex(currentFilterPosition - 1);
613 exposureIN->setValue(m_FilterManager->getFilterExposure());
618 for (
auto &oneFocuser : m_Focusers)
620 if (oneFocuser->getDeviceName() == device->getDeviceName())
624 focuserCombo->addItem(device->getDeviceName());
626 m_Focusers.append(device);
636 for (
int i = 0; i < focuserCombo->count(); i++)
637 if (device == focuserCombo->itemText(i))
639 focuserCombo->setCurrentIndex(i);
650 return m_Focuser->getDeviceName();
657 if (FocuserNum == -1)
658 FocuserNum = focuserCombo->currentIndex();
660 if (FocuserNum == -1)
666 if (FocuserNum < m_Focusers.
count())
667 m_Focuser = m_Focusers.
at(FocuserNum);
669 m_FilterManager->setFocusReady(m_Focuser->isConnected());
672 for (
auto &oneFocuser : m_Focusers)
677 hasDeviation = m_Focuser->hasDeviation();
679 canAbsMove = m_Focuser->canAbsMove();
683 getAbsFocusPosition();
685 absTicksSpin->setEnabled(
true);
686 absTicksLabel->setEnabled(
true);
687 startGotoB->setEnabled(
true);
689 absTicksSpin->setValue(currentPosition);
693 absTicksSpin->setEnabled(
false);
694 absTicksLabel->setEnabled(
false);
695 startGotoB->setEnabled(
false);
698 canRelMove = m_Focuser->canRelMove();
703 if (canAbsMove ==
false && canRelMove ==
true)
705 currentPosition = 50000;
706 absMotionMax = 100000;
710 canTimerMove = m_Focuser->canTimerMove();
716 if (!canAbsMove && !canRelMove && canTimerMove)
718 currentPosition = 50000;
719 absMotionMax = 100000;
723 focusType = (canRelMove || canAbsMove || canTimerMove) ? FOCUS_AUTO : FOCUS_MANUAL;
724 profilePlot->setFocusAuto(focusType == FOCUS_AUTO);
726 bool hasBacklash = m_Focuser->hasBacklash();
727 focusBacklashSpin->setEnabled(hasBacklash);
728 focusBacklashSpin->disconnect(
this);
731 double min = 0, max = 0, step = 0;
732 m_Focuser->getMinMaxStep(
"FOCUS_BACKLASH_STEPS",
"FOCUS_BACKLASH_VALUE", &min, &max, &step);
733 focusBacklashSpin->setMinimum(min);
734 focusBacklashSpin->setMaximum(max);
735 focusBacklashSpin->setSingleStep(step);
736 focusBacklashSpin->setValue(m_Focuser->getBacklash());
741 if (m_Focuser->getBacklash() == value)
747 m_Focuser->setBacklash(value);
756 focusBacklashSpin->setValue(0);
767 for (
auto &oneCamera : m_Cameras)
769 if (oneCamera->getDeviceName() == device->getDeviceName())
773 for (
auto &oneCamera : m_Cameras)
774 oneCamera->disconnect(
this);
777 m_Cameras.append(device);
779 CCDCaptureCombo->addItem(device->getDeviceName());
785 void Focus::getAbsFocusPosition()
790 auto absMove = m_Focuser->getNumber(
"ABS_FOCUS_POSITION");
794 const auto &it = absMove->at(0);
795 currentPosition =
static_cast<int>(it->getValue());
796 absMotionMax = it->getMax();
797 absMotionMin = it->getMin();
799 absTicksSpin->setMinimum(it->getMin());
800 absTicksSpin->setMaximum(it->getMax());
801 absTicksSpin->setSingleStep(it->getStep());
804 double const travel = std::abs(it->getMax() - it->getMin());
805 if (travel < maxTravelIN->maximum())
806 maxTravelIN->setMaximum(travel);
810 stepIN->setMaximum(it->getMax() / 2);
818 if (currentTemperatureSourceElement && currentTemperatureSourceElement->nvp == nvp)
820 if (m_LastSourceAutofocusTemperature != INVALID_VALUE)
822 delta = currentTemperatureSourceElement->value - m_LastSourceAutofocusTemperature;
823 emit newFocusTemperatureDelta(abs(delta), currentTemperatureSourceElement->value);
827 emit newFocusTemperatureDelta(0, currentTemperatureSourceElement->value);
830 absoluteTemperatureLabel->setText(
QString(
"%1 °C").arg(currentTemperatureSourceElement->value, 0,
'f', 2));
831 deltaTemperatureLabel->setText(
QString(
"%1%2 °C").arg((delta > 0.0 ?
"+" :
"")).arg(delta, 0,
'f', 2));
833 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
835 deltaTemperatureLabel->setStyleSheet(
"color: lightcoral");
837 deltaTemperatureLabel->setStyleSheet(
"color: lightblue");
841 void Focus::setLastFocusTemperature()
843 m_LastSourceAutofocusTemperature = currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE;
846 deltaTemperatureLabel->setText(
QString(
"0 °C"));
847 deltaTemperatureLabel->setStyleSheet(
"color: lightgreen");
849 emit newFocusTemperatureDelta(0, -1e6);
853 void Focus::initializeFocuserTemperature()
855 auto temperatureProperty = currentFocuser->getBaseDevice()->getNumber(
"FOCUS_TEMPERATURE");
857 if (temperatureProperty && temperatureProperty->getState() != IPS_ALERT)
859 focuserTemperature = temperatureProperty->at(0)->getValue();
860 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Setting current focuser temperature: %1").
arg(focuserTemperature, 0,
'f', 2);
864 focuserTemperature = INVALID_VALUE;
865 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focuser temperature is not available");
869 void Focus::setLastFocusTemperature()
873 if (focuserTemperature != INVALID_VALUE)
875 lastFocusTemperature = focuserTemperature;
876 lastFocusTemperatureSource = FOCUSER_TEMPERATURE;
878 else if (observatoryTemperature != INVALID_VALUE)
880 lastFocusTemperature = observatoryTemperature;
881 lastFocusTemperatureSource = OBSERVATORY_TEMPERATURE;
885 lastFocusTemperature = INVALID_VALUE;
886 lastFocusTemperatureSource = NO_TEMPERATURE;
889 emit newFocusTemperatureDelta(0, -1e6);
893 void Focus::updateTemperature(TemperatureSource source,
double newTemperature)
895 if (source == FOCUSER_TEMPERATURE && focuserTemperature != newTemperature)
897 focuserTemperature = newTemperature;
898 emitTemperatureEvents(source, newTemperature);
900 else if (source == OBSERVATORY_TEMPERATURE && observatoryTemperature != newTemperature)
902 observatoryTemperature = newTemperature;
903 emitTemperatureEvents(source, newTemperature);
907 void Focus::emitTemperatureEvents(TemperatureSource source,
double newTemperature)
909 if (source != lastFocusTemperatureSource)
914 if (lastFocusTemperature != INVALID_VALUE && newTemperature != INVALID_VALUE)
916 emit newFocusTemperatureDelta(abs(newTemperature - lastFocusTemperature), newTemperature);
920 emit newFocusTemperatureDelta(0, newTemperature);
927 if (m_Focuser ==
nullptr)
929 appendLogText(
i18n(
"No Focuser connected."));
930 completeFocusProcedure(Ekos::FOCUS_ABORTED);
934 if (m_Camera ==
nullptr)
936 appendLogText(
i18n(
"No CCD connected."));
937 completeFocusProcedure(Ekos::FOCUS_ABORTED);
941 if (!canAbsMove && !canRelMove && stepIN->value() <= MINIMUM_PULSE_TIMER)
943 appendLogText(
i18n(
"Starting pulse step is too low. Increase the step size to %1 or higher...",
944 MINIMUM_PULSE_TIMER * 5));
945 completeFocusProcedure(Ekos::FOCUS_ABORTED);
951 appendLogText(
i18n(
"Autofocus is already running, discarding start request."));
954 else inAutoFocus =
true;
956 m_LastFocusDirection = FOCUS_NONE;
958 waitStarSelectTimer.
stop();
965 m_RestartState = RESTART_NONE;
973 getAbsFocusPosition();
974 pulseDuration = stepIN->value();
980 pulseDuration = stepIN->value();
982 absMotionMax = 100000;
987 pulseDuration = stepIN->value();
989 absMotionMax = 100000;
993 focuserAdditionalMovement = 0;
1006 profilePlot->clear();
1008 qCInfo(KSTARS_EKOS_FOCUS) <<
"Starting focus with Detection: " << focusDetectionCombo->currentText()
1009 <<
" Algorithm: " << focusAlgorithmCombo->currentText()
1010 <<
" Box size: " << focusBoxSize->value()
1011 <<
" Subframe: " << ( useSubFrame->isChecked() ?
"yes" :
"no" )
1012 <<
" Autostar: " << ( useAutoStar->isChecked() ?
"yes" :
"no" )
1013 <<
" Full frame: " << ( useFullField->isChecked() ?
"yes" :
"no " )
1014 <<
" [" << fullFieldInnerRing->value() <<
"%," << fullFieldOuterRing->value() <<
"%]"
1015 <<
" Step Size: " << stepIN->value() <<
" Threshold: " << thresholdSpin->value()
1016 <<
" Gaussian Sigma: " << gaussianSigmaSpin->value()
1017 <<
" Gaussian Kernel size: " << gaussianKernelSizeSpin->value()
1018 <<
" Multi row average: " << multiRowAverageSpin->value()
1019 <<
" Tolerance: " << toleranceIN->value()
1020 <<
" Frames: " << 1 <<
" Maximum Travel: " << maxTravelIN->value()
1021 <<
" Curve Fit: " << curveFitCombo->currentText()
1022 <<
" Use Weights: " << ( useWeights->isChecked() ?
"yes" :
"no" )
1023 <<
" R2 Limit: " << R2Limit->value();
1025 if (currentTemperatureSourceElement)
1026 emit autofocusStarting(currentTemperatureSourceElement->value, filter());
1028 if (useAutoStar->isChecked())
1029 appendLogText(
i18n(
"Autofocus in progress..."));
1030 else if (!inAutoFocus)
1031 appendLogText(
i18n(
"Please wait until image capture is complete..."));
1036 const bool isOAG = m_Camera->getTelescopeType() == Options::guideScopeType();
1037 if (isOAG && m_GuidingSuspended ==
false && suspendGuideCheck->isChecked())
1039 m_GuidingSuspended =
true;
1040 emit suspendGuiding();
1044 state = Ekos::FOCUS_PROGRESS;
1045 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
1046 emit newStatus(state);
1051 KSNotification::event(
QLatin1String(
"FocusStarted"),
i18n(
"Autofocus operation started"));
1054 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
1056 const int position =
static_cast<int>(currentPosition);
1057 FocusAlgorithmInterface::FocusParams params(
1058 maxTravelIN->value(), stepIN->value(), position, absMotionMin, absMotionMax,
1059 MAXIMUM_ABS_ITERATIONS, toleranceIN->value() / 100.0, filter(),
1060 currentTemperatureSourceElement ? currentTemperatureSourceElement->value : INVALID_VALUE,
1061 Options::initialFocusOutSteps(),
1062 m_FocusAlgorithm, focusBacklashSpin->value(), curveFit, useWeights->isChecked());
1064 initialFocuserAbsPosition = position;
1065 linearFocuser.reset(MakeLinearFocuser(params));
1066 curveFitting.reset(
new CurveFitting());
1067 linearRequestedPosition = linearFocuser->initialPosition();
1068 const int newPosition = adjustLinearPosition(position, linearRequestedPosition, focusBacklashSpin->value());
1069 if (newPosition != position)
1071 if (!changeFocus(newPosition - position))
1073 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1082 int Focus::adjustLinearPosition(
int position,
int newPosition,
int backlash)
1084 if (newPosition > position)
1086 constexpr
int extraMotionSteps = 5;
1090 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && backlash > 0)
1092 adjustment = backlash;
1093 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear: extending outward movement by backlash %1").
arg(adjustment);
1097 adjustment = extraMotionSteps * stepIN->value();
1098 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear: extending outward movement by %1").
arg(adjustment);
1101 if (newPosition + adjustment > absMotionMax)
1102 adjustment =
static_cast<int>(absMotionMax) - newPosition;
1104 focuserAdditionalMovement = adjustment;
1106 return newPosition + adjustment;
1115 resetFocusIteration = MAXIMUM_RESET_ITERATIONS + 1;
1117 if (captureInProgress && inAutoFocus ==
false && inFocusLoop ==
false)
1119 captureB->setEnabled(
true);
1120 stopFocusB->setEnabled(
false);
1122 appendLogText(
i18n(
"Capture aborted."));
1127 stopFocusB->setEnabled(
false);
1128 appendLogText(
i18n(
"Detection in progress, please wait."));
1136 completeFocusProcedure(
abort ? Ekos::FOCUS_ABORTED : Ekos::FOCUS_FAILED);
1143 if (state == FOCUS_IDLE || state == FOCUS_COMPLETE || state == FOCUS_FAILED || state == FOCUS_ABORTED)
1147 int old = resetFocusIteration;
1153 resetFocusIteration = old;
1159 if (state <= FOCUS_ABORTED)
1163 appendLogText(
i18n(
"Autofocus aborted."));
1166 void Focus::stop(Ekos::FocusState completionState)
1168 qCDebug(KSTARS_EKOS_FOCUS) <<
"Stopping Focus";
1170 captureTimeout.
stop();
1171 m_FocusMotionTimer.
stop();
1172 m_FocusMotionTimerCounter = 0;
1174 inAutoFocus =
false;
1175 focuserAdditionalMovement = 0;
1176 inFocusLoop =
false;
1177 captureInProgress =
false;
1178 isVShapeSolution =
false;
1179 captureFailureCounter = 0;
1180 minimumRequiredHFR = -1;
1188 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1190 if (rememberUploadMode != m_Camera->getUploadMode())
1191 m_Camera->setUploadMode(rememberUploadMode);
1194 if (m_RememberCameraFastExposure)
1196 m_RememberCameraFastExposure =
false;
1197 m_Camera->setFastExposureEnabled(
true);
1200 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1201 targetChip->abortExposure();
1210 if (m_GuidingSuspended)
1212 emit resumeGuiding();
1213 m_GuidingSuspended =
false;
1216 if (completionState == Ekos::FOCUS_ABORTED || completionState == Ekos::FOCUS_FAILED)
1218 state = completionState;
1219 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
1220 emit newStatus(state);
1228 if (settleTime > 0 && captureInProgress ==
false)
1230 captureTimer.
start(
static_cast<int>(settleTime * 1000));
1234 if (captureInProgress)
1236 qCWarning(KSTARS_EKOS_FOCUS) <<
"Capture called while already in progress. Capture is ignored.";
1240 if (m_Camera ==
nullptr)
1242 appendLogText(
i18n(
"Error: No Camera detected."));
1247 if (m_Camera->isConnected() ==
false)
1249 appendLogText(
i18n(
"Error: Lost connection to Camera."));
1255 captureTimeout.
stop();
1257 waitStarSelectTimer.
stop();
1259 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1261 if (m_Camera->isBLOBEnabled() ==
false)
1263 m_Camera->setBLOBEnabled(
true);
1266 if (FilterPosCombo->currentIndex() != -1)
1268 if (m_FilterWheel ==
nullptr)
1270 appendLogText(
i18n(
"Error: No Filter Wheel detected."));
1274 if (m_FilterWheel->isConnected() ==
false)
1276 appendLogText(
i18n(
"Error: Lost connection to Filter Wheel."));
1281 int targetPosition = FilterPosCombo->currentIndex() + 1;
1282 QString lockedFilter = m_FilterManager->getFilterLock(FilterPosCombo->currentText());
1287 if (lockedFilter !=
"--" && lockedFilter != FilterPosCombo->currentText())
1289 int lockedFilterIndex = FilterPosCombo->findText(lockedFilter);
1290 if (lockedFilterIndex >= 0)
1293 fallbackFilterPending =
true;
1294 fallbackFilterPosition = targetPosition;
1295 targetPosition = lockedFilterIndex + 1;
1299 filterPositionPending = (targetPosition != currentFilterPosition);
1301 if (filterPositionPending)
1304 m_FilterManager->setFilterPosition(targetPosition,
1305 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY | FilterManager::OFFSET_POLICY));
1310 m_FocusView->setProperty(
"suspended", darkFrameCheck->isChecked());
1311 prepareCapture(targetChip);
1314 connect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1316 if (frameSettings.
contains(targetChip))
1318 QVariantMap settings = frameSettings[targetChip];
1319 targetChip->setFrame(settings[
"x"].toInt(), settings[
"y"].toInt(), settings[
"w"].toInt(),
1320 settings[
"h"].toInt());
1321 settings[
"binx"] = activeBin;
1322 settings[
"biny"] = activeBin;
1323 frameSettings[targetChip] = settings;
1326 captureInProgress =
true;
1327 if (state != FOCUS_PROGRESS)
1329 state = FOCUS_PROGRESS;
1330 emit newStatus(state);
1333 m_FocusView->setBaseSize(focusingWidget->size());
1335 if (targetChip->capture(exposureIN->value()))
1339 captureTimeout.
start(Options::focusCaptureTimeout() * 1000);
1341 if (inFocusLoop ==
false)
1342 appendLogText(
i18n(
"Capturing image..."));
1346 else if (inAutoFocus)
1348 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1354 if (m_Camera->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1356 rememberUploadMode = ISD::Camera::UPLOAD_LOCAL;
1357 m_Camera->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1361 if (m_Camera->isFastExposureEnabled())
1363 m_RememberCameraFastExposure =
true;
1364 m_Camera->setFastExposureEnabled(
false);
1367 m_Camera->setEncodingFormat(
"FITS");
1368 targetChip->setBatchMode(
false);
1369 targetChip->setBinning(activeBin, activeBin);
1370 targetChip->setCaptureMode(FITS_FOCUS);
1371 targetChip->setFrameType(FRAME_LIGHT);
1374 if (darkFrameCheck->isChecked())
1375 targetChip->setCaptureFilter(FITS_NONE);
1377 targetChip->setCaptureFilter(defaultScale);
1379 if (ISOCombo->isEnabled() && ISOCombo->currentIndex() != -1 &&
1380 targetChip->getISOIndex() != ISOCombo->currentIndex())
1381 targetChip->setISOIndex(ISOCombo->currentIndex());
1383 if (gainIN->isEnabled())
1384 m_Camera->setGain(gainIN->value());
1390 ms = stepIN->value();
1391 return changeFocus(-ms);
1397 ms = stepIN->value();
1398 return changeFocus(ms);
1402 bool Focus::changeFocus(
int amount)
1404 const int absAmount = abs(amount);
1408 if (inAutoFocus && absAmount <= 1)
1410 capture(FocusSettleTime->value());
1414 if (m_Focuser ==
nullptr)
1416 appendLogText(
i18n(
"Error: No Focuser detected."));
1421 if (m_Focuser->isConnected() ==
false)
1423 appendLogText(
i18n(
"Error: Lost connection to Focuser."));
1428 const bool focusingOut = amount > 0;
1429 const QString dirStr = focusingOut ?
i18n(
"outward") :
i18n(
"inward");
1430 m_LastFocusDirection = focusingOut ? FOCUS_OUT : FOCUS_IN;
1433 m_Focuser->focusOut();
1435 m_Focuser->focusIn();
1438 m_FocusMotionTimerCounter = 0;
1439 m_FocusMotionTimer.
start();
1443 m_LastFocusSteps = currentPosition + amount;
1444 m_Focuser->moveAbs(currentPosition + amount);
1445 appendLogText(
i18n(
"Focusing %2 by %1 steps...", absAmount, dirStr));
1447 else if (canRelMove)
1449 m_LastFocusSteps = absAmount;
1450 m_Focuser->moveRel(absAmount);
1451 appendLogText(
i18np(
"Focusing %2 by %1 step...",
"Focusing %2 by %1 steps...", absAmount, dirStr));
1455 m_LastFocusSteps = absAmount;
1456 m_Focuser->moveByTimer(absAmount);
1457 appendLogText(
i18n(
"Focusing %2 by %1 ms...", absAmount, dirStr));
1466 void Focus::handleFocusMotionTimeout()
1468 if (++m_FocusMotionTimerCounter > 3)
1470 appendLogText(
i18n(
"Focuser is not responding to commands. Aborting..."));
1471 completeFocusProcedure(Ekos::FOCUS_ABORTED);
1474 const QString dirStr = m_LastFocusDirection == FOCUS_OUT ?
i18n(
"outward") :
i18n(
"inward");
1477 m_Focuser->moveAbs(m_LastFocusSteps);
1478 appendLogText(
i18n(
"Focus motion timed out. Focusing to %1 steps...", m_LastFocusSteps));
1480 else if (canRelMove)
1482 m_Focuser->moveRel(m_LastFocusSteps);
1483 appendLogText(
i18n(
"Focus motion timed out. Focusing %2 by %1 steps...", m_LastFocusSteps,
1488 m_Focuser->moveByTimer(m_LastFocusSteps);
1489 appendLogText(
i18n(
"Focus motion timed out. Focusing %2 by %1 ms...",
1490 m_LastFocusSteps, dirStr));
1497 if (data->property(
"chip").toInt() == ISD::CameraChip::GUIDE_CCD)
1502 m_FocusView->loadData(data);
1506 m_ImageData.
reset();
1508 captureTimeout.
stop();
1509 captureTimeoutCounter = 0;
1511 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1513 disconnect(m_Camera, &ISD::Camera::error,
this, &Ekos::Focus::processCaptureError);
1515 if (m_ImageData && darkFrameCheck->isChecked())
1517 QVariantMap settings = frameSettings[targetChip];
1518 uint16_t offsetX = settings[
"x"].toInt() / settings[
"binx"].toInt();
1519 uint16_t offsetY = settings[
"y"].toInt() / settings[
"biny"].toInt();
1522 m_DarkProcessor->denoise(targetChip, m_ImageData, exposureIN->value(), offsetX, offsetY);
1526 setCaptureComplete();
1530 void Focus::calculateHFR()
1532 appendLogText(
i18n(
"Detection complete."));
1535 double hfr = FocusAlgorithmInterface::IGNORED_HFR;
1537 if (m_StarFinderWatcher.
result() ==
false)
1539 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to extract any stars.";
1543 if (Options::focusUseFullField())
1545 m_FocusView->setStarFilterRange(
static_cast <float> (fullFieldInnerRing->value() / 100.0),
1546 static_cast <float> (fullFieldOuterRing->value() / 100.0));
1547 m_FocusView->filterStars();
1550 hfr = m_ImageData->getHFR(HFR_AVERAGE);
1554 m_FocusView->setTrackingBoxEnabled(
true);
1559 if (starCenter.
isNull() ==
false)
1560 hfr = m_ImageData->getHFR(starCenter.
x(), starCenter.
y());
1564 hfr = m_ImageData->getHFR(focusDetection == ALGORITHM_SEP ? HFR_HIGH : HFR_MAX);
1568 hfrInProgress =
false;
1573 void Focus::analyzeSources()
1575 appendLogText(
i18n(
"Detecting sources..."));
1576 hfrInProgress =
true;
1578 QVariantMap extractionSettings;
1579 extractionSettings[
"optionsProfileIndex"] = Options::focusOptionsProfile();
1580 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::FocusProfiles);
1581 m_ImageData->setSourceExtractorSettings(extractionSettings);
1585 if (Options::focusUseFullField())
1587 m_FocusView->setTrackingBoxEnabled(
false);
1589 if (focusDetection != ALGORITHM_CENTROID && focusDetection != ALGORITHM_SEP)
1590 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
1592 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(focusDetection));
1596 QRect searchBox = m_FocusView->isTrackingBoxEnabled() ? m_FocusView->getTrackingBox() :
QRect();
1600 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(focusDetection, searchBox));
1605 m_FocusView->setTrackingBoxEnabled(
false);
1609 if (focusDetection != ALGORITHM_CENTROID && focusDetection != ALGORITHM_SEP)
1610 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(ALGORITHM_CENTROID));
1613 m_StarFinderWatcher.
setFuture(m_ImageData->findStars(focusDetection, searchBox));
1618 bool Focus::appendHFR(
double newHFR)
1621 HFRFrames.
append(newHFR);
1625 samples.erase(std::remove_if(samples.begin(), samples.end(), [](
const double HFR)
1627 return HFR == FocusAlgorithmInterface::IGNORED_HFR;
1631 if (samples.count() > 3)
1634 std::sort(samples.begin(), samples.end());
1636 ((samples.size() % 2) ?
1637 samples[samples.size() / 2] :
1638 (
static_cast<double>(samples[samples.size() / 2 - 1]) + samples[samples.size() / 2]) * .5);
1641 const auto mean = std::accumulate(samples.begin(), samples.end(), .0) / samples.size();
1644 double variance = 0;
1645 foreach (
auto val, samples)
1646 variance += (val - mean) * (val - mean);
1649 const double stddev = sqrt(variance / samples.size());
1652 const double sigmaHigh = median + stddev * 2;
1653 const double sigmaLow = median - stddev * 2;
1660 auto val = i.next();
1661 if (val > sigmaHigh || val < sigmaLow)
1667 currentHFR = samples.isEmpty() ? -1 : std::accumulate(samples.begin(), samples.end(), .0) / samples.size();
1670 return HFRFrames.
count() < focusFramesSpin->value();
1673 void Focus::settle(
const FocusState completionState,
const bool autoFocusUsed)
1675 state = completionState;
1676 if (completionState == Ekos::FOCUS_COMPLETE)
1681 const int size = hfr_position.
size();
1682 QString analysis_results =
"";
1684 for (
int i = 0; i <
size; ++i)
1687 .arg(i == 0 ?
"" :
"|" )
1692 KSNotification::event(
QLatin1String(
"FocusSuccessful"),
i18n(
"Autofocus operation completed successfully"));
1693 emit autofocusComplete(filter(), analysis_results);
1700 KSNotification::event(
QLatin1String(
"FocusFailed"),
i18n(
"Autofocus operation failed"),
1701 KSNotification::EVENT_ALERT);
1702 emit autofocusAborted(filter(),
"");
1706 qCDebug(KSTARS_EKOS_FOCUS) <<
"Settled. State:" << Ekos::getFocusStatusString(state);
1709 if (fallbackFilterPending)
1711 m_FilterManager->setFilterPosition(fallbackFilterPosition,
1712 static_cast<FilterManager::FilterPolicy
>(FilterManager::CHANGE_POLICY | FilterManager::OFFSET_POLICY));
1715 emit newStatus(state);
1720 void Focus::completeFocusProcedure(FocusState completionState,
bool plot)
1724 if (completionState == Ekos::FOCUS_COMPLETE)
1727 emit
redrawHFRPlot(polynomialFit.get(), currentPosition, currentHFR);
1728 appendLogText(
i18np(
"Focus procedure completed after %1 iteration.",
1729 "Focus procedure completed after %1 iterations.", hfr_position.
count()));
1731 setLastFocusTemperature();
1735 qCInfo(KSTARS_EKOS_FOCUS) <<
"Autofocus values: position," << currentPosition <<
", temperature,"
1736 << m_LastSourceAutofocusTemperature <<
", filter," << filter()
1737 <<
", HFR," << currentHFR <<
", altitude," << mountAlt;
1739 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL)
1742 hfr_position.
append(currentPosition);
1743 hfr_value.
append(currentHFR);
1746 appendFocusLogText(
QString(
"%1, %2, %3, %4, %5\n")
1754 absTicksSpin->setValue(currentPosition);
1757 else if (canAbsMove && initialFocuserAbsPosition >= 0 && resetFocusIteration <= MAXIMUM_RESET_ITERATIONS)
1760 bool const retry_focusing = m_RestartState == RESTART_NONE && ++resetFocusIteration < MAXIMUM_RESET_ITERATIONS;
1765 m_RestartState = RESTART_NOW;
1774 emit autofocusAborted(filter(),
"");
1786 resetFocusIteration = 0;
1787 m_RestartState = RESTART_ABORT;
1793 resetFocusIteration = 0;
1796 const bool autoFocusUsed = inAutoFocus;
1799 stop(completionState);
1802 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && plot)
1803 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
1806 int const settleTime = m_GuidingSuspended ? GuideSettleTime->value() : 0;
1809 appendLogText(
i18n(
"Settling for %1s...", settleTime));
1811 QTimer::singleShot(settleTime * 1000,
this, [ &, settleTime, completionState, autoFocusUsed]()
1813 settle(completionState, autoFocusUsed);
1816 appendLogText(
i18n(
"Settling complete."));
1823 if (m_Focuser && m_Focuser->isConnected() && initialFocuserAbsPosition >= 0)
1826 if (currentPosition == initialFocuserAbsPosition)
1829 appendLogText(
i18n(
"Autofocus failed, moving back to initial focus position %1.", initialFocuserAbsPosition));
1830 m_Focuser->moveAbs(initialFocuserAbsPosition);
1835 void Focus::setCurrentHFR(
double value)
1840 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus newFITS #" << HFRFrames.
count() + 1 <<
": Current HFR " << currentHFR <<
" Num stars "
1841 << (starSelected ? 1 : m_ImageData->getDetectedStars());
1844 if (appendHFR(currentHFR))
1849 else HFRFrames.
clear();
1853 emit newHFR(currentHFR, currentPosition);
1855 emit newHFR(currentHFR, -1);
1859 HFROut->setText(HFRText);
1860 starsOut->setText(
QString(
"%1").arg(m_ImageData->getDetectedStars()));
1861 iterOut->setText(
QString(
"%1").arg(absIterations + 1));
1864 if (lastHFR == FocusAlgorithmInterface::IGNORED_HFR)
1865 appendLogText(
i18n(
"FITS received. No stars detected."));
1871 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && isVShapeSolution)
1873 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
1877 Edge selectedHFRStarHFR = m_ImageData->getSelectedHFRStar();
1884 if (starCenter.
isNull() ==
false && (inAutoFocus || minimumRequiredHFR >= 0))
1887 starSelected =
true;
1888 starCenter.
setX(qMax(0,
static_cast<int>(selectedHFRStarHFR.x)));
1889 starCenter.
setY(qMax(0,
static_cast<int>(selectedHFRStarHFR.y)));
1891 syncTrackingBoxPosition();
1895 oneStar.
setZ(currentHFR);
1896 starsHFR.
append(oneStar);
1901 QVector3D oneStar(starCenter.
x(), starCenter.
y(), currentHFR);
1902 starsHFR.
append(oneStar);
1905 if (currentHFR > maxHFR)
1906 maxHFR = currentHFR;
1914 if (inFocusLoop || (inAutoFocus && ! isPositionBased()))
1916 int pos = hfr_position.
empty() ? 1 : hfr_position.
last() + 1;
1917 addPlotPosition(
pos, currentHFR);
1923 QVector3D oneStar(starCenter.
x(), starCenter.
y(), FocusAlgorithmInterface::IGNORED_HFR);
1924 starsHFR.
append(oneStar);
1929 m_FocusView->updateFrame();
1934 void Focus::setCaptureComplete()
1936 DarkLibrary::Instance()->disconnect(
this);
1939 syncTrackingBoxPosition();
1942 if (inFocusLoop ==
false)
1943 appendLogText(
i18n(
"Image received."));
1945 if (captureInProgress && inFocusLoop ==
false && inAutoFocus ==
false)
1946 m_Camera->setUploadMode(rememberUploadMode);
1948 if (m_RememberCameraFastExposure && inFocusLoop ==
false && inAutoFocus ==
false)
1950 m_RememberCameraFastExposure =
false;
1951 m_Camera->setFastExposureEnabled(
true);
1954 captureInProgress =
false;
1958 emit newImage(m_FocusView);
1960 emit newStarPixmap(m_FocusView->getTrackingBoxPixmap(10));
1966 if (inFocusLoop ==
false || (inFocusLoop && (m_FocusView->isTrackingBoxEnabled() || Options::focusUseFullField())))
1972 void Focus::setHFRComplete()
1982 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
1985 int subBinX = 1, subBinY = 1;
1986 if (!targetChip->getBinning(&subBinX, &subBinY))
1987 qCDebug(KSTARS_EKOS_FOCUS) <<
"Warning: target chip is reporting no binning property, using 1x1.";
1994 if (Options::focusUseFullField() ==
false && starCenter.
isNull())
1996 int x = 0,
y = 0, w = 0, h = 0;
1999 if (frameSettings.
contains(targetChip))
2001 QVariantMap settings = frameSettings[targetChip];
2002 x = settings[
"x"].toInt();
2003 y = settings[
"y"].toInt();
2004 w = settings[
"w"].toInt();
2005 h = settings[
"h"].toInt();
2009 targetChip->getFrame(&
x, &
y, &w, &h);
2012 if (useAutoStar->isChecked())
2015 const Edge selectedHFRStar = m_ImageData->getSelectedHFRStar();
2017 if (selectedHFRStar.x == -1)
2019 appendLogText(
i18n(
"Failed to automatically select a star. Please select a star manually."));
2022 m_FocusView->setTrackingBox(
QRect(w - focusBoxSize->value() / (subBinX * 2),
2023 h - focusBoxSize->value() / (subBinY * 2),
2024 focusBoxSize->value() / subBinX, focusBoxSize->value() / subBinY));
2025 m_FocusView->setTrackingBoxEnabled(
true);
2028 state = Ekos::FOCUS_WAITING;
2029 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2030 emit newStatus(state);
2033 waitStarSelectTimer.
start();
2039 starCenter.
setX(selectedHFRStar.x);
2040 starCenter.
setY(selectedHFRStar.y);
2041 starCenter.
setZ(subBinX);
2042 starSelected =
true;
2043 syncTrackingBoxPosition();
2045 defaultScale =
static_cast<FITSScale
>(filterCombo->currentIndex());
2048 if (subFramed ==
false && useSubFrame->isEnabled() && useSubFrame->isChecked())
2050 int offset = (
static_cast<double>(focusBoxSize->value()) / subBinX) * 1.5;
2051 int subX = (selectedHFRStar.x - offset) * subBinX;
2052 int subY = (selectedHFRStar.y - offset) * subBinY;
2053 int subW = offset * 2 * subBinX;
2054 int subH = offset * 2 * subBinY;
2056 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
2057 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
2064 if ((subW + subX) > maxW)
2066 if ((subH + subY) > maxH)
2071 QVariantMap settings = frameSettings[targetChip];
2072 settings[
"x"] = subX;
2073 settings[
"y"] = subY;
2074 settings[
"w"] = subW;
2075 settings[
"h"] = subH;
2076 settings[
"binx"] = subBinX;
2077 settings[
"biny"] = subBinY;
2079 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" << subX <<
"Y:" << subY <<
"W:" << subW <<
"H:" << subH <<
"binX:" <<
2080 subBinX <<
"binY:" << subBinY;
2084 frameSettings[targetChip] = settings;
2087 starCenter.
setX(subW / (2 * subBinX));
2088 starCenter.
setY(subH / (2 * subBinY));
2089 starCenter.
setZ(subBinX);
2093 m_FocusView->setFirstLoad(
true);
2102 starCenter.
setX(selectedHFRStar.x);
2103 starCenter.
setY(selectedHFRStar.y);
2104 starCenter.
setZ(subBinX);
2117 appendLogText(
i18n(
"Capture complete. Select a star to focus."));
2119 starSelected =
false;
2123 int subBinX = 1, subBinY = 1;
2124 targetChip->getBinning(&subBinX, &subBinY);
2126 m_FocusView->setTrackingBox(
QRect((w - focusBoxSize->value()) / (subBinX * 2),
2127 (h - focusBoxSize->value()) / (2 * subBinY),
2128 focusBoxSize->value() / subBinX, focusBoxSize->value() / subBinY));
2129 m_FocusView->setTrackingBoxEnabled(
true);
2132 state = Ekos::FOCUS_WAITING;
2133 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2134 emit newStatus(state);
2137 waitStarSelectTimer.
start();
2143 if (minimumRequiredHFR >= 0)
2146 if (currentHFR == -1)
2148 if (noStarCount++ < MAX_RECAPTURE_RETRIES)
2150 appendLogText(
i18n(
"No stars detected while testing HFR, capturing again..."));
2152 if (noStarCount == MAX_RECAPTURE_RETRIES)
2161 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2166 else if (currentHFR > minimumRequiredHFR)
2168 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is above required minimum HFR:" << minimumRequiredHFR <<
2169 ". Starting AutoFocus...";
2170 minimumRequiredHFR = -1;
2176 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR:" << currentHFR <<
"is below required minimum HFR:" << minimumRequiredHFR <<
2177 ". Autofocus successful.";
2178 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
2186 if (Options::focusLogging() && Options::saveFocusImages())
2196 QString filename = path + QStringLiteral(
"/") +
name;
2197 m_ImageData->saveImage(filename);
2201 if (inAutoFocus ==
false)
2205 if (state != Ekos::FOCUS_IDLE)
2207 state = Ekos::FOCUS_IDLE;
2208 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2209 emit newStatus(state);
2217 if (state != Ekos::FOCUS_PROGRESS)
2219 state = Ekos::FOCUS_PROGRESS;
2220 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
2221 emit newStatus(state);
2226 if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
2228 else if (canAbsMove || canRelMove)
2239 polynomialFit.reset();
2240 hfr_position.
clear();
2242 isVShapeSolution =
false;
2243 emit
initHFRPlot(inFocusLoop ==
false && isPositionBased());
2246 bool Focus::autoFocusChecks()
2248 if (++absIterations > MAXIMUM_ABS_ITERATIONS)
2250 appendLogText(
i18n(
"Autofocus failed to reach proper focus. Try increasing tolerance value."));
2251 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2256 if (currentHFR == FocusAlgorithmInterface::IGNORED_HFR)
2258 if (noStarCount < MAX_RECAPTURE_RETRIES)
2261 appendLogText(
i18n(
"No stars detected, capturing again..."));
2265 else if (m_FocusAlgorithm == FOCUS_LINEAR)
2270 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
2275 appendLogText(
i18n(
"Failed to detect any stars. Reset frame and try again."));
2276 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2286 void Focus::plotLinearFocus()
2296 linearFocuser->getMeasurements(&positions, &HFRs, &sigmas);
2297 const FocusAlgorithmInterface::FocusParams ¶ms = linearFocuser->getParams();
2303 bool incrementalChange =
false;
2304 if (positions.
size() > 1 && positions.
size() == lastPositions.
size() + 1)
2307 for (
int i = 0; i < positions.
size() - 1; ++i)
2308 if (positions[i] != lastPositions[i] || HFRs[i] != lastHFRs[i])
2313 incrementalChange =
ok;
2315 lastPositions = positions;
2318 if (params.useWeights)
2320 if (incrementalChange)
2326 for (
int i = 0; i < positions.
size(); ++i)
2332 if (incrementalChange)
2337 for (
int i = 0; i < positions.
size(); ++i)
2338 emit
newHFRPlotPosition(
static_cast<double>(positions[i]), HFRs[i], params.initialStepSize, plt);
2343 if (HFRs.
size() > 3)
2348 double minPosition, minValue;
2349 double searchMin = std::max(params.minPositionAllowed, params.startPosition - params.maxTravel);
2350 double searchMax = std::min(params.maxPositionAllowed, params.startPosition + params.maxTravel);
2352 linearFocuser->getPass1Measurements(&pass1Positions, &pass1HFRs, &pass1Sigmas);
2353 if (m_FocusAlgorithm == FOCUS_LINEAR)
2357 polynomialFit.reset(
new PolynomialFit(2, pass1Positions, pass1HFRs));
2359 if (polynomialFit->findMinimum(params.startPosition, searchMin, searchMax, &minPosition, &minValue))
2365 if (linearFocuser->isDone())
2380 curveFitting->fitCurve(pass1Positions, pass1HFRs, pass1Sigmas, params.curveFit, params.useWeights);
2382 if (curveFitting->findMin(params.startPosition, searchMin, searchMax, &minPosition, &minValue, params.curveFit))
2384 R2 = curveFitting->calculateR2(
static_cast<CurveFitting::CurveFit
>(params.curveFit));
2385 emit
drawCurve(curveFitting.get(),
true,
true, plt);
2393 emit
drawCurve(curveFitting.get(),
false,
false, plt);
2400 HFROut->setText(
QString(
"%1").arg(linearFocuser->latestHFR(), 0,
'f', 2));
2402 emit
setTitle(linearFocuser->getTextStatus(R2));
2404 if (!plt) HFRPlot->replot();
2409 void Focus::plotLinearFinalUpdates()
2411 emit
updateTitle(linearFocuser->getTextStatus(R2),
true);
2414 void Focus::autoFocusLinear()
2416 if (!autoFocusChecks())
2419 if (!canAbsMove && !canRelMove && canTimerMove)
2422 if (linearRequestedPosition != currentPosition)
2425 qCDebug(KSTARS_EKOS_FOCUS) <<
"Linear: warning, changing position " << currentPosition <<
" to "
2426 << linearRequestedPosition;
2428 currentPosition = linearRequestedPosition;
2432 addPlotPosition(currentPosition, currentHFR,
false);
2435 bool useFocusStarsHFR = Options::focusUseFullField() && focusFramesSpin->value() == 1;
2436 auto focusStars = useFocusStarsHFR || (m_FocusAlgorithm == FOCUS_LINEAR1PASS) ? &(m_ImageData->getStarCenters()) :
nullptr;
2439 linearRequestedPosition = linearFocuser->newMeasurement(currentPosition, currentHFR, focusStars);
2440 if (m_FocusAlgorithm == FOCUS_LINEAR1PASS && linearFocuser->isDone())
2442 plotLinearFinalUpdates();
2447 nextPosition = adjustLinearPosition(currentPosition, linearRequestedPosition, focusBacklashSpin->value());
2449 if (linearFocuser->isDone())
2451 if (linearFocuser->solution() != -1)
2455 if (curveFit == CurveFitting::FOCUS_QUADRATIC)
2457 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
2458 else if (R2 >= R2Limit->value())
2460 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear Curve Fit check passed R2=%1 R2Limit=%2").
arg(R2).
arg(R2Limit->value());
2461 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
2464 else if (R2Retries == 0)
2467 appendLogText(
i18n(
"Curve Fit check failed R2=%1 R2Limit=%2 retrying...", R2, R2Limit->value()));
2468 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
2474 appendLogText(
i18n(
"Curve Fit check failed again R2=%1 R2Limit=%2 but continuing...", R2, R2Limit->value()));
2475 completeFocusProcedure(Ekos::FOCUS_COMPLETE,
false);
2481 qCDebug(KSTARS_EKOS_FOCUS) << linearFocuser->doneReason();
2482 appendLogText(
"Linear autofocus algorithm aborted.");
2483 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
2489 const int delta = nextPosition - currentPosition;
2491 if (!changeFocus(delta))
2492 completeFocusProcedure(Ekos::FOCUS_ABORTED,
false);
2498 void Focus::autoFocusAbs()
2502 static int minHFRPos = 0, focusOutLimit = 0, focusInLimit = 0, lastHFRPos = 0, fluctuations = 0;
2503 static double minHFR = 0, lastDelta = 0;
2504 double targetPosition = 0;
2505 bool ignoreLimitedDelta =
false;
2507 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 3);
2510 qCDebug(KSTARS_EKOS_FOCUS) <<
"========================================";
2511 qCDebug(KSTARS_EKOS_FOCUS) <<
"Current HFR: " << currentHFR <<
" Current Position: " << currentPosition;
2512 qCDebug(KSTARS_EKOS_FOCUS) <<
"Last minHFR: " << minHFR <<
" Last MinHFR Pos: " << minHFRPos;
2513 qCDebug(KSTARS_EKOS_FOCUS) <<
"Delta: " << deltaTxt <<
"%";
2514 qCDebug(KSTARS_EKOS_FOCUS) <<
"========================================";
2517 appendLogText(
i18n(
"FITS received. HFR %1 @ %2. Delta (%3%)", HFRText, currentPosition, deltaTxt));
2519 appendLogText(
i18n(
"FITS received. HFR %1 @ %2.", HFRText, currentPosition));
2521 if (!autoFocusChecks())
2524 addPlotPosition(currentPosition, currentHFR);
2526 switch (m_LastFocusDirection)
2529 lastHFR = currentHFR;
2530 initialFocuserAbsPosition = currentPosition;
2531 minHFR = currentHFR;
2532 minHFRPos = currentPosition;
2542 if (absMotionMax < currentPosition + pulseDuration)
2544 if (currentPosition < absMotionMax)
2546 pulseDuration = absMotionMax - currentPosition;
2551 m_LastFocusDirection = FOCUS_IN;
2554 else if (currentPosition + pulseDuration < absMotionMin)
2556 if (absMotionMin < currentPosition)
2558 pulseDuration = currentPosition - absMotionMin;
2563 m_LastFocusDirection = FOCUS_OUT;
2567 if (!changeFocus(pulseDuration))
2568 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2574 if (reverseDir && focusInLimit && focusOutLimit &&
2575 fabs(currentHFR - minHFR) < (toleranceIN->value() / 100.0) && HFRInc == 0)
2577 if (absIterations <= 2)
2579 QString message =
i18n(
"Change in HFR is too small. Try increasing the step size or decreasing the tolerance.");
2582 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2584 else if (noStarCount > 0)
2586 QString message =
i18n(
"Failed to detect focus star in frame. Capture and select a focus star.");
2589 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2593 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
2597 else if (currentHFR < lastHFR)
2600 if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_OUT && lastHFRPos < focusInLimit && fabs(currentHFR - lastHFR) > 0.1)
2602 focusInLimit = lastHFRPos;
2603 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusInLimit " << focusInLimit;
2605 else if (HFRInc >= 1 && m_LastFocusDirection == FOCUS_IN && lastHFRPos > focusOutLimit &&
2606 fabs(currentHFR - lastHFR) > 0.1)
2608 focusOutLimit = lastHFRPos;
2609 qCDebug(KSTARS_EKOS_FOCUS) <<
"New FocusOutLimit " << focusOutLimit;
2612 double factor = std::max(1.0, HFRDec / 2.0);
2613 if (m_LastFocusDirection == FOCUS_IN)
2614 targetPosition = currentPosition - (pulseDuration * factor);
2616 targetPosition = currentPosition + (pulseDuration * factor);
2618 qCDebug(KSTARS_EKOS_FOCUS) <<
"current Position" << currentPosition <<
" targetPosition " << targetPosition;
2620 lastHFR = currentHFR;
2623 if (lastHFR < minHFR)
2626 minHFRPos = currentPosition;
2627 qCDebug(KSTARS_EKOS_FOCUS) <<
"new minHFR " << minHFR <<
" @ position " << minHFRPos;
2630 lastHFRPos = currentPosition;
2637 if (hfr_position.
count() >= 2)
2654 lastHFR = currentHFR;
2655 lastHFRPos = currentPosition;
2664 qCDebug(KSTARS_EKOS_FOCUS) <<
"Focus is moving away from optimal HFR.";
2667 if (m_LastFocusDirection == FOCUS_IN)
2669 focusInLimit = currentPosition;
2670 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus IN limit to " << focusInLimit;
2674 focusOutLimit = currentPosition;
2675 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus OUT limit to " << focusOutLimit;
2678 if (m_FocusAlgorithm == FOCUS_POLYNOMIAL && hfr_position.
count() > 4)
2680 polynomialFit.reset(
new PolynomialFit(2, 5, hfr_position, hfr_value));
2683 double min_position = 0, min_hfr = 0;
2684 isVShapeSolution = polynomialFit->findMinimum(minHFRPos, a, b, &min_position, &min_hfr);
2685 qCDebug(KSTARS_EKOS_FOCUS) <<
"Found Minimum?" << (isVShapeSolution ?
"Yes" :
"No");
2686 if (isVShapeSolution)
2688 ignoreLimitedDelta =
true;
2689 qCDebug(KSTARS_EKOS_FOCUS) <<
"Minimum Solution:" << min_hfr <<
"@" << min_position;
2690 targetPosition = round(min_position);
2691 appendLogText(
i18n(
"Found polynomial solution @ %1",
QString::number(min_position,
'f', 0)));
2693 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
true);
2698 emit
drawPolynomial(polynomialFit.get(), isVShapeSolution,
false);
2707 if (std::abs(lastDelta) > 0)
2708 targetPosition = currentPosition + lastDelta;
2710 targetPosition = currentPosition + pulseDuration;
2712 else if (isVShapeSolution ==
false)
2714 ignoreLimitedDelta =
true;
2716 if (m_LastFocusDirection == FOCUS_OUT)
2717 targetPosition = minHFRPos - pulseDuration / 2;
2719 targetPosition = minHFRPos + pulseDuration / 2;
2722 qCDebug(KSTARS_EKOS_FOCUS) <<
"new targetPosition " << targetPosition;
2726 if (focusInLimit != 0 && m_LastFocusDirection == FOCUS_IN && targetPosition < focusInLimit)
2728 targetPosition = focusInLimit;
2729 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus in limit " << targetPosition;
2731 else if (focusOutLimit != 0 && m_LastFocusDirection == FOCUS_OUT && targetPosition > focusOutLimit)
2733 targetPosition = focusOutLimit;
2734 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limiting target pulse to focus out limit " << targetPosition;
2738 if (targetPosition < absMotionMin)
2739 targetPosition = absMotionMin;
2740 else if (targetPosition > absMotionMax)
2741 targetPosition = absMotionMax;
2744 if (targetPosition == currentPosition)
2748 if (targetPosition == minHFRPos || isVShapeSolution)
2750 appendLogText(
"Stopping at minimum recorded HFR position.");
2751 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
2755 QString message =
i18n(
"Focuser cannot move further, device limits reached. Autofocus aborted.");
2758 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2764 if (fluctuations >= MAXIMUM_FLUCTUATIONS)
2766 QString message =
i18n(
"Unstable fluctuations. Try increasing initial step size or exposure time.");
2769 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2774 if (focusOutLimit && focusOutLimit == focusInLimit)
2776 QString message =
i18n(
"Deadlock reached. Please try again with different settings.");
2779 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2784 if (fabs(targetPosition - initialFocuserAbsPosition) > maxTravelIN->value())
2786 int minTravelLimit = qMax(0.0, initialFocuserAbsPosition - maxTravelIN->value());
2787 int maxTravelLimit = qMin(absMotionMax, initialFocuserAbsPosition + maxTravelIN->value());
2791 if (fabs(currentPosition - minTravelLimit) > 10 && targetPosition < minTravelLimit)
2793 targetPosition = minTravelLimit;
2796 else if (fabs(currentPosition - maxTravelLimit) > 10 && targetPosition > maxTravelLimit)
2798 targetPosition = maxTravelLimit;
2802 qCDebug(KSTARS_EKOS_FOCUS) <<
"targetPosition (" << targetPosition <<
") - initHFRAbsPos ("
2803 << initialFocuserAbsPosition <<
") exceeds maxTravel distance of " << maxTravelIN->value();
2808 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2814 lastDelta = (targetPosition - currentPosition);
2816 qCDebug(KSTARS_EKOS_FOCUS) <<
"delta (targetPosition - currentPosition) " << lastDelta;
2819 if (ignoreLimitedDelta ==
false)
2821 double limitedDelta = qMax(-1.0 * maxSingleStepIN->value(), qMin(1.0 * maxSingleStepIN->value(), lastDelta));
2822 if (std::fabs(limitedDelta - lastDelta) > 0)
2824 qCDebug(KSTARS_EKOS_FOCUS) <<
"Limited delta to maximum permitted single step " << maxSingleStepIN->value();
2825 lastDelta = limitedDelta;
2830 if (!changeFocus(lastDelta))
2831 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2837 void Focus::addPlotPosition(
int pos,
double hfr,
bool plot)
2845 void Focus::autoFocusRel()
2847 static int noStarCount = 0;
2848 static double minHFR = 1e6;
2849 QString deltaTxt =
QString(
"%1").
arg(fabs(currentHFR - minHFR) * 100.0, 0,
'g', 2);
2853 appendLogText(
i18n(
"FITS received. HFR %1. Delta (%2%) Min HFR (%3)", HFRText, deltaTxt, minHFRText));
2855 if (pulseDuration <= MINIMUM_PULSE_TIMER)
2857 appendLogText(
i18n(
"Autofocus failed to reach proper focus. Try adjusting the tolerance value."));
2858 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2863 if (currentHFR == FocusAlgorithmInterface::IGNORED_HFR)
2865 if (noStarCount < MAX_RECAPTURE_RETRIES)
2868 appendLogText(
i18n(
"No stars detected, capturing again..."));
2872 else if (m_FocusAlgorithm == FOCUS_LINEAR || m_FocusAlgorithm == FOCUS_LINEAR1PASS)
2874 appendLogText(
i18n(
"Failed to detect any stars at position %1. Continuing...", currentPosition));
2879 appendLogText(
i18n(
"Failed to detect any stars. Reset frame and try again."));
2880 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2887 switch (m_LastFocusDirection)
2890 lastHFR = currentHFR;
2892 changeFocus(-pulseDuration);
2897 if (fabs(currentHFR - minHFR) < (toleranceIN->value() / 100.0) && HFRInc == 0)
2899 completeFocusProcedure(Ekos::FOCUS_COMPLETE);
2901 else if (currentHFR < lastHFR)
2903 if (currentHFR < minHFR)
2904 minHFR = currentHFR;
2906 lastHFR = currentHFR;
2907 changeFocus(m_LastFocusDirection == FOCUS_IN ? -pulseDuration : pulseDuration);
2914 lastHFR = currentHFR;
2918 pulseDuration *= 0.75;
2920 if (!changeFocus(m_LastFocusDirection == FOCUS_IN ? pulseDuration : -pulseDuration))
2921 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2927 void Focus::autoFocusProcessPositionChange(IPState state)
2929 if (state == IPS_OK && captureInProgress ==
false)
2935 if (focuserAdditionalMovement > 0)
2937 int temp = focuserAdditionalMovement;
2938 focuserAdditionalMovement = 0;
2939 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Linear: un-doing extension. Moving back in by %1").
arg(temp);
2943 appendLogText(
i18n(
"Focuser error, check INDI panel."));
2944 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2949 qCDebug(KSTARS_EKOS_FOCUS) <<
QString(
"Focus position reached at %1, starting capture in %2 seconds.").
arg(
2950 currentPosition).
arg(FocusSettleTime->value());
2951 capture(FocusSettleTime->value());
2954 else if (state == IPS_ALERT)
2956 appendLogText(
i18n(
"Focuser error, check INDI panel."));
2957 completeFocusProcedure(Ekos::FOCUS_ABORTED);
2963 if (m_Focuser ==
nullptr)
2967 if (nvp->device != m_Focuser->getDeviceName())
2974 if (!strcmp(nvp->name,
"FOCUS_BACKLASH_STEPS"))
2976 focusBacklashSpin->setValue(nvp->np[0].value);
2980 if (!strcmp(nvp->name,
"ABS_FOCUS_POSITION"))
2982 m_FocusMotionTimer.
stop();
2983 INumber *
pos = IUFindNumber(nvp,
"FOCUS_ABSOLUTE_POSITION");
2988 int newPosition =
static_cast<int>(
pos->value);
2993 if (currentPosition == newPosition && currentPositionState == nvp->s)
2996 currentPositionState = nvp->s;
2998 if (currentPosition != newPosition)
3000 currentPosition = newPosition;
3001 qCDebug(KSTARS_EKOS_FOCUS) <<
"Abs Focuser position changed to " << currentPosition <<
"State:" << pstateStr(
3002 currentPositionState);
3004 emit absolutePositionChanged(currentPosition);
3008 if (nvp->s == IPS_OK)
3015 adjustFocus =
false;
3016 m_LastFocusDirection = FOCUS_NONE;
3017 emit focusPositionAdjusted();
3021 if (m_RestartState == RESTART_NOW && status() != Ekos::FOCUS_ABORTED)
3023 m_RestartState = RESTART_NONE;
3024 inAutoFocus =
false;
3025 appendLogText(
i18n(
"Restarting autofocus process..."));
3028 else if (m_RestartState == RESTART_ABORT)
3034 m_RestartState = RESTART_NONE;
3035 inAutoFocus =
false;
3036 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3040 if (canAbsMove && inAutoFocus)
3042 autoFocusProcessPositionChange(nvp->s);
3044 else if (nvp->s == IPS_ALERT)
3045 appendLogText(
i18n(
"Focuser error, check INDI panel."));
3052 if (!strcmp(nvp->name,
"manualfocusdrive"))
3054 m_FocusMotionTimer.
stop();
3056 INumber *
pos = IUFindNumber(nvp,
"manualfocusdrive");
3057 if (
pos && nvp->s == IPS_OK)
3059 currentPosition +=
pos->value;
3060 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
3061 emit absolutePositionChanged(currentPosition);
3064 if (adjustFocus && nvp->s == IPS_OK)
3066 adjustFocus =
false;
3067 m_LastFocusDirection = FOCUS_NONE;
3068 emit focusPositionAdjusted();
3073 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3075 m_RestartState = RESTART_NONE;
3076 inAutoFocus =
false;
3077 appendLogText(
i18n(
"Restarting autofocus process..."));
3080 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3083 m_RestartState = RESTART_NONE;
3084 inAutoFocus =
false;
3085 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3088 if (canRelMove && inAutoFocus)
3090 autoFocusProcessPositionChange(nvp->s);
3092 else if (nvp->s == IPS_ALERT)
3093 appendLogText(
i18n(
"Focuser error, check INDI panel."));
3098 if (!strcmp(nvp->name,
"REL_FOCUS_POSITION"))
3100 m_FocusMotionTimer.
stop();
3102 INumber *
pos = IUFindNumber(nvp,
"FOCUS_RELATIVE_POSITION");
3103 if (
pos && nvp->s == IPS_OK)
3105 currentPosition +=
pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
3106 qCDebug(KSTARS_EKOS_FOCUS)
3107 <<
QString(
"Rel Focuser position changed by %1 to %2")
3109 absTicksLabel->setText(
QString::number(
static_cast<int>(currentPosition)));
3110 emit absolutePositionChanged(currentPosition);
3113 if (adjustFocus && nvp->s == IPS_OK)
3115 adjustFocus =
false;
3116 m_LastFocusDirection = FOCUS_NONE;
3117 emit focusPositionAdjusted();
3122 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3124 m_RestartState = RESTART_NONE;
3125 inAutoFocus =
false;
3126 appendLogText(
i18n(
"Restarting autofocus process..."));
3129 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3132 m_RestartState = RESTART_NONE;
3133 inAutoFocus =
false;
3134 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3137 if (canRelMove && inAutoFocus)
3139 autoFocusProcessPositionChange(nvp->s);
3141 else if (nvp->s == IPS_ALERT)
3142 appendLogText(
i18n(
"Focuser error, check INDI panel."));
3150 if (!strcmp(nvp->name,
"FOCUS_TIMER"))
3152 m_FocusMotionTimer.
stop();
3154 if (m_RestartState == RESTART_NOW && nvp->s == IPS_OK && status() != Ekos::FOCUS_ABORTED)
3156 m_RestartState = RESTART_NONE;
3157 inAutoFocus =
false;
3158 appendLogText(
i18n(
"Restarting autofocus process..."));
3161 else if (m_RestartState == RESTART_ABORT && nvp->s == IPS_OK)
3164 m_RestartState = RESTART_NONE;
3165 inAutoFocus =
false;
3166 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3169 if (canAbsMove ==
false && canRelMove ==
false && inAutoFocus)
3172 INumber *
pos = IUFindNumber(nvp,
"FOCUS_TIMER_VALUE");
3175 currentPosition +=
pos->value * (m_LastFocusDirection == FOCUS_IN ? -1 : 1);
3176 qCDebug(KSTARS_EKOS_FOCUS)
3177 <<
QString(
"Timer Focuser position changed by %1 to %2")
3180 autoFocusProcessPositionChange(nvp->s);
3182 else if (nvp->s == IPS_ALERT)
3183 appendLogText(
i18n(
"Focuser error, check INDI panel."));
3189 void Focus::appendLogText(
const QString &text)
3191 m_LogText.
insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
3192 KStarsData::Instance()->lt().toString(
"yyyy-MM-ddThh:mm:ss"), text));
3194 qCInfo(KSTARS_EKOS_FOCUS) << text;
3199 void Focus::clearLog()
3205 void Focus::appendFocusLogText(
const QString &lines)
3207 if (Options::focusLogging())
3210 if (!m_FocusLogFile.
exists())
3214 dir.mkpath(
"focuslogs");
3216 if (m_FocusLogEnabled)
3219 header <<
"date, time, position, temperature, filter, HFR, altitude\n";
3223 qCWarning(KSTARS_EKOS_FOCUS) <<
"Failed to open focus log file: " << m_FocusLogFileName;
3226 if (m_FocusLogEnabled)
3237 if (m_Camera ==
nullptr)
3239 appendLogText(
i18n(
"No CCD connected."));
3243 waitStarSelectTimer.
stop();
3251 state = Ekos::FOCUS_FRAMING;
3252 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
3253 emit newStatus(state);
3257 appendLogText(
i18n(
"Starting continuous exposure..."));
3262 void Focus::resetButtons()
3266 startFocusB->setEnabled(
false);
3267 startLoopB->setEnabled(
false);
3268 stopFocusB->setEnabled(
true);
3270 captureB->setEnabled(
false);
3277 stopFocusB->setEnabled(
true);
3279 startFocusB->setEnabled(
false);
3280 startLoopB->setEnabled(
false);
3281 captureB->setEnabled(
false);
3282 focusOutB->setEnabled(
false);
3283 focusInB->setEnabled(
false);
3284 startGotoB->setEnabled(
false);
3285 stopGotoB->setEnabled(
false);
3287 resetFrameB->setEnabled(
false);
3292 bool const enableCaptureButtons = captureInProgress ==
false && hfrInProgress ==
false;
3294 captureB->setEnabled(enableCaptureButtons);
3295 resetFrameB->setEnabled(enableCaptureButtons);
3296 startLoopB->setEnabled(enableCaptureButtons);
3300 focusOutB->setEnabled(
true);
3301 focusInB->setEnabled(
true);
3303 startFocusB->setEnabled(focusType == FOCUS_AUTO);
3304 stopFocusB->setEnabled(!enableCaptureButtons);
3305 startGotoB->setEnabled(canAbsMove);
3306 stopGotoB->setEnabled(
true);
3310 focusOutB->setEnabled(
false);
3311 focusInB->setEnabled(
false);
3313 startFocusB->setEnabled(
false);
3314 stopFocusB->setEnabled(
false);
3315 startGotoB->setEnabled(
false);
3316 stopGotoB->setEnabled(
false);
3320 void Focus::updateBoxSize(
int value)
3322 if (m_Camera ==
nullptr)
3325 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
3327 if (targetChip ==
nullptr)
3330 int subBinX, subBinY;
3331 targetChip->getBinning(&subBinX, &subBinY);
3333 QRect trackBox = m_FocusView->getTrackingBox();
3337 QRect(
center.x() - value / (2 * subBinX),
center.y() - value / (2 * subBinY), value / subBinX, value / subBinY);
3339 m_FocusView->setTrackingBox(trackBox);
3344 if (m_ImageData.
isNull())
3351 emit newImage(m_FocusView);
3357 if (state == Ekos::FOCUS_PROGRESS)
3360 if (subFramed ==
false)
3362 rememberStarCenter.
setX(
x);
3363 rememberStarCenter.
setY(
y);
3366 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
3368 int subBinX, subBinY;
3369 targetChip->getBinning(&subBinX, &subBinY);
3372 if (subBinX != activeBin)
3378 int offset = (
static_cast<double>(focusBoxSize->value()) / subBinX) * 1.5;
3382 bool squareMovedOutside =
false;
3384 if (subFramed ==
false && useSubFrame->isChecked() && targetChip->canSubframe())
3386 int minX, maxX, minY, maxY, minW, maxW, minH, maxH;
3388 targetChip->getFrameMinMax(&minX, &maxX, &minY, &maxY, &minW, &maxW, &minH, &maxH);
3391 x = (
x - offset) * subBinX;
3392 y = (
y - offset) * subBinY;
3393 int w = offset * 2 * subBinX;
3394 int h = offset * 2 * subBinY;
3413 QVariantMap settings = frameSettings[targetChip];
3418 settings[
"binx"] = subBinX;
3419 settings[
"biny"] = subBinY;
3421 frameSettings[targetChip] = settings;
3425 qCDebug(KSTARS_EKOS_FOCUS) <<
"Frame is subframed. X:" <<
x <<
"Y:" <<
y <<
"W:" << w <<
"H:" << h <<
"binX:" << subBinX <<
3428 m_FocusView->setFirstLoad(
true);
3433 starCenter.
setX(w / (2 * subBinX));
3434 starCenter.
setY(h / (2 * subBinY));
3439 double dist = sqrt((starCenter.
x() -
x) * (starCenter.
x() -
x) + (starCenter.
y() -
y) * (starCenter.
y() -
y));
3441 squareMovedOutside = (dist > (
static_cast<double>(focusBoxSize->value()) / subBinX));
3445 starRect =
QRect(starCenter.
x() - focusBoxSize->value() / (2 * subBinX),
3446 starCenter.
y() - focusBoxSize->value() / (2 * subBinY), focusBoxSize->value() / subBinX,
3447 focusBoxSize->value() / subBinY);
3448 m_FocusView->setTrackingBox(starRect);
3453 starCenter.
setZ(subBinX);
3457 defaultScale =
static_cast<FITSScale
>(filterCombo->currentIndex());
3459 if (squareMovedOutside && inAutoFocus ==
false && useAutoStar->isChecked())
3461 useAutoStar->blockSignals(
true);
3462 useAutoStar->setChecked(
false);
3463 useAutoStar->blockSignals(
false);
3464 appendLogText(
i18n(
"Disabling Auto Star Selection as star selection box was moved manually."));
3465 starSelected =
false;
3467 else if (starSelected ==
false)
3469 appendLogText(
i18n(
"Focus star is selected."));
3470 starSelected =
true;
3474 waitStarSelectTimer.
stop();
3475 FocusState nextState = inAutoFocus ? FOCUS_PROGRESS : FOCUS_IDLE;
3476 if (nextState != state)
3479 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
3480 emit newStatus(state);
3486 if (inAutoFocus || inFocusLoop)
3488 qCDebug(KSTARS_EKOS_FOCUS) <<
"Check Focus rejected, focus procedure is already running.";
3492 qCDebug(KSTARS_EKOS_FOCUS) <<
"Check Focus requested with minimum required HFR" << requiredHFR;
3493 minimumRequiredHFR = requiredHFR;
3495 appendLogText(
"Capturing to check HFR...");
3500 void Focus::toggleSubframe(
bool enable)
3502 if (enable ==
false)
3505 starSelected =
false;
3508 if (useFullField->isChecked())
3509 useFullField->setChecked(!enable);
3511 if (useFullField->isChecked() && (curveFit == CurveFitting::FOCUS_HYPERBOLA || curveFit == CurveFitting::FOCUS_PARABOLA))
3513 useWeights->setEnabled(
true);
3514 else if (curveFit == CurveFitting::FOCUS_HYPERBOLA || curveFit == CurveFitting::FOCUS_PARABOLA)
3516 useWeights->setEnabled(
false);
3517 useWeights->setChecked(
false);
3523 Options::setFocusEffect(index);
3524 defaultScale =
static_cast<FITSScale
>(index);
3527 switch (defaultScale)
3531 case FITS_ROTATE_CW:
3532 case FITS_ROTATE_CCW:
3539 appendLogText(
i18n(
"Warning: Only use filter '%1' for preview as it may interfere with autofocus operation.",
3540 FITSViewer::filterTypes.value(index - 1,
"???")));
3546 exposureIN->setValue(value);
3551 INDI_UNUSED(subBinY);
3552 binningCombo->setCurrentIndex(subBinX - 1);
3557 for (
int i = 0; i < filterCombo->count(); i++)
3558 if (filterCombo->itemText(i) == value)
3560 filterCombo->setCurrentIndex(i);
3561 filterCombo->activated(i);
3568 useAutoStar->setChecked(enable);
3569 Options::setFocusAutoStarEnabled(enable);
3574 useSubFrame->setChecked(enable);
3575 Options::setFocusSubFrame(enable);
3580 focusBoxSize->setValue(boxSize);
3581 stepIN->setValue(stepSize);
3582 maxTravelIN->setValue(maxTravel);
3583 toleranceIN->setValue(tolerance);
3586 void Focus::checkAutoStarTimeout()
3589 if (starCenter.
isNull() && (inAutoFocus || minimumRequiredHFR > 0))
3593 if (rememberStarCenter.
isNull() ==
false)
3596 appendLogText(
i18n(
"No star was selected. Using last known position..."));
3601 initialFocuserAbsPosition = -1;
3602 appendLogText(
i18n(
"No star was selected. Aborting..."));
3603 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3605 else if (state == FOCUS_WAITING)
3608 qCDebug(KSTARS_EKOS_FOCUS) <<
"State:" << Ekos::getFocusStatusString(state);
3609 emit newStatus(state);
3613 void Focus::setAbsoluteFocusTicks()
3615 if (m_Focuser ==
nullptr)
3617 appendLogText(
i18n(
"Error: No Focuser detected."));
3622 if (m_Focuser->isConnected() ==
false)
3624 appendLogText(
i18n(
"Error: Lost connection to Focuser."));
3629 qCDebug(KSTARS_EKOS_FOCUS) <<
"Setting focus ticks to " << absTicksSpin->value();
3631 m_Focuser->moveAbs(absTicksSpin->value());
3646 void Focus::syncTrackingBoxPosition()
3648 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
3649 Q_ASSERT(targetChip);
3651 int subBinX = 1, subBinY = 1;
3652 targetChip->getBinning(&subBinX, &subBinY);
3654 if (starCenter.
isNull() ==
false)
3656 double boxSize = focusBoxSize->value();
3658 targetChip->getFrame(&
x, &
y, &w, &h);
3660 if (boxSize / subBinX >= w || boxSize / subBinY >= h)
3662 focusBoxSize->setValue((boxSize / subBinX >= w) ? w : h);
3667 if (subBinX != starCenter.
z())
3669 if (starCenter.
z() > 0)
3671 starCenter.
setX(starCenter.
x() * (starCenter.
z() / subBinX));
3672 starCenter.
setY(starCenter.
y() * (starCenter.
z() / subBinY));
3675 starCenter.
setZ(subBinX);
3678 QRect starRect =
QRect(starCenter.
x() - boxSize / (2 * subBinX), starCenter.
y() - boxSize / (2 * subBinY),
3679 boxSize / subBinX, boxSize / subBinY);
3680 m_FocusView->setTrackingBoxEnabled(
true);
3681 m_FocusView->setTrackingBox(starRect);
3685 void Focus::showFITSViewer()
3687 static int lastFVTabID = -1;
3694 fv->loadData(m_ImageData, url, &lastFVTabID);
3696 else if (fv->updateData(m_ImageData, url, lastFVTabID, &lastFVTabID) ==
false)
3697 fv->loadData(m_ImageData, url, &lastFVTabID);
3703 void Focus::adjustFocusOffset(
int value,
bool useAbsoluteOffset)
3707 int relativeOffset = 0;
3709 if (useAbsoluteOffset ==
false)
3710 relativeOffset = value;
3712 relativeOffset = value - currentPosition;
3714 changeFocus(relativeOffset);
3717 void Focus::toggleFocusingWidgetFullScreen()
3719 if (focusingWidget->parent() ==
nullptr)
3721 focusingWidget->setParent(
this);
3722 rightLayout->insertWidget(0, focusingWidget);
3723 focusingWidget->showNormal();
3727 focusingWidget->setParent(
nullptr);
3728 focusingWidget->setWindowTitle(
i18nc(
"@title:window",
"Focus Frame"));
3730 focusingWidget->showMaximized();
3731 focusingWidget->show();
3735 void Focus::setMountStatus(ISD::Mount::Status newState)
3739 case ISD::Mount::MOUNT_PARKING:
3740 case ISD::Mount::MOUNT_SLEWING:
3741 case ISD::Mount::MOUNT_MOVING:
3742 captureB->setEnabled(
false);
3743 startFocusB->setEnabled(
false);
3744 startLoopB->setEnabled(
false);
3759 void Focus::setMountCoords(
const SkyPoint &position, ISD::Mount::PierSide pierSide,
const dms &ha)
3768 auto name = deviceRemoved->getDeviceName();
3771 for (
auto &focuser : m_Focusers)
3773 if (focuser->getDeviceName() == name)
3775 m_Focusers.removeAll(focuser);
3776 focuserCombo->removeItem(focuserCombo->findText(name));
3788 for (
auto &oneSource : m_TemperatureSources)
3790 if (oneSource->getDeviceName() == name)
3792 m_TemperatureSources.removeAll(oneSource);
3793 temperatureSourceCombo->removeItem(temperatureSourceCombo->findText(name));
3804 for (
auto &ccd : m_Cameras)
3806 if (ccd->getDeviceName() == name)
3808 m_Cameras.removeAll(ccd);
3809 CCDCaptureCombo->removeItem(CCDCaptureCombo->findText(name));
3810 CCDCaptureCombo->removeItem(CCDCaptureCombo->findText(name +
" Guider"));
3812 if (m_Cameras.empty())
3815 CCDCaptureCombo->setCurrentIndex(-1);
3819 m_Camera = m_Cameras[0];
3820 CCDCaptureCombo->setCurrentIndex(0);
3834 for (
auto &filter : m_FilterWheels)
3836 if (filter->getDeviceName() == name)
3838 m_FilterWheels.removeAll(filter);
3839 FilterDevicesCombo->removeItem(FilterDevicesCombo->findText(name));
3840 if (m_FilterWheels.empty())
3842 m_FilterWheel =
nullptr;
3843 FilterDevicesCombo->setCurrentIndex(-1);
3846 FilterDevicesCombo->setCurrentIndex(0);
3861 m_FilterManager = manager;
3864 m_FilterManager->show();
3865 m_FilterManager->raise();
3868 connect(m_FilterManager.
data(), &FilterManager::ready, [
this]()
3870 if (filterPositionPending)
3872 filterPositionPending = false;
3875 else if (fallbackFilterPending)
3877 fallbackFilterPending =
false;
3878 emit newStatus(state);
3883 connect(m_FilterManager.data(), &FilterManager::failed, [
this]()
3885 appendLogText(i18n(
"Filter operation failed."));
3886 completeFocusProcedure(Ekos::FOCUS_ABORTED);
3890 connect(
this, &Focus::newStatus, [
this](Ekos::FocusState state)
3892 if (FilterPosCombo->currentIndex() != -1 && canAbsMove && state == Ekos::FOCUS_COMPLETE)
3894 m_FilterManager->setFilterAbsoluteFocusPosition(FilterPosCombo->currentIndex(), currentPosition);
3899 connect(
this, &Focus::focusPositionAdjusted,
this, [
this]()
3901 if (m_GuidingSuspended && state != Ekos::FOCUS_PROGRESS)
3905 m_GuidingSuspended = false;
3906 emit resumeGuiding();
3912 connect(m_FilterManager.data(), &FilterManager::newStatus,
this, [
this](Ekos::FilterState filterState)
3915 const bool isOAG = m_Camera->getTelescopeType() == Options::guideScopeType();
3916 if (isOAG && filterState == FILTER_OFFSET && state != Ekos::FOCUS_PROGRESS)
3918 if (m_GuidingSuspended == false && suspendGuideCheck->isChecked())
3920 m_GuidingSuspended = true;
3921 emit suspendGuiding();
3929 m_FilterManager->setFilterExposure(FilterPosCombo->currentIndex(), exposureIN->value());
3931 Options::setFocusExposure(exposureIN->value());
3934 connect(m_FilterManager.data(), &FilterManager::labelsChanged,
this, [
this]()
3936 FilterPosCombo->clear();
3937 FilterPosCombo->addItems(m_FilterManager->getFilterLabels());
3938 currentFilterPosition = m_FilterManager->getFilterPosition();
3939 FilterPosCombo->setCurrentIndex(currentFilterPosition - 1);
3942 connect(m_FilterManager.data(), &FilterManager::positionChanged,
this, [
this]()
3944 currentFilterPosition = m_FilterManager->getFilterPosition();
3945 FilterPosCombo->setCurrentIndex(currentFilterPosition - 1);
3948 connect(m_FilterManager.data(), &FilterManager::exposureChanged,
this, [
this]()
3950 exposureIN->setValue(m_FilterManager->getFilterExposure());
3956 exposureIN->setValue(m_FilterManager->getFilterExposure(text));
3961 void Focus::toggleVideo(
bool enabled)
3963 if (m_Camera ==
nullptr)
3966 if (m_Camera->isBLOBEnabled() ==
false)
3969 if (Options::guiderType() != Ekos::Guide::GUIDE_INTERNAL)
3970 m_Camera->setBLOBEnabled(
true);
3977 m_Camera->setVideoStreamEnabled(enabled);
3979 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"));
3983 m_Camera->setVideoStreamEnabled(enabled);
3999 void Focus::setVideoStreamEnabled(
bool enabled)
4003 liveVideoB->setChecked(
true);
4008 liveVideoB->setChecked(
false);
4013 void Focus::processCaptureTimeout()
4015 captureTimeoutCounter++;
4017 if (captureTimeoutCounter >= 3)
4019 captureTimeoutCounter = 0;
4020 captureTimeout.stop();
4021 appendLogText(
i18n(
"Exposure timeout. Aborting..."));
4022 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4026 appendLogText(
i18n(
"Exposure timeout. Restarting exposure..."));
4027 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4028 targetChip->abortExposure();
4030 prepareCapture(targetChip);
4032 if (targetChip->capture(exposureIN->value()))
4036 captureTimeout.start(Options::focusCaptureTimeout() * 1000);
4038 if (inFocusLoop ==
false)
4039 appendLogText(
i18n(
"Capturing image again..."));
4043 else if (inAutoFocus)
4045 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4054 appendLogText(
i18n(
"Failed to save image. Aborting..."));
4055 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4059 captureFailureCounter++;
4061 if (captureFailureCounter >= 3)
4063 captureFailureCounter = 0;
4064 appendLogText(
i18n(
"Exposure failure. Aborting..."));
4065 completeFocusProcedure(Ekos::FOCUS_ABORTED);
4069 appendLogText(
i18n(
"Exposure failure. Restarting exposure..."));
4070 ISD::CameraChip *targetChip = m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD);
4071 targetChip->abortExposure();
4072 targetChip->capture(exposureIN->value());
4075 void Focus::syncSettings()
4082 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
4087 if (dsb == FocusSettleTime)
4088 Options::setFocusSettleTime(dsb->
value());
4093 else if (dsb == gainIN)
4094 Options::setFocusGain(dsb->
value());
4099 else if (dsb == fullFieldInnerRing)
4100 Options::setFocusFullFieldInnerRadius(dsb->
value());
4101 else if (dsb == fullFieldOuterRing)
4102 Options::setFocusFullFieldOuterRadius(dsb->
value());
4103 else if (dsb == GuideSettleTime)
4104 Options::setGuideSettleTime(dsb->
value());
4105 else if (dsb == maxTravelIN)
4106 Options::setFocusMaxTravel(dsb->
value());
4107 else if (dsb == toleranceIN)
4108 Options::setFocusTolerance(dsb->
value());
4109 else if (dsb == thresholdSpin)
4110 Options::setFocusThreshold(dsb->
value());
4111 else if (dsb == gaussianSigmaSpin)
4112 Options::setFocusGaussianSigma(dsb->
value());
4113 else if (dsb == initialFocusOutStepsIN)
4114 Options::setInitialFocusOutSteps(dsb->
value());
4115 else if (dsb == R2Limit)
4116 Options::setFocusR2Limit(dsb->
value());
4118 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
4123 if (sb == focusBoxSize)
4124 Options::setFocusBoxSize(sb->
value());
4125 else if (sb == stepIN)
4126 Options::setFocusTicks(sb->
value());
4127 else if (sb == maxSingleStepIN)
4128 Options::setFocusMaxSingleStep(sb->
value());
4129 else if (sb == focusFramesSpin)
4130 Options::setFocusFramesCount(sb->
value());
4131 else if (sb == gaussianKernelSizeSpin)
4132 Options::setFocusGaussianKernelSize(sb->
value());
4133 else if (sb == multiRowAverageSpin)
4134 Options::setFocusMultiRowAverage(sb->
value());
4135 else if (sb == captureTimeoutSpin)
4136 Options::setFocusCaptureTimeout(sb->
value());
4137 else if (sb == motionTimeoutSpin)
4138 Options::setFocusMotionTimeout(sb->
value());
4141 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
4146 if (cb == useAutoStar)
4147 Options::setFocusAutoStarEnabled(cb->
isChecked());
4148 else if (cb == useSubFrame)
4149 Options::setFocusSubFrame(cb->
isChecked());
4150 else if (cb == darkFrameCheck)
4151 Options::setUseFocusDarkFrame(cb->
isChecked());
4152 else if (cb == useFullField)
4153 Options::setFocusUseFullField(cb->
isChecked());
4154 else if (cb == suspendGuideCheck)
4155 Options::setSuspendGuiding(cb->
isChecked());
4156 else if (cb == useWeights)
4157 Options::setFocusUseWeights(cb->
isChecked());
4160 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
4165 if (cbox == focuserCombo)
4166 Options::setDefaultFocusFocuser(cbox->
currentText());
4167 else if (cbox == CCDCaptureCombo)
4169 else if (cbox == binningCombo)
4172 Options::setFocusXBin(activeBin);
4174 else if (cbox == FilterDevicesCombo)
4175 Options::setDefaultFocusFilterWheel(cbox->
currentText());
4176 else if (cbox == temperatureSourceCombo)
4177 Options::setDefaultFocusTemperatureSource(cbox->
currentText());
4183 else if (cbox == focusAlgorithmCombo)
4185 else if (cbox == focusDetectionCombo)
4187 else if (cbox == curveFitCombo)
4191 emit settingsUpdated(getSettings());
4194 void Focus::loadSettings()
4200 FocusSettleTime->setValue(Options::focusSettleTime());
4206 exposureIN->setValue(Options::focusExposure());
4208 activeBin = Options::focusXBin();
4209 binningCombo->setCurrentIndex(activeBin - 1);
4211 gainIN->setValue(Options::focusGain());
4217 useSubFrame->setChecked(Options::focusSubFrame());
4219 darkFrameCheck->setChecked(Options::useFocusDarkFrame());
4221 useFullField->setChecked(Options::focusUseFullField());
4223 fullFieldInnerRing->setValue(Options::focusFullFieldInnerRadius());
4225 fullFieldOuterRing->setValue(Options::focusFullFieldOuterRadius());
4227 suspendGuideCheck->setChecked(Options::suspendGuiding());
4229 GuideSettleTime->setValue(Options::guideSettleTime());
4231 useWeights->setChecked(Options::focusUseWeights());
4233 R2Limit->setValue(Options::focusR2Limit());
4236 focusBoxSize->setValue(Options::focusBoxSize());
4238 maxTravelIN->setMinimum(0.0);
4239 if (Options::focusMaxTravel() > maxTravelIN->maximum())
4240 maxTravelIN->setMaximum(Options::focusMaxTravel());
4241 maxTravelIN->setValue(Options::focusMaxTravel());
4243 stepIN->setValue(Options::focusTicks());
4245 maxSingleStepIN->setValue(Options::focusMaxSingleStep());
4247 initialFocusOutStepsIN->setValue(Options::initialFocusOutSteps());
4249 toleranceIN->setValue(Options::focusTolerance());
4251 thresholdSpin->setValue(Options::focusThreshold());
4253 setFocusAlgorithm(
static_cast<FocusAlgorithm
>(Options::focusAlgorithm()));
4255 focusAlgorithmCombo->setCurrentIndex(m_FocusAlgorithm);
4257 focusFramesSpin->setValue(Options::focusFramesCount());
4259 focusDetection =
static_cast<StarAlgorithm
>(Options::focusDetection());
4260 thresholdSpin->setEnabled(focusDetection == ALGORITHM_THRESHOLD);
4261 focusDetectionCombo->setCurrentIndex(focusDetection);
4263 gaussianSigmaSpin->setValue(Options::focusGaussianSigma());
4264 gaussianKernelSizeSpin->setValue(Options::focusGaussianKernelSize());
4266 multiRowAverageSpin->setValue(Options::focusMultiRowAverage());
4267 multiRowAverageSpin->setEnabled(focusDetection == ALGORITHM_BAHTINOV);
4269 captureTimeoutSpin->setValue(Options::focusCaptureTimeout());
4270 motionTimeoutSpin->setValue(Options::focusMotionTimeout());
4272 setCurveFit(
static_cast<CurveFitting::CurveFit
>(Options::focusCurveFit()));
4274 curveFitCombo->setCurrentIndex(curveFit);
4278 if (focusDetection == ALGORITHM_BAHTINOV)
4280 Options::setFocusAutoStarEnabled(
false);
4281 focusBoxSize->setMaximum(512);
4286 if (Options::focusBoxSize() > 256)
4288 Options::setFocusBoxSize(32);
4290 focusBoxSize->setMaximum(256);
4293 focusBoxSize->setValue(Options::focusBoxSize());
4295 useAutoStar->setChecked(Options::focusAutoStarEnabled());
4296 useAutoStar->setEnabled(focusDetection != ALGORITHM_BAHTINOV);
4299 void Focus::initSettingsConnections()
4302 for (
auto &oneWidget : findChildren<QComboBox*>())
4303 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated),
this, &Ekos::Focus::syncSettings);
4306 for (
auto &oneWidget : findChildren<QDoubleSpinBox*>())
4310 for (
auto &oneWidget : findChildren<QSpinBox*>())
4314 for (
auto &oneWidget : findChildren<QCheckBox*>())
4318 void Focus::initPlots()
4322 profileDialog =
new QDialog(
this);
4325 profileDialog->setWindowTitle(
i18nc(
"@title:window",
"Relative Profile"));
4326 profilePlot =
new FocusProfilePlot(profileDialog);
4329 profileDialog->setLayout(profileLayout);
4330 profileDialog->resize(400, 300);
4333 connect(
this, &Ekos::Focus::newHFR, [
this](
double currentHFR,
int pos)
4335 Q_UNUSED(pos) profilePlot->drawProfilePlot(currentHFR);
4339 void Focus::initConnections()
4342 waitStarSelectTimer.setInterval(AUTO_STAR_TIMEOUT);
4343 connect(&waitStarSelectTimer, &
QTimer::timeout,
this, &Ekos::Focus::checkAutoStarTimeout);
4355 connect(toggleFullScreenB, &
QPushButton::clicked,
this, &Ekos::Focus::toggleFocusingWidgetFullScreen);
4358 captureTimer.setSingleShot(
true);
4365 captureTimeout.setSingleShot(
true);
4366 connect(&captureTimeout, &
QTimer::timeout,
this, &Ekos::Focus::processCaptureTimeout);
4387 fullFieldInnerRing->setEnabled(toggled);
4388 fullFieldOuterRing->setEnabled(toggled);
4391 useSubFrame->setChecked(
false);
4392 useAutoStar->setChecked(
false);
4393 if (curveFit == CurveFitting::FOCUS_HYPERBOLA || curveFit == CurveFitting::FOCUS_PARABOLA)
4395 useWeights->setEnabled(
true);
4400 m_FocusView->setStarFilterRange(0, 1);
4401 if (curveFit == CurveFitting::FOCUS_HYPERBOLA || curveFit == CurveFitting::FOCUS_PARABOLA)
4403 useWeights->setEnabled(
false);
4404 useWeights->setChecked(
false);
4433 focusDetection =
static_cast<StarAlgorithm
>(index);
4434 thresholdSpin->setEnabled(focusDetection == ALGORITHM_THRESHOLD);
4435 multiRowAverageSpin->setEnabled(focusDetection == ALGORITHM_BAHTINOV);
4436 if (focusDetection == ALGORITHM_BAHTINOV)
4439 useAutoStar->setChecked(
false);
4440 focusBoxSize->setMaximum(512);
4445 if (Options::focusBoxSize() > 256)
4447 Options::setFocusBoxSize(32);
4449 focusBoxSize->setValue(Options::focusBoxSize());
4451 focusBoxSize->setMaximum(256);
4453 useAutoStar->setEnabled(focusDetection != ALGORITHM_BAHTINOV);
4459 setFocusAlgorithm(
static_cast<FocusAlgorithm
>(index));
4466 setCurveFit(
static_cast<CurveFitting::CurveFit
>(index));
4475 starSelected =
false;
4476 m_FocusView->setTrackingBox(
QRect());
4481 void Focus::setFocusAlgorithm(FocusAlgorithm algorithm)
4483 m_FocusAlgorithm = algorithm;
4486 case FOCUS_ITERATIVE:
4487 initialFocusOutStepsIN->setEnabled(
false);
4488 maxTravelIN->setEnabled(
true);
4489 stepIN->setEnabled(
true);
4490 maxSingleStepIN->setEnabled(
true);
4491 toleranceIN->setEnabled(
true);
4492 curveFitCombo->setEnabled(
false);
4493 curveFitCombo->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
4496 case FOCUS_POLYNOMIAL:
4497 initialFocusOutStepsIN->setEnabled(
false);
4498 maxTravelIN->setEnabled(
true);
4499 stepIN->setEnabled(
true);
4500 maxSingleStepIN->setEnabled(
true);
4501 toleranceIN->setEnabled(
true);
4502 curveFitCombo->setEnabled(
false);
4503 curveFitCombo->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
4507 initialFocusOutStepsIN->setEnabled(
true);
4508 maxTravelIN->setEnabled(
true);
4509 stepIN->setEnabled(
true);
4510 maxSingleStepIN->setEnabled(
false);
4511 toleranceIN->setEnabled(
true);
4512 curveFitCombo->setEnabled(
false);
4513 curveFitCombo->setCurrentIndex(CurveFitting::FOCUS_QUADRATIC);
4516 case FOCUS_LINEAR1PASS:
4517 initialFocusOutStepsIN->setEnabled(
true);
4518 maxTravelIN->setEnabled(
true);
4519 stepIN->setEnabled(
true);
4520 maxSingleStepIN->setEnabled(
false);
4521 toleranceIN->setEnabled(
false);
4522 curveFitCombo->setEnabled(
true);
4527 void Focus::setCurveFit(CurveFitting::CurveFit curve)
4532 case CurveFitting::FOCUS_QUADRATIC:
4533 useWeights->setEnabled(
false);
4534 useWeights->setChecked(
false);
4535 R2Limit->setEnabled(
false);
4538 case CurveFitting::FOCUS_HYPERBOLA:
4539 useWeights->setEnabled(useFullField->isChecked());
4540 R2Limit->setEnabled(
true);
4543 case CurveFitting::FOCUS_PARABOLA:
4544 useWeights->setEnabled(useFullField->isChecked());
4545 R2Limit->setEnabled(
true);
4550 void Focus::initView()
4552 m_FocusView.reset(
new FITSView(focusingWidget, FITS_FOCUS));
4554 m_FocusView->setBaseSize(focusingWidget->size());
4555 m_FocusView->createFloatingToolBar();
4558 focusingWidget->setLayout(vlayout);
4560 m_FocusView->setStarsEnabled(
true);
4561 m_FocusView->setStarsHFREnabled(
true);
4571 settings.
insert(
"camera", CCDCaptureCombo->currentText());
4572 settings.
insert(
"focuser", focuserCombo->currentText());
4573 settings.
insert(
"fw", FilterDevicesCombo->currentText());
4574 settings.
insert(
"filter", FilterPosCombo->currentText());
4575 settings.
insert(
"exp", exposureIN->value());
4576 settings.
insert(
"bin", qMax(1, binningCombo->currentIndex() + 1));
4577 settings.
insert(
"gain", gainIN->value());
4578 settings.
insert(
"iso", ISOCombo->currentIndex());
4585 void Focus::setSettings(
const QJsonObject &settings)
4587 static bool init =
false;
4590 if (syncControl(settings,
"camera", CCDCaptureCombo) || init ==
false)
4593 if (syncControl(settings,
"focuser", focuserCombo) || init ==
false)
4596 if (syncControl(settings,
"fw", FilterDevicesCombo) || init ==
false)
4599 syncControl(settings,
"filter", FilterPosCombo);
4600 Options::setLockAlignFilterIndex(FilterPosCombo->currentIndex());
4602 syncControl(settings,
"exp", exposureIN);
4604 const int bin = settings[
"bin"].toInt(binningCombo->currentIndex() + 1) - 1;
4605 if (bin != binningCombo->currentIndex())
4606 binningCombo->setCurrentIndex(bin);
4609 if (m_Camera->hasGain())
4610 syncControl(settings,
"gain", gainIN);
4612 if (ISOCombo->count() > 1)
4614 const int iso = settings[
"iso"].toInt(ISOCombo->currentIndex());
4615 if (iso != ISOCombo->currentIndex())
4616 ISOCombo->setCurrentIndex(iso);
4630 settings.
insert(
"autostar", useAutoStar->isChecked());
4631 settings.
insert(
"dark", darkFrameCheck->isChecked());
4632 settings.
insert(
"subframe", useSubFrame->isChecked());
4633 settings.
insert(
"box", focusBoxSize->value());
4634 settings.
insert(
"fullfield", useFullField->isChecked());
4635 settings.
insert(
"inner", fullFieldInnerRing->value());
4636 settings.
insert(
"outer", fullFieldOuterRing->value());
4637 settings.
insert(
"suspend", suspendGuideCheck->isChecked());
4638 settings.
insert(
"guide_settle", GuideSettleTime->value());
4639 settings.
insert(
"useweights", useWeights->isChecked());
4640 settings.
insert(
"R2Limit", R2Limit->value());
4648 void Focus::setPrimarySettings(
const QJsonObject &settings)
4650 syncControl(settings,
"autostar", useAutoStar);
4651 syncControl(settings,
"dark", darkFrameCheck);
4652 syncControl(settings,
"subframe", useSubFrame);
4653 syncControl(settings,
"box", focusBoxSize);
4654 syncControl(settings,
"fullfield", useFullField);
4655 syncControl(settings,
"inner", fullFieldInnerRing);
4656 syncControl(settings,
"outer", fullFieldOuterRing);
4657 syncControl(settings,
"suspend", suspendGuideCheck);
4658 syncControl(settings,
"guide_settle", GuideSettleTime);
4659 syncControl(settings,
"useweights", useWeights);
4660 syncControl(settings,
"R2Limit", R2Limit);
4671 settings.
insert(
"detection", focusDetectionCombo->currentText());
4672 settings.
insert(
"algorithm", focusAlgorithmCombo->currentText());
4673 settings.
insert(
"sep", focusOptionsProfiles->currentText());
4674 settings.
insert(
"threshold", thresholdSpin->value());
4675 settings.
insert(
"tolerance", toleranceIN->value());
4676 settings.
insert(
"average", focusFramesSpin->value());
4677 settings.
insert(
"rows", multiRowAverageSpin->value());
4678 settings.
insert(
"kernel", gaussianKernelSizeSpin->value());
4679 settings.
insert(
"sigma", gaussianSigmaSpin->value());
4680 settings.
insert(
"curvefit", curveFitCombo->currentText());
4688 void Focus::setProcessSettings(
const QJsonObject &settings)
4690 syncControl(settings,
"detection", focusDetectionCombo);
4691 syncControl(settings,
"algorithm", focusAlgorithmCombo);
4692 syncControl(settings,
"sep", focusOptionsProfiles);
4693 syncControl(settings,
"threshold", thresholdSpin);
4694 syncControl(settings,
"tolerance", toleranceIN);
4695 syncControl(settings,
"average", focusFramesSpin);
4696 syncControl(settings,
"rows", multiRowAverageSpin);
4697 syncControl(settings,
"kernel", gaussianKernelSizeSpin);
4698 syncControl(settings,
"sigma", gaussianSigmaSpin);
4699 syncControl(settings,
"curvefit", curveFitCombo);
4709 settings.
insert(
"step", stepIN->value());
4710 settings.
insert(
"travel", maxTravelIN->value());
4711 settings.
insert(
"maxstep", maxSingleStepIN->value());
4712 settings.
insert(
"backlash", focusBacklashSpin->value());
4713 settings.
insert(
"settle", FocusSettleTime->value());
4714 settings.
insert(
"out", initialFocusOutStepsIN->value());
4722 void Focus::setMechanicsSettings(
const QJsonObject &settings)
4724 syncControl(settings,
"step", stepIN);
4725 syncControl(settings,
"travel", maxTravelIN);
4726 syncControl(settings,
"maxstep", maxSingleStepIN);
4727 syncControl(settings,
"backlash", focusBacklashSpin);
4728 syncControl(settings,
"settle", FocusSettleTime);
4729 syncControl(settings,
"out", initialFocusOutStepsIN);
4742 if ((pSB = qobject_cast<QSpinBox *>(widget)))
4744 const int value = settings[key].toInt(pSB->
value());
4745 if (value != pSB->
value())
4751 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
4753 const double value = settings[key].toDouble(pDSB->
value());
4754 if (value != pDSB->
value())
4760 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
4762 const bool value = settings[key].toBool(pCB->
isChecked());
4770 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))