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

KDE's Doxygen guidelines are available online.