File indexing completed on 2024-04-28 03:43:19
0001 /* Ekos state machine for a single capture job sequence 0002 SPDX-FileCopyrightText: Wolfgang Reissenberger <sterne-jaeger@openfuture.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "sequencejobstate.h" 0008 0009 #include "Options.h" 0010 #include "kstarsdata.h" 0011 #include "indicom.h" 0012 #include "ekos/auxiliary/rotatorutils.h" 0013 0014 namespace Ekos 0015 { 0016 SequenceJobState::SequenceJobState(const QSharedPointer<CaptureModuleState> &sharedState) 0017 { 0018 m_CaptureModuleState = sharedState; 0019 } 0020 0021 void SequenceJobState::setFrameType(CCDFrameType frameType) 0022 { 0023 // set the frame type 0024 m_frameType = frameType; 0025 // reset the preparation state 0026 m_PreparationState = PREP_NONE; 0027 } 0028 0029 void SequenceJobState::initPreparation(bool isPreview) 0030 { 0031 m_status = JOB_BUSY; 0032 m_isPreview = isPreview; 0033 wpScopeStatus = WP_NONE; 0034 } 0035 0036 void SequenceJobState::prepareLightFrameCapture(bool enforceCCDTemp, bool isPreview) 0037 { 0038 // precondition: do not start while already being busy and conditions haven't changed 0039 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature) 0040 return; 0041 0042 // initialize the states 0043 initPreparation(isPreview); 0044 0045 // Reset all prepare actions 0046 setAllActionsReady(); 0047 0048 // disable batch mode for previews 0049 emit setCCDBatchMode(!isPreview); 0050 0051 // Check if we need to update temperature (only skip if the value is initialized and within the limits) 0052 prepareTemperatureCheck(enforceCCDTemp); 0053 0054 // Check if we need to update rotator (only skip if the value is initialized and within the limits) 0055 prepareRotatorCheck(); 0056 0057 // Hint: Filter changes are actually done in SequenceJob::capture(); 0058 0059 // preparation started 0060 m_PreparationState = PREP_BUSY; 0061 // check if the preparations are already completed 0062 checkAllActionsReady(); 0063 } 0064 0065 void SequenceJobState::prepareFlatFrameCapture(bool enforceCCDTemp, bool isPreview) 0066 { 0067 // precondition: do not start while already being busy and conditions haven't changed 0068 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature) 0069 return; 0070 0071 // initialize the states 0072 initPreparation(isPreview); 0073 0074 // Reset all prepare actions 0075 setAllActionsReady(); 0076 0077 // disable batch mode for previews 0078 emit setCCDBatchMode(!isPreview); 0079 0080 // Check if we need to update temperature (only skip if the value is initialized and within the limits) 0081 prepareTemperatureCheck(enforceCCDTemp); 0082 0083 // preparation started 0084 m_PreparationState = PREP_BUSY; 0085 // check if the preparations are already completed 0086 checkAllActionsReady(); 0087 } 0088 0089 void SequenceJobState::prepareDarkFrameCapture(bool enforceCCDTemp, bool isPreview) 0090 { 0091 // precondition: do not start while already being busy and conditions haven't changed 0092 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature) 0093 return; 0094 0095 // initialize the states 0096 initPreparation(isPreview); 0097 0098 // Reset all prepare actions 0099 setAllActionsReady(); 0100 0101 // disable batch mode for previews 0102 emit setCCDBatchMode(!isPreview); 0103 0104 // Check if we need to update temperature (only skip if the value is initialized and within the limits) 0105 prepareTemperatureCheck(enforceCCDTemp); 0106 0107 // preparation started 0108 m_PreparationState = PREP_BUSY; 0109 // check if the preparations are already completed 0110 checkAllActionsReady(); 0111 } 0112 0113 void SequenceJobState::prepareBiasFrameCapture(bool enforceCCDTemp, bool isPreview) 0114 { 0115 prepareDarkFrameCapture(enforceCCDTemp, isPreview); 0116 } 0117 0118 bool SequenceJobState::initCapture(CCDFrameType frameType, bool isPreview, bool isAutofocusReady, FITSMode mode) 0119 { 0120 m_PreparationState = PREP_INIT_CAPTURE; 0121 autoFocusReady = isAutofocusReady; 0122 m_fitsMode = mode; 0123 0124 //check for setting the target filter 0125 prepareTargetFilter(frameType, isPreview); 0126 checkAllActionsReady(); 0127 0128 return areActionsReady(); 0129 } 0130 0131 bool SequenceJobState::areActionsReady() 0132 { 0133 for (bool &ready : prepareActions.values()) 0134 { 0135 if (ready == false) 0136 return false; 0137 } 0138 0139 return true; 0140 } 0141 0142 void SequenceJobState::checkAllActionsReady() 0143 { 0144 switch (m_PreparationState) 0145 { 0146 // capture preparation 0147 case PREP_BUSY: 0148 switch (m_frameType) 0149 { 0150 case FRAME_LIGHT: 0151 if (areActionsReady()) 0152 { 0153 // as last step ensure that the scope is uncovered 0154 if (checkLightFrameScopeCoverOpen() != IPS_OK) 0155 return; 0156 0157 m_PreparationState = PREP_COMPLETED; 0158 emit prepareComplete(); 0159 } 0160 break; 0161 case FRAME_FLAT: 0162 if (!areActionsReady()) 0163 return; 0164 0165 // 1. Check if the selected flats light source is ready 0166 if (checkFlatsCoverReady() != IPS_OK) 0167 return; 0168 0169 // 2. If we used AUTOFOCUS before for a specific frame (e.g. Lum) 0170 // then the absolute focus position for Lum is recorded in the filter manager 0171 // when we take flats again, we always go back to the same focus position as the light frames to ensure 0172 // near identical focus for both frames. 0173 if (checkFlatSyncFocus() != IPS_OK) 0174 return; 0175 0176 // all preparations ready, avoid doubled events 0177 if (m_PreparationState == PREP_BUSY) 0178 { 0179 m_PreparationState = PREP_COMPLETED; 0180 emit prepareComplete(); 0181 } 0182 break; 0183 // darks and bias frames are handled in the same way 0184 case FRAME_DARK: 0185 case FRAME_BIAS: 0186 if (!areActionsReady()) 0187 return; 0188 0189 // 1. check if the scope is covered appropriately 0190 if (checkDarksCoverReady() != IPS_OK) 0191 return; 0192 0193 // 2. avoid doubled events 0194 if (m_PreparationState == PREP_BUSY) 0195 { 0196 m_PreparationState = PREP_COMPLETED; 0197 emit prepareComplete(); 0198 } 0199 break; 0200 default: 0201 // all other cases not refactored yet, preparation immediately completed 0202 emit prepareComplete(); 0203 break; 0204 } 0205 break; 0206 0207 // capture initialization (final preparation steps before starting frame capturing) 0208 case PREP_INIT_CAPTURE: 0209 if (areActionsReady()) 0210 { 0211 // reset the state to avoid double events 0212 m_PreparationState = PREP_NONE; 0213 emit initCaptureComplete(m_fitsMode); 0214 } 0215 break; 0216 0217 case PREP_NONE: 0218 case PREP_COMPLETED: 0219 // in all other cases do nothing 0220 break; 0221 } 0222 } 0223 0224 void SequenceJobState::setAllActionsReady() 0225 { 0226 QMutableMapIterator<CaptureModuleState::PrepareActions, bool> it(prepareActions); 0227 0228 while (it.hasNext()) 0229 { 0230 it.next(); 0231 it.setValue(true); 0232 } 0233 // reset the initialization state 0234 for (CaptureModuleState::PrepareActions action : 0235 { 0236 CaptureModuleState::ACTION_FILTER, CaptureModuleState::ACTION_ROTATOR, CaptureModuleState::ACTION_TEMPERATURE 0237 }) 0238 setInitialized(action, false); 0239 } 0240 0241 void SequenceJobState::prepareTargetFilter(CCDFrameType frameType, bool isPreview) 0242 { 0243 if (targetFilterID != INVALID_VALUE) 0244 { 0245 if (isInitialized(CaptureModuleState::ACTION_FILTER) == false) 0246 { 0247 prepareActions[CaptureModuleState::ACTION_FILTER] = false; 0248 0249 // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet. 0250 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady == false) 0251 m_filterPolicy = static_cast<FilterManager::FilterPolicy>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY); 0252 0253 emit readFilterPosition(); 0254 } 0255 else if (targetFilterID != m_CaptureModuleState->currentFilterID) 0256 { 0257 // mark filter preparation action 0258 prepareActions[CaptureModuleState::ACTION_FILTER] = false; 0259 0260 // determine policy 0261 m_filterPolicy = FilterManager::ALL_POLICIES; 0262 0263 // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet. 0264 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady == false) 0265 m_filterPolicy = static_cast<FilterManager::FilterPolicy>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY); 0266 0267 emit changeFilterPosition(targetFilterID, m_filterPolicy); 0268 emit prepareState(CAPTURE_CHANGING_FILTER); 0269 } 0270 } 0271 } 0272 0273 void SequenceJobState::prepareTemperatureCheck(bool enforceCCDTemp) 0274 { 0275 // turn on CCD temperature enforcing if required 0276 m_enforceTemperature = enforceCCDTemp; 0277 0278 if (m_enforceTemperature) 0279 { 0280 prepareActions[CaptureModuleState::ACTION_TEMPERATURE] = false; 0281 if (isInitialized(CaptureModuleState::ACTION_TEMPERATURE)) 0282 { 0283 // ignore the next value since after setting temperature the next received value will be 0284 // exactly this value no matter what the CCD temperature 0285 ignoreNextValue[CaptureModuleState::ACTION_TEMPERATURE] = true; 0286 // request setting temperature 0287 emit setCCDTemperature(targetTemperature); 0288 emit prepareState(CAPTURE_SETTING_TEMPERATURE); 0289 } 0290 // trigger setting current value first if not initialized 0291 else 0292 emit readCurrentState(CAPTURE_SETTING_TEMPERATURE); 0293 0294 } 0295 } 0296 0297 void SequenceJobState::prepareRotatorCheck() 0298 { 0299 if (targetPositionAngle > Ekos::INVALID_VALUE) 0300 { 0301 if (isInitialized(CaptureModuleState::ACTION_ROTATOR)) 0302 { 0303 prepareActions[CaptureModuleState::ACTION_ROTATOR] = false; 0304 double rawAngle = RotatorUtils::Instance()->calcRotatorAngle(targetPositionAngle); 0305 emit prepareState(CAPTURE_SETTING_ROTATOR); 0306 emit setRotatorAngle(rawAngle); 0307 } 0308 // trigger setting current value first if not initialized 0309 else 0310 emit readCurrentState(CAPTURE_SETTING_ROTATOR); 0311 } 0312 } 0313 0314 IPState SequenceJobState::checkCalibrationPreActionsReady() 0315 { 0316 IPState result = IPS_OK; 0317 0318 if (m_CalibrationPreAction & ACTION_WALL) 0319 result = checkWallPositionReady(FRAME_FLAT); 0320 0321 if (result != IPS_OK) 0322 return result; 0323 0324 if (m_CalibrationPreAction & ACTION_PARK_MOUNT) 0325 result = checkPreMountParkReady(); 0326 0327 if (result != IPS_OK) 0328 return result; 0329 0330 if (m_CalibrationPreAction & ACTION_PARK_DOME) 0331 result = checkPreDomeParkReady(); 0332 0333 return result; 0334 } 0335 0336 IPState SequenceJobState::checkFlatsCoverReady() 0337 { 0338 auto result = checkCalibrationPreActionsReady(); 0339 if (result == IPS_OK) 0340 { 0341 if (m_CaptureModuleState->hasDustCap && m_CaptureModuleState->hasLightBox) 0342 return checkDustCapReady(FRAME_FLAT); 0343 // In case we have a wall action then we are facing a flat light source and we can immediately continue to next step 0344 else if (m_CalibrationPreAction & ACTION_WALL) 0345 return IPS_OK; 0346 else 0347 { 0348 // In case we ONLY have a lightbox then we need to ensure it's toggled correctly first 0349 if (m_CaptureModuleState->hasLightBox) 0350 return checkDustCapReady(FRAME_FLAT); 0351 0352 return checkManualCoverReady(true); 0353 } 0354 } 0355 0356 return result; 0357 } 0358 0359 IPState SequenceJobState::checkDarksCoverReady() 0360 { 0361 IPState result = checkCalibrationPreActionsReady();; 0362 0363 if (result == IPS_OK) 0364 { 0365 // 1. check if the CCD has a shutter 0366 result = checkHasShutter(); 0367 if (result != IPS_OK) 0368 return result; 0369 0370 if (m_CaptureModuleState->hasDustCap) 0371 return checkDustCapReady(FRAME_DARK); 0372 // In case we have a wall action then we are facing a designated location and we can immediately continue to next step 0373 else if (m_CalibrationPreAction & ACTION_WALL) 0374 return IPS_OK; 0375 else 0376 return checkManualCoverReady(false); 0377 } 0378 return result; 0379 } 0380 0381 IPState SequenceJobState::checkManualCoverReady(bool lightSourceRequired) 0382 { 0383 // Manual mode we need to cover mount with evenly illuminated field. 0384 if (lightSourceRequired && m_CaptureModuleState->m_ManualCoverState != CaptureModuleState::MANUAL_COVER_CLOSED_LIGHT) 0385 { 0386 if (coverQueryState == CAL_CHECK_CONFIRMATION) 0387 return IPS_BUSY; 0388 0389 // request asking the user to cover the scope manually with a light source 0390 emit askManualScopeCover(i18n("Cover the telescope with an evenly illuminated light source."), 0391 i18n("Flat Frame"), true); 0392 coverQueryState = CAL_CHECK_CONFIRMATION; 0393 0394 return IPS_BUSY; 0395 } 0396 else if (!lightSourceRequired && m_CaptureModuleState->m_ManualCoverState != CaptureModuleState::MANUAL_COVER_CLOSED_DARK && 0397 m_CaptureModuleState->shutterStatus == CaptureModuleState::SHUTTER_NO) 0398 { 0399 if (coverQueryState == CAL_CHECK_CONFIRMATION) 0400 return IPS_BUSY; 0401 0402 emit askManualScopeCover(i18n("Cover the telescope in order to take a dark exposure."), 0403 i18n("Dark Exposure"), false); 0404 0405 coverQueryState = CAL_CHECK_CONFIRMATION; 0406 0407 return IPS_BUSY; 0408 } 0409 return IPS_OK; 0410 } 0411 0412 IPState SequenceJobState::checkDustCapReady(CCDFrameType frameType) 0413 { 0414 // turning on flat light running 0415 if (m_CaptureModuleState->getLightBoxLightState() == CaptureModuleState::CAP_LIGHT_BUSY || 0416 m_CaptureModuleState->getDustCapState() == CaptureModuleState::CAP_PARKING || 0417 m_CaptureModuleState->getDustCapState() == CaptureModuleState::CAP_UNPARKING) 0418 return IPS_BUSY; 0419 // error occured 0420 if (m_CaptureModuleState->getDustCapState() == CaptureModuleState::CAP_ERROR) 0421 return IPS_ALERT; 0422 0423 auto captureLights = (frameType == FRAME_LIGHT); 0424 0425 // for flats open the cap and close it otherwise 0426 CaptureModuleState::CapState targetCapState = captureLights ? CaptureModuleState::CAP_IDLE : CaptureModuleState::CAP_PARKED; 0427 // If cap is parked, unpark it since dark cap uses external light source. 0428 if (m_CaptureModuleState->hasDustCap && m_CaptureModuleState->getDustCapState() != targetCapState) 0429 { 0430 m_CaptureModuleState->setDustCapState(captureLights ? CaptureModuleState::CAP_UNPARKING : CaptureModuleState::CAP_PARKING); 0431 emit parkDustCap(!captureLights); 0432 emit newLog(captureLights ? i18n("Unparking dust cap...") : i18n("Parking dust cap...")); 0433 return IPS_BUSY; 0434 } 0435 0436 auto captureFlats = (frameType == FRAME_FLAT); 0437 CaptureModuleState::LightState targetLightBoxStatus = captureFlats ? CaptureModuleState::CAP_LIGHT_ON : 0438 CaptureModuleState::CAP_LIGHT_OFF; 0439 0440 if (m_CaptureModuleState->hasLightBox && m_CaptureModuleState->getLightBoxLightState() != targetLightBoxStatus) 0441 { 0442 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_BUSY); 0443 emit setLightBoxLight(captureFlats); 0444 emit newLog(captureFlats ? i18n("Turn light box light on...") : i18n("Turn light box light off...")); 0445 return IPS_BUSY; 0446 } 0447 0448 // nothing more to do 0449 return IPS_OK; 0450 } 0451 0452 IPState SequenceJobState::checkWallPositionReady(CCDFrameType frametype) 0453 { 0454 if (m_CaptureModuleState->hasTelescope) 0455 { 0456 if (wpScopeStatus < WP_SLEWING) 0457 { 0458 wallCoord.HorizontalToEquatorial(KStarsData::Instance()->lst(), 0459 KStarsData::Instance()->geo()->lat()); 0460 wpScopeStatus = WP_SLEWING; 0461 emit slewTelescope(wallCoord); 0462 emit newLog(i18n("Mount slewing to wall position (az =%1 alt =%2)", 0463 wallCoord.alt().toDMSString(), wallCoord.az().toDMSString())); 0464 return IPS_BUSY; 0465 } 0466 // wait until actions completed 0467 else if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY) 0468 return IPS_BUSY; 0469 // Check if slewing is complete 0470 else if (wpScopeStatus == WP_SLEW_COMPLETED) 0471 { 0472 wpScopeStatus = WP_TRACKING_BUSY; 0473 emit setScopeTracking(false); 0474 emit newLog(i18n("Slew to wall position complete, stop tracking.")); 0475 return IPS_BUSY; 0476 } 0477 else if (wpScopeStatus == WP_TRACKING_OFF) 0478 emit newLog(i18n("Slew to wall position complete, tracking stopped.")); 0479 0480 // wall position reached, check if we have a light box to turn on for flats and off otherwise 0481 bool captureFlats = (frametype == FRAME_FLAT); 0482 CaptureModuleState::LightState targetLightState = (captureFlats ? CaptureModuleState::CAP_LIGHT_ON : 0483 CaptureModuleState::CAP_LIGHT_OFF); 0484 0485 if (m_CaptureModuleState->hasLightBox == true) 0486 { 0487 if (m_CaptureModuleState->getLightBoxLightState() != targetLightState) 0488 { 0489 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_BUSY); 0490 emit setLightBoxLight(captureFlats); 0491 emit newLog(captureFlats ? i18n("Turn light box light on...") : i18n("Turn light box light off...")); 0492 return IPS_BUSY; 0493 } 0494 } 0495 } 0496 // everything ready 0497 return IPS_OK; 0498 } 0499 0500 IPState SequenceJobState::checkPreMountParkReady() 0501 { 0502 if (m_CaptureModuleState->hasTelescope) 0503 { 0504 if (m_CaptureModuleState->getScopeParkState() == ISD::PARK_ERROR) 0505 { 0506 emit newLog(i18n("Parking mount failed, aborting...")); 0507 emit abortCapture(); 0508 return IPS_ALERT; 0509 } 0510 else if (m_CaptureModuleState->getScopeParkState() == ISD::PARK_PARKING) 0511 return IPS_BUSY; 0512 else if (m_CaptureModuleState->getScopeParkState() != ISD::PARK_PARKED) 0513 { 0514 m_CaptureModuleState->setScopeParkState(ISD::PARK_PARKING); 0515 emit setScopeParked(true); 0516 emit newLog(i18n("Parking mount prior to calibration frames capture...")); 0517 return IPS_BUSY; 0518 } 0519 } 0520 // everything ready 0521 return IPS_OK; 0522 } 0523 0524 IPState SequenceJobState::checkPreDomeParkReady() 0525 { 0526 if (m_CaptureModuleState->hasDome) 0527 { 0528 if (m_CaptureModuleState->getDomeState() == ISD::Dome::DOME_ERROR) 0529 { 0530 emit newLog(i18n("Parking dome failed, aborting...")); 0531 emit abortCapture(); 0532 return IPS_ALERT; 0533 } 0534 else if (m_CaptureModuleState->getDomeState() == ISD::Dome::DOME_PARKING) 0535 return IPS_BUSY; 0536 else if (m_CaptureModuleState->getDomeState() != ISD::Dome::DOME_PARKED) 0537 { 0538 m_CaptureModuleState->setDomeState(ISD::Dome::DOME_PARKING); 0539 emit setDomeParked(true); 0540 emit newLog(i18n("Parking dome prior to calibration frames capture...")); 0541 return IPS_BUSY; 0542 } 0543 } 0544 // everything ready 0545 return IPS_OK; 0546 } 0547 0548 IPState SequenceJobState::checkFlatSyncFocus() 0549 { 0550 // check already running? 0551 if (flatSyncStatus == FS_BUSY) 0552 { 0553 QTimer::singleShot(1000, this, [this] 0554 { 0555 // wait for one second and repeat the request again 0556 emit flatSyncFocus(targetFilterID); 0557 }); 0558 return IPS_BUSY; 0559 } 0560 0561 if (m_frameType == FRAME_FLAT && Options::flatSyncFocus() && flatSyncStatus != FS_COMPLETED) 0562 { 0563 flatSyncStatus = FS_BUSY; 0564 emit flatSyncFocus(targetFilterID); 0565 return IPS_BUSY; 0566 } 0567 // everything ready 0568 return IPS_OK; 0569 } 0570 0571 IPState SequenceJobState::checkHasShutter() 0572 { 0573 if (m_CaptureModuleState->shutterStatus == CaptureModuleState::SHUTTER_BUSY) 0574 return IPS_BUSY; 0575 if (m_CaptureModuleState->shutterStatus != CaptureModuleState::SHUTTER_UNKNOWN) 0576 return IPS_OK; 0577 // query the status 0578 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_BUSY; 0579 emit queryHasShutter(); 0580 return IPS_BUSY; 0581 } 0582 0583 IPState SequenceJobState::checkLightFrameScopeCoverOpen() 0584 { 0585 // Account for light box only (no dust cap) 0586 if (m_CaptureModuleState->hasLightBox && m_CaptureModuleState->getLightBoxLightState() != CaptureModuleState::CAP_LIGHT_OFF) 0587 { 0588 if (m_CaptureModuleState->getLightBoxLightState() != CaptureModuleState::CAP_LIGHT_BUSY) 0589 { 0590 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_BUSY); 0591 emit setLightBoxLight(false); 0592 emit newLog(i18n("Turn light box light off...")); 0593 } 0594 return IPS_BUSY; 0595 } 0596 0597 // If we have a dust cap, then we must unpark 0598 if (m_CaptureModuleState->hasDustCap) 0599 { 0600 if (m_CaptureModuleState->getDustCapState() != CaptureModuleState::CAP_IDLE) 0601 { 0602 if (m_CaptureModuleState->getDustCapState() != CaptureModuleState::CAP_UNPARKING) 0603 { 0604 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_UNPARKING); 0605 emit parkDustCap(false); 0606 emit newLog(i18n("Unparking dust cap...")); 0607 } 0608 return IPS_BUSY; 0609 } 0610 0611 return IPS_OK; 0612 } 0613 0614 // If telescopes were MANUALLY covered before 0615 // we need to manually uncover them. 0616 if (m_CaptureModuleState->m_ManualCoverState != CaptureModuleState::MANAUL_COVER_OPEN) 0617 { 0618 // If we already asked for confirmation and waiting for it 0619 // let us see if the confirmation is fulfilled 0620 // otherwise we return. 0621 if (coverQueryState == CAL_CHECK_CONFIRMATION) 0622 return IPS_BUSY; 0623 0624 emit askManualScopeOpen(m_CaptureModuleState->m_ManualCoverState == CaptureModuleState::MANUAL_COVER_CLOSED_LIGHT); 0625 0626 return IPS_BUSY; 0627 } 0628 0629 // scope cover open (or no scope cover) 0630 return IPS_OK; 0631 } 0632 0633 bool SequenceJobState::isInitialized(CaptureModuleState::PrepareActions action) 0634 { 0635 return m_CaptureModuleState.data()->isInitialized[action]; 0636 } 0637 0638 void SequenceJobState::setInitialized(CaptureModuleState::PrepareActions action, bool init) 0639 { 0640 m_CaptureModuleState.data()->isInitialized[action] = init; 0641 } 0642 0643 void SequenceJobState::setCurrentFilterID(int value) 0644 { 0645 m_CaptureModuleState->currentFilterID = value; 0646 if (isInitialized(CaptureModuleState::ACTION_FILTER) == false && value != targetFilterID) 0647 { 0648 // mark filter preparation action 0649 // TODO introduce settle time 0650 prepareActions[CaptureModuleState::ACTION_FILTER] = false; 0651 0652 emit changeFilterPosition(targetFilterID, m_filterPolicy); 0653 emit prepareState(CAPTURE_CHANGING_FILTER); 0654 } 0655 setInitialized(CaptureModuleState::ACTION_FILTER, true); 0656 0657 if (value == targetFilterID) 0658 prepareActions[CaptureModuleState::ACTION_FILTER] = true; 0659 0660 checkAllActionsReady(); 0661 } 0662 0663 void SequenceJobState::setCurrentCCDTemperature(double currentTemperature) 0664 { 0665 // skip if next value should be ignored 0666 if (ignoreNextValue[CaptureModuleState::ACTION_TEMPERATURE]) 0667 { 0668 ignoreNextValue[CaptureModuleState::ACTION_TEMPERATURE] = false; 0669 return; 0670 } 0671 0672 if (isInitialized(CaptureModuleState::ACTION_TEMPERATURE)) 0673 { 0674 if (m_enforceTemperature == false 0675 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff()) 0676 prepareActions[CaptureModuleState::ACTION_TEMPERATURE] = true; 0677 0678 checkAllActionsReady(); 0679 } 0680 else 0681 { 0682 setInitialized(CaptureModuleState::ACTION_TEMPERATURE, true); 0683 if (m_enforceTemperature == false 0684 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff()) 0685 { 0686 prepareActions[CaptureModuleState::ACTION_TEMPERATURE] = true; 0687 checkAllActionsReady(); 0688 } 0689 else 0690 { 0691 prepareTemperatureCheck(m_enforceTemperature); 0692 } 0693 } 0694 } 0695 0696 void SequenceJobState::setCurrentRotatorPositionAngle(double rotatorAngle, IPState state) 0697 { 0698 double currentPositionAngle = RotatorUtils::Instance()->calcCameraAngle(rotatorAngle, false); 0699 0700 if (isInitialized(CaptureModuleState::ACTION_ROTATOR)) 0701 { 0702 // TODO introduce settle time 0703 // TODO make sure rotator has fully stopped -> see 'align.cpp' captureAndSolve() 0704 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold() 0705 && state != IPS_BUSY) 0706 prepareActions[CaptureModuleState::ACTION_ROTATOR] = true; 0707 0708 checkAllActionsReady(); 0709 } 0710 else 0711 { 0712 setInitialized(CaptureModuleState::ACTION_ROTATOR, true); 0713 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold() 0714 && state != IPS_BUSY) 0715 { 0716 prepareActions[CaptureModuleState::ACTION_ROTATOR] = true; 0717 checkAllActionsReady(); 0718 } 0719 else 0720 { 0721 prepareRotatorCheck(); 0722 } 0723 } 0724 } 0725 0726 void SequenceJobState::setFocusStatus(FocusState state) 0727 { 0728 switch (state) 0729 { 0730 case FOCUS_COMPLETE: 0731 // did we wait for a successful autofocus run? 0732 if (prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] == false) 0733 { 0734 prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] = true; 0735 checkAllActionsReady(); 0736 } 0737 break; 0738 case FOCUS_ABORTED: 0739 case FOCUS_FAILED: 0740 // finish preparation with failure 0741 emit prepareComplete(false); 0742 break; 0743 default: 0744 // in all other cases do nothing 0745 break; 0746 } 0747 } 0748 0749 void SequenceJobState::updateManualScopeCover(bool closed, bool success, bool light) 0750 { 0751 // covering confirmed 0752 if (success == true) 0753 { 0754 if (closed) 0755 m_CaptureModuleState->m_ManualCoverState = light ? CaptureModuleState::MANUAL_COVER_CLOSED_LIGHT : 0756 CaptureModuleState::MANUAL_COVER_CLOSED_DARK; 0757 else 0758 m_CaptureModuleState->m_ManualCoverState = CaptureModuleState::MANAUL_COVER_OPEN; 0759 coverQueryState = CAL_CHECK_TASK; 0760 // re-run checks 0761 checkAllActionsReady(); 0762 } 0763 // cancelled 0764 else 0765 { 0766 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_UNKNOWN; 0767 coverQueryState = CAL_CHECK_TASK; 0768 // abort, no further checks 0769 emit abortCapture(); 0770 } 0771 } 0772 0773 void SequenceJobState::lightBoxLight(bool on) 0774 { 0775 m_CaptureModuleState->setLightBoxLightState(on ? CaptureModuleState::CAP_LIGHT_ON : CaptureModuleState::CAP_LIGHT_OFF); 0776 emit newLog(i18n(on ? "Light box on." : "Light box off.")); 0777 // re-run checks 0778 checkAllActionsReady(); 0779 } 0780 0781 void SequenceJobState::dustCapStateChanged(ISD::DustCap::Status status) 0782 { 0783 switch (status) 0784 { 0785 case ISD::DustCap::CAP_ERROR: 0786 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_ERROR); 0787 emit abortCapture(); 0788 break; 0789 case ISD::DustCap::CAP_PARKED: 0790 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_PARKED); 0791 emit newLog(i18n("Dust cap parked.")); 0792 break; 0793 case ISD::DustCap::CAP_IDLE: 0794 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_IDLE); 0795 emit newLog(i18n("Dust cap unparked.")); 0796 break; 0797 case ISD::DustCap::CAP_UNPARKING: 0798 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_UNPARKING); 0799 break; 0800 case ISD::DustCap::CAP_PARKING: 0801 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_PARKING); 0802 break; 0803 } 0804 0805 // re-run checks 0806 checkAllActionsReady(); 0807 } 0808 0809 void SequenceJobState::scopeStatusChanged(ISD::Mount::Status status) 0810 { 0811 // handle wall position 0812 switch (status) 0813 { 0814 case ISD::Mount::MOUNT_TRACKING: 0815 if (wpScopeStatus == WP_SLEWING) 0816 wpScopeStatus = WP_SLEW_COMPLETED; 0817 break; 0818 case ISD::Mount::MOUNT_IDLE: 0819 if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY) 0820 wpScopeStatus = WP_TRACKING_OFF; 0821 break; 0822 default: 0823 // do nothing 0824 break; 0825 } 0826 m_CaptureModuleState->setScopeState(status); 0827 // re-run checks 0828 checkAllActionsReady(); 0829 } 0830 0831 void SequenceJobState::scopeParkStatusChanged(ISD::ParkStatus status) 0832 { 0833 m_CaptureModuleState->setScopeParkState(status); 0834 // re-run checks 0835 checkAllActionsReady(); 0836 } 0837 0838 void SequenceJobState::domeStatusChanged(ISD::Dome::Status status) 0839 { 0840 m_CaptureModuleState->setDomeState(status); 0841 // re-run checks 0842 checkAllActionsReady(); 0843 } 0844 0845 void SequenceJobState::flatSyncFocusChanged(bool completed) 0846 { 0847 flatSyncStatus = (completed ? FS_COMPLETED : FS_BUSY); 0848 // re-run checks 0849 checkAllActionsReady(); 0850 } 0851 0852 void SequenceJobState::hasShutter(bool present) 0853 { 0854 if (present == true) 0855 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_YES; 0856 else 0857 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_NO; 0858 0859 // re-run checks 0860 checkAllActionsReady(); 0861 } 0862 0863 SequenceJobState::PreparationState SequenceJobState::getPreparationState() const 0864 { 0865 return m_PreparationState; 0866 } 0867 0868 void SequenceJobState::setFilterStatus(FilterState filterState) 0869 { 0870 switch (filterState) 0871 { 0872 case FILTER_AUTOFOCUS: 0873 // we need to wait until focusing has completed 0874 prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] = false; 0875 emit prepareState(CAPTURE_FOCUSING); 0876 break; 0877 0878 // nothing to do in all other cases 0879 case FILTER_IDLE: 0880 case FILTER_OFFSET: 0881 case FILTER_CHANGE: 0882 break; 0883 } 0884 0885 } 0886 } // namespace