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

KDE's Doxygen guidelines are available online.