You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1046 lines
26 KiB
1046 lines
26 KiB
/* INDI STD
|
|
Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
|
|
|
|
This apppication is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
2004-01-18: This class handles INDI Standard properties.
|
|
*/
|
|
|
|
#include "indistd.h"
|
|
#include "Options.h"
|
|
#include "indielement.h"
|
|
#include "indiproperty.h"
|
|
#include "indigroup.h"
|
|
#include "indidevice.h"
|
|
#include "indidriver.h"
|
|
#include "kstars.h"
|
|
#include "kstarsdata.h"
|
|
#include "skymap.h"
|
|
#include "skyobject.h"
|
|
#include "simclock.h"
|
|
#include "devicemanager.h"
|
|
#include "timedialog.h"
|
|
#include "streamwg.h"
|
|
#include "ccdpreviewwg.h"
|
|
#include "fitsviewer.h"
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <ctype.h>
|
|
#include <zlib.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <tqtimer.h>
|
|
#include <tqlabel.h>
|
|
#include <tqfont.h>
|
|
#include <tqeventloop.h>
|
|
#include <tqsocketnotifier.h>
|
|
|
|
#include <tdelocale.h>
|
|
#include <kdebug.h>
|
|
#include <kpushbutton.h>
|
|
#include <klineedit.h>
|
|
#include <kstatusbar.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tdeapplication.h>
|
|
#include <kprogress.h>
|
|
#include <kurl.h>
|
|
#include <kdirlister.h>
|
|
#include <tdeaction.h>
|
|
|
|
|
|
#define STD_BUFFER_SIZ 1024000
|
|
#define FRAME_ILEN 1024
|
|
|
|
INDIStdDevice::INDIStdDevice(INDI_D *associatedDevice, KStars * kswPtr)
|
|
{
|
|
|
|
dp = associatedDevice;
|
|
ksw = kswPtr;
|
|
initDevCounter = 0;
|
|
setCount = 0;
|
|
batchMode = false;
|
|
ISOMode = false;
|
|
|
|
currentObject = NULL;
|
|
streamWindow = new StreamWG(this, ksw);
|
|
CCDPreviewWindow = new CCDPreviewWG(this, ksw);
|
|
|
|
devTimer = new TQTimer(this);
|
|
seqLister = new KDirLister();
|
|
|
|
telescopeSkyObject = new SkyObject(0, 0, 0, 0, i18n("Telescope"));
|
|
ksw->data()->appendTelescopeObject(telescopeSkyObject);
|
|
|
|
connect( devTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(timerDone()) );
|
|
connect( seqLister, TQT_SIGNAL(newItems (const KFileItemList & )), this, TQT_SLOT(checkSeqBoundary(const KFileItemList &)));
|
|
|
|
downloadDialog = new KProgressDialog(NULL, 0, i18n("INDI"), i18n("Downloading Data..."));
|
|
downloadDialog->cancel();
|
|
|
|
parser = newLilXML();
|
|
}
|
|
|
|
INDIStdDevice::~INDIStdDevice()
|
|
{
|
|
streamWindow->enableStream(false);
|
|
streamWindow->close();
|
|
CCDPreviewWindow->enableStream(false);
|
|
CCDPreviewWindow->close();
|
|
streamDisabled();
|
|
delete (seqLister);
|
|
}
|
|
|
|
void INDIStdDevice::handleBLOB(unsigned char *buffer, int bufferSize, TQString dataFormat)
|
|
{
|
|
|
|
if (dataFormat == ".fits") dataType = DATA_FITS;
|
|
else if (dataFormat == ".stream") dataType = DATA_STREAM;
|
|
else if (dataFormat == ".ccdpreview") dataType = DATA_CCDPREVIEW;
|
|
else dataType = DATA_OTHER;
|
|
|
|
if (dataType == DATA_STREAM)
|
|
{
|
|
if (!streamWindow->processStream)
|
|
return;
|
|
|
|
streamWindow->show();
|
|
streamWindow->streamFrame->newFrame( buffer, bufferSize, streamWindow->streamWidth, streamWindow->streamHeight);
|
|
}
|
|
else if (dataType == DATA_CCDPREVIEW)
|
|
{
|
|
if (!CCDPreviewWindow->processStream)
|
|
return;
|
|
CCDPreviewWindow->show();
|
|
CCDPreviewWindow->streamFrame->newFrame( buffer, bufferSize, CCDPreviewWindow->streamWidth, CCDPreviewWindow->streamHeight);
|
|
}
|
|
else if (dataType == DATA_FITS || dataType == DATA_OTHER)
|
|
{
|
|
char filename[256];
|
|
FILE *fitsTempFile;
|
|
int fd, nr, n=0;
|
|
TQString currentDir = Options::fitsSaveDirectory();
|
|
|
|
streamWindow->close();
|
|
|
|
if (dataType == DATA_FITS && !batchMode && Options::indiFITSDisplay())
|
|
{
|
|
strcpy(filename, "/tmp/fitsXXXXXX");
|
|
if ((fd = mkstemp(filename)) < 0)
|
|
{
|
|
KMessageBox::error(NULL, "Error making temporary filename.");
|
|
return;
|
|
}
|
|
close(fd);
|
|
}
|
|
else
|
|
{
|
|
char ts[32];
|
|
struct tm *tp;
|
|
time_t t;
|
|
time (&t);
|
|
tp = gmtime (&t);
|
|
|
|
if (currentDir[currentDir.length() -1] == '/')
|
|
currentDir.truncate(currentDir.length() - 1);
|
|
|
|
strncpy(filename, currentDir.ascii(), currentDir.length());
|
|
filename[currentDir.length()] = '\0';
|
|
|
|
if (dataType == DATA_FITS)
|
|
{
|
|
char tempFileStr[256];
|
|
strncpy(tempFileStr, filename, 256);
|
|
|
|
if ( batchMode && !ISOMode)
|
|
snprintf(filename, sizeof(filename), "%s/%s_%02d.fits", tempFileStr, seqPrefix.ascii(), setCount);
|
|
else if (!batchMode && !Options::indiFITSDisplay())
|
|
{
|
|
strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
|
|
snprintf(filename, sizeof(filename), "%s/file_%s.fits", tempFileStr, ts);
|
|
}
|
|
else
|
|
{
|
|
strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
|
|
snprintf(filename, sizeof(filename), "%s/%s_%02d_%s.fits", tempFileStr, seqPrefix.ascii(), setCount, ts);
|
|
}
|
|
|
|
setCount++;
|
|
}
|
|
else
|
|
{
|
|
strftime (ts, sizeof(ts), "/file-%Y-%m-%dT%H:%M:%S.", tp);
|
|
strncat(filename, ts, sizeof(ts));
|
|
strncat(filename, dataFormat.ascii(), 10);
|
|
}
|
|
}
|
|
|
|
fitsTempFile = fopen(filename, "w");
|
|
|
|
if (fitsTempFile == NULL) return;
|
|
|
|
for (nr=0; nr < (int) bufferSize; nr += n)
|
|
n = fwrite( ((unsigned char *) buffer) + nr, 1, bufferSize - nr, fitsTempFile);
|
|
|
|
fclose(fitsTempFile);
|
|
|
|
// We're done if we have DATA_OTHER
|
|
if (dataType == DATA_OTHER)
|
|
{
|
|
ksw->statusBar()->changeItem( i18n("Data file saved to %1").arg(filename), 0);
|
|
return;
|
|
}
|
|
else if (dataType == DATA_FITS && (batchMode || !Options::indiFITSDisplay()))
|
|
{
|
|
ksw->statusBar()->changeItem( i18n("FITS file saved to %1").arg(filename), 0);
|
|
emit FITSReceived(dp->label);
|
|
return;
|
|
}
|
|
|
|
KURL fileURL(filename);
|
|
|
|
FITSViewer * fv = new FITSViewer(&fileURL, ksw);
|
|
fv->fitsChange();
|
|
fv->show();
|
|
}
|
|
|
|
}
|
|
|
|
/* Process standard Text and Number properties arrives from the driver */
|
|
void INDIStdDevice::setTextValue(INDI_P *pp)
|
|
{
|
|
INDI_E *el;
|
|
int wd, ht, bpp, bo, mu;
|
|
long mgd;
|
|
double fwhm;
|
|
int d, m, y, min, sec, hour;
|
|
ExtDate indiDate;
|
|
TQTime indiTime;
|
|
KStarsDateTime indiDateTime;
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
|
|
case TIME:
|
|
if ( Options::indiAutoTime() )
|
|
handleDevCounter();
|
|
|
|
// Update KStars time once we receive update from INDI
|
|
el = pp->findElement("UTC");
|
|
if (!el) return;
|
|
|
|
sscanf(el->text.ascii(), "%d%*[^0-9]%d%*[^0-9]%dT%d%*[^0-9]%d%*[^0-9]%d", &y, &m, &d, &hour, &min, &sec);
|
|
indiDate.setYMD(y, m, d);
|
|
indiTime.setHMS(hour, min, sec);
|
|
indiDateTime.setDate(indiDate);
|
|
indiDateTime.setTime(indiTime);
|
|
|
|
ksw->data()->changeDateTime(indiDateTime);
|
|
ksw->data()->syncLST();
|
|
|
|
break;
|
|
|
|
case SDTIME:
|
|
if ( Options::indiAutoTime())
|
|
handleDevCounter();
|
|
break;
|
|
|
|
case GEOGRAPHIC_COORD:
|
|
if ( Options::indiAutoGeo() )
|
|
handleDevCounter();
|
|
break;
|
|
|
|
case CCD_EXPOSE_DURATION:
|
|
if (pp->state == PS_IDLE || pp->state == PS_OK)
|
|
pp->set_w->setText(i18n("Start"));
|
|
break;
|
|
|
|
case CCD_FRAME:
|
|
el = pp->findElement("WIDTH");
|
|
if (!el) return;
|
|
wd = (int) el->value;
|
|
el = pp->findElement("HEIGHT");
|
|
if (!el) return;
|
|
ht = (int) el->value;
|
|
|
|
streamWindow->setSize(wd, ht);
|
|
//streamWindow->allocateStreamBuffer();
|
|
break;
|
|
case CCDPREVIEW_CTRL:
|
|
el = pp->findElement("WIDTH");
|
|
if (!el) return;
|
|
wd = (int) el->value;
|
|
el = pp->findElement("HEIGHT");
|
|
if (!el) return;
|
|
ht = (int) el->value;
|
|
el = pp->findElement("BYTEORDER");
|
|
if (!el) return;
|
|
bo = (int) el->value;
|
|
el = pp->findElement("BYTESPERPIXEL");
|
|
if (!el) return;
|
|
bpp = (int) el->value;
|
|
el = pp->findElement("MAXGOODDATA");
|
|
if (!el) return;
|
|
mgd = (long) el->value;
|
|
CCDPreviewWindow->setCtrl(wd, ht, bo ,bpp,mgd);
|
|
|
|
break;
|
|
|
|
case CCD_INFO:
|
|
el = pp->findElement("CCD_FWHM_PIXEL");
|
|
if (!el) return;
|
|
fwhm = el->value;
|
|
el = pp->findElement("CCD_PIXEL_SIZE");
|
|
if (!el) return;
|
|
mu = (int) el->value;
|
|
CCDPreviewWindow->setCCDInfo(fwhm, mu);
|
|
break;
|
|
|
|
case EQUATORIAL_COORD:
|
|
case EQUATORIAL_EOD_COORD:
|
|
if (!dp->isOn()) break;
|
|
el = pp->findElement("RA");
|
|
if (!el) return;
|
|
telescopeSkyObject->setRA(el->value);
|
|
el = pp->findElement("DEC");
|
|
if (!el) return;
|
|
telescopeSkyObject->setDec(el->value);
|
|
telescopeSkyObject->EquatorialToHorizontal(ksw->LST(), ksw->geo()->lat());
|
|
// Force immediate update of skymap if the focus object is our telescope.
|
|
if (ksw->map()->focusObject() == telescopeSkyObject)
|
|
ksw->map()->updateFocus();
|
|
else
|
|
ksw->map()->update();
|
|
break;
|
|
|
|
case HORIZONTAL_COORD:
|
|
if (!dp->isOn()) break;
|
|
el = pp->findElement("ALT");
|
|
if (!el) return;
|
|
telescopeSkyObject->setAlt(el->value);
|
|
el = pp->findElement("AZ");
|
|
if (!el) return;
|
|
telescopeSkyObject->setAz(el->value);
|
|
telescopeSkyObject->HorizontalToEquatorial(ksw->LST(), ksw->geo()->lat());
|
|
// Force immediate update of skymap if the focus object is our telescope.
|
|
if (ksw->map()->focusObject() == telescopeSkyObject)
|
|
ksw->map()->updateFocus();
|
|
else
|
|
ksw->map()->update();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void INDIStdDevice::setLabelState(INDI_P *pp)
|
|
{
|
|
INDI_E *lp;
|
|
INDI_P *imgProp;
|
|
TDEAction *tmpAction;
|
|
INDIDriver *drivers = ksw->getINDIDriver();
|
|
TQFont buttonFont;
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
case CONNECTION:
|
|
lp = pp->findElement("CONNECT");
|
|
if (!lp) return;
|
|
|
|
if (lp->state == PS_ON)
|
|
{
|
|
initDeviceOptions();
|
|
emit linkAccepted();
|
|
|
|
imgProp = dp->findProp("CCD_EXPOSE_DURATION");
|
|
if (imgProp)
|
|
{
|
|
tmpAction = ksw->actionCollection()->action("capture_sequence");
|
|
if (!tmpAction)
|
|
kdDebug() << "Warning: capture_sequence action not found" << endl;
|
|
else
|
|
tmpAction->setEnabled(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (streamWindow)
|
|
{
|
|
//sNotifier->disconnect();
|
|
//dp->parentMgr->sNotifier->disconnect();
|
|
streamWindow->enableStream(false);
|
|
streamWindow->close();
|
|
|
|
//close(streamFD);
|
|
}
|
|
|
|
if (ksw->map()->focusObject() == telescopeSkyObject)
|
|
{
|
|
ksw->map()->stopTracking();
|
|
ksw->map()->setFocusObject(NULL);
|
|
}
|
|
|
|
drivers->updateMenuActions();
|
|
ksw->map()->forceUpdateNow();
|
|
emit linkRejected();
|
|
}
|
|
break;
|
|
|
|
case VIDEO_STREAM:
|
|
lp = pp->findElement("ON");
|
|
if (!lp) return;
|
|
if (lp->state == PS_ON)
|
|
streamWindow->enableStream(true);
|
|
else
|
|
streamWindow->enableStream(false);
|
|
break;
|
|
|
|
case CCDPREVIEW_STREAM:
|
|
lp = pp->findElement("ON");
|
|
if (!lp) return;
|
|
if (lp->state == PS_ON)
|
|
CCDPreviewWindow->enableStream(true);
|
|
else
|
|
CCDPreviewWindow->enableStream(false);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void INDIStdDevice::streamDisabled()
|
|
{
|
|
INDI_P *pp;
|
|
INDI_E *el;
|
|
|
|
//pp = dp->findProp("CONNECTION");
|
|
//if (!pp) return;
|
|
//if (pp->state == PS_OFF) return;
|
|
|
|
pp = dp->findProp("VIDEO_STREAM");
|
|
if (!pp) return;
|
|
|
|
el = pp->findElement("OFF");
|
|
if (!el) return;
|
|
|
|
if (el->state == PS_ON)
|
|
return;
|
|
|
|
// Turn stream off
|
|
pp->newSwitch(1);
|
|
|
|
}
|
|
|
|
void INDIStdDevice::updateSequencePrefix(TQString newPrefix)
|
|
{
|
|
seqPrefix = newPrefix;
|
|
|
|
seqLister->setNameFilter(TQString("%1_*.fits").arg(seqPrefix));
|
|
|
|
setCount = 0;
|
|
|
|
if (ISOMode) return;
|
|
|
|
seqLister->openURL(Options::fitsSaveDirectory());
|
|
|
|
checkSeqBoundary(seqLister->items());
|
|
|
|
}
|
|
|
|
void INDIStdDevice::checkSeqBoundary(const KFileItemList & items)
|
|
{
|
|
int newFileIndex;
|
|
TQString tempName;
|
|
char *tempPrefix = new char[64];
|
|
|
|
// No need to check when in ISO mode
|
|
if (ISOMode)
|
|
return;
|
|
|
|
for ( KFileItemListIterator it( items ) ; it.current() ; ++it )
|
|
{
|
|
tempName = it.current()->name();
|
|
|
|
// find the prefix first
|
|
if (tempName.find(seqPrefix) == -1)
|
|
continue;
|
|
|
|
strncpy(tempPrefix, tempName.ascii(), 64);
|
|
tempPrefix[63] = '\0';
|
|
|
|
char * t = tempPrefix;
|
|
|
|
// skip chars
|
|
while (*t) { if (isdigit(*t)) break; t++; }
|
|
//tempPrefix = t;
|
|
|
|
newFileIndex = strtol(t, NULL, 10);
|
|
|
|
if (newFileIndex >= setCount)
|
|
setCount = newFileIndex + 1;
|
|
}
|
|
|
|
delete [] (tempPrefix);
|
|
|
|
}
|
|
|
|
void INDIStdDevice::updateTime()
|
|
{
|
|
INDI_P *pp;
|
|
INDI_E *lp;
|
|
|
|
pp = dp->findProp("TIME");
|
|
if (!pp) return;
|
|
|
|
lp = pp->findElement("UTC");
|
|
|
|
if (!lp) return;
|
|
|
|
TQTime newTime( ksw->data()->ut().time());
|
|
ExtDate newDate( ksw->data()->ut().date());
|
|
|
|
lp->write_w->setText(TQString("%1-%2-%3T%4:%5:%6").arg(newDate.year()).arg(newDate.month())
|
|
.arg(newDate.day()).arg(newTime.hour())
|
|
.arg(newTime.minute()).arg(newTime.second()));
|
|
pp->newText();
|
|
|
|
pp = dp->findProp("SDTIME");
|
|
if (!pp) return;
|
|
lp = pp->findElement("LST");
|
|
if (!lp) return;
|
|
|
|
lp->write_w->setText(ksw->LST()->toHMSString());
|
|
pp->newText();
|
|
}
|
|
|
|
void INDIStdDevice::updateLocation()
|
|
{
|
|
INDI_P *pp;
|
|
INDI_E * latEle, * longEle;
|
|
GeoLocation *geo = ksw->geo();
|
|
|
|
pp = dp->findProp("GEOGRAPHIC_COORD");
|
|
if (!pp) return;
|
|
|
|
dms tempLong (geo->lng()->degree(), geo->lng()->arcmin(), geo->lng()->arcsec());
|
|
dms fullCir(360,0,0);
|
|
|
|
if (tempLong.degree() < 0)
|
|
tempLong.setD ( fullCir.Degrees() + tempLong.Degrees());
|
|
|
|
latEle = pp->findElement("LAT");
|
|
if (!latEle) return;
|
|
longEle = pp->findElement("LONG");
|
|
if (!longEle) return;
|
|
|
|
longEle->write_w->setText(TQString("%1:%2:%3").arg(tempLong.degree()).arg(tempLong.arcmin()).arg(tempLong.arcsec()));
|
|
latEle->write_w->setText(TQString("%1:%2:%3").arg(geo->lat()->degree()).arg(geo->lat()->arcmin()).arg(geo->lat()->arcsec()));
|
|
|
|
pp->newText();
|
|
}
|
|
|
|
|
|
void INDIStdDevice::registerProperty(INDI_P *pp)
|
|
{
|
|
INDI_E * portEle;
|
|
INDIDriver *drivers = ksw->getINDIDriver();
|
|
TQString str;
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
case DEVICE_PORT:
|
|
portEle = pp->findElement("PORT");
|
|
if (!portEle) return;
|
|
|
|
if (drivers)
|
|
{
|
|
for (unsigned int i=0; i < drivers->devices.size(); i++)
|
|
{
|
|
if (drivers->devices[i]->mgrID == dp->parentMgr->mgrID)
|
|
{
|
|
if (drivers->devices[i]->deviceType == KSTARS_TELESCOPE)
|
|
{
|
|
portEle->read_w->setText( Options::indiTelescopePort() );
|
|
portEle->write_w->setText( Options::indiTelescopePort() );
|
|
portEle->text = Options::indiTelescopePort();
|
|
break;
|
|
}
|
|
else if (drivers->devices[i]->deviceType == KSTARS_VIDEO)
|
|
{
|
|
portEle->read_w->setText( Options::indiVideoPort() );
|
|
portEle->write_w->setText( Options::indiVideoPort() );
|
|
portEle->text = Options::indiVideoPort();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void INDIStdDevice::initDeviceOptions()
|
|
{
|
|
|
|
INDI_P *prop;
|
|
|
|
initDevCounter = 0;
|
|
|
|
if ( Options::indiAutoTime() )
|
|
{
|
|
prop = dp->findProp("TIME");
|
|
if (prop)
|
|
{
|
|
updateTime();
|
|
initDevCounter += 5;
|
|
}
|
|
}
|
|
|
|
if ( Options::indiAutoGeo() )
|
|
{
|
|
prop = dp->findProp("GEOGRAPHIC_COORD");
|
|
if (prop)
|
|
{
|
|
updateLocation();
|
|
initDevCounter += 2;
|
|
}
|
|
}
|
|
|
|
if ( Options::indiMessages() )
|
|
ksw->statusBar()->changeItem( i18n("%1 is online.").arg(dp->name), 0);
|
|
|
|
ksw->map()->forceUpdateNow();
|
|
}
|
|
|
|
void INDIStdDevice::handleDevCounter()
|
|
{
|
|
|
|
if (initDevCounter <= 0)
|
|
return;
|
|
|
|
initDevCounter--;
|
|
|
|
if ( initDevCounter == 0 && Options::indiMessages() )
|
|
ksw->statusBar()->changeItem( i18n("%1 is online and ready.").arg(dp->name), 0);
|
|
|
|
}
|
|
|
|
bool INDIStdDevice::handleNonSidereal()
|
|
{
|
|
if (!currentObject)
|
|
return false;
|
|
|
|
int trackIndex=0;
|
|
INDI_E *nameEle;
|
|
|
|
kdDebug() << "Object of type " << currentObject->typeName() << endl;
|
|
//TODO Meade claims that the library access is available to
|
|
// all telescopes, which is unture. Only classic meade support
|
|
// that. They claim that library funcion will be available to all
|
|
// in "later" firmware revisions for the autostar and GPS.
|
|
// As a temprory solution, I'm going to explicity check for the
|
|
// device name which ideally I'm not supposed to do since all properties
|
|
// should be defined from the INDI driver, but since the INDI autostar
|
|
// and gps define the library functions (based on Meade's future claims)
|
|
// I will check the device name until Meade's respondes to my query.
|
|
|
|
// Update: Solution
|
|
// Only Meade Classic will offer an explicit SOLAR_SYSTEM property. If such a property exists
|
|
// then we take advantage of it. Otherwise, we send RA/DEC to the telescope and start a timer
|
|
// based on the object type. Objects with high proper motions will require faster updates.
|
|
// handle Non Sideral is ONLY called when tracking an object, not slewing.
|
|
INDI_P *prop = dp->findProp(TQString("SOLAR_SYSTEM"));
|
|
INDI_P *setMode = dp->findProp(TQString("ON_COORD_SET"));
|
|
|
|
// If the device support it
|
|
if (prop && setMode)
|
|
{
|
|
for (unsigned int i=0; i < setMode->el.count(); i++)
|
|
if (setMode->el.at(i)->name == "TRACK")
|
|
{ trackIndex = i; break; }
|
|
|
|
kdDebug() << "Device supports SOLAR_SYSTEM property" << endl;
|
|
|
|
for (unsigned int i=0; i < prop->el.count(); i++)
|
|
if (currentObject->name().lower() == prop->el.at(i)->label.lower())
|
|
{
|
|
prop->newSwitch(i);
|
|
setMode->newSwitch(trackIndex);
|
|
|
|
/* Send object name if available */
|
|
nameEle = dp->findElem("OBJECT_NAME");
|
|
if (nameEle && nameEle->pp->perm != PP_RO)
|
|
{
|
|
nameEle->write_w->setText(currentObject->name());
|
|
nameEle->pp->newText();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
kdDebug() << "Device doesn't support SOLAR_SYSTEM property, issuing a timer" << endl;
|
|
kdDebug() << "Starting timer for object of type " << currentObject->typeName() << endl;
|
|
|
|
|
|
switch (currentObject->type())
|
|
{
|
|
// Planet/Moon
|
|
case 2:
|
|
kdDebug() << "Initiating pulse tracking for " << currentObject->name() << endl;
|
|
devTimer->start(INDI_PULSE_TRACKING);
|
|
break;
|
|
// Comet/Asteroid
|
|
case 9:
|
|
case 10:
|
|
kdDebug() << "Initiating pulse tracking for " << currentObject->name() << endl;
|
|
devTimer->start(INDI_PULSE_TRACKING);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void INDIStdDevice::timerDone()
|
|
{
|
|
INDI_P *prop;
|
|
INDI_E *RAEle, *DecEle;
|
|
INDI_E *el;
|
|
bool useJ2000 = false;
|
|
|
|
if (!dp->isOn())
|
|
{
|
|
devTimer->stop();
|
|
return;
|
|
}
|
|
|
|
prop = dp->findProp("ON_COORD_SET");
|
|
if (prop == NULL || !currentObject)
|
|
return;
|
|
|
|
el = prop->findElement("TRACK");
|
|
if (!el) return;
|
|
|
|
if (el->state != PS_ON)
|
|
{
|
|
devTimer->stop();
|
|
return;
|
|
}
|
|
|
|
prop = dp->findProp("EQUATORIAL_EOD_COORD");
|
|
|
|
if (prop == NULL)
|
|
{
|
|
prop = dp->findProp("EQUATORIAL_COORD");
|
|
if (prop) useJ2000 = true;
|
|
}
|
|
|
|
if (prop == NULL || !currentObject)
|
|
return;
|
|
|
|
// wait until slew is done
|
|
if (prop->state == PS_BUSY)
|
|
return;
|
|
|
|
kdDebug() << "Timer called, starting processing" << endl;
|
|
|
|
SkyPoint sp(currentObject->ra(), currentObject->dec());
|
|
|
|
kdDebug() << "RA: " << currentObject->ra()->toHMSString() << " - DEC: " << currentObject->dec()->toDMSString() << endl;
|
|
kdDebug() << "Az: " << currentObject->az()->toHMSString() << " - Alt " << currentObject->alt()->toDMSString() << endl;
|
|
|
|
if (useJ2000)
|
|
{
|
|
sp.set(currentObject->ra(), currentObject->dec());
|
|
sp.apparentCoord( ksw->data()->ut().djd() , (long double) J2000);
|
|
}
|
|
|
|
// We need to get from JNow (Skypoint) to J2000
|
|
// The ra0() of a skyPoint is the same as its JNow ra() without this process
|
|
|
|
// Use J2000 coordinate as required by INDI
|
|
RAEle = prop->findElement("RA");
|
|
if (!RAEle) return;
|
|
DecEle = prop->findElement("DEC");
|
|
if (!DecEle) return;
|
|
|
|
RAEle->write_w->setText(TQString("%1:%2:%3").arg(sp.ra()->hour())
|
|
.arg(sp.ra()->minute())
|
|
.arg(sp.ra()->second()));
|
|
DecEle->write_w->setText(TQString("%1:%2:%3").arg(sp.dec()->degree())
|
|
.arg(sp.dec()->arcmin())
|
|
.arg(sp.dec()->arcsec()));
|
|
prop->newText();
|
|
|
|
}
|
|
|
|
INDIStdProperty::INDIStdProperty(INDI_P *associatedProperty, KStars * kswPtr, INDIStdDevice *stdDevPtr)
|
|
{
|
|
pp = associatedProperty;
|
|
ksw = kswPtr;
|
|
stdDev = stdDevPtr;
|
|
}
|
|
|
|
INDIStdProperty::~INDIStdProperty()
|
|
{
|
|
|
|
}
|
|
|
|
void INDIStdProperty::newText()
|
|
{
|
|
INDI_E *lp;
|
|
INDIDriver *drivers = ksw->getINDIDriver();
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
/* Set expose duration button to 'cancel' when busy */
|
|
case CCD_EXPOSE_DURATION:
|
|
pp->set_w->setText(i18n("Cancel"));
|
|
break;
|
|
|
|
/* Save Port name in KStars options */
|
|
case DEVICE_PORT:
|
|
lp = pp->findElement("PORT");
|
|
|
|
if (lp && drivers)
|
|
{
|
|
for (unsigned int i=0; i < drivers->devices.size(); i++)
|
|
{
|
|
if (drivers->devices[i]->mgrID == stdDev->dp->parentMgr->mgrID)
|
|
{
|
|
if (drivers->devices[i]->deviceType == KSTARS_TELESCOPE)
|
|
{
|
|
Options::setIndiTelescopePort( lp->text );
|
|
kdDebug() << "Setting telescope port " << lp->text << endl;
|
|
}
|
|
else if (drivers->devices[i]->deviceType == KSTARS_VIDEO)
|
|
{
|
|
Options::setIndiVideoPort( lp->text );
|
|
kdDebug() << "Setting video port " << lp->text << endl;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
bool INDIStdProperty::convertSwitch(int switchIndex, INDI_E *lp)
|
|
{
|
|
|
|
INDI_E *RAEle(NULL), *DecEle(NULL), *AzEle(NULL), *AltEle(NULL), *nameEle(NULL);
|
|
INDI_P * prop;
|
|
SkyPoint sp;
|
|
int selectedCoord=0; /* 0 for Equatorial, 1 for Horizontal */
|
|
bool useJ2000 (false);
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
/* Handle Slew/Track/Sync */
|
|
case ON_COORD_SET:
|
|
// #1 set current object to NULL
|
|
stdDev->currentObject = NULL;
|
|
// #2 Deactivate timer if present
|
|
if (stdDev->devTimer->isActive())
|
|
stdDev->devTimer->stop();
|
|
|
|
prop = pp->pg->dp->findProp("EQUATORIAL_EOD_COORD");
|
|
if (prop == NULL)
|
|
{
|
|
prop = pp->pg->dp->findProp("EQUATORIAL_COORD");
|
|
if (prop == NULL)
|
|
{
|
|
prop = pp->pg->dp->findProp("HORIZONTAL_COORD");
|
|
if (prop == NULL)
|
|
return false;
|
|
else
|
|
selectedCoord = 1; /* Select horizontal */
|
|
}
|
|
else
|
|
useJ2000 = true;
|
|
}
|
|
|
|
switch (selectedCoord)
|
|
{
|
|
// Equatorial
|
|
case 0:
|
|
if (prop->perm == PP_RO) return false;
|
|
RAEle = prop->findElement("RA");
|
|
if (!RAEle) return false;
|
|
DecEle = prop->findElement("DEC");
|
|
if (!DecEle) return false;
|
|
break;
|
|
|
|
// Horizontal
|
|
case 1:
|
|
if (prop->perm == PP_RO) return false;
|
|
AzEle = prop->findElement("AZ");
|
|
if (!AzEle) return false;
|
|
AltEle = prop->findElement("ALT");
|
|
if (!AltEle) return false;
|
|
break;
|
|
}
|
|
|
|
stdDev->currentObject = ksw->map()->clickedObject();
|
|
// Track is similar to slew, except that for non-sidereal objects
|
|
// it tracks the objects automatically via a timer.
|
|
if ((lp->name == "TRACK"))
|
|
if (stdDev->handleNonSidereal())
|
|
return true;
|
|
|
|
/* Send object name if available */
|
|
if (stdDev->currentObject)
|
|
{
|
|
nameEle = pp->pg->dp->findElem("OBJECT_NAME");
|
|
if (nameEle && nameEle->pp->perm != PP_RO)
|
|
{
|
|
nameEle->write_w->setText(stdDev->currentObject->name());
|
|
nameEle->pp->newText();
|
|
}
|
|
}
|
|
|
|
switch (selectedCoord)
|
|
{
|
|
case 0:
|
|
if (stdDev->currentObject)
|
|
sp.set (stdDev->currentObject->ra(), stdDev->currentObject->dec());
|
|
else
|
|
sp.set (ksw->map()->clickedPoint()->ra(), ksw->map()->clickedPoint()->dec());
|
|
|
|
if (useJ2000)
|
|
sp.apparentCoord(ksw->data()->ut().djd(), (long double) J2000);
|
|
|
|
RAEle->write_w->setText(TQString("%1:%2:%3").arg(sp.ra()->hour()).arg(sp.ra()->minute()).arg(sp.ra()->second()));
|
|
DecEle->write_w->setText(TQString("%1:%2:%3").arg(sp.dec()->degree()).arg(sp.dec()->arcmin()).arg(sp.dec()->arcsec()));
|
|
|
|
break;
|
|
|
|
case 1:
|
|
if (stdDev->currentObject)
|
|
{
|
|
sp.setAz(*stdDev->currentObject->az());
|
|
sp.setAlt(*stdDev->currentObject->alt());
|
|
}
|
|
else
|
|
{
|
|
sp.setAz(*ksw->map()->clickedPoint()->az());
|
|
sp.setAlt(*ksw->map()->clickedPoint()->alt());
|
|
}
|
|
|
|
AzEle->write_w->setText(TQString("%1:%2:%3").arg(sp.az()->degree()).arg(sp.az()->arcmin()).arg(sp.az()->arcsec()));
|
|
AltEle->write_w->setText(TQString("%1:%2:%3").arg(sp.alt()->degree()).arg(sp.alt()->arcmin()).arg(sp.alt()->arcsec()));
|
|
|
|
break;
|
|
}
|
|
|
|
pp->newSwitch(switchIndex);
|
|
prop->newText();
|
|
|
|
return true;
|
|
break;
|
|
|
|
/* Handle Abort */
|
|
case ABORT_MOTION:
|
|
kdDebug() << "Stopping timer." << endl;
|
|
stdDev->devTimer->stop();
|
|
pp->newSwitch(switchIndex);
|
|
return true;
|
|
break;
|
|
|
|
case MOVEMENT:
|
|
pp->newSwitch(switchIndex);
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Return true if the complete operation is done here, or false if the operation is to be completed in the properties newSwitch()
|
|
bool INDIStdProperty::newSwitch(int id, INDI_E* el)
|
|
{
|
|
INDI_P *prop;
|
|
el=el;
|
|
|
|
switch (pp->stdID)
|
|
{
|
|
case CONNECTION:
|
|
if (id == 1)
|
|
stdDev->streamDisabled();
|
|
else
|
|
{
|
|
prop = pp->pg->dp->findProp("DEVICE_PORT");
|
|
if (prop)
|
|
prop->newText();
|
|
}
|
|
break;
|
|
case ABORT_MOTION:
|
|
case PARK:
|
|
case MOVEMENT:
|
|
//TODO add text in the status bar "Slew aborted."
|
|
stdDev->devTimer->stop();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void INDIStdProperty::newTime()
|
|
{
|
|
INDI_E * timeEle;
|
|
INDI_P *SDProp;
|
|
|
|
timeEle = pp->findElement("UTC");
|
|
if (!timeEle) return;
|
|
|
|
TimeDialog timedialog ( ksw->data()->ut(), ksw );
|
|
|
|
if ( timedialog.exec() == TQDialog::Accepted )
|
|
{
|
|
TQTime newTime( timedialog.selectedTime() );
|
|
ExtDate newDate( timedialog.selectedDate() );
|
|
|
|
timeEle->write_w->setText(TQString("%1-%2-%3T%4:%5:%6")
|
|
.arg(newDate.year()).arg(newDate.month())
|
|
.arg(newDate.day()).arg(newTime.hour())
|
|
.arg(newTime.minute()).arg(newTime.second()));
|
|
pp->newText();
|
|
}
|
|
else return;
|
|
|
|
SDProp = pp->pg->dp->findProp("SDTIME");
|
|
if (!SDProp) return;
|
|
timeEle = SDProp->findElement("LST");
|
|
if (!timeEle) return;
|
|
|
|
timeEle->write_w->setText(ksw->LST()->toHMSString());
|
|
SDProp->newText();
|
|
}
|
|
|
|
#include "indistd.moc"
|