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