File indexing completed on 2024-04-21 03:43:37
0001 /* 0002 SPDX-FileCopyrightText: 2023 Wolfgang Reissenberger <sterne-jaeger@openfuture.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QObject> 0010 #include <QProcess> 0011 #include "ekos/ekos.h" 0012 #include "indi/indiweather.h" 0013 #include "kstarsdatetime.h" 0014 #include "geolocation.h" 0015 #include "schedulertypes.h" 0016 #include <QDateTime> 0017 #include <QUrl> 0018 0019 class SchedulerJob; 0020 0021 namespace Ekos 0022 { 0023 0024 class SchedulerProcess; 0025 class SchedulerJob; 0026 0027 /** 0028 * @class SchedulerState 0029 * @brief The SchedulerState class holds all attributes defining the scheduler's state. 0030 */ 0031 class SchedulerModuleState : public QObject 0032 { 0033 Q_OBJECT 0034 0035 public: 0036 0037 0038 SchedulerModuleState(); 0039 0040 // //////////////////////////////////////////////////////////////////// 0041 // Overall scheduler state 0042 // //////////////////////////////////////////////////////////////////// 0043 /** 0044 * @brief init Set initial conditions that need to be set before starting 0045 */ 0046 void init(); 0047 0048 // //////////////////////////////////////////////////////////////////// 0049 // profiles and scheduler jobs 0050 // //////////////////////////////////////////////////////////////////// 0051 0052 const QString ¤tProfile() const 0053 { 0054 return m_currentProfile; 0055 } 0056 /** 0057 * @brief setCurrentProfile Set the current profile name. 0058 * @param newName new current profile name 0059 * @param signal send an update efent if true 0060 */ 0061 void setCurrentProfile(const QString &newName, bool signal = true); 0062 0063 const QStringList &profiles() const 0064 { 0065 return m_profiles; 0066 } 0067 void updateProfiles(const QStringList &newProfiles); 0068 0069 SchedulerJob *activeJob() const 0070 { 0071 return m_activeJob; 0072 } 0073 void setActiveJob(SchedulerJob *newActiveJob); 0074 0075 QList<SchedulerJob *> &mutlableJobs() 0076 { 0077 return m_jobs; 0078 } 0079 const QList<SchedulerJob *> &jobs() const 0080 { 0081 return m_jobs; 0082 } 0083 0084 void setJobs(QList<SchedulerJob *> &newJobs) 0085 { 0086 m_jobs = newJobs; 0087 } 0088 0089 /** 0090 * @brief updateStage Helper function that updates the stage label of the active job. 0091 */ 0092 void updateJobStage(SchedulerJobStage stage); 0093 0094 /** 0095 * @brief getJSONJobs get jobs in JSON format 0096 * @return 0097 */ 0098 QJsonArray getJSONJobs(); 0099 0100 0101 // //////////////////////////////////////////////////////////////////// 0102 // state attributes accessors 0103 // //////////////////////////////////////////////////////////////////// 0104 0105 bool dirty() const 0106 { 0107 return m_dirty; 0108 } 0109 void setDirty(bool value) 0110 { 0111 m_dirty = value; 0112 } 0113 0114 // (coarse grained) execution state of the scheduler 0115 const SchedulerState &schedulerState() const 0116 { 0117 return m_schedulerState; 0118 } 0119 void setSchedulerState(const SchedulerState &newState); 0120 0121 const StartupState &startupState() const 0122 { 0123 return m_startupState; 0124 } 0125 0126 int currentPosition() const 0127 { 0128 return m_currentPosition; 0129 } 0130 void setCurrentPosition(int newCurrentPosition); 0131 0132 void setStartupState(StartupState state); 0133 0134 const QUrl &startupScriptURL() const 0135 { 0136 return m_startupScriptURL; 0137 } 0138 void setStartupScriptURL(const QUrl &newURL) 0139 { 0140 m_startupScriptURL = newURL; 0141 } 0142 0143 const ShutdownState &shutdownState() const 0144 { 0145 return m_shutdownState; 0146 } 0147 void setShutdownState(ShutdownState state); 0148 0149 const QUrl &shutdownScriptURL() const 0150 { 0151 return m_shutdownScriptURL; 0152 } 0153 void setShutdownScriptURL(const QUrl &newShutdownScriptURL) 0154 { 0155 m_shutdownScriptURL = newShutdownScriptURL; 0156 } 0157 0158 const ParkWaitState &parkWaitState() const 0159 { 0160 return m_parkWaitState; 0161 } 0162 void setParkWaitState(ParkWaitState state); 0163 0164 /** 0165 * @brief True if the scheduler is between iterations and delaying longer than the typical update period. 0166 */ 0167 bool currentlySleeping() 0168 { 0169 return iterationTimer().isActive() && timerState() == RUN_WAKEUP; 0170 } 0171 0172 // //////////////////////////////////////////////////////////////////// 0173 // job handling 0174 // //////////////////////////////////////////////////////////////////// 0175 0176 /** 0177 * @brief removeJob Remove the job from the job list at the given position. 0178 * If this is the currently active job, don't remove it and return false. 0179 * @return true iff removing succeeded 0180 */ 0181 bool removeJob(const int currentRow); 0182 0183 0184 // //////////////////////////////////////////////////////////////////// 0185 // Controls for the preemptive shutdown feature. 0186 // //////////////////////////////////////////////////////////////////// 0187 // Is the scheduler shutting down until later when it will resume a job? 0188 void enablePreemptiveShutdown(const QDateTime &wakeupTime); 0189 void disablePreemptiveShutdown(); 0190 const QDateTime &preemptiveShutdownWakeupTime() const; 0191 bool preemptiveShutdown() const; 0192 0193 0194 // //////////////////////////////////////////////////////////////////// 0195 // overall EKOS state 0196 // //////////////////////////////////////////////////////////////////// 0197 EkosState ekosState() const 0198 { 0199 return m_ekosState; 0200 } 0201 void setEkosState(EkosState state); 0202 // last communication result with EKOS 0203 CommunicationStatus ekosCommunicationStatus() const 0204 { 0205 return m_EkosCommunicationStatus; 0206 } 0207 void setEkosCommunicationStatus(CommunicationStatus newEkosCommunicationStatus) 0208 { 0209 m_EkosCommunicationStatus = newEkosCommunicationStatus; 0210 } 0211 // counter for failed EKOS connection attempts 0212 void resetEkosConnectFailureCount(uint8_t newEkosConnectFailureCount = 0) 0213 { 0214 m_ekosConnectFailureCount = newEkosConnectFailureCount; 0215 } 0216 bool increaseEkosConnectFailureCount(); 0217 0218 void resetParkingCapFailureCount(uint8_t value = 0) 0219 { 0220 m_parkingCapFailureCount = value; 0221 } 0222 bool increaseParkingCapFailureCount(); 0223 void resetParkingMountFailureCount(uint8_t value = 0) 0224 { 0225 m_parkingMountFailureCount = value; 0226 } 0227 bool increaseParkingMountFailureCount(); 0228 uint8_t parkingMountFailureCount() const 0229 { 0230 return m_parkingMountFailureCount; 0231 } 0232 void resetParkingDomeFailureCount(uint8_t value = 0) 0233 { 0234 m_parkingDomeFailureCount = value; 0235 } 0236 bool increaseParkingDomeFailureCount(); 0237 0238 int indexToUse() const 0239 { 0240 return m_IndexToUse; 0241 } 0242 void setIndexToUse(int newIndexToUse) 0243 { 0244 m_IndexToUse = newIndexToUse; 0245 } 0246 0247 int healpixToUse() const 0248 { 0249 return m_HealpixToUse; 0250 } 0251 void setHealpixToUse(int newHealpixToUse) 0252 { 0253 m_HealpixToUse = newHealpixToUse; 0254 } 0255 0256 QMap<QString, uint16_t> &capturedFramesCount() 0257 { 0258 return m_CapturedFramesCount; 0259 } 0260 0261 void setCapturedFramesCount(const QMap<QString, uint16_t> &newCapturedFramesCount) 0262 { 0263 m_CapturedFramesCount = newCapturedFramesCount; 0264 } 0265 0266 /** 0267 * @brief resetFailureCounters Reset all failure counters 0268 */ 0269 void resetFailureCounters(); 0270 0271 // //////////////////////////////////////////////////////////////////// 0272 // overall INDI state 0273 // //////////////////////////////////////////////////////////////////// 0274 INDIState indiState() const 0275 { 0276 return m_indiState; 0277 } 0278 void setIndiState(INDIState state); 0279 // last communication result with INDI 0280 CommunicationStatus indiCommunicationStatus() const 0281 { 0282 return m_INDICommunicationStatus; 0283 } 0284 void setIndiCommunicationStatus(CommunicationStatus newINDICommunicationStatus) 0285 { 0286 m_INDICommunicationStatus = newINDICommunicationStatus; 0287 } 0288 // counters for failed INDI connection attempts 0289 void resetIndiConnectFailureCount(uint8_t newIndiConnectFailureCount = 0) 0290 { 0291 m_indiConnectFailureCount = newIndiConnectFailureCount; 0292 } 0293 bool increaseIndiConnectFailureCount(); 0294 /** 0295 * @brief isINDIConnected Determines the status of the INDI connection. 0296 * @return True if INDI connection is up and usable, else false. 0297 */ 0298 bool isINDIConnected() const 0299 { 0300 return (indiCommunicationStatus() == Ekos::Success); 0301 } 0302 // //////////////////////////////////////////////////////////////////// 0303 // device states 0304 // //////////////////////////////////////////////////////////////////// 0305 bool mountReady() const 0306 { 0307 return m_MountReady; 0308 } 0309 void setMountReady(bool readiness) 0310 { 0311 m_MountReady = readiness; 0312 } 0313 bool captureReady() const 0314 { 0315 return m_CaptureReady; 0316 } 0317 void setCaptureReady(bool readiness) 0318 { 0319 m_CaptureReady = readiness; 0320 } 0321 bool domeReady() const 0322 { 0323 return m_DomeReady; 0324 } 0325 void setDomeReady(bool readiness) 0326 { 0327 m_DomeReady = readiness; 0328 } 0329 bool capReady() const 0330 { 0331 return m_CapReady; 0332 } 0333 void setCapReady(bool readiness) 0334 { 0335 m_CapReady = readiness; 0336 } 0337 0338 uint16_t captureBatch() const 0339 { 0340 return m_captureBatch; 0341 } 0342 void resetCaptureBatch() 0343 { 0344 m_captureBatch = 0; 0345 } 0346 uint16_t increaseCaptureBatch() 0347 { 0348 return m_captureBatch++; 0349 } 0350 0351 uint8_t captureFailureCount() const 0352 { 0353 return m_captureFailureCount; 0354 } 0355 void resetCaptureFailureCount() 0356 { 0357 m_captureFailureCount = 0; 0358 } 0359 bool increaseCaptureFailureCount(); 0360 0361 uint8_t focusFailureCount() const 0362 { 0363 return m_focusFailureCount; 0364 } 0365 void resetFocusFailureCount() 0366 { 0367 m_focusFailureCount = 0; 0368 } 0369 bool increaseFocusFailureCount(); 0370 0371 bool autofocusCompleted() const 0372 { 0373 return m_autofocusCompleted; 0374 } 0375 void setAutofocusCompleted(bool value) 0376 { 0377 m_autofocusCompleted = value; 0378 } 0379 0380 uint8_t guideFailureCount() const 0381 { 0382 return m_guideFailureCount; 0383 } 0384 void resetGuideFailureCount() 0385 { 0386 m_guideFailureCount = 0; 0387 } 0388 bool increaseGuideFailureCount(); 0389 0390 uint8_t alignFailureCount() const 0391 { 0392 return m_alignFailureCount; 0393 } 0394 void resetAlignFailureCount() 0395 { 0396 m_alignFailureCount = 0; 0397 } 0398 bool increaseAlignFailureCount(); 0399 0400 int restartGuidingInterval() const 0401 { 0402 return m_restartGuidingInterval; 0403 } 0404 0405 const KStarsDateTime &restartGuidingTime() const 0406 { 0407 return m_restartGuidingTime; 0408 } 0409 0410 ISD::Weather::Status weatherStatus() const 0411 { 0412 return m_weatherStatus; 0413 } 0414 void setWeatherStatus(ISD::Weather::Status newWeatherStatus) 0415 { 0416 m_weatherStatus = newWeatherStatus; 0417 } 0418 0419 // //////////////////////////////////////////////////////////////////// 0420 // Timers and time 0421 // //////////////////////////////////////////////////////////////////// 0422 // Returns milliseconds since startCurrentOperationTImer() was called. 0423 qint64 getCurrentOperationMsec() const; 0424 // Starts the above operation timer. 0425 // TODO. It would be better to make this a class and give each operation its own timer. 0426 // TODO. These should be disabled once no longer relevant. 0427 // These are implement with a KStarsDateTime instead of a QTimer type class 0428 // so that the simulated clock can be used. 0429 void startCurrentOperationTimer(); 0430 0431 // Controls for the guiding timer, which restarts guiding after failure. 0432 void cancelGuidingTimer(); 0433 bool isGuidingTimerActive(); 0434 void startGuidingTimer(int milliseconds); 0435 0436 /** @brief Setter used in testing to fix the local time. Otherwise getter gets from KStars instance. */ 0437 /** @{ */ 0438 static KStarsDateTime getLocalTime(); 0439 static void setLocalTime(KStarsDateTime *time) 0440 { 0441 storedLocalTime = time; 0442 } 0443 static bool hasLocalTime() 0444 { 0445 return storedLocalTime != nullptr; 0446 } 0447 0448 /** @} */ 0449 0450 0451 // //////////////////////////////////////////////////////////////////// 0452 // Astronomical calculations 0453 // //////////////////////////////////////////////////////////////////// 0454 /** 0455 * @brief calculateDawnDusk find the next astronomical dawn and dusk after the current date and time of observation 0456 */ 0457 static void calculateDawnDusk(QDateTime const &when, QDateTime &nDawn, QDateTime &nDusk); 0458 0459 /** 0460 * @brief calculateDawnDusk Calculate dawn and dusk times for today 0461 */ 0462 void calculateDawnDusk(); 0463 0464 static QDateTime Dawn() 0465 { 0466 return m_Dawn; 0467 } 0468 static QDateTime Dusk() 0469 { 0470 return m_Dusk; 0471 } 0472 static QDateTime PreDawnDateTime() 0473 { 0474 return m_PreDawnDateTime; 0475 } 0476 0477 /** @brief Setter used in testing to fix the geo location. Otherwise getter gets from KStars instance. */ 0478 /** @{ */ 0479 static const GeoLocation *getGeo(); 0480 static void setGeo(GeoLocation *geo) 0481 { 0482 storedGeo = geo; 0483 } 0484 static bool hasGeo(); 0485 0486 // //////////////////////////////////////////////////////////////////// 0487 // Scheduler iterations 0488 // //////////////////////////////////////////////////////////////////// 0489 0490 // Setup the parameters for the next scheduler iteration. 0491 // When milliseconds is not passed in, it uses m_UpdatePeriodMs. 0492 void setupNextIteration(SchedulerTimerState nextState); 0493 void setupNextIteration(SchedulerTimerState nextState, int milliseconds); 0494 0495 SchedulerTimerState timerState() const 0496 { 0497 return m_timerState; 0498 } 0499 0500 void setTimerState(SchedulerTimerState newTimerState) 0501 { 0502 m_timerState = newTimerState; 0503 } 0504 0505 QTimer &iterationTimer() 0506 { 0507 return m_iterationTimer; 0508 } 0509 0510 bool iterationSetup() const 0511 { 0512 return m_iterationSetup; 0513 } 0514 void setIterationSetup(bool setup) 0515 { 0516 m_iterationSetup = setup; 0517 } 0518 0519 qint64 startMSecs() const 0520 { 0521 return m_startMSecs; 0522 } 0523 void setStartMSecs(qint64 value) 0524 { 0525 m_startMSecs = value; 0526 } 0527 int increaseSchedulerIteration() 0528 { 0529 return ++m_schedulerIteration; 0530 } 0531 void resetSchedulerIteration() 0532 { 0533 m_schedulerIteration = 0; 0534 } 0535 0536 int timerInterval() const 0537 { 0538 return m_timerInterval; 0539 } 0540 void setTimerInterval(int value) 0541 { 0542 m_timerInterval = value; 0543 } 0544 0545 void setUpdatePeriodMs(int ms) 0546 { 0547 m_UpdatePeriodMs = ms; 0548 } 0549 int updatePeriodMs() const 0550 { 0551 return m_UpdatePeriodMs; 0552 } 0553 0554 uint sequenceExecutionCounter() const 0555 { 0556 return m_sequenceExecutionCounter; 0557 } 0558 void resetSequenceExecutionCounter() 0559 { 0560 m_sequenceExecutionCounter = 1; 0561 } 0562 void increaseSequenceExecutionCounter() 0563 { 0564 m_sequenceExecutionCounter++; 0565 } 0566 0567 static uint maxFailureAttempts(); 0568 0569 /** 0570 * @brief checkRepeatSequence Check if the entire job sequence might be repeated 0571 * @return true if the checkbox is set and the number of iterations is below the 0572 * configured threshold 0573 */ 0574 bool checkRepeatSequence(); 0575 0576 signals: 0577 // //////////////////////////////////////////////////////////////////// 0578 // communication with the UI 0579 // //////////////////////////////////////////////////////////////////// 0580 // State change of EKOS 0581 void ekosStateChanged(EkosState state); 0582 // State change of INDI 0583 void indiStateChanged(INDIState state); 0584 // overall scheduler state changed 0585 void schedulerStateChanged(SchedulerState state); 0586 // startup state 0587 void startupStateChanged(StartupState state); 0588 // shutdown state 0589 void shutdownStateChanged(ShutdownState state); 0590 // parking state 0591 void parkWaitStateChanged(ParkWaitState state); 0592 // profiles updated 0593 void profilesChanged(); 0594 // current profile changed 0595 void currentProfileChanged(); 0596 // new log text for the module log window 0597 void newLog(const QString &text); 0598 // current position in the job list changed 0599 void currentPositionChanged(int pos); 0600 // job stage of the current job changed 0601 void jobStageChanged(SchedulerJobStage stage); 0602 // night time calculation updated 0603 void updateNightTime(SchedulerJob const * job = nullptr); 0604 0605 0606 private: 0607 // //////////////////////////////////////////////////////////////////// 0608 // Scheduler jobs 0609 // //////////////////////////////////////////////////////////////////// 0610 // List of all jobs as entered by the user or file 0611 QList<SchedulerJob *> m_jobs; 0612 // Active job 0613 SchedulerJob *m_activeJob { nullptr }; 0614 0615 // //////////////////////////////////////////////////////////////////// 0616 // state attributes 0617 // //////////////////////////////////////////////////////////////////// 0618 // coarse grained state describing the general execution state 0619 SchedulerState m_schedulerState { SCHEDULER_IDLE }; 0620 // states of the scheduler startup 0621 StartupState m_startupState { STARTUP_IDLE }; 0622 // Startup script URL 0623 QUrl m_startupScriptURL; 0624 // states of the scheduler shutdown 0625 ShutdownState m_shutdownState { SHUTDOWN_IDLE }; 0626 // current position on the job list - necessary if there is no line selected in the 0627 // UI, for example after deleting a row. 0628 int m_currentPosition { -1 }; 0629 // Shutdown script URL 0630 QUrl m_shutdownScriptURL; 0631 // states of parking 0632 ParkWaitState m_parkWaitState { PARKWAIT_IDLE }; 0633 // current profile 0634 QString m_currentProfile; 0635 // all profiles 0636 QStringList m_profiles; 0637 // Was job modified and needs saving? 0638 bool m_dirty { false }; 0639 0640 // EKOS state describing whether EKOS is running (remember that the scheduler 0641 // does not need EKOS running). 0642 EkosState m_ekosState { EKOS_IDLE }; 0643 // Execution state of INDI 0644 INDIState m_indiState { INDI_IDLE }; 0645 // Last communication result with EKOS and INDI 0646 CommunicationStatus m_EkosCommunicationStatus { Ekos::Idle }; 0647 CommunicationStatus m_INDICommunicationStatus { Ekos::Idle }; 0648 0649 // device readiness 0650 bool m_MountReady { false }; 0651 bool m_CaptureReady { false }; 0652 bool m_DomeReady { false }; 0653 bool m_CapReady { false }; 0654 0655 // Restricts (the internal solver) to using the index and healpix 0656 // from the previous solve, if that solve was successful, when 0657 // doing the pointing check. -1 means no restriction. 0658 int m_IndexToUse { -1 }; 0659 int m_HealpixToUse { -1 }; 0660 0661 // Check if initial autofocus is completed and do not run autofocus until 0662 // there is a change is telescope position/alignment. 0663 bool m_autofocusCompleted { false }; 0664 0665 // Keep watch of weather status 0666 ISD::Weather::Status m_weatherStatus { ISD::Weather::WEATHER_IDLE }; 0667 0668 // //////////////////////////////////////////////////////////////////// 0669 // counters 0670 // //////////////////////////////////////////////////////////////////// 0671 // count for job sequence iteration 0672 uint m_sequenceExecutionCounter { 1 }; 0673 // Keep track of INDI connection failures 0674 uint8_t m_indiConnectFailureCount { 0 }; 0675 // Keep track of Ekos connection failures 0676 uint8_t m_ekosConnectFailureCount { 0 }; 0677 // failures parking dust cap 0678 uint8_t m_parkingCapFailureCount { 0 }; 0679 // failures parking mount 0680 uint8_t m_parkingMountFailureCount { 0 }; 0681 // failures parking dome 0682 uint8_t m_parkingDomeFailureCount { 0 }; 0683 // How many repeated job batches did we complete thus far? 0684 uint16_t m_captureBatch { 0 }; 0685 // Keep track of Ekos capture module failures 0686 uint8_t m_captureFailureCount { 0 }; 0687 // Keep track of Ekos focus module failures 0688 uint8_t m_focusFailureCount { 0 }; 0689 // Keep track of Ekos guide module failures 0690 uint8_t m_guideFailureCount { 0 }; 0691 // Keep track of Ekos align module failures 0692 uint8_t m_alignFailureCount { 0 }; 0693 // frames count for all signatures 0694 QMap<QString, uint16_t> m_CapturedFramesCount; 0695 0696 // //////////////////////////////////////////////////////////////////// 0697 // Scheduler iterations 0698 // //////////////////////////////////////////////////////////////////// 0699 0700 // The type of scheduler iteration that should be run next. 0701 SchedulerTimerState m_timerState { RUN_NOTHING }; 0702 // Variable keeping the number of millisconds the scheduler should wait 0703 // after the current scheduler iteration. 0704 int m_timerInterval { -1 }; 0705 // Whether the scheduler has been setup for the next iteration, 0706 // that is, whether timerInterval and timerState have been set this iteration. 0707 bool m_iterationSetup { false }; 0708 // The timer used to wakeup the scheduler between iterations. 0709 QTimer m_iterationTimer; 0710 // Counter for how many scheduler iterations have been processed. 0711 int m_schedulerIteration { 0 }; 0712 // The time when the scheduler first started running iterations. 0713 qint64 m_startMSecs { 0 }; 0714 // This is the time between typical scheduler iterations. 0715 // The time can be modified for testing. 0716 int m_UpdatePeriodMs = 1000; 0717 0718 // //////////////////////////////////////////////////////////////////// 0719 // time and timers 0720 // //////////////////////////////////////////////////////////////////// 0721 // constants for current dawn and dusk 0722 /// Store next dawn to calculate dark skies range 0723 static QDateTime m_Dawn; 0724 /// Store next dusk to calculate dark skies range 0725 static QDateTime m_Dusk; 0726 /// Pre-dawn is where we stop all jobs, it is a user-configurable value before Dawn. 0727 static QDateTime m_PreDawnDateTime; 0728 // Generic time to track timeout of current operation in progress. 0729 // Used by startCurrentOperationTimer() and getCurrentOperationMsec(). 0730 KStarsDateTime currentOperationTime; 0731 bool currentOperationTimeStarted { false }; 0732 // Delay for restarting the guider 0733 int m_restartGuidingInterval { -1 }; 0734 KStarsDateTime m_restartGuidingTime; 0735 // Used in testing, instead of KStars::Instance() resources 0736 static KStarsDateTime *storedLocalTime; 0737 // The various preemptiveShutdown states are controlled by this one variable. 0738 QDateTime m_preemptiveShutdownWakeupTime; 0739 0740 // These are used in testing, instead of KStars::Instance() resources 0741 static GeoLocation *storedGeo; 0742 0743 }; 0744 } // Ekos namespace