Kstars

sequencejob.cpp
1 /*
2  SPDX-FileCopyrightText: 2012 Jasem Mutlaq <[email protected]>
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 
26 const QStringList SequenceJob::StatusStrings = QStringList() << i18n("Idle") << i18n("In Progress") << i18n("Error") <<
27  i18n("Aborted")
28  << i18n("Complete");
29 
30 
31 SequenceJob::SequenceJob()
32 {
33  // Set default property values
34  m_CoreProperties[SJ_Exposure] = -1;
35  m_CoreProperties[SJ_Gain] = -1;
36  m_CoreProperties[SJ_Offset] = -1;
37  m_CoreProperties[SJ_ISOIndex] = -1;
38  m_CoreProperties[SJ_Count] = -1;
39  m_CoreProperties[SJ_Delay] = -1;
40  m_CoreProperties[SJ_Binning] = QPoint(1, 1);
41  m_CoreProperties[SJ_ROI] = QRect(0, 0, 0, 0);
42  m_CoreProperties[SJ_ExpPrefixEnabled] = false;
43  m_CoreProperties[SJ_TimeStampPrefixEnabled] = false;
44  m_CoreProperties[SJ_EnforceTemperature] = false;
45  m_CoreProperties[SJ_FilterPrefixEnabled] = false;
46  m_CoreProperties[SJ_DarkFlat] = false;
47  m_CoreProperties[SJ_GuiderActive] = false;
48  m_CoreProperties[SJ_Encoding] = "FITS";
49 }
50 
51 SequenceJob::SequenceJob(const QSharedPointer<CaptureDeviceAdaptor> cp,
53 {
54  captureDeviceAdaptor = cp;
55  // initialize the state machine
56  stateMachine = new SequenceJobState(sharedState);
57 
58  // signal forwarding between this and the state machine
59  connect(this, &SequenceJob::updateGuiderDrift, stateMachine, &SequenceJobState::setCurrentGuiderDrift);
60  connect(stateMachine, &SequenceJobState::prepareState, this, &SequenceJob::prepareState);
61  connect(stateMachine, &SequenceJobState::prepareComplete, this, &SequenceJob::processPrepareComplete);
62  connect(stateMachine, &SequenceJobState::abortCapture, this, &SequenceJob::processAbortCapture);
63  connect(stateMachine, &SequenceJobState::newLog, this, &SequenceJob::newLog);
64 }
65 
66 /**
67  * @brief SequenceJob::SequenceJob Construct job from XML source
68  * @param root pointer to valid job stored in XML format.
69  */
70 SequenceJob::SequenceJob(XMLEle *root): SequenceJob()
71 {
72  XMLEle *ep = nullptr;
73  XMLEle *subEP = nullptr;
74 
75  // set own unconnected state machine
77  sharedState.reset(new SequenceJobState::CaptureState);
78  stateMachine = new SequenceJobState(sharedState);
79 
80  // We expect all data read from the XML to be in the C locale - QLocale::c().
81  QLocale cLocale = QLocale::c();
82 
83  const QMap<QString, CCDFrameType> frameTypes =
84  {
85  { "Light", FRAME_LIGHT }, { "Dark", FRAME_DARK }, { "Bias", FRAME_BIAS }, { "Flat", FRAME_FLAT }
86  };
87 
88  setFrameType(FRAME_NONE);
89  setCoreProperty(SJ_Exposure, 0);
90  /* Reset light frame presence flag before enumerating */
91  // JM 2018-09-14: If last sequence job is not LIGHT
92  // then scheduler job light frame is set to whatever last sequence job is
93  // so if it was non-LIGHT, this value is set to false which is wrong.
94  //if (nullptr != schedJob)
95  // schedJob->setLightFramesRequired(false);
96 
97  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
98  {
99  if (!strcmp(tagXMLEle(ep), "Exposure"))
100  {
101  setCoreProperty(SJ_Exposure, atof(pcdataXMLEle(ep)));
102  }
103  if (!strcmp(tagXMLEle(ep), "Format"))
104  {
105  setCoreProperty(SJ_Format, pcdataXMLEle(ep));
106  }
107  if (!strcmp(tagXMLEle(ep), "Encoding"))
108  {
109  setCoreProperty(SJ_Encoding, pcdataXMLEle(ep));
110  }
111  else if (!strcmp(tagXMLEle(ep), "Filter"))
112  {
113  setCoreProperty(SJ_Filter, QString(pcdataXMLEle(ep)));
114  }
115  else if (!strcmp(tagXMLEle(ep), "Type"))
116  {
117  /* Record frame type and mark presence of light frames for this sequence */
118  QString frameTypeStr = QString(pcdataXMLEle(ep));
119  if (frameTypes.contains(frameTypeStr))
120  {
121  setFrameType(frameTypes[frameTypeStr]);
122  }
123  //if (FRAME_LIGHT == frameType && nullptr != schedJob)
124  //schedJob->setLightFramesRequired(true);
125  }
126  else if (!strcmp(tagXMLEle(ep), "Prefix"))
127  {
128  subEP = findXMLEle(ep, "RawPrefix");
129  if (subEP)
130  setCoreProperty(SJ_RawPrefix, QString(pcdataXMLEle(subEP)));
131 
132  subEP = findXMLEle(ep, "FilterEnabled");
133  if (subEP)
134  setCoreProperty(SJ_FilterPrefixEnabled, !strcmp("1", pcdataXMLEle(subEP)));
135 
136  subEP = findXMLEle(ep, "ExpEnabled");
137  if (subEP)
138  setCoreProperty(SJ_ExpPrefixEnabled, (!strcmp("1", pcdataXMLEle(subEP))));
139 
140  subEP = findXMLEle(ep, "TimeStampEnabled");
141  if (subEP)
142  setCoreProperty(SJ_TimeStampPrefixEnabled, (!strcmp("1", pcdataXMLEle(subEP))));
143 
144  }
145  else if (!strcmp(tagXMLEle(ep), "Count"))
146  {
147  setCoreProperty(SJ_Count, atoi(pcdataXMLEle(ep)));
148  }
149  else if (!strcmp(tagXMLEle(ep), "Delay"))
150  {
151  setCoreProperty(SJ_Delay, atoi(pcdataXMLEle(ep)));
152  }
153  else if (!strcmp(tagXMLEle(ep), "FITSDirectory"))
154  {
155  setCoreProperty(SJ_LocalDirectory, (pcdataXMLEle(ep)));
156  }
157  else if (!strcmp(tagXMLEle(ep), "RemoteDirectory"))
158  {
159  setCoreProperty(SJ_RemoteDirectory, (pcdataXMLEle(ep)));
160  }
161  else if (!strcmp(tagXMLEle(ep), "UploadMode"))
162  {
163  setUploadMode(static_cast<ISD::Camera::UploadMode>(atoi(pcdataXMLEle(ep))));
164  }
165  else if (!strcmp(tagXMLEle(ep), "Calibration"))
166  {
167  subEP = findXMLEle(ep, "FlatSource");
168  if (subEP)
169  {
170  XMLEle * typeEP = findXMLEle(subEP, "Type");
171  if (typeEP)
172  {
173  if (!strcmp(pcdataXMLEle(typeEP), "Manual"))
174  setFlatFieldSource(SOURCE_MANUAL);
175  else if (!strcmp(pcdataXMLEle(typeEP), "FlatCap"))
176  setFlatFieldSource(SOURCE_FLATCAP);
177  else if (!strcmp(pcdataXMLEle(typeEP), "DarkCap"))
178  setFlatFieldSource(SOURCE_DARKCAP);
179  else if (!strcmp(pcdataXMLEle(typeEP), "Wall"))
180  {
181  XMLEle * azEP = findXMLEle(subEP, "Az");
182  XMLEle * altEP = findXMLEle(subEP, "Alt");
183 
184  if (azEP && altEP)
185  {
186  setFlatFieldSource(SOURCE_WALL);
187  SkyPoint wallCoord;
188  wallCoord.setAz(dms::fromString(pcdataXMLEle(azEP), true));
189  wallCoord.setAlt(dms::fromString(pcdataXMLEle(altEP), true));
190  setWallCoord(wallCoord);
191  }
192  }
193  else
194  setFlatFieldSource(SOURCE_DAWN_DUSK);
195  }
196  }
197 
198  subEP = findXMLEle(ep, "FlatDuration");
199  if (subEP)
200  {
201  const char * dark = findXMLAttValu(subEP, "dark");
202  setCoreProperty(SJ_DarkFlat, !strcmp(dark, "true"));
203 
204  XMLEle * typeEP = findXMLEle(subEP, "Type");
205 
206  if (typeEP)
207  {
208  if (!strcmp(pcdataXMLEle(typeEP), "Manual"))
209  setFlatFieldDuration(DURATION_MANUAL);
210  }
211 
212  XMLEle * aduEP = findXMLEle(subEP, "Value");
213  if (aduEP)
214  {
215  setFlatFieldDuration(DURATION_ADU);
216  setCoreProperty(SJ_TargetADU, cLocale.toDouble(pcdataXMLEle(aduEP)));
217  }
218 
219  aduEP = findXMLEle(subEP, "Tolerance");
220  if (aduEP)
221  {
222  setCoreProperty(SJ_TargetADUTolerance, cLocale.toDouble(pcdataXMLEle(aduEP)));
223  }
224  }
225 
226  subEP = findXMLEle(ep, "PreMountPark");
227  if (subEP)
228  {
229  setPreMountPark(!strcmp(pcdataXMLEle(subEP), "True"));
230  }
231 
232  subEP = findXMLEle(ep, "PreDomePark");
233  if (subEP)
234  {
235  setPreDomePark(!strcmp(pcdataXMLEle(subEP), "True"));
236  }
237  }
238  }
239 }
240 
241 void SequenceJob::resetStatus(JOBStatus status)
242 {
243  setStatus(status);
244  setCalibrationStage(SequenceJobState::CAL_NONE);
245  switch (status)
246  {
247  case JOB_IDLE:
248  setCompleted(0);
249  // 2022.03.10: Keeps failing on Windows despite installing latest libindi
250 #ifndef Q_OS_WIN
251  INDI_FALLTHROUGH;
252 #endif
253  case JOB_ERROR:
254  case JOB_ABORTED:
255  case JOB_DONE:
256  m_ExposeLeft = 0;
257  m_CaptureRetires = 0;
258  m_JobProgressIgnored = false;
259  break;
260  case JOB_BUSY:
261  // do nothing
262  break;
263  }
264 }
265 
266 void SequenceJob::abort()
267 {
268  setStatus(JOB_ABORTED);
269  if (captureDeviceAdaptor.data()->getActiveChip()->canAbort())
270  captureDeviceAdaptor.data()->getActiveChip()->abortExposure();
271  captureDeviceAdaptor.data()->getActiveChip()->setBatchMode(false);
272 }
273 
274 void SequenceJob::done()
275 {
276  setStatus(JOB_DONE);
277 }
278 
279 int SequenceJob::getJobRemainingTime(double estimatedDownloadTime)
280 {
281  double remaining = (getCoreProperty(SJ_Exposure).toDouble() +
282  estimatedDownloadTime +
283  getCoreProperty(SJ_Delay).toDouble() / 1000) *
284  (getCoreProperty(SJ_Count).toDouble() - getCompleted());
285 
286  if (getStatus() == JOB_BUSY)
287  {
288  if (getExposeLeft() > 0.0)
289  remaining -= getCoreProperty(SJ_Exposure).toDouble() - getExposeLeft();
290  else
291  remaining += getExposeLeft() + estimatedDownloadTime;
292  }
293 
294  return static_cast<int>(std::round(remaining));
295 }
296 
297 void SequenceJob::setStatus(JOBStatus const in_status)
298 {
299  stateMachine->reset(in_status);
300  if( !getCoreProperty(SequenceJob::SJ_Preview).toBool() && nullptr != statusCell)
301  statusCell->setText(StatusStrings[in_status]);
302 }
303 
304 void SequenceJob::setStatusCell(QTableWidgetItem* cell)
305 {
306  statusCell = cell;
307  if (nullptr != cell)
308  {
311  setStatus(getStatus());
312  }
313 }
314 
315 void SequenceJob::setCompleted(int value)
316 {
317  m_Completed = value;
318  if( !getCoreProperty(SequenceJob::SJ_Preview).toBool() && nullptr != countCell)
319  countCell->setText(QString("%L1/%L2").arg(value).arg(getCoreProperty(SJ_Count).toInt()));
320 }
321 
322 int SequenceJob::getCompleted() const
323 {
324  return m_Completed;
325 }
326 
327 void SequenceJob::setCountCell(QTableWidgetItem* cell)
328 {
329  countCell = cell;
330  if (nullptr != cell)
331  {
334  setCoreProperty(SJ_Count, getCoreProperty(SJ_Count));
335  }
336 }
337 
338 
339 
340 QMap<QString, QMap<QString, QVariant> > SequenceJob::getCustomProperties() const
341 {
342  return m_CustomProperties;
343 }
344 
345 void SequenceJob::setCustomProperties(const QMap<QString, QMap<QString, QVariant> > &value)
346 {
347  m_CustomProperties = value;
348 }
349 
350 const QMap<ScriptTypes, QString> &SequenceJob::getScripts() const
351 {
352  return m_Scripts;
353 }
354 
355 void SequenceJob::setScripts(const QMap<ScriptTypes, QString> &scripts)
356 {
357  m_Scripts = scripts;
358 }
359 
360 QString SequenceJob::getScript(ScriptTypes type) const
361 {
362  return m_Scripts[type];
363 }
364 
365 void SequenceJob::setScript(ScriptTypes type, const QString &value)
366 {
367  m_Scripts[type] = value;
368 }
369 
370 void SequenceJob::connectDeviceAdaptor()
371 {
372  captureDeviceAdaptor->setCurrentSequenceJobState(stateMachine);
373  captureDeviceAdaptor->connectRotator();
374  captureDeviceAdaptor->connectActiveCamera();
375  captureDeviceAdaptor->connectTelescope();
376  captureDeviceAdaptor->connectDome();
377  captureDeviceAdaptor->connectDustCap();
378  // connect state machine with device adaptor
379  connect(stateMachine, &SequenceJobState::readCurrentState, captureDeviceAdaptor.data(),
380  &CaptureDeviceAdaptor::readCurrentState);
381  connect(stateMachine, &SequenceJobState::flatSyncFocus, captureDeviceAdaptor.data(), &CaptureDeviceAdaptor::flatSyncFocus);
382  // connect device adaptor with state machine
383  connect(captureDeviceAdaptor.data(), &CaptureDeviceAdaptor::flatSyncFocusChanged, stateMachine,
384  &SequenceJobState::flatSyncFocusChanged);
385 }
386 
387 void SequenceJob::disconnectDeviceAdaptor()
388 {
389  captureDeviceAdaptor->disconnectRotator();
390  captureDeviceAdaptor->disconnectActiveCamera();
391  captureDeviceAdaptor->disconnectTelescope();
392  captureDeviceAdaptor->disconnectDome();
393  captureDeviceAdaptor->disconnectDustCap();
394  disconnect(stateMachine, &SequenceJobState::readCurrentState, captureDeviceAdaptor.data(),
395  &CaptureDeviceAdaptor::readCurrentState);
396  disconnect(stateMachine, &SequenceJobState::flatSyncFocus, captureDeviceAdaptor.data(),
397  &CaptureDeviceAdaptor::flatSyncFocus);
398  disconnect(captureDeviceAdaptor.data(), &CaptureDeviceAdaptor::flatSyncFocusChanged, stateMachine,
399  &SequenceJobState::flatSyncFocusChanged);
400 }
401 
402 CAPTUREResult SequenceJob::capture(bool autofocusReady, FITSMode mode)
403 {
404  captureDeviceAdaptor.data()->getActiveChip()->setBatchMode(!getCoreProperty(SequenceJob::SJ_Preview).toBool());
405  captureDeviceAdaptor.data()->getActiveCamera()->setISOMode(getCoreProperty(SJ_TimeStampPrefixEnabled).toBool());
406  captureDeviceAdaptor.data()->getActiveCamera()->setSeqPrefix(getCoreProperty(SJ_FullPrefix).toString());
407 
408  auto placeholderPath = Ekos::PlaceholderPath(getCoreProperty(SJ_LocalDirectory).toString() + "/sequence.esq");
409  placeholderPath.setGenerateFilenameSettings(*this);
410  captureDeviceAdaptor.data()->getActiveCamera()->setPlaceholderPath(placeholderPath);
411 
412  if (getCoreProperty(SequenceJob::SJ_Preview).toBool())
413  {
414  if (captureDeviceAdaptor.data()->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
415  captureDeviceAdaptor.data()->getActiveCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
416  }
417  else
418  captureDeviceAdaptor.data()->getActiveCamera()->setUploadMode(m_UploadMode);
419 
420  QMapIterator<QString, QMap<QString, QVariant>> i(m_CustomProperties);
421  while (i.hasNext())
422  {
423  i.next();
424  INDI::Property *customProp = captureDeviceAdaptor.data()->getActiveCamera()->getProperty(i.key());
425  if (customProp)
426  {
427  QMap<QString, QVariant> elements = i.value();
429 
430  switch (customProp->getType())
431  {
432  case INDI_SWITCH:
433  {
434  auto sp = customProp->getSwitch();
435  while (j.hasNext())
436  {
437  j.next();
438  auto oneSwitch = sp->findWidgetByName(j.key().toLatin1().data());
439  if (oneSwitch)
440  oneSwitch->setState(static_cast<ISState>(j.value().toInt()));
441  }
442  captureDeviceAdaptor.data()->getActiveCamera()->getDriverInfo()->getClientManager()->sendNewSwitch(sp);
443  }
444  break;
445  case INDI_TEXT:
446  {
447  auto tp = customProp->getText();
448  while (j.hasNext())
449  {
450  j.next();
451  auto oneText = tp->findWidgetByName(j.key().toLatin1().data());
452  if (oneText)
453  oneText->setText(j.value().toString().toLatin1().constData());
454  }
455  captureDeviceAdaptor.data()->getActiveCamera()->getDriverInfo()->getClientManager()->sendNewText(tp);
456  }
457  break;
458  case INDI_NUMBER:
459  {
460  auto np = customProp->getNumber();
461  while (j.hasNext())
462  {
463  j.next();
464  auto oneNumber = np->findWidgetByName(j.key().toLatin1().data());
465  if (oneNumber)
466  oneNumber->setValue(j.value().toDouble());
467  }
468  captureDeviceAdaptor.data()->getActiveCamera()->getDriverInfo()->getClientManager()->sendNewNumber(np);
469  }
470  break;
471  default:
472  continue;
473  }
474  }
475  }
476 
477  const auto remoteDirectory = getCoreProperty(SJ_RemoteDirectory).toString();
478  if (captureDeviceAdaptor.data()->getActiveChip()->isBatchMode() && remoteDirectory.isEmpty() == false)
479  captureDeviceAdaptor.data()->getActiveCamera()->updateUploadSettings(remoteDirectory + getCoreProperty(
480  SJ_DirectoryPostfix).toString());
481 
482  const int ISOIndex = getCoreProperty(SJ_ISOIndex).toInt();
483  if (ISOIndex != -1)
484  {
485  if (ISOIndex != captureDeviceAdaptor.data()->getActiveChip()->getISOIndex())
486  captureDeviceAdaptor.data()->getActiveChip()->setISOIndex(ISOIndex);
487  }
488 
489  const auto gain = getCoreProperty(SJ_Gain).toDouble();
490  if (gain >= 0)
491  {
492  captureDeviceAdaptor.data()->getActiveCamera()->setGain(gain);
493  }
494 
495  const auto offset = getCoreProperty(SJ_Offset).toDouble();
496  if (offset >= 0)
497  {
498  captureDeviceAdaptor.data()->getActiveCamera()->setOffset(offset);
499  }
500 
501  const auto frameType = getFrameType();
502  // Only change filters for FLAT and LIGHT frames.
503  // TODO add support for setting a dark filter to block all light
504  if (stateMachine->targetFilterID != -1 && captureDeviceAdaptor.data()->getFilterWheel() != nullptr &&
505  (frameType == FRAME_FLAT || frameType == FRAME_LIGHT))
506  {
507  if (stateMachine->targetFilterID != stateMachine->m_CaptureState->currentFilterID)
508  {
509  emit prepareState(CAPTURE_CHANGING_FILTER);
510 
511  FilterManager::FilterPolicy policy = FilterManager::ALL_POLICIES;
512  // Don't perform autofocus on preview or calibration frames or if Autofocus is not ready yet.
513  if (getCoreProperty(SequenceJob::SJ_Preview).toBool() || frameType != FRAME_LIGHT || autofocusReady == false)
514  policy = static_cast<FilterManager::FilterPolicy>(policy & ~FilterManager::AUTOFOCUS_POLICY);
515 
516  m_FilterManager->setFilterPosition(stateMachine->targetFilterID, policy);
517  return CAPTURE_FILTER_BUSY;
518  }
519  }
520 
521  // Only attempt to set ROI and Binning if CCD transfer format is FITS
522  if (captureDeviceAdaptor.data()->getActiveCamera()->getEncodingFormat() == QLatin1String("FITS"))
523  {
524  int currentBinX = 1, currentBinY = 1;
525  captureDeviceAdaptor.data()->getActiveChip()->getBinning(&currentBinX, &currentBinY);
526 
527  const auto binning = getCoreProperty(SJ_Binning).toPoint();
528  // N.B. Always set binning _before_ setting frame because if the subframed image
529  // is problematic in 1x1 but works fine for 2x2, then it would fail it was set first
530  // So setting binning first always ensures this will work.
531  if (captureDeviceAdaptor.data()->getActiveChip()->canBin()
532  && captureDeviceAdaptor.data()->getActiveChip()->setBinning(binning.x(), binning.y()) == false)
533  {
534  setStatus(JOB_ERROR);
535  return CAPTURE_BIN_ERROR;
536  }
537 
538  const auto roi = getCoreProperty(SJ_ROI).toRect();
539 
540  if ((roi.width() > 0 && roi.height() > 0) && captureDeviceAdaptor.data()->getActiveChip()->canSubframe()
541  && captureDeviceAdaptor.data()->getActiveChip()->setFrame(roi.x(),
542  roi.y(),
543  roi.width(),
544  roi.height(),
545  currentBinX != binning.x()) == false)
546  {
547  setStatus(JOB_ERROR);
548  return CAPTURE_FRAME_ERROR;
549  }
550  }
551 
552  captureDeviceAdaptor.data()->getActiveCamera()->setCaptureFormat(getCoreProperty(SJ_Format).toString());
553  captureDeviceAdaptor.data()->getActiveCamera()->setEncodingFormat(getCoreProperty(SJ_Encoding).toString());
554  captureDeviceAdaptor.data()->getActiveChip()->setFrameType(getFrameType());
555 
556  // In case FITS Viewer is not enabled. Then for flat frames, we still need to keep the data
557  // otherwise INDI CCD would simply discard loading the data in batch mode as the data are already
558  // saved to disk and since no extra processing is required, FITSData is not loaded up with the data.
559  // But in case of automatically calculated flat frames, we need FITSData.
560  // Therefore, we need to explicitly set mode to FITS_CALIBRATE so that FITSData is generated.
561  captureDeviceAdaptor.data()->getActiveChip()->setCaptureMode(mode);
562  captureDeviceAdaptor.data()->getActiveChip()->setCaptureFilter(FITS_NONE);
563 
564  setStatus(getStatus());
565 
566  const auto exposure = getCoreProperty(SJ_Exposure).toDouble();
567  m_ExposeLeft = exposure;
568  captureDeviceAdaptor.data()->getActiveChip()->capture(exposure);
569 
570  return CAPTURE_OK;
571 }
572 
573 void SequenceJob::setTargetFilter(int pos, const QString &name)
574 {
575  stateMachine->targetFilterID = pos;
576  setCoreProperty(SJ_Filter, name);
577 }
578 
579 double SequenceJob::getExposeLeft() const
580 {
581  return m_ExposeLeft;
582 }
583 
584 void SequenceJob::setExposeLeft(double value)
585 {
586  m_ExposeLeft = value;
587 }
588 
589 
590 int SequenceJob::getCaptureRetires() const
591 {
592  return m_CaptureRetires;
593 }
594 
595 void SequenceJob::setCaptureRetires(int value)
596 {
597  m_CaptureRetires = value;
598 }
599 
600 int SequenceJob::getCurrentFilter() const
601 {
602  return stateMachine->m_CaptureState->currentFilterID;
603 }
604 
605 void SequenceJob::setCurrentFilter(int value)
606 {
607  // forward it to the state machine
608  stateMachine->setCurrentFilterID(value);
609 }
610 
611 // Setter: Set upload mode
612 void SequenceJob::setUploadMode(ISD::Camera::UploadMode value)
613 {
614  m_UploadMode = value;
615 }
616 // Getter: get upload mode
617 ISD::Camera::UploadMode SequenceJob::getUploadMode() const
618 {
619  return m_UploadMode;
620 }
621 
622 // Setter: Set flat field source
623 void SequenceJob::setFlatFieldSource(FlatFieldSource value)
624 {
625  stateMachine->flatFieldSource = value;
626 }
627 // Getter: Get flat field source
628 FlatFieldSource SequenceJob::getFlatFieldSource() const
629 {
630  return stateMachine->flatFieldSource;
631 }
632 
633 void SequenceJob::setWallCoord(const SkyPoint &value)
634 {
635  stateMachine->wallCoord = value;
636 }
637 
638 const SkyPoint &SequenceJob::getWallCoord() const
639 {
640  return stateMachine->wallCoord;
641 }
642 
643 // Setter: Set flat field duration
644 void SequenceJob::setFlatFieldDuration(FlatFieldDuration value)
645 {
646  m_FlatFieldDuration = value;
647 }
648 
649 // Getter: Get flat field duration
650 FlatFieldDuration SequenceJob::getFlatFieldDuration() const
651 {
652  return m_FlatFieldDuration;
653 }
654 
655 void SequenceJob::setJobProgressIgnored(bool value)
656 {
657  m_JobProgressIgnored = value;
658 }
659 
660 bool SequenceJob::getJobProgressIgnored() const
661 {
662  return m_JobProgressIgnored;
663 }
664 
665 void SequenceJob::setLightBox(ISD::LightBox *lightBox)
666 {
667  stateMachine->m_CaptureState->hasLightBox = (lightBox != nullptr);
668 }
669 
670 void SequenceJob::setDustCap(ISD::DustCap *dustCap)
671 {
672  stateMachine->m_CaptureState->hasDustCap = (dustCap != nullptr);
673 }
674 
675 void SequenceJob::addMount(ISD::Mount *scope)
676 {
677  stateMachine->m_CaptureState->hasTelescope = (scope != nullptr);
678 }
679 
680 void SequenceJob::setDome(ISD::Dome *dome)
681 {
682  stateMachine->m_CaptureState->hasDome = (dome != nullptr);
683 }
684 
685 void SequenceJob::setFilterManager(const QSharedPointer<FilterManager> &manager)
686 {
687  m_FilterManager = manager;
688 }
689 
690 void SequenceJob::setFrameType(CCDFrameType value)
691 {
692  m_FrameType = value;
693  // propagate the frame type to the state machine
694  stateMachine->setFrameType(value);
695 }
696 
697 // Getter: Get Frame Type
698 CCDFrameType SequenceJob::getFrameType() const
699 {
700  return m_FrameType;
701 }
702 
703 QString SequenceJob::getSignature()
704 {
705  auto localDirectory = getCoreProperty(SJ_LocalDirectory).toString();
706  auto directoryPostfix = getCoreProperty(SJ_DirectoryPostfix).toString();
707  auto fullPrefix = getCoreProperty(SJ_FullPrefix).toString();
708 
709  return QString(localDirectory + directoryPostfix + QDir::separator() + fullPrefix).remove(ISOMarker);
710 
711 }
712 
713 void SequenceJob::prepareCapture()
714 {
715  // create the event connections
716  connectDeviceAdaptor();
717  // simply forward it to the state machine
718  switch (getFrameType())
719  {
720  case FRAME_LIGHT:
721  stateMachine->prepareLightFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
722  getCoreProperty(SJ_EnforceStartGuiderDrift).toBool() && getCoreProperty(SJ_GuiderActive).toBool(),
723  getCoreProperty(SJ_Preview).toBool());
724  break;
725  case FRAME_FLAT:
726  stateMachine->prepareFlatFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
727  getCoreProperty(SJ_Preview).toBool());
728  break;
729  case FRAME_DARK:
730  stateMachine->prepareDarkFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
731  getCoreProperty(SJ_Preview).toBool());
732  break;
733  case FRAME_BIAS:
734  stateMachine->prepareBiasFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
735  getCoreProperty(SJ_Preview).toBool());
736  break;
737  default:
738  // not refactored yet, immediately completed
739  processPrepareComplete();
740  break;
741  }
742 }
743 
744 void SequenceJob::processPrepareComplete()
745 {
746  disconnectDeviceAdaptor();
747  emit prepareComplete();
748 }
749 
750 void SequenceJob::processAbortCapture()
751 {
752  disconnectDeviceAdaptor();
753  emit abortCapture();
754 }
755 
756 IPState SequenceJob::checkFlatFramePendingTasksCompleted()
757 {
758  // no further checks necessary
759  return IPS_OK;
760 }
761 
762 void SequenceJob::setCoreProperty(PropertyID id, const QVariant &value)
763 {
764  // Handle special cases
765  switch (id)
766  {
767  case SJ_Count:
768  if( !getCoreProperty(SequenceJob::SJ_Preview).toBool() && nullptr != countCell)
769  countCell->setText(QString("%L1/%L2").arg(m_Completed).arg(value.toInt()));
770  break;
771 
772  case SJ_RemoteDirectory:
773  {
774  auto remoteDir = value.toString();
775  if (remoteDir.endsWith('/'))
776  {
777  remoteDir.chop(1);
778  m_CoreProperties[id] = remoteDir;
779  }
780  }
781  break;
782 
783  case SJ_GuiderActive:
784  // Inform the state machine if guiding is running. This is necessary during the preparation phase
785  // where the state machine might wait for guide deviations if enforcing initial guiding drift is selected.
786  // If guiding aborts after the preparation has started, the state machine might wait infinitely for an
787  // updated guide drift.
788  if (m_CoreProperties[SJ_GuiderActive] != value)
789  {
790  stateMachine->setEnforceInitialGuidingDrift(value.toBool() &&
791  m_CoreProperties[SJ_EnforceStartGuiderDrift].toBool());
792  }
793  break;
794  default:
795  break;
796  }
797  // store value
798  m_CoreProperties[id] = value;
799 }
800 
801 QVariant SequenceJob::getCoreProperty(PropertyID id) const
802 {
803  return m_CoreProperties[id];
804 }
805 }
AlignHCenter
void setAlt(dms alt)
Sets Alt, the Altitude.
Definition: skypoint.h:194
bool contains(const Key &key) const const
void setTextAlignment(int alignment)
Type type(const QSqlDatabase &db)
Ekos is an advanced Astrophotography tool for Linux. It is based on a modular extensible framework to...
Definition: align.cpp:70
double toDouble(const QString &s, bool *ok) const const
const T value(const Key &key, const T &defaultValue) const const
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
QChar separator()
void chop(int n)
Sequence Job is a container for the details required to capture a series of images.
Definition: sequencejob.h:18
ItemIsSelectable
QString i18n(const char *text, const TYPE &arg...)
char * toString(const T &value)
QLocale c()
int toInt(bool *ok) const const
bool toBool() const const
QString & remove(int position, int n)
void setAz(dms az)
Sets Az, the Azimuth.
Definition: skypoint.h:230
void setFlags(Qt::ItemFlags flags)
static dms fromString(const QString &s, bool deg)
Static function to create a DMS object from a QString.
Definition: dms.cpp:421
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 15 2022 04:04:05 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.