Kstars

schedulermodulestate.h
1/*
2 SPDX-FileCopyrightText: 2023 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include <QObject>
10#include <QProcess>
11#include "ekos/ekos.h"
12#include "indi/indiweather.h"
13#include "kstarsdatetime.h"
14#include "geolocation.h"
15#include "schedulertypes.h"
16#include "ekos/capture/capturetypes.h"
17#include <QDateTime>
18#include <QUrl>
19
20class SchedulerJob;
21
22namespace Ekos
23{
24
26class SchedulerJob;
27
28/**
29 * @class SchedulerState
30 * @brief The SchedulerState class holds all attributes defining the scheduler's state.
31 */
32class SchedulerModuleState : public QObject
33{
35
36 public:
37
38
39 SchedulerModuleState();
40
41 // ////////////////////////////////////////////////////////////////////
42 // Overall scheduler state
43 // ////////////////////////////////////////////////////////////////////
44 /**
45 * @brief init Set initial conditions that need to be set before starting
46 */
47 void init();
48
49 // ////////////////////////////////////////////////////////////////////
50 // profiles and scheduler jobs
51 // ////////////////////////////////////////////////////////////////////
52
53 const QString &currentProfile() const
54 {
55 return m_currentProfile;
56 }
57 /**
58 * @brief setCurrentProfile Set the current profile name.
59 * @param newName new current profile name
60 * @param signal send an update efent if true
61 */
62 void setCurrentProfile(const QString &newName, bool signal = true);
63
64 const QStringList &profiles() const
65 {
66 return m_profiles;
67 }
68 void updateProfiles(const QStringList &newProfiles);
69
70 SchedulerJob *activeJob(const QString &trainname = "") const;
71 void setActiveJob(SchedulerJob *newActiveJob);
72
73 /**
74 * @brief Return the master jobs only, slave jobs are ignored
75 */
76 QList<SchedulerJob *> leadJobs();
77
78 /**
79 * @brief Return the slave jobs only, master jobs are ignored
80 */
81 QList<SchedulerJob *> followerJobs();
82
83 QList<SchedulerJob *> &mutlableJobs()
84 {
85 return m_jobs;
86 }
87 const QList<SchedulerJob *> &jobs() const
88 {
89 return m_jobs;
90 }
91
92 void setJobs(QList<SchedulerJob *> &newJobs)
93 {
94 m_jobs = newJobs;
95 }
96
97 /**
98 * @brief updateStage Helper function that updates the stage label of the active job.
99 */
100 void updateJobStage(SchedulerJobStage stage);
101
102 /**
103 * @brief getJSONJobs get jobs in JSON format
104 * @return
105 */
106 QJsonArray getJSONJobs();
107
108
109 // ////////////////////////////////////////////////////////////////////
110 // state attributes accessors
111 // ////////////////////////////////////////////////////////////////////
112
113
114 bool dirty() const
115 {
116 return m_dirty;
117 }
118 void setDirty(bool value)
119 {
120 m_dirty = value;
121 }
122
123 // (coarse grained) execution state of the scheduler
124 const SchedulerState &schedulerState() const
125 {
126 return m_schedulerState;
127 }
128 void setSchedulerState(const SchedulerState &newState);
129
130 const StartupState &startupState() const
131 {
132 return m_startupState;
133 }
134
135 int currentPosition() const
136 {
137 return m_currentPosition;
138 }
139 void setCurrentPosition(int newCurrentPosition);
140
141 void setStartupState(StartupState state);
142
143 const QUrl &startupScriptURL() const
144 {
145 return m_startupScriptURL;
146 }
147 void setStartupScriptURL(const QUrl &newURL)
148 {
149 m_startupScriptURL = newURL;
150 }
151
152 const ShutdownState &shutdownState() const
153 {
154 return m_shutdownState;
155 }
156 void setShutdownState(ShutdownState state);
157
158 const QUrl &shutdownScriptURL() const
159 {
160 return m_shutdownScriptURL;
161 }
162 void setShutdownScriptURL(const QUrl &newShutdownScriptURL)
163 {
164 m_shutdownScriptURL = newShutdownScriptURL;
165 }
166
167 const ParkWaitState &parkWaitState() const
168 {
169 return m_parkWaitState;
170 }
171 void setParkWaitState(ParkWaitState state);
172
173 /**
174 * @brief True if the scheduler is between iterations and delaying longer than the typical update period.
175 */
176 bool currentlySleeping()
177 {
178 return iterationTimer().isActive() && timerState() == RUN_WAKEUP;
179 }
180
181 // ////////////////////////////////////////////////////////////////////
182 // job handling
183 // ////////////////////////////////////////////////////////////////////
184
185 /**
186 * @brief removeJob Remove the job from the job list at the given position.
187 * If this is the currently active job, don't remove it and return false.
188 * @return true iff removing succeeded
189 */
190 bool removeJob(const int currentRow);
191
192 /**
193 * @brief refreshSlaveLists walk through the jobs and update the slave lists
194 */
195 void refreshFollowerLists();
196
197 /**
198 * @brief walk through the job list and find the first master job
199 */
200 SchedulerJob *findLead(int position, bool upward = true);
201
202
203 // ////////////////////////////////////////////////////////////////////
204 // Controls for the preemptive shutdown feature.
205 // ////////////////////////////////////////////////////////////////////
206 // Is the scheduler shutting down until later when it will resume a job?
207 void enablePreemptiveShutdown(const QDateTime &wakeupTime);
208 void disablePreemptiveShutdown();
209 const QDateTime &preemptiveShutdownWakeupTime() const;
210 bool preemptiveShutdown() const;
211
212
213 // ////////////////////////////////////////////////////////////////////
214 // overall EKOS state
215 // ////////////////////////////////////////////////////////////////////
216 EkosState ekosState() const
217 {
218 return m_ekosState;
219 }
220 void setEkosState(EkosState state);
221 // last communication result with EKOS
222 CommunicationStatus ekosCommunicationStatus() const
223 {
224 return m_EkosCommunicationStatus;
225 }
226 void setEkosCommunicationStatus(CommunicationStatus newEkosCommunicationStatus)
227 {
228 m_EkosCommunicationStatus = newEkosCommunicationStatus;
229 }
230 // counter for failed EKOS connection attempts
231 void resetEkosConnectFailureCount(uint8_t newEkosConnectFailureCount = 0)
232 {
233 m_ekosConnectFailureCount = newEkosConnectFailureCount;
234 }
235 bool increaseEkosConnectFailureCount();
236
237 void resetParkingCapFailureCount(uint8_t value = 0)
238 {
239 m_parkingCapFailureCount = value;
240 }
241 bool increaseParkingCapFailureCount();
242 void resetParkingMountFailureCount(uint8_t value = 0)
243 {
244 m_parkingMountFailureCount = value;
245 }
246 bool increaseParkingMountFailureCount();
247 uint8_t parkingMountFailureCount() const
248 {
249 return m_parkingMountFailureCount;
250 }
251 void resetParkingDomeFailureCount(uint8_t value = 0)
252 {
253 m_parkingDomeFailureCount = value;
254 }
255 bool increaseParkingDomeFailureCount();
256
257 int indexToUse() const
258 {
259 return m_IndexToUse;
260 }
261 void setIndexToUse(int newIndexToUse)
262 {
263 m_IndexToUse = newIndexToUse;
264 }
265
266 int healpixToUse() const
267 {
268 return m_HealpixToUse;
269 }
270 void setHealpixToUse(int newHealpixToUse)
271 {
272 m_HealpixToUse = newHealpixToUse;
273 }
274
275 CapturedFramesMap &capturedFramesCount()
276 {
277 return m_CapturedFramesCount;
278 }
279
280 void setCapturedFramesCount(const CapturedFramesMap &newCapturedFramesCount)
281 {
282 m_CapturedFramesCount = newCapturedFramesCount;
283 }
284
285 void setWeatherGracePeriodActive(bool active)
286 {
287 m_WeatherGracePeriodActive = active;
288 }
289 bool weatherGracePeriodActive() const
290 {
291 return m_WeatherGracePeriodActive;
292 }
293
294 /**
295 * @brief resetFailureCounters Reset all failure counters
296 */
297 void resetFailureCounters();
298
299 // ////////////////////////////////////////////////////////////////////
300 // overall INDI state
301 // ////////////////////////////////////////////////////////////////////
302 INDIState indiState() const
303 {
304 return m_indiState;
305 }
306 void setIndiState(INDIState state);
307 // last communication result with INDI
308 CommunicationStatus indiCommunicationStatus() const
309 {
310 return m_INDICommunicationStatus;
311 }
312 void setIndiCommunicationStatus(CommunicationStatus newINDICommunicationStatus)
313 {
314 m_INDICommunicationStatus = newINDICommunicationStatus;
315 emit indiCommunicationStatusChanged(m_INDICommunicationStatus);
316 }
317 // counters for failed INDI connection attempts
318 void resetIndiConnectFailureCount(uint8_t newIndiConnectFailureCount = 0)
319 {
320 m_indiConnectFailureCount = newIndiConnectFailureCount;
321 }
322 bool increaseIndiConnectFailureCount();
323 /**
324 * @brief isINDIConnected Determines the status of the INDI connection.
325 * @return True if INDI connection is up and usable, else false.
326 */
327 bool isINDIConnected() const
328 {
329 return (indiCommunicationStatus() == Ekos::Success);
330 }
331 // ////////////////////////////////////////////////////////////////////
332 // device states
333 // ////////////////////////////////////////////////////////////////////
334 bool mountReady() const
335 {
336 return m_MountReady;
337 }
338 void setMountReady(bool readiness)
339 {
340 m_MountReady = readiness;
341 }
342 bool captureReady() const
343 {
344 return m_CaptureReady;
345 }
346 void setCaptureReady(bool readiness)
347 {
348 m_CaptureReady = readiness;
349 }
350 bool domeReady() const
351 {
352 return m_DomeReady;
353 }
354 void setDomeReady(bool readiness)
355 {
356 m_DomeReady = readiness;
357 }
358 bool capReady() const
359 {
360 return m_CapReady;
361 }
362 void setCapReady(bool readiness)
363 {
364 m_CapReady = readiness;
365 }
366
367 uint16_t captureBatch() const
368 {
369 return m_captureBatch;
370 }
371 void resetCaptureBatch()
372 {
373 m_captureBatch = 0;
374 }
375 uint16_t increaseCaptureBatch()
376 {
377 return m_captureBatch++;
378 }
379
380 uint8_t captureFailureCount() const
381 {
382 return m_captureFailureCount;
383 }
384 void resetCaptureFailureCount()
385 {
386 m_captureFailureCount = 0;
387 }
388 bool increaseCaptureFailureCount();
389
390 uint8_t focusFailureCount(const QString &trainname) const
391 {
392 return m_focusFailureCount[trainname];
393 }
394 void resetFocusFailureCount(const QString &trainname)
395 {
396 m_focusFailureCount[trainname] = 0;
397 }
398 void resetFocusFailureCount()
399 {
400 m_focusFailureCount.clear();
401 }
402 bool increaseFocusFailureCount(const QString &trainname);
403
404 bool increaseAllFocusFailureCounts();
405
406 bool autofocusCompleted(const QString &trainname) const;
407 void setAutofocusCompleted(const QString &trainname, bool value);
408 bool autofocusCompleted() const;
409
410 void resetAutofocusCompleted()
411 {
412 m_autofocusCompleted.clear();
413 }
414
415 uint8_t guideFailureCount() const
416 {
417 return m_guideFailureCount;
418 }
419 void resetGuideFailureCount()
420 {
421 m_guideFailureCount = 0;
422 }
423 bool increaseGuideFailureCount();
424
425 uint8_t alignFailureCount() const
426 {
427 return m_alignFailureCount;
428 }
429 void resetAlignFailureCount()
430 {
431 m_alignFailureCount = 0;
432 }
433 bool increaseAlignFailureCount();
434
435 int restartGuidingInterval() const
436 {
437 return m_restartGuidingInterval;
438 }
439
440 const KStarsDateTime &restartGuidingTime() const
441 {
442 return m_restartGuidingTime;
443 }
444
445 ISD::Weather::Status weatherStatus() const
446 {
447 return m_weatherStatus;
448 }
449 void setWeatherStatus(ISD::Weather::Status newWeatherStatus)
450 {
451 m_weatherStatus = newWeatherStatus;
452 }
453
454 // ////////////////////////////////////////////////////////////////////
455 // Timers and time
456 // ////////////////////////////////////////////////////////////////////
457 // Returns milliseconds since startCurrentOperationTImer() was called.
458 qint64 getCurrentOperationMsec() const;
459 // Starts the above operation timer.
460 // TODO. It would be better to make this a class and give each operation its own timer.
461 // TODO. These should be disabled once no longer relevant.
462 // These are implement with a KStarsDateTime instead of a QTimer type class
463 // so that the simulated clock can be used.
464 void startCurrentOperationTimer();
465
466 // Controls for the guiding timer, which restarts guiding after failure.
467 void cancelGuidingTimer();
468 bool isGuidingTimerActive();
469 void startGuidingTimer(int milliseconds);
470
471 /** @brief Setter used in testing to fix the local time. Otherwise getter gets from KStars instance. */
472 /** @{ */
473 static KStarsDateTime getLocalTime();
474 static void setLocalTime(KStarsDateTime *time)
475 {
476 storedLocalTime = time;
477 }
478 static bool hasLocalTime()
479 {
480 return storedLocalTime != nullptr;
481 }
482
483 /** @} */
484
485
486 // ////////////////////////////////////////////////////////////////////
487 // Astronomical calculations
488 // ////////////////////////////////////////////////////////////////////
489 /**
490 * @brief calculateDawnDusk find the next astronomical dawn and dusk after the current date and time of observation
491 */
492 static void calculateDawnDusk(QDateTime const &when, QDateTime &nDawn, QDateTime &nDusk);
493
494 /**
495 * @brief calculateDawnDusk Calculate dawn and dusk times for today
496 */
497 void calculateDawnDusk();
498
499 static QDateTime Dawn()
500 {
501 return m_Dawn;
502 }
503 static QDateTime Dusk()
504 {
505 return m_Dusk;
506 }
507 static QDateTime PreDawnDateTime()
508 {
509 return m_PreDawnDateTime;
510 }
511
512 /** @brief Setter used in testing to fix the geo location. Otherwise getter gets from KStars instance. */
513 /** @{ */
514 static const GeoLocation *getGeo();
515 static void setGeo(GeoLocation *geo)
516 {
517 storedGeo = geo;
518 }
519 static bool hasGeo();
520
521 // ////////////////////////////////////////////////////////////////////
522 // Scheduler iterations
523 // ////////////////////////////////////////////////////////////////////
524
525 // Setup the parameters for the next scheduler iteration.
526 // When milliseconds is not passed in, it uses m_UpdatePeriodMs.
527 void setupNextIteration(SchedulerTimerState nextState);
528 void setupNextIteration(SchedulerTimerState nextState, int milliseconds);
529
530 SchedulerTimerState timerState() const
531 {
532 return m_timerState;
533 }
534
535 void setTimerState(SchedulerTimerState newTimerState)
536 {
537 m_timerState = newTimerState;
538 }
539
540 QTimer &iterationTimer()
541 {
542 return m_iterationTimer;
543 }
544
545 QTimer &tickleTimer()
546 {
547 return m_tickleTimer;
548 }
549
550 bool iterationSetup() const
551 {
552 return m_iterationSetup;
553 }
554 void setIterationSetup(bool setup)
555 {
556 m_iterationSetup = setup;
557 }
558
559 qint64 startMSecs() const
560 {
561 return m_startMSecs;
562 }
563 void setStartMSecs(qint64 value)
564 {
565 m_startMSecs = value;
566 }
567 int increaseSchedulerIteration()
568 {
569 return ++m_schedulerIteration;
570 }
571 void resetSchedulerIteration()
572 {
573 m_schedulerIteration = 0;
574 }
575
576 int timerInterval() const
577 {
578 return m_timerInterval;
579 }
580 void setTimerInterval(int value)
581 {
582 m_timerInterval = value;
583 }
584
585 void setUpdatePeriodMs(int ms)
586 {
587 m_UpdatePeriodMs = ms;
588 }
589 int updatePeriodMs() const
590 {
591 return m_UpdatePeriodMs;
592 }
593
594 uint sequenceExecutionCounter() const
595 {
596 return m_sequenceExecutionCounter;
597 }
598 void resetSequenceExecutionCounter()
599 {
600 m_sequenceExecutionCounter = 1;
601 }
602 void increaseSequenceExecutionCounter()
603 {
604 m_sequenceExecutionCounter++;
605 }
606
607 static uint maxFailureAttempts();
608
609 QStringList &logText()
610 {
611 return m_logText;
612 }
613 QString getLogText()
614 {
615 return logText().join("\n");
616 }
617 void clearLog();
618
619 /**
620 * @brief checkRepeatSequence Check if the entire job sequence might be repeated
621 * @return true if the checkbox is set and the number of iterations is below the
622 * configured threshold
623 */
624 bool checkRepeatSequence();
625
626 void resetSolverIteration()
627 {
628 m_solverIteration = 0;
629 }
630 uint32_t increaseSolverIteration()
631 {
632 return ++m_solverIteration;
633 }
634
635 signals:
636 // ////////////////////////////////////////////////////////////////////
637 // communication with the UI
638 // ////////////////////////////////////////////////////////////////////
639 // State change of EKOS
640 void ekosStateChanged(EkosState state);
641 // State change of INDI
642 void indiStateChanged(INDIState state);
643 // High level INDI state changes
644 void indiCommunicationStatusChanged(CommunicationStatus status);
645 // overall scheduler state changed
646 void schedulerStateChanged(SchedulerState state);
647 // startup state
648 void startupStateChanged(StartupState state);
649 // shutdown state
650 void shutdownStateChanged(ShutdownState state);
651 // parking state
652 void parkWaitStateChanged(ParkWaitState state);
653 // profiles updated
654 void profilesChanged();
655 // current profile changed
656 void currentProfileChanged();
657 // new log text for the module log window
658 void newLog(const QString &text);
659 // current position in the job list changed
660 void currentPositionChanged(int pos);
661 // job stage of the current job changed
662 void jobStageChanged(SchedulerJobStage stage);
663 // night time calculation updated
664 void updateNightTime(SchedulerJob const * job = nullptr);
665
666
667 private:
668 // ////////////////////////////////////////////////////////////////////
669 // Scheduler jobs
670 // ////////////////////////////////////////////////////////////////////
671 // List of all jobs as entered by the user or file
673 // Active master job
674 SchedulerJob *m_activeJob { nullptr };
675
676 // ////////////////////////////////////////////////////////////////////
677 // state attributes
678 // ////////////////////////////////////////////////////////////////////
679 // coarse grained state describing the general execution state
680 SchedulerState m_schedulerState { SCHEDULER_IDLE };
681 // states of the scheduler startup
682 StartupState m_startupState { STARTUP_IDLE };
683 // Startup script URL
684 QUrl m_startupScriptURL;
685 // states of the scheduler shutdown
686 ShutdownState m_shutdownState { SHUTDOWN_IDLE };
687 // current position on the job list - necessary if there is no line selected in the
688 // UI, for example after deleting a row.
689 int m_currentPosition { -1 };
690 // Shutdown script URL
691 QUrl m_shutdownScriptURL;
692 // states of parking
693 ParkWaitState m_parkWaitState { PARKWAIT_IDLE };
694 // current profile
695 QString m_currentProfile;
696 // all profiles
697 QStringList m_profiles;
698 /// Store all log strings
699 QStringList m_logText;
700 // Was job modified and needs saving?
701 bool m_dirty { false };
702
703 // EKOS state describing whether EKOS is running (remember that the scheduler
704 // does not need EKOS running).
705 EkosState m_ekosState { EKOS_IDLE };
706 // Execution state of INDI
707 INDIState m_indiState { INDI_IDLE };
708 // Last communication result with EKOS and INDI
709 CommunicationStatus m_EkosCommunicationStatus { Ekos::Idle };
710 CommunicationStatus m_INDICommunicationStatus { Ekos::Idle };
711
712 // device readiness
713 bool m_MountReady { false };
714 bool m_CaptureReady { false };
715 bool m_DomeReady { false };
716 bool m_CapReady { false };
717
718 // Restricts (the internal solver) to using the index and healpix
719 // from the previous solve, if that solve was successful, when
720 // doing the pointing check. -1 means no restriction.
721 int m_IndexToUse { -1 };
722 int m_HealpixToUse { -1 };
723
724 // Check if initial autofocus is completed and do not run autofocus until
725 // there is a change is telescope position/alignment.
726 QMap <QString, bool> m_autofocusCompleted;
727
728 // Used when solving position every nth capture.
729 uint32_t m_solverIteration {0};
730
731
732 // Keep watch of weather status
733 ISD::Weather::Status m_weatherStatus { ISD::Weather::WEATHER_IDLE };
734
735 // ////////////////////////////////////////////////////////////////////
736 // counters
737 // ////////////////////////////////////////////////////////////////////
738 // count for job sequence iteration
739 uint m_sequenceExecutionCounter { 1 };
740 // Keep track of INDI connection failures
741 uint8_t m_indiConnectFailureCount { 0 };
742 // Keep track of Ekos connection failures
743 uint8_t m_ekosConnectFailureCount { 0 };
744 // failures parking dust cap
745 uint8_t m_parkingCapFailureCount { 0 };
746 // failures parking mount
747 uint8_t m_parkingMountFailureCount { 0 };
748 // failures parking dome
749 uint8_t m_parkingDomeFailureCount { 0 };
750 // How many repeated job batches did we complete thus far?
751 uint16_t m_captureBatch { 0 };
752 // Keep track of Ekos capture module failures
753 uint8_t m_captureFailureCount { 0 };
754 // Keep track of Ekos focus module failures
755 QMap <QString, uint8_t> m_focusFailureCount;
756 // Keep track of Ekos guide module failures
757 uint8_t m_guideFailureCount { 0 };
758 // Keep track of Ekos align module failures
759 uint8_t m_alignFailureCount { 0 };
760 // frames count for all signatures
761 CapturedFramesMap m_CapturedFramesCount;
762
763 // ////////////////////////////////////////////////////////////////////
764 // Scheduler iterations
765 // ////////////////////////////////////////////////////////////////////
766
767 // The type of scheduler iteration that should be run next.
768 SchedulerTimerState m_timerState { RUN_NOTHING };
769 // Variable keeping the number of millisconds the scheduler should wait
770 // after the current scheduler iteration.
771 int m_timerInterval { -1 };
772 // Whether the scheduler has been setup for the next iteration,
773 // that is, whether timerInterval and timerState have been set this iteration.
774 bool m_iterationSetup { false };
775 // The timer used to wakeup the scheduler between iterations.
776 QTimer m_iterationTimer;
777 // The timer used to update the scheduler graph when the scheduler is sleeping.
778 QTimer m_tickleTimer;
779 // Counter for how many scheduler iterations have been processed.
780 int m_schedulerIteration { 0 };
781 // The time when the scheduler first started running iterations.
782 qint64 m_startMSecs { 0 };
783 // This is the time between typical scheduler iterations.
784 // The time can be modified for testing.
785 int m_UpdatePeriodMs = 1000;
786
787 // ////////////////////////////////////////////////////////////////////
788 // time and timers
789 // ////////////////////////////////////////////////////////////////////
790 // constants for current dawn and dusk
791 /// Store next dawn to calculate dark skies range
792 static QDateTime m_Dawn;
793 /// Store next dusk to calculate dark skies range
794 static QDateTime m_Dusk;
795 /// Pre-dawn is where we stop all jobs, it is a user-configurable value before Dawn.
796 static QDateTime m_PreDawnDateTime;
797 // Generic time to track timeout of current operation in progress.
798 // Used by startCurrentOperationTimer() and getCurrentOperationMsec().
799 KStarsDateTime currentOperationTime;
800 bool currentOperationTimeStarted { false };
801 // Delay for restarting the guider
802 int m_restartGuidingInterval { -1 };
803 KStarsDateTime m_restartGuidingTime;
804 // Used in testing, instead of KStars::Instance() resources
805 static KStarsDateTime *storedLocalTime;
806 // The various preemptiveShutdown states are controlled by this one variable.
807 QDateTime m_preemptiveShutdownWakeupTime;
808 // Are we in weather grace period?
809 bool m_WeatherGracePeriodActive {false};
810
811 // These are used in testing, instead of KStars::Instance() resources
812 static GeoLocation *storedGeo;
813
814};
815} // Ekos namespace
The SchedulerProcess class holds the entire business logic for controlling the execution of the EKOS ...
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
Definition geolocation.h:28
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
The SchedulerState class holds all attributes defining the scheduler's state.
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:83
QMap< QString, uint16_t > CapturedFramesMap
mapping signature --> frames count
void clear()
Q_OBJECTQ_OBJECT
QString join(QChar separator) const const
bool isActive() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 11:58:36 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.