diff --git a/kstars/auxiliary/ksutils.cpp b/kstars/auxiliary/ksutils.cpp --- a/kstars/auxiliary/ksutils.cpp +++ b/kstars/auxiliary/ksutils.cpp @@ -1029,18 +1029,20 @@ "org.kde.kstars.ekos.guide.debug=%6\n" "org.kde.kstars.ekos.align.debug=%7\n" "org.kde.kstars.ekos.mount.debug=%8\n" - "org.kde.kstars.ekos.scheduler.debug=%9\n" - "org.kde.kstars.debug=%1").arg( + "org.kde.kstars.ekos.scheduler.debug=%9\n").arg( Options::verboseLogging() ? "true" : "false", Options::iNDILogging() ? "true" : "false", Options::fITSLogging() ? "true" : "false", Options::captureLogging() ? "true" : "false", Options::focusLogging() ? "true" : "false", Options::guideLogging() ? "true" : "false", Options::alignmentLogging() ? "true" : "false", Options::mountLogging() ? "true" : "false", - Options::schedulerLogging() ? "true" : "false" - ); + Options::schedulerLogging() ? "true" : "false") + .append(QString("org.kde.kstars.ekos.observatory.debug=%2\n" + "org.kde.kstars.debug=%1").arg( + Options::verboseLogging() ? "true" : "false", + Options::observatoryLogging() ? "true" : "false")); QLoggingCategory::setFilterRules(rules); } diff --git a/kstars/ekos/auxiliary/dome.h b/kstars/ekos/auxiliary/dome.h --- a/kstars/ekos/auxiliary/dome.h +++ b/kstars/ekos/auxiliary/dome.h @@ -93,11 +93,15 @@ */ Q_SCRIPTABLE bool isMoving(); + Q_SCRIPTABLE bool isRolloffRoof(); Q_SCRIPTABLE double azimuthPosition(); Q_SCRIPTABLE void setAzimuthPosition(double position); Q_SCRIPTABLE void setRelativePosition(double position); + Q_SCRIPTABLE bool moveDome(bool moveCW, bool start); + + Q_SCRIPTABLE bool isAutoSync(); Q_SCRIPTABLE bool setAutoSync(bool activate); @@ -148,6 +152,7 @@ ISD::Dome *currentDome { nullptr }; ISD::ParkStatus m_ParkStatus { ISD::PARK_UNKNOWN }; ISD::Dome::ShutterStatus m_ShutterStatus { ISD::Dome::SHUTTER_UNKNOWN }; + void setStatus(ISD::Dome::Status status); }; } diff --git a/kstars/ekos/auxiliary/dome.cpp b/kstars/ekos/auxiliary/dome.cpp --- a/kstars/ekos/auxiliary/dome.cpp +++ b/kstars/ekos/auxiliary/dome.cpp @@ -37,10 +37,11 @@ currentDome->disconnect(this); connect(currentDome, &ISD::Dome::newStatus, this, &Dome::newStatus); - connect(currentDome, &ISD::Dome::newParkStatus, this, &Dome::newParkStatus); + connect(currentDome, &ISD::Dome::newStatus, this, &Dome::setStatus); connect(currentDome, &ISD::Dome::newParkStatus, [&](ISD::ParkStatus status) { m_ParkStatus = status; + emit newParkStatus(status); }); connect(currentDome, &ISD::Dome::newShutterStatus, this, &Dome::newShutterStatus); connect(currentDome, &ISD::Dome::newShutterStatus, [&](ISD::Dome::ShutterStatus status) @@ -53,22 +54,6 @@ connect(currentDome, &ISD::Dome::Disconnected, this, &Dome::disconnected); } -//void Dome::setTelescope(ISD::GDInterface *newTelescope) -//{ -// if (currentDome == nullptr) -// return; - -// ITextVectorProperty *activeDevices = currentDome->getBaseDevice()->getText("ACTIVE_DEVICES"); -// if (activeDevices) -// { -// IText *activeTelescope = IUFindText(activeDevices, "ACTIVE_TELESCOPE"); -// if (activeTelescope) -// { -// IUSaveText(activeTelescope, newTelescope->getDeviceName()); -// currentDome->getDriverInfo()->getClientManager()->sendNewText(activeDevices); -// } -// } -//} bool Dome::canPark() { @@ -110,6 +95,12 @@ return currentDome->isMoving(); } +bool Dome::isRolloffRoof() +{ + // a rolloff roof is a dome that can move neither absolutely nor relatively + return (currentDome && !currentDome->canAbsMove() && !currentDome->canRelMove()); +} + bool Dome::canAbsoluteMove() { if (currentDome) @@ -145,6 +136,15 @@ currentDome->setRelativePosition(position); } +bool Dome::moveDome(bool moveCW, bool start) +{ + if (currentDome == nullptr) + return false; + + return currentDome->moveDome(moveCW ? ISD::Dome::DOME_CW : ISD::Dome::DOME_CCW, + start ? ISD::Dome::MOTION_START : ISD::Dome::MOTION_STOP); +} + bool Dome::isAutoSync() { if (currentDome) @@ -178,49 +178,34 @@ return false; } -#if 0 -Dome::ParkingStatus Dome::getParkingStatus() +void Dome::removeDevice(ISD::GDInterface *device) { - if (currentDome == nullptr || currentDome->canPark() == false) - return PARKING_ERROR; - - ISwitchVectorProperty *parkSP = currentDome->getBaseDevice()->getSwitch("DOME_PARK"); - - if (parkSP == nullptr) - return PARKING_ERROR; - - switch (parkSP->s) + device->disconnect(this); + if (device == currentDome) { - case IPS_IDLE: - return PARKING_IDLE; - - case IPS_OK: - if (parkSP->sp[0].s == ISS_ON) - return PARKING_OK; - else - return UNPARKING_OK; - - case IPS_BUSY: - if (parkSP->sp[0].s == ISS_ON) - return PARKING_BUSY; - else - return UNPARKING_BUSY; - - case IPS_ALERT: - return PARKING_ERROR; + currentDome = nullptr; } - - return PARKING_ERROR; } -#endif -void Dome::removeDevice(ISD::GDInterface *device) +void Dome::setStatus(ISD::Dome::Status status) { - device->disconnect(this); - if (device == currentDome) + // special case for rolloff roofs. + if (isRolloffRoof()) { - currentDome = nullptr; + // if a parked rollof roof starts to move, its state changes to unparking + if (status == ISD::Dome::DOME_MOVING_CW && (m_ParkStatus == ISD::PARK_PARKED || m_ParkStatus == ISD::PARK_PARKING)) + { + m_ParkStatus = ISD::PARK_UNPARKING; + emit newParkStatus(m_ParkStatus); + } + // if a unparked rollof roof starts to move, its state changes to parking + else if (status == ISD::Dome::DOME_MOVING_CCW && (m_ParkStatus == ISD::PARK_UNPARKED || m_ParkStatus == ISD::PARK_UNPARKING)) + { + m_ParkStatus = ISD::PARK_PARKING; + emit newParkStatus(m_ParkStatus); + } } + // in all other cases, do nothing } } diff --git a/kstars/ekos/auxiliary/opslogs.ui b/kstars/ekos/auxiliary/opslogs.ui --- a/kstars/ekos/auxiliary/opslogs.ui +++ b/kstars/ekos/auxiliary/opslogs.ui @@ -6,8 +6,8 @@ 0 0 - 454 - 309 + 501 + 400 @@ -71,158 +71,178 @@ Logs - - - - Output: - - - - - + + - Log Ekos Guide module activity + Disable all logging output - Guide + &Disable + + + false - modulesGroup + verbosityButtonGroup - - + + + + Qt::Horizontal + + + + + - Auxiliary + Weather driversGroup - - - - Log Ekos Alignment module activity + + + + Verbosity: + + + + - Alignment + Focuser - modulesGroup + driversGroup - - + + - Log output to log file + Log Ekos Scheduler module activity - File + Scheduler + + modulesGroup + - - + + - Log Ekos Mount module activity + Log INDI devices activity - Mount + INDI modulesGroup - - - - Have problem with Ekos? Turn on logging for Ekos modules that exhibit issues. - + + - Ekos + Mount + + driversGroup + - - + + - Log debug messages to default output device used by the platform (e.g. Standard Error) + Log Ekos Focus module activity - Defaul&t - - - false + Focus + + modulesGroup + - - + + - Filter Wheel + Rotator driversGroup - - - - Qt::Horizontal - - - - - + + - Disable all logging output + Enable verbose debug output - &Disable - - - false + &Verbose verbosityButtonGroup - - + + - Enable verbose debug output + Log Ekos Guide module activity - &Verbose + Guide - verbosityButtonGroup + modulesGroup - - - - Qt::Horizontal + + + + CCD + + driversGroup + - - + + - Mount + GPS driversGroup + + + + Output: + + + + + + + Have problems with INDI drivers? Turn on logging for drivers that exhibit issues. + + + Drivers + + + @@ -239,67 +259,56 @@ - - - - Verbosity: + + + + Log FITS processing activity - - - - - Weather + FITS - driversGroup + modulesGroup - - + + - Have problems with INDI drivers? Turn on logging for drivers that exhibit issues. + Log Ekos Alignment module activity - Drivers + Alignment + + modulesGroup + - - + + - Focuser + Dome driversGroup - - + + - Log INDI devices activity - - - INDI + Adaptive Optics - - modulesGroup - - - - - - Dome + AO driversGroup - + Detector @@ -322,85 +331,89 @@ - - + + - Log Ekos Focus module activity + Have problem with Ekos? Turn on logging for Ekos modules that exhibit issues. - Focus + Ekos - - modulesGroup - - - + + - Log Ekos Scheduler module activity + Log debug messages to default output device used by the platform (e.g. Standard Error) - Scheduler + Defaul&t + + + false - - modulesGroup - - - + + - Log FITS processing activity + Log Ekos Mount module activity - FITS + Mount modulesGroup - - + + - CCD + Filter Wheel driversGroup - - + + + + Qt::Horizontal + + + + + - GPS + Auxiliary driversGroup - - + + + + Log output to log file + - Rotator + File - - driversGroup - - - + + - Adaptive Optics + <html><head/><body><p>Log Ekos Observatory module activity</p></body></html> - AO + Observatory - driversGroup + modulesGroup @@ -497,11 +510,11 @@ false - false + diff --git a/kstars/ekos/observatory/observatory.h b/kstars/ekos/observatory/observatory.h --- a/kstars/ekos/observatory/observatory.h +++ b/kstars/ekos/observatory/observatory.h @@ -81,6 +81,11 @@ void setWarningActions(WeatherActions actions); void setAlertActions(WeatherActions actions); + // button handling + void toggleButtons(QPushButton *buttonPressed, QString titlePressed, QPushButton *buttonCounterpart, QString titleCounterpart); + void activateButton(QPushButton *button, QString title); + void buttonPressed(QPushButton *button, QString title); + private slots: // observatory status handling void setObseratoryStatusControl(ObservatoryStatusControl control); @@ -103,6 +108,7 @@ void shutdownDome(); void setDomeStatus(ISD::Dome::Status status); + void setDomeParkStatus(ISD::ParkStatus status); void setShutterStatus(ISD::Dome::ShutterStatus status); }; } diff --git a/kstars/ekos/observatory/observatory.cpp b/kstars/ekos/observatory/observatory.cpp --- a/kstars/ekos/observatory/observatory.cpp +++ b/kstars/ekos/observatory/observatory.cpp @@ -36,8 +36,6 @@ // make invisible, since not implemented yet weatherWarningSchedulerCB->setVisible(false); weatherAlertSchedulerCB->setVisible(false); - motionCWButton->setVisible(false); - motionCCWButton->setVisible(false); } void Observatory::setObseratoryStatusControl(ObservatoryStatusControl control) @@ -59,6 +57,7 @@ connect(model, &Ekos::ObservatoryDomeModel::ready, this, &Ekos::Observatory::initDome); connect(model, &Ekos::ObservatoryDomeModel::disconnected, this, &Ekos::Observatory::shutdownDome); connect(model, &Ekos::ObservatoryDomeModel::newStatus, this, &Ekos::Observatory::setDomeStatus); + connect(model, &Ekos::ObservatoryDomeModel::newParkStatus, this, &Ekos::Observatory::setDomeParkStatus); connect(model, &Ekos::ObservatoryDomeModel::newShutterStatus, this, &Ekos::Observatory::setShutterStatus); connect(model, &Ekos::ObservatoryDomeModel::azimuthPositionChanged, this, &Ekos::Observatory::domeAzimuthChanged); connect(model, &Ekos::ObservatoryDomeModel::newAutoSyncStatus, this, &Ekos::Observatory::showAutoSync); @@ -125,6 +124,10 @@ { connect(getDomeModel(), &Ekos::ObservatoryDomeModel::newLog, this, &Ekos::Observatory::appendLogText); + // dome motion buttons + connect(motionCWButton, &QPushButton::clicked, [=](bool checked) {getDomeModel()->moveDome(true, checked);}); + connect(motionCCWButton, &QPushButton::clicked, [=](bool checked) {getDomeModel()->moveDome(false, checked);}); + if (getDomeModel()->canPark()) { connect(domePark, &QPushButton::clicked, getDomeModel(), &Ekos::ObservatoryDomeModel::park); @@ -138,42 +141,54 @@ domeUnpark->setEnabled(false); } - // initialize the dome motion controls - domeAzimuthChanged(getDomeModel()->azimuthPosition()); + if (getDomeModel()->isRolloffRoof()) + { + SlavingBox->setVisible(false); + domeAzimuthPosition->setText("N/A"); + enableMotionControl(true); + } + else + { + // initialize the dome motion controls + domeAzimuthChanged(getDomeModel()->azimuthPosition()); + + // slaving + showAutoSync(getDomeModel()->isAutoSync()); + connect(slavingEnableButton, &QPushButton::clicked, this, [this]() + { + enableAutoSync(true); + }); + connect(slavingDisableButton, &QPushButton::clicked, this, [this]() + { + enableAutoSync(false); + }); + } + // shutter handling if (getDomeModel()->hasShutter()) { shutterBox->setVisible(true); shutterBox->setEnabled(true); connect(shutterOpen, &QPushButton::clicked, getDomeModel(), &Ekos::ObservatoryDomeModel::openShutter); connect(shutterClosed, &QPushButton::clicked, getDomeModel(), &Ekos::ObservatoryDomeModel::closeShutter); shutterClosed->setEnabled(true); shutterOpen->setEnabled(true); + setShutterStatus(getDomeModel()->shutterStatus()); + useShutterCB->setVisible(true); } else { shutterBox->setVisible(false); weatherWarningShutterCB->setVisible(false); weatherAlertShutterCB->setVisible(false); + useShutterCB->setVisible(false); } + // abort button should always be available motionAbortButton->setEnabled(true); - - // slaving - connect(slavingEnableButton, &QPushButton::clicked, this, [this]() - { - enableAutoSync(true); - }); - connect(slavingDisableButton, &QPushButton::clicked, this, [this]() - { - enableAutoSync(false); - }); - - + // update the dome status setDomeStatus(getDomeModel()->status()); - setShutterStatus(getDomeModel()->shutterStatus()); - - enableAutoSync(getDomeModel()->isAutoSync()); + setDomeParkStatus(getDomeModel()->parkStatus()); } } @@ -194,76 +209,159 @@ void Observatory::setDomeStatus(ISD::Dome::Status status) { + qCDebug(KSTARS_EKOS_OBSERVATORY) << "Setting dome status to " << status; + switch (status) { case ISD::Dome::DOME_ERROR: break; case ISD::Dome::DOME_IDLE: - domePark->setChecked(false); - domePark->setText(i18n("Park")); - domeUnpark->setChecked(true); - domeUnpark->setText(i18n("UnParked")); - enableMotionControl(true); + motionCWButton->setChecked(false); + motionCWButton->setEnabled(true); + motionCCWButton->setChecked(false); + motionCCWButton->setEnabled(true); + appendLogText(i18n("Dome is idle.")); break; - case ISD::Dome::DOME_MOVING: - enableMotionControl(false); - appendLogText(i18n("Dome is moving...")); + + case ISD::Dome::DOME_MOVING_CW: + motionCWButton->setChecked(true); + motionCCWButton->setEnabled(true); + motionCCWButton->setChecked(false); + if (getDomeModel()->isRolloffRoof()) + { + domeAzimuthPosition->setText(i18n("Opening")); + toggleButtons(domeUnpark, i18n("Unparking"), domePark, i18n("Park")); + appendLogText(i18n("Dome is opening...")); + } + else + { + appendLogText(i18n("Dome is moving clockwise...")); + } break; + + case ISD::Dome::DOME_MOVING_CCW: + motionCWButton->setChecked(false); + motionCWButton->setEnabled(true); + motionCCWButton->setChecked(true); + if (getDomeModel()->isRolloffRoof()) + { + domeAzimuthPosition->setText(i18n("Closing")); + toggleButtons(domePark, i18n("Parking"), domeUnpark, i18n("Unpark")); + appendLogText(i18n("Dome is closing...")); + } + else + { + appendLogText(i18n("Dome is moving counter clockwise...")); + } + break; + case ISD::Dome::DOME_PARKED: - domePark->setChecked(true); - domePark->setText(i18n("Parked")); - domeUnpark->setChecked(false); - domeUnpark->setText(i18n("UnPark")); - enableMotionControl(false); + setDomeParkStatus(ISD::PARK_PARKED); + appendLogText(i18n("Dome is parked.")); break; + case ISD::Dome::DOME_PARKING: - domePark->setText(i18n("Parking")); - domeUnpark->setText(i18n("UnPark")); - enableMotionControl(false); + toggleButtons(domePark, i18n("Parking"), domeUnpark, i18n("Unpark")); + motionCWButton->setEnabled(true); + + if (getDomeModel()->isRolloffRoof()) + domeAzimuthPosition->setText(i18n("Closing")); + else + enableMotionControl(false); + + motionCWButton->setChecked(false); + motionCCWButton->setChecked(true); + appendLogText(i18n("Dome is parking...")); break; + case ISD::Dome::DOME_UNPARKING: - domePark->setText(i18n("Park")); - domeUnpark->setText(i18n("UnParking")); - enableMotionControl(false); + toggleButtons(domeUnpark, i18n("Unparking"), domePark, i18n("Park")); + motionCCWButton->setEnabled(true); + + if (getDomeModel()->isRolloffRoof()) + domeAzimuthPosition->setText(i18n("Opening")); + else + enableMotionControl(false); + + motionCWButton->setChecked(true); + motionCCWButton->setChecked(false); + appendLogText(i18n("Dome is unparking...")); break; + case ISD::Dome::DOME_TRACKING: enableMotionControl(true); + motionCWButton->setEnabled(true); + motionCCWButton->setChecked(true); appendLogText(i18n("Dome is tracking.")); break; } } +void Observatory::setDomeParkStatus(ISD::ParkStatus status) +{ + qCDebug(KSTARS_EKOS_OBSERVATORY) << "Setting dome park status to " << status; + switch (status) + { + case ISD::PARK_UNPARKED: + activateButton(domePark, i18n("Park")); + buttonPressed(domeUnpark, i18n("Unparked")); + motionCWButton->setChecked(false); + motionCWButton->setEnabled(false); + motionCCWButton->setChecked(false); + + if (getDomeModel()->isRolloffRoof()) + domeAzimuthPosition->setText(i18n("Open")); + else + enableMotionControl(true); + break; + + case ISD::PARK_PARKED: + buttonPressed(domePark, i18n("Parked")); + activateButton(domeUnpark, i18n("Unpark")); + motionCWButton->setChecked(false); + motionCCWButton->setChecked(false); + motionCCWButton->setEnabled(false); + + if (getDomeModel()->isRolloffRoof()) + domeAzimuthPosition->setText(i18n("Closed")); + else + enableMotionControl(false); + break; + + default: + break; + } +} + void Observatory::setShutterStatus(ISD::Dome::ShutterStatus status) { + qCDebug(KSTARS_EKOS_OBSERVATORY) << "Setting shutter status to " << status; + switch (status) { case ISD::Dome::SHUTTER_OPEN: - shutterOpen->setChecked(true); - shutterClosed->setChecked(false); - shutterOpen->setText(i18n("Opened")); - shutterClosed->setText(i18n("Close")); + buttonPressed(shutterOpen, i18n("Opened")); + activateButton(shutterClosed, i18n("Close")); appendLogText(i18n("Shutter is open.")); break; + case ISD::Dome::SHUTTER_OPENING: - shutterOpen->setText(i18n("Opening")); - shutterClosed->setText(i18n("Closed")); + toggleButtons(shutterOpen, i18n("Opening"), shutterClosed, i18n("Close")); appendLogText(i18n("Shutter is opening...")); break; + case ISD::Dome::SHUTTER_CLOSED: - shutterOpen->setChecked(false); - shutterClosed->setChecked(true); - shutterOpen->setText(i18n("Open")); - shutterClosed->setText(i18n("Closed")); + buttonPressed(shutterClosed, i18n("Closed")); + activateButton(shutterOpen, i18n("Open")); appendLogText(i18n("Shutter is closed.")); break; case ISD::Dome::SHUTTER_CLOSING: - shutterOpen->setText(i18n("Opened")); - shutterClosed->setText(i18n("Closing")); + toggleButtons(shutterClosed, i18n("Closing"), shutterOpen, i18n("Open")); appendLogText(i18n("Shutter is closing...")); break; default: @@ -317,14 +415,29 @@ { motionMoveRelButton->setEnabled(enabled); relativeMotionSB->setEnabled(enabled); + motionCWButton->setEnabled(enabled); + motionCCWButton->setEnabled(enabled); } else { motionMoveRelButton->setEnabled(false); relativeMotionSB->setEnabled(false); + motionCWButton->setEnabled(false); + motionCCWButton->setEnabled(false); } - + // special case for rolloff roofs + if (getDomeModel()->isRolloffRoof()) + { + motionCWButton->setText(i18n("Open")); + motionCCWButton->setText(i18n("Close")); + motionCWButton->setEnabled(enabled); + motionCCWButton->setEnabled(enabled); + motionMoveAbsButton->setVisible(false); + motionMoveRelButton->setVisible(false); + absoluteMotionSB->setVisible(false); + relativeMotionSB->setVisible(false); + } } void Observatory::enableAutoSync(bool enabled) @@ -441,6 +554,34 @@ weatherAlertDelaySB->setValue(actions.delay); } +void Observatory::toggleButtons(QPushButton *buttonPressed, QString titlePressed, QPushButton *buttonCounterpart, QString titleCounterpart) +{ + buttonPressed->setEnabled(false); + buttonPressed->setText(titlePressed); + + buttonCounterpart->setEnabled(true); + buttonCounterpart->setChecked(false); + buttonCounterpart->setCheckable(false); + buttonCounterpart->setText(titleCounterpart); +} + +void Observatory::activateButton(QPushButton *button, QString title) +{ + button->setEnabled(true); + button->setCheckable(false); + button->setText(title); +} + +void Observatory::buttonPressed(QPushButton *button, QString title) +{ + button->setEnabled(false); + button->setCheckable(true); + button->setChecked(true); + button->setText(title); + +} + + void Observatory::statusControlSettingsChanged() { ObservatoryStatusControl control; diff --git a/kstars/ekos/observatory/observatory.ui b/kstars/ekos/observatory/observatory.ui --- a/kstars/ekos/observatory/observatory.ui +++ b/kstars/ekos/observatory/observatory.ui @@ -50,7 +50,7 @@ Dome - + 3 @@ -63,261 +63,402 @@ 3 - + - - - - - - false - - - - 96 - 36 - - - - - 96 - 36 - - - - <html><head/><body><p>Park the dome. For advanced control of the dome please use the INDI tab.</p></body></html> - - - QPushButton:checked + + + + + 160 + 0 + + + + + 320 + 16777215 + + + + + 24 + 75 + true + + + + 0 + + + Qt::AlignCenter + + + + + + + Position + + + + + + + + + + + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + false + + + Motion + + + + + + + false + + + Absolute position the dome should move. + + + 999.990000000000009 + + + + + + + false + + + + 96 + 36 + + + + + 96 + 36 + + + + Move the dome to the given absolute position. + + + Move (abs) + + + + + + + false + + + Relative position the dome should move. + + + -999.990000000000009 + + + 999.990000000000009 + + + + + + + false + + + + 96 + 36 + + + + + 96 + 36 + + + + Move the dome for the given degrees and direction. + + + QPushButton:checked { background-color: maroon; border: 1px outset; font-weight:bold; } - - - Park - - - - 32 - 16 - - - - true - - - - - - - false - - - - 96 - 36 - - - - - 96 - 36 - - - - <html><head/><body><p>Unpark the dome. For advanced control of the dome please use the INDI tab.</p></body></html> - - - QPushButton:checked + + + Move (rel) + + + + + + + false + + + + 96 + 36 + + + + + 96 + 36 + + + + Rotate clockwise + + + QPushButton:checked { background-color: maroon; border: 1px outset; font-weight:bold; } - - - UnPark - - - true - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - 96 - 36 - - - - - 96 - 36 - - - - Abort dome motion - - - QPushButton:checked + + + &CW + + + true + + + + + + + false + + + + 96 + 36 + + + + + 96 + 36 + + + + Rotate counter clockwise + + + QPushButton:checked { background-color: maroon; border: 1px outset; font-weight:bold; } - - - Abort - - - - + + + CCW + + + true + + + + + - - - - - - false - - - Relative position the dome should move. - - - -999.990000000000009 - - - 999.990000000000009 - - - - - - - false - - - - 96 - 36 - - - - - 96 - 36 - - - - Move the dome for the given degrees and direction. - - - QPushButton:checked + + + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Slaving + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 96 + 36 + + + + + 96 + 36 + + + + <html><head/><body><p>Enable slaving, dome motion <span style=" font-weight:600;">follows telescope motion</span></p></body></html> + + + QPushButton:checked { background-color: maroon; border: 1px outset; font-weight:bold; } - - - Move (rel) - - - - - - - false - - - Absolute position the dome should move. - - - 999.990000000000009 - - - - - - - false - - - - 96 - 36 - - - - - 96 - 36 - - - - Move the dome to the given absolute position. - - - Move (abs) - - - - - - - + + + Enable + + + true + + + + + + + + 96 + 36 + + + + + 96 + 36 + + + + <html><head/><body><p>Disable slaving, dome <span style=" font-weight:600;">does not follow telescope motion</span>.</p></body></html> + + + QPushButton:checked +{ +background-color: maroon; +border: 1px outset; +font-weight:bold; +} + + + Disable + + + true + + + + + + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + false + - 160 - 0 + 96 + 36 - 320 - 16777215 + 96 + 36 - - - 24 - 75 - true - + + <html><head/><body><p>Park the dome. For advanced control of the dome please use the INDI tab.</p></body></html> + + + QPushButton:checked +{ +background-color: maroon; +border: 1px outset; +font-weight:bold; +} - 0 + Park - - Qt::AlignCenter + + + 32 + 16 + + + + false - - + + false @@ -334,7 +475,7 @@ - Rotate counter clockwise + <html><head/><body><p>Unpark the dome. For advanced control of the dome please use the INDI tab.</p></body></html> QPushButton:checked @@ -345,36 +486,31 @@ } - CCW + UnPark - - - - - + false - - Motion: + + false - - - - + + + + Qt::Horizontal - - - - - - Position + + + 40 + 20 + - + - - + + false @@ -391,7 +527,7 @@ - Rotate clockwise + Abort dome motion QPushButton:checked @@ -402,100 +538,10 @@ } - &CW + Abort - - - - - - Slaving - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 96 - 36 - - - - - 96 - 36 - - - - <html><head/><body><p>Enable slaving, dome motion <span style=" font-weight:600;">follows telescope motion</span></p></body></html> - - - QPushButton:checked -{ -background-color: maroon; -border: 1px outset; -font-weight:bold; -} - - - Enable - - - true - - - - - - - - 96 - 36 - - - - - 96 - 36 - - - - <html><head/><body><p>Disable slaving, dome <span style=" font-weight:600;">does not follow telescope motion</span>.</p></body></html> - - - QPushButton:checked -{ -background-color: maroon; -border: 1px outset; -font-weight:bold; -} - - - Disable - - - true - - - - - @@ -576,7 +622,7 @@ - true + false @@ -612,7 +658,7 @@ Open - true + false false @@ -853,7 +899,7 @@ - Delay (sec): + Delay (se&c): @@ -945,7 +991,7 @@ - Delay (sec): + De&lay (sec): diff --git a/kstars/ekos/observatory/observatorydomemodel.h b/kstars/ekos/observatory/observatorydomemodel.h --- a/kstars/ekos/observatory/observatorydomemodel.h +++ b/kstars/ekos/observatory/observatorydomemodel.h @@ -37,6 +37,7 @@ } void park(); void unpark(); + ISD::ParkStatus parkStatus(); double azimuthPosition() { @@ -62,6 +63,11 @@ return (domeInterface != nullptr && domeInterface->canRelativeMove()); } + bool isRolloffRoof() + { + return (domeInterface != nullptr && domeInterface->isRolloffRoof()); + } + bool isAutoSync() { return (domeInterface != nullptr && domeInterface->isAutoSync()); @@ -78,6 +84,8 @@ void openShutter(); void closeShutter(); + bool moveDome(bool moveCW, bool start); + public slots: void execute(WeatherActions actions); @@ -87,6 +95,7 @@ signals: void newStatus(ISD::Dome::Status state); + void newParkStatus(ISD::ParkStatus status); void newShutterStatus(ISD::Dome::ShutterStatus status); void newAutoSyncStatus(bool enabled); void azimuthPositionChanged(double position); diff --git a/kstars/ekos/observatory/observatorydomemodel.cpp b/kstars/ekos/observatory/observatorydomemodel.cpp --- a/kstars/ekos/observatory/observatorydomemodel.cpp +++ b/kstars/ekos/observatory/observatorydomemodel.cpp @@ -20,6 +20,7 @@ connect(domeInterface, &Dome::ready, this, &ObservatoryDomeModel::ready); connect(domeInterface, &Dome::disconnected, this, &ObservatoryDomeModel::disconnected); connect(domeInterface, &Dome::newStatus, this, &ObservatoryDomeModel::newStatus); + connect(domeInterface, &Dome::newParkStatus, this, &ObservatoryDomeModel::newParkStatus); connect(domeInterface, &Dome::newShutterStatus, this, &ObservatoryDomeModel::newShutterStatus); connect(domeInterface, &Dome::azimuthPositionChanged, this, &ObservatoryDomeModel::azimuthPositionChanged); connect(domeInterface, &Dome::newAutoSyncStatus, this, &ObservatoryDomeModel::newAutoSyncStatus); @@ -61,6 +62,23 @@ domeInterface->unpark(); } +ISD::ParkStatus ObservatoryDomeModel::parkStatus() +{ + if (domeInterface == nullptr) + return ISD::PARK_UNKNOWN; + else if (isRolloffRoof()) + { + // we need to override the parking status of the dome interface for opening and closing rolloff roofs + if (domeInterface->status() == ISD::Dome::DOME_MOVING_CW) + return ISD::PARK_UNPARKING; + else if (domeInterface->status() == ISD::Dome::DOME_MOVING_CCW) + return ISD::PARK_PARKING; + } + + // in all other cases use the underlying park status + return domeInterface->parkStatus(); +} + void ObservatoryDomeModel::setAutoSync(bool activate) { if (domeInterface == nullptr) @@ -98,6 +116,15 @@ domeInterface->controlShutter(false); } +bool ObservatoryDomeModel::moveDome(bool moveCW, bool start) +{ + if (domeInterface == nullptr) + return false; + + emit newLog(i18n("%2 dome motion %1...", moveCW ? "clockwise" : "counter clockwise", start ? "Starting" : "Stopping")); + return domeInterface->moveDome(moveCW, start); +} + void ObservatoryDomeModel::execute(WeatherActions actions) { if (hasShutter() && actions.closeShutter) diff --git a/kstars/ekos/observatory/observatorymodel.cpp b/kstars/ekos/observatory/observatorymodel.cpp --- a/kstars/ekos/observatory/observatorymodel.cpp +++ b/kstars/ekos/observatory/observatorymodel.cpp @@ -29,6 +29,7 @@ if (model != nullptr) { connect(mDomeModel, &ObservatoryDomeModel::newStatus, [this](ISD::Dome::Status s) { Q_UNUSED(s); updateStatus(); }); + connect(mDomeModel, &ObservatoryDomeModel::newParkStatus, [this](ISD::ParkStatus s) { Q_UNUSED(s); updateStatus(); }); connect(mDomeModel, &ObservatoryDomeModel::newShutterStatus, [this](ISD::Dome::ShutterStatus s) { Q_UNUSED(s); updateStatus(); }); if (mWeatherModel != nullptr) connect(mWeatherModel, &ObservatoryWeatherModel::execute, mDomeModel, &ObservatoryDomeModel::execute); @@ -73,9 +74,7 @@ bool ObservatoryModel::isReady() { // dome relevant for the status and dome is ready - if (mStatusControl.useDome && (getDomeModel() == nullptr || - (getDomeModel()->status() != ISD::Dome::DOME_IDLE && - getDomeModel()->status() != ISD::Dome::DOME_TRACKING))) + if (mStatusControl.useDome && (getDomeModel() == nullptr || getDomeModel()->parkStatus() != ISD::PARK_UNPARKED)) return false; // shutter relevant for the status and shutter open diff --git a/kstars/indi/indidome.h b/kstars/indi/indidome.h --- a/kstars/indi/indidome.h +++ b/kstars/indi/indidome.h @@ -18,7 +18,7 @@ { /** * @class Dome - * Focuser class handles control of INDI dome devices. Both open and closed loop (senor feedback) domes are supported. + * Class handles control of INDI dome devices. Both open and closed loop (sensor feedback) domes are supported. * * @author Jasem Mutlaq */ @@ -31,7 +31,8 @@ typedef enum { DOME_IDLE, - DOME_MOVING, + DOME_MOVING_CW, + DOME_MOVING_CCW, DOME_TRACKING, DOME_PARKING, DOME_UNPARKING, @@ -49,6 +50,19 @@ SHUTTER_ERROR } ShutterStatus; + typedef enum + { + DOME_CW, + DOME_CCW + } DomeDirection; + + typedef enum + { + MOTION_START, + MOTION_STOP + } DomeMotionCommand; + + void processSwitch(ISwitchVectorProperty *svp) override; void processText(ITextVectorProperty *tvp) override; void processNumber(INumberVectorProperty *nvp) override; @@ -86,6 +100,7 @@ bool setAzimuthPosition(double position); bool setRelativePosition(double position); + bool moveDome(DomeDirection dir, DomeMotionCommand operation); bool hasShutter() const { diff --git a/kstars/indi/indidome.cpp b/kstars/indi/indidome.cpp --- a/kstars/indi/indidome.cpp +++ b/kstars/indi/indidome.cpp @@ -219,12 +219,19 @@ { Status lastStatus = m_Status; - if (svp->s == IPS_BUSY && lastStatus != DOME_MOVING && lastStatus != DOME_PARKING && lastStatus != DOME_UNPARKING) + if (svp->s == IPS_BUSY && lastStatus != DOME_MOVING_CW && lastStatus != DOME_MOVING_CCW && lastStatus != DOME_PARKING && lastStatus != DOME_UNPARKING) { - m_Status = DOME_MOVING; + m_Status = svp->sp->s == ISS_ON ? DOME_MOVING_CW : DOME_MOVING_CCW; emit newStatus(m_Status); + + // rolloff roofs: cw = opening = unparking, ccw = closing = parking + if (!canAbsMove() && !canRelMove()) + { + m_ParkStatus = m_Status == DOME_MOVING_CW ? PARK_UNPARKING : PARK_PARKING; + emit newParkStatus(m_ParkStatus); + } } - else if (svp->s == IPS_OK && lastStatus == DOME_MOVING) + else if (svp->s == IPS_OK && (lastStatus == DOME_MOVING_CW || lastStatus == DOME_MOVING_CCW)) { m_Status = DOME_TRACKING; emit newStatus(m_Status); @@ -443,6 +450,21 @@ return true; } +bool Dome::moveDome(DomeDirection dir, DomeMotionCommand operation) +{ + ISwitchVectorProperty *domeMotion = baseDevice->getSwitch("DOME_MOTION"); + if (domeMotion == nullptr) + return false; + + ISwitch *opSwitch = IUFindSwitch(domeMotion, dir == DomeDirection::DOME_CW ? "DOME_CW": "DOME_CCW"); + IUResetSwitch(domeMotion); + opSwitch->s = (operation == DomeMotionCommand::MOTION_START ? ISS_ON : ISS_OFF); + + clientManager->sendNewSwitch(domeMotion); + + return true; +} + bool Dome::ControlShutter(bool open) { ISwitchVectorProperty *shutterSP = baseDevice->getSwitch("DOME_SHUTTER"); @@ -506,8 +528,11 @@ case ISD::Dome::DOME_UNPARKING: return i18n("UnParking"); - case ISD::Dome::DOME_MOVING: - return i18n("Moving"); + case ISD::Dome::DOME_MOVING_CW: + return i18n("Moving clockwise"); + + case ISD::Dome::DOME_MOVING_CCW: + return i18n("Moving counter clockwise"); case ISD::Dome::DOME_TRACKING: return i18n("Tracking"); diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg --- a/kstars/kstars.kcfg +++ b/kstars/kstars.kcfg @@ -1383,6 +1383,10 @@ Log Ekos Mount Module activity. false + + Log Ekos Observatory Module activity. + false +