7#include "sequencejob.h"
9#include <KNotifications/KNotification>
10#include <ekos_capture_debug.h>
11#include "capturedeviceadaptor.h"
12#include "skyobjects/skypoint.h"
13#include "ksnotification.h"
15#define MF_TIMER_TIMEOUT 90000
16#define MF_RA_DIFF_LIMIT 4
20QString const &SequenceJob::ISOMarker(
"_ISO8601");
42 devices.
reset(
new CaptureDeviceAdaptor());
44 init(SequenceJob::JOBTYPE_BATCH, root,
sharedState, targetName);
55void Ekos::SequenceJob::init(SequenceJobType jobType,
XMLEle *root,
65 connect(state.data(), &SequenceJobState::prepareState,
this, &SequenceJob::prepareState);
66 connect(state.data(), &SequenceJobState::prepareComplete,
this, &SequenceJob::processPrepareComplete);
67 connect(state.data(), &SequenceJobState::abortCapture,
this, &SequenceJob::processAbortCapture);
68 connect(state.data(), &SequenceJobState::newLog,
this, &SequenceJob::newLog);
70 connect(state.data(), &SequenceJobState::initCaptureComplete,
this, &SequenceJob::capture);
77 auto placeholderPath = Ekos::PlaceholderPath();
78 placeholderPath.processJobInfo(
this);
81void SequenceJob::resetStatus(JOBStatus status)
84 setCalibrationStage(SequenceJobState::CAL_NONE);
98 m_JobProgressIgnored =
false;
106void SequenceJob::abort()
108 setStatus(JOB_ABORTED);
109 if (devices.
data()->getActiveChip())
111 if (devices.
data()->getActiveChip()->canAbort())
112 devices.
data()->getActiveChip()->abortExposure();
113 devices.
data()->getActiveChip()->setBatchMode(
false);
117void SequenceJob::done()
126 getCoreProperty(SJ_Delay).
toDouble() / 1000) *
127 (getCoreProperty(SJ_Count).
toDouble() - getCompleted());
129 if (getStatus() == JOB_BUSY)
131 if (getExposeLeft() > 0.0)
137 return static_cast<int>(std::round(
remaining));
140void SequenceJob::setStatus(JOBStatus
const in_status)
145void SequenceJob::setISO(
int index)
147 if (devices->getActiveChip())
149 setCoreProperty(SequenceJob::SJ_ISOIndex, index);
150 const auto isolist = devices->getActiveChip()->getISOList();
151 if (
isolist.count() > index && index >= 0)
152 setCoreProperty(SequenceJob::SJ_ISO,
isolist[index]);
158 if (!devices->getActiveCamera())
159 return QStringList({
"Light",
"Bias",
"Dark",
"Flat"});
163 return tChip->getFrameTypes();
168 if (devices->getFilterManager().isNull())
171 return devices->getFilterManager()->getFilterLabels();
175void SequenceJob::connectDeviceAdaptor()
177 devices->setCurrentSequenceJobState(state);
179 connect(state.
data(), &SequenceJobState::readCurrentState, devices.
data(),
180 &CaptureDeviceAdaptor::readCurrentState);
181 connect(state.
data(), &SequenceJobState::flatSyncFocus, devices.
data(),
182 &CaptureDeviceAdaptor::flatSyncFocus);
184 connect(devices.
data(), &CaptureDeviceAdaptor::flatSyncFocusChanged, state.
data(),
185 &SequenceJobState::flatSyncFocusChanged);
188void SequenceJob::disconnectDeviceAdaptor()
190 devices->disconnectDevices(state.
data());
192 &CaptureDeviceAdaptor::readCurrentState);
194 &CaptureDeviceAdaptor::flatSyncFocus);
196 &SequenceJobState::flatSyncFocusChanged);
199void SequenceJob::startCapturing(
bool autofocusReady, FITSMode mode)
201 state->initCapture(getFrameType(), jobType() == SequenceJob::JOBTYPE_PREVIEW,
autofocusReady, mode);
204void SequenceJob::capture(FITSMode mode)
206 if (!devices.
data()->getActiveCamera() || !devices.
data()->getActiveChip())
211 CCDFrameTypeNames[getFrameType()]);
212 logentry.append(
QString(
", filter = %1, upload mode = %2").arg(getCoreProperty(SJ_Filter).
toString()).arg(getUploadMode()));
214 devices.
data()->getActiveChip()->setBatchMode(jobType() != SequenceJob::JOBTYPE_PREVIEW);
215 devices.
data()->getActiveCamera()->setSeqPrefix(getCoreProperty(SJ_FullPrefix).
toString());
216 logentry.append(
QString(
", batch mode = %1, seq prefix = %2").arg(jobType() != SequenceJob::JOBTYPE_PREVIEW ?
"true" :
217 "false").arg(getCoreProperty(SJ_FullPrefix).
toString()));
219 if (jobType() == SequenceJob::JOBTYPE_PREVIEW)
221 if (devices.
data()->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
222 devices.
data()->getActiveCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
225 devices.
data()->getActiveCamera()->setUploadMode(m_UploadMode);
231 auto customProp = devices.
data()->getActiveCamera()->getProperty(i.key());
245 auto oneSwitch = sp->findWidgetByName(
j.key().toLatin1().data());
249 devices.
data()->getActiveCamera()->sendNewProperty(sp);
258 auto oneText = tp->findWidgetByName(
j.key().toLatin1().data());
260 oneText->setText(
j.value().toString().toLatin1().constData());
262 devices.
data()->getActiveCamera()->sendNewProperty(tp);
271 auto oneNumber = np->findWidgetByName(
j.key().toLatin1().data());
275 devices.
data()->getActiveCamera()->sendNewProperty(np);
286 if (devices.
data()->getActiveChip()->isBatchMode() &&
291 if (getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
299 if (
ISOIndex != devices.
data()->getActiveChip()->getISOIndex())
303 const auto gain = getCoreProperty(SJ_Gain).
toDouble();
307 devices.
data()->getActiveCamera()->setGain(gain);
310 const auto offset = getCoreProperty(SJ_Offset).
toDouble();
314 devices.
data()->getActiveCamera()->setOffset(offset);
317 devices.
data()->getActiveCamera()->setCaptureFormat(getCoreProperty(SJ_Format).
toString());
318 devices.
data()->getActiveCamera()->setEncodingFormat(getCoreProperty(SJ_Encoding).
toString());
319 devices.
data()->getActiveChip()->setFrameType(getFrameType());
320 logentry.append(
QString(
", format = %1, encoding = %2").arg(getCoreProperty(SJ_Format).
toString()).arg(getCoreProperty(
327 const auto binning = getCoreProperty(SJ_Binning).
toPoint();
331 if (devices.
data()->getActiveChip()->canBin())
333 if (devices.
data()->getActiveChip()->setBinning(binning.x(), binning.y()) ==
false)
335 qCWarning(
KSTARS_EKOS_CAPTURE()) <<
"Cannot set binning to " <<
"x =" << binning.
x() <<
", y =" << binning.y();
336 setStatus(JOB_ERROR);
337 emit captureStarted(CaptureModuleState::CAPTURE_BIN_ERROR);
346 const auto roi = getCoreProperty(SJ_ROI).
toRect();
348 if (devices.
data()->getActiveChip()->canSubframe())
350 if ((
roi.width() > 0 &&
roi.height() > 0) && devices.
data()->getActiveChip()->setFrame(
roi.x(),
357 roi.width() <<
"height =" <<
roi.height();
358 setStatus(JOB_ERROR);
359 emit captureStarted(CaptureModuleState::CAPTURE_FRAME_ERROR);
365 logentry.append(
", Cannot subframe");
372 devices.
data()->getActiveChip()->setCaptureMode(mode);
373 devices.
data()->getActiveChip()->setCaptureFilter(FITS_NONE);
375 setStatus(getStatus());
377 const auto exposure = getCoreProperty(SJ_Exposure).
toDouble();
378 m_ExposeLeft = exposure;
379 devices.
data()->getActiveChip()->capture(exposure);
383 emit captureStarted(CaptureModuleState::CAPTURE_OK);
386void SequenceJob::setTargetFilter(
int pos,
const QString &name)
388 state->targetFilterID = pos;
389 setCoreProperty(SJ_Filter, name);
392double SequenceJob::getExposeLeft()
const
397void SequenceJob::setExposeLeft(
double value)
399 m_ExposeLeft = value;
403int SequenceJob::getCaptureRetires()
const
405 return m_CaptureRetires;
408void SequenceJob::setCaptureRetires(
int value)
410 m_CaptureRetires = value;
413int SequenceJob::getCurrentFilter()
const
415 return state->m_CaptureModuleState->currentFilterID;
418ISD::Mount::PierSide SequenceJob::getPierSide()
const
420 return state->m_CaptureModuleState->getPierSide();
424void SequenceJob::setUploadMode(ISD::Camera::UploadMode value)
426 m_UploadMode = value;
429ISD::Camera::UploadMode SequenceJob::getUploadMode()
const
435void SequenceJob::setCalibrationPreAction(uint32_t value)
437 state->m_CalibrationPreAction = value;
440uint32_t SequenceJob::getCalibrationPreAction()
const
442 return state->m_CalibrationPreAction;
445void SequenceJob::setWallCoord(
const SkyPoint &value)
447 state->wallCoord = value;
450const SkyPoint &SequenceJob::getWallCoord()
const
452 return state->wallCoord;
456void SequenceJob::setFlatFieldDuration(FlatFieldDuration value)
458 m_FlatFieldDuration = value;
462FlatFieldDuration SequenceJob::getFlatFieldDuration()
const
464 return m_FlatFieldDuration;
467void SequenceJob::setJobProgressIgnored(
bool value)
469 m_JobProgressIgnored = value;
472bool SequenceJob::getJobProgressIgnored()
const
474 return m_JobProgressIgnored;
477void SequenceJob::updateDeviceStates()
479 setLightBox(devices->lightBox());
480 addMount(devices->mount());
481 setDome(devices->dome());
482 setDustCap(devices->dustCap());
487 state->m_CaptureModuleState->hasLightBox = (lightBox !=
nullptr);
492 state->m_CaptureModuleState->hasDustCap = (dustCap !=
nullptr);
497 state->m_CaptureModuleState->hasTelescope = (scope !=
nullptr);
500void SequenceJob::setDome(
ISD::Dome * dome)
502 state->m_CaptureModuleState->hasDome = (dome !=
nullptr);
505double SequenceJob::currentTemperature()
const
507 return devices->cameraTemperature();
510double SequenceJob::currentGain()
const
512 return devices->cameraGain();
515double SequenceJob::currentOffset()
const
517 return devices->cameraOffset();
520void SequenceJob::prepareCapture()
523 switch (getFrameType())
526 state->prepareLightFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
527 jobType() == SequenceJob::JOBTYPE_PREVIEW);
530 state->prepareFlatFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
531 jobType() == SequenceJob::JOBTYPE_PREVIEW);
534 state->prepareDarkFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
535 jobType() == SequenceJob::JOBTYPE_PREVIEW);
538 state->prepareBiasFrameCapture(getCoreProperty(SJ_EnforceTemperature).toBool(),
539 jobType() == SequenceJob::JOBTYPE_PREVIEW);
543 processPrepareComplete();
548void SequenceJob::processPrepareComplete(
bool success)
550 emit prepareComplete(success);
553void SequenceJob::processAbortCapture()
555 disconnectDeviceAdaptor();
559IPState SequenceJob::checkFlatFramePendingTasksCompleted()
565void SequenceJob::setCoreProperty(PropertyID
id,
const QVariant &value)
570 case SJ_RemoteDirectory:
585 m_CoreProperties[id] = value;
588QVariant SequenceJob::getCoreProperty(PropertyID
id)
const
590 return m_CoreProperties[id];
593void SequenceJob::loadFrom(
XMLEle *root,
const QString &targetName, SequenceJobType jobType,
599 m_CoreProperties[SJ_Exposure] = -1;
600 m_CoreProperties[SJ_Gain] = -1;
601 m_CoreProperties[SJ_Offset] = -1;
602 m_CoreProperties[SJ_ISOIndex] = -1;
603 m_CoreProperties[SJ_Count] = -1;
604 m_CoreProperties[SJ_Delay] = -1;
605 m_CoreProperties[SJ_Binning] =
QPoint(1, 1);
606 m_CoreProperties[SJ_ROI] =
QRect(0, 0, 0, 0);
607 m_CoreProperties[SJ_EnforceTemperature] =
false;
608 m_CoreProperties[SJ_GuiderActive] =
false;
609 m_CoreProperties[SJ_DitherPerJobFrequency] = 0;
610 m_CoreProperties[SJ_Encoding] =
"FITS";
613 if (targetName !=
"")
614 setCoreProperty(SequenceJob::SJ_TargetName, targetName);
619 bool isDarkFlat =
false;
629 setCoreProperty(SequenceJob::SJ_Format,
pcdataXMLEle(ep));
632 setCoreProperty(SequenceJob::SJ_Encoding,
pcdataXMLEle(ep));
644 setCoreProperty(SequenceJob::SJ_Binning, binning);
662 setCoreProperty(SequenceJob::SJ_ROI,
roi);
670 setCoreProperty(SequenceJob::SJ_EnforceTemperature,
true);
672 setCoreProperty(SequenceJob::SJ_EnforceTemperature,
false);
677 const auto index = std::max(1, filterLabels().indexOf(name) + 1);
678 setTargetFilter(index, name);
683 setFrameType(
static_cast<CCDFrameType
>(
qMax(0, index)));
689 if (targetName ==
"")
691 setCoreProperty(SequenceJob::SJ_TargetName,
jobTarget);
704 if (targetName ==
"")
706 setCoreProperty(SequenceJob::SJ_TargetName,
jobTarget);
722 setCoreProperty(SequenceJob::SJ_PlaceholderFormat,
755 setCoreProperty(SequenceJob::SJ_LocalDirectory,
pcdataXMLEle(ep));
759 setCoreProperty(SequenceJob::SJ_PlaceholderFormat,
pcdataXMLEle(ep));
767 setCoreProperty(SequenceJob::SJ_RemoteDirectory,
pcdataXMLEle(ep));
798 elements[
name] = value;
804 propertyMap[
name] = elements;
807 setCustomProperties(propertyMap);
809 setCoreProperty(SequenceJob::SJ_Gain, devices->cameraGain(propertyMap));
810 setCoreProperty(SequenceJob::SJ_Offset, devices->cameraOffset(propertyMap));
822 if (getCalibrationPreAction() & ACTION_WALL)
829 setCalibrationPreAction((getCalibrationPreAction() & ~ACTION_PARK_MOUNT) | ACTION_WALL);
833 setWallCoord(wallCoord);
837 qCWarning(
KSTARS_EKOS_CAPTURE) <<
"Wall position coordinates missing, disabling slew to wall position action.";
838 setCalibrationPreAction((getCalibrationPreAction() & ~ACTION_WALL) | ACTION_NONE);
852 setCalibrationPreAction(ACTION_NONE);
860 setCalibrationPreAction((getCalibrationPreAction() & ~ACTION_PARK_MOUNT) | ACTION_WALL);
864 setWallCoord(wallCoord);
873 setCalibrationPreAction(getCalibrationPreAction() | ACTION_PARK_MOUNT);
878 setCalibrationPreAction(getCalibrationPreAction() | ACTION_PARK_DOME);
884 isDarkFlat = !
strcmp(dark,
"true");
890 setFlatFieldDuration(DURATION_MANUAL);
896 setFlatFieldDuration(DURATION_ADU);
914 setJobType(SequenceJob::JOBTYPE_DARKFLAT);
919 auto roi = getCoreProperty(SequenceJob::SJ_ROI).
toRect();
923 outstream <<
"<Exposure>" <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_Exposure).toDouble()) <<
"</Exposure>" <<
928 outstream <<
"<X>" <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_Binning).toPoint().x()) <<
"</X>" <<
Qt::endl;
929 outstream <<
"<Y>" <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_Binning).toPoint().y()) <<
"</Y>" <<
Qt::endl;
937 if (getTargetTemperature() != Ekos::INVALID_VALUE)
938 outstream <<
"<Temperature force='" << (getCoreProperty(SequenceJob::SJ_EnforceTemperature).
toBool() ?
"true" :
940 <<
cLocale.toString(getTargetTemperature()) <<
"</Temperature>" <<
Qt::endl;
941 if (getTargetFilter() >= 0)
944 outstream <<
"<Count>" <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_Count).toInt()) <<
"</Count>" <<
Qt::endl;
946 outstream <<
"<Delay>" <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_Delay).toInt() / 1000.0) <<
"</Delay>" <<
948 if (getCoreProperty(SequenceJob::SJ_TargetName) !=
"")
959 <<
cLocale.toString(getCoreProperty(SequenceJob::SJ_DitherPerJobFrequency).toInt()) <<
"</GuideDitherPerJob>" <<
961 outstream <<
"<FITSDirectory>" << getCoreProperty(SequenceJob::SJ_LocalDirectory).
toString() <<
"</FITSDirectory>" <<
963 outstream <<
"<PlaceholderFormat>" << getCoreProperty(SequenceJob::SJ_PlaceholderFormat).
toString() <<
964 "</PlaceholderFormat>" <<
966 outstream <<
"<PlaceholderSuffix>" << getCoreProperty(SequenceJob::SJ_PlaceholderSuffix).
toUInt() <<
967 "</PlaceholderSuffix>" <<
970 if (getCoreProperty(SequenceJob::SJ_RemoteDirectory).
toString().isEmpty() ==
false)
971 outstream <<
"<RemoteDirectory>" << getCoreProperty(SequenceJob::SJ_RemoteDirectory).
toString() <<
"</RemoteDirectory>"
973 if (getCoreProperty(SequenceJob::SJ_ISOIndex).toInt() != -1)
974 outstream <<
"<ISOIndex>" << (getCoreProperty(SequenceJob::SJ_ISOIndex).
toInt()) <<
"</ISOIndex>" <<
Qt::endl;
975 if (getTargetRotation() != Ekos::INVALID_VALUE)
985 while (iter.hasNext())
990 outstream <<
"<OneElement name='" << iter.key()
991 <<
"'>" << iter.value().toString() <<
"</OneElement>" <<
Qt::endl;
995 outstream <<
"<OneElement name='" << iter.key()
996 <<
"'>" << iter.value().toDouble() <<
"</OneElement>" <<
Qt::endl;
1006 if (getCalibrationPreAction() & ACTION_WALL)
1013 outstream <<
"<FlatDuration dark='" << (jobType() == SequenceJob::JOBTYPE_DARKFLAT ?
"true" :
"false")
1015 if (getFlatFieldDuration() == DURATION_MANUAL)
1024 outstream <<
"<SkyFlat>" << (getCoreProperty(SequenceJob::SJ_SkyFlat).
toBool() ?
"true" :
"false") <<
CameraChip class controls a particular chip in camera.
Class handles control of INDI dome devices.
Handles operation of a remotely controlled dust cover cap.
Handles operation of a remotely controlled light box.
device handle controlling Mounts.
The sky coordinates of a point in the sky.
void setAlt(dms alt)
Sets Alt, the Altitude.
void setAz(dms az)
Sets Az, the Azimuth.
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
@ SCRIPT_POST_CAPTURE
Script to run after a sequence capture is completed.
@ SCRIPT_POST_JOB
Script to run after a sequence job is completed.
@ SCRIPT_PRE_CAPTURE
Script to run before a sequence capture is started.
@ SCRIPT_PRE_JOB
Script to run before a sequence job is started.
QString name(StandardShortcut id)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QString arg(Args &&... args) const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
QTextStream & endl(QTextStream &stream)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool toBool() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QPoint toPoint() const const
QRect toRect() const const
QString toString() const const
uint toUInt(bool *ok) const const