00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "imagesequence.h"
00013 #include "kstars.h"
00014 #include "indidriver.h"
00015 #include "indielement.h"
00016 #include "indiproperty.h"
00017 #include "indimenu.h"
00018 #include "indidevice.h"
00019 #include "indistd.h"
00020 #include "devicemanager.h"
00021 #include "Options.h"
00022
00023 #include <kdebug.h>
00024 #include <kmessagebox.h>
00025 #include <klocale.h>
00026 #include <klineedit.h>
00027 #include <kprogress.h>
00028 #include <knuminput.h>
00029
00030 #include <qtimer.h>
00031 #include <qcombobox.h>
00032 #include <qpushbutton.h>
00033 #include <qlabel.h>
00034 #include <qcheckbox.h>
00035 #include <qstringlist.h>
00036
00037 #define RETRY_MAX 12
00038 #define RETRY_PERIOD 5000
00039
00040 imagesequence::imagesequence(QWidget* parent, const char* name, bool modal, WFlags fl)
00041 : imgSequenceDlg(parent,name, modal,fl)
00042 {
00043
00044 ksw = (KStars *) parent;
00045 INDIMenu *devMenu = ksw->getINDIMenu();
00046
00047 if (devMenu)
00048 {
00049 connect (devMenu, SIGNAL(newDevice()), this, SLOT(newCCD()));
00050 connect (devMenu, SIGNAL(newDevice()), this, SLOT(newFilter()));
00051 }
00052
00053 seqTimer = new QTimer(this);
00054
00055 setModal(false);
00056
00057
00058 connect(startB, SIGNAL(clicked()), this, SLOT(startSequence()));
00059 connect(stopB, SIGNAL(clicked()), this, SLOT(stopSequence()));
00060 connect(closeB, SIGNAL(clicked()), this, SLOT(close()));
00061 connect(seqTimer, SIGNAL(timeout()), this, SLOT(prepareCapture()));
00062 connect(CCDCombo, SIGNAL(activated(int)), this, SLOT(checkCCD(int)));
00063 connect(filterCombo, SIGNAL(activated(int)), this, SLOT(updateFilterCombo(int)));
00064
00065 active = false;
00066 ISOStamp = false;
00067 seqExpose = 0;
00068 seqTotalCount = 0;
00069 seqCurrentCount = 0;
00070 seqDelay = 0;
00071 lastCCD = 0;
00072 lastFilter = 0;
00073 stdDevCCD = NULL;
00074 stdDevFilter = NULL;
00075
00076 }
00077
00078 imagesequence::~imagesequence()
00079 {
00080 }
00081
00082 bool imagesequence::updateStatus()
00083 {
00084 bool result;
00085
00086 result = setupCCDs();
00087 setupFilters();
00088
00089
00090 return result;
00091
00092 }
00093
00094 void imagesequence::newCCD()
00095 {
00096
00097 if (isVisible())
00098 setupCCDs();
00099 }
00100
00101 void imagesequence::newFilter()
00102 {
00103
00104 if (isVisible())
00105 setupFilters();
00106 }
00107
00108 bool imagesequence::setupCCDs()
00109 {
00110 bool imgDeviceFound (false);
00111 INDI_P *imgProp;
00112 INDIMenu *devMenu = ksw->getINDIMenu();
00113 if (devMenu == NULL)
00114 return false;
00115
00116 CCDCombo->clear();
00117
00118 for (uint i=0; i < devMenu->mgr.count(); i++)
00119 {
00120 for (uint j=0; j < devMenu->mgr.at(i)->indi_dev.count(); j++)
00121 {
00122 imgProp = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("CCD_EXPOSE_DURATION");
00123 if (!imgProp)
00124 continue;
00125
00126 imgDeviceFound = true;
00127
00128 if (devMenu->mgr.at(i)->indi_dev.at(j)->label.isEmpty())
00129 devMenu->mgr.at(i)->indi_dev.at(j)->label = devMenu->mgr.at(i)->indi_dev.at(j)->name;
00130
00131 CCDCombo->insertItem(devMenu->mgr.at(i)->indi_dev.at(j)->label);
00132
00133 }
00134
00135 }
00136
00137 if (imgDeviceFound)
00138 {
00139 CCDCombo->setCurrentItem(lastCCD);
00140 currentCCD = CCDCombo->currentText();
00141 }
00142 else return false;
00143
00144 if (!verifyCCDIntegrity())
00145 {
00146 stopSequence();
00147 return false;
00148 }
00149 else
00150 {
00151 INDI_P *exposeProp;
00152 INDI_E *exposeElem;
00153
00154 exposeProp = stdDevCCD->dp->findProp("CCD_EXPOSE_DURATION");
00155 if (!exposeProp)
00156 {
00157 KMessageBox::error(this, i18n("Device does not support CCD_EXPOSE_DURATION property."));
00158 return false;
00159 }
00160
00161 exposeElem = exposeProp->findElement("EXPOSE_DURATION");
00162 if (!exposeElem)
00163 {
00164 KMessageBox::error(this, i18n("CCD_EXPOSE_DURATION property is missing DURATION element."));
00165 return false;
00166 }
00167
00168 exposureIN->setValue(exposeElem->value);
00169 }
00170
00171 return true;
00172
00173 }
00174
00175 bool imagesequence::setupFilters()
00176 {
00177 bool filterDeviceFound(false);
00178 INDI_P *filterProp;
00179 INDIMenu *devMenu = ksw->getINDIMenu();
00180 if (devMenu == NULL)
00181 return false;
00182
00183 filterCombo->clear();
00184 filterPosCombo->clear();
00185
00186 filterCombo->insertItem(i18n("None"));
00187
00188
00189 for (uint i=0; i < devMenu->mgr.count(); i++)
00190 {
00191 for (uint j=0; j < devMenu->mgr.at(i)->indi_dev.count(); j++)
00192 {
00193 filterProp = devMenu->mgr.at(i)->indi_dev.at(j)->findProp("FILTER_SLOT");
00194 if (!filterProp)
00195 continue;
00196
00197 filterDeviceFound = true;
00198
00199 if (devMenu->mgr.at(i)->indi_dev.at(j)->label.isEmpty())
00200 devMenu->mgr.at(i)->indi_dev.at(j)->label = devMenu->mgr.at(i)->indi_dev.at(j)->name;
00201
00202 filterCombo->insertItem(devMenu->mgr.at(i)->indi_dev.at(j)->label);
00203
00204 }
00205
00206 }
00207
00208
00209
00210 if (filterDeviceFound)
00211 {
00212 filterCombo->setCurrentItem(lastFilter);
00213 currentFilter = filterCombo->currentText();
00214 updateFilterCombo(lastFilter);
00215 return true;
00216 }
00217 else
00218 return false;
00219
00220 }
00221
00222 void imagesequence::resetButtons()
00223 {
00224 startB->setEnabled(true);
00225 stopB->setEnabled(false);
00226
00227 }
00228
00229 void imagesequence::startSequence()
00230 {
00231
00232 if (active)
00233 stopSequence();
00234
00235
00236 if (!verifyCCDIntegrity())
00237 return;
00238
00239
00240
00241 active = true;
00242 ISOStamp = ISOCheck->isChecked() ? true : false;
00243 seqExpose = exposureIN->value();
00244 seqTotalCount = countIN->value();
00245 seqCurrentCount = 0;
00246 seqDelay = delayIN->value() * 1000;
00247 currentCCD = CCDCombo->currentText();
00248 lastCCD = CCDCombo->currentItem();
00249 currentFilter = filterCombo->currentText();
00250 lastFilter = filterCombo->currentItem();
00251
00252 fullImgCountOUT->setText( QString("%1").arg(seqTotalCount));
00253 currentImgCountOUT->setText(QString("%1").arg(seqCurrentCount));
00254
00255
00256 connect(stdDevCCD, SIGNAL(FITSReceived(QString)), this, SLOT(newFITS(QString)));
00257
00258
00259 imgProgress->setEnabled(true);
00260 imgProgress->setTotalSteps(seqTotalCount);
00261 imgProgress->setProgress(seqCurrentCount);
00262
00263 stdDevCCD->batchMode = true;
00264 stdDevCCD->ISOMode = ISOStamp;
00265
00266 stdDevCCD->updateSequencePrefix(prefixIN->text());
00267
00268
00269
00270 startB->setEnabled(false);
00271 stopB->setEnabled(true);
00272
00273 prepareCapture();
00274 }
00275
00276 void imagesequence::stopSequence()
00277 {
00278
00279 retries = 0;
00280 seqTotalCount = 0;
00281 seqCurrentCount = 0;
00282 active = false;
00283
00284 imgProgress->setEnabled(false);
00285 fullImgCountOUT->setText("");
00286 currentImgCountOUT->setText("");
00287
00288 resetButtons();
00289 seqTimer->stop();
00290
00291 if (stdDevCCD)
00292 {
00293 stdDevCCD->seqCount = 0;
00294 stdDevCCD->batchMode = false;
00295 stdDevCCD->ISOMode = false;
00296
00297 stdDevCCD->disconnect( SIGNAL(FITSReceived(QString)));
00298 }
00299
00300 }
00301
00302 void imagesequence::checkCCD(int ccdNum)
00303 {
00304 INDI_D *idevice = NULL;
00305 QString targetCCD = CCDCombo->text(ccdNum);
00306
00307 INDIMenu *imenu = ksw->getINDIMenu();
00308 if (!imenu)
00309 {
00310 KMessageBox::error(this, i18n("INDI Menu has not been initialized properly. Restart KStars."));
00311 return;
00312 }
00313
00314 idevice = imenu->findDeviceByLabel(targetCCD);
00315
00316 if (!idevice)
00317 {
00318 KMessageBox::error(this, i18n("INDI device %1 no longer exists.").arg(targetCCD));
00319 CCDCombo->removeItem(ccdNum);
00320 lastCCD = CCDCombo->currentItem();
00321 if (lastCCD != -1)
00322 checkCCD(lastCCD);
00323 return;
00324 }
00325
00326 if (!idevice->isOn())
00327 {
00328 KMessageBox::error(this, i18n("%1 is disconnected. Establish a connection to the device using the INDI Control Panel.").arg(targetCCD));
00329
00330 CCDCombo->setCurrentItem(lastCCD);
00331 return;
00332 }
00333
00334 currentCCD = targetCCD;
00335
00336 }
00337
00338 void imagesequence::newFITS(QString deviceLabel)
00339 {
00340
00341 if (deviceLabel != currentCCD)
00342 return;
00343
00344 seqCurrentCount++;
00345 imgProgress->setProgress(seqCurrentCount);
00346
00347 currentImgCountOUT->setText( QString("%1").arg(seqCurrentCount));
00348
00349
00350 if (seqCurrentCount == seqTotalCount)
00351 {
00352 stdDevCCD->batchMode = false;
00353 stdDevCCD->ISOMode = false;
00354 retries = 0;
00355 seqTotalCount = 0;
00356 seqCurrentCount = 0;
00357 active = false;
00358 seqTimer->stop();
00359
00360 if (stdDevCCD)
00361 stdDevCCD->disconnect( SIGNAL(FITSReceived(QString)));
00362
00363 resetButtons();
00364 }
00365 else
00366 seqTimer->start(seqDelay);
00367
00368 }
00369
00370
00371 bool imagesequence::verifyCCDIntegrity()
00372 {
00373
00374 QString targetCCD;
00375 INDI_D *idevice = NULL;
00376 INDI_P *exposeProp;
00377 INDI_E *exposeElem;
00378 stdDevCCD = NULL;
00379
00380 INDIMenu *imenu = ksw->getINDIMenu();
00381 if (!imenu)
00382 {
00383 KMessageBox::error(this, i18n("INDI Menu has not been initialized properly. Restart KStars."));
00384 return false;
00385 }
00386
00387 targetCCD = CCDCombo->currentText();
00388
00389 if (targetCCD.isEmpty())
00390 return false;
00391
00392
00393 idevice = imenu->findDeviceByLabel(targetCCD);
00394
00395
00396 if (!idevice)
00397 {
00398 KMessageBox::error(this, i18n("INDI device %1 no longer exists.").arg(targetCCD));
00399 CCDCombo->removeItem(CCDCombo->currentItem());
00400 lastCCD = CCDCombo->currentItem();
00401 return false;
00402 }
00403
00404 if (!idevice->isOn())
00405 {
00406 KMessageBox::error(this, i18n("%1 is disconnected. Establish a connection to the device using the INDI Control Panel.").arg(currentCCD));
00407
00408 return false;
00409 }
00410
00411 stdDevCCD = idevice->stdDev;
00412
00413 exposeProp = stdDevCCD->dp->findProp("CCD_EXPOSE_DURATION");
00414 if (!exposeProp)
00415 {
00416 KMessageBox::error(this, i18n("Device does not support CCD_EXPOSE_DURATION property."));
00417 return false;
00418 }
00419
00420 exposeElem = exposeProp->findElement("EXPOSE_DURATION");
00421 if (!exposeElem)
00422 {
00423 KMessageBox::error(this, i18n("CCD_EXPOSE_DURATION property is missing DURATION element."));
00424 return false;
00425 }
00426
00427 return true;
00428 }
00429
00430 bool imagesequence::verifyFilterIntegrity()
00431 {
00432
00433 QString targetFilter;
00434 INDIMenu *devMenu = ksw->getINDIMenu();
00435 INDI_D *filterDevice (NULL);
00436 INDI_E *filterElem(NULL);
00437 if (devMenu == NULL)
00438 return false;
00439
00440 targetFilter = filterCombo->currentText();
00441
00442 if (targetFilter.isEmpty() || targetFilter == i18n("None"))
00443 {
00444 filterPosCombo->clear();
00445 return false;
00446 }
00447
00448
00449 filterDevice = devMenu->findDeviceByLabel(targetFilter);
00450 if (filterDevice == NULL)
00451 {
00452 KMessageBox::error(this, i18n("INDI device %1 no longer exists.").arg(targetFilter));
00453 filterCombo->removeItem(filterCombo->currentItem());
00454 filterCombo->setCurrentItem(0);
00455 currentFilter = filterCombo->currentText();
00456 filterPosCombo->clear();
00457 stdDevFilter = NULL;
00458 return false;
00459 }
00460
00461
00462 if (!filterDevice->isOn())
00463 {
00464 KMessageBox::error(this, i18n("%1 is disconnected. Establish a connection to the device using the INDI Control Panel.").arg(targetFilter));
00465 filterCombo->setCurrentItem(0);
00466 currentFilter = filterCombo->currentText();
00467 filterPosCombo->clear();
00468 stdDevFilter = NULL;
00469 return false;
00470 }
00471
00472
00473 filterElem = filterDevice->findElem("SLOT");
00474 if (filterElem == NULL)
00475 {
00476 KMessageBox::error(this, i18n("Device does not support FILTER_SLOT property."));
00477 filterCombo->setCurrentItem(0);
00478 currentFilter = filterCombo->currentText();
00479 filterPosCombo->clear();
00480 stdDevFilter = NULL;
00481 return false;
00482 }
00483
00484 stdDevFilter = filterDevice->stdDev;
00485 lastFilter = filterCombo->currentItem();
00486 currentFilter = targetFilter;
00487
00488
00489 return true;
00490
00491 }
00492
00493 void imagesequence::prepareCapture()
00494 {
00495 INDI_P * tempProp(NULL);
00496
00497
00498 if (currentFilter.isEmpty() || currentFilter == i18n("None"))
00499 captureImage();
00500 else
00501 {
00502 if (!verifyFilterIntegrity())
00503 {
00504 stopSequence();
00505 return;
00506 }
00507
00508 if ( stdDevFilter && ((tempProp = stdDevFilter->dp->findProp("FILTER_SLOT")) != NULL))
00509 {
00510 connect (tempProp, SIGNAL(okState()), this, SLOT(captureImage()));
00511 selectFilter();
00512 }
00513 else
00514 kdDebug() << "Error: std Filter device lost or missing FILTER_SLOT property" << endl;
00515 }
00516
00517 }
00518
00519 void imagesequence::captureImage()
00520 {
00521
00522 INDI_P * exposeProp(NULL);
00523 INDI_E * exposeElem(NULL);
00524 INDI_P * tempProp(NULL);
00525
00526
00527
00528
00529
00530
00531
00532
00533 if ( stdDevFilter && ((tempProp = stdDevFilter->dp->findProp("FILTER_SLOT")) != NULL))
00534 tempProp->disconnect( SIGNAL (okState()));
00535
00536 if (!verifyCCDIntegrity())
00537 {
00538 stopSequence();
00539 return;
00540 }
00541
00542 exposeProp = stdDevCCD->dp->findProp("CCD_EXPOSE_DURATION");
00543 exposeElem = exposeProp->findElement("EXPOSE_DURATION");
00544
00545
00546 seqTimer->stop();
00547
00548
00549 if (exposeProp->state == PS_BUSY)
00550 {
00551 retries++;
00552
00553 if (retries > RETRY_MAX)
00554 {
00555 seqTimer->stop();
00556 KMessageBox::error(this, i18n("Device is busy and not responding."));
00557 stopSequence();
00558 retries = 0;
00559 return;
00560 }
00561
00562 seqTimer->start(RETRY_PERIOD);
00563 }
00564
00565
00566 if (exposeProp->perm == PP_RW || exposeProp->perm == PP_WO)
00567 {
00568 if (seqExpose < exposeElem->min || seqExpose > exposeElem->max)
00569 {
00570 stopSequence();
00571 KMessageBox::error(this, i18n("Expose duration is invalid. %1 supports expose durations from %2 to %3 seconds only.").arg(currentCCD).arg(exposeElem->min).arg(exposeElem->max));
00572 return;
00573 }
00574
00575
00576 exposeElem->targetValue = seqExpose;
00577 if (exposeElem->spin_w)
00578 {
00579 exposeElem->spin_w->setValue(seqExpose);
00580 exposeElem->spinChanged(seqExpose);
00581 }
00582 else
00583 exposeElem->write_w->setText( QString("%1").arg(seqExpose));
00584
00585 }
00586
00587
00588 exposeProp->newText();
00589
00590 }
00591
00592 void imagesequence::updateFilterCombo(int filterNum)
00593 {
00594 INDIMenu *devMenu = ksw->getINDIMenu();
00595 QStringList filterList;
00596 INDI_E *filterElem;
00597 unsigned int filterMax;
00598
00599 if (!verifyFilterIntegrity())
00600 return;
00601
00602 filterList = Options::filterAlias();
00603
00604 filterElem = devMenu->findDeviceByLabel(filterCombo->text(filterNum))->findElem("SLOT");
00605 filterMax = (int) filterElem->max;
00606
00607
00608 filterPosCombo->clear();
00609
00610 if (filterList.empty())
00611 for (unsigned int i=0; i <= filterMax; i++)
00612 filterList << QString("%1").arg(i);
00613
00614
00615 if (filterList.count() <= filterMax)
00616 {
00617 filterPosCombo->insertStringList(filterList);
00618 for (unsigned int i = filterList.count() ; i <= filterMax ; i++)
00619 filterPosCombo->insertItem(QString("%1").arg(i));
00620 } else
00621 {
00622
00623 for (unsigned int i = 0 ; i <= filterMax ; i++)
00624 filterPosCombo->insertItem(QString("%1").arg(filterList[i]));
00625
00626 }
00627
00628 filterPosCombo->setCurrentItem(((int) filterElem->value));
00629
00630 }
00631
00632 void imagesequence::selectFilter()
00633 {
00634
00635 INDI_P * filterProp(NULL);
00636 INDI_E * filterElem(NULL);
00637 INDI_D * filterDev(NULL);
00638 INDIMenu *devMenu = ksw->getINDIMenu();
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 if (!verifyFilterIntegrity())
00649 return;
00650
00651 filterDev = devMenu->findDeviceByLabel(currentFilter);
00652 filterProp = filterDev->findProp("FILTER_SLOT");
00653 filterElem = filterProp->findElement("SLOT");
00654
00655
00656 if (filterPosCombo->currentItem() == filterElem->read_w->text().toInt())
00657 {
00658 captureImage();
00659 return;
00660 }
00661
00662 if (filterProp->perm == PP_RW || filterProp->perm == PP_WO)
00663 {
00664 filterElem->targetValue = filterPosCombo->currentItem();
00665 if (filterElem->spin_w)
00666 {
00667 filterElem->spin_w->setValue(filterElem->targetValue);
00668 filterElem->spinChanged(filterElem->targetValue);
00669 }
00670 else
00671 filterElem->write_w->setText(QString("%1").arg(filterElem->targetValue));
00672
00673
00674 filterProp->newText();
00675 }
00676
00677 }
00678
00679 #include "imagesequence.moc"
00680