• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kstars

imagesequence.cpp

Go to the documentation of this file.
00001 /*  Image Sequence
00002     Capture image sequence from an imaging device.
00003     
00004     Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
00005 
00006     This application is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
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   // Connect signals and slots
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   // If everything okay, let's show the dialog
00090   return result;
00091    
00092  }
00093 
00094 void imagesequence::newCCD()
00095 {
00096    // Only update when it's visible
00097    if (isVisible())
00098       setupCCDs();
00099 }
00100 
00101 void imagesequence::newFilter()
00102 {
00103    // Only update when it's visible
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   // Second step is to check for filter wheel, it is only optional.
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   // If we found device, let's populate filters combo with aliases assigned to filter numbers
00209   // In Configure INDI
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   // Let's find out which device has been selected and that it's connected.
00236   if (!verifyCCDIntegrity())
00237    return;
00238   
00239  
00240   // Get expose paramater
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;      /* in ms */
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   // Ok, now let's connect signals and slots for this device
00256   connect(stdDevCCD, SIGNAL(FITSReceived(QString)), this, SLOT(newFITS(QString)));
00257   
00258   // set the progress info
00259   imgProgress->setEnabled(true);
00260   imgProgress->setTotalSteps(seqTotalCount);
00261   imgProgress->setProgress(seqCurrentCount);
00262   
00263   stdDevCCD->batchMode    = true;
00264   stdDevCCD->ISOMode      = ISOStamp;
00265   // Set this LAST
00266   stdDevCCD->updateSequencePrefix(prefixIN->text());
00267   
00268   
00269   // Update button status
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   // If the FITS is not for our device, simply ignore
00341   if (deviceLabel != currentCCD)
00342    return;
00343 
00344   seqCurrentCount++;
00345   imgProgress->setProgress(seqCurrentCount);
00346   
00347   currentImgCountOUT->setText( QString("%1").arg(seqCurrentCount));
00348   
00349   // if we're done
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   // #2 Check if the device exists
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   // #1 Check the device exists
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   // #2 Make sure it's connected
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   // #3 Make sure it has FILTER_SLOT std property by searching for its SLOT element
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   // We're good
00489   return true;
00490 
00491 }
00492 
00493 void imagesequence::prepareCapture()
00494 {
00495   INDI_P * tempProp(NULL);
00496 
00497   // Do we need to select filter First??
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   // Let's capture a new frame in acoord with the settings
00527   // We need to take into consideration the following conditions:
00528   // A. The device has been disconnected.
00529   // B. The device has been lost.
00530   // C. The property is still busy.
00531   // D. The property has been lost.
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   // disable timer until it's called again by newFITS, or called for retries
00546   seqTimer->stop();
00547   
00548   // Make sure it's not busy, if it is then schedual.
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   // Set duration if applicable. We check the property permission, min, and max values
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     // we're okay, set it
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   // We're done! Send it to the driver
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   // Clear combo
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   // Fill filter combo
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       // filterMax < filterList.count()
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   // Let's select a new filter in acoord with the settings
00641   // We need to take into consideration the following conditions:
00642   // A. The device has been disconnected.
00643   // B. The device has been lost.
00644   // C. The property is still busy.
00645   // D. The property has been lost.
00646   
00647   // We have a filter, let's check if it's valid
00648   if (!verifyFilterIntegrity())
00649    return;
00650 
00651   filterDev = devMenu->findDeviceByLabel(currentFilter);
00652   filterProp = filterDev->findProp("FILTER_SLOT");
00653   filterElem = filterProp->findElement("SLOT");
00654 
00655   // Do we need to change the filter position??
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     // We're done! Send it to the driver
00674     filterProp->newText();
00675   }
00676 
00677 }
00678 
00679 #include "imagesequence.moc"
00680 

kstars

Skip menu "kstars"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • keduca
  • kstars
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal