Kstars

sequencejobstate.cpp
1/* Ekos state machine for a single capture job sequence
2 SPDX-FileCopyrightText: Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "sequencejobstate.h"
8
9#include "Options.h"
10#include "kstarsdata.h"
11#include "indicom.h"
12#include "ekos/auxiliary/rotatorutils.h"
13
14namespace Ekos
15{
16SequenceJobState::SequenceJobState(const QSharedPointer<CameraState> &sharedState)
17{
18 m_CameraState = sharedState;
19}
20
21void SequenceJobState::setFrameType(CCDFrameType frameType)
22{
23 // set the frame type
24 m_frameType = frameType;
25 // reset the preparation state
26 m_PreparationState = PREP_NONE;
27}
28
29void SequenceJobState::initPreparation(bool isPreview)
30{
31 m_status = JOB_BUSY;
32 m_isPreview = isPreview;
33 wpScopeStatus = WP_NONE;
34}
35
36void SequenceJobState::prepareLightFrameCapture(bool enforceCCDTemp, bool isPreview)
37{
38 // precondition: do not start while already being busy and conditions haven't changed
39 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
40 return;
41
42 // initialize the states
43 initPreparation(isPreview);
44
45 // Reset all prepare actions
46 setAllActionsReady();
47
48 // disable batch mode for previews
49 emit setCCDBatchMode(!isPreview);
50
51 // Check if we need to update temperature (only skip if the value is initialized and within the limits)
52 prepareTemperatureCheck(enforceCCDTemp);
53
54 // Check if we need to update rotator (only skip if the value is initialized and within the limits)
55 prepareRotatorCheck();
56
57 // Hint: Filter changes are actually done in SequenceJob::capture();
58
59 // preparation started
60 m_PreparationState = PREP_BUSY;
61 // check if the preparations are already completed
62 checkAllActionsReady();
63}
64
65void SequenceJobState::prepareFlatFrameCapture(bool enforceCCDTemp, bool isPreview)
66{
67 // precondition: do not start while already being busy and conditions haven't changed
68 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
69 return;
70
71 // initialize the states
72 initPreparation(isPreview);
73
74 // Reset all prepare actions
75 setAllActionsReady();
76
77 // disable batch mode for previews
78 emit setCCDBatchMode(!isPreview);
79
80 // Check if we need to update temperature (only skip if the value is initialized and within the limits)
81 prepareTemperatureCheck(enforceCCDTemp);
82
83 // preparation started
84 m_PreparationState = PREP_BUSY;
85 // check if the preparations are already completed
86 checkAllActionsReady();
87}
88
89void SequenceJobState::prepareDarkFrameCapture(bool enforceCCDTemp, bool isPreview)
90{
91 // precondition: do not start while already being busy and conditions haven't changed
92 if (m_status == JOB_BUSY && enforceCCDTemp == m_enforceTemperature)
93 return;
94
95 // initialize the states
96 initPreparation(isPreview);
97
98 // Reset all prepare actions
99 setAllActionsReady();
100
101 // disable batch mode for previews
102 emit setCCDBatchMode(!isPreview);
103
104 // Check if we need to update temperature (only skip if the value is initialized and within the limits)
105 prepareTemperatureCheck(enforceCCDTemp);
106
107 // preparation started
108 m_PreparationState = PREP_BUSY;
109 // check if the preparations are already completed
110 checkAllActionsReady();
111}
112
113void SequenceJobState::prepareBiasFrameCapture(bool enforceCCDTemp, bool isPreview)
114{
115 prepareDarkFrameCapture(enforceCCDTemp, isPreview);
116}
117
118bool SequenceJobState::initCapture(CCDFrameType frameType, bool isPreview, bool isAutofocusReady, FITSMode mode)
119{
120 m_PreparationState = PREP_INIT_CAPTURE;
121 autoFocusReady = isAutofocusReady;
122 m_fitsMode = mode;
123
124 //check for setting the target filter
125 prepareTargetFilter(frameType, isPreview);
126 checkAllActionsReady();
127
128 return areActionsReady();
129}
130
131bool SequenceJobState::areActionsReady()
132{
133 for (bool &ready : prepareActions.values())
134 {
135 if (ready == false)
136 return false;
137 }
138
139 return true;
140}
141
142void SequenceJobState::checkAllActionsReady()
143{
144 // ignore events if preparation is already completed
145 if (preparationCompleted())
146 return;
147
148 switch (m_PreparationState)
149 {
150 // capture preparation
151 case PREP_BUSY:
152 switch (m_frameType)
153 {
154 case FRAME_LIGHT:
155 if (areActionsReady())
156 {
157 // as last step ensure that the scope is uncovered
158 if (checkLightFrameScopeCoverOpen() != IPS_OK)
159 return;
160
161 m_PreparationState = PREP_COMPLETED;
162 emit prepareComplete();
163 }
164 break;
165 case FRAME_FLAT:
166 if (!areActionsReady())
167 return;
168
169 // 1. Check if the selected flats light source is ready
170 if (checkFlatsCoverReady() != IPS_OK)
171 return;
172
173 // 2. If we used AUTOFOCUS before for a specific frame (e.g. Lum)
174 // then the absolute focus position for Lum is recorded in the filter manager
175 // when we take flats again, we always go back to the same focus position as the light frames to ensure
176 // near identical focus for both frames.
177 if (checkFlatSyncFocus() != IPS_OK)
178 return;
179
180 // all preparations ready, avoid doubled events
181 if (m_PreparationState == PREP_BUSY)
182 {
183 m_PreparationState = PREP_COMPLETED;
184 emit prepareComplete();
185 }
186 break;
187 // darks and bias frames are handled in the same way
188 case FRAME_DARK:
189 case FRAME_BIAS:
190 if (!areActionsReady())
191 return;
192
193 // 1. check if the scope is covered appropriately
194 if (checkDarksCoverReady() != IPS_OK)
195 return;
196
197 // 2. avoid doubled events
198 if (m_PreparationState == PREP_BUSY)
199 {
200 m_PreparationState = PREP_COMPLETED;
201 emit prepareComplete();
202 }
203 break;
204 default:
205 // all other cases not refactored yet, preparation immediately completed
206 emit prepareComplete();
207 break;
208 }
209 break;
210
211 // capture initialization (final preparation steps before starting frame capturing)
212 case PREP_INIT_CAPTURE:
213 if (areActionsReady())
214 {
215 // reset the state to avoid double events
216 m_PreparationState = PREP_NONE;
217 emit initCaptureComplete(m_fitsMode);
218 }
219 break;
220
221 case PREP_NONE:
222 case PREP_COMPLETED:
223 // in all other cases do nothing
224 break;
225 }
226}
227
228void SequenceJobState::setAllActionsReady()
229{
231
232 while (it.hasNext())
233 {
234 it.next();
235 it.setValue(true);
236 }
237 // reset the initialization state
238 for (CaptureWorkflowActionType action :
239 {
240 CAPTURE_ACTION_FILTER, CAPTURE_ACTION_ROTATOR, CAPTURE_ACTION_TEMPERATURE
241 })
242 setInitialized(action, false);
243}
244
245void SequenceJobState::prepareTargetFilter(CCDFrameType frameType, bool isPreview)
246{
247 if (targetFilterID != INVALID_VALUE)
248 {
249 if (isInitialized(CAPTURE_ACTION_FILTER) == false)
250 {
251 prepareActions[CAPTURE_ACTION_FILTER] = false;
252
253 // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet.
254 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady == false)
255 m_filterPolicy = static_cast<FilterManager::FilterPolicy>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY);
256
257 emit readFilterPosition();
258 }
259 else if (targetFilterID != m_CameraState->currentFilterID)
260 {
261 // mark filter preparation action
262 prepareActions[CAPTURE_ACTION_FILTER] = false;
263
264 // determine policy
265 m_filterPolicy = FilterManager::ALL_POLICIES;
266
267 // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet.
268 if (isPreview || frameType != FRAME_LIGHT || autoFocusReady == false)
269 m_filterPolicy = static_cast<FilterManager::FilterPolicy>(m_filterPolicy & ~FilterManager::AUTOFOCUS_POLICY);
270
271 emit changeFilterPosition(targetFilterID, m_filterPolicy);
272 emit prepareState(CAPTURE_CHANGING_FILTER);
273 }
274 }
275}
276
277void SequenceJobState::prepareTemperatureCheck(bool enforceCCDTemp)
278{
279 // turn on CCD temperature enforcing if required
280 m_enforceTemperature = enforceCCDTemp;
281
282 if (m_enforceTemperature)
283 {
284 prepareActions[CAPTURE_ACTION_TEMPERATURE] = false;
285 if (isInitialized(CAPTURE_ACTION_TEMPERATURE))
286 {
287 // ignore the next value since after setting temperature the next received value will be
288 // exactly this value no matter what the CCD temperature
289 ignoreNextValue[CAPTURE_ACTION_TEMPERATURE] = true;
290 // request setting temperature
291 emit setCCDTemperature(targetTemperature);
292 emit prepareState(CAPTURE_SETTING_TEMPERATURE);
293 }
294 // trigger setting current value first if not initialized
295 else
296 emit readCurrentState(CAPTURE_SETTING_TEMPERATURE);
297
298 }
299}
300
301void SequenceJobState::prepareRotatorCheck()
302{
303 if (targetPositionAngle > Ekos::INVALID_VALUE)
304 {
305 if (isInitialized(CAPTURE_ACTION_ROTATOR))
306 {
307 prepareActions[CAPTURE_ACTION_ROTATOR] = false;
308 double rawAngle = RotatorUtils::Instance()->calcRotatorAngle(targetPositionAngle);
309 emit prepareState(CAPTURE_SETTING_ROTATOR);
310 emit setRotatorAngle(rawAngle);
311 }
312 // trigger setting current value first if not initialized
313 else
314 emit readCurrentState(CAPTURE_SETTING_ROTATOR);
315 }
316}
317
318IPState SequenceJobState::checkCalibrationPreActionsReady()
319{
320 IPState result = IPS_OK;
321
322 if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
323 result = checkWallPositionReady(FRAME_FLAT);
324
325 if (result != IPS_OK)
326 return result;
327
328 if (m_CalibrationPreAction & CAPTURE_PREACTION_PARK_MOUNT)
329 result = checkPreMountParkReady();
330
331 if (result != IPS_OK)
332 return result;
333
334 if (m_CalibrationPreAction & CAPTURE_PREACTION_PARK_DOME)
335 result = checkPreDomeParkReady();
336
337 return result;
338}
339
340IPState SequenceJobState::checkFlatsCoverReady()
341{
342 auto result = checkCalibrationPreActionsReady();
343 if (result == IPS_OK)
344 {
345 if (m_CameraState->hasDustCap && m_CameraState->hasLightBox)
346 return checkDustCapReady(FRAME_FLAT);
347 // In case we have a wall action then we are facing a flat light source and we can immediately continue to next step
348 else if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
349 return IPS_OK;
350 else
351 {
352 // In case we ONLY have a lightbox then we need to ensure it's toggled correctly first
353 if (m_CameraState->hasLightBox)
354 return checkDustCapReady(FRAME_FLAT);
355
356 return checkManualCoverReady(true);
357 }
358 }
359
360 return result;
361}
362
363IPState SequenceJobState::checkDarksCoverReady()
364{
365 IPState result = checkCalibrationPreActionsReady();;
366
367 if (result == IPS_OK)
368 {
369 // 1. check if the CCD has a shutter
370 result = checkHasShutter();
371 if (result != IPS_OK)
372 return result;
373
374 if (m_CameraState->hasDustCap)
375 return checkDustCapReady(FRAME_DARK);
376 // In case we have a wall action then we are facing a designated location and we can immediately continue to next step
377 else if (m_CalibrationPreAction & CAPTURE_PREACTION_WALL)
378 return IPS_OK;
379 else
380 return checkManualCoverReady(false);
381 }
382 return result;
383}
384
385IPState SequenceJobState::checkManualCoverReady(bool lightSourceRequired)
386{
387 // Manual mode we need to cover mount with evenly illuminated field.
388 if (lightSourceRequired && m_CameraState->m_ManualCoverState != CameraState::MANUAL_COVER_CLOSED_LIGHT)
389 {
390 if (coverQueryState == CAL_CHECK_CONFIRMATION)
391 return IPS_BUSY;
392
393 // request asking the user to cover the scope manually with a light source
394 emit askManualScopeCover(i18n("Cover the telescope with an evenly illuminated light source."),
395 i18n("Flat Frame"), true);
396 coverQueryState = CAL_CHECK_CONFIRMATION;
397
398 return IPS_BUSY;
399 }
400 else if (!lightSourceRequired && m_CameraState->m_ManualCoverState != CameraState::MANUAL_COVER_CLOSED_DARK &&
401 m_CameraState->shutterStatus == SHUTTER_NO)
402 {
403 if (coverQueryState == CAL_CHECK_CONFIRMATION)
404 return IPS_BUSY;
405
406 emit askManualScopeCover(i18n("Cover the telescope in order to take a dark exposure."),
407 i18n("Dark Exposure"), false);
408
409 coverQueryState = CAL_CHECK_CONFIRMATION;
410
411 return IPS_BUSY;
412 }
413 return IPS_OK;
414}
415
416IPState SequenceJobState::checkDustCapReady(CCDFrameType frameType)
417{
418 // turning on flat light running
419 if (m_CameraState->getLightBoxLightState() == CAP_LIGHT_BUSY ||
420 m_CameraState->getDustCapState() == CAP_PARKING ||
421 m_CameraState->getDustCapState() == CAP_UNPARKING)
422 return IPS_BUSY;
423 // error occured
424 if (m_CameraState->getDustCapState() == CAP_ERROR)
425 return IPS_ALERT;
426
427 auto captureLights = (frameType == FRAME_LIGHT);
428
429 // for flats open the cap and close it otherwise
430 CapState targetCapState = captureLights ? CAP_IDLE : CAP_PARKED;
431 // If cap is parked, unpark it since dark cap uses external light source.
432 if (m_CameraState->hasDustCap && m_CameraState->getDustCapState() != targetCapState)
433 {
434 m_CameraState->setDustCapState(captureLights ? CAP_UNPARKING : CAP_PARKING);
435 emit parkDustCap(!captureLights);
436 emit newLog(captureLights ? i18n("Unparking dust cap...") : i18n("Parking dust cap..."));
437 return IPS_BUSY;
438 }
439
440 auto captureFlats = (frameType == FRAME_FLAT);
441 LightState targetLightBoxStatus = captureFlats ? CAP_LIGHT_ON :
442 CAP_LIGHT_OFF;
443
444 if (m_CameraState->hasLightBox && m_CameraState->getLightBoxLightState() != targetLightBoxStatus)
445 {
446 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
447 emit setLightBoxLight(captureFlats);
448 emit newLog(captureFlats ? i18n("Turn light box light on...") : i18n("Turn light box light off..."));
449 return IPS_BUSY;
450 }
451
452 // nothing more to do
453 return IPS_OK;
454}
455
456IPState SequenceJobState::checkWallPositionReady(CCDFrameType frametype)
457{
458 if (m_CameraState->hasTelescope)
459 {
460 if (wpScopeStatus < WP_SLEWING)
461 {
462 wallCoord.HorizontalToEquatorial(KStarsData::Instance()->lst(),
463 KStarsData::Instance()->geo()->lat());
464 wpScopeStatus = WP_SLEWING;
465 emit slewTelescope(wallCoord);
466 emit newLog(i18n("Mount slewing to wall position (az =%1 alt =%2)",
467 wallCoord.alt().toDMSString(), wallCoord.az().toDMSString()));
468 return IPS_BUSY;
469 }
470 // wait until actions completed
471 else if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
472 return IPS_BUSY;
473 // Check if slewing is complete
474 else if (wpScopeStatus == WP_SLEW_COMPLETED)
475 {
476 wpScopeStatus = WP_TRACKING_BUSY;
477 emit setScopeTracking(false);
478 emit newLog(i18n("Slew to wall position complete, stop tracking."));
479 return IPS_BUSY;
480 }
481 else if (wpScopeStatus == WP_TRACKING_OFF)
482 emit newLog(i18n("Slew to wall position complete, tracking stopped."));
483
484 // wall position reached, check if we have a light box to turn on for flats and off otherwise
485 bool captureFlats = (frametype == FRAME_FLAT);
486 LightState targetLightState = (captureFlats ? CAP_LIGHT_ON :
487 CAP_LIGHT_OFF);
488
489 if (m_CameraState->hasLightBox == true)
490 {
491 if (m_CameraState->getLightBoxLightState() != targetLightState)
492 {
493 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
494 emit setLightBoxLight(captureFlats);
495 emit newLog(captureFlats ? i18n("Turn light box light on...") : i18n("Turn light box light off..."));
496 return IPS_BUSY;
497 }
498 }
499 }
500 // everything ready
501 return IPS_OK;
502}
503
504IPState SequenceJobState::checkPreMountParkReady()
505{
506 if (m_CameraState->hasTelescope)
507 {
508 switch (m_CameraState->getScopeParkState())
509 {
510 case ISD::PARK_PARKED:
511 break;
512 case ISD::PARK_ERROR:
513 emit newLog(i18n("Parking mount failed, aborting..."));
514 emit abortCapture();
515 return IPS_ALERT;
516 case ISD::PARK_PARKING:
517 return IPS_BUSY;
518 case ISD::PARK_UNPARKED:
519 case ISD::PARK_UNPARKING:
520 // park the scope
521 emit setScopeParked(true);
522 emit newLog(i18n("Parking mount prior to calibration frames capture..."));
523 return IPS_BUSY;
524 case ISD::PARK_UNKNOWN:
525 // retrieve the mount park state
526 emit readCurrentMountParkState();
527 return IPS_BUSY;
528 }
529 }
530 // everything ready
531 return IPS_OK;
532
533}
534
535IPState SequenceJobState::checkPreDomeParkReady()
536{
537 if (m_CameraState->hasDome)
538 {
539 if (m_CameraState->getDomeState() == ISD::Dome::DOME_ERROR)
540 {
541 emit newLog(i18n("Parking dome failed, aborting..."));
542 emit abortCapture();
543 return IPS_ALERT;
544 }
545 else if (m_CameraState->getDomeState() == ISD::Dome::DOME_PARKING)
546 return IPS_BUSY;
547 else if (m_CameraState->getDomeState() != ISD::Dome::DOME_PARKED)
548 {
549 m_CameraState->setDomeState(ISD::Dome::DOME_PARKING);
550 emit setDomeParked(true);
551 emit newLog(i18n("Parking dome prior to calibration frames capture..."));
552 return IPS_BUSY;
553 }
554 }
555 // everything ready
556 return IPS_OK;
557}
558
559IPState SequenceJobState::checkFlatSyncFocus()
560{
561 // check already running?
562 if (flatSyncStatus == FS_BUSY)
563 {
564 QTimer::singleShot(1000, this, [this]
565 {
566 // wait for one second and repeat the request again
567 emit flatSyncFocus(targetFilterID);
568 });
569 return IPS_BUSY;
570 }
571
572 if (m_frameType == FRAME_FLAT && Options::flatSyncFocus() && flatSyncStatus != FS_COMPLETED)
573 {
574 flatSyncStatus = FS_BUSY;
575 emit flatSyncFocus(targetFilterID);
576 return IPS_BUSY;
577 }
578 // everything ready
579 return IPS_OK;
580}
581
582IPState SequenceJobState::checkHasShutter()
583{
584 if (m_CameraState->shutterStatus == SHUTTER_BUSY)
585 return IPS_BUSY;
586 if (m_CameraState->shutterStatus != SHUTTER_UNKNOWN)
587 return IPS_OK;
588 // query the status
589 m_CameraState->shutterStatus = SHUTTER_BUSY;
590 emit queryHasShutter();
591 return IPS_BUSY;
592}
593
594IPState SequenceJobState::checkLightFrameScopeCoverOpen()
595{
596 // Account for light box only (no dust cap)
597 if (m_CameraState->hasLightBox && m_CameraState->getLightBoxLightState() != CAP_LIGHT_OFF)
598 {
599 if (m_CameraState->getLightBoxLightState() != CAP_LIGHT_BUSY)
600 {
601 m_CameraState->setLightBoxLightState(CAP_LIGHT_BUSY);
602 emit setLightBoxLight(false);
603 emit newLog(i18n("Turn light box light off..."));
604 }
605 return IPS_BUSY;
606 }
607
608 // If we have a dust cap, then we must unpark
609 if (m_CameraState->hasDustCap)
610 {
611 if (m_CameraState->getDustCapState() != CAP_IDLE)
612 {
613 if (m_CameraState->getDustCapState() != CAP_UNPARKING)
614 {
615 m_CameraState->setDustCapState(CAP_UNPARKING);
616 emit parkDustCap(false);
617 emit newLog(i18n("Unparking dust cap..."));
618 }
619 return IPS_BUSY;
620 }
621
622 return IPS_OK;
623 }
624
625 // If telescopes were MANUALLY covered before
626 // we need to manually uncover them.
627 if (m_CameraState->m_ManualCoverState != CameraState::MANAUL_COVER_OPEN)
628 {
629 // If we already asked for confirmation and waiting for it
630 // let us see if the confirmation is fulfilled
631 // otherwise we return.
632 if (coverQueryState == CAL_CHECK_CONFIRMATION)
633 return IPS_BUSY;
634
635 emit askManualScopeOpen(m_CameraState->m_ManualCoverState == CameraState::MANUAL_COVER_CLOSED_LIGHT);
636
637 return IPS_BUSY;
638 }
639
640 // scope cover open (or no scope cover)
641 return IPS_OK;
642}
643
644bool SequenceJobState::isInitialized(CaptureWorkflowActionType action)
645{
646 return m_CameraState.data()->isInitialized[action];
647}
648
649void SequenceJobState::setInitialized(CaptureWorkflowActionType action, bool init)
650{
651 m_CameraState.data()->isInitialized[action] = init;
652}
653
654void SequenceJobState::setCurrentFilterID(int value)
655{
656 // ignore events if preparation is already completed
657 if (preparationCompleted())
658 return;
659
660 m_CameraState->currentFilterID = value;
661 if (isInitialized(CAPTURE_ACTION_FILTER) == false && value != targetFilterID)
662 {
663 // mark filter preparation action
664 // TODO introduce settle time
665 prepareActions[CAPTURE_ACTION_FILTER] = false;
666
667 emit changeFilterPosition(targetFilterID, m_filterPolicy);
668 emit prepareState(CAPTURE_CHANGING_FILTER);
669 }
670 setInitialized(CAPTURE_ACTION_FILTER, true);
671
672 if (value == targetFilterID)
673 prepareActions[CAPTURE_ACTION_FILTER] = true;
674
675 checkAllActionsReady();
676}
677
678void SequenceJobState::setCurrentCCDTemperature(double currentTemperature)
679{
680 // ignore events if preparation is already completed
681 if (preparationCompleted())
682 return;
683
684 // skip if next value should be ignored
685 if (ignoreNextValue[CAPTURE_ACTION_TEMPERATURE])
686 {
687 ignoreNextValue[CAPTURE_ACTION_TEMPERATURE] = false;
688 return;
689 }
690
691 if (isInitialized(CAPTURE_ACTION_TEMPERATURE))
692 {
693 if (m_enforceTemperature == false
694 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
695 prepareActions[CAPTURE_ACTION_TEMPERATURE] = true;
696
697 checkAllActionsReady();
698 }
699 else
700 {
701 setInitialized(CAPTURE_ACTION_TEMPERATURE, true);
702 if (m_enforceTemperature == false
703 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
704 {
705 prepareActions[CAPTURE_ACTION_TEMPERATURE] = true;
706 checkAllActionsReady();
707 }
708 else
709 {
710 prepareTemperatureCheck(m_enforceTemperature);
711 }
712 }
713}
714
715void SequenceJobState::setCurrentRotatorPositionAngle(double rotatorAngle, IPState state)
716{
717 // ignore events if preparation is already completed
718 if (preparationCompleted())
719 return;
720
721 double currentPositionAngle = RotatorUtils::Instance()->calcCameraAngle(rotatorAngle, false);
722
723 if (isInitialized(CAPTURE_ACTION_ROTATOR))
724 {
725 // TODO introduce settle time
726 // TODO make sure rotator has fully stopped -> see 'align.cpp' captureAndSolve()
727 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
728 && state != IPS_BUSY)
729 prepareActions[CAPTURE_ACTION_ROTATOR] = true;
730
731 checkAllActionsReady();
732 }
733 else
734 {
735 setInitialized(CAPTURE_ACTION_ROTATOR, true);
736 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
737 && state != IPS_BUSY)
738 {
739 prepareActions[CAPTURE_ACTION_ROTATOR] = true;
740 checkAllActionsReady();
741 }
742 else
743 {
744 prepareRotatorCheck();
745 }
746 }
747}
748
749void SequenceJobState::setFocusStatus(FocusState state)
750{
751 // ignore events if preparation is already completed
752 if (preparationCompleted())
753 return;
754
755 switch (state)
756 {
757 case FOCUS_COMPLETE:
758 // did we wait for a successful autofocus run?
759 if (prepareActions[CAPTURE_ACTION_AUTOFOCUS] == false)
760 {
761 prepareActions[CAPTURE_ACTION_AUTOFOCUS] = true;
762 checkAllActionsReady();
763 }
764 break;
765 case FOCUS_ABORTED:
766 case FOCUS_FAILED:
767 // finish preparation with failure
768 emit prepareComplete(false);
769 break;
770 default:
771 // in all other cases do nothing
772 break;
773 }
774}
775
776void SequenceJobState::updateManualScopeCover(bool closed, bool success, bool light)
777{
778 // ignore events if preparation is already completed
779 if (preparationCompleted())
780 return;
781
782 // covering confirmed
783 if (success == true)
784 {
785 if (closed)
786 m_CameraState->m_ManualCoverState = light ? CameraState::MANUAL_COVER_CLOSED_LIGHT :
787 CameraState::MANUAL_COVER_CLOSED_DARK;
788 else
789 m_CameraState->m_ManualCoverState = CameraState::MANAUL_COVER_OPEN;
790 coverQueryState = CAL_CHECK_TASK;
791 // re-run checks
792 checkAllActionsReady();
793 }
794 // cancelled
795 else
796 {
797 m_CameraState->shutterStatus = SHUTTER_UNKNOWN;
798 coverQueryState = CAL_CHECK_TASK;
799 // abort, no further checks
800 emit abortCapture();
801 }
802}
803
804void SequenceJobState::lightBoxLight(bool on)
805{
806 // ignore events if preparation is already completed
807 if (preparationCompleted())
808 return;
809
810 m_CameraState->setLightBoxLightState(on ? CAP_LIGHT_ON : CAP_LIGHT_OFF);
811 emit newLog(i18n(on ? "Light box on." : "Light box off."));
812 // re-run checks
813 checkAllActionsReady();
814}
815
816void SequenceJobState::dustCapStateChanged(ISD::DustCap::Status status)
817{
818 // ignore events if preparation is already completed
819 if (preparationCompleted())
820 return;
821
822 switch (status)
823 {
824 case ISD::DustCap::CAP_ERROR:
825 emit abortCapture();
826 break;
827 default:
828 // do nothing
829 break;
830 }
831
832 // re-run checks
833 checkAllActionsReady();
834}
835
836void SequenceJobState::scopeStatusChanged(ISD::Mount::Status status)
837{
838 // ignore events if preparation is already completed
839 if (preparationCompleted())
840 return;
841
842 // handle wall position
843 switch (status)
844 {
845 case ISD::Mount::MOUNT_TRACKING:
846 if (wpScopeStatus == WP_SLEWING)
847 wpScopeStatus = WP_SLEW_COMPLETED;
848 break;
849 case ISD::Mount::MOUNT_IDLE:
850 if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
851 wpScopeStatus = WP_TRACKING_OFF;
852 break;
853 case ISD::Mount::MOUNT_PARKING:
854 // Ensure the parking state to avoid double park calls
855 m_CameraState->setScopeParkState(ISD::PARK_PARKING);
856 break;
857 default:
858 // do nothing
859 break;
860 }
861 // re-run checks
862 checkAllActionsReady();
863}
864
865void SequenceJobState::scopeParkStatusChanged(ISD::ParkStatus)
866{
867 // re-run checks
868 checkAllActionsReady();
869}
870
871void SequenceJobState::domeStatusChanged(ISD::Dome::Status)
872{
873 // re-run checks
874 checkAllActionsReady();
875}
876
877void SequenceJobState::flatSyncFocusChanged(bool completed)
878{
879 // ignore events if preparation is already completed
880 if (preparationCompleted())
881 return;
882
883 flatSyncStatus = (completed ? FS_COMPLETED : FS_BUSY);
884 // re-run checks
885 checkAllActionsReady();
886}
887
888void SequenceJobState::hasShutter(bool present)
889{
890 // ignore events if preparation is already completed
891 if (preparationCompleted())
892 return;
893
894 if (present == true)
895 m_CameraState->shutterStatus = SHUTTER_YES;
896 else
897 m_CameraState->shutterStatus = SHUTTER_NO;
898
899 // re-run checks
900 checkAllActionsReady();
901}
902
903SequenceJobState::PreparationState SequenceJobState::getPreparationState() const
904{
905 return m_PreparationState;
906}
907
908void SequenceJobState::setFilterStatus(FilterState filterState)
909{
910 // ignore events if preparation is already completed
911 if (preparationCompleted())
912 return;
913
914 switch (filterState)
915 {
916 case FILTER_AUTOFOCUS:
917 // we need to wait until focusing has completed
918 prepareActions[CAPTURE_ACTION_AUTOFOCUS] = false;
919 emit prepareState(CAPTURE_FOCUSING);
920 break;
921
922 // nothing to do in all other cases
923 case FILTER_IDLE:
924 case FILTER_OFFSET:
925 case FILTER_CHANGE:
926 break;
927 }
928
929}
930} // namespace
const dms & az() const
Definition skypoint.h:275
const dms & alt() const
Definition skypoint.h:281
void HorizontalToEquatorial(const dms *LST, const dms *lat)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates,...
Definition skypoint.cpp:143
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition dms.cpp:287
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:83
@ CAPTURE_SETTING_ROTATOR
Definition ekos.h:108
@ CAPTURE_FOCUSING
Definition ekos.h:103
@ CAPTURE_CHANGING_FILTER
Definition ekos.h:105
@ CAPTURE_SETTING_TEMPERATURE
Definition ekos.h:107
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
GeoCoordinates geo(const QVariant &location)
QList< T > values() const const
T * data() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.