File indexing completed on 2024-04-21 14:47:26
0001 /* 0002 KStars UI tests for meridian flip - special cases. 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_meridianflip_specials.h" 0010 0011 #if defined(HAVE_INDI) 0012 0013 #include "kstars_ui_tests.h" 0014 #include "Options.h" 0015 #include "ekos/capture/capture.h" 0016 0017 TestEkosMeridianFlipSpecials::TestEkosMeridianFlipSpecials(QObject *parent) : TestEkosMeridianFlipBase(parent) 0018 { 0019 } 0020 0021 TestEkosMeridianFlipSpecials::TestEkosMeridianFlipSpecials(QString guider, 0022 QObject *parent) : TestEkosMeridianFlipBase(guider, parent) 0023 { 0024 } 0025 0026 void TestEkosMeridianFlipSpecials::testCaptureGuidingDeviationMF() 0027 { 0028 // set up the capture sequence 0029 QVERIFY(prepareCaptureTestcase(40, true, false)); 0030 0031 // start guiding 0032 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0033 0034 // start capturing 0035 QVERIFY(startCapturing()); 0036 0037 // wait until a flip is planned 0038 QVERIFY(QTest::qWaitFor([&]() 0039 { 0040 return m_CaptureHelper->expectedMeridianFlipStates.head() != Ekos::MeridianFlipState::MOUNT_FLIP_PLANNED; 0041 }, 60000)); 0042 0043 qCInfo(KSTARS_EKOS_TEST()) << "Meridian flip planned..."; 0044 // guiding deviation leads to a suspended capture 0045 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_SUSPENDED); 0046 0047 // now send motion north to create a guiding deviation 0048 Ekos::Manager::Instance()->mountModule()->doPulse(RA_INC_DIR, 2000, DEC_INC_DIR, 2000); 0049 qCInfo(KSTARS_EKOS_TEST()) << "Sent 2000ms RA+DEC guiding."; 0050 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates, 20000); 0051 0052 // check if meridian flip runs and completes successfully 0053 QVERIFY(checkMFExecuted(25)); 0054 0055 // set guards for post MF checks 0056 // 1. dithering happen after first capture otherwise it is sufficient to wait for start of capturing 0057 if (dithering_checked) 0058 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_IMAGE_RECEIVED); 0059 else 0060 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_CAPTURING); 0061 0062 // 2. ensure that focusing starts 0063 if (refocus_checked) 0064 m_CaptureHelper->expectedFocusStates.enqueue(Ekos::FOCUS_PROGRESS); 0065 0066 // check if guiding is running 0067 if (m_CaptureHelper->use_guiding) 0068 { 0069 m_CaptureHelper->expectedGuidingStates.enqueue(Ekos::GUIDE_GUIDING); 0070 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedGuidingStates, 30000); 0071 } 0072 0073 // check refocusing, that should happen immediately after the guiding calibration 0074 // both for in sequence and time based re-focusing 0075 QVERIFY(checkRefocusing()); 0076 0077 // check if capturing has been started 0078 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates, 60000); 0079 0080 // After the first capture dithering should take place 0081 QVERIFY(checkDithering()); 0082 } 0083 0084 void TestEkosMeridianFlipSpecials::testCaptureGuidingRecalibrationMF() 0085 { 0086 // use three steps in each direction for calibration 0087 Options::setAutoModeIterations(3); 0088 0089 // set up the capture sequence 0090 QVERIFY(prepareCaptureTestcase(30, false, false)); 0091 0092 // start guiding 0093 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0094 0095 // now enable resetting guiding calibration 0096 Options::setResetGuideCalibration(true); 0097 Options::setReuseGuideCalibration(false); 0098 0099 // start capturing 0100 QVERIFY(startCapturing()); 0101 0102 // check if meridian flip runs and completes successfully 0103 QVERIFY(checkMFExecuted(45)); 0104 0105 // check if guiding calibration is executed 0106 m_CaptureHelper->expectedGuidingStates.enqueue(Ekos::GUIDE_CALIBRATING); 0107 m_CaptureHelper->expectedGuidingStates.enqueue(Ekos::GUIDE_CALIBRATION_SUCCESS); 0108 m_CaptureHelper->expectedGuidingStates.enqueue(Ekos::GUIDE_GUIDING); 0109 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_CAPTURING); 0110 // check if capturing starts right now 0111 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates.isEmpty(), 120000); 0112 // check if calibration was finished 0113 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->expectedGuidingStates.isEmpty(), 30000); 0114 } 0115 0116 0117 void TestEkosMeridianFlipSpecials::testCaptureDitheringDelayedAfterMF() 0118 { 0119 // set up the capture sequence 0120 QVERIFY(prepareCaptureTestcase(15, false, false)); 0121 0122 // start guiding 0123 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0124 0125 // start capturing 0126 QVERIFY(startCapturing()); 0127 0128 // check if single capture completes correctly 0129 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_IMAGE_RECEIVED); 0130 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates, 21000); 0131 0132 // check if meridian flip runs and completes successfully 0133 QVERIFY(checkMFExecuted(25)); 0134 0135 // Now check if everything continues as it should be 0136 QVERIFY(checkPostMFBehavior()); 0137 } 0138 0139 0140 void TestEkosMeridianFlipSpecials::testCaptureAlignGuidingPausedMF() 0141 { 0142 // set up the capture sequence 0143 QVERIFY(prepareCaptureTestcase(40, false, false)); 0144 0145 // start alignment 0146 QVERIFY(executeAlignment(5.0)); 0147 0148 // start guiding 0149 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0150 0151 // start capturing 0152 QVERIFY(startCapturing()); 0153 0154 // Let capture run a little bit 0155 QTest::qWait(5000); 0156 0157 // switch to capture module 0158 KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(Ekos::Manager::Instance()->captureModule(), 1000); 0159 0160 // stop capturing 0161 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_PAUSED); 0162 KTRY_CLICK(Ekos::Manager::Instance()->captureModule(), pauseB); 0163 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates, 20000); 0164 0165 // check if meridian flip runs and completes successfully 0166 QVERIFY(checkMFExecuted(40)); 0167 0168 // check if capture remains paused (after a meridian flip it is marked as idle - bug or feature?) 0169 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getCaptureStatus() == Ekos::CAPTURE_PAUSED, 5000); 0170 0171 // Lets wait a little bit 0172 QTest::qWait(5000); 0173 0174 // now finish pause 0175 qCInfo(KSTARS_EKOS_TEST) << "Finishing paused capture... "; 0176 KTRY_CLICK(Ekos::Manager::Instance()->captureModule(), startB); 0177 0178 // Now check if everything continues as it should be 0179 QVERIFY(checkPostMFBehavior()); 0180 } 0181 0182 0183 void TestEkosMeridianFlipSpecials::testCaptureAlignGuidingPauseMFPlanned() 0184 { 0185 // set up the capture sequence 0186 QVERIFY(prepareCaptureTestcase(10, false, false)); 0187 0188 // set a high delay so that it does not start too early 0189 QVERIFY(enableMeridianFlip(120.0)); 0190 0191 // start alignment 0192 QVERIFY(executeAlignment(5.0)); 0193 0194 // start guiding 0195 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0196 0197 // switch to capture module 0198 KTRY_SWITCH_TO_MODULE_WITH_TIMEOUT(Ekos::Manager::Instance()->captureModule(), 1000); 0199 0200 // start capturing 0201 QVERIFY(startCapturing()); 0202 0203 // reset the MF delay after capturing has started 0204 QVERIFY(enableMeridianFlip(0.0)); 0205 0206 // Wait until the meridian flip has been planned 0207 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getMeridianFlipStatus() == Ekos::MeridianFlipState::MOUNT_FLIP_PLANNED, 60000); 0208 0209 // pause capturing 0210 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_PAUSED); 0211 KTRY_CLICK(Ekos::Manager::Instance()->captureModule(), pauseB); 0212 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates, 40000); 0213 0214 // check if meridian flip runs and completes successfully 0215 QVERIFY(checkMFExecuted(40)); 0216 0217 // check if capture remains paused (after a meridian flip it is marked as idle - bug or feature?) 0218 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getCaptureStatus() == Ekos::CAPTURE_PAUSED, 5000); 0219 0220 // Lets wait a little bit 0221 QTest::qWait(5000); 0222 0223 // now finish pause 0224 qCInfo(KSTARS_EKOS_TEST) << "Finishing paused capture... "; 0225 KTRY_CLICK(Ekos::Manager::Instance()->captureModule(), startB); 0226 0227 // Now check if everything continues as it should be 0228 QVERIFY(checkPostMFBehavior()); 0229 } 0230 0231 void TestEkosMeridianFlipSpecials::testAbortRefocusMF() 0232 { 0233 // set up the capture sequence 0234 QVERIFY(prepareCaptureTestcase(20, false, false)); 0235 // refocus every 1min 0236 KTRY_SET_SPINBOX(Ekos::Manager::Instance()->captureModule(), limitRefocusN, 1); 0237 // add additional 5 degrees for delay to prevent a meridian flip before focusing starts 0238 KTRY_SET_DOUBLESPINBOX(Ekos::Manager::Instance()->mountModule(), meridianFlipOffsetDegrees, 5.0); 0239 0240 // start guiding 0241 QVERIFY(m_CaptureHelper->startGuiding(2.0)); 0242 0243 // start capturing 0244 QVERIFY(startCapturing()); 0245 0246 // expect focusing starts and aborts 0247 m_CaptureHelper->expectedFocusStates.append(Ekos::FOCUS_PROGRESS); 0248 m_CaptureHelper->expectedFocusStates.append(Ekos::FOCUS_ABORTED); 0249 0250 // wait until focusing starts 0251 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getFocusStatus() == Ekos::FOCUS_PROGRESS, 90000); 0252 // trigger the meridian flip by clearing the offset 0253 meridianFlipOffsetDegrees->setValue(0.0); 0254 qCInfo(KSTARS_EKOS_TEST) << "Meridian flip offset cleared."; 0255 // expect focus abort due to started meridian flip 0256 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedFocusStates, 90000); 0257 qCInfo(KSTARS_EKOS_TEST) << "Focusing aborted."; 0258 0259 // check if meridian flip runs and completes successfully 0260 QVERIFY(checkMFExecuted(40)); 0261 // do not expect focusing to restart after the flip 0262 refocus_checked = false; 0263 // Now check if everything continues as it should be 0264 QVERIFY(checkPostMFBehavior()); 0265 } 0266 0267 void TestEkosMeridianFlipSpecials::testSchedulerCaptureMF() 0268 { 0269 // setup the scheduler 0270 QVERIFY(prepareSchedulerTestcase(15, false, Ekos::FINISH_LOOP, 1)); 0271 // start the scheduled procedure 0272 QVERIFY(startScheduler()); 0273 // check if meridian flip runs and completes successfully 0274 QVERIFY(checkMFExecuted(120)); 0275 // Now check if everything continues as it should be 0276 QVERIFY(checkPostMFBehavior()); 0277 } 0278 0279 void TestEkosMeridianFlipSpecials::testAbortSchedulerRefocusMF() 0280 { 0281 // setup the scheduler 0282 QVERIFY(prepareSchedulerTestcase(20, false, Ekos::FINISH_LOOP, 1)); 0283 // update the initial focuser position 0284 KTRY_GADGET(Ekos::Manager::Instance()->focusModule(), QLineEdit, absTicksLabel); 0285 initialFocusPosition = absTicksLabel->text().toInt(); 0286 // start the scheduled procedure 0287 QVERIFY(startScheduler()); 0288 // add additional 5 degrees for delay to prevent a meridian flip before focusing starts 0289 KTRY_SET_DOUBLESPINBOX(Ekos::Manager::Instance()->mountModule(), meridianFlipOffsetDegrees, 5.0); 0290 0291 // expect focusing starts and aborts 0292 m_CaptureHelper->expectedFocusStates.append(Ekos::FOCUS_PROGRESS); 0293 m_CaptureHelper->expectedFocusStates.append(Ekos::FOCUS_ABORTED); 0294 0295 // wait until focusing starts 0296 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getFocusStatus() == Ekos::FOCUS_PROGRESS, 90000); 0297 // trigger the meridian flip by clearing the offset after 1 sec 0298 QTest::qWait(1000.0); 0299 meridianFlipOffsetDegrees->setValue(0.0); 0300 qCInfo(KSTARS_EKOS_TEST) << "Meridian flip offset cleared."; 0301 // expect focus abort due to started meridian flip 0302 KVERIFY_EMPTY_QUEUE_WITH_TIMEOUT(m_CaptureHelper->expectedFocusStates, 90000); 0303 qCInfo(KSTARS_EKOS_TEST) << "Focusing aborted."; 0304 // check if the focuser moved back to the last known focus position 0305 // moving back should be finished 5 secs after focusing aborted 0306 QTRY_VERIFY2_WITH_TIMEOUT(initialFocusPosition == absTicksLabel->text().toInt(), 0307 QString("Focuser is at position %1 instead of initial focus position %2") 0308 .arg(absTicksLabel->text()).arg(initialFocusPosition).toLocal8Bit(), 5000); 0309 0310 // check if meridian flip runs and completes successfully 0311 QVERIFY(checkMFExecuted(120)); 0312 0313 // Now check if everything continues as it should be 0314 QVERIFY(checkPostMFBehavior()); 0315 } 0316 0317 void TestEkosMeridianFlipSpecials::testSimpleRepeatedMF() 0318 { 0319 // slew close to the meridian 0320 QVERIFY(positionMountForMF(7.0)); 0321 0322 // set the HA to delay the meridian flip by 2 min = 360° / 24 / 30 = 0.5° 0323 QProcess *indi_setprop = new QProcess(this); 0324 indi_setprop->start(QString("indi_setprop"), {QString("-n"), QString("%1.FLIP_HA.FLIP_HA=%2").arg(m_CaptureHelper->m_MountDevice).arg(0.5)}); 0325 0326 // check if meridian flip runs and completes successfully 0327 QVERIFY(checkMFExecuted(10)); 0328 0329 // pier side should still be west pointing east, i.e. no meridian flip took place 0330 KTRY_GADGET(Ekos::Manager::Instance()->mountModule(), QLabel, pierSideLabel); 0331 QTRY_VERIFY(pierSideLabel->text() == "Pier Side: West (pointing East)"); 0332 0333 qCInfo(KSTARS_EKOS_TEST()) << "Waiting 4 minutes for a second meridian flip..."; 0334 // expected beginning of the meridian flip 0335 m_CaptureHelper->expectedMeridianFlipStates.enqueue(Ekos::MeridianFlipState::MOUNT_FLIP_PLANNED); 0336 m_CaptureHelper->expectedMeridianFlipStates.enqueue(Ekos::MeridianFlipState::MOUNT_FLIP_RUNNING); 0337 0338 // but the pier side should not change, so lets wait for 4 minutes for a second meridian flip 0339 QVERIFY(checkMFExecuted(4 * 60 + 10)); 0340 0341 // set back the HA to delay the meridian flip 0342 indi_setprop = new QProcess(this); 0343 indi_setprop->start(QString("indi_setprop"), {QString("-n"), QString("%1.FLIP_HA.FLIP_HA=%2").arg(m_CaptureHelper->m_MountDevice).arg(0)}); 0344 } 0345 0346 void TestEkosMeridianFlipSpecials::testCaptureRealignMF() 0347 { 0348 if (!astrometry_available) 0349 QSKIP("No astrometry files available to run test"); 0350 0351 // prepare for alignment tests 0352 m_CaptureHelper->prepareAlignmentModule(); 0353 // enforce re-alignment 0354 Options::setAlignCheckFrequency(1); 0355 Options::setAlignCheckThreshold(0.0); 0356 // setup the scheduler 0357 QVERIFY(prepareSchedulerTestcase(17, true, Ekos::FINISH_REPEAT, 1)); 0358 // start the scheduled procedure 0359 QVERIFY(startScheduler()); 0360 // make the alignment exposure so long that the flip happens while capturing the frame for alignment 0361 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getCaptureStatus() == Ekos::CAPTURE_CAPTURING, 60000); 0362 KTRY_SET_DOUBLESPINBOX(Ekos::Manager::Instance()->alignModule(), alignExposure, 60.0); 0363 qCInfo(KSTARS_EKOS_TEST()) << "Setting alignment exposure to 60s."; 0364 // check if meridian flip has been started 0365 QVERIFY(checkMFStarted(120)); 0366 // set the alignment exposure time back 0367 alignExposure->setValue(5.0); 0368 qCInfo(KSTARS_EKOS_TEST()) << "Setting alignment exposure back to 5s."; 0369 // check if meridian flip has been completed 0370 QVERIFY(checkMFExecuted(120)); 0371 // Now check if after the flip everything continues as it should be 0372 QVERIFY(checkPostMFBehavior()); 0373 // check if capturing starts right now 0374 QFETCH(double, exptime); 0375 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->getCaptureStatus() == Ekos::CAPTURE_CAPTURING, 2 * exptime * 1000); 0376 qCInfo(KSTARS_EKOS_TEST()) << "Capturing started."; 0377 // check if an image has been captured 0378 m_CaptureHelper->expectedCaptureStates.enqueue(Ekos::CAPTURE_IMAGE_RECEIVED); 0379 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->expectedCaptureStates.isEmpty(), 30000); 0380 } 0381 0382 void TestEkosMeridianFlipSpecials::testCapturePostRealignmentFailedHandling() 0383 { 0384 if (!astrometry_available) 0385 QSKIP("No astrometry files available to run test"); 0386 0387 // prepare for alignment tests 0388 m_CaptureHelper->prepareAlignmentModule(); 0389 // setup the scheduler 0390 QVERIFY(prepareSchedulerTestcase(17, true, Ekos::FINISH_REPEAT, 1)); 0391 // start the scheduled procedure 0392 QVERIFY(startScheduler()); 0393 // check if meridian flip has been started 0394 QVERIFY(checkMFStarted(120)); 0395 // Create massive noise such that solving fails 0396 KTRY_INDI_PROPERTY(m_CaptureHelper->m_CCDDevice, "Simulator Config", "SIMULATOR_SETTINGS", ccd_settings); 0397 INDI_E *noise_setting = ccd_settings->getElement("SIM_NOISE"); 0398 QVERIFY(ccd_settings != nullptr); 0399 noise_setting->setValue(100.0); 0400 ccd_settings->processSetButton(); 0401 // set the alignment exposure so low that alignment fails 0402 KTRY_SET_DOUBLESPINBOX(Ekos::Manager::Instance()->alignModule(), alignExposure, 0.1); 0403 // check if meridian flip has been completed 0404 QVERIFY(checkMFExecuted(120)); 0405 // expect 4 failed alignments (normal, blind solve + 2x retrying) 0406 for (int i = 0; i < 4; i++) 0407 m_CaptureHelper->expectedAlignStates.enqueue(Ekos::ALIGN_FAILED); 0408 QTRY_VERIFY_WITH_TIMEOUT(m_CaptureHelper->expectedAlignStates.isEmpty(), 30000); 0409 } 0410 0411 0412 /* ********************************************************************************* 0413 * 0414 * Test data 0415 * 0416 * ********************************************************************************* */ 0417 0418 void TestEkosMeridianFlipSpecials::testCaptureGuidingDeviationMF_data() 0419 { 0420 prepareTestData(45.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {true}, {false, true}); 0421 } 0422 0423 void TestEkosMeridianFlipSpecials::testCaptureGuidingRecalibrationMF_data() 0424 { 0425 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 6}, {"Red,Green,Blue,Red,Green,Blue", 1}}, {0}, {true}, {false}); 0426 } 0427 0428 void TestEkosMeridianFlipSpecials::testCaptureDitheringDelayedAfterMF_data() 0429 { 0430 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Red,Green,Blue,Red,Green,Blue", 1}}, {0}, {true}, {true}); 0431 } 0432 0433 void TestEkosMeridianFlipSpecials::testCaptureAlignGuidingPausedMF_data() 0434 { 0435 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {true}, {false}); 0436 } 0437 0438 void TestEkosMeridianFlipSpecials::testCaptureAlignGuidingPauseMFPlanned_data() 0439 { 0440 prepareTestData(12.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {true}, {false}); 0441 } 0442 0443 void TestEkosMeridianFlipSpecials::testAbortRefocusMF_data() 0444 { 0445 prepareTestData(32.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {1}, {false}, {false}); 0446 } 0447 0448 void TestEkosMeridianFlipSpecials::testSchedulerCaptureMF_data() 0449 { 0450 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 1}}, {0}, {true, false}, {false}); 0451 } 0452 0453 void TestEkosMeridianFlipSpecials::testAbortSchedulerRefocusMF_data() 0454 { 0455 prepareTestData(30.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {1}, {true, false}, {false}); 0456 } 0457 0458 void TestEkosMeridianFlipSpecials::testSimpleRepeatedMF_data() 0459 { 0460 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {false}, {false}); 0461 } 0462 0463 void TestEkosMeridianFlipSpecials::testCaptureRealignMF_data() 0464 { 0465 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {false}, {false}); 0466 } 0467 0468 void TestEkosMeridianFlipSpecials::testCapturePostRealignmentFailedHandling_data() 0469 { 0470 prepareTestData(18.0, {"Greenwich"}, {true}, {{"Luminance", 6}}, {0}, {false}, {false}); 0471 } 0472 0473 0474 QTEST_KSTARS_WITH_GUIDER_MAIN(TestEkosMeridianFlipSpecials) 0475 0476 #endif // HAVE_INDI