1 /* 2 SPDX-FileCopyrightText: 2013 Jasem Mutlaq <mutlaqja@ikarustech.com> 3 SPDX-FileCopyrightText: 2013-2021 Jasem Mutlaq <mutlaqja@ikarustech.com> 4 SPDX-FileCopyrightText: 2018-2020 Robert Lancaster <rlancaste@gmail.com> 5 SPDX-FileCopyrightText: 2019-2021 Hy Murveit <hy@murveit.com> 6 7 SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #pragma once 11 12 #include "ui_align.h" 13 #include "ekos/ekos.h" 14 #include "indi/indiccd.h" 15 #include "indi/indistd.h" 16 #include "indi/inditelescope.h" 17 #include "indi/indidome.h" 18 #include "ksuserdb.h" 19 #include "ekos/auxiliary/filtermanager.h" 20 #include "ekos/auxiliary/darkprocessor.h" 21 22 #include <QTime> 23 #include <QTimer> 24 #include <QElapsedTimer> 25 #include <KConfigDialog> 26 27 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) 28 #include <QtDBus/qtdbusglobal.h> 29 #else 30 #include <QtDBus/qdbusmacros.h> 31 #endif 32 33 #include <stellarsolver.h> 34 #include <memory> 35 36 class QProgressIndicator; 37 38 class AlignView; 39 class FOV; 40 class StarObject; 41 class ProfileInfo; 42 43 namespace Ekos 44 { 45 class AstrometryParser; 46 class RemoteAstrometryParser; 47 class OpsAstrometry; 48 class OpsAlign; 49 class StellarSolverProfileEditor; 50 class OpsPrograms; 51 class OpsASTAP; 52 class OpsAstrometryIndexFiles; 53 class MountModel; 54 class PolarAlignmentAssistant; 55 class ManualRotator; 56 57 /** 58 *@class Align 59 *@short Align class handles plate-solving and polar alignment measurement and correction using astrometry.net 60 * The align class employs StellarSolver library for local solvers and supports remote INDI-based solver. 61 * StellarSolver supports internal and external solvers (Astrometry.net, ASTAP, Online Astrometry). 62 * If an image is solved successfully, the image central J2000 RA & DE coordinates along with pixel scale, rotation, and partiy are 63 * reported back. 64 * Index files management is supported with ability to download astrometry.net files. The user may select and edit different solver 65 * profiles that provide settings to control both extraction and solving profiles in detail. Manual and automatic field rotation 66 * is supported in order to align the solved images to a particular orientation in the sky. The manual rotation assistant is an interactive 67 * tool that helps the user to arrive at the desired framing. 68 * Align module provide Polar Align Helper tool which enables easy-to-follow polar alignment procedure given wide FOVs (> 1.5 degrees) 69 * Legacy polar aligment is deprecated. 70 *@author Jasem Mutlaq 71 *@version 1.5 72 */ 73 class Align : public QWidget, public Ui::Align 74 { 75 Q_OBJECT 76 Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Align") 77 Q_PROPERTY(Ekos::AlignState status READ status NOTIFY newStatus) 78 Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) 79 Q_PROPERTY(QString camera READ camera WRITE setCamera) 80 Q_PROPERTY(QString filterWheel READ filterWheel WRITE setFilterWheel) 81 Q_PROPERTY(QString filter READ filter WRITE setFilter) 82 Q_PROPERTY(double exposure READ exposure WRITE setExposure) 83 Q_PROPERTY(QList<double> fov READ fov) 84 Q_PROPERTY(QList<double> cameraInfo READ cameraInfo) 85 Q_PROPERTY(QList<double> telescopeInfo READ telescopeInfo) 86 //Q_PROPERTY(QString solverArguments READ solverArguments WRITE setSolverArguments) 87 88 public: 89 explicit Align(ProfileInfo *activeProfile); 90 virtual ~Align() override; 91 92 typedef enum { GOTO_SYNC, GOTO_SLEW, GOTO_NOTHING } GotoMode; 93 typedef enum { SOLVER_LOCAL, SOLVER_REMOTE } SolverMode; 94 typedef enum 95 { 96 ALIGN_RESULT_SUCCESS, 97 ALIGN_RESULT_WARNING, 98 ALIGN_RESULT_FAILED 99 } AlignResult; 100 101 typedef enum 102 { 103 BLIND_IDLE, 104 BLIND_ENGAGNED, 105 BLIND_USED 106 } BlindState; 107 108 /** @defgroup AlignDBusInterface Ekos DBus Interface - Align Module 109 * Ekos::Align interface provides advanced scripting capabilities to solve images using online or offline astrometry.net 110 */ 111 112 /*@{*/ 113 114 /** DBUS interface function. 115 * Select CCD 116 * @param device CCD device name 117 * @return Returns true if device if found and selected, false otherwise. 118 */ 119 Q_SCRIPTABLE bool setCamera(const QString &device); 120 Q_SCRIPTABLE QString camera(); 121 122 /** DBUS interface function. 123 * select the filter device from the available filter drivers. The filter device can be the same as the CCD driver if the filter functionality was embedded within the driver. 124 * @param device The filter device name 125 * @return Returns true if filter device is found and set, false otherwise. 126 */ 127 Q_SCRIPTABLE bool setFilterWheel(const QString &device); 128 Q_SCRIPTABLE QString filterWheel(); 129 130 /** DBUS interface function. 131 * select the filter from the available filters. 132 * @param filter The filter name 133 * @return Returns true if filter is found and set, false otherwise. 134 */ 135 Q_SCRIPTABLE bool setFilter(const QString &filter); 136 Q_SCRIPTABLE QString filter(); 137 138 /** DBUS interface function. 139 * Start the plate-solving process given the passed image file. 140 * @param filename Name of image file to solve. FITS and JPG/JPG/TIFF formats are accepted. 141 * @param isGenerated Set to true if filename is generated from a CCD capture operation. If the file is loaded from any storage or network media, pass false. 142 * @return Returns true if device if found and selected, false otherwise. 143 */ 144 Q_SCRIPTABLE Q_NOREPLY void startSolving(); 145 146 /** DBUS interface function. 147 * Select Solver Action after successfully solving an image. 148 * @param mode 0 for Sync, 1 for Slew To Target, 2 for Nothing (just display solution results) 149 */ 150 Q_SCRIPTABLE Q_NOREPLY void setSolverAction(int mode); 151 152 /** DBUS interface function. 153 * Returns the solver's solution results 154 * @return Returns array of doubles. First item is RA in degrees. Second item is DEC in degrees. 155 */ 156 Q_SCRIPTABLE QList<double> getSolutionResult(); 157 158 /** DBUS interface function. 159 * Returns the solver's current status 160 * @return Returns solver status (Ekos::AlignState) 161 */ status()162 Q_SCRIPTABLE Ekos::AlignState status() 163 { 164 return state; 165 } 166 167 /** DBUS interface function. 168 * @return Returns State of load slew procedure. Idle if not started. Busy if in progress. Ok if complete. Alert if procedure failed. 169 */ getLoadAndSlewStatus()170 Q_SCRIPTABLE int getLoadAndSlewStatus() 171 { 172 return m_SolveFromFile; 173 } 174 175 /** DBUS interface function. 176 * Sets the exposure of the selected CCD device. 177 * @param value Exposure value in seconds 178 */ 179 Q_SCRIPTABLE Q_NOREPLY void setExposure(double value); exposure()180 Q_SCRIPTABLE double exposure() 181 { 182 return exposureIN->value(); 183 } 184 185 /** DBUS interface function. 186 * Sets the telescope type (PRIMARY or GUIDE) that should be used for FOV calculations. This value is loaded form driver settings by default. 187 * @param index 0 for PRIMARY telescope, 1 for GUIDE telescope 188 */ 189 Q_SCRIPTABLE Q_NOREPLY void setFOVTelescopeType(int index); FOVTelescopeType()190 int FOVTelescopeType() 191 { 192 return FOVScopeCombo->currentIndex(); 193 } 194 195 /** DBUS interface function. 196 * Get currently active camera info in this order: 197 * width, height, pixel_size_x, pixel_size_y 198 */ 199 Q_SCRIPTABLE QList<double> cameraInfo(); 200 201 /** DBUS interface function. 202 * Get current active telescope info in this order: 203 * focal length, aperture 204 */ 205 Q_SCRIPTABLE QList<double> telescopeInfo(); 206 207 /** @}*/ 208 209 /** 210 * @brief Add CCD to the list of available CCD. 211 * @param newCCD pointer to CCD device. 212 */ 213 void addCCD(ISD::GDInterface *newCCD); 214 215 /** 216 * @brief addFilter Add filter to the list of available filters. 217 * @param newFilter pointer to filter device. 218 */ 219 void addFilter(ISD::GDInterface *newFilter); 220 221 /** 222 * @brief Set the current telescope 223 * @param newTelescope pointer to telescope device. 224 */ 225 void setTelescope(ISD::GDInterface *newTelescope); 226 227 /** 228 * @brief Set the current dome 229 * @param newDome pointer to telescope device. 230 */ 231 void setDome(ISD::GDInterface *newDome); 232 233 void setRotator(ISD::GDInterface *newRotator); 234 235 void removeDevice(ISD::GDInterface *device); 236 237 /** 238 * @brief Set telescope and guide scope info. All measurements is in millimeters. 239 * @param primaryFocalLength Primary Telescope Focal Length. Set to 0 to skip setting this value. 240 * @param primaryAperture Primary Telescope Aperture. Set to 0 to skip setting this value. 241 * @param guideFocalLength Guide Telescope Focal Length. Set to 0 to skip setting this value. 242 * @param guideAperture Guide Telescope Aperture. Set to 0 to skip setting this value. 243 */ 244 void setTelescopeInfo(double primaryFocalLength, double primaryAperture, double guideFocalLength, double guideAperture); 245 246 /** 247 * @brief setAstrometryDevice 248 * @param newAstrometry 249 */ 250 void setAstrometryDevice(ISD::GDInterface *newAstrometry); 251 252 /** 253 * @brief CCD information is updated, sync them. 254 */ 255 void syncCCDInfo(); 256 257 /** 258 * @brief Generate arguments we pass to the remote solver. 259 */ 260 QStringList generateRemoteArgs(const QSharedPointer<FITSData> &imageData); 261 262 /** 263 * @brief Does our parser exist in the system? 264 */ 265 bool isParserOK(); 266 267 // Log logText()268 QStringList logText() 269 { 270 return m_LogText; 271 } getLogText()272 QString getLogText() 273 { 274 return m_LogText.join("\n"); 275 } 276 void clearLog(); 277 278 /** 279 * @brief getFOVScale Returns calculated FOV values 280 * @param fov_w FOV width in arcmins 281 * @param fov_h FOV height in arcmins 282 * @param fov_scale FOV scale in arcsec per pixel 283 */ 284 void getFOVScale(double &fov_w, double &fov_h, double &fov_scale); 285 QList<double> fov(); 286 287 /** 288 * @brief getCalculatedFOVScale Get calculated FOV scales from the current CCD+Telescope combination. 289 * @param fov_w return calculated fov width in arcminutes 290 * @param fov_h return calculated fov height in arcminutes 291 * @param fov_scale return calculated fov pixcale in arcsecs per pixel. 292 * @note This is NOT the same as effective FOV which is the measured FOV from astrometry. It is the 293 * theoretical FOV from calculated values. 294 */ 295 void getCalculatedFOVScale(double &fov_w, double &fov_h, double &fov_scale); 296 297 void setFilterManager(const QSharedPointer<FilterManager> &manager); 298 299 /** 300 * @brief Sync the telescope to the solved alignment coordinate. 301 */ 302 void Sync(); 303 304 /** 305 * @brief Slew the telescope to the solved alignment coordinate. 306 */ 307 void Slew(); 308 309 /** 310 * @brief Sync the telescope to the solved alignment coordinate, and then slew to the target coordinate. 311 */ 312 void SlewToTarget(); 313 314 /** 315 * @brief getStellarSolverProfiles 316 * @return list of StellarSolver profile names 317 */ 318 QStringList getStellarSolverProfiles(); 319 currentGOTOMode()320 GotoMode currentGOTOMode() const 321 { 322 return m_CurrentGotoMode; 323 } 324 325 /** 326 * @brief generateOptions Generate astrometry.net option given the supplied map 327 * @param optionsMap List of key=value pairs for all astrometry.net options 328 * @return String List of valid astrometry.net options 329 */ 330 static QStringList generateRemoteOptions(const QVariantMap &optionsMap); 331 static void generateFOVBounds(double fov_h, QString &fov_low, QString &fov_high, double tolerance = 0.05); 332 333 // access to the mount model UI, required for testing mountModel()334 MountModel * mountModel() const 335 { 336 return m_MountModel; 337 } 338 polarAlignmentAssistant()339 PolarAlignmentAssistant *polarAlignmentAssistant() const 340 { 341 return m_PolarAlignmentAssistant; 342 } 343 wcsSynced()344 bool wcsSynced() const 345 { 346 return m_wcsSynced; 347 } 348 349 /** 350 * @brief Process updated device properties 351 * @param nvp pointer to updated property. 352 */ 353 void processNumber(INumberVectorProperty *nvp); 354 355 /** 356 * @brief Process updated device properties 357 * @param svp pointer to updated property. 358 */ 359 void processSwitch(ISwitchVectorProperty *svp); 360 361 /** 362 * @brief Check CCD and make sure information is updated and FOV is re-calculated. 363 * @param CCDNum By default, we check the already selected CCD in the dropdown menu. If CCDNum is specified, the check is made against this specific CCD in the dropdown menu. CCDNum is the index of the CCD in the dropdown menu. 364 */ 365 void checkCCD(int CCDNum = -1); 366 367 /** 368 * @brief Check Filter and make sure information is updated accordingly. 369 * @param filterNum By default, we check the already selected filter in the dropdown menu. If filterNum is specified, the check is made against this specific filter in the dropdown menu. 370 * filterNum is the index of the filter in the dropdown menu. 371 */ 372 void checkFilter(int filterNum = -1); 373 374 /** 375 * @brief checkCCDExposureProgress Track the progress of CCD exposure 376 * @param targetChip Target chip under exposure 377 * @param remaining how many seconds remaining 378 * @param state status of exposure 379 */ 380 void checkCCDExposureProgress(ISD::CCDChip *targetChip, double remaining, IPState state); 381 /** 382 * @brief Process new FITS received from CCD. 383 * @param bp pointer to blob property 384 */ 385 void processData(const QSharedPointer<FITSData> &data); 386 387 /** DBUS interface function. 388 * Loads an image (FITS, RAW, or JPG/PNG) and solve its coordinates, then it slews to the solved coordinates and an image is captured and solved to ensure 389 * the telescope is pointing to the same coordinates of the image. 390 * @param image buffer to image data. 391 * @param extension image extension (e.g. cr2, jpg, fits,..etc). 392 */ 393 bool loadAndSlew(const QByteArray &image, const QString &extension); 394 395 /** \addtogroup AlignDBusInterface 396 * @{ 397 */ 398 399 /** 400 * @brief Stop aligning 401 * @param mode stop mode (abort or suspend) 402 */ 403 void stop(Ekos::AlignState mode); 404 405 /** DBUS interface function. 406 * Aborts the solving operation, handle outside of the align module. 407 */ abort()408 Q_SCRIPTABLE Q_NOREPLY void abort() 409 { 410 stop(ALIGN_ABORTED); 411 } 412 413 /** 414 * @brief Suspend aligning, recovery handled by the align module itself. 415 */ suspend()416 void suspend() 417 { 418 stop(ALIGN_SUSPENDED); 419 } 420 421 /** DBUS interface function. 422 * Select the solver mode 423 * @param type Set solver type. 0 LOCAL, 1 REMOTE (requires remote astrometry driver to be activated) 424 */ 425 Q_SCRIPTABLE Q_NOREPLY void setSolverMode(int mode); 426 427 /** DBUS interface function. 428 * Capture and solve an image using the astrometry.net engine 429 * @return Returns true if the procedure started successful, false otherwise. 430 */ 431 Q_SCRIPTABLE bool captureAndSolve(); 432 433 /** DBUS interface function. 434 * Loads an image (FITS, RAW, or JPG/PNG) and solve its coordinates, then it slews to the solved coordinates and an image is captured and solved to ensure 435 * the telescope is pointing to the same coordinates of the image. 436 * @param fileURL URL to the image to solve 437 */ 438 Q_SCRIPTABLE bool loadAndSlew(QString fileURL = QString()); 439 440 /** DBUS interface function. 441 * Sets the target coordinates that the solver compares the solution coordinates to. 442 * By default, the target coordinates are those of the current mount when the capture and 443 * solve operation is started. In case of SYNC, only the error between the the solution and target 444 * coordinates is calculated. When Slew to Target is selected, the mount would be slewed afterwards to 445 * this target coordinate. 446 * @param ra0 J2000 Right Ascension in hours. 447 * @param de0 J2000 Declination in degrees. 448 */ 449 Q_SCRIPTABLE Q_NOREPLY void setTargetCoords(double ra0, double de0); 450 451 /** 452 * @brief getTargetCoords QList of target coordinates. 453 * @return First value is J2000 RA in hours. Second value is J2000 DE in degrees. 454 */ 455 Q_SCRIPTABLE QList<double> getTargetCoords(); 456 457 458 /** 459 * @brief Set the alignment target where the mount is expected to point at. 460 * @param targetObject object close to the target position 461 * @param targetCoord exact coordinates of the target position (could slightly differ to targetObject) 462 */ 463 void setTarget(const SkyObject &targetObject, const SkyPoint &targetCoord); 464 465 /** 466 * @brief Clear the target, make it invalid. 467 */ clearTarget()468 Q_SCRIPTABLE Q_NOREPLY void clearTarget() 469 { 470 m_targetCoordValid = false; 471 } 472 473 /** 474 * @brief Set the coordinates that the mount reports as its position 475 * @param position current mount position 476 */ setTelescopeCoordinates(const SkyPoint & position)477 void setTelescopeCoordinates(const SkyPoint &position) 478 { 479 telescopeCoord = position; 480 } 481 482 483 Q_SCRIPTABLE Q_NOREPLY void setTargetRotation(double rotation); 484 485 /** DBUS interface function. 486 * Sets the binning of the selected CCD device. 487 * @param binIndex Index of binning value. Default values range from 0 (binning 1x1) to 3 (binning 4x4) 488 */ 489 Q_SCRIPTABLE Q_NOREPLY void setBinningIndex(int binIndex); 490 491 /** @}*/ 492 493 /** 494 * @brief Solver finished successfully, process the data and execute the required actions depending on the mode. 495 * @param orientation Orientation of image in degrees (East of North) 496 * @param ra Center RA in solved image, degrees. 497 * @param dec Center DEC in solved image, degrees. 498 * @param pixscale Image scale is arcsec/pixel 499 * @param eastToTheRight When the image is rotated, so that North is up, East would be to the right. 500 */ 501 void solverFinished(double orientation, double ra, double dec, double pixscale, bool eastToTheRight); 502 503 void solverComplete(); 504 505 /** 506 * @brief If the target is valid (see m_targetCoordValid), simply return. If the target is not valid, 507 * use thecurrent mount coordinates as target coordinates. 508 */ 509 void updateTargetCoords(); 510 511 /** 512 * @brief Process solver failure. 513 */ 514 void solverFailed(); 515 516 /** 517 * @brief We received new telescope info, process them and update FOV. 518 */ 519 bool syncTelescopeInfo(); 520 521 void setFocusStatus(Ekos::FocusState state); 522 523 // Log 524 void appendLogText(const QString &); 525 526 // Capture 527 void setCaptureComplete(); 528 529 // Update Capture Module status 530 void setCaptureStatus(Ekos::CaptureState newState); 531 // Update Mount module status 532 void setMountStatus(ISD::Telescope::Status newState); 533 // void setMountCoords(const QString &ra, const QString &dec, const QString &az, 534 // const QString &alt, int pierSide, const QString &ha); 535 536 // Align Settings 537 QJsonObject getSettings() const; 538 void setSettings(const QJsonObject &settings); 539 540 void zoomAlignView(); 541 void setAlignZoom(double scale); 542 543 private slots: 544 545 void setDefaultCCD(QString ccd); 546 547 void saveSettleTime(); 548 549 // Solver timeout 550 void checkAlignmentTimeout(); 551 void setAlignTableResult(AlignResult result); 552 553 void updateTelescopeType(int index); 554 555 // External View 556 void showFITSViewer(); 557 void toggleAlignWidgetFullScreen(); 558 559 /** 560 * @brief prepareCapture Set common settings for capture for align module 561 * @param targetChip target Chip 562 */ 563 void prepareCapture(ISD::CCDChip *targetChip); 564 565 //Solutions Display slots 566 void buildTarget(); 567 void handlePointTooltip(QMouseEvent *event); 568 void handleVerticalPlotSizeChange(); 569 void handleHorizontalPlotSizeChange(); 570 void selectSolutionTableRow(int row, int column); 571 void slotClearAllSolutionPoints(); 572 void slotRemoveSolutionPoint(); 573 void slotAutoScaleGraph(); 574 575 void slotMountModel(); 576 577 // Settings 578 void syncSettings(); 579 580 protected slots: 581 /** 582 * @brief After a solver process is completed successfully, sync, slew to target, or do nothing as set by the user. 583 */ 584 void executeGOTO(); 585 586 /** 587 * @brief refreshAlignOptions is called when settings are updated in OpsAlign. 588 */ 589 void refreshAlignOptions(); 590 591 void processPAHStage(int stage); 592 593 signals: 594 void newLog(const QString &text); 595 void newStatus(Ekos::AlignState state); 596 void newSolution(const QVariantMap &solution); 597 598 // This is sent when we load an image in the view 599 void newImage(FITSView *view); 600 // This is sent when the pixmap is updated within the view 601 void newFrame(FITSView *view); 602 // Send new solver results 603 void newSolverResults(double orientation, double ra, double dec, double pixscale); 604 605 // Settings 606 void settingsUpdated(const QJsonObject &settings); 607 608 private: 609 /** 610 * @brief Retrieve the align status indicator 611 */ 612 QProgressIndicator *getProgressStatus(); 613 614 /** 615 * @brief Stop the progress animation in the solution table 616 */ 617 void stopProgressAnimation(); 618 619 void exportSolutionPoints(); 620 621 /** 622 * @brief Calculate Field of View of CCD+Telescope combination that we need to pass to astrometry.net solver. 623 */ 624 void calculateFOV(); 625 626 /** 627 * @brief calculateEffectiveFocalLength Calculate Focal Length purely form astrometric data. 628 */ 629 void calculateEffectiveFocalLength(double newFOVW); 630 631 /** 632 * @brief calculateAlignTargetDiff Find the difference between aligned vs. target coordinates and update 633 * the GUI accordingly. 634 */ 635 void calculateAlignTargetDiff(); 636 637 /** 638 * @brief Get formatted RA & DEC coordinates compatible with astrometry.net format. 639 * @param ra Right ascension 640 * @param dec Declination 641 * @param ra_str will contain the formatted RA string 642 * @param dec_str will contain the formatted DEC string 643 */ 644 void getFormattedCoords(double ra, double dec, QString &ra_str, QString &dec_str); 645 646 uint8_t getSolverDownsample(uint16_t binnedW); 647 648 /** 649 * @brief setWCSEnabled enables/disables World Coordinate System settings in the CCD driver. 650 * @param enable true to enable WCS, false to disable. 651 */ 652 void setWCSEnabled(bool enable); 653 654 void resizeEvent(QResizeEvent *event) override; 655 656 KPageWidgetItem *m_IndexFilesPage; 657 QString savedOptionsProfiles; 658 659 /** 660 * @brief React when a mount motion has been detected 661 */ 662 void handleMountMotion(); 663 664 /** 665 * @brief Continue aligning according to the current mount status 666 */ 667 void handleMountStatus(); 668 669 /** 670 * @brief initPolarAlignmentAssistant Initialize Polar Alignment Asssistant Tool 671 */ 672 void initPolarAlignmentAssistant(); 673 674 /** 675 * @brief initManualRotator Initialize Manual Rotator Tool 676 */ 677 void initManualRotator(); 678 679 /** 680 * @brief initDarkProcessor Initialize Dark Processor 681 */ 682 void initDarkProcessor(); 683 684 bool matchPAHStage(uint32_t stage); 685 686 687 // Effective FOV 688 689 /** 690 * @brief getEffectiveFOV Search database for effective FOV that matches the current profile and settings 691 * @return Variant Map containing effect FOV data or empty variant map if none found 692 */ 693 QVariantMap getEffectiveFOV(); 694 void saveNewEffectiveFOV(double newFOVW, double newFOVH); 695 QList<QVariantMap> effectiveFOVs; 696 void syncFOV(); 697 698 // We are using calculated FOV now until a more accurate effective FOV is found. 699 bool m_EffectiveFOVPending { false }; 700 /// Which chip should we invoke in the current CCD? 701 bool useGuideHead { false }; 702 /// Can the mount sync its coordinates to those set by Ekos? 703 bool canSync { false }; 704 // m_SolveFromFile is true we load an image and solve it, no capture is done. 705 bool m_SolveFromFile { false }; 706 // Target Position Angle of solver Load&Slew image to be used for rotator if necessary 707 double loadSlewTargetPA { std::numeric_limits<double>::quiet_NaN() }; 708 double currentRotatorPA { -1 }; 709 /// Solver iterations count 710 uint8_t solverIterations { 0 }; 711 /// Was solving with scale off used? 712 BlindState useBlindScale {BLIND_IDLE}; 713 /// Was solving with position off used? 714 BlindState useBlindPosition {BLIND_IDLE}; 715 716 // FOV 717 double ccd_hor_pixel { -1 }; 718 double ccd_ver_pixel { -1 }; 719 double focal_length { -1 }; 720 double aperture { -1 }; 721 double fov_x { 0 }; 722 double fov_y { 0 }; 723 double fov_pixscale { 0 }; 724 int ccd_width { 0 }; 725 int ccd_height { 0 }; 726 727 // Keep track of solver results 728 double sOrientation { INVALID_VALUE }; 729 double sRA { INVALID_VALUE }; 730 double sDEC { INVALID_VALUE }; 731 732 /// Solver alignment coordinates 733 SkyPoint alignCoord; 734 /// Target coordinates we need to slew to 735 SkyPoint m_targetCoord; 736 /// do we have valid target coordinates? 737 bool m_targetCoordValid = false; 738 /// Current telescope coordinates 739 SkyPoint telescopeCoord; 740 /// Coord from Load & Slew 741 SkyPoint loadSlewCoord; 742 /// Difference between solution and target coordinate 743 double m_TargetDiffTotal { 1e6 }; 744 double m_TargetDiffRA { 1e6 }; 745 double m_TargetDiffDE { 1e6 }; 746 747 /// Progress icon if the solver is running 748 std::unique_ptr<QProgressIndicator> pi; 749 750 /// Keep track of how long the solver is running 751 QElapsedTimer solverTimer; 752 753 // StellarSolver Profiles 754 std::unique_ptr<StellarSolver> m_StellarSolver; 755 QList<SSolver::Parameters> m_StellarSolverProfiles; 756 757 /// Have we slewed? 758 bool m_wasSlewStarted { false }; 759 // Above flag only stays false for 10s after slew start. 760 QElapsedTimer slewStartTimer; 761 bool didSlewStart(); 762 // Only wait this many milliseconds for slew to start. 763 // Otherwise assume it has begun. 764 static constexpr int MAX_WAIT_FOR_SLEW_START_MSEC = 10000; 765 766 // Online and Offline parsers 767 AstrometryParser* parser { nullptr }; 768 std::unique_ptr<RemoteAstrometryParser> remoteParser; 769 ISD::GDInterface *remoteParserDevice { nullptr }; 770 771 // Pointers to our devices 772 ISD::Telescope *currentTelescope { nullptr }; 773 ISD::Dome *currentDome { nullptr }; 774 ISD::CCD *currentCCD { nullptr }; 775 ISD::GDInterface *currentRotator { nullptr }; 776 QList<ISD::CCD *> CCDs; 777 778 /// Optional device filter 779 ISD::GDInterface *currentFilter { nullptr }; 780 /// They're generic GDInterface because they could be either ISD::CCD or ISD::Filter 781 QList<ISD::GDInterface *> Filters; 782 int currentFilterPosition { -1 }; 783 /// True if we need to change filter position and wait for result before continuing capture 784 bool filterPositionPending { false }; 785 786 /// Keep track of solver FOV to be plotted in the skymap after each successful solve operation 787 std::shared_ptr<FOV> solverFOV; 788 std::shared_ptr<FOV> sensorFOV; 789 790 /// WCS 791 bool m_wcsSynced { false }; 792 793 /// Log 794 QStringList m_LogText; 795 796 /// Issue counters 797 uint8_t m_CaptureTimeoutCounter { 0 }; 798 uint8_t m_CaptureErrorCounter { 0 }; 799 uint8_t m_SlewErrorCounter { 0 }; 800 801 QTimer m_CaptureTimer; 802 803 // State 804 AlignState state { ALIGN_IDLE }; 805 FocusState m_FocusState { FOCUS_IDLE }; 806 CaptureState m_CaptureState { CAPTURE_IDLE }; 807 808 // Track which upload mode the CCD is set to. If set to UPLOAD_LOCAL, then we need to switch it to UPLOAD_CLIENT in order to do focusing, and then switch it back to UPLOAD_LOCAL 809 ISD::CCD::UploadMode rememberUploadMode { ISD::CCD::UPLOAD_CLIENT }; 810 811 GotoMode m_CurrentGotoMode; 812 813 QString dirPath; 814 815 // Timer 816 QTimer m_AlignTimer; 817 818 // Align Frame 819 AlignView *alignView { nullptr }; 820 821 // FITS Viewer in case user want to display in it instead of internal view 822 QPointer<FITSViewer> fv; 823 824 QUrl alignURL; 825 QUrl alignURLPath; 826 827 // keep track of autoWSC 828 bool rememberAutoWCS { false }; 829 bool rememberSolverWCS { false }; 830 //bool rememberMeridianFlip { false }; 831 832 // Differential Slewing 833 bool differentialSlewingActivated { false }; 834 bool targetAccuracyNotMet { false }; 835 836 // Astrometry Options 837 OpsAstrometry *opsAstrometry { nullptr }; 838 OpsAlign *opsAlign { nullptr }; 839 OpsPrograms *opsPrograms { nullptr }; 840 OpsAstrometryIndexFiles *opsAstrometryIndexFiles { nullptr }; 841 OpsASTAP *opsASTAP { nullptr }; 842 StellarSolverProfileEditor *optionsProfileEditor { nullptr }; 843 844 // Drawing 845 QCPCurve *centralTarget { nullptr }; 846 QCPCurve *yellowTarget { nullptr }; 847 QCPCurve *redTarget { nullptr }; 848 QCPCurve *concentricRings { nullptr }; 849 850 // Telescope Settings 851 ISD::CCD::TelescopeType rememberTelescopeType = { ISD::CCD::TELESCOPE_UNKNOWN }; 852 double primaryFL = -1, primaryAperture = -1, guideFL = -1, guideAperture = -1; 853 double primaryEffectiveFL = -1, guideEffectiveFL = -1; 854 bool m_isRateSynced = false; 855 bool domeReady = true; 856 857 // CCD Exposure Looping 858 bool m_RememberCameraFastExposure = { false }; 859 860 // Controls 861 double GainSpinSpecialValue {INVALID_VALUE}; 862 double TargetCustomGainValue {-1}; 863 864 // Filter Manager 865 QSharedPointer<FilterManager> filterManager; 866 867 // Data 868 QSharedPointer<FITSData> m_ImageData; 869 870 // Active Profile 871 ProfileInfo *m_ActiveProfile { nullptr }; 872 873 // Threshold to notify settle time is 3 seconds 874 static constexpr uint16_t DELAY_THRESHOLD_NOTIFY { 3000 }; 875 876 // Mount Model 877 // N.B. We do not need to use "smart pointer" here as the object memroy 878 // is taken care of by the Qt framework. 879 MountModel *m_MountModel {nullptr}; 880 PolarAlignmentAssistant *m_PolarAlignmentAssistant {nullptr}; 881 ManualRotator *m_ManualRotator {nullptr}; 882 883 // Dark Processor 884 QPointer<DarkProcessor> m_DarkProcessor; 885 886 }; 887 } 888