1 /* 2 SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #ifndef MOUNT_H 8 #define MOUNT_H 9 10 #include <QQmlContext> 11 #include <QtDBus> 12 #include "ui_mount.h" 13 14 #include "indi/indistd.h" 15 #include "indi/indifocuser.h" 16 #include "indi/inditelescope.h" 17 18 class QQuickView; 19 class QQuickItem; 20 21 namespace Ekos 22 { 23 /** 24 *@class Mount 25 *@short Supports controlling INDI telescope devices including setting/retrieving mount properties, slewing, motion and speed controls, in addition to enforcing altitude limits and parking/unparking. 26 *@author Jasem Mutlaq 27 *@version 1.4 28 */ 29 30 class Mount : public QWidget, public Ui::Mount 31 { 32 Q_OBJECT 33 Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Mount") 34 Q_PROPERTY(ISD::Telescope::Status status READ status NOTIFY newStatus) 35 Q_PROPERTY(ISD::ParkStatus parkStatus READ parkStatus NOTIFY newParkStatus) 36 Q_PROPERTY(QStringList logText READ logText NOTIFY newLog) 37 Q_PROPERTY(QList<double> altitudeLimits READ altitudeLimits WRITE setAltitudeLimits) 38 Q_PROPERTY(bool altitudeLimitsEnabled READ altitudeLimitsEnabled WRITE setAltitudeLimitsEnabled) 39 Q_PROPERTY(double hourAngleLimit READ hourAngleLimit WRITE setHourAngleLimit) 40 Q_PROPERTY(bool hourAngleLimitEnabled READ hourAngleLimitEnabled WRITE setHourAngleLimitEnabled) 41 Q_PROPERTY(bool autoParkEnabled READ autoParkEnabled WRITE setAutoParkEnabled) 42 Q_PROPERTY(QList<double> equatorialCoords READ equatorialCoords) 43 Q_PROPERTY(QList<double> horizontalCoords READ horizontalCoords) 44 Q_PROPERTY(QList<double> telescopeInfo READ telescopeInfo WRITE setTelescopeInfo) 45 Q_PROPERTY(double hourAngle READ hourAngle) 46 Q_PROPERTY(int slewRate READ slewRate WRITE setSlewRate) 47 Q_PROPERTY(int slewStatus READ slewStatus) 48 Q_PROPERTY(bool canPark READ canPark) 49 Q_PROPERTY(ISD::Telescope::PierSide pierSide READ pierSide NOTIFY pierSideChanged) 50 51 public: 52 Mount(); 53 ~Mount(); 54 55 //typedef enum { PARKING_IDLE, PARKING_OK, UNPARKING_OK, PARKING_BUSY, UNPARKING_BUSY, PARKING_ERROR } ParkingStatus; 56 57 // This enum defines the meridian flip state machine, this is implemented in 58 typedef enum 59 { 60 FLIP_NONE, // this is the default state, comparing the hour angle with the next flip position 61 // it moves to FLIP_PLANNED when a flip is needed. 62 FLIP_PLANNED, // this signals to the Capture class that a flip is required, the Capture class will 63 // move to FLIP_ACCEPTED when it has completed everything that needs to be done. 64 FLIP_WAITING, // Capture seems to set this state to signal that the flip will have to wait 65 FLIP_ACCEPTED, // Capture signals to the mount that a flip slew can be started 66 FLIP_RUNNING, // this signals that a flip slew is in progress, when the slew stops the state 67 // is set to FLIP_COMPLETED 68 FLIP_COMPLETED, // this checks that the flip was completed successfully or not and after tidying up 69 // moves to FLIP_NONE to wait for the next flip requirement. 70 // Capture sees this and resumes. 71 FLIP_ERROR // errors in the flip process should end up here 72 } MeridianFlipStatus; 73 74 /** 75 * @brief setTelescope Sets the mount module telescope interface 76 * @param newTelescope pointer to telescope interface object 77 */ 78 void setTelescope(ISD::GDInterface *newTelescope); 79 80 void setGPS(ISD::GDInterface *newGPS); 81 82 void removeDevice(ISD::GDInterface *device); 83 84 // Log functions 85 void appendLogText(const QString &); 86 void clearLog(); logText()87 QStringList logText() 88 { 89 return m_LogText; 90 } getLogText()91 QString getLogText() const 92 { 93 return m_LogText.join("\n"); 94 } 95 status()96 ISD::Telescope::Status status() const 97 { 98 return m_Status; 99 } pierSide()100 ISD::Telescope::PierSide pierSide() const 101 { 102 if (currentTelescope) 103 return currentTelescope->pierSide(); 104 else 105 return ISD::Telescope::PIER_UNKNOWN; 106 } parkStatus()107 ISD::ParkStatus parkStatus() const 108 { 109 return m_ParkStatus; 110 } 111 meridianFlipStatus()112 MeridianFlipStatus meridianFlipStatus() const 113 { 114 return m_MFStatus; 115 } 116 117 /** @defgroup MountDBusInterface Ekos Mount DBus Interface 118 * Mount interface provides advanced scripting capabilities to control INDI mounts. 119 */ 120 121 /*@{*/ 122 123 /** DBUS interface function. 124 * Returns the mount altitude limits. 125 * @return Returns array of doubles. First item is minimum altitude in degrees. Second item is maximum altitude limit in degrees. 126 */ 127 Q_SCRIPTABLE QList<double> altitudeLimits(); 128 129 /** DBUS interface function. 130 * Sets the mount altitude limits, and whether they are enabled or disabled. 131 * @param limits is a list of double values. 2 values are expected: minAltitude & maxAltitude 132 */ 133 Q_SCRIPTABLE Q_NOREPLY void setAltitudeLimits(QList<double> limits); 134 135 /** DBUS interface function. 136 * Enable or disable mount altitude limits. 137 */ 138 Q_SCRIPTABLE void setAltitudeLimitsEnabled(bool enable); 139 140 /** DBUS interface function. 141 * Returns whether the mount limits are enabled or disabled. 142 * @return True if enabled, false otherwise. 143 */ 144 Q_SCRIPTABLE bool altitudeLimitsEnabled(); 145 146 /** DBUS interface function. 147 * Returns the mount hour angle limit. 148 * @return Returns hour angle limit in hours. 149 */ 150 Q_SCRIPTABLE double hourAngleLimit(); 151 152 /** DBUS interface function. 153 * Sets the mount altitude limits, and whether they are enabled or disabled. 154 * @param limits is a list of double values. 2 values are expected: minAltitude & maxAltitude 155 */ 156 Q_SCRIPTABLE Q_NOREPLY void setHourAngleLimit(double limit); 157 158 /** DBUS interface function. 159 * Enable or disable mount hour angle limit. Mount cannot slew and/or track past this 160 * hour angle distance. 161 */ 162 Q_SCRIPTABLE void setHourAngleLimitEnabled(bool enable); 163 164 /** DBUS interface function. 165 * Returns whether the mount limits are enabled or disabled. 166 * @return True if enabled, false otherwise. 167 */ 168 Q_SCRIPTABLE bool hourAngleLimitEnabled(); 169 170 /** 171 * @brief autoParkEnabled Check if auto-park is enabled. 172 * @return True if enabled. 173 */ 174 Q_SCRIPTABLE bool autoParkEnabled(); 175 176 /** 177 * @brief setAutoParkEnabled Toggle Auto Park 178 * @param enable True to start, false to stop 179 */ 180 Q_SCRIPTABLE void setAutoParkEnabled(bool enable); 181 182 /** 183 * @brief setAutoParkDailyEnabled toggles everyday Auto Park 184 * @param enable true to activate, false to deactivate 185 */ 186 Q_SCRIPTABLE void setAutoParkDailyEnabled(bool enabled); 187 188 /** 189 * @brief setAutoParkStartup Set time when automatic parking is activated. 190 * @param startup Startup time. should not be more than 12 hours away. 191 */ 192 Q_SCRIPTABLE void setAutoParkStartup(QTime startup); 193 194 Q_SCRIPTABLE bool meridianFlipEnabled(); 195 Q_SCRIPTABLE double meridianFlipValue(); 196 197 /** DBUS interface function. 198 * Slew the mount to the RA/DEC (JNow). 199 * @param RA Right ascention is hours. 200 * @param DEC Declination in degrees. 201 * @return true if the command is sent successfully, false otherwise. 202 */ 203 Q_INVOKABLE Q_SCRIPTABLE bool slew(double RA, double DEC); 204 205 /** 206 @brief Like above but RA and DEC are strings HH:MM:SS and DD:MM:SS 207 */ 208 Q_INVOKABLE bool slew(const QString &RA, const QString &DEC); 209 210 /** DBUS interface function. 211 * Slew the mount to the target. Target name must be valid in KStars. 212 * @param target name 213 * @return true if the command is sent successfully, false otherwise. 214 */ 215 Q_INVOKABLE Q_SCRIPTABLE bool gotoTarget(const QString &target); 216 217 /** DBUS interface function. 218 * Sync the mount to the RA/DEC (JNow). 219 * @param RA Right ascention is hours. 220 * @param DEC Declination in degrees. 221 * @return true if the command is sent successfully, false otherwise. 222 */ 223 Q_INVOKABLE Q_SCRIPTABLE bool sync(double RA, double DEC); 224 225 /** DBUS interface function. 226 * Sync the mount to the target. Target name must be valid in KStars. 227 * @param target name 228 * @return true if the command is sent successfully, false otherwise. 229 */ 230 Q_INVOKABLE Q_SCRIPTABLE bool syncTarget(const QString &target); 231 232 /** 233 @brief Like above but RA and DEC are strings HH:MM:SS and DD:MM:SS 234 */ 235 Q_INVOKABLE bool sync(const QString &RA, const QString &DEC); 236 237 /** DBUS interface function. 238 * Get equatorial coords (JNow). An array of doubles is returned. First element is RA in hours. Second elements is DEC in degrees. 239 */ 240 Q_SCRIPTABLE QList<double> equatorialCoords(); 241 242 /** DBUS interface function. 243 * Get Horizontal coords. An array of doubles is returned. First element is Azimuth in degrees. Second elements is Altitude in degrees. 244 */ 245 Q_SCRIPTABLE QList<double> horizontalCoords(); 246 247 /** DBUS interface function. 248 * Get Horizontal coords. 249 */ 250 Q_SCRIPTABLE SkyPoint currentTarget(); 251 252 /** DBUS interface function. 253 * Get mount hour angle in hours (-12 to +12). 254 */ 255 Q_SCRIPTABLE double hourAngle(); 256 257 double initialPositionHA; 258 /** DBUS interface function. 259 * Get the hour angle of that time the mount has slewed to the current position. 260 * This is used to manage the meridian flip for mounts which do not report pier side. 261 * only one attempt to flip is done. 262 */ initialHA()263 Q_SCRIPTABLE double initialHA() 264 { 265 return initialPositionHA; 266 } 267 setInitialHA(double ha)268 Q_SCRIPTABLE void setInitialHA(double ha) 269 { 270 initialPositionHA = ha; 271 } 272 273 /** DBUS interface function. 274 * Aborts the mount motion 275 * @return true if the command is sent successfully, false otherwise. 276 */ 277 Q_INVOKABLE Q_SCRIPTABLE bool abort(); 278 279 /** DBUS interface function. 280 * Get the mount slew status ("Idle","Complete", "Busy", "Error") 281 */ 282 Q_INVOKABLE Q_SCRIPTABLE IPState slewStatus(); 283 284 285 /** DBUS interface function. 286 * Get the mount slew rate index 0 to N-1, or -1 if slew rates are not supported. 287 */ 288 Q_INVOKABLE Q_SCRIPTABLE int slewRate(); 289 290 Q_INVOKABLE Q_SCRIPTABLE bool setSlewRate(int index); 291 292 /** DBUS interface function. 293 * Get telescope and guide scope info. An array of doubles is returned in order. 294 * Primary Telescope Focal Length (mm), Primary Telescope Aperture (mm), Guide Telescope Focal Length (mm), Guide Telescope Aperture (mm) 295 */ 296 Q_INVOKABLE Q_SCRIPTABLE QList<double> telescopeInfo(); 297 298 /** DBUS interface function. 299 * Set telescope and guide scope info and save them in INDI mount driver. All measurements is in millimeters. 300 * @param info An ordered 4-item list as following: 301 * primaryFocalLength Primary Telescope Focal Length. Set to 0 to skip setting this value. 302 * primaryAperture Primary Telescope Aperture. Set to 0 to skip setting this value. 303 * guideFocalLength Guide Telescope Focal Length. Set to 0 to skip setting this value. 304 * guideAperture Guide Telescope Aperture. Set to 0 to skip setting this value. 305 */ 306 Q_SCRIPTABLE Q_NOREPLY void setTelescopeInfo(const QList<double> &info); 307 308 /** DBUS interface function. 309 * Reset mount model if supported by the mount. 310 * @return true if the command is executed successfully, false otherwise. 311 */ 312 Q_INVOKABLE Q_SCRIPTABLE bool resetModel(); 313 314 /** DBUS interface function. 315 * Can mount park? 316 */ 317 Q_INVOKABLE Q_SCRIPTABLE bool canPark(); 318 319 /** DBUS interface function. 320 * Park mount 321 */ 322 Q_INVOKABLE Q_SCRIPTABLE bool park(); 323 324 /** DBUS interface function. 325 * Unpark mount 326 */ 327 Q_INVOKABLE Q_SCRIPTABLE bool unpark(); 328 329 /** DBUS interface function. 330 * Return parking status of the mount. 331 */ 332 //Q_INVOKABLE Q_SCRIPTABLE ParkingStatus getParkingStatus(); 333 334 Q_INVOKABLE void setTrackEnabled(bool enabled); 335 336 Q_INVOKABLE void setJ2000Enabled(bool enabled); 337 338 /** @}*/ 339 340 Q_INVOKABLE void findTarget(); 341 342 // target coord conversions for displaying 343 Q_INVOKABLE bool raDecToAzAlt(QString qsRA, QString qsDec); 344 Q_INVOKABLE bool raDecToHaDec(QString qsRA); 345 Q_INVOKABLE bool azAltToRaDec(QString qsAz, QString qsAlt); 346 Q_INVOKABLE bool azAltToHaDec(QString qsAz, QString qsAlt); 347 Q_INVOKABLE bool haDecToRaDec(QString qsHA); 348 Q_INVOKABLE bool haDecToAzAlt(QString qsHA, QString qsDec); 349 350 // Center mount in Sky Map 351 Q_INVOKABLE void centerMount(); 352 353 // Get list of scopes 354 //QJsonArray getScopes() const; 355 356 /* 357 * @brief Check if a meridian flip if necessary. 358 * @param lst current local sideral time 359 * @return true if a meridian flip is necessary 360 */ 361 bool checkMeridianFlip(dms lst); 362 363 /* 364 * @brief Execute a meridian flip if necessary. 365 * @return true if a meridian flip was necessary 366 */ 367 Q_INVOKABLE bool executeMeridianFlip(); 368 369 Q_INVOKABLE void setUpDownReversed(bool enabled); 370 Q_INVOKABLE void setLeftRightReversed(bool enabled); 371 meridianFlipStatusDescription()372 QString meridianFlipStatusDescription() 373 { 374 return meridianFlipStatusText->text(); 375 } 376 377 /// 378 /// \brief meridianFlipStatusString 379 /// \param status 380 /// \return return the string for the status 381 /// 382 static QString meridianFlipStatusString(MeridianFlipStatus status); 383 384 public slots: 385 386 /** 387 * @brief syncTelescopeInfo Update telescope information to reflect any property changes 388 */ 389 void syncTelescopeInfo(); 390 /** 391 * @brief updateNumber Update number properties under watch in the mount module 392 * @param nvp pointer to number property 393 */ 394 void updateNumber(INumberVectorProperty *nvp); 395 396 /** 397 * @brief updateSwitch Update switch properties under watch in the mount module 398 * @param svp pointer to switch property 399 */ 400 void updateSwitch(ISwitchVectorProperty *svp); 401 402 403 /** 404 * @brief updateText Update text properties under watch in the mount module 405 * @param tvp pointer to text property 406 */ 407 void updateText(ITextVectorProperty *tvp); 408 409 /** 410 * @brief updateLog Update mount module log to include any messages arriving for the telescope driver 411 * @param messageID ID of the new message 412 */ 413 void updateLog(int messageID); 414 415 /** 416 * @brief updateTelescopeCoords is triggered by the ISD::Telescope::newCoord() event and updates the displayed 417 * coordinates of the mount and to ensure mount is within altitude limits if the altitude limits are enabled. 418 * The frequency of this update depends on the REFRESH parameter of the INDI mount device. 419 * @param position latest coordinates the mount reports it is pointing to 420 * @param pierSide pierSide 421 * @param ha hour angle of the latest coordinates 422 */ 423 void updateTelescopeCoords(const SkyPoint &position, ISD::Telescope::PierSide pierSide, const dms &ha); 424 425 /** 426 * @brief move Issues motion command to the mount to move in a particular direction based the request NS and WE values 427 * @param command Either ISD::Telescope::MOTION_START (0) or ISD::Telescope::MOTION_STOP (1) 428 * @param NS is either -1 for no direction, or ISD::Telescope::MOTION_NORTH (0), or ISD::Telescope::MOTION_SOUTH (1) 429 * @param WE is either -1 for no direction, or ISD::Telescope::MOTION_WEST (0), or ISD::Telescope::MOTION_EAST (1) 430 */ 431 void motionCommand(int command, int NS, int WE); 432 433 /** 434 * @brief Send a guide pulse to the telescope. 435 * @param ra_dir RA guide direction 436 * @param ra_msecs duration of the RA guiding pulse in milliseconds 437 * @param dec_dir dec guide direction 438 * @param dec_msecs duration of the DEC guiding pulse in milliseconds 439 */ 440 void doPulse(GuideDirection ra_dir, int ra_msecs, GuideDirection dec_dir, int dec_msecs); 441 442 /** 443 * @brief save Save telescope focal length and aperture in the INDI telescope driver configuration. 444 */ 445 void save(); 446 447 /** 448 * @brief saveLimits Saves altitude limit to the user options and updates the INDI telescope driver limits 449 */ 450 void saveLimits(); 451 452 /** 453 * @brief enableAltitudeLimits Enable or disable altitude limits 454 * @param enable True to enable, false to disable. 455 */ 456 void enableAltitudeLimits(bool enable); 457 458 /** 459 * @brief enableAltLimits calls enableAltitudeLimits(true). This function is mostly used to enable altitude limit after a meridian flip is complete. 460 */ 461 void enableAltLimits(); 462 463 /** 464 * @brief disableAltLimits calls enableAltitudeLimits(false). This function is mostly used to disable altitude limit once a meridial flip process is started. 465 */ 466 void disableAltLimits(); 467 468 /** 469 * @brief enableHourAngleLimits Enable or disable hour angle limits 470 * @param enable True to enable, false to disable. 471 */ 472 void enableHourAngleLimits(bool enable); 473 474 /** 475 * @brief enableHaLimits calls enableHourAngleLimits(true). This function is mostly used to enable hour angle limit after a meridian flip is complete. 476 */ 477 void enableHaLimits(); 478 479 /** 480 * @brief disableAltLimits calls enableHourAngleLimits(false). This function is mostly used to disable altitude limit once a meridial flip process is started. 481 */ 482 void disableHaLimits(); 483 484 bool setScopeConfig(int index); 485 486 void toggleMountToolBox(); 487 488 void meridianFlipStatusChanged(MeridianFlipStatus status); 489 490 /* 491 * @brief set meridian flip activation and hours 492 * @param activate true iff the meridian flip should be executed 493 * @param hours angle past the meridian when the flip should be delayed 494 */ 495 void setMeridianFlipValues(bool activate, double hours); 496 497 /** 498 * @brief registerNewModule Register an Ekos module as it arrives via DBus 499 * and create the appropriate DBus interface to communicate with it. 500 * @param name of module 501 */ 502 void registerNewModule(const QString &name); 503 504 private slots: 505 void startParkTimer(); 506 void stopParkTimer(); 507 void startAutoPark(); 508 509 void meridianFlipSetupChanged(); 510 511 signals: 512 void newLog(const QString &text); 513 /** 514 * @brief Update event with the current telescope position 515 * @param position mount position. Independent from the mount type, 516 * the EQ coordinates(both JNow and J2000) as well as the alt/az values are filled. 517 * @param pierside for GEMs report the pier side the scope is currently (PierSide::PIER_WEST means 518 * the mount is on the western side of the pier pointing east of the meridian). 519 * @param ha current hour angle 520 */ 521 void newCoords(const SkyPoint &position, ISD::Telescope::PierSide pierSide, const dms &ha); 522 /** 523 * @brief The mount has finished the slew to a new target. 524 * @param currentObject object close to the position the mount is pointing to 525 * @param currentCoords exact position where the mount is positioned 526 */ 527 void newTarget(SkyObject ¤tObject, SkyPoint ¤tCoord); 528 /** 529 * @brief Change in the mount status. 530 */ 531 void newStatus(ISD::Telescope::Status status); 532 void newParkStatus(ISD::ParkStatus status); 533 void pierSideChanged(ISD::Telescope::PierSide side); 534 void slewRateChanged(int index); 535 void ready(); 536 void newMeridianFlipStatus(MeridianFlipStatus status); 537 void newMeridianFlipText(const QString &text); 538 539 private: 540 void syncGPS(); 541 void setScopeStatus(ISD::Telescope::Status status); 542 MeridianFlipStatus m_MFStatus = FLIP_NONE; 543 void setMeridianFlipStatus(MeridianFlipStatus status); 544 void meridianFlipStatusChangedInternal(MeridianFlipStatus status); 545 QString pierSideStateString(); 546 547 // A meridian flip requires a slew of 180 degrees in the hour angle axis so will take at least 548 // the time for that, currently set to 20 seconds 549 // not reliable for pointing state change detection but reported if the pier side is unknown 550 QDateTime minMeridianFlipEndTime; 551 int minMeridianFlipDurationSecs = 20; 552 553 double flipDelayHrs = 0.0; // delays the next flip attempt if it fails 554 555 QPointer<QDBusInterface> captureInterface { nullptr }; 556 557 ISD::Telescope *currentTelescope = nullptr; 558 ISD::GDInterface *currentGPS = nullptr; 559 QStringList m_LogText; 560 SkyPoint *currentTargetPosition = nullptr; 561 SkyPoint telescopeCoord; 562 QString lastNotificationMessage; 563 564 // Auto Park 565 QTimer autoParkTimer; 566 567 // Limits 568 int m_AbortDispatch {-1}; 569 bool m_AltitudeLimitEnabled {false}; 570 double m_LastAltitude {0}; 571 bool m_HourAngleLimitEnabled {false}; 572 double m_LastHourAngle {0}; 573 574 // GPS 575 bool GPSInitialized = {false}; 576 577 ISD::Telescope::Status m_Status = ISD::Telescope::MOUNT_IDLE; 578 ISD::ParkStatus m_ParkStatus = ISD::PARK_UNKNOWN; 579 580 QQuickView *m_BaseView = nullptr; 581 QQuickItem *m_BaseObj = nullptr; 582 QQmlContext *m_Ctxt = nullptr; 583 584 QQuickItem *m_SpeedSlider = nullptr, *m_SpeedLabel = nullptr, 585 *m_raValue = nullptr, *m_deValue = nullptr, *m_azValue = nullptr, 586 *m_altValue = nullptr, *m_haValue = nullptr, *m_zaValue = nullptr, 587 *m_targetText = nullptr, *m_targetRAText = nullptr, 588 *m_targetDEText = nullptr, *m_Park = nullptr, *m_Unpark = nullptr, 589 *m_statusText = nullptr, *m_J2000Check = nullptr, 590 *m_JNowCheck = nullptr, *m_equatorialCheck = nullptr, 591 *m_horizontalCheck = nullptr, *m_haEquatorialCheck = nullptr, 592 *m_leftRightCheck = nullptr, *m_upDownCheck = nullptr; 593 }; 594 } 595 596 597 #endif // Mount 598