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

KDE's Doxygen guidelines are available online.