moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / devicemanager.cpp
blobcd880be14079f256c6402e743b8119f9129ce4d5
1 /* Device Manager
2 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
4 This application is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 JM Changelog
10 2004-16-1: Start
14 #include "Options.h"
15 #include "devicemanager.h"
16 #include "indimenu.h"
17 #include "indiproperty.h"
18 #include "indigroup.h"
19 #include "indidevice.h"
20 #include "indi/indicom.h"
21 #include "kstars.h"
22 #include "kstarsdatetime.h"
24 #include <qsocketnotifier.h>
25 #include <qtextedit.h>
27 #include <klocale.h>
28 #include <kdebug.h>
29 #include <kmessagebox.h>
30 #include <kstatusbar.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <termios.h>
40 /*******************************************************************
41 ** The device manager contain devices running from one indiserver
42 ** This allow KStars to control multiple devices distributed acorss
43 ** multiple servers seemingly in a way that is completely transparent
44 ** to devices and drivers alike.
45 ** The device Manager can be thought of as the 'networking' parent
46 ** of devices, while indimenu is 'GUI' parent of devices
47 *******************************************************************/
49 DeviceManager::DeviceManager(INDIMenu *INDIparent, int inID)
52 parent = INDIparent;
53 mgrID = inID;
55 indi_dev.setAutoDelete(true);
57 serverFD = -1;
58 serverFP = NULL;
59 XMLParser = NULL;
60 sNotifier = NULL;
64 DeviceManager::~DeviceManager()
67 if (serverFP)
68 fclose(serverFP);
70 if (serverFD >= 0)
71 close(serverFD);
73 if (XMLParser)
75 delLilXML(XMLParser);
76 XMLParser = NULL;
79 indi_dev.clear();
83 bool DeviceManager::indiConnect(QString inHost, QString inPort)
85 host = inHost;
86 port = inPort;
87 QString errMsg;
88 struct sockaddr_in pin;
89 struct hostent *serverHostName = gethostbyname(host.ascii());
90 errMsg = QString("Connection to INDI host at %1 on port %2 failed.").arg(host).arg(port);
92 memset(&pin, 0, sizeof(pin));
93 pin.sin_family = AF_INET;
94 pin.sin_addr.s_addr = ((struct in_addr *) (serverHostName->h_addr))->s_addr;
95 pin.sin_port = htons(port.toInt());
97 if ( (serverFD = socket(AF_INET, SOCK_STREAM, 0)) == -1)
99 KMessageBox::error(0, i18n("Cannot create socket"));
100 return false;
103 if ( ::connect(serverFD, (struct sockaddr*) &pin, sizeof(pin)) == -1)
105 KMessageBox::error(0, errMsg);
106 serverFD = -1;
107 return false;
110 // callback notified
111 sNotifier = new QSocketNotifier( serverFD, QSocketNotifier::Read, this);
112 QObject::connect( sNotifier, SIGNAL(activated(int)), this, SLOT(dataReceived()));
114 if (XMLParser)
115 delLilXML(XMLParser);
116 XMLParser = newLilXML();
118 // ready for fprintf
119 serverFP = fdopen(serverFD, "w");
121 if (serverFP == NULL)
123 KMessageBox::error(0, i18n("Cannot read server file descriptor"));
124 serverFD = -1;
125 return false;
128 setbuf (serverFP, NULL);
130 fprintf(serverFP, "<getProperties version='%g'/>\n", INDIVERSION);
132 // We made it!
133 return true;
137 void DeviceManager::dataReceived()
139 char ibuf[32]; /* not so much user input lags */
140 char errmsg[ERRMSG_SIZE];
141 int i, nr;
143 /* read INDI command */
144 nr = read (serverFD, ibuf, sizeof(ibuf)-1);
145 if (nr <= 0)
147 if (nr < 0)
148 strcpy (errmsg, "INDI: input error.");
149 else
150 strcpy (errmsg, "INDI: agent closed connection.");
153 tcflush(serverFD, TCIFLUSH);
154 sNotifier->disconnect();
155 close(serverFD);
156 parent->removeDeviceMgr(mgrID);
157 KMessageBox::error(0, QString::fromLatin1(errmsg));
159 return;
162 ibuf[ sizeof( ibuf )-1 ] = '\0';
164 /* process each char */
165 for (i = 0; i < nr; i++)
167 if (!XMLParser)
168 return;
170 XMLEle *root = readXMLEle (XMLParser, (int)ibuf[i], errmsg);
171 if (root)
173 //prXMLEle (stdout, root, 0);
174 if (dispatchCommand(root, errmsg) < 0)
176 fprintf(stderr, "%s", errmsg);
177 prXMLEle (stdout, root, 0);
180 delXMLEle (root);
182 else if (*errmsg)
184 kdDebug() << errmsg << endl;
189 int DeviceManager::dispatchCommand(XMLEle *root, char errmsg[])
192 if (!strcmp (tagXMLEle(root), "message"))
193 return messageCmd(root, errmsg);
194 else if (!strcmp (tagXMLEle(root), "delProperty"))
195 return delPropertyCmd(root, errmsg);
197 /* Get the device, if not available, create it */
198 INDI_D *dp = findDev (root, 1, errmsg);
199 if (dp == NULL)
200 return -1;
202 if (!strcmp (tagXMLEle(root), "defTextVector"))
203 return dp->buildTextGUI(root, errmsg);
204 else if (!strcmp (tagXMLEle(root), "defNumberVector"))
205 return dp->buildNumberGUI(root, errmsg);
206 else if (!strcmp (tagXMLEle(root), "defSwitchVector"))
207 return dp->buildSwitchesGUI(root, errmsg);
208 else if (!strcmp (tagXMLEle(root), "defLightVector"))
209 return dp->buildLightsGUI(root, errmsg);
210 else if (!strcmp (tagXMLEle(root), "defBLOBVector"))
211 return dp->buildBLOBGUI(root, errmsg);
212 else if (!strcmp (tagXMLEle(root), "setTextVector") ||
213 !strcmp (tagXMLEle(root), "setNumberVector") ||
214 !strcmp (tagXMLEle(root), "setSwitchVector") ||
215 !strcmp (tagXMLEle(root), "setLightVector") ||
216 !strcmp (tagXMLEle(root), "setBLOBVector"))
217 return dp->setAnyCmd(root, errmsg);
219 return (-1);
222 /* delete the property in the given device, including widgets and data structs.
223 * when last property is deleted, delete the device too.
224 * if no property name attribute at all, delete the whole device regardless.
225 * return 0 if ok, else -1 with reason in errmsg[].
227 int DeviceManager::delPropertyCmd (XMLEle *root, char errmsg[])
230 XMLAtt *ap;
231 INDI_D *dp;
232 INDI_P *pp;
234 /* dig out device and optional property name */
235 dp = findDev (root, 0, errmsg);
236 if (!dp)
237 return (-1);
239 checkMsg(root, dp);
241 ap = findXMLAtt (root, "name");
243 /* Delete property if it exists, otherwise, delete the whole device */
244 if (ap)
246 pp = dp->findProp(QString(valuXMLAtt(ap)));
248 if(pp)
249 return dp->removeProperty(pp);
250 else
251 return (-1);
253 // delete the whole device
254 else
255 return removeDevice(dp->name, errmsg);
259 int DeviceManager::removeDevice(QString devName, char errmsg[])
262 // remove all devices if devName == NULL
263 if (devName == NULL)
265 indi_dev.clear();
266 return (0);
269 for (unsigned int i=0; i < indi_dev.count(); i++)
271 if (indi_dev.at(i)->name == devName)
273 kdDebug() << "Device Manager: Device found, deleting " << devName << endl;
274 indi_dev.remove(i);
275 return (0);
279 snprintf(errmsg, ERRMSG_SIZE, "Device %.32s not found" , devName.ascii());
280 return -1;
283 INDI_D * DeviceManager::findDev (QString devName, char errmsg[])
285 /* search for existing */
286 for (unsigned int i = 0; i < indi_dev.count(); i++)
288 if (indi_dev.at(i)->name == devName)
289 return (indi_dev.at(i));
292 snprintf (errmsg, ERRMSG_SIZE, "INDI: no such device %.32s", devName.ascii());
293 kdDebug() << errmsg;
295 return NULL;
298 /* add new device to mainrc_w using info in dep.
299 - * if trouble return NULL with reason in errmsg[]
300 - */
301 INDI_D * DeviceManager::addDevice (XMLEle *dep, char errmsg[])
303 INDI_D *dp;
304 XMLAtt *ap;
306 /* allocate new INDI_D on indi_dev */
307 ap = findAtt (dep, "device", errmsg);
308 if (!ap)
309 return NULL;
311 if (parent->currentLabel.isEmpty())
312 parent->setCustomLabel(valuXMLAtt(ap));
314 dp = new INDI_D(parent, this, QString(valuXMLAtt(ap)), parent->currentLabel);
316 indi_dev.append(dp);
318 emit newDevice();
320 // Reset label
321 parent->currentLabel = "";
323 /* ok */
324 return dp;
327 INDI_D * DeviceManager::findDev (XMLEle *root, int create, char errmsg[])
329 XMLAtt *ap;
330 char *dn;
332 /* get device name */
333 ap = findAtt (root, "device", errmsg);
334 if (!ap)
335 return (NULL);
336 dn = valuXMLAtt(ap);
338 /* search for existing */
339 for (uint i = 0; i < indi_dev.count(); i++)
341 if (indi_dev.at(i)->name == QString(dn))
342 return (indi_dev.at(i));
345 /* not found, create if ok */
346 if (create)
347 return (addDevice (root, errmsg));
350 snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.32s> no such device %.32s", tagXMLEle(root), dn);
351 return NULL;
354 /* a general message command received from the device.
355 * return 0 if ok, else -1 with reason in errmsg[].
357 int DeviceManager::messageCmd (XMLEle *root, char errmsg[])
359 checkMsg (root, findDev (root, 0, errmsg));
360 return (0);
363 /* display message attribute.
364 * N.B. don't put carriage control in msg, we take care of that.
366 void DeviceManager::checkMsg (XMLEle *root, INDI_D *dp)
368 XMLAtt *ap;
369 ap = findXMLAtt(root, "message");
371 if (ap)
372 doMsg(root, dp);
375 /* display valu of message and timestamp in dp's scrolled area, if any, else general.
376 * prefix our time stamp if not included.
377 * N.B. don't put carriage control in msg, we take care of that.
379 void DeviceManager::doMsg (XMLEle *msg, INDI_D *dp)
381 QTextEdit *txt_w;
382 XMLAtt *message;
383 XMLAtt *timestamp;
385 if (dp == NULL)
387 kdDebug() << "Warning: dp is null." << endl;
388 return;
391 txt_w = dp->msgST_w;
393 /* prefix our timestamp if not with msg */
394 timestamp = findXMLAtt (msg, "timestamp");
396 if (timestamp)
397 txt_w->insert(QString(valuXMLAtt(timestamp)) + QString(" "));
398 else
399 txt_w->insert( KStarsDateTime::currentDateTime().toString("yyyy/mm/dd - h:m:s ap "));
401 /* finally! the msg */
402 message = findXMLAtt(msg, "message");
404 txt_w->insert( QString(valuXMLAtt(message)) + QString("\n"));
406 if ( Options::indiMessages() )
407 parent->ksw->statusBar()->changeItem( QString(valuXMLAtt(message)), 0);
411 void DeviceManager::sendNewText (INDI_P *pp)
413 INDI_E *lp;
415 fprintf(serverFP, "<newTextVector\n");
416 fprintf(serverFP, " device='%s'\n", pp->pg->dp->name.ascii());
417 fprintf(serverFP, " name='%s'\n>", pp->name.ascii());
419 for (lp = pp->el.first(); lp != NULL; lp = pp->el.next())
421 fprintf(serverFP, " <oneText\n");
422 fprintf(serverFP, " name='%s'>\n", lp->name.ascii());
423 fprintf(serverFP, " %s\n", lp->text.ascii());
424 fprintf(serverFP, " </oneText>\n");
426 fprintf(serverFP, "</newTextVector>\n");
429 void DeviceManager::sendNewNumber (INDI_P *pp)
431 INDI_E *lp;
433 fprintf(serverFP, "<newNumberVector\n");
434 fprintf(serverFP, " device='%s'\n", pp->pg->dp->name.ascii());
435 fprintf(serverFP, " name='%s'\n>", pp->name.ascii());
437 for (lp = pp->el.first(); lp != NULL; lp = pp->el.next())
439 fprintf(serverFP, " <oneNumber\n");
440 fprintf(serverFP, " name='%s'>\n", lp->name.ascii());
441 fprintf(serverFP, " %g\n", lp->targetValue);
442 fprintf(serverFP, " </oneNumber>\n");
444 fprintf(serverFP, "</newNumberVector>\n");
448 void DeviceManager::sendNewSwitch (INDI_P *pp, int index)
450 INDI_E *lp;
451 int i=0;
453 fprintf (serverFP,"<newSwitchVector\n");
454 fprintf (serverFP," device='%s'\n", pp->pg->dp->name.ascii());
455 fprintf (serverFP," name='%s'>\n", pp->name.ascii());
457 for (lp = pp->el.first(); lp != NULL; lp = pp->el.next(), i++)
458 if (i == index)
460 fprintf (serverFP," <oneSwitch\n");
461 fprintf (serverFP," name='%s'>\n", lp->name.ascii());
462 fprintf (serverFP," %s\n", lp->state == PS_ON ? "On" : "Off");
463 fprintf (serverFP," </oneSwitch>\n");
464 break;
466 fprintf (serverFP, "</newSwitchVector>\n");
470 void DeviceManager::startBlob (QString devName, QString propName, QString timestamp)
473 fprintf (serverFP, "<newBLOBVector\n");
474 fprintf (serverFP, " device='%s'\n", devName.ascii());
475 fprintf (serverFP, " name='%s'\n", propName.ascii());
476 fprintf (serverFP, " timestamp='%s'>\n", timestamp.ascii());
480 void DeviceManager::sendOneBlob(QString blobName, unsigned int blobSize, QString blobFormat, unsigned char * blobBuffer)
483 fprintf (serverFP, " <oneBLOB\n");
484 fprintf (serverFP, " name='%s'\n", blobName.ascii());
485 fprintf (serverFP, " size='%d'\n", blobSize);
486 fprintf (serverFP, " format='%s'>\n", blobFormat.ascii());
488 for (unsigned i = 0; i < blobSize; i += 72)
489 fprintf (serverFP, " %.72s\n", blobBuffer+i);
491 fprintf (serverFP, " </oneBLOB>\n");
495 void DeviceManager::finishBlob()
497 fprintf (serverFP, "</newBLOBVector>\n");
501 #include "devicemanager.moc"