Kstars

capturemodulestate.h
1/* Ekos state machine for the Capture module
2 SPDX-FileCopyrightText: 2022 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include <QObject>
10
11#include "Options.h"
12
13#include "ekos/ekos.h"
14#include "indiapi.h"
15#include "indi/indistd.h"
16#include "indi/indidustcap.h"
17#include "indi/indicamera.h"
18#include "indi/indimount.h"
19#include "indi/indidome.h"
20
21#include "ekos/manager/meridianflipstate.h"
22#include "ekos/auxiliary/filtermanager.h"
23#include "ekos/scheduler/schedulertypes.h"
24#include "ekos/capture/refocusstate.h"
25#include "ekos/focus/focusutils.h"
26#include "placeholderpath.h"
27
28// Wait 3-minutes as maximum beyond exposure
29// value.
30#define CAPTURE_TIMEOUT_THRESHOLD 180000
31
32class FITSData;
33
34namespace Ekos
35{
36
37// Typedef for HFR Check algorithms.
38typedef enum
39{
40 HFR_CHECK_LAST_AUTOFOCUS, /* Use last Autofocus as reference */
41 HFR_CHECK_FIXED, /* User supplied fixed reference */
42 HFR_CHECK_MEDIAN_MEASURE, /* Use median algorithm as reference */
43 HFR_CHECK_MAX_ALGO /* Max counter for enum */
44} HFR_CHECK_ALGORITHM;
45constexpr double HFR_CHECK_DEFAULT_THRESHOLD = 10.0;
46
47class SequenceJob;
48class SequenceQueue;
49class CaptureDeviceAdaptor;
50class RefocusState;
51
52class CaptureModuleState: public QObject
53{
55 public:
56 /* Action types to be executed before capturing may start. */
57 typedef enum
58 {
59 ACTION_FILTER, /* Change the filter and wait until the correct filter is set. */
60 ACTION_TEMPERATURE, /* Set the camera chip target temperature and wait until the target temperature has been reached. */
61 ACTION_ROTATOR, /* Set the camera rotator target angle and wait until the target angle has been reached. */
62 ACTION_PREPARE_LIGHTSOURCE, /* Setup the selected flat lights source. */
63 ACTION_MOUNT_PARK, /* Park the mount. */
64 ACTION_DOME_PARK, /* Park the dome. */
65 ACTION_FLAT_SYNC_FOCUS, /* Move the focuser to the focus position for the selected filter. */
66 ACTION_SCOPE_COVER, /* Ensure that the scope cover (if present) is opened. */
67 ACTION_AUTOFOCUS /* Execute autofocus (might be triggered due to filter change). */
68 } PrepareActions;
69
70 typedef enum
71 {
72 SHUTTER_YES, /* the CCD has a shutter */
73 SHUTTER_NO, /* the CCD has no shutter */
74 SHUTTER_BUSY, /* determining whether the CCD has a shutter running */
75 SHUTTER_UNKNOWN /* unknown whether the CCD has a shutter */
76 } ShutterStatus;
77
78 typedef enum
79 {
80 CAP_IDLE,
81 CAP_PARKING,
82 CAP_UNPARKING,
83 CAP_PARKED,
84 CAP_ERROR,
85 CAP_UNKNOWN
86 } CapState;
87
88 typedef enum
89 {
90 CAP_LIGHT_OFF, /* light is on */
91 CAP_LIGHT_ON, /* light is off */
92 CAP_LIGHT_UNKNOWN, /* unknown whether on or off */
93 CAP_LIGHT_BUSY /* light state changing */
94 } LightState;
95
96 typedef enum
97 {
98 CONTINUE_ACTION_NONE, /* do nothing */
99 CONTINUE_ACTION_NEXT_EXPOSURE, /* start next exposure */
100 CONTINUE_ACTION_CAPTURE_COMPLETE /* recall capture complete */
101 } ContinueAction;
102
103 /* Result when starting to capture {@see SequenceJob::capture(bool, FITSMode)}. */
104 typedef enum
105 {
106 CAPTURE_OK, /* Starting a new capture succeeded. */
107 CAPTURE_FRAME_ERROR, /* Setting frame parameters failed, capture not started. */
108 CAPTURE_BIN_ERROR, /* Setting binning parameters failed, capture not started. */
109 CAPTURE_FOCUS_ERROR, /* NOT USED. */
110 } CAPTUREResult;
111
112 /* Interval with double lower and upper bound */
113 typedef struct
114 {
115 double min, max;
116 } DoubleRange;
117
118 CaptureModuleState(QObject *parent = nullptr);
119
120 // ////////////////////////////////////////////////////////////////////
121 // sequence jobs
122 // ////////////////////////////////////////////////////////////////////
123 QList<SequenceJob *> &allJobs();
124
125 QSharedPointer<SequenceQueue> getSequenceQueue()
126 {
127 return m_sequenceQueue;
128 }
129
130 SequenceJob *getActiveJob() const
131 {
132 return m_activeJob;
133 }
134 void setActiveJob(SequenceJob *value);
135
136 const QUrl &sequenceURL() const;
137 void setSequenceURL(const QUrl &newSequenceURL);
138
139 // ////////////////////////////////////////////////////////////////////
140 // pointer to last captured frame
141 // ////////////////////////////////////////////////////////////////////
142 QSharedPointer<FITSData> imageData()
143 {
144 return m_ImageData;
145 }
146 void setImageData(QSharedPointer<FITSData> newImageData)
147 {
148 m_ImageData = newImageData;
149 }
150
151 // ////////////////////////////////////////////////////////////////////
152 // capture attributes
153 // ////////////////////////////////////////////////////////////////////
154 // current filter ID
155 int currentFilterID { Ekos::INVALID_VALUE };
156 // Map tracking whether the current value has been initialized.
157 // With this construct we could do a lazy initialization of current values if setCurrent...()
158 // sets this flag to true. This is necessary since we listen to the events, but as long as
159 // the value does not change, there won't be an event.
160 QMap<PrepareActions, bool> isInitialized;
161
162 // ////////////////////////////////////////////////////////////////////
163 // flat preparation attributes
164 // ////////////////////////////////////////////////////////////////////
165 // flag if telescope has been covered
166 typedef enum
167 {
168 MANAUL_COVER_OPEN,
169 MANUAL_COVER_CLOSED_LIGHT,
170 MANUAL_COVER_CLOSED_DARK
171 } ManualCoverState;
172
173 ManualCoverState m_ManualCoverState { MANAUL_COVER_OPEN };
174 // flag if there is a light box device
175 bool hasLightBox { false };
176 // flag if there is a dust cap device
177 bool hasDustCap { false };
178 // flag if there is a telescope device
179 bool hasTelescope { false };
180 // flag if there is a dome device
181 bool hasDome { false };
182
183 // ////////////////////////////////////////////////////////////////////
184 // dark preparation attributes
185 // ////////////////////////////////////////////////////////////////////
186 ShutterStatus shutterStatus { SHUTTER_UNKNOWN };
187
188
189 // ////////////////////////////////////////////////////////////////////
190 // state changes
191 // ////////////////////////////////////////////////////////////////////
192 /**
193 * @brief captureStarted The preparation to capture have been started.
194 */
195 void initCapturePreparation();
196
197 // ////////////////////////////////////////////////////////////////////
198 // state accessors
199 // ////////////////////////////////////////////////////////////////////
200 CaptureState getCaptureState() const
201 {
202 return m_CaptureState;
203 }
204 void setCaptureState(CaptureState value);
205
206 bool isStartingCapture() const
207 {
208 return m_StartingCapture;
209 }
210 void setStartingCapture(bool newStartingCapture)
211 {
212 m_StartingCapture = newStartingCapture;
213 }
214
215 ContinueAction getContinueAction() const
216 {
217 return m_ContinueAction;
218 }
219 void setContinueAction(ContinueAction newPauseFunction)
220 {
221 m_ContinueAction = newPauseFunction;
222 }
223
224 FocusState getFocusState() const
225 {
226 return m_FocusState;
227 }
228 void setFocusState(FocusState value)
229 {
230 m_FocusState = value;
231 }
232
233 GuideState getGuideState() const
234 {
235 return m_GuideState;
236 }
237 void setGuideState(GuideState state);
238
239 // short cut for all guiding states that indicate guiding is on
240 bool isGuidingOn();
241 // short cut for all guiding states that indicate guiding in state GUIDING
242 bool isActivelyGuiding();
243
244 bool useGuideHead() const
245 {
246 return m_useGuideHead;
247 }
248 void setUseGuideHead(bool value)
249 {
250 m_useGuideHead = value;
251 }
252 bool isGuidingDeviationDetected() const
253 {
254 return m_GuidingDeviationDetected;
255 }
256 void setGuidingDeviationDetected(bool newDeviationDetected)
257 {
258 m_GuidingDeviationDetected = newDeviationDetected;
259 }
260
261 bool suspendGuidingOnDownload() const
262 {
263 return m_SuspendGuidingOnDownload;
264 }
265 void setSuspendGuidingOnDownload(bool value)
266 {
267 m_SuspendGuidingOnDownload = value;
268 }
269
270 int SpikesDetected() const
271 {
272 return m_SpikesDetected;
273 }
274 int increaseSpikesDetected()
275 {
276 return ++m_SpikesDetected;
277 }
278 void resetSpikesDetected()
279 {
280 m_SpikesDetected = 0;
281 }
282
283 IPState getDitheringState() const
284 {
285 return m_DitheringState;
286 }
287 void setDitheringState(IPState value)
288 {
289 m_DitheringState = value;
290 }
291
292 AlignState getAlignState() const
293 {
294 return m_AlignState;
295 }
296 void setAlignState(AlignState value);
297
298 FilterState getFilterManagerState() const
299 {
300 return m_FilterManagerState;
301 }
302 void setFilterManagerState(FilterState value)
303 {
304 m_FilterManagerState = value;
305 }
306
307 int getCurrentFilterPosition() const
308 {
309 return m_CurrentFilterPosition;
310 }
311
312 const QString &getCurrentFilterName() const
313 {
314 return m_CurrentFilterName;
315 }
316
317 const QString &CurrentFocusFilterName() const
318 {
319 return m_CurrentFocusFilterName;
320 }
321
322 void setCurrentFilterPosition(int position, const QString &name, const QString &focusFilterName);
323
324 LightState getLightBoxLightState() const
325 {
326 return m_lightBoxLightState;
327 }
328 void setLightBoxLightState(LightState value)
329 {
330 m_lightBoxLightState = value;
331 }
332
333 bool lightBoxLightEnabled() const
334 {
335 return m_lightBoxLightEnabled;
336 }
337 void setLightBoxLightEnabled(bool value)
338 {
339 m_lightBoxLightEnabled = value;
340 }
341
342 CapState getDustCapState() const
343 {
344 return m_dustCapState;
345 }
346 void setDustCapState(CapState value)
347 {
348 m_dustCapState = value;
349 }
350
351 ISD::Mount::Status getScopeState() const
352 {
353 return m_scopeState;
354 }
355 void setScopeState(ISD::Mount::Status value)
356 {
357 m_scopeState = value;
358 }
359
360 ISD::Mount::PierSide getPierSide() const
361 {
362 return m_pierSide;
363 }
364 void setPierSide(ISD::Mount::PierSide value)
365 {
366 m_pierSide = value;
367 }
368
369 ISD::ParkStatus getScopeParkState() const
370 {
371 return m_scopeParkState;
372 }
373 void setScopeParkState(ISD::ParkStatus value)
374 {
375 m_scopeParkState = value;
376 }
377
378 ISD::Dome::Status getDomeState() const
379 {
380 return m_domeState;
381 }
382 void setDomeState(ISD::Dome::Status value)
383 {
384 m_domeState = value;
385 }
386
387 QSharedPointer<MeridianFlipState> getMeridianFlipState();
388 void setMeridianFlipState(QSharedPointer<MeridianFlipState> state);
389
390 QSharedPointer<RefocusState> getRefocusState() const
391 {
392 return m_refocusState;
393 }
394
395 const QString &observerName() const
396 {
397 return m_ObserverName;
398 }
399 void setObserverName(const QString &value);
400
401 bool ignoreJobProgress() const
402 {
403 return m_ignoreJobProgress;
404 }
405 void setIgnoreJobProgress(bool value)
406 {
407 m_ignoreJobProgress = value;
408 }
409
410 bool isRememberFastExposure() const
411 {
412 return m_RememberFastExposure;
413 }
414 void setRememberFastExposure(bool value)
415 {
416 m_RememberFastExposure = value;
417 }
418
419 bool dirty() const
420 {
421 return m_Dirty;
422 }
423 void setDirty(bool value)
424 {
425 m_Dirty = value;
426 }
427
428 bool isBusy() const
429 {
430 return m_Busy;
431 }
432 void setBusy(bool busy);
433
434 bool isLooping() const
435 {
436 return m_Looping;
437 }
438 void setLooping(bool newLooping)
439 {
440 m_Looping = newLooping;
441 }
442
443 QJsonArray &getSequence()
444 {
445 return m_SequenceArray;
446 }
447 void setSequence(const QJsonArray &value)
448 {
449 m_SequenceArray = value;
450 }
451
452 PlaceholderPath &placeholderPath()
453 {
454 return m_currentPlaceholderPath;
455 }
456 void initPlaceholderPath()
457 {
458 m_currentPlaceholderPath = PlaceholderPath();
459 }
460
461 /**
462 * @brief generateFilename generate the final file name for storing captured frames locally.
463 * @param extension file name extension (including ".")
464 * @param filename resulting file name
465 * @return
466 */
467 bool generateFilename(const QString &extension, QString *filename);
468
469 // ////////////////////////////////////////////////////////////////////
470 // counters
471 // ////////////////////////////////////////////////////////////////////
472
473 int getAlignmentRetries() const
474 {
475 return m_AlignmentRetries;
476 }
477 int increaseAlignmentRetries()
478 {
479 return ++m_AlignmentRetries;
480 }
481 void resetAlignmentRetries()
482 {
483 m_AlignmentRetries = 0;
484 }
485
486 int getDitherCounter() const
487 {
488 return m_ditherCounter;
489 }
490 void decreaseDitherCounter();
491
492 /**
493 * @brief resetDitherCounter Reset the dither counter to its start value. If a per job counter is
494 * set to > 0, this value is used and the general dither counter otherwise.
495 */
496 void resetDitherCounter();
497
498 int nextSequenceID() const
499 {
500 return m_nextSequenceID;
501 }
502 void setNextSequenceID(int id)
503 {
504 m_nextSequenceID = id;
505 }
506
507 uint16_t capturedFramesCount(const QString &signature) const
508 {
509 return m_capturedFramesMap[signature];
510 }
511 void setCapturedFramesCount(const QString &signature, uint16_t count);
512
513 double lastRemainingFrameTimeMS() const
514 {
515 return m_lastRemainingFrameTimeMS;
516 }
517 void setLastRemainingFrameTimeMS(double value)
518 {
519 m_lastRemainingFrameTimeMS = value;
520 }
521
522 // ////////////////////////////////////////////////////////////////////
523 // Timers
524 // ////////////////////////////////////////////////////////////////////
525 QTimer &getCaptureTimeout()
526 {
527 return m_captureTimeout;
528 }
529 uint8_t captureTimeoutCounter() const
530 {
531 return m_CaptureTimeoutCounter;
532 }
533 void setCaptureTimeoutCounter(uint8_t value)
534 {
535 m_CaptureTimeoutCounter = value;
536 }
537 uint8_t deviceRestartCounter() const
538 {
539 return m_DeviceRestartCounter;
540 }
541 void setDeviceRestartCounter(uint8_t value)
542 {
543 m_DeviceRestartCounter = value;
544 }
545 QTimer &downloadProgressTimer()
546 {
547 return m_downloadProgressTimer;
548 }
549 QElapsedTimer &downloadTimer()
550 {
551 return m_DownloadTimer;
552 }
553 QTimer &getCaptureDelayTimer()
554 {
555 return m_captureDelayTimer;
556 }
557 QTimer &getGuideDeviationTimer()
558 {
559 return m_guideDeviationTimer;
560 }
561
562 QTime &imageCountDown()
563 {
564 return m_imageCountDown;
565 }
566 void imageCountDownAddMSecs(int value)
567 {
568 m_imageCountDown = m_imageCountDown.addMSecs(value);
569 }
570
571 QTime &sequenceCountDown()
572 {
573 return m_sequenceCountDown;
574 }
575 void sequenceCountDownAddMSecs(int value)
576 {
577 m_sequenceCountDown = m_sequenceCountDown.addMSecs(value);
578 }
579
580 /**
581 * @brief changeSequenceValue Change a single sequence in the sequence array
582 * @param index position in the array
583 * @param key sequence key
584 * @param value new sequence value
585 */
586 void changeSequenceValue(int index, QString key, QString value);
587
588 // ////////////////////////////////////////////////////////////////////
589 // Action checks
590 // ////////////////////////////////////////////////////////////////////
591 /**
592 * @brief Check, whether dithering is necessary and, in that case initiate it.
593 *
594 * Dithering is only required for batch images and does not apply for PREVIEW.
595 *
596 * There are several situations that determine, if dithering is necessary:
597 * 1. the current job captures light frames AND the dither counter has reached 0 AND
598 * 2. guiding is running OR the manual dithering option is selected AND
599 * 3. there is a guiding camera active AND
600 * 4. there hasn't just a meridian flip been finised.
601 *
602 * @return true iff dithering is necessary.
603 */
604
605 bool checkDithering();
606
607 bool checkCapturing()
608 {
609 return (m_CaptureState == CAPTURE_CAPTURING || m_CaptureState == CAPTURE_PAUSE_PLANNED);
610 }
611
612 /**
613 * @brief updateMFMountState Handle changes of the meridian flip mount state
614 */
615 void updateMFMountState(MeridianFlipState::MeridianFlipMountState status);
616
617 /**
618 * @brief updateMeridianFlipStage Update the meridian flip stage
619 */
620 void updateMeridianFlipStage(const MeridianFlipState::MFStage &stage);
621
622 /**
623 * @brief checkMeridianFlipActive
624 * @return true iff the meridian flip itself or post flip actions are running
625 */
626 bool checkMeridianFlipActive();
627
628 /**
629 * @brief Check whether a meridian flip has been requested and trigger it
630 * @return true iff a meridian flip has been triggered
631 */
632 bool checkMeridianFlipReady();
633
634 /**
635 * @brief checkPostMeridianFlipActions Execute the checks necessary after the mount
636 * has completed the meridian flip.
637 * @return true iff the post meridian flip actions are ongoing, false if completed or not necessary
638 */
639 bool checkPostMeridianFlipActions();
640
641 /**
642 * @brief Check if an alignment needs to be executed after completing
643 * a meridian flip.
644 * @return
645 */
646 bool checkAlignmentAfterFlip();
647
648 /**
649 * @brief checkGuideDeviationTimeout Handle timeout when no guide deviation has been received.
650 */
651 void checkGuideDeviationTimeout();
652
653 /**
654 * @brief Check if the mount's flip has been completed and start guiding
655 * if necessary. Starting guiding after the meridian flip works through
656 * the signal {@see startGuidingAfterFlip()}
657 * @return true if guiding needs to start but is not running yet
658 */
659 bool checkGuidingAfterFlip();
660
661 /**
662 * @brief processGuidingFailed React when guiding failed.
663 *
664 * If aguiding has been started before and stopped, capturing aborts except
665 * for the case that either
666 * - a meridian flip is running
667 * - a job is running for non light frames
668 * - capturing is either paused or suspended
669 * In these case, nothing is done.
670 */
671 void processGuidingFailed();
672
673 /**
674 * @brief Process changes necessary when the focus state changes.
675 */
676 void updateFocusState(FocusState state);
677
678 /**
679 * @brief Check if focusing is running (abbreviating function for focus state
680 * neither idle nor completed nor aborted).
681 */
682 bool checkFocusRunning()
683 {
684 return (m_FocusState != FOCUS_IDLE && m_FocusState != FOCUS_COMPLETE && m_FocusState != FOCUS_ABORTED);
685 }
686
687 /**
688 * @brief Converts from RefocusReason (used by Capture) to AutofocusReason (used by Focus)
689 * @param reasonInfo for the associated reason code
690 * @return Reason code for the Autofocus
691 */
692 AutofocusReason getAFReason(RefocusState::RefocusReason state, QString &reasonInfo);
693
694 /**
695 * @brief Start focusing if necessary (see {@see RefocusState#checkFocusRequired()}).
696 * @return TRUE if we need to run focusing, false if not necessary
697 */
698 bool startFocusIfRequired();
699
700 /**
701 * @brief Start adaptive focus if necessary
702 * @return TRUE if we need adaptive focus, false if not necessary
703 */
704
705 void updateAdaptiveFocusState(bool success);
706
707 /**
708 * @brief calculate new HFR threshold based on median value for current selected filter
709 */
710 void updateHFRThreshold();
711
712 /**
713 * @brief get the focus filter for the currently active capture filter
714 */
715 QString getFocusFilterName();
716
717 /**
718 * @brief Slot that listens to guiding deviations reported by the Guide module.
719 *
720 * Depending on the current status, it triggers several actions:
721 * - If there is no active job, it calls {@see m_captureModuleState->checkMeridianFlipReady()}, which may initiate a meridian flip.
722 * - If guiding has been started after a meridian flip and the deviation is within the expected limits,
723 * the meridian flip is regarded as completed by setMeridianFlipStage(MF_NONE) (@see setMeridianFlipStage()).
724 * - If the deviation is beyond the defined limit, capturing is suspended (@see suspend()) and the
725 * #guideDeviationTimer is started.
726 * - Otherwise, it checks if there has been a job suspended and restarts it, since guiding is within the limits.
727 */
728
729 void setGuideDeviation(double deviation_rms);
730
731 /**
732 * @brief addDownloadTime Record a new download time
733 */
734 void addDownloadTime(double time);
735
736 /**
737 * @brief averageDownloadTime Determine the average download time
738 * @return
739 */
740 double averageDownloadTime()
741 {
742 return (downloadsCounter == 0 ? 0 : totalDownloadTime / downloadsCounter);
743 }
744
745 /**
746 * @brief setDarkFlatExposure Given a dark flat job, find the exposure suitable from it by searching for
747 * completed flat frames.
748 * @param job Dark flat job
749 * @return True if a matching exposure is found and set, false otherwise.
750 * @warning This only works if the flat frames were captured in the same live session.
751 * If the flat frames were captured in another session (i.e. Ekos restarted), then all automatic exposure
752 * calculation results are discarded since Ekos does not save this information to the sequene file.
753 * Possible solution is to write to a local config file to keep this information persist between sessions.
754 */
755 bool setDarkFlatExposure(SequenceJob *job);
756
757 /**
758 * @brief checkSeqBoundary Determine the next file number sequence.
759 * That is, if we have file1.png and file2.png, then the next
760 * sequence should be file3.png.
761 */
762 void checkSeqBoundary();
763 /**
764 * @brief isModelinDSLRInfo Check if the DSLR model is already known
765 */
766 bool isModelinDSLRInfo(const QString &model);
767
768 // ////////////////////////////////////////////////////////////////////
769 // Helper functions
770 // ////////////////////////////////////////////////////////////////////
771
772 /**
773 * @brief activeJobID Determine the ID of the currently active job
774 */
775 int activeJobID();
776
777 /**
778 * @brief pPendingJobCount Returns the number of pending uncompleted jobs in the sequence queue.
779 */
780 int pendingJobCount();
781
782 /**
783 * @brief getJobState Returns the job state (Idle, In Progress, Error, Aborted, Complete)
784 * @param id job number. Job IDs start from 0 to N-1.
785 */
786
787 QString jobState(int id);
788
789 /**
790 * @brief jobFilterName Returns the job filter name.
791 * @param id job number. Job IDs start from 0 to N-1.
792 */
793 QString jobFilterName(int id);
794
795 /**
796 * @param id job number. Job IDs start from 0 to N-1.
797 * @return Returns the frame type (light, dark, ...) of the job.
798 */
799 CCDFrameType jobFrameType(int id);
800
801 /**
802 * @brief jobImageProgress Returns The number of images completed capture in the job.
803 * @param id job number. Job IDs start from 0 to N-1.
804 */
805 int jobImageProgress(int id);
806
807 /**
808 * @param id job number. Job IDs start from 0 to N-1.
809 * @return Returns the total number of images to capture in the job.
810 */
811 int jobImageCount(int id);
812
813 /**
814 * @param id job number. Job IDs start from 0 to N-1.
815 * @return Returns the number of seconds left in an exposure operation.
816 */
817 double jobExposureProgress(int id);
818
819 /**
820 * @param id job number. Job IDs start from 0 to N-1.
821 * @return Returns the total requested exposure duration in the job.
822 */
823 double jobExposureDuration(int id);
824
825 /**
826 * @return Returns the percentage of completed captures in all active jobs
827 */
828 double progressPercentage();
829
830 /**
831 * @return Returns true if there's an active job and it is a preview job.
832 */
833 bool isActiveJobPreview();
834
835 /**
836 * @return Returns time left in seconds until active job is estimated to be complete.
837 */
838 int activeJobRemainingTime();
839
840 /**
841 * @return Returns overall time left in seconds until all jobs are estimated to be complete
842 */
843 int overallRemainingTime();
844
845 /**
846 * Returns the overall sequence queue status. If there are no jobs pending, it returns "Invalid". If all jobs are idle, it returns "Idle". If all jobs are complete, it returns "Complete". If one or more jobs are aborted
847 * it returns "Aborted" unless it was temporarily aborted due to guiding deviations, then it would return "Suspended". If one or more jobs have errors, it returns "Error". If any jobs is under progress, returns "Running".
848 */
849 QString sequenceQueueStatus();
850
851 /**
852 * @brief getCalibrationSettings Get Calibration settings
853 * @return settings as JSON object
854 */
855 QJsonObject calibrationSettings();
856
857 /**
858 * @brief setCalibrationSettings Set Calibration settings
859 * @param settings as JSON object
860 */
861 void setCalibrationSettings(const QJsonObject &settings);
862
863 /**
864 * @brief hasCapturedFramesMap Check if at least one frame has been recorded
865 */
866 bool hasCapturedFramesMap()
867 {
868 return m_capturedFramesMap.count() > 0;
869 }
870 /**
871 * @brief addCapturedFrame Record a captured frame
872 */
873 void addCapturedFrame(const QString &signature);
874 /**
875 * @brief removeCapturedFrameCount Reduce the frame counts for the given signature
876 */
877 void removeCapturedFrameCount(const QString &signature, uint16_t count);
878 /**
879 * @brief clearCapturedFramesMap Clear the map of captured frames counts
880 */
881 void clearCapturedFramesMap()
882 {
883 m_capturedFramesMap.clear();
884 }
885
886 bool isCaptureRunning()
887 {
888 return (m_CaptureState != CAPTURE_IDLE && m_CaptureState != CAPTURE_COMPLETE && m_CaptureState != CAPTURE_ABORTED);
889 }
890
891 ScriptTypes captureScriptType() const
892 {
893 return m_CaptureScriptType;
894 }
895 void setCaptureScriptType(ScriptTypes value)
896 {
897 m_CaptureScriptType = value;
898 }
899 double targetADU() const
900 {
901 return m_targetADU;
902 }
903 void setTargetADU(double value)
904 {
905 m_targetADU = value;
906 }
907 double targetADUTolerance() const
908 {
909 return m_TargetADUTolerance;
910 }
911 void setTargetADUTolerance(double value)
912 {
913 m_TargetADUTolerance = value;
914 }
915 bool skyFlat() const
916 {
917 return m_skyFlat;
918 }
919 void setSkyFlat(bool enabled)
920 {
921 m_skyFlat = enabled;
922 }
923 SkyPoint &wallCoord()
924 {
925 return m_wallCoord;
926 }
927 void setWallCoord(SkyPoint value)
928 {
929 m_wallCoord = value;
930 }
931 const DoubleRange &exposureRange() const
932 {
933 return m_ExposureRange;
934 }
935 void setExposureRange(double min, double max)
936 {
937 m_ExposureRange.min = min;
938 m_ExposureRange.max = max;
939 }
940
942 {
943 return m_frameSettings;
944 }
945 void setFrameSettings(const QMap<ISD::CameraChip *, QVariantMap> &value)
946 {
947 m_frameSettings = value;
948 }
949
950 FlatFieldDuration flatFieldDuration() const
951 {
952 return m_flatFieldDuration;
953 }
954 void setFlatFieldDuration(FlatFieldDuration value)
955 {
956 m_flatFieldDuration = value;
957 }
958
959 uint32_t calibrationPreAction() const
960 {
961 return m_CalibrationPreAction;
962 }
963 void setCalibrationPreAction(uint32_t value)
964 {
965 m_CalibrationPreAction = value;
966 }
967
968 QList<QMap<QString, QVariant> > &DSLRInfos()
969 {
970 return m_DSLRInfos;
971 }
972
973signals:
974 // controls for capture execution
975 void captureBusy(bool busy);
976 void startCapture();
977 void abortCapture();
978 void suspendCapture();
979 void executeActiveJob();
980 void updatePrepareState(CaptureState state);
981 void captureStarted(CAPTUREResult rc);
982 // mount meridian flip status update event
983 void newMeridianFlipStage(MeridianFlipState::MFStage status);
984 // meridian flip started
985 void meridianFlipStarted();
986 // new guiding deviation measured
987 void newGuiderDrift(double deviation_rms);
988 // guiding should be started after a successful meridian flip
989 void guideAfterMeridianFlip();
990 // new capture state
991 void newStatus(Ekos::CaptureState status);
992 // forward new focus status
993 void newFocusStatus(FocusState status);
994 // forward new adaptive focus status
995 void newAdaptiveFocusStatus(bool success);
996 // check focusing is necessary for the given HFR
997 void checkFocus(double hfr);
998 // run Autofocus
999 void runAutoFocus(AutofocusReason autofocusReason, const QString &reasonInfo);
1000 // reset the focuser to the last known focus position
1001 void resetFocus();
1002 // signal focus module to perform adaptive focus
1003 void adaptiveFocus();
1004 // abort capturing if fast exposure mode is used
1005 void abortFastExposure();
1006 // new HFR focus limit calculated
1007 void newLimitFocusHFR(double hfr);
1008 // Select the filter at the given position
1009 void newFilterPosition(int targetFilterPosition, FilterManager::FilterPolicy policy = FilterManager::ALL_POLICIES);
1010 // capture sequence status changes
1011 void sequenceChanged(const QJsonArray &sequence);
1012 // new log text for the module log window
1013 void newLog(const QString &text);
1014
1015 private:
1016 // Container for the list of SequenceJobs.
1017 QSharedPointer<SequenceQueue> m_sequenceQueue;
1018 // Currently active sequence job.
1019 SequenceJob *m_activeJob { nullptr };
1020 // pointer to the image data
1021 QSharedPointer<FITSData> m_ImageData;
1022 // CCD Chip frame settings
1024 // DSLR Infos
1025 QList<QMap<QString, QVariant>> m_DSLRInfos;
1026
1027 // current filter position
1028 // TODO: check why we have both currentFilterID and this, seems redundant
1029 int m_CurrentFilterPosition { -1 };
1030 // current filter name matching the filter position
1031 QString m_CurrentFilterName { "--" };
1032 // holds the filter name used for focusing or "--" if the current one is used
1033 QString m_CurrentFocusFilterName { "--" };
1034 // Captured Frames Map
1035 CapturedFramesMap m_capturedFramesMap;
1036 // are we in the starting phase of capturing?
1037 bool m_StartingCapture { true };
1038 // Does the camera have a dedicated guiding chip?
1039 bool m_useGuideHead { false };
1040 // Guide Deviation
1041 bool m_GuidingDeviationDetected { false };
1042 // suspend guiding when downloading a captured image
1043 bool m_SuspendGuidingOnDownload { false };
1044 // Guiding spikes
1045 int m_SpikesDetected { 0 };
1046 // Timer for guiding recovery
1047 QTimer m_guideDeviationTimer;
1048 // Capture timeout timer
1049 QTimer m_captureTimeout;
1050 uint8_t m_CaptureTimeoutCounter { 0 };
1051 uint8_t m_DeviceRestartCounter { 0 };
1052 // time left of the current exposure
1053 QTime m_imageCountDown;
1054 double m_lastRemainingFrameTimeMS;
1055 // Timer for delay before capturing an image
1056 // @see CaptureProcess::captureImageWithDelay()
1057 QTimer m_captureDelayTimer;
1058 // time left for the current sequence
1059 QTime m_sequenceCountDown;
1060 // timer for updating the download progress
1061 QTimer m_downloadProgressTimer;
1062 // timer measuring the download time
1063 QElapsedTimer m_DownloadTimer;
1064 // sum over all recorded list of download times
1065 double totalDownloadTime {0};
1066 // number of downloaded frames
1067 uint downloadsCounter {0};
1068 // current placeholder path
1069 PlaceholderPath m_currentPlaceholderPath;
1070 // next capture sequence ID
1071 int m_nextSequenceID { 0 };
1072 // how to continue after pausing
1073 ContinueAction m_ContinueAction { CONTINUE_ACTION_NONE };
1074 // name of the observer
1075 QString m_ObserverName;
1076 // ignore already captured files
1077 bool m_ignoreJobProgress { true };
1078 // Fast Exposure
1079 bool m_RememberFastExposure {false};
1080 // Set dirty bit to indicate sequence queue file was modified and needs saving.
1081 bool m_Dirty { false };
1082 // Capturing (incl. preparation actions) is active
1083 bool m_Busy { false };
1084 // preview loop running
1085 bool m_Looping { false };
1086 // script type of the currently running script
1087 ScriptTypes m_CaptureScriptType { SCRIPT_N };
1088 // Flat field automation
1089 double m_TargetADUTolerance { 1000 };
1090 double m_targetADU { 0 };
1091 bool m_skyFlat { false };
1092 SkyPoint m_wallCoord;
1093 FlatFieldDuration m_flatFieldDuration { DURATION_MANUAL };
1094 uint32_t m_CalibrationPreAction { ACTION_NONE };
1095 bool m_lightBoxLightEnabled { false };
1096 // Allowed camera exposure times
1097 DoubleRange m_ExposureRange;
1098 // Misc
1099 QJsonArray m_SequenceArray;
1100
1101 // ////////////////////////////////////////////////////////////////////
1102 // device states
1103 // ////////////////////////////////////////////////////////////////////
1104 CaptureState m_CaptureState { CAPTURE_IDLE };
1105 FocusState m_FocusState { FOCUS_IDLE };
1106 GuideState m_GuideState { GUIDE_IDLE };
1107 IPState m_DitheringState {IPS_IDLE};
1108 AlignState m_AlignState { ALIGN_IDLE };
1109 FilterState m_FilterManagerState { FILTER_IDLE };
1110 LightState m_lightBoxLightState { CAP_LIGHT_UNKNOWN };
1111 CapState m_dustCapState { CAP_UNKNOWN };
1112 ISD::Mount::Status m_scopeState { ISD::Mount::MOUNT_IDLE };
1113 ISD::Mount::PierSide m_pierSide { ISD::Mount::PIER_UNKNOWN };
1114 ISD::ParkStatus m_scopeParkState { ISD::PARK_UNKNOWN };
1115 ISD::Dome::Status m_domeState { ISD::Dome::DOME_IDLE };
1116
1117 // ////////////////////////////////////////////////////////////////////
1118 // counters
1119 // ////////////////////////////////////////////////////////////////////
1120 // Number of alignment retries
1121 int m_AlignmentRetries { 0 };
1122 // How many images to capture before dithering operation is executed?
1123 uint m_ditherCounter { 0 };
1124
1125 /* Refocusing */
1126 QSharedPointer<RefocusState> m_refocusState;
1127 /* Meridian Flip */
1129
1130 /**
1131 * @brief Add log message
1132 */
1133 void appendLogText(const QString &message);
1134
1135};
1136
1137}; // namespace
Sequence Job is a container for the details required to capture a series of images.
The sky coordinates of a point in the sky.
Definition skypoint.h:45
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:79
QMap< QString, uint16_t > CapturedFramesMap
mapping signature --> frames count
@ ALIGN_IDLE
No ongoing operations.
Definition ekos.h:146
CaptureState
Capture states.
Definition ekos.h:92
@ CAPTURE_PAUSE_PLANNED
Definition ekos.h:96
@ CAPTURE_ABORTED
Definition ekos.h:99
@ CAPTURE_COMPLETE
Definition ekos.h:112
@ CAPTURE_CAPTURING
Definition ekos.h:95
@ CAPTURE_IDLE
Definition ekos.h:93
void clear()
size_type count() const const
Q_OBJECTQ_OBJECT
QObject * parent() const const
QTime addMSecs(int ms) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:48:25 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.