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<CaptureModuleState> &sharedState)
17{
18 m_CaptureModuleState = 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 (CaptureModuleState::PrepareActions action :
235 {
236 CaptureModuleState::ACTION_FILTER, CaptureModuleState::ACTION_ROTATOR, CaptureModuleState::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(CaptureModuleState::ACTION_FILTER) == false)
246 {
247 prepareActions[CaptureModuleState::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_CaptureModuleState->currentFilterID)
256 {
257 // mark filter preparation action
258 prepareActions[CaptureModuleState::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[CaptureModuleState::ACTION_TEMPERATURE] = false;
281 if (isInitialized(CaptureModuleState::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[CaptureModuleState::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(CaptureModuleState::ACTION_ROTATOR))
302 {
303 prepareActions[CaptureModuleState::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_CaptureModuleState->hasDustCap && m_CaptureModuleState->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_CaptureModuleState->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_CaptureModuleState->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_CaptureModuleState->m_ManualCoverState != CaptureModuleState::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_CaptureModuleState->m_ManualCoverState != CaptureModuleState::MANUAL_COVER_CLOSED_DARK &&
397 m_CaptureModuleState->shutterStatus == CaptureModuleState::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_CaptureModuleState->getLightBoxLightState() == CaptureModuleState::CAP_LIGHT_BUSY ||
416 m_CaptureModuleState->getDustCapState() == CaptureModuleState::CAP_PARKING ||
417 m_CaptureModuleState->getDustCapState() == CaptureModuleState::CAP_UNPARKING)
418 return IPS_BUSY;
419 // error occured
420 if (m_CaptureModuleState->getDustCapState() == CaptureModuleState::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 CaptureModuleState::CapState targetCapState = captureLights ? CaptureModuleState::CAP_IDLE : CaptureModuleState::CAP_PARKED;
427 // If cap is parked, unpark it since dark cap uses external light source.
428 if (m_CaptureModuleState->hasDustCap && m_CaptureModuleState->getDustCapState() != targetCapState)
429 {
430 m_CaptureModuleState->setDustCapState(captureLights ? CaptureModuleState::CAP_UNPARKING : CaptureModuleState::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 CaptureModuleState::LightState targetLightBoxStatus = captureFlats ? CaptureModuleState::CAP_LIGHT_ON :
438 CaptureModuleState::CAP_LIGHT_OFF;
439
440 if (m_CaptureModuleState->hasLightBox && m_CaptureModuleState->getLightBoxLightState() != targetLightBoxStatus)
441 {
442 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::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_CaptureModuleState->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 CaptureModuleState::LightState targetLightState = (captureFlats ? CaptureModuleState::CAP_LIGHT_ON :
483 CaptureModuleState::CAP_LIGHT_OFF);
484
485 if (m_CaptureModuleState->hasLightBox == true)
486 {
487 if (m_CaptureModuleState->getLightBoxLightState() != targetLightState)
488 {
489 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::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_CaptureModuleState->hasTelescope)
503 {
504 if (m_CaptureModuleState->getScopeParkState() == ISD::PARK_ERROR)
505 {
506 emit newLog(i18n("Parking mount failed, aborting..."));
507 emit abortCapture();
508 return IPS_ALERT;
509 }
510 else if (m_CaptureModuleState->getScopeParkState() == ISD::PARK_PARKING)
511 return IPS_BUSY;
512 else if (m_CaptureModuleState->getScopeParkState() != ISD::PARK_PARKED)
513 {
514 m_CaptureModuleState->setScopeParkState(ISD::PARK_PARKING);
515 emit setScopeParked(true);
516 emit newLog(i18n("Parking mount prior to calibration frames capture..."));
517 return IPS_BUSY;
518 }
519 }
520 // everything ready
521 return IPS_OK;
522}
523
524IPState SequenceJobState::checkPreDomeParkReady()
525{
526 if (m_CaptureModuleState->hasDome)
527 {
528 if (m_CaptureModuleState->getDomeState() == ISD::Dome::DOME_ERROR)
529 {
530 emit newLog(i18n("Parking dome failed, aborting..."));
531 emit abortCapture();
532 return IPS_ALERT;
533 }
534 else if (m_CaptureModuleState->getDomeState() == ISD::Dome::DOME_PARKING)
535 return IPS_BUSY;
536 else if (m_CaptureModuleState->getDomeState() != ISD::Dome::DOME_PARKED)
537 {
538 m_CaptureModuleState->setDomeState(ISD::Dome::DOME_PARKING);
539 emit setDomeParked(true);
540 emit newLog(i18n("Parking dome prior to calibration frames capture..."));
541 return IPS_BUSY;
542 }
543 }
544 // everything ready
545 return IPS_OK;
546}
547
548IPState SequenceJobState::checkFlatSyncFocus()
549{
550 // check already running?
551 if (flatSyncStatus == FS_BUSY)
552 {
553 QTimer::singleShot(1000, this, [this]
554 {
555 // wait for one second and repeat the request again
556 emit flatSyncFocus(targetFilterID);
557 });
558 return IPS_BUSY;
559 }
560
561 if (m_frameType == FRAME_FLAT && Options::flatSyncFocus() && flatSyncStatus != FS_COMPLETED)
562 {
563 flatSyncStatus = FS_BUSY;
564 emit flatSyncFocus(targetFilterID);
565 return IPS_BUSY;
566 }
567 // everything ready
568 return IPS_OK;
569}
570
571IPState SequenceJobState::checkHasShutter()
572{
573 if (m_CaptureModuleState->shutterStatus == CaptureModuleState::SHUTTER_BUSY)
574 return IPS_BUSY;
575 if (m_CaptureModuleState->shutterStatus != CaptureModuleState::SHUTTER_UNKNOWN)
576 return IPS_OK;
577 // query the status
578 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_BUSY;
579 emit queryHasShutter();
580 return IPS_BUSY;
581}
582
583IPState SequenceJobState::checkLightFrameScopeCoverOpen()
584{
585 // Account for light box only (no dust cap)
586 if (m_CaptureModuleState->hasLightBox && m_CaptureModuleState->getLightBoxLightState() != CaptureModuleState::CAP_LIGHT_OFF)
587 {
588 if (m_CaptureModuleState->getLightBoxLightState() != CaptureModuleState::CAP_LIGHT_BUSY)
589 {
590 m_CaptureModuleState->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_BUSY);
591 emit setLightBoxLight(false);
592 emit newLog(i18n("Turn light box light off..."));
593 }
594 return IPS_BUSY;
595 }
596
597 // If we have a dust cap, then we must unpark
598 if (m_CaptureModuleState->hasDustCap)
599 {
600 if (m_CaptureModuleState->getDustCapState() != CaptureModuleState::CAP_IDLE)
601 {
602 if (m_CaptureModuleState->getDustCapState() != CaptureModuleState::CAP_UNPARKING)
603 {
604 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_UNPARKING);
605 emit parkDustCap(false);
606 emit newLog(i18n("Unparking dust cap..."));
607 }
608 return IPS_BUSY;
609 }
610
611 return IPS_OK;
612 }
613
614 // If telescopes were MANUALLY covered before
615 // we need to manually uncover them.
616 if (m_CaptureModuleState->m_ManualCoverState != CaptureModuleState::MANAUL_COVER_OPEN)
617 {
618 // If we already asked for confirmation and waiting for it
619 // let us see if the confirmation is fulfilled
620 // otherwise we return.
621 if (coverQueryState == CAL_CHECK_CONFIRMATION)
622 return IPS_BUSY;
623
624 emit askManualScopeOpen(m_CaptureModuleState->m_ManualCoverState == CaptureModuleState::MANUAL_COVER_CLOSED_LIGHT);
625
626 return IPS_BUSY;
627 }
628
629 // scope cover open (or no scope cover)
630 return IPS_OK;
631}
632
633bool SequenceJobState::isInitialized(CaptureModuleState::PrepareActions action)
634{
635 return m_CaptureModuleState.data()->isInitialized[action];
636}
637
638void SequenceJobState::setInitialized(CaptureModuleState::PrepareActions action, bool init)
639{
640 m_CaptureModuleState.data()->isInitialized[action] = init;
641}
642
643void SequenceJobState::setCurrentFilterID(int value)
644{
645 m_CaptureModuleState->currentFilterID = value;
646 if (isInitialized(CaptureModuleState::ACTION_FILTER) == false && value != targetFilterID)
647 {
648 // mark filter preparation action
649 // TODO introduce settle time
650 prepareActions[CaptureModuleState::ACTION_FILTER] = false;
651
652 emit changeFilterPosition(targetFilterID, m_filterPolicy);
653 emit prepareState(CAPTURE_CHANGING_FILTER);
654 }
655 setInitialized(CaptureModuleState::ACTION_FILTER, true);
656
657 if (value == targetFilterID)
658 prepareActions[CaptureModuleState::ACTION_FILTER] = true;
659
660 checkAllActionsReady();
661}
662
663void SequenceJobState::setCurrentCCDTemperature(double currentTemperature)
664{
665 // skip if next value should be ignored
666 if (ignoreNextValue[CaptureModuleState::ACTION_TEMPERATURE])
667 {
668 ignoreNextValue[CaptureModuleState::ACTION_TEMPERATURE] = false;
669 return;
670 }
671
672 if (isInitialized(CaptureModuleState::ACTION_TEMPERATURE))
673 {
674 if (m_enforceTemperature == false
675 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
676 prepareActions[CaptureModuleState::ACTION_TEMPERATURE] = true;
677
678 checkAllActionsReady();
679 }
680 else
681 {
682 setInitialized(CaptureModuleState::ACTION_TEMPERATURE, true);
683 if (m_enforceTemperature == false
684 || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
685 {
686 prepareActions[CaptureModuleState::ACTION_TEMPERATURE] = true;
687 checkAllActionsReady();
688 }
689 else
690 {
691 prepareTemperatureCheck(m_enforceTemperature);
692 }
693 }
694}
695
696void SequenceJobState::setCurrentRotatorPositionAngle(double rotatorAngle, IPState state)
697{
698 double currentPositionAngle = RotatorUtils::Instance()->calcCameraAngle(rotatorAngle, false);
699
700 if (isInitialized(CaptureModuleState::ACTION_ROTATOR))
701 {
702 // TODO introduce settle time
703 // TODO make sure rotator has fully stopped -> see 'align.cpp' captureAndSolve()
704 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
705 && state != IPS_BUSY)
706 prepareActions[CaptureModuleState::ACTION_ROTATOR] = true;
707
708 checkAllActionsReady();
709 }
710 else
711 {
712 setInitialized(CaptureModuleState::ACTION_ROTATOR, true);
713 if (fabs(currentPositionAngle - targetPositionAngle) * 60 <= Options::astrometryRotatorThreshold()
714 && state != IPS_BUSY)
715 {
716 prepareActions[CaptureModuleState::ACTION_ROTATOR] = true;
717 checkAllActionsReady();
718 }
719 else
720 {
721 prepareRotatorCheck();
722 }
723 }
724}
725
726void SequenceJobState::setFocusStatus(FocusState state)
727{
728 switch (state)
729 {
730 case FOCUS_COMPLETE:
731 // did we wait for a successful autofocus run?
732 if (prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] == false)
733 {
734 prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] = true;
735 checkAllActionsReady();
736 }
737 break;
738 case FOCUS_ABORTED:
739 case FOCUS_FAILED:
740 // finish preparation with failure
741 emit prepareComplete(false);
742 break;
743 default:
744 // in all other cases do nothing
745 break;
746 }
747}
748
749void SequenceJobState::updateManualScopeCover(bool closed, bool success, bool light)
750{
751 // covering confirmed
752 if (success == true)
753 {
754 if (closed)
755 m_CaptureModuleState->m_ManualCoverState = light ? CaptureModuleState::MANUAL_COVER_CLOSED_LIGHT :
756 CaptureModuleState::MANUAL_COVER_CLOSED_DARK;
757 else
758 m_CaptureModuleState->m_ManualCoverState = CaptureModuleState::MANAUL_COVER_OPEN;
759 coverQueryState = CAL_CHECK_TASK;
760 // re-run checks
761 checkAllActionsReady();
762 }
763 // cancelled
764 else
765 {
766 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_UNKNOWN;
767 coverQueryState = CAL_CHECK_TASK;
768 // abort, no further checks
769 emit abortCapture();
770 }
771}
772
773void SequenceJobState::lightBoxLight(bool on)
774{
775 m_CaptureModuleState->setLightBoxLightState(on ? CaptureModuleState::CAP_LIGHT_ON : CaptureModuleState::CAP_LIGHT_OFF);
776 emit newLog(i18n(on ? "Light box on." : "Light box off."));
777 // re-run checks
778 checkAllActionsReady();
779}
780
781void SequenceJobState::dustCapStateChanged(ISD::DustCap::Status status)
782{
783 switch (status)
784 {
785 case ISD::DustCap::CAP_ERROR:
786 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_ERROR);
787 emit abortCapture();
788 break;
789 case ISD::DustCap::CAP_PARKED:
790 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_PARKED);
791 emit newLog(i18n("Dust cap parked."));
792 break;
793 case ISD::DustCap::CAP_IDLE:
794 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_IDLE);
795 emit newLog(i18n("Dust cap unparked."));
796 break;
797 case ISD::DustCap::CAP_UNPARKING:
798 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_UNPARKING);
799 break;
800 case ISD::DustCap::CAP_PARKING:
801 m_CaptureModuleState->setDustCapState(CaptureModuleState::CAP_PARKING);
802 break;
803 }
804
805 // re-run checks
806 checkAllActionsReady();
807}
808
809void SequenceJobState::scopeStatusChanged(ISD::Mount::Status status)
810{
811 // handle wall position
812 switch (status)
813 {
814 case ISD::Mount::MOUNT_TRACKING:
815 if (wpScopeStatus == WP_SLEWING)
816 wpScopeStatus = WP_SLEW_COMPLETED;
817 break;
818 case ISD::Mount::MOUNT_IDLE:
819 if (wpScopeStatus == WP_SLEWING || wpScopeStatus == WP_TRACKING_BUSY)
820 wpScopeStatus = WP_TRACKING_OFF;
821 break;
822 default:
823 // do nothing
824 break;
825 }
826 m_CaptureModuleState->setScopeState(status);
827 // re-run checks
828 checkAllActionsReady();
829}
830
831void SequenceJobState::scopeParkStatusChanged(ISD::ParkStatus status)
832{
833 m_CaptureModuleState->setScopeParkState(status);
834 // re-run checks
835 checkAllActionsReady();
836}
837
838void SequenceJobState::domeStatusChanged(ISD::Dome::Status status)
839{
840 m_CaptureModuleState->setDomeState(status);
841 // re-run checks
842 checkAllActionsReady();
843}
844
845void SequenceJobState::flatSyncFocusChanged(bool completed)
846{
847 flatSyncStatus = (completed ? FS_COMPLETED : FS_BUSY);
848 // re-run checks
849 checkAllActionsReady();
850}
851
852void SequenceJobState::hasShutter(bool present)
853{
854 if (present == true)
855 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_YES;
856 else
857 m_CaptureModuleState->shutterStatus = CaptureModuleState::SHUTTER_NO;
858
859 // re-run checks
860 checkAllActionsReady();
861}
862
863SequenceJobState::PreparationState SequenceJobState::getPreparationState() const
864{
865 return m_PreparationState;
866}
867
868void SequenceJobState::setFilterStatus(FilterState filterState)
869{
870 switch (filterState)
871 {
872 case FILTER_AUTOFOCUS:
873 // we need to wait until focusing has completed
874 prepareActions[CaptureModuleState::ACTION_AUTOFOCUS] = false;
875 emit prepareState(CAPTURE_FOCUSING);
876 break;
877
878 // nothing to do in all other cases
879 case FILTER_IDLE:
880 case FILTER_OFFSET:
881 case FILTER_CHANGE:
882 break;
883 }
884
885}
886} // 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
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
@ 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()
T * data() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.