File indexing completed on 2024-03-24 15:18:34

0001 /*
0002     Helper class of KStars UI capture tests
0003 
0004     SPDX-FileCopyrightText: 2020 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "test_ekos_capture_helper.h"
0010 
0011 #include "test_ekos.h"
0012 #include "ekos/capture/scriptsmanager.h"
0013 #include "ekos/capture/capture.h"
0014 #include "ekos/scheduler/scheduler.h"
0015 #include "Options.h"
0016 
0017 TestEkosCaptureHelper::TestEkosCaptureHelper(QString guider) : TestEkosHelper(guider) {}
0018 
0019 void TestEkosCaptureHelper::init()
0020 {
0021     TestEkosHelper::init();
0022     QStandardPaths::setTestModeEnabled(true);
0023     QFileInfo test_dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation), "test");
0024     destination = new QTemporaryDir(test_dir.absolutePath());
0025     QVERIFY(destination->isValid());
0026     QVERIFY(destination->autoRemove());
0027 }
0028 
0029 void TestEkosCaptureHelper::cleanup()
0030 {
0031     // remove destination directory
0032     if (destination != nullptr)
0033         destination->remove();
0034     delete destination;
0035 }
0036 
0037 
0038 bool TestEkosCaptureHelper::startCapturing(bool checkCapturing)
0039 {
0040     // switch to the capture module
0041     KWRAP_SUB(KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(Ekos::Manager::Instance()->captureModule(), 1000));
0042 
0043     // check if capture is in a stopped state
0044     KWRAP_SUB(QVERIFY(getCaptureStatus() == Ekos::CAPTURE_IDLE || getCaptureStatus() == Ekos::CAPTURE_ABORTED
0045                       || getCaptureStatus() == Ekos::CAPTURE_COMPLETE));
0046 
0047     // ensure at least one capture is started if requested
0048     if (checkCapturing)
0049         expectedCaptureStates.enqueue(Ekos::CAPTURE_CAPTURING);
0050     // press start
0051     KTRY_GADGET_SUB(Ekos::Manager::Instance()->captureModule(), QPushButton, startB);
0052     KTRY_CLICK_SUB(Ekos::Manager::Instance()->captureModule(), startB);
0053 
0054     // check if capturing has started
0055     KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT_SUB(expectedCaptureStates, 120000);
0056     // all checks succeeded
0057     return true;
0058 }
0059 
0060 bool TestEkosCaptureHelper::stopCapturing()
0061 {
0062     // check if capture is in a stopped state
0063     if (getCaptureStatus() == Ekos::CAPTURE_IDLE || getCaptureStatus() == Ekos::CAPTURE_ABORTED
0064             || getCaptureStatus() == Ekos::CAPTURE_COMPLETE)
0065         return true;
0066 
0067     // switch to the capture module
0068     KWRAP_SUB(KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(Ekos::Manager::Instance()->captureModule(), 1000));
0069 
0070     // else press stop
0071     expectedCaptureStates.enqueue(Ekos::CAPTURE_ABORTED);
0072     KTRY_GADGET_SUB(Ekos::Manager::Instance()->captureModule(), QPushButton, startB);
0073     KTRY_CLICK_SUB(Ekos::Manager::Instance()->captureModule(), startB);
0074 
0075     // check if capturing has stopped
0076     KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT_SUB(expectedCaptureStates, 5000);
0077     // all checks succeeded
0078     return true;
0079 }
0080 
0081 QString TestEkosCaptureHelper::calculateSignature(QString target, QString filter, QString fitsDirectory)
0082 {
0083     if (target == "")
0084         return fitsDirectory + QDir::separator() + "Light" + QDir::separator() + filter + QDir::separator() + "Light_" + filter +
0085                "_";
0086     else
0087         return fitsDirectory + QDir::separator() + target + QDir::separator() + "Light" + QDir::separator() + filter +
0088                QDir::separator() + target + "_" + "Light_" + filter + "_";
0089 }
0090 
0091 QStringList TestEkosCaptureHelper::searchFITS(const QDir &dir) const
0092 {
0093     QStringList list = dir.entryList(QDir::Files);
0094 
0095     //foreach (auto &f, list)
0096     //    QWARN(QString(dir.path()+'/'+f).toStdString().c_str());
0097 
0098     foreach (auto &d, dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs))
0099         list.append(searchFITS(QDir(dir.path() + '/' + d)));
0100 
0101     return list;
0102 }
0103 
0104 void TestEkosCaptureHelper::ensureCCDShutter(bool shutter)
0105 {
0106     if (m_CCDDevice != "")
0107     {
0108         // ensure that we know that the CCD has a shutter
0109         QStringList shutterlessCCDs = Options::shutterlessCCDs();
0110         QStringList shutterfulCCDs  = Options::shutterfulCCDs();
0111         if (shutter)
0112         {
0113             // remove CCD device from shutterless CCDs
0114             shutterlessCCDs.removeAll(m_CCDDevice);
0115             Options::setShutterlessCCDs(shutterlessCCDs);
0116             // add CCD device if necessary to shutterful CCDs
0117             if (! shutterfulCCDs.contains(m_CCDDevice))
0118             {
0119                 shutterfulCCDs.append(m_CCDDevice);
0120                 Options::setShutterfulCCDs(shutterfulCCDs);
0121             }
0122         }
0123         else
0124         {
0125             // remove CCD device from shutterful CCDs
0126             shutterfulCCDs.removeAll(m_CCDDevice);
0127             Options::setShutterfulCCDs(shutterfulCCDs);
0128             // add CCD device if necessary to shutterless CCDs
0129             if (! shutterlessCCDs.contains(m_CCDDevice))
0130             {
0131                 shutterlessCCDs.append(m_CCDDevice);
0132                 Options::setShutterlessCCDs(shutterlessCCDs);
0133             }
0134         }
0135 
0136     }
0137 }
0138 
0139 
0140 QDir *TestEkosCaptureHelper::getImageLocation()
0141 {
0142     if (imageLocation == nullptr || imageLocation->exists() == false)
0143         imageLocation = new QDir(destination->path() + "/images");
0144 
0145     return imageLocation;
0146 }
0147 
0148 bool TestEkosCaptureHelper::fillCaptureSequences(QString target, QString sequence, double exptime, QString fitsDirectory,
0149         int delay, QString format)
0150 {
0151     if (sequence == "")
0152         return true;
0153 
0154     for (QString value : sequence.split(","))
0155     {
0156         KVERIFY_SUB(value.indexOf(":") > -1);
0157         QString filter = value.left(value.indexOf(":"));
0158         int count      = value.right(value.length() - value.indexOf(":") - 1).toInt();
0159         KTRY_SET_LINEEDIT_SUB(Ekos::Manager::Instance()->captureModule(), placeholderFormatT, format);
0160         if (count > 0)
0161             KWRAP_SUB(KTRY_CAPTURE_ADD_LIGHT(exptime, count, delay, filter, target, fitsDirectory));
0162         // ensure that no old values are present
0163         Ekos::Manager::Instance()->captureModule()->setCapturedFramesMap(calculateSignature(target, filter, fitsDirectory), 0);
0164     }
0165 
0166     return true;
0167 }
0168 
0169 bool TestEkosCaptureHelper::fillScriptManagerDialog(const QMap<Ekos::ScriptTypes, QString> &scripts)
0170 {
0171     Ekos::ScriptsManager *manager = Ekos::Manager::Instance()->findChild<Ekos::ScriptsManager*>();
0172     // fail if manager not found
0173     KVERIFY2_SUB(manager != nullptr, "Cannot find script manager!");
0174     manager->setScripts(scripts);
0175     manager->done(QDialog::Accepted);
0176     return true;
0177 }
0178 
0179 void TestEkosCaptureHelper::cleanupScheduler()
0180 {
0181     Ekos::Manager::Instance()->schedulerModule()->stop();
0182     QTest::qWait(5000);
0183     // remove jobs
0184     Ekos::Manager::Instance()->schedulerModule()->removeAllJobs();
0185 }
0186 
0187 QStringList TestEkosCaptureHelper::getSimpleEsqContent(CaptureSettings settings, QVector<SimpleCaptureLightsJob> jobs,
0188         ESQVersion version)
0189 {
0190     QStringList result = serializeGeneralSettings(settings, version);
0191 
0192 
0193     for (QVector<SimpleCaptureLightsJob>::iterator job_iter = jobs.begin(); job_iter !=  jobs.end(); job_iter++)
0194         result.append(serializeJob(*job_iter, version));
0195 
0196     result.append("</SequenceQueue>");
0197     return result;
0198 }
0199 
0200 QStringList TestEkosCaptureHelper::getSimpleEsqContent(CaptureSettings settings, QVector<SimpleCaptureCalibratingJob> jobs,
0201         ESQVersion version)
0202 {
0203     QStringList result = serializeGeneralSettings(settings, version);
0204 
0205 
0206     for (QVector<SimpleCaptureCalibratingJob>::iterator job_iter = jobs.begin(); job_iter !=  jobs.end(); job_iter++)
0207         result.append(serializeJob(*job_iter, version));
0208 
0209     result.append("</SequenceQueue>");
0210     return result;
0211 }
0212 
0213 QStringList TestEkosCaptureHelper::serializeGeneralSettings(CaptureSettings settings, ESQVersion version)
0214 {
0215     QStringList result({"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
0216                         QString("<SequenceQueue version='%1'><CCD>CCD Simulator</CCD>").arg(esqVersionNames[version]),
0217                         "<FilterWheel>CCD Simulator</FilterWheel>",
0218                         QString("<Observer>%1</Observer>").arg(settings.observer),
0219                         QString("<GuideDeviation enabled='%1'>%2</GuideDeviation>").arg(settings.guideDeviation.enabled ? "true" : "false").arg(settings.guideDeviation.value),
0220                         QString("<GuideStartDeviation enabled='%1'>%2</GuideStartDeviation>").arg(settings.startGuideDeviation.enabled ? "true" : "false").arg(settings.startGuideDeviation.value),
0221                         QString("<Autofocus enabled='%1'>%2</Autofocus>").arg(settings.inSequenceFocus.enabled ? "true" : "false").arg(settings.inSequenceFocus.value),
0222                         QString("<RefocusOnTemperatureDelta enabled='%1'>%2</RefocusOnTemperatureDelta>").arg(settings.autofocusOnTemperature.enabled ? "true" : "false").arg(settings.autofocusOnTemperature.value),
0223                         QString("<RefocusEveryN enabled='%1'>%2</RefocusEveryN>").arg(settings.refocusEveryN.enabled ? "true" : "false").arg(settings.refocusEveryN.value),
0224                         QString("<RefocusOnMeridianFlip enabled='%1'/>").arg(settings.refocusAfterMeridianFlip ? "true" : "false")});
0225 
0226     return result;
0227 }
0228 
0229 QStringList TestEkosCaptureHelper::serializeJob(const TestEkosCaptureHelper::SimpleCaptureLightsJob &job,
0230         ESQVersion version)
0231 {
0232     QStringList result({"<Job>",
0233                         QString("<Exposure>%1</Exposure>").arg(job.exposureTime),
0234                         "<Format>Mono</Format>",
0235                         QString("<Encoding>%1</Encoding>").arg(job.encoding),
0236                         QString("<Binning><X>%1</X><Y>%2</Y></Binning>").arg(job.binX).arg(job.binY),
0237                         QString("<Frame><X>%1</X><Y>%2</Y><W>%3</W><H>%4</H></Frame>").arg(job.x).arg(job.y).arg(job.w).arg(job.h),
0238                         QString("<Temperature force='%2'>%1</Temperature>").arg(job.cameraTemperature.value).arg(job.cameraTemperature.enabled ? "true" : "false"),
0239                         QString("<Filter>%1</Filter>").arg(job.filterName),
0240                         QString("<Type>%1</Type>").arg(job.type),
0241                         QString("<Count>%1</Count>").arg(job.count),
0242                         QString("<Delay>%1</Delay>").arg(job.delayMS / 1000)});
0243     switch (version)
0244     {
0245         case ESQ_VERSION_2_4:
0246             result.append(QString("<Prefix><RawPrefix>%1</RawPrefix></Prefix>").arg(job.targetName));
0247         case ESQ_VERSION_2_5:
0248             // no target specified
0249             break;
0250         case ESQ_VERSION_2_6:
0251             result.append(QString("<TargetName>%1</TargetName>").arg(job.targetName));
0252             break;
0253     }
0254 
0255     result.append({QString("<PlaceholderFormat>%1</PlaceholderFormat>").arg(job.placeholderFormat),
0256                    QString("<PlaceholderSuffix>%1</PlaceholderSuffix>").arg(job.formatSuffix),
0257                    QString("<FITSDirectory>%1</FITSDirectory>").arg(job.fitsDirectory),
0258                    QString("<UploadMode>%1</UploadMode>").arg(job.uploadMode),
0259                    "<Properties />",
0260                    "<Calibration>"});
0261     switch (version)
0262     {
0263         case ESQ_VERSION_2_4:
0264         case ESQ_VERSION_2_5:
0265             result.append({"<FlatSource><Type>Manual</Type></FlatSource>",
0266                            "<FlatDuration><Type>ADU</Type><Value>15000</Value><Tolerance>1000</Tolerance></FlatDuration>",
0267                            "<PreMountPark>False</PreMountPark>",
0268                            "<PreDomePark>False</PreDomePark>",
0269                            "</Calibration>",
0270                            "</Job>"});
0271             break;
0272         case ESQ_VERSION_2_6:
0273             result.append({QString("<PreAction><Type>%1</Type></PreAction>").arg(0),
0274                            "<FlatDuration><Type>ADU</Type><Value>15000</Value><Tolerance>1000</Tolerance></FlatDuration>",
0275                            "</Calibration>",
0276                            "</Job>"});
0277             break;
0278     }
0279     return result;
0280 }
0281 
0282 QStringList TestEkosCaptureHelper::serializeJob(const SimpleCaptureCalibratingJob &job, ESQVersion version)
0283 {
0284     QStringList result({"<Job>",
0285                         QString("<Exposure>%1</Exposure>").arg(job.exposureTime),
0286                         "<Format>Mono</Format>",
0287                         QString("<Encoding>%1</Encoding>").arg("FITS"),
0288                         QString("<Binning><X>%1</X><Y>%2</Y></Binning>").arg(2).arg(2),
0289                         QString("<Frame><X>%1</X><Y>%2</Y><W>%3</W><H>%4</H></Frame>").arg(0).arg(0).arg(1280).arg(1080),
0290                         QString("<Temperature force='%2'>%1</Temperature>").arg(-20).arg("true"),
0291                         QString("<Filter>%1</Filter>").arg("Luminance"),
0292                         QString("<Type>%1</Type>").arg(job.type),
0293                         QString("<Count>%1</Count>").arg(job.count),
0294                         QString("<Delay>%1</Delay>").arg(2),
0295                         QString("<PlaceholderFormat>%1</PlaceholderFormat>").arg("/%t/%T/%F/%t_%T_%F_%e_%D"),
0296                         QString("<PlaceholderSuffix>%1</PlaceholderSuffix>").arg(2),
0297                         QString("<FITSDirectory>%1</FITSDirectory>").arg("/home/pi"),
0298                         QString("<UploadMode>%1</UploadMode>").arg(0),
0299                         "<Properties />",
0300                         "<Calibration>"});
0301 
0302 
0303     switch (version)
0304     {
0305         case ESQ_VERSION_2_4:
0306         case ESQ_VERSION_2_5:
0307             if (job.preAction & ACTION_WALL)
0308             {
0309                 result.append("<FlatSource><Type>Wall</Type>");
0310                 result.append(QString("<Az>%1</Az>").arg(job.wall_az));
0311                 result.append(QString("<Alt>%1</Alt>").arg(job.wall_alt));
0312                 result.append(QString("</FlatSource>"));
0313             }
0314             else
0315                 result.append("<FlatSource><Type>Manual</Type></FlatSource>");
0316 
0317             result.append({QString("<PreMountPark>%1</PreMountPark>").arg((job.preAction & ACTION_PARK_MOUNT) > 0 ? "True" : "False"),
0318                            QString("<PreDomePark>%1</PreDomePark>").arg((job.preAction & ACTION_PARK_DOME) > 0 ? "True" : "False")});
0319             break;
0320 
0321         case ESQ_VERSION_2_6:
0322             result.append(QString("<PreAction><Type>%1</Type>").arg(job.preAction));
0323             if (job.preAction & ACTION_WALL)
0324                 result.append({QString("<Az>%1</Az>").arg(job.wall_az),
0325                                QString("<Alt>%1</Alt>").arg(job.wall_alt)});
0326             result.append("</PreAction>");
0327             break;
0328     }
0329     result.append("<FlatDuration dark='false'>");
0330     if (job.duration_manual)
0331         result.append("<Type>Manual</Type>");
0332     else if (job.duration_adu)
0333         result.append(QString("<Type>ADU</Type><Value>%1</Value><Tolerance>%2</Tolerance>").arg(job.adu).arg(job.tolerance));
0334 
0335     result.append({"</FlatDuration>",
0336                    "</Calibration>",
0337                    "</Job>"});
0338 
0339     return result;
0340 
0341 }
0342