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 newLog(
i18n(
"Unparking mount..."));
508 emit setScopeParked(
false);
510 case ISD::PARK_UNKNOWN:
512 emit readCurrentMountParkState();
514 case ISD::PARK_UNPARKED:
515 wpScopeStatus = WP_UNPARKED;
516 emit newLog(
i18n(
"Mount unparked."));
518 checkWallPositionReady(frametype);
523 else if (wpScopeStatus < WP_SLEWING)
525 wallCoord.HorizontalToEquatorial(KStarsData::Instance()->lst(),
526 KStarsData::Instance()->
geo()->lat());
527 wpScopeStatus = WP_SLEWING;
528 emit slewTelescope(wallCoord);
529 emit newLog(
i18n(
"Mount slewing to wall position (az =%1 alt =%2)",
530 wallCoord.az().toDMSString(), wallCoord.alt().toDMSString()));
534 else if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
537 else if (wpScopeStatus == WP_SLEW_COMPLETED)
539 wpScopeStatus = WP_TRACKING_BUSY;
540 emit setScopeTracking(
false);
541 emit newLog(
i18n(
"Slew to wall position complete, stop tracking."));
544 else if (wpScopeStatus == WP_TRACKING_OFF)
545 emit newLog(
i18n(
"Slew to wall position complete, tracking stopped."));
548 bool captureFlats = (frametype == FRAME_FLAT);
549 LightState targetLightState = (captureFlats ? CAP_LIGHT_ON :
552 if (m_CameraState->hasLightBox ==
true)
554 if (m_CameraState->getLightBoxLightState() != targetLightState)
556 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
557 emit setLightBoxLight(captureFlats);
558 emit newLog(captureFlats ?
i18n(
"Turn light box light on...") :
i18n(
"Turn light box light off..."));
567IPState SequenceJobState::checkPreMountParkReady()
569 if (m_CameraState->hasTelescope)
571 switch (m_CameraState->getScopeParkState())
573 case ISD::PARK_PARKED:
575 case ISD::PARK_ERROR:
576 emit newLog(
i18n(
"Parking mount failed, aborting..."));
579 case ISD::PARK_PARKING:
581 case ISD::PARK_UNPARKED:
582 case ISD::PARK_UNPARKING:
584 emit setScopeParked(
true);
585 emit newLog(
i18n(
"Parking mount prior to calibration frames capture..."));
587 case ISD::PARK_UNKNOWN:
589 emit readCurrentMountParkState();
598IPState SequenceJobState::checkPreDomeParkReady()
600 if (m_CameraState->hasDome)
602 if (m_CameraState->getDomeState() == ISD::Dome::DOME_ERROR)
604 emit newLog(
i18n(
"Parking dome failed, aborting..."));
608 else if (m_CameraState->getDomeState() == ISD::Dome::DOME_PARKING)
610 else if (m_CameraState->getDomeState() != ISD::Dome::DOME_PARKED)
612 m_CameraState->setDomeState(ISD::Dome::DOME_PARKING);
613 emit setDomeParked(
true);
614 emit newLog(
i18n(
"Parking dome prior to calibration frames capture..."));
622IPState SequenceJobState::checkFlatSyncFocus()
625 if (flatSyncStatus == FS_BUSY)
627 m_FlatSyncCheck.start();
631 if (m_frameType == FRAME_FLAT && Options::flatSyncFocus() && flatSyncStatus != FS_COMPLETED)
633 flatSyncStatus = FS_BUSY;
634 emit flatSyncFocus(targetFilterID);
641IPState SequenceJobState::checkHasShutter()
643 if (m_CameraState->shutterStatus == SHUTTER_BUSY)
645 if (m_CameraState->shutterStatus != SHUTTER_UNKNOWN)
648 m_CameraState->shutterStatus = SHUTTER_BUSY;
649 emit queryHasShutter();
653IPState SequenceJobState::checkLightFrameScopeCoverOpen()
656 if (m_CameraState->hasLightBox && m_CameraState->getLightBoxLightState() != CAP_LIGHT_OFF)
658 if (m_CameraState->getLightBoxLightState() != CAP_LIGHT_BUSY)
660 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
661 emit setLightBoxLight(
false);
662 emit newLog(
i18n(
"Turn light box light off..."));
668 if (m_CameraState->hasDustCap)
670 if (m_CameraState->getDustCapState() != CAP_IDLE)
672 if (m_CameraState->getDustCapState() != CAP_UNPARKING)
674 m_CameraState->setDustCapState(CAP_UNPARKING);
675 emit parkDustCap(
false);
676 emit newLog(
i18n(
"Unparking dust cap..."));
686 if (m_CameraState->m_ManualCoverState != CameraState::MANAUL_COVER_OPEN)
691 if (coverQueryState == CAL_CHECK_CONFIRMATION)
694 emit askManualScopeOpen(m_CameraState->m_ManualCoverState == CameraState::MANUAL_COVER_CLOSED_LIGHT);
703bool SequenceJobState::isInitialized(CaptureWorkflowActionType action)
705 return m_CameraState.data()->isInitialized[action];
708void SequenceJobState::setInitialized(CaptureWorkflowActionType action,
bool init)
710 m_CameraState.data()->isInitialized[action] =
init;
713void SequenceJobState::setCurrentFilterID(
int value)
716 if (preparationCompleted())
719 m_CameraState->currentFilterID = value;
720 if (isInitialized(CAPTURE_ACTION_FILTER) ==
false && value != targetFilterID)
724 prepareActions[CAPTURE_ACTION_FILTER] =
false;
726 emit changeFilterPosition(targetFilterID, m_filterPolicy);
729 setInitialized(CAPTURE_ACTION_FILTER,
true);
731 if (value == targetFilterID)
732 prepareActions[CAPTURE_ACTION_FILTER] =
true;
735 m_PreparationState = PREP_NONE;
736 emit prepareComplete(
false);
740 checkAllActionsReady();
743void SequenceJobState::setCurrentCCDTemperature(
double currentTemperature)
746 if (preparationCompleted())
750 if (ignoreNextValue[CAPTURE_ACTION_TEMPERATURE])
752 ignoreNextValue[CAPTURE_ACTION_TEMPERATURE] =
false;
756 if (isInitialized(CAPTURE_ACTION_TEMPERATURE))
758 if (m_enforceTemperature ==
false
759 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
760 prepareActions[CAPTURE_ACTION_TEMPERATURE] =
true;
762 checkAllActionsReady();
766 setInitialized(CAPTURE_ACTION_TEMPERATURE,
true);
767 if (m_enforceTemperature ==
false
768 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
770 prepareActions[CAPTURE_ACTION_TEMPERATURE] =
true;
771 checkAllActionsReady();
775 prepareTemperatureCheck(m_enforceTemperature);
780void SequenceJobState::setCurrentRotatorPositionAngle(
double rotatorAngle, IPState state)
783 if (preparationCompleted())
786 double currentPositionAngle = RotatorUtils::Instance()->calcCameraAngle(rotatorAngle,
false);
788 if (isInitialized(CAPTURE_ACTION_ROTATOR))
792 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
793 && state != IPS_BUSY)
794 prepareActions[CAPTURE_ACTION_ROTATOR] =
true;
796 checkAllActionsReady();
800 setInitialized(CAPTURE_ACTION_ROTATOR,
true);
801 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
802 && state != IPS_BUSY)
804 prepareActions[CAPTURE_ACTION_ROTATOR] =
true;
805 checkAllActionsReady();
809 prepareRotatorCheck();
814void SequenceJobState::setFocusStatus(FocusState state)
817 if (preparationCompleted())
824 if (prepareActions[CAPTURE_ACTION_AUTOFOCUS] ==
false)
826 prepareActions[CAPTURE_ACTION_AUTOFOCUS] =
true;
827 checkAllActionsReady();
833 emit prepareComplete(
false);
841void SequenceJobState::updateManualScopeCover(
bool closed,
bool success,
bool light)
844 if (preparationCompleted())
851 m_CameraState->m_ManualCoverState = light ? CameraState::MANUAL_COVER_CLOSED_LIGHT :
852 CameraState::MANUAL_COVER_CLOSED_DARK;
854 m_CameraState->m_ManualCoverState = CameraState::MANAUL_COVER_OPEN;
855 coverQueryState = CAL_CHECK_TASK;
857 checkAllActionsReady();
862 m_CameraState->shutterStatus = SHUTTER_UNKNOWN;
863 coverQueryState = CAL_CHECK_TASK;
869void SequenceJobState::lightBoxLight(
bool on)
872 if (preparationCompleted())
875 m_CameraState->setLightBoxLightState(on ? CAP_LIGHT_ON : CAP_LIGHT_OFF);
876 emit newLog(
i18n(on ?
"Light box on." :
"Light box off."));
878 checkAllActionsReady();
881void SequenceJobState::dustCapStateChanged(ISD::DustCap::Status status)
884 if (preparationCompleted())
889 case ISD::DustCap::CAP_ERROR:
898 checkAllActionsReady();
901void SequenceJobState::scopeStatusChanged(ISD::Mount::Status status)
904 if (preparationCompleted())
910 case ISD::Mount::MOUNT_TRACKING:
911 if (wpScopeStatus == WP_SLEWING)
912 wpScopeStatus = WP_SLEW_COMPLETED;
914 case ISD::Mount::MOUNT_IDLE:
915 if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
916 wpScopeStatus = WP_TRACKING_OFF;
918 case ISD::Mount::MOUNT_PARKING:
920 m_CameraState->setScopeParkState(ISD::PARK_PARKING);
927 checkAllActionsReady();
930void SequenceJobState::scopeParkStatusChanged(ISD::ParkStatus)
933 checkAllActionsReady();
936void SequenceJobState::domeStatusChanged(ISD::Dome::Status)
939 checkAllActionsReady();
942void SequenceJobState::flatSyncFocusChanged(
bool completed)
945 if (preparationCompleted())
948 flatSyncStatus = (completed ? FS_COMPLETED : FS_BUSY);
950 checkAllActionsReady();
953void SequenceJobState::hasShutter(
bool present)
956 if (preparationCompleted())
960 m_CameraState->shutterStatus = SHUTTER_YES;
962 m_CameraState->shutterStatus = SHUTTER_NO;
965 checkAllActionsReady();
968SequenceJobState::PreparationState SequenceJobState::getPreparationState()
const
970 return m_PreparationState;
973void SequenceJobState::setFilterStatus(FilterState filterState)
976 if (preparationCompleted())
981 case FILTER_AUTOFOCUS:
983 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
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
GeoCoordinates geo(const QVariant &location)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)