File indexing completed on 2024-04-28 15:09:52
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 #include "ui_guide.h" 0010 #include "guideinterface.h" 0011 #include "ekos/ekos.h" 0012 #include "indi/indicamera.h" 0013 #include "indi/indimount.h" 0014 0015 #include <QTime> 0016 #include <QTimer> 0017 0018 #include <random> 0019 0020 class QProgressIndicator; 0021 class QTabWidget; 0022 0023 class FITSView; 0024 class FITSViewer; 0025 class ScrollGraph; 0026 class GuideView; 0027 0028 namespace Ekos 0029 { 0030 class OpsCalibration; 0031 class OpsGuide; 0032 class OpsDither; 0033 class OpsGPG; 0034 class InternalGuider; 0035 class PHD2; 0036 class LinGuider; 0037 class GuideStateWidget; 0038 class ManualPulse; 0039 class DarkProcessor; 0040 0041 /** 0042 * @class Guide 0043 * @short Performs calibration and autoguiding using an ST4 port or directly via the INDI driver. Can be used with the following external guiding applications: 0044 * PHD2 0045 * LinGuider 0046 * 0047 * @author Jasem Mutlaq 0048 * @version 1.4 0049 */ 0050 class Guide : public QWidget, public Ui::Guide 0051 { 0052 Q_OBJECT 0053 Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Guide") 0054 Q_PROPERTY(Ekos::GuideState status READ status NOTIFY newStatus) 0055 Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) 0056 Q_PROPERTY(QString opticalTrain READ opticalTrain WRITE setOpticalTrain) 0057 Q_PROPERTY(QString camera READ camera) 0058 Q_PROPERTY(QString guider READ guider) 0059 Q_PROPERTY(double exposure READ exposure WRITE setExposure) 0060 Q_PROPERTY(QList<double> axisDelta READ axisDelta NOTIFY newAxisDelta) 0061 Q_PROPERTY(QList<double> axisSigma READ axisSigma NOTIFY newAxisSigma) 0062 0063 public: 0064 Guide(); 0065 ~Guide(); 0066 0067 enum GuiderStage 0068 { 0069 CALIBRATION_STAGE, 0070 GUIDE_STAGE 0071 }; 0072 enum GuiderType 0073 { 0074 GUIDE_INTERNAL, 0075 GUIDE_PHD2, 0076 GUIDE_LINGUIDER 0077 }; 0078 0079 /** @defgroup GuideDBusInterface Ekos DBus Interface - Capture Module 0080 * Ekos::Guide interface provides advanced scripting capabilities to calibrate and guide a mount via a CCD camera. 0081 */ 0082 0083 /*@{*/ 0084 0085 /** DBUS interface function. 0086 * select the CCD device from the available CCD drivers. 0087 * @param device The CCD device name 0088 * @return Returns true if CCD device is found and set, false otherwise. 0089 */ 0090 Q_SCRIPTABLE QString camera(); 0091 0092 /** DBUS interface function. 0093 * select the ST4 device from the available ST4 drivers. 0094 * @param device The ST4 device name 0095 * @return Returns true if ST4 device is found and set, false otherwise. 0096 */ 0097 Q_SCRIPTABLE QString guider(); 0098 0099 /** DBUS interface function. 0100 * @brief connectGuider Establish connection to guider application. For internal guider, this always returns true. 0101 * @return True if successfully connected, false otherwise. 0102 */ 0103 Q_SCRIPTABLE bool connectGuider(); 0104 0105 /** DBUS interface function. 0106 * @brief disconnectGuider Disconnect from guider application. For internal guider, this always returns true. 0107 * @return True if successfully disconnected, false otherwise. 0108 */ 0109 Q_SCRIPTABLE bool disconnectGuider(); 0110 0111 /** 0112 * @brief getStatus Return guide module status 0113 * @return state of guide module from Ekos::GuideState 0114 */ 0115 Q_SCRIPTABLE Ekos::GuideState status() 0116 { 0117 return m_State; 0118 } 0119 0120 /** DBUS interface function. 0121 * Set CCD exposure value 0122 * @param value exposure value in seconds. 0123 */ 0124 Q_SCRIPTABLE Q_NOREPLY void setExposure(double value); 0125 double exposure() 0126 { 0127 return guideExposure->value(); 0128 } 0129 0130 /** DBUS interface function. 0131 * Set calibration dark frame option. The options must be set before starting the calibration operation. If no options are set, the options loaded from the user configuration are used. 0132 * @param enable if true, a dark frame will be captured to subtract from the light frame. 0133 */ 0134 Q_SCRIPTABLE Q_NOREPLY void setDarkFrameEnabled(bool enable); 0135 0136 /** @}*/ 0137 0138 /** 0139 * @brief Add new Camera 0140 * @param device pointer to camera device. 0141 * @return True if added successfully, false if duplicate or failed to add. 0142 */ 0143 bool setCamera(ISD::Camera *device); 0144 0145 0146 /** 0147 * @brief Add new Mount 0148 * @param device pointer to Mount device. 0149 * @return True if added successfully, false if duplicate or failed to add. 0150 */ 0151 bool setMount(ISD::Mount *device); 0152 0153 /** 0154 * @brief Add new Guider 0155 * @param device pointer to Guider device. 0156 * @return True if added successfully, false if duplicate or failed to add. 0157 */ 0158 bool setGuider(ISD::Guider *device); 0159 0160 /** 0161 * @brief Add new Adaptive Optics 0162 * @param device pointer to AO device. 0163 * @return True if added successfully, false if duplicate or failed to add. 0164 */ 0165 bool setAdaptiveOptics(ISD::AdaptiveOptics *device); 0166 0167 void removeDevice(const QSharedPointer<ISD::GenericDevice> &device); 0168 void configurePHD2Camera(); 0169 0170 bool isDithering(); 0171 void syncTelescopeInfo(); 0172 void syncCameraInfo(); 0173 0174 /** 0175 * @brief clearLog As the name suggests 0176 */ 0177 void clearLog(); 0178 QStringList logText() 0179 { 0180 return m_LogText; 0181 } 0182 0183 /** 0184 * @return Return current log text of guide module 0185 */ 0186 QString getLogText() 0187 { 0188 return m_LogText.join("\n"); 0189 } 0190 0191 /** 0192 * @brief getStarPosition Return star center as selected by the user or auto-detected by KStars 0193 * @return QVector3D of starCenter. The 3rd parameter is used to store current bin settings and in unrelated to the star position. 0194 */ 0195 QVector3D getStarPosition() 0196 { 0197 return starCenter; 0198 } 0199 0200 // Tracking Box 0201 int getTrackingBoxSize() 0202 { 0203 return guideSquareSize->currentText().toInt(); 0204 } 0205 0206 GuideInterface *getGuiderInstance() 0207 { 0208 return m_GuiderInstance; 0209 } 0210 0211 // Settings 0212 QVariantMap getAllSettings() const; 0213 void setAllSettings(const QVariantMap &settings); 0214 0215 public slots: 0216 0217 /** DBUS interface function. 0218 * Start the autoguiding operation. 0219 * @return Returns true if guiding started successfully, false otherwise. 0220 */ 0221 Q_SCRIPTABLE bool guide(); 0222 0223 /** DBUS interface function. 0224 * Stop any active calibration, guiding, or dithering operation 0225 * @return Returns true if operation is stopped successfully, false otherwise. 0226 */ 0227 Q_SCRIPTABLE bool abort(); 0228 0229 /** DBUS interface function. 0230 * Start the calibration operation. Note that this will not start guiding automatically. 0231 * @return Returns true if calibration started successfully, false otherwise. 0232 */ 0233 Q_SCRIPTABLE bool calibrate(); 0234 0235 /** DBUS interface function. 0236 * Clear calibration data. Next time any guide operation is performed, a calibration is first started. 0237 */ 0238 Q_SCRIPTABLE Q_NOREPLY void clearCalibration(); 0239 0240 /** DBUS interface function. 0241 * @brief dither Starts dithering process in a random direction restricted by the number of pixels specified in dither options 0242 * @return True if dither started successfully, false otherwise. 0243 */ 0244 Q_SCRIPTABLE bool dither(); 0245 0246 /** DBUS interface function. 0247 * @brief suspend Suspend autoguiding 0248 * @return True if successful, false otherwise. 0249 */ 0250 Q_SCRIPTABLE bool suspend(); 0251 0252 /** DBUS interface function. 0253 * @brief resume Resume autoguiding 0254 * @return True if successful, false otherwise. 0255 */ 0256 Q_SCRIPTABLE bool resume(); 0257 0258 /** DBUS interface function. 0259 * Capture a guide frame 0260 * @return Returns true if capture command is sent successfully to INDI server. 0261 */ 0262 Q_SCRIPTABLE bool capture(); 0263 0264 /** DBUS interface function. 0265 * Loop frames specified by the exposure control continuously until stopped. 0266 */ 0267 Q_SCRIPTABLE Q_NOREPLY void loop(); 0268 0269 /** DBUS interface function. 0270 * Set guiding options. The options must be set before starting the guiding operation. If no options are set, the options loaded from the user configuration are used. 0271 * @param enable if true, it will select a subframe around the guide star depending on the boxSize size. 0272 */ 0273 Q_SCRIPTABLE Q_NOREPLY void setSubFrameEnabled(bool enable); 0274 0275 /** DBUS interface function. 0276 * Set guiding options. The options must be set before starting the guiding operation. If no options are set, the options loaded from the user configuration are used. 0277 * @param enable if true, it will select a subframe around the guide star depending on the boxSize size. 0278 */ 0279 Q_SCRIPTABLE Q_NOREPLY void setAutoStarEnabled(bool enable); 0280 0281 /** DBUS interface function. 0282 * Selects which guiding process to utilize for calibration & guiding. 0283 * @param type Type of guider process to use. 0 for internal guider, 1 for external PHD2, 2 for external lin_guider. Pass -1 to select default guider in options. 0284 * @return True if guiding is switched to the new requested type. False otherwise. 0285 */ 0286 Q_SCRIPTABLE bool setGuiderType(int type); 0287 0288 /** DBUS interface function. 0289 * @brief axisDelta returns the last immediate axis delta deviation in arcseconds. This is the deviation of locked star position when guiding started. 0290 * @return List of doubles. First member is RA deviation. Second member is DE deviation. 0291 */ 0292 Q_SCRIPTABLE QList<double> axisDelta(); 0293 0294 /** DBUS interface function. 0295 * @brief axisSigma return axis sigma deviation in arcseconds RMS. This is the RMS deviation of locked star position when guiding started. 0296 * @return List of doubles. First member is RA deviation. Second member is DE deviation. 0297 */ 0298 Q_SCRIPTABLE QList<double> axisSigma(); 0299 0300 /** 0301 * @brief checkCamera Check all CCD parameters and ensure all variables are updated to reflect the selected CCD 0302 * @param ccdNum CCD index number in the CCD selection combo box 0303 */ 0304 void checkCamera(); 0305 0306 /** 0307 * @brief checkExposureValue This function is called by the INDI framework whenever there is a new exposure value. We use it to know if there is a problem with the exposure 0308 * @param targetChip Chip for which the exposure is undergoing 0309 * @param exposure numbers of seconds left in the exposure 0310 * @param expState State of the exposure property 0311 */ 0312 void checkExposureValue(ISD::CameraChip *targetChip, double exposure, IPState expState); 0313 0314 /** 0315 * @brief newFITS is called by the INDI framework whenever there is a new BLOB arriving 0316 */ 0317 void processData(const QSharedPointer<FITSData> &data); 0318 0319 // Aborts the current exposure, if one is ongoing. 0320 void abortExposure(); 0321 0322 // This Function will allow PHD2 to update the exposure values to the recommended ones. 0323 QString setRecommendedExposureValues(QList<double> values); 0324 0325 // Append Log entry 0326 void appendLogText(const QString &); 0327 0328 // Update Guide module status 0329 void setStatus(Ekos::GuideState newState); 0330 0331 // Update Capture Module status 0332 void setCaptureStatus(Ekos::CaptureState newState); 0333 // Update Mount module status 0334 void setMountStatus(ISD::Mount::Status newState); 0335 void setMountCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &ha); 0336 0337 // Update Pier Side 0338 void setPierSide(ISD::Mount::PierSide newSide); 0339 0340 // Star Position 0341 void setStarPosition(const QVector3D &newCenter, bool updateNow); 0342 0343 // Capture 0344 void setCaptureComplete(); 0345 0346 // Pulse both RA and DEC axes 0347 bool sendMultiPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs, CaptureAfterPulses followWithCapture); 0348 // Pulse for one of the mount axes 0349 bool sendSinglePulse(GuideDirection dir, int msecs, CaptureAfterPulses followWithCapture); 0350 0351 /** 0352 * @brief setDECSwap Change ST4 declination pulse direction. +DEC pulses increase DEC if swap is OFF. When on +DEC pulses result in decreasing DEC. 0353 * @param enable True to enable DEC swap. Off to disable it. 0354 */ 0355 void setDECSwap(bool enable); 0356 0357 0358 /** 0359 * @brief updateSetting Update per-train and global setting 0360 * @param key Name of setting 0361 * @param value Value 0362 * @note per-train and global settings are updated. Changes are saved to database 0363 * and to disk immediately. 0364 */ 0365 void updateSetting(const QString &key, const QVariant &value); 0366 0367 //plot slots 0368 void handleVerticalPlotSizeChange(); 0369 void handleHorizontalPlotSizeChange(); 0370 void clearGuideGraphs(); 0371 void clearCalibrationGraphs(); 0372 void slotAutoScaleGraphs(); 0373 void buildTarget(); 0374 void guideHistory(); 0375 void setLatestGuidePoint(bool isChecked); 0376 0377 void updateDirectionsFromPHD2(const QString &mode); 0378 0379 void guideAfterMeridianFlip(); 0380 0381 // Trains 0382 QString opticalTrain() const 0383 { 0384 return opticalTrainCombo->currentText(); 0385 } 0386 void setOpticalTrain(const QString &value) 0387 { 0388 opticalTrainCombo->setCurrentText(value); 0389 } 0390 0391 protected slots: 0392 void updateCCDBin(int index); 0393 0394 /** 0395 * @brief processCCDNumber Process number properties arriving from CCD. Currently, binning changes are processed. 0396 * @param nvp pointer to number property. 0397 */ 0398 void updateProperty(INDI::Property prop); 0399 0400 /** 0401 * @brief setTrackingStar Gets called when the user select a star in the guide frame 0402 * @param x X coordinate of star 0403 * @param y Y coordinate of star 0404 */ 0405 void setTrackingStar(int x, int y); 0406 0407 void saveDefaultGuideExposure(); 0408 0409 void updateTrackingBoxSize(int currentIndex); 0410 0411 //void onXscaleChanged( int i ); 0412 //void onYscaleChanged( int i ); 0413 void onThresholdChanged(int i); 0414 void onEnableDirRA(); 0415 void onEnableDirDEC(); 0416 0417 void setAxisDelta(double ra, double de); 0418 void setAxisSigma(double ra, double de); 0419 void setAxisPulse(double ra, double de); 0420 void setSNR(double snr); 0421 void calibrationUpdate(GuideInterface::CalibrationUpdateType type, const QString &message = QString(""), double dx = 0, 0422 double dy = 0); 0423 0424 void guideInfo(const QString &info); 0425 0426 void processGuideOptions(); 0427 void configSEPMultistarOptions(); 0428 0429 void onControlDirectionChanged(); 0430 0431 void showFITSViewer(); 0432 0433 void processCaptureTimeout(); 0434 0435 void nonGuidedDither(); 0436 0437 signals: 0438 void newLog(const QString &text); 0439 void newStatus(Ekos::GuideState status); 0440 0441 void newImage(const QSharedPointer<FITSView> &view); 0442 void newStarPixmap(QPixmap &); 0443 0444 void trainChanged(); 0445 0446 // Immediate deviations in arcsecs 0447 void newAxisDelta(double ra, double de); 0448 // Sigma deviations in arcsecs RMS 0449 void newAxisSigma(double ra, double de); 0450 0451 void guideStats(double raError, double decError, int raPulse, int decPulse, 0452 double snr, double skyBg, int numStars); 0453 0454 void guideChipUpdated(ISD::CameraChip *); 0455 void settingsUpdated(const QVariantMap &settings); 0456 void driverTimedout(const QString &deviceName); 0457 0458 private: 0459 0460 void resizeEvent(QResizeEvent *event) override; 0461 0462 /** 0463 * @brief updateGuideParams Update the guider and frame parameters due to any changes in the mount and/or ccd frame 0464 */ 0465 void updateGuideParams(); 0466 0467 /** 0468 * @brief check if the guiding chip of the camera should be used (if present) 0469 */ 0470 void checkUseGuideHead(); 0471 0472 /** 0473 * @brief syncTrackingBoxPosition Sync the tracking box to the current selected star center 0474 */ 0475 void syncTrackingBoxPosition(); 0476 0477 /** 0478 * @brief setBusy Indicate busy status within the module visually 0479 * @param enable True if module is busy, false otherwise 0480 */ 0481 void setBusy(bool enable); 0482 0483 /** 0484 * @brief setBLOBEnabled Enable or disable BLOB reception from current CCD if using external guider 0485 * @param enable True to enable BLOB reception, false to disable BLOB reception 0486 * @param name CCD to enable to disable. If empty (default), then action is applied to all CCDs. 0487 */ 0488 void setExternalGuiderBLOBEnabled(bool enable); 0489 0490 /** 0491 * @brief prepareCapture Set common settings for capture for guide module 0492 * @param targetChip target Chip 0493 */ 0494 void prepareCapture(ISD::CameraChip *targetChip); 0495 0496 0497 void handleManualDither(); 0498 0499 //////////////////////////////////////////////////////////////////// 0500 /// Settings 0501 //////////////////////////////////////////////////////////////////// 0502 0503 /** 0504 * @brief Connect GUI elements to sync settings once updated. 0505 */ 0506 void connectSettings(); 0507 /** 0508 * @brief Stop updating settings when GUI elements are updated. 0509 */ 0510 void disconnectSettings(); 0511 /** 0512 * @brief loadSettings Load setting from Options and set them accordingly. 0513 */ 0514 void loadGlobalSettings(); 0515 0516 /** 0517 * @brief syncSettings When checkboxes, comboboxes, or spin boxes are updated, save their values in the 0518 * global and per-train settings. 0519 */ 0520 void syncSettings(); 0521 0522 /** 0523 * @brief syncControl Sync setting to widget. The value depends on the widget type. 0524 * @param settings Map of all settings 0525 * @param key name of widget to sync 0526 * @param widget pointer of widget to set 0527 * @return True if sync successful, false otherwise 0528 */ 0529 bool syncControl(const QVariantMap &settings, const QString &key, QWidget * widget); 0530 0531 // Operation stack 0532 void buildOperationStack(GuideState operation); 0533 bool executeOperationStack(); 0534 bool executeOneOperation(GuideState operation); 0535 0536 // Init Functions 0537 void initPlots(); 0538 void initDriftGraph(); 0539 void initCalibrationPlot(); 0540 void initView(); 0541 void initConnections(); 0542 0543 bool captureOneFrame(); 0544 0545 void setupOpticalTrainManager(); 0546 void refreshOpticalTrain(); 0547 0548 // Driver 0549 void reconnectDriver(const QString &camera, QVariantMap settings); 0550 0551 // Operation Stack 0552 QStack<GuideState> operationStack; 0553 0554 // Devices 0555 ISD::Camera *m_Camera { nullptr }; 0556 ISD::Mount *m_Mount { nullptr }; 0557 ISD::Guider *m_Guider { nullptr }; 0558 ISD::AdaptiveOptics *m_AO { nullptr }; 0559 0560 // Guider process 0561 GuideInterface *m_GuiderInstance { nullptr }; 0562 0563 //This is for the configure PHD2 camera method. 0564 QString m_LastPHD2CameraName, m_LastPHD2MountName; 0565 GuiderType guiderType { GUIDE_INTERNAL }; 0566 0567 // Star 0568 QVector3D starCenter; 0569 0570 // Guide Params 0571 int guideBinIndex { 0 }; // Selected or saved binning for guiding 0572 double ccdPixelSizeX { -1 }; 0573 double ccdPixelSizeY { -1 }; 0574 0575 // Scope info 0576 double m_Aperture { -1 }; 0577 double m_FocalLength { -1 }; 0578 double m_FocalRatio { -1 }; 0579 double m_Reducer {-1}; 0580 0581 double guideDeviationRA { 0 }; 0582 double guideDeviationDEC { 0 }; 0583 double pixScaleX { -1 }; 0584 double pixScaleY { -1 }; 0585 0586 // State 0587 GuideState m_State { GUIDE_IDLE }; 0588 GuideStateWidget *guideStateWidget { nullptr }; 0589 0590 // Guide timer 0591 QElapsedTimer guideTimer; 0592 0593 // Capture timeout timer 0594 QTimer captureTimeout; 0595 uint8_t m_CaptureTimeoutCounter { 0 }; 0596 uint8_t m_DeviceRestartCounter { 0 }; 0597 0598 // Pulse Timer 0599 QTimer m_PulseTimer; 0600 0601 // Log 0602 QStringList m_LogText; 0603 0604 // Misc 0605 bool useGuideHead { false }; 0606 0607 // Progress Activity Indicator 0608 QProgressIndicator *pi { nullptr }; 0609 0610 // Options 0611 OpsCalibration *opsCalibration { nullptr }; 0612 OpsGuide *opsGuide { nullptr }; 0613 OpsDither *opsDither { nullptr }; 0614 OpsGPG *opsGPG { nullptr }; 0615 0616 // Guide Frame 0617 QSharedPointer<GuideView> m_GuideView; 0618 0619 // Calibration done already? 0620 bool calibrationComplete { false }; 0621 0622 // Was the modified frame subFramed? 0623 bool subFramed { false }; 0624 0625 // CCD Chip frame settings 0626 QMap<ISD::CameraChip *, QVariantMap> frameSettings; 0627 0628 // Profile Pixmap 0629 QPixmap profilePixmap; 0630 // drift plot 0631 QPixmap driftPlotPixmap; 0632 0633 // Flag to start auto calibration followed immediately by guiding 0634 //bool autoCalibrateGuide { false }; 0635 0636 // Pointers of guider processes 0637 QPointer<InternalGuider> internalGuider; 0638 QPointer<PHD2> phd2Guider; 0639 QPointer<LinGuider> linGuider; 0640 QSharedPointer<FITSViewer> fv; 0641 QSharedPointer<FITSData> m_ImageData; 0642 0643 // Dark Processor 0644 QPointer<DarkProcessor> m_DarkProcessor; 0645 0646 // Manual Pulse Dialog 0647 QPointer<ManualPulse> m_ManaulPulse; 0648 0649 double primaryFL = -1, primaryAperture = -1, guideFL = -1, guideAperture = -1; 0650 ISD::Mount::Status m_MountStatus { ISD::Mount::MOUNT_IDLE }; 0651 0652 bool graphOnLatestPt = true; 0653 0654 //This is for enforcing the PHD2 Star lock when Guide is pressed, 0655 //autostar is not selected, and the user has chosen a star. 0656 //This connection storage is so that the connection can be disconnected after enforcement 0657 QMetaObject::Connection guideConnect; 0658 0659 QCPItemText *calLabel { nullptr }; 0660 0661 // The scales of these zoom levels are defined in Guide::zoomX(). 0662 static constexpr int defaultXZoomLevel = 3; 0663 int driftGraphZoomLevel {defaultXZoomLevel}; 0664 0665 0666 // The accumulated non-guided dither offsets (in milliseconds) in the RA and DEC directions. 0667 int nonGuidedDitherRaOffsetMsec = 0, nonGuidedDitherDecOffsetMsec = 0; 0668 0669 // Random generator for non guided dithering 0670 std::mt19937 nonGuidedPulseGenerator; 0671 0672 // Flag to check if random generator for non guided dithering is initialized. 0673 bool isNonGuidedDitherInitialized = false; 0674 0675 // Reset non guided dithering properties and initialize the random generator seed if not already done. 0676 // Should be called in Guide::Guide() for initial seed initialization, and then in setCaptureStatus to reset accumulated drift 0677 // every time a capture task is completed or aborted. 0678 void resetNonGuidedDither(); 0679 0680 QVariantMap m_Settings; 0681 QVariantMap m_GlobalSettings; 0682 }; 0683 }