1 /*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "sequencejob.h"
8
9 #include "kstars.h"
10 #include "kstarsdata.h"
11 #include "Options.h"
12 #include "indi/driverinfo.h"
13 #include "indi/clientmanager.h"
14 #include "ekos/scheduler/schedulerjob.h"
15
16 #include <KNotifications/KNotification>
17 #include <ekos_capture_debug.h>
18
19 #define MF_TIMER_TIMEOUT 90000
20 #define MF_RA_DIFF_LIMIT 4
21
22 namespace Ekos
23 {
24 QString const &SequenceJob::ISOMarker("_ISO8601");
25
SequenceJob()26 SequenceJob::SequenceJob()
27 {
28 statusStrings = QStringList() << i18n("Idle") << i18n("In Progress") << i18n("Error") << i18n("Aborted")
29 << i18n("Complete");
30 currentTemperature = targetTemperature = Ekos::INVALID_VALUE;
31 currentGuiderDrift = targetStartGuiderDrift = Ekos::INVALID_VALUE;
32 targetRotation = currentRotation = Ekos::INVALID_VALUE;
33
34 prepareActions[ACTION_FILTER] = true;
35 prepareActions[ACTION_TEMPERATURE] = true;
36 prepareActions[ACTION_ROTATOR] = true;
37 prepareActions[ACTION_GUIDER_DRIFT] = true;
38 }
39
SequenceJob(XMLEle * root)40 SequenceJob::SequenceJob(XMLEle *root):
41 SequenceJob()
42 {
43 XMLEle *ep = nullptr;
44 XMLEle *subEP = nullptr;
45
46 // We expect all data read from the XML to be in the C locale - QLocale::c().
47 QLocale cLocale = QLocale::c();
48
49 const QMap<QString, CCDFrameType> frameTypes =
50 {
51 { "Light", FRAME_LIGHT }, { "Dark", FRAME_DARK }, { "Bias", FRAME_BIAS }, { "Flat", FRAME_FLAT }
52 };
53
54 frameType = FRAME_NONE;
55 exposure = 0;
56 /* Reset light frame presence flag before enumerating */
57 // JM 2018-09-14: If last sequence job is not LIGHT
58 // then scheduler job light frame is set to whatever last sequence job is
59 // so if it was non-LIGHT, this value is set to false which is wrong.
60 //if (nullptr != schedJob)
61 // schedJob->setLightFramesRequired(false);
62
63 for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
64 {
65 if (!strcmp(tagXMLEle(ep), "Exposure"))
66 {
67 exposure = atof(pcdataXMLEle(ep));
68 }
69 else if (!strcmp(tagXMLEle(ep), "Filter"))
70 {
71 filter = QString(pcdataXMLEle(ep));
72 }
73 else if (!strcmp(tagXMLEle(ep), "Type"))
74 {
75 /* Record frame type and mark presence of light frames for this sequence */
76 QString frameTypeStr = QString(pcdataXMLEle(ep));
77 if (frameTypes.contains(frameTypeStr))
78 {
79 frameType = frameTypes[frameTypeStr];
80 }
81 //if (FRAME_LIGHT == frameType && nullptr != schedJob)
82 //schedJob->setLightFramesRequired(true);
83 }
84 else if (!strcmp(tagXMLEle(ep), "Prefix"))
85 {
86 subEP = findXMLEle(ep, "RawPrefix");
87 if (subEP)
88 m_RawPrefix = QString(pcdataXMLEle(subEP));
89
90 subEP = findXMLEle(ep, "FilterEnabled");
91 if (subEP)
92 filterPrefixEnabled = !strcmp("1", pcdataXMLEle(subEP));
93
94 subEP = findXMLEle(ep, "ExpEnabled");
95 if (subEP)
96 expPrefixEnabled = (!strcmp("1", pcdataXMLEle(subEP)));
97
98 subEP = findXMLEle(ep, "TimeStampEnabled");
99 if (subEP)
100 timeStampPrefixEnabled = (!strcmp("1", pcdataXMLEle(subEP)));
101
102 }
103 else if (!strcmp(tagXMLEle(ep), "Count"))
104 {
105 setCount(atoi(pcdataXMLEle(ep)));
106 }
107 else if (!strcmp(tagXMLEle(ep), "Delay"))
108 {
109 setDelay(atoi(pcdataXMLEle(ep)));
110 }
111 else if (!strcmp(tagXMLEle(ep), "FITSDirectory"))
112 {
113 setLocalDir(pcdataXMLEle(ep));
114 }
115 else if (!strcmp(tagXMLEle(ep), "RemoteDirectory"))
116 {
117 setRemoteDir(pcdataXMLEle(ep));
118 }
119 else if (!strcmp(tagXMLEle(ep), "UploadMode"))
120 {
121 setUploadMode(static_cast<ISD::CCD::UploadMode>(atoi(pcdataXMLEle(ep))));
122 }
123 else if (!strcmp(tagXMLEle(ep), "Calibration"))
124 {
125 subEP = findXMLEle(ep, "FlatSource");
126 if (subEP)
127 {
128 XMLEle * typeEP = findXMLEle(subEP, "Type");
129 if (typeEP)
130 {
131 if (!strcmp(pcdataXMLEle(typeEP), "Manual"))
132 setFlatFieldSource(SOURCE_MANUAL);
133 else if (!strcmp(pcdataXMLEle(typeEP), "FlatCap"))
134 setFlatFieldSource(SOURCE_FLATCAP);
135 else if (!strcmp(pcdataXMLEle(typeEP), "DarkCap"))
136 setFlatFieldSource(SOURCE_DARKCAP);
137 else if (!strcmp(pcdataXMLEle(typeEP), "Wall"))
138 {
139 XMLEle * azEP = findXMLEle(subEP, "Az");
140 XMLEle * altEP = findXMLEle(subEP, "Alt");
141
142 if (azEP && altEP)
143 {
144 setFlatFieldSource(SOURCE_WALL);
145 SkyPoint wallCoord;
146 wallCoord.setAz(dms::fromString(pcdataXMLEle(azEP), true));
147 wallCoord.setAlt(dms::fromString(pcdataXMLEle(altEP), true));
148 setWallCoord(wallCoord);
149 }
150 }
151 else
152 setFlatFieldSource(SOURCE_DAWN_DUSK);
153 }
154 }
155
156 subEP = findXMLEle(ep, "FlatDuration");
157 if (subEP)
158 {
159 XMLEle * typeEP = findXMLEle(subEP, "Type");
160 if (typeEP)
161 {
162 if (!strcmp(pcdataXMLEle(typeEP), "Manual"))
163 setFlatFieldDuration(DURATION_MANUAL);
164 }
165
166 XMLEle * aduEP = findXMLEle(subEP, "Value");
167 if (aduEP)
168 {
169 setFlatFieldDuration(DURATION_ADU);
170 setTargetADU(cLocale.toDouble(pcdataXMLEle(aduEP)));
171 }
172
173 aduEP = findXMLEle(subEP, "Tolerance");
174 if (aduEP)
175 {
176 setTargetADUTolerance(cLocale.toDouble(pcdataXMLEle(aduEP)));
177 }
178 }
179
180 subEP = findXMLEle(ep, "PreMountPark");
181 if (subEP)
182 {
183 setPreMountPark(!strcmp(pcdataXMLEle(subEP), "True"));
184 }
185
186 subEP = findXMLEle(ep, "PreDomePark");
187 if (subEP)
188 {
189 setPreDomePark(!strcmp(pcdataXMLEle(subEP), "True"));
190 }
191 }
192 }
193 }
194
resetStatus()195 void SequenceJob::resetStatus()
196 {
197 setStatus(JOB_IDLE);
198 setCompleted(0);
199 exposeLeft = 0;
200 captureRetires = 0;
201 m_JobProgressIgnored = false;
202 }
203
abort()204 void SequenceJob::abort()
205 {
206 setStatus(JOB_ABORTED);
207 if (activeChip->canAbort())
208 activeChip->abortExposure();
209 activeChip->setBatchMode(false);
210 }
211
done()212 void SequenceJob::done()
213 {
214 setStatus(JOB_DONE);
215 }
216
prepareCapture()217 void SequenceJob::prepareCapture()
218 {
219 status = JOB_BUSY;
220
221 prepareReady = false;
222
223 // Reset all prepare actions
224 setAllActionsReady();
225
226 activeChip->setBatchMode(!preview);
227
228 // Filter changes are actually done in capture();
229 prepareActions[ACTION_FILTER] = true;
230 if (targetFilter != -1 && activeFilter != nullptr &&
231 frameType == FRAME_LIGHT && targetFilter != currentFilter)
232 emit prepareState(CAPTURE_CHANGING_FILTER);
233
234 // Check if we need to update temperature
235 if (enforceTemperature && fabs(targetTemperature - currentTemperature) > Options::maxTemperatureDiff())
236 {
237 prepareActions[ACTION_TEMPERATURE] = false;
238 emit prepareState(CAPTURE_SETTING_TEMPERATURE);
239 activeCCD->setTemperature(targetTemperature);
240 }
241
242 // Check if we need to wait for the guider to settle.
243 if (!guiderDriftOK())
244 {
245 prepareActions[ACTION_GUIDER_DRIFT] = false;
246 emit prepareState(CAPTURE_GUIDER_DRIFT);
247 }
248
249 // Check if we need to update rotator
250 if (targetRotation != Ekos::INVALID_VALUE
251 && fabs(currentRotation - targetRotation) * 60 > Options::astrometryRotatorThreshold())
252 {
253 // PA = RawAngle * Multiplier + Offset
254 double rawAngle = (targetRotation - Options::pAOffset()) / Options::pAMultiplier();
255 prepareActions[ACTION_ROTATOR] = false;
256 emit prepareState(CAPTURE_SETTING_ROTATOR);
257 activeRotator->runCommand(INDI_SET_ROTATOR_ANGLE, &rawAngle);
258 }
259
260 if (prepareReady == false && areActionsReady())
261 {
262 prepareReady = true;
263 emit prepareComplete();
264 }
265 }
266
setAllActionsReady()267 void SequenceJob::setAllActionsReady()
268 {
269 QMutableMapIterator<PrepareActions, bool> i(prepareActions);
270
271 while (i.hasNext())
272 {
273 i.next();
274 i.setValue(true);
275 }
276 }
277
setStatus(JOBStatus const in_status)278 void SequenceJob::setStatus(JOBStatus const in_status)
279 {
280 status = in_status;
281 if( !preview && nullptr != statusCell)
282 statusCell->setText(statusStrings[in_status]);
283 }
284
setStatusCell(QTableWidgetItem * cell)285 void SequenceJob::setStatusCell(QTableWidgetItem* cell)
286 {
287 statusCell = cell;
288 if (nullptr != cell)
289 {
290 cell->setTextAlignment(Qt::AlignHCenter);
291 cell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
292 setStatus(getStatus());
293 }
294 }
295
setCount(int in_count)296 void SequenceJob::setCount(int in_count)
297 {
298 count = in_count;
299 if( !preview && nullptr != countCell)
300 countCell->setText(QString("%L1/%L2").arg(completed).arg(in_count));
301 }
302
setCompleted(int in_completed)303 void SequenceJob::setCompleted(int in_completed)
304 {
305 completed = in_completed;
306 if( !preview && nullptr != countCell)
307 countCell->setText(QString("%L1/%L2").arg(in_completed).arg(count));
308 }
309
setCountCell(QTableWidgetItem * cell)310 void SequenceJob::setCountCell(QTableWidgetItem* cell)
311 {
312 countCell = cell;
313 if (nullptr != cell)
314 {
315 cell->setTextAlignment(Qt::AlignHCenter);
316 cell->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
317 setCount(getCount());
318 }
319 }
320
getJobProgressIgnored() const321 bool SequenceJob::getJobProgressIgnored() const
322 {
323 return m_JobProgressIgnored;
324 }
325
setJobProgressIgnored(bool JobProgressIgnored)326 void SequenceJob::setJobProgressIgnored(bool JobProgressIgnored)
327 {
328 m_JobProgressIgnored = JobProgressIgnored;
329 }
330
getDirectoryPostfix() const331 QString SequenceJob::getDirectoryPostfix() const
332 {
333 return directoryPostfix;
334 }
335
setDirectoryPostfix(const QString & value)336 void SequenceJob::setDirectoryPostfix(const QString &value)
337 {
338 directoryPostfix = value;
339 }
340
getCustomProperties() const341 QMap<QString, QMap<QString, double> > SequenceJob::getCustomProperties() const
342 {
343 return customProperties;
344 }
345
setCustomProperties(const QMap<QString,QMap<QString,double>> & value)346 void SequenceJob::setCustomProperties(const QMap<QString, QMap<QString, double> > &value)
347 {
348 customProperties = value;
349 }
350
areActionsReady()351 bool SequenceJob::areActionsReady()
352 {
353 for (bool &ready : prepareActions.values())
354 {
355 if (ready == false)
356 return false;
357 }
358
359 return true;
360 }
361
capture(bool autofocusReady)362 SequenceJob::CAPTUREResult SequenceJob::capture(bool autofocusReady)
363 {
364 activeChip->setBatchMode(!preview);
365
366 activeCCD->setISOMode(timeStampPrefixEnabled);
367
368 activeCCD->setSeqPrefix(fullPrefix);
369
370 auto placeholderPath = Ekos::PlaceholderPath(localDirectory + "/sequence.esq");
371 placeholderPath.setGenerateFilenameSettings(*this);
372 activeCCD->setPlaceholderPath(placeholderPath);
373
374 if (preview)
375 {
376 if (activeCCD->getUploadMode() != ISD::CCD::UPLOAD_CLIENT)
377 activeCCD->setUploadMode(ISD::CCD::UPLOAD_CLIENT);
378 }
379 else
380 activeCCD->setUploadMode(uploadMode);
381
382 QMapIterator<QString, QMap<QString, double>> i(customProperties);
383 while (i.hasNext())
384 {
385 i.next();
386 INDI::Property *customProp = activeCCD->getProperty(i.key());
387 if (customProp)
388 {
389 QMap<QString, double> numbers = i.value();
390 QMapIterator<QString, double> j(numbers);
391 auto np = customProp->getNumber();
392 while (j.hasNext())
393 {
394 j.next();
395 auto oneNumber = np->findWidgetByName(j.key().toLatin1().data());
396 if (oneNumber)
397 oneNumber->setValue(j.value());
398 }
399
400 activeCCD->getDriverInfo()->getClientManager()->sendNewNumber(np);
401 }
402 }
403
404 if (activeChip->isBatchMode() && remoteDirectory.isEmpty() == false)
405 activeCCD->updateUploadSettings(remoteDirectory + directoryPostfix);
406
407 if (isoIndex != -1)
408 {
409 if (isoIndex != activeChip->getISOIndex())
410 activeChip->setISOIndex(isoIndex);
411 }
412
413 if (gain != -1)
414 {
415 activeCCD->setGain(gain);
416 }
417
418 if (offset != -1)
419 {
420 activeCCD->setOffset(offset);
421 }
422
423 if (targetFilter != -1 && activeFilter != nullptr)
424 {
425 if (targetFilter != currentFilter)
426 {
427 emit prepareState(CAPTURE_CHANGING_FILTER);
428
429 FilterManager::FilterPolicy policy = FilterManager::ALL_POLICIES;
430 // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet.
431 if (isPreview() || frameType != FRAME_LIGHT || autofocusReady == false)
432 policy = static_cast<FilterManager::FilterPolicy>(policy & ~FilterManager::AUTOFOCUS_POLICY);
433
434 filterManager->setFilterPosition(targetFilter, policy);
435 return CAPTURE_FILTER_BUSY;
436 }
437 }
438
439 if (!guiderDriftOK())
440 {
441 emit prepareState(CAPTURE_GUIDER_DRIFT);
442 return CAPTURE_GUIDER_DRIFT_WAIT;
443 }
444
445 // Only attempt to set ROI and Binning if CCD transfer format is FITS
446 if (activeCCD->getTransferFormat() == ISD::CCD::FORMAT_FITS)
447 {
448 int currentBinX = 1, currentBinY = 1;
449 activeChip->getBinning(¤tBinX, ¤tBinY);
450
451 // N.B. Always set binning _before_ setting frame because if the subframed image
452 // is problematic in 1x1 but works fine for 2x2, then it would fail it was set first
453 // So setting binning first always ensures this will work.
454 if (activeChip->canBin() && activeChip->setBinning(binX, binY) == false)
455 {
456 setStatus(JOB_ERROR);
457 return CAPTURE_BIN_ERROR;
458 }
459
460 if ((w > 0 && h > 0) && activeChip->canSubframe() && activeChip->setFrame(x, y, w, h, currentBinX != binX) == false)
461 {
462 setStatus(JOB_ERROR);
463 return CAPTURE_FRAME_ERROR;
464 }
465 }
466
467 activeChip->setFrameType(frameType);
468 activeChip->setCaptureMode(FITS_NORMAL);
469 activeChip->setCaptureFilter(FITS_NONE);
470
471 // If filter is different that CCD, send the filter info
472 // if (activeFilter && activeFilter != activeCCD)
473 // activeCCD->setFilter(filter);
474
475 //status = JOB_BUSY;
476 setStatus(getStatus());
477
478 exposeLeft = exposure;
479
480 activeChip->capture(exposure);
481
482 return CAPTURE_OK;
483 }
484
setTargetFilter(int pos,const QString & name)485 void SequenceJob::setTargetFilter(int pos, const QString &name)
486 {
487 targetFilter = pos;
488 filter = name;
489 }
490
setFrameType(CCDFrameType type)491 void SequenceJob::setFrameType(CCDFrameType type)
492 {
493 frameType = type;
494 }
495
getExposeLeft() const496 double SequenceJob::getExposeLeft() const
497 {
498 return exposeLeft;
499 }
500
setExposeLeft(double value)501 void SequenceJob::setExposeLeft(double value)
502 {
503 exposeLeft = value;
504 }
505
setPrefixSettings(const QString & rawFilePrefix,bool filterEnabled,bool exposureEnabled,bool tsEnabled)506 void SequenceJob::setPrefixSettings(const QString &rawFilePrefix, bool filterEnabled, bool exposureEnabled,
507 bool tsEnabled)
508 {
509 m_RawPrefix = rawFilePrefix;
510 filterPrefixEnabled = filterEnabled;
511 expPrefixEnabled = exposureEnabled;
512 timeStampPrefixEnabled = tsEnabled;
513 }
514
getPrefixSettings(QString & rawFilePrefix,bool & filterEnabled,bool & exposureEnabled,bool & tsEnabled)515 void SequenceJob::getPrefixSettings(QString &rawFilePrefix, bool &filterEnabled, bool &exposureEnabled, bool &tsEnabled)
516 {
517 rawFilePrefix = m_RawPrefix;
518 filterEnabled = filterPrefixEnabled;
519 exposureEnabled = expPrefixEnabled;
520 tsEnabled = timeStampPrefixEnabled;
521 }
522
getCurrentTemperature() const523 double SequenceJob::getCurrentTemperature() const
524 {
525 return currentTemperature;
526 }
527
setCurrentTemperature(double value)528 void SequenceJob::setCurrentTemperature(double value)
529 {
530 currentTemperature = value;
531
532 if (enforceTemperature == false || fabs(targetTemperature - currentTemperature) <= Options::maxTemperatureDiff())
533 prepareActions[ACTION_TEMPERATURE] = true;
534
535 if (prepareReady == false && areActionsReady())
536 {
537 prepareReady = true;
538 emit prepareComplete();
539 }
540 }
541
getTargetTemperature() const542 double SequenceJob::getTargetTemperature() const
543 {
544 return targetTemperature;
545 }
546
setTargetTemperature(double value)547 void SequenceJob::setTargetTemperature(double value)
548 {
549 targetTemperature = value;
550 }
551
setTargetStartGuiderDrift(double value)552 void SequenceJob::setTargetStartGuiderDrift(double value)
553 {
554 targetStartGuiderDrift = value;
555 }
556
getTargetStartGuiderDrift() const557 double SequenceJob::getTargetStartGuiderDrift() const
558 {
559 return targetStartGuiderDrift;
560 }
561
getTargetADU() const562 double SequenceJob::getTargetADU() const
563 {
564 return calibrationSettings.targetADU;
565 }
566
setTargetADU(double value)567 void SequenceJob::setTargetADU(double value)
568 {
569 calibrationSettings.targetADU = value;
570 }
571
getTargetADUTolerance() const572 double SequenceJob::getTargetADUTolerance() const
573 {
574 return calibrationSettings.targetADUTolerance;
575 }
576
setTargetADUTolerance(double value)577 void SequenceJob::setTargetADUTolerance(double value)
578 {
579 calibrationSettings.targetADUTolerance = value;
580 }
581
getCaptureRetires() const582 int SequenceJob::getCaptureRetires() const
583 {
584 return captureRetires;
585 }
586
setCaptureRetires(int value)587 void SequenceJob::setCaptureRetires(int value)
588 {
589 captureRetires = value;
590 }
591
getFlatFieldSource() const592 FlatFieldSource SequenceJob::getFlatFieldSource() const
593 {
594 return calibrationSettings.flatFieldSource;
595 }
596
setFlatFieldSource(const FlatFieldSource & value)597 void SequenceJob::setFlatFieldSource(const FlatFieldSource &value)
598 {
599 calibrationSettings.flatFieldSource = value;
600 }
601
getFlatFieldDuration() const602 FlatFieldDuration SequenceJob::getFlatFieldDuration() const
603 {
604 return calibrationSettings.flatFieldDuration;
605 }
606
setFlatFieldDuration(const FlatFieldDuration & value)607 void SequenceJob::setFlatFieldDuration(const FlatFieldDuration &value)
608 {
609 calibrationSettings.flatFieldDuration = value;
610 }
611
getWallCoord() const612 SkyPoint SequenceJob::getWallCoord() const
613 {
614 return calibrationSettings.wallCoord;
615 }
616
setWallCoord(const SkyPoint & value)617 void SequenceJob::setWallCoord(const SkyPoint &value)
618 {
619 calibrationSettings.wallCoord = value;
620 }
621
isPreMountPark() const622 bool SequenceJob::isPreMountPark() const
623 {
624 return calibrationSettings.preMountPark;
625 }
626
setPreMountPark(bool value)627 void SequenceJob::setPreMountPark(bool value)
628 {
629 calibrationSettings.preMountPark = value;
630 }
631
isPreDomePark() const632 bool SequenceJob::isPreDomePark() const
633 {
634 return calibrationSettings.preDomePark;
635 }
636
setPreDomePark(bool value)637 void SequenceJob::setPreDomePark(bool value)
638 {
639 calibrationSettings.preDomePark = value;
640 }
641
getEnforceTemperature() const642 bool SequenceJob::getEnforceTemperature() const
643 {
644 return enforceTemperature;
645 }
646
setEnforceTemperature(bool value)647 void SequenceJob::setEnforceTemperature(bool value)
648 {
649 enforceTemperature = value;
650 }
651
getEnforceStartGuiderDrift() const652 bool SequenceJob::getEnforceStartGuiderDrift() const
653 {
654 return enforceStartGuiderDrift;
655 }
656
setEnforceStartGuiderDrift(bool value)657 void SequenceJob::setEnforceStartGuiderDrift(bool value)
658 {
659 enforceStartGuiderDrift = value;
660 }
661
getUploadMode() const662 ISD::CCD::UploadMode SequenceJob::getUploadMode() const
663 {
664 return uploadMode;
665 }
666
setUploadMode(const ISD::CCD::UploadMode & value)667 void SequenceJob::setUploadMode(const ISD::CCD::UploadMode &value)
668 {
669 uploadMode = value;
670 }
671
getRemoteDir() const672 QString SequenceJob::getRemoteDir() const
673 {
674 return remoteDirectory;
675 }
676
setRemoteDir(const QString & value)677 void SequenceJob::setRemoteDir(const QString &value)
678 {
679 remoteDirectory = value;
680 if (remoteDirectory.endsWith('/'))
681 remoteDirectory.chop(1);
682 }
683
getTransforFormat() const684 ISD::CCD::TransferFormat SequenceJob::getTransforFormat() const
685 {
686 return transforFormat;
687 }
688
setTransforFormat(const ISD::CCD::TransferFormat & value)689 void SequenceJob::setTransforFormat(const ISD::CCD::TransferFormat &value)
690 {
691 transforFormat = value;
692 }
693
getGain() const694 double SequenceJob::getGain() const
695 {
696 return gain;
697 }
698
setGain(double value)699 void SequenceJob::setGain(double value)
700 {
701 gain = value;
702 }
703
getOffset() const704 double SequenceJob::getOffset() const
705 {
706 return offset;
707 }
708
setOffset(double value)709 void SequenceJob::setOffset(double value)
710 {
711 offset = value;
712 }
713
getTargetRotation() const714 double SequenceJob::getTargetRotation() const
715 {
716 return targetRotation;
717 }
718
setTargetRotation(double value)719 void SequenceJob::setTargetRotation(double value)
720 {
721 targetRotation = value;
722 }
723
getISOIndex() const724 int SequenceJob::getISOIndex() const
725 {
726 return isoIndex;
727 }
728
setISOIndex(int value)729 void SequenceJob::setISOIndex(int value)
730 {
731 isoIndex = value;
732 }
733
getCurrentFilter() const734 int SequenceJob::getCurrentFilter() const
735 {
736 return currentFilter;
737 }
738
setCurrentFilter(int value)739 void SequenceJob::setCurrentFilter(int value)
740 {
741 currentFilter = value;
742
743 if (currentFilter == targetFilter)
744 prepareActions[ACTION_FILTER] = true;
745
746 if (prepareReady == false && areActionsReady())
747 {
748 prepareReady = true;
749 emit prepareComplete();
750 }
751 }
752
setCurrentRotation(double value)753 void SequenceJob::setCurrentRotation(double value)
754 {
755 currentRotation = value;
756
757 if (fabs(currentRotation - targetRotation) * 60 <= Options::astrometryRotatorThreshold())
758 prepareActions[ACTION_ROTATOR] = true;
759
760 if (prepareReady == false && areActionsReady())
761 {
762 prepareReady = true;
763 emit prepareComplete();
764 }
765
766 }
767
getCurrentGuiderDrift() const768 double SequenceJob::getCurrentGuiderDrift() const
769 {
770 return currentGuiderDrift;
771 }
772
resetCurrentGuiderDrift()773 void SequenceJob::resetCurrentGuiderDrift()
774 {
775 setCurrentGuiderDrift(1e8);
776 }
777
guiderDriftOK() const778 bool SequenceJob::guiderDriftOK() const
779 {
780 return (!guiderActive ||
781 !enforceStartGuiderDrift ||
782 frameType != FRAME_LIGHT ||
783 currentGuiderDrift <= targetStartGuiderDrift);
784 }
785
setCurrentGuiderDrift(double value)786 void SequenceJob::setCurrentGuiderDrift(double value)
787 {
788 currentGuiderDrift = value;
789 prepareActions[ACTION_GUIDER_DRIFT] = guiderDriftOK();
790
791 if (prepareReady == false && areActionsReady())
792 {
793 prepareReady = true;
794 emit prepareComplete();
795 }
796 }
797
798 }
799