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

0001 /*
0002     SPDX-FileCopyrightText: 2023 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "capturemodulestate.h"
0010 #include "sequencejob.h"
0011 
0012 #include "indiapi.h"
0013 
0014 #include <QObject>
0015 
0016 namespace Ekos
0017 {
0018 
0019 class CaptureDeviceAdaptor;
0020 class DarkProcessor;
0021 
0022 /**
0023  * @class CaptureProcess
0024  * @brief The CaptureProcess class holds the entire business logic to control capturing execution.
0025  *
0026  * Capture Execution
0027  * =================
0028  * Executing the sequence jobs is a complex process (explained here for light frames) and works roughly
0029  * as follows and starts by calling {@see Capture#start()} either from the scheduler, by DBUS or by
0030  * pressing the start button:
0031  * 1. Select the next sequence job to be executed ({@see startNextPendingJob()}. If the list of jobs is
0032  * empty, an {@see #addJob()} event is sent. The corresponding callback function
0033  * {@see #jobAdded(SequenceJob*)} is triggered. Now we know that at least one sequence job is
0034  * to be executed.
0035  * 2. Prepare the selected job
0036  *    - update the counters of captured frames ({@see #prepareJob(SequenceJob *)})
0037  *    - execute the pre job script, if existing ({@see #prepareActiveJobStage1()})
0038  *    - set temperature, rotator angle and wait (if required) for the initial guiding
0039  *      deviation being below the configured threshold ({@see #prepareJobExecution()})
0040  *      and wait until these parameters are OK.
0041  * 3. Prepare capturing a single frame
0042  *    We still need to do some preparation steps before capturing starts.
0043  *    - {@see #executeJob()} is the starting point, which simply sets the capture state
0044  *      to "busy" and sets the FITS attributes to the camera
0045  *    - Check all tasks that need to be completed before capturing may start (post meridian
0046  *      flip actions, guiding deviation, dithering, re-focusing, ..., see {@see #checkLightFramePendingTasks()}
0047  * 4. Capture a single frame
0048  *    - Initiate capturing (set diverse settings of {@see #activeCamera()} (see {@see #captureImage})
0049  *    - hand over the control of capturing to the sequence job ({@see SequenceJob#startCapturing()})
0050  *    - Select the correct filter (@see SequenceJobState#prepareTargetFilter()}
0051  *    - As soon as the correct filter is set, the sequence job state will send the event
0052  *      {@see SequenceJobState::initCaptureComplete()}, which will finally call trigger
0053  *      {@see SequenceJob::capture()}
0054  * 5. Listen upon capturing progress
0055  *    - listen to the event {@see ISD::Camera::newExposureValue}, update the remaining
0056  *      time and wait until the INDI state changes from busy to OK
0057  *    - start the download timer to measure download times
0058  *    - listen to the event {@see ISD::Camera::newImage} and start processing the FITS image
0059  *      as soon as it has been recieved
0060  * 6. Process received image
0061  *    - update the FITS image meta data {@see #updateImageMetadataAction()}
0062  *    - update time calculation and counters and execute post capture script ({@see imageCapturingCompleted()})
0063  * 7. Check how to continue the sequence execution ({@see resumeSequence()})
0064  *    - if the current sequence job isn't completed,
0065  *      - execute the post capture script
0066  *      - start next exposure (similar to 3.) ({@see startNextExposure()})
0067  *        TODO: check why we need this separate method and cannot use {@see updatePreCaptureCalibrationStatus()}
0068  *    - if the current sequence is complete,
0069  *      - execute the post sequence script ({@see processJobCompletion1()})
0070  *      - stop the current sequence job ({@see processJobCompletion2()})
0071  *      - recall {@see resumeSequence()}, which calls {@see startNextJob()}
0072  *      - if there is another job to be executed, jump to 2., otherwise Capture is completed
0073  *        by sending a stopCapture(CAPTURE_COMPLETE) event
0074  *
0075  *  Autofocus
0076  *  =========
0077  *  Capture has three ways that trigger autofocus during a capturing sequence: HFR based, temperature drift based,
0078  *  timer based and post meridian flip based. Each time the capture execution reaches the preparation of caturing
0079  *  a single frame (3. above) (see {@see CaptureModuleState#startFocusIfRequired()} and
0080  *  {@see RefocusState#checkFocusRequired()}).
0081  *
0082  *  Meridian Flip
0083  *  =============
0084  *  The meridian flip itself is executed by the Mount module and is controlled by
0085  *  (see {@see MeridianFlipState}). Nevertheless, the Capture module plays an
0086  *  important rule in the meridian flip:
0087  *  1. Accept a flip to be executed
0088  *     As soon as a meridian flip has been planned (informed through
0089  *     {@see #updateMFMountState(MeridianFlipState::MeridianFlipMountState)}, the meridian flip state is set
0090  *     to MF_REQUESTED.
0091  *     - If capturing is running the state remains in this state until the frame has been captured. As soon as
0092  *       the capturing state changes to id, suspended or aborted (see {@see CaptureModuleState::setCaptureState(CaptureState)}),
0093  *       the meridian flip state is set to MF_ACCEPTED (see {@see MeridianFlipState::updateMeridianFlipStage(const MFStage)}).
0094  *       This is triggered from {@see #checkLightFramePendingTasks()}, i.e. this function is looping once per second until
0095  *       the meridian flip has been completed.
0096  *     - If capturing is not running, the latter happens immediately.
0097  *     Now the meridian flip is started.
0098  *  2. Post MF actions
0099  *     As soon as the meridian flip has been completed (and the Capture module is waiting for it), the Capture module
0100  *     takes over the control and executes all necessary tasks: aligning, re-focusing, guiding, etc. This happens all through
0101  *     {@see #checkLightFramePendingTasks()}. As soon as all has recovered, capturing continues.
0102  */
0103 class CaptureProcess : public QObject
0104 {
0105     Q_OBJECT
0106 
0107 public:
0108     typedef enum
0109     {
0110         ADU_LEAST_SQUARES,
0111         ADU_POLYNOMIAL
0112     } ADUAlgorithm;
0113 
0114     CaptureProcess(QSharedPointer<CaptureModuleState> newModuleState, QSharedPointer<CaptureDeviceAdaptor> newDeviceAdaptor);
0115 
0116     // ////////////////////////////////////////////////////////////////////
0117     // handle connectivity to modules and devices
0118     // ////////////////////////////////////////////////////////////////////
0119     /**
0120      * @brief setMount Connect to the given mount device (and deconnect the old one
0121      * if existing)
0122      * @param device pointer to Mount device.
0123      * @return True if added successfully, false if duplicate or failed to add.
0124     */
0125     bool setMount(ISD::Mount *device);
0126 
0127     /**
0128      * @brief setRotator Connect to the given rotator device (and deconnect
0129      *  the old one if existing)
0130      * @param device pointer to rotator INDI device
0131      * @return True if added successfully, false if duplicate or failed to add.
0132      */
0133     bool setRotator(ISD::Rotator * device);
0134 
0135     /**
0136      * @brief setDustCap Connect to the given dust cap device (and deconnect
0137      * the old one if existing)
0138      * @param device pointer to dust cap INDI device
0139      * @return True if added successfully, false if duplicate or failed to add.
0140      */
0141     bool setDustCap(ISD::DustCap *device);
0142 
0143     /**
0144      * @brief setLightBox Connect to the given dust cap device (and deconnect
0145      * the old one if existing)
0146      * @param device pointer to light box INDI device.
0147      * @return True if added successfully, false if duplicate or failed to add.
0148     */
0149     bool setLightBox(ISD::LightBox *device);
0150 
0151     /**
0152      * @brief setDome Connect to the given dome device
0153      * @param device point to dome INDI device
0154      * @return True if added successfully, false if duplicate or failed to add.
0155      */
0156     bool setDome(ISD::Dome *device);
0157 
0158     /**
0159      * @brief setCamera Connect to the given camera device (and deconnect
0160      * the old one if existing)
0161      * @param device pointer to camera INDI device.
0162      * @return True if added successfully, false if duplicate or failed to add.
0163     */
0164     bool setCamera(ISD::Camera *device);
0165 
0166     /**
0167      * @brief setScope Set active train telescope name
0168      * @param name Name of scope
0169      */
0170     void setScope(const QString &name)
0171     {
0172         m_Scope = name;
0173     }
0174 
0175     /**
0176       * @brief Connect or disconnect the camera device
0177       * @param connection flag if connect (=true) or disconnect (=false)
0178       */
0179     void setCamera(bool connection);
0180 
0181     /**
0182      * @brief setFilterWheel Connect to the given filter wheel device (and deconnect
0183      * the old one if existing)
0184      * @param device pointer to filter wheel INDI device.
0185      * @return True if added successfully, false if duplicate or failed to add.
0186     */
0187     bool setFilterWheel(ISD::FilterWheel *device);
0188 
0189     /**
0190      * Toggle video streaming if supported by the device.
0191      * @param enabled Set to true to start video streaming, false to stop it if active.
0192      */
0193     void toggleVideo(bool enabled);
0194 
0195     // ////////////////////////////////////////////////////////////////////
0196     // capturing process steps
0197     // ////////////////////////////////////////////////////////////////////
0198 
0199     /**
0200      * @brief toggleSequence Toggle sequence state depending on its current state.
0201      * 1. If paused, then resume sequence.
0202      * 2. If idle or completed, then start sequence.
0203      * 3. Otherwise, abort current sequence.
0204      */
0205     void toggleSequence();
0206 
0207     /**
0208      * @brief startNextPendingJob Start the next pending job.
0209      *
0210      * Find the next job to be executed:
0211      * 1. If there are already some jobs defined, {@see #findNextPendingJob()} is
0212      *    used to find the next job to be executed.
0213      * 2. If the list is empty, the current settings are used to create a job instantly,
0214      *    which subsequently will be executed.
0215      */
0216     void startNextPendingJob();
0217 
0218     /**
0219      * @brief Counterpart to the event {@see#createJob(SequenceJob::SequenceJobType)}
0220      * where the event receiver reports whether one has been added successfully
0221      * and of which type it was.
0222      */
0223     void jobCreated(SequenceJob *newJob);
0224 
0225     /**
0226      * @brief capturePreview Capture a preview (single or looping ones)
0227      */
0228     void capturePreview(bool loop = false);
0229 
0230     /**
0231      * @brief stopCapturing Stopping the entire capturing state
0232      * (envelope for aborting, suspending, pausing, ...)
0233      * @param targetState state capturing should be having afterwards
0234      */
0235     void stopCapturing(CaptureState targetState);
0236 
0237     /**
0238      * @brief pauseCapturing Pauses capturing as soon as the current
0239      * capture is complete.
0240      */
0241     void pauseCapturing();
0242 
0243     /**
0244      * @brief startJob Start the execution of a selected sequence job:
0245      * - Initialize the state for capture preparation ({@see CaptureModuleState#initCapturePreparation()}
0246      * - Prepare the selected job ({@see #prepareJob(SequenceJob *)})
0247      * @param job selected sequence job
0248      */
0249     void startJob(SequenceJob *job);
0250 
0251     /**
0252      * @brief prepareJob Update the counters of existing frames and continue with prepareActiveJob(), if there exist less
0253      *        images than targeted. If enough images exist, continue with processJobCompletion().
0254      */
0255     void prepareJob(SequenceJob *job);
0256 
0257     /**
0258      * @brief prepareActiveJobStage1 Check for pre job script to execute. If none, move to stage 2
0259      */
0260     void prepareActiveJobStage1();
0261     /**
0262      * @brief prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
0263      */
0264     void prepareActiveJobStage2();
0265 
0266     /**
0267      * @brief preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and
0268      *        let the #activeJob execute the preparation actions before a capture may
0269      *        take place (@see SequenceJob::prepareCapture()).
0270      *
0271      * After triggering the settings, this method returns. This mechanism is slightly tricky, since it
0272      * asynchronous and event based and works as collaboration between Capture and SequenceJob. Capture has
0273      * the connection to devices and SequenceJob knows the target values.
0274      *
0275      * Each time Capture receives an updated value - e.g. the current CCD temperature
0276      * (@see updateCCDTemperature()) - it informs the #activeJob about the current CCD temperature.
0277      * SequenceJob checks, if it has reached the target value and if yes, sets this action as as completed.
0278      *
0279      * As soon as all actions are completed, SequenceJob emits a prepareComplete() event, which triggers
0280      * executeJob() from the CaptureProcess.
0281      */
0282     void prepareJobExecution();
0283 
0284     /**
0285      * @brief executeJob Start the execution of #activeJob by initiating updatePreCaptureCalibrationStatus().
0286      */
0287     void executeJob();
0288 
0289     /**
0290      * @brief refreshOpticalTrain Refresh the devices from the optical train configuration
0291      * @param name name of the optical train configuration
0292      */
0293     void refreshOpticalTrain(QString name);
0294 
0295     /**
0296      * @brief Check all tasks that might be pending before capturing may start.
0297      *
0298      * The following checks are executed:
0299      *  1. Are there any pending jobs that failed? If yes, return with IPS_ALERT.
0300      *  2. Has pausing been initiated (@see checkPausing()).
0301      *  3. Is a meridian flip already running (@see m_MeridianFlipState->checkMeridianFlipRunning()) or ready
0302      *     for execution (@see CaptureModuleState::checkMeridianFlipReady()).
0303      *  4. check guide deviation for non meridian flip stages if the initial guide limit is set.
0304      *     Wait until the guide deviation is reported to be below the limit
0305      *     (@see Capture::setGuideDeviation(double, double)).
0306      *  5. Check if dithering is required or running.
0307      *  6. Check if re-focusing is required
0308      *     Needs to be checked after dithering checks to avoid dithering in parallel
0309      *     to focusing, since @startFocusIfRequired() might change its value over time
0310      *  7. Resume guiding if it was suspended (@see Capture::resumeGuiding())
0311      *
0312      * @return IPS_OK iff no task is pending, IPS_BUSY otherwise (or IPS_ALERT if a problem occured)
0313      */
0314     IPState checkLightFramePendingTasks();
0315 
0316 
0317     /**
0318      * @brief updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),
0319      *        which contains all checks before captureImage() may be called.
0320      *
0321      * If processPreCaptureCalibrationStage() returns IPS_OK (i.e. everything is ready so that
0322      * capturing may be started), captureImage() is called. Otherwise, it waits for a second and
0323      * calls itself again.
0324      */
0325     void updatePreCaptureCalibrationStatus();
0326 
0327     /**
0328      * @brief processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may start.
0329      *
0330      * For light frames, checkLightFramePendingTasks() is called.
0331      *
0332      * @return IPS_OK if all necessary tasks have been completed
0333      */
0334     IPState processPreCaptureCalibrationStage();
0335 
0336     /**
0337      * @brief captureStarted Manage the result when capturing has been started
0338      */
0339     void captureStarted(CaptureModuleState::CAPTUREResult rc);
0340 
0341     /**
0342      * @brief checkNextExposure Try to start capturing the next exposure (@see startNextExposure()).
0343      *        If startNextExposure() returns, that there are still some jobs pending,
0344      *        we wait for 1 second and retry to start it again.
0345      *        If one of the pending preparation jobs has problems, the looping stops.
0346      */
0347     void checkNextExposure();
0348 
0349     /**
0350      * @brief startNextExposure Ensure that all pending preparation tasks are be completed (focusing, dithering, etc.)
0351      *        and start the next exposure.
0352      *
0353      * Checks of pending preparations depends upon the frame type:
0354      *
0355      * - For light frames, pending preparations like focusing, dithering etc. needs
0356      *   to be checked before each single frame capture. efore starting to capture the next light frame,
0357      *   checkLightFramePendingTasks() is called to check if all pending preparation tasks have
0358      *   been completed successfully. As soon as this is the case, the sequence timer
0359      *   #seqTimer is started to wait the configured delay and starts capturing the next image.
0360      *
0361      * - For bias, dark and flat frames, preparation jobs are only executed when starting a sequence.
0362      *   Hence, for these frames we directly start the sequence timer #seqTimer.
0363      *
0364      * @return IPS_OK, iff all pending preparation jobs are completed (@see checkLightFramePendingTasks()).
0365      *         In that case, the #seqTimer is started to wait for the configured settling delay and then
0366      *         capture the next image (@see Capture::captureImage). In case that a pending task aborted,
0367      *         IPS_IDLE is returned.
0368      */
0369 
0370     IPState startNextExposure();
0371 
0372     /**
0373      * @brief resumeSequence Try to continue capturing.
0374      *
0375      * Take the active job, if there is one, or search for the next one that is either
0376      * idle or aborted. If a new job is selected, call startNextJob() to prepare it.
0377      * If the current job is still active, initiate checkNextExposure().
0378      *
0379      * @return IPS_OK if there is a job that may be continued, IPS_BUSY otherwise.
0380      */
0381     IPState resumeSequence();
0382 
0383     /**
0384      * @brief newFITS process new FITS data received from camera. Update status of active job and overall sequence.
0385      * @param data pointer to blob containing FITS data
0386      */
0387     void processFITSData(const QSharedPointer<FITSData> &data);
0388 
0389     /**
0390      * @brief setNewRemoteFile A new image has been stored as remote file
0391      * @param file local file path
0392      */
0393     void processNewRemoteFile(QString file);
0394 
0395     /**
0396      * @brief processCaptureCompleted Manage the capture process after a captured image has been successfully downloaded from the camera.
0397      *
0398      * When a image frame has been captured and downloaded successfully, send the image to the client (if configured)
0399      * and execute the book keeping for the captured frame. After this, either processJobCompletion() is executed
0400      * in case that the job is completed, and resumeSequence() otherwise.
0401      *
0402      * Special case for flat capturing: exposure time calibration is executed in this process step as well.
0403      *
0404      * Book keeping means:
0405      * - increase / decrease the counters for focusing and dithering
0406      * - increase the frame counter
0407      * - update the average download time
0408      *
0409      * @return IPS_OK if processing has been completed, IPS_BUSY if otherwise.
0410      */
0411     IPState processCaptureCompleted();
0412 
0413     /**
0414      * @brief Manage the capture process after a captured image has been successfully downloaded
0415      * from the camera.
0416      *
0417      * - stop timers for timeout and download progress
0418      * - update the download time calculation
0419      * - update captured frames counters ({@see updateCompletedCaptureCountersAction()})
0420      * - check flat calibration (for flats only)
0421      * - execute the post capture script (if existing)
0422      * - resume the sequence ({@see resumeSequence()})
0423      */
0424     void imageCapturingCompleted();
0425 
0426     /**
0427      * @brief processJobCompletionStage1 Process job completion. In stage 1 when simply check if the is a post-job script to be running
0428      * if yes, we run it and wait until it is done before we move to stage2
0429      */
0430     void processJobCompletion1();
0431 
0432     /**
0433      * @brief processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a next sequence
0434      *        and start it, if there is a next one to be started (@see resumeSequence()).
0435      */
0436     void processJobCompletion2();
0437 
0438     /**
0439      * @brief startNextJob Select the next job that is either idle or aborted and
0440      * call prepareJob(*SequenceJob) to prepare its execution and
0441      * resume guiding if it was suspended (and no meridian flip is running).
0442      * @return IPS_OK if a job to be executed exists, IPS_IDLE otherwise.
0443      */
0444     IPState startNextJob();
0445 
0446     /**
0447      * @brief captureImage Initiates image capture in the active job.
0448      */
0449     void captureImage();
0450 
0451     /**
0452      * @brief resetFrame Reset frame settings of the camera
0453      */
0454     void resetFrame();
0455 
0456     // ////////////////////////////////////////////////////////////////////
0457     // capturing actions
0458     // ////////////////////////////////////////////////////////////////////
0459 
0460     /**
0461      * @brief setExposureProgress Manage exposure progress reported by
0462      * the camera device.
0463      */
0464     void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state);
0465 
0466     /**
0467      * @brief setDownloadProgress update the Capture Module and Summary
0468      *        Screen's estimate of how much time is left in the download
0469      */
0470     void setDownloadProgress();
0471 
0472     /**
0473      * @brief continueFramingAction If framing is running, start the next capture sequence
0474      * @return IPS_OK in all cases
0475      */
0476     IPState continueFramingAction(const QSharedPointer<FITSData> &imageData);
0477 
0478     /**
0479      * @brief updateDownloadTimesAction Add the current download time to the list of already measured ones
0480      */
0481     IPState updateDownloadTimesAction();
0482 
0483     /**
0484      * @brief previewImageCompletedAction Activities required when a preview image has been captured.
0485      * @return IPS_OK if a preview has been completed, IPS_IDLE otherwise
0486      */
0487     IPState previewImageCompletedAction(QSharedPointer<FITSData> imageData);
0488 
0489     /**
0490      * @brief updateCompletedCaptureCounters Update counters if an image has been captured
0491      * @return
0492      */
0493     IPState updateCompletedCaptureCountersAction();
0494 
0495     /**
0496      * @brief updateImageMetadataAction Update meta data of a captured image
0497      */
0498     IPState updateImageMetadataAction(QSharedPointer<FITSData> imageData);
0499 
0500     /**
0501      * @brief runCaptureScript Run the pre-/post capture/job script
0502      * @param scriptType script type (pre-/post capture/job)
0503      * @param precond additional pre condition for starting the script
0504      * @return IPS_BUSY, of script exists, IPS_OK otherwise
0505      */
0506     IPState runCaptureScript(ScriptTypes scriptType, bool precond = true);
0507 
0508     /**
0509      * @brief scriptFinished Slot managing the return status of
0510      * pre/post capture/job scripts
0511      */
0512     void scriptFinished(int exitCode, QProcess::ExitStatus status);
0513 
0514     /**
0515      * @brief setCamera select camera device
0516      * @param name Name of the camera device
0517     */
0518     void selectCamera(QString name);
0519 
0520     /**
0521      * @brief configureCamera Refreshes the CCD information in the capture module.
0522      */
0523     void checkCamera();
0524 
0525     /**
0526      * @brief syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
0527      * This include Max width, height, and pixel sizes.
0528      * @param model Name of camera driver in the DSLR database.
0529      */
0530     void syncDSLRToTargetChip(const QString &model);
0531 
0532     /**
0533      * @brief reconnectDriver Reconnect the camera driver
0534      */
0535     void reconnectCameraDriver(const QString &camera, const QString &filterWheel);
0536 
0537     /**
0538      * @brief Generic method for removing any connected device.
0539      */
0540     void removeDevice(const QSharedPointer<ISD::GenericDevice> &device);
0541 
0542     /**
0543      * @brief processCaptureTimeout If exposure timed out, let's handle it.
0544      */
0545     void processCaptureTimeout();
0546 
0547     /**
0548      * @brief processCaptureError Handle when image capture fails
0549      * @param type error type
0550      */
0551     void processCaptureError(ISD::Camera::ErrorType type);
0552 
0553     /**
0554      * @brief checkFlatCalibration check the flat calibration
0555      * @param imageData current image data to be analysed
0556      * @param exp_min minimal possible exposure time
0557      * @param exp_max maximal possible exposure time
0558      * @return false iff calibration has not been reached yet
0559      */
0560     bool checkFlatCalibration(QSharedPointer<FITSData> imageData, double exp_min, double exp_max);
0561 
0562     /**
0563      * @brief calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
0564      * @param currentADU ADU of the last captured frame
0565      * @return next exposure time to be tried for the flat capturing
0566      */
0567     double calculateFlatExpTime(double currentADU);
0568 
0569     /**
0570      * @brief clearFlatCache Clear the measured values for flat calibrations
0571      */
0572     void clearFlatCache();
0573 
0574     /**
0575      * @brief updateTelescopeInfo Update the scope information in the camera's
0576      * INDI driver.
0577      */
0578     void updateTelescopeInfo();
0579 
0580     /**
0581      * @brief updateFilterInfo Update the filter information in the INDI
0582      * drivers of the current camera and dust cap
0583      */
0584     void updateFilterInfo();
0585 
0586     // ////////////////////////////////////////////////////////////////////
0587     // XML capture sequence file handling
0588     // ////////////////////////////////////////////////////////////////////
0589     /**
0590      * Loads the Ekos Sequence Queue file in the Sequence Queue. Jobs are appended to existing jobs.
0591      * @param fileURL full URL of the filename
0592      * @param targetName override the target defined in the sequence queue file (necessary for using the target of the scheduler)
0593      */
0594      bool loadSequenceQueue(const QString &fileURL, const QString &targetName = "", bool setOptions = true);
0595 
0596     /**
0597      * Saves the Sequence Queue to the Ekos Sequence Queue file.
0598      * @param fileURL full URL of the filename
0599      */
0600      bool saveSequenceQueue(const QString &path, bool loadOptions = true);
0601 
0602     // ////////////////////////////////////////////////////////////////////
0603     // helper functions
0604     // ////////////////////////////////////////////////////////////////////
0605 
0606     /**
0607      * @brief checkPausing check if a pause has been planned and pause subsequently
0608      * @param continueAction action to be executed when resume after pausing
0609      * @return true iff capturing has been paused
0610      */
0611     bool checkPausing(CaptureModuleState::ContinueAction continueAction);
0612 
0613     /**
0614      * @brief findExecutableJob find next job to be executed
0615      */
0616     SequenceJob *findNextPendingJob();
0617 
0618     //  Based on  John Burkardt LLSQ (LGPL)
0619     void llsq(QVector<double> x, QVector<double> y, double &a, double &b);
0620 
0621     /**
0622      * @brief generateScriptArguments Generate argument list to pass to capture script
0623      * @return generates argument list consisting of one argument -metadata followed by JSON-formatted key:value pair:
0624      * -ts UNIX timestamp
0625      * -image full path to captured image (if any)
0626      * -size size of file in bytes (if any)
0627      * -job {name, index}
0628      * -capture {name, index}
0629      * -filter
0630      * TODO depending on user feedback.
0631      */
0632     QStringList generateScriptArguments() const;
0633 
0634     /**
0635      * @brief Does the CCD has a cooler control (On/Off) ?
0636      */
0637     bool hasCoolerControl();
0638 
0639     /**
0640      * @brief Set the CCD cooler ON/OFF
0641      *
0642      */
0643     bool setCoolerControl(bool enable);
0644 
0645     /**
0646      * @brief restartCamera Restarts the INDI driver associated with a camera. Remote and Local drivers are supported.
0647      * @param name Name of camera to restart. If a driver defined multiple cameras, they would be removed and added again
0648      * after driver restart.
0649      * @note Restarting camera should only be used as a last resort when it comes completely unresponsive. Due the complex
0650      * nature of driver interactions with Ekos, restarting cameras can lead to unexpected behavior.
0651      */
0652     void restartCamera(const QString &name);
0653 
0654     /**
0655      * @brief frameTypes Retrieve the frame types from the active camera's primary chip.
0656      */
0657     QStringList frameTypes();
0658     /**
0659      * @brief filterLabels list of currently available filter labels
0660      */
0661     QStringList filterLabels();
0662 
0663     /**
0664      * @brief getGain Update the gain value from the custom property value. Depending
0665      *        on the camera, it is either stored as GAIN property value of CCD_GAIN or as
0666      *        Gain property value from CCD_CONTROLS.
0667      */
0668     void updateGain(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
0669 
0670     /**
0671      * @brief getOffset Update the offset value from the custom property value. Depending
0672      *        on the camera, it is either stored as OFFSET property value of CCD_OFFSET or as
0673      *        Offset property value from CCD_CONTROLS.
0674      */
0675     void updateOffset(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
0676 
0677 
0678     // ////////////////////////////////////////////////////////////////////
0679     // attributes access
0680     // ////////////////////////////////////////////////////////////////////
0681     QProcess &captureScript()
0682     {
0683         return m_CaptureScript;
0684     }
0685 
0686 signals:
0687     // controls for capture execution
0688     void addJob (SequenceJob *job);
0689     void createJob(SequenceJob::SequenceJobType jobtype = SequenceJob::JOBTYPE_BATCH);
0690     void jobStarting();
0691     void stopCapture(CaptureState targetState = CAPTURE_IDLE);
0692     void captureAborted(double exposureSeconds);
0693     void captureStopped();
0694     void syncGUIToJob(SequenceJob *job);
0695     void updateFrameProperties(int reset);
0696     void updateJobTable(SequenceJob *job, bool full = false);
0697     void jobExecutionPreparationStarted();
0698     void jobPrepared(SequenceJob *job);
0699     void captureImageStarted();
0700     void captureTarget(QString targetName);
0701     void captureRunning();
0702     void newExposureProgress(SequenceJob *job);
0703     void newDownloadProgress(double downloadTimeLeft);
0704     void downloadingFrame();
0705     void updateCaptureCountDown(int deltaMS);
0706     void darkFrameCompleted();
0707     void updateMeridianFlipStage(MeridianFlipState::MFStage stage);
0708     void cameraReady();
0709     void refreshCamera();
0710     void refreshCameraSettings();
0711     void refreshFilterSettings();
0712     void processingFITSfinished(bool success);
0713     void rotatorReverseToggled(bool enabled);
0714     // communication with other modules
0715     void newImage(SequenceJob *job, const QSharedPointer<FITSData> &data);
0716     void suspendGuiding();
0717     void resumeGuiding();
0718     void abortFocus();
0719     void captureComplete(const QVariantMap &metadata);
0720     void sequenceChanged(const QJsonArray &sequence);
0721     void driverTimedout(const QString &deviceName);
0722     // new log text for the module log window
0723     void newLog(const QString &text);
0724 
0725 
0726 private:
0727     QSharedPointer<CaptureModuleState> m_State;
0728     QSharedPointer<CaptureDeviceAdaptor> m_DeviceAdaptor;
0729     QPointer<DarkProcessor> m_DarkProcessor;
0730 
0731     // Pre-/post capture script process
0732     QProcess m_CaptureScript;
0733     QString m_Scope;
0734     // Flat field automation
0735     QVector<double> ExpRaw, ADURaw;
0736     ADUAlgorithm targetADUAlgorithm { ADU_LEAST_SQUARES };
0737 
0738 
0739     /**
0740      * @brief activeJob Shortcut for the module state
0741      */
0742     QSharedPointer<CaptureModuleState> state() const
0743     {
0744         return m_State;
0745     }
0746 
0747     /**
0748      * @brief activeJob Shortcut to device adapter
0749      */
0750     QSharedPointer<CaptureDeviceAdaptor> devices()
0751     {
0752         return m_DeviceAdaptor;
0753     }
0754 
0755     /**
0756      * @brief activeJob Shortcut to the active job held in the state machine
0757      */
0758     SequenceJob *activeJob()
0759     {
0760         return  state()->getActiveJob();
0761     }
0762 
0763     /**
0764      * @brief activeCamera Shortcut to the active camera held in the device adaptor
0765      */
0766     ISD::Camera *activeCamera();
0767 
0768     /**
0769      * @brief resetAllJobs Iterate over all jobs and reset them.
0770      */
0771     void resetAllJobs();
0772     /**
0773      * @brief resetJobStatus Reset a single job to the given status
0774      */
0775     void resetJobStatus(JOBStatus newStatus);
0776     /**
0777      * @brief updatedCaptureCompleted Update the completed captures count to the given
0778      * number.
0779      */
0780     void updatedCaptureCompleted(int count);
0781 };
0782 } // Ekos namespace