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 "ksmessagebox.h"
26#include "fitsviewer/fitsdata.h"
27#include "fitsviewer/fitstab.h"
29#include "fitsviewer/fitsviewer.h"
31#include "ksnotification.h"
32#include <ekos_capture_debug.h>
34#ifdef HAVE_STELLARSOLVER
35#include "ekos/auxiliary/stellarsolverprofileeditor.h"
43 setObjectName(
"CameraProcess");
44 m_State = newModuleState;
45 m_DeviceAdaptor = newDeviceAdaptor;
48 connect(devices().data(), &CaptureDeviceAdaptor::newCamera,
this, &CameraProcess::selectCamera);
53 state()->downloadProgressTimer().setInterval(100);
57 m_DarkProcessor =
new DarkProcessor(
this);
58 connect(m_DarkProcessor, &DarkProcessor::newLog,
this, &CameraProcess::newLog);
59 connect(m_DarkProcessor, &DarkProcessor::darkFrameCompleted,
this, &CameraProcess::darkFrameCompleted);
64 this, &CameraProcess::scriptFinished);
68 emit newLog(m_CaptureScript.errorString());
74 emit newLog(m_CaptureScript.readAllStandardError());
79 emit newLog(m_CaptureScript.readAllStandardOutput());
85 if (devices()->mount() && devices()->mount() == device)
87 updateTelescopeInfo();
91 if (devices()->mount())
92 devices()->mount()->disconnect(state().data());
94 devices()->setMount(device);
96 if (!devices()->mount())
99 devices()->mount()->disconnect(
this);
102 updateTelescopeInfo();
109 if ((devices()->rotator() == device) && (device !=
nullptr))
113 if (devices()->mount())
115 if (devices()->rotator())
116 devices()->rotator()->disconnect(
this);
119 state()->isInitialized[CAPTURE_ACTION_ROTATOR] =
false;
123 Manager::Instance()->createRotatorController(device);
124 connect(devices().data(), &CaptureDeviceAdaptor::rotatorReverseToggled,
this, &CameraProcess::rotatorReverseToggled,
127 devices()->setRotator(device);
135 if (devices()->dustCap() && devices()->dustCap() == device)
138 devices()->setDustCap(device);
139 state()->setDustCapState(CAP_UNKNOWN);
148 if (devices()->lightBox() == device)
151 devices()->setLightBox(device);
152 state()->setLightBoxLightState(CAP_LIGHT_UNKNOWN);
159 if (devices()->dome() == device)
162 devices()->setDome(device);
169 if (devices()->getActiveCamera() == device)
174 disconnect(activeCamera(), &ISD::Camera::newImage,
this, &CameraProcess::showFITSPreview);
176 devices()->setActiveCamera(device);
179 if (state()->getCaptureTimeout().isActive() && state()->getCaptureState() ==
CAPTURE_CAPTURING)
184 connect(activeCamera(), &ISD::Camera::newImage,
this, &CameraProcess::showFITSPreview);
190void CameraProcess::toggleVideo(
bool enabled)
192 if (devices()->getActiveCamera() ==
nullptr)
195 if (devices()->getActiveCamera()->isBLOBEnabled() ==
false)
197 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
198 devices()->getActiveCamera()->setBLOBEnabled(
true);
204 devices()->getActiveCamera()->setBLOBEnabled(
true);
205 devices()->getActiveCamera()->setVideoStreamEnabled(enabled);
208 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
209 i18n(
"Image Transfer"), 15);
215 devices()->getActiveCamera()->setVideoStreamEnabled(enabled);
219void CameraProcess::toggleSequence()
221 const CaptureState capturestate = state()->getCaptureState();
228 emit newLog(
i18n(
"Sequence resumed."));
231 switch (state()->getContinueAction())
233 case CAPTURE_CONTINUE_ACTION_CAPTURE_COMPLETE:
236 case CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE:
245 startNextPendingJob();
253void CameraProcess::startNextPendingJob()
255 if (state()->allJobs().count() > 0)
257 SequenceJob *nextJob = findNextPendingJob();
258 if (nextJob !=
nullptr)
264 emit newLog(
i18n(
"No pending jobs found. Please add a job to the sequence queue."));
274void CameraProcess::jobCreated(SequenceJob *newJob)
276 if (newJob ==
nullptr)
278 emit newLog(
i18n(
"No new job created."));
282 switch (newJob->jobType())
284 case SequenceJob::JOBTYPE_BATCH:
285 startNextPendingJob();
287 case SequenceJob::JOBTYPE_PREVIEW:
288 state()->setActiveJob(newJob);
297void CameraProcess::capturePreview(
bool loop)
299 if (state()->getFocusState() >= FOCUS_PROGRESS)
301 emit newLog(
i18n(
"Cannot capture while focus module is busy."));
303 else if (activeJob() ==
nullptr)
305 if (loop && !state()->isLooping())
307 state()->setLooping(
true);
308 emit newLog(
i18n(
"Starting framing..."));
311 emit createJob(SequenceJob::JOBTYPE_PREVIEW);
316 prepareJob(activeJob());
324 state()->resetAlignmentRetries();
328 state()->getCaptureTimeout().stop();
329 state()->getCaptureDelayTimer().stop();
330 if (activeJob() !=
nullptr)
332 if (activeJob()->getStatus() == JOB_BUSY)
338 stopText =
i18n(
"CCD capture suspended");
339 resetJobStatus(JOB_BUSY);
343 stopText =
i18n(
"CCD capture complete");
344 resetJobStatus(JOB_DONE);
348 stopText = state()->isLooping() ?
i18n(
"Framing stopped") :
i18n(
"CCD capture stopped");
349 resetJobStatus(JOB_ABORTED);
353 stopText =
i18n(
"CCD capture stopped");
354 resetJobStatus(JOB_IDLE);
357 emit captureAborted(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
358 KSNotification::event(
QLatin1String(
"CaptureFailed"), stopText, KSNotification::Capture, KSNotification::Alert);
359 emit newLog(stopText);
363 checkPausing(CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE))
366 activeJob()->abort();
367 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
369 int index = state()->allJobs().indexOf(activeJob());
370 state()->changeSequenceValue(index,
"Status",
"Aborted");
371 emit updateJobTable(activeJob());
376 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
380 else if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
386 state()->allJobs().removeOne(activeJob());
388 activeJob()->deleteLater();
390 state()->setActiveJob(
nullptr);
398 state()->setCaptureState(targetState);
400 state()->setLooping(
false);
401 state()->setBusy(
false);
403 state()->getCaptureDelayTimer().stop();
405 state()->setActiveJob(
nullptr);
408 if (devices()->lightBox() && state()->lightBoxLightEnabled())
410 state()->setLightBoxLightEnabled(
false);
411 devices()->lightBox()->setLightEnabled(
false);
418 if (devices()->getActiveCamera() && devices()->getActiveChip()
419 && devices()->getActiveCamera()->isFastExposureEnabled())
420 devices()->getActiveChip()->abortExposure();
423 emit captureStopped();
426void CameraProcess::pauseCapturing()
428 if (state()->isCaptureRunning() ==
false)
433 emit newLog(
i18n(
"Pausing only possible while frame capture is running."));
434 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Pause button pressed while not capturing.";
438 state()->setContinueAction(CAPTURE_CONTINUE_ACTION_NONE);
440 emit newLog(
i18n(
"Sequence shall be paused after current exposure is complete."));
443void CameraProcess::startJob(SequenceJob *job)
445 state()->initCapturePreparation();
449void CameraProcess::prepareJob(SequenceJob * job)
451 if (activeCamera() ==
nullptr || activeCamera()->isConnected() ==
false)
453 emit newLog(
i18n(
"No camera detected. Check train configuration and connection settings."));
454 activeJob()->abort();
458 state()->setActiveJob(job);
462 if (job->jobType() == SequenceJob::JOBTYPE_PREVIEW && Options::useFITSViewer() ==
false
463 && Options::useSummaryPreview() ==
false)
469 Options::setUseFITSViewer(
true);
476 activeJob()->abort();
478 KSMessageBox::Instance()->questionYesNo(
i18n(
"No view available for previews. Enable FITS viewer?"),
479 i18n(
"Display preview"), 15);
484 if (state()->isLooping() ==
false)
485 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Preparing capture job" << job->getSignature() <<
"for execution.";
487 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
491 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
492 state()->setNextSequenceID(1);
498 QString signature = activeJob()->getSignature();
504 state()->checkSeqBoundary();
524 int count = state()->capturedFramesCount(signature);
529 for (
auto &a_job : state()->allJobs())
530 if (a_job == activeJob())
532 else if (a_job->getSignature() == activeJob()->getSignature())
533 count -= a_job->getCompleted();
536 updatedCaptureCompleted(count);
540 else if (state()->hasCapturedFramesMap())
543 updatedCaptureCompleted(0);
549 else if (state()->ignoreJobProgress()
550 && activeJob()->getJobProgressIgnored() ==
false)
552 activeJob()->setJobProgressIgnored(
true);
553 updatedCaptureCompleted(0);
558 if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
559 activeJob()->getCompleted())
561 updatedCaptureCompleted(activeJob()->getCoreProperty(
562 SequenceJob::SJ_Count).toInt());
563 emit newLog(
i18n(
"Job requires %1-second %2 images, has already %3/%4 captures and does not need to run.",
564 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
565 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
566 activeJob()->getCompleted(),
567 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
568 processJobCompletion2();
576 emit newLog(
i18n(
"Job requires %1-second %2 images, has %3/%4 frames captured and will be processed.",
577 QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(), 0,
'f', 3),
578 job->getCoreProperty(SequenceJob::SJ_Filter).
toString(),
579 activeJob()->getCompleted(),
580 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
585 activeCamera()->setNextSequenceID(state()->nextSequenceID());
589 if (activeCamera()->isBLOBEnabled() ==
false)
594 if (Options::guiderType() != Guide::GUIDE_INTERNAL)
596 activeCamera()->setBLOBEnabled(
true);
603 activeCamera()->setBLOBEnabled(
true);
604 prepareActiveJobStage1();
610 activeCamera()->setBLOBEnabled(
true);
611 state()->setBusy(
false);
614 KSMessageBox::Instance()->questionYesNo(
i18n(
"Image transfer is disabled for this camera. Would you like to enable it?"),
615 i18n(
"Image Transfer"), 15);
621 emit jobPrepared(job);
623 prepareActiveJobStage1();
627void CameraProcess::prepareActiveJobStage1()
629 if (activeJob() ==
nullptr)
631 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage1 with null activeJob().";
637 if (runCaptureScript(
SCRIPT_PRE_JOB, activeJob()->getCompleted() == 0) == IPS_BUSY)
640 prepareActiveJobStage2();
643void CameraProcess::prepareActiveJobStage2()
646 if (activeJob() ==
nullptr)
648 qWarning(KSTARS_EKOS_CAPTURE) <<
"prepareActiveJobStage2 with null activeJob().";
651 emit newImage(activeJob(), state()->imageData());
667 prepareJobExecution();
670void CameraProcess::executeJob()
672 if (activeJob() ==
nullptr)
674 qWarning(KSTARS_EKOS_CAPTURE) <<
"executeJob with null activeJob().";
679 if (!activeCamera() || !devices()->getActiveChip())
687 if (Options::defaultObserver().isEmpty() ==
false)
689 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetName) !=
"")
690 FITSHeaders.
append(
FITSData::Record(
"Object", activeJob()->getCoreProperty(SequenceJob::SJ_TargetName).toString(),
695 activeCamera()->setFITSHeaders(FITSHeaders);
698 state()->setBusy(
true);
699 state()->setUseGuideHead((devices()->getActiveChip()->getType() == ISD::CameraChip::PRIMARY_CCD) ?
702 emit syncGUIToJob(activeJob());
706 if (activeJob()->jobType() == SequenceJob::JOBTYPE_DARKFLAT)
709 if (state()->setDarkFlatExposure(activeJob())
710 && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
712 auto placeholderPath = PlaceholderPath();
714 placeholderPath.processJobInfo(activeJob());
715 state()->setNextSequenceID(1);
720 updatePreCaptureCalibrationStatus();
724void CameraProcess::prepareJobExecution()
726 if (activeJob() ==
nullptr)
728 qWarning(KSTARS_EKOS_CAPTURE) <<
"preparePreCaptureActions with null activeJob().";
733 state()->setBusy(
true);
736 activeJob()->setCoreProperty(SequenceJob::SJ_GuiderActive,
737 state()->isActivelyGuiding());
740 activeJob()->prepareCapture();
743 emit jobExecutionPreparationStarted();
746void CameraProcess::refreshOpticalTrain(
QString name)
748 state()->setOpticalTrain(name);
750 auto mount = OpticalTrainManager::Instance()->getMount(name);
753 auto scope = OpticalTrainManager::Instance()->getScope(name);
754 setScope(scope[
"name"].toString());
756 auto camera = OpticalTrainManager::Instance()->getCamera(name);
759 auto filterWheel = OpticalTrainManager::Instance()->getFilterWheel(name);
760 setFilterWheel(filterWheel);
762 auto rotator = OpticalTrainManager::Instance()->getRotator(name);
765 auto dustcap = OpticalTrainManager::Instance()->getDustCap(name);
768 auto lightbox = OpticalTrainManager::Instance()->getLightBox(name);
769 setLightBox(lightbox);
772IPState CameraProcess::checkLightFramePendingTasks()
779 if (checkPausing(CAPTURE_CONTINUE_ACTION_NEXT_EXPOSURE) ==
true)
783 if (state()->checkMeridianFlipActive())
789 state()->getGuideState() == GUIDE_GUIDING &&
790 Options::enforceStartGuiderDrift())
794 if ((state()->getCaptureState() ==
CAPTURE_DITHERING && state()->getDitheringState() != IPS_OK)
795 || state()->checkDithering())
803 if (state()->checkFocusRunning() || state()->startFocusIfRequired())
808 if (state()->getGuideState() == GUIDE_SUSPENDED && activeJob()->getFrameType() == FRAME_LIGHT)
810 emit newLog(
i18n(
"Autoguiding resumed."));
811 emit resumeGuiding();
822void CameraProcess::captureStarted(CaptureResult rc)
829 state()->getCaptureTimeout().start(
static_cast<int>(activeJob()->getCoreProperty(
830 SequenceJob::SJ_Exposure).toDouble()) * 1000 +
831 CAPTURE_TIMEOUT_THRESHOLD);
833 state()->imageCountDown().setHMS(0, 0, 0);
834 double ms_left = std::ceil(activeJob()->getExposeLeft() * 1000.0);
835 state()->imageCountDownAddMSecs(
int(ms_left));
836 state()->setLastRemainingFrameTimeMS(ms_left);
837 state()->sequenceCountDown().setHMS(0, 0, 0);
838 state()->sequenceCountDownAddMSecs(activeJob()->getJobRemainingTime(state()->averageDownloadTime()) * 1000);
841 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
843 auto index = state()->allJobs().indexOf(activeJob());
844 if (index >= 0 && index < state()->getSequence().count())
845 state()->changeSequenceValue(index,
"Status",
"In Progress");
847 emit updateJobTable(activeJob());
849 emit captureRunning();
853 case CAPTURE_FRAME_ERROR:
854 emit newLog(
i18n(
"Failed to set sub frame."));
858 case CAPTURE_BIN_ERROR:
859 emit newLog((
i18n(
"Failed to set binning.")));
863 case CAPTURE_FOCUS_ERROR:
864 emit newLog((
i18n(
"Cannot capture while focus module is busy.")));
870void CameraProcess::checkNextExposure()
872 IPState started = startNextExposure();
875 if (started == IPS_BUSY)
879IPState CameraProcess::captureImageWithDelay()
881 auto theJob = activeJob();
883 if (theJob ==
nullptr)
886 const int seqDelay = theJob->getCoreProperty(SequenceJob::SJ_Delay).toInt();
890 state()->setCaptureState(CAPTURE_WAITING);
892 state()->getCaptureDelayTimer().start(seqDelay);
896IPState CameraProcess::startNextExposure()
901 auto theJob = activeJob();
903 if (theJob ==
nullptr)
907 if (activeJob()->getFrameType() == FRAME_LIGHT)
909 IPState pending = checkLightFramePendingTasks();
910 if (pending != IPS_OK)
915 return captureImageWithDelay();
920IPState CameraProcess::resumeSequence()
923 if (checkPausing(CAPTURE_CONTINUE_ACTION_CAPTURE_COMPLETE) ==
true)
929 return startNextJob();
934 else if (activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
935 activeJob()->getCompleted())
937 processJobCompletion1();
945 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
946 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
948 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
949 emit resumeGuiding();
953 if (activeCamera()->isFastExposureEnabled())
955 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
957 state()->checkSeqBoundary();
958 activeCamera()->setNextSequenceID(state()->nextSequenceID());
968 if (activeCamera()->isFastExposureEnabled())
970 state()->setRememberFastExposure(
true);
971 activeCamera()->setFastExposureEnabled(
false);
979 if (activeCamera()->isFastExposureEnabled())
982 activeJob()->getFrameType() == FRAME_LIGHT &&
983 checkLightFramePendingTasks() == IPS_OK)
991 state()->setRememberFastExposure(
true);
992 activeCamera()->setFastExposureEnabled(
false);
1008 if (data && activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1010 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
1011 && activeJob()->getCalibrationStage() != SequenceJobState::CAL_CALIBRATION)
1013 if (state()->generateFilename(extension, &filename) && activeCamera()->saveCurrentImage(filename))
1015 data->setFilename(filename);
1021 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Saving current image failed!";
1026 KSMessageBox::Instance()->error(
i18n(
"Failed writing image to %1\nPlease check folder, filename & permissions.",
1028 i18n(
"Image Write Failed"), 30);
1043 state()->setImageData(data);
1044 blobInfo =
QString(
"{Device: %1 Property: %2 Element: %3 Chip: %4}").
arg(data->property(
"device").toString())
1045 .
arg(data->property(
"blobVector").toString())
1046 .
arg(data->property(
"blobElement").toString())
1047 .
arg(data->property(
"chip").toInt());
1050 state()->imageData().reset();
1052 const SequenceJob *job = activeJob();
1057 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring received FITS as active job is null.";
1059 emit processingFITSfinished(
false);
1063 if (state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1066 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as meridian flip stage is" <<
1067 state()->getMeridianFlipState()->getMeridianFlipStage();
1068 emit processingFITSfinished(
false);
1072 const SequenceJob::SequenceJobType currentJobType = activeJob()->jobType();
1074 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1079 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as current capture state is not active" <<
1080 state()->getCaptureState();
1082 emit processingFITSfinished(
false);
1088 tChip = activeCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>(data->property(
"chip").toInt()));
1089 if (tChip != devices()->getActiveChip())
1091 if (state()->getGuideState() == GUIDE_IDLE)
1092 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it does not correspond to the target chip"
1093 << devices()->getActiveChip()->getType();
1095 emit processingFITSfinished(
false);
1100 if (devices()->getActiveChip()->getCaptureMode() == FITS_FOCUS ||
1101 devices()->getActiveChip()->getCaptureMode() == FITS_GUIDE)
1103 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as it has the wrong capture mode" <<
1104 devices()->getActiveChip()->getCaptureMode();
1106 emit processingFITSfinished(
false);
1111 if (data && data->property(
"device").toString() != activeCamera()->getDeviceName())
1113 qCWarning(KSTARS_EKOS_CAPTURE) << blobInfo <<
"Ignoring Received FITS as the blob device name does not equal active camera"
1114 << activeCamera()->getDeviceName();
1116 emit processingFITSfinished(
false);
1120 if (currentJobType == SequenceJob::JOBTYPE_PREVIEW)
1123 if (checkSavingReceivedImage(data, extension, filename))
1125 FITSMode captureMode = tChip->getCaptureMode();
1126 FITSScale captureFilter = tChip->getCaptureFilter();
1127 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
1132 if (data && Options::autoDark() && job->jobType() == SequenceJob::JOBTYPE_PREVIEW && state()->useGuideHead() ==
false)
1134 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
1137 m_DarkProcessor.data()->denoise(trainID.
toUInt(),
1138 devices()->getActiveChip(),
1139 state()->imageData(),
1140 job->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble(),
1141 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
x(),
1142 job->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
y());
1145 qWarning(KSTARS_EKOS_CAPTURE) <<
"Invalid train ID for darks substraction:" << trainID.
toUInt();
1148 if (currentJobType == SequenceJob::JOBTYPE_PREVIEW)
1159 SequenceJob *thejob = activeJob();
1161 if (thejob ==
nullptr)
1166 if (activeCamera()->isFastExposureEnabled() ==
false && state()->isLooping() ==
false)
1168 disconnect(activeCamera(), &ISD::Camera::newExposureValue,
this,
1170 DarkLibrary::Instance()->disconnect(
this);
1174 bool alreadySaved =
false;
1175 switch (thejob->getFrameType())
1179 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1183 if (thejob->getFlatFieldDuration() == DURATION_ADU
1184 && thejob->getCoreProperty(SequenceJob::SJ_TargetADU).
toDouble() > 0)
1186 if (
checkFlatCalibration(state()->imageData(), state()->exposureRange().min, state()->exposureRange().max) ==
false)
1191 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1193 if (checkSavingReceivedImage(data, extension, filename))
1194 alreadySaved =
true;
1198 thejob->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
1206 qWarning(KSTARS_EKOS_CAPTURE) <<
"Job completed with frametype NONE!";
1213 if (thejob->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION_COMPLETE)
1214 thejob->setCalibrationStage(SequenceJobState::CAL_CAPTURING);
1216 if (activeJob() && currentJobType != SequenceJob::JOBTYPE_PREVIEW &&
1217 activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1220 if (alreadySaved || checkSavingReceivedImage(data, extension, filename))
1229 emit newImage(thejob, state()->imageData());
1236 if (currentJobType != SequenceJob::JOBTYPE_PREVIEW)
1240 emit processingFITSfinished(
true);
1245 ISD::CameraChip * tChip = activeCamera()->getChip(
static_cast<ISD::CameraChip::ChipType
>(data->property(
"chip").toInt()));
1247 updateFITSViewer(data, tChip->getCaptureMode(), tChip->getCaptureFilter(),
"", data->property(
"device").toString());
1252 emit newLog(
i18n(
"Remote image saved to %1", file));
1255 if (activeCamera() && activeCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1265 if (activeJob() ==
nullptr)
1267 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Processing pre capture calibration without active job, state = " <<
1268 getCaptureStatusString(state()->getCaptureState());
1275 if (activeJob()->getFrameType() != FRAME_LIGHT
1276 && state()->getGuideState() == GUIDE_GUIDING)
1278 emit newLog(
i18n(
"Autoguiding suspended."));
1279 emit suspendGuiding();
1283 switch (activeJob()->getFrameType())
1305 if (state()->isBusy() ==
false)
1307 emit newLog(
i18n(
"Warning: Calibration process was prematurely terminated."));
1313 if (rc == IPS_ALERT)
1315 else if (rc == IPS_BUSY)
1321 captureImageWithDelay();
1326 if (activeJob() ==
nullptr)
1328 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage1 with null activeJob().";
1342 if (activeJob() ==
nullptr)
1344 qWarning(KSTARS_EKOS_CAPTURE) <<
"procesJobCompletionStage2 with null activeJob().";
1348 activeJob()->done();
1350 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1352 int index = state()->allJobs().indexOf(activeJob());
1353 QJsonArray seqArray = state()->getSequence();
1354 QJsonObject oneSequence = seqArray[index].toObject();
1355 oneSequence[
"Status"] =
"Complete";
1356 seqArray.
replace(index, oneSequence);
1357 state()->setSequence(seqArray);
1358 emit sequenceChanged(seqArray);
1359 emit updateJobTable(activeJob());
1373 KSNotification::event(
QLatin1String(
"CaptureSuccessful"),
i18n(
"CCD capture sequence completed"),
1374 KSNotification::Capture);
1380 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1381 emit resumeGuiding();
1388 SequenceJob * next_job =
nullptr;
1390 for (
auto &oneJob : state()->allJobs())
1392 if (oneJob->getStatus() == JOB_IDLE || oneJob->getStatus() == JOB_ABORTED)
1406 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload() &&
1407 state()->getMeridianFlipState()->checkMeridianFlipActive() ==
false)
1409 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Resuming guiding...";
1410 emit resumeGuiding();
1417 qCDebug(KSTARS_EKOS_CAPTURE) <<
"All capture jobs complete.";
1424 if (activeJob() ==
nullptr)
1428 if (!activeCamera() || !activeCamera()->isConnected())
1430 emit newLog(
i18n(
"Error: Lost connection to CCD."));
1435 state()->getCaptureTimeout().stop();
1436 state()->getCaptureDelayTimer().stop();
1437 if (activeCamera()->isFastExposureEnabled())
1439 int remaining = state()->isLooping() ? 100000 : (activeJob()->getCoreProperty(
1440 SequenceJob::SJ_Count).
toInt() -
1441 activeJob()->getCompleted());
1443 activeCamera()->setFastCount(
static_cast<uint
>(remaining));
1448 if (activeJob()->getFrameType() == FRAME_FLAT)
1451 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW
1452 && activeJob()->getFlatFieldDuration() == DURATION_ADU &&
1453 activeJob()->getCalibrationStage() == SequenceJobState::CAL_NONE)
1455 if (activeCamera()->getEncodingFormat() !=
"FITS" &&
1456 activeCamera()->getEncodingFormat() !=
"XISF")
1458 emit newLog(
i18n(
"Cannot calculate ADU levels in non-FITS images."));
1463 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
1468 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1470 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1471 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
1476 if (activeCamera()->getUploadMode() != activeJob()->getUploadMode())
1477 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1480 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
1482 state()->checkSeqBoundary();
1483 activeCamera()->setNextSequenceID(state()->nextSequenceID());
1487 if (state()->isRememberFastExposure())
1489 state()->setRememberFastExposure(
false);
1490 activeCamera()->setFastExposureEnabled(
true);
1493 if (state()->frameSettings().contains(devices()->getActiveChip()))
1495 const auto roi = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect();
1496 QVariantMap settings;
1497 settings[
"x"] = roi.x();
1498 settings[
"y"] = roi.y();
1499 settings[
"w"] = roi.width();
1500 settings[
"h"] = roi.height();
1501 settings[
"binx"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
x();
1502 settings[
"biny"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
y();
1504 state()->frameSettings()[devices()->getActiveChip()] = settings;
1508 activeCamera()->setEncodingFormat(activeJob()->getCoreProperty(
1509 SequenceJob::SJ_Encoding).toString());
1511 state()->setStartingCapture(
true);
1512 state()->placeholderPath().setGenerateFilenameSettings(*activeJob());
1515 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
1517 auto remoteUpload = state()->placeholderPath().generateSequenceFilename(*activeJob(),
false,
true, 1,
"",
"",
false,
1521 auto remoteDirectory = remoteUpload.mid(0, lastSeparator);
1522 auto remoteFilename = remoteUpload.mid(lastSeparator + 1);
1523 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatDirectory, remoteDirectory);
1524 activeJob()->setCoreProperty(SequenceJob::SJ_RemoteFormatFilename, remoteFilename);
1530 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(),
1531 activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION ? FITS_CALIBRATE :
1535 if (state()->isRememberFastExposure())
1537 state()->setRememberFastExposure(
false);
1538 activeCamera()->setFastExposureEnabled(
true);
1541 emit captureTarget(activeJob()->getCoreProperty(SequenceJob::SJ_TargetName).toString());
1542 emit captureImageStarted();
1547 devices()->setActiveChip(state()->useGuideHead() ?
1548 devices()->getActiveCamera()->getChip(
1549 ISD::CameraChip::GUIDE_CCD) :
1550 devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1551 devices()->getActiveChip()->resetFrame();
1552 emit updateFrameProperties(1);
1558 if (state()->checkCapturing() ==
false)
1561 if (devices()->getActiveChip() != tChip ||
1562 devices()->getActiveChip()->getCaptureMode() != FITS_NORMAL
1563 || state()->getMeridianFlipState()->getMeridianFlipStage() >= MeridianFlipState::MF_ALIGNING)
1566 double deltaMS = std::ceil(1000.0 * value - state()->lastRemainingFrameTimeMS());
1567 emit updateCaptureCountDown(
int(deltaMS));
1568 state()->setLastRemainingFrameTimeMS(state()->lastRemainingFrameTimeMS() + deltaMS);
1572 activeJob()->setExposeLeft(value);
1574 emit newExposureProgress(activeJob());
1577 if (activeJob() && ipstate == IPS_ALERT)
1579 int retries = activeJob()->getCaptureRetires() + 1;
1581 activeJob()->setCaptureRetires(retries);
1583 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
1587 activeJob()->abort();
1591 emit newLog((
i18n(
"Restarting capture attempt #%1", retries)));
1593 state()->setNextSequenceID(1);
1599 if (activeJob() !=
nullptr && ipstate == IPS_OK)
1601 activeJob()->setCaptureRetires(0);
1602 activeJob()->setExposeLeft(0);
1604 if (devices()->getActiveCamera()
1605 && devices()->getActiveCamera()->getUploadMode() == ISD::Camera::UPLOAD_LOCAL)
1607 if (activeJob()->getStatus() == JOB_BUSY)
1609 emit processingFITSfinished(
false);
1614 if (state()->getGuideState() == GUIDE_GUIDING && Options::guiderType() == 0
1615 && state()->suspendGuidingOnDownload())
1617 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Autoguiding suspended until primary CCD chip completes downloading...";
1618 emit suspendGuiding();
1621 emit downloadingFrame();
1624 state()->downloadTimer().start();
1625 state()->downloadProgressTimer().start();
1633 double downloadTimeLeft = state()->averageDownloadTime() - state()->downloadTimer().elapsed() /
1635 if(downloadTimeLeft >= 0)
1637 state()->imageCountDown().setHMS(0, 0, 0);
1638 state()->imageCountDownAddMSecs(
int(std::ceil(downloadTimeLeft * 1000)));
1639 emit newDownloadProgress(downloadTimeLeft);
1647 emit newImage(activeJob(), imageData);
1649 if (activeCamera()->isFastExposureEnabled() ==
false)
1651 const int seqDelay = activeJob()->getCoreProperty(SequenceJob::SJ_Delay).
toInt();
1657 if (activeJob() !=
nullptr)
1658 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1661 else if (activeJob() !=
nullptr)
1662 activeJob()->startCapturing(state()->getRefocusState()->isAutoFocusReady(), FITS_NORMAL);
1672 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL
1673 && state()->downloadTimer().isValid())
1676 double currentDownloadTime = state()->downloadTimer().elapsed() / 1000.0;
1677 state()->addDownloadTime(currentDownloadTime);
1679 state()->downloadTimer().invalidate();
1683 emit newLog(
i18n(
"Download Time: %1 s, New Download Time Estimate: %2 s.", dLTimeString, estimatedTimeString));
1690 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
1693 activeCamera()->setUploadMode(activeJob()->getUploadMode());
1695 state()->setActiveJob(
nullptr);
1697 if (state()->getGuideState() == GUIDE_SUSPENDED && state()->suspendGuidingOnDownload())
1698 emit resumeGuiding();
1709 state()->getCaptureTimeout().stop();
1710 state()->setCaptureTimeoutCounter(0);
1712 state()->downloadProgressTimer().stop();
1715 if (state()->isLooping())
1729 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW
1730 || activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
1734 updatedCaptureCompleted(activeJob()->getCompleted() + 1);
1736 state()->getRefocusState()->decreaseInSequenceFocusCounter();
1738 state()->getRefocusState()->setAdaptiveFocusDone(
false);
1742 if (state()->getMeridianFlipState()->getMeridianFlipStage() < MeridianFlipState::MF_FLIPPING)
1743 state()->decreaseDitherCounter();
1746 state()->addCapturedFrame(activeJob()->getSignature());
1749 emit newLog(
i18n(
"Received image %1 out of %2.", activeJob()->getCompleted(),
1750 activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt()));
1755 double hfr = -1, eccentricity = -1;
1756 int numStars = -1, median = -1;
1761 if (Options::autoHFR() && imageData && !imageData->areStarsSearched() && imageData->getRecordValue(
"FRAME", frameType)
1762 && frameType.
toString() ==
"Light")
1764#ifdef HAVE_STELLARSOLVER
1767 QVariantMap extractionSettings;
1768 extractionSettings[
"optionsProfileIndex"] = Options::hFROptionsProfile();
1769 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::HFRProfiles);
1770 imageData->setSourceExtractorSettings(extractionSettings);
1775 hfr = imageData->getHFR(HFR_AVERAGE);
1776 numStars = imageData->getSkyBackground().starsDetected;
1777 median = imageData->getMedian();
1778 eccentricity = imageData->getEccentricity();
1779 filename = imageData->filename();
1782 if (state()->isLooping() ==
false && activeJob() !=
nullptr && activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
1783 emit newLog(
i18n(
"Captured %1", filename));
1785 auto remainingPlaceholders = PlaceholderPath::remainingPlaceholders(filename);
1786 if (remainingPlaceholders.size() > 0)
1789 i18n(
"WARNING: remaining and potentially unknown placeholders %1 in %2",
1790 remainingPlaceholders.join(
", "), filename));
1796 QVariantMap metadata;
1797 metadata[
"filename"] = filename;
1798 metadata[
"type"] = activeJob()->getFrameType();
1799 metadata[
"exposure"] = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
1800 metadata[
"filter"] = activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString();
1801 metadata[
"width"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
width();
1802 metadata[
"height"] = activeJob()->getCoreProperty(SequenceJob::SJ_ROI).
toRect().
height();
1803 metadata[
"binx"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
x();
1804 metadata[
"biny"] = activeJob()->getCoreProperty(SequenceJob::SJ_Binning).
toPoint().
y();
1805 metadata[
"hfr"] = hfr;
1806 metadata[
"starCount"] = numStars;
1807 metadata[
"median"] = median;
1808 metadata[
"eccentricity"] = eccentricity;
1809 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Captured frame metadata: filename =" << filename <<
", type =" << metadata[
"type"].toInt()
1810 <<
"exposure =" << metadata[
"exposure"].toDouble() <<
"filter =" << metadata[
"filter"].toString() <<
"width =" <<
1811 metadata[
"width"].toInt() <<
"height =" << metadata[
"height"].toInt() <<
"hfr =" << metadata[
"hfr"].toDouble() <<
1812 "starCount =" << metadata[
"starCount"].toInt() <<
"median =" << metadata[
"median"].toInt() <<
"eccentricity =" <<
1813 metadata[
"eccentricity"].toDouble();
1815 emit captureComplete(metadata);
1824 const QString captureScript = activeJob()->getScript(scriptType);
1825 if (captureScript.
isEmpty() ==
false && precond)
1827 state()->setCaptureScriptType(scriptType);
1830 emit newLog(
i18n(
"Executing capture script %1", captureScript));
1842 switch (state()->captureScriptType())
1845 emit newLog(
i18n(
"Pre capture script finished with code %1.", exitCode));
1846 if (activeJob() && activeJob()->getStatus() == JOB_IDLE)
1853 emit newLog(
i18n(
"Post capture script finished with code %1.", exitCode));
1856 if (activeJob() ==
nullptr
1857 || activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt() <=
1858 activeJob()->getCompleted())
1863 else if (state()->checkMeridianFlipReady())
1865 emit newLog(
i18n(
"Processing meridian flip..."));
1875 emit newLog(
i18n(
"Pre job script finished with code %1.", exitCode));
1880 emit newLog(
i18n(
"Post job script finished with code %1.", exitCode));
1894 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
1895 if (activeCamera() && trainID.
isValid())
1898 if (devices()->filterWheel())
1900 if (activeCamera() && activeCamera()->getDeviceName() == name)
1903 emit refreshCamera(
true);
1906 emit refreshCamera(
false);
1917 if (!activeCamera())
1923 devices()->setActiveChip(
nullptr);
1926 if (activeCamera()->getDeviceName().contains(
"Guider"))
1928 state()->setUseGuideHead(
true);
1929 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::GUIDE_CCD));
1932 if (devices()->getActiveChip() ==
nullptr)
1934 state()->setUseGuideHead(
false);
1935 devices()->setActiveChip(activeCamera()->getChip(ISD::CameraChip::PRIMARY_CCD));
1938 emit refreshCameraSettings();
1943 auto pos = std::find_if(state()->DSLRInfos().begin(),
1946 return (oneDSLRInfo[
"Model"] == model);
1950 if (pos != state()->DSLRInfos().end())
1953 devices()->getActiveChip()->setImageInfo(camera[
"Width"].toInt(),
1954 camera[
"Height"].toInt(),
1955 camera[
"PixelW"].toDouble(),
1956 camera[
"PixelH"].toDouble(),
1963 if (activeCamera() && activeCamera()->getDeviceName() == camera)
1966 auto rememberState = state()->getCaptureState();
1969 state()->setCaptureState(rememberState);
1972 state()->setCaptureTimeoutCounter(0);
1976 devices()->setActiveChip(devices()->getActiveChip());
1990 auto name = device->getDeviceName();
1991 device->disconnect(
this);
1994 if (devices()->mount() && devices()->mount()->getDeviceName() == device->getDeviceName())
1996 devices()->mount()->disconnect(
this);
1997 devices()->setMount(
nullptr);
1998 if (activeJob() !=
nullptr)
1999 activeJob()->addMount(
nullptr);
2003 if (devices()->dome() && devices()->dome()->getDeviceName() == device->getDeviceName())
2005 devices()->dome()->disconnect(
this);
2006 devices()->setDome(
nullptr);
2010 if (devices()->rotator() && devices()->rotator()->getDeviceName() == device->getDeviceName())
2012 devices()->rotator()->disconnect(
this);
2013 devices()->setRotator(
nullptr);
2017 if (devices()->dustCap() && devices()->dustCap()->getDeviceName() == device->getDeviceName())
2019 devices()->dustCap()->disconnect(
this);
2020 devices()->setDustCap(
nullptr);
2021 state()->hasDustCap =
false;
2022 state()->setDustCapState(CAP_UNKNOWN);
2026 if (devices()->lightBox() && devices()->lightBox()->getDeviceName() == device->getDeviceName())
2028 devices()->lightBox()->disconnect(
this);
2029 devices()->setLightBox(
nullptr);
2030 state()->hasLightBox =
false;
2031 state()->setLightBoxLightState(CAP_LIGHT_UNKNOWN);
2035 if (activeCamera() && activeCamera()->getDeviceName() == name)
2038 devices()->setActiveCamera(
nullptr);
2039 devices()->setActiveChip(
nullptr);
2042 if (INDIListener::findDevice(name, generic))
2043 DarkLibrary::Instance()->removeDevice(generic);
2052 if (devices()->filterWheel() && devices()->filterWheel()->getDeviceName() == name)
2054 devices()->filterWheel()->disconnect(
this);
2055 devices()->setFilterWheel(
nullptr);
2059 emit refreshFilterSettings();
2066 state()->setCaptureTimeoutCounter(state()->captureTimeoutCounter() + 1);
2068 if (state()->deviceRestartCounter() >= 3)
2070 state()->setCaptureTimeoutCounter(0);
2071 state()->setDeviceRestartCounter(0);
2072 emit newLog(
i18n(
"Exposure timeout. Aborting..."));
2077 if (state()->captureTimeoutCounter() > 3 && activeCamera())
2079 emit newLog(
i18n(
"Exposure timeout. More than 3 have been detected, will restart driver."));
2080 QString camera = activeCamera()->getDeviceName();
2081 QString fw = (devices()->filterWheel() !=
nullptr) ?
2082 devices()->filterWheel()->getDeviceName() :
"";
2083 emit driverTimedout(camera);
2086 state()->setDeviceRestartCounter(state()->deviceRestartCounter() + 1);
2094 if (activeCamera() && activeJob())
2097 emit newLog(
i18n(
"Exposure timeout. Restarting exposure..."));
2098 activeCamera()->setEncodingFormat(
"FITS");
2099 auto rememberState = state()->getCaptureState();
2102 state()->setCaptureState(rememberState);
2104 auto targetChip = activeCamera()->getChip(state()->useGuideHead() ?
2105 ISD::CameraChip::GUIDE_CCD :
2106 ISD::CameraChip::PRIMARY_CCD);
2107 targetChip->abortExposure();
2108 const double exptime = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble();
2109 targetChip->capture(exptime);
2110 state()->getCaptureTimeout().start(
static_cast<int>((exptime) * 1000 + CAPTURE_TIMEOUT_THRESHOLD));
2114 else if (state()->captureTimeoutCounter() < 40)
2116 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Unable to restart exposure as camera is missing, trying again in 5 seconds...";
2121 state()->setCaptureTimeoutCounter(0);
2122 state()->setDeviceRestartCounter(0);
2123 emit newLog(
i18n(
"Exposure timeout. Too many. Aborting..."));
2136 if (type == ISD::Camera::ERROR_CAPTURE)
2138 int retries = activeJob()->getCaptureRetires() + 1;
2140 activeJob()->setCaptureRetires(retries);
2142 emit newLog(
i18n(
"Capture failed. Check INDI Control Panel for details."));
2150 emit newLog(
i18n(
"Restarting capture attempt #%1", retries));
2152 state()->setNextSequenceID(1);
2169 double currentADU = imageData->getADU();
2170 bool outOfRange =
false, saturated =
false;
2172 switch (imageData->bpp())
2175 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT8_MAX)
2177 else if (currentADU / UINT8_MAX > 0.95)
2182 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT16_MAX)
2184 else if (currentADU / UINT16_MAX > 0.95)
2189 if (activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble() > UINT32_MAX)
2191 else if (currentADU / UINT32_MAX > 0.95)
2201 emit newLog(
i18n(
"Flat calibration failed. Captured image is only %1-bit while requested ADU is %2.",
2203 ,
QString::number(activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).toDouble(),
'f', 2)));
2209 double nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 0.1;
2210 nextExposure = qBound(exp_min, nextExposure, exp_max);
2212 emit newLog(
i18n(
"Current image is saturated (%1). Next exposure is %2 seconds.",
2215 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2216 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
2217 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2219 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2225 double ADUDiff = fabs(currentADU - activeJob()->getCoreProperty(
2226 SequenceJob::SJ_TargetADU).toDouble());
2229 if (ADUDiff <= state()->targetADUTolerance())
2231 if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
2234 i18n(
"Current ADU %1 within target ADU tolerance range.",
QString::number(currentADU,
'f', 0)));
2235 activeCamera()->setUploadMode(activeJob()->getUploadMode());
2236 auto placeholderPath = PlaceholderPath();
2238 placeholderPath.processJobInfo(activeJob());
2240 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION_COMPLETE);
2245 if (activeCamera() && activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
2246 state()->checkSeqBoundary();
2252 double nextExposure = -1;
2255 if (std::fabs(imageData->getMax(0) - imageData->getMin(0)) < 10)
2256 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 0.5;
2260 if (nextExposure <= 0 || std::isnan(nextExposure))
2263 i18n(
"Unable to calculate optimal exposure settings, please capture the flats manually."));
2269 nextExposure = qBound(exp_min, nextExposure, exp_max);
2271 emit newLog(
i18n(
"Current ADU is %1 Next exposure is %2 seconds.",
QString::number(currentADU,
'f', 0),
2272 QString(
"%L1").arg(nextExposure, 0,
'f', 6)));
2274 activeJob()->setCalibrationStage(SequenceJobState::CAL_CALIBRATION);
2275 activeJob()->setCoreProperty(SequenceJob::SJ_Exposure, nextExposure);
2276 if (activeCamera()->getUploadMode() != ISD::Camera::UPLOAD_CLIENT)
2278 activeCamera()->setUploadMode(ISD::Camera::UPLOAD_CLIENT);
2289 if (activeJob() ==
nullptr)
2291 qWarning(KSTARS_EKOS_CAPTURE) <<
"setCurrentADU with null activeJob().";
2296 double nextExposure = 0;
2297 double targetADU = activeJob()->getCoreProperty(SequenceJob::SJ_TargetADU).
toDouble();
2298 std::vector<double> coeff;
2302 if(activeJob()->getCoreProperty(SequenceJob::SJ_SkyFlat).toBool() && ExpRaw.size() > 2)
2304 int remove = ExpRaw.size() - 2;
2305 ExpRaw.remove(0, remove);
2306 ADURaw.remove(0, remove);
2310 ExpRaw.append(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
2311 ADURaw.append(currentADU);
2313 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Capture: Current ADU = " << currentADU <<
" targetADU = " << targetADU
2314 <<
" Exposure Count: " << ExpRaw.count();
2318 if (ExpRaw.count() >= 2)
2320 if (ExpRaw.count() >= 5)
2324 coeff = gsl_polynomial_fit(ADURaw.data(), ExpRaw.data(), ExpRaw.count(), 2, chisq);
2325 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Running polynomial fitting. Found " << coeff.size() <<
" coefficients.";
2326 if (std::isnan(coeff[0]) || std::isinf(coeff[0]))
2328 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coefficients are invalid.";
2329 targetADUAlgorithm = ADU_LEAST_SQUARES;
2333 nextExposure = coeff[0] + (coeff[1] * targetADU) + (coeff[2] * pow(targetADU, 2));
2335 if (nextExposure < 0 || (nextExposure > ExpRaw.last() || targetADU < ADURaw.last())
2336 || (nextExposure < ExpRaw.last() || targetADU > ADURaw.last()))
2339 targetADUAlgorithm = ADU_LEAST_SQUARES;
2343 targetADUAlgorithm = ADU_POLYNOMIAL;
2344 for (
size_t i = 0; i < coeff.size(); i++)
2345 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Coeff #" << i <<
"=" << coeff[i];
2350 bool looping =
false;
2351 if (ExpRaw.count() >= 10)
2353 int size = ExpRaw.count();
2354 looping = (std::fabs(ExpRaw[size - 1] - ExpRaw[size - 2] < 0.01)) &&
2355 (std::fabs(ExpRaw[size - 2] - ExpRaw[size - 3] < 0.01));
2356 if (looping && targetADUAlgorithm == ADU_POLYNOMIAL)
2358 qWarning(KSTARS_EKOS_CAPTURE) <<
"Detected looping in polynomial results. Falling back to llsqr.";
2359 targetADUAlgorithm = ADU_LEAST_SQUARES;
2366 if (targetADUAlgorithm == ADU_LEAST_SQUARES)
2368 double a = 0, b = 0;
2369 llsq(ExpRaw, ADURaw, a, b);
2374 nextExposure = (targetADU - b) / a;
2376 if (nextExposure < 0)
2384 if (nextExposure == 0.0 || nextExposure > 180)
2386 if (currentADU < targetADU)
2387 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * 1.25;
2389 nextExposure = activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).
toDouble() * .75;
2392 qCDebug(KSTARS_EKOS_CAPTURE) <<
"next flat exposure is" << nextExposure;
2394 return nextExposure;
2406 if (devices()->mount() && activeCamera() && devices()->mount()->isConnected())
2409 auto activeDevices = activeCamera()->
getText(
"ACTIVE_DEVICES");
2412 auto activeTelescope = activeDevices->findWidgetByName(
"ACTIVE_TELESCOPE");
2413 if (activeTelescope)
2415 activeTelescope->setText(devices()->mount()->getDeviceName().toLatin1().constData());
2427 all_devices.
append(activeCamera());
2428 if (devices()->dustCap())
2429 all_devices.
append(devices()->dustCap());
2431 for (
auto &oneDevice : all_devices)
2433 auto activeDevices = oneDevice->getText(
"ACTIVE_DEVICES");
2436 auto activeFilter = activeDevices->findWidgetByName(
"ACTIVE_FILTER");
2440 if (devices()->filterWheel())
2442 if (activeFilterText != devices()->filterWheel()->getDeviceName())
2444 activeFilter->setText(devices()->filterWheel()->getDeviceName().toLatin1().constData());
2445 oneDevice->sendNewProperty(activeDevices);
2449 else if (activeFilterText.
isEmpty())
2452 qCDebug(KSTARS_EKOS_CAPTURE) <<
"No active filter wheel. " << oneDevice->getDeviceName() <<
" ACTIVE_FILTER is reset.";
2453 activeFilter->setText(
"");
2454 oneDevice->sendNewProperty(activeDevices);
2461QString Ekos::CameraProcess::createTabTitle(
const FITSMode &captureMode,
const QString &deviceName)
2463 const bool isPreview = (activeJob() ==
nullptr || (activeJob() && activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW));
2464 if (isPreview && Options::singlePreviewFITS())
2468 if (Options::singleWindowCapturedFITS())
2469 return (
i18n(
"%1 Preview", deviceName));
2472 return(
i18n(
"Preview"));
2474 else if (captureMode == FITS_CALIBRATE)
2478 const QString filtername = activeJob()->getCoreProperty(SequenceJob::SJ_Filter).toString();
2479 if (filtername ==
"")
2482 return(
QString(
"%1 %2").arg(filtername).arg(
i18n(
"Flat Calibration")));
2485 return(
i18n(
"Calibration"));
2491 const FITSScale &captureFilter,
const QString &filename,
const QString &deviceName)
2497 switch (captureMode)
2500 case FITS_CALIBRATE:
2502 if (Options::useFITSViewer())
2505 bool success =
false;
2509 QString tabTitle = createTabTitle(captureMode, deviceName);
2512 int *tabID = &m_fitsvViewerTabIDs.normalTabID;
2513 if (*tabID == -1 || Options::singlePreviewFITS() ==
false)
2516 success = getFITSViewer()->loadData(data, fileURL, &tabIndex, captureMode, captureFilter, tabTitle);
2519 auto tabs = getFITSViewer()->tabs();
2520 if (tabIndex < tabs.size() && captureMode == FITS_NORMAL)
2522 emit newView(tabs[tabIndex]->getView());
2523 tabs[tabIndex]->disconnect(
this);
2524 connect(tabs[tabIndex].get(), &FITSTab::updated,
this, [
this]
2527 emit newView(tab->getView());
2533 success = getFITSViewer()->updateData(data, fileURL, *tabID, &tabIndex, captureMode, captureFilter, tabTitle);
2540 qCCritical(KSTARS_EKOS_CAPTURE()) <<
"error adding/updating FITS";
2544 if (Options::focusFITSOnNewImage())
2545 getFITSViewer()->raise();
2558 FITSMode captureMode = tChip ==
nullptr ? FITS_UNKNOWN : tChip->getCaptureMode();
2559 FITSScale captureFilter = tChip ==
nullptr ? FITS_NONE : tChip->getCaptureFilter();
2560 updateFITSViewer(data, captureMode, captureFilter, filename, data->property(
"device").toString());
2564 const QString &targetName,
bool setOptions)
2566 state()->clearCapturedFramesMap();
2567 auto queue = state()->getSequenceQueue();
2568 if (!queue->load(fileURL, targetName, devices(), state()))
2570 QString message =
i18n(
"Unable to open file %1", fileURL);
2571 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
2577 queue->setOptions();
2579 state()->updateHFRThreshold();
2582 for (
auto j : state()->allJobs())
2591 state()->getSequenceQueue()->loadOptions();
2592 return state()->getSequenceQueue()->save(path, state()->observerName());
2616 disconnect(activeCamera(), &ISD::Camera::ready,
this, &CameraProcess::cameraReady);
2623 if (devices()->filterWheel() && devices()->filterWheel() == device)
2626 if (devices()->filterWheel())
2627 devices()->filterWheel()->disconnect(
this);
2629 devices()->setFilterWheel(device);
2631 return (device !=
nullptr);
2638 emit newLog(
i18n(
"Sequence paused."));
2643 state()->setContinueAction(continueAction);
2653 SequenceJob * first_job =
nullptr;
2656 for (
auto &job : state()->allJobs())
2658 if (job->getStatus() == JOB_IDLE || job->getStatus() == JOB_ABORTED)
2667 if (first_job ==
nullptr)
2670 for (
auto &job : state()->allJobs())
2672 if (job->getStatus() != JOB_DONE)
2675 if (state()->getCaptureDelayTimer().isActive())
2677 if (state()->getCaptureDelayTimer().interval() <= 0)
2678 state()->getCaptureDelayTimer().setInterval(1000);
2685 if (!state()->ignoreJobProgress())
2688 i18n(
"All jobs are complete. Do you want to reset the status of all jobs and restart capturing?"),
2696 first_job = state()->allJobs().first();
2700 else if (state()->ignoreJobProgress())
2702 emit newLog(
i18n(
"Warning: option \"Always Reset Sequence When Starting\" is enabled and resets the sequence counts."));
2709void CameraProcess::resetJobStatus(JOBStatus newStatus)
2711 if (activeJob() !=
nullptr)
2713 activeJob()->resetStatus(newStatus);
2714 emit updateJobTable(activeJob());
2718void CameraProcess::resetAllJobs()
2720 for (
auto &job : state()->allJobs())
2725 m_State->clearCapturedFramesMap();
2727 emit updateJobTable(
nullptr);
2730void CameraProcess::updatedCaptureCompleted(
int count)
2732 activeJob()->setCompleted(count);
2733 emit updateJobTable(activeJob());
2758 for (i = 0; i < n; i++)
2763 xbar = xbar /
static_cast<double>(n);
2764 ybar = ybar /
static_cast<double>(n);
2770 for (i = 0; i < n; i++)
2772 top = top + (x[i] - xbar) * (y[i] - ybar);
2773 bot = bot + (x[i] - xbar) * (x[i] - xbar);
2778 b = ybar - a * xbar;
2790 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2798 if (devices()->getActiveCamera() && devices()->getActiveCamera()->
hasCoolerControl())
2799 return devices()->getActiveCamera()->setCoolerControl(enable);
2810 emit driverTimedout(name);
2817 KSMessageBox::Instance()->questionYesNo(
i18n(
"Are you sure you want to restart %1 camera driver?", name),
2818 i18n(
"Driver Restart"), 5);
2823 if (!activeCamera())
2826 ISD::CameraChip *tChip = devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD);
2828 return tChip->getFrameTypes();
2833 if (devices()->getFilterManager().isNull())
2836 return devices()->getFilterManager()->getFilterLabels();
2841 if (devices()->getActiveCamera()->getProperty(
"CCD_GAIN"))
2846 ccdGain[
"GAIN"] = value;
2847 propertyMap[
"CCD_GAIN"] = ccdGain;
2851 propertyMap[
"CCD_GAIN"].remove(
"GAIN");
2852 if (propertyMap[
"CCD_GAIN"].size() == 0)
2853 propertyMap.remove(
"CCD_GAIN");
2856 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2861 ccdGain[
"Gain"] = value;
2862 propertyMap[
"CCD_CONTROLS"] = ccdGain;
2866 propertyMap[
"CCD_CONTROLS"].remove(
"Gain");
2867 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2868 propertyMap.remove(
"CCD_CONTROLS");
2875 if (devices()->getActiveCamera()->getProperty(
"CCD_OFFSET"))
2880 ccdOffset[
"OFFSET"] = value;
2881 propertyMap[
"CCD_OFFSET"] = ccdOffset;
2885 propertyMap[
"CCD_OFFSET"].remove(
"OFFSET");
2886 if (propertyMap[
"CCD_OFFSET"].size() == 0)
2887 propertyMap.remove(
"CCD_OFFSET");
2890 else if (devices()->getActiveCamera()->getProperty(
"CCD_CONTROLS"))
2895 ccdOffset[
"Offset"] = value;
2896 propertyMap[
"CCD_CONTROLS"] = ccdOffset;
2900 propertyMap[
"CCD_CONTROLS"].remove(
"Offset");
2901 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
2902 propertyMap.remove(
"CCD_CONTROLS");
2910 if (!m_FITSViewerWindow.
isNull() && ! m_FITSViewerWindow.
isNull())
2911 return m_FITSViewerWindow;
2914 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
2919 connect(m_FITSViewerWindow.
get(), &FITSViewer::closed,
this, [
this](
int tabIndex)
2921 if (tabIndex == m_fitsvViewerTabIDs.normalTabID)
2922 m_fitsvViewerTabIDs.normalTabID = -1;
2923 else if (tabIndex == m_fitsvViewerTabIDs.calibrationTabID)
2924 m_fitsvViewerTabIDs.calibrationTabID = -1;
2925 else if (tabIndex == m_fitsvViewerTabIDs.focusTabID)
2926 m_fitsvViewerTabIDs.focusTabID = -1;
2927 else if (tabIndex == m_fitsvViewerTabIDs.guideTabID)
2928 m_fitsvViewerTabIDs.guideTabID = -1;
2929 else if (tabIndex == m_fitsvViewerTabIDs.alignTabID)
2930 m_fitsvViewerTabIDs.alignTabID = -1;
2934 connect(m_FITSViewerWindow.
get(), &FITSViewer::terminated,
this, [
this]()
2936 m_fitsvViewerTabIDs = {-1, -1, -1, -1, -1};
2937 m_FITSViewerWindow.
clear();
2940 return m_FITSViewerWindow;
2945 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)
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.