6#include "captureprocess.h"
7#include "capturedeviceadaptor.h"
8#include "refocusstate.h"
9#include "sequencejob.h"
10#include "sequencequeue.h"
11#include "ekos/manager.h"
12#include "ekos/auxiliary/darklibrary.h"
13#include "ekos/auxiliary/darkprocessor.h"
14#include "ekos/auxiliary/opticaltrainmanager.h"
15#include "ekos/auxiliary/profilesettings.h"
16#include "ekos/guide/guide.h"
17#include "indi/indilistener.h"
18#include "indi/indirotator.h"
19#include "indi/blobmanager.h"
20#include "indi/indilightbox.h"
21#include "ksmessagebox.h"
25#include "fitsviewer/fitsdata.h"
26#include "fitsviewer/fitstab.h"
28#include "fitsviewer/fitsviewer.h"
30#include "ksnotification.h"
31#include <ekos_capture_debug.h>
33#ifdef HAVE_STELLARSOLVER
34#include "ekos/auxiliary/stellarsolverprofileeditor.h"
46 connect(devices().data(), &CaptureDeviceAdaptor::newCamera,
this, &CaptureProcess::selectCamera);
51 state()->downloadProgressTimer().setInterval(100);
55 m_DarkProcessor =
new DarkProcessor(
this);
56 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &CaptureProcess::newLog);
57 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, &CaptureProcess::darkFrameCompleted);
62 this, &CaptureProcess::scriptFinished);
66 emit newLog(m_CaptureScript.errorString());
72 emit newLog(m_CaptureScript.readAllStandardError());
77 emit newLog(m_CaptureScript.readAllStandardOutput());
83 if (devices()->mount() && devices()->mount() == device)
85 updateTelescopeInfo();
89 if (devices()->mount())
90 devices()->mount()->disconnect(state().data());
92 devices()->setMount(device);
94 if (!devices()->mount())
97 devices()->mount()->disconnect(
this);
100 updateTelescopeInfo();
107 if ((devices()->rotator() == device) && (device !=
nullptr))
111 if (devices()->mount())
113 if (devices()->rotator())
114 devices()->rotator()->disconnect(
this);
117 state()->isInitialized[CaptureModuleState::ACTION_ROTATOR] =
false;
121 Manager::Instance()->createRotatorController(device);
122 connect(devices().data(), &CaptureDeviceAdaptor::rotatorReverseToggled,
this, &CaptureProcess::rotatorReverseToggled,
125 devices()->setRotator(device);
133 if (devices()->dustCap() && devices()->dustCap() == device)
136 devices()->setDustCap(device);
137 state()->setDustCapState(CaptureModuleState::CAP_UNKNOWN);
146 if (devices()->lightBox() == device)
149 devices()->setLightBox(device);
150 state()->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_UNKNOWN);
157 if (devices()->dome() == device)
160 devices()->setDome(device);
167 if (devices()->getActiveCamera() == device)
170 devices()->setActiveCamera(device);
173 if (state()->getCaptureTimeout().isActive() && state()->getCaptureState() ==
CAPTURE_CAPTURING)
180void CaptureProcess::toggleVideo(
bool enabled)
182 if (devices()->getActiveCamera() ==
nullptr)
185 if (devices()->getActiveCamera()->isBLOBEnabled() ==
false)
187 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
188 devices()->getActiveCamera()->setBLOBEnabled(
true);
193 KSMessageBox::Instance()->disconnect(
this);
194 devices()->getActiveCamera()->setBLOBEnabled(
true);
195 devices()->getActiveCamera()->setVideoStreamEnabled(enabled);
198 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
199 i18n(
"Image Transfer"), 15);
205 devices()->getActiveCamera()->setVideoStreamEnabled(enabled);
209void CaptureProcess::toggleSequence()
218 emit newLog(
i18n(
"Sequence resumed."));
221 switch (state()->getContinueAction())
223 case CaptureModuleState::CONTINUE_ACTION_CAPTURE_COMPLETE:
226 case CaptureModuleState::CONTINUE_ACTION_NEXT_EXPOSURE:
235 startNextPendingJob();
243void CaptureProcess::startNextPendingJob()
245 if (state()->allJobs().count() > 0)
247 SequenceJob *
nextJob = findNextPendingJob();
254 emit newLog(
i18n(
"No pending jobs found. Please add a job to the sequence queue."));
264void CaptureProcess::jobCreated(SequenceJob *
newJob)
268 emit newLog(
i18n(
"No new job created."));
272 switch (
newJob->jobType())
274 case SequenceJob::JOBTYPE_BATCH:
275 startNextPendingJob();
277 case SequenceJob::JOBTYPE_PREVIEW:
278 state()->setActiveJob(
newJob);
287void CaptureProcess::capturePreview(
bool loop)
289 if (state()->getFocusState() >= FOCUS_PROGRESS)
291 emit newLog(
i18n(
"Cannot capture while focus module is busy."));
293 else if (activeJob() ==
nullptr)
295 if (loop && !state()->isLooping())
297 state()->setLooping(
true);
298 emit newLog(
i18n(
"Starting framing..."));
301 emit createJob(SequenceJob::JOBTYPE_PREVIEW);
306 prepareJob(activeJob());
314 state()->resetAlignmentRetries();
318 state()->getCaptureTimeout().stop();
319 state()->getCaptureDelayTimer().stop();
320 if (activeJob() !=
nullptr)
322 if (activeJob()->getStatus() == JOB_BUSY)
329 resetJobStatus(JOB_BUSY);
334 resetJobStatus(JOB_DONE);
338 stopText = state()->isLooping() ?
i18n(
"Framing stopped") :
i18n(
"CCD capture stopped");
339 resetJobStatus(JOB_ABORTED);
344 resetJobStatus(JOB_IDLE);
347 emit captureAborted(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
348 KSNotification::event(
QLatin1String(
"CaptureFailed"),
stopText, KSNotification::Capture, KSNotification::Alert);
350 activeJob()->abort();
351 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
353 int index = state()->allJobs().indexOf(activeJob());
354 state()->changeSequenceValue(index,
"Status",
"Aborted");
355 emit updateJobTable(activeJob());
360 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
364 else if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
370 state()->allJobs().removeOne(activeJob());
372 activeJob()->deleteLater();
374 state()->setActiveJob(
nullptr);
382 state()->setCaptureState(targetState);
384 state()->setLooping(
false);
385 state()->setBusy(
false);
387 state()->getCaptureDelayTimer().stop();
389 state()->setActiveJob(
nullptr);
392 if (devices()->lightBox() && state()->lightBoxLightEnabled())
394 state()->setLightBoxLightEnabled(
false);
395 devices()->lightBox()->setLightEnabled(
false);
402 if (devices()->getActiveCamera() && devices()->getActiveChip()
403 && devices()->getActiveCamera()->isFastExposureEnabled())
404 devices()->getActiveChip()->abortExposure();
407 emit captureStopped();
410void CaptureProcess::pauseCapturing()
417 emit newLog(
i18n(
"Pausing only possible while frame capture is running."));
422 state()->setContinueAction(CaptureModuleState::CONTINUE_ACTION_NONE);
424 emit newLog(
i18n(
"Sequence shall be paused after current exposure is complete."));
427void CaptureProcess::startJob(SequenceJob *job)
429 state()->initCapturePreparation();
433void CaptureProcess::prepareJob(SequenceJob * job)
435 state()->setActiveJob(job);
439 if (job->jobType() == SequenceJob::JOBTYPE_PREVIEW && Options::useFITSViewer() ==
false
440 && Options::useSummaryPreview() ==
false)
445 KSMessageBox::Instance()->disconnect(
this);
446 Options::setUseFITSViewer(
true);
452 KSMessageBox::Instance()->disconnect(
this);
453 activeJob()->abort();
455 KSMessageBox::Instance()->questionYesNo(
i18n(
"No view available for previews. Enable FITS viewer?"),
456 i18n(
"Display preview"), 15);
461 if (state()->isLooping() ==
false)
462 qCDebug(
KSTARS_EKOS_CAPTURE) <<
"Preparing capture job" << job->getSignature() <<
"for execution.";
464 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
468 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
469 state()->setNextSequenceID(1);
475 QString signature = activeJob()->getSignature();
481 state()->checkSeqBoundary();
501 int count = state()->capturedFramesCount(signature);
506 for (
auto &
a_job : state()->allJobs())
507 if (
a_job == activeJob())
509 else if (
a_job->getSignature() == activeJob()->getSignature())
510 count -=
a_job->getCompleted();
513 updatedCaptureCompleted(count);
517 else if (state()->hasCapturedFramesMap())
520 updatedCaptureCompleted(0);
526 else if (state()->ignoreJobProgress()
527 && activeJob()->getJobProgressIgnored() ==
false)
529 activeJob()->setJobProgressIgnored(
true);
530 updatedCaptureCompleted(0);
535 if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
536 activeJob()->getCompleted())
538 updatedCaptureCompleted(activeJob()->getCoreProperty(
539 SequenceJob::SJ_Count).toInt());
540 emit newLog(
i18n(
"Job requires %1-second %2 images, has already %3/%4 captures and does not need to run.",
541 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
542 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
543 activeJob()->getCompleted(),
544 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
545 processJobCompletion2();
553 emit newLog(
i18n(
"Job requires %1-second %2 images, has %3/%4 frames captured and will be processed.",
554 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
555 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
556 activeJob()->getCompleted(),
557 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
562 activeCamera()->setNextSequenceID(state()->nextSequenceID());
566 if (activeCamera()->isBLOBEnabled() ==
false)
571 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
573 activeCamera()->setBLOBEnabled(
true);
579 KSMessageBox::Instance()->disconnect(
this);
580 activeCamera()->setBLOBEnabled(
true);
581 prepareActiveJobStage1();
586 KSMessageBox::Instance()->disconnect(
this);
587 activeCamera()->setBLOBEnabled(
true);
588 state()->setBusy(
false);
591 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
592 i18n(
"Image Transfer"), 15);
598 emit jobPrepared(job);
600 prepareActiveJobStage1();
604void CaptureProcess::prepareActiveJobStage1()
606 if (activeJob() ==
nullptr)
617 prepareActiveJobStage2();
620void CaptureProcess::prepareActiveJobStage2()
623 if (activeJob() ==
nullptr)
628 emit newImage(activeJob(), state()->imageData());
644 prepareJobExecution();
647void CaptureProcess::executeJob()
649 if (activeJob() ==
nullptr)
656 if (!activeCamera() || !devices()->getActiveChip())
664 if (Options::defaultObserver().isEmpty() ==
false)
666 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetName) !=
"")
675 state()->setBusy(
true);
676 state()->setUseGuideHead((devices()->getActiveChip()->getType() == ISD::CameraChip::PRIMARY_CCD) ?
679 emit syncGUIToJob(activeJob());
683 if (activeJob()->jobType() == SequenceJob::JOBTYPE_DARKFLAT)
686 if (state()->setDarkFlatExposure(activeJob())
687 && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
689 auto placeholderPath = PlaceholderPath();
691 placeholderPath.processJobInfo(activeJob());
692 state()->setNextSequenceID(1);
697 updatePreCaptureCalibrationStatus();
701void CaptureProcess::prepareJobExecution()
703 if (activeJob() ==
nullptr)
710 state()->setBusy(
true);
713 activeJob()->setCoreProperty(SequenceJob::SJ_GuiderActive,
714 state()->isActivelyGuiding());
717 activeJob()->prepareCapture();
720 emit jobExecutionPreparationStarted();
723void CaptureProcess::refreshOpticalTrain(
QString name)
725 auto mount = OpticalTrainManager::Instance()->getMount(name);
728 auto scope = OpticalTrainManager::Instance()->getScope(name);
729 setScope(scope[
"name"].toString());
731 auto camera = OpticalTrainManager::Instance()->getCamera(name);
734 auto filterWheel = OpticalTrainManager::Instance()->getFilterWheel(name);
735 setFilterWheel(filterWheel);
737 auto rotator = OpticalTrainManager::Instance()->getRotator(name);
740 auto dustcap = OpticalTrainManager::Instance()->getDustCap(name);
743 auto lightbox = OpticalTrainManager::Instance()->getLightBox(name);
747IPState CaptureProcess::checkLightFramePendingTasks()
754 if (checkPausing(CaptureModuleState::CONTINUE_ACTION_NEXT_EXPOSURE) ==
true)
758 if (state()->checkMeridianFlipActive())
764 state()->getGuideState() == GUIDE_GUIDING &&
765 Options::enforceStartGuiderDrift())
770 || state()->checkDithering())
776 if ((state()->getCaptureState() ==
CAPTURE_FOCUSING && state()->checkFocusRunning())
777 || state()->startFocusIfRequired())
782 if (state()->getGuideState() == GUIDE_SUSPENDED && activeJob()->getFrameType() == FRAME_LIGHT)
784 emit newLog(
i18n(
"Autoguiding resumed."));
785 emit resumeGuiding();
796void CaptureProcess::captureStarted(CaptureModuleState::CAPTUREResult
rc)
800 case CaptureModuleState::CAPTURE_OK:
803 state()->getCaptureTimeout().start(
static_cast<int>(activeJob()->getCoreProperty(
804 SequenceJob::SJ_Exposure).toDouble()) * 1000 +
805 CAPTURE_TIMEOUT_THRESHOLD);
807 state()->imageCountDown().setHMS(0, 0, 0);
808 double ms_left = std::ceil(activeJob()->getExposeLeft() * 1000.0);
809 state()->imageCountDownAddMSecs(
int(
ms_left));
810 state()->setLastRemainingFrameTimeMS(
ms_left);
811 state()->sequenceCountDown().setHMS(0, 0, 0);
812 state()->sequenceCountDownAddMSecs(activeJob()->getJobRemainingTime(state()->averageDownloadTime()) * 1000);
815 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
817 auto index = state()->allJobs().indexOf(activeJob());
818 if (index >= 0 && index < state()->getSequence().count())
819 state()->changeSequenceValue(index,
"Status",
"In Progress");
821 emit updateJobTable(activeJob());
823 emit captureRunning();
827 case CaptureModuleState::CAPTURE_FRAME_ERROR:
828 emit newLog(
i18n(
"Failed to set sub frame."));
832 case CaptureModuleState::CAPTURE_BIN_ERROR:
833 emit newLog((
i18n(
"Failed to set binning.")));
837 case CaptureModuleState::CAPTURE_FOCUS_ERROR:
838 emit newLog((
i18n(
"Cannot capture while focus module is busy.")));
844void CaptureProcess::checkNextExposure()
846 IPState started = startNextExposure();
853IPState CaptureProcess::captureImageWithDelay()
855 auto theJob = activeJob();
864 state()->setCaptureState(CAPTURE_WAITING);
866 state()->getCaptureDelayTimer().start(
seqDelay);
870IPState CaptureProcess::startNextExposure()
875 auto theJob = activeJob();
881 if (activeJob()->getFrameType() == FRAME_LIGHT)
883 IPState
pending = checkLightFramePendingTasks();
889 return captureImageWithDelay();
894IPState CaptureProcess::resumeSequence()
897 if (checkPausing(CaptureModuleState::CONTINUE_ACTION_CAPTURE_COMPLETE) ==
true)
903 return startNextJob();
908 else if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
909 activeJob()->getCompleted())
911 processJobCompletion1();
919 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
920 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
923 emit resumeGuiding();
927 if (activeCamera()->isFastExposureEnabled())
929 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
931 state()->checkSeqBoundary();
932 activeCamera()->setNextSequenceID(state()->nextSequenceID());
942 if (activeCamera()->isFastExposureEnabled())
944 state()->setRememberFastExposure(
true);
945 activeCamera()->setFastExposureEnabled(
false);
953 if (activeCamera()->isFastExposureEnabled())
956 activeJob()->getFrameType() == FRAME_LIGHT &&
957 checkLightFramePendingTasks() ==
IPS_OK)
965 state()->setRememberFastExposure(
true);
966 activeCamera()->setFastExposureEnabled(
false);
982 if (data && activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
984 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
985 && activeJob()->getCalibrationStage() != SequenceJobState::CAL_CALIBRATION)
987 if (state()->generateFilename(extension, &filename) && activeCamera()->saveCurrentImage(filename))
989 data->setFilename(filename);
998 KSMessageBox::Instance()->disconnect(
this);
1000 KSMessageBox::Instance()->error(
i18n(
"Failed writing image to %1\nPlease check folder, filename & permissions.",
1002 i18n(
"Image Write Failed"), 30);
1017 state()->setImageData(data);
1018 blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1019 .
arg(data->property(
"blobVector").toString())
1020 .
arg(data->property(
"blobElement").toString())
1021 .
arg(data->property(
"chip").
toInt());
1024 state()->imageData().reset();
1026 const SequenceJob *job = activeJob();
1033 emit processingFITSfinished(
false);
1037 if (state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1041 state()->getMeridianFlipState()->getMeridianFlipStage();
1042 emit processingFITSfinished(
false);
1047 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1053 state()->getCaptureState();
1055 emit processingFITSfinished(
false);
1061 tChip = activeCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>(data->property(
"chip").
toInt()));
1062 if (
tChip != devices()->getActiveChip())
1064 if (state()->getGuideState() == GUIDE_IDLE)
1066 << devices()->getActiveChip()->getType();
1068 emit processingFITSfinished(
false);
1073 if (devices()->getActiveChip()->getCaptureMode() == FITS_FOCUS ||
1074 devices()->getActiveChip()->getCaptureMode() == FITS_GUIDE)
1077 devices()->getActiveChip()->getCaptureMode();
1079 emit processingFITSfinished(
false);
1084 if (data && data->property(
"device").toString() != activeCamera()->getDeviceName())
1087 << activeCamera()->getDeviceName();
1089 emit processingFITSfinished(
false);
1093 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1096 if (checkSavingReceivedImage(data, extension, filename))
1098 FITSMode captureMode =
tChip->getCaptureMode();
1099 FITSScale captureFilter =
tChip->getCaptureFilter();
1100 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
1105 if (data && Options::autoDark() && job->jobType() == SequenceJob::JOBTYPE_PREVIEW && state()->useGuideHead() ==
false)
1107 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
1110 m_DarkProcessor.data()->denoise(trainID.
toUInt(),
1111 devices()->getActiveChip(),
1112 state()->imageData(),
1113 job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(),
1114 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
x(),
1115 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
y());
1121 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1132 SequenceJob *
thejob = activeJob();
1139 if (activeCamera()->isFastExposureEnabled() ==
false && state()->isLooping() ==
false)
1141 disconnect(activeCamera(), &ISD::Camera::newExposureValue,
this,
1143 DarkLibrary::Instance()->disconnect(
this);
1151 switch (
thejob->getFrameType())
1155 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1159 if (
thejob->getFlatFieldDuration() == DURATION_ADU
1160 &&
thejob->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > 0 &&
1161 thejob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
1163 if (
checkFlatCalibration(state()->imageData(), state()->exposureRange().min, state()->exposureRange().max) ==
false)
1165 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1167 if (checkSavingReceivedImage(data, extension, filename))
1170 updatedCaptureCompleted(activeJob()->getCompleted() + 1);
1176 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1188 if (
thejob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION_COMPLETE)
1189 thejob->setCalibrationStage(SequenceJobState::CAL_CAPTURING);
1191 if (activeJob() && activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW &&
1192 activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1195 if (
alreadySaved || checkSavingReceivedImage(data, extension, filename))
1197 FITSMode captureMode =
tChip->getCaptureMode();
1198 FITSScale captureFilter =
tChip->getCaptureFilter();
1199 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
1217 emit processingFITSfinished(
true);
1222 emit newLog(
i18n(
"Remote image saved to %1", file));
1225 if (activeCamera() && activeCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1235 if (activeJob() ==
nullptr)
1237 qCWarning(
KSTARS_EKOS_CAPTURE) <<
"Processing pre capture calibration without active job, state = " <<
1238 getCaptureStatusString(state()->getCaptureState());
1245 if (activeJob()->getFrameType() != FRAME_LIGHT
1246 && state()->getGuideState() == GUIDE_GUIDING)
1248 emit newLog(
i18n(
"Autoguiding suspended."));
1249 emit suspendGuiding();
1253 switch (activeJob()->getFrameType())
1275 if (state()->isBusy() ==
false)
1277 emit newLog(
i18n(
"Warning: Calibration process was prematurely terminated."));
1291 captureImageWithDelay();
1296 if (activeJob() ==
nullptr)
1312 if (activeJob() ==
nullptr)
1318 activeJob()->done();
1320 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1322 int index = state()->allJobs().indexOf(activeJob());
1329 emit updateJobTable(activeJob());
1343 KSNotification::event(
QLatin1String(
"CaptureSuccessful"),
i18n(
"CCD capture sequence completed"),
1344 KSNotification::Capture);
1350 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1351 emit resumeGuiding();
1360 for (
auto &
oneJob : state()->allJobs())
1362 if (
oneJob->getStatus() == JOB_IDLE ||
oneJob->getStatus() == JOB_ABORTED)
1376 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
1377 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
1380 emit resumeGuiding();
1394 if (activeJob() ==
nullptr)
1398 if (!activeCamera() || !activeCamera()->isConnected())
1400 emit newLog(
i18n(
"Error: Lost connection to CCD."));
1405 state()->getCaptureTimeout().stop();
1406 state()->getCaptureDelayTimer().stop();
1407 if (activeCamera()->isFastExposureEnabled())
1409 int remaining = state()->isLooping() ? 100000 : (activeJob()->getCoreProperty(
1410 SequenceJob::SJ_Count).
toInt() -
1411 activeJob()->getCompleted());
1413 activeCamera()->setFastCount(
static_cast<uint
>(
remaining));
1418 if (activeJob()->getFrameType() == FRAME_FLAT)
1421 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
1422 && activeJob()->getFlatFieldDuration() == DURATION_ADU &&
1423 activeJob()->getCalibrationStage() == SequenceJobState::CAL_NONE)
1425 if (activeCamera()->getEncodingFormat() !=
"FITS" &&
1426 activeCamera()->getEncodingFormat() !=
"XISF")
1428 emit newLog(
i18n(
"Cannot calculate ADU levels in non-FITS images."));
1433 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
1438 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1440 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1441 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1446 if (activeCamera()->getUploadMode() != activeJob()->getUploadMode())
1447 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1450 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1452 state()->checkSeqBoundary();
1453 activeCamera()->setNextSequenceID(state()->nextSequenceID());
1457 if (state()->isRememberFastExposure())
1459 state()->setRememberFastExposure(
false);
1460 activeCamera()->setFastExposureEnabled(
true);
1463 if (state()->frameSettings().contains(devices()->getActiveChip()))
1465 const auto roi = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect();
1466 QVariantMap settings;
1467 settings[
"x"] =
roi.x();
1468 settings[
"y"] =
roi.y();
1469 settings[
"w"] =
roi.width();
1470 settings[
"h"] =
roi.height();
1471 settings[
"binx"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
x();
1472 settings[
"biny"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
y();
1474 state()->frameSettings()[devices()->getActiveChip()] = settings;
1478 activeCamera()->setEncodingFormat(activeJob()->getCoreProperty(
1479 SequenceJob::SJ_Encoding).toString());
1481 state()->setStartingCapture(
true);
1482 state()->placeholderPath().setGenerateFilenameSettings(*activeJob());
1485 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1487 auto remoteUpload = state()->placeholderPath().generateSequenceFilename(*activeJob(),
false,
true, 1,
"",
"",
false,
1493 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatDirectory,
remoteDirectory);
1494 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatFilename,
remoteFilename);
1500 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(),
1501 activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION ? FITS_CALIBRATE :
1505 if (state()->isRememberFastExposure())
1507 state()->setRememberFastExposure(
false);
1508 activeCamera()->setFastExposureEnabled(
true);
1511 emit captureTarget(activeJob()->getCoreProperty(SequenceJob::SJ_TargetName).toString());
1512 emit captureImageStarted();
1517 devices()->setActiveChip(state()->useGuideHead() ?
1518 devices()->getActiveCamera()->getChip(
1519 ISD::CameraChip::GUIDE_CCD) :
1520 devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1521 devices()->getActiveChip()->resetFrame();
1522 emit updateFrameProperties(1);
1528 if (state()->checkCapturing() ==
false)
1531 if (devices()->getActiveChip() !=
tChip ||
1532 devices()->getActiveChip()->getCaptureMode() != FITS_NORMAL
1533 || state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1536 double deltaMS = std::ceil(1000.0 * value - state()->lastRemainingFrameTimeMS());
1538 state()->setLastRemainingFrameTimeMS(state()->lastRemainingFrameTimeMS() +
deltaMS);
1542 activeJob()->setExposeLeft(value);
1544 emit newExposureProgress(activeJob());
1549 int retries = activeJob()->getCaptureRetires() + 1;
1551 activeJob()->setCaptureRetires(retries);
1553 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
1557 activeJob()->abort();
1561 emit newLog((
i18n(
"Restarting capture attempt #%1", retries)));
1563 state()->setNextSequenceID(1);
1571 activeJob()->setCaptureRetires(0);
1572 activeJob()->setExposeLeft(0);
1574 if (devices()->getActiveCamera()
1575 && devices()->getActiveCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1577 if (activeJob()->getStatus() == JOB_BUSY)
1579 emit processingFITSfinished(
false);
1584 if (state()->getGuideState() == GUIDE_GUIDING && Options::guiderType() == 0
1585 && state()->suspendGuidingOnDownload())
1587 qCDebug(
KSTARS_EKOS_CAPTURE) <<
"Autoguiding suspended until primary CCD chip completes downloading...";
1588 emit suspendGuiding();
1591 emit downloadingFrame();
1594 state()->downloadTimer().start();
1595 state()->downloadProgressTimer().start();
1603 double downloadTimeLeft = state()->averageDownloadTime() - state()->downloadTimer().elapsed() /
1607 state()->imageCountDown().setHMS(0, 0, 0);
1617 emit newImage(activeJob(), imageData);
1619 if (activeCamera()->isFastExposureEnabled() ==
false)
1621 const int seqDelay = activeJob()->getCoreProperty(SequenceJob::SJ_Delay).
toInt();
1627 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(),
1632 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(),
1643 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL
1644 && state()->downloadTimer().isValid())
1650 state()->downloadTimer().invalidate();
1661 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1664 emit newImage(activeJob(), imageData);
1666 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1668 state()->setActiveJob(
nullptr);
1670 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1671 emit resumeGuiding();
1682 state()->getCaptureTimeout().stop();
1683 state()->setCaptureTimeoutCounter(0);
1685 state()->downloadProgressTimer().stop();
1688 if (state()->isLooping())
1702 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW
1703 || activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
1707 updatedCaptureCompleted(activeJob()->getCompleted() + 1);
1709 state()->getRefocusState()->decreaseInSequenceFocusCounter();
1711 state()->getRefocusState()->setAdaptiveFocusDone(
false);
1715 if (state()->getMeridianFlipState()->getMeridianFlipStage() < MeridianFlipState::MF_FLIPPING)
1716 state()->decreaseDitherCounter();
1719 state()->addCapturedFrame(activeJob()->getSignature());
1722 emit newLog(
i18n(
"Received image %1 out of %2.", activeJob()->getCompleted(),
1723 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
1734 if (Options::autoHFR() && imageData && !imageData->areStarsSearched() && imageData->getRecordValue(
"FRAME", frameType)
1735 && frameType.
toString() ==
"Light")
1737#ifdef HAVE_STELLARSOLVER
1746 result.waitForFinished();
1748 hfr = imageData->getHFR(HFR_AVERAGE);
1749 numStars = imageData->getSkyBackground().starsDetected;
1750 median = imageData->getMedian();
1752 filename = imageData->filename();
1755 if (state()->isLooping() ==
false && activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1756 emit newLog(
i18n(
"Captured %1", filename));
1758 auto remainingPlaceholders = PlaceholderPath::remainingPlaceholders(filename);
1759 if (remainingPlaceholders.size() > 0)
1762 i18n(
"WARNING: remaining and potentially unknown placeholders %1 in %2",
1763 remainingPlaceholders.join(
", "), filename));
1769 QVariantMap metadata;
1770 metadata[
"filename"] = filename;
1771 metadata[
"type"] = activeJob()->getFrameType();
1772 metadata[
"exposure"] = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
1773 metadata[
"filter"] = activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString();
1774 metadata[
"width"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
width();
1775 metadata[
"height"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
height();
1776 metadata[
"hfr"] = hfr;
1778 metadata[
"median"] = median;
1780 emit captureComplete(metadata);
1789 const QString captureScript = activeJob()->getScript(scriptType);
1792 state()->setCaptureScriptType(scriptType);
1795 emit newLog(
i18n(
"Executing capture script %1", captureScript));
1807 switch (state()->captureScriptType())
1810 emit newLog(
i18n(
"Pre capture script finished with code %1.", exitCode));
1811 if (activeJob() && activeJob()->getStatus() == JOB_IDLE)
1818 emit newLog(
i18n(
"Post capture script finished with code %1.", exitCode));
1821 if (activeJob() ==
nullptr
1822 || activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
1823 activeJob()->getCompleted())
1828 else if (state()->checkMeridianFlipReady())
1830 emit newLog(
i18n(
"Processing meridian flip..."));
1840 emit newLog(
i18n(
"Pre job script finished with code %1.", exitCode));
1845 emit newLog(
i18n(
"Post job script finished with code %1.", exitCode));
1858 if (activeCamera() && activeCamera()->getDeviceName() == name)
1861 emit refreshCamera();
1871 if (!activeCamera())
1877 devices()->setActiveChip(
nullptr);
1880 if (activeCamera()->getDeviceName().contains(
"Guider"))
1882 state()->setUseGuideHead(
true);
1883 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::GUIDE_CCD));
1886 if (devices()->getActiveChip() ==
nullptr)
1888 state()->setUseGuideHead(
false);
1889 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1892 emit refreshCameraSettings();
1897 auto pos = std::find_if(state()->DSLRInfos().begin(),
1904 if (pos != state()->DSLRInfos().end())
1907 devices()->getActiveChip()->setImageInfo(camera[
"Width"].toInt(),
1908 camera[
"Height"].toInt(),
1909 camera[
"PixelW"].toDouble(),
1910 camera[
"PixelH"].toDouble(),
1917 if (activeCamera() && activeCamera()->getDeviceName() == camera)
1920 auto rememberState = state()->getCaptureState();
1923 state()->setCaptureState(rememberState);
1926 state()->setCaptureTimeoutCounter(0);
1930 devices()->setActiveChip(devices()->getActiveChip());
1944 auto name = device->getDeviceName();
1945 device->disconnect(
this);
1948 if (devices()->mount() && devices()->mount()->getDeviceName() == device->getDeviceName())
1950 devices()->mount()->disconnect(
this);
1951 devices()->setMount(
nullptr);
1952 if (activeJob() !=
nullptr)
1953 activeJob()->addMount(
nullptr);
1957 if (devices()->dome() && devices()->dome()->getDeviceName() == device->getDeviceName())
1959 devices()->dome()->disconnect(
this);
1960 devices()->setDome(
nullptr);
1964 if (devices()->rotator() && devices()->rotator()->getDeviceName() == device->getDeviceName())
1966 devices()->rotator()->disconnect(
this);
1967 devices()->setRotator(
nullptr);
1971 if (devices()->dustCap() && devices()->dustCap()->getDeviceName() == device->getDeviceName())
1973 devices()->dustCap()->disconnect(
this);
1974 devices()->setDustCap(
nullptr);
1975 state()->hasDustCap =
false;
1976 state()->setDustCapState(CaptureModuleState::CAP_UNKNOWN);
1980 if (devices()->lightBox() && devices()->lightBox()->getDeviceName() == device->getDeviceName())
1982 devices()->lightBox()->disconnect(
this);
1983 devices()->setLightBox(
nullptr);
1984 state()->hasLightBox =
false;
1985 state()->setLightBoxLightState(CaptureModuleState::CAP_LIGHT_UNKNOWN);
1989 if (activeCamera() && activeCamera()->getDeviceName() == name)
1992 devices()->setActiveCamera(
nullptr);
1993 devices()->setActiveChip(
nullptr);
1996 if (INDIListener::findDevice(name,
generic))
1997 DarkLibrary::Instance()->removeDevice(
generic);
2006 if (devices()->filterWheel() && devices()->filterWheel()->getDeviceName() == name)
2008 devices()->filterWheel()->disconnect(
this);
2009 devices()->setFilterWheel(
nullptr);
2013 emit refreshFilterSettings();
2020 state()->setCaptureTimeoutCounter(state()->captureTimeoutCounter() + 1);
2022 if (state()->deviceRestartCounter() >= 3)
2024 state()->setCaptureTimeoutCounter(0);
2025 state()->setDeviceRestartCounter(0);
2026 emit newLog(
i18n(
"Exposure timeout. Aborting..."));
2031 if (state()->captureTimeoutCounter() > 3 && activeCamera())
2033 emit newLog(
i18n(
"Exposure timeout. More than 3 have been detected, will restart driver."));
2034 QString camera = activeCamera()->getDeviceName();
2035 QString fw = (devices()->filterWheel() !=
nullptr) ?
2036 devices()->filterWheel()->getDeviceName() :
"";
2037 emit driverTimedout(camera);
2040 state()->setDeviceRestartCounter(state()->deviceRestartCounter() + 1);
2048 if (activeCamera() && activeJob())
2051 emit newLog(
i18n(
"Exposure timeout. Restarting exposure..."));
2052 activeCamera()->setEncodingFormat(
"FITS");
2053 auto rememberState = state()->getCaptureState();
2056 state()->setCaptureState(rememberState);
2058 auto targetChip = activeCamera()->getChip(state()->useGuideHead() ?
2059 ISD::CameraChip::GUIDE_CCD :
2060 ISD::CameraChip::PRIMARY_CCD);
2061 targetChip->abortExposure();
2062 const double exptime = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
2063 targetChip->capture(exptime);
2064 state()->getCaptureTimeout().start(
static_cast<int>((exptime) * 1000 + CAPTURE_TIMEOUT_THRESHOLD));
2068 else if (state()->captureTimeoutCounter() < 40)
2070 qCDebug(
KSTARS_EKOS_CAPTURE) <<
"Unable to restart exposure as camera is missing, trying again in 5 seconds...";
2075 state()->setCaptureTimeoutCounter(0);
2076 state()->setDeviceRestartCounter(0);
2077 emit newLog(
i18n(
"Exposure timeout. Too many. Aborting..."));
2090 if (type == ISD::Camera::ERROR_CAPTURE)
2092 int retries = activeJob()->getCaptureRetires() + 1;
2094 activeJob()->setCaptureRetires(retries);
2096 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
2104 emit newLog(
i18n(
"Restarting capture attempt #%1", retries));
2106 state()->setNextSequenceID(1);
2120 if (imageData.isNull())
2126 switch (imageData->bpp())
2129 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() >
UINT8_MAX)
2136 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() >
UINT16_MAX)
2143 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() >
UINT32_MAX)
2155 emit newLog(
i18n(
"Flat calibration failed. Captured image is only %1-bit while requested ADU is %2.",
2157 ,
QString::number(activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble(),
'f', 2)));
2166 emit newLog(
i18n(
"Current image is saturated (%1). Next exposure is %2 seconds.",
2169 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2170 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure,
nextExposure);
2171 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2173 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2180 SequenceJob::SJ_TargetADU).toDouble());
2183 if (
ADUDiff <= state()->targetADUTolerance())
2185 if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
2189 activeCamera()->setUploadMode(activeJob()->getUploadMode());
2190 auto placeholderPath = PlaceholderPath();
2192 placeholderPath.processJobInfo(activeJob());
2194 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
2199 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
2200 state()->checkSeqBoundary();
2209 if (std::fabs(imageData->getMax(0) - imageData->getMin(0)) < 10)
2217 i18n(
"Unable to calculate optimal exposure settings, please capture the flats manually."));
2228 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2229 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure,
nextExposure);
2230 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2232 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2243 if (activeJob() ==
nullptr)
2251 double targetADU = activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).
toDouble();
2252 std::vector<double>
coeff;
2256 if(activeJob()->getCoreProperty(SequenceJob::SJ_SkyFlat).toBool() && ExpRaw.size() > 2)
2258 int remove = ExpRaw.size() - 2;
2259 ExpRaw.remove(0, remove);
2260 ADURaw.remove(0, remove);
2264 ExpRaw.append(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
2268 <<
" Exposure Count: " << ExpRaw.count();
2272 if (ExpRaw.count() >= 2)
2274 if (ExpRaw.count() >= 5)
2278 coeff = gsl_polynomial_fit(ADURaw.data(), ExpRaw.data(), ExpRaw.count(), 2,
chisq);
2280 if (std::isnan(
coeff[0]) || std::isinf(
coeff[0]))
2283 targetADUAlgorithm = ADU_LEAST_SQUARES;
2290 || (
nextExposure < ExpRaw.last() || targetADU > ADURaw.last()))
2293 targetADUAlgorithm = ADU_LEAST_SQUARES;
2297 targetADUAlgorithm = ADU_POLYNOMIAL;
2298 for (
size_t i = 0; i <
coeff.size(); i++)
2305 if (ExpRaw.count() >= 10)
2307 int size = ExpRaw.count();
2308 looping = (std::fabs(ExpRaw[size - 1] - ExpRaw[size - 2] < 0.01)) &&
2309 (std::fabs(ExpRaw[size - 2] - ExpRaw[size - 3] < 0.01));
2310 if (
looping && targetADUAlgorithm == ADU_POLYNOMIAL)
2313 targetADUAlgorithm = ADU_LEAST_SQUARES;
2320 if (targetADUAlgorithm == ADU_LEAST_SQUARES)
2322 double a = 0, b = 0;
2323 llsq(ExpRaw, ADURaw, a, b);
2360 if (devices()->mount() && activeCamera() && devices()->mount()->isConnected())
2369 activeTelescope->setText(devices()->mount()->getDeviceName().toLatin1().constData());
2382 if (devices()->dustCap())
2394 if (devices()->filterWheel())
2398 activeFilter->setText(devices()->filterWheel()->getDeviceName().toLatin1().constData());
2416 const FITSScale &captureFilter,
const QString &filename,
const QString &deviceName)
2422 switch (captureMode)
2425 case FITS_CALIBRATE:
2427 if (Options::useFITSViewer())
2430 bool success =
false;
2432 int *
tabID = &m_fitsvViewerTabIDs.normalTabID;
2433 const bool isPreview = (activeJob() && activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW);
2434 if (*
tabID == -1 || Options::singlePreviewFITS() ==
false)
2440 if (
isPreview && Options::singlePreviewFITS())
2444 if (Options::singleWindowCapturedFITS())
2451 success = getFITSViewer()->loadData(data,
fileURL, &tabIndex, captureMode, captureFilter,
previewTitle);
2454 auto tabs = getFITSViewer()->tabs();
2455 if (tabIndex < tabs.size() && captureMode == FITS_NORMAL)
2457 emit newView(tabs[tabIndex]->getView());
2458 tabs[tabIndex]->disconnect(
this);
2459 connect(tabs[tabIndex].get(), &FITSTab::updated,
this, [
this]
2462 emit newView(tab->getView());
2470 success = getFITSViewer()->updateData(data,
fileURL, *
tabID, &tabIndex, captureFilter, captureMode);
2481 if (Options::focusFITSOnNewImage())
2482 getFITSViewer()->raise();
2494 const QString &targetName,
bool setOptions)
2496 state()->clearCapturedFramesMap();
2497 auto queue = state()->getSequenceQueue();
2498 if (!queue->load(
fileURL, targetName, devices(), state()))
2501 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
2507 queue->setOptions();
2509 state()->updateHFRThreshold();
2512 for (
auto j : state()->allJobs())
2521 state()->getSequenceQueue()->loadOptions();
2522 return state()->getSequenceQueue()->save(path, state()->observerName());
2542 disconnect(activeCamera(), &ISD::Camera::ready,
this, &CaptureProcess::cameraReady);
2549 if (devices()->filterWheel() && devices()->filterWheel() == device)
2552 if (devices()->filterWheel())
2553 devices()->filterWheel()->disconnect(
this);
2555 devices()->setFilterWheel(device);
2557 return (device !=
nullptr);
2564 emit newLog(
i18n(
"Sequence paused."));
2582 for (
auto &job : state()->allJobs())
2584 if (job->getStatus() == JOB_IDLE || job->getStatus() == JOB_ABORTED)
2596 for (
auto &job : state()->allJobs())
2598 if (job->getStatus() != JOB_DONE)
2601 if (state()->getCaptureDelayTimer().isActive())
2603 if (state()->getCaptureDelayTimer().interval() <= 0)
2604 state()->getCaptureDelayTimer().setInterval(1000);
2611 if (!state()->ignoreJobProgress())
2614 i18n(
"All jobs are complete. Do you want to reset the status of all jobs and restart capturing?"),
2626 else if (state()->ignoreJobProgress())
2628 emit newLog(
i18n(
"Warning: option \"Always Reset Sequence When Starting\" is enabled and resets the sequence counts."));
2635void CaptureProcess::resetJobStatus(JOBStatus newStatus)
2637 if (activeJob() !=
nullptr)
2639 activeJob()->resetStatus(newStatus);
2640 emit updateJobTable(activeJob());
2644void CaptureProcess::resetAllJobs()
2646 for (
auto &job : state()->allJobs())
2651 m_State->clearCapturedFramesMap();
2653 emit updateJobTable(
nullptr);
2656void CaptureProcess::updatedCaptureCompleted(
int count)
2658 activeJob()->setCompleted(count);
2659 emit updateJobTable(activeJob());
2684 for (i = 0; i < n; i++)
2689 xbar =
xbar /
static_cast<double>(n);
2690 ybar =
ybar /
static_cast<double>(n);
2696 for (i = 0; i < n; i++)
2698 top = top + (x[i] -
xbar) * (y[i] -
ybar);
2699 bot = bot + (x[i] -
xbar) * (x[i] -
xbar);
2716 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2724 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2725 return devices()->getActiveCamera()->setCoolerControl(enable);
2734 KSMessageBox::Instance()->disconnect(
this);
2736 emit driverTimedout(name);
2740 KSMessageBox::Instance()->disconnect(
this);
2743 KSMessageBox::Instance()->questionYesNo(
i18n(
"Are you sure you want to restart %1 camera driver?", name),
2744 i18n(
"Driver Restart"), 5);
2749 if (!activeCamera())
2754 return tChip->getFrameTypes();
2759 if (devices()->getFilterManager().isNull())
2762 return devices()->getFilterManager()->getFilterLabels();
2767 if (devices()->getActiveCamera()->getProperty(
"CCD_GAIN"))
2773 propertyMap[
"CCD_GAIN"] =
ccdGain;
2777 propertyMap[
"CCD_GAIN"].remove(
"GAIN");
2778 if (propertyMap[
"CCD_GAIN"].size() == 0)
2779 propertyMap.remove(
"CCD_GAIN");
2782 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2788 propertyMap[
"CCD_CONTROLS"] =
ccdGain;
2792 propertyMap[
"CCD_CONTROLS"].remove(
"Gain");
2793 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2794 propertyMap.remove(
"CCD_CONTROLS");
2801 if (devices()->getActiveCamera()->getProperty(
"CCD_OFFSET"))
2811 propertyMap[
"CCD_OFFSET"].remove(
"OFFSET");
2812 if (propertyMap[
"CCD_OFFSET"].size() == 0)
2813 propertyMap.remove(
"CCD_OFFSET");
2816 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2822 propertyMap[
"CCD_CONTROLS"] =
ccdOffset;
2826 propertyMap[
"CCD_CONTROLS"].remove(
"Offset");
2827 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2828 propertyMap.remove(
"CCD_CONTROLS");
2836 if (!m_FITSViewerWindow.
isNull() && ! m_FITSViewerWindow.
isNull())
2837 return m_FITSViewerWindow;
2840 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
2845 connect(m_FITSViewerWindow.
get(), &FITSViewer::closed,
this, [
this](
int tabIndex)
2847 if (tabIndex == m_fitsvViewerTabIDs.normalTabID)
2848 m_fitsvViewerTabIDs.normalTabID = -1;
2849 else if (tabIndex == m_fitsvViewerTabIDs.calibrationTabID)
2850 m_fitsvViewerTabIDs.calibrationTabID = -1;
2851 else if (tabIndex == m_fitsvViewerTabIDs.focusTabID)
2852 m_fitsvViewerTabIDs.focusTabID = -1;
2853 else if (tabIndex == m_fitsvViewerTabIDs.guideTabID)
2854 m_fitsvViewerTabIDs.guideTabID = -1;
2855 else if (tabIndex == m_fitsvViewerTabIDs.alignTabID)
2856 m_fitsvViewerTabIDs.alignTabID = -1;
2860 connect(m_FITSViewerWindow.
get(), &FITSViewer::terminated,
this, [
this]()
2862 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
2863 m_FITSViewerWindow.
clear();
2866 return m_FITSViewerWindow;
2871 return devices()->getActiveCamera();
void processCaptureError(ISD::Camera::ErrorType type)
processCaptureError Handle when image capture fails
void clearFlatCache()
clearFlatCache Clear the measured values for flat calibrations
QStringList generateScriptArguments() const
generateScriptArguments Generate argument list to pass to capture script
IPState processPreCaptureCalibrationStage()
processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may st...
void processCaptureTimeout()
processCaptureTimeout If exposure timed out, let's handle it.
IPState resumeSequence()
resumeSequence Try to continue capturing.
void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state)
setExposureProgress Manage exposure progress reported by the camera device.
QStringList frameTypes()
frameTypes Retrieve the frame types from the active camera's primary chip.
void updateFITSViewer(const QSharedPointer< FITSData > data, const FITSMode &captureMode, const FITSScale &captureFilter, const QString &filename, const QString &deviceName)
updateFITSViewer display new image in the configured FITSViewer tab.
void processFITSData(const QSharedPointer< FITSData > &data, const QString &extension)
newFITS process new FITS data received from camera.
bool saveSequenceQueue(const QString &path, bool loadOptions=true)
Saves the Sequence Queue to the Ekos Sequence Queue file.
void prepareJobExecution()
preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and...
void checkCamera()
configureCamera Refreshes the CCD information in the capture module.
void updateCompletedCaptureCountersAction()
updateCompletedCaptureCounters Update counters if an image has been captured
void setDownloadProgress()
setDownloadProgress update the Capture Module and Summary Screen's estimate of how much time is left ...
void removeDevice(const QSharedPointer< ISD::GenericDevice > &device)
Generic method for removing any connected device.
bool setCamera(ISD::Camera *device)
setCamera Connect to the given camera device (and deconnect the old one if existing)
void syncDSLRToTargetChip(const QString &model)
syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
IPState runCaptureScript(ScriptTypes scriptType, bool precond=true)
runCaptureScript Run the pre-/post capture/job script
QStringList filterLabels()
filterLabels list of currently available filter labels
void checkNextExposure()
checkNextExposure Try to start capturing the next exposure (
bool hasCoolerControl()
Does the CCD has a cooler control (On/Off) ?
double calculateFlatExpTime(double currentADU)
calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
void prepareActiveJobStage2()
prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
IPState startNextExposure()
startNextExposure Ensure that all pending preparation tasks are be completed (focusing,...
bool checkPausing(CaptureModuleState::ContinueAction continueAction)
checkPausing check if a pause has been planned and pause subsequently
void restartCamera(const QString &name)
restartCamera Restarts the INDI driver associated with a camera.
IPState continueFramingAction(const QSharedPointer< FITSData > &imageData)
continueFramingAction If framing is running, start the next capture sequence
IPState startNextJob()
startNextJob Select the next job that is either idle or aborted and call prepareJob(*SequenceJob) to ...
void updateGain(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getGain Update the gain value from the custom property value.
void scriptFinished(int exitCode, QProcess::ExitStatus status)
scriptFinished Slot managing the return status of pre/post capture/job scripts
void captureImage()
captureImage Initiates image capture in the active job.
void updatePreCaptureCalibrationStatus()
updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),...
void updateTelescopeInfo()
updateTelescopeInfo Update the scope information in the camera's INDI driver.
void updateFilterInfo()
updateFilterInfo Update the filter information in the INDI drivers of the current camera and dust cap
void stopCapturing(CaptureState targetState)
stopCapturing Stopping the entire capturing state (envelope for aborting, suspending,...
void resetFrame()
resetFrame Reset frame settings of the camera
void processJobCompletion1()
processJobCompletionStage1 Process job completion.
void updateOffset(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getOffset Update the offset value from the custom property value.
void processNewRemoteFile(QString file)
setNewRemoteFile A new image has been stored as remote file
bool loadSequenceQueue(const QString &fileURL, const QString &targetName="", bool setOptions=true)
Loads the Ekos Sequence Queue file in the Sequence Queue.
bool setCoolerControl(bool enable)
Set the CCD cooler ON/OFF.
IPState updateDownloadTimesAction()
updateDownloadTimesAction Add the current download time to the list of already measured ones
void reconnectCameraDriver(const QString &camera, const QString &filterWheel)
reconnectDriver Reconnect the camera driver
SequenceJob * findNextPendingJob()
findExecutableJob find next job to be executed
bool checkFlatCalibration(QSharedPointer< FITSData > imageData, double exp_min, double exp_max)
checkFlatCalibration check the flat calibration
void prepareJob(SequenceJob *job)
prepareJob Update the counters of existing frames and continue with prepareActiveJob(),...
void selectCamera(QString name)
setCamera select camera device
IPState checkLightFramePendingTasks()
Check all tasks that might be pending before capturing may start.
void processJobCompletion2()
processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a ne...
IPState updateImageMetadataAction(QSharedPointer< FITSData > imageData)
updateImageMetadataAction Update meta data of a captured image
IPState previewImageCompletedAction(QSharedPointer< FITSData > imageData)
previewImageCompletedAction Activities required when a preview image has been captured.
bool setFilterWheel(ISD::FilterWheel *device)
setFilterWheel Connect to the given filter wheel device (and deconnect the old one if existing)
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
void sendNewProperty(INDI::Property prop)
Send new property command to server.
INDI::PropertyView< IText > * getText(const QString &name) const
Class handles control of INDI dome devices.
Handles operation of a remotely controlled dust cover cap.
Handles operation of a remotely controlled light box.
device handle controlling Mounts.
void newTargetName(const QString &name)
The mount has finished the slew to a new target.
Rotator class handles control of INDI Rotator devices.
static KStars * Instance()
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
CaptureState
Capture states.
@ SCRIPT_POST_CAPTURE
Script to run after a sequence capture is completed.
@ SCRIPT_POST_JOB
Script to run after a sequence job is completed.
@ SCRIPT_PRE_CAPTURE
Script to run before a sequence capture is started.
@ SCRIPT_PRE_JOB
Script to run before a sequence job is started.
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QObject * sender() const const
void errorOccurred(QProcess::ProcessError error)
void finished(int exitCode, QProcess::ExitStatus exitStatus)
void readyReadStandardError()
void readyReadStandardOutput()
void start(OpenMode mode)
bool isNull() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
bool isValid() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QPoint toPoint() const const
QRect toRect() const const
QString toString() const const
uint toUInt(bool *ok) const const
Object to hold FITS Header records.