9 #include "captureadaptor.h"
11 #include "kstarsdata.h"
13 #include "rotatorsettings.h"
14 #include "sequencejob.h"
15 #include "placeholderpath.h"
16 #include "ui_calibrationoptions.h"
17 #include "auxiliary/ksmessagebox.h"
18 #include "ekos/manager.h"
19 #include "ekos/auxiliary/darklibrary.h"
20 #include "ekos/auxiliary/profilesettings.h"
21 #include "ekos/auxiliary/opticaltrainmanager.h"
22 #include "scriptsmanager.h"
23 #include "fitsviewer/fitsdata.h"
24 #include "indi/driverinfo.h"
25 #include "indi/indifilterwheel.h"
26 #include "indi/indilistener.h"
27 #include "oal/observeradd.h"
28 #include "ekos/guide/guide.h"
30 #include <basedevice.h>
32 #include <ekos_capture_debug.h>
34 #define MF_TIMER_TIMEOUT 90000
35 #define GD_TIMER_TIMEOUT 60000
36 #define MF_RA_DIFF_LIMIT 4
40 #define CAPTURE_TIMEOUT_THRESHOLD 180000
43 #define SQ_FORMAT_VERSION 2.5
45 #define SQ_COMPAT_VERSION 2.0
56 qRegisterMetaType<CaptureState>(
"CaptureState");
57 qDBusRegisterMetaType<CaptureState>();
59 new CaptureAdaptor(
this);
60 m_captureModuleState.
reset(
new CaptureModuleState());
61 m_captureDeviceAdaptor.
reset(
new CaptureDeviceAdaptor(m_captureModuleState));
74 KStarsData::Instance()->
userdb()->GetAllDSLRInfos(DSLRInfos);
76 if (DSLRInfos.
count() > 0)
78 qCDebug(KSTARS_EKOS_CAPTURE) <<
"DSLR Cameras Info:";
79 qCDebug(KSTARS_EKOS_CAPTURE) << DSLRInfos;
82 m_LimitsDialog =
new QDialog(
this);
83 m_LimitsUI.reset(
new Ui::Limits());
84 m_LimitsUI->setupUi(m_LimitsDialog);
90 m_RotatorControlPanel.reset(
new RotatorSettings(Manager::Instance()));
93 targetDriftLabel->setVisible(
false);
94 targetDrift->setVisible(
false);
95 targetDriftUnit->setVisible(
false);
96 avgDownloadTime->setVisible(
false);
97 avgDownloadLabel->setVisible(
false);
98 secLabel->setVisible(
false);
101 double angle = m_RotatorControlPanel->targetRawAngle();
102 m_captureDeviceAdaptor->setRotatorAngle(&angle);
109 double rawAngle = (m_RotatorControlPanel->adjustedOffset() + m_RotatorControlPanel->targetPositionAngle()) /
110 Options::pAMultiplier();
113 while (rawAngle > 360)
116 m_RotatorControlPanel->setTargetRawAngle(rawAngle);
117 m_captureDeviceAdaptor->setRotatorAngle(&rawAngle);
121 m_captureDeviceAdaptor->reverseRotator(toggled);
125 seqDelayTimer =
new QTimer(
this);
127 m_captureModuleState->getCaptureDelayTimer().setSingleShot(
true);
148 m_captureModuleState->getGuideDeviationTimer().setInterval(GD_TIMER_TIMEOUT);
149 connect(&m_captureModuleState->getGuideDeviationTimer(), &
QTimer::timeout,
this, &Capture::checkGuideDeviationTimeout);
153 darkB->setChecked(Options::autoDark());
156 Options::setAutoDark(darkB->isChecked());
168 if (m_captureDeviceAdaptor->getActiveCamera())
170 QVariantMap auxInfo = m_captureDeviceAdaptor->getActiveCamera()->getDriverInfo()->getAuxInfo();
171 auxInfo[QString(
"%1_TC").arg(m_captureDeviceAdaptor->getActiveCamera()->getDeviceName())] = toggled;
172 m_captureDeviceAdaptor->getActiveCamera()->getDriverInfo()->setAuxInfo(auxInfo);
181 m_captureModuleState->updateHFRThreshold();
182 generatePreviewFilename();
203 if (m_captureDeviceAdaptor->getActiveCamera())
204 m_captureDeviceAdaptor->getActiveCamera()->setTemperature(cameraTemperatureN->value());
208 if (m_captureDeviceAdaptor->getActiveCamera())
209 m_captureDeviceAdaptor->getActiveCamera()->setCoolerControl(
true);
213 if (m_captureDeviceAdaptor->getActiveCamera())
214 m_captureDeviceAdaptor->getActiveCamera()->setCoolerControl(
false);
219 &Capture::checkFrameType);
254 addToQueueB->setToolTip(
i18n(
"Add job to sequence queue"));
255 removeFromQueueB->setToolTip(
i18n(
"Remove job from sequence queue"));
260 connect(m_captureDeviceAdaptor.
data(), &CaptureDeviceAdaptor::newCCDTemperatureValue,
this,
262 connect(m_captureDeviceAdaptor.
data(), &CaptureDeviceAdaptor::newRotatorAngle,
this,
269 m_LimitsUI->startGuiderDriftS->setChecked(Options::enforceStartGuiderDrift());
272 Options::setEnforceStartGuiderDrift(checked);
276 m_LimitsUI->startGuiderDriftN->setValue(Options::startGuideDeviation());
279 Options::setStartGuideDeviation(m_LimitsUI->startGuiderDriftN->value());
283 m_LimitsUI->limitGuideDeviationS->setChecked(Options::enforceGuideDeviation());
286 Options::setEnforceGuideDeviation(checked);
290 m_LimitsUI->limitGuideDeviationN->setValue(Options::guideDeviation());
293 Options::setGuideDeviation(m_LimitsUI->limitGuideDeviationN->value());
297 m_LimitsUI->limitFocusHFRS->setChecked(Options::enforceAutofocusHFR());
300 Options::setEnforceAutofocusHFR(checked);
301 if (checked == false)
302 m_captureModuleState->getRefocusState()->setInSequenceFocus(false);
306 m_LimitsUI->limitFocusHFRN->setValue(Options::hFRDeviation());
309 Options::setHFRDeviation(m_LimitsUI->limitFocusHFRN->value());
311 connect(m_captureModuleState.
get(), &CaptureModuleState::newLimitFocusHFR,
this, [
this](
double hfr)
313 m_LimitsUI->limitFocusHFRN->setValue(hfr);
317 m_LimitsUI->limitFocusDeltaTS->setChecked(Options::enforceAutofocusOnTemperature());
320 Options::setEnforceAutofocusOnTemperature(checked);
324 m_LimitsUI->limitFocusDeltaTN->setValue(Options::maxFocusTemperatureDelta());
327 Options::setMaxFocusTemperatureDelta(m_LimitsUI->limitFocusDeltaTN->value());
331 m_LimitsUI->limitRefocusS->setChecked(Options::enforceRefocusEveryN());
334 Options::setEnforceRefocusEveryN(checked);
338 m_LimitsUI->limitRefocusN->setValue(
static_cast<int>(Options::refocusEveryN()));
341 Options::setRefocusEveryN(static_cast<uint>(m_LimitsUI->limitRefocusN->value()));
345 FilterEnabled = Options::fileSettingsUseFilter();
348 ExpEnabled = Options::fileSettingsUseDuration();
351 TimeStampEnabled = Options::fileSettingsUseTimestamp();
354 m_LimitsUI->meridianRefocusS->setChecked(Options::refocusAfterMeridianFlip());
357 Options::setRefocusAfterMeridianFlip(checked);
362 m_LimitsUI->limitGuideDeviationS,
363 m_LimitsUI->limitRefocusS,
364 m_LimitsUI->limitGuideDeviationS,
366 for (
const QCheckBox * control : checkBoxes)
371 m_LimitsUI->limitFocusHFRN,
372 m_LimitsUI->limitFocusDeltaTN,
373 m_LimitsUI->limitGuideDeviationN,
383 m_ObserverName = Options::defaultObserver();
394 this, &Capture::scriptFinished);
417 fileRemoteDirT->setEnabled(index != 0);
420 customPropertiesDialog.reset(
new CustomProperties());
423 customPropertiesDialog.get()->
show();
424 customPropertiesDialog.get()->
raise();
426 connect(customPropertiesDialog.get(), &CustomProperties::valueChanged,
this, [&]()
428 const double newGain = getGain();
429 if (captureGainN && newGain >= 0)
430 captureGainN->setValue(newGain);
431 const int newOffset = getOffset();
433 captureOffsetN->setValue(newOffset);
436 flatFieldSource =
static_cast<FlatFieldSource
>(Options::calibrationFlatSourceIndex());
437 flatFieldDuration =
static_cast<FlatFieldDuration
>(Options::calibrationFlatDurationIndex());
438 wallCoord.
setAz(Options::calibrationWallAz());
439 wallCoord.
setAlt(Options::calibrationWallAlt());
440 targetADU = Options::calibrationADUValue();
441 targetADUTolerance = Options::calibrationADUValueTolerance();
443 if(!Options::captureDirectory().isEmpty())
444 fileDirectoryT->setText(Options::captureDirectory());
448 Options::setCaptureDirectory(fileDirectoryT->text());
453 Options::setCaptureDirectory(fileDirectoryT->text());
454 generatePreviewFilename();
457 if (Options::remoteCaptureDirectory().isEmpty() ==
false)
459 fileRemoteDirT->setText(Options::remoteCaptureDirectory());
463 Options::setRemoteCaptureDirectory(fileRemoteDirT->text());
464 generatePreviewFilename();
470 for (
auto &button : qButtons)
471 button->setAutoDefault(
false);
479 DarkLibrary::Instance()->setCaptureModule(
this);
481 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &Capture::appendLogText);
482 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, &Capture::setCaptureComplete);
485 connect(
this, &Capture::newStatus, captureStatusWidget, &LedStatusWidget::setCaptureState);
492 connect(m_captureModuleState.
data(), &CaptureModuleState::newLog,
this, &Capture::appendLogText);
493 connect(m_captureModuleState.
data(), &CaptureModuleState::newStatus,
this, &Capture::newStatus);
494 connect(m_captureModuleState.
data(), &CaptureModuleState::checkFocus,
this, &Capture::checkFocus);
495 connect(m_captureModuleState.
data(), &CaptureModuleState::resetFocus,
this, &Capture::resetFocus);
496 connect(m_captureModuleState.
data(), &CaptureModuleState::guideAfterMeridianFlip,
this,
497 &Capture::guideAfterMeridianFlip);
499 connect(m_captureModuleState.
data(), &CaptureModuleState::newMeridianFlipStage,
this, &Capture::updateMeridianFlipStage);
500 connect(m_captureModuleState.
data(), &CaptureModuleState::meridianFlipStarted,
this, &Capture::meridianFlipStarted);
502 connect(m_captureModuleState.
data(), &CaptureModuleState::newFilterPosition,
503 m_captureDeviceAdaptor.
data(), &CaptureDeviceAdaptor::setFilterPosition);
504 connect(m_captureModuleState.
data(), &CaptureModuleState::abortFastExposure,
505 m_captureDeviceAdaptor.
data(), &CaptureDeviceAdaptor::abortFastExposure);
507 setupOpticalTrainManager();
513 placeholderFormatT->setText(Options::placeholderFormat());
516 Options::setPlaceholderFormat(placeholderFormatT->text());
517 generatePreviewFilename();
521 &Capture::generatePreviewFilename);
524 m_TargetName = targetNameT->text();
525 generatePreviewFilename();
526 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Changed target to" << m_TargetName <<
"because of user edit";
534 qDeleteAll(m_captureModuleState->allJobs());
535 m_captureModuleState->allJobs().
clear();
540 if (m_Camera && m_Camera == device)
553 connect(m_Camera, &ISD::ConcreteDevice::Connected,
this, [
this]()
555 CCDFWGroup->setEnabled(
true);
556 sequenceBox->setEnabled(
true);
557 for (
auto &oneChild : sequenceControlsButtonGroup->buttons())
558 oneChild->setEnabled(
true);
560 connect(m_Camera, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
562 CCDFWGroup->setEnabled(
false);
563 sequenceBox->setEnabled(
false);
564 for (
auto &oneChild : sequenceControlsButtonGroup->buttons())
565 oneChild->setEnabled(
false);
567 opticalTrainCombo->setEnabled(
true);
568 trainLabel->setEnabled(
true);
572 auto isConnected = m_Camera && m_Camera->isConnected();
573 CCDFWGroup->setEnabled(isConnected);
574 sequenceBox->setEnabled(isConnected);
575 for (
auto &oneChild : sequenceControlsButtonGroup->buttons())
576 oneChild->setEnabled(isConnected);
580 cameraLabel->clear();
584 cameraLabel->setText(m_Camera->getDeviceName());
593 if (device->hasGuideHead())
594 addGuideHead(device);
614 if (m_FilterWheel && m_FilterWheel == device)
621 m_FilterWheel->disconnect(
this);
623 m_FilterWheel = device;
624 m_captureDeviceAdaptor->setFilterWheel(m_FilterWheel);
628 connect(m_FilterWheel, &ISD::ConcreteDevice::Connected,
this, [
this]()
630 FilterPosLabel->setEnabled(
true);
631 FilterPosCombo->setEnabled(
true);
632 filterManagerB->setEnabled(
true);
634 connect(m_FilterWheel, &ISD::ConcreteDevice::Disconnected,
this, [
this]()
636 FilterPosLabel->setEnabled(
false);
637 FilterPosCombo->setEnabled(
false);
638 filterManagerB->setEnabled(
false);
642 auto isConnected = m_FilterWheel && m_FilterWheel->isConnected();
643 FilterPosLabel->setEnabled(isConnected);
644 FilterPosCombo->setEnabled(isConnected);
645 filterManagerB->setEnabled(isConnected);
657 if (m_Dome && m_Dome == device)
666 m_captureDeviceAdaptor->setDome(m_Dome);
673 if (m_DustCap && m_DustCap == device)
682 m_captureDeviceAdaptor->setDustCap(m_DustCap);
690 if (m_Mount && m_Mount == device)
702 m_captureDeviceAdaptor->setMount(m_Mount);
707 m_captureDeviceAdaptor->getMount()->disconnect(
this);
710 m_RotatorControlPanel->setCurrentPierSide(device->pierSide());
711 connect(m_captureDeviceAdaptor->getMount(), &ISD::Mount::pierSideChanged, m_RotatorControlPanel.get(),
712 &RotatorSettings::setCurrentPierSide);
719 if (m_Rotator && m_Rotator == device)
721 rotatorB->setEnabled(
true);
732 rotatorB->setEnabled(
false);
736 connect(m_captureDeviceAdaptor.
data(), &CaptureDeviceAdaptor::rotatorReverseToggled,
this,
737 &Capture::setRotatorReversed,
740 m_captureDeviceAdaptor->setRotator(device);
741 rotatorB->setEnabled(
true);
747 if (m_LightBox && m_LightBox == device)
756 m_captureDeviceAdaptor->setLightBox(m_LightBox);
768 appendLogText(
i18n(
"Pausing only possible while frame capture is running."));
769 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Pause button pressed while not capturing.";
773 m_captureModuleState->setContinueAction(CaptureModuleState::CONTINUE_ACTION_NONE);
775 appendLogText(
i18n(
"Sequence shall be paused after current exposure is complete."));
776 pauseB->setEnabled(
false);
779 startB->setToolTip(
i18n(
"Resume Sequence"));
789 startB->setToolTip(
i18n(
"Stop Sequence"));
790 pauseB->setEnabled(
true);
796 appendLogText(
i18n(
"Sequence resumed."));
799 switch (m_captureModuleState->getContinueAction())
801 case CaptureModuleState::CONTINUE_ACTION_CAPTURE_COMPLETE:
802 setCaptureComplete();
804 case CaptureModuleState::CONTINUE_ACTION_NEXT_EXPOSURE:
811 else if (m_captureModuleState->getCaptureState() ==
CAPTURE_IDLE
825 if (name ==
"Mount" && mountInterface ==
nullptr)
827 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Registering new Module (" << name <<
")";
828 mountInterface =
new QDBusInterface(
"org.kde.kstars",
"/KStars/Ekos/Mount",
842 m_captureModuleState->setStartingCapture(
false);
845 ignoreJobProgress = !capturedFramesMap.
count() && Options::alwaysResetSequenceWhenStarting();
847 if (queueTable->rowCount() == 0)
853 SequenceJob * first_job =
nullptr;
855 for (
auto &job : m_captureModuleState->allJobs())
857 if (job->getStatus() == JOB_IDLE || job->getStatus() == JOB_ABORTED)
866 if (first_job ==
nullptr)
869 for (
auto &job : m_captureModuleState->allJobs())
871 if (job->getStatus() != JOB_DONE)
874 if (m_captureModuleState->getCaptureDelayTimer().isActive())
876 if (m_captureModuleState->getCaptureDelayTimer().interval() <= 0)
877 m_captureModuleState->getCaptureDelayTimer().setInterval(1000);
879 else appendLogText(
i18n(
"No pending jobs found. Please add a job to the sequence queue."));
885 if (!ignoreJobProgress)
888 i18n(
"All jobs are complete. Do you want to reset the status of all jobs and restart capturing?"),
890 "reset_job_complete_status_warning") != KMessageBox::Continue)
894 for (
auto &job : m_captureModuleState->allJobs())
897 first_job = m_captureModuleState->allJobs().first();
901 else if (ignoreJobProgress)
903 appendLogText(
i18n(
"Warning: option \"Always Reset Sequence When Starting\" is enabled and resets the sequence counts."));
904 for (
auto &job : m_captureModuleState->allJobs())
909 if (m_captureModuleState->isGuidingDeviationDetected() ==
false
913 m_captureModuleState->getRefocusState()->startRefocusTimer();
918 if (m_captureModuleState->isGuidingDeviationDetected() ==
false)
920 m_captureModuleState->resetDitherCounter();
921 m_captureModuleState->getRefocusState()->resetInSequenceFocusCounter();
924 m_captureModuleState->setGuidingDeviationDetected(
false);
925 m_captureModuleState->resetSpikesDetected();
930 startB->setToolTip(
i18n(
"Stop Sequence"));
931 pauseB->setEnabled(
true);
935 if (Options::enforceGuideDeviation() && autoGuideReady ==
false)
936 appendLogText(
i18n(
"Warning: Guide deviation is selected but autoguide process was not started."));
937 if (m_LimitsUI->limitFocusHFRS->isChecked() && m_captureModuleState->getRefocusState()->isAutoFocusReady() ==
false)
938 appendLogText(
i18n(
"Warning: in-sequence focusing is selected but autofocus process was not started."));
939 if (m_LimitsUI->limitFocusDeltaTS->isChecked() && m_captureModuleState->getRefocusState()->isAutoFocusReady() ==
false)
940 appendLogText(
i18n(
"Warning: temperature delta check is selected but autofocus process was not started."));
942 prepareJob(first_job);
951 m_captureModuleState->resetAlignmentRetries();
955 captureTimeout.
stop();
956 m_captureModuleState->getCaptureDelayTimer().stop();
961 if (activeJob !=
nullptr)
963 if (activeJob->getStatus() == JOB_BUSY)
969 stopText =
i18n(
"CCD capture suspended");
970 activeJob->resetStatus(JOB_BUSY);
974 stopText =
i18n(
"CCD capture complete");
975 activeJob->resetStatus(JOB_DONE);
979 stopText =
i18n(
"CCD capture aborted");
980 activeJob->resetStatus(JOB_ABORTED);
984 stopText =
i18n(
"CCD capture stopped");
985 activeJob->resetStatus(JOB_IDLE);
988 emit captureAborted(activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
989 KSNotification::event(
QLatin1String(
"CaptureFailed"), stopText, KSNotification::Capture, KSNotification::Alert);
990 appendLogText(stopText);
992 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false)
994 int index = m_captureModuleState->allJobs().indexOf(activeJob);
995 QJsonObject oneSequence = m_SequenceArray[index].toObject();
996 oneSequence[
"Status"] =
"Aborted";
997 m_SequenceArray.
replace(index, oneSequence);
998 emit sequenceChanged(m_SequenceArray);
1003 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false)
1005 activeJob->disconnect(
this);
1008 else if (activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
1010 activeJob->disconnect(
this);
1011 activeJob->setCoreProperty(SequenceJob::SJ_Preview,
false);
1012 if (m_captureDeviceAdaptor->getActiveCamera())
1013 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(activeJob->getUploadMode());
1018 if (m_captureDeviceAdaptor->getActiveCamera())
1019 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(activeJob->getUploadMode());
1020 m_captureModuleState->allJobs().removeOne(activeJob);
1022 activeJob->deleteLater();
1024 setActiveJob(
nullptr);
1032 m_captureModuleState->setCaptureState(targetState);
1035 if (m_captureDeviceAdaptor->getLightBox() && lightBoxLightEnabled)
1037 lightBoxLightEnabled =
false;
1038 m_captureDeviceAdaptor->getLightBox()->setLightEnabled(
false);
1042 connectCamera(
false);
1045 if (m_captureDeviceAdaptor->getActiveCamera() &&
1046 m_captureDeviceAdaptor->getActiveChip() &&
1047 m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled())
1048 m_captureDeviceAdaptor->getActiveChip()->abortExposure();
1050 imgProgress->
reset();
1051 imgProgress->setEnabled(
false);
1053 frameRemainingTime->setText(
"--:--:--");
1054 jobRemainingTime->setText(
"--:--:--");
1055 frameInfoLabel->setText(
i18n(
"Expose (-/-):"));
1056 m_isFraming =
false;
1061 auto captureState = m_captureModuleState->getCaptureState();
1066 startB->setToolTip(
i18n(
"Start Sequence"));
1067 pauseB->setEnabled(
false);
1070 seqDelayTimer->
stop();
1072 setActiveJob(
nullptr);
1077 if (m_captureDeviceAdaptor->getActiveCamera())
1078 return m_captureDeviceAdaptor->getActiveCamera()->getDeviceName();
1089 m_captureDeviceAdaptor->setActiveCamera(m_Camera);
1091 m_captureDeviceAdaptor->setActiveChip(
nullptr);
1094 if (m_Camera->getDeviceName().
contains(
"Guider"))
1096 useGuideHead =
true;
1097 m_captureDeviceAdaptor->setActiveChip(m_Camera->getChip(ISD::CameraChip::GUIDE_CCD));
1100 if (m_captureDeviceAdaptor->getActiveChip() ==
nullptr)
1102 useGuideHead =
false;
1103 m_captureDeviceAdaptor->setActiveChip(m_Camera->getChip(ISD::CameraChip::PRIMARY_CCD));
1108 ISD::CameraChip *targetChip = m_captureDeviceAdaptor->getActiveChip();
1109 if (!targetChip || !targetChip->getCCD() || targetChip->isCapturing())
1112 if (m_Camera->hasCoolerControl())
1114 coolerOnB->setEnabled(
true);
1115 coolerOffB->setEnabled(
true);
1116 coolerOnB->setChecked(m_Camera->isCoolerOn());
1117 coolerOffB->setChecked(!m_Camera->isCoolerOn());
1121 coolerOnB->setEnabled(
false);
1122 coolerOnB->setChecked(
false);
1123 coolerOffB->setEnabled(
false);
1124 coolerOffB->setChecked(
false);
1127 updateFrameProperties();
1129 QStringList frameTypes = m_captureDeviceAdaptor->getActiveChip()->getFrameTypes();
1131 captureTypeS->
clear();
1134 captureTypeS->setEnabled(
false);
1137 captureTypeS->setEnabled(
true);
1138 captureTypeS->addItems(frameTypes);
1139 captureTypeS->setCurrentIndex(m_captureDeviceAdaptor->getActiveChip()->getFrameType());
1143 captureFormatS->blockSignals(
true);
1144 captureFormatS->clear();
1145 captureFormatS->addItems(m_Camera->getCaptureFormats());
1146 captureFormatS->setCurrentText(m_Camera->getCaptureFormat());
1147 captureFormatS->blockSignals(
false);
1150 captureEncodingS->blockSignals(
true);
1151 captureEncodingS->clear();
1152 captureEncodingS->addItems(m_Camera->getEncodingFormats());
1153 captureEncodingS->setCurrentText(m_Camera->getEncodingFormat());
1154 captureEncodingS->blockSignals(
false);
1156 customPropertiesDialog->setCCD(m_Camera);
1158 liveVideoB->setEnabled(m_Camera->hasVideoStream());
1159 if (m_Camera->hasVideoStream())
1160 setVideoStreamEnabled(m_Camera->isStreamingEnabled());
1176 DarkLibrary::Instance()->checkCamera();
1179 void Capture::connectCamera(
bool connection)
1183 connect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newExposureValue,
this,
1185 connect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newImage,
this, &Capture::processData,
1188 connect(m_Camera, &ISD::Camera::ready,
this, &Capture::ready);
1192 disconnect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newImage,
this, &Capture::processData);
1193 disconnect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newExposureValue,
this,
1194 &Capture::setExposureProgress);
1196 disconnect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::ready,
this, &Capture::ready);
1200 void Capture::syncCameraInfo()
1202 auto m_Camera = m_captureDeviceAdaptor->getActiveCamera();
1206 if (m_Camera->hasCooler())
1208 cameraTemperatureS->setEnabled(
true);
1209 cameraTemperatureN->setEnabled(
true);
1211 if (m_Camera->getPermission(
"CCD_TEMPERATURE") != IP_RO)
1213 double min, max, step;
1214 setTemperatureB->setEnabled(
true);
1215 cameraTemperatureN->setReadOnly(
false);
1216 cameraTemperatureS->setEnabled(
true);
1217 temperatureRegulationB->setEnabled(
true);
1218 m_Camera->getMinMaxStep(
"CCD_TEMPERATURE",
"CCD_TEMPERATURE_VALUE", &min, &max, &step);
1219 cameraTemperatureN->setMinimum(min);
1220 cameraTemperatureN->setMaximum(max);
1221 cameraTemperatureN->setSingleStep(1);
1222 bool isChecked = m_Camera->getDriverInfo()->getAuxInfo().value(
QString(
"%1_TC").arg(m_Camera->getDeviceName()),
1224 cameraTemperatureS->setChecked(isChecked);
1228 setTemperatureB->setEnabled(
false);
1229 cameraTemperatureN->setReadOnly(
true);
1230 cameraTemperatureS->setEnabled(
false);
1231 cameraTemperatureS->setChecked(
false);
1232 temperatureRegulationB->setEnabled(
false);
1235 double temperature = 0;
1236 if (m_Camera->getTemperature(&temperature))
1238 temperatureOUT->setText(
QString(
"%L1").arg(temperature, 0,
'f', 2));
1239 if (cameraTemperatureN->cleanText().isEmpty())
1240 cameraTemperatureN->setValue(temperature);
1245 cameraTemperatureS->setEnabled(
false);
1246 cameraTemperatureN->setEnabled(
false);
1247 temperatureRegulationB->setEnabled(
false);
1248 cameraTemperatureN->clear();
1249 temperatureOUT->clear();
1250 setTemperatureB->setEnabled(
false);
1253 auto isoList = m_captureDeviceAdaptor->getActiveChip()->getISOList();
1254 captureISOS->blockSignals(
true);
1255 captureISOS->
clear();
1258 if (isoList.isEmpty())
1260 captureISOS->setEnabled(
false);
1264 captureISOS->setEnabled(
true);
1265 captureISOS->addItems(isoList);
1266 captureISOS->setCurrentIndex(m_captureDeviceAdaptor->getActiveChip()->getISOIndex());
1270 double pixelX = 0, pixelY = 0;
1271 bool rc = m_captureDeviceAdaptor->getActiveChip()->getImageInfo(w, h, pixelX, pixelY, bbp);
1272 bool isModelInDB = isModelinDSLRInfo(
QString(m_Camera->getDeviceName()));
1275 if (rc ==
true && (pixelX == 0.0 || pixelY == 0.0 || isModelInDB ==
false))
1279 if (isModelInDB ==
false)
1290 captureISOS->blockSignals(
false);
1293 if (m_Camera->hasGain())
1295 double min, max, step, value, targetCustomGain;
1296 m_Camera->getGainMinMaxStep(&min, &max, &step);
1299 GainSpinSpecialValue = min - step;
1300 captureGainN->setRange(GainSpinSpecialValue, max);
1301 captureGainN->setSpecialValueText(
i18n(
"--"));
1302 captureGainN->setEnabled(
true);
1303 captureGainN->setSingleStep(step);
1304 m_Camera->getGain(&value);
1307 targetCustomGain = getGain();
1311 if (targetCustomGain > 0)
1312 captureGainN->setValue(targetCustomGain);
1314 captureGainN->setValue(GainSpinSpecialValue);
1316 captureGainN->setReadOnly(m_Camera->getGainPermission() == IP_RO);
1320 if (captureGainN->value() != GainSpinSpecialValue)
1321 setGain(captureGainN->value());
1326 captureGainN->setEnabled(
false);
1327 currentGainLabel->clear();
1331 if (m_Camera->hasOffset())
1333 double min, max, step, value, targetCustomOffset;
1334 m_Camera->getOffsetMinMaxStep(&min, &max, &step);
1337 OffsetSpinSpecialValue = min - step;
1338 captureOffsetN->setRange(OffsetSpinSpecialValue, max);
1339 captureOffsetN->setSpecialValueText(
i18n(
"--"));
1340 captureOffsetN->setEnabled(
true);
1341 captureOffsetN->setSingleStep(step);
1342 m_Camera->getOffset(&value);
1345 targetCustomOffset = getOffset();
1349 if (targetCustomOffset > 0)
1350 captureOffsetN->setValue(targetCustomOffset);
1352 captureOffsetN->setValue(OffsetSpinSpecialValue);
1354 captureOffsetN->setReadOnly(m_Camera->getOffsetPermission() == IP_RO);
1358 if (captureOffsetN->value() != OffsetSpinSpecialValue)
1359 setOffset(captureOffsetN->value());
1364 captureOffsetN->setEnabled(
false);
1365 currentOffsetLabel->clear();
1376 if (!m_captureDeviceAdaptor->getActiveCamera())
1379 suspendGuideOnDownload =
1380 (m_captureDeviceAdaptor->getActiveCamera()->getChip(ISD::CameraChip::GUIDE_CCD) == guideChip) ||
1381 (guideChip->getCCD() == m_captureDeviceAdaptor->getActiveCamera() &&
1382 m_captureDeviceAdaptor->getActiveCamera()->getDriverInfo()->getAuxInfo().value(
"mdpd",
false).toBool());
1385 void Capture::resetFrameToZero()
1387 captureFrameXN->setMinimum(0);
1388 captureFrameXN->setMaximum(0);
1389 captureFrameXN->setValue(0);
1391 captureFrameYN->setMinimum(0);
1392 captureFrameYN->setMaximum(0);
1393 captureFrameYN->setValue(0);
1395 captureFrameWN->setMinimum(0);
1396 captureFrameWN->setMaximum(0);
1397 captureFrameWN->setValue(0);
1399 captureFrameHN->setMinimum(0);
1400 captureFrameHN->setMaximum(0);
1401 captureFrameHN->setValue(0);
1404 void Capture::updateFrameProperties(
int reset)
1406 if (!m_captureDeviceAdaptor->getActiveCamera())
1409 int binx = 1, biny = 1;
1410 double min, max, step;
1411 int xstep = 0, ystep = 0;
1415 QString exposureElem = useGuideHead ?
QString(
"GUIDER_EXPOSURE_VALUE") :
QString(
"CCD_EXPOSURE_VALUE");
1416 m_captureDeviceAdaptor->setActiveChip(useGuideHead ? m_captureDeviceAdaptor->getActiveCamera()->getChip(
1417 ISD::CameraChip::GUIDE_CCD) :
1418 m_captureDeviceAdaptor->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1420 captureFrameWN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canSubframe());
1421 captureFrameHN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canSubframe());
1422 captureFrameXN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canSubframe());
1423 captureFrameYN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canSubframe());
1425 captureBinHN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canBin());
1426 captureBinVN->setEnabled(m_captureDeviceAdaptor->getActiveChip()->canBin());
1429 exposureValues << 0.01 << 0.02 << 0.05 << 0.1 << 0.2 << 0.25 << 0.5 << 1 << 1.5 << 2 << 2.5 << 3 << 5 << 6 << 7 << 8 << 9 <<
1430 10 << 20 << 30 << 40 << 50 << 60 << 120 << 180 << 300 << 600 << 900 << 1200 << 1800;
1432 if (m_captureDeviceAdaptor->getActiveCamera()->getMinMaxStep(exposureProp, exposureElem, &min, &max, &step))
1435 captureExposureN->setDecimals(6);
1437 captureExposureN->setDecimals(3);
1438 for(
int i = 0; i < exposureValues.
count(); i++)
1440 double value = exposureValues.
at(i);
1441 if(value < min || value > max)
1449 exposureValues.
append(max);
1452 captureExposureN->setRecommendedValues(exposureValues);
1454 if (m_captureDeviceAdaptor->getActiveCamera()->getMinMaxStep(frameProp,
"WIDTH", &min, &max, &step))
1463 xstep =
static_cast<int>(max * 0.05);
1465 xstep =
static_cast<int>(step);
1467 if (min >= 0 && max > 0)
1469 captureFrameWN->setMinimum(
static_cast<int>(min));
1470 captureFrameWN->setMaximum(
static_cast<int>(max));
1471 captureFrameWN->setSingleStep(xstep);
1477 if (m_captureDeviceAdaptor->getActiveCamera()->getMinMaxStep(frameProp,
"HEIGHT", &min, &max, &step))
1486 ystep =
static_cast<int>(max * 0.05);
1488 ystep =
static_cast<int>(step);
1490 if (min >= 0 && max > 0)
1492 captureFrameHN->setMinimum(
static_cast<int>(min));
1493 captureFrameHN->setMaximum(
static_cast<int>(max));
1494 captureFrameHN->setSingleStep(ystep);
1500 if (m_captureDeviceAdaptor->getActiveCamera()->getMinMaxStep(frameProp,
"X", &min, &max, &step))
1511 if (min >= 0 && max > 0)
1513 captureFrameXN->setMinimum(
static_cast<int>(min));
1514 captureFrameXN->setMaximum(
static_cast<int>(max));
1515 captureFrameXN->setSingleStep(
static_cast<int>(step));
1521 if (m_captureDeviceAdaptor->getActiveCamera()->getMinMaxStep(frameProp,
"Y", &min, &max, &step))
1532 if (min >= 0 && max > 0)
1534 captureFrameYN->setMinimum(
static_cast<int>(min));
1535 captureFrameYN->setMaximum(
static_cast<int>(max));
1536 captureFrameYN->setSingleStep(
static_cast<int>(step));
1543 if (useGuideHead ==
false)
1546 if (reset == 1 || frameSettings.
contains(m_captureDeviceAdaptor->getActiveChip()) ==
false)
1548 QVariantMap settings;
1552 settings[
"w"] = captureFrameWN->maximum();
1553 settings[
"h"] = captureFrameHN->maximum();
1554 settings[
"binx"] = 1;
1555 settings[
"biny"] = 1;
1557 frameSettings[m_captureDeviceAdaptor->getActiveChip()] = settings;
1559 else if (reset == 2 && frameSettings.
contains(m_captureDeviceAdaptor->getActiveChip()))
1561 QVariantMap settings = frameSettings[m_captureDeviceAdaptor->getActiveChip()];
1564 x = settings[
"x"].toInt();
1565 y = settings[
"y"].toInt();
1566 w = settings[
"w"].toInt();
1567 h = settings[
"h"].toInt();
1570 x = qBound(captureFrameXN->minimum(),
x, captureFrameXN->maximum() - 1);
1571 y = qBound(captureFrameYN->minimum(),
y, captureFrameYN->maximum() - 1);
1572 w = qBound(captureFrameWN->minimum(), w, captureFrameWN->maximum());
1573 h = qBound(captureFrameHN->minimum(), h, captureFrameHN->maximum());
1580 frameSettings[m_captureDeviceAdaptor->getActiveChip()] = settings;
1583 if (frameSettings.
contains(m_captureDeviceAdaptor->getActiveChip()))
1585 QVariantMap settings = frameSettings[m_captureDeviceAdaptor->getActiveChip()];
1586 int x = settings[
"x"].toInt();
1587 int y = settings[
"y"].toInt();
1588 int w = settings[
"w"].toInt();
1589 int h = settings[
"h"].toInt();
1591 if (m_captureDeviceAdaptor->getActiveChip()->canBin())
1593 m_captureDeviceAdaptor->getActiveChip()->getMaxBin(&binx, &biny);
1594 captureBinHN->setMaximum(binx);
1595 captureBinVN->setMaximum(biny);
1597 captureBinHN->setValue(settings[
"binx"].toInt());
1598 captureBinVN->setValue(settings[
"biny"].toInt());
1602 captureBinHN->setValue(1);
1603 captureBinVN->setValue(1);
1607 captureFrameXN->setValue(
x);
1609 captureFrameYN->setValue(
y);
1611 captureFrameWN->setValue(w);
1613 captureFrameHN->setValue(h);
1619 if (m_captureDeviceAdaptor->getActiveCamera() ==
nullptr)
1622 if ((prop.isNameMatch(
"CCD_FRAME") && useGuideHead ==
false) ||
1623 (prop.isNameMatch(
"GUIDER_FRAME") && useGuideHead))
1624 updateFrameProperties();
1625 else if ((prop.isNameMatch(
"CCD_INFO") && useGuideHead ==
false) ||
1626 (prop.isNameMatch(
"GUIDER_INFO") && useGuideHead))
1627 updateFrameProperties(2);
1628 else if (prop.isNameMatch(
"CCD_CONTROLS"))
1630 auto nvp = prop.getNumber();
1631 auto gain = nvp->findWidgetByName(
"Gain");
1634 auto offset = nvp->findWidgetByName(
"Offset");
1638 else if (prop.isNameMatch(
"CCD_GAIN"))
1640 auto nvp = prop.getNumber();
1641 currentGainLabel->setText(
QString::number(nvp->at(0)->getValue(),
'f', 0));
1643 else if (prop.isNameMatch(
"CCD_OFFSET"))
1645 auto nvp = prop.getNumber();
1646 currentOffsetLabel->setText(
QString::number(nvp->at(0)->getValue(),
'f', 0));
1650 void Capture::resetFrame()
1652 m_captureDeviceAdaptor->setActiveChip(useGuideHead ? m_captureDeviceAdaptor->getActiveCamera()->getChip(
1653 ISD::CameraChip::GUIDE_CCD) :
1654 m_captureDeviceAdaptor->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1655 m_captureDeviceAdaptor->getActiveChip()->resetFrame();
1656 updateFrameProperties(1);
1659 void Capture::syncFrameType(
const QString &name)
1661 if (!m_Camera || name != m_Camera->getDeviceName())
1664 ISD::CameraChip * tChip = m_captureDeviceAdaptor->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD);
1668 captureTypeS->
clear();
1671 captureTypeS->setEnabled(
false);
1674 captureTypeS->setEnabled(
true);
1675 captureTypeS->addItems(frameTypes);
1676 captureTypeS->setCurrentIndex(tChip->getFrameType());
1680 QString Capture::filterWheel()
1683 return m_FilterWheel->getDeviceName();
1692 FilterPosCombo->setCurrentText(filter);
1701 return FilterPosCombo->currentText();
1706 const QString currentFilterText = FilterPosCombo->itemText(m_FilterManager->getFilterPosition() - 1);
1707 m_captureModuleState->setCurrentFilterPosition(m_FilterManager->getFilterPosition(),
1709 m_FilterManager->getFilterLock(currentFilterText));
1714 FilterPosCombo->clear();
1718 FilterPosLabel->setEnabled(
false);
1719 FilterPosCombo->setEnabled(
false);
1720 filterEditB->setEnabled(
false);
1722 m_captureDeviceAdaptor->setFilterManager(m_FilterManager);
1726 FilterPosLabel->setEnabled(
true);
1727 FilterPosCombo->setEnabled(
true);
1728 filterEditB->setEnabled(
true);
1730 setupFilterManager();
1734 FilterPosCombo->addItems(m_FilterManager->getFilterLabels());
1738 filterEditB->setEnabled(m_captureModuleState->getCurrentFilterPosition() > 0);
1740 FilterPosCombo->setCurrentIndex(m_captureModuleState->getCurrentFilterPosition() - 1);
1743 void Capture::syncFilterInfo()
1747 devices.
append(m_Camera);
1749 devices.
append(m_DustCap);
1751 for (
auto &oneDevice : devices)
1753 auto activeDevices = oneDevice->getText(
"ACTIVE_DEVICES");
1756 auto activeFilter = activeDevices->findWidgetByName(
"ACTIVE_FILTER");
1761 if (activeFilter->getText() != m_FilterWheel->getDeviceName())
1763 activeFilter->setText(m_FilterWheel->getDeviceName().toLatin1().constData());
1764 oneDevice->sendNewProperty(activeDevices);
1771 qCDebug(KSTARS_EKOS_CAPTURE) <<
"No active filter wheel. " << oneDevice->getDeviceName() <<
" ACTIVE_FILTER is reset.";
1772 activeFilter->setText(
"");
1773 oneDevice->sendNewProperty(activeDevices);
1781 IPState Capture::startNextExposure()
1786 if (activeJob ==
nullptr)
1790 if (activeJob->getFrameType() == FRAME_LIGHT)
1792 IPState pending = checkLightFramePendingTasks();
1793 if (pending != IPS_OK)
1798 const int seqDelay = activeJob->getCoreProperty(SequenceJob::SJ_Delay).toInt();
1804 seqDelayTimer->
start(seqDelay);
1809 void Capture::checkNextExposure()
1811 IPState started = startNextExposure();
1814 if (started == IPS_BUSY)
1827 blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1828 .
arg(data->property(
"blobVector").toString())
1829 .
arg(data->property(
"blobElement").toString())
1830 .
arg(data->property(
"chip").toInt());
1833 m_ImageData.
reset();
1836 if (activeJob ==
nullptr)
1839 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring received FITS as active job is null.";
1846 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as meridian flip stage is" <<
1852 if (m_captureDeviceAdaptor->getActiveCamera()
1853 && m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1864 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as current capture state is not active" <<
1865 m_captureModuleState->getCaptureState();
1872 tChip = m_captureDeviceAdaptor->getActiveCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>
1873 (data->property(
"chip").toInt()));
1874 if (tChip != m_captureDeviceAdaptor->getActiveChip())
1876 if (m_captureModuleState->getGuideState() == GUIDE_IDLE)
1877 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it does not correspond to the target chip"
1878 << m_captureDeviceAdaptor->getActiveChip()->getType();
1883 if (m_captureDeviceAdaptor->getActiveChip()->getCaptureMode() == FITS_FOCUS ||
1884 m_captureDeviceAdaptor->getActiveChip()->getCaptureMode() == FITS_GUIDE)
1886 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1887 m_captureDeviceAdaptor->getActiveChip()->getCaptureMode();
1893 if (data && data->property(
"device").toString() != m_captureDeviceAdaptor->getActiveCamera()->getDeviceName())
1895 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as the blob device name does not equal active camera"
1896 << m_captureDeviceAdaptor->getActiveCamera()->getDeviceName();
1902 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() && previewB->isEnabled() ==
false)
1903 previewB->setEnabled(
true);
1906 if (data && darkB->isChecked() && activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() && useGuideHead ==
false)
1908 m_DarkProcessor->denoise(OpticalTrainManager::Instance()->
id(opticalTrainCombo->currentText()),
1909 m_captureDeviceAdaptor->getActiveChip(),
1911 activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(),
1912 activeJob->getCoreProperty(SequenceJob::SJ_ROI).toRect().x(),
1913 activeJob->getCoreProperty(SequenceJob::SJ_ROI).toRect().y());
1918 setCaptureComplete();
1921 IPState Capture::setCaptureComplete()
1923 captureTimeout.
stop();
1924 m_CaptureTimeoutCounter = 0;
1926 downloadProgressTimer.
stop();
1934 emit newImage(activeJob, m_ImageData);
1936 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled() ==
false)
1939 const int seqDelay = activeJob->getCoreProperty(SequenceJob::SJ_Delay).toInt();
1945 activeJob->startCapturing(m_captureModuleState->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1949 activeJob->startCapturing(m_captureModuleState->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1956 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled() ==
false)
1958 disconnect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newExposureValue,
this,
1959 &Capture::setExposureProgress);
1960 DarkLibrary::Instance()->disconnect(
this);
1965 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL && m_DownloadTimer.
isValid())
1969 double currentDownloadTime = m_DownloadTimer.
elapsed() / 1000.0;
1970 downloadTimes << currentDownloadTime;
1973 appendLogText(
i18n(
"Download Time: %1 s, New Download Time Estimate: %2 s.", dLTimeString, estimatedTimeString));
1980 if (activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() >= 1)
1981 KSNotification::event(
QLatin1String(
"EkosCaptureImageReceived"),
i18n(
"Captured image received"),
1982 KSNotification::Capture);
1985 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool())
1988 emit newImage(activeJob, m_ImageData);
1989 m_captureModuleState->allJobs().removeOne(activeJob);
1991 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(activeJob->getUploadMode());
1993 setActiveJob(
nullptr);
1995 if (m_captureModuleState->getGuideState() == GUIDE_SUSPENDED && suspendGuideOnDownload)
1996 emit resumeGuiding();
2001 if (checkPausing() ==
true)
2004 m_captureModuleState->setContinueAction(CaptureModuleState::CONTINUE_ACTION_CAPTURE_COMPLETE);
2008 if (! activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool()
2009 && activeJob->getCalibrationStage() != SequenceJobState::CAL_CALIBRATION)
2012 activeJob->setCompleted(activeJob->getCompleted() + 1);
2014 m_captureModuleState->getRefocusState()->decreaseInSequenceFocusCounter();
2020 m_captureModuleState->decreaseDitherCounter();
2024 emit newImage(activeJob, m_ImageData);
2031 SchedulerJob::CapturedFramesMap::iterator frame_item = capturedFramesMap.
find(activeJob->getSignature());
2032 if (capturedFramesMap.
end() != frame_item)
2033 frame_item.value()++;
2035 if (activeJob->getFrameType() != FRAME_LIGHT)
2037 if (processPostCaptureCalibrationStage() ==
false)
2040 if (activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION_COMPLETE)
2041 activeJob->setCalibrationStage(SequenceJobState::CAL_CAPTURING);
2045 imgProgress->setValue(activeJob->getCompleted());
2047 appendLogText(
i18n(
"Received image %1 out of %2.", activeJob->getCompleted(),
2048 activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt()));
2050 double hfr = -1, eccentricity = -1;
2051 int numStars = -1, median = -1;
2056 if (Options::autoHFR() && m_ImageData && !m_ImageData->areStarsSearched() && m_ImageData->getRecordValue(
"FRAME", frameType)
2057 && frameType.
toString() ==
"Light")
2059 QFuture<bool> result = m_ImageData->findStars(ALGORITHM_SEP);
2062 hfr = m_ImageData->getHFR(HFR_AVERAGE);
2063 numStars = m_ImageData->getSkyBackground().starsDetected;
2064 median = m_ImageData->getMedian();
2065 eccentricity = m_ImageData->getEccentricity();
2066 filename = m_ImageData->filename();
2067 appendLogText(
i18n(
"Captured %1", filename));
2068 auto remainingPlaceholders = PlaceholderPath::remainingPlaceholders(filename);
2069 if (remainingPlaceholders.size() > 0)
2072 i18n(
"WARNING: remaining and potentially unknown placeholders %1 in %2",
2073 remainingPlaceholders.join(
", "), filename));
2081 QVariantMap metadata;
2082 metadata[
"filename"] = filename;
2083 metadata[
"type"] = activeJob->getFrameType();
2084 metadata[
"exposure"] = activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble();
2085 metadata[
"filter"] = activeJob->getCoreProperty(SequenceJob::SJ_Filter).toString();
2086 metadata[
"width"] = activeJob->getCoreProperty(SequenceJob::SJ_ROI).toRect().width();
2087 metadata[
"height"] = activeJob->getCoreProperty(SequenceJob::SJ_ROI).toRect().height();
2088 metadata[
"hfr"] = hfr;
2089 metadata[
"starCount"] = numStars;
2090 metadata[
"median"] = median;
2091 metadata[
"eccentricity"] = eccentricity;
2092 emit captureComplete(metadata);
2097 if (postCaptureScript.
isEmpty() ==
false)
2100 m_CaptureScript.
start(postCaptureScript, generateScriptArguments());
2101 appendLogText(
i18n(
"Executing post capture script %1", postCaptureScript));
2106 if (activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt() <= activeJob->getCompleted())
2108 processJobCompletionStage1();
2113 return resumeSequence();
2116 void Capture::processJobCompletionStage1()
2118 if (activeJob ==
nullptr)
2120 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage1 with null activeJob.";
2129 m_CaptureScript.
start(postJobScript, generateScriptArguments());
2130 appendLogText(
i18n(
"Executing post job script %1", postJobScript));
2135 processJobCompletionStage2();
2138 void Capture::processJobCompletionStage2()
2140 if (activeJob ==
nullptr)
2142 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage2 with null activeJob.";
2148 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false)
2150 int index = m_captureModuleState->allJobs().indexOf(activeJob);
2151 QJsonObject oneSequence = m_SequenceArray[index].toObject();
2152 oneSequence[
"Status"] =
"Complete";
2153 m_SequenceArray.
replace(index, oneSequence);
2154 emit sequenceChanged(m_SequenceArray);
2160 if (resumeSequence() == IPS_OK)
2166 KSNotification::event(
QLatin1String(
"CaptureSuccessful"),
i18n(
"CCD capture sequence completed"),
2167 KSNotification::Capture);
2173 if (m_captureModuleState->getGuideState() == GUIDE_SUSPENDED && suspendGuideOnDownload)
2174 emit resumeGuiding();
2179 IPState Capture::resumeSequence()
2186 for (
auto &oneJob : m_captureModuleState->allJobs())
2188 if (oneJob->getStatus() == JOB_IDLE || oneJob->getStatus() == JOB_ABORTED)
2198 prepareJob(next_job);
2202 if (m_captureModuleState->getGuideState() == GUIDE_SUSPENDED && suspendGuideOnDownload &&
2205 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
2206 emit resumeGuiding();
2213 qCDebug(KSTARS_EKOS_CAPTURE) <<
"All capture jobs complete.";
2222 if (m_captureModuleState->getGuideState() == GUIDE_SUSPENDED && suspendGuideOnDownload &&
2225 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
2226 emit resumeGuiding();
2230 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled())
2232 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
2235 m_captureDeviceAdaptor->getActiveCamera()->setNextSequenceID(nextSequenceID);
2244 if (!preCaptureScript.
isEmpty())
2246 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled())
2248 m_RememberFastExposure =
true;
2249 m_captureDeviceAdaptor->getActiveCamera()->setFastExposureEnabled(
false);
2253 m_CaptureScript.
start(preCaptureScript, generateScriptArguments());
2254 appendLogText(
i18n(
"Executing pre capture script %1", preCaptureScript));
2261 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled())
2264 activeJob->getFrameType() == FRAME_LIGHT &&
2265 checkLightFramePendingTasks() == IPS_OK)
2273 m_RememberFastExposure =
true;
2274 m_captureDeviceAdaptor->getActiveCamera()->setFastExposureEnabled(
false);
2277 checkNextExposure();
2287 if (m_captureModuleState->getFocusState() >= FOCUS_PROGRESS)
2289 appendLogText(
i18n(
"Cannot capture while focus module is busy."));
2298 prepareJob(m_captureModuleState->allJobs().last());
2304 if (m_captureModuleState->getFocusState() >= FOCUS_PROGRESS)
2306 appendLogText(
i18n(
"Cannot start framing while focus module is busy."));
2308 else if (!m_isFraming)
2311 appendLogText(
i18n(
"Starting framing..."));
2319 targetDriftLabel->setVisible(
true);
2320 targetDrift->setVisible(
true);
2321 targetDriftUnit->setVisible(
true);
2323 targetDrift->setText(
QString(
"%L1").arg(targetDiff, 0,
'd', 1));
2326 void Capture::captureImage()
2328 if (activeJob ==
nullptr)
2332 if (m_captureDeviceAdaptor->getActiveCamera()->isConnected() ==
false)
2334 appendLogText(
i18n(
"Error: Lost connection to CCD."));
2339 captureTimeout.
stop();
2340 seqDelayTimer->
stop();
2341 m_captureModuleState->getCaptureDelayTimer().stop();
2343 if (m_captureDeviceAdaptor->getFilterWheel() !=
nullptr)
2351 if (m_captureDeviceAdaptor->getActiveCamera()->isFastExposureEnabled())
2353 int remaining = m_isFraming ? 100000 : (activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt() -
2354 activeJob->getCompleted());
2356 m_captureDeviceAdaptor->getActiveCamera()->setFastCount(
static_cast<uint
>(remaining));
2359 connectCamera(
true);
2361 if (activeJob->getFrameType() == FRAME_FLAT)
2364 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false
2365 && activeJob->getFlatFieldDuration() == DURATION_ADU &&
2366 activeJob->getCalibrationStage() == SequenceJobState::CAL_NONE)
2368 if (m_captureDeviceAdaptor->getActiveCamera()->getEncodingFormat() !=
"FITS" &&
2369 m_captureDeviceAdaptor->getActiveCamera()->getEncodingFormat() !=
"XISF")
2371 appendLogText(
i18n(
"Cannot calculate ADU levels in non-FITS images."));
2376 activeJob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2381 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool())
2383 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2384 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2389 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != activeJob->getUploadMode())
2390 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(activeJob->getUploadMode());
2393 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
2396 m_captureDeviceAdaptor->getActiveCamera()->setNextSequenceID(nextSequenceID);
2399 if (frameSettings.
contains(m_captureDeviceAdaptor->getActiveChip()))
2401 const auto roi = activeJob->getCoreProperty(SequenceJob::SJ_ROI).toRect();
2402 QVariantMap settings;
2403 settings[
"x"] = roi.x();
2404 settings[
"y"] = roi.y();
2405 settings[
"w"] = roi.width();
2406 settings[
"h"] = roi.height();
2407 settings[
"binx"] = activeJob->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x();
2408 settings[
"biny"] = activeJob->getCoreProperty(SequenceJob::SJ_Binning).toPoint().y();
2410 frameSettings[m_captureDeviceAdaptor->getActiveChip()] = settings;
2414 if (m_RememberFastExposure)
2416 m_RememberFastExposure =
false;
2417 m_captureDeviceAdaptor->getActiveCamera()->setFastExposureEnabled(
true);
2421 m_captureDeviceAdaptor->getActiveCamera()->setEncodingFormat(activeJob->getCoreProperty(
2422 SequenceJob::SJ_Encoding).toString());
2425 if (activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
2426 captureStatusWidget->setStatus(
i18n(
"Calibrating..."),
Qt::yellow);
2428 m_captureModuleState->setStartingCapture(
true);
2429 auto placeholderPath = PlaceholderPath(m_SequenceURL.
toLocalFile());
2430 placeholderPath.setGenerateFilenameSettings(*activeJob, m_TargetName);
2431 m_captureDeviceAdaptor->getActiveCamera()->setPlaceholderPath(placeholderPath);
2435 activeJob->startCapturing(m_captureModuleState->getRefocusState()->isAutoFocusReady(),
2436 activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION ? FITS_CALIBRATE : FITS_NORMAL);
2442 if (rc != CAPTURE_OK)
2444 disconnect(m_captureDeviceAdaptor->getActiveCamera(), &ISD::Camera::newExposureValue,
this,
2445 &Capture::setExposureProgress);
2452 emit captureStarting(activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(),
2453 activeJob->getCoreProperty(SequenceJob::SJ_Filter).toString());
2454 appendLogText(
i18n(
"Capturing %1-second %2 image...",
2455 QString(
"%L1").arg(activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f', 3),
2456 activeJob->getCoreProperty(SequenceJob::SJ_Filter).toString()));
2457 captureTimeout.
start(
static_cast<int>(activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble()) * 1000 +
2458 CAPTURE_TIMEOUT_THRESHOLD);
2460 imageCountDown.
setHMS(0, 0, 0);
2461 double ms_left = std::ceil(activeJob->getExposeLeft() * 1000.0);
2462 imageCountDown = imageCountDown.
addMSecs(
int(ms_left));
2463 lastRemainingFrameTimeMS = ms_left;
2464 sequenceCountDown.
setHMS(0, 0, 0);
2466 frameInfoLabel->setText(
QString(
"%1 %2 (%L3/%L4):").arg(CCDFrameTypeNames[activeJob->getFrameType()])
2467 .
arg(activeJob->getCoreProperty(SequenceJob::SJ_Filter).toString())
2468 .
arg(activeJob->getCompleted()).
arg(activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt()));
2470 avgDownloadTime->setVisible(
true);
2471 avgDownloadLabel->setVisible(
true);
2472 secLabel->setVisible(
true);
2474 avgDownloadTime->setText(
QString(
"%L1").arg(getEstimatedDownloadTime(), 0,
'd', 2));
2476 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false)
2478 auto index = m_captureModuleState->allJobs().indexOf(activeJob);
2479 if (index >= 0 && index < m_SequenceArray.
count())
2481 QJsonObject oneSequence = m_SequenceArray[index].toObject();
2482 oneSequence[
"Status"] =
"In Progress";
2483 m_SequenceArray.
replace(index, oneSequence);
2484 emit sequenceChanged(m_SequenceArray);
2490 case CAPTURE_FRAME_ERROR:
2491 appendLogText(
i18n(
"Failed to set sub frame."));
2495 case CAPTURE_BIN_ERROR:
2496 appendLogText(
i18n(
"Failed to set binning."));
2500 case CAPTURE_FOCUS_ERROR:
2501 appendLogText(
i18n(
"Cannot capture while focus module is busy."));
2507 void Capture::updateSequencePrefix(
const QString &newPrefix)
2509 seqPrefix = newPrefix;
2513 void Capture::checkSeqBoundary()
2519 auto placeholderPath = PlaceholderPath(m_SequenceURL.
toLocalFile());
2522 nextSequenceID = placeholderPath.checkSeqBoundary(*activeJob, m_TargetName);
2525 void Capture::appendLogText(
const QString &text)
2527 m_LogText.
insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2",
2528 KStarsData::Instance()->lt().
toString(
"yyyy-MM-ddThh:mm:ss"), text));
2530 qCInfo(KSTARS_EKOS_CAPTURE) << text;
2535 void Capture::clearLog()
2541 void Capture::setDownloadProgress()
2545 double downloadTimeLeft = getEstimatedDownloadTime() - m_DownloadTimer.
elapsed() / 1000.0;
2546 if(downloadTimeLeft > 0)
2548 imageCountDown.
setHMS(0, 0, 0);
2549 imageCountDown = imageCountDown.
addSecs(
int(std::ceil(downloadTimeLeft)));
2550 frameRemainingTime->setText(imageCountDown.
toString(
"hh:mm:ss"));
2551 emit newDownloadProgress(downloadTimeLeft);
2556 void Capture::setExposureProgress(
ISD::CameraChip * tChip,
double value, IPState state)
2558 if (m_captureDeviceAdaptor->getActiveChip() != tChip ||
2559 m_captureDeviceAdaptor->getActiveChip()->getCaptureMode() != FITS_NORMAL
2563 double deltaMS = std::ceil(1000.0 * value - lastRemainingFrameTimeMS);
2564 updateCaptureCountDown(
int(deltaMS));
2565 lastRemainingFrameTimeMS += deltaMS;
2569 activeJob->setExposeLeft(value);
2571 emit newExposureProgress(activeJob);
2574 if (activeJob && state == IPS_ALERT)
2576 int retries = activeJob->getCaptureRetires() + 1;
2578 activeJob->setCaptureRetires(retries);
2580 appendLogText(
i18n(
"Capture failed. Check INDI Control Panel for details."));
2588 appendLogText(
i18n(
"Restarting capture attempt #%1", retries));
2596 if (activeJob !=
nullptr && state == IPS_OK)
2598 activeJob->setCaptureRetires(0);
2599 activeJob->setExposeLeft(0);
2601 if (m_captureDeviceAdaptor->getActiveCamera()
2602 && m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
2604 if (activeJob && activeJob->getStatus() == JOB_BUSY)
2606 processData(
nullptr);
2612 if (m_captureModuleState->getGuideState() == GUIDE_GUIDING && Options::guiderType() == 0 && suspendGuideOnDownload)
2614 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Autoguiding suspended until primary CCD chip completes downloading...";
2615 emit suspendGuiding();
2618 captureStatusWidget->setStatus(
i18n(
"Downloading..."),
Qt::yellow);
2621 m_DownloadTimer.
start();
2622 downloadProgressTimer.
start();
2629 void Capture::updateCaptureCountDown(
int deltaMillis)
2631 imageCountDown = imageCountDown.
addMSecs(deltaMillis);
2632 sequenceCountDown = sequenceCountDown.
addMSecs(deltaMillis);
2633 frameRemainingTime->setText(imageCountDown.
toString(
"hh:mm:ss"));
2634 jobRemainingTime->setText(sequenceCountDown.
toString(
"hh:mm:ss"));
2642 if (type == ISD::Camera::ERROR_CAPTURE)
2644 int retries = activeJob->getCaptureRetires() + 1;
2646 activeJob->setCaptureRetires(retries);
2648 appendLogText(
i18n(
"Capture failed. Check INDI Control Panel for details."));
2656 appendLogText(
i18n(
"Restarting capture attempt #%1", retries));
2672 if (activeJob == value)
2676 if (activeJob !=
nullptr)
2678 disconnect(
this,
nullptr, activeJob,
nullptr);
2679 disconnect(activeJob,
nullptr,
this,
nullptr);
2681 activeJob->disconnectDeviceAdaptor();
2687 m_captureModuleState->setActiveJob(value);
2690 if (activeJob !=
nullptr)
2693 activeJob->connectDeviceAdaptor();
2695 connect(
this, &Capture::newGuiderDrift, activeJob, &SequenceJob::updateGuiderDrift);
2697 connect(activeJob, &SequenceJob::prepareState,
this, &Capture::updatePrepareState);
2698 connect(activeJob, &SequenceJob::prepareComplete,
this, [
this](
bool success)
2707 qWarning(KSTARS_EKOS_CAPTURE) <<
"Capture preparation failed, aborting.";
2714 connect(activeJob, &SequenceJob::newLog,
this, &Capture::newLog);
2716 activeJob->setLightBox(m_captureDeviceAdaptor->getLightBox());
2717 activeJob->addMount(m_captureDeviceAdaptor->getMount());
2718 activeJob->setDome(m_captureDeviceAdaptor->getDome());
2719 activeJob->setDustCap(m_captureDeviceAdaptor->getDustCap());
2720 activeJob->setAutoFocusReady(m_captureModuleState->getRefocusState()->isAutoFocusReady());
2726 if (cameraTemperatureS->isEnabled() ==
false && m_captureDeviceAdaptor->getActiveCamera())
2728 if (m_captureDeviceAdaptor->getActiveCamera()->getPermission(
"CCD_TEMPERATURE") != IP_RO)
2732 temperatureOUT->setText(
QString(
"%L1").arg(value, 0,
'f', 2));
2734 if (cameraTemperatureN->cleanText().isEmpty())
2735 cameraTemperatureN->setValue(value);
2738 void Capture::updateRotatorAngle(
double value)
2741 m_RotatorControlPanel->setCurrentRawAngle(value);
2746 return addJob(
false,
false);
2755 SequenceJob * job =
nullptr;
2757 if (filenamePreview == NOT_PREVIEW)
2759 if (fileUploadModeS->currentIndex() != ISD::Camera::UPLOAD_CLIENT && fileRemoteDirT->text().isEmpty())
2761 KSNotification::error(
i18n(
"You must set remote directory for Local & Both modes."));
2765 if (fileUploadModeS->currentIndex() != ISD::Camera::UPLOAD_LOCAL && fileDirectoryT->text().isEmpty())
2767 KSNotification::error(
i18n(
"You must set local directory for Client & Both modes."));
2772 if (m_JobUnderEdit && filenamePreview == NOT_PREVIEW)
2773 job = m_captureModuleState->allJobs().at(queueTable->currentRow());
2776 job =
new SequenceJob(m_captureDeviceAdaptor, m_captureModuleState);
2779 Q_ASSERT_X(job, __FUNCTION__,
"Capture Job is invalid.");
2781 job->setCoreProperty(SequenceJob::SJ_Format, captureFormatS->currentText());
2782 job->setCoreProperty(SequenceJob::SJ_Encoding, captureEncodingS->currentText());
2783 job->setCoreProperty(SequenceJob::SJ_DarkFlat, isDarkFlat);
2784 job->setCoreProperty(SequenceJob::SJ_UsingPlaceholders,
true);
2787 job->setCoreProperty(SequenceJob::SJ_ISOIndex, captureISOS->currentIndex());
2790 job->setCoreProperty(SequenceJob::SJ_Gain, getGain());
2792 if (getOffset() >= 0)
2793 job->setCoreProperty(SequenceJob::SJ_Offset, getOffset());
2795 job->setCoreProperty(SequenceJob::SJ_Encoding, captureEncodingS->currentText());
2796 job->setCoreProperty(SequenceJob::SJ_Preview, preview);
2798 if (cameraTemperatureN->isEnabled())
2800 job->setCoreProperty(SequenceJob::SJ_EnforceTemperature, cameraTemperatureS->isChecked());
2801 job->setTargetTemperature(cameraTemperatureN->value());
2804 job->setUploadMode(
static_cast<ISD::Camera::UploadMode
>(fileUploadModeS->currentIndex()));
2805 job->setScripts(m_Scripts);
2806 job->setFlatFieldDuration(flatFieldDuration);
2807 job->setFlatFieldSource(flatFieldSource);
2808 job->setPreMountPark(preMountPark);
2809 job->setPreDomePark(preDomePark);
2810 job->setWallCoord(wallCoord);
2811 job->setCoreProperty(SequenceJob::SJ_TargetADU, targetADU);
2812 job->setCoreProperty(SequenceJob::SJ_TargetADUTolerance, targetADUTolerance);
2813 job->setCoreProperty(SequenceJob::SJ_FilterPrefixEnabled, FilterEnabled);
2814 job->setCoreProperty(SequenceJob::SJ_ExpPrefixEnabled, ExpEnabled);
2815 job->setCoreProperty(SequenceJob::SJ_TimeStampPrefixEnabled, TimeStampEnabled);
2816 job->setFrameType(
static_cast<CCDFrameType
>(qMax(0, captureTypeS->currentIndex())));
2818 job->setCoreProperty(SequenceJob::SJ_EnforceStartGuiderDrift, (job->getFrameType() == FRAME_LIGHT
2819 && Options::enforceStartGuiderDrift()));
2820 job->setTargetStartGuiderDrift(Options::startGuideDeviation());
2823 if (FilterPosCombo->currentIndex() != -1 && m_captureDeviceAdaptor->getFilterWheel() !=
nullptr)
2824 job->setTargetFilter(FilterPosCombo->currentIndex() + 1, FilterPosCombo->currentText());
2826 job->setCoreProperty(SequenceJob::SJ_Exposure, captureExposureN->value());
2828 job->setCoreProperty(SequenceJob::SJ_Count, captureCountN->value());
2830 job->setCoreProperty(SequenceJob::SJ_Binning,
QPoint(captureBinHN->value(), captureBinVN->value()));
2833 job->setCoreProperty(SequenceJob::SJ_Delay, captureDelayN->value() * 1000);
2836 job->setCustomProperties(customPropertiesDialog->getCustomProperties());
2838 if (m_captureDeviceAdaptor->getRotator() && m_RotatorControlPanel->isRotationEnforced())
2840 job->setTargetRotation(m_RotatorControlPanel->targetPositionAngle());
2843 job->setCoreProperty(SequenceJob::SJ_ROI,
QRect(captureFrameXN->value(), captureFrameYN->value(), captureFrameWN->value(),
2844 captureFrameHN->value()));
2845 job->setCoreProperty(SequenceJob::SJ_RemoteDirectory, fileRemoteDirT->text());
2846 job->setCoreProperty(SequenceJob::SJ_LocalDirectory, fileDirectoryT->text());
2847 job->setCoreProperty(SequenceJob::SJ_PlaceholderFormat, placeholderFormatT->text());
2848 job->setCoreProperty(SequenceJob::SJ_PlaceholderSuffix, formatSuffixN->value());
2850 if (m_JobUnderEdit ==
false || filenamePreview != NOT_PREVIEW)
2854 if (m_captureModuleState->allJobs().isEmpty() && preview ==
false)
2855 ignoreJobProgress =
true;
2857 m_captureModuleState->allJobs().append(job);
2866 auto placeholderPath = PlaceholderPath();
2867 placeholderPath.addJob(job, m_TargetName);
2870 if (m_JobUnderEdit ==
false)
2872 currentRow = queueTable->rowCount();
2873 queueTable->insertRow(currentRow);
2876 currentRow = queueTable->currentRow();
2879 job->setStatusCell(status);
2882 filter->setText(
"--");
2883 jsonJob.
insert(
"Filter",
"--");
2884 if (FilterPosCombo->count() > 0 && (captureTypeS->currentIndex() == FRAME_LIGHT
2885 || captureTypeS->currentIndex() == FRAME_FLAT || isDarkFlat))
2887 filter->setText(FilterPosCombo->currentText());
2888 jsonJob.
insert(
"Filter", FilterPosCombo->currentText());
2895 job->setCountCell(count);
2899 exp->
setText(
QString(
"%L1").arg(captureExposureN->value(), 0,
'f', captureExposureN->decimals()));
2905 type->setText(isDarkFlat ?
i18n(
"Dark Flat") : captureTypeS->currentText());
2908 jsonJob.
insert(
"Type", isDarkFlat ?
i18n(
"Dark Flat") : type->text());
2911 bin->setText(
QString(
"%1x%2").arg(captureBinHN->value()).
arg(captureBinVN->value()));
2914 jsonJob.
insert(
"Bin", bin->text());
2917 if (captureISOS && captureISOS->currentIndex() != -1)
2919 iso->
setText(captureISOS->currentText());
2922 else if (job->getCoreProperty(SequenceJob::SJ_Gain).toDouble() >= 0)
2930 jsonJob.
insert(
"ISO/Gain",
"--");
2936 if (job->getCoreProperty(SequenceJob::SJ_Offset).toDouble() >= 0)
2944 jsonJob.
insert(
"Offset",
"--");
2949 if (m_JobUnderEdit ==
false)
2951 queueTable->setItem(currentRow, 0, status);
2952 queueTable->setItem(currentRow, 1, filter);
2953 queueTable->setItem(currentRow, 2, count);
2954 queueTable->setItem(currentRow, 3, exp);
2955 queueTable->setItem(currentRow, 4, type);
2956 queueTable->setItem(currentRow, 5, bin);
2957 queueTable->setItem(currentRow, 6, iso);
2958 queueTable->setItem(currentRow, 7, offset);
2960 m_SequenceArray.
append(jsonJob);
2961 emit sequenceChanged(m_SequenceArray);
2964 removeFromQueueB->setEnabled(
true);
2966 if (queueTable->rowCount() > 0)
2968 queueSaveAsB->setEnabled(
true);
2969 queueSaveB->setEnabled(
true);
2970 resetB->setEnabled(
true);
2974 if (queueTable->rowCount() > 1)
2976 queueUpB->setEnabled(
true);
2977 queueDownB->setEnabled(
true);
2980 if (m_JobUnderEdit && filenamePreview == NOT_PREVIEW)
2982 m_JobUnderEdit =
false;
2984 appendLogText(
i18n(
"Job #%1 changes applied.", currentRow + 1));
2986 m_SequenceArray.
replace(currentRow, jsonJob);
2987 emit sequenceChanged(m_SequenceArray);
2990 QString signature = placeholderPath.generateFilename(*job, m_TargetName, filenamePreview != REMOTE_PREVIEW,
true, 1,
2991 ".fits",
"",
false,
true);
2992 job->setCoreProperty(SequenceJob::SJ_Signature, signature);
2997 void Capture::removeJobFromQueue()
2999 int currentRow = queueTable->currentRow();
3002 currentRow = queueTable->rowCount() - 1;
3007 if (queueTable->rowCount() == 0)
3010 if (currentRow > queueTable->rowCount())
3011 queueTable->selectRow(queueTable->rowCount() - 1);
3013 queueTable->selectRow(currentRow);
3028 if (index < 0 || index >= m_captureModuleState->allJobs().count())
3032 queueTable->removeRow(index);
3034 emit sequenceChanged(m_SequenceArray);
3036 if (m_captureModuleState->allJobs().empty())
3039 SequenceJob * job = m_captureModuleState->allJobs().at(index);
3040 m_captureModuleState->allJobs().removeOne(job);
3041 if (job == activeJob)
3042 setActiveJob(
nullptr);
3046 if (queueTable->rowCount() == 0)
3047 removeFromQueueB->setEnabled(
false);
3049 if (queueTable->rowCount() == 1)
3051 queueUpB->setEnabled(
false);
3052 queueDownB->setEnabled(
false);
3055 for (
int i = 0; i < m_captureModuleState->allJobs().count(); i++)
3056 m_captureModuleState->allJobs().at(i)->setStatusCell(queueTable->item(i, 0));
3058 if (index < queueTable->rowCount())
3059 queueTable->selectRow(index);
3060 else if (queueTable->rowCount() > 0)
3061 queueTable->selectRow(queueTable->rowCount() - 1);
3063 if (queueTable->rowCount() == 0)
3065 queueSaveAsB->setEnabled(
false);
3066 queueSaveB->setEnabled(
false);
3067 resetB->setEnabled(
false);
3077 int currentRow = queueTable->currentRow();
3079 int columnCount = queueTable->columnCount();
3081 if (currentRow <= 0 || queueTable->rowCount() == 1)
3084 int destinationRow = currentRow - 1;
3086 for (
int i = 0; i < columnCount; i++)
3091 queueTable->setItem(destinationRow, i, downItem);
3092 queueTable->setItem(currentRow, i, upItem);
3095 SequenceJob * job = m_captureModuleState->allJobs().takeAt(currentRow);
3097 m_captureModuleState->allJobs().removeOne(job);
3098 m_captureModuleState->allJobs().insert(destinationRow, job);
3100 QJsonObject currentJob = m_SequenceArray[currentRow].toObject();
3101 m_SequenceArray.
replace(currentRow, m_SequenceArray[destinationRow]);
3102 m_SequenceArray.
replace(destinationRow, currentJob);
3103 emit sequenceChanged(m_SequenceArray);
3105 queueTable->selectRow(destinationRow);
3107 for (
int i = 0; i < m_captureModuleState->allJobs().count(); i++)
3108 m_captureModuleState->allJobs().at(i)->setStatusCell(queueTable->item(i, 0));
3115 int currentRow = queueTable->currentRow();
3117 int columnCount = queueTable->columnCount();
3119 if (currentRow < 0 || queueTable->rowCount() == 1 || (currentRow + 1) == queueTable->rowCount())
3122 int destinationRow = currentRow + 1;
3124 for (
int i = 0; i < columnCount; i++)
3129 queueTable->setItem(destinationRow, i, downItem);
3130 queueTable->setItem(currentRow, i, upItem);
3133 SequenceJob * job = m_captureModuleState->allJobs().takeAt(currentRow);
3135 m_captureModuleState->allJobs().removeOne(job);
3136 m_captureModuleState->allJobs().insert(destinationRow, job);
3138 QJsonObject currentJob = m_SequenceArray[currentRow].toObject();
3139 m_SequenceArray.
replace(currentRow, m_SequenceArray[destinationRow]);
3140 m_SequenceArray.
replace(destinationRow, currentJob);
3141 emit sequenceChanged(m_SequenceArray);
3143 queueTable->selectRow(destinationRow);
3145 for (
int i = 0; i < m_captureModuleState->allJobs().count(); i++)
3146 m_captureModuleState->allJobs().at(i)->setStatusCell(queueTable->item(i, 0));
3151 void Capture::setBusy(
bool enable)
3155 previewB->setEnabled(!enable);
3156 loopB->setEnabled(!enable);
3157 opticalTrainCombo->setEnabled(!enable);
3158 trainB->setEnabled(!enable);
3170 if (job->getCoreProperty(SequenceJob::SJ_Preview).toBool() && Options::useFITSViewer() ==
false
3171 && Options::useSummaryPreview() ==
false)
3177 Options::setUseFITSViewer(
true);
3186 KSMessageBox::Instance()->questionYesNo(
i18n(
"No view available for previews. Enable FITS viewer?"),
3187 i18n(
"Display preview"), 15);
3192 if (m_isFraming ==
false)
3193 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Preparing capture job" << job->getSignature() <<
"for execution.";
3195 int index = m_captureModuleState->allJobs().indexOf(job);
3197 queueTable->selectRow(index);
3199 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool() ==
false)
3202 imgProgress->setEnabled(
true);
3203 imgProgress->setMaximum(activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt());
3204 imgProgress->setValue(activeJob->getCompleted());
3206 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
3207 updateSequencePrefix(activeJob->getCoreProperty(SequenceJob::SJ_FullPrefix).toString());
3213 QString signature = activeJob->getSignature();
3239 if (capturedFramesMap.
contains(signature))
3242 int count = capturedFramesMap[signature];
3245 for (
auto &a_job : m_captureModuleState->allJobs())
3246 if (a_job == activeJob)
3248 else if (a_job->getSignature() == activeJob->getSignature())
3249 count -= a_job->getCompleted();
3252 activeJob->setCompleted(count);
3256 else if (capturedFramesMap.
count() > 0)
3259 activeJob->setCompleted(0);
3265 else if (ignoreJobProgress && activeJob->getJobProgressIgnored() ==
false)
3267 activeJob->setJobProgressIgnored(
true);
3268 activeJob->setCompleted(0);
3273 if (activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt() <= activeJob->getCompleted())
3275 activeJob->setCompleted(activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt());
3276 appendLogText(
i18n(
"Job requires %1-second %2 images, has already %3/%4 captures and does not need to run.",
3277 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f', 3),
3278 job->getCoreProperty(SequenceJob::SJ_Filter).toString(),
3279 activeJob->getCompleted(), activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt()));
3280 processJobCompletionStage2();
3288 appendLogText(
i18n(
"Job requires %1-second %2 images, has %3/%4 frames captured and will be processed.",
3289 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f', 3),
3290 job->getCoreProperty(SequenceJob::SJ_Filter).toString(),
3291 activeJob->getCompleted(), activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt()));
3296 m_captureDeviceAdaptor->getActiveCamera()->setNextSequenceID(nextSequenceID);
3300 if (m_captureDeviceAdaptor->getActiveCamera()->isBLOBEnabled() ==
false)
3305 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
3307 m_captureDeviceAdaptor->getActiveCamera()->setBLOBEnabled(
true);
3315 m_captureDeviceAdaptor->getActiveCamera()->setBLOBEnabled(
true);
3316 prepareActiveJobStage1();
3323 m_captureDeviceAdaptor->getActiveCamera()->setBLOBEnabled(
true);
3327 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
3328 i18n(
"Image Transfer"), 15);
3334 prepareActiveJobStage1();
3338 void Capture::prepareActiveJobStage1()
3340 if (activeJob ==
nullptr)
3342 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage1 with null activeJob.";
3349 if (!preJobScript.
isEmpty() && activeJob->getCompleted() == 0)
3352 m_CaptureScript.
start(preJobScript, generateScriptArguments());
3353 appendLogText(
i18n(
"Executing pre job script %1", preJobScript));
3357 prepareActiveJobStage2();
3360 void Capture::prepareActiveJobStage2()
3363 if (activeJob ==
nullptr)
3365 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage2 with null activeJob.";
3368 emit newImage(activeJob, m_ImageData);
3380 if (activeJob !=
nullptr)
3384 if (!preCaptureScript.
isEmpty())
3387 m_CaptureScript.
start(preCaptureScript, generateScriptArguments());
3388 appendLogText(
i18n(
"Executing pre capture script %1", preCaptureScript));
3393 preparePreCaptureActions();
3396 void Capture::preparePreCaptureActions()
3398 if (activeJob ==
nullptr)
3400 qWarning(KSTARS_EKOS_CAPTURE) <<
"preparePreCaptureActions with null activeJob.";
3407 if (activeJob->getCoreProperty(SequenceJob::SJ_Preview).toBool())
3411 startB->setToolTip(
i18n(
"Stop"));
3415 activeJob->setCoreProperty(SequenceJob::SJ_GuiderActive, isActivelyGuiding());
3418 activeJob->prepareCapture();
3421 void Capture::updatePrepareState(
CaptureState prepareState)
3423 m_captureModuleState->setCaptureState(prepareState);
3425 if (activeJob ==
nullptr)
3427 qWarning(KSTARS_EKOS_CAPTURE) <<
"updatePrepareState with null activeJob.";
3432 switch (prepareState)
3435 appendLogText(
i18n(
"Setting temperature to %1 °C...", activeJob->getTargetTemperature()));
3436 captureStatusWidget->setStatus(
i18n(
"Set Temp to %1 °C...", activeJob->getTargetTemperature()),
Qt::yellow);
3439 appendLogText(
i18n(
"Waiting for guide drift below %1\"...", activeJob->getTargetStartGuiderDrift()));
3440 captureStatusWidget->setStatus(
i18n(
"Wait for Guider < %1\"...", activeJob->getTargetStartGuiderDrift()),
Qt::yellow);
3444 appendLogText(
i18n(
"Setting rotation to %1 degrees E of N...", activeJob->getTargetRotation()));
3445 captureStatusWidget->setStatus(
i18n(
"Set Rotator to %1 deg...", activeJob->getTargetRotation()),
Qt::yellow);
3454 void Capture::executeJob()
3456 if (activeJob ==
nullptr)
3458 qWarning(KSTARS_EKOS_CAPTURE) <<
"executeJob with null activeJob.";
3463 if (m_ObserverName.
isEmpty() ==
false)
3465 if (m_TargetName.
isEmpty() ==
false)
3469 m_captureDeviceAdaptor->getActiveCamera()->setFITSHeaders(FITSHeaders);
3474 useGuideHead = (m_captureDeviceAdaptor->getActiveChip()->getType() == ISD::CameraChip::PRIMARY_CCD) ?
false :
true;
3476 syncGUIToJob(activeJob);
3480 if (activeJob->getCoreProperty(SequenceJob::SJ_DarkFlat).toBool())
3483 if (setDarkFlatExposure(activeJob)
3484 && m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
3486 auto placeholderPath = PlaceholderPath();
3488 placeholderPath.processJobInfo(activeJob, m_TargetName);
3489 updateSequencePrefix(activeJob->getCoreProperty(SequenceJob::SJ_FullPrefix).toString());
3494 updatePreCaptureCalibrationStatus();
3497 void Capture::updatePreCaptureCalibrationStatus()
3500 if (isBusy ==
false)
3502 appendLogText(
i18n(
"Warning: Calibration process was prematurely terminated."));
3506 IPState rc = processPreCaptureCalibrationStage();
3508 if (rc == IPS_ALERT)
3510 else if (rc == IPS_BUSY)
3519 void Capture::setFocusTemperatureDelta(
double focusTemperatureDelta,
double absTemperture)
3521 Q_UNUSED(absTemperture);
3525 m_captureModuleState->getRefocusState()->setFocusTemperatureDelta(focusTemperatureDelta);
3530 const double deviation_rms = std::hypot(delta_ra, delta_dec);
3533 emit newGuiderDrift(deviation_rms);
3535 m_captureModuleState->setGuideDeviation(deviation_rms);
3542 m_captureModuleState->updateFocusState(state);
3543 if (activeJob !=
nullptr)
3544 activeJob->setFocusStatus(state);
3549 if ((m_captureModuleState->getRefocusState()->isRefocusing()
3550 || m_captureModuleState->getRefocusState()->isInSequenceFocus()) && activeJob && activeJob->getStatus() == JOB_BUSY)
3554 case FOCUS_COMPLETE:
3555 appendLogText(
i18n(
"Focus complete."));
3556 captureStatusWidget->setStatus(
i18n(
"Focus complete."),
Qt::yellow);
3560 captureStatusWidget->setStatus(
i18n(
"Autofocus failed."),
Qt::darkRed);
3569 void Capture::updateMeridianFlipStage(MeridianFlipState::MFStage stage)
3576 case MeridianFlipState::MF_READY:
3584 case MeridianFlipState::MF_INITIATED:
3585 captureStatusWidget->setStatus(
i18n(
"Meridian Flip..."),
Qt::yellow);
3586 KSNotification::event(
QLatin1String(
"MeridianFlipStarted"),
i18n(
"Meridian flip started"), KSNotification::Capture);
3589 case MeridianFlipState::MF_COMPLETED:
3590 captureStatusWidget->setStatus(
i18n(
"Flip complete."),
Qt::yellow);
3593 if (m_captureModuleState->getRefocusState()->isInSequenceFocus())
3594 m_LimitsUI->limitFocusHFRN->setValue(m_captureModuleState->getFileHFR());
3604 int Capture::getTotalFramesCount(
QString signature)
3609 foreach (
SequenceJob * job, m_captureModuleState->allJobs())
3612 QString sig = job->getSignature();
3613 if (sig == signature)
3615 result += job->getCoreProperty(SequenceJob::SJ_Count).toInt();
3626 void Capture::setRotatorReversed(
bool toggled)
3628 m_RotatorControlPanel->ReverseDirectionCheck->setEnabled(
true);
3630 m_RotatorControlPanel->ReverseDirectionCheck->blockSignals(
true);
3631 m_RotatorControlPanel->ReverseDirectionCheck->setChecked(toggled);
3632 m_RotatorControlPanel->ReverseDirectionCheck->blockSignals(
false);
3638 if (m_captureModuleState->isCaptureRunning() ==
false)
3640 m_TargetName = name;
3641 targetNameT->setText(m_TargetName);
3642 generatePreviewFilename();
3646 void Capture::syncTelescopeInfo()
3648 if (m_Mount && m_Camera && m_Mount->isConnected())
3651 auto activeDevices = m_Camera->
getText(
"ACTIVE_DEVICES");
3654 auto activeTelescope = activeDevices->findWidgetByName(
"ACTIVE_TELESCOPE");
3655 if (activeTelescope)
3657 activeTelescope->setText(m_captureDeviceAdaptor->getMount()->getDeviceName().toLatin1().constData());
3664 void Capture::saveFITSDirectory()
3675 void Capture::loadSequenceQueue()
3679 "Ekos Sequence Queue (*.esq)");
3683 if (fileURL.
isValid() ==
false)
3686 KSNotification::sorry(
message,
i18n(
"Invalid URL"));
3695 bool Capture::loadSequenceQueue(
const QString &fileURL,
bool ignoreTarget)
3697 QFile sFile(fileURL);
3701 KSNotification::sorry(
message,
i18n(
"Could Not Open File"));
3705 capturedFramesMap.
clear();
3708 LilXML * xmlParser = newLilXML();
3710 char errmsg[MAXRBUF];
3711 XMLEle * root =
nullptr;
3712 XMLEle * ep =
nullptr;
3720 root = readXMLEle(xmlParser, c, errmsg);
3724 double sqVersion = cLocale.
toDouble(findXMLAttValu(root,
"version"));
3725 if (sqVersion < SQ_COMPAT_VERSION)
3727 appendLogText(
i18n(
"Deprecated sequence file format version %1. Please construct a new sequence file.",
3732 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
3734 if (!strcmp(tagXMLEle(ep),
"Observer"))
3736 m_ObserverName =
QString(pcdataXMLEle(ep));
3738 else if (!strcmp(tagXMLEle(ep),
"GuideDeviation"))
3740 m_LimitsUI->limitGuideDeviationS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3741 m_LimitsUI->limitGuideDeviationN->setValue(cLocale.
toDouble(pcdataXMLEle(ep)));
3743 else if (!strcmp(tagXMLEle(ep),
"CCD"))
3747 else if (!strcmp(tagXMLEle(ep),
"FilterWheel"))
3751 else if (!strcmp(tagXMLEle(ep),
"GuideStartDeviation"))
3753 m_LimitsUI->startGuiderDriftS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3754 m_LimitsUI->startGuiderDriftN->setValue(cLocale.
toDouble(pcdataXMLEle(ep)));
3756 else if (!strcmp(tagXMLEle(ep),
"Autofocus"))
3758 m_LimitsUI->limitFocusHFRS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3759 double const HFRValue = cLocale.
toDouble(pcdataXMLEle(ep));
3762 m_captureModuleState->setFileHFR(HFRValue > 0.0 ? HFRValue : 0.0);
3763 m_LimitsUI->limitFocusHFRN->setValue(m_captureModuleState->getFileHFR());
3765 else if (!strcmp(tagXMLEle(ep),
"RefocusOnTemperatureDelta"))
3767 m_LimitsUI->limitFocusDeltaTS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3768 double const deltaValue = cLocale.
toDouble(pcdataXMLEle(ep));
3769 m_LimitsUI->limitFocusDeltaTN->setValue(deltaValue);
3771 else if (!strcmp(tagXMLEle(ep),
"RefocusEveryN"))
3773 m_LimitsUI->limitRefocusS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3774 int const minutesValue = cLocale.
toInt(pcdataXMLEle(ep));
3776 m_LimitsUI->limitRefocusN->setValue(minutesValue > 0 ? minutesValue : 0);
3778 else if (!strcmp(tagXMLEle(ep),
"RefocusOnMeridianFlip"))
3780 m_LimitsUI->meridianRefocusS->setChecked(!strcmp(findXMLAttValu(ep,
"enabled"),
"true"));
3782 else if (!strcmp(tagXMLEle(ep),
"MeridianFlip"))
3786 if (! strcmp(findXMLAttValu(ep,
"enabled"),
"true"))
3788 i18n(
"Meridian flip configuration has been shifted to the mount module. Please configure the meridian flip there."));
3792 processJobInfo(ep, ignoreTarget);
3799 appendLogText(
QString(errmsg));
3800 delLilXML(xmlParser);
3807 delLilXML(xmlParser);
3809 queueSaveB->setToolTip(
"Save to " + sFile.
fileName());
3811 syncRefocusOptionsFromGUI();
3815 bool Capture::processJobInfo(XMLEle * root,
bool ignoreTarget)
3819 m_RotatorControlPanel->setRotationEnforced(
false);
3821 bool isDarkFlat =
false;
3824 bool foundPlaceholderFormat =
false;
3826 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
3828 if (!strcmp(tagXMLEle(ep),
"Exposure"))
3829 captureExposureN->setValue(cLocale.
toDouble(pcdataXMLEle(ep)));
3830 else if (!strcmp(tagXMLEle(ep),
"Format"))
3831 captureFormatS->setCurrentText(pcdataXMLEle(ep));
3832 else if (!strcmp(tagXMLEle(ep),
"Encoding"))
3834 captureEncodingS->setCurrentText(pcdataXMLEle(ep));
3836 else if (!strcmp(tagXMLEle(ep),
"Binning"))
3838 subEP = findXMLEle(ep,
"X");
3840 captureBinHN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3841 subEP = findXMLEle(ep,
"Y");
3843 captureBinVN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3845 else if (!strcmp(tagXMLEle(ep),
"Frame"))
3847 subEP = findXMLEle(ep,
"X");
3849 captureFrameXN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3850 subEP = findXMLEle(ep,
"Y");
3852 captureFrameYN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3853 subEP = findXMLEle(ep,
"W");
3855 captureFrameWN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3856 subEP = findXMLEle(ep,
"H");
3858 captureFrameHN->setValue(cLocale.
toInt(pcdataXMLEle(subEP)));
3860 else if (!strcmp(tagXMLEle(ep),
"Temperature"))
3862 if (cameraTemperatureN->isEnabled())
3863 cameraTemperatureN->setValue(cLocale.
toDouble(pcdataXMLEle(ep)));
3866 if (!strcmp(findXMLAttValu(ep,
"force"),
"true"))
3867 cameraTemperatureS->setChecked(
true);
3868 else if (!strcmp(findXMLAttValu(ep,
"force"),
"false"))
3869 cameraTemperatureS->setChecked(
false);
3871 else if (!strcmp(tagXMLEle(ep),
"Filter"))
3874 if (FilterPosCombo->findText(pcdataXMLEle(ep)) == -1)
3876 appendLogText(
i18n(
"Warning: Filter %1 not found in filter wheel.", pcdataXMLEle(ep)));
3877 qWarning(KSTARS_EKOS_CAPTURE) <<
QString(
"Filter %1 not found in filter wheel.").
arg(pcdataXMLEle(ep));
3879 FilterPosCombo->setCurrentText(pcdataXMLEle(ep));
3881 else if (!strcmp(tagXMLEle(ep),
"Type"))
3883 captureTypeS->setCurrentText(pcdataXMLEle(ep));
3885 else if (!strcmp(tagXMLEle(ep),
"Prefix"))
3888 subEP = findXMLEle(ep,
"RawPrefix");
3889 if (subEP && ignoreTarget ==
false)
3891 if (strcmp(pcdataXMLEle(subEP),
"") != 0)
3892 qWarning(KSTARS_EKOS_CAPTURE) <<
QString(
"Sequence job raw prefix %1 ignored.").
arg(pcdataXMLEle(subEP));
3894 subEP = findXMLEle(ep,
"FilterEnabled");
3896 FilterEnabled = !strcmp(
"1", pcdataXMLEle(subEP));
3897 subEP = findXMLEle(ep,
"ExpEnabled");
3899 ExpEnabled = !strcmp(
"1", pcdataXMLEle(subEP));
3900 subEP = findXMLEle(ep,
"TimeStampEnabled");
3902 TimeStampEnabled = !strcmp(
"1", pcdataXMLEle(subEP));
3904 else if (!strcmp(tagXMLEle(ep),
"Count"))
3906 captureCountN->setValue(cLocale.
toInt(pcdataXMLEle(ep)));
3908 else if (!strcmp(tagXMLEle(ep),
"Delay"))
3910 captureDelayN->setValue(cLocale.
toInt(pcdataXMLEle(ep)));
3912 else if (!strcmp(tagXMLEle(ep),
"PostCaptureScript"))
3916 else if (!strcmp(tagXMLEle(ep),
"PreCaptureScript"))
3920 else if (!strcmp(tagXMLEle(ep),
"PostJobScript"))
3924 else if (!strcmp(tagXMLEle(ep),
"PreJobScript"))
3928 else if (!strcmp(tagXMLEle(ep),
"FITSDirectory"))
3930 fileDirectoryT->setText(pcdataXMLEle(ep));
3932 else if (!strcmp(tagXMLEle(ep),
"PlaceholderFormat"))
3934 placeholderFormatT->setText(pcdataXMLEle(ep));
3935 foundPlaceholderFormat =
true;
3937 else if (!strcmp(tagXMLEle(ep),
"PlaceholderSuffix"))
3939 formatSuffixN->setValue(cLocale.
toUInt(pcdataXMLEle(ep)));
3940 foundPlaceholderFormat =
true;
3942 else if (!strcmp(tagXMLEle(ep),
"RemoteDirectory"))
3944 fileRemoteDirT->setText(pcdataXMLEle(ep));
3946 else if (!strcmp(tagXMLEle(ep),
"UploadMode"))
3948 fileUploadModeS->setCurrentIndex(cLocale.
toInt(pcdataXMLEle(ep)));
3950 else if (!strcmp(tagXMLEle(ep),
"ISOIndex"))
3953 captureISOS->setCurrentIndex(cLocale.
toInt(pcdataXMLEle(ep)));
3955 else if (!strcmp(tagXMLEle(ep),
"Rotation"))
3957 m_RotatorControlPanel->setRotationEnforced(
true);
3958 m_RotatorControlPanel->setTargetPositionAngle(cLocale.
toDouble(pcdataXMLEle(ep)));
3960 else if (!strcmp(tagXMLEle(ep),
"Properties"))
3964 for (subEP = nextXMLEle(ep, 1); subEP !=
nullptr; subEP = nextXMLEle(ep, 0))
3967 XMLEle * oneElement =
nullptr;
3968 for (oneElement = nextXMLEle(subEP, 1); oneElement !=
nullptr; oneElement = nextXMLEle(subEP, 0))
3970 const char *
name = findXMLAttValu(oneElement,
"name");
3973 auto xmlValue = pcdataXMLEle(oneElement);
3975 auto value = cLocale.
toDouble(xmlValue, &ok);
3977 elements[
name] = value;
3979 elements[
name] = xmlValue;
3982 const char *
name = findXMLAttValu(subEP,
"name");
3983 propertyMap[
name] = elements;
3986 customPropertiesDialog->setCustomProperties(propertyMap);
3987 const double gain = getGain();
3989 captureGainN->setValue(gain);
3990 const double offset = getOffset();
3992 captureOffsetN->setValue(offset);
3994 else if (!strcmp(tagXMLEle(ep),
"Calibration"))
3996 subEP = findXMLEle(ep,
"FlatSource");
3999 XMLEle * typeEP = findXMLEle(subEP,
"Type");
4002 if (!strcmp(pcdataXMLEle(typeEP),
"Manual"))
4003 flatFieldSource = SOURCE_MANUAL;
4004 else if (!strcmp(pcdataXMLEle(typeEP),
"FlatCap"))
4005 flatFieldSource = SOURCE_FLATCAP;
4006 else if (!strcmp(pcdataXMLEle(typeEP),
"DarkCap"))
4007 flatFieldSource = SOURCE_DARKCAP;
4008 else if (!strcmp(pcdataXMLEle(typeEP),
"Wall"))
4010 XMLEle * azEP = findXMLEle(subEP,
"Az");
4011 XMLEle * altEP = findXMLEle(subEP,
"Alt");
4015 flatFieldSource = SOURCE_WALL;
4021 flatFieldSource = SOURCE_DAWN_DUSK;
4025 subEP = findXMLEle(ep,
"FlatDuration");
4028 const char * dark = findXMLAttValu(subEP,
"dark");
4029 isDarkFlat = !strcmp(dark,
"true");
4031 XMLEle * typeEP = findXMLEle(subEP,
"Type");
4034 if (!strcmp(pcdataXMLEle(typeEP),
"Manual"))
4035 flatFieldDuration = DURATION_MANUAL;
4038 XMLEle * aduEP = findXMLEle(subEP,
"Value");
4041 flatFieldDuration = DURATION_ADU;
4042 targetADU = cLocale.
toDouble(pcdataXMLEle(aduEP));
4045 aduEP = findXMLEle(subEP,
"Tolerance");
4048 targetADUTolerance = cLocale.
toDouble(pcdataXMLEle(aduEP));
4052 subEP = findXMLEle(ep,
"PreMountPark");
4055 if (!strcmp(pcdataXMLEle(subEP),
"True"))
4056 preMountPark =
true;
4058 preMountPark =
false;
4061 subEP = findXMLEle(ep,
"PreDomePark");
4064 if (!strcmp(pcdataXMLEle(subEP),
"True"))
4067 preDomePark =
false;
4072 if (!foundPlaceholderFormat)
4073 placeholderFormatT->setText(PlaceholderPath::defaultFormat(FilterEnabled, ExpEnabled, TimeStampEnabled));
4075 addJob(
false, isDarkFlat);
4080 void Capture::saveSequenceQueue()
4082 QUrl backupCurrent = m_SequenceURL;
4085 m_SequenceURL.
clear();
4088 if (m_Dirty ==
false && !m_SequenceURL.
isEmpty())
4095 "Ekos Sequence Queue (*.esq)");
4099 m_SequenceURL = backupCurrent;
4114 KSNotification::error(
i18n(
"Failed to save sequence queue"),
i18n(
"Save"));
4123 KSNotification::sorry(
message,
i18n(
"Invalid URL"));
4127 void Capture::saveSequenceQueueAs()
4129 m_SequenceURL.
clear();
4133 bool Capture::saveSequenceQueue(
const QString &path)
4138 {
"Light", FRAME_LIGHT }, {
"Dark", FRAME_DARK }, {
"Bias", FRAME_BIAS }, {
"Flat", FRAME_FLAT }
4146 KSNotification::sorry(
message,
i18n(
"Could not open file"));
4155 outstream <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <<
Qt::endl;
4156 outstream <<
"<SequenceQueue version='" << SQ_FORMAT_VERSION <<
"'>" <<
Qt::endl;
4157 if (m_ObserverName.
isEmpty() ==
false)
4158 outstream <<
"<Observer>" << m_ObserverName <<
"</Observer>" <<
Qt::endl;
4159 outstream <<
"<GuideDeviation enabled='" << (m_LimitsUI->limitGuideDeviationS->isChecked() ?
"true" :
"false") <<
"'>"
4160 << cLocale.
toString(m_LimitsUI->limitGuideDeviationN->value()) <<
"</GuideDeviation>" <<
Qt::endl;
4161 outstream <<
"<GuideStartDeviation enabled='" << (m_LimitsUI->startGuiderDriftS->isChecked() ?
"true" :
"false") <<
"'>"
4162 << cLocale.
toString(m_LimitsUI->startGuiderDriftN->value()) <<
"</GuideStartDeviation>" <<
Qt::endl;
4164 if (m_LimitsUI->limitFocusHFRS->isChecked() && !Options::saveHFRToFile())
4166 "Warning: HFR-based autofocus is set but option \"Save Sequence HFR Value to File\" is not enabled. "
4167 "Current HFR value will not be written to sequence file."));
4168 outstream <<
"<Autofocus enabled='" << (m_LimitsUI->limitFocusHFRS->isChecked() ?
"true" :
"false") <<
"'>"
4169 << cLocale.
toString(Options::saveHFRToFile() ? m_LimitsUI->limitFocusHFRN->value() : 0) <<
"</Autofocus>" <<
Qt::endl;
4170 outstream <<
"<RefocusOnTemperatureDelta enabled='" << (m_LimitsUI->limitFocusDeltaTS->isChecked() ?
"true" :
"false") <<
4172 << cLocale.
toString(m_LimitsUI->limitFocusDeltaTN->value()) <<
"</RefocusOnTemperatureDelta>" <<
Qt::endl;
4173 outstream <<
"<RefocusEveryN enabled='" << (m_LimitsUI->limitRefocusS->isChecked() ?
"true" :
"false") <<
"'>"
4174 << cLocale.
toString(m_LimitsUI->limitRefocusN->value()) <<
"</RefocusEveryN>" <<
Qt::endl;
4175 outstream <<
"<RefocusOnMeridianFlip enabled='" << (m_LimitsUI->meridianRefocusS->isChecked() ?
"true" :
"false") <<
"'/>"
4177 for (
auto &job : m_captureModuleState->allJobs())
4179 auto filterEnabled = job->getCoreProperty(SequenceJob::SJ_FilterPrefixEnabled).toBool();
4180 auto expEnabled = job->getCoreProperty(SequenceJob::SJ_ExpPrefixEnabled).toBool();
4181 auto tsEnabled = job->getCoreProperty(SequenceJob::SJ_TimeStampPrefixEnabled).toBool();
4182 auto roi = job->getCoreProperty(SequenceJob::SJ_ROI).toRect();
4186 outstream <<
"<Exposure>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble()) <<
"</Exposure>" <<
4188 outstream <<
"<Format>" << job->getCoreProperty(SequenceJob::SJ_Format).toString() <<
"</Format>" <<
Qt::endl;
4189 outstream <<
"<Encoding>" << job->getCoreProperty(SequenceJob::SJ_Encoding).toString() <<
"</Encoding>" <<
Qt::endl;
4190 outstream <<
"<Binning>" <<
Qt::endl;
4191 outstream <<
"<X>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x()) <<
"</X>" <<
Qt::endl;
4192 outstream <<
"<Y>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x()) <<
"</Y>" <<
Qt::endl;
4193 outstream <<
"</Binning>" <<
Qt::endl;
4194 outstream <<
"<Frame>" <<
Qt::endl;
4198 outstream <<
"<H>" << cLocale.
toString(roi.height()) <<
"</H>" <<
Qt::endl;
4199 outstream <<
"</Frame>" <<
Qt::endl;
4200 if (job->getTargetTemperature() != Ekos::INVALID_VALUE)
4201 outstream <<
"<Temperature force='" << (job->getCoreProperty(SequenceJob::SJ_EnforceTemperature).toBool() ?
"true" :
4203 << cLocale.
toString(job->getTargetTemperature()) <<
"</Temperature>" <<
Qt::endl;
4204 if (job->getTargetFilter() >= 0)
4205 outstream <<
"<Filter>" << job->getCoreProperty(SequenceJob::SJ_Filter).toString() <<
"</Filter>" <<
Qt::endl;
4206 outstream <<
"<Type>" << frameTypes.
key(job->getFrameType()) <<
"</Type>" <<
Qt::endl;
4207 outstream <<
"<Prefix>" <<
Qt::endl;
4208 outstream <<
"<FilterEnabled>" << (filterEnabled ? 1 : 0) <<
"</FilterEnabled>" <<
Qt::endl;
4209 outstream <<
"<ExpEnabled>" << (expEnabled ? 1 : 0) <<
"</ExpEnabled>" <<
Qt::endl;
4210 outstream <<
"<TimeStampEnabled>" << (tsEnabled ? 1 : 0) <<
"</TimeStampEnabled>" <<
Qt::endl;
4211 outstream <<
"</Prefix>" <<
Qt::endl;
4212 outstream <<
"<Count>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_Count).toInt()) <<
"</Count>" <<
Qt::endl;
4214 outstream <<
"<Delay>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_Delay).toInt() / 1000.0) <<
"</Delay>" <<
4224 outstream <<
"<FITSDirectory>" << job->getCoreProperty(SequenceJob::SJ_LocalDirectory).toString() <<
"</FITSDirectory>" <<
4226 outstream <<
"<PlaceholderFormat>" << job->getCoreProperty(SequenceJob::SJ_PlaceholderFormat).toString() <<
4227 "</PlaceholderFormat>" <<
4229 outstream <<
"<PlaceholderSuffix>" << job->getCoreProperty(SequenceJob::SJ_PlaceholderSuffix).toUInt() <<
4230 "</PlaceholderSuffix>" <<
4232 outstream <<
"<UploadMode>" << job->getUploadMode() <<
"</UploadMode>" <<
Qt::endl;
4233 if (job->getCoreProperty(SequenceJob::SJ_RemoteDirectory).toString().isEmpty() ==
false)
4234 outstream <<
"<RemoteDirectory>" << job->getCoreProperty(SequenceJob::SJ_RemoteDirectory).toString() <<
"</RemoteDirectory>"
4236 if (job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt() != -1)
4237 outstream <<
"<ISOIndex>" << (job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt()) <<
"</ISOIndex>" <<
Qt::endl;
4238 if (job->getTargetRotation() != Ekos::INVALID_VALUE)
4239 outstream <<
"<Rotation>" << (job->getTargetRotation()) <<
"</Rotation>" <<
Qt::endl;
4241 outstream <<
"<Properties>" <<
Qt::endl;
4245 outstream <<
"<PropertyVector name='" << customIter.
key() <<
"'>" <<
Qt::endl;
4253 outstream <<
"<OneElement name='" << iter.
key()
4254 <<
"'>" << iter.
value().toString() <<
"</OneElement>" <<
Qt::endl;
4258 outstream <<
"<OneElement name='" << iter.
key()
4259 <<
"'>" << iter.
value().toDouble() <<
"</OneElement>" <<
Qt::endl;
4262 outstream <<
"</PropertyVector>" <<
Qt::endl;
4264 outstream <<
"</Properties>" <<
Qt::endl;
4266 outstream <<
"<Calibration>" <<
Qt::endl;
4267 outstream <<
"<FlatSource>" <<
Qt::endl;
4268 if (job->getFlatFieldSource() == SOURCE_MANUAL)
4269 outstream <<
"<Type>Manual</Type>" <<
Qt::endl;
4270 else if (job->getFlatFieldSource() == SOURCE_FLATCAP)
4271 outstream <<
"<Type>FlatCap</Type>" <<
Qt::endl;
4272 else if (job->getFlatFieldSource() == SOURCE_DARKCAP)
4273 outstream <<
"<Type>DarkCap</Type>" <<
Qt::endl;
4274 else if (job->getFlatFieldSource() == SOURCE_WALL)
4276 outstream <<
"<Type>Wall</Type>" <<
Qt::endl;
4277 outstream <<
"<Az>" << cLocale.
toString(job->getWallCoord().az().Degrees()) <<
"</Az>" <<
Qt::endl;
4278 outstream <<
"<Alt>" << cLocale.
toString(job->getWallCoord().alt().Degrees()) <<
"</Alt>" <<
Qt::endl;
4281 outstream <<
"<Type>DawnDust</Type>" <<
Qt::endl;
4282 outstream <<
"</FlatSource>" <<
Qt::endl;
4284 outstream <<
"<FlatDuration dark='" << (job->getCoreProperty(SequenceJob::SJ_DarkFlat).toBool() ?
"true" :
"false")
4286 if (job->getFlatFieldDuration() == DURATION_MANUAL)
4287 outstream <<
"<Type>Manual</Type>" <<
Qt::endl;
4290 outstream <<
"<Type>ADU</Type>" <<
Qt::endl;
4291 outstream <<
"<Value>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble()) <<
"</Value>" <<
4293 outstream <<
"<Tolerance>" << cLocale.
toString(job->getCoreProperty(SequenceJob::SJ_TargetADUTolerance).toDouble()) <<
4296 outstream <<
"</FlatDuration>" <<
Qt::endl;
4298 outstream <<
"<PreMountPark>" << (job->getPreMountPark() ?
"True" :
"False") <<
4300 outstream <<
"<PreDomePark>" << (job->getPreDomePark() ?
"True" :
"False") <<
4302 outstream <<
"</Calibration>" <<
Qt::endl;
4307 outstream <<
"</SequenceQueue>" <<
Qt::endl;
4309 appendLogText(
i18n(
"Sequence queue saved to %1", path));
4313 queueSaveB->setToolTip(
"Save to " + file.
fileName());
4318 void Capture::resetJobs()
4324 if (m_JobUnderEdit ==
true)
4326 SequenceJob * job = m_captureModuleState->allJobs().at(queueTable->currentRow());
4333 nullptr,
i18n(
"Are you sure you want to reset status of all jobs?"),
i18n(
"Reset job status"),
4339 foreach (
SequenceJob * job, m_captureModuleState->allJobs())
4344 capturedFramesMap.
clear();
4347 ignoreJobProgress = Options::alwaysResetSequenceWhenStarting();
4353 ignoreJobProgress =
true;
4356 void Capture::syncGUIToJob(SequenceJob * job)
4360 qWarning(KSTARS_EKOS_CAPTURE) <<
"syncGuiToJob with null job.";
4365 const auto roi = job->getCoreProperty(SequenceJob::SJ_ROI).toRect();
4367 captureFormatS->setCurrentText(job->getCoreProperty(SequenceJob::SJ_Format).toString());
4368 captureEncodingS->setCurrentText(job->getCoreProperty(SequenceJob::SJ_Encoding).toString());
4369 captureExposureN->setValue(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
4370 captureBinHN->setValue(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x());
4371 captureBinVN->setValue(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().y());
4372 captureFrameXN->setValue(roi.x());
4373 captureFrameYN->setValue(roi.y());
4374 captureFrameWN->setValue(roi.width());
4375 captureFrameHN->setValue(roi.height());
4376 FilterPosCombo->setCurrentIndex(job->getTargetFilter() - 1);
4377 captureTypeS->setCurrentIndex(job->getFrameType());
4378 captureCountN->setValue(job->getCoreProperty(SequenceJob::SJ_Count).toInt());
4379 captureDelayN->setValue(job->getCoreProperty(SequenceJob::SJ_Delay).toInt() / 1000);
4380 fileDirectoryT->setText(job->getCoreProperty(SequenceJob::SJ_LocalDirectory).toString());
4381 fileUploadModeS->setCurrentIndex(job->getUploadMode());
4382 fileRemoteDirT->setEnabled(fileUploadModeS->currentIndex() != 0);
4383 fileRemoteDirT->setText(job->getCoreProperty(SequenceJob::SJ_RemoteDirectory).toString());
4384 placeholderFormatT->setText(job->getCoreProperty(SequenceJob::SJ_PlaceholderFormat).toString());
4385 formatSuffixN->setValue(job->getCoreProperty(SequenceJob::SJ_PlaceholderSuffix).toUInt());
4388 cameraTemperatureS->setChecked(job->getCoreProperty(SequenceJob::SJ_EnforceTemperature).toBool());
4389 if (job->getCoreProperty(SequenceJob::SJ_EnforceTemperature).toBool())
4390 cameraTemperatureN->setValue(job->getTargetTemperature());
4393 m_LimitsUI->startGuiderDriftS->setChecked(job->getCoreProperty(SequenceJob::SJ_EnforceStartGuiderDrift).toBool());
4394 if (job->getCoreProperty(SequenceJob::SJ_EnforceStartGuiderDrift).toBool())
4395 m_LimitsUI->startGuiderDriftN->setValue(job->getTargetStartGuiderDrift());
4398 calibrationB->setEnabled(job->getFrameType() != FRAME_LIGHT);
4399 generateDarkFlatsB->setEnabled(job->getFrameType() != FRAME_LIGHT);
4400 flatFieldDuration = job->getFlatFieldDuration();
4401 flatFieldSource = job->getFlatFieldSource();
4402 targetADU = job->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble();
4403 targetADUTolerance = job->getCoreProperty(SequenceJob::SJ_TargetADUTolerance).toDouble();
4404 wallCoord = job->getWallCoord();
4405 preMountPark = job->getPreMountPark();
4406 preDomePark = job->getPreDomePark();
4409 m_Scripts = job->getScripts();
4412 customPropertiesDialog->setCustomProperties(job->getCustomProperties());
4415 captureISOS->setCurrentIndex(job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt());
4417 double gain = getGain();
4419 captureGainN->setValue(gain);
4421 captureGainN->setValue(GainSpinSpecialValue);
4423 double offset = getOffset();
4425 captureOffsetN->setValue(offset);
4427 captureOffsetN->setValue(OffsetSpinSpecialValue);
4429 if (job->getTargetRotation() != Ekos::INVALID_VALUE)
4431 m_RotatorControlPanel->setRotationEnforced(
true);
4432 m_RotatorControlPanel->setTargetPositionAngle(job->getTargetRotation());
4435 m_RotatorControlPanel->setRotationEnforced(
false);
4438 if (Options::alignCheckFrequency() == 0)
4440 targetDriftLabel->setVisible(
false);
4441 targetDrift->setVisible(
false);
4442 targetDriftUnit->setVisible(
false);
4455 if (GainSpinSpecialValue > INVALID_VALUE && captureGainN->value() > GainSpinSpecialValue)
4456 gain = captureGainN->
value();
4457 else if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasGain())
4458 m_captureDeviceAdaptor->getActiveCamera()->getGain(&gain);
4461 if (OffsetSpinSpecialValue > INVALID_VALUE && captureOffsetN->value() > OffsetSpinSpecialValue)
4462 offset = captureOffsetN->value();
4463 else if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasOffset())
4464 m_captureDeviceAdaptor->getActiveCamera()->getOffset(&offset);
4468 iso = captureISOS->currentIndex();
4469 else if (m_captureDeviceAdaptor->getActiveCamera())
4470 iso = m_captureDeviceAdaptor->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD)->getISOIndex();
4472 settings.
insert(
"optical_train", opticalTrainCombo->currentText());
4473 settings.
insert(
"filter", FilterPosCombo->currentText());
4474 settings.
insert(
"dark", darkB->isChecked());
4475 settings.
insert(
"exp", captureExposureN->value());
4476 settings.
insert(
"bin", captureBinHN->value());
4477 settings.
insert(
"iso", iso);
4478 settings.
insert(
"frameType", captureTypeS->currentIndex());
4479 settings.
insert(
"captureFormat", captureFormatS->currentIndex());
4480 settings.
insert(
"transferFormat", captureEncodingS->currentIndex());
4481 settings.
insert(
"gain", gain);
4482 settings.
insert(
"offset", offset);
4483 settings.
insert(
"temperature", cameraTemperatureN->value());
4496 if (i.
row() < 0 || (i.
row() + 1) > m_captureModuleState->allJobs().size())
4501 if (job ==
nullptr || job->getCoreProperty(SequenceJob::SJ_DarkFlat).toBool())
4509 if (m_captureModuleState->allJobs().size() >= 2)
4511 queueUpB->setEnabled(i.
row() > 0);
4512 queueDownB->setEnabled(i.
row() + 1 < m_captureModuleState->allJobs().size());
4521 if (selectJob(i) ==
false)
4524 appendLogText(
i18n(
"Editing job #%1...", i.
row() + 1));
4527 addToQueueB->setToolTip(
i18n(
"Apply job changes."));
4528 removeFromQueueB->setToolTip(
i18n(
"Cancel job changes."));
4531 previewB->setDefault(
false);
4532 addToQueueB->setDefault(
true);
4534 m_JobUnderEdit =
true;
4537 void Capture::resetJobEdit()
4540 appendLogText(
i18n(
"Editing job canceled."));
4542 m_JobUnderEdit =
false;
4545 addToQueueB->setToolTip(
i18n(
"Add job to sequence queue"));
4546 removeFromQueueB->setToolTip(
i18n(
"Remove job from sequence queue"));
4548 addToQueueB->setDefault(
false);
4549 previewB->setDefault(
true);
4554 int totalImageCount = 0;
4555 int totalImageCompleted = 0;
4557 foreach (SequenceJob * job, m_captureModuleState->allJobs())
4559 totalImageCount += job->getCoreProperty(SequenceJob::SJ_Count).toInt();
4560 totalImageCompleted += job->getCompleted();
4563 if (totalImageCount != 0)
4564 return ((
static_cast<double>(totalImageCompleted) / totalImageCount) * 100.0);
4571 if (activeJob ==
nullptr)
4574 for (
int i = 0; i < m_captureModuleState->allJobs().count(); i++)
4576 if (activeJob == m_captureModuleState->allJobs().at(i))
4585 int completedJobs = 0;
4587 foreach (SequenceJob * job, m_captureModuleState->allJobs())
4589 if (job->getStatus() == JOB_DONE)
4593 return (m_captureModuleState->allJobs().count() - completedJobs);
4598 if (id < m_captureModuleState->allJobs().count())
4600 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4601 return job->getStatusString();
4609 if (id < m_captureModuleState->allJobs().count())
4611 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4612 return job->getCoreProperty(SequenceJob::SJ_Filter).toString();
4620 if (id < m_captureModuleState->allJobs().count())
4622 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4623 return job->getCompleted();
4631 if (id < m_captureModuleState->allJobs().count())
4633 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4634 return job->getCoreProperty(SequenceJob::SJ_Count).toInt();
4642 if (id < m_captureModuleState->allJobs().count())
4644 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4645 return job->getExposeLeft();
4653 if (id < m_captureModuleState->allJobs().count())
4655 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4656 return job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble();
4664 if (id < m_captureModuleState->allJobs().count())
4666 SequenceJob * job = m_captureModuleState->allJobs().at(
id);
4667 return job->getFrameType();
4676 double estimatedDownloadTime = getEstimatedDownloadTime();
4678 foreach (SequenceJob * job, m_captureModuleState->allJobs())
4679 remaining += job->getJobRemainingTime(estimatedDownloadTime);
4686 if (activeJob ==
nullptr)
4689 return activeJob->getJobRemainingTime(getEstimatedDownloadTime());
4694 m_LimitsUI->limitGuideDeviationS->setChecked(enable);
4696 m_LimitsUI->limitGuideDeviationN->setValue(value);
4701 m_LimitsUI->limitFocusHFRS->setChecked(enable);
4703 m_LimitsUI->limitFocusHFRN->setValue(HFR);
4710 setActiveJob(
nullptr);
4711 while (queueTable->rowCount() > 0)
4712 queueTable->removeRow(0);
4713 qDeleteAll(m_captureModuleState->allJobs());
4714 m_captureModuleState->allJobs().
clear();
4716 while (m_SequenceArray.
count())
4718 emit sequenceChanged(m_SequenceArray);
4723 if (m_captureModuleState->allJobs().count() == 0)
4729 int idle = 0, error = 0, complete = 0, aborted = 0, running = 0;
4731 foreach (SequenceJob * job, m_captureModuleState->allJobs())
4733 switch (job->getStatus())
4767 if (idle == m_captureModuleState->allJobs().count())
4770 if (complete == m_captureModuleState->allJobs().count())
4776 bool Capture::checkPausing()
4780 appendLogText(
i18n(
"Sequence paused."));
4783 connectCamera(
false);
4786 updateMeridianFlipStage(MeridianFlipState::MF_READY);
4797 void Capture::checkGuideDeviationTimeout()
4799 if (activeJob && activeJob->getStatus() == JOB_ABORTED && m_captureModuleState->isGuidingDeviationDetected())
4801 appendLogText(
i18n(
"Guide module timed out."));
4802 m_captureModuleState->setGuidingDeviationDetected(
false);
4812 void Capture::setAlignStatus(
AlignState state)
4814 if (state != m_captureModuleState->getAlignState())
4815 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Align State changed from" << Ekos::getAlignStatusString(
4816 m_captureModuleState->getAlignState()) <<
"to" << Ekos::getAlignStatusString(state);
4817 m_captureModuleState->setAlignState(state);
4826 appendLogText(
i18n(
"Post flip re-alignment completed successfully."));
4827 m_captureModuleState->resetAlignmentRetries();
4829 if (m_captureModuleState->checkGuidingAfterFlip() ==
false)
4832 updateMeridianFlipStage(MeridianFlipState::MF_NONE);
4843 if (m_captureModuleState->increaseAlignmentRetries() >= 3)
4845 appendLogText(
i18n(
"Post-flip alignment failed."));
4850 appendLogText(
i18n(
"Post-flip alignment failed. Retrying..."));
4854 updateMeridianFlipStage(MeridianFlipState::MF_ALIGNING);
4864 void Capture::setGuideStatus(GuideState state)
4866 if (state != m_captureModuleState->getGuideState())
4867 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Guiding state changed from" << Ekos::getGuideStatusString(
4868 m_captureModuleState->getGuideState())
4869 <<
"to" << Ekos::getGuideStatusString(state);
4876 case GUIDE_CALIBRATION_SUCCESS:
4877 autoGuideReady =
true;
4881 case GUIDE_CALIBRATION_ERROR:
4882 processGuidingFailed();
4883 m_captureModuleState->setGuideState(state);
4886 case GUIDE_DITHERING_SUCCESS:
4887 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Dithering succeeded, capture state" << getCaptureStatusString(
4888 m_captureModuleState->getCaptureState());
4890 appendLogText(
i18n(
"Dithering succeeded."));
4894 if (Options::guidingSettle() > 0)
4897 appendLogText(
i18n(
"Dither complete. Resuming in %1 seconds...", Options::guidingSettle()));
4900 m_captureModuleState->setDitheringState(IPS_OK);
4905 appendLogText(
i18n(
"Dither complete."));
4906 m_captureModuleState->setDitheringState(IPS_OK);
4910 case GUIDE_DITHERING_ERROR:
4911 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Dithering failed, capture state" << getCaptureStatusString(
4912 m_captureModuleState->getCaptureState());
4916 if (Options::guidingSettle() > 0)
4919 appendLogText(
i18n(
"Warning: Dithering failed. Resuming in %1 seconds...", Options::guidingSettle()));
4923 m_captureModuleState->setDitheringState(IPS_OK);
4928 appendLogText(
i18n(
"Warning: Dithering failed."));
4930 m_captureModuleState->setDitheringState(IPS_OK);
4939 m_captureModuleState->setGuideState(state);
4941 if (activeJob !=
nullptr)
4942 activeJob->setCoreProperty(SequenceJob::SJ_GuiderActive, isActivelyGuiding());
4946 void Capture::processGuidingFailed()
4948 if (m_captureModuleState->getFocusState() > FOCUS_PROGRESS)
4950 appendLogText(
i18n(
"Autoguiding stopped. Waiting for autofocus to finish..."));
4953 else if (m_captureModuleState->isGuidingOn()
4956 ((activeJob && activeJob->getStatus() == JOB_BUSY && activeJob->getFrameType() == FRAME_LIGHT) ||
4958 || this->m_captureModuleState->getCaptureState() ==
CAPTURE_PAUSED))
4960 appendLogText(
i18n(
"Autoguiding stopped. Aborting..."));
4965 if (m_captureModuleState->increaseAlignmentRetries() >= 3)
4967 appendLogText(
i18n(
"Post meridian flip calibration error. Aborting..."));
4971 autoGuideReady =
false;
4974 void Capture::checkFrameType(
int index)
4976 calibrationB->setEnabled(index != FRAME_LIGHT);
4977 generateDarkFlatsB->setEnabled(index != FRAME_LIGHT);
4980 double Capture::setCurrentADU(
double value)
4982 if (activeJob ==
nullptr)
4984 qWarning(KSTARS_EKOS_CAPTURE) <<
"setCurrentADU with null activeJob.";
4989 double nextExposure = 0;
4990 double targetADU = activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble();
4991 std::vector<double> coeff;
4994 ExpRaw.
append(activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
4997 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Capture: Current ADU = " << value <<
" targetADU = " << targetADU
4998 <<
" Exposure Count: " << ExpRaw.
count();
5002 if (ExpRaw.
count() >= 2)
5004 if (ExpRaw.
count() >= 5)
5008 coeff = gsl_polynomial_fit(ADURaw.
data(), ExpRaw.
data(), ExpRaw.
count(), 2, chisq);
5009 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Running polynomial fitting. Found " << coeff.size() <<
" coefficients.";
5010 if (std::isnan(coeff[0]) || std::isinf(coeff[0]))
5012 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coefficients are invalid.";
5013 targetADUAlgorithm = ADU_LEAST_SQUARES;
5017 nextExposure = coeff[0] + (coeff[1] * targetADU) + (coeff[2] * pow(targetADU, 2));
5019 if (nextExposure < 0 || (nextExposure > ExpRaw.
last() || targetADU < ADURaw.
last())
5020 || (nextExposure < ExpRaw.
last() || targetADU > ADURaw.
last()))
5023 targetADUAlgorithm = ADU_LEAST_SQUARES;
5027 targetADUAlgorithm = ADU_POLYNOMIAL;
5028 for (
size_t i = 0; i < coeff.size(); i++)
5029 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coeff #" << i <<
"=" << coeff[i];
5034 bool looping =
false;
5035 if (ExpRaw.
count() >= 10)
5038 looping = (std::fabs(ExpRaw[
size - 1] - ExpRaw[
size - 2] < 0.01)) &&
5039 (std::fabs(ExpRaw[
size - 2] - ExpRaw[
size - 3] < 0.01));
5040 if (looping && targetADUAlgorithm == ADU_POLYNOMIAL)
5042 qWarning(KSTARS_EKOS_CAPTURE) <<
"Detected looping in polynomial results. Falling back to llsqr.";
5043 targetADUAlgorithm = ADU_LEAST_SQUARES;
5050 if (targetADUAlgorithm == ADU_LEAST_SQUARES)
5052 double a = 0, b = 0;
5053 llsq(ExpRaw, ADURaw, a, b);
5058 nextExposure = (targetADU - b) / a;
5060 if (nextExposure < 0)
5068 if (nextExposure == 0.0 || nextExposure > 180)
5070 if (value < targetADU)
5071 nextExposure = activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() * 1.25;
5073 nextExposure = activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() * .75;
5076 qCDebug(KSTARS_EKOS_CAPTURE) <<
"next flat exposure is" << nextExposure;
5078 return nextExposure;
5104 for (i = 0; i < n; i++)
5109 xbar = xbar /
static_cast<double>(n);
5110 ybar = ybar /
static_cast<double>(n);
5116 for (i = 0; i < n; i++)
5118 top = top + (
x[i] - xbar) * (
y[i] - ybar);
5119 bot = bot + (
x[i] - xbar) * (
x[i] - xbar);
5124 b = ybar - a * xbar;
5127 void Capture::setDirty()
5135 if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasCoolerControl())
5143 if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasCoolerControl())
5144 return m_captureDeviceAdaptor->getActiveCamera()->setCoolerControl(enable);
5152 if (m_captureModuleState->getFileHFR() > 0)
5155 m_LimitsUI->limitFocusHFRN->setValue(0);
5159 void Capture::openCalibrationDialog()
5161 QDialog calibrationDialog(
this);
5163 Ui_calibrationOptions calibrationOptions;
5164 calibrationOptions.setupUi(&calibrationDialog);
5166 if (m_captureDeviceAdaptor->getMount())
5168 calibrationOptions.parkMountC->setEnabled(m_captureDeviceAdaptor->getMount()->canPark());
5169 calibrationOptions.parkMountC->setChecked(preMountPark);
5172 calibrationOptions.parkMountC->setEnabled(
false);
5174 if (m_captureDeviceAdaptor->getDome())
5176 calibrationOptions.parkDomeC->setEnabled(m_captureDeviceAdaptor->getDome()->canPark());
5177 calibrationOptions.parkDomeC->setChecked(preDomePark);
5180 calibrationOptions.parkDomeC->setEnabled(
false);
5182 switch (flatFieldSource)
5185 calibrationOptions.manualSourceC->setChecked(
true);
5188 case SOURCE_FLATCAP:
5189 calibrationOptions.flatDeviceSourceC->setChecked(
true);
5192 case SOURCE_DARKCAP:
5193 calibrationOptions.darkDeviceSourceC->setChecked(
true);
5197 calibrationOptions.wallSourceC->setChecked(
true);
5198 calibrationOptions.azBox->setText(wallCoord.
az().
toDMSString());
5199 calibrationOptions.altBox->setText(wallCoord.
alt().
toDMSString());
5202 case SOURCE_DAWN_DUSK:
5203 calibrationOptions.dawnDuskFlatsC->setChecked(
true);
5207 switch (flatFieldDuration)
5209 case DURATION_MANUAL:
5210 calibrationOptions.manualDurationC->setChecked(
true);
5214 calibrationOptions.ADUC->setChecked(
true);
5215 calibrationOptions.ADUValue->setValue(
static_cast<int>(std::round(targetADU)));
5216 calibrationOptions.ADUTolerance->setValue(
static_cast<int>(std::round(targetADUTolerance)));
5222 if (calibrationOptions.manualSourceC->isChecked())
5223 flatFieldSource = SOURCE_MANUAL;
5224 else if (calibrationOptions.flatDeviceSourceC->isChecked())
5225 flatFieldSource = SOURCE_FLATCAP;
5226 else if (calibrationOptions.darkDeviceSourceC->isChecked())
5227 flatFieldSource = SOURCE_DARKCAP;
5228 else if (calibrationOptions.wallSourceC->isChecked())
5230 dms wallAz, wallAlt;
5231 bool azOk =
false, altOk =
false;
5233 wallAz = calibrationOptions.azBox->createDms(&azOk);
5234 wallAlt = calibrationOptions.altBox->createDms(&altOk);
5238 flatFieldSource = SOURCE_WALL;
5239 wallCoord.
setAz(wallAz);
5240 wallCoord.
setAlt(wallAlt);
5244 calibrationOptions.manualSourceC->setChecked(
true);
5245 KSNotification::error(
i18n(
"Wall coordinates are invalid."));
5249 flatFieldSource = SOURCE_DAWN_DUSK;
5251 if (calibrationOptions.manualDurationC->isChecked())
5252 flatFieldDuration = DURATION_MANUAL;
5255 flatFieldDuration = DURATION_ADU;
5256 targetADU = calibrationOptions.ADUValue->value();
5257 targetADUTolerance = calibrationOptions.ADUTolerance->value();
5260 preMountPark = calibrationOptions.parkMountC->isChecked();
5261 preDomePark = calibrationOptions.parkDomeC->isChecked();
5265 Options::setCalibrationFlatSourceIndex(flatFieldSource);
5266 Options::setCalibrationFlatDurationIndex(flatFieldDuration);
5267 Options::setCalibrationWallAz(wallCoord.
az().
Degrees());
5268 Options::setCalibrationWallAlt(wallCoord.
alt().
Degrees());
5269 Options::setCalibrationADUValue(
static_cast<uint
>(std::round(targetADU)));
5270 Options::setCalibrationADUValueTolerance(
static_cast<uint
>(std::round(targetADUTolerance)));
5275 IPState Capture::checkLightFramePendingTasks()
5282 if (checkPausing() ==
true)
5285 m_captureModuleState->setContinueAction(CaptureModuleState::CONTINUE_ACTION_NEXT_EXPOSURE);
5290 if (
getMeridianFlipState()->checkMeridianFlipRunning() || m_captureModuleState->checkMeridianFlipReady())
5294 if (m_captureModuleState->getCaptureState() ==
CAPTURE_ALIGNING || m_captureModuleState->checkAlignmentAfterFlip())
5300 && m_captureModuleState->getGuideState() != GUIDE_GUIDING && m_captureModuleState->checkGuidingAfterFlip())
5309 if (Options::enforceGuideDeviation() || Options::enforceStartGuiderDrift())
5312 updateMeridianFlipStage(MeridianFlipState::MF_NONE);
5318 m_captureModuleState->getGuideState() == GUIDE_GUIDING &&
5319 Options::enforceStartGuiderDrift())
5323 if ((m_captureModuleState->getCaptureState() ==
CAPTURE_DITHERING && m_captureModuleState->getDitheringState() != IPS_OK)
5324 || m_captureModuleState->checkDithering())
5330 if ((m_captureModuleState->getCaptureState() ==
CAPTURE_FOCUSING && m_captureModuleState->checkFocusRunning())
5331 || m_captureModuleState->startFocusIfRequired())
5335 if (m_captureModuleState->getGuideState() == GUIDE_SUSPENDED)
5337 appendLogText(
i18n(
"Autoguiding resumed."));
5338 emit resumeGuiding();
5350 IPState Capture::processPreCaptureCalibrationStage()
5353 if (activeJob ==
nullptr)
5355 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Processing pre capture calibration without active job, state = " <<
5356 getCaptureStatusString(m_captureModuleState->getCaptureState());
5363 if (activeJob->getFrameType() != FRAME_LIGHT && m_captureModuleState->getGuideState() == GUIDE_GUIDING)
5365 appendLogText(
i18n(
"Autoguiding suspended."));
5366 emit suspendGuiding();
5370 switch (activeJob->getFrameType())
5373 return checkLightFramePendingTasks();
5386 bool Capture::processPostCaptureCalibrationStage()
5388 if (activeJob ==
nullptr)
5390 qWarning(KSTARS_EKOS_CAPTURE) <<
"processPostCaptureCalibrationStage with null activeJob.";
5396 if (activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION_COMPLETE)
5397 if (activeJob && activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt() <= activeJob->getCompleted())
5401 if (activeJob->getFrameType() == FRAME_FLAT && activeJob->getFlatFieldDuration() == DURATION_ADU &&
5402 activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > 0)
5404 if (!m_ImageData.
isNull())
5406 double currentADU = m_ImageData->getADU();
5407 bool outOfRange =
false, saturated =
false;
5409 switch (m_ImageData->bpp())
5412 if (activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT8_MAX)
5414 else if (currentADU / UINT8_MAX > 0.95)
5419 if (activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT16_MAX)
5421 else if (currentADU / UINT16_MAX > 0.95)
5426 if (activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT32_MAX)
5428 else if (currentADU / UINT32_MAX > 0.95)
5438 appendLogText(
i18n(
"Flat calibration failed. Captured image is only %1-bit while requested ADU is %2.",
5440 ,
QString::number(activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble(),
'f', 2)));
5446 double nextExposure = activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() * 0.1;
5447 nextExposure = qBound(captureExposureN->minimum(), nextExposure, captureExposureN->maximum());
5449 appendLogText(
i18n(
"Current image is saturated (%1). Next exposure is %2 seconds.",
5452 activeJob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
5453 activeJob->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
5454 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
5456 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
5458 startNextExposure();
5462 double ADUDiff = fabs(currentADU - activeJob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble());
5465 if (ADUDiff <= targetADUTolerance)
5467 if (activeJob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
5470 i18n(
"Current ADU %1 within target ADU tolerance range.",
QString::number(currentADU,
'f', 0)));
5471 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(activeJob->getUploadMode());
5472 auto placeholderPath = PlaceholderPath();
5474 placeholderPath.processJobInfo(activeJob, m_TargetName);
5476 activeJob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
5481 if (m_captureDeviceAdaptor->getActiveCamera()
5482 && m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
5483 updateSequencePrefix(activeJob->getCoreProperty(SequenceJob::SJ_FullPrefix).toString());
5485 startNextExposure();
5492 double nextExposure = -1;
5495 if (std::fabs(m_ImageData->getMax(0) - m_ImageData->getMin(0)) < 10)
5496 nextExposure = activeJob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() * 0.5;
5498 nextExposure = setCurrentADU(currentADU);
5500 if (nextExposure <= 0 || std::isnan(nextExposure))
5503 i18n(
"Unable to calculate optimal exposure settings, please capture the flats manually."));
5509 nextExposure = qBound(captureExposureN->minimum(), nextExposure, captureExposureN->maximum());
5511 appendLogText(
i18n(
"Current ADU is %1 Next exposure is %2 seconds.",
QString::number(currentADU,
'f', 0),
5512 QString(
"%L1").arg(nextExposure, 0,
'f', 6)));
5514 activeJob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
5515 activeJob->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
5517 if (m_captureDeviceAdaptor->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
5519 m_captureDeviceAdaptor->getActiveCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
5522 startNextExposure();
5527 activeJob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
5531 void Capture::setNewRemoteFile(
QString file)
5533 appendLogText(
i18n(
"Remote image saved to %1", file));
5540 switch (m_CaptureScriptType)
5543 appendLogText(
i18n(
"Pre capture script finished with code %1.", exitCode));
5544 if (activeJob && activeJob->getStatus() == JOB_IDLE)
5545 preparePreCaptureActions();
5547 checkNextExposure();
5551 appendLogText(
i18n(
"Post capture script finished with code %1.", exitCode));
5554 if (activeJob ==
nullptr || activeJob->getCoreProperty(SequenceJob::SJ_Count).toInt() <= activeJob->getCompleted())
5556 processJobCompletionStage1();
5559 else if (m_captureModuleState->checkMeridianFlipReady())
5561 appendLogText(
i18n(
"Processing meridian flip..."));
5566 appendLogText(
i18n(
"Resuming sequence..."));
5572 appendLogText(
i18n(
"Pre job script finished with code %1.", exitCode));
5573 prepareActiveJobStage2();
5577 appendLogText(
i18n(
"Post job script finished with code %1.", exitCode));
5578 processJobCompletionStage2();
5586 if (m_captureDeviceAdaptor->getActiveCamera() ==
nullptr)
5589 if (m_captureDeviceAdaptor->getActiveCamera()->isBLOBEnabled() ==
false)
5591 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
5592 m_captureDeviceAdaptor->getActiveCamera()->setBLOBEnabled(
true);
5598 m_captureDeviceAdaptor->getActiveCamera()->setBLOBEnabled(
true);
5599 m_captureDeviceAdaptor->getActiveCamera()->setVideoStreamEnabled(
enabled);
5602 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
5603 i18n(
"Image Transfer"), 15);
5609 m_captureDeviceAdaptor->getActiveCamera()->setVideoStreamEnabled(
enabled);
5614 if (m_captureDeviceAdaptor->getActiveCamera() ==
nullptr)
5617 return m_captureDeviceAdaptor->getActiveCamera()->setStreamLimits(maxBufferSize, maxPreviewFPS);
5620 void Capture::setVideoStreamEnabled(
bool enabled)
5624 liveVideoB->setChecked(
true);
5629 liveVideoB->setChecked(
false);
5634 void Capture::setMountStatus(ISD::Mount::Status newState)
5638 case ISD::Mount::MOUNT_PARKING:
5639 case ISD::Mount::MOUNT_SLEWING:
5640 case ISD::Mount::MOUNT_MOVING:
5641 previewB->setEnabled(
false);
5642 liveVideoB->setEnabled(
false);
5646 if (isBusy ==
false)
5647 startB->setEnabled(
false);
5651 if (isBusy ==
false)
5653 previewB->setEnabled(
true);
5654 if (m_captureDeviceAdaptor->getActiveCamera())
5655 liveVideoB->setEnabled(m_captureDeviceAdaptor->getActiveCamera()->hasVideoStream());
5656 startB->setEnabled(
true);
5663 void Capture::updateMFMountState(MeridianFlipState::MeridianFlipMountState status)
5666 m_captureModuleState->updateMFMountState(status);
5669 void Capture::showObserverDialog()
5674 for (
auto &o : m_observerList)
5675 observers <<
QString(
"%1 %2").
arg(o->name(), o->surname());
5677 QDialog observersDialog(
this);
5678 observersDialog.setWindowTitle(
i18nc(
"@title:window",
"Select Current Observer"));
5682 QComboBox observerCombo(&observersDialog);
5683 observerCombo.addItems(observers);
5684 observerCombo.setCurrentText(m_ObserverName);
5688 manageObserver.setFixedSize(
QSize(32, 32));
5691 manageObserver.setToolTip(
i18n(
"Manage Observers"));
5700 for (
auto &o : m_observerList)
5701 observers <<
QString(
"%1 %2").
arg(o->name(), o->surname());
5703 observerCombo.
clear();
5704 observerCombo.addItems(observers);
5705 observerCombo.setCurrentText(m_ObserverName);
5714 observersDialog.setLayout(
layout);
5716 observersDialog.exec();
5718 m_ObserverName = observerCombo.currentText();
5720 Options::setDefaultObserver(m_ObserverName);
5724 void Capture::setAlignResults(
double orientation,
double ra,
double de,
double pixscale)
5726 Q_UNUSED(orientation)
5731 if (m_captureDeviceAdaptor->getRotator() ==
nullptr)
5734 m_RotatorControlPanel->refresh();
5737 void Capture::setFilterStatus(FilterState filterState)
5739 if (filterState != m_captureModuleState->getFilterManagerState())
5740 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Focus State changed from" << Ekos::getFilterStatusString(
5741 m_captureModuleState->getFilterManagerState()) <<
"to" << Ekos::getFilterStatusString(filterState);
5744 switch (filterState)
5747 appendLogText(
i18n(
"Changing focus offset by %1 steps...",
5748 m_FilterManager->getTargetFilterOffset()));
5752 appendLogText(
i18n(
"Changing filter to %1...",
5753 FilterPosCombo->itemText(m_FilterManager->getTargetFilterPosition() - 1)));
5756 case FILTER_AUTOFOCUS:
5757 appendLogText(
i18n(
"Auto focus on filter change..."));
5762 if (m_captureModuleState->getFilterManagerState() == FILTER_CHANGE)
5764 appendLogText(
i18n(
"Filter set to %1.",
5765 FilterPosCombo->itemText(m_FilterManager->getTargetFilterPosition() - 1)));
5773 m_captureModuleState->setFilterManagerState(filterState);
5776 void Capture::setupFilterManager()
5779 if (m_FilterManager)
5780 m_FilterManager->disconnect(
this);
5783 Manager::Instance()->createFilterManager(m_FilterWheel);
5786 Manager::Instance()->getFilterManager(m_FilterWheel->getDeviceName(), m_FilterManager);
5788 m_captureDeviceAdaptor->setFilterManager(m_FilterManager);
5790 connect(m_FilterManager.
get(), &FilterManager::updated,
this, [
this]()
5792 emit filterManagerUpdated(m_FilterWheel);
5796 connect(m_FilterManager.
get(), &FilterManager::newStatus,
this, &Capture::newFilterStatus);
5800 m_FilterManager->refreshFilterModel();
5801 m_FilterManager->show();
5802 m_FilterManager->raise();
5807 connect(m_FilterManager.
get(), &FilterManager::failed,
this, [
this]()
5811 appendLogText(i18n(
"Filter operation failed."));
5817 connect(m_FilterManager.get(), &FilterManager::newStatus,
this, &Capture::setFilterStatus);
5820 connect(m_FilterManager.get(), &FilterManager::newStatus, captureStatusWidget, &LedStatusWidget::setFilterState);
5822 connect(m_FilterManager.get(), &FilterManager::labelsChanged,
this, [
this]()
5824 FilterPosCombo->clear();
5825 FilterPosCombo->addItems(m_FilterManager->getFilterLabels());
5826 FilterPosCombo->setCurrentIndex(m_FilterManager->getFilterPosition() - 1);
5827 updateCurrentFilterPosition();
5830 connect(m_FilterManager.get(), &FilterManager::positionChanged,
this, [
this]()
5832 FilterPosCombo->setCurrentIndex(m_FilterManager->getFilterPosition() - 1);
5833 updateCurrentFilterPosition();
5837 void Capture::addDSLRInfo(
const QString &model, uint32_t maxW, uint32_t maxH,
double pixelW,
double pixelH)
5840 auto pos = std::find_if(DSLRInfos.begin(), DSLRInfos.end(), [model](
const auto & oneDSLRInfo)
5842 return (oneDSLRInfo[
"Model"] == model);
5845 if (pos != DSLRInfos.end())
5847 KStarsData::Instance()->
userdb()->DeleteDSLRInfo(model);
5848 DSLRInfos.removeOne(*pos);
5852 oneDSLRInfo[
"Model"] = model;
5853 oneDSLRInfo[
"Width"] = maxW;
5854 oneDSLRInfo[
"Height"] = maxH;
5855 oneDSLRInfo[
"PixelW"] = pixelW;
5856 oneDSLRInfo[
"PixelH"] = pixelH;
5858 KStarsData::Instance()->
userdb()->AddDSLRInfo(oneDSLRInfo);
5859 KStarsData::Instance()->
userdb()->GetAllDSLRInfos(DSLRInfos);
5861 updateFrameProperties();
5863 syncDSLRToTargetChip(model);
5867 dslrInfoDialog.reset();
5870 bool Capture::isModelinDSLRInfo(
const QString &model)
5874 return (oneDSLRInfo[
"Model"] == model);
5877 return (pos != DSLRInfos.end());
5880 void Capture::cullToDSLRLimits()
5882 QString model(m_captureDeviceAdaptor->getActiveCamera()->getDeviceName());
5887 return (oneDSLRInfo[
"Model"] == model);
5890 if (pos != DSLRInfos.end())
5892 if (captureFrameWN->maximum() == 0 || captureFrameWN->maximum() > (*pos)[
"Width"].toInt())
5894 captureFrameWN->setValue((*pos)[
"Width"].toInt());
5895 captureFrameWN->setMaximum((*pos)[
"Width"].toInt());
5898 if (captureFrameHN->maximum() == 0 || captureFrameHN->maximum() > (*pos)[
"Height"].toInt())
5900 captureFrameHN->setValue((*pos)[
"Height"].toInt());
5901 captureFrameHN->setMaximum((*pos)[
"Height"].toInt());
5906 void Capture::setCapturedFramesMap(
const QString &signature,
int count)
5908 capturedFramesMap[signature] =
static_cast<ushort
>(count);
5909 qCDebug(KSTARS_EKOS_CAPTURE) <<
5910 QString(
"Client module indicates that storage for '%1' has already %2 captures processed.").
arg(signature).
arg(count);
5912 ignoreJobProgress =
false;
5917 auto opticalTrain = settings[
"optical_train"].toString(opticalTrainCombo->currentText());
5918 auto targetFilter = settings[
"filter"].toString(FilterPosCombo->currentText());
5920 opticalTrainCombo->setCurrentText(opticalTrain);
5921 FilterPosCombo->setCurrentText(targetFilter);
5923 captureExposureN->setValue(settings[
"exp"].toDouble(1));
5925 int bin = settings[
"bin"].toInt(1);
5926 setBinning(bin, bin);
5928 double temperature = settings[
"temperature"].toDouble(INVALID_VALUE);
5929 if (temperature > INVALID_VALUE && m_captureDeviceAdaptor->getActiveCamera()
5930 && m_captureDeviceAdaptor->getActiveCamera()->hasCoolerControl())
5932 setForceTemperature(
true);
5933 setTargetTemperature(temperature);
5936 setForceTemperature(
false);
5938 double gain = settings[
"gain"].toDouble(GainSpinSpecialValue);
5939 if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasGain())
5941 if (gain == GainSpinSpecialValue)
5942 captureGainN->setValue(GainSpinSpecialValue);
5947 double offset = settings[
"offset"].toDouble(OffsetSpinSpecialValue);
5948 if (m_captureDeviceAdaptor->getActiveCamera() && m_captureDeviceAdaptor->getActiveCamera()->hasOffset())
5950 if (offset == OffsetSpinSpecialValue)
5951 captureOffsetN->setValue(OffsetSpinSpecialValue);
5956 int transferFormat = settings[
"transferFormat"].toInt(-1);
5957 if (transferFormat >= 0)
5959 captureEncodingS->setCurrentIndex(transferFormat);
5962 QString captureFormat = settings[
"captureFormat"].toString(captureFormatS->currentText());
5963 if (captureFormat != captureFormatS->currentText())
5964 captureFormatS->setCurrentText(captureFormat);
5966 captureTypeS->setCurrentIndex(qMax(0, settings[
"frameType"].toInt(0)));
5969 int isoIndex = settings[
"iso"].toInt(-1);
5973 bool dark = settings[
"dark"].toBool(darkB->isChecked());
5974 if (dark != darkB->isChecked())
5975 darkB->setChecked(dark);
5980 const auto prefix = settings[
"prefix"].toString(targetNameT->text());
5981 const auto directory = settings[
"directory"].toString(fileDirectoryT->text());
5982 const auto upload = settings[
"upload"].toInt(fileUploadModeS->currentIndex());
5983 const auto remote = settings[
"remote"].toString(fileRemoteDirT->text());
5984 const auto format = settings[
"format"].toString(placeholderFormatT->text());
5985 const auto suffix = settings[
"suffix"].toInt(formatSuffixN->value());
5987 targetNameT->setText(prefix);
5988 fileDirectoryT->setText(directory);
5989 fileUploadModeS->setCurrentIndex(upload);
5990 fileRemoteDirT->setText(remote);
5991 placeholderFormatT->setText(format);
5992 formatSuffixN->setValue(suffix);
5999 {
"prefix", targetNameT->text()},
6000 {
"directory", fileDirectoryT->text()},
6001 {
"format", placeholderFormatT->text()},
6002 {
"suffix", formatSuffixN->
value()},
6003 {
"upload", fileUploadModeS->currentIndex()},
6004 {
"remote", fileRemoteDirT->text()}
6012 const int source = settings[
"source"].toInt(flatFieldSource);
6013 const int duration = settings[
"duration"].toInt(flatFieldDuration);
6014 const double az = settings[
"az"].toDouble(wallCoord.az().Degrees());
6015 const double al = settings[
"al"].toDouble(wallCoord.alt().Degrees());
6016 const int adu = settings[
"adu"].toInt(
static_cast<int>(std::round(targetADU)));
6017 const int tolerance = settings[
"tolerance"].toInt(
static_cast<int>(std::round(targetADUTolerance)));
6018 const bool parkMount = settings[
"parkMount"].toBool(preMountPark);
6019 const bool parkDome = settings[
"parkDome"].toBool(preDomePark);
6021 flatFieldSource =
static_cast<FlatFieldSource
>(source);
6022 flatFieldDuration =
static_cast<FlatFieldDuration
>(duration);
6023 wallCoord.setAz(az);
6024 wallCoord.setAlt(al);
6026 targetADUTolerance = tolerance;
6027 preMountPark = parkMount;
6028 preDomePark = parkDome;
6035 {
"source", flatFieldSource},
6036 {
"duration", flatFieldDuration},
6037 {
"az", wallCoord.az().Degrees()},
6038 {
"al", wallCoord.alt().Degrees()},
6040 {
"tolerance", targetADUTolerance},
6041 {
"parkMount", preMountPark},
6042 {
"parkDome", preDomePark},
6050 const bool deviationCheck = settings[
"deviationCheck"].toBool(Options::enforceGuideDeviation());
6051 const double deviationValue = settings[
"deviationValue"].toDouble(Options::guideDeviation());
6052 const bool focusHFRCheck = settings[
"focusHFRCheck"].toBool(m_LimitsUI->limitFocusHFRS->isChecked());
6053 const double focusHFRValue = settings[
"focusHFRValue"].toDouble(m_LimitsUI->limitFocusHFRN->value());
6054 const bool focusDeltaTCheck = settings[
"focusDeltaTCheck"].toBool(m_LimitsUI->limitFocusDeltaTS->isChecked());
6055 const double focusDeltaTValue = settings[
"focusDeltaTValue"].toDouble(m_LimitsUI->limitFocusDeltaTN->value());
6056 const bool refocusNCheck = settings[
"refocusNCheck"].toBool(m_LimitsUI->limitRefocusS->isChecked());
6057 const int refocusNValue = settings[
"refocusNValue"].toInt(m_LimitsUI->limitRefocusN->value());
6061 m_LimitsUI->limitGuideDeviationS->setChecked(
true);
6062 m_LimitsUI->limitGuideDeviationN->setValue(deviationValue);
6065 m_LimitsUI->limitGuideDeviationS->setChecked(
false);
6069 m_LimitsUI->limitFocusHFRS->setChecked(
true);
6070 m_LimitsUI->limitFocusHFRN->setValue(focusHFRValue);
6073 m_LimitsUI->limitFocusHFRS->setChecked(
false);
6075 if (focusDeltaTCheck)
6077 m_LimitsUI->limitFocusDeltaTS->setChecked(
true);
6078 m_LimitsUI->limitFocusDeltaTN->setValue(focusDeltaTValue);
6081 m_LimitsUI->limitFocusDeltaTS->setChecked(
false);
6085 m_LimitsUI->limitRefocusS->setChecked(
true);
6086 m_LimitsUI->limitRefocusN->setValue(refocusNValue);
6089 m_LimitsUI->limitRefocusS->setChecked(
false);
6091 syncRefocusOptionsFromGUI();