Commit 55c27e94 authored by Jasem Mutlaq's avatar Jasem Mutlaq
Browse files

Adding support to remotely controlled dust covers

parent 7d526b92
......@@ -61,6 +61,7 @@ if (INDI_FOUND)
indi/indifilter.cpp
indi/indidome.cpp
indi/indiweather.cpp
indi/indicap.cpp
indi/indidbus.cpp
indi/opsindi.cpp
indi/telescopewizardprocess.cpp
......@@ -99,6 +100,7 @@ if (CFITSIO_FOUND)
ekos/mount.cpp
ekos/dome.cpp
ekos/weather.cpp
ekos/dustcap.cpp
ekos/astrometryparser.cpp
ekos/offlineastrometryparser.cpp
ekos/onlineastrometryparser.cpp
......@@ -502,6 +504,7 @@ qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Align.xml ekos/align.h Ekos
qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Mount.xml ekos/mount.h Ekos::Mount)
qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Dome.xml ekos/dome.h Ekos::Dome)
qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.Weather.xml ekos/weather.h Ekos::Weather)
qt5_add_dbus_adaptor(kstars_SRCS org.kde.kstars.Ekos.DustCap.xml ekos/dustcap.h Ekos::DustCap)
endif(INDI_FOUND)
kconfig_add_kcfg_files(kstars_SRCS ${kstars_KCFG_SRCS})
......
/* Ekos DustCap Interface
Copyright (C) 2015 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 "dustcap.h"
#include "ekosmanager.h"
#include "kstars.h"
#include "dustcapadaptor.h"
#include <basedevice.h>
namespace Ekos
{
DustCap::DustCap()
{
new DustCapAdaptor(this);
QDBusConnection::sessionBus().registerObject("/KStars/Ekos/DustCap", this);
currentDustCap = NULL;
}
DustCap::~DustCap()
{
}
void DustCap::setDustCap(ISD::GDInterface *newDustCap)
{
currentDustCap = static_cast<ISD::DustCap *>(newDustCap);
}
DustCap::ParkingStatus DustCap::getParkingStatus()
{
if (currentDustCap == NULL)
return PARKING_ERROR;
ISwitchVectorProperty *parkSP = currentDustCap->getBaseDevice()->getSwitch("CAP_PARK");
if (parkSP == NULL)
return PARKING_ERROR;
switch (parkSP->s)
{
case IPS_IDLE:
return PARKING_IDLE;
case IPS_OK:
if (parkSP->sp[0].s == ISS_ON)
return PARKING_OK;
else
return UNPARKING_OK;
break;
case IPS_BUSY:
if (parkSP->sp[0].s == ISS_ON)
return PARKING_BUSY;
else
return UNPARKING_BUSY;
case IPS_ALERT:
return PARKING_ERROR;
}
return PARKING_ERROR;
}
bool DustCap::park()
{
if (currentDustCap == NULL)
return false;
return currentDustCap->Park();
}
bool DustCap::unPark()
{
if (currentDustCap == NULL)
return false;
return currentDustCap->UnPark();
}
bool DustCap::hasLight()
{
if (currentDustCap == NULL)
return false;
return currentDustCap->hasLight();
}
bool DustCap::setLight(uint8_t val)
{
if (currentDustCap == NULL)
return false;
return currentDustCap->SetLight(val);
}
}
/* Ekos DustCap interface
Copyright (C) 2015 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 DUSTCAP_H
#define DUSTCAP_H
#include <QtDBus/QtDBus>
#include "indi/indistd.h"
#include "indi/indicap.h"
namespace Ekos
{
/**
*@class DustCap
*@short Supports basic DustCap functions (open/close) and optionally control flat light
*@author Jasem Mutlaq
*@version 1.0
*/
class DustCap : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.DustCap")
public:
typedef enum { PARKING_IDLE, PARKING_OK, UNPARKING_OK, PARKING_BUSY, UNPARKING_BUSY, PARKING_ERROR } ParkingStatus;
DustCap();
~DustCap();
/** @defgroup DustCapDBusInterface Ekos DBus Interface - DustCap Interface
* Ekos::DustCap interface provides basic DustCap operations.
*/
/*@{*/
/** DBUS interface function.
* Park / Close dust cap
* @return True if operation started/successful, false otherwise
*/
Q_SCRIPTABLE bool park();
/** DBUS interface function.
* UnPark / Open dust cap
* @return True if operation started/successful, false otherwise
*/
Q_SCRIPTABLE bool unPark();
/** DBUS interface function.
* hasLight: Does the dust cap have a flat light source?
* @return True if there if flat light, false othereise
*/
Q_SCRIPTABLE bool hasLight();
/** DBUS interface function.
* SetLight: Turn on/off flat light and set intensity, if supported.
* @return True if operation started/successful, false otherwise
*/
Q_SCRIPTABLE bool setLight(uint8_t val);
/** DBUS interface function.
* Get the dome park status
*/
Q_SCRIPTABLE ParkingStatus getParkingStatus();
/** @}*/
/**
* @brief setDustCap set the DustCap device
* @param newDustCap pointer to DustCap device.
*/
void setDustCap(ISD::GDInterface *newDustCap);
private:
// Devices needed for DustCap operation
ISD::DustCap *currentDustCap;
};
}
#endif // DustCap_H
......@@ -71,6 +71,7 @@ EkosManager::EkosManager()
ao = NULL;
dome = NULL;
weather = NULL;
dustCap = NULL;
scope_di = NULL;
ccd_di = NULL;
......@@ -94,6 +95,7 @@ EkosManager::EkosManager()
domeProcess = NULL;
schedulerProcess = NULL;
weatherProcess = NULL;
dustCapProcess = NULL;
ekosOption = NULL;
......@@ -159,6 +161,7 @@ EkosManager::~EkosManager()
delete weatherProcess;
delete mountProcess;
delete schedulerProcess;
delete dustCapProcess;
}
void EkosManager::closeEvent(QCloseEvent * /*event*/)
......@@ -815,6 +818,7 @@ void EkosManager::reset()
alignProcess = NULL;
mountProcess = NULL;
weatherProcess = NULL;
dustCapProcess = NULL;
ekosStartingStatus = STATUS_IDLE;
indiConnectionStatus= STATUS_IDLE;
......@@ -1054,6 +1058,7 @@ bool EkosManager::start()
connect(INDIListener::Instance(), SIGNAL(newFocuser(ISD::GDInterface*)), this, SLOT(setFocuser(ISD::GDInterface*)));
connect(INDIListener::Instance(), SIGNAL(newDome(ISD::GDInterface*)), this, SLOT(setDome(ISD::GDInterface*)));
connect(INDIListener::Instance(), SIGNAL(newWeather(ISD::GDInterface*)), this, SLOT(setWeather(ISD::GDInterface*)));
connect(INDIListener::Instance(), SIGNAL(newDustCap(ISD::GDInterface*)), this, SLOT(setDustCap(ISD::GDInterface*)));
connect(INDIListener::Instance(), SIGNAL(newST4(ISD::ST4*)), this, SLOT(setST4(ISD::ST4*)));
connect(INDIListener::Instance(), SIGNAL(deviceRemoved(ISD::GDInterface*)), this, SLOT(removeDevice(ISD::GDInterface*)), Qt::DirectConnection);
connect(DriverManager::Instance(), SIGNAL(serverTerminated(QString,QString)), this, SLOT(cleanDevices()));
......@@ -1938,6 +1943,17 @@ void EkosManager::setWeather(ISD::GDInterface *weatherDevice)
appendLogText(i18n("%1 is online.", weather->getDeviceName()));
}
void EkosManager::setDustCap(ISD::GDInterface *dustCapDevice)
{
initDustCap();
dustCap = dustCapDevice;
dustCapProcess->setDustCap(dustCap);
appendLogText(i18n("%1 is online.", dustCap->getDeviceName()));
}
void EkosManager::removeDevice(ISD::GDInterface* devInterface)
{
switch (devInterface->getType())
......@@ -2411,6 +2427,14 @@ void EkosManager::initWeather()
weatherProcess = new Ekos::Weather();
}
void EkosManager::initDustCap()
{
if (dustCapProcess)
return;
dustCapProcess = new Ekos::DustCap();
}
void EkosManager::setST4(ISD::ST4 * st4Driver)
{
appendLogText(i18n("Guider port from %1 is ready.", st4Driver->getDeviceName()));
......@@ -2462,6 +2486,10 @@ void EkosManager::removeTabs()
delete (weatherProcess);
weatherProcess = NULL;
dustCap = NULL;
delete (dustCapProcess);
dustCapProcess = NULL;
aux1 = NULL;
aux2 = NULL;
aux3 = NULL;
......
......@@ -22,6 +22,7 @@
#include "mount.h"
#include "dome.h"
#include "weather.h"
#include "dustcap.h"
#include "scheduler.h"
#include <QDialog>
......@@ -43,6 +44,8 @@ class KPageWidgetItem;
* <li>\ref MountDBusInterface "Mount Module DBus Interface"</li>
* <li>\ref GuideDBusInterface "Guide Module DBus Interface"</li>
* <li>\ref AlignDBusInterface "Align Module DBus Interface"</li>
* <li>\ref WeatherDBusInterface "Weather DBus Interface"</li>
* <li>\ref DustCapDBusInterface "Dust Cap DBus Interface"</li>
* </ul>
* For low level access to INDI devices, the \ref INDIDBusInterface "INDI Dbus Interface" provides complete access to INDI devices and properties.
*@author Jasem Mutlaq
......@@ -213,6 +216,7 @@ protected slots:
void setFocuser(ISD::GDInterface *);
void setDome(ISD::GDInterface *);
void setWeather(ISD::GDInterface *);
void setDustCap(ISD::GDInterface *);
void setST4(ISD::ST4 *);
private:
......@@ -226,6 +230,7 @@ protected slots:
void initMount();
void initDome();
void initWeather();
void initDustCap();
void initLocalDrivers();
void initRemoteDrivers();
......@@ -245,7 +250,7 @@ protected slots:
bool remoteCCDRegistered;
bool remoteGuideRegistered;
ISD::GDInterface *scope, *ccd, *guider, *focuser, *filter, *aux1, *aux2, *aux3, *aux4, *dome, *ao, *weather;
ISD::GDInterface *scope, *ccd, *guider, *focuser, *filter, *aux1, *aux2, *aux3, *aux4, *dome, *ao, *weather, *dustCap;
DriverInfo *scope_di, *ccd_di, *guider_di, *filter_di, *focuser_di, *aux1_di, *aux2_di, *aux3_di,*aux4_di, *ao_di, *dome_di, *weather_di, *remote_indi;
Ekos::Capture *captureProcess;
......@@ -256,6 +261,7 @@ protected slots:
Ekos::Scheduler *schedulerProcess;
Ekos::Dome *domeProcess;
Ekos::Weather *weatherProcess;
Ekos::DustCap *dustCapProcess;
QString guiderCCDName;
QString primaryCCDName;
......
......@@ -76,6 +76,7 @@ Scheduler::Scheduler()
guideInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Guide", "org.kde.kstars.Ekos.Guide", QDBusConnection::sessionBus(), this);
domeInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Dome", "org.kde.kstars.Ekos.Dome", QDBusConnection::sessionBus(), this);
weatherInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/Weather", "org.kde.kstars.Ekos.Weather", QDBusConnection::sessionBus(), this);
capInterface = new QDBusInterface("org.kde.kstars", "/KStars/Ekos/DustCap", "org.kde.kstars.Ekos.DustCap", QDBusConnection::sessionBus(), this);
moon = dynamic_cast<KSMoon*> (KStarsData::Instance()->skyComposite()->findByName("Moon"));
......@@ -1516,27 +1517,27 @@ bool Scheduler::checkINDIState()
{
switch (indiState)
{
case INDI_IDLE:
case INDI_IDLE:
{
// Even in idle state, we make sure that INDI is not already connected.
QDBusReply<int> isINDIConnected = ekosInterface->call(QDBus::AutoDetect,"getINDIConnectionStatus");
if (isINDIConnected.value()== EkosManager::STATUS_SUCCESS)
{
// Even in idle state, we make sure that INDI is not already connected.
QDBusReply<int> isINDIConnected = ekosInterface->call(QDBus::AutoDetect,"getINDIConnectionStatus");
if (isINDIConnected.value()== EkosManager::STATUS_SUCCESS)
{
indiState = INDI_PROPERTY_CHECK;
return false;
}
else
{
ekosInterface->call(QDBus::AutoDetect,"connectDevices");
indiState = INDI_CONNECTING;
return false;
}
indiState = INDI_PROPERTY_CHECK;
return false;
}
else
{
ekosInterface->call(QDBus::AutoDetect,"connectDevices");
indiState = INDI_CONNECTING;
return false;
}
}
break;
case INDI_CONNECTING:
{
QDBusReply<int> isINDIConnected = ekosInterface->call(QDBus::AutoDetect,"getINDIConnectionStatus");
case INDI_CONNECTING:
{
QDBusReply<int> isINDIConnected = ekosInterface->call(QDBus::AutoDetect,"getINDIConnectionStatus");
if(isINDIConnected.value()== EkosManager::STATUS_SUCCESS)
{
appendLogText(i18n("INDI devices connected."));
......@@ -1550,11 +1551,11 @@ bool Scheduler::checkINDIState()
stop();
// TODO deal with INDI connection error? Wait until user resolves it? stop scheduler?
return false;
return false;
}
else
return false;
}
}
break;
case INDI_PROPERTY_CHECK:
......@@ -1570,14 +1571,15 @@ bool Scheduler::checkINDIState()
unparkDomeCheck->setEnabled(boolReply.value());
parkDomeCheck->setEnabled(boolReply.value());
boolReply = captureInterface->call(QDBus::AutoDetect,"hasCoolerControl");
warmCCDCheck->setEnabled(boolReply.value());
boolReply = captureInterface->call(QDBus::AutoDetect,"hasCoolerControl");
warmCCDCheck->setEnabled(boolReply.value());
if (weatherInterface->isValid())
{
QDBusReply<int> updateReply = weatherInterface->call(QDBus::AutoDetect, "getUpdatePeriod");
if (updateReply.error().type() == QDBusError::NoError)
{
weatherCheck->setEnabled(true);
QDBusReply<int> updateReply = weatherInterface->call(QDBus::AutoDetect, "getUpdatePeriod");
if (updateReply.error().type() == QDBusError::NoError && updateReply.value() > 0)
if (updateReply.value() > 0)
{
weatherTimer.setInterval(updateReply.value() * 1000);
connect(&weatherTimer, SIGNAL(timeout()), this, SLOT(checkWeather()));
......@@ -1586,14 +1588,26 @@ bool Scheduler::checkINDIState()
// Check weather initially
checkWeather();
}
}
else
weatherCheck->setEnabled(false);
}
else
weatherCheck->setEnabled(false);
QDBusReply<int> capReply = capInterface->call(QDBus::AutoDetect, "hasLight");
if (capReply.error().type() == QDBusError::NoError)
{
capCheck->setEnabled(true);
uncapCheck->setEnabled(true);
}
else
{
capCheck->setEnabled(false);
uncapCheck->setEnabled(false);
}
indiState = INDI_READY;
return true;
}
break;
break;
case INDI_READY:
return true;
......@@ -1606,66 +1620,77 @@ bool Scheduler::checkStartupState()
{
switch (startupState)
{
case STARTUP_IDLE:
{
KNotification::event( QLatin1String( "ObservatoryStartup" ) , i18n("Observatory is in the startup process"));
// If Ekos is already started, we skip the script and move on to mount unpark step
QDBusReply<int> isEkosStarted;
isEkosStarted = ekosInterface->call(QDBus::AutoDetect,"getEkosStartingStatus");
if (isEkosStarted.value() == EkosManager::STATUS_SUCCESS)
{
if (startupScriptURL.isEmpty() == false)
appendLogText(i18n("Ekos is already started, skipping startup script..."));
startupState = STARTUP_UNPARK_DOME;
return true;
}
case STARTUP_IDLE:
{
KNotification::event( QLatin1String( "ObservatoryStartup" ) , i18n("Observatory is in the startup process"));
// If Ekos is already started, we skip the script and move on to mount unpark step
QDBusReply<int> isEkosStarted;
isEkosStarted = ekosInterface->call(QDBus::AutoDetect,"getEkosStartingStatus");
if (isEkosStarted.value() == EkosManager::STATUS_SUCCESS)
{
if (startupScriptURL.isEmpty() == false)
{
startupState = STARTUP_SCRIPT;
executeScript(startupScriptURL.toString(QUrl::PreferLocalFile));
return false;
}
appendLogText(i18n("Ekos is already started, skipping startup script..."));
startupState = STARTUP_UNPARK_DOME;
return false;
}
break;
return true;
}
case STARTUP_SCRIPT:
if (startupScriptURL.isEmpty() == false)
{
startupState = STARTUP_SCRIPT;
executeScript(startupScriptURL.toString(QUrl::PreferLocalFile));
return false;
break;
}
case STARTUP_UNPARK_DOME:
startupState = STARTUP_UNPARK_DOME;
return false;
}
break;
case STARTUP_SCRIPT:
return false;
break;
case STARTUP_UNPARK_DOME:
if (unparkDomeCheck->isEnabled() && unparkDomeCheck->isChecked())
unParkDome();
unParkDome();
else
startupState = STARTUP_UNPARK_MOUNT;
startupState = STARTUP_UNPARK_MOUNT;
break;
case STARTUP_UNPARKING_DOME:
case STARTUP_UNPARKING_DOME:
checkDomeParkingStatus();
break;
case STARTUP_UNPARK_MOUNT:
case STARTUP_UNPARK_MOUNT:
if (unparkMountCheck->isEnabled() && unparkMountCheck->isChecked())
unParkMount();
unParkMount();
else
startupState = STARTUP_COMPLETE;
break;
startupState = STARTUP_UNPARK_CAP;
break;
case STARTUP_UNPARKING_MOUNT:
case STARTUP_UNPARKING_MOUNT:
checkMountParkingStatus();
break;
case STARTUP_COMPLETE:
return true;
case STARTUP_UNPARK_CAP:
if (uncapCheck->isEnabled() && uncapCheck->isChecked())
unParkCap();
else
startupState = STARTUP_COMPLETE;
break;
case STARTUP_ERROR:
stop();
return true;
break;
case STARTUP_UNPARKING_CAP:
checkCapParkingStatus();
break;
case STARTUP_COMPLETE:
return true;
case STARTUP_ERROR:
stop();
return true;
break;
}
......@@ -1676,7 +1701,7 @@ bool Scheduler::checkShutdownState()
{
switch (shutdownState)
{
case SHUTDOWN_IDLE:
case SHUTDOWN_IDLE:
KNotification::event( QLatin1String( "ObservatoryShutdown" ) , i18n("Observatory is in the shutdown process"));
weatherTimer.stop();
......@@ -1704,6 +1729,12 @@ bool Scheduler::checkShutdownState()
captureInterface->call(QDBus::AutoDetect, "setCoolerControl", arg);
}
if (capCheck->isEnabled() && capCheck->isChecked())
{
shutdownState = SHUTDOWN_PARK_CAP;
return false;
}
if (parkMountCheck->isEnabled() && parkMountCheck->isChecked())
{
shutdownState = SHUTDOWN_PARK_MOUNT;
......@@ -1721,53 +1752,64 @@ bool Scheduler::checkShutdownState()
return false;
}
shutdownState = SHUTDOWN_COMPLETE;
shutdownState = SHUTDOWN_COMPLETE;
return true;
break;
case SHUTDOWN_PARK_MOUNT:
if (parkMountCheck->isEnabled() && parkMountCheck->isChecked())
parkMount();
else
shutdownState = SHUTDOWN_PARK_DOME;
break;