File indexing completed on 2025-04-20 09:31:06
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #ifdef USE_QT5_INDI 0010 #include <baseclientqt.h> 0011 #else 0012 #include <baseclient.h> 0013 #endif 0014 0015 #include "ui_manager.h" 0016 0017 #include "ekos.h" 0018 #include "fitsviewer/summaryfitsview.h" 0019 #include "indi/indistd.h" 0020 #include "auxiliary/portselector.h" 0021 #include "ksnotification.h" 0022 #include "auxiliary/opslogs.h" 0023 #include "ekos/capture/rotatorsettings.h" 0024 0025 #include <QDialog> 0026 #include <QHash> 0027 0028 #include <memory> 0029 0030 //! Generic record interfaces and implementations. 0031 namespace EkosLive 0032 { 0033 class Client; 0034 class Message; 0035 class Media; 0036 } 0037 0038 class DriverInfo; 0039 class ProfileInfo; 0040 class KPageWidgetItem; 0041 class OpsEkos; 0042 0043 /** 0044 * @class Manager 0045 * @short Primary class to handle all Ekos modules. 0046 * The Ekos Manager class manages startup and shutdown of INDI devices and registeration of devices within Ekos Modules. Ekos module consist of \ref Ekos::Mount, \ref Ekos::Capture, \ref Ekos::Focus, \ref Ekos::Guide, and \ref Ekos::Align modules. 0047 * \defgroup EkosDBusInterface "Ekos DBus Interface" provides high level functions to control devices and Ekos modules for a total robotic operation: 0048 * <ul> 0049 * <li>\ref CaptureDBusInterface "Capture Module DBus Interface"</li> 0050 * <li>\ref FocusDBusInterface "Focus Module DBus Interface"</li> 0051 * <li>\ref MountDBusInterface "Mount Module DBus Interface"</li> 0052 * <li>\ref GuideDBusInterface "Guide Module DBus Interface"</li> 0053 * <li>\ref AlignDBusInterface "Align Module DBus Interface"</li> 0054 * <li>\ref WeatherDBusInterface "Weather DBus Interface"</li> 0055 * <li>\ref DustCapDBusInterface "Dust Cap DBus Interface"</li> 0056 * </ul> 0057 * For low level access to INDI devices, the \ref INDIDBusInterface "INDI Dbus Interface" provides complete access to INDI devices and properties. 0058 * Ekos Manager provides a summary of operations progress in the <i>Summary</i> section of the <i>Setup</i> tab. 0059 * 0060 * @author Jasem Mutlaq 0061 * @version 1.8 0062 */ 0063 namespace Ekos 0064 { 0065 0066 class Analyze; 0067 class Capture; 0068 class Scheduler; 0069 class Focus; 0070 class Align; 0071 class Guide; 0072 class Mount; 0073 class Observatory; 0074 // class RotatorSettings; 0075 0076 class Manager : public QDialog, public Ui::Manager 0077 { 0078 Q_OBJECT 0079 Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos") 0080 0081 Q_SCRIPTABLE Q_PROPERTY(Ekos::CommunicationStatus indiStatus READ indiStatus NOTIFY indiStatusChanged) 0082 Q_SCRIPTABLE Q_PROPERTY(Ekos::CommunicationStatus ekosStatus READ ekosStatus NOTIFY ekosStatusChanged) 0083 Q_SCRIPTABLE Q_PROPERTY(Ekos::CommunicationStatus settleStatus READ settleStatus NOTIFY settleStatusChanged) 0084 Q_SCRIPTABLE Q_PROPERTY(bool ekosLiveStatus READ ekosLiveStatus NOTIFY ekosLiveStatusChanged) 0085 Q_SCRIPTABLE Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) 0086 0087 enum class EkosModule 0088 { 0089 Setup, 0090 Scheduler, 0091 Analyze, 0092 Capture, 0093 Focus, 0094 Mount, 0095 Align, 0096 Guide, 0097 Observatory, 0098 }; 0099 public: 0100 static Manager *Instance(); 0101 static void release(); 0102 0103 // No OP 0104 void initialize() {} 0105 0106 void appendLogText(const QString &); 0107 void setOptionsWidget(KPageWidgetItem *ops, OpsEkos *opsEkosPtr) 0108 { 0109 ekosOptionsWidget = ops; 0110 opsEkos = opsEkosPtr; 0111 } 0112 void addObjectToScheduler(SkyObject *object); 0113 0114 Scheduler *schedulerModule() 0115 { 0116 return schedulerProcess.get(); 0117 } 0118 Guide *guideModule() 0119 { 0120 return guideProcess.get(); 0121 } 0122 Align *alignModule() 0123 { 0124 return alignProcess.get(); 0125 } 0126 Mount *mountModule() 0127 { 0128 return mountProcess.get(); 0129 } 0130 Focus *focusModule() 0131 { 0132 return focusProcess.get(); 0133 } 0134 Capture *captureModule() 0135 { 0136 return captureProcess.get(); 0137 } 0138 FITSView *getSummaryPreview() 0139 { 0140 return m_SummaryView.get(); 0141 } 0142 0143 // Filter Manager 0144 void createFilterManager(ISD::FilterWheel *device); 0145 bool getFilterManager(const QString &name, QSharedPointer<FilterManager> &fm); 0146 bool getFilterManager(QSharedPointer<FilterManager> &fm); 0147 0148 // Rotator Control 0149 void createRotatorController(ISD::Rotator *device); 0150 bool getRotatorController(const QString &Name, QSharedPointer<RotatorSettings> &rs); 0151 bool existRotatorController(); 0152 0153 QString getCurrentJobName(); 0154 void announceEvent(const QString &message, KSNotification::EventSource source, KSNotification::EventType event); 0155 0156 /** 0157 * @brief activateModule Switch tab to specific module name (i.e. CCD) and raise Ekos screen to focus. 0158 * @param name module name CCD, Guide, Focus, Mount, Scheduler, or Observatory. 0159 * @param popup if True, show Ekos Manager window in the foreground. 0160 */ 0161 void activateModule(const QString &name, bool popup = false); 0162 0163 /** 0164 * @brief addProfile Add a new profile to the database. 0165 * @param profileInfo Collection of profile parameters to include the following: 0166 * 1. name: Profile name 0167 * 2. auto_connect: True of False for Autoconnect? 0168 * 3. Mode: "local" or "remote" 0169 * 4. remote_host: Optional. remote host (default localhost) 0170 * 5. remote_port: Optional. remote port (default 7624) 0171 * 6. guiding: 0 for "Internal", 1 for "PHD2", or 2 for "LinGuider" 0172 * 7. remote_guiding_host: Optional. remote host for guider application (default localhost) 0173 * 8. remote_guide_port: Optional. remote port for guider application. 0174 * 9. use_web_manager: True or False? 0175 * 10. web_manager_port. Optional. INDI Web Manager port (default 8624) 0176 * 12. primary_scope: ID of primary scope to use. This is the ID from OAL::Scope list in the database. 0177 * 13. guide_scope: ID of guide scope to use. This is the ID from OAL::Scope list in the database. 0178 * 14. mount: Mount driver label (default --). 0179 * 15. ccd: CCD driver label (default --). 0180 * 16. guider: Guider driver label (default --). 0181 * 17. focuser: Focuser driver label (default --). 0182 * 18. filter: Filter Wheel driver label (default --). 0183 * 19. ao: Adaptive Optics driver label (default --). 0184 * 20. dome: Dome driver label (default --). 0185 * 21. Weather: Weather station driver label (default --). 0186 * 22. aux1: aux1 driver label (default --). 0187 * 23. aux2: aux2 driver label (default --). 0188 * 24. aux3: aux3 driver label (default --). 0189 * 25. aux4: aux4 driver label (default --). 0190 */ 0191 void addNamedProfile(const QJsonObject &profileInfo); 0192 0193 /** Same as above, except it edits an existing named profile */ 0194 void editNamedProfile(const QJsonObject &profileInfo); 0195 0196 /** 0197 * @brief deleteProfile Delete existing equipment profile 0198 * @param name Name of profile 0199 * @warning Ekos must be stopped for this to work. It will fail if Ekos is online. 0200 */ 0201 void deleteNamedProfile(const QString &name); 0202 0203 /** 0204 * @brief getProfile Get a single profile information. 0205 * @param name Profile name 0206 * @return A JSon object with the detail profile info as described in addProfile function. 0207 */ 0208 QJsonObject getNamedProfile(const QString &name); 0209 0210 /** 0211 * DBus commands to manage equipment profiles. 0212 */ 0213 0214 /*@{*/ 0215 0216 /** 0217 * DBUS interface function. 0218 * set Current device profile. 0219 * @param profileName Profile name 0220 * @return True if profile is set, false if not found. 0221 */ 0222 Q_SCRIPTABLE bool setProfile(const QString &profileName); 0223 0224 /** 0225 * DBUS interface function 0226 * @brief getProfiles Return a list of all device profiles 0227 * @return List of device profiles 0228 */ 0229 Q_SCRIPTABLE QStringList getProfiles(); 0230 0231 /** @}*/ 0232 0233 0234 /** 0235 * Manager interface provides advanced scripting capabilities to establish and shutdown Ekos services. 0236 */ 0237 0238 /*@{*/ 0239 0240 /** 0241 * DBUS interface function. 0242 * @return INDI connection status (0 Idle, 1 Pending, 2 Connected, 3 Error) 0243 * @deprecated 0244 */ 0245 Q_SCRIPTABLE unsigned int getINDIConnectionStatus() 0246 { 0247 return m_indiStatus; 0248 } 0249 0250 Q_SCRIPTABLE Ekos::CommunicationStatus indiStatus() 0251 { 0252 return m_indiStatus; 0253 } 0254 0255 /** 0256 * DBUS interface function. 0257 * @return Ekos starting status (0 Idle, 1 Pending, 2 Started, 3 Error) 0258 * @deprecated 0259 */ 0260 Q_SCRIPTABLE unsigned int getEkosStartingStatus() 0261 { 0262 return m_ekosStatus; 0263 } 0264 0265 Q_SCRIPTABLE Ekos::CommunicationStatus ekosStatus() 0266 { 0267 return m_ekosStatus; 0268 } 0269 0270 /** 0271 * DBUS interface function. 0272 * @return Settle status (0 Idle, 1 Pending, 2 Started, 3 Error) 0273 */ 0274 Q_SCRIPTABLE Ekos::CommunicationStatus settleStatus() 0275 { 0276 return m_settleStatus; 0277 } 0278 0279 /** 0280 * DBUS interface function. Toggle Ekos logging. 0281 * @param name Name of logging to toggle. Available options are: 0282 * ** VERBOSE 0283 * ** INDI 0284 * ** FITS 0285 * ** CAPTURE 0286 * ** FOCUS 0287 * ** GUIDE 0288 * ** ALIGNMENT 0289 * ** MOUNT 0290 * ** SCHEDULER 0291 * ** OBSERVATORY 0292 * @param enabled True to enable, false otherwise. 0293 */ 0294 Q_SCRIPTABLE Q_NOREPLY void setEkosLoggingEnabled(const QString &name, bool enabled); 0295 0296 /** 0297 * DBUS interface function. 0298 * If connection mode is local, the function first establishes an INDI server with all the specified drivers in Ekos options or as set by the user. For remote connection, 0299 * it establishes connection to the remote INDI server. 0300 * @return Returns true if server started successful (local mode) or connection to remote server is successful (remote mode). 0301 */ 0302 Q_SCRIPTABLE void start(); 0303 0304 /** 0305 * DBUS interface function. 0306 * If connection mode is local, the function terminates the local INDI server and drivers. For remote, it disconnects from the remote INDI server. 0307 */ 0308 Q_SCRIPTABLE void stop(); 0309 0310 Q_SCRIPTABLE QStringList logText() 0311 { 0312 return m_LogText; 0313 } 0314 0315 Q_SCRIPTABLE bool ekosLiveStatus(); 0316 0317 /** 0318 * DBUS interface function. 0319 * @param enabled Connect to EkosLive if true, otherwise disconnect. 0320 */ 0321 Q_SCRIPTABLE void setEkosLiveConnected(bool enabled); 0322 0323 /** 0324 * @brief setEkosLiveConfig Set EkosLive settings 0325 * @param rememberCredentials Remember username and password for next session. 0326 * @param autoConnect If true, it will automatically connect to EkosLive service. 0327 */ 0328 Q_SCRIPTABLE void setEkosLiveConfig(bool rememberCredentials, bool autoConnect); 0329 0330 /** 0331 * @brief setEkosLiveUser Save EkosLive username and password 0332 * @param username User name 0333 * @param password Password 0334 */ 0335 Q_SCRIPTABLE void setEkosLiveUser(const QString &username, const QString &password); 0336 0337 /** 0338 * @brief acceptPortSelection Accept current port selection settings in the Selector Dialog 0339 */ 0340 Q_SCRIPTABLE void acceptPortSelection(); 0341 0342 signals: 0343 // Have to use full Ekos::CommunicationStatus for DBus signal to work 0344 void ekosStatusChanged(Ekos::CommunicationStatus status); 0345 void indiStatusChanged(Ekos::CommunicationStatus status); 0346 void settleStatusChanged(Ekos::CommunicationStatus status); 0347 void ekosLiveStatusChanged(bool status); 0348 0349 void newLog(const QString &text); 0350 void newModule(const QString &name); 0351 void newDevice(const QString &name, int interface); 0352 0353 protected: 0354 void closeEvent(QCloseEvent *event) override; 0355 void hideEvent(QHideEvent *) override; 0356 void showEvent(QShowEvent *) override; 0357 void resizeEvent(QResizeEvent *) override; 0358 0359 public slots: 0360 0361 /** 0362 * DBUS interface function. 0363 * Connects all the INDI devices started by Ekos. 0364 */ 0365 Q_SCRIPTABLE Q_NOREPLY void connectDevices(); 0366 0367 /** 0368 * DBUS interface function. 0369 * Disconnects all the INDI devices started by Ekos. 0370 */ 0371 Q_SCRIPTABLE Q_NOREPLY void disconnectDevices(); 0372 0373 /** @}*/ 0374 0375 void processINDI(); 0376 void cleanDevices(bool stopDrivers = true); 0377 0378 void processNewDevice(const QSharedPointer<ISD::GenericDevice> &device); 0379 0380 void processNewProperty(INDI::Property); 0381 void processUpdateProperty(INDI::Property); 0382 void processDeleteProperty(INDI::Property); 0383 void processMessage(int id); 0384 0385 0386 void setDeviceReady(); 0387 0388 void restartDriver(const QString &deviceName); 0389 0390 private slots: 0391 0392 void changeAlwaysOnTop(Qt::ApplicationState state); 0393 0394 void showEkosOptions(); 0395 0396 void updateLog(); 0397 void clearLog(); 0398 0399 void processTabChange(); 0400 0401 void setServerStarted(const QString &host, int port); 0402 void setServerFailed(const QString &host, int port, const QString &message); 0403 //void setServerTerminated(const QString &host, int port, const QString &message); 0404 0405 void setClientStarted(const QString &host, int port); 0406 void setClientFailed(const QString &host, int port, const QString &message); 0407 void setClientTerminated(const QString &host, int port, const QString &message); 0408 0409 void removeDevice(const QSharedPointer<ISD::GenericDevice> &device); 0410 0411 void deviceConnected(); 0412 void deviceDisconnected(); 0413 0414 //void processINDIModeChange(); 0415 void checkINDITimeout(); 0416 0417 // Logs 0418 void updateDebugInterfaces(); 0419 void watchDebugProperty(INDI::Property prop); 0420 0421 void addMount(ISD::Mount *device); 0422 void addCamera(ISD::Camera *device); 0423 void addFilterWheel(ISD::FilterWheel *device); 0424 void addFocuser(ISD::Focuser *device); 0425 void addRotator(ISD::Rotator *device); 0426 void addDome(ISD::Dome *device); 0427 void addWeather(ISD::Weather *device); 0428 void addDustCap(ISD::DustCap *device); 0429 void addLightBox(ISD::LightBox *device); 0430 void addGuider(ISD::Guider *device); 0431 void addGPS(ISD::GPS *device); 0432 0433 /** 0434 * @brief syncGenericDevice Check if this device needs to be added to any Ekos module. 0435 * @param device pointer to generic device. 0436 */ 0437 void syncGenericDevice(const QSharedPointer<ISD::GenericDevice> &device); 0438 void createModules(const QSharedPointer<ISD::GenericDevice> &device); 0439 0440 // Profiles 0441 void addProfile(); 0442 void editProfile(); 0443 void deleteProfile(); 0444 void wizardProfile(); 0445 0446 // Mount Summary 0447 void updateMountCoords(const SkyPoint position, ISD::Mount::PierSide pierSide, const dms &ha); 0448 void updateMountStatus(ISD::Mount::Status status); 0449 void setTarget(const QString &name); 0450 0451 // Capture Summary 0452 void updateCaptureStatus(CaptureState status); 0453 void updateCaptureProgress(SequenceJob *job, const QSharedPointer<FITSData> &data); 0454 void updateExposureProgress(SequenceJob *job); 0455 void updateCaptureCountDown(); 0456 0457 // Focus summary 0458 void updateFocusStatus(FocusState status); 0459 void updateCurrentHFR(double newHFR, int position, bool inAutofocus); 0460 0461 // Guide Summary 0462 void updateGuideStatus(GuideState status); 0463 void updateSigmas(double ra, double de); 0464 0465 private: 0466 explicit Manager(QWidget *parent); 0467 ~Manager() override; 0468 0469 void removeTabs(); 0470 void reset(); 0471 void initCapture(); 0472 void initFocus(); 0473 void initGuide(); 0474 void initAlign(); 0475 void initMount(); 0476 void initObservatory(); 0477 0478 void loadDrivers(); 0479 void loadProfiles(); 0480 int addModuleTab(EkosModule module, QWidget *tab, const QIcon &icon); 0481 0482 /** 0483 * @brief syncActiveDevices Syncs ACTIVE_DEVICES such as ACTIVE_TELESCOPE and ACTIVE_CCD 0484 * to the currently detected devices. 0485 */ 0486 void syncActiveDevices(); 0487 0488 /** 0489 * @brief isINDIReady Check whether all INDI devices are connected and ready and emit signals accordingly. 0490 * @return True if all INDI devices are connected and ready. 0491 */ 0492 bool isINDIReady(); 0493 0494 // Connect Signals/Slots of Ekos modules 0495 void connectModules(); 0496 0497 // Check if INDI server is already running 0498 bool isRunning(const QString &process); 0499 0500 bool getCurrentProfile(QSharedPointer<ProfileInfo> &profile) const; 0501 void updateProfileLocation(const QSharedPointer<ProfileInfo> &profile); 0502 void setProfileMapping(const QJsonObject &payload) 0503 { 0504 m_ProfileMapping = payload; 0505 } 0506 // Port Selector Save profile when connect all is pressed 0507 void setPortSelectionComplete(); 0508 // Check if the driver binary must be one only to avoid duplicate instances 0509 // Some driver binaries support multiple devices per binary 0510 // so we only need to start a single instance to handle them all. 0511 bool checkUniqueBinaryDriver(const QSharedPointer<DriverInfo> &primaryDriver, 0512 const QSharedPointer<DriverInfo> &secondaryDriver); 0513 0514 // Containers 0515 0516 // All Drivers 0517 QHash<QString, QSharedPointer<DriverInfo>> driversList; 0518 0519 // All managed drivers 0520 QList<QSharedPointer<DriverInfo>> managedDrivers; 0521 0522 // Smart pointers for the various Ekos Modules 0523 std::unique_ptr<Capture> captureProcess; 0524 std::unique_ptr<Focus> focusProcess; 0525 std::unique_ptr<Guide> guideProcess; 0526 std::unique_ptr<Align> alignProcess; 0527 std::unique_ptr<Mount> mountProcess; 0528 std::unique_ptr<Analyze> analyzeProcess; 0529 std::unique_ptr<Scheduler> schedulerProcess; 0530 std::unique_ptr<Observatory> observatoryProcess; 0531 std::unique_ptr<EkosLive::Client> ekosLiveClient; 0532 0533 bool m_LocalMode { true }; 0534 bool m_isStarted { false }; 0535 bool m_RemoteManagerStart { false }; 0536 0537 int m_DriverDevicesCount { 0 }; 0538 0539 QStringList m_LogText; 0540 KPageWidgetItem *ekosOptionsWidget { nullptr }; 0541 OpsEkos *opsEkos { nullptr }; 0542 0543 CommunicationStatus m_ekosStatus { Ekos::Idle }; 0544 CommunicationStatus m_indiStatus { Ekos::Idle }; 0545 // Settle is used to know once all properties from all devices have been defined 0546 // There is no way to know this for sure so we use a debounace mechanism. 0547 CommunicationStatus m_settleStatus { Ekos::Idle }; 0548 0549 std::unique_ptr<QStandardItemModel> profileModel; 0550 QList<QSharedPointer<ProfileInfo>> profiles; 0551 QJsonObject m_ProfileMapping; 0552 0553 // Mount Summary 0554 QPointer<QProcess> indiHubAgent; 0555 KLed *mountMotionState { nullptr }; 0556 0557 0558 // Capture Summary 0559 QTimer m_CountdownTimer; 0560 QTimer settleTimer; 0561 // Preview Frame 0562 QSharedPointer<SummaryFITSView> m_SummaryView; 0563 0564 QSharedPointer<ProfileInfo> m_CurrentProfile; 0565 bool profileWizardLaunched { false }; 0566 QString m_PrimaryCamera, m_GuideCamera; 0567 0568 // Port Selector 0569 std::unique_ptr<Selector::Dialog> m_PortSelector; 0570 QTimer m_PortSelectorTimer; 0571 0572 QMap<QString, QSharedPointer<FilterManager>> m_FilterManagers; 0573 QMap<QString, QSharedPointer<RotatorSettings>> m_RotatorControllers; 0574 0575 // Logs 0576 QPointer<OpsLogs> opsLogs; 0577 0578 // E.g. Setup, Scheduler, and Analyze. 0579 int numPermanentTabs { 0 }; 0580 0581 friend class EkosLive::Client; 0582 friend class EkosLive::Message; 0583 friend class EkosLive::Media; 0584 0585 static Manager *_Manager; 0586 }; 0587 0588 }