1 /* 2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #pragma once 8 9 #include "ui_guide.h" 10 #include "guideinterface.h" 11 #include "guidestatewidget.h" 12 #include "ekos/ekos.h" 13 #include "indi/indiccd.h" 14 #include "indi/inditelescope.h" 15 #include "ekos/auxiliary/darkprocessor.h" 16 17 #include <QTime> 18 #include <QTimer> 19 #include <QtDBus> 20 21 #include <random> 22 23 class QProgressIndicator; 24 class QTabWidget; 25 26 class FITSView; 27 class FITSViewer; 28 class ScrollGraph; 29 class GuideView; 30 31 namespace Ekos 32 { 33 class OpsCalibration; 34 class OpsGuide; 35 class OpsDither; 36 class OpsGPG; 37 class InternalGuider; 38 class PHD2; 39 class LinGuider; 40 41 /** 42 * @class Guide 43 * @short Performs calibration and autoguiding using an ST4 port or directly via the INDI driver. Can be used with the following external guiding applications: 44 * PHD2 45 * LinGuider 46 * 47 * @author Jasem Mutlaq 48 * @version 1.4 49 */ 50 class Guide : public QWidget, public Ui::Guide 51 { 52 Q_OBJECT 53 Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Guide") 54 Q_PROPERTY(Ekos::GuideState status READ status NOTIFY newStatus) 55 Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) 56 Q_PROPERTY(QString camera READ camera WRITE setCamera) 57 Q_PROPERTY(QString st4 READ st4 WRITE setST4) 58 Q_PROPERTY(double exposure READ exposure WRITE setExposure) 59 Q_PROPERTY(QList<double> axisDelta READ axisDelta NOTIFY newAxisDelta) 60 Q_PROPERTY(QList<double> axisSigma READ axisSigma NOTIFY newAxisSigma) 61 62 public: 63 Guide(); 64 ~Guide(); 65 66 enum GuiderStage 67 { 68 CALIBRATION_STAGE, 69 GUIDE_STAGE 70 }; 71 enum GuiderType 72 { 73 GUIDE_INTERNAL, 74 GUIDE_PHD2, 75 GUIDE_LINGUIDER 76 }; 77 78 /** @defgroup GuideDBusInterface Ekos DBus Interface - Capture Module 79 * Ekos::Guide interface provides advanced scripting capabilities to calibrate and guide a mount via a CCD camera. 80 */ 81 82 /*@{*/ 83 84 /** DBUS interface function. 85 * select the CCD device from the available CCD drivers. 86 * @param device The CCD device name 87 * @return Returns true if CCD device is found and set, false otherwise. 88 */ 89 Q_SCRIPTABLE bool setCamera(const QString &device); 90 Q_SCRIPTABLE QString camera(); 91 92 /** DBUS interface function. 93 * select the ST4 device from the available ST4 drivers. 94 * @param device The ST4 device name 95 * @return Returns true if ST4 device is found and set, false otherwise. 96 */ 97 Q_SCRIPTABLE bool setST4(const QString &device); 98 Q_SCRIPTABLE QString st4(); 99 100 /** DBUS interface function. 101 * @return Returns List of registered ST4 devices. 102 */ 103 Q_SCRIPTABLE QStringList getST4Devices(); 104 105 /** DBUS interface function. 106 * @brief connectGuider Establish connection to guider application. For internal guider, this always returns true. 107 * @return True if successfully connected, false otherwise. 108 */ 109 Q_SCRIPTABLE bool connectGuider(); 110 111 /** DBUS interface function. 112 * @brief disconnectGuider Disconnect from guider application. For internal guider, this always returns true. 113 * @return True if successfully disconnected, false otherwise. 114 */ 115 Q_SCRIPTABLE bool disconnectGuider(); 116 117 /** 118 * @brief getStatus Return guide module status 119 * @return state of guide module from Ekos::GuideState 120 */ status()121 Q_SCRIPTABLE Ekos::GuideState status() 122 { 123 return state; 124 } 125 126 /** DBUS interface function. 127 * Set CCD exposure value 128 * @param value exposure value in seconds. 129 */ 130 Q_SCRIPTABLE Q_NOREPLY void setExposure(double value); exposure()131 double exposure() 132 { 133 return exposureIN->value(); 134 } 135 136 /** DBUS interface function. 137 * Set image filter to apply to the image after capture. 138 * @param value Image filter (Auto Stretch, High Contrast, Equalize, High Pass) 139 */ 140 Q_SCRIPTABLE Q_NOREPLY void setImageFilter(const QString &value); 141 142 /** DBUS interface function. 143 * Set calibration Use Two Axis 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. 144 * @param enable if true, calibration will be performed in both RA and DEC axis. Otherwise, only RA axis will be calibrated. 145 */ 146 Q_SCRIPTABLE Q_NOREPLY void setCalibrationTwoAxis(bool enable); 147 148 /** DBUS interface function. 149 * Set auto star calibration 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. 150 * @param enable if true, Ekos will attempt to automatically select the best guide star and proceed with the calibration procedure. 151 */ 152 Q_SCRIPTABLE Q_NOREPLY void setCalibrationAutoStar(bool enable); 153 154 /** DBUS interface function. 155 * In case of automatic star selection, calculate the appropriate square size given the selected star width. The options must be set before starting the calibration operation. If no options are set, the options loaded from the user configuration are used. 156 * @param enable if true, Ekos will attempt to automatically select the best square size for calibration and guiding phases. 157 */ 158 Q_SCRIPTABLE Q_NOREPLY void setCalibrationAutoSquareSize(bool enable); 159 160 /** DBUS interface function. 161 * 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. 162 * @param enable if true, a dark frame will be captured to subtract from the light frame. 163 */ 164 Q_SCRIPTABLE Q_NOREPLY void setDarkFrameEnabled(bool enable); 165 166 /** DBUS interface function. 167 * Set calibration parameters. 168 * @param pulseDuration Pulse duration in milliseconds to use in the calibration steps. 169 */ 170 Q_SCRIPTABLE Q_NOREPLY void setCalibrationPulseDuration(int pulseDuration); 171 172 /** DBUS interface function. 173 * Set guiding box size. The options must be set before starting the guiding operation. If no options are set, the options loaded from the user configuration are used. 174 * @param index box size index (0 to 4) for box size from 8 to 128 pixels. The box size should be suitable for the size of the guide star selected. The boxSize is also used to select the subframe size around the guide star. Default is 16 pixels 175 */ 176 Q_SCRIPTABLE Q_NOREPLY void setGuideBoxSizeIndex(int index); 177 178 /** DBUS interface function. 179 * Set guiding algorithm. The options must be set before starting the guiding operation. If no options are set, the options loaded from the user configuration are used. 180 * @param index Select the algorithm used to calculate the centroid of the guide star (0 --> Smart, 1 --> Fast, 2 --> Auto, 3 --> No thresh). 181 */ 182 Q_SCRIPTABLE Q_NOREPLY void setGuideAlgorithmIndex(int index); 183 184 /** DBUS interface function. 185 * Enable or disables dithering. Set dither range 186 * @param enable if true, dithering is enabled and is performed after each exposure is complete. Otherwise, dithering is disabled. 187 * @param value dithering range in pixels. Ekos will move the guide star in a random direction for the specified dithering value in pixels. 188 */ 189 Q_SCRIPTABLE Q_NOREPLY void setDitherSettings(bool enable, double value); 190 191 /** @}*/ 192 193 void addCamera(ISD::GDInterface *newCCD); 194 void configurePHD2Camera(); 195 void setTelescope(ISD::GDInterface *newTelescope); 196 void addST4(ISD::ST4 *setST4); 197 void setAO(ISD::ST4 *newAO); 198 void removeDevice(ISD::GDInterface *device); 199 200 bool isDithering(); 201 202 void addGuideHead(ISD::GDInterface *newCCD); 203 void syncTelescopeInfo(); 204 void syncCCDInfo(); 205 206 /** 207 * @brief clearLog As the name suggests 208 */ 209 void clearLog(); logText()210 QStringList logText() 211 { 212 return m_LogText; 213 } 214 215 /** 216 * @return Return current log text of guide module 217 */ getLogText()218 QString getLogText() 219 { 220 return m_LogText.join("\n"); 221 } 222 223 /** 224 * @brief getStarPosition Return star center as selected by the user or auto-detected by KStars 225 * @return QVector3D of starCenter. The 3rd parameter is used to store current bin settings and in unrelated to the star position. 226 */ getStarPosition()227 QVector3D getStarPosition() 228 { 229 return starCenter; 230 } 231 232 // Tracking Box getTrackingBoxSize()233 int getTrackingBoxSize() 234 { 235 return boxSizeCombo->currentText().toInt(); 236 } 237 getGuider()238 GuideInterface *getGuider() 239 { 240 return guider; 241 } 242 243 QJsonObject getSettings() const; 244 void setSettings(const QJsonObject &settings); 245 246 public slots: 247 248 /** DBUS interface function. 249 * Start the autoguiding operation. 250 * @return Returns true if guiding started successfully, false otherwise. 251 */ 252 Q_SCRIPTABLE bool guide(); 253 254 /** DBUS interface function. 255 * Stop any active calibration, guiding, or dithering operation 256 * @return Returns true if operation is stopped successfully, false otherwise. 257 */ 258 Q_SCRIPTABLE bool abort(); 259 260 /** DBUS interface function. 261 * Start the calibration operation. Note that this will not start guiding automatically. 262 * @return Returns true if calibration started successfully, false otherwise. 263 */ 264 Q_SCRIPTABLE bool calibrate(); 265 266 /** DBUS interface function. 267 * Clear calibration data. Next time any guide operation is performed, a calibration is first started. 268 */ 269 Q_SCRIPTABLE Q_NOREPLY void clearCalibration(); 270 271 /** DBUS interface function. 272 * @brief dither Starts dithering process in a random direction restricted by the number of pixels specified in dither options 273 * @return True if dither started successfully, false otherwise. 274 */ 275 Q_SCRIPTABLE bool dither(); 276 277 /** DBUS interface function. 278 * @brief suspend Suspend autoguiding 279 * @return True if successful, false otherwise. 280 */ 281 Q_SCRIPTABLE bool suspend(); 282 283 /** DBUS interface function. 284 * @brief resume Resume autoguiding 285 * @return True if successful, false otherwise. 286 */ 287 Q_SCRIPTABLE bool resume(); 288 289 /** DBUS interface function. 290 * Capture a guide frame 291 * @return Returns true if capture command is sent successfully to INDI server. 292 */ 293 Q_SCRIPTABLE bool capture(); 294 295 /** DBUS interface function. 296 * Loop frames specified by the exposure control continuously until stopped. 297 */ 298 Q_SCRIPTABLE Q_NOREPLY void loop(); 299 300 /** DBUS interface function. 301 * 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. 302 * @param enable if true, it will select a subframe around the guide star depending on the boxSize size. 303 */ 304 Q_SCRIPTABLE Q_NOREPLY void setSubFrameEnabled(bool enable); 305 306 /** DBUS interface function. 307 * Selects which guiding process to utilize for calibration & guiding. 308 * @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. 309 * @return True if guiding is switched to the new requested type. False otherwise. 310 */ 311 Q_SCRIPTABLE bool setGuiderType(int type); 312 313 /** DBUS interface function. 314 * @brief axisDelta returns the last immediate axis delta deviation in arcseconds. This is the deviation of locked star position when guiding started. 315 * @return List of doubles. First member is RA deviation. Second member is DE deviation. 316 */ 317 Q_SCRIPTABLE QList<double> axisDelta(); 318 319 /** DBUS interface function. 320 * @brief axisSigma return axis sigma deviation in arcseconds RMS. This is the RMS deviation of locked star position when guiding started. 321 * @return List of doubles. First member is RA deviation. Second member is DE deviation. 322 */ 323 Q_SCRIPTABLE QList<double> axisSigma(); 324 325 /** 326 * @brief checkCCD Check all CCD parameters and ensure all variables are updated to reflect the selected CCD 327 * @param ccdNum CCD index number in the CCD selection combo box 328 */ 329 void checkCCD(int ccdNum = -1); 330 331 /** 332 * @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 333 * @param targetChip Chip for which the exposure is undergoing 334 * @param exposure numbers of seconds left in the exposure 335 * @param expState State of the exposure property 336 */ 337 void checkExposureValue(ISD::CCDChip *targetChip, double exposure, IPState expState); 338 339 /** 340 * @brief newFITS is called by the INDI framework whenever there is a new BLOB arriving 341 */ 342 void processData(const QSharedPointer<FITSData> &data); 343 344 /** 345 * @brief setST4 Sets a new ST4 device from the combobox index 346 * @param index Index of selected ST4 in the combobox 347 */ 348 void setST4(int index); 349 350 /** 351 * @brief Set telescope and guide scope info. All measurements is in millimeters. 352 * @param primaryFocalLength Primary Telescope Focal Length. Set to 0 to skip setting this value. 353 * @param primaryAperture Primary Telescope Aperture. Set to 0 to skip setting this value. 354 * @param guideFocalLength Guide Telescope Focal Length. Set to 0 to skip setting this value. 355 * @param guideAperture Guide Telescope Aperture. Set to 0 to skip setting this value. 356 */ 357 void setTelescopeInfo(double primaryFocalLength, double primaryAperture, double guideFocalLength, double guideAperture); 358 359 // This Function will allow PHD2 to update the exposure values to the recommended ones. 360 QString setRecommendedExposureValues(QList<double> values); 361 362 // Append Log entry 363 void appendLogText(const QString &); 364 365 // Update Guide module status 366 void setStatus(Ekos::GuideState newState); 367 368 // Update Capture Module status 369 void setCaptureStatus(Ekos::CaptureState newState); 370 // Update Mount module status 371 void setMountStatus(ISD::Telescope::Status newState); 372 void setMountCoords(const SkyPoint &position, ISD::Telescope::PierSide pierSide, const dms &ha); 373 374 // Update Pier Side 375 void setPierSide(ISD::Telescope::PierSide newSide); 376 377 // Star Position 378 void setStarPosition(const QVector3D &newCenter, bool updateNow); 379 380 // Capture 381 void setCaptureComplete(); 382 383 // Send pulse to ST4 driver 384 bool sendPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs); 385 bool sendPulse(GuideDirection dir, int msecs); 386 387 /** 388 * @brief setDECSwap Change ST4 declination pulse direction. +DEC pulses increase DEC if swap is OFF. When on +DEC pulses result in decreasing DEC. 389 * @param enable True to enable DEC swap. Off to disable it. 390 */ 391 void setDECSwap(bool enable); 392 393 //plot slots 394 void handleVerticalPlotSizeChange(); 395 void handleHorizontalPlotSizeChange(); 396 void clearGuideGraphs(); 397 void clearCalibrationGraphs(); 398 void slotAutoScaleGraphs(); 399 void buildTarget(); 400 void guideHistory(); 401 void setLatestGuidePoint(bool isChecked); 402 403 void updateDirectionsFromPHD2(const QString &mode); 404 405 void guideAfterMeridianFlip(); 406 407 protected slots: 408 void updateTelescopeType(int index); 409 void updateCCDBin(int index); 410 411 /** 412 * @brief processCCDNumber Process number properties arriving from CCD. Currently, binning changes are processed. 413 * @param nvp pointer to number property. 414 */ 415 void processCCDNumber(INumberVectorProperty *nvp); 416 417 /** 418 * @brief setTrackingStar Gets called when the user select a star in the guide frame 419 * @param x X coordinate of star 420 * @param y Y coordinate of star 421 */ 422 void setTrackingStar(int x, int y); 423 424 void saveDefaultGuideExposure(); 425 426 void updateTrackingBoxSize(int currentIndex); 427 428 //void onXscaleChanged( int i ); 429 //void onYscaleChanged( int i ); 430 void onThresholdChanged(int i); 431 void onEnableDirRA(bool enable); 432 void onEnableDirDEC(bool enable); 433 void syncSettings(); 434 435 void setAxisDelta(double ra, double de); 436 void setAxisSigma(double ra, double de); 437 void setAxisPulse(double ra, double de); 438 void setSNR(double snr); 439 void calibrationUpdate(GuideInterface::CalibrationUpdateType type, const QString &message = QString(""), double dx = 0, 440 double dy = 0); 441 442 void processGuideOptions(); 443 void configSEPMultistarOptions(); 444 445 void onControlDirectionChanged(bool enable); 446 void updatePHD2Directions(); 447 448 void showFITSViewer(); 449 450 void processCaptureTimeout(); 451 452 void nonGuidedDither(); 453 454 signals: 455 void newLog(const QString &text); 456 void newStatus(Ekos::GuideState status); 457 458 void newImage(FITSView *view); 459 void newStarPixmap(QPixmap &); 460 461 // Immediate deviations in arcsecs 462 void newAxisDelta(double ra, double de); 463 // Sigma deviations in arcsecs RMS 464 void newAxisSigma(double ra, double de); 465 466 void guideStats(double raError, double decError, int raPulse, int decPulse, 467 double snr, double skyBg, int numStars); 468 469 void guideChipUpdated(ISD::CCDChip *); 470 void settingsUpdated(const QJsonObject &settings); 471 void driverTimedout(const QString &deviceName); 472 473 private slots: 474 void setDefaultST4(const QString &driver); 475 void setDefaultCCD(const QString &ccd); 476 477 private: 478 479 void resizeEvent(QResizeEvent *event) override; 480 481 /** 482 * @brief updateGuideParams Update the guider and frame parameters due to any changes in the mount and/or ccd frame 483 */ 484 void updateGuideParams(); 485 486 /** 487 * @brief syncTrackingBoxPosition Sync the tracking box to the current selected star center 488 */ 489 void syncTrackingBoxPosition(); 490 491 /** 492 * @brief loadSettings Loads and applies all settings from KStars options 493 */ 494 void loadSettings(); 495 496 /** 497 * @brief saveSettings Saves all current settings into KStars options 498 */ 499 void saveSettings(); 500 501 /** 502 * @brief setBusy Indicate busy status within the module visually 503 * @param enable True if module is busy, false otherwise 504 */ 505 void setBusy(bool enable); 506 507 /** 508 * @brief setBLOBEnabled Enable or disable BLOB reception from current CCD if using external guider 509 * @param enable True to enable BLOB reception, false to disable BLOB reception 510 * @param name CCD to enable to disable. If empty (default), then action is applied to all CCDs. 511 */ 512 void setExternalGuiderBLOBEnabled(bool enable); 513 514 /** 515 * @brief prepareCapture Set common settings for capture for guide module 516 * @param targetChip target Chip 517 */ 518 void prepareCapture(ISD::CCDChip *targetChip); 519 520 521 void handleManualDither(); 522 523 // Operation stack 524 void buildOperationStack(GuideState operation); 525 bool executeOperationStack(); 526 bool executeOneOperation(GuideState operation); 527 528 // Init Functions 529 void initPlots(); 530 void initDriftGraph(); 531 void initCalibrationPlot(); 532 void initView(); 533 void initConnections(); 534 535 bool captureOneFrame(); 536 537 // Driver 538 void reconnectDriver(const QString &camera, const QString &via); 539 540 // Operation Stack 541 QStack<GuideState> operationStack; 542 543 // Devices 544 ISD::CCD *currentCCD { nullptr }; 545 QString lastPHD2CameraName; //This is for the configure PHD2 camera method. 546 ISD::Telescope *currentTelescope { nullptr }; 547 ISD::ST4 *ST4Driver { nullptr }; 548 ISD::ST4 *GuideDriver { nullptr }; 549 550 // Device Containers 551 QList<ISD::ST4 *> ST4List; 552 QList<ISD::CCD *> CCDs; 553 554 // Guider process 555 GuideInterface *guider { nullptr }; 556 GuiderType guiderType { GUIDE_INTERNAL }; 557 558 // Star 559 QVector3D starCenter; 560 561 // Guide Params 562 int guideBinIndex { 0 }; // Selected or saved binning for guiding 563 int guideFilterIndex { 0 }; // Selected or saved filter for post-treatment 564 double ccdPixelSizeX { -1 }; 565 double ccdPixelSizeY { -1 }; 566 double aperture { -1 }; 567 double focal_length { -1 }; 568 double guideDeviationRA { 0 }; 569 double guideDeviationDEC { 0 }; 570 double pixScaleX { -1 }; 571 double pixScaleY { -1 }; 572 573 // State 574 GuideState state { GUIDE_IDLE }; 575 GuideStateWidget *guideStateWidget { nullptr }; 576 577 // Guide timer 578 QTime guideTimer; 579 580 // Capture timeout timer 581 QTimer captureTimeout; 582 uint8_t m_CaptureTimeoutCounter { 0 }; 583 uint8_t m_DeviceRestartCounter { 0 }; 584 585 // Pulse Timer 586 QTimer pulseTimer; 587 588 // Log 589 QStringList m_LogText; 590 591 // Misc 592 bool useGuideHead { false }; 593 594 // Progress Activity Indicator 595 QProgressIndicator *pi { nullptr }; 596 597 // Options 598 OpsCalibration *opsCalibration { nullptr }; 599 OpsGuide *opsGuide { nullptr }; 600 OpsDither *opsDither { nullptr }; 601 OpsGPG *opsGPG { nullptr }; 602 603 // Guide Frame 604 GuideView *guideView { nullptr }; 605 606 // Calibration done already? 607 bool calibrationComplete { false }; 608 609 // Was the modified frame subFramed? 610 bool subFramed { false }; 611 612 // CCD Chip frame settings 613 QMap<ISD::CCDChip *, QVariantMap> frameSettings; 614 615 // Profile Pixmap 616 QPixmap profilePixmap; 617 // drift plot 618 QPixmap driftPlotPixmap; 619 620 // Flag to start auto calibration followed immediately by guiding 621 //bool autoCalibrateGuide { false }; 622 623 // Pointers of guider processes 624 QPointer<InternalGuider> internalGuider; 625 QPointer<PHD2> phd2Guider; 626 QPointer<LinGuider> linGuider; 627 QPointer<FITSViewer> fv; 628 QSharedPointer<FITSData> m_ImageData; 629 630 // Dark Processor 631 QPointer<DarkProcessor> m_DarkProcessor; 632 633 double primaryFL = -1, primaryAperture = -1, guideFL = -1, guideAperture = -1; 634 ISD::Telescope::Status m_MountStatus { ISD::Telescope::MOUNT_IDLE }; 635 636 bool graphOnLatestPt = true; 637 638 //This is for enforcing the PHD2 Star lock when Guide is pressed, 639 //autostar is not selected, and the user has chosen a star. 640 //This connection storage is so that the connection can be disconnected after enforcement 641 QMetaObject::Connection guideConnect; 642 643 QCPItemText *calLabel { nullptr }; 644 645 // The scales of these zoom levels are defined in Guide::zoomX(). 646 static constexpr int defaultXZoomLevel = 3; 647 int driftGraphZoomLevel {defaultXZoomLevel}; 648 649 650 // The accumulated non-guided dither offsets (in milliseconds) in the RA and DEC directions. 651 int nonGuidedDitherRaOffsetMsec = 0, nonGuidedDitherDecOffsetMsec = 0; 652 653 // Random generator for non guided dithering 654 std::mt19937 nonGuidedPulseGenerator; 655 656 // Flag to check if random generator for non guided dithering is initialized. 657 bool isNonGuidedDitherInitialized = false; 658 659 // Reset non guided dithering properties and initialize the random generator seed if not already done. 660 // Should be called in Guide::Guide() for initial seed initialization, and then in setCaptureStatus to reset accumulated drift 661 // every time a capture task is completed or aborted. 662 void resetNonGuidedDither(); 663 }; 664 } 665