Commit bdcb7178 authored by Jasem Mutlaq's avatar Jasem Mutlaq

Add support to remote astrometry solver in INDI::CCD driver

parent 255818d1
......@@ -119,6 +119,7 @@ if(INDI_FOUND)
ekos/astrometryparser.cpp
ekos/offlineastrometryparser.cpp
ekos/onlineastrometryparser.cpp
ekos/remoteastrometryparser.cpp
ekos/profileeditor.cpp
ekos/opsekos.cpp
ekos/QProgressIndicator.cpp
......
......@@ -34,6 +34,7 @@
#include "onlineastrometryparser.h"
#include "offlineastrometryparser.h"
#include "remoteastrometryparser.h"
#include <basedevice.h>
......@@ -83,6 +84,7 @@ Align::Align()
solverFOV->setColor(KStars::Instance()->data()->colorScheme()->colorNamed( "SolverFOVColor" ).name());
onlineParser = NULL;
offlineParser = NULL;
remoteParser = NULL;
connect(solveB, SIGNAL(clicked()), this, SLOT(captureAndSolve()));
connect(stopB, SIGNAL(clicked()), this, SLOT(abort()));
......@@ -133,20 +135,29 @@ Align::Align()
altStage = ALT_INIT;
azStage = AZ_INIT;
// Online/Offline solver check
kcfg_onlineSolver->setChecked(Options::solverOnline());
kcfg_offlineSolver->setChecked(Options::solverOnline() == false);
connect(kcfg_onlineSolver, SIGNAL(toggled(bool)), SLOT(setSolverType(bool)));
// Online/Offline/Remote solver check
solverTypeGroup->setId(onlineSolverR, SOLVER_ONLINE);
solverTypeGroup->setId(offlineSolverR, SOLVER_OFFLINE);
solverTypeGroup->setId(remoteSolverR, SOLVER_REMOTE);
solverTypeGroup->button(Options::solverType())->setChecked(true);
connect(solverTypeGroup, SIGNAL(buttonClicked(int)), SLOT(setSolverType(int)));
if (kcfg_onlineSolver->isChecked())
switch(solverTypeGroup->checkedId())
{
case SOLVER_ONLINE:
onlineParser = new Ekos::OnlineAstrometryParser();
parser = onlineParser;
}
else
{
parser = onlineParser;
break;
case SOLVER_OFFLINE:
offlineParser = new OfflineAstrometryParser();
parser = offlineParser;
break;
case SOLVER_REMOTE:
remoteParser = new RemoteAstrometryParser();
parser = remoteParser;
break;
}
parser->setAlign(this);
......@@ -174,6 +185,7 @@ Align::~Align()
{
delete(pi);
delete(solverFOV);
delete(parser);
}
bool Align::isParserOK()
......@@ -194,11 +206,11 @@ bool Align::isVerbose()
return kcfg_solverVerbose->isChecked();
}
void Align::setSolverType(bool useOnline)
void Align::setSolverType(int type)
{
if (useOnline)
switch(type)
{
case SOLVER_ONLINE:
if (onlineParser != NULL)
{
parser = onlineParser;
......@@ -207,17 +219,32 @@ void Align::setSolverType(bool useOnline)
onlineParser = new Ekos::OnlineAstrometryParser();
parser = onlineParser;
}
else
{
break;
case SOLVER_OFFLINE:
if (offlineParser != NULL)
{
parser = offlineParser;
return;
}
offlineParser = new Ekos::OfflineAstrometryParser();
parser = offlineParser;
break;
case SOLVER_REMOTE:
if (remoteParser != NULL)
{
parser = remoteParser;
(dynamic_cast<RemoteAstrometryParser*>(parser))->setCCD(currentCCD);
return;
}
remoteParser = new Ekos::RemoteAstrometryParser();
parser = remoteParser;
(dynamic_cast<RemoteAstrometryParser*>(parser))->setCCD(currentCCD);
break;
}
parser->setAlign(this);
......@@ -254,8 +281,13 @@ void Align::checkCCD(int ccdNum)
ccdNum = CCDCaptureCombo->currentIndex();
if (ccdNum <= CCDs.count())
{
currentCCD = CCDs.at(ccdNum);
if (solverTypeGroup->checkedId() == SOLVER_REMOTE)
(dynamic_cast<RemoteAstrometryParser*>(parser))->setCCD(currentCCD);
}
syncCCDInfo();
}
......@@ -588,10 +620,26 @@ bool Align::captureAndSolve()
connect(currentCCD, SIGNAL(BLOBUpdated(IBLOB*)), this, SLOT(newFITS(IBLOB*)));
connect(currentCCD, SIGNAL(newExposureValue(ISD::CCDChip*,double,IPState)), this, SLOT(checkCCDExposureProgress(ISD::CCDChip*,double,IPState)));
if (currentCCD->getUploadMode() == ISD::CCD::UPLOAD_LOCAL)
// In case of remote solver, we set mode to either UPLOAD_LOCAL (when preview is OFF) or UPLOAD_BOTH (when preview is on)
if (solverTypeGroup->checkedId() == SOLVER_REMOTE)
{
rememberUploadMode = currentCCD->getUploadMode();
if (kcfg_solverPreview->isChecked())
currentCCD->setUploadMode(ISD::CCD::UPLOAD_BOTH);
else
currentCCD->setUploadMode(ISD::CCD::UPLOAD_LOCAL);
// For solver remote we need to start solver BEFORE capture
startSovling(QString());
}
else
{
rememberUploadMode = ISD::CCD::UPLOAD_LOCAL;
currentCCD->setUploadMode(ISD::CCD::UPLOAD_CLIENT);
if (currentCCD->getUploadMode() == ISD::CCD::UPLOAD_LOCAL)
{
rememberUploadMode = ISD::CCD::UPLOAD_LOCAL;
currentCCD->setUploadMode(ISD::CCD::UPLOAD_CLIENT);
}
}
targetChip->resetFrame();
......@@ -626,9 +674,11 @@ void Align::newFITS(IBLOB *bp)
appendLogText(i18n("Image received."));
char *finalFileName = (char *) bp->aux2;
startSovling(QString(finalFileName));
if (solverTypeGroup->checkedId() != SOLVER_REMOTE)
{
char *finalFileName = (char *) bp->aux2;
startSovling(QString(finalFileName));
}
}
void Align::setGOTOMode(int mode)
......@@ -665,7 +715,7 @@ void Align::startSovling(const QString &filename, bool isGenerated)
Options::setSolverXBin(binXIN->value());
Options::setSolverYBin(binYIN->value());
Options::setSolverUpdateCoords(kcfg_solverUpdateCoords->isChecked());
Options::setSolverOnline(kcfg_onlineSolver->isChecked());
Options::setSolverType(solverTypeGroup->checkedId());
Options::setSolverPreview(kcfg_solverPreview->isChecked());
Options::setSolverOptions(kcfg_solverOptions->text());
Options::setSolverOTA(kcfg_solverOTA->isChecked());
......
......@@ -31,6 +31,7 @@ namespace Ekos
class AstrometryParser;
class OnlineAstrometryParser;
class OfflineAstrometryParser;
class RemoteAstrometryParser;
/**
*@class Align
......@@ -54,6 +55,7 @@ public:
typedef enum { AZ_INIT, AZ_FIRST_TARGET, AZ_SYNCING, AZ_SLEWING, AZ_SECOND_TARGET, AZ_CORRECTING, AZ_FINISHED } AZStage;
typedef enum { ALT_INIT, ALT_FIRST_TARGET, ALT_SYNCING, ALT_SLEWING, ALT_SECOND_TARGET, ALT_CORRECTING, ALT_FINISHED } ALTStage;
typedef enum { ALIGN_SYNC, ALIGN_SLEW, ALIGN_SOLVE } GotoMode;
typedef enum { SOLVER_ONLINE, SOLVER_OFFLINE, SOLVER_REMOTE} SolverType;
/** @defgroup AlignDBusInterface Ekos DBus Interface - Align Module
* Ekos::Align interface provides advanced scripting capabilities to solve images using online or offline astrometry.net
......@@ -233,10 +235,10 @@ public slots:
Q_SCRIPTABLE Q_NOREPLY void abort();
/** DBUS interface function.
* Select the solver type (online or offline)
* @param useOnline if true, select the online solver, otherwise the offline solver is selected.
* Select the solver type
* @param type Set solver type. 0 online, 1 offline, 2 remote
*/
Q_SCRIPTABLE Q_NOREPLY void setSolverType(bool useOnline);
Q_SCRIPTABLE Q_NOREPLY void setSolverType(int type);
/** DBUS interface function.
* Capture and solve an image using the astrometry.net engine
......@@ -419,6 +421,7 @@ private:
AstrometryParser *parser;
OnlineAstrometryParser *onlineParser;
OfflineAstrometryParser *offlineParser;
RemoteAstrometryParser *remoteParser;
// Pointers to our devices
ISD::Telescope *currentTelescope;
......
......@@ -504,20 +504,52 @@
</spacer>
</item>
<item>
<widget class="QRadioButton" name="kcfg_onlineSolver">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Online Sol&amp;ver</string>
<string>Solver:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="onlineSolverR">
<property name="toolTip">
<string>Use online astrometry.net solver to solve the image. You must have an internet connection and a valid API key.</string>
</property>
<property name="text">
<string>Online</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">solverTypeGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="offlineSolverR">
<property name="toolTip">
<string>Use offline astrometry.net solver. You must install all the necessary index files for your field of view.</string>
</property>
<property name="text">
<string>Offline</string>
</property>
<attribute name="buttonGroup">
<string notr="true">solverTypeGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="kcfg_offlineSolver">
<widget class="QRadioButton" name="remoteSolverR">
<property name="toolTip">
<string>Use astrometry solver on remote machine running INDI server.</string>
</property>
<property name="text">
<string>Offline Solver</string>
<string>Remote</string>
</property>
<attribute name="buttonGroup">
<string notr="true">solverTypeGroup</string>
</attribute>
</widget>
</item>
</layout>
......@@ -914,4 +946,7 @@
</customwidgets>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="solverTypeGroup"/>
</buttongroups>
</ui>
/* Astrometry.net Parser - Remote
Copyright (C) 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application 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.
*/
#include <unistd.h>
#include <QDir>
#include <KMessageBox>
#include <KLocalizedString>
#include "Options.h"
#include <basedevice.h>
#include "indi/clientmanager.h"
#include "indi/driverinfo.h"
#include "remoteastrometryparser.h"
#include "align.h"
namespace Ekos
{
RemoteAstrometryParser::RemoteAstrometryParser() : AstrometryParser()
{
currentCCD = NULL;
solverRunning=false;
}
RemoteAstrometryParser::~RemoteAstrometryParser()
{
}
bool RemoteAstrometryParser::init()
{
return true;
}
void RemoteAstrometryParser::verifyIndexFiles(double, double)
{
}
bool RemoteAstrometryParser::startSovler(const QString &filename, const QStringList &args, bool generated)
{
INDI_UNUSED(filename);
INDI_UNUSED(generated);
solverRunning = true;
ITextVectorProperty *solverSettings = currentCCD->getBaseDevice()->getText("ASTROMETRY_SETTINGS");
ISwitchVectorProperty *solverSwitch = currentCCD->getBaseDevice()->getSwitch("ASTROMETRY_SOLVER");
if (solverSettings == NULL || solverSwitch == NULL)
{
align->appendLogText(i18n("CCD does not support remote solver."));
emit solverFailed();
return false;
}
for (int i=0; i < solverSettings->ntp; i++)
{
if (!strcmp(solverSettings->tp[i].name, "ASTROMETRY_SETTINGS_BINARY"))
IUSaveText(&solverSettings->tp[i], Options::astrometrySolver().toLatin1().constData());
else if (!strcmp(solverSettings->tp[i].name, "ASTROMETRY_SETTINGS_OPTIONS"))
IUSaveText(&solverSettings->tp[i], args.join(" ").toLatin1().constData());
}
currentCCD->getDriverInfo()->getClientManager()->sendNewText(solverSettings);
ISwitch *enableSW = IUFindSwitch(solverSwitch, "ASTROMETRY_SOLVER_ENABLE");
if (enableSW->s == ISS_OFF)
{
IUResetSwitch(solverSwitch);
enableSW->s = ISS_ON;
currentCCD->getDriverInfo()->getClientManager()->sendNewSwitch(solverSwitch);
}
align->appendLogText(i18n("Starting remote solver..."));
solverTimer.start();
return true;
}
bool RemoteAstrometryParser::stopSolver()
{
// Disable solver
ISwitchVectorProperty *svp = currentCCD->getBaseDevice()->getSwitch("ASTROMETRY_SOLVER");
if (!svp)
return false;
ISwitch *disableSW = IUFindSwitch(svp, "ASTROMETRY_SOLVER_DISABLE");
if (disableSW->s == ISS_OFF)
{
IUResetSwitch(svp);
disableSW->s = ISS_ON;
currentCCD->getDriverInfo()->getClientManager()->sendNewSwitch(svp);
}
solverRunning=false;
solverTimer.stop();
return true;
}
void RemoteAstrometryParser::setCCD(ISD::CCD *ccd)
{
if (ccd == currentCCD)
return;
currentCCD = ccd;
currentCCD->disconnect(this);
connect(currentCCD, SIGNAL(switchUpdated(ISwitchVectorProperty*)), this, SLOT(checkCCDStatus(ISwitchVectorProperty*)));
connect(currentCCD, SIGNAL(numberUpdated(INumberVectorProperty*)), this, SLOT(checkCCDResults(INumberVectorProperty*)));
}
void RemoteAstrometryParser::checkCCDStatus(ISwitchVectorProperty *svp)
{
if (solverRunning == false || strcmp(svp->name, "ASTROMETRY_SOLVER"))
return;
if (svp->s == IPS_ALERT)
{
stopSolver();
align->appendLogText(i18n("Solver failed. Try again."));
emit solverFailed();
return;
}
}
void RemoteAstrometryParser::checkCCDResults(INumberVectorProperty * nvp)
{
if (solverRunning == false || strcmp(nvp->name, "ASTROMETRY_RESULTS") || nvp->s != IPS_OK)
return;
double pixscale, ra, de, orientation;
pixscale=ra=de=orientation=-1000;
for (int i=0; i < nvp->nnp; i++)
{
if (!strcmp(nvp->np[i].name, "ASTROMETRY_RESULTS_PIXSCALE"))
pixscale = nvp->np[i].value;
else if (!strcmp(nvp->np[i].name, "ASTROMETRY_RESULTS_ORIENTATION"))
orientation = nvp->np[i].value;
else if (!strcmp(nvp->np[i].name, "ASTROMETRY_RESULTS_RA"))
ra = nvp->np[i].value;
else if (!strcmp(nvp->np[i].name, "ASTROMETRY_RESULTS_DE"))
de = nvp->np[i].value;
}
if (pixscale != -1000 && ra != -1000 && de != -1000 && orientation != -1000)
{
int elapsed = (int) round(solverTimer.elapsed()/1000.0);
align->appendLogText(i18np("Solver completed in %1 second.", "Solver completed in %1 seconds.", elapsed));
stopSolver();
emit solverFinished(orientation, ra, de, pixscale);
}
}
}
/* Astrometry.net Parser - Remote
Copyright (C) 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application 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.
*/
#ifndef REMOTEASTROMETRYPARSER_H
#define REMOTEASTROMETRYPARSER_H
#include "indi/indiccd.h"
#include "astrometryparser.h"
namespace Ekos
{
class Align;
/**
* @class RemoteAstrometryParser
* RemoteAstrometryParser invokes the remote astrometry.net solver in the remote CCD driver to solve the captured image.
* The offline astrometry.net plus index files must be installed and configured on the remote host running the INDI CCD driver.
*
* @authro Jasem Mutlaq
*/
class RemoteAstrometryParser: public AstrometryParser
{
Q_OBJECT
public:
RemoteAstrometryParser();
virtual ~RemoteAstrometryParser();
virtual void setAlign(Align *_align) { align = _align; }
virtual bool init();
virtual void verifyIndexFiles(double fov_x, double fov_y);
virtual bool startSovler(const QString &filename, const QStringList &args, bool generated=true);
virtual bool stopSolver();
void setCCD(ISD::CCD *ccd);
public slots:
void checkCCDStatus(ISwitchVectorProperty * svp);
void checkCCDResults(INumberVectorProperty * nvp);
private:
ISD::CCD *currentCCD;
bool solverRunning;
bool captureRunning;
Align *align;
QTime solverTimer;
};
}
#endif // REMOTEASTROMETRYPARSER_H
......@@ -1484,9 +1484,9 @@
<whatsthis>Display captured image in FITS Viewer before starting the plate solving process.</whatsthis>
<default>false</default>
</entry>
<entry name="SolverOnline" type="Bool">
<label>Use astrometry.net online solver.</label>
<default>true</default>
<entry name="SolverType" type="UInt">
<label>Set solver type (online, offline, remote).</label>
<default>0</default>
</entry>
<entry name="SolverOptions" type="String">
<label>Options passed to the astrometry solver.</label>
......
......@@ -5,7 +5,7 @@
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="setSolverType">
<arg name="useOnline" type="b" direction="in"/>
<arg name="type" type="i" direction="in"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="captureAndSolve">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment