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

KDE's Doxygen guidelines are available online.