summaryrefslogtreecommitdiffstats
path: root/kstars/kstars/devicemanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kstars/kstars/devicemanager.cpp')
-rw-r--r--kstars/kstars/devicemanager.cpp502
1 files changed, 502 insertions, 0 deletions
diff --git a/kstars/kstars/devicemanager.cpp b/kstars/kstars/devicemanager.cpp
new file mode 100644
index 00000000..5552fe39
--- /dev/null
+++ b/kstars/kstars/devicemanager.cpp
@@ -0,0 +1,502 @@
+/* Device Manager
+ Copyright (C) 2003 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.
+
+ JM Changelog
+ 2004-16-1: Start
+
+ */
+
+#include "Options.h"
+#include "devicemanager.h"
+#include "indimenu.h"
+#include "indiproperty.h"
+#include "indigroup.h"
+#include "indidevice.h"
+#include "indi/indicom.h"
+#include "kstars.h"
+#include "kstarsdatetime.h"
+
+#include <qsocketnotifier.h>
+#include <qtextedit.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+
+ /*******************************************************************
+** The device manager contain devices running from one indiserver
+** This allow KStars to control multiple devices distributed acorss
+** multiple servers seemingly in a way that is completely transparent
+** to devices and drivers alike.
+** The device Manager can be thought of as the 'networking' parent
+** of devices, while indimenu is 'GUI' parent of devices
+*******************************************************************/
+
+DeviceManager::DeviceManager(INDIMenu *INDIparent, int inID)
+{
+
+ parent = INDIparent;
+ mgrID = inID;
+
+ indi_dev.setAutoDelete(true);
+
+ serverFD = -1;
+ serverFP = NULL;
+ XMLParser = NULL;
+ sNotifier = NULL;
+
+}
+
+DeviceManager::~DeviceManager()
+{
+
+ if (serverFP)
+ fclose(serverFP);
+
+ if (serverFD >= 0)
+ close(serverFD);
+
+ if (XMLParser)
+ {
+ delLilXML(XMLParser);
+ XMLParser = NULL;
+ }
+
+ indi_dev.clear();
+
+}
+
+bool DeviceManager::indiConnect(QString inHost, QString inPort)
+{
+ host = inHost;
+ port = inPort;
+ QString errMsg;
+ struct sockaddr_in pin;
+ struct hostent *serverHostName = gethostbyname(host.ascii());
+ errMsg = QString("Connection to INDI host at %1 on port %2 failed.").arg(host).arg(port);
+
+ memset(&pin, 0, sizeof(pin));
+ pin.sin_family = AF_INET;
+ pin.sin_addr.s_addr = ((struct in_addr *) (serverHostName->h_addr))->s_addr;
+ pin.sin_port = htons(port.toInt());
+
+ if ( (serverFD = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ KMessageBox::error(0, i18n("Cannot create socket"));
+ return false;
+ }
+
+ if ( ::connect(serverFD, (struct sockaddr*) &pin, sizeof(pin)) == -1)
+ {
+ KMessageBox::error(0, errMsg);
+ serverFD = -1;
+ return false;
+ }
+
+ // callback notified
+ sNotifier = new QSocketNotifier( serverFD, QSocketNotifier::Read, this);
+ QObject::connect( sNotifier, SIGNAL(activated(int)), this, SLOT(dataReceived()));
+
+ if (XMLParser)
+ delLilXML(XMLParser);
+ XMLParser = newLilXML();
+
+ // ready for fprintf
+ serverFP = fdopen(serverFD, "w");
+
+ if (serverFP == NULL)
+ {
+ KMessageBox::error(0, i18n("Cannot read server file descriptor"));
+ serverFD = -1;
+ return false;
+ }
+
+ setbuf (serverFP, NULL);
+
+ fprintf(serverFP, "<enableBLOB>Also</enableBLOB>\n");
+ fprintf(serverFP, "<getProperties version='%g'/>\n", INDIVERSION);
+
+ // We made it!
+ return true;
+}
+
+
+void DeviceManager::dataReceived()
+{
+ char ibuf[32]; /* not so much user input lags */
+ char errmsg[ERRMSG_SIZE];
+ int i, nr;
+
+ /* read INDI command */
+ nr = read (serverFD, ibuf, sizeof(ibuf)-1);
+ if (nr <= 0)
+ {
+ if (nr < 0)
+ strcpy (errmsg, "INDI: input error.");
+ else
+ strcpy (errmsg, "INDI: agent closed connection.");
+
+
+ tcflush(serverFD, TCIFLUSH);
+ sNotifier->disconnect();
+ close(serverFD);
+ parent->removeDeviceMgr(mgrID);
+ KMessageBox::error(0, QString::fromLatin1(errmsg));
+
+ return;
+ }
+
+ ibuf[ sizeof( ibuf )-1 ] = '\0';
+
+ /* process each char */
+ for (i = 0; i < nr; i++)
+ {
+ if (!XMLParser)
+ return;
+
+ XMLEle *root = readXMLEle (XMLParser, (int)ibuf[i], errmsg);
+ if (root)
+ {
+ //prXMLEle (stdout, root, 0);
+ if (dispatchCommand(root, errmsg) < 0)
+ {
+ fprintf(stderr, "%s", errmsg);
+ prXMLEle (stdout, root, 0);
+ }
+
+ delXMLEle (root);
+ }
+ else if (*errmsg)
+ {
+ kdDebug() << errmsg << endl;
+ }
+ }
+}
+
+int DeviceManager::dispatchCommand(XMLEle *root, char errmsg[])
+{
+
+ if (!strcmp (tagXMLEle(root), "message"))
+ return messageCmd(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "delProperty"))
+ return delPropertyCmd(root, errmsg);
+
+ /* Get the device, if not available, create it */
+ INDI_D *dp = findDev (root, 1, errmsg);
+ if (dp == NULL)
+ return -1;
+
+ if (!strcmp (tagXMLEle(root), "defTextVector"))
+ return dp->buildTextGUI(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "defNumberVector"))
+ return dp->buildNumberGUI(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "defSwitchVector"))
+ return dp->buildSwitchesGUI(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "defLightVector"))
+ return dp->buildLightsGUI(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "defBLOBVector"))
+ return dp->buildBLOBGUI(root, errmsg);
+ else if (!strcmp (tagXMLEle(root), "setTextVector") ||
+ !strcmp (tagXMLEle(root), "setNumberVector") ||
+ !strcmp (tagXMLEle(root), "setSwitchVector") ||
+ !strcmp (tagXMLEle(root), "setLightVector") ||
+ !strcmp (tagXMLEle(root), "setBLOBVector"))
+ return dp->setAnyCmd(root, errmsg);
+
+ return (-1);
+}
+
+/* delete the property in the given device, including widgets and data structs.
+ * when last property is deleted, delete the device too.
+ * if no property name attribute at all, delete the whole device regardless.
+ * return 0 if ok, else -1 with reason in errmsg[].
+ */
+int DeviceManager::delPropertyCmd (XMLEle *root, char errmsg[])
+{
+
+ XMLAtt *ap;
+ INDI_D *dp;
+ INDI_P *pp;
+
+ /* dig out device and optional property name */
+ dp = findDev (root, 0, errmsg);
+ if (!dp)
+ return (-1);
+
+ checkMsg(root, dp);
+
+ ap = findXMLAtt (root, "name");
+
+ /* Delete property if it exists, otherwise, delete the whole device */
+ if (ap)
+ {
+ pp = dp->findProp(QString(valuXMLAtt(ap)));
+
+ if(pp)
+ return dp->removeProperty(pp);
+ else
+ return (-1);
+ }
+ // delete the whole device
+ else
+ return removeDevice(dp->name, errmsg);
+
+}
+
+int DeviceManager::removeDevice(QString devName, char errmsg[])
+{
+
+ // remove all devices if devName == NULL
+ if (devName == NULL)
+ {
+ indi_dev.clear();
+ return (0);
+ }
+
+ for (unsigned int i=0; i < indi_dev.count(); i++)
+ {
+ if (indi_dev.at(i)->name == devName)
+ {
+ kdDebug() << "Device Manager: Device found, deleting " << devName << endl;
+ indi_dev.remove(i);
+ return (0);
+ }
+ }
+
+ snprintf(errmsg, ERRMSG_SIZE, "Device %.32s not found" , devName.ascii());
+ return -1;
+}
+
+INDI_D * DeviceManager::findDev (QString devName, char errmsg[])
+{
+ /* search for existing */
+ for (unsigned int i = 0; i < indi_dev.count(); i++)
+ {
+ if (indi_dev.at(i)->name == devName)
+ return (indi_dev.at(i));
+ }
+
+ snprintf (errmsg, ERRMSG_SIZE, "INDI: no such device %.32s", devName.ascii());
+ kdDebug() << errmsg;
+
+ return NULL;
+}
+
+/* add new device to mainrc_w using info in dep.
+- * if trouble return NULL with reason in errmsg[]
+- */
+INDI_D * DeviceManager::addDevice (XMLEle *dep, char errmsg[])
+{
+ INDI_D *dp;
+ XMLAtt *ap;
+
+ /* allocate new INDI_D on indi_dev */
+ ap = findAtt (dep, "device", errmsg);
+ if (!ap)
+ return NULL;
+
+ if (parent->currentLabel.isEmpty())
+ parent->setCustomLabel(valuXMLAtt(ap));
+
+ dp = new INDI_D(parent, this, QString(valuXMLAtt(ap)), parent->currentLabel);
+
+ indi_dev.append(dp);
+
+ emit newDevice();
+
+ // Reset label
+ parent->currentLabel = "";
+
+ /* ok */
+ return dp;
+}
+
+INDI_D * DeviceManager::findDev (XMLEle *root, int create, char errmsg[])
+{
+ XMLAtt *ap;
+ char *dn;
+
+ /* get device name */
+ ap = findAtt (root, "device", errmsg);
+ if (!ap)
+ return (NULL);
+ dn = valuXMLAtt(ap);
+
+ /* search for existing */
+ for (uint i = 0; i < indi_dev.count(); i++)
+ {
+ if (indi_dev.at(i)->name == QString(dn))
+ return (indi_dev.at(i));
+ }
+
+ /* not found, create if ok */
+ if (create)
+ return (addDevice (root, errmsg));
+
+
+ snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.32s> no such device %.32s", tagXMLEle(root), dn);
+ return NULL;
+}
+
+/* a general message command received from the device.
+ * return 0 if ok, else -1 with reason in errmsg[].
+ */
+int DeviceManager::messageCmd (XMLEle *root, char errmsg[])
+{
+ checkMsg (root, findDev (root, 0, errmsg));
+ return (0);
+}
+
+/* display message attribute.
+ * N.B. don't put carriage control in msg, we take care of that.
+ */
+void DeviceManager::checkMsg (XMLEle *root, INDI_D *dp)
+{
+ XMLAtt *ap;
+ ap = findXMLAtt(root, "message");
+
+ if (ap)
+ doMsg(root, dp);
+}
+
+/* display valu of message and timestamp in dp's scrolled area, if any, else general.
+ * prefix our time stamp if not included.
+ * N.B. don't put carriage control in msg, we take care of that.
+ */
+void DeviceManager::doMsg (XMLEle *msg, INDI_D *dp)
+{
+ QTextEdit *txt_w;
+ XMLAtt *message;
+ XMLAtt *timestamp;
+
+ if (dp == NULL)
+ {
+ kdDebug() << "Warning: dp is null." << endl;
+ return;
+ }
+
+ txt_w = dp->msgST_w;
+
+ /* prefix our timestamp if not with msg */
+ timestamp = findXMLAtt (msg, "timestamp");
+
+ if (timestamp)
+ txt_w->insert(QString(valuXMLAtt(timestamp)) + QString(" "));
+ else
+ txt_w->insert( KStarsDateTime::currentDateTime().toString("yyyy/mm/dd - h:m:s ap "));
+
+ /* finally! the msg */
+ message = findXMLAtt(msg, "message");
+
+ txt_w->insert( QString(valuXMLAtt(message)) + QString("\n"));
+
+ if ( Options::indiMessages() )
+ parent->ksw->statusBar()->changeItem( QString(valuXMLAtt(message)), 0);
+
+}
+
+void DeviceManager::sendNewText (INDI_P *pp)
+{
+ INDI_E *lp;
+
+ fprintf(serverFP, "<newTextVector\n");
+ fprintf(serverFP, " device='%s'\n", pp->pg->dp->name.ascii());
+ fprintf(serverFP, " name='%s'\n>", pp->name.ascii());
+
+ for (lp = pp->el.first(); lp != NULL; lp = pp->el.next())
+ {
+ fprintf(serverFP, " <oneText\n");
+ fprintf(serverFP, " name='%s'>\n", lp->name.ascii());
+ fprintf(serverFP, " %s\n", lp->text.ascii());
+ fprintf(serverFP, " </oneText>\n");
+ }
+ fprintf(serverFP, "</newTextVector>\n");
+}
+
+void DeviceManager::sendNewNumber (INDI_P *pp)
+{
+ INDI_E *lp;
+
+ fprintf(serverFP, "<newNumberVector\n");
+ fprintf(serverFP, " device='%s'\n", pp->pg->dp->name.ascii());
+ fprintf(serverFP, " name='%s'\n>", pp->name.ascii());
+
+ for (lp = pp->el.first(); lp != NULL; lp = pp->el.next())
+ {
+ fprintf(serverFP, " <oneNumber\n");
+ fprintf(serverFP, " name='%s'>\n", lp->name.ascii());
+ fprintf(serverFP, " %g\n", lp->targetValue);
+ fprintf(serverFP, " </oneNumber>\n");
+ }
+ fprintf(serverFP, "</newNumberVector>\n");
+
+}
+
+void DeviceManager::sendNewSwitch (INDI_P *pp, int index)
+{
+ INDI_E *lp;
+ int i=0;
+
+ fprintf (serverFP,"<newSwitchVector\n");
+ fprintf (serverFP," device='%s'\n", pp->pg->dp->name.ascii());
+ fprintf (serverFP," name='%s'>\n", pp->name.ascii());
+
+ for (lp = pp->el.first(); lp != NULL; lp = pp->el.next(), i++)
+ if (i == index)
+ {
+ fprintf (serverFP," <oneSwitch\n");
+ fprintf (serverFP," name='%s'>\n", lp->name.ascii());
+ fprintf (serverFP," %s\n", lp->state == PS_ON ? "On" : "Off");
+ fprintf (serverFP," </oneSwitch>\n");
+ break;
+ }
+ fprintf (serverFP, "</newSwitchVector>\n");
+
+}
+
+void DeviceManager::startBlob (QString devName, QString propName, QString timestamp)
+{
+
+ fprintf (serverFP, "<newBLOBVector\n");
+ fprintf (serverFP, " device='%s'\n", devName.ascii());
+ fprintf (serverFP, " name='%s'\n", propName.ascii());
+ fprintf (serverFP, " timestamp='%s'>\n", timestamp.ascii());
+
+}
+
+void DeviceManager::sendOneBlob(QString blobName, unsigned int blobSize, QString blobFormat, unsigned char * blobBuffer)
+{
+
+ fprintf (serverFP, " <oneBLOB\n");
+ fprintf (serverFP, " name='%s'\n", blobName.ascii());
+ fprintf (serverFP, " size='%d'\n", blobSize);
+ fprintf (serverFP, " format='%s'>\n", blobFormat.ascii());
+
+ for (unsigned i = 0; i < blobSize; i += 72)
+ fprintf (serverFP, " %.72s\n", blobBuffer+i);
+
+ fprintf (serverFP, " </oneBLOB>\n");
+
+}
+
+void DeviceManager::finishBlob()
+{
+ fprintf (serverFP, "</newBLOBVector>\n");
+}
+
+
+#include "devicemanager.moc"