Kstars

captureprocess.h
1/*
2 SPDX-FileCopyrightText: 2023 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include "capturemodulestate.h"
10#include "sequencejob.h"
11
12#include "indiapi.h"
13
14#include <QObject>
15
16class FITSViewer;
17
18namespace Ekos
19{
20
21class CaptureDeviceAdaptor;
22class DarkProcessor;
23
24/**
25 * @class CaptureProcess
26 * @brief The CaptureProcess class holds the entire business logic to control capturing execution.
27 *
28 * Capture Execution
29 * =================
30 * Executing the sequence jobs is a complex process (explained here for light frames) and works roughly
31 * as follows and starts by calling {@see Capture#start()} either from the scheduler, by DBUS or by
32 * pressing the start button:
33 * 1. Select the next sequence job to be executed ({@see startNextPendingJob()}. If the list of jobs is
34 * empty, an {@see #addJob()} event is sent. The corresponding callback function
35 * {@see #jobAdded(SequenceJob*)} is triggered. Now we know that at least one sequence job is
36 * to be executed.
37 * 2. Prepare the selected job
38 * - update the counters of captured frames ({@see #prepareJob(SequenceJob *)})
39 * - execute the pre job script, if existing ({@see #prepareActiveJobStage1()})
40 * - set temperature, rotator angle and wait (if required) for the initial guiding
41 * deviation being below the configured threshold ({@see #prepareJobExecution()})
42 * and wait until these parameters are OK.
43 * 3. Prepare capturing a single frame
44 * We still need to do some preparation steps before capturing starts.
45 * - {@see #executeJob()} is the starting point, which simply sets the capture state
46 * to "busy" and sets the FITS attributes to the camera
47 * - Check all tasks that need to be completed before capturing may start (post meridian
48 * flip actions, guiding deviation, dithering, re-focusing, ..., see {@see #checkLightFramePendingTasks()}
49 * 4. Capture a single frame
50 * - Initiate capturing (set diverse settings of {@see #activeCamera()} (see {@see #captureImage})
51 * - hand over the control of capturing to the sequence job ({@see SequenceJob#startCapturing()})
52 * - Select the correct filter (@see SequenceJobState#prepareTargetFilter()}
53 * - As soon as the correct filter is set, the sequence job state will send the event
54 * {@see SequenceJobState::initCaptureComplete()}, which will finally call trigger
55 * {@see SequenceJob::capture()}
56 * 5. Listen upon capturing progress
57 * - listen to the event {@see ISD::Camera::newExposureValue}, update the remaining
58 * time and wait until the INDI state changes from busy to OK
59 * - start the download timer to measure download times
60 * - listen to the event {@see ISD::Camera::newImage} and start processing the FITS image
61 * as soon as it has been recieved
62 * 6. Process received image
63 * - update the FITS image meta data {@see #updateImageMetadataAction()}
64 * - update time calculation and counters and execute post capture script ({@see imageCapturingCompleted()})
65 * 7. Check how to continue the sequence execution ({@see resumeSequence()})
66 * - if the current sequence job isn't completed,
67 * - execute the post capture script
68 * - start next exposure (similar to 3.) ({@see startNextExposure()})
69 * TODO: check why we need this separate method and cannot use {@see updatePreCaptureCalibrationStatus()}
70 * - if the current sequence is complete,
71 * - execute the post sequence script ({@see processJobCompletion1()})
72 * - stop the current sequence job ({@see processJobCompletion2()})
73 * - recall {@see resumeSequence()}, which calls {@see startNextJob()}
74 * - if there is another job to be executed, jump to 2., otherwise Capture is completed
75 * by sending a stopCapture(CAPTURE_COMPLETE) event
76 *
77 * ADU based flats calibration
78 * ===========================
79 * Capturing ADU based flats begins like capturing other frame types. The difference begins as soon as an
80 * image has been received (step 6 above) in {@see imageCapturingCompleted()}. Here {@see checkFlatCalibration()}
81 * is called to check the frame's ADU. If the ADU isn't in the expected range, a new frame is captured with
82 * modified exposure time ({@see startNextExposure()}.
83 *
84 * Autofocus
85 * =========
86 * Capture has three ways that trigger autofocus during a capturing sequence: HFR based, temperature drift based,
87 * timer based and post meridian flip based. Each time the capture execution reaches the preparation of caturing
88 * a single frame (3. above) (see {@see CaptureModuleState#startFocusIfRequired()} and
89 * {@see RefocusState#checkFocusRequired()}).
90 *
91 * Meridian Flip
92 * =============
93 * The meridian flip itself is executed by the Mount module and is controlled by
94 * (see {@see MeridianFlipState}). Nevertheless, the Capture module plays an
95 * important rule in the meridian flip:
96 * 1. Accept a flip to be executed
97 * As soon as a meridian flip has been planned (informed through
98 * {@see #updateMFMountState(MeridianFlipState::MeridianFlipMountState)}, the meridian flip state is set
99 * to MF_REQUESTED.
100 * - If capturing is running the state remains in this state until the frame has been captured. As soon as
101 * the capturing state changes to id, suspended or aborted (see {@see CaptureModuleState::setCaptureState(CaptureState)}),
102 * the meridian flip state is set to MF_ACCEPTED (see {@see MeridianFlipState::updateMeridianFlipStage(const MFStage)}).
103 * This is triggered from {@see #checkLightFramePendingTasks()}, i.e. this function is looping once per second until
104 * the meridian flip has been completed.
105 * - If capturing is not running, the latter happens immediately.
106 * Now the meridian flip is started.
107 * 2. Post MF actions
108 * As soon as the meridian flip has been completed (and the Capture module is waiting for it), the Capture module
109 * takes over the control and executes all necessary tasks: aligning, re-focusing, guiding, etc. This happens all through
110 * {@see #checkLightFramePendingTasks()}. As soon as all has recovered, capturing continues.
111 */
113{
115
116public:
117 typedef enum
118 {
119 ADU_LEAST_SQUARES,
120 ADU_POLYNOMIAL
121 } ADUAlgorithm;
122
123 typedef struct
124 {
125 int normalTabID { -1 };
126 int calibrationTabID { -1 };
127 int focusTabID { -1 };
128 int guideTabID { -1 };
129 int alignTabID { -1 };
130
131 } FitsvViewerTabIDs;
132
133
135
136 // ////////////////////////////////////////////////////////////////////
137 // handle connectivity to modules and devices
138 // ////////////////////////////////////////////////////////////////////
139 /**
140 * @brief setMount Connect to the given mount device (and deconnect the old one
141 * if existing)
142 * @param device pointer to Mount device.
143 * @return True if added successfully, false if duplicate or failed to add.
144 */
145 bool setMount(ISD::Mount *device);
146
147 /**
148 * @brief setRotator Connect to the given rotator device (and deconnect
149 * the old one if existing)
150 * @param device pointer to rotator INDI device
151 * @return True if added successfully, false if duplicate or failed to add.
152 */
153 bool setRotator(ISD::Rotator * device);
154
155 /**
156 * @brief setDustCap Connect to the given dust cap device (and deconnect
157 * the old one if existing)
158 * @param device pointer to dust cap INDI device
159 * @return True if added successfully, false if duplicate or failed to add.
160 */
161 bool setDustCap(ISD::DustCap *device);
162
163 /**
164 * @brief setLightBox Connect to the given dust cap device (and deconnect
165 * the old one if existing)
166 * @param device pointer to light box INDI device.
167 * @return True if added successfully, false if duplicate or failed to add.
168 */
169 bool setLightBox(ISD::LightBox *device);
170
171 /**
172 * @brief setDome Connect to the given dome device
173 * @param device point to dome INDI device
174 * @return True if added successfully, false if duplicate or failed to add.
175 */
176 bool setDome(ISD::Dome *device);
177
178 /**
179 * @brief setCamera Connect to the given camera device (and deconnect
180 * the old one if existing)
181 * @param device pointer to camera INDI device.
182 * @return True if added successfully, false if duplicate or failed to add.
183 */
184 bool setCamera(ISD::Camera *device);
185
186 /**
187 * @brief setScope Set active train telescope name
188 * @param name Name of scope
189 */
190 void setScope(const QString &name)
191 {
192 m_Scope = name;
193 }
194
195 /**
196 * @brief Connect or disconnect the camera device
197 * @param connection flag if connect (=true) or disconnect (=false)
198 */
199 void setCamera(bool connection);
200
201 /**
202 * @brief setFilterWheel Connect to the given filter wheel device (and deconnect
203 * the old one if existing)
204 * @param device pointer to filter wheel INDI device.
205 * @return True if added successfully, false if duplicate or failed to add.
206 */
207 bool setFilterWheel(ISD::FilterWheel *device);
208
209 /**
210 * Toggle video streaming if supported by the device.
211 * @param enabled Set to true to start video streaming, false to stop it if active.
212 */
213 void toggleVideo(bool enabled);
214
215 // ////////////////////////////////////////////////////////////////////
216 // capturing process steps
217 // ////////////////////////////////////////////////////////////////////
218
219 /**
220 * @brief toggleSequence Toggle sequence state depending on its current state.
221 * 1. If paused, then resume sequence.
222 * 2. If idle or completed, then start sequence.
223 * 3. Otherwise, abort current sequence.
224 */
225 void toggleSequence();
226
227 /**
228 * @brief startNextPendingJob Start the next pending job.
229 *
230 * Find the next job to be executed:
231 * 1. If there are already some jobs defined, {@see #findNextPendingJob()} is
232 * used to find the next job to be executed.
233 * 2. If the list is empty, the current settings are used to create a job instantly,
234 * which subsequently will be executed.
235 */
236 void startNextPendingJob();
237
238 /**
239 * @brief Counterpart to the event {@see#createJob(SequenceJob::SequenceJobType)}
240 * where the event receiver reports whether one has been added successfully
241 * and of which type it was.
242 */
243 void jobCreated(SequenceJob *newJob);
244
245 /**
246 * @brief capturePreview Capture a preview (single or looping ones)
247 */
248 void capturePreview(bool loop = false);
249
250 /**
251 * @brief stopCapturing Stopping the entire capturing state
252 * (envelope for aborting, suspending, pausing, ...)
253 * @param targetState state capturing should be having afterwards
254 */
255 void stopCapturing(CaptureState targetState);
256
257 /**
258 * @brief pauseCapturing Pauses capturing as soon as the current
259 * capture is complete.
260 */
261 void pauseCapturing();
262
263 /**
264 * @brief startJob Start the execution of a selected sequence job:
265 * - Initialize the state for capture preparation ({@see CaptureModuleState#initCapturePreparation()}
266 * - Prepare the selected job ({@see #prepareJob(SequenceJob *)})
267 * @param job selected sequence job
268 */
269 void startJob(SequenceJob *job);
270
271 /**
272 * @brief prepareJob Update the counters of existing frames and continue with prepareActiveJob(), if there exist less
273 * images than targeted. If enough images exist, continue with processJobCompletion().
274 */
275 void prepareJob(SequenceJob *job);
276
277 /**
278 * @brief prepareActiveJobStage1 Check for pre job script to execute. If none, move to stage 2
279 */
281 /**
282 * @brief prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
283 */
285
286 /**
287 * @brief preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and
288 * let the #activeJob execute the preparation actions before a capture may
289 * take place (@see SequenceJob::prepareCapture()).
290 *
291 * After triggering the settings, this method returns. This mechanism is slightly tricky, since it
292 * asynchronous and event based and works as collaboration between Capture and SequenceJob. Capture has
293 * the connection to devices and SequenceJob knows the target values.
294 *
295 * Each time Capture receives an updated value - e.g. the current CCD temperature
296 * (@see updateCCDTemperature()) - it informs the #activeJob about the current CCD temperature.
297 * SequenceJob checks, if it has reached the target value and if yes, sets this action as as completed.
298 *
299 * As soon as all actions are completed, SequenceJob emits a prepareComplete() event, which triggers
300 * executeJob() from the CaptureProcess.
301 */
302 void prepareJobExecution();
303
304 /**
305 * @brief executeJob Start the execution of #activeJob by initiating updatePreCaptureCalibrationStatus().
306 */
307 void executeJob();
308
309 /**
310 * @brief refreshOpticalTrain Refresh the devices from the optical train configuration
311 * @param name name of the optical train configuration
312 */
313 void refreshOpticalTrain(QString name);
314
315 /**
316 * @brief Check all tasks that might be pending before capturing may start.
317 *
318 * The following checks are executed:
319 * 1. Are there any pending jobs that failed? If yes, return with IPS_ALERT.
320 * 2. Has pausing been initiated (@see checkPausing()).
321 * 3. Is a meridian flip already running (@see m_MeridianFlipState->checkMeridianFlipRunning()) or ready
322 * for execution (@see CaptureModuleState::checkMeridianFlipReady()).
323 * 4. check guide deviation for non meridian flip stages if the initial guide limit is set.
324 * Wait until the guide deviation is reported to be below the limit
325 * (@see Capture::setGuideDeviation(double, double)).
326 * 5. Check if dithering is required or running.
327 * 6. Check if re-focusing is required
328 * Needs to be checked after dithering checks to avoid dithering in parallel
329 * to focusing, since @startFocusIfRequired() might change its value over time
330 * 7. Resume guiding if it was suspended (@see Capture::resumeGuiding())
331 *
332 * @return IPS_OK iff no task is pending, IPS_BUSY otherwise (or IPS_ALERT if a problem occured)
333 */
335
336
337 /**
338 * @brief updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),
339 * which contains all checks before captureImage() may be called.
340 *
341 * If processPreCaptureCalibrationStage() returns IPS_OK (i.e. everything is ready so that
342 * capturing may be started), captureImage() is called. Otherwise, it waits for a second and
343 * calls itself again.
344 */
346
347 /**
348 * @brief processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may start.
349 *
350 * For light frames, checkLightFramePendingTasks() is called.
351 *
352 * @return IPS_OK if all necessary tasks have been completed
353 */
355
356 /**
357 * @brief captureStarted Manage the result when capturing has been started
358 */
359 void captureStarted(CaptureModuleState::CAPTUREResult rc);
360
361 /**
362 * @brief checkNextExposure Try to start capturing the next exposure (@see startNextExposure()).
363 * If startNextExposure() returns, that there are still some jobs pending,
364 * we wait for 1 second and retry to start it again.
365 * If one of the pending preparation jobs has problems, the looping stops.
366 */
367 void checkNextExposure();
368
369 /**
370 * @brief startNextExposure Ensure that all pending preparation tasks are be completed (focusing, dithering, etc.)
371 * and start the next exposure.
372 *
373 * Checks of pending preparations depends upon the frame type:
374 *
375 * - For light frames, pending preparations like focusing, dithering etc. needs
376 * to be checked before each single frame capture. efore starting to capture the next light frame,
377 * checkLightFramePendingTasks() is called to check if all pending preparation tasks have
378 * been completed successfully. As soon as this is the case, the sequence timer
379 * #seqTimer is started to wait the configured delay and starts capturing the next image.
380 *
381 * - For bias, dark and flat frames, preparation jobs are only executed when starting a sequence.
382 * Hence, for these frames we directly start the sequence timer #seqTimer.
383 *
384 * @return IPS_OK, iff all pending preparation jobs are completed (@see checkLightFramePendingTasks()).
385 * In that case, the #seqTimer is started to wait for the configured settling delay and then
386 * capture the next image (@see Capture::captureImage). In case that a pending task aborted,
387 * IPS_IDLE is returned.
388 */
389
390 IPState startNextExposure();
391
392 /**
393 * @brief resumeSequence Try to continue capturing.
394 *
395 * Take the active job, if there is one, or search for the next one that is either
396 * idle or aborted. If a new job is selected, call startNextJob() to prepare it.
397 * If the current job is still active, initiate checkNextExposure().
398 *
399 * @return IPS_OK if there is a job that may be continued, IPS_BUSY otherwise.
400 */
401 IPState resumeSequence();
402
403 /**
404 * @brief newFITS process new FITS data received from camera. Update status of active job and overall sequence.
405 *
406 * Manage the capture process after a captured image has been successfully downloaded
407 * from the camera:
408 * - stop timers for timeout and download progress
409 * - update the download time calculation
410 * - update captured frames counters ({@see updateCompletedCaptureCountersAction()})
411 * - check flat calibration (for flats only)
412 * - execute the post capture script (if existing)
413 * - resume the sequence ({@see resumeSequence()})
414 *
415 * @param data pointer to blob containing FITS data
416 * @param extension defining the file type
417 */
418 void processFITSData(const QSharedPointer<FITSData> &data, const QString &extension);
419
420 /**
421 * @brief setNewRemoteFile A new image has been stored as remote file
422 * @param file local file path
423 */
424 void processNewRemoteFile(QString file);
425
426 /**
427 * @brief processJobCompletionStage1 Process job completion. In stage 1 when simply check if the is a post-job script to be running
428 * if yes, we run it and wait until it is done before we move to stage2
429 */
431
432 /**
433 * @brief processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a next sequence
434 * and start it, if there is a next one to be started (@see resumeSequence()).
435 */
437
438 /**
439 * @brief startNextJob Select the next job that is either idle or aborted and
440 * call prepareJob(*SequenceJob) to prepare its execution and
441 * resume guiding if it was suspended (and no meridian flip is running).
442 * @return IPS_OK if a job to be executed exists, IPS_IDLE otherwise.
443 */
444 IPState startNextJob();
445
446 /**
447 * @brief captureImage Initiates image capture in the active job.
448 */
449 void captureImage();
450
451 /**
452 * @brief resetFrame Reset frame settings of the camera
453 */
454 void resetFrame();
455
456 // ////////////////////////////////////////////////////////////////////
457 // capturing actions
458 // ////////////////////////////////////////////////////////////////////
459
460 /**
461 * @brief setExposureProgress Manage exposure progress reported by
462 * the camera device.
463 */
464 void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state);
465
466 /**
467 * @brief setDownloadProgress update the Capture Module and Summary
468 * Screen's estimate of how much time is left in the download
469 */
470 void setDownloadProgress();
471
472 /**
473 * @brief continueFramingAction If framing is running, start the next capture sequence
474 * @return IPS_OK in all cases
475 */
476 IPState continueFramingAction(const QSharedPointer<FITSData> &imageData);
477
478 /**
479 * @brief updateDownloadTimesAction Add the current download time to the list of already measured ones
480 */
482
483 /**
484 * @brief previewImageCompletedAction Activities required when a preview image has been captured.
485 * @return IPS_OK if a preview has been completed, IPS_IDLE otherwise
486 */
488
489 /**
490 * @brief updateCompletedCaptureCounters Update counters if an image has been captured
491 */
493
494 /**
495 * @brief updateImageMetadataAction Update meta data of a captured image
496 */
498
499 /**
500 * @brief runCaptureScript Run the pre-/post capture/job script
501 * @param scriptType script type (pre-/post capture/job)
502 * @param precond additional pre condition for starting the script
503 * @return IPS_BUSY, of script exists, IPS_OK otherwise
504 */
505 IPState runCaptureScript(ScriptTypes scriptType, bool precond = true);
506
507 /**
508 * @brief scriptFinished Slot managing the return status of
509 * pre/post capture/job scripts
510 */
511 void scriptFinished(int exitCode, QProcess::ExitStatus status);
512
513 /**
514 * @brief setCamera select camera device
515 * @param name Name of the camera device
516 */
517 void selectCamera(QString name);
518
519 /**
520 * @brief configureCamera Refreshes the CCD information in the capture module.
521 */
522 void checkCamera();
523
524 /**
525 * @brief syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
526 * This include Max width, height, and pixel sizes.
527 * @param model Name of camera driver in the DSLR database.
528 */
529 void syncDSLRToTargetChip(const QString &model);
530
531 /**
532 * @brief reconnectDriver Reconnect the camera driver
533 */
534 void reconnectCameraDriver(const QString &camera, const QString &filterWheel);
535
536 /**
537 * @brief Generic method for removing any connected device.
538 */
540
541 /**
542 * @brief processCaptureTimeout If exposure timed out, let's handle it.
543 */
545
546 /**
547 * @brief processCaptureError Handle when image capture fails
548 * @param type error type
549 */
551
552 /**
553 * @brief checkFlatCalibration check the flat calibration
554 * @param imageData current image data to be analysed
555 * @param exp_min minimal possible exposure time
556 * @param exp_max maximal possible exposure time
557 * @return false iff calibration has not been reached yet
558 */
559 bool checkFlatCalibration(QSharedPointer<FITSData> imageData, double exp_min, double exp_max);
560
561 /**
562 * @brief calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
563 * @param currentADU ADU of the last captured frame
564 * @return next exposure time to be tried for the flat capturing
565 */
566 double calculateFlatExpTime(double currentADU);
567
568 /**
569 * @brief clearFlatCache Clear the measured values for flat calibrations
570 */
571 void clearFlatCache();
572
573 /**
574 * @brief updateTelescopeInfo Update the scope information in the camera's
575 * INDI driver.
576 */
577 void updateTelescopeInfo();
578
579 /**
580 * @brief updateFilterInfo Update the filter information in the INDI
581 * drivers of the current camera and dust cap
582 */
583 void updateFilterInfo();
584
585 /**
586 * @brief updateFITSViewer display new image in the configured FITSViewer tab.
587 */
588 void updateFITSViewer(const QSharedPointer<FITSData> data, const FITSMode &captureMode, const FITSScale &captureFilter, const QString &filename, const QString &deviceName);
589
590 // ////////////////////////////////////////////////////////////////////
591 // XML capture sequence file handling
592 // ////////////////////////////////////////////////////////////////////
593 /**
594 * Loads the Ekos Sequence Queue file in the Sequence Queue. Jobs are appended to existing jobs.
595 * @param fileURL full URL of the filename
596 * @param targetName override the target defined in the sequence queue file (necessary for using the target of the scheduler)
597 */
598 bool loadSequenceQueue(const QString &fileURL, const QString &targetName = "", bool setOptions = true);
599
600 /**
601 * Saves the Sequence Queue to the Ekos Sequence Queue file.
602 * @param fileURL full URL of the filename
603 */
604 bool saveSequenceQueue(const QString &path, bool loadOptions = true);
605
606 // ////////////////////////////////////////////////////////////////////
607 // helper functions
608 // ////////////////////////////////////////////////////////////////////
609
610 /**
611 * @brief checkPausing check if a pause has been planned and pause subsequently
612 * @param continueAction action to be executed when resume after pausing
613 * @return true iff capturing has been paused
614 */
615 bool checkPausing(CaptureModuleState::ContinueAction continueAction);
616
617 /**
618 * @brief findExecutableJob find next job to be executed
619 */
620 SequenceJob *findNextPendingJob();
621
622 // Based on John Burkardt LLSQ (LGPL)
623 void llsq(QVector<double> x, QVector<double> y, double &a, double &b);
624
625 /**
626 * @brief generateScriptArguments Generate argument list to pass to capture script
627 * @return generates argument list consisting of one argument -metadata followed by JSON-formatted key:value pair:
628 * -ts UNIX timestamp
629 * -image full path to captured image (if any)
630 * -size size of file in bytes (if any)
631 * -job {name, index}
632 * -capture {name, index}
633 * -filter
634 * TODO depending on user feedback.
635 */
637
638 /**
639 * @brief Does the CCD has a cooler control (On/Off) ?
640 */
641 bool hasCoolerControl();
642
643 /**
644 * @brief Set the CCD cooler ON/OFF
645 *
646 */
647 bool setCoolerControl(bool enable);
648
649 /**
650 * @brief restartCamera Restarts the INDI driver associated with a camera. Remote and Local drivers are supported.
651 * @param name Name of camera to restart. If a driver defined multiple cameras, they would be removed and added again
652 * after driver restart.
653 * @note Restarting camera should only be used as a last resort when it comes completely unresponsive. Due the complex
654 * nature of driver interactions with Ekos, restarting cameras can lead to unexpected behavior.
655 */
656 void restartCamera(const QString &name);
657
658 /**
659 * @brief frameTypes Retrieve the frame types from the active camera's primary chip.
660 */
662 /**
663 * @brief filterLabels list of currently available filter labels
664 */
666
667 /**
668 * @brief getGain Update the gain value from the custom property value. Depending
669 * on the camera, it is either stored as GAIN property value of CCD_GAIN or as
670 * Gain property value from CCD_CONTROLS.
671 */
672 void updateGain(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
673
674 /**
675 * @brief getOffset Update the offset value from the custom property value. Depending
676 * on the camera, it is either stored as OFFSET property value of CCD_OFFSET or as
677 * Offset property value from CCD_CONTROLS.
678 */
679 void updateOffset(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
680
681
682 // ////////////////////////////////////////////////////////////////////
683 // attributes access
684 // ////////////////////////////////////////////////////////////////////
685 QProcess &captureScript()
686 {
687 return m_CaptureScript;
688 }
689
690signals:
691 // controls for capture execution
692 void addJob (SequenceJob *job);
693 void createJob(SequenceJob::SequenceJobType jobtype = SequenceJob::JOBTYPE_BATCH);
694 void jobStarting();
695 void stopCapture(CaptureState targetState = CAPTURE_IDLE);
696 void captureAborted(double exposureSeconds);
697 void captureStopped();
698 void syncGUIToJob(SequenceJob *job);
699 void updateFrameProperties(int reset);
700 void updateJobTable(SequenceJob *job, bool full = false);
701 void jobExecutionPreparationStarted();
702 void jobPrepared(SequenceJob *job);
703 void captureImageStarted();
704 void captureTarget(QString targetName);
705 void captureRunning();
706 void newExposureProgress(SequenceJob *job);
707 void newDownloadProgress(double downloadTimeLeft);
708 void downloadingFrame();
709 void updateCaptureCountDown(int deltaMS);
710 void darkFrameCompleted();
711 void updateMeridianFlipStage(MeridianFlipState::MFStage stage);
712 void cameraReady();
713 void refreshCamera();
714 void refreshCameraSettings();
715 void refreshFilterSettings();
716 void processingFITSfinished(bool success);
717 void rotatorReverseToggled(bool enabled);
718 // communication with other modules
719 void newImage(SequenceJob *job, const QSharedPointer<FITSData> &data);
720 void newView(const QSharedPointer<FITSView> &view);
721 void suspendGuiding();
722 void resumeGuiding();
723 void abortFocus();
724 void captureComplete(const QVariantMap &metadata);
725 void sequenceChanged(const QJsonArray &sequence);
726 void driverTimedout(const QString &deviceName);
727 // new log text for the module log window
728 void newLog(const QString &text);
729
730
731private:
734 QPointer<DarkProcessor> m_DarkProcessor;
735 QSharedPointer<FITSViewer> m_FITSViewerWindow;
736 FitsvViewerTabIDs m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
737
738 // Pre-/post capture script process
739 QProcess m_CaptureScript;
740 QString m_Scope;
741 // Flat field automation
742 QVector<double> ExpRaw, ADURaw;
743 ADUAlgorithm targetADUAlgorithm { ADU_LEAST_SQUARES };
744
745
746 /**
747 * @brief activeJob Shortcut for the module state
748 */
750 {
751 return m_State;
752 }
753
754 /**
755 * @brief activeJob Shortcut to device adapter
756 */
758 {
759 return m_DeviceAdaptor;
760 }
761
762 /**
763 * @brief Get or Create FITSViewer if we are using FITSViewer
764 * or if capture mode is calibrate since for now we are forced to open the file in the viewer
765 * this should be fixed in the future and should only use FITSData.
766 */
767 QSharedPointer<FITSViewer> getFITSViewer();
768
769 /**
770 * @brief activeJob Shortcut to the active job held in the state machine
771 */
772 SequenceJob *activeJob()
773 {
774 return state()->getActiveJob();
775 }
776
777 /**
778 * @brief activeCamera Shortcut to the active camera held in the device adaptor
779 */
780 ISD::Camera *activeCamera();
781
782 /**
783 * @brief resetAllJobs Iterate over all jobs and reset them.
784 */
785 void resetAllJobs();
786 /**
787 * @brief resetJobStatus Reset a single job to the given status
788 */
789 void resetJobStatus(JOBStatus newStatus);
790 /**
791 * @brief updatedCaptureCompleted Update the completed captures count to the given
792 * number.
793 */
794 void updatedCaptureCompleted(int count);
795 /**
796 * @brief captureImageWithDelay Helper function that starts the sequence delay timer
797 * for starting to capture after the configured delay.
798 */
799 IPState captureImageWithDelay();
800 /**
801 * @brief saveReceivedImage Save the received image if the state allows it
802 * @return true iff everything worked as expected
803 */
804 bool checkSavingReceivedImage(const QSharedPointer<FITSData> &data, const QString &extension, QString &filename);
805};
806} // Ekos namespace
The CaptureProcess class holds the entire business logic to control capturing execution.
void processCaptureError(ISD::Camera::ErrorType type)
processCaptureError Handle when image capture fails
bool setDome(ISD::Dome *device)
setDome Connect to the given dome device
void toggleSequence()
toggleSequence Toggle sequence state depending on its current state.
void clearFlatCache()
clearFlatCache Clear the measured values for flat calibrations
QStringList generateScriptArguments() const
generateScriptArguments Generate argument list to pass to capture script
void startNextPendingJob()
startNextPendingJob Start the next pending job.
IPState processPreCaptureCalibrationStage()
processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may st...
void processCaptureTimeout()
processCaptureTimeout If exposure timed out, let's handle it.
IPState resumeSequence()
resumeSequence Try to continue capturing.
void captureStarted(CaptureModuleState::CAPTUREResult rc)
captureStarted Manage the result when capturing has been started
void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state)
setExposureProgress Manage exposure progress reported by the camera device.
QStringList frameTypes()
frameTypes Retrieve the frame types from the active camera's primary chip.
void updateFITSViewer(const QSharedPointer< FITSData > data, const FITSMode &captureMode, const FITSScale &captureFilter, const QString &filename, const QString &deviceName)
updateFITSViewer display new image in the configured FITSViewer tab.
void processFITSData(const QSharedPointer< FITSData > &data, const QString &extension)
newFITS process new FITS data received from camera.
bool saveSequenceQueue(const QString &path, bool loadOptions=true)
Saves the Sequence Queue to the Ekos Sequence Queue file.
void prepareJobExecution()
preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and...
void checkCamera()
configureCamera Refreshes the CCD information in the capture module.
void executeJob()
executeJob Start the execution of activeJob by initiating updatePreCaptureCalibrationStatus().
void startJob(SequenceJob *job)
startJob Start the execution of a selected sequence job:
bool setLightBox(ISD::LightBox *device)
setLightBox Connect to the given dust cap device (and deconnect the old one if existing)
void updateCompletedCaptureCountersAction()
updateCompletedCaptureCounters Update counters if an image has been captured
void setDownloadProgress()
setDownloadProgress update the Capture Module and Summary Screen's estimate of how much time is left ...
void removeDevice(const QSharedPointer< ISD::GenericDevice > &device)
Generic method for removing any connected device.
bool setCamera(ISD::Camera *device)
setCamera Connect to the given camera device (and deconnect the old one if existing)
bool setMount(ISD::Mount *device)
setMount Connect to the given mount device (and deconnect the old one if existing)
void toggleVideo(bool enabled)
Toggle video streaming if supported by the device.
void syncDSLRToTargetChip(const QString &model)
syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
bool setRotator(ISD::Rotator *device)
setRotator Connect to the given rotator device (and deconnect the old one if existing)
IPState runCaptureScript(ScriptTypes scriptType, bool precond=true)
runCaptureScript Run the pre-/post capture/job script
QStringList filterLabels()
filterLabels list of currently available filter labels
void checkNextExposure()
checkNextExposure Try to start capturing the next exposure (
bool hasCoolerControl()
Does the CCD has a cooler control (On/Off) ?
double calculateFlatExpTime(double currentADU)
calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
void prepareActiveJobStage2()
prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
IPState startNextExposure()
startNextExposure Ensure that all pending preparation tasks are be completed (focusing,...
bool checkPausing(CaptureModuleState::ContinueAction continueAction)
checkPausing check if a pause has been planned and pause subsequently
void prepareActiveJobStage1()
prepareActiveJobStage1 Check for pre job script to execute.
void restartCamera(const QString &name)
restartCamera Restarts the INDI driver associated with a camera.
IPState continueFramingAction(const QSharedPointer< FITSData > &imageData)
continueFramingAction If framing is running, start the next capture sequence
IPState startNextJob()
startNextJob Select the next job that is either idle or aborted and call prepareJob(*SequenceJob) to ...
bool setDustCap(ISD::DustCap *device)
setDustCap Connect to the given dust cap device (and deconnect the old one if existing)
void updateGain(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getGain Update the gain value from the custom property value.
void scriptFinished(int exitCode, QProcess::ExitStatus status)
scriptFinished Slot managing the return status of pre/post capture/job scripts
void captureImage()
captureImage Initiates image capture in the active job.
void updatePreCaptureCalibrationStatus()
updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),...
void updateTelescopeInfo()
updateTelescopeInfo Update the scope information in the camera's INDI driver.
void refreshOpticalTrain(QString name)
refreshOpticalTrain Refresh the devices from the optical train configuration
void updateFilterInfo()
updateFilterInfo Update the filter information in the INDI drivers of the current camera and dust cap
void stopCapturing(CaptureState targetState)
stopCapturing Stopping the entire capturing state (envelope for aborting, suspending,...
void pauseCapturing()
pauseCapturing Pauses capturing as soon as the current capture is complete.
void resetFrame()
resetFrame Reset frame settings of the camera
void processJobCompletion1()
processJobCompletionStage1 Process job completion.
void updateOffset(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getOffset Update the offset value from the custom property value.
void processNewRemoteFile(QString file)
setNewRemoteFile A new image has been stored as remote file
bool loadSequenceQueue(const QString &fileURL, const QString &targetName="", bool setOptions=true)
Loads the Ekos Sequence Queue file in the Sequence Queue.
bool setCoolerControl(bool enable)
Set the CCD cooler ON/OFF.
IPState updateDownloadTimesAction()
updateDownloadTimesAction Add the current download time to the list of already measured ones
void reconnectCameraDriver(const QString &camera, const QString &filterWheel)
reconnectDriver Reconnect the camera driver
void setScope(const QString &name)
setScope Set active train telescope name
SequenceJob * findNextPendingJob()
findExecutableJob find next job to be executed
bool checkFlatCalibration(QSharedPointer< FITSData > imageData, double exp_min, double exp_max)
checkFlatCalibration check the flat calibration
void prepareJob(SequenceJob *job)
prepareJob Update the counters of existing frames and continue with prepareActiveJob(),...
void selectCamera(QString name)
setCamera select camera device
IPState checkLightFramePendingTasks()
Check all tasks that might be pending before capturing may start.
void processJobCompletion2()
processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a ne...
void jobCreated(SequenceJob *newJob)
Counterpart to the event {.
IPState updateImageMetadataAction(QSharedPointer< FITSData > imageData)
updateImageMetadataAction Update meta data of a captured image
IPState previewImageCompletedAction(QSharedPointer< FITSData > imageData)
previewImageCompletedAction Activities required when a preview image has been captured.
bool setFilterWheel(ISD::FilterWheel *device)
setFilterWheel Connect to the given filter wheel device (and deconnect the old one if existing)
void capturePreview(bool loop=false)
capturePreview Capture a preview (single or looping ones)
Primary window to view monochrome and color FITS images.
Definition fitsviewer.h:50
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
Definition indicamera.h:44
Class handles control of INDI dome devices.
Definition indidome.h:23
Handles operation of a remotely controlled dust cover cap.
Definition indidustcap.h:23
Handles operation of a remotely controlled light box.
device handle controlling Mounts.
Definition indimount.h:27
Rotator class handles control of INDI Rotator devices.
Definition indirotator.h:20
Sequence Job is a container for the details required to capture a series of images.
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:79
CaptureState
Capture states.
Definition ekos.h:92
@ CAPTURE_IDLE
Definition ekos.h:93
ScriptTypes
Definition ekos.h:173
Q_OBJECTQ_OBJECT
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:49:50 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.