6#include "cameraprocess.h"
7#include "QtWidgets/qstatusbar.h"
8#include "capturedeviceadaptor.h"
9#include "refocusstate.h"
10#include "sequencejob.h"
11#include "sequencequeue.h"
12#include "ekos/manager.h"
13#include "ekos/auxiliary/darklibrary.h"
14#include "ekos/auxiliary/darkprocessor.h"
15#include "ekos/auxiliary/opticaltrainmanager.h"
16#include "ekos/auxiliary/profilesettings.h"
17#include "ekos/guide/guide.h"
18#include "indi/indilistener.h"
19#include "indi/indirotator.h"
20#include "indi/blobmanager.h"
21#include "indi/indilightbox.h"
22#include "indi/streamwg.h"
23#include "ksmessagebox.h"
27#include "fitsviewer/fitsdata.h"
28#include "fitsviewer/fitstab.h"
30#include "fitsviewer/fitsviewer.h"
32#include "ksnotification.h"
33#include <ekos_capture_debug.h>
35#ifdef HAVE_STELLARSOLVER
36#include "ekos/auxiliary/stellarsolverprofileeditor.h"
44 setObjectName(
"CameraProcess");
45 m_State = newModuleState;
46 m_DeviceAdaptor = newDeviceAdaptor;
49 connect(devices().data(), &CaptureDeviceAdaptor::newCamera,
this, &CameraProcess::selectCamera);
54 state()->downloadProgressTimer().setInterval(100);
58 m_DarkProcessor =
new DarkProcessor(
this);
59 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &CameraProcess::newLog);
60 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, &CameraProcess::darkFrameCompleted);
65 this, &CameraProcess::scriptFinished);
69 emit newLog(m_CaptureScript.errorString());
75 emit newLog(m_CaptureScript.readAllStandardError());
80 emit newLog(m_CaptureScript.readAllStandardOutput());
86 if (devices()->mount() && devices()->mount() == device)
88 updateTelescopeInfo();
92 if (devices()->mount())
93 devices()->mount()->disconnect(state().data());
95 devices()->setMount(device);
97 if (!devices()->mount())
100 devices()->mount()->disconnect(
this);
103 updateTelescopeInfo();
110 if ((devices()->rotator() == device) && (device !=
nullptr))
114 if (devices()->mount())
116 if (devices()->rotator())
117 devices()->rotator()->disconnect(
this);
120 state()->isInitialized[CAPTURE_ACTION_ROTATOR] =
false;
124 Manager::Instance()->createRotatorController(device);
125 connect(devices().data(), &CaptureDeviceAdaptor::rotatorReverseToggled,
this, &CameraProcess::rotatorReverseToggled,
128 devices()->setRotator(device);
136 if (devices()->dustCap() && devices()->dustCap() == device)
139 devices()->setDustCap(device);
140 state()->setDustCapState(CAP_UNKNOWN);
149 if (devices()->lightBox() == device)
152 devices()->setLightBox(device);
153 state()->setLightBoxLightState(CAP_LIGHT_UNKNOWN);
160 if (devices()->dome() == device)
163 devices()->setDome(device);
170 if (devices()->getActiveCamera() == device)
175 disconnect(activeCamera(), &ISD::Camera::newImage,
this, &CameraProcess::showFITSPreview);
177 devices()->setActiveCamera(device);
180 if (state()->getCaptureTimeout().isActive() && state()->getCaptureState() ==
CAPTURE_CAPTURING)
186 connect(activeCamera(), &ISD::Camera::newImage,
this, &CameraProcess::showFITSPreview);
188 connect(device, &ISD::Camera::updateVideoWindow,
this, &CameraProcess::updateVideoWindow);
195void CameraProcess::toggleVideo(
bool enabled)
197 if (devices() ==
nullptr || devices()->getActiveCamera() ==
nullptr)
201 enabled = devices()->getActiveCamera()->isStreamingEnabled();
204 getVideoWindow()->close();
207 if (devices()->getActiveCamera()->isBLOBEnabled() ==
false)
209 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
210 devices()->getActiveCamera()->setBLOBEnabled(
true);
216 devices()->getActiveCamera()->setBLOBEnabled(
true);
217 devices()->getActiveCamera()->setVideoStreamEnabled(
true);
220 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
221 i18n(
"Image Transfer"), 15);
228 devices()->getActiveCamera()->setVideoStreamEnabled(
true);
233void CameraProcess::toggleSequence()
235 const CaptureState capturestate = state()->getCaptureState();
242 emit newLog(
i18n(
"Sequence resumed."));
245 switch (state()->getContinueAction())
247 case CAPTURE_CONTINUE_ACTION_CAPTURE_COMPLETE:
250 case CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE:
259 startNextPendingJob();
267void CameraProcess::startNextPendingJob()
269 if (state()->allJobs().count() > 0)
271 SequenceJob *nextJob = findNextPendingJob();
272 if (nextJob !=
nullptr)
278 emit newLog(
i18n(
"No pending jobs found. Please add a job to the sequence queue."));
288void CameraProcess::jobCreated(SequenceJob *newJob)
290 if (newJob ==
nullptr)
292 emit newLog(
i18n(
"No new job created."));
296 switch (newJob->jobType())
298 case SequenceJob::JOBTYPE_BATCH:
299 startNextPendingJob();
301 case SequenceJob::JOBTYPE_PREVIEW:
302 state()->setActiveJob(newJob);
311void CameraProcess::capturePreview(
bool loop)
313 if (state()->getFocusState() >= FOCUS_PROGRESS)
315 emit newLog(
i18n(
"Cannot capture while focus module is busy."));
317 else if (activeJob() ==
nullptr)
319 if (loop && !state()->isLooping())
321 state()->setLooping(
true);
322 emit newLog(
i18n(
"Starting framing..."));
325 emit createJob(SequenceJob::JOBTYPE_PREVIEW);
330 prepareJob(activeJob());
338 state()->resetAlignmentRetries();
342 state()->getCaptureTimeout().stop();
343 state()->getCaptureDelayTimer().stop();
344 if (activeJob() !=
nullptr)
346 if (activeJob()->getStatus() == JOB_BUSY)
352 stopText =
i18n(
"CCD capture suspended");
353 resetJobStatus(JOB_BUSY);
357 stopText =
i18n(
"CCD capture complete");
358 resetJobStatus(JOB_DONE);
362 stopText = state()->isLooping() ?
i18n(
"Framing stopped") :
i18n(
"CCD capture stopped");
363 resetJobStatus(JOB_ABORTED);
367 stopText =
i18n(
"CCD capture stopped");
368 resetJobStatus(JOB_IDLE);
371 emit captureAborted(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
372 KSNotification::event(
QLatin1String(
"CaptureFailed"), stopText, KSNotification::Capture, KSNotification::Alert);
373 emit newLog(stopText);
377 checkPausing(CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE))
380 activeJob()->abort();
381 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
383 int index = state()->allJobs().indexOf(activeJob());
384 state()->changeSequenceValue(index,
"Status",
"Aborted");
385 emit updateJobTable(activeJob());
390 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
394 else if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
400 state()->allJobs().removeOne(activeJob());
402 activeJob()->deleteLater();
404 state()->setActiveJob(
nullptr);
412 state()->setCaptureState(targetState);
414 state()->setLooping(
false);
415 state()->setBusy(
false);
417 state()->getCaptureDelayTimer().stop();
419 state()->setActiveJob(
nullptr);
422 if (devices()->lightBox() && state()->lightBoxLightEnabled())
424 state()->setLightBoxLightEnabled(
false);
425 devices()->lightBox()->setLightEnabled(
false);
432 if (devices()->getActiveCamera() && devices()->getActiveChip()
433 && devices()->getActiveCamera()->isFastExposureEnabled())
434 devices()->getActiveChip()->abortExposure();
437 emit captureStopped();
440void CameraProcess::pauseCapturing()
442 if (state()->isCaptureRunning() ==
false)
447 emit newLog(
i18n(
"Pausing only possible while frame capture is running."));
448 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Pause button pressed while not capturing.";
452 state()->setContinueAction(CAPTURE_CONTINUE_ACTION_NONE);
454 emit newLog(
i18n(
"Sequence shall be paused after current exposure is complete."));
457void CameraProcess::startJob(SequenceJob *job)
459 state()->initCapturePreparation();
463void CameraProcess::prepareJob(SequenceJob * job)
465 if (activeCamera() ==
nullptr || activeCamera()->isConnected() ==
false)
467 emit newLog(
i18n(
"No camera detected. Check train configuration and connection settings."));
468 activeJob()->abort();
472 state()->setActiveJob(job);
476 if (job->jobType() == SequenceJob::JOBTYPE_PREVIEW && Options::useFITSViewer() ==
false
477 && Options::useSummaryPreview() ==
false)
483 Options::setUseFITSViewer(
true);
490 activeJob()->abort();
492 KSMessageBox::Instance()->questionYesNo(
i18n(
"No view available for previews. Enable FITS viewer?"),
493 i18n(
"Display preview"), 15);
498 if (state()->isLooping() ==
false)
499 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Preparing capture job" << job->getSignature() <<
"for execution.";
501 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
505 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
506 state()->setNextSequenceID(1);
512 QString signature = activeJob()->getSignature();
518 state()->checkSeqBoundary();
538 int count = state()->capturedFramesCount(signature);
543 for (
auto &a_job : state()->allJobs())
544 if (a_job == activeJob())
546 else if (a_job->getSignature() == activeJob()->getSignature())
547 count -= a_job->getCompleted();
550 updatedCaptureCompleted(count);
554 else if (state()->hasCapturedFramesMap())
557 updatedCaptureCompleted(0);
563 else if (state()->ignoreJobProgress()
564 && activeJob()->getJobProgressIgnored() ==
false)
566 activeJob()->setJobProgressIgnored(
true);
567 updatedCaptureCompleted(0);
572 if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
573 activeJob()->getCompleted())
575 updatedCaptureCompleted(activeJob()->getCoreProperty(
576 SequenceJob::SJ_Count).toInt());
577 emit newLog(
i18n(
"Job requires %1-second %2 images, has already %3/%4 captures and does not need to run.",
578 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
579 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
580 activeJob()->getCompleted(),
581 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
582 processJobCompletion2();
589 if (activeJob()->getFrameType() != FRAME_VIDEO)
592 emit newLog(
i18n(
"Job requires %1-second %2 images, has %3/%4 frames captured and will be processed.",
593 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
594 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
595 activeJob()->getCompleted(),
596 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
601 activeCamera()->setNextSequenceID(state()->nextSequenceID());
605 emit newLog(
i18n(
"Job requires %1 x %2-second %3 video and will be processed.",
606 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt(),
607 QString(
"%L1").arg(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f', 3),
608 activeJob()->getCoreProperty(SequenceJob::SJ_Filter).toString()));
613 if (activeCamera()->isBLOBEnabled() ==
false)
618 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
620 activeCamera()->setBLOBEnabled(
true);
627 activeCamera()->setBLOBEnabled(
true);
628 prepareActiveJobStage1();
634 activeCamera()->setBLOBEnabled(
true);
635 state()->setBusy(
false);
638 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
639 i18n(
"Image Transfer"), 15);
645 emit jobPrepared(job);
647 prepareActiveJobStage1();
651void CameraProcess::prepareActiveJobStage1()
653 if (activeJob() ==
nullptr)
655 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage1 with null activeJob().";
661 if (runCaptureScript(
SCRIPT_PRE_JOB, activeJob()->getCompleted() == 0) == IPS_BUSY)
664 prepareActiveJobStage2();
667void CameraProcess::prepareActiveJobStage2()
670 if (activeJob() ==
nullptr)
672 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage2 with null activeJob().";
675 emit newImage(activeJob(), state()->imageData());
691 prepareJobExecution();
694void CameraProcess::executeJob()
696 if (activeJob() ==
nullptr)
698 qWarning(KSTARS_EKOS_CAPTURE) <<
"executeJob with null activeJob().";
703 if (!activeCamera() || !devices()->getActiveChip())
711 if (Options::defaultObserver().isEmpty() ==
false)
713 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetName) !=
"")
714 FITSHeaders.
append(
FITSData::Record(
"Object", activeJob()->getCoreProperty(SequenceJob::SJ_TargetName).toString(),
719 activeCamera()->setFITSHeaders(FITSHeaders);
722 state()->setBusy(
true);
723 state()->setUseGuideHead((devices()->getActiveChip()->getType() == ISD::CameraChip::PRIMARY_CCD) ?
726 emit syncGUIToJob(activeJob());
730 if (activeJob()->jobType() == SequenceJob::JOBTYPE_DARKFLAT)
733 if (state()->setDarkFlatExposure(activeJob())
734 && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
736 auto placeholderPath = PlaceholderPath();
738 placeholderPath.processJobInfo(activeJob());
739 state()->setNextSequenceID(1);
744 updatePreCaptureCalibrationStatus();
748void CameraProcess::prepareJobExecution()
750 if (activeJob() ==
nullptr)
752 qWarning(KSTARS_EKOS_CAPTURE) <<
"preparePreCaptureActions with null activeJob().";
757 state()->setBusy(
true);
760 activeJob()->setCoreProperty(SequenceJob::SJ_GuiderActive,
761 state()->isActivelyGuiding());
764 activeJob()->prepareCapture();
767 emit jobExecutionPreparationStarted();
770void CameraProcess::refreshOpticalTrain(
QString name)
772 state()->setOpticalTrain(name);
774 auto mount = OpticalTrainManager::Instance()->getMount(name);
777 auto scope = OpticalTrainManager::Instance()->getScope(name);
778 setScope(scope[
"name"].toString());
780 auto camera = OpticalTrainManager::Instance()->getCamera(name);
783 auto filterWheel = OpticalTrainManager::Instance()->getFilterWheel(name);
784 setFilterWheel(filterWheel);
786 auto rotator = OpticalTrainManager::Instance()->getRotator(name);
789 auto dustcap = OpticalTrainManager::Instance()->getDustCap(name);
792 auto lightbox = OpticalTrainManager::Instance()->getLightBox(name);
793 setLightBox(lightbox);
796IPState CameraProcess::checkLightFramePendingTasks()
803 if (checkPausing(CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE) ==
true)
807 if (state()->checkMeridianFlipActive())
813 state()->getGuideState() == GUIDE_GUIDING &&
814 Options::enforceStartGuiderDrift())
818 if ((state()->getCaptureState() ==
CAPTURE_DITHERING && state()->getDitheringState() != IPS_OK)
819 || state()->checkDithering())
827 if (state()->checkFocusRunning() || state()->startFocusIfRequired())
832 if (state()->getGuideState() == GUIDE_SUSPENDED && activeJob()->getFrameType() == FRAME_LIGHT)
834 emit newLog(
i18n(
"Autoguiding resumed."));
835 emit resumeGuiding();
846void CameraProcess::captureStarted(CaptureResult rc)
853 state()->getCaptureTimeout().start(
static_cast<int>(activeJob()->getCoreProperty(
854 SequenceJob::SJ_Exposure).toDouble()) * 1000 +
855 CAPTURE_TIMEOUT_THRESHOLD);
857 state()->imageCountDown().setHMS(0, 0, 0);
858 double ms_left = std::ceil(activeJob()->getExposeLeft() * 1000.0);
859 state()->imageCountDownAddMSecs(
int(ms_left));
860 state()->setLastRemainingFrameTimeMS(ms_left);
861 state()->sequenceCountDown().setHMS(0, 0, 0);
862 state()->sequenceCountDownAddMSecs(activeJob()->getJobRemainingTime(state()->averageDownloadTime()) * 1000);
865 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
867 auto index = state()->allJobs().indexOf(activeJob());
868 if (index >= 0 && index < state()->getSequence().count())
869 state()->changeSequenceValue(index,
"Status",
"In Progress");
871 emit updateJobTable(activeJob());
873 emit captureRunning();
877 case CAPTURE_FRAME_ERROR:
878 emit newLog(
i18n(
"Failed to set sub frame."));
882 case CAPTURE_BIN_ERROR:
883 emit newLog((
i18n(
"Failed to set binning.")));
887 case CAPTURE_FOCUS_ERROR:
888 emit newLog((
i18n(
"Cannot capture while focus module is busy.")));
894void CameraProcess::checkNextExposure()
896 IPState started = startNextExposure();
899 if (started == IPS_BUSY)
903IPState CameraProcess::captureImageWithDelay()
905 auto theJob = activeJob();
907 if (theJob ==
nullptr)
910 const int seqDelay = theJob->getCoreProperty(SequenceJob::SJ_Delay).toInt();
914 state()->setCaptureState(CAPTURE_WAITING);
916 state()->getCaptureDelayTimer().start(seqDelay);
920IPState CameraProcess::startNextExposure()
925 auto theJob = activeJob();
927 if (theJob ==
nullptr)
931 if (activeJob()->getFrameType() == FRAME_LIGHT)
933 IPState pending = checkLightFramePendingTasks();
934 if (pending != IPS_OK)
939 return captureImageWithDelay();
944IPState CameraProcess::resumeSequence()
947 if (checkPausing(CAPTURE_CONTINUE_ACTION_CAPTURE_COMPLETE) ==
true)
953 return startNextJob();
958 else if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
959 activeJob()->getCompleted())
961 processJobCompletion1();
969 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
970 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
972 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
973 emit resumeGuiding();
977 if (activeCamera()->isFastExposureEnabled())
979 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
981 state()->checkSeqBoundary();
982 activeCamera()->setNextSequenceID(state()->nextSequenceID());
992 if (activeCamera()->isFastExposureEnabled())
994 state()->setRememberFastExposure(
true);
995 activeCamera()->setFastExposureEnabled(
false);
1003 if (activeCamera()->isFastExposureEnabled())
1006 activeJob()->getFrameType() == FRAME_LIGHT &&
1007 checkLightFramePendingTasks() == IPS_OK)
1015 state()->setRememberFastExposure(
true);
1016 activeCamera()->setFastExposureEnabled(
false);
1019 checkNextExposure();
1032 if (data && activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1034 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
1035 && activeJob()->getCalibrationStage() != SequenceJobState::CAL_CALIBRATION)
1037 if (state()->generateFilename(extension, &filename) && activeCamera()->saveCurrentImage(filename))
1039 data->setFilename(filename);
1045 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Saving current image failed!";
1050 KSMessageBox::Instance()->error(
i18n(
"Failed writing image to %1\nPlease check folder, filename & permissions.",
1052 i18n(
"Image Write Failed"), 30);
1067 state()->setImageData(data);
1068 blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1069 .
arg(data->property(
"blobVector").toString())
1070 .
arg(data->property(
"blobElement").toString())
1071 .
arg(data->property(
"chip").toInt());
1074 state()->imageData().reset();
1076 const SequenceJob *job = activeJob();
1081 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring received FITS as active job is null.";
1083 emit processingFITSfinished(
false);
1087 if (state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1090 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as meridian flip stage is" <<
1091 state()->getMeridianFlipState()->getMeridianFlipStage();
1092 emit processingFITSfinished(
false);
1096 const SequenceJob::SequenceJobType currentJobType = activeJob()->jobType();
1098 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1103 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as current capture state is not active" <<
1104 state()->getCaptureState();
1106 emit processingFITSfinished(
false);
1112 tChip = activeCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>(data->property(
"chip").toInt()));
1113 if (tChip != devices()->getActiveChip())
1115 if (state()->getGuideState() == GUIDE_IDLE)
1116 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it does not correspond to the target chip"
1117 << devices()->getActiveChip()->getType();
1119 emit processingFITSfinished(
false);
1124 if (devices()->getActiveChip()->getCaptureMode() == FITS_FOCUS ||
1125 devices()->getActiveChip()->getCaptureMode() == FITS_GUIDE)
1127 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1128 devices()->getActiveChip()->getCaptureMode();
1130 emit processingFITSfinished(
false);
1135 if (data && data->property(
"device").toString() != activeCamera()->getDeviceName())
1137 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as the blob device name does not equal active camera"
1138 << activeCamera()->getDeviceName();
1140 emit processingFITSfinished(
false);
1144 if (currentJobType == SequenceJob::JOBTYPE_PREVIEW)
1147 if (checkSavingReceivedImage(data, extension, filename))
1149 FITSMode captureMode = tChip->getCaptureMode();
1150 FITSScale captureFilter = tChip->getCaptureFilter();
1151 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
1156 if (data && Options::autoDark() && job->jobType() == SequenceJob::JOBTYPE_PREVIEW && state()->useGuideHead() ==
false)
1158 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
1161 m_DarkProcessor.data()->denoise(trainID.
toUInt(),
1162 devices()->getActiveChip(),
1163 state()->imageData(),
1164 job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(),
1165 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
x(),
1166 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
y());
1169 qWarning(KSTARS_EKOS_CAPTURE) <<
"Invalid train ID for darks substraction:" << trainID.
toUInt();
1172 if (currentJobType == SequenceJob::JOBTYPE_PREVIEW)
1183 SequenceJob *thejob = activeJob();
1185 if (thejob ==
nullptr)
1190 if (activeCamera()->isFastExposureEnabled() ==
false && state()->isLooping() ==
false)
1192 disconnect(activeCamera(), &ISD::Camera::newExposureValue,
this,
1194 DarkLibrary::Instance()->disconnect(
this);
1198 bool alreadySaved =
false;
1199 switch (thejob->getFrameType())
1203 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1207 if (thejob->getFlatFieldDuration() == DURATION_ADU
1208 && thejob->getCoreProperty(SequenceJob::SJ_TargetADU).
toDouble() > 0)
1210 if (
checkFlatCalibration(state()->imageData(), state()->exposureRange().min, state()->exposureRange().max) ==
false)
1215 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1217 if (checkSavingReceivedImage(data, extension, filename))
1218 alreadySaved =
true;
1222 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1231 qWarning(KSTARS_EKOS_CAPTURE) <<
"Job completed with frametype NONE!";
1238 if (thejob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION_COMPLETE)
1239 thejob->setCalibrationStage(SequenceJobState::CAL_CAPTURING);
1241 if (activeJob() && currentJobType != SequenceJob::JOBTYPE_PREVIEW &&
1242 activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1245 if (alreadySaved || checkSavingReceivedImage(data, extension, filename))
1254 emit newImage(thejob, state()->imageData());
1261 if (currentJobType != SequenceJob::JOBTYPE_PREVIEW)
1265 emit processingFITSfinished(
true);
1270 ISD::CameraChip * tChip = activeCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>(data->property(
"chip").toInt()));
1272 updateFITSViewer(data, tChip->getCaptureMode(), tChip->getCaptureFilter(),
"", data->property(
"device").toString());
1277 emit newLog(
i18n(
"Remote image saved to %1", file));
1280 if (activeCamera() && activeCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1290 if (activeJob() ==
nullptr)
1292 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Processing pre capture calibration without active job, state = " <<
1293 getCaptureStatusString(state()->getCaptureState());
1300 if (activeJob()->getFrameType() != FRAME_LIGHT
1301 && state()->getGuideState() == GUIDE_GUIDING)
1303 emit newLog(
i18n(
"Autoguiding suspended."));
1304 emit suspendGuiding();
1308 switch (activeJob()->getFrameType())
1331 if (state()->isBusy() ==
false)
1333 emit newLog(
i18n(
"Warning: Calibration process was prematurely terminated."));
1339 if (rc == IPS_ALERT)
1341 else if (rc == IPS_BUSY)
1347 captureImageWithDelay();
1352 if (activeJob() ==
nullptr)
1354 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage1 with null activeJob().";
1368 if (activeJob() ==
nullptr)
1370 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage2 with null activeJob().";
1374 activeJob()->done();
1376 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1378 int index = state()->allJobs().indexOf(activeJob());
1379 QJsonArray seqArray = state()->getSequence();
1380 QJsonObject oneSequence = seqArray[index].toObject();
1381 oneSequence[
"Status"] =
"Complete";
1382 seqArray.
replace(index, oneSequence);
1383 state()->setSequence(seqArray);
1384 emit sequenceChanged(seqArray);
1385 emit updateJobTable(activeJob());
1399 KSNotification::event(
QLatin1String(
"CaptureSuccessful"),
i18n(
"CCD capture sequence completed"),
1400 KSNotification::Capture);
1406 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1407 emit resumeGuiding();
1414 SequenceJob * next_job =
nullptr;
1416 for (
auto &oneJob : state()->allJobs())
1418 if (oneJob->getStatus() == JOB_IDLE || oneJob->getStatus() == JOB_ABORTED)
1432 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
1433 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
1435 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
1436 emit resumeGuiding();
1443 qCDebug(KSTARS_EKOS_CAPTURE) <<
"All capture jobs complete.";
1450 if (activeJob() ==
nullptr)
1454 if (!activeCamera() || !activeCamera()->isConnected())
1456 emit newLog(
i18n(
"Error: Lost connection to CCD."));
1461 state()->getCaptureTimeout().stop();
1462 state()->getCaptureDelayTimer().stop();
1463 if (activeCamera()->isFastExposureEnabled())
1465 int remaining = state()->isLooping() ? 100000 : (activeJob()->getCoreProperty(
1466 SequenceJob::SJ_Count).
toInt() -
1467 activeJob()->getCompleted());
1469 activeCamera()->setFastCount(
static_cast<uint
>(remaining));
1474 if (activeJob()->getFrameType() == FRAME_FLAT)
1477 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
1478 && activeJob()->getFlatFieldDuration() == DURATION_ADU &&
1479 activeJob()->getCalibrationStage() == SequenceJobState::CAL_NONE)
1481 if (activeCamera()->getEncodingFormat() !=
"FITS" &&
1482 activeCamera()->getEncodingFormat() !=
"XISF")
1484 emit newLog(
i18n(
"Cannot calculate ADU levels in non-FITS images."));
1489 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
1494 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1496 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1497 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1502 if (activeCamera()->getUploadMode() != activeJob()->getUploadMode())
1503 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1506 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1508 state()->checkSeqBoundary();
1509 activeCamera()->setNextSequenceID(state()->nextSequenceID());
1513 if (state()->isRememberFastExposure())
1515 state()->setRememberFastExposure(
false);
1516 activeCamera()->setFastExposureEnabled(
true);
1519 if (state()->frameSettings().contains(devices()->getActiveChip()))
1521 const auto roi = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect();
1522 QVariantMap settings;
1523 settings[
"x"] = roi.x();
1524 settings[
"y"] = roi.y();
1525 settings[
"w"] = roi.width();
1526 settings[
"h"] = roi.height();
1527 settings[
"binx"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
x();
1528 settings[
"biny"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
y();
1530 state()->frameSettings()[devices()->getActiveChip()] = settings;
1534 activeCamera()->setEncodingFormat(activeJob()->getCoreProperty(
1535 SequenceJob::SJ_Encoding).toString());
1537 state()->setStartingCapture(
true);
1538 state()->placeholderPath().setGenerateFilenameSettings(*activeJob());
1541 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1543 auto remoteUpload = state()->placeholderPath().generateSequenceFilename(*activeJob(),
false,
true, 1,
"",
"",
false,
1547 auto remoteDirectory = remoteUpload.mid(0, lastSeparator);
1548 auto remoteFilename = remoteUpload.mid(lastSeparator + 1);
1549 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatDirectory, remoteDirectory);
1550 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatFilename, remoteFilename);
1556 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(),
1557 activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION ? FITS_CALIBRATE :
1561 if (state()->isRememberFastExposure())
1563 state()->setRememberFastExposure(
false);
1564 activeCamera()->setFastExposureEnabled(
true);
1567 emit captureTarget(activeJob()->getCoreProperty(SequenceJob::SJ_TargetName).toString());
1568 emit captureImageStarted();
1573 devices()->setActiveChip(state()->useGuideHead() ?
1574 devices()->getActiveCamera()->getChip(
1575 ISD::CameraChip::GUIDE_CCD) :
1576 devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1577 devices()->getActiveChip()->resetFrame();
1578 emit updateFrameProperties(1);
1584 if (state()->checkCapturing() ==
false)
1587 if (devices()->getActiveChip() != tChip ||
1588 devices()->getActiveChip()->getCaptureMode() != FITS_NORMAL
1589 || state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1592 double deltaMS = std::ceil(1000.0 * value - state()->lastRemainingFrameTimeMS());
1593 emit updateCaptureCountDown(
int(deltaMS));
1594 state()->setLastRemainingFrameTimeMS(state()->lastRemainingFrameTimeMS() + deltaMS);
1598 activeJob()->setExposeLeft(value);
1600 emit newExposureProgress(activeJob());
1603 if (activeJob() && ipstate == IPS_ALERT)
1605 int retries = activeJob()->getCaptureRetires() + 1;
1607 activeJob()->setCaptureRetires(retries);
1609 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
1613 activeJob()->abort();
1617 emit newLog((
i18n(
"Restarting capture attempt #%1", retries)));
1619 state()->setNextSequenceID(1);
1625 if (activeJob() !=
nullptr && ipstate == IPS_OK)
1627 activeJob()->setCaptureRetires(0);
1628 activeJob()->setExposeLeft(0);
1630 if (devices()->getActiveCamera()
1631 && devices()->getActiveCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1633 if (activeJob()->getStatus() == JOB_BUSY)
1635 emit processingFITSfinished(
false);
1640 if (state()->getGuideState() == GUIDE_GUIDING && Options::guiderType() == 0
1641 && state()->suspendGuidingOnDownload())
1643 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Autoguiding suspended until primary CCD chip completes downloading...";
1644 emit suspendGuiding();
1647 emit downloadingFrame();
1650 state()->downloadTimer().start();
1651 state()->downloadProgressTimer().start();
1659 double downloadTimeLeft = state()->averageDownloadTime() - state()->downloadTimer().elapsed() /
1661 if(downloadTimeLeft >= 0)
1663 state()->imageCountDown().setHMS(0, 0, 0);
1664 state()->imageCountDownAddMSecs(
int(std::ceil(downloadTimeLeft * 1000)));
1665 emit newDownloadProgress(downloadTimeLeft);
1673 emit newImage(activeJob(), imageData);
1675 if (activeCamera()->isFastExposureEnabled() ==
false)
1677 const int seqDelay = activeJob()->getCoreProperty(SequenceJob::SJ_Delay).
toInt();
1683 if (activeJob() !=
nullptr)
1684 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1687 else if (activeJob() !=
nullptr)
1688 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1698 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL
1699 && state()->downloadTimer().isValid())
1702 double currentDownloadTime = state()->downloadTimer().elapsed() / 1000.0;
1703 state()->addDownloadTime(currentDownloadTime);
1705 state()->downloadTimer().invalidate();
1709 emit newLog(
i18n(
"Download Time: %1 s, New Download Time Estimate: %2 s.", dLTimeString, estimatedTimeString));
1716 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1719 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1721 state()->setActiveJob(
nullptr);
1723 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1724 emit resumeGuiding();
1735 state()->getCaptureTimeout().stop();
1736 state()->setCaptureTimeoutCounter(0);
1738 state()->downloadProgressTimer().stop();
1741 if (state()->isLooping())
1755 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW
1756 || activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
1760 updatedCaptureCompleted(activeJob()->getCompleted() + 1);
1762 state()->getRefocusState()->decreaseInSequenceFocusCounter();
1764 state()->getRefocusState()->setAdaptiveFocusDone(
false);
1768 if (state()->getMeridianFlipState()->getMeridianFlipStage() < MeridianFlipState::MF_FLIPPING)
1769 state()->decreaseDitherCounter();
1772 state()->addCapturedFrame(activeJob()->getSignature());
1775 emit newLog(
i18n(
"Received image %1 out of %2.", activeJob()->getCompleted(),
1776 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
1781 double hfr = -1, eccentricity = -1;
1782 int numStars = -1, median = -1;
1787 if (Options::autoHFR() && imageData && !imageData->areStarsSearched() && imageData->getRecordValue(
"FRAME", frameType)
1788 && frameType.
toString() ==
"Light")
1790#ifdef HAVE_STELLARSOLVER
1793 QVariantMap extractionSettings;
1794 extractionSettings[
"optionsProfileIndex"] = Options::hFROptionsProfile();
1795 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::HFRProfiles);
1796 imageData->setSourceExtractorSettings(extractionSettings);
1801 hfr = imageData->getHFR(HFR_AVERAGE);
1802 numStars = imageData->getSkyBackground().starsDetected;
1803 median = imageData->getMedian();
1804 eccentricity = imageData->getEccentricity();
1805 filename = imageData->filename();
1808 if (state()->isLooping() ==
false && activeJob() !=
nullptr && activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1809 emit newLog(
i18n(
"Captured %1", filename));
1811 auto remainingPlaceholders = PlaceholderPath::remainingPlaceholders(filename);
1812 if (remainingPlaceholders.size() > 0)
1815 i18n(
"WARNING: remaining and potentially unknown placeholders %1 in %2",
1816 remainingPlaceholders.join(
", "), filename));
1822 QVariantMap metadata;
1823 metadata[
"filename"] = filename;
1824 metadata[
"type"] = activeJob()->getFrameType();
1825 metadata[
"exposure"] = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
1826 metadata[
"filter"] = activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString();
1827 metadata[
"width"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
width();
1828 metadata[
"height"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
height();
1829 metadata[
"binx"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
x();
1830 metadata[
"biny"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
y();
1831 metadata[
"hfr"] = hfr;
1832 metadata[
"starCount"] = numStars;
1833 metadata[
"median"] = median;
1834 metadata[
"eccentricity"] = eccentricity;
1835 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Captured frame metadata: filename =" << filename <<
", type =" << metadata[
"type"].toInt()
1836 <<
"exposure =" << metadata[
"exposure"].toDouble() <<
"filter =" << metadata[
"filter"].toString() <<
"width =" <<
1837 metadata[
"width"].toInt() <<
"height =" << metadata[
"height"].toInt() <<
"hfr =" << metadata[
"hfr"].toDouble() <<
1838 "starCount =" << metadata[
"starCount"].toInt() <<
"median =" << metadata[
"median"].toInt() <<
"eccentricity =" <<
1839 metadata[
"eccentricity"].toDouble();
1841 emit captureComplete(metadata);
1850 const QString captureScript = activeJob()->getScript(scriptType);
1851 if (captureScript.
isEmpty() ==
false && precond)
1853 state()->setCaptureScriptType(scriptType);
1856 emit newLog(
i18n(
"Executing capture script %1", captureScript));
1868 switch (state()->captureScriptType())
1871 emit newLog(
i18n(
"Pre capture script finished with code %1.", exitCode));
1872 if (activeJob() && activeJob()->getStatus() == JOB_IDLE)
1879 emit newLog(
i18n(
"Post capture script finished with code %1.", exitCode));
1882 if (activeJob() ==
nullptr
1883 || activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
1884 activeJob()->getCompleted())
1889 else if (state()->checkMeridianFlipReady())
1891 emit newLog(
i18n(
"Processing meridian flip..."));
1901 emit newLog(
i18n(
"Pre job script finished with code %1.", exitCode));
1906 emit newLog(
i18n(
"Post job script finished with code %1.", exitCode));
1920 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
1921 if (activeCamera() && trainID.
isValid())
1924 if (devices()->filterWheel())
1926 if (activeCamera() && activeCamera()->getDeviceName() == name)
1929 emit refreshCamera(
true);
1932 emit refreshCamera(
false);
1943 if (!activeCamera())
1949 devices()->setActiveChip(
nullptr);
1952 if (activeCamera()->getDeviceName().contains(
"Guider"))
1954 state()->setUseGuideHead(
true);
1955 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::GUIDE_CCD));
1958 if (devices()->getActiveChip() ==
nullptr)
1960 state()->setUseGuideHead(
false);
1961 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1964 emit refreshCameraSettings();
1969 auto pos = std::find_if(state()->DSLRInfos().begin(),
1972 return (oneDSLRInfo[
"Model"] == model);
1976 if (pos != state()->DSLRInfos().end())
1979 devices()->getActiveChip()->setImageInfo(camera[
"Width"].toInt(),
1980 camera[
"Height"].toInt(),
1981 camera[
"PixelW"].toDouble(),
1982 camera[
"PixelH"].toDouble(),
1989 if (activeCamera() && activeCamera()->getDeviceName() == camera)
1992 auto rememberState = state()->getCaptureState();
1995 state()->setCaptureState(rememberState);
1998 state()->setCaptureTimeoutCounter(0);
2002 devices()->setActiveChip(devices()->getActiveChip());
2016 auto name = device->getDeviceName();
2017 device->disconnect(
this);
2020 if (devices()->mount() && devices()->mount()->getDeviceName() == device->getDeviceName())
2022 devices()->mount()->disconnect(
this);
2023 devices()->setMount(
nullptr);
2024 if (activeJob() !=
nullptr)
2025 activeJob()->addMount(
nullptr);
2029 if (devices()->dome() && devices()->dome()->getDeviceName() == device->getDeviceName())
2031 devices()->dome()->disconnect(
this);
2032 devices()->setDome(
nullptr);
2036 if (devices()->rotator() && devices()->rotator()->getDeviceName() == device->getDeviceName())
2038 devices()->rotator()->disconnect(
this);
2039 devices()->setRotator(
nullptr);
2043 if (devices()->dustCap() && devices()->dustCap()->getDeviceName() == device->getDeviceName())
2045 devices()->dustCap()->disconnect(
this);
2046 devices()->setDustCap(
nullptr);
2047 state()->hasDustCap =
false;
2048 state()->setDustCapState(CAP_UNKNOWN);
2052 if (devices()->lightBox() && devices()->lightBox()->getDeviceName() == device->getDeviceName())
2054 devices()->lightBox()->disconnect(
this);
2055 devices()->setLightBox(
nullptr);
2056 state()->hasLightBox =
false;
2057 state()->setLightBoxLightState(CAP_LIGHT_UNKNOWN);
2061 if (activeCamera() && activeCamera()->getDeviceName() == name)
2064 devices()->setActiveCamera(
nullptr);
2065 devices()->setActiveChip(
nullptr);
2068 if (INDIListener::findDevice(name, generic))
2069 DarkLibrary::Instance()->removeDevice(generic);
2078 if (devices()->filterWheel() && devices()->filterWheel()->getDeviceName() == name)
2080 devices()->filterWheel()->disconnect(
this);
2081 devices()->setFilterWheel(
nullptr);
2085 emit refreshFilterSettings();
2092 state()->setCaptureTimeoutCounter(state()->captureTimeoutCounter() + 1);
2094 if (state()->deviceRestartCounter() >= 3)
2096 state()->setCaptureTimeoutCounter(0);
2097 state()->setDeviceRestartCounter(0);
2098 emit newLog(
i18n(
"Exposure timeout. Aborting..."));
2103 if (state()->captureTimeoutCounter() > 3 && activeCamera())
2105 emit newLog(
i18n(
"Exposure timeout. More than 3 have been detected, will restart driver."));
2106 QString camera = activeCamera()->getDeviceName();
2107 QString fw = (devices()->filterWheel() !=
nullptr) ?
2108 devices()->filterWheel()->getDeviceName() :
"";
2109 emit driverTimedout(camera);
2112 state()->setDeviceRestartCounter(state()->deviceRestartCounter() + 1);
2120 if (activeCamera() && activeJob())
2123 emit newLog(
i18n(
"Exposure timeout. Restarting exposure..."));
2124 activeCamera()->setEncodingFormat(
"FITS");
2125 auto rememberState = state()->getCaptureState();
2128 state()->setCaptureState(rememberState);
2130 auto targetChip = activeCamera()->getChip(state()->useGuideHead() ?
2131 ISD::CameraChip::GUIDE_CCD :
2132 ISD::CameraChip::PRIMARY_CCD);
2133 targetChip->abortExposure();
2134 const double exptime = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
2135 targetChip->capture(exptime);
2136 state()->getCaptureTimeout().start(
static_cast<int>((exptime) * 1000 + CAPTURE_TIMEOUT_THRESHOLD));
2140 else if (state()->captureTimeoutCounter() < 40)
2142 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Unable to restart exposure as camera is missing, trying again in 5 seconds...";
2147 state()->setCaptureTimeoutCounter(0);
2148 state()->setDeviceRestartCounter(0);
2149 emit newLog(
i18n(
"Exposure timeout. Too many. Aborting..."));
2162 if (type == ISD::Camera::ERROR_CAPTURE)
2164 int retries = activeJob()->getCaptureRetires() + 1;
2166 activeJob()->setCaptureRetires(retries);
2168 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
2176 emit newLog(
i18n(
"Restarting capture attempt #%1", retries));
2178 state()->setNextSequenceID(1);
2195 double currentADU = imageData->getADU();
2196 bool outOfRange =
false, saturated =
false;
2198 switch (imageData->bpp())
2201 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT8_MAX)
2203 else if (currentADU / UINT8_MAX > 0.95)
2208 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT16_MAX)
2210 else if (currentADU / UINT16_MAX > 0.95)
2215 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT32_MAX)
2217 else if (currentADU / UINT32_MAX > 0.95)
2227 emit newLog(
i18n(
"Flat calibration failed. Captured image is only %1-bit while requested ADU is %2.",
2229 ,
QString::number(activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble(),
'f', 2)));
2235 double nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 0.1;
2236 nextExposure = qBound(exp_min, nextExposure, exp_max);
2238 emit newLog(
i18n(
"Current image is saturated (%1). Next exposure is %2 seconds.",
2241 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2242 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
2243 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2245 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2251 double ADUDiff = fabs(currentADU - activeJob()->getCoreProperty(
2252 SequenceJob::SJ_TargetADU).toDouble());
2255 if (ADUDiff <= state()->targetADUTolerance())
2257 if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
2260 i18n(
"Current ADU %1 within target ADU tolerance range.",
QString::number(currentADU,
'f', 0)));
2261 activeCamera()->setUploadMode(activeJob()->getUploadMode());
2262 auto placeholderPath = PlaceholderPath();
2264 placeholderPath.processJobInfo(activeJob());
2266 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
2271 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
2272 state()->checkSeqBoundary();
2278 double nextExposure = -1;
2281 if (std::fabs(imageData->getMax(0) - imageData->getMin(0)) < 10)
2282 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 0.5;
2286 if (nextExposure <= 0 || std::isnan(nextExposure))
2289 i18n(
"Unable to calculate optimal exposure settings, please capture the flats manually."));
2295 nextExposure = qBound(exp_min, nextExposure, exp_max);
2297 emit newLog(
i18n(
"Current ADU is %1 Next exposure is %2 seconds.",
QString::number(currentADU,
'f', 0),
2298 QString(
"%L1").arg(nextExposure, 0,
'f', 6)));
2300 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2301 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
2302 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2304 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2315 if (activeJob() ==
nullptr)
2317 qWarning(KSTARS_EKOS_CAPTURE) <<
"setCurrentADU with null activeJob().";
2322 double nextExposure = 0;
2323 double targetADU = activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).
toDouble();
2324 std::vector<double> coeff;
2328 if(activeJob()->getCoreProperty(SequenceJob::SJ_SkyFlat).toBool() && ExpRaw.size() > 2)
2330 int remove = ExpRaw.size() - 2;
2331 ExpRaw.remove(0, remove);
2332 ADURaw.remove(0, remove);
2336 ExpRaw.append(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
2337 ADURaw.append(currentADU);
2339 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Capture: Current ADU = " << currentADU <<
" targetADU = " << targetADU
2340 <<
" Exposure Count: " << ExpRaw.count();
2344 if (ExpRaw.count() >= 2)
2346 if (ExpRaw.count() >= 5)
2350 coeff = gsl_polynomial_fit(ADURaw.data(), ExpRaw.data(), ExpRaw.count(), 2, chisq);
2351 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Running polynomial fitting. Found " << coeff.size() <<
" coefficients.";
2352 if (std::isnan(coeff[0]) || std::isinf(coeff[0]))
2354 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coefficients are invalid.";
2355 targetADUAlgorithm = ADU_LEAST_SQUARES;
2359 nextExposure = coeff[0] + (coeff[1] * targetADU) + (coeff[2] * pow(targetADU, 2));
2361 if (nextExposure < 0 || (nextExposure > ExpRaw.last() || targetADU < ADURaw.last())
2362 || (nextExposure < ExpRaw.last() || targetADU > ADURaw.last()))
2365 targetADUAlgorithm = ADU_LEAST_SQUARES;
2369 targetADUAlgorithm = ADU_POLYNOMIAL;
2370 for (
size_t i = 0; i < coeff.size(); i++)
2371 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coeff #" << i <<
"=" << coeff[i];
2376 bool looping =
false;
2377 if (ExpRaw.count() >= 10)
2379 int size = ExpRaw.count();
2380 looping = (std::fabs(ExpRaw[size - 1] - ExpRaw[size - 2] < 0.01)) &&
2381 (std::fabs(ExpRaw[size - 2] - ExpRaw[size - 3] < 0.01));
2382 if (looping && targetADUAlgorithm == ADU_POLYNOMIAL)
2384 qWarning(KSTARS_EKOS_CAPTURE) <<
"Detected looping in polynomial results. Falling back to llsqr.";
2385 targetADUAlgorithm = ADU_LEAST_SQUARES;
2392 if (targetADUAlgorithm == ADU_LEAST_SQUARES)
2394 double a = 0, b = 0;
2395 llsq(ExpRaw, ADURaw, a, b);
2400 nextExposure = (targetADU - b) / a;
2402 if (nextExposure < 0)
2410 if (nextExposure == 0.0 || nextExposure > 180)
2412 if (currentADU < targetADU)
2413 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 1.25;
2415 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * .75;
2418 qCDebug(KSTARS_EKOS_CAPTURE) <<
"next flat exposure is" << nextExposure;
2420 return nextExposure;
2432 if (devices()->mount() && activeCamera() && devices()->mount()->isConnected())
2435 auto activeDevices = activeCamera()->
getText(
"ACTIVE_DEVICES");
2438 auto activeTelescope = activeDevices->findWidgetByName(
"ACTIVE_TELESCOPE");
2439 if (activeTelescope)
2441 activeTelescope->setText(devices()->mount()->getDeviceName().toLatin1().constData());
2453 all_devices.
append(activeCamera());
2454 if (devices()->dustCap())
2455 all_devices.
append(devices()->dustCap());
2457 for (
auto &oneDevice : all_devices)
2459 auto activeDevices = oneDevice->getText(
"ACTIVE_DEVICES");
2462 auto activeFilter = activeDevices->findWidgetByName(
"ACTIVE_FILTER");
2466 if (devices()->filterWheel())
2468 if (activeFilterText != devices()->filterWheel()->getDeviceName())
2470 activeFilter->setText(devices()->filterWheel()->getDeviceName().toLatin1().constData());
2471 oneDevice->sendNewProperty(activeDevices);
2475 else if (activeFilterText.
isEmpty())
2478 qCDebug(KSTARS_EKOS_CAPTURE) <<
"No active filter wheel. " << oneDevice->getDeviceName() <<
" ACTIVE_FILTER is reset.";
2479 activeFilter->setText(
"");
2480 oneDevice->sendNewProperty(activeDevices);
2487QString Ekos::CameraProcess::createTabTitle(
const FITSMode &captureMode,
const QString &deviceName)
2489 const bool isPreview = (activeJob() ==
nullptr || (activeJob() && activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW));
2490 if (isPreview && Options::singlePreviewFITS())
2494 if (Options::singleWindowCapturedFITS())
2495 return (
i18n(
"%1 Preview", deviceName));
2498 return(
i18n(
"Preview"));
2500 else if (captureMode == FITS_CALIBRATE)
2504 const QString filtername = activeJob()->getCoreProperty(SequenceJob::SJ_Filter).toString();
2505 if (filtername ==
"")
2508 return(
QString(
"%1 %2").arg(filtername).arg(
i18n(
"Flat Calibration")));
2511 return(
i18n(
"Calibration"));
2517 const FITSScale &captureFilter,
const QString &filename,
const QString &deviceName)
2523 switch (captureMode)
2526 case FITS_CALIBRATE:
2528 if (Options::useFITSViewer())
2531 bool success =
false;
2535 QString tabTitle = createTabTitle(captureMode, deviceName);
2538 int *tabID = &m_fitsvViewerTabIDs.normalTabID;
2539 if (*tabID == -1 || Options::singlePreviewFITS() ==
false)
2542 success = getFITSViewer()->loadData(data, fileURL, &tabIndex, captureMode, captureFilter, tabTitle);
2545 auto tabs = getFITSViewer()->tabs();
2546 if (tabIndex < tabs.size() && captureMode == FITS_NORMAL)
2548 emit newView(tabs[tabIndex]->getView());
2549 tabs[tabIndex]->disconnect(
this);
2550 connect(tabs[tabIndex].get(), &FITSTab::updated,
this, [
this]
2553 emit newView(tab->getView());
2559 success = getFITSViewer()->updateData(data, fileURL, *tabID, &tabIndex, captureMode, captureFilter, tabTitle);
2566 qCCritical(KSTARS_EKOS_CAPTURE()) <<
"error adding/updating FITS";
2570 if (Options::focusFITSOnNewImage())
2571 getFITSViewer()->raise();
2584 FITSMode captureMode = tChip ==
nullptr ? FITS_UNKNOWN : tChip->getCaptureMode();
2585 FITSScale captureFilter = tChip ==
nullptr ? FITS_NONE : tChip->getCaptureFilter();
2586 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
2592 if (m_VideoWindow.
isNull() && activeCamera() !=
nullptr)
2594 m_VideoWindow.
reset(
new StreamWG(activeCamera()));
2599 connect(activeCamera(), &ISD::Camera::videoRecordToggled, m_VideoWindow.
get(), &StreamWG::enableStream,
2605 return m_VideoWindow;
2608void CameraProcess::updateVideoWindow(
int width,
int height,
bool streamEnabled)
2612 if (width > 0 && height > 0)
2617void CameraProcess::closeVideoWindow()
2619 if (m_VideoWindow.
isNull())
2622 m_VideoWindow->close();
2625void CameraProcess::showVideoFrame(INDI::Property prop,
int width,
int height)
2636 const QString &targetName,
bool setOptions)
2638 state()->clearCapturedFramesMap();
2639 auto queue = state()->getSequenceQueue();
2640 if (!queue->load(fileURL, targetName, devices(), state()))
2642 QString message =
i18n(
"Unable to open file %1", fileURL);
2643 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
2649 queue->setOptions();
2651 state()->updateHFRThreshold();
2654 for (
auto j : state()->allJobs())
2663 state()->getSequenceQueue()->loadOptions();
2664 return state()->getSequenceQueue()->save(path, state()->observerName());
2676 connect(activeCamera(), &ISD::Camera::videoRecordToggled,
this, &CameraProcess::updateVideoRecordStatus,
2690 disconnect(activeCamera(), &ISD::Camera::ready,
this, &CameraProcess::cameraReady);
2697 if (devices()->filterWheel() && devices()->filterWheel() == device)
2700 if (devices()->filterWheel())
2701 devices()->filterWheel()->disconnect(
this);
2703 devices()->setFilterWheel(device);
2705 return (device !=
nullptr);
2712 emit newLog(
i18n(
"Sequence paused."));
2717 state()->setContinueAction(continueAction);
2727 SequenceJob * first_job =
nullptr;
2730 for (
auto &job : state()->allJobs())
2732 if (job->getStatus() == JOB_IDLE || job->getStatus() == JOB_ABORTED)
2741 if (first_job ==
nullptr)
2744 for (
auto &job : state()->allJobs())
2746 if (job->getStatus() != JOB_DONE)
2749 if (state()->getCaptureDelayTimer().isActive())
2751 if (state()->getCaptureDelayTimer().interval() <= 0)
2752 state()->getCaptureDelayTimer().setInterval(1000);
2759 if (!state()->ignoreJobProgress())
2762 i18n(
"All jobs are complete. Do you want to reset the status of all jobs and restart capturing?"),
2770 first_job = state()->allJobs().first();
2774 else if (state()->ignoreJobProgress())
2776 emit newLog(
i18n(
"Warning: option \"Always Reset Sequence When Starting\" is enabled and resets the sequence counts."));
2783void CameraProcess::resetJobStatus(JOBStatus newStatus)
2785 if (activeJob() !=
nullptr)
2787 activeJob()->resetStatus(newStatus);
2788 emit updateJobTable(activeJob());
2792void CameraProcess::resetAllJobs()
2794 for (
auto &job : state()->allJobs())
2799 m_State->clearCapturedFramesMap();
2801 emit updateJobTable(
nullptr);
2804void CameraProcess::updatedCaptureCompleted(
int count)
2806 activeJob()->setCompleted(count);
2807 emit updateJobTable(activeJob());
2810void CameraProcess::updateVideoRecordStatus(
bool enabled)
2813 if (activeJob() ==
nullptr)
2816 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Video recording" << (enabled ?
"started." :
"stopped.");
2818 if (enabled ==
false)
2820 updatedCaptureCompleted(activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt());
2847 for (i = 0; i < n; i++)
2852 xbar = xbar /
static_cast<double>(n);
2853 ybar = ybar /
static_cast<double>(n);
2859 for (i = 0; i < n; i++)
2861 top = top + (x[i] - xbar) * (y[i] - ybar);
2862 bot = bot + (x[i] - xbar) * (x[i] - xbar);
2867 b = ybar - a * xbar;
2879 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2887 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2888 return devices()->getActiveCamera()->setCoolerControl(enable);
2899 emit driverTimedout(name);
2906 KSMessageBox::Instance()->questionYesNo(
i18n(
"Are you sure you want to restart %1 camera driver?", name),
2907 i18n(
"Driver Restart"), 5);
2912 if (!activeCamera())
2915 ISD::CameraChip *tChip = devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD);
2918 if (devices()->getActiveCamera()->hasVideoStream())
2919 types.
append(CAPTURE_TYPE_VIDEO);
2926 if (devices()->getFilterManager().isNull())
2929 return devices()->getFilterManager()->getFilterLabels();
2934 if (devices()->getActiveCamera()->getProperty(
"CCD_GAIN"))
2939 ccdGain[
"GAIN"] = value;
2940 propertyMap[
"CCD_GAIN"] = ccdGain;
2944 propertyMap[
"CCD_GAIN"].remove(
"GAIN");
2945 if (propertyMap[
"CCD_GAIN"].size() == 0)
2946 propertyMap.remove(
"CCD_GAIN");
2949 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2954 ccdGain[
"Gain"] = value;
2955 propertyMap[
"CCD_CONTROLS"] = ccdGain;
2959 propertyMap[
"CCD_CONTROLS"].remove(
"Gain");
2960 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2961 propertyMap.remove(
"CCD_CONTROLS");
2968 if (devices()->getActiveCamera()->getProperty(
"CCD_OFFSET"))
2973 ccdOffset[
"OFFSET"] = value;
2974 propertyMap[
"CCD_OFFSET"] = ccdOffset;
2978 propertyMap[
"CCD_OFFSET"].remove(
"OFFSET");
2979 if (propertyMap[
"CCD_OFFSET"].size() == 0)
2980 propertyMap.remove(
"CCD_OFFSET");
2983 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2988 ccdOffset[
"Offset"] = value;
2989 propertyMap[
"CCD_CONTROLS"] = ccdOffset;
2993 propertyMap[
"CCD_CONTROLS"].remove(
"Offset");
2994 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2995 propertyMap.remove(
"CCD_CONTROLS");
3003 if (!m_FITSViewerWindow.
isNull())
3004 return m_FITSViewerWindow;
3007 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
3012 connect(m_FITSViewerWindow.
get(), &FITSViewer::closed,
this, [
this](
int tabIndex)
3014 if (tabIndex == m_fitsvViewerTabIDs.normalTabID)
3015 m_fitsvViewerTabIDs.normalTabID = -1;
3016 else if (tabIndex == m_fitsvViewerTabIDs.calibrationTabID)
3017 m_fitsvViewerTabIDs.calibrationTabID = -1;
3018 else if (tabIndex == m_fitsvViewerTabIDs.focusTabID)
3019 m_fitsvViewerTabIDs.focusTabID = -1;
3020 else if (tabIndex == m_fitsvViewerTabIDs.guideTabID)
3021 m_fitsvViewerTabIDs.guideTabID = -1;
3022 else if (tabIndex == m_fitsvViewerTabIDs.alignTabID)
3023 m_fitsvViewerTabIDs.alignTabID = -1;
3027 connect(m_FITSViewerWindow.
get(), &FITSViewer::terminated,
this, [
this]()
3029 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
3030 m_FITSViewerWindow.
clear();
3033 return m_FITSViewerWindow;
3038 return devices()->getActiveCamera();
IPState runCaptureScript(ScriptTypes scriptType, bool precond=true)
runCaptureScript Run the pre-/post capture/job script
void updateTelescopeInfo()
updateTelescopeInfo Update the scope information in the camera's INDI driver.
void processCaptureTimeout()
processCaptureTimeout If exposure timed out, let's handle it.
void setExposureProgress(ISD::CameraChip *tChip, double value, IPState state)
setExposureProgress Manage exposure progress reported by the camera device.
IPState startNextExposure()
startNextExposure Ensure that all pending preparation tasks are be completed (focusing,...
void updatePreCaptureCalibrationStatus()
updatePreCaptureCalibrationStatus This is a wrapping loop for processPreCaptureCalibrationStage(),...
void reconnectCameraDriver(const QString &camera, const QString &filterWheel)
reconnectDriver Reconnect the camera driver
IPState checkLightFramePendingTasks()
Check all tasks that might be pending before capturing may start.
void checkNextExposure()
checkNextExposure Try to start capturing the next exposure (
void clearFlatCache()
clearFlatCache Clear the measured values for flat calibrations
bool loadSequenceQueue(const QString &fileURL, const QString &targetName="", bool setOptions=true)
Loads the Ekos Sequence Queue file in the Sequence Queue.
bool setFilterWheel(ISD::FilterWheel *device)
setFilterWheel Connect to the given filter wheel device (and deconnect the old one if existing)
Q_SCRIPTABLE void resetFrame()
resetFrame Reset frame settings of the camera
bool saveSequenceQueue(const QString &path, bool loadOptions=true)
Saves the Sequence Queue to the Ekos Sequence Queue file.
QStringList generateScriptArguments() const
generateScriptArguments Generate argument list to pass to capture script
IPState previewImageCompletedAction()
previewImageCompletedAction Activities required when a preview image has been captured.
bool setCoolerControl(bool enable)
Set the CCD cooler ON/OFF.
void updateCompletedCaptureCountersAction()
updateCompletedCaptureCounters Update counters if an image has been captured
void scriptFinished(int exitCode, QProcess::ExitStatus status)
scriptFinished Slot managing the return status of pre/post capture/job scripts
void selectCamera(QString name)
setCamera select camera device
SequenceJob * findNextPendingJob()
findExecutableJob find next job to be executed
void stopCapturing(CaptureState targetState)
stopCapturing Stopping the entire capturing state (envelope for aborting, suspending,...
void updateFilterInfo()
updateFilterInfo Update the filter information in the INDI drivers of the current camera and dust cap
IPState processPreCaptureCalibrationStage()
processPreCaptureCalibrationStage Execute the tasks that need to be completed before capturing may st...
bool setCamera(ISD::Camera *device)
setCamera Connect to the given camera device (and deconnect the old one if existing)
QSharedPointer< StreamWG > getVideoWindow()
getVideoWindow Return the current video window and initialize it if required.
void checkCamera()
configureCamera Refreshes the CCD information in the capture module.
void updateGain(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getGain Update the gain value from the custom property value.
QStringList filterLabels()
filterLabels list of currently available filter labels
IPState startNextJob()
startNextJob Select the next job that is either idle or aborted and call prepareJob(*SequenceJob) to ...
bool checkPausing(CaptureContinueAction continueAction)
checkPausing check if a pause has been planned and pause subsequently
void prepareActiveJobStage2()
prepareActiveJobStage2 Reset #calibrationStage and continue with preparePreCaptureActions().
void showFITSPreview(const QSharedPointer< FITSData > &data)
showFITSPreview Directly show the FITS data as preview
void removeDevice(const QSharedPointer< ISD::GenericDevice > &device)
Generic method for removing any connected device.
IPState resumeSequence()
resumeSequence Try to continue capturing.
QStringList frameTypes()
frameTypes Retrieve the frame types from the active camera's primary chip.
void updateOffset(double value, QMap< QString, QMap< QString, QVariant > > &propertyMap)
getOffset Update the offset value from the custom property value.
void processJobCompletion2()
processJobCompletionStage2 Stop execution of the current sequence and check whether there exists a ne...
bool checkFlatCalibration(QSharedPointer< FITSData > imageData, double exp_min, double exp_max)
checkFlatCalibration check the flat calibration
IPState updateImageMetadataAction(QSharedPointer< FITSData > imageData)
updateImageMetadataAction Update meta data of a captured image
void processFITSData(const QSharedPointer< FITSData > &data, const QString &extension)
newFITS process new FITS data received from camera.
void prepareJob(SequenceJob *job)
prepareJob Update the counters of existing frames and continue with prepareActiveJob(),...
void processNewRemoteFile(QString file)
setNewRemoteFile A new image has been stored as remote file
IPState updateDownloadTimesAction()
updateDownloadTimesAction Add the current download time to the list of already measured ones
double calculateFlatExpTime(double currentADU)
calculateFlatExpTime calculate the next flat exposure time from the measured ADU value
void processCaptureError(ISD::Camera::ErrorType type)
processCaptureError Handle when image capture fails
IPState continueFramingAction(const QSharedPointer< FITSData > &imageData)
continueFramingAction If framing is running, start the next capture sequence
void syncDSLRToTargetChip(const QString &model)
syncDSLRToTargetChip Syncs INDI driver CCD_INFO property to the DSLR values.
void setDownloadProgress()
setDownloadProgress update the Capture Module and Summary Screen's estimate of how much time is left ...
void prepareJobExecution()
preparePreCaptureActions Trigger setting the filter, temperature, (if existing) the rotator angle and...
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 processJobCompletion1()
processJobCompletionStage1 Process job completion.
void captureImage()
captureImage Initiates image capture in the active job.
void restartCamera(const QString &name)
restartCamera Restarts the INDI driver associated with a camera.
bool hasCoolerControl()
Does the CCD has a cooler control (On/Off) ?
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.
This is the main window for KStars.
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()
void replace(qsizetype i, const QJsonValue &value)
void append(QList< T > &&value)
qsizetype count() const const
bool isEmpty() const const
QStatusBar * statusBar() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
T qobject_cast(QObject *object)
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
void showMessage(const QString &message, int timeout)
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.