7#include "sequencejobstate.h"
10#include "kstarsdata.h"
12#include "ekos/auxiliary/rotatorutils.h"
16SequenceJobState::SequenceJobState(
const QSharedPointer<CameraState> &sharedState)
18 m_CameraState = sharedState;
19 m_FlatSyncCheck.setSingleShot(
true);
20 m_FlatSyncCheck.setInterval(1000);
21 m_FlatSyncCheck.callOnTimeout(
this, [
this]()
23 emit flatSyncFocus(targetFilterID);
27 m_CaptureOperationsTimer.setSingleShot(
false);
28 m_CaptureOperationsTimer.setInterval(Options::captureOperationsTimeout() * 1000);
32 if (m_CameraState->isCapturePausing() || m_PreparationState == PREP_COMPLETED || m_PreparationState == PREP_NONE)
34 m_CaptureOperationsTimer.stop();
39 if (!preparationCompleted())
41 emit newLog(
i18n(
"Capture operations timed out after %1 seconds.", Options::captureOperationsTimeout()));
42 m_CaptureOperationsTimer.stop();
43 emit prepareComplete(
false);
48void SequenceJobState::setFrameType(CCDFrameType frameType)
51 m_frameType = frameType;
53 m_PreparationState = PREP_NONE;
56void SequenceJobState::initPreparation(
bool isPreview)
59 m_isPreview = isPreview;
60 wpScopeStatus = WP_NONE;
61 m_CaptureOperationsTimer.start();
64void SequenceJobState::prepareLightFrameCapture(
bool enforceCCDTemp,
bool isPreview)
67 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
71 initPreparation(isPreview);
77 emit setCCDBatchMode(!isPreview);
80 prepareTemperatureCheck(enforceCCDTemp);
83 prepareRotatorCheck();
88 m_PreparationState = PREP_BUSY;
90 checkAllActionsReady();
93void SequenceJobState::prepareFlatFrameCapture(
bool enforceCCDTemp,
bool isPreview)
96 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
100 initPreparation(isPreview);
103 setAllActionsReady();
106 emit setCCDBatchMode(!isPreview);
109 prepareTemperatureCheck(enforceCCDTemp);
112 m_PreparationState = PREP_BUSY;
114 checkAllActionsReady();
117void SequenceJobState::prepareDarkFrameCapture(
bool enforceCCDTemp,
bool isPreview)
120 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
124 initPreparation(isPreview);
127 setAllActionsReady();
130 emit setCCDBatchMode(!isPreview);
133 prepareTemperatureCheck(enforceCCDTemp);
136 m_PreparationState = PREP_BUSY;
138 checkAllActionsReady();
141void SequenceJobState::prepareBiasFrameCapture(
bool enforceCCDTemp,
bool isPreview)
143 prepareDarkFrameCapture(enforceCCDTemp, isPreview);
146bool SequenceJobState::initCapture(CCDFrameType frameType,
bool isPreview,
bool isAutofocusReady, FITSMode mode)
148 m_PreparationState = PREP_INIT_CAPTURE;
149 autoFocusReady = isAutofocusReady;
151 m_CaptureOperationsTimer.start();
154 prepareTargetFilter(frameType, isPreview);
155 checkAllActionsReady();
157 return areActionsReady();
160bool SequenceJobState::areActionsReady()
162 for (
bool &ready : prepareActions.values())
171void SequenceJobState::checkAllActionsReady()
174 if (preparationCompleted())
176 m_CaptureOperationsTimer.stop();
180 switch (m_PreparationState)
187 if (areActionsReady())
190 if (checkLightFrameScopeCoverOpen() != IPS_OK)
193 m_PreparationState = PREP_COMPLETED;
194 emit prepareComplete();
198 if (!areActionsReady())
202 if (checkFlatsCoverReady() != IPS_OK)
209 if (checkFlatSyncFocus() != IPS_OK)
213 if (m_PreparationState == PREP_BUSY)
215 m_PreparationState = PREP_COMPLETED;
216 emit prepareComplete();
222 if (!areActionsReady())
226 if (checkDarksCoverReady() != IPS_OK)
230 if (m_PreparationState == PREP_BUSY)
232 m_PreparationState = PREP_COMPLETED;
233 emit prepareComplete();
238 emit prepareComplete();
244 case PREP_INIT_CAPTURE:
245 if (areActionsReady())
248 m_PreparationState = PREP_NONE;
249 emit initCaptureComplete(m_fitsMode);
260void SequenceJobState::setAllActionsReady()
262 QMutableMapIterator<CaptureWorkflowActionType, bool> it(prepareActions);
270 for (CaptureWorkflowActionType action :
272 CAPTURE_ACTION_FILTER, CAPTURE_ACTION_ROTATOR, CAPTURE_ACTION_TEMPERATURE
274 setInitialized(action,
false);
277void SequenceJobState::prepareTargetFilter(CCDFrameType frameType,
bool isPreview)
279 if (targetFilterID != INVALID_VALUE)
281 if (isInitialized(CAPTURE_ACTION_FILTER) ==
false)
283 prepareActions[CAPTURE_ACTION_FILTER] =
false;
286 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady ==
false)
287 m_filterPolicy =
static_cast<FilterManager::FilterPolicy
>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY);
289 emit readFilterPosition();
291 else if (targetFilterID != m_CameraState->currentFilterID)
294 prepareActions[CAPTURE_ACTION_FILTER] =
false;
297 m_filterPolicy = FilterManager::ALL_POLICIES;
300 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady ==
false)
301 m_filterPolicy =
static_cast<FilterManager::FilterPolicy
>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY);
303 emit changeFilterPosition(targetFilterID, m_filterPolicy);
309void SequenceJobState::prepareTemperatureCheck(
bool enforceCCDTemp)
312 m_enforceTemperature = enforceCCDTemp;
314 if (m_enforceTemperature)
316 prepareActions[CAPTURE_ACTION_TEMPERATURE] =
false;
317 if (isInitialized(CAPTURE_ACTION_TEMPERATURE))
321 ignoreNextValue[CAPTURE_ACTION_TEMPERATURE] =
true;
323 emit setCCDTemperature(targetTemperature);
333void SequenceJobState::prepareRotatorCheck()
335 if (targetPositionAngle > Ekos::INVALID_VALUE)
337 if (isInitialized(CAPTURE_ACTION_ROTATOR))
339 prepareActions[CAPTURE_ACTION_ROTATOR] =
false;
340 double rawAngle = RotatorUtils::Instance()->calcRotatorAngle(targetPositionAngle);
342 emit setRotatorAngle(rawAngle);
350IPState SequenceJobState::checkCalibrationPreActionsReady()
352 IPState result = IPS_OK;
354 if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
355 result = checkWallPositionReady(FRAME_FLAT);
357 if (result != IPS_OK)
360 if (m_CalibrationPreAction & CAPTURE_PREACTION_PARK_MOUNT)
361 result = checkPreMountParkReady();
363 if (result != IPS_OK)
366 if (m_CalibrationPreAction & CAPTURE_PREACTION_PARK_DOME)
367 result = checkPreDomeParkReady();
372IPState SequenceJobState::checkFlatsCoverReady()
374 auto result = checkCalibrationPreActionsReady();
375 if (result == IPS_OK)
377 if (m_CameraState->hasDustCap && m_CameraState->hasLightBox)
378 return checkDustCapReady(FRAME_FLAT);
380 else if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
385 if (m_CameraState->hasLightBox)
386 return checkDustCapReady(FRAME_FLAT);
388 return checkManualCoverReady(
true);
395IPState SequenceJobState::checkDarksCoverReady()
397 IPState result = checkCalibrationPreActionsReady();;
399 if (result == IPS_OK)
402 result = checkHasShutter();
403 if (result != IPS_OK)
406 if (m_CameraState->hasDustCap)
407 return checkDustCapReady(FRAME_DARK);
409 else if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
412 return checkManualCoverReady(
false);
417IPState SequenceJobState::checkManualCoverReady(
bool lightSourceRequired)
420 if (lightSourceRequired && m_CameraState->m_ManualCoverState != CameraState::MANUAL_COVER_CLOSED_LIGHT)
422 if (coverQueryState == CAL_CHECK_CONFIRMATION)
426 emit askManualScopeCover(
i18n(
"Cover the telescope with an evenly illuminated light source."),
427 i18n(
"Flat Frame"),
true);
428 coverQueryState = CAL_CHECK_CONFIRMATION;
432 else if (!lightSourceRequired && m_CameraState->m_ManualCoverState != CameraState::MANUAL_COVER_CLOSED_DARK &&
433 m_CameraState->shutterStatus == SHUTTER_NO)
435 if (coverQueryState == CAL_CHECK_CONFIRMATION)
438 emit askManualScopeCover(
i18n(
"Cover the telescope in order to take a dark exposure."),
439 i18n(
"Dark Exposure"),
false);
441 coverQueryState = CAL_CHECK_CONFIRMATION;
448IPState SequenceJobState::checkDustCapReady(CCDFrameType frameType)
451 if (m_CameraState->getLightBoxLightState() == CAP_LIGHT_BUSY ||
452 m_CameraState->getDustCapState() == CAP_PARKING ||
453 m_CameraState->getDustCapState() == CAP_UNPARKING)
456 if (m_CameraState->getDustCapState() == CAP_ERROR)
459 auto captureLights = (frameType == FRAME_LIGHT);
462 CapState targetCapState = captureLights ? CAP_IDLE : CAP_PARKED;
464 if (m_CameraState->hasDustCap && m_CameraState->getDustCapState() != targetCapState)
466 m_CameraState->setDustCapState(captureLights ? CAP_UNPARKING : CAP_PARKING);
467 emit parkDustCap(!captureLights);
468 emit newLog(captureLights ?
i18n(
"Unparking dust cap...") :
i18n(
"Parking dust cap..."));
472 auto captureFlats = (frameType == FRAME_FLAT);
473 LightState targetLightBoxStatus = captureFlats ? CAP_LIGHT_ON :
476 if (m_CameraState->hasLightBox && m_CameraState->getLightBoxLightState() != targetLightBoxStatus)
478 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
479 emit setLightBoxLight(captureFlats);
480 emit newLog(captureFlats ?
i18n(
"Turn light box light on...") :
i18n(
"Turn light box light off..."));
488IPState SequenceJobState::checkWallPositionReady(CCDFrameType frametype)
490 if (m_CameraState->hasTelescope)
493 if (wpScopeStatus < WP_UNPARKED)
495 switch (m_CameraState->getScopeParkState())
497 case ISD::PARK_ERROR:
498 emit newLog(
i18n(
"Parking mount failed, aborting..."));
501 case ISD::PARK_UNPARKING:
502 case ISD::PARK_PARKING:
504 case ISD::PARK_PARKED:
506 wpScopeStatus = WP_UNPARKING;
507 emit setScopeParked(
false);
509 case ISD::PARK_UNKNOWN:
511 emit readCurrentMountParkState();
513 case ISD::PARK_UNPARKED:
514 wpScopeStatus = WP_UNPARKED;
519 else if (wpScopeStatus < WP_SLEWING)
521 wallCoord.HorizontalToEquatorial(KStarsData::Instance()->lst(),
522 KStarsData::Instance()->
geo()->lat());
523 wpScopeStatus = WP_SLEWING;
524 emit slewTelescope(wallCoord);
525 emit newLog(
i18n(
"Mount slewing to wall position (az =%1 alt =%2)",
526 wallCoord.az().toDMSString(), wallCoord.alt().toDMSString()));
530 else if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
533 else if (wpScopeStatus == WP_SLEW_COMPLETED)
535 wpScopeStatus = WP_TRACKING_BUSY;
536 emit setScopeTracking(
false);
537 emit newLog(
i18n(
"Slew to wall position complete, stop tracking."));
540 else if (wpScopeStatus == WP_TRACKING_OFF)
541 emit newLog(
i18n(
"Slew to wall position complete, tracking stopped."));
544 bool captureFlats = (frametype == FRAME_FLAT);
545 LightState targetLightState = (captureFlats ? CAP_LIGHT_ON :
548 if (m_CameraState->hasLightBox ==
true)
550 if (m_CameraState->getLightBoxLightState() != targetLightState)
552 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
553 emit setLightBoxLight(captureFlats);
554 emit newLog(captureFlats ?
i18n(
"Turn light box light on...") :
i18n(
"Turn light box light off..."));
563IPState SequenceJobState::checkPreMountParkReady()
565 if (m_CameraState->hasTelescope)
567 switch (m_CameraState->getScopeParkState())
569 case ISD::PARK_PARKED:
571 case ISD::PARK_ERROR:
572 emit newLog(
i18n(
"Parking mount failed, aborting..."));
575 case ISD::PARK_PARKING:
577 case ISD::PARK_UNPARKED:
578 case ISD::PARK_UNPARKING:
580 emit setScopeParked(
true);
581 emit newLog(
i18n(
"Parking mount prior to calibration frames capture..."));
583 case ISD::PARK_UNKNOWN:
585 emit readCurrentMountParkState();
594IPState SequenceJobState::checkPreDomeParkReady()
596 if (m_CameraState->hasDome)
598 if (m_CameraState->getDomeState() == ISD::Dome::DOME_ERROR)
600 emit newLog(
i18n(
"Parking dome failed, aborting..."));
604 else if (m_CameraState->getDomeState() == ISD::Dome::DOME_PARKING)
606 else if (m_CameraState->getDomeState() != ISD::Dome::DOME_PARKED)
608 m_CameraState->setDomeState(ISD::Dome::DOME_PARKING);
609 emit setDomeParked(
true);
610 emit newLog(
i18n(
"Parking dome prior to calibration frames capture..."));
618IPState SequenceJobState::checkFlatSyncFocus()
621 if (flatSyncStatus == FS_BUSY)
623 m_FlatSyncCheck.start();
627 if (m_frameType == FRAME_FLAT && Options::flatSyncFocus() && flatSyncStatus != FS_COMPLETED)
629 flatSyncStatus = FS_BUSY;
630 emit flatSyncFocus(targetFilterID);
637IPState SequenceJobState::checkHasShutter()
639 if (m_CameraState->shutterStatus == SHUTTER_BUSY)
641 if (m_CameraState->shutterStatus != SHUTTER_UNKNOWN)
644 m_CameraState->shutterStatus = SHUTTER_BUSY;
645 emit queryHasShutter();
649IPState SequenceJobState::checkLightFrameScopeCoverOpen()
652 if (m_CameraState->hasLightBox && m_CameraState->getLightBoxLightState() != CAP_LIGHT_OFF)
654 if (m_CameraState->getLightBoxLightState() != CAP_LIGHT_BUSY)
656 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
657 emit setLightBoxLight(
false);
658 emit newLog(
i18n(
"Turn light box light off..."));
664 if (m_CameraState->hasDustCap)
666 if (m_CameraState->getDustCapState() != CAP_IDLE)
668 if (m_CameraState->getDustCapState() != CAP_UNPARKING)
670 m_CameraState->setDustCapState(CAP_UNPARKING);
671 emit parkDustCap(
false);
672 emit newLog(
i18n(
"Unparking dust cap..."));
682 if (m_CameraState->m_ManualCoverState != CameraState::MANAUL_COVER_OPEN)
687 if (coverQueryState == CAL_CHECK_CONFIRMATION)
690 emit askManualScopeOpen(m_CameraState->m_ManualCoverState == CameraState::MANUAL_COVER_CLOSED_LIGHT);
699bool SequenceJobState::isInitialized(CaptureWorkflowActionType action)
701 return m_CameraState.data()->isInitialized[action];
704void SequenceJobState::setInitialized(CaptureWorkflowActionType action,
bool init)
706 m_CameraState.data()->isInitialized[action] =
init;
709void SequenceJobState::setCurrentFilterID(
int value)
712 if (preparationCompleted())
715 m_CameraState->currentFilterID = value;
716 if (isInitialized(CAPTURE_ACTION_FILTER) ==
false && value != targetFilterID)
720 prepareActions[CAPTURE_ACTION_FILTER] =
false;
722 emit changeFilterPosition(targetFilterID, m_filterPolicy);
725 setInitialized(CAPTURE_ACTION_FILTER,
true);
727 if (value == targetFilterID)
728 prepareActions[CAPTURE_ACTION_FILTER] =
true;
731 m_PreparationState = PREP_NONE;
732 emit prepareComplete(
false);
736 checkAllActionsReady();
739void SequenceJobState::setCurrentCCDTemperature(
double currentTemperature)
742 if (preparationCompleted())
746 if (ignoreNextValue[CAPTURE_ACTION_TEMPERATURE])
748 ignoreNextValue[CAPTURE_ACTION_TEMPERATURE] =
false;
752 if (isInitialized(CAPTURE_ACTION_TEMPERATURE))
754 if (m_enforceTemperature ==
false
755 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
756 prepareActions[CAPTURE_ACTION_TEMPERATURE] =
true;
758 checkAllActionsReady();
762 setInitialized(CAPTURE_ACTION_TEMPERATURE,
true);
763 if (m_enforceTemperature ==
false
764 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
766 prepareActions[CAPTURE_ACTION_TEMPERATURE] =
true;
767 checkAllActionsReady();
771 prepareTemperatureCheck(m_enforceTemperature);
776void SequenceJobState::setCurrentRotatorPositionAngle(
double rotatorAngle, IPState state)
779 if (preparationCompleted())
782 double currentPositionAngle = RotatorUtils::Instance()->calcCameraAngle(rotatorAngle,
false);
784 if (isInitialized(CAPTURE_ACTION_ROTATOR))
788 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
789 && state != IPS_BUSY)
790 prepareActions[CAPTURE_ACTION_ROTATOR] =
true;
792 checkAllActionsReady();
796 setInitialized(CAPTURE_ACTION_ROTATOR,
true);
797 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
798 && state != IPS_BUSY)
800 prepareActions[CAPTURE_ACTION_ROTATOR] =
true;
801 checkAllActionsReady();
805 prepareRotatorCheck();
810void SequenceJobState::setFocusStatus(FocusState state)
813 if (preparationCompleted())
820 if (prepareActions[CAPTURE_ACTION_AUTOFOCUS] ==
false)
822 prepareActions[CAPTURE_ACTION_AUTOFOCUS] =
true;
823 checkAllActionsReady();
829 emit prepareComplete(
false);
837void SequenceJobState::updateManualScopeCover(
bool closed,
bool success,
bool light)
840 if (preparationCompleted())
847 m_CameraState->m_ManualCoverState = light ? CameraState::MANUAL_COVER_CLOSED_LIGHT :
848 CameraState::MANUAL_COVER_CLOSED_DARK;
850 m_CameraState->m_ManualCoverState = CameraState::MANAUL_COVER_OPEN;
851 coverQueryState = CAL_CHECK_TASK;
853 checkAllActionsReady();
858 m_CameraState->shutterStatus = SHUTTER_UNKNOWN;
859 coverQueryState = CAL_CHECK_TASK;
865void SequenceJobState::lightBoxLight(
bool on)
868 if (preparationCompleted())
871 m_CameraState->setLightBoxLightState(on ? CAP_LIGHT_ON : CAP_LIGHT_OFF);
872 emit newLog(
i18n(on ?
"Light box on." :
"Light box off."));
874 checkAllActionsReady();
877void SequenceJobState::dustCapStateChanged(ISD::DustCap::Status status)
880 if (preparationCompleted())
885 case ISD::DustCap::CAP_ERROR:
894 checkAllActionsReady();
897void SequenceJobState::scopeStatusChanged(ISD::Mount::Status status)
900 if (preparationCompleted())
906 case ISD::Mount::MOUNT_TRACKING:
907 if (wpScopeStatus == WP_SLEWING)
908 wpScopeStatus = WP_SLEW_COMPLETED;
910 case ISD::Mount::MOUNT_IDLE:
911 if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
912 wpScopeStatus = WP_TRACKING_OFF;
914 case ISD::Mount::MOUNT_PARKING:
916 m_CameraState->setScopeParkState(ISD::PARK_PARKING);
923 checkAllActionsReady();
926void SequenceJobState::scopeParkStatusChanged(ISD::ParkStatus)
929 checkAllActionsReady();
932void SequenceJobState::domeStatusChanged(ISD::Dome::Status)
935 checkAllActionsReady();
938void SequenceJobState::flatSyncFocusChanged(
bool completed)
941 if (preparationCompleted())
944 flatSyncStatus = (completed ? FS_COMPLETED : FS_BUSY);
946 checkAllActionsReady();
949void SequenceJobState::hasShutter(
bool present)
952 if (preparationCompleted())
956 m_CameraState->shutterStatus = SHUTTER_YES;
958 m_CameraState->shutterStatus = SHUTTER_NO;
961 checkAllActionsReady();
964SequenceJobState::PreparationState SequenceJobState::getPreparationState()
const
966 return m_PreparationState;
969void SequenceJobState::setFilterStatus(FilterState filterState)
972 if (preparationCompleted())
977 case FILTER_AUTOFOCUS:
979 prepareActions[CAPTURE_ACTION_AUTOFOCUS] =
false;
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
@ CAPTURE_SETTING_ROTATOR
@ CAPTURE_CHANGING_FILTER
@ CAPTURE_SETTING_TEMPERATURE
GeoCoordinates geo(const QVariant &location)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)