Kstars

camerastate.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 CameraState: 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 CameraState(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 uint SpikesDetected() const
271 {
272 return m_SpikesDetected;
273 }
274 uint 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 /**
343 * @brief dust cap status change
344 */
345 void dustCapStateChanged(ISD::DustCap::Status status);
346
347 CapState getDustCapState() const
348 {
349 return m_dustCapState;
350 }
351 void setDustCapState(CapState value)
352 {
353 m_dustCapState = value;
354 }
355
356 ISD::Mount::Status getScopeState() const
357 {
358 return m_scopeState;
359 }
360 void setScopeState(ISD::Mount::Status value)
361 {
362 m_scopeState = value;
363 }
364
365 ISD::Mount::PierSide getPierSide() const
366 {
367 return m_pierSide;
368 }
369 void setPierSide(ISD::Mount::PierSide value)
370 {
371 m_pierSide = value;
372 }
373
374 ISD::ParkStatus getScopeParkState() const
375 {
376 return m_scopeParkState;
377 }
378 void setScopeParkState(ISD::ParkStatus value)
379 {
380 m_scopeParkState = value;
381 }
382
383 ISD::Dome::Status getDomeState() const
384 {
385 return m_domeState;
386 }
387 void setDomeState(ISD::Dome::Status value)
388 {
389 m_domeState = value;
390 }
391
392 QSharedPointer<MeridianFlipState> getMeridianFlipState();
393 void setMeridianFlipState(QSharedPointer<MeridianFlipState> state);
394
395 QSharedPointer<RefocusState> getRefocusState() const
396 {
397 return m_refocusState;
398 }
399
400 const QString &observerName() const
401 {
402 return m_ObserverName;
403 }
404 void setObserverName(const QString &value);
405
406 bool ignoreJobProgress() const
407 {
408 return m_ignoreJobProgress;
409 }
410 void setIgnoreJobProgress(bool value)
411 {
412 m_ignoreJobProgress = value;
413 }
414
415 bool isRememberFastExposure() const
416 {
417 return m_RememberFastExposure;
418 }
419 void setRememberFastExposure(bool value)
420 {
421 m_RememberFastExposure = value;
422 }
423
424 bool dirty() const
425 {
426 return m_Dirty;
427 }
428 void setDirty(bool value)
429 {
430 m_Dirty = value;
431 }
432
433 bool isBusy() const
434 {
435 return m_Busy;
436 }
437 void setBusy(bool busy);
438
439 bool isLooping() const
440 {
441 return m_Looping;
442 }
443 void setLooping(bool newLooping)
444 {
445 m_Looping = newLooping;
446 }
447
448 QJsonArray &getSequence()
449 {
450 return m_SequenceArray;
451 }
452 void setSequence(const QJsonArray &value)
453 {
454 m_SequenceArray = value;
455 }
456
457 PlaceholderPath &placeholderPath()
458 {
459 return m_currentPlaceholderPath;
460 }
461 void initPlaceholderPath()
462 {
463 m_currentPlaceholderPath = PlaceholderPath();
464 }
465
466 /**
467 * @brief generateFilename generate the final file name for storing captured frames locally.
468 * @param extension file name extension (including ".")
469 * @param filename resulting file name
470 * @return
471 */
472 bool generateFilename(const QString &extension, QString *filename);
473
474 // ////////////////////////////////////////////////////////////////////
475 // counters
476 // ////////////////////////////////////////////////////////////////////
477
478 int getAlignmentRetries() const
479 {
480 return m_AlignmentRetries;
481 }
482 int increaseAlignmentRetries()
483 {
484 return ++m_AlignmentRetries;
485 }
486 void resetAlignmentRetries()
487 {
488 m_AlignmentRetries = 0;
489 }
490
491 int getDitherCounter() const
492 {
493 return m_ditherCounter;
494 }
495 void decreaseDitherCounter();
496
497 /**
498 * @brief resetDitherCounter Reset the dither counter to its start value. If a per job counter is
499 * set to > 0, this value is used and the general dither counter otherwise.
500 */
501 void resetDitherCounter();
502
503 int nextSequenceID() const
504 {
505 return m_nextSequenceID;
506 }
507 void setNextSequenceID(int id)
508 {
509 m_nextSequenceID = id;
510 }
511
512 uint16_t capturedFramesCount(const QString &signature) const
513 {
514 return m_capturedFramesMap[signature];
515 }
516 void setCapturedFramesCount(const QString &signature, uint16_t count);
517
518 double lastRemainingFrameTimeMS() const
519 {
520 return m_lastRemainingFrameTimeMS;
521 }
522 void setLastRemainingFrameTimeMS(double value)
523 {
524 m_lastRemainingFrameTimeMS = value;
525 }
526
527 // ////////////////////////////////////////////////////////////////////
528 // Timers
529 // ////////////////////////////////////////////////////////////////////
530 QTimer &getCaptureTimeout()
531 {
532 return m_captureTimeout;
533 }
534 uint8_t captureTimeoutCounter() const
535 {
536 return m_CaptureTimeoutCounter;
537 }
538 void setCaptureTimeoutCounter(uint8_t value)
539 {
540 m_CaptureTimeoutCounter = value;
541 }
542 uint8_t deviceRestartCounter() const
543 {
544 return m_DeviceRestartCounter;
545 }
546 void setDeviceRestartCounter(uint8_t value)
547 {
548 m_DeviceRestartCounter = value;
549 }
550 QTimer &downloadProgressTimer()
551 {
552 return m_downloadProgressTimer;
553 }
554 QElapsedTimer &downloadTimer()
555 {
556 return m_DownloadTimer;
557 }
558 QTimer &getCaptureDelayTimer()
559 {
560 return m_captureDelayTimer;
561 }
562 QTimer &getGuideDeviationTimer()
563 {
564 return m_guideDeviationTimer;
565 }
566
567 QTime &imageCountDown()
568 {
569 return m_imageCountDown;
570 }
571 void imageCountDownAddMSecs(int value)
572 {
573 m_imageCountDown = m_imageCountDown.addMSecs(value);
574 }
575
576 QTime &sequenceCountDown()
577 {
578 return m_sequenceCountDown;
579 }
580 void sequenceCountDownAddMSecs(int value)
581 {
582 m_sequenceCountDown = m_sequenceCountDown.addMSecs(value);
583 }
584
585 /**
586 * @brief changeSequenceValue Change a single sequence in the sequence array
587 * @param index position in the array
588 * @param key sequence key
589 * @param value new sequence value
590 */
591 void changeSequenceValue(int index, QString key, QString value);
592
593 // ////////////////////////////////////////////////////////////////////
594 // Action checks
595 // ////////////////////////////////////////////////////////////////////
596 /**
597 * @brief Check, whether dithering is necessary and, in that case initiate it.
598 *
599 * Dithering is only required for batch images and does not apply for PREVIEW.
600 *
601 * There are several situations that determine, if dithering is necessary:
602 * 1. the current job captures light frames AND the dither counter has reached 0 AND
603 * 2. guiding is running OR the manual dithering option is selected AND
604 * 3. there is a guiding camera active AND
605 * 4. there hasn't just a meridian flip been finised.
606 *
607 * @return true iff dithering is necessary.
608 */
609
610 bool checkDithering();
611
612 bool checkCapturing()
613 {
614 return (m_CaptureState == CAPTURE_CAPTURING || m_CaptureState == CAPTURE_PAUSE_PLANNED);
615 }
616
617 /**
618 * @brief updateMFMountState Handle changes of the meridian flip mount state
619 */
620 void updateMFMountState(MeridianFlipState::MeridianFlipMountState status);
621
622 /**
623 * @brief updateMeridianFlipStage Update the meridian flip stage
624 */
625 void updateMeridianFlipStage(const MeridianFlipState::MFStage &stage);
626
627 /**
628 * @brief checkMeridianFlipActive
629 * @return true iff the meridian flip itself or post flip actions are running
630 */
631 bool checkMeridianFlipActive();
632
633 /**
634 * @brief Check whether a meridian flip has been requested and trigger it
635 * @return true iff a meridian flip has been triggered
636 */
637 bool checkMeridianFlipReady();
638
639 /**
640 * @brief checkPostMeridianFlipActions Execute the checks necessary after the mount
641 * has completed the meridian flip.
642 * @return true iff the post meridian flip actions are ongoing, false if completed or not necessary
643 */
644 bool checkPostMeridianFlipActions();
645
646 /**
647 * @brief Check if an alignment needs to be executed after completing
648 * a meridian flip.
649 * @return
650 */
651 bool checkAlignmentAfterFlip();
652
653 /**
654 * @brief checkGuideDeviationTimeout Handle timeout when no guide deviation has been received.
655 */
656 void checkGuideDeviationTimeout();
657
658 /**
659 * @brief Check if the mount's flip has been completed and start guiding
660 * if necessary. Starting guiding after the meridian flip works through
661 * the signal {@see startGuidingAfterFlip()}
662 * @return true if guiding needs to start but is not running yet
663 */
664 bool checkGuidingAfterFlip();
665
666 /**
667 * @brief processGuidingFailed React when guiding failed.
668 *
669 * If aguiding has been started before and stopped, capturing aborts except
670 * for the case that either
671 * - a meridian flip is running
672 * - a job is running for non light frames
673 * - capturing is either paused or suspended
674 * In these case, nothing is done.
675 */
676 void processGuidingFailed();
677
678 /**
679 * @brief Process changes necessary when the focus state changes.
680 */
681 void updateFocusState(FocusState state);
682
683 /**
684 * @brief Check if focusing is running (abbreviating function for focus state
685 * neither idle nor completed nor aborted).
686 */
687 bool checkFocusRunning()
688 {
689 return (m_FocusState != FOCUS_IDLE && m_FocusState != FOCUS_COMPLETE && m_FocusState != FOCUS_ABORTED);
690 }
691
692 /**
693 * @brief Converts from RefocusReason (used by Capture) to AutofocusReason (used by Focus)
694 * @param reasonInfo for the associated reason code
695 * @return Reason code for the Autofocus
696 */
697 AutofocusReason getAFReason(RefocusState::RefocusReason state, QString &reasonInfo);
698
699 /**
700 * @brief Start focusing if necessary (see {@see RefocusState#checkFocusRequired()}).
701 * @return TRUE if we need to run focusing, false if not necessary
702 */
703 bool startFocusIfRequired();
704
705 /**
706 * @brief Start adaptive focus if necessary
707 * @return TRUE if we need adaptive focus, false if not necessary
708 */
709
710 void updateAdaptiveFocusState(bool success);
711
712 /**
713 * @brief calculate new HFR threshold based on median value for current selected filter
714 */
715 void updateHFRThreshold();
716
717 /**
718 * @brief get the focus filter for the currently active capture filter
719 */
720 QString getFocusFilterName();
721
722 /**
723 * @brief Slot that listens to guiding deviations reported by the Guide module.
724 *
725 * Depending on the current status, it triggers several actions:
726 * - If there is no active job, it calls {@see CameraState::checkMeridianFlipReady()}, which may initiate a meridian flip.
727 * - If guiding has been started after a meridian flip and the deviation is within the expected limits,
728 * the meridian flip is regarded as completed by setMeridianFlipStage(MF_NONE) (@see setMeridianFlipStage()).
729 * - If the deviation is beyond the defined limit, capturing is suspended (@see suspend()) and the
730 * #guideDeviationTimer is started.
731 * - Otherwise, it checks if there has been a job suspended and restarts it, since guiding is within the limits.
732 */
733
734 void setGuideDeviation(double deviation_rms);
735
736 /**
737 * @brief addDownloadTime Record a new download time
738 */
739 void addDownloadTime(double time);
740
741 /**
742 * @brief averageDownloadTime Determine the average download time
743 * @return
744 */
745 double averageDownloadTime()
746 {
747 return (downloadsCounter == 0 ? 0 : totalDownloadTime / downloadsCounter);
748 }
749
750 /**
751 * @brief setDarkFlatExposure Given a dark flat job, find the exposure suitable from it by searching for
752 * completed flat frames.
753 * @param job Dark flat job
754 * @return True if a matching exposure is found and set, false otherwise.
755 * @warning This only works if the flat frames were captured in the same live session.
756 * If the flat frames were captured in another session (i.e. Ekos restarted), then all automatic exposure
757 * calculation results are discarded since Ekos does not save this information to the sequene file.
758 * Possible solution is to write to a local config file to keep this information persist between sessions.
759 */
760 bool setDarkFlatExposure(SequenceJob *job);
761
762 /**
763 * @brief checkSeqBoundary Determine the next file number sequence.
764 * That is, if we have file1.png and file2.png, then the next
765 * sequence should be file3.png.
766 */
767 void checkSeqBoundary();
768 /**
769 * @brief isModelinDSLRInfo Check if the DSLR model is already known
770 */
771 bool isModelinDSLRInfo(const QString &model);
772
773 // ////////////////////////////////////////////////////////////////////
774 // Helper functions
775 // ////////////////////////////////////////////////////////////////////
776
777 /**
778 * @brief activeJobID Determine the ID of the currently active job
779 */
780 int activeJobID();
781
782 /**
783 * @brief pPendingJobCount Returns the number of pending uncompleted jobs in the sequence queue.
784 */
785 int pendingJobCount();
786
787 /**
788 * @brief getJobState Returns the job state (Idle, In Progress, Error, Aborted, Complete)
789 * @param id job number. Job IDs start from 0 to N-1.
790 */
791
792 QString jobState(int id);
793
794 /**
795 * @brief jobFilterName Returns the job filter name.
796 * @param id job number. Job IDs start from 0 to N-1.
797 */
798 QString jobFilterName(int id);
799
800 /**
801 * @param id job number. Job IDs start from 0 to N-1.
802 * @return Returns the frame type (light, dark, ...) of the job.
803 */
804 CCDFrameType jobFrameType(int id);
805
806 /**
807 * @brief jobImageProgress Returns The number of images completed capture in the job.
808 * @param id job number. Job IDs start from 0 to N-1.
809 */
810 int jobImageProgress(int id);
811
812 /**
813 * @param id job number. Job IDs start from 0 to N-1.
814 * @return Returns the total number of images to capture in the job.
815 */
816 int jobImageCount(int id);
817
818 /**
819 * @param id job number. Job IDs start from 0 to N-1.
820 * @return Returns the number of seconds left in an exposure operation.
821 */
822 double jobExposureProgress(int id);
823
824 /**
825 * @param id job number. Job IDs start from 0 to N-1.
826 * @return Returns the total requested exposure duration in the job.
827 */
828 double jobExposureDuration(int id);
829
830 /**
831 * @return Returns the percentage of completed captures in all active jobs
832 */
833 double progressPercentage();
834
835 /**
836 * @return Returns true if there's an active job and it is a preview job.
837 */
838 bool isActiveJobPreview();
839
840 /**
841 * @return Returns time left in seconds until active job is estimated to be complete.
842 */
843 int activeJobRemainingTime();
844
845 /**
846 * @return Returns overall time left in seconds until all jobs are estimated to be complete
847 */
848 int overallRemainingTime();
849
850 /**
851 * 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
852 * 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".
853 */
854 QString sequenceQueueStatus();
855
856 /**
857 * @brief getCalibrationSettings Get Calibration settings
858 * @return settings as JSON object
859 */
860 QJsonObject calibrationSettings();
861
862 /**
863 * @brief setCalibrationSettings Set Calibration settings
864 * @param settings as JSON object
865 */
866 void setCalibrationSettings(const QJsonObject &settings);
867
868 /**
869 * @brief hasCapturedFramesMap Check if at least one frame has been recorded
870 */
871 bool hasCapturedFramesMap()
872 {
873 return m_capturedFramesMap.count() > 0;
874 }
875 /**
876 * @brief addCapturedFrame Record a captured frame
877 */
878 void addCapturedFrame(const QString &signature);
879 /**
880 * @brief removeCapturedFrameCount Reduce the frame counts for the given signature
881 */
882 void removeCapturedFrameCount(const QString &signature, uint16_t count);
883 /**
884 * @brief clearCapturedFramesMap Clear the map of captured frames counts
885 */
886 void clearCapturedFramesMap()
887 {
888 m_capturedFramesMap.clear();
889 }
890
891 bool isCaptureRunning()
892 {
893 return (m_CaptureState != CAPTURE_IDLE && m_CaptureState != CAPTURE_COMPLETE && m_CaptureState != CAPTURE_ABORTED);
894 }
895
896 ScriptTypes captureScriptType() const
897 {
898 return m_CaptureScriptType;
899 }
900 void setCaptureScriptType(ScriptTypes value)
901 {
902 m_CaptureScriptType = value;
903 }
904 double targetADU() const
905 {
906 return m_targetADU;
907 }
908 void setTargetADU(double value)
909 {
910 m_targetADU = value;
911 }
912 double targetADUTolerance() const
913 {
914 return m_TargetADUTolerance;
915 }
916 void setTargetADUTolerance(double value)
917 {
918 m_TargetADUTolerance = value;
919 }
920 bool skyFlat() const
921 {
922 return m_skyFlat;
923 }
924 void setSkyFlat(bool enabled)
925 {
926 m_skyFlat = enabled;
927 }
928 SkyPoint &wallCoord()
929 {
930 return m_wallCoord;
931 }
932 void setWallCoord(SkyPoint value)
933 {
934 m_wallCoord = value;
935 }
936 const DoubleRange &exposureRange() const
937 {
938 return m_ExposureRange;
939 }
940 void setExposureRange(double min, double max)
941 {
942 m_ExposureRange.min = min;
943 m_ExposureRange.max = max;
944 }
945
947 {
948 return m_frameSettings;
949 }
950 void setFrameSettings(const QMap<ISD::CameraChip *, QVariantMap> &value)
951 {
952 m_frameSettings = value;
953 }
954
955 FlatFieldDuration flatFieldDuration() const
956 {
957 return m_flatFieldDuration;
958 }
959 void setFlatFieldDuration(FlatFieldDuration value)
960 {
961 m_flatFieldDuration = value;
962 }
963
964 uint32_t calibrationPreAction() const
965 {
966 return m_CalibrationPreAction;
967 }
968 void setCalibrationPreAction(uint32_t value)
969 {
970 m_CalibrationPreAction = value;
971 }
972
973 QList<QMap<QString, QVariant> > &DSLRInfos()
974 {
975 return m_DSLRInfos;
976 }
977
978signals:
979 // controls for capture execution
980 void captureBusy(bool busy);
981 void startCapture();
982 void abortCapture();
983 void suspendCapture();
984 void executeActiveJob();
985 void updatePrepareState(CaptureState state);
986 void captureStarted(CAPTUREResult rc);
987 // mount meridian flip status update event
988 void newMeridianFlipStage(MeridianFlipState::MFStage status);
989 // meridian flip started
990 void meridianFlipStarted();
991 // new guiding deviation measured
992 void newGuiderDrift(double deviation_rms);
993 // guiding should be started after a successful meridian flip
994 void guideAfterMeridianFlip();
995 // new capture state
996 void newStatus(CaptureState status);
997 // forward new focus status
998 void newFocusStatus(FocusState status);
999 // forward new adaptive focus status
1000 void newAdaptiveFocusStatus(bool success);
1001 // check focusing is necessary for the given HFR
1002 void checkFocus(double hfr);
1003 // run Autofocus
1004 void runAutoFocus(AutofocusReason autofocusReason, const QString &reasonInfo);
1005 // reset the focuser to the last known focus position
1006 void resetFocus();
1007 // signal focus module to perform adaptive focus
1008 void adaptiveFocus();
1009 // abort capturing if fast exposure mode is used
1010 void abortFastExposure();
1011 // new HFR focus limit calculated
1012 void newLimitFocusHFR(double hfr);
1013 // Select the filter at the given position
1014 void newFilterPosition(int targetFilterPosition, FilterManager::FilterPolicy policy = FilterManager::ALL_POLICIES);
1015 // capture sequence status changes
1016 void sequenceChanged(const QJsonArray &sequence);
1017 // new log text for the module log window
1018 void newLog(const QString &text);
1019
1020 private:
1021 // Container for the list of SequenceJobs.
1022 QSharedPointer<SequenceQueue> m_sequenceQueue;
1023 // Currently active sequence job.
1024 SequenceJob *m_activeJob { nullptr };
1025 // pointer to the image data
1026 QSharedPointer<FITSData> m_ImageData;
1027 // CCD Chip frame settings
1029 // DSLR Infos
1030 QList<QMap<QString, QVariant>> m_DSLRInfos;
1031
1032 // current filter position
1033 // TODO: check why we have both currentFilterID and this, seems redundant
1034 int m_CurrentFilterPosition { -1 };
1035 // current filter name matching the filter position
1036 QString m_CurrentFilterName { "--" };
1037 // holds the filter name used for focusing or "--" if the current one is used
1038 QString m_CurrentFocusFilterName { "--" };
1039 // Captured Frames Map
1040 CapturedFramesMap m_capturedFramesMap;
1041 // are we in the starting phase of capturing?
1042 bool m_StartingCapture { true };
1043 // Does the camera have a dedicated guiding chip?
1044 bool m_useGuideHead { false };
1045 // Guide Deviation
1046 bool m_GuidingDeviationDetected { false };
1047 // suspend guiding when downloading a captured image
1048 bool m_SuspendGuidingOnDownload { false };
1049 // Guiding spikes
1050 uint m_SpikesDetected { 0 };
1051 // Timer for guiding recovery
1052 QTimer m_guideDeviationTimer;
1053 // Capture timeout timer
1054 QTimer m_captureTimeout;
1055 uint8_t m_CaptureTimeoutCounter { 0 };
1056 uint8_t m_DeviceRestartCounter { 0 };
1057 // time left of the current exposure
1058 QTime m_imageCountDown;
1059 double m_lastRemainingFrameTimeMS;
1060 // Timer for delay before capturing an image
1061 // @see CaptureProcess::captureImageWithDelay()
1062 QTimer m_captureDelayTimer;
1063 // time left for the current sequence
1064 QTime m_sequenceCountDown;
1065 // timer for updating the download progress
1066 QTimer m_downloadProgressTimer;
1067 // timer measuring the download time
1068 QElapsedTimer m_DownloadTimer;
1069 // sum over all recorded list of download times
1070 double totalDownloadTime {0};
1071 // number of downloaded frames
1072 uint downloadsCounter {0};
1073 // current placeholder path
1074 PlaceholderPath m_currentPlaceholderPath;
1075 // next capture sequence ID
1076 int m_nextSequenceID { 0 };
1077 // how to continue after pausing
1078 ContinueAction m_ContinueAction { CONTINUE_ACTION_NONE };
1079 // name of the observer
1080 QString m_ObserverName;
1081 // ignore already captured files
1082 bool m_ignoreJobProgress { true };
1083 // Fast Exposure
1084 bool m_RememberFastExposure {false};
1085 // Set dirty bit to indicate sequence queue file was modified and needs saving.
1086 bool m_Dirty { false };
1087 // Capturing (incl. preparation actions) is active
1088 bool m_Busy { false };
1089 // preview loop running
1090 bool m_Looping { false };
1091 // script type of the currently running script
1092 ScriptTypes m_CaptureScriptType { SCRIPT_N };
1093 // Flat field automation
1094 double m_TargetADUTolerance { 1000 };
1095 double m_targetADU { 0 };
1096 bool m_skyFlat { false };
1097 SkyPoint m_wallCoord;
1098 FlatFieldDuration m_flatFieldDuration { DURATION_MANUAL };
1099 uint32_t m_CalibrationPreAction { ACTION_NONE };
1100 bool m_lightBoxLightEnabled { false };
1101 // Allowed camera exposure times
1102 DoubleRange m_ExposureRange;
1103 // Misc
1104 QJsonArray m_SequenceArray;
1105
1106 // ////////////////////////////////////////////////////////////////////
1107 // device states
1108 // ////////////////////////////////////////////////////////////////////
1109 CaptureState m_CaptureState { CAPTURE_IDLE };
1110 FocusState m_FocusState { FOCUS_IDLE };
1111 GuideState m_GuideState { GUIDE_IDLE };
1112 IPState m_DitheringState {IPS_IDLE};
1113 AlignState m_AlignState { ALIGN_IDLE };
1114 FilterState m_FilterManagerState { FILTER_IDLE };
1115 LightState m_lightBoxLightState { CAP_LIGHT_UNKNOWN };
1116 CapState m_dustCapState { CAP_UNKNOWN };
1117 ISD::Mount::Status m_scopeState { ISD::Mount::MOUNT_IDLE };
1118 ISD::Mount::PierSide m_pierSide { ISD::Mount::PIER_UNKNOWN };
1119 ISD::ParkStatus m_scopeParkState { ISD::PARK_UNKNOWN };
1120 ISD::Dome::Status m_domeState { ISD::Dome::DOME_IDLE };
1121
1122 // ////////////////////////////////////////////////////////////////////
1123 // counters
1124 // ////////////////////////////////////////////////////////////////////
1125 // Number of alignment retries
1126 int m_AlignmentRetries { 0 };
1127 // How many images to capture before dithering operation is executed?
1128 uint m_ditherCounter { 0 };
1129
1130 /* Refocusing */
1131 QSharedPointer<RefocusState> m_refocusState;
1132 /* Meridian Flip */
1134
1135 /**
1136 * @brief Add log message
1137 */
1138 void appendLogText(const QString &message);
1139
1140};
1141
1142}; // 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
@ 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 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.