File indexing completed on 2024-04-28 03:43:19
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "sequencequeue.h" 0008 0009 #include <KNotifications/KNotification> 0010 #include <ekos_capture_debug.h> 0011 0012 #include "capturemodulestate.h" 0013 #include "capturedeviceadaptor.h" 0014 #include "ksnotification.h" 0015 #include "sequencejob.h" 0016 0017 // Current Sequence File Format: 0018 constexpr double SQ_FORMAT_VERSION = 2.6; 0019 // We accept file formats with version back to: 0020 constexpr double SQ_COMPAT_VERSION = 2.0; 0021 0022 namespace Ekos 0023 { 0024 0025 bool SequenceQueue::load(const QString &fileURL, const QString &targetName, 0026 const QSharedPointer<CaptureDeviceAdaptor> devices, 0027 const QSharedPointer<CaptureModuleState> state) 0028 { 0029 QFile sFile(fileURL); 0030 if (!sFile.open(QIODevice::ReadOnly)) 0031 { 0032 QString message = i18n("Unable to open file %1", fileURL); 0033 KSNotification::sorry(message, i18n("Could Not Open File")); 0034 return false; 0035 } 0036 0037 LilXML * xmlParser = newLilXML(); 0038 0039 char errmsg[MAXRBUF]; 0040 XMLEle * root = nullptr; 0041 XMLEle * ep = nullptr; 0042 char c; 0043 0044 // We expect all data read from the XML to be in the C locale - QLocale::c(). 0045 QLocale cLocale = QLocale::c(); 0046 0047 while (sFile.getChar(&c)) 0048 { 0049 root = readXMLEle(xmlParser, c, errmsg); 0050 0051 if (root) 0052 { 0053 double sqVersion = cLocale.toDouble(findXMLAttValu(root, "version")); 0054 if (sqVersion < SQ_COMPAT_VERSION) 0055 { 0056 emit newLog(i18n("Deprecated sequence file format version %1. Please construct a new sequence file.", 0057 sqVersion)); 0058 return false; 0059 } 0060 0061 for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0)) 0062 { 0063 if (!strcmp(tagXMLEle(ep), "Observer")) 0064 { 0065 state->setObserverName(QString(pcdataXMLEle(ep))); 0066 } 0067 else if (!strcmp(tagXMLEle(ep), "GuideDeviation")) 0068 { 0069 m_GuideDeviationSet = true; 0070 m_EnforceGuideDeviation = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0071 m_GuideDeviation = cLocale.toDouble(pcdataXMLEle(ep)); 0072 } 0073 else if (!strcmp(tagXMLEle(ep), "CCD")) 0074 { 0075 // Old field in some files. Without this empty test, it would fall through to the else condition and create a job. 0076 } 0077 else if (!strcmp(tagXMLEle(ep), "FilterWheel")) 0078 { 0079 // Old field in some files. Without this empty test, it would fall through to the else condition and create a job. 0080 } 0081 else if (!strcmp(tagXMLEle(ep), "GuideStartDeviation")) 0082 { 0083 m_GuideStartDeviationSet = true; 0084 m_EnforceStartGuiderDrift = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0085 m_StartGuideDeviation = cLocale.toDouble(pcdataXMLEle(ep)); 0086 } 0087 else if (!strcmp(tagXMLEle(ep), "Autofocus")) 0088 { 0089 // Old field in some files. Without this empty test, it would fall through to the else condition and create a job. 0090 } 0091 else if (!strcmp(tagXMLEle(ep), "HFRCheck")) 0092 { 0093 m_AutofocusSet = true; 0094 m_EnforceAutofocusHFR = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0095 0096 XMLEle *epHFR; 0097 //Set default values in case of malformed XML 0098 m_HFRDeviation = 0.0; 0099 m_HFRCheckAlgorithm = HFR_CHECK_LAST_AUTOFOCUS; 0100 m_HFRCheckThresholdPercentage = HFR_CHECK_DEFAULT_THRESHOLD; 0101 m_HFRCheckFrames = 1; 0102 0103 for (epHFR = nextXMLEle(ep, 1); epHFR != nullptr; epHFR = nextXMLEle(ep, 0)) 0104 { 0105 if (!strcmp(tagXMLEle(epHFR), "HFRDeviation")) 0106 { 0107 double const HFRValue = cLocale.toDouble(pcdataXMLEle(epHFR)); 0108 // Set the HFR value from XML, or reset it to zero, don't let another unrelated older HFR be used 0109 if (HFRValue >= 0.0) 0110 m_HFRDeviation = HFRValue; 0111 } 0112 0113 if (!strcmp(tagXMLEle(epHFR), "HFRCheckAlgorithm")) 0114 { 0115 int HFRCheckAlgo = cLocale.toInt(pcdataXMLEle(epHFR)); 0116 // Set the HFR Check Algo from XML, or reset it to Last Autofocus 0117 if (HFRCheckAlgo >= 0 && HFRCheckAlgo < HFR_CHECK_MAX_ALGO) 0118 m_HFRCheckAlgorithm = static_cast<HFR_CHECK_ALGORITHM>(HFRCheckAlgo); 0119 } 0120 else if (!strcmp(tagXMLEle(epHFR), "HFRCheckThreshold")) 0121 { 0122 double const hFRCheckThreshold = cLocale.toDouble(pcdataXMLEle(epHFR)); 0123 // Set the HFR Threshold Percentage from XML, or reset it to 10%, don't let another unrelated older value be used 0124 if (hFRCheckThreshold >= 0.0) 0125 m_HFRCheckThresholdPercentage = hFRCheckThreshold; 0126 } 0127 else if (!strcmp(tagXMLEle(epHFR), "HFRCheckFrames")) 0128 { 0129 int const hFRCheckFrames = cLocale.toInt(pcdataXMLEle(epHFR)); 0130 // Set the HFR Frames from XML, or reset it to 1, don't let another unrelated older value be used 0131 if (hFRCheckFrames > 1) 0132 m_HFRCheckFrames = hFRCheckFrames; 0133 } 0134 } 0135 } 0136 else if (!strcmp(tagXMLEle(ep), "RefocusOnTemperatureDelta")) 0137 { 0138 m_RefocusOnTemperatureDeltaSet = true; 0139 m_EnforceAutofocusOnTemperature = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0140 double const deltaValue = cLocale.toDouble(pcdataXMLEle(ep)); 0141 m_MaxFocusTemperatureDelta = deltaValue; 0142 } 0143 else if (!strcmp(tagXMLEle(ep), "RefocusEveryN")) 0144 { 0145 m_RefocusEveryNSet = true; 0146 m_EnforceRefocusEveryN = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0147 int const minutesValue = cLocale.toInt(pcdataXMLEle(ep)); 0148 // Set the refocus period from XML, or reset it to zero, don't let another unrelated older refocus period be used. 0149 m_RefocusEveryN = minutesValue > 0 ? minutesValue : 0; 0150 } 0151 else if (!strcmp(tagXMLEle(ep), "RefocusOnMeridianFlip")) 0152 { 0153 m_RefocusOnMeridianFlipSet = true; 0154 m_RefocusAfterMeridianFlip = !strcmp(findXMLAttValu(ep, "enabled"), "true"); 0155 } 0156 else if (!strcmp(tagXMLEle(ep), "MeridianFlip")) 0157 { 0158 // meridian flip is managed by the mount only 0159 // older files might nevertheless contain MF settings 0160 if (! strcmp(findXMLAttValu(ep, "enabled"), "true")) 0161 emit newLog( 0162 i18n("Meridian flip configuration has been shifted to the mount module. Please configure the meridian flip there.")); 0163 } 0164 else 0165 { 0166 auto job = new SequenceJob(devices, state, SequenceJob::JOBTYPE_BATCH, ep, targetName); 0167 m_allJobs.append(job); 0168 } 0169 } 0170 delXMLEle(root); 0171 } 0172 else if (errmsg[0]) 0173 { 0174 emit newLog(QString(errmsg)); 0175 delLilXML(xmlParser); 0176 return false; 0177 } 0178 } 0179 0180 state->setSequenceURL(QUrl::fromLocalFile(fileURL)); 0181 state->setDirty(false); 0182 delLilXML(xmlParser); 0183 return true; 0184 } 0185 0186 void SequenceQueue::setOptions() 0187 { 0188 if (m_GuideDeviationSet) 0189 { 0190 Options::setEnforceGuideDeviation(m_EnforceGuideDeviation); 0191 Options::setGuideDeviation(m_GuideDeviation); 0192 } 0193 if (m_GuideStartDeviationSet) 0194 { 0195 Options::setEnforceStartGuiderDrift(m_EnforceStartGuiderDrift); 0196 Options::setStartGuideDeviation(m_StartGuideDeviation); 0197 } 0198 if (m_AutofocusSet) 0199 { 0200 Options::setEnforceAutofocusHFR(m_EnforceAutofocusHFR); 0201 Options::setHFRCheckAlgorithm(m_HFRCheckAlgorithm); 0202 Options::setHFRThresholdPercentage(m_HFRCheckThresholdPercentage); 0203 Options::setInSequenceCheckFrames(m_HFRCheckFrames); 0204 Options::setHFRDeviation(m_HFRDeviation); 0205 } 0206 if (m_RefocusOnTemperatureDeltaSet) 0207 { 0208 Options::setEnforceAutofocusOnTemperature(m_EnforceAutofocusOnTemperature); 0209 Options::setMaxFocusTemperatureDelta(m_MaxFocusTemperatureDelta); 0210 } 0211 if (m_RefocusEveryNSet) 0212 { 0213 Options::setEnforceRefocusEveryN(m_EnforceRefocusEveryN); 0214 Options::setRefocusEveryN(m_RefocusEveryN); 0215 } 0216 if (m_RefocusOnMeridianFlipSet) 0217 { 0218 Options::setRefocusAfterMeridianFlip(m_RefocusAfterMeridianFlip); 0219 } 0220 } 0221 0222 void SequenceQueue::loadOptions() 0223 { 0224 m_GuideDeviationSet = true; 0225 0226 m_EnforceGuideDeviation = Options::enforceGuideDeviation(); 0227 m_GuideDeviation = Options::guideDeviation(); 0228 0229 m_GuideStartDeviationSet = true; 0230 m_EnforceStartGuiderDrift = Options::enforceStartGuiderDrift(); 0231 m_StartGuideDeviation = Options::startGuideDeviation(); 0232 0233 m_AutofocusSet = true; 0234 m_EnforceAutofocusHFR = Options::enforceAutofocusHFR(); 0235 m_HFRCheckAlgorithm = static_cast<HFR_CHECK_ALGORITHM>(Options::hFRCheckAlgorithm()); 0236 m_HFRCheckThresholdPercentage = Options::hFRThresholdPercentage(); 0237 m_HFRCheckFrames = Options::inSequenceCheckFrames(); 0238 m_HFRDeviation = Options::hFRDeviation(); 0239 0240 m_RefocusOnTemperatureDeltaSet = true; 0241 m_EnforceAutofocusOnTemperature = Options::enforceAutofocusOnTemperature(); 0242 m_MaxFocusTemperatureDelta = Options::maxFocusTemperatureDelta(); 0243 0244 m_RefocusEveryNSet = true; 0245 m_EnforceRefocusEveryN = Options::enforceRefocusEveryN(); 0246 m_RefocusEveryN = Options::refocusEveryN(); 0247 0248 m_RefocusOnMeridianFlipSet = true; 0249 m_RefocusAfterMeridianFlip = Options::refocusAfterMeridianFlip(); 0250 } 0251 0252 bool SequenceQueue::save(const QString &path, const QString &observerName) 0253 { 0254 QFile file; 0255 file.setFileName(path); 0256 0257 if (!file.open(QIODevice::WriteOnly)) 0258 { 0259 QString message = i18n("Unable to write to file %1", path); 0260 KSNotification::sorry(message, i18n("Could not open file")); 0261 return false; 0262 } 0263 0264 QTextStream outstream(&file); 0265 0266 // We serialize sequence data to XML using the C locale 0267 QLocale cLocale = QLocale::c(); 0268 0269 outstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << Qt::endl; 0270 outstream << "<SequenceQueue version='" << SQ_FORMAT_VERSION << "'>" << Qt::endl; 0271 if (observerName.isEmpty() == false) 0272 outstream << "<Observer>" << observerName << "</Observer>" << Qt::endl; 0273 outstream << "<GuideDeviation enabled='" << (m_EnforceGuideDeviation ? "true" : "false") << "'>" 0274 << cLocale.toString(m_GuideDeviation) << "</GuideDeviation>" << Qt::endl; 0275 outstream << "<GuideStartDeviation enabled='" << (m_EnforceStartGuiderDrift ? "true" : "false") << "'>" 0276 << cLocale.toString(m_StartGuideDeviation) << "</GuideStartDeviation>" << Qt::endl; 0277 outstream << "<HFRCheck enabled='" << (m_EnforceAutofocusHFR ? "true" : "false") << "'>" << Qt::endl; 0278 outstream << "<HFRDeviation>" << cLocale.toString(m_HFRDeviation) << "</HFRDeviation>" << Qt::endl; 0279 outstream << "<HFRCheckAlgorithm>" << m_HFRCheckAlgorithm << "</HFRCheckAlgorithm>" << Qt::endl; 0280 outstream << "<HFRCheckThreshold>" << cLocale.toString(m_HFRCheckThresholdPercentage) << "</HFRCheckThreshold>" << Qt::endl; 0281 outstream << "<HFRCheckFrames>" << cLocale.toString(m_HFRCheckFrames) << "</HFRCheckFrames>" << Qt::endl; 0282 outstream << "</HFRCheck>" << Qt::endl; 0283 outstream << "<RefocusOnTemperatureDelta enabled='" << (m_EnforceAutofocusOnTemperature ? "true" : "false") << 0284 "'>" 0285 << cLocale.toString(m_MaxFocusTemperatureDelta) << "</RefocusOnTemperatureDelta>" << Qt::endl; 0286 outstream << "<RefocusEveryN enabled='" << (m_EnforceRefocusEveryN ? "true" : "false") << "'>" 0287 << cLocale.toString(m_RefocusEveryN) << "</RefocusEveryN>" << Qt::endl; 0288 outstream << "<RefocusOnMeridianFlip enabled='" << (m_RefocusAfterMeridianFlip ? "true" : "false") << "'/>" 0289 << Qt::endl; 0290 0291 for (auto &job : m_allJobs) 0292 { 0293 job->saveTo(outstream, cLocale); 0294 } 0295 0296 outstream << "</SequenceQueue>" << Qt::endl; 0297 0298 emit newLog(i18n("Sequence queue saved to %1", path)); 0299 file.flush(); 0300 file.close(); 0301 0302 return true; 0303 } 0304 0305 } 0306