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.
15 #include "devicemanager.h"
17 #include "indiproperty.h"
18 #include "indigroup.h"
19 #include "indidevice.h"
20 #include "indi/indicom.h"
22 #include "kstarsdatetime.h"
24 #include <qsocketnotifier.h>
25 #include <qtextedit.h>
29 #include <kmessagebox.h>
30 #include <kstatusbar.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.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
)
55 indi_dev
.setAutoDelete(true);
64 DeviceManager::~DeviceManager()
83 bool DeviceManager::indiConnect(QString inHost
, QString inPort
)
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"));
103 if ( ::connect(serverFD
, (struct sockaddr
*) &pin
, sizeof(pin
)) == -1)
105 KMessageBox::error(0, errMsg
);
111 sNotifier
= new QSocketNotifier( serverFD
, QSocketNotifier::Read
, this);
112 QObject::connect( sNotifier
, SIGNAL(activated(int)), this, SLOT(dataReceived()));
115 delLilXML(XMLParser
);
116 XMLParser
= newLilXML();
119 serverFP
= fdopen(serverFD
, "w");
121 if (serverFP
== NULL
)
123 KMessageBox::error(0, i18n("Cannot read server file descriptor"));
128 setbuf (serverFP
, NULL
);
130 fprintf(serverFP
, "<getProperties version='%g'/>\n", INDIVERSION
);
137 void DeviceManager::dataReceived()
139 char ibuf
[32]; /* not so much user input lags */
140 char errmsg
[ERRMSG_SIZE
];
143 /* read INDI command */
144 nr
= read (serverFD
, ibuf
, sizeof(ibuf
)-1);
148 strcpy (errmsg
, "INDI: input error.");
150 strcpy (errmsg
, "INDI: agent closed connection.");
153 tcflush(serverFD
, TCIFLUSH
);
154 sNotifier
->disconnect();
156 parent
->removeDeviceMgr(mgrID
);
157 KMessageBox::error(0, QString::fromLatin1(errmsg
));
162 ibuf
[ sizeof( ibuf
)-1 ] = '\0';
164 /* process each char */
165 for (i
= 0; i
< nr
; i
++)
170 XMLEle
*root
= readXMLEle (XMLParser
, (int)ibuf
[i
], errmsg
);
173 //prXMLEle (stdout, root, 0);
174 if (dispatchCommand(root
, errmsg
) < 0)
176 fprintf(stderr
, "%s", errmsg
);
177 prXMLEle (stdout
, root
, 0);
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
);
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
);
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
[])
234 /* dig out device and optional property name */
235 dp
= findDev (root
, 0, errmsg
);
241 ap
= findXMLAtt (root
, "name");
243 /* Delete property if it exists, otherwise, delete the whole device */
246 pp
= dp
->findProp(QString(valuXMLAtt(ap
)));
249 return dp
->removeProperty(pp
);
253 // delete the whole device
255 return removeDevice(dp
->name
, errmsg
);
259 int DeviceManager::removeDevice(QString devName
, char errmsg
[])
262 // remove all devices if devName == NULL
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
;
279 snprintf(errmsg
, ERRMSG_SIZE
, "Device %.32s not found" , devName
.ascii());
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());
298 /* add new device to mainrc_w using info in dep.
299 - * if trouble return NULL with reason in errmsg[]
301 INDI_D
* DeviceManager::addDevice (XMLEle
*dep
, char errmsg
[])
306 /* allocate new INDI_D on indi_dev */
307 ap
= findAtt (dep
, "device", errmsg
);
311 if (parent
->currentLabel
.isEmpty())
312 parent
->setCustomLabel(valuXMLAtt(ap
));
314 dp
= new INDI_D(parent
, this, QString(valuXMLAtt(ap
)), parent
->currentLabel
);
321 parent
->currentLabel
= "";
327 INDI_D
* DeviceManager::findDev (XMLEle
*root
, int create
, char errmsg
[])
332 /* get device name */
333 ap
= findAtt (root
, "device", errmsg
);
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 */
347 return (addDevice (root
, errmsg
));
350 snprintf (errmsg
, ERRMSG_SIZE
, "INDI: <%.32s> no such device %.32s", tagXMLEle(root
), dn
);
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
));
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
)
369 ap
= findXMLAtt(root
, "message");
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
)
387 kdDebug() << "Warning: dp is null." << endl
;
393 /* prefix our timestamp if not with msg */
394 timestamp
= findXMLAtt (msg
, "timestamp");
397 txt_w
->insert(QString(valuXMLAtt(timestamp
)) + QString(" "));
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
)
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
)
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
)
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
++)
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");
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"