1 /*
2     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "ui_focus.h"
10 #include "focusprofileplot.h"
11 #include "ekos/ekos.h"
12 #include "ekos/auxiliary/filtermanager.h"
13 #include "ekos/auxiliary/stellarsolverprofileeditor.h"
14 #include "ekos/auxiliary/darkprocessor.h"
15 #include "ekos/mount/mount.h"
16 #include "fitsviewer/fitsviewer.h"
17 #include "indi/indiccd.h"
18 #include "indi/indifocuser.h"
19 #include "indi/indistd.h"
20 #include "indi/indiweather.h"
21 #include "indi/inditelescope.h"
22 
23 #include <QtDBus/QtDBus>
24 #include <parameters.h>
25 
26 namespace Ekos
27 {
28 
29 class FocusAlgorithmInterface;
30 class PolynomialFit;
31 
32 /**
33  * @class Focus
34  * @short Supports manual focusing and auto focusing using relative and absolute INDI focusers.
35  *
36  * @author Jasem Mutlaq
37  * @version 1.5
38  */
39 class Focus : public QWidget, public Ui::Focus
40 {
41         Q_OBJECT
42         Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Focus")
43         Q_PROPERTY(Ekos::FocusState status READ status NOTIFY newStatus)
44         Q_PROPERTY(QStringList logText READ logText NOTIFY newLog)
45         Q_PROPERTY(QString camera READ camera WRITE setCamera)
46         Q_PROPERTY(QString focuser READ focuser WRITE setFocuser)
47         Q_PROPERTY(QString filterWheel READ filterWheel WRITE setFilterWheel)
48         Q_PROPERTY(QString filter READ filter WRITE setFilter)
49         Q_PROPERTY(double HFR READ getHFR NOTIFY newHFR)
50         Q_PROPERTY(double exposure READ exposure WRITE setExposure)
51 
52     public:
53         Focus();
54         ~Focus();
55 
56         typedef enum { FOCUS_NONE, FOCUS_IN, FOCUS_OUT } FocusDirection;
57         typedef enum { FOCUS_MANUAL, FOCUS_AUTO } FocusType;
58         typedef enum { FOCUS_ITERATIVE, FOCUS_POLYNOMIAL, FOCUS_LINEAR } FocusAlgorithm;
59         //typedef enum { FOCUSER_TEMPERATURE, OBSERVATORY_TEMPERATURE, NO_TEMPERATURE } TemperatureSource;
60 
61         /** @defgroup FocusDBusInterface Ekos DBus Interface - Focus Module
62              * Ekos::Focus interface provides advanced scripting capabilities to perform manual and automatic focusing operations.
63             */
64 
65         /*@{*/
66 
67         /** DBUS interface function.
68              * select the CCD device from the available CCD drivers.
69              * @param device The CCD device name
70              * @return Returns true if CCD device is found and set, false otherwise.
71              */
72         Q_SCRIPTABLE bool setCamera(const QString &device);
73         Q_SCRIPTABLE QString camera();
74 
75         /** DBUS interface function.
76              * select the focuser device from the available focuser drivers. The focuser device can be the same as the CCD driver if the focuser functionality was embedded within the driver.
77              * @param device The focuser device name
78              * @return Returns true if focuser device is found and set, false otherwise.
79              */
80         Q_SCRIPTABLE bool setFocuser(const QString &device);
81         Q_SCRIPTABLE QString focuser();
82 
83         /** DBUS interface function.
84              * select the filter device from the available filter drivers. The filter device can be the same as the CCD driver if the filter functionality was embedded within the driver.
85              * @param device The filter device name
86              * @return Returns true if filter device is found and set, false otherwise.
87              */
88         Q_SCRIPTABLE bool setFilterWheel(const QString &device);
89         Q_SCRIPTABLE QString filterWheel();
90 
91         /** DBUS interface function.
92              * select the filter from the available filters.
93              * @param filter The filter name
94              * @return Returns true if filter is found and set, false otherwise.
95              */
96         Q_SCRIPTABLE bool setFilter(const QString &filter);
97         Q_SCRIPTABLE QString filter();
98 
99         /** DBUS interface function.
100              * @return Returns True if current focuser supports auto-focusing
101              */
canAutoFocus()102         Q_SCRIPTABLE bool canAutoFocus()
103         {
104             return (focusType == FOCUS_AUTO);
105         }
106 
107         /** DBUS interface function.
108              * @return Returns Half-Flux-Radius in pixels.
109              */
getHFR()110         Q_SCRIPTABLE double getHFR()
111         {
112             return currentHFR;
113         }
114 
115         /** DBUS interface function.
116              * Set CCD exposure value
117              * @param value exposure value in seconds.
118              */
119         Q_SCRIPTABLE Q_NOREPLY void setExposure(double value);
exposure()120         Q_SCRIPTABLE double exposure()
121         {
122             return exposureIN->value();
123         }
124 
125         /** DBUS interface function.
126              * Set CCD binning
127              * @param binX horizontal binning
128              * @param binY vertical binning
129              */
130         Q_SCRIPTABLE Q_NOREPLY void setBinning(int binX, int binY);
131 
132         /** DBUS interface function.
133              * Set image filter to apply to the image after capture.
134              * @param value Image filter (Auto Stretch, High Contrast, Equalize, High Pass)
135              */
136         Q_SCRIPTABLE Q_NOREPLY void setImageFilter(const QString &value);
137 
138         /** DBUS interface function.
139              * Set Auto Focus options. The options must be set before starting the autofocus operation. If no options are set, the options loaded from the user configuration are used.
140              * @param enable If true, Ekos will attempt to automatically select the best focus star in the frame. If it fails to select a star, the user will be asked to select a star manually.
141              */
142         Q_SCRIPTABLE Q_NOREPLY void setAutoStarEnabled(bool enable);
143 
144         /** DBUS interface function.
145              * Set Auto Focus options. The options must be set before starting the autofocus operation. If no options are set, the options loaded from the user configuration are used.
146              * @param enable if true, Ekos will capture a subframe around the selected focus star. The subframe size is determined by the boxSize parameter.
147              */
148         Q_SCRIPTABLE Q_NOREPLY void setAutoSubFrameEnabled(bool enable);
149 
150         /** DBUS interface function.
151              * Set Autofocus parameters
152              * @param boxSize the box size around the focus star in pixels. The boxsize is used to subframe around the focus star.
153              * @param stepSize the initial step size to be commanded to the focuser. If the focuser is absolute, the step size is in ticks. For relative focusers, the focuser will be commanded to focus inward for stepSize milliseconds initially.
154              * @param maxTravel the maximum steps permitted before the autofocus operation aborts.
155              * @param tolerance Measure of how accurate the autofocus algorithm is. If the difference between the current HFR and minimum measured HFR is less than %tolerance after the focuser traversed both ends of the V-curve, then the focusing operation
156              * is deemed successful. Otherwise, the focusing operation will continue.
157              */
158         Q_SCRIPTABLE Q_NOREPLY void setAutoFocusParameters(int boxSize, int stepSize, int maxTravel, double tolerance);
159 
160         /** DBUS interface function.
161             * resetFrame Resets the CCD frame to its full native resolution.
162             */
163         Q_SCRIPTABLE Q_NOREPLY void resetFrame();
164 
165         /** DBUS interface function.
166             * Return state of Focuser module (Ekos::FocusState)
167             */
168 
status()169         Q_SCRIPTABLE Ekos::FocusState status()
170         {
171             return state;
172         }
173 
174         /** @}*/
175 
176         /**
177              * @brief Add CCD to the list of available CCD.
178              * @param newCCD pointer to CCD device.
179              */
180         void addCCD(ISD::GDInterface *newCCD);
181 
182         /**
183              * @brief addFocuser Add focuser to the list of available focusers.
184              * @param newFocuser pointer to focuser device.
185              */
186         void addFocuser(ISD::GDInterface *newFocuser);
187 
188         /**
189              * @brief addFilter Add filter to the list of available filters.
190              * @param newFilter pointer to filter device.
191              */
192         void addFilter(ISD::GDInterface *newFilter);
193 
194 
195         /**
196              * @brief addTemperatureSource Add temperature source to the list of available sources.
197              * @param newSource Device with temperature reporting capability
198              */
199         void addTemperatureSource(ISD::GDInterface *newSource);
200 
201         /**
202          * @brief removeDevice Remove device from Focus module
203          * @param deviceRemoved pointer to device
204          */
205         void removeDevice(ISD::GDInterface *deviceRemoved);
206 
207         void setFilterManager(const QSharedPointer<FilterManager> &manager);
208 
209         void clearLog();
logText()210         QStringList logText()
211         {
212             return m_LogText;
213         }
getLogText()214         QString getLogText()
215         {
216             return m_LogText.join("\n");
217         }
218 
219         // Presets
220         QJsonObject getSettings() const;
221         void setSettings(const QJsonObject &settings);
222         // Primary Settings
223         QJsonObject getPrimarySettings() const;
224         void setPrimarySettings(const QJsonObject &settings);
225         // Process Settings
226         QJsonObject getProcessSettings() const;
227         void setProcessSettings(const QJsonObject &settings);
228         // Mechanics Settings
229         QJsonObject getMechanicsSettings() const;
230         void setMechanicsSettings(const QJsonObject &settings);
231 
232     public slots:
233 
234         /** \addtogroup FocusDBusInterface
235              *  @{
236              */
237 
238         /* Focus */
239         /** DBUS interface function.
240              * Start the autofocus operation.
241              */
242         Q_SCRIPTABLE Q_NOREPLY void start();
243 
244         /** DBUS interface function.
245              * Abort the autofocus operation.
246              */
247         Q_SCRIPTABLE Q_NOREPLY void abort();
248 
249         /** DBUS interface function.
250              * Capture a focus frame.
251              * @param settleTime if > 0 wait for the given time in seconds before starting to capture
252              */
253         Q_SCRIPTABLE Q_NOREPLY void capture(double settleTime = 0.0);
254 
255         /** DBUS interface function.
256              * Focus inward
257              * @param ms If set, focus inward for ms ticks (Absolute Focuser), or ms milliseconds (Relative Focuser). If not set, it will use the value specified in the options.
258              */
259         Q_SCRIPTABLE bool focusIn(int ms = -1);
260 
261         /** DBUS interface function.
262              * Focus outward
263              * @param ms If set, focus outward for ms ticks (Absolute Focuser), or ms milliseconds (Relative Focuser). If not set, it will use the value specified in the options.
264              */
265         Q_SCRIPTABLE bool focusOut(int ms = -1);
266 
267         /** @}*/
268 
269         /**
270              * @brief startFraming Begins continuous capture of the CCD and calculates HFR every frame.
271              */
272         void startFraming();
273 
274         /**
275          * @brief Move the focuser to the initial focus position.
276          */
277         void resetFocuser();
278 
279         /**
280              * @brief checkStopFocus Perform checks before stopping the autofocus operation. Some checks are necessary for in-sequence focusing.
281              * @param abort true iff focusing should be aborted, false if it should only be stopped and marked as failed
282              */
283         void checkStopFocus(bool abort);
284 
285         /**
286          * @brief React when a meridian flip has been started
287          */
288         void meridianFlipStarted();
289 
290         /**
291              * @brief Check CCD and make sure information is updated accordingly. This simply calls syncCCDInfo for the current CCD.
292              * @param CCDNum By default, we check the already selected CCD in the dropdown menu. If CCDNum is specified, the check is made against this specific CCD in the dropdown menu.
293              *  CCDNum is the index of the CCD in the dropdown menu.
294              */
295         void checkCCD(int CCDNum = -1);
296 
297         /**
298              * @brief syncCCDInfo Read current CCD information and update settings accordingly.
299              */
300         void syncCCDInfo();
301 
302         /**
303              * @brief Check Focuser and make sure information is updated accordingly.
304              * @param FocuserNum By default, we check the already selected focuser in the dropdown menu. If FocuserNum is specified, the check is made against this specific focuser in the dropdown menu.
305              *  FocuserNum is the index of the focuser in the dropdown menu.
306              */
307         void checkFocuser(int FocuserNum = -1);
308 
309         /**
310              * @brief Check Filter and make sure information is updated accordingly.
311              * @param filterNum By default, we check the already selected filter in the dropdown menu. If filterNum is specified, the check is made against this specific filter in the dropdown menu.
312              *  filterNum is the index of the filter in the dropdown menu.
313              */
314         void checkFilter(int filterNum = -1);
315 
316         /**
317              * @brief Check temperature source and make sure information is updated accordingly.
318              * @param index Index of source in combo box. If -1, then use the currently selected source.
319              */
320         void checkTemperatureSource(int index = -1);
321 
322         /**
323              * @brief clearDataPoints Remove all data points from HFR plots
324              */
325         void clearDataPoints();
326 
327         /**
328              * @brief focusStarSelected The user selected a focus star, save its coordinates and subframe it if subframing is enabled.
329              * @param x X coordinate
330              * @param y Y coordinate
331              */
332         void focusStarSelected(int x, int y);
333 
334         /**
335          * @brief selectFocusStarFraction Select the focus star based by fraction of the overall size.
336          * It calls focusStarSelected after multiplying the fractions (0.0 to 1.0) with the focus view width and height.
337          * @param x final x = x * focusview_width
338          * @param y final y = y * focusview_height
339          */
340         void selectFocusStarFraction(double x, double y);
341 
342         /**
343              * @brief newFITS A new FITS blob is received by the CCD driver.
344              * @param bp pointer to blob data
345              */
346         void processData(const QSharedPointer<FITSData> &data);
347 
348         /**
349              * @brief processFocusNumber Read focus number properties of interest as they arrive from the focuser driver and process them accordingly.
350              * @param nvp pointer to updated focuser number property.
351              */
352         void processFocusNumber(INumberVectorProperty *nvp);
353 
354         /**
355              * @brief processTemperatureSource Updates focus temperature source.
356              * @param nvp pointer to updated focuser number property.
357              */
358         void processTemperatureSource(INumberVectorProperty *nvp);
359 
360         /**
361              * @brief checkFocus Given the minimum required HFR, check focus and calculate HFR. If current HFR exceeds required HFR, start autofocus process, otherwise do nothing.
362              * @param requiredHFR Minimum HFR to trigger autofocus process.
363              */
364         void checkFocus(double requiredHFR);
365 
366         /**
367              * @brief setFocusStatus Upon completion of the focusing process, set its status (fail or pass) and reset focus process to clean state.
368              * @param status If true, the focus process finished successfully. Otherwise, it failed.
369              */
370         //void setAutoFocusResult(bool status);
371 
372         /**
373              * @brief filterChangeWarning Warn the user it is not a good idea to apply image filter in the filter process as they can skew the HFR calculations.
374              * @param index Index of image filter selected by the user.
375              */
376         void filterChangeWarning(int index);
377 
378         // Logging methods - one for INFO messages to the kstars log, and one for a CSV auto-focus log
379         void appendLogText(const QString &);
380         void appendFocusLogText(const QString &);
381 
382         // Adjust focuser offset, relative or absolute
383         void adjustFocusOffset(int value, bool useAbsoluteOffset);
384 
385         // Update Mount module status
386         void setMountStatus(ISD::Telescope::Status newState);
387 
388         // Update Altitude From Mount
389         void setMountCoords(const SkyPoint &position, ISD::Telescope::PierSide pierSide, const dms &ha);
390 
391         /**
392          * @brief toggleVideo Turn on and off video streaming if supported by the camera.
393          * @param enabled Set to true to start video streaming, false to stop it if active.
394          */
395         void toggleVideo(bool enabled);
396 
397         /**
398          * @brief setWeatherData Updates weather data that could be used to extract focus temperature from observatory
399          * in case focus native temperature is not available.
400          */
401         //void setWeatherData(const std::vector<ISD::Weather::WeatherData> &data);
402 
403         /**
404          * @brief loadOptionsProfiles Load StellarSolver Profile
405          */
406         void loadStellarSolverProfiles();
407 
408         /**
409          * @brief getStellarSolverProfiles
410          * @return list of StellarSolver profile names
411          */
412         QStringList getStellarSolverProfiles();
413 
414 
415 
416     protected:
417         void addPlotPosition(int pos, double hfr, bool plot = true);
418 
419     private slots:
420         /**
421              * @brief toggleSubframe Process enabling and disabling subfrag.
422              * @param enable If true, subframing is enabled. If false, subframing is disabled. Even if subframing is enabled, it must be supported by the CCD driver.
423              */
424         void toggleSubframe(bool enable);
425 
426         void checkAutoStarTimeout();
427 
428         void setAbsoluteFocusTicks();
429 
430         void updateBoxSize(int value);
431 
432         void processCaptureTimeout();
433 
434         void processCaptureError(ISD::CCD::ErrorType type);
435 
436         void setCaptureComplete();
437 
438         void showFITSViewer();
439 
440         void toggleFocusingWidgetFullScreen();
441 
442         void setVideoStreamEnabled(bool enabled);
443 
444         void syncSettings();
445 
446         void calculateHFR();
447         void setCurrentHFR(double value);
448 
449     signals:
450         void newLog(const QString &text);
451         void newStatus(Ekos::FocusState state);
452         void newHFR(double hfr, int position);
453         void newFocusTemperatureDelta(double delta, double absTemperature);
454 
455         void absolutePositionChanged(int value);
456         void focusPositionAdjusted();
457 
458         void suspendGuiding();
459         void resumeGuiding();
460         void newImage(FITSView *view);
461         void newStarPixmap(QPixmap &);
462         void settingsUpdated(const QJsonObject &settings);
463 
464         // Signals for Analyze.
465         void autofocusStarting(double temperature, const QString &filter);
466         void autofocusComplete(const QString &filter, const QString &points);
467         void autofocusAborted(const QString &filter, const QString &points);
468 
469         // HFR V curve plot events
470         /**
471          * @brief initialize the HFR V plot
472          * @param showPosition show focuser position (true) or count focus iterations (false)
473          */
474         void initHFRPlot(bool showPosition);
475 
476         /**
477           * @brief new HFR plot position
478           * @param pos focuser position
479           * @param hfr measured star HFR value
480           * @param pulseDuration Pulse duration in ms for relative focusers that only support timers,
481           *        or the number of ticks in a relative or absolute focuser
482           * */
483         void newHFRPlotPosition(double pos, double hfr, int pulseDuration, bool plot = true);
484 
485         /**
486          * @brief draw the approximating polynomial into the HFR V-graph
487          * @param poly pointer to the polynomial approximation
488          * @param isVShape has the solution a V shape?
489          * @param activate make the graph visible?
490          */
491         void drawPolynomial(PolynomialFit *poly, bool isVShape, bool activate, bool plot = true);
492 
493         /**
494          * @brief Focus solution with minimal HFR found
495          * @param solutionPosition focuser position
496          * @param solutionValue HFR value
497          */
498         void minimumFound(double solutionPosition, double solutionValue, bool plot = true);
499 
500         /**
501          * @brief redraw the entire HFR plot
502          * @param poly pointer to the polynomial approximation
503          * @param solutionPosition solution focuser position
504          * @param solutionValue solution HFR value
505          */
506         void redrawHFRPlot(PolynomialFit *poly, double solutionPosition, double solutionValue);
507 
508         /**
509          * @brief draw a title on the focus plot
510          * @param title the title
511          */
512         void setTitle(const QString &title, bool plot = true);
513 
514     private:
515 
516         QList<SSolver::Parameters> m_StellarSolverProfiles;
517         QString savedOptionsProfiles;
518         StellarSolverProfileEditor *optionsProfileEditor { nullptr };
519 
520         ////////////////////////////////////////////////////////////////////
521         /// Connections
522         ////////////////////////////////////////////////////////////////////
523         void initConnections();
524 
525         ////////////////////////////////////////////////////////////////////
526         /// Settings
527         ////////////////////////////////////////////////////////////////////
528 
529         /**
530          * @brief initSettings Connect settings to slots to update the value when changed
531          */
532         void initSettingsConnections();
533         /**
534          * @brief loadSettings Load setting from Options and set them accordingly.
535          */
536         void loadSettings();
537 
538         ////////////////////////////////////////////////////////////////////
539         /// HFR Plot
540         ////////////////////////////////////////////////////////////////////
541         void initPlots();
542 
543         ////////////////////////////////////////////////////////////////////
544         /// Positions
545         ////////////////////////////////////////////////////////////////////
546         void getAbsFocusPosition();
547         bool autoFocusChecks();
548         void autoFocusAbs();
549         void autoFocusLinear();
550         void autoFocusRel();
551 
552         // Linear does plotting differently from the rest.
553         void plotLinearFocus();
554 
555         /** @brief Helper function determining whether the focuser behaves like a position
556          *         based one (vs. a timer based)
557          */
isPositionBased()558         bool isPositionBased()
559         {
560             return (canAbsMove || canRelMove || (focusAlgorithm == FOCUS_LINEAR));
561         }
562         void resetButtons();
563         void stop(FocusState completionState = FOCUS_ABORTED);
564 
565         void initView();
566 
567         /**
568          * @brief prepareCapture Set common settings for capture for focus module
569          * @param targetChip target Chip
570          */
571         void prepareCapture(ISD::CCDChip *targetChip);
572         ////////////////////////////////////////////////////////////////////
573         /// HFR
574         ////////////////////////////////////////////////////////////////////
575         void setHFRComplete();
576 
577         // Sets the algorithm and enables/disables various UI inputs.
578         void setFocusAlgorithm(FocusAlgorithm algorithm);
579 
580         // Move the focuser in (negative) or out (positive amount).
581         bool changeFocus(int amount);
582 
583         // Start up capture, or occasionally move focuser again, after current focus-move accomplished.
584         void autoFocusProcessPositionChange(IPState state);
585 
586         // For the Linear algorithm, which always scans in (from higher position to lower position)
587         // if we notice the new position is higher than the current position (that is, it is the start
588         // of a new scan), we adjust the new position to be several steps further out than requested
589         // and set focuserAdditionalMovement to the extra motion, so that after this motion completes
590         // we will then scan back in (back to the originally requested position). This "dance" is done
591         // to reduce backlash on such movement changes and so that we've always focused in before capture.
592         int adjustLinearPosition(int position, int newPosition);
593 
594         /**
595          * @brief syncTrackingBoxPosition Sync the tracking box to the current selected star center
596          */
597         void syncTrackingBoxPosition();
598 
599         /** @internal Search for stars using the method currently configured, and return the consolidated HFR.
600          * @param image_data is the FITS frame to work with.
601          * @return the HFR of the star or field of stars in the frame, depending on the consolidation method, or -1 if it cannot be estimated.
602          */
603         void analyzeSources();
604 
605         /** @internal Add a new HFR for the current focuser position.
606          * @param newHFR is the new HFR to consider for the current focuser position.
607          * @return true if a new sample is required, else false.
608          */
609         bool appendHFR(double newHFR);
610 
611 
612         /**
613          * @brief completeAutofocusProcedure finishes off autofocus and emits a message for other modules.
614          */
615         void completeFocusProcedure(FocusState completionState, bool plot = true);
616 
617         /**
618          * @brief activities to be executed after the configured settling time
619          * @param completionState state the focuser completed with
620          * @param autoFocusUsed is autofocus running?
621          */
622         void settle(const FocusState completionState, const bool autoFocusUsed);
623 
624         //        void initializeFocuserTemperature();
625         void setLastFocusTemperature();
626         bool findTemperatureElement(ISD::GDInterface *device);
627         //        void updateTemperature(TemperatureSource source, double newTemperature);
628         //        void emitTemperatureEvents(TemperatureSource source, double newTemperature);
629 
630         bool syncControl(const QJsonObject &settings, const QString &key, QWidget * widget);
631 
632         /**
633          * @brief handleFocusMotionTimeout When focuser is command to go to a target position, we expect to receive a notification
634          * that it arrived at the desired destination. If not, we command it again.
635          */
636         void handleFocusMotionTimeout();
637 
638         /// Focuser device needed for focus operation
639         ISD::Focuser *currentFocuser { nullptr };
640         /// CCD device needed for focus operation
641         ISD::CCD *currentCCD { nullptr };
642         /// Optional device filter
643         ISD::GDInterface *currentFilter { nullptr };
644         /// Optional temperature source element
645         INumber *currentTemperatureSourceElement {nullptr};
646 
647         /// Current filter position
648         int currentFilterPosition { -1 };
649         int fallbackFilterPosition { -1 };
650         /// True if we need to change filter position and wait for result before continuing capture
651         bool filterPositionPending { false };
652         bool fallbackFilterPending { false };
653 
654         /// List of Focusers
655         QList<ISD::Focuser *> Focusers;
656         /// List of CCDs
657         QList<ISD::CCD *> CCDs;
658         /// They're generic GDInterface because they could be either ISD::CCD or ISD::Filter
659         QList<ISD::GDInterface *> Filters;
660         /// They're generic GDInterface because they could be either ISD::CCD or ISD::Filter or ISD::Weather
661         QList<ISD::GDInterface *> TemperatureSources;
662 
663         /// As the name implies
664         FocusDirection m_LastFocusDirection { FOCUS_NONE };
665         /// Keep track of the last requested steps
666         uint32_t m_LastFocusSteps {0};
667         /// What type of focusing are we doing right now?
668         FocusType focusType { FOCUS_MANUAL };
669         /// Focus HFR & Centeroid algorithms
670         StarAlgorithm focusDetection { ALGORITHM_GRADIENT };
671         /// Focus Process Algorithm
672         FocusAlgorithm focusAlgorithm { FOCUS_ITERATIVE };
673 
674         /*********************
675          * HFR Club variables
676          *********************/
677 
678         /// Current HFR value just fetched from FITS file
679         double currentHFR { 0 };
680         /// Last HFR value recorded
681         double lastHFR { 0 };
682         /// If (currentHFR > deltaHFR) we start the autofocus process.
683         double minimumRequiredHFR { -1 };
684         /// Maximum HFR recorded
685         double maxHFR { 1 };
686         /// Is HFR increasing? We're going away from the sweet spot! If HFRInc=1, we re-capture just to make sure HFR calculations are correct, if HFRInc > 1, we switch directions
687         int HFRInc { 0 };
688         /// If HFR decreasing? Well, good job. Once HFR start decreasing, we can start calculating HFR slope and estimating our next move.
689         int HFRDec { 0 };
690 
691         /****************************
692          * Absolute position focusers
693          ****************************/
694         /// Absolute focus position
695         int currentPosition { 0 };
696         /// Motion state of the absolute focuser
697         IPState currentPositionState {IPS_IDLE};
698         /// What was our position before we started the focus process?
699         int initialFocuserAbsPosition { -1 };
700         /// Pulse duration in ms for relative focusers that only support timers, or the number of ticks in a relative or absolute focuser
701         int pulseDuration { 1000 };
702         /// Does the focuser support absolute motion?
703         bool canAbsMove { false };
704         /// Does the focuser support relative motion?
705         bool canRelMove { false };
706         /// Does the focuser support timer-based motion?
707         bool canTimerMove { false };
708         /// Maximum range of motion for our lovely absolute focuser
709         double absMotionMax { 0 };
710         /// Minimum range of motion for our lovely absolute focuser
711         double absMotionMin { 0 };
712         /// How many iterations have we completed now in our absolute autofocus algorithm? We can't go forever
713         int absIterations { 0 };
714 
715         /****************************
716          * Misc. variables
717          ****************************/
718 
719         /// Are we in the process of capturing an image?
720         bool captureInProgress { false };
721         /// Are we in the process of calculating HFR?
722         bool hfrInProgress { false };
723         // Was the frame modified by us? Better keep track since we need to return it to its previous state once we are done with the focus operation.
724         //bool frameModified;
725         /// Was the modified frame subFramed?
726         bool subFramed { false };
727         /// If the autofocus process fails, let's not ruin the capture session probably taking place in the next tab. Instead, we should restart it and try again, but we keep count until we hit MAXIMUM_RESET_ITERATIONS
728         /// and then we truly give up.
729         int resetFocusIteration { 0 };
730         /// Which filter must we use once the autofocus process kicks in?
731         int lockedFilterIndex { -1 };
732         /// Keep track of what we're doing right now
733         bool inAutoFocus { false };
734         bool inFocusLoop { false };
735         //bool inSequenceFocus { false };
736         bool restartFocus { false };
737         /// Did we reverse direction?
738         bool reverseDir { false };
739         /// Did the user or the auto selection process finish selecting our focus star?
740         bool starSelected { false };
741         /// Adjust the focus position to a target value
742         bool adjustFocus { false };
743         // Target frame dimensions
744         //int fx,fy,fw,fh;
745         /// If HFR=-1 which means no stars detected, we need to decide how many times should the re-capture process take place before we give up or reverse direction.
746         int noStarCount { 0 };
747         /// Track which upload mode the CCD is set to. If set to UPLOAD_LOCAL, then we need to switch it to UPLOAD_CLIENT in order to do focusing, and then switch it back to UPLOAD_LOCAL
748         ISD::CCD::UploadMode rememberUploadMode { ISD::CCD::UPLOAD_CLIENT };
749         /// Previous binning setting
750         int activeBin { 0 };
751         /// HFR values for captured frames before averages
752         QVector<double> HFRFrames;
753         // Camera Fast Exposure
754         bool m_RememberCameraFastExposure = { false };
755         // Future Watch
756         QFutureWatcher<bool> m_StarFinderWatcher;
757 
758         /// Autofocus log file info.
759         QStringList m_LogText;
760         QFile m_FocusLogFile;
761         QString m_FocusLogFileName;
762         bool m_FocusLogEnabled { false };
763 
764         ITextVectorProperty *filterName { nullptr };
765         INumberVectorProperty *filterSlot { nullptr };
766 
767         /****************************
768          * Plot variables
769          ****************************/
770 
771         /// Plot minimum positions
772         double minPos { 1e6 };
773         /// Plot maximum positions
774         double maxPos { 0 };
775 
776         /// HFR V curve plot points
777         QVector<double> hfr_position, hfr_value;
778         bool isVShapeSolution = false;
779 
780         /// State
781         Ekos::FocusState state { Ekos::FOCUS_IDLE };
782 
783         /// FITS Scale
784         FITSScale defaultScale;
785 
786         /// CCD Chip frame settings
787         QMap<ISD::CCDChip *, QVariantMap> frameSettings;
788 
789         /// Selected star coordinates
790         QVector3D starCenter;
791 
792         // Remember last star center coordinates in case of timeout in manual select mode
793         QVector3D rememberStarCenter;
794 
795         /// Focus Frame
796         FITSView *focusView { nullptr };
797 
798         /// Star Select Timer
799         QTimer waitStarSelectTimer;
800 
801         /// FITS Viewer in case user want to display in it instead of internal view
802         QPointer<FITSViewer> fv;
803 
804         /// Track star position and HFR to know if we're detecting bogus stars due to detection algorithm false positive results
805         QVector<QVector3D> starsHFR;
806 
807         /// Relative Profile
808         FocusProfilePlot *profilePlot { nullptr };
809         QDialog *profileDialog { nullptr };
810 
811         /// Polynomial fitting.
812         std::unique_ptr<PolynomialFit> polynomialFit;
813         int polySolutionFound { 0 };
814 
815         // Capture timers
816         QTimer captureTimer;
817         QTimer captureTimeout;
818         uint8_t captureTimeoutCounter { 0 };
819         uint8_t captureFailureCounter { 0 };
820 
821         // Focus motion timer.
822         QTimer m_FocusMotionTimer;
823         uint8_t m_FocusMotionTimerCounter {0};
824 
825         // Guide Suspend
826         bool m_GuidingSuspended { false };
827 
828         // Filter Manager
829         QSharedPointer<FilterManager> filterManager;
830 
831         // Data
832         QSharedPointer<FITSData> m_ImageData;
833 
834         // Linear focuser.
835         std::unique_ptr<FocusAlgorithmInterface> linearFocuser;
836         int focuserAdditionalMovement { 0 };
837         int linearRequestedPosition { 0 };
838 
839         bool hasDeviation { false };
840 
841         //double observatoryTemperature { INVALID_VALUE };
842         double m_LastSourceAutofocusTemperature { INVALID_VALUE };
843         //TemperatureSource lastFocusTemperatureSource { NO_TEMPERATURE };
844 
845         // Mount altitude value for logging
846         double mountAlt { INVALID_VALUE };
847 
848         // Dark Processor
849         QPointer<DarkProcessor> m_DarkProcessor;
850 };
851 }
852