File indexing completed on 2024-04-28 03:43:19

0001 /*  Ekos state machine for a single capture job sequence.
0002     SPDX-FileCopyrightText: Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "indi/indicommon.h"
0010 #include "skypoint.h"
0011 #include "capturemodulestate.h"
0012 #include "ekos/auxiliary/filtermanager.h"
0013 #include "fitsviewer/fitscommon.h"
0014 
0015 #include <QWidget>
0016 #include <QVector>
0017 #include <QMap>
0018 
0019 namespace Ekos
0020 {
0021 /* Status of a single {@see SequenceJob}. */
0022 typedef enum
0023 {
0024     JOB_IDLE,     /* Initial state, nothing happens. */
0025     JOB_BUSY,     /* Job is running.                 */
0026     JOB_ERROR,    /* Error occured, unresolved.      */
0027     JOB_ABORTED,  /* Job stopped before completion.  */
0028     JOB_DONE      /* Job completed.                  */
0029 } JOBStatus;
0030 
0031 class SequenceJobState: public QObject
0032 {
0033         Q_OBJECT
0034 
0035         friend class SequenceJob;
0036         friend class CaptureDeviceAdaptor;
0037         // Fixme: too many friends
0038         friend class Capture;
0039 
0040     public:
0041         typedef enum
0042         {
0043             CAL_NONE,                    /* initial state */
0044             CAL_DUSTCAP_PARKING,         /* unused        */
0045             CAL_DUSTCAP_PARKED,          /* unused        */
0046             CAL_LIGHTBOX_ON,             /* unused        */
0047             CAL_SLEWING,                 /* unused        */
0048             CAL_SLEWING_COMPLETE,        /* unused        */
0049             CAL_MOUNT_PARKING,           /* unused        */
0050             CAL_MOUNT_PARKED,            /* unused        */
0051             CAL_DOME_PARKING,            /* unused        */
0052             CAL_DOME_PARKED,             /* unused        */
0053             CAL_PRECAPTURE_COMPLETE,     /* unused        */
0054             CAL_CALIBRATION,
0055             CAL_CALIBRATION_COMPLETE,
0056             CAL_CAPTURING
0057         } CalibrationStage;
0058 
0059         typedef enum
0060         {
0061             PREP_NONE,           /* preparation has not been executed                               */
0062             PREP_BUSY,           /* preparation started                                             */
0063             PREP_COMPLETED,      /* preparation completed                                           */
0064             PREP_INIT_CAPTURE    /* initialize capturing (last step before device capturing starts) */
0065         } PreparationState;
0066 
0067         typedef enum
0068         {
0069             CAL_CHECK_TASK,
0070             CAL_CHECK_CONFIRMATION,
0071         } CalibrationCheckType;
0072 
0073         typedef enum
0074         {
0075             WP_NONE,           /* slewing to wall position not started */
0076             WP_SLEWING,        /* slewing to wall position started     */
0077             WP_SLEW_COMPLETED, /* wall position reached                */
0078             WP_TRACKING_BUSY,  /* turning tracking off running         */
0079             WP_TRACKING_OFF    /* wall position reached, tracking off  */
0080         } ScopeWallPositionStatus;
0081 
0082         typedef enum      /* synching the focuser to the focus position */
0083         {
0084             FS_NONE,      /* not started                                */
0085             FS_BUSY,      /* running                                    */
0086             FS_COMPLETED  /* completed                                  */
0087         } FlatSyncStatus;
0088 
0089         SequenceJobState(const QSharedPointer<CaptureModuleState> &sharedState);
0090 
0091         /**
0092          * @brief Initialize the state machine.
0093          * @param frameType frame type for which the preparation should be done
0094          */
0095         void setFrameType(CCDFrameType frameType);
0096         CCDFrameType getFrameType()
0097         {
0098             return m_frameType;
0099         }
0100 
0101         /**
0102          * @brief initPreparation Reset all states properly for capture preparation
0103          * @param isPreview flag if the captures are in the preview mode
0104          */
0105         void initPreparation(bool isPreview);
0106 
0107         /**
0108          * @brief Trigger all peparation actions before a capture may be started.
0109          * @param enforceCCDTemp flag if the CCD temperature should be set to the target value.
0110          * @param isPreview flag if the captures are in the preview mode
0111          */
0112         void prepareLightFrameCapture(bool enforceCCDTemp, bool isPreview);
0113 
0114         /**
0115          * @brief Initiate tasks required so that capturing of flats may start.
0116          * @param enforceCCDTemp flag if the CCD temperature should be set to the target value.
0117          * @param isPreview flag if the captures are in the preview mode
0118          */
0119         void prepareFlatFrameCapture(bool enforceCCDTemp, bool isPreview);
0120 
0121         /**
0122          * @brief Initiate tasks required so that capturing of darks may start.
0123          * @param enforceCCDTemp flag if the CCD temperature should be set to the target value.
0124          * @param isPreview flag if the captures are in the preview mode
0125          */
0126         void prepareDarkFrameCapture(bool enforceCCDTemp, bool isPreview);
0127 
0128         /**
0129          * @brief Initiate tasks required so that capturing of bias may start.
0130          * @param enforceCCDTemp flag if the CCD temperature should be set to the target value.
0131          * @param isPreview flag if the captures are in the preview mode
0132          */
0133         void prepareBiasFrameCapture(bool enforceCCDTemp, bool isPreview);
0134 
0135         /**
0136          * @brief initCapture Initialize capturing (currently only setting the
0137          * target filter).
0138          * @param frameType frame type to be captured
0139          * @param isPreview is the captured frame only a preview?
0140          * @param isAutofocusReady is an autofocus possible?
0141          * @return true if the initialization is already completed
0142          */
0143         bool initCapture(CCDFrameType frameType, bool isPreview, bool isAutofocusReady, FITSMode mode);
0144 
0145         /**
0146          * @brief The current capture sequence job status
0147          */
0148         JOBStatus getStatus()
0149         {
0150             return m_status;
0151         }
0152 
0153         /**
0154          * @brief Preparation state of the sequence job
0155          */
0156         PreparationState getPreparationState() const;
0157 
0158         /**
0159          * @brief Reset the status to a dedicated value.
0160          * @param status new status, by default {@see JOB_IDLE}
0161          */
0162         void reset(JOBStatus status = JOB_IDLE)
0163         {
0164             m_status = status;
0165         }
0166 
0167     public slots:
0168         //////////////////////////////////////////////////////////////////////
0169         // Slots for device events that change the state.
0170         //////////////////////////////////////////////////////////////////////
0171 
0172         /**
0173          * @brief setFilterStatus Update the current filter state
0174          */
0175         void setFilterStatus(FilterState filterState);
0176 
0177         /**
0178          * @brief Update the currently active filter ID
0179          */
0180         void setCurrentFilterID(int value);
0181 
0182         /**
0183          * @brief Update the current CCD temperature
0184          */
0185         void setCurrentCCDTemperature(double value);
0186         /**
0187          * @brief Set the target CCD temperature
0188          */
0189         void setTargetCCDTemperature(double value)
0190         {
0191             targetTemperature = value;
0192         }
0193 
0194         /**
0195          * @brief setFocusStatus Evaluate the current focus state
0196          */
0197         void setFocusStatus(FocusState state);
0198 
0199         /**
0200          * @brief Update the current rotator position (calculated from the rotator angle)
0201          */
0202         void setCurrentRotatorPositionAngle(double currentRotation, IPState state);
0203         /**
0204          * @brief Set the target rotation angle
0205          */
0206         void setTargetRotatorAngle(double value)
0207         {
0208             targetPositionAngle = value;
0209         }
0210 
0211         /**
0212          * @brief Cover for the scope with a flats light source or dark cover done
0213          */
0214         void updateManualScopeCover(bool closed, bool success, bool light);
0215         /**
0216          * @brief Light box light is on.
0217          */
0218         void lightBoxLight(bool on);
0219         /**
0220          * @brief dust cap status change
0221          */
0222         void dustCapStateChanged(ISD::DustCap::Status status);
0223         /**
0224          * @brief telescope status change
0225          */
0226         void scopeStatusChanged(ISD::Mount::Status status);
0227         /**
0228          * @brief telescope status change
0229          */
0230         void scopeParkStatusChanged(ISD::ParkStatus status);
0231         /**
0232          * @brief dome status change
0233          */
0234         void domeStatusChanged(ISD::Dome::Status status);
0235         /**
0236          * @brief flat sync focus status change
0237          */
0238         void flatSyncFocusChanged(bool completed);
0239         /**
0240          * @brief CCD has a shutter
0241          */
0242         void hasShutter(bool present);
0243 
0244     signals:
0245         // communicate that a preparation step needs to be executed
0246         void prepareState(Ekos::CaptureState state);
0247         // ask for the current device state
0248         void readCurrentState(Ekos::CaptureState state);
0249         // Capture preparation complete(d)
0250         void prepareComplete(bool success = true);
0251         // Capture initialization complete(d)
0252         void initCaptureComplete(FITSMode mode);
0253         // change the rotator angle
0254         void setRotatorAngle(double rawAngle);
0255         // ask for the current filter position
0256         void readFilterPosition();
0257         // Change the filter to the given position and the filter change policy
0258         void changeFilterPosition(int targetFilterPosition, FilterManager::FilterPolicy policy);
0259         // set the CCD target temperature
0260         void setCCDTemperature(double temp);
0261         // set CCD to preview mode
0262         void setCCDBatchMode(bool m_preview);
0263         // ask for manually covering the scope with a flat light source or dark cover
0264         void askManualScopeCover(QString question, QString title, bool light);
0265         // ask for manually opening the scope cover
0266         void askManualScopeOpen(bool light);
0267         // turn light on in the light box
0268         void setLightBoxLight(bool on);
0269         // turn light on in the dust cap
0270         void setDustCapLight(bool on);
0271         // park the dust cap
0272         void parkDustCap(bool park);
0273         // slew the telescope to a target
0274         void slewTelescope(SkyPoint &target);
0275         // turn scope tracking on and off
0276         void setScopeTracking(bool on);
0277         // park / unpark telescope
0278         void setScopeParked(bool parked);
0279         // park / unpark dome
0280         void setDomeParked(bool parked);
0281         // check if the focuser needs to be moved to the focus position.
0282         void flatSyncFocus(int targetFilterID);
0283         // ask whether the CCD has a shutter
0284         void queryHasShutter();
0285         // abort capturing
0286         void abortCapture();
0287         // log entry
0288         void newLog(QString);
0289 
0290     private:
0291         // current status of the capture sequence job
0292         JOBStatus m_status { JOB_IDLE };
0293 
0294         // Is the capture preparation ready?
0295         PreparationState m_PreparationState { PREP_NONE };
0296 
0297         // ////////////////////////////////////////////////////////////////////
0298         // capture preparation relevant flags
0299         // ////////////////////////////////////////////////////////////////////
0300 
0301         // Mapping PrepareActions --> bool marks whether a certain action is completed (=true) or not (=false)
0302         QMap<CaptureModuleState::PrepareActions, bool> prepareActions;
0303         // This is a workaround for a specific INDI behaviour. If a INDI property is set, it sends this value
0304         // back to the clients. If the value does not immediately change to the target value (like e.g. the CCD
0305         // temperature), the first value after setting a property must be ignored.
0306         QMap<CaptureModuleState::PrepareActions, bool> ignoreNextValue;
0307 
0308         // capture frame type (light, flat, dark, bias)
0309         CCDFrameType m_frameType { FRAME_NONE };
0310         // do we shoot a preview?
0311         bool m_isPreview { false };
0312         // should a certain temperature should be enforced?
0313         bool m_enforceTemperature { false };
0314         // flag if auto focus has been completed for the selected filter
0315         bool autoFocusReady;
0316         // Capturing mode, necessary for the display in the FITS viewer
0317         FITSMode m_fitsMode;
0318         // ////////////////////////////////////////////////////////////////////
0319         // flat preparation attributes
0320         // ////////////////////////////////////////////////////////////////////
0321         // status of the focuser synchronisation
0322         FlatSyncStatus flatSyncStatus { FS_NONE };
0323         // light source for flat capturing
0324         uint32_t m_CalibrationPreAction { ACTION_NONE };
0325         // wall coordinates for capturing flats with the wall as light source
0326         SkyPoint wallCoord;
0327         // telescope status for flats using the wall position
0328         ScopeWallPositionStatus wpScopeStatus { WP_NONE };
0329 
0330         // ////////////////////////////////////////////////////////////////////
0331         // capture preparation state
0332         // ////////////////////////////////////////////////////////////////////
0333         /**
0334          * @brief Check if all actions are ready and emit {@see prepareComplete()} if all are ready.
0335          */
0336         void checkAllActionsReady();
0337 
0338         /**
0339          * @brief Check if all preparation actions are completed
0340          * @return true if all preparation actions are completed
0341          */
0342         bool areActionsReady();
0343 
0344         /**
0345          * @brief Clear all actions required for preparation
0346          */
0347         void setAllActionsReady();
0348 
0349         /**
0350          * @brief Prepare CCD temperature checks
0351          */
0352         void prepareTemperatureCheck(bool enforceCCDTemp);
0353 
0354         /**
0355          * @brief prepareRotatorCheck Check if the rotator is at the expected
0356          *        target angle.
0357          */
0358         void prepareRotatorCheck();
0359 
0360         /**
0361          * @brief prepareTargetFilter Initiate changing the filter to the target position
0362          *        {@see #targetFilterID}
0363          * @param frameType frame type to be captured
0364          * @param isPreview is the captured frame only a preview?
0365          */
0366         void prepareTargetFilter(CCDFrameType frameType, bool isPreview);
0367 
0368         /**
0369          * @brief Before capturing light frames check, if the scope cover is open.
0370          * @return IPS_OK if cover closed, IPS_BUSY if not and IPS_ALERT if the
0371          *         process should be aborted.
0372          */
0373         IPState checkLightFrameScopeCoverOpen();
0374 
0375         /**
0376          * @brief Check if a certain action has already been initialized
0377          */
0378         bool isInitialized(CaptureModuleState::PrepareActions action);
0379         /**
0380          * @brief Set a certain action as initialized
0381          */
0382         void setInitialized(CaptureModuleState::PrepareActions action, bool init);
0383 
0384         // ////////////////////////////////////////////////////////////////////
0385         // flats preparation state
0386         // ////////////////////////////////////////////////////////////////////
0387 
0388         /**
0389          * @brief checkCalibrationPreActionsReady Check if we completed all the required pre-calibration actions
0390          * @return IPS_OK if completed, IPS_BUSY if in progress, and IPS_ALERT if trouble.
0391          */
0392         IPState checkCalibrationPreActionsReady();
0393 
0394         /**
0395          * @brief Check if the cover and light for flats is ready
0396          * @return IPS_OK if cover closed, IPS_BUSY if not and IPS_ALERT if the
0397          *         process should be aborted.
0398          */
0399         IPState checkFlatsCoverReady();
0400 
0401         /**
0402          * @brief Check if the selected dark covers is ready.
0403          * @return IPS_OK if cover closed, IPS_BUSY if not and IPS_ALERT if the
0404          *         process should be aborted.
0405          */
0406         IPState checkDarksCoverReady();
0407 
0408         /**
0409           * @brief Ask the user to place a flat screen onto the telescope if a light source is required.
0410           * @return IPS_OK if cover closed, IPS_BUSY if not and IPS_ALERT if the
0411           *         process should be aborted.
0412           */
0413         IPState checkManualCoverReady(bool lightSourceRequired);
0414 
0415         /**
0416          * @brief Check if the telescope dust cap is ready for capturing flats or darks.
0417          * @return IPS_OK if cap is closed, IPS_BUSY if not and IPS_ALERT if the
0418          *         process should be aborted.
0419          */
0420         IPState checkDustCapReady(CCDFrameType frameType);
0421 
0422         /**
0423          * @brief Check if the telescope is pointing to the desired position on the wall
0424          *        for capturing flats.
0425          * @return IPS_OK if cap is closed, IPS_BUSY if not and IPS_ALERT if the
0426          *         process should be aborted.
0427          */
0428         IPState checkWallPositionReady(CCDFrameType frametype);
0429 
0430         /**
0431          * @brief Check mount parking before capturing flats.
0432          * @return IPS_OK if cap is closed, IPS_BUSY if not and IPS_ALERT if the
0433          *         process should be aborted.
0434          */
0435         IPState checkPreMountParkReady();
0436 
0437         /**
0438          * @brief Check dome parking before capturing flats.
0439          * @return IPS_OK if cap is closed, IPS_BUSY if not and IPS_ALERT if the
0440          *         process should be aborted.
0441          */
0442         IPState checkPreDomeParkReady();
0443 
0444         /**
0445          * @brief Check if the focuser needs to be moved to the focus position.
0446          * @return IPS_OK if cover closed, IPS_BUSY if not and IPS_ALERT if the
0447           *        process should be aborted.
0448          */
0449         IPState checkFlatSyncFocus();
0450 
0451         // ////////////////////////////////////////////////////////////////////
0452         // darks preparation state
0453         // ////////////////////////////////////////////////////////////////////
0454 
0455         /**
0456          * @brief Check if the CCD has a shutter or not.
0457          * @return IPS_OK if ready, IPS_BUSY if running and IPS_ALERT if the
0458          *         process should be aborted.
0459          */
0460         IPState checkHasShutter();
0461 
0462         // ////////////////////////////////////////////////////////////////////
0463         // Attributes shared across all sequence jobs
0464         // ////////////////////////////////////////////////////////////////////
0465         QSharedPointer<CaptureModuleState>  m_CaptureModuleState;
0466 
0467         // ////////////////////////////////////////////////////////////////////
0468         // sequence job specific states
0469         // ////////////////////////////////////////////////////////////////////
0470         // target filter ID
0471         int targetFilterID { Ekos::INVALID_VALUE };
0472         FilterManager::FilterPolicy m_filterPolicy { FilterManager::ALL_POLICIES };
0473         // target temperature
0474         double targetTemperature { Ekos::INVALID_VALUE };
0475         // target rotation in absolute ticks, NOT angle
0476         double targetPositionAngle { Ekos::INVALID_VALUE };
0477         // calibration state
0478         CalibrationStage calibrationStage { CAL_NONE };
0479         // query state for (un)covering the scope
0480         CalibrationCheckType coverQueryState { CAL_CHECK_TASK };
0481 };
0482 
0483 }; // namespace