File indexing completed on 2024-04-28 15:09:07

0001 /*
0002     SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef ANALYZE_H
0008 #define ANALYZE_H
0009 
0010 #include <memory>
0011 #include "ekos/ekos.h"
0012 #include "ekos/mount/mount.h"
0013 #include "indi/indimount.h"
0014 #include "yaxistool.h"
0015 #include "ui_analyze.h"
0016 #include "ekos/manager/meridianflipstate.h"
0017 
0018 class FITSViewer;
0019 class OffsetDateTimeTicker;
0020 class QCustomPlot;
0021 
0022 namespace Ekos
0023 {
0024 
0025 class RmsFilter;
0026 
0027 /**
0028  *@class Analyze
0029  *@short Analysis tab for Ekos sessions.
0030  *@author Hy Murveit
0031  *@version 1.0
0032  */
0033 class Analyze : public QWidget, public Ui::Analyze
0034 {
0035         Q_OBJECT
0036 
0037     public:
0038         Analyze();
0039         ~Analyze();
0040 
0041         // Baseclass used to represent a segment of Timeline data.
0042         class Session
0043         {
0044             public:
0045                 // Start and end time in seconds since start of the log.
0046                 double start, end;
0047                 // y-offset for the timeline plot. Each line uses a different integer.
0048                 int offset;
0049                 // Variables used in temporary sessions. A temporary session
0050                 // represents a process that has started but not yet finished.
0051                 // Those are plotted "for now", but will be replaced by the
0052                 // finished line when the process completes.
0053                 // Rect is the temporary graphic on the Timeline, and
0054                 // temporaryBrush defines its look.
0055                 QCPItemRect *rect;
0056                 QBrush temporaryBrush;
0057 
0058                 Session(double s, double e, int o, QCPItemRect *r)
0059                     : start(s), end(e), offset(o), rect(r) {}
0060 
0061                 Session() : start(0), end(0), offset(0), rect(nullptr) {}
0062 
0063                 // These 2 are used to build tables for the details display.
0064                 void setupTable(const QString &name, const QString &status,
0065                                 const QDateTime &startClock, const QDateTime &endClock,
0066                                 QTableWidget *table);
0067                 void addRow(const QString &key, const QString &value);
0068 
0069                 // True if this session is temporary.
0070                 bool isTemporary() const;
0071 
0072             private:
0073                 QTableWidget *details;
0074                 QString htmlString;
0075         };
0076         // Below are subclasses of Session used to represent all the different
0077         // lines in the Timeline. Each of those hold different types of information
0078         // about the process it represents.
0079         class CaptureSession : public Session
0080         {
0081             public:
0082                 bool aborted;
0083                 QString filename;
0084                 double duration;
0085                 QString filter;
0086                 double hfr;
0087                 CaptureSession(double start_, double end_, QCPItemRect *rect,
0088                                bool aborted_, const QString &filename_,
0089                                double duration_, const QString &filter_)
0090                     : Session(start_, end_, CAPTURE_Y, rect),
0091                       aborted(aborted_), filename(filename_),
0092                       duration(duration_), filter(filter_), hfr(0) {}
0093                 CaptureSession() : Session(0, 0, CAPTURE_Y, nullptr) {}
0094         };
0095         // Guide sessions collapse some of the possible guiding states.
0096         // SimpleGuideState are those collapsed states.
0097         typedef enum
0098         {
0099             G_IDLE, G_GUIDING, G_CALIBRATING, G_SUSPENDED, G_DITHERING, G_IGNORE
0100         } SimpleGuideState;
0101         class GuideSession : public Session
0102         {
0103             public:
0104                 SimpleGuideState simpleState;
0105                 GuideSession(double start_, double end_, QCPItemRect *rect, SimpleGuideState state_)
0106                     : Session(start_, end_, GUIDE_Y, rect), simpleState(state_) {}
0107                 GuideSession() : Session(0, 0, GUIDE_Y, nullptr) {}
0108         };
0109         class AlignSession : public Session
0110         {
0111             public:
0112                 AlignState state;
0113                 AlignSession(double start_, double end_, QCPItemRect *rect, AlignState state_)
0114                     : Session(start_, end_, ALIGN_Y, rect), state(state_) {}
0115                 AlignSession() : Session(0, 0, ALIGN_Y, nullptr) {}
0116         };
0117         class MountSession : public Session
0118         {
0119             public:
0120                 ISD::Mount::Status state;
0121                 MountSession(double start_, double end_, QCPItemRect *rect, ISD::Mount::Status state_)
0122                     : Session(start_, end_, MOUNT_Y, rect), state(state_) {}
0123                 MountSession() : Session(0, 0, MOUNT_Y, nullptr) {}
0124         };
0125         class MountFlipSession : public Session
0126         {
0127             public:
0128                 MeridianFlipState::MeridianFlipMountState state;
0129                 MountFlipSession(double start_, double end_, QCPItemRect *rect, MeridianFlipState::MeridianFlipMountState state_)
0130                     : Session(start_, end_, MERIDIAN_MOUNT_FLIP_Y, rect), state(state_) {}
0131                 MountFlipSession() : Session(0, 0, MERIDIAN_MOUNT_FLIP_Y, nullptr) {}
0132         };
0133         class SchedulerJobSession : public Session
0134         {
0135             public:
0136                 SchedulerJobSession(double start_, double end_, QCPItemRect *rect,
0137                                     const QString &jobName_, const QString &reason_)
0138                     : Session(start_, end_, SCHEDULER_Y, rect), jobName(jobName_), reason(reason_) {}
0139                 SchedulerJobSession() : Session(0, 0, SCHEDULER_Y, nullptr) {}
0140                 QString jobName;
0141                 QString reason;
0142         };
0143         class FocusSession : public Session
0144         {
0145             public:
0146                 bool success;
0147                 double temperature;
0148                 QString filter;
0149 
0150                 // Standard focus parameters
0151                 QString points;
0152                 QString curve;
0153                 QString title;
0154                 QVector<double> positions; // Double to be more friendly to QCustomPlot addData.
0155                 QVector<double> hfrs;
0156 
0157                 // Adaptive focus parameters
0158                 double tempTicks, altitude, altTicks;
0159                 int prevPosError, thisPosError, totalTicks, adaptedPosition;
0160 
0161                 // false for adaptiveFocus.
0162                 bool standardSession = true;
0163 
0164                 FocusSession() : Session(0, 0, FOCUS_Y, nullptr) {}
0165                 FocusSession(double start_, double end_, QCPItemRect *rect, bool ok, double temperature_,
0166                              const QString &filter_, const QString &points_, const QString &curve_, const QString &title_);
0167                 FocusSession(double start_, double end_, QCPItemRect *rect,
0168                              const QString &filter_, double temperature_, double tempTicks_, double altitude_,
0169                              double altTicks_, int prevPosError, int thisPosError, int totalTicks_, int position_);
0170                 double focusPosition();
0171         };
0172 
0173         void clearLog();
0174         QStringList logText()
0175         {
0176             return m_LogText;
0177         }
0178         QString getLogText()
0179         {
0180             return m_LogText.join("\n");
0181         }
0182 
0183     public slots:
0184         // These slots are messages received from the different Ekos processes
0185         // used to gather data about those processes.
0186 
0187         // From Capture
0188         void captureComplete(const QVariantMap &metadata);
0189         void captureStarting(double exposureSeconds, const QString &filter);
0190         void captureAborted(double exposureSeconds);
0191 
0192         // From Guide
0193         void guideState(Ekos::GuideState status);
0194         void guideStats(double raError, double decError, int raPulse, int decPulse,
0195                         double snr, double skyBg, int numStars);
0196 
0197         // From Focus
0198         void autofocusStarting(double temperature, const QString &filter);
0199         void autofocusComplete(const QString &filter, const QString &points, const QString &curve, const QString &title);
0200         void adaptiveFocusComplete(const QString &filter, double temperature, double tempTicks,
0201                                    double altitude, double altTicks, int prevPosError, int thisPosError, int totalTicks,
0202                                    int position, bool focuserMoved);
0203         void autofocusAborted(const QString &filter, const QString &points);
0204         void newTemperature(double temperatureDelta, double temperature);
0205 
0206         // From Align
0207         void alignState(Ekos::AlignState state);
0208 
0209         // From Mount
0210         void mountState(ISD::Mount::Status status);
0211         void mountCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &haValue);
0212         void mountFlipStatus(Ekos::MeridianFlipState::MeridianFlipMountState status);
0213 
0214         void schedulerJobStarted(const QString &jobName);
0215         void schedulerJobEnded(const QString &jobName, const QString &endReason);
0216         void newTargetDistance(double targetDistance);
0217 
0218         // From YAxisTool
0219         void userChangedYAxis(QObject *key, const YAxisInfo &axisInfo);
0220         void userSetLeftAxis(QCPAxis *axis);
0221         void userSetAxisColor(QObject *key, const YAxisInfo &axisInfo, const QColor &color);
0222 
0223         void yAxisRangeChanged(const QCPRange &newRange);
0224 
0225         void appendLogText(const QString &);
0226 
0227     private slots:
0228 
0229     signals:
0230         void newLog(const QString &text);
0231 
0232     private:
0233 
0234         // The file-reading, processInputLine(), and signal-slot codepaths share the methods below
0235         // to process their messages. Time is the offset in seconds from the start of the log.
0236         // BatchMode is true in the file reading path. It means don't call replot() as there may be
0237         // many more messages to come. The rest of the args are specific to the message type.
0238         void processCaptureStarting(double time, double exposureSeconds, const QString &filter);
0239         void processCaptureComplete(double time, const QString &filename, double exposureSeconds, const QString &filter,
0240                                     double hfr, int numStars, int median, double eccentricity, bool batchMode = false);
0241         void processCaptureAborted(double time, double exposureSeconds, bool batchMode = false);
0242         void processAutofocusStarting(double time, double temperature, const QString &filter);
0243         void processAutofocusComplete(double time, const QString &filter, const QString &points, const QString &curve,
0244                                       const QString &title, bool batchMode = false);
0245         void processAdaptiveFocusComplete(double time, const QString &filter, double temperature, double tempTicks,
0246                                           double altitude, double altTicks, int prevPosError, int thisPosError, int totalTicks,
0247                                           int position, bool focuserMoved, bool batchMode = false);
0248         void processAutofocusAborted(double time, const QString &filter, const QString &points, bool batchMode = false);
0249         void processTemperature(double time, double temperature, bool batchMode = false);
0250         void processGuideState(double time, const QString &state, bool batchMode = false);
0251         void processGuideStats(double time, double raError, double decError, int raPulse,
0252                                int decPulse, double snr, double skyBg, int numStars, bool batchMode = false);
0253         void processMountCoords(double time, double ra, double dec, double az, double alt,
0254                                 int pierSide, double ha, bool batchMode = false);
0255 
0256         void processMountState(double time, const QString &statusString, bool batchMode = false);
0257         void processAlignState(double time, const QString &statusString, bool batchMode = false);
0258         void processMountFlipState(double time, const QString &statusString, bool batchMode = false);
0259 
0260         void processSchedulerJobStarted(double time, const QString &jobName);
0261         void processSchedulerJobEnded(double time, const QString &jobName, const QString &reason, bool batchMode = false);
0262         void checkForMissingSchedulerJobEnd(double time);
0263         void processTargetDistance(double time, double targetDistance, bool batchMode = false);
0264 
0265         // Plotting primatives.
0266         void replot(bool adjustSlider = true);
0267         void zoomIn();
0268         void zoomOut();
0269         void scroll(int value);
0270         void scrollRight();
0271         void scrollLeft();
0272         void statsYZoom(double zoomAmount);
0273         void statsYZoomIn();
0274         void statsYZoomOut();
0275         // Return true if the session is visible on the plots.
0276         bool isVisible(const Session &s) const;
0277         // Shift the view so that time is at the center (keeping the current plot width).
0278         void adjustView(double time);
0279 
0280 
0281         // maxXValue keeps the largest time offset we've received so far.
0282         // It represents the extent of the plots (0 -> maxXValue).
0283         // This is called each time a message is received in case that message's
0284         // time is past the current value of maxXValue.
0285         void updateMaxX(double time);
0286 
0287         // Callbacks for when the timeline is clicked. ProcessTimelineClick
0288         // will determine which segment on which line was clicked and then
0289         // call captureSessionClicked() or focusSessionClicked, etc.
0290         void processTimelineClick(QMouseEvent *event, bool doubleClick);
0291         void captureSessionClicked(CaptureSession &c, bool doubleClick);
0292         void focusSessionClicked(FocusSession &c, bool doubleClick);
0293         void guideSessionClicked(GuideSession &c, bool doubleClick);
0294         void mountSessionClicked(MountSession &c, bool doubleClick);
0295         void alignSessionClicked(AlignSession &c, bool doubleClick);
0296         void mountFlipSessionClicked(MountFlipSession &c, bool doubleClick);
0297         void schedulerSessionClicked(SchedulerJobSession &c, bool doubleClick);
0298 
0299         // Low-level callbacks.
0300         // These two call processTimelineClick().
0301         void timelineMousePress(QMouseEvent *event);
0302         void timelineMouseDoubleClick(QMouseEvent *event);
0303         // Calls zoomIn or zoomOut.
0304         void timelineMouseWheel(QWheelEvent *event);
0305         // Sets the various displays visbile or not according to the checkboxes.
0306         void setVisibility();
0307 
0308         void processStatsClick(QMouseEvent *event, bool doubleClick);
0309         void statsMousePress(QMouseEvent *event);
0310         void statsMouseDoubleClick(QMouseEvent *event);
0311         void statsMouseMove(QMouseEvent *event);
0312         void setupKeyboardShortcuts(QWidget *plot);
0313 
0314         // (Un)highlights a segment on the timeline after one is clicked.
0315         // This indicates which segment's data is displayed in the
0316         // graphicsPlot and details table.
0317         void highlightTimelineItem(const Session &session);
0318         void unhighlightTimelineItem();
0319 
0320         // Tied to the keyboard shortcuts that go to the next or previous
0321         // items on the timeline. next==true means next, otherwise previous.
0322         void changeTimelineItem(bool next);
0323         // These are assigned to various keystrokes.
0324         void nextTimelineItem();
0325         void previousTimelineItem();
0326 
0327         // logTime() returns the number of seconds between "now" or "time" and
0328         // the start of the log. They are useful for recording signal and storing
0329         // them to file. They are not useful when reading data from files.
0330         double logTime();
0331         // Returns the number of seconds between time and the start of the log.
0332         double logTime(const QDateTime &time);
0333         // Goes back from logSeconds to human-readable clock time.
0334         QDateTime clockTime(double logSeconds);
0335 
0336         // Add a new segment to the Timeline graph.
0337         // Returns a rect item, which is only important temporary objects, who
0338         // need to erase the item when the temporary session is removed.
0339         // This memory is owned by QCustomPlot and shouldn't be freed.
0340         // This pointer is stored in Session::rect.
0341         QCPItemRect * addSession(double start, double end, double y,
0342                                  const QBrush &brush, const QBrush *stripeBrush = nullptr);
0343 
0344         // Manage temporary sessions (only used for live data--file-reading doesn't
0345         // need temporary sessions). For example, when an image capture has started
0346         // but not yet completed, a temporary session is added to the timeline to
0347         // represent the not-yet-completed capture.
0348         void addTemporarySession(Session *session, double time, double duration,
0349                                  int y_offset, const QBrush &brush);
0350         void removeTemporarySession(Session *session);
0351         void removeTemporarySessions();
0352         void adjustTemporarySession(Session *session);
0353         void adjustTemporarySessions();
0354 
0355         // Add new stats to the statsPlot.
0356         void addGuideStats(double raDrift, double decDrift, int raPulse, int decPulse,
0357                            double snr, int numStars, double skyBackground, double time);
0358         void addGuideStatsInternal(double raDrift, double decDrift, double raPulse,
0359                                    double decPulse, double snr, double numStars,
0360                                    double skyBackground, double drift, double rms, double time);
0361         void addMountCoords(double ra, double dec, double az, double alt, int pierSide,
0362                             double ha, double time);
0363         void addHFR(double hfr, int numCaptureStars, int median, double eccentricity,
0364                     const double time, double startTime);
0365         void addTemperature(double temperature, const double time);
0366         void addFocusPosition(double focusPosition, double time);
0367         void addTargetDistance(double targetDistance, const double time);
0368 
0369         // Initialize the graphs (axes, linestyle, pen, name, checkbox callbacks).
0370         // Returns the graph index.
0371         int initGraph(QCustomPlot *plot, QCPAxis *yAxis, QCPGraph::LineStyle lineStyle,
0372                       const QColor &color, const QString &name);
0373         template <typename Func>
0374         int initGraphAndCB(QCustomPlot *plot, QCPAxis *yAxis, QCPGraph::LineStyle lineStyle,
0375                            const QColor &color, const QString &name, const QString &shortName,
0376                            QCheckBox *cb, Func setCb, QLineEdit *out = nullptr);
0377 
0378         // Make graphs visible/invisible & add/delete them from the legend.
0379         void toggleGraph(int graph_id, bool show);
0380 
0381         // Initializes the main QCustomPlot windows.
0382         void initStatsPlot();
0383         void initTimelinePlot();
0384         void initGraphicsPlot();
0385         void initInputSelection();
0386 
0387         // Displays the focus positions and HFRs on the graphics plot.
0388         void displayFocusGraphics(const QVector<double> &positions, const QVector<double> &hfrs, const QString &curve,
0389                                   const QString &title, bool success);
0390         // Displays the guider ra and dec drift plot, and computes RMS errors.
0391         void displayGuideGraphics(double start, double end, double *raRMS,
0392                                   double *decRMS, double *totalRMS, int *numSamples);
0393 
0394         // Updates the stats value display boxes next to their checkboxes.
0395         void updateStatsValues();
0396         // Manages the statsPlot cursor.
0397         void setStatsCursor(double time);
0398         void removeStatsCursor();
0399         void keepCurrent(int state);
0400 
0401         // Restore checkboxs from Options.
0402         void initStatsCheckboxes();
0403 
0404         // Clears the data, resets the various plots & displays.
0405         void reset();
0406         void resetGraphicsPlot();
0407 
0408         // Resets the variables used to process the signals received.
0409         void resetCaptureState();
0410         void resetAutofocusState();
0411         void resetGuideState();
0412         void resetGuideStats();
0413         void resetAlignState();
0414         void resetMountState();
0415         void resetMountCoords();
0416         void resetMountFlipState();
0417         void resetSchedulerJob();
0418         void resetTemperature();
0419 
0420         // Read and display an input .analyze file.
0421         double readDataFromFile(const QString &filename);
0422         double processInputLine(const QString &line);
0423 
0424         // Opens a FITS file for viewing.
0425         void displayFITS(const QString &filename);
0426 
0427         // Pop up a help-message window.
0428         void helpMessage();
0429 
0430         // Write the analyze log file message.
0431         void saveMessage(const QString &type, const QString &message);
0432         // low level file writing.
0433         void startLog();
0434         void appendToLog(const QString &lines);
0435 
0436         // Used to capture double clicks on stats output QLineEdits to set y-axis limits.
0437         bool eventFilter(QObject *o, QEvent *e) override;
0438         QTimer clickTimer;
0439         YAxisInfo m_ClickTimerInfo;
0440 
0441         // Utility that adds a y-axis to the stats plot.
0442         QCPAxis *newStatsYAxis(const QString &label, double lower = YAxisInfo::LOWER_RESCALE,
0443                                double upper = YAxisInfo::UPPER_RESCALE);
0444 
0445         // Save and restore user-updated y-axis limits.
0446         QString serializeYAxes();
0447         bool restoreYAxes(const QString &encoding);
0448 
0449         // Sets the y-axis to be displayed on the left of the statsPlot.
0450         void setLeftAxis(QCPAxis *axis);
0451         void updateYAxisMap(QObject *key, const YAxisInfo &axisInfo);
0452 
0453         // The pop-up allowing users to edit y-axis lower and upper graph values.
0454         YAxisTool m_YAxisTool;
0455 
0456         // The y-axis values displayed to the left of the stat's graph.
0457         QCPAxis *activeYAxis { nullptr };
0458 
0459         void startYAxisTool(QObject *key, const YAxisInfo &info);
0460 
0461         // Map connecting QLineEdits to Y-Axes, so when a QLineEdit is double clicked,
0462         // the corresponding y-axis can be found.
0463         std::map<QObject*, YAxisInfo> yAxisMap;
0464 
0465         // The .analyze log file being written.
0466         QString logFilename { "" };
0467         QFile logFile;
0468         bool logInitialized { false };
0469 
0470         // These define the view for the timeline and stats plots.
0471         // The plots start plotStart seconds from the start of the session, and
0472         // are plotWidth seconds long. The end of the X-axis is maxXValue.
0473         double plotStart { 0.0 };
0474         double plotWidth { 10.0 };
0475         double maxXValue { 10.0 };
0476 
0477         // Data are displayed in seconds since the session started.
0478         // analyzeStartTime is when the session started, used to translate to clock time.
0479         QDateTime analyzeStartTime;
0480         QString analyzeTimeZone { "" };
0481         bool startTimeInitialized { false };
0482 
0483         // displayStartTime is similar to analyzeStartTime, but references the
0484         // start of the log being displayed (e.g. if reading from a file).
0485         // When displaying the current session it should equal analyzeStartTime.
0486         QDateTime displayStartTime;
0487 
0488         // AddGuideStats uses RmsFilter to compute RMS values of the squared
0489         // RA and DEC errors, thus calculating the RMS error.
0490         std::unique_ptr<RmsFilter> guiderRms;
0491         std::unique_ptr<RmsFilter> captureRms;
0492 
0493         // Used to keep track of the y-axis position when moving it with the mouse.
0494         double yAxisInitialPos = { 0 };
0495 
0496         // Used to display clock-time on the X-axis.
0497         QSharedPointer<OffsetDateTimeTicker> dateTicker;
0498 
0499         // The rectangle over the current selection.
0500         // Memory owned by QCustomPlot.
0501         QCPItemRect *selectionHighlight { nullptr };
0502 
0503         // FITS Viewer to display FITS images.
0504         QSharedPointer<FITSViewer> fitsViewer;
0505         // When trying to load a FITS file, if the original file path doesn't
0506         // work, Analyze tries to find the file under the alternate folder.
0507         QString alternateFolder;
0508 
0509         // The vertical line in the stats plot.
0510         QCPItemLine *statsCursor { nullptr };
0511         QCPItemLine *timelineCursor { nullptr };
0512         double statsCursorTime { -1 };
0513 
0514         // Keeps the directory from the last time the user loaded a .analyze file.
0515         QUrl dirPath;
0516 
0517         // True if Analyze is displaying data as it comes in from the other modules.
0518         // False if Analyze is displaying data read from a file.
0519         bool runtimeDisplay { true };
0520 
0521         // When a module's session is ongoing, we represent it as a "temporary session"
0522         // which will be replaced once the session is done.
0523         CaptureSession temporaryCaptureSession;
0524         FocusSession temporaryFocusSession;
0525         GuideSession temporaryGuideSession;
0526         AlignSession temporaryAlignSession;
0527         MountSession temporaryMountSession;
0528         MountFlipSession temporaryMountFlipSession;
0529         SchedulerJobSession temporarySchedulerJobSession;
0530 
0531         // Capture state-machine variables.
0532         double captureStartedTime { -1 };
0533         double previousCaptureStartedTime { 1 };
0534         double previousCaptureCompletedTime { 1 };
0535         QString captureStartedFilter { "" };
0536 
0537         // Autofocus state-machine variables.
0538         double autofocusStartedTime { -1 };
0539         QString autofocusStartedFilter { "" };
0540         double autofocusStartedTemperature { 0 };
0541 
0542         // GuideState state-machine variables.
0543         SimpleGuideState lastGuideStateStarted { G_IDLE };
0544         double guideStateStartedTime { -1 };
0545 
0546         // GuideStats state-machine variables.
0547         double lastGuideStatsTime { -1 };
0548         double lastCaptureRmsTime { -1 };
0549         int numStarsMax { 0 };
0550         double snrMax { 0 };
0551         double skyBgMax { 0 };
0552         int medianMax { 0 };
0553         int numCaptureStarsMax { 0 };
0554         double lastTemperature { -1000 };
0555 
0556         // AlignState state-machine variables.
0557         AlignState lastAlignStateReceived { ALIGN_IDLE };
0558         AlignState lastAlignStateStarted { ALIGN_IDLE };
0559         double lastAlignStateStartedTime { -1 };
0560 
0561         // MountState state-machine variables.
0562         double mountStateStartedTime { -1 };
0563         ISD::Mount::Status lastMountState { ISD::Mount::Status::MOUNT_IDLE };
0564 
0565         // Mount coords state machine variables.
0566         // Used to filter out mount Coords messages--we only process ones
0567         // where the values have changed significantly.
0568         double lastMountRa { -1 };
0569         double lastMountDec { -1 };
0570         double lastMountHa { -1 };
0571         double lastMountAz { -1 };
0572         double lastMountAlt { -1 };
0573         int lastMountPierSide { -1 };
0574 
0575         // Flip state machine variables
0576         MeridianFlipState::MeridianFlipMountState lastMountFlipStateReceived { MeridianFlipState::MOUNT_FLIP_NONE};
0577         MeridianFlipState::MeridianFlipMountState lastMountFlipStateStarted { MeridianFlipState::MOUNT_FLIP_NONE };
0578         double mountFlipStateStartedTime { -1 };
0579 
0580         // SchedulerJob state machine variables
0581         double schedulerJobStartedTime;
0582         QString schedulerJobStartedJobName;
0583 
0584         QMap<QString, QColor> schedulerJobColors;
0585         QBrush schedulerJobBrush(const QString &jobName, bool temporary);
0586 
0587         void setSelectedSession(const Session &s);
0588         void clearSelectedSession();
0589         Session m_selectedSession;
0590 
0591         // Analyze log file info.
0592         QStringList m_LogText;
0593 
0594         // Y-offsets for the timeline plot for the various modules.
0595         static constexpr int CAPTURE_Y = 1;
0596         static constexpr int FOCUS_Y = 2;
0597         static constexpr int ALIGN_Y = 3;
0598         static constexpr int GUIDE_Y = 4;
0599         static constexpr int MERIDIAN_MOUNT_FLIP_Y = 5;
0600         static constexpr int MOUNT_Y = 6;
0601         static constexpr int SCHEDULER_Y = 7;
0602         static constexpr int LAST_Y = 8;
0603 };
0604 }
0605 
0606 
0607 #endif // Analyze