Kstars

cameraprocess.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 "camerastate.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 CameraProcess
26 * @brief The CameraProcess 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 CameraState#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 CameraState::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 */
112class CameraProcess : public QObject
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 Q_SCRIPTABLE 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 Q_SCRIPTABLE void pauseCapturing();
262
263 /**
264 * @brief startJob Start the execution of a selected sequence job:
265 * - Initialize the state for capture preparation ({@see CameraState#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 CameraProcess.
301 */
302 void prepareJobExecution();
303
304 /**
305 * @brief executeJob Start the execution of #activeJob by initiating updatePreCaptureCalibrationStatus().
306 */
307 Q_SCRIPTABLE 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 CameraState#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(CameraState::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 showFITSPreview Directly show the FITS data as preview
422 * @param data pointer to blob containing FITS data
423 */
425
426 /**
427 * @brief setNewRemoteFile A new image has been stored as remote file
428 * @param file local file path
429 */
430 void processNewRemoteFile(QString file);
431
432 /**
433 * @brief processJobCompletionStage1 Process job completion. In stage 1 when simply check if the is a post-job script to be running
434 * if yes, we run it and wait until it is done before we move to stage2
435 */
437
438 /**
439 * @brief processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a next sequence
440 * and start it, if there is a next one to be started (@see resumeSequence()).
441 */
443
444 /**
445 * @brief startNextJob Select the next job that is either idle or aborted and
446 * call prepareJob(*SequenceJob) to prepare its execution and
447 * resume guiding if it was suspended (and no meridian flip is running).
448 * @return IPS_OK if a job to be executed exists, IPS_IDLE otherwise.
449 */
450 IPState startNextJob();
451
452 /**
453 * @brief captureImage Initiates image capture in the active job.
454 */
455 void captureImage();
456
457 /**
458 * @brief resetFrame Reset frame settings of the camera
459 */
460 Q_SCRIPTABLE void resetFrame();
461
462 // ////////////////////////////////////////////////////////////////////
463 // capturing actions
464 // ////////////////////////////////////////////////////////////////////
465
466 /**
467 * @brief setExposureProgress Manage exposure progress reported by
468 * the camera device.
469 */
470 void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state);
471
472 /**
473 * @brief setDownloadProgress update the Capture Module and Summary
474 * Screen's estimate of how much time is left in the download
475 */
476 void setDownloadProgress();
477
478 /**
479 * @brief continueFramingAction If framing is running, start the next capture sequence
480 * @return IPS_OK in all cases
481 */
482 IPState continueFramingAction(const QSharedPointer<FITSData> &imageData);
483
484 /**
485 * @brief updateDownloadTimesAction Add the current download time to the list of already measured ones
486 */
488
489 /**
490 * @brief previewImageCompletedAction Activities required when a preview image has been captured.
491 * @return IPS_OK if a preview has been completed, IPS_IDLE otherwise
492 */
494
495 /**
496 * @brief updateCompletedCaptureCounters Update counters if an image has been captured
497 */
499
500 /**
501 * @brief updateImageMetadataAction Update meta data of a captured image
502 */
504
505 /**
506 * @brief runCaptureScript Run the pre-/post capture/job script
507 * @param scriptType script type (pre-/post capture/job)
508 * @param precond additional pre condition for starting the script
509 * @return IPS_BUSY, of script exists, IPS_OK otherwise
510 */
511 IPState runCaptureScript(ScriptTypes scriptType, bool precond = true);
512
513 /**
514 * @brief scriptFinished Slot managing the return status of
515 * pre/post capture/job scripts
516 */
517 void scriptFinished(int exitCode, QProcess::ExitStatus status);
518
519 /**
520 * @brief setCamera select camera device
521 * @param name Name of the camera device
522 */
523 void selectCamera(QString name);
524
525 /**
526 * @brief configureCamera Refreshes the CCD information in the capture module.
527 */
528 void checkCamera();
529
530 /**
531 * @brief syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
532 * This include Max width, height, and pixel sizes.
533 * @param model Name of camera driver in the DSLR database.
534 */
535 void syncDSLRToTargetChip(const QString &model);
536
537 /**
538 * @brief reconnectDriver Reconnect the camera driver
539 */
540 void reconnectCameraDriver(const QString &camera, const QString &filterWheel);
541
542 /**
543 * @brief Generic method for removing any connected device.
544 */
546
547 /**
548 * @brief processCaptureTimeout If exposure timed out, let's handle it.
549 */
551
552 /**
553 * @brief processCaptureError Handle when image capture fails
554 * @param type error type
555 */
557
558 /**
559 * @brief checkFlatCalibration check the flat calibration
560 * @param imageData current image data to be analysed
561 * @param exp_min minimal possible exposure time
562 * @param exp_max maximal possible exposure time
563 * @return false iff calibration has not been reached yet
564 */
565 bool checkFlatCalibration(QSharedPointer<FITSData> imageData, double exp_min, double exp_max);
566
567 /**
568 * @brief calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
569 * @param currentADU ADU of the last captured frame
570 * @return next exposure time to be tried for the flat capturing
571 */
572 double calculateFlatExpTime(double currentADU);
573
574 /**
575 * @brief clearFlatCache Clear the measured values for flat calibrations
576 */
577 void clearFlatCache();
578
579 /**
580 * @brief updateTelescopeInfo Update the scope information in the camera's
581 * INDI driver.
582 */
583 void updateTelescopeInfo();
584
585 /**
586 * @brief updateFilterInfo Update the filter information in the INDI
587 * drivers of the current camera and dust cap
588 */
589 void updateFilterInfo();
590
591 /**
592 * @brief updateFITSViewer display new image in the configured FITSViewer tab.
593 */
594 void updateFITSViewer(const QSharedPointer<FITSData> data, const FITSMode &captureMode, const FITSScale &captureFilter, const QString &filename, const QString &deviceName);
595 void updateFITSViewer(const QSharedPointer<FITSData> data, ISD::CameraChip *tChip, const QString &filename);
596
597 // ////////////////////////////////////////////////////////////////////
598 // XML capture sequence file handling
599 // ////////////////////////////////////////////////////////////////////
600 /**
601 * Loads the Ekos Sequence Queue file in the Sequence Queue. Jobs are appended to existing jobs.
602 * @param fileURL full URL of the filename
603 * @param targetName override the target defined in the sequence queue file (necessary for using the target of the scheduler)
604 */
605 bool loadSequenceQueue(const QString &fileURL, const QString &targetName = "", bool setOptions = true);
606
607 /**
608 * Saves the Sequence Queue to the Ekos Sequence Queue file.
609 * @param fileURL full URL of the filename
610 */
611 bool saveSequenceQueue(const QString &path, bool loadOptions = true);
612
613 // ////////////////////////////////////////////////////////////////////
614 // helper functions
615 // ////////////////////////////////////////////////////////////////////
616
617 /**
618 * @brief checkPausing check if a pause has been planned and pause subsequently
619 * @param continueAction action to be executed when resume after pausing
620 * @return true iff capturing has been paused
621 */
622 bool checkPausing(CameraState::ContinueAction continueAction);
623
624 /**
625 * @brief findExecutableJob find next job to be executed
626 */
627 SequenceJob *findNextPendingJob();
628
629 // Based on John Burkardt LLSQ (LGPL)
630 void llsq(QVector<double> x, QVector<double> y, double &a, double &b);
631
632 /**
633 * @brief generateScriptArguments Generate argument list to pass to capture script
634 * @return generates argument list consisting of one argument -metadata followed by JSON-formatted key:value pair:
635 * -ts UNIX timestamp
636 * -image full path to captured image (if any)
637 * -size size of file in bytes (if any)
638 * -job {name, index}
639 * -capture {name, index}
640 * -filter
641 * TODO depending on user feedback.
642 */
644
645 /**
646 * @brief Does the CCD has a cooler control (On/Off) ?
647 */
648 bool hasCoolerControl();
649
650 /**
651 * @brief Set the CCD cooler ON/OFF
652 *
653 */
654 bool setCoolerControl(bool enable);
655
656 /**
657 * @brief restartCamera Restarts the INDI driver associated with a camera. Remote and Local drivers are supported.
658 * @param name Name of camera to restart. If a driver defined multiple cameras, they would be removed and added again
659 * after driver restart.
660 * @note Restarting camera should only be used as a last resort when it comes completely unresponsive. Due the complex
661 * nature of driver interactions with Ekos, restarting cameras can lead to unexpected behavior.
662 */
663 void restartCamera(const QString &name);
664
665 /**
666 * @brief frameTypes Retrieve the frame types from the active camera's primary chip.
667 */
669 /**
670 * @brief filterLabels list of currently available filter labels
671 */
673
674 /**
675 * @brief getGain Update the gain value from the custom property value. Depending
676 * on the camera, it is either stored as GAIN property value of CCD_GAIN or as
677 * Gain property value from CCD_CONTROLS.
678 */
679 void updateGain(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
680
681 /**
682 * @brief getOffset Update the offset value from the custom property value. Depending
683 * on the camera, it is either stored as OFFSET property value of CCD_OFFSET or as
684 * Offset property value from CCD_CONTROLS.
685 */
686 void updateOffset(double value, QMap<QString, QMap<QString, QVariant> > &propertyMap);
687
688
689 // ////////////////////////////////////////////////////////////////////
690 // attributes access
691 // ////////////////////////////////////////////////////////////////////
692 QProcess &captureScript()
693 {
694 return m_CaptureScript;
695 }
696
697signals:
698 // controls for capture execution
699 void addJob (SequenceJob *job);
700 void createJob(SequenceJob::SequenceJobType jobtype = SequenceJob::JOBTYPE_BATCH);
701 void jobStarting();
702 void stopCapture(CaptureState targetState = CAPTURE_IDLE);
703 void captureAborted(double exposureSeconds);
704 void captureStopped();
705 void syncGUIToJob(SequenceJob *job);
706 void updateFrameProperties(int reset);
707 void updateJobTable(SequenceJob *job, bool full = false);
708 void jobExecutionPreparationStarted();
709 void jobPrepared(SequenceJob *job);
710 void captureImageStarted();
711 void captureTarget(QString targetName);
712 void captureRunning();
713 void newExposureProgress(SequenceJob *job, const QString &devicename);
714 void newDownloadProgress(double downloadTimeLeft, const QString &devicename);
715 void downloadingFrame();
716 void updateCaptureCountDown(int deltaMS);
717 void darkFrameCompleted();
718 void updateMeridianFlipStage(MeridianFlipState::MFStage stage);
719 void cameraReady();
720 void refreshCamera(bool isValid);
721 void refreshCameraSettings();
722 void refreshFilterSettings();
723 void processingFITSfinished(bool success);
724 void rotatorReverseToggled(bool enabled);
725 // communication with other modules
726 void newImage(SequenceJob *job, const QSharedPointer<FITSData> &data, const QString &devicename = "");
727 void newView(const QSharedPointer<FITSView> &view);
728 void suspendGuiding();
729 void resumeGuiding();
730 void abortFocus();
731 void captureComplete(const QVariantMap &metadata);
732 void sequenceChanged(const QJsonArray &sequence);
733 void driverTimedout(const QString &deviceName);
734 // new log text for the module log window
735 void newLog(const QString &text);
736
737
738private:
741 QPointer<DarkProcessor> m_DarkProcessor;
742 QSharedPointer<FITSViewer> m_FITSViewerWindow;
743 FitsvViewerTabIDs m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
744
745 // Pre-/post capture script process
746 QProcess m_CaptureScript;
747 QString m_Scope;
748 // Flat field automation
749 QVector<double> ExpRaw, ADURaw;
750 ADUAlgorithm targetADUAlgorithm { ADU_LEAST_SQUARES };
751
752
753 /**
754 * @brief activeJob Shortcut for the module state
755 */
756 QSharedPointer<CameraState> state() const
757 {
758 return m_State;
759 }
760
761 /**
762 * @brief activeJob Shortcut to device adapter
763 */
765 {
766 return m_DeviceAdaptor;
767 }
768
769 /**
770 * @brief Get or Create FITSViewer if we are using FITSViewer
771 * or if capture mode is calibrate since for now we are forced to open the file in the viewer
772 * this should be fixed in the future and should only use FITSData.
773 */
774 QSharedPointer<FITSViewer> getFITSViewer();
775
776 /**
777 * @brief activeJob Shortcut to the active job held in the state machine
778 */
779 SequenceJob *activeJob()
780 {
781 return state()->getActiveJob();
782 }
783
784 /**
785 * @brief activeCamera Shortcut to the active camera held in the device adaptor
786 */
787 ISD::Camera *activeCamera();
788
789 /**
790 * @brief resetAllJobs Iterate over all jobs and reset them.
791 */
792 void resetAllJobs();
793 /**
794 * @brief resetJobStatus Reset a single job to the given status
795 */
796 void resetJobStatus(JOBStatus newStatus);
797 /**
798 * @brief updatedCaptureCompleted Update the completed captures count to the given
799 * number.
800 */
801 void updatedCaptureCompleted(int count);
802 /**
803 * @brief captureImageWithDelay Helper function that starts the sequence delay timer
804 * for starting to capture after the configured delay.
805 */
806 IPState captureImageWithDelay();
807 /**
808 * @brief saveReceivedImage Save the received image if the state allows it
809 * @return true iff everything worked as expected
810 */
811 bool checkSavingReceivedImage(const QSharedPointer<FITSData> &data, const QString &extension, QString &filename);
812
813 /**
814 * @brief createTabText Create the tab to be displayed in the FITSViewer tab
815 */
816 QString createTabTitle(const FITSMode &captureMode, const QString &deviceName);
817};
818} // Ekos namespace
The CameraProcess class holds the entire business logic to control capturing execution.
IPState runCaptureScript(ScriptTypes scriptType, bool precond=true)
runCaptureScript Run the pre-/post capture/job script
void updateTelescopeInfo()
updateTelescopeInfo Update the scope information in the camera's INDI driver.
void processCaptureTimeout()
processCaptureTimeout If exposure timed out, let's handle it.
bool setMount(ISD::Mount *device)
setMount Connect to the given mount device (and deconnect the old one if existing)
void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state)
setExposureProgress Manage exposure progress reported by the camera device.
IPState startNextExposure()
startNextExposure Ensure that all pending preparation tasks are be completed (focusing,...
void updatePreCaptureCalibrationStatus()
updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),...
void reconnectCameraDriver(const QString &camera, const QString &filterWheel)
reconnectDriver Reconnect the camera driver
IPState checkLightFramePendingTasks()
Check all tasks that might be pending before capturing may start.
void checkNextExposure()
checkNextExposure Try to start capturing the next exposure (
void clearFlatCache()
clearFlatCache Clear the measured values for flat calibrations
bool loadSequenceQueue(const QString &fileURL, const QString &targetName="", bool setOptions=true)
Loads the Ekos Sequence Queue file in the Sequence Queue.
bool setFilterWheel(ISD::FilterWheel *device)
setFilterWheel Connect to the given filter wheel device (and deconnect the old one if existing)
void startNextPendingJob()
startNextPendingJob Start the next pending job.
Q_SCRIPTABLE void resetFrame()
resetFrame Reset frame settings of the camera
bool saveSequenceQueue(const QString &path, bool loadOptions=true)
Saves the Sequence Queue to the Ekos Sequence Queue file.
QStringList generateScriptArguments() const
generateScriptArguments Generate argument list to pass to capture script
void captureStarted(CameraState::CAPTUREResult rc)
captureStarted Manage the result when capturing has been started
IPState previewImageCompletedAction()
previewImageCompletedAction Activities required when a preview image has been captured.
bool setDome(ISD::Dome *device)
setDome Connect to the given dome device
bool setCoolerControl(bool enable)
Set the CCD cooler ON/OFF.
void setScope(const QString &name)
setScope Set active train telescope name
void prepareActiveJobStage1()
prepareActiveJobStage1 Check for pre job script to execute.
void updateCompletedCaptureCountersAction()
updateCompletedCaptureCounters Update counters if an image has been captured
void scriptFinished(int exitCode, QProcess::ExitStatus status)
scriptFinished Slot managing the return status of pre/post capture/job scripts
bool setRotator(ISD::Rotator *device)
setRotator Connect to the given rotator device (and deconnect the old one if existing)
void selectCamera(QString name)
setCamera select camera device
Q_SCRIPTABLE void executeJob()
executeJob Start the execution of activeJob by initiating updatePreCaptureCalibrationStatus().
bool checkPausing(CameraState::ContinueAction continueAction)
checkPausing check if a pause has been planned and pause subsequently
SequenceJob * findNextPendingJob()
findExecutableJob find next job to be executed
void stopCapturing(CaptureState targetState)
stopCapturing Stopping the entire capturing state (envelope for aborting, suspending,...
void updateFilterInfo()
updateFilterInfo Update the filter information in the INDI drivers of the current camera and dust cap
IPState processPreCaptureCalibrationStage()
processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may st...
bool setCamera(ISD::Camera *device)
setCamera Connect to the given camera device (and deconnect the old one if existing)
void checkCamera()
configureCamera Refreshes the CCD information in the capture module.
void updateGain(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getGain Update the gain value from the custom property value.
QStringList filterLabels()
filterLabels list of currently available filter labels
bool setLightBox(ISD::LightBox *device)
setLightBox Connect to the given dust cap device (and deconnect the old one if existing)
Q_SCRIPTABLE void toggleSequence()
toggleSequence Toggle sequence state depending on its current state.
IPState startNextJob()
startNextJob Select the next job that is either idle or aborted and call prepareJob(*SequenceJob) to ...
void prepareActiveJobStage2()
prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
void showFITSPreview(const QSharedPointer< FITSData > &data)
showFITSPreview Directly show the FITS data as preview
void removeDevice(const QSharedPointer< ISD::GenericDevice > &device)
Generic method for removing any connected device.
IPState resumeSequence()
resumeSequence Try to continue capturing.
void startJob(SequenceJob *job)
startJob Start the execution of a selected sequence job:
void refreshOpticalTrain(QString name)
refreshOpticalTrain Refresh the devices from the optical train configuration
QStringList frameTypes()
frameTypes Retrieve the frame types from the active camera's primary chip.
void updateOffset(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getOffset Update the offset value from the custom property value.
void capturePreview(bool loop=false)
capturePreview Capture a preview (single or looping ones)
void processJobCompletion2()
processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a ne...
bool checkFlatCalibration(QSharedPointer< FITSData > imageData, double exp_min, double exp_max)
checkFlatCalibration check the flat calibration
IPState updateImageMetadataAction(QSharedPointer< FITSData > imageData)
updateImageMetadataAction Update meta data of a captured image
void processFITSData(const QSharedPointer< FITSData > &data, const QString &extension)
newFITS process new FITS data received from camera.
void jobCreated(SequenceJob *newJob)
Counterpart to the event {.
void prepareJob(SequenceJob *job)
prepareJob Update the counters of existing frames and continue with prepareActiveJob(),...
void processNewRemoteFile(QString file)
setNewRemoteFile A new image has been stored as remote file
Q_SCRIPTABLE void pauseCapturing()
pauseCapturing Pauses capturing as soon as the current capture is complete.
IPState updateDownloadTimesAction()
updateDownloadTimesAction Add the current download time to the list of already measured ones
double calculateFlatExpTime(double currentADU)
calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
void processCaptureError(ISD::Camera::ErrorType type)
processCaptureError Handle when image capture fails
IPState continueFramingAction(const QSharedPointer< FITSData > &imageData)
continueFramingAction If framing is running, start the next capture sequence
void syncDSLRToTargetChip(const QString &model)
syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
void setDownloadProgress()
setDownloadProgress update the Capture Module and Summary Screen's estimate of how much time is left ...
void prepareJobExecution()
preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and...
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 processJobCompletion1()
processJobCompletionStage1 Process job completion.
void captureImage()
captureImage Initiates image capture in the active job.
bool setDustCap(ISD::DustCap *device)
setDustCap Connect to the given dust cap device (and deconnect the old one if existing)
void restartCamera(const QString &name)
restartCamera Restarts the INDI driver associated with a camera.
bool hasCoolerControl()
Does the CCD has a cooler control (On/Off) ?
void toggleVideo(bool enabled)
Toggle video streaming if supported by the device.
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:25
Handles operation of a remotely controlled dust cover cap.
Definition indidustcap.h:25
Handles operation of a remotely controlled light box.
device handle controlling Mounts.
Definition indimount.h:29
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 Jul 26 2024 11:59:51 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.