File indexing completed on 2024-04-28 03:43:14

0001 /*  Ekos commands for the capture module
0002     SPDX-FileCopyrightText: Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "capturedeviceadaptor.h"
0008 
0009 #include "ksmessagebox.h"
0010 #include "Options.h"
0011 #include "indi/indistd.h"
0012 #include "ekos_capture_debug.h"
0013 #include "sequencejobstate.h"
0014 
0015 #include "indi/indicamera.h"
0016 #include "indi/indidustcap.h"
0017 #include "indi/indidome.h"
0018 #include "indi/indilightbox.h"
0019 #include "indi/indimount.h"
0020 #include "indi/indirotator.h"
0021 #include "ekos/auxiliary/rotatorutils.h"
0022 
0023 namespace Ekos
0024 {
0025 
0026 
0027 void CaptureDeviceAdaptor::connectDome(SequenceJobState *state)
0028 {
0029     if (state == nullptr)
0030         return;
0031 
0032     connect(state, &SequenceJobState::setDomeParked, this, &CaptureDeviceAdaptor::setDomeParked);
0033     connect(this, &CaptureDeviceAdaptor::domeStatusChanged, state, &SequenceJobState::domeStatusChanged);
0034 }
0035 
0036 void CaptureDeviceAdaptor::disconnectDome(SequenceJobState *state)
0037 {
0038     if (state == nullptr)
0039         return;
0040 
0041     disconnect(state, &SequenceJobState::setDomeParked, this, &CaptureDeviceAdaptor::setDomeParked);
0042     disconnect(this, &CaptureDeviceAdaptor::domeStatusChanged, state, &SequenceJobState::domeStatusChanged);
0043 }
0044 
0045 void CaptureDeviceAdaptor::setCurrentSequenceJobState(QSharedPointer<SequenceJobState> jobState)
0046 {
0047     // clear old connections
0048     disconnectDevices(currentSequenceJobState.data());
0049     // add new connections
0050     connectRotator(jobState.data());
0051     connectFilterManager(jobState.data());
0052     connectActiveCamera(jobState.data());
0053     connectMount(jobState.data());
0054     connectDome(jobState.data());
0055     connectDustCap(jobState.data());
0056     currentSequenceJobState = jobState;
0057 
0058 }
0059 
0060 void CaptureDeviceAdaptor::setDustCap(ISD::DustCap *device)
0061 {
0062     disconnectDustCap(currentSequenceJobState.data());
0063     m_ActiveDustCap = device;
0064     connectDustCap(currentSequenceJobState.data());
0065 }
0066 
0067 void CaptureDeviceAdaptor::disconnectDevices(SequenceJobState *state)
0068 {
0069     disconnectRotator(state);
0070     disconnectFilterManager(state);
0071     disconnectActiveCamera(state);
0072     disconnectMount(state);
0073     disconnectDome(state);
0074     disconnectDustCap(state);
0075 }
0076 
0077 
0078 
0079 
0080 
0081 void CaptureDeviceAdaptor::connectDustCap(SequenceJobState *state)
0082 {
0083     if (m_ActiveDustCap != nullptr)
0084         connect(m_ActiveDustCap, &ISD::DustCap::newStatus, this, &CaptureDeviceAdaptor::dustCapStatusChanged);
0085 
0086     if (state == nullptr)
0087         return;
0088 
0089     connect(state, &SequenceJobState::askManualScopeCover, this, &CaptureDeviceAdaptor::askManualScopeCover);
0090     connect(state, &SequenceJobState::askManualScopeOpen, this, &CaptureDeviceAdaptor::askManualScopeOpen);
0091     connect(state, &SequenceJobState::setLightBoxLight, this, &CaptureDeviceAdaptor::setLightBoxLight);
0092     connect(state, &SequenceJobState::parkDustCap, this, &CaptureDeviceAdaptor::parkDustCap);
0093 
0094     connect(this, &CaptureDeviceAdaptor::manualScopeCoverUpdated, state, &SequenceJobState::updateManualScopeCover);
0095     connect(this, &CaptureDeviceAdaptor::lightBoxLight, state, &SequenceJobState::lightBoxLight);
0096     connect(this, &CaptureDeviceAdaptor::dustCapStatusChanged, state, &SequenceJobState::dustCapStateChanged);
0097 }
0098 
0099 void CaptureDeviceAdaptor::disconnectDustCap(SequenceJobState *state)
0100 {
0101     if (m_ActiveDustCap != nullptr)
0102         disconnect(m_ActiveDustCap, nullptr, this, nullptr);
0103 
0104     if (state == nullptr)
0105         return;
0106 
0107     disconnect(state, &SequenceJobState::askManualScopeCover, this, &CaptureDeviceAdaptor::askManualScopeCover);
0108     disconnect(state, &SequenceJobState::askManualScopeOpen, this, &CaptureDeviceAdaptor::askManualScopeOpen);
0109     disconnect(state, &SequenceJobState::setLightBoxLight, this, &CaptureDeviceAdaptor::setLightBoxLight);
0110     disconnect(state, &SequenceJobState::parkDustCap, this, &CaptureDeviceAdaptor::parkDustCap);
0111 
0112     disconnect(this, &CaptureDeviceAdaptor::manualScopeCoverUpdated, state, &SequenceJobState::updateManualScopeCover);
0113     disconnect(this, &CaptureDeviceAdaptor::lightBoxLight, state, &SequenceJobState::lightBoxLight);
0114     disconnect(this, &CaptureDeviceAdaptor::dustCapStatusChanged, state, &SequenceJobState::dustCapStateChanged);
0115 }
0116 
0117 void CaptureDeviceAdaptor::setMount(ISD::Mount *device)
0118 {
0119     if (m_ActiveMount == device)
0120         return;
0121 
0122     // clean up old connections
0123     if (m_ActiveMount != nullptr)
0124     {
0125         disconnect(m_ActiveMount, nullptr, this, nullptr);
0126         disconnectMount(currentSequenceJobState.data());
0127     }
0128     // connect new device
0129     if (device != nullptr)
0130     {
0131         connect(device, &ISD::Mount::newStatus, this, &CaptureDeviceAdaptor::scopeStatusChanged);
0132         connect(device, &ISD::Mount::pierSideChanged, this, &CaptureDeviceAdaptor::pierSideChanged);
0133         connect(device, &ISD::Mount::newParkStatus, this, &CaptureDeviceAdaptor::scopeParkStatusChanged);
0134         connectMount(currentSequenceJobState.data());
0135 
0136         // update mount states
0137         emit pierSideChanged(device->pierSide());
0138         emit scopeParkStatusChanged(device->parkStatus());
0139     }
0140 
0141     m_ActiveMount = device;
0142 }
0143 
0144 void CaptureDeviceAdaptor::connectMount(SequenceJobState *state)
0145 {
0146     if (state == nullptr)
0147         return;
0148 
0149     connect(state, &SequenceJobState::slewTelescope, this, &CaptureDeviceAdaptor::slewTelescope);
0150     connect(state, &SequenceJobState::setScopeTracking, this, &CaptureDeviceAdaptor::setScopeTracking);
0151     connect(state, &SequenceJobState::setScopeParked, this, &CaptureDeviceAdaptor::setScopeParked);
0152 
0153     connect(this, &CaptureDeviceAdaptor::scopeStatusChanged, state, &SequenceJobState::scopeStatusChanged);
0154     connect(this, &CaptureDeviceAdaptor::scopeParkStatusChanged, state, &SequenceJobState::scopeParkStatusChanged);
0155 }
0156 
0157 void CaptureDeviceAdaptor::disconnectMount(SequenceJobState *state)
0158 {
0159     if (state == nullptr)
0160         return;
0161 
0162     disconnect(state, &SequenceJobState::slewTelescope, this, &CaptureDeviceAdaptor::slewTelescope);
0163     disconnect(state, &SequenceJobState::setScopeTracking, this, &CaptureDeviceAdaptor::setScopeTracking);
0164     disconnect(state, &SequenceJobState::setScopeParked, this, &CaptureDeviceAdaptor::setScopeParked);
0165 
0166     disconnect(this, &CaptureDeviceAdaptor::scopeStatusChanged, state, &SequenceJobState::scopeStatusChanged);
0167     disconnect(this, &CaptureDeviceAdaptor::scopeParkStatusChanged, state, &SequenceJobState::scopeParkStatusChanged);
0168 }
0169 
0170 void CaptureDeviceAdaptor::setDome(ISD::Dome *device)
0171 {
0172     if (m_ActiveDome == device)
0173         return;
0174 
0175     // clean up old connections
0176     if (m_ActiveDome != nullptr)
0177     {
0178         disconnect(m_ActiveDome, nullptr, this, nullptr);
0179         disconnectDome(currentSequenceJobState.data());
0180     }
0181     // connect new device
0182     if (device != nullptr)
0183     {
0184         connect(device, &ISD::Dome::newStatus, this, &CaptureDeviceAdaptor::domeStatusChanged);
0185         connectDome(currentSequenceJobState.data());
0186     }
0187 
0188     m_ActiveDome = device;
0189 }
0190 
0191 void CaptureDeviceAdaptor::setRotator(ISD::Rotator *device)
0192 {
0193     // do nothing if *real* rotator is already connected
0194     if ((m_ActiveRotator == device) && (device != nullptr))
0195         return;
0196 
0197     // clean up old connections
0198     if (m_ActiveRotator != nullptr)
0199     {
0200         m_ActiveRotator->disconnect(this);
0201         disconnectRotator(currentSequenceJobState.data());
0202     }
0203 
0204     m_ActiveRotator = device;
0205 
0206     // connect new device
0207     if (m_ActiveRotator != nullptr)
0208     {
0209         connect(m_ActiveRotator, &ISD::Rotator::newAbsoluteAngle, this, &CaptureDeviceAdaptor::newRotatorAngle,
0210                 Qt::UniqueConnection);
0211         connect(m_ActiveRotator, &ISD::Rotator::reverseToggled, this, &CaptureDeviceAdaptor::rotatorReverseToggled,
0212                 Qt::UniqueConnection);
0213         connectRotator(currentSequenceJobState.data());
0214 
0215         emit newRotator(device->getDeviceName());
0216     }
0217     else
0218         emit newRotator(""); // no real rotator present, so check if user wants to use "manual rotator"
0219 
0220 }
0221 
0222 void CaptureDeviceAdaptor::connectRotator(SequenceJobState *state)
0223 {
0224     if (state == nullptr)
0225         return;
0226 
0227     connect(this, &CaptureDeviceAdaptor::newRotatorAngle, state, &SequenceJobState::setCurrentRotatorPositionAngle,
0228             Qt::UniqueConnection);
0229     connect(state, &SequenceJobState::setRotatorAngle, this, &CaptureDeviceAdaptor::setRotatorAngle);
0230 }
0231 
0232 void CaptureDeviceAdaptor::disconnectRotator(SequenceJobState *state)
0233 {
0234     if (state == nullptr)
0235         return;
0236 
0237     disconnect(state, &SequenceJobState::setRotatorAngle, this, &CaptureDeviceAdaptor::setRotatorAngle);
0238     disconnect(this, &CaptureDeviceAdaptor::newRotatorAngle, state, &SequenceJobState::setCurrentRotatorPositionAngle);
0239 }
0240 
0241 void CaptureDeviceAdaptor::setRotatorAngle(double rawAngle)
0242 {
0243     if (m_ActiveRotator != nullptr && m_ActiveRotator->setAbsoluteAngle(rawAngle))
0244     {
0245         RotatorUtils::Instance()->initTimeFrame(rawAngle);
0246         qCInfo(KSTARS_EKOS_CAPTURE) << "Setting rotator angle to" << rawAngle << "degrees.";
0247     }
0248     else
0249         qCWarning(KSTARS_EKOS_CAPTURE) << "Setting rotator angle to " << rawAngle
0250                                        << "failed due to missing or unresponsive rotator.";
0251 }
0252 
0253 double CaptureDeviceAdaptor::getRotatorAngle()
0254 {
0255     if (m_ActiveRotator != nullptr)
0256         return m_ActiveRotator->absoluteAngle();
0257     else
0258         return 0;
0259 }
0260 
0261 IPState CaptureDeviceAdaptor::getRotatorAngleState()
0262 {
0263     if (m_ActiveRotator != nullptr)
0264         return m_ActiveRotator->absoluteAngleState();
0265     else
0266         return IPS_ALERT;
0267 }
0268 
0269 void CaptureDeviceAdaptor::reverseRotator(bool toggled)
0270 {
0271     if (m_ActiveRotator != nullptr)
0272     {
0273         m_ActiveRotator->setReversed(toggled);
0274         m_ActiveRotator->setConfig(SAVE_CONFIG);
0275     }
0276 }
0277 
0278 void CaptureDeviceAdaptor::readRotatorAngle()
0279 {
0280     if (m_ActiveRotator != nullptr)
0281         emit newRotatorAngle(m_ActiveRotator->absoluteAngle(), m_ActiveRotator->absoluteAngleState());
0282 }
0283 
0284 
0285 
0286 void CaptureDeviceAdaptor::setActiveCamera(ISD::Camera *device)
0287 {
0288     if (m_ActiveCamera == device)
0289         return;
0290 
0291     // disconnect device events if the new device is not empty
0292     if (m_ActiveCamera != nullptr)
0293     {
0294         m_ActiveCamera->disconnect(this);
0295         disconnectActiveCamera(currentSequenceJobState.data());
0296 
0297     }
0298 
0299     // store the link to the new device
0300     m_ActiveCamera = device;
0301 
0302     // connect device events if the new device is not empty
0303     if (m_ActiveCamera != nullptr)
0304     {
0305         // publish device events
0306         connect(m_ActiveCamera, &ISD::Camera::newTemperatureValue, this,
0307                 &CaptureDeviceAdaptor::newCCDTemperatureValue, Qt::UniqueConnection);
0308         connect(m_ActiveCamera, &ISD::ConcreteDevice::Connected, this, [this]()
0309         {
0310             emit CameraConnected(true);
0311         });
0312         connect(m_ActiveCamera, &ISD::ConcreteDevice::Disconnected, this, [this]()
0313         {
0314             emit CameraConnected(false);
0315         });
0316 
0317         if (m_ActiveCamera->hasGuideHead())
0318             addGuideHead(device);
0319     }
0320     connectActiveCamera(currentSequenceJobState.data());
0321 
0322     // communicate new camera
0323     emit newCamera(device == nullptr ? "" : device->getDeviceName());
0324 }
0325 
0326 void CaptureDeviceAdaptor::setFilterWheel(ISD::FilterWheel *device)
0327 {
0328     if (m_ActiveFilterWheel == device)
0329         return;
0330 
0331     // disconnect device events if the new device is not empty
0332     if (m_ActiveFilterWheel != nullptr)
0333         m_ActiveFilterWheel->disconnect(this);
0334 
0335     // store the link to the new device
0336     m_ActiveFilterWheel = device;
0337 
0338     // connect device events if the new device is not empty
0339     if (m_ActiveFilterWheel != nullptr)
0340     {
0341         connect(m_ActiveFilterWheel, &ISD::ConcreteDevice::Connected, this, [this]()
0342         {
0343             emit FilterWheelConnected(true);
0344         });
0345         connect(m_ActiveFilterWheel, &ISD::ConcreteDevice::Disconnected, this, [this]()
0346         {
0347             emit FilterWheelConnected(false);
0348         });
0349     }
0350 
0351     // communicate new device
0352     emit newFilterWheel(device == nullptr ? "" : device->getDeviceName());
0353 }
0354 
0355 void CaptureDeviceAdaptor::connectActiveCamera(SequenceJobState *state)
0356 {
0357     if (state == nullptr)
0358         return;
0359 
0360     //connect state machine to device adaptor
0361     connect(state, &SequenceJobState::setCCDTemperature, this, &CaptureDeviceAdaptor::setCCDTemperature);
0362     connect(state, &SequenceJobState::setCCDBatchMode, this, &CaptureDeviceAdaptor::enableCCDBatchMode);
0363     connect(state, &SequenceJobState::queryHasShutter, this, &CaptureDeviceAdaptor::queryHasShutter);
0364 
0365     // forward own events to the state machine
0366     connect(this, &CaptureDeviceAdaptor::flatSyncFocusChanged, state, &SequenceJobState::flatSyncFocusChanged);
0367     connect(this, &CaptureDeviceAdaptor::hasShutter, state, &SequenceJobState::hasShutter);
0368     connect(this, &CaptureDeviceAdaptor::newCCDTemperatureValue, state, &SequenceJobState::setCurrentCCDTemperature,
0369             Qt::UniqueConnection);
0370 }
0371 
0372 void CaptureDeviceAdaptor::disconnectActiveCamera(SequenceJobState *state)
0373 {
0374     if (state == nullptr)
0375         return;
0376 
0377     disconnect(state, &SequenceJobState::setCCDTemperature, this, &CaptureDeviceAdaptor::setCCDTemperature);
0378     disconnect(state, &SequenceJobState::setCCDBatchMode, this, &CaptureDeviceAdaptor::enableCCDBatchMode);
0379     disconnect(state, &SequenceJobState::queryHasShutter, this, &CaptureDeviceAdaptor::queryHasShutter);
0380 
0381     disconnect(this, &CaptureDeviceAdaptor::flatSyncFocusChanged, state, &SequenceJobState::flatSyncFocusChanged);
0382     disconnect(this, &CaptureDeviceAdaptor::hasShutter, state, &SequenceJobState::hasShutter);
0383     disconnect(this, &CaptureDeviceAdaptor::newCCDTemperatureValue, state, &SequenceJobState::setCurrentCCDTemperature);
0384 }
0385 
0386 void CaptureDeviceAdaptor::connectFilterManager(SequenceJobState *state)
0387 {
0388     if (state == nullptr)
0389         return;
0390 
0391     connect(state, &SequenceJobState::changeFilterPosition, this, &CaptureDeviceAdaptor::setFilterPosition);
0392     connect(state, &SequenceJobState::readFilterPosition, this, &CaptureDeviceAdaptor::updateFilterPosition);
0393     connect(this, &CaptureDeviceAdaptor::filterIdChanged, state, &SequenceJobState::setCurrentFilterID);
0394 
0395     if (m_FilterManager.isNull() == false)
0396         connect(m_FilterManager.get(), &FilterManager::newStatus, state, &SequenceJobState::setFilterStatus);
0397 }
0398 
0399 void CaptureDeviceAdaptor::disconnectFilterManager(SequenceJobState *state)
0400 {
0401     if (state == nullptr)
0402         return;
0403 
0404     disconnect(state, &SequenceJobState::readFilterPosition, this, &CaptureDeviceAdaptor::updateFilterPosition);
0405     disconnect(state, &SequenceJobState::changeFilterPosition, this, &CaptureDeviceAdaptor::setFilterPosition);
0406     disconnect(this, &CaptureDeviceAdaptor::filterIdChanged, state, &SequenceJobState::setCurrentFilterID);
0407 
0408     if (m_FilterManager.isNull() == false)
0409         disconnect(m_FilterManager.get(), &FilterManager::newStatus, state, &SequenceJobState::setFilterStatus);
0410 }
0411 
0412 void Ekos::CaptureDeviceAdaptor::updateFilterPosition()
0413 {
0414     if (m_FilterManager.isNull())
0415     {
0416         qCritical(KSTARS_EKOS_CAPTURE) << "Filter manager is not initilized yet. Filter wheel missing from train?";
0417         emit filterIdChanged(-1);
0418     }
0419     else
0420         emit filterIdChanged(m_FilterManager->getFilterPosition());
0421 }
0422 
0423 void CaptureDeviceAdaptor::readCurrentState(CaptureState state)
0424 {
0425     switch(state)
0426     {
0427         case CAPTURE_SETTING_TEMPERATURE:
0428             if (m_ActiveCamera != nullptr)
0429             {
0430                 double currentTemperature;
0431                 m_ActiveCamera->getTemperature(&currentTemperature);
0432                 emit newCCDTemperatureValue(currentTemperature);
0433             }
0434             break;
0435         case CAPTURE_SETTING_ROTATOR:
0436             readRotatorAngle();
0437             break;
0438         case CAPTURE_GUIDER_DRIFT:
0439             // intentionally left empty since the guider regularly updates the drift
0440             break;
0441         default:
0442             // this should not happen!
0443             qWarning(KSTARS_EKOS_CAPTURE) << "Reading device state " << state << " not implemented!";
0444             break;
0445     }
0446 }
0447 
0448 void CaptureDeviceAdaptor::setCCDTemperature(double temp)
0449 {
0450     if (m_ActiveCamera != nullptr)
0451         m_ActiveCamera->setTemperature(temp);
0452 }
0453 
0454 void CaptureDeviceAdaptor::enableCCDBatchMode(bool enable)
0455 {
0456     if (m_ActiveChip != nullptr)
0457         m_ActiveChip->setBatchMode(enable);
0458 }
0459 
0460 void CaptureDeviceAdaptor::abortFastExposure()
0461 {
0462     if (m_ActiveCamera != nullptr && m_ActiveChip != nullptr && m_ActiveCamera->isFastExposureEnabled())
0463         m_ActiveChip->abortExposure();
0464 }
0465 
0466 double CaptureDeviceAdaptor::cameraGain(QMap<QString, QMap<QString, QVariant> > propertyMap)
0467 {
0468     if (getActiveCamera())
0469     {
0470         // derive attributes from active camera
0471         if (getActiveCamera()->getProperty("CCD_GAIN"))
0472             return propertyMap["CCD_GAIN"].value("GAIN", -1).toDouble();
0473         else if (getActiveCamera()->getProperty("CCD_CONTROLS"))
0474             return propertyMap["CCD_CONTROLS"].value("Gain", -1).toDouble();
0475     }
0476     else // no active camera set, e.g. whien used from the scheduler
0477     {
0478         // if camera is unknown, use the custom property that is set
0479         if (propertyMap.keys().contains("CCD_GAIN"))
0480             return propertyMap["CCD_GAIN"].value("GAIN", -1).toDouble();
0481         else if(propertyMap.keys().contains("CCD_CONTROLS"))
0482             return propertyMap["CCD_CONTROLS"].value("Gain", -1).toDouble();
0483     }
0484 
0485     // none found
0486     return -1;
0487 
0488 }
0489 
0490 double CaptureDeviceAdaptor::cameraGain()
0491 {
0492     double value = INVALID_VALUE;
0493     if (getActiveCamera() != nullptr)
0494         getActiveCamera()->getGain(&value);
0495 
0496     return value;
0497 }
0498 
0499 double CaptureDeviceAdaptor::cameraOffset(QMap<QString, QMap<QString, QVariant> > propertyMap)
0500 {
0501     if (getActiveCamera())
0502     {
0503         if (getActiveCamera()->getProperty("CCD_OFFSET"))
0504             return propertyMap["CCD_OFFSET"].value("OFFSET", -1).toDouble();
0505         else if (getActiveCamera()->getProperty("CCD_CONTROLS"))
0506             return propertyMap["CCD_CONTROLS"].value("Offset", -1).toDouble();
0507     }
0508     else
0509     {
0510         // if camera is unknown, use the custom property that is set
0511         if (propertyMap.keys().contains("CCD_OFFSET"))
0512             return propertyMap["CCD_OFFSET"].value("OFFSET", -1).toDouble();
0513         else if(propertyMap.keys().contains("CCD_CONTROLS"))
0514             return propertyMap["CCD_CONTROLS"].value("Offset", -1).toDouble();
0515     }
0516     return -1;
0517 }
0518 
0519 double CaptureDeviceAdaptor::cameraOffset()
0520 {
0521     double value = INVALID_VALUE;
0522     if (getActiveCamera() != nullptr)
0523         getActiveCamera()->getOffset(&value);
0524 
0525     return value;
0526 }
0527 
0528 double CaptureDeviceAdaptor::cameraTemperature()
0529 {
0530     double value = INVALID_VALUE;
0531     if (getActiveCamera() != nullptr)
0532         getActiveCamera()->getTemperature(&value);
0533 
0534     return value;
0535 }
0536 
0537 void CaptureDeviceAdaptor::setFilterPosition(int targetFilterPosition, FilterManager::FilterPolicy policy)
0538 {
0539     if (m_FilterManager.isNull() == false && m_ActiveFilterWheel != nullptr)
0540         m_FilterManager->setFilterPosition(targetFilterPosition, policy);
0541 }
0542 
0543 
0544 
0545 
0546 
0547 void CaptureDeviceAdaptor::setFilterManager(QSharedPointer<FilterManager> device)
0548 {
0549     // avoid doubled definition
0550     if (m_FilterManager == device)
0551         return;
0552 
0553     // disconnect old filter manager
0554     if (m_FilterManager.isNull() == false)
0555     {
0556         disconnect(m_FilterManager.get(), &FilterManager::ready, this, &CaptureDeviceAdaptor::updateFilterPosition);
0557         disconnectFilterManager(currentSequenceJobState.data());
0558     }
0559     //connect new filter manager
0560     if (device.isNull() == false)
0561     {
0562         connect(device.get(), &FilterManager::ready, this, &CaptureDeviceAdaptor::updateFilterPosition);
0563         connectFilterManager(currentSequenceJobState.data());
0564     }
0565 
0566     m_FilterManager = device;
0567 }
0568 
0569 void CaptureDeviceAdaptor::askManualScopeCover(QString question, QString title, bool light)
0570 {
0571     // do not ask again
0572     if (light && m_ManualLightCoveringAsked == true)
0573     {
0574         emit manualScopeCoverUpdated(true, true, true);
0575         return;
0576     }
0577     else if (!light && m_ManualDarkCoveringAsked == true)
0578     {
0579         emit manualScopeCoverUpdated(true, true, false);
0580         return;
0581     }
0582 
0583     // Continue
0584     connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this, light]()
0585     {
0586         emit manualScopeCoverUpdated(true, true, light);
0587         KSMessageBox::Instance()->disconnect(this);
0588         m_ManualLightCoveringAsked = false;
0589         m_ManualLightOpeningAsked = false;
0590         m_ManualDarkCoveringAsked = false;
0591         m_ManualDarkOpeningAsked = false;
0592         if (light)
0593             m_ManualLightCoveringAsked = true;
0594         else
0595             m_ManualDarkCoveringAsked = true;
0596     });
0597 
0598     // Cancel
0599     connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this, light]()
0600     {
0601         if (light)
0602             m_ManualLightCoveringAsked = false;
0603         else
0604             m_ManualDarkCoveringAsked = false;
0605 
0606         emit manualScopeCoverUpdated(true, false, light);
0607         KSMessageBox::Instance()->disconnect(this);
0608     });
0609 
0610     KSMessageBox::Instance()->warningContinueCancel(question, title, Options::manualCoverTimeout());
0611 
0612 }
0613 
0614 void CaptureDeviceAdaptor::askManualScopeOpen(bool light)
0615 {
0616     // do not ask again
0617     if (light && m_ManualLightOpeningAsked == true)
0618     {
0619         emit manualScopeCoverUpdated(false, true, true);
0620         return;
0621     }
0622     else if (!light && m_ManualDarkOpeningAsked == true)
0623     {
0624         emit manualScopeCoverUpdated(false, true, false);
0625         return;
0626     }
0627 
0628     // Continue
0629     connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this, light]()
0630     {
0631         m_ManualLightCoveringAsked = false;
0632         m_ManualLightOpeningAsked = false;
0633         m_ManualDarkCoveringAsked = false;
0634         m_ManualDarkOpeningAsked = false;
0635 
0636         if (light)
0637             m_ManualLightOpeningAsked = true;
0638         else
0639             m_ManualDarkOpeningAsked = true;
0640 
0641         emit manualScopeCoverUpdated(false, true, light);
0642         KSMessageBox::Instance()->disconnect(this);
0643     });
0644 
0645     // Cancel
0646     connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this, light]()
0647     {
0648         if (light)
0649             m_ManualLightOpeningAsked = false;
0650         else
0651             m_ManualDarkOpeningAsked = false;
0652         emit manualScopeCoverUpdated(false, false, light);
0653         KSMessageBox::Instance()->disconnect(this);
0654     });
0655 
0656     KSMessageBox::Instance()->warningContinueCancel(i18n("Remove cover from the telescope in order to continue."),
0657             i18n("Telescope Covered"), Options::manualCoverTimeout());
0658 
0659 }
0660 
0661 void CaptureDeviceAdaptor::setLightBoxLight(bool on)
0662 {
0663     m_ActiveLightBox->setLightEnabled(on);
0664     emit lightBoxLight(on);
0665 }
0666 
0667 void CaptureDeviceAdaptor::parkDustCap(bool park)
0668 {
0669     // park
0670     if (park == true)
0671         if (m_ActiveDustCap->park())
0672             emit dustCapStatusChanged(ISD::DustCap::CAP_PARKING);
0673         else
0674             emit dustCapStatusChanged(ISD::DustCap::CAP_ERROR);
0675     // unpark
0676     else if (m_ActiveDustCap->unpark())
0677         emit dustCapStatusChanged(ISD::DustCap::CAP_UNPARKING);
0678     else
0679         emit dustCapStatusChanged(ISD::DustCap::CAP_ERROR);
0680 }
0681 
0682 void CaptureDeviceAdaptor::slewTelescope(SkyPoint &target)
0683 {
0684     if (m_ActiveMount != nullptr)
0685     {
0686         m_ActiveMount->Slew(&target);
0687         emit scopeStatusChanged(ISD::Mount::MOUNT_SLEWING);
0688     }
0689 }
0690 
0691 void CaptureDeviceAdaptor::setScopeTracking(bool on)
0692 {
0693     if (m_ActiveMount != nullptr)
0694     {
0695         m_ActiveMount->setTrackEnabled(on);
0696         emit scopeStatusChanged(on ? ISD::Mount::MOUNT_TRACKING : ISD::Mount::MOUNT_IDLE);
0697     }
0698 }
0699 
0700 void CaptureDeviceAdaptor::setScopeParked(bool parked)
0701 {
0702     if (m_ActiveMount != nullptr)
0703     {
0704         if (parked == true)
0705         {
0706             if (m_ActiveMount->park())
0707                 emit scopeStatusChanged(ISD::Mount::MOUNT_PARKING);
0708             else
0709                 emit scopeStatusChanged(ISD::Mount::MOUNT_ERROR);
0710         }
0711         else
0712         {
0713             if (m_ActiveMount->unpark() == false)
0714                 emit scopeStatusChanged(ISD::Mount::MOUNT_ERROR);
0715         }
0716     }
0717 }
0718 
0719 void CaptureDeviceAdaptor::setDomeParked(bool parked)
0720 {
0721     if (m_ActiveDome != nullptr)
0722     {
0723         if (parked == true)
0724         {
0725             if (m_ActiveDome->park())
0726                 emit domeStatusChanged(ISD::Dome::DOME_PARKING);
0727             else
0728                 emit domeStatusChanged(ISD::Dome::DOME_ERROR);
0729         }
0730         else
0731         {
0732             if (m_ActiveDome->unpark() == false)
0733                 emit domeStatusChanged(ISD::Dome::DOME_ERROR);
0734         }
0735     }
0736 
0737 }
0738 
0739 void CaptureDeviceAdaptor::flatSyncFocus(int targetFilterID)
0740 {
0741     if (getFilterManager()->syncAbsoluteFocusPosition(targetFilterID - 1))
0742         emit flatSyncFocusChanged(true);
0743     else
0744         emit flatSyncFocusChanged(false);
0745 }
0746 
0747 void CaptureDeviceAdaptor::queryHasShutter()
0748 {
0749     if (m_ActiveCamera == nullptr)
0750     {
0751         emit hasShutter(false);
0752         return;
0753     }
0754     QStringList shutterfulCCDs  = Options::shutterfulCCDs();
0755     QStringList shutterlessCCDs = Options::shutterlessCCDs();
0756     QString deviceName = m_ActiveCamera->getDeviceName();
0757 
0758     bool shutterFound   = shutterfulCCDs.contains(deviceName);
0759     // FIXME: what about || (captureISOS && captureISOS->count() > 0?
0760     bool noShutterFound = shutterlessCCDs.contains(deviceName);
0761 
0762     if (shutterFound == true)
0763         emit hasShutter(true);
0764     else if (noShutterFound == true)
0765         emit hasShutter(false);
0766     else
0767     {
0768         // If we have no information, we ask before we proceed.
0769         QString deviceName = m_ActiveCamera->getDeviceName();
0770         // Yes, has shutter
0771         connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this]()
0772         {
0773             KSMessageBox::Instance()->disconnect(this);
0774             QStringList shutterfulCCDs  = Options::shutterfulCCDs();
0775             shutterfulCCDs.append(m_ActiveCamera->getDeviceName());
0776             Options::setShutterfulCCDs(shutterfulCCDs);
0777             emit hasShutter(true);
0778         });
0779         // No, has no shutter
0780         connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this]()
0781         {
0782             KSMessageBox::Instance()->disconnect(this);
0783             QStringList shutterlessCCDs = Options::shutterlessCCDs();
0784             shutterlessCCDs.append(m_ActiveCamera->getDeviceName());
0785             Options::setShutterlessCCDs(shutterlessCCDs);
0786             emit hasShutter(false);
0787         });
0788 
0789         KSMessageBox::Instance()->questionYesNo(i18n("Does %1 have a shutter?", deviceName),
0790                                                 i18n("Dark Exposure"));
0791     }
0792 }
0793 
0794 } // namespace