source: BAORadio/libindi/v1.0.1/libs/indibase/baseclient.cpp@ 654

Last change on this file since 654 was 502, checked in by frichard, 15 years ago

-BAOControl : petite interface permettant de contrôler les antennes via le pilote indi_BAO
-Le pilote indi_BAO utilise désormais indilib v 0.7

File size: 12.5 KB
Line 
1#include <stdlib.h>
2#include <string.h>
3
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/socket.h>
7#include <netinet/in.h>
8#include <netdb.h>
9
10#include "baseclient.h"
11#include "basedriver.h"
12#include "indicom.h"
13
14#include <errno.h>
15
16#define MAXINDIBUF 64
17
18INDI::BaseClient::BaseClient()
19{
20 cServer = "localhost";
21 cPort = 7624;
22
23}
24
25
26INDI::BaseClient::~BaseClient()
27{
28
29 disconnect();
30
31}
32
33void INDI::BaseClient::setServer(const char * hostname, unsigned int port)
34{
35 cServer = hostname;
36 cPort = port;
37
38}
39
40void INDI::BaseClient::watchDevice(const char * deviceName)
41{
42 cDeviceNames.push_back(deviceName);
43}
44
45bool INDI::BaseClient::connect()
46{
47 struct sockaddr_in serv_addr;
48 struct hostent *hp;
49
50 /* lookup host address */
51 hp = gethostbyname(cServer.c_str());
52 if (!hp)
53 {
54 herror ("gethostbyname");
55 return false;
56 }
57
58 /* create a socket to the INDI server */
59 (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
60 serv_addr.sin_family = AF_INET;
61 serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
62 serv_addr.sin_port = htons(cPort);
63 if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
64 {
65 perror ("socket");
66 return false;
67 }
68
69 /* connect */
70 if (::connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
71 {
72 perror ("connect");
73 return false;
74 }
75
76 /* prepare for line-oriented i/o with client */
77 svrwfp = fdopen (sockfd, "w");
78 svrrfp = fdopen (sockfd, "r");
79
80 int result = pthread_create( &listen_thread, NULL, &INDI::BaseClient::listenHelper, this);
81
82 if (result != 0)
83 {
84 perror("thread");
85 return false;
86 }
87
88 return true;
89}
90
91void INDI::BaseClient::disconnect()
92{
93 char errmsg[MAXRBUF];
94 removeDevice(NULL, errmsg);
95 if (lillp)
96 delLilXML(lillp);
97 lillp = NULL;
98 pthread_cancel(listen_thread);
99 close(sockfd);
100 if (svrwfp)
101 fclose(svrwfp);
102 svrwfp = NULL;
103 if (svrrfp)
104 fclose(svrrfp);
105 svrrfp = NULL;
106}
107
108INDI::BaseDriver * INDI::BaseClient::getDevice(const char * deviceName)
109{
110 vector<INDI::BaseDriver *>::const_iterator devi;
111 for ( devi = cDevices.begin(); devi != cDevices.end(); devi++)
112 if (!strcmp(deviceName, (*devi)->deviceName()))
113 return (*devi);
114
115 return NULL;
116}
117
118void * INDI::BaseClient::listenHelper(void *context)
119{
120 (static_cast<INDI::BaseClient *> (context))->listenINDI();
121}
122
123void INDI::BaseClient::listenINDI()
124{
125 char msg[MAXRBUF];
126 char buffer[MAXINDIBUF];
127 int n=0, err_code=0;
128
129 if (cDeviceNames.empty())
130 fprintf(svrwfp, "<getProperties version='%g'/>\n", INDIV);
131 else
132 {
133 vector<string>::const_iterator stri;
134 for ( stri = cDeviceNames.begin(); stri != cDeviceNames.end(); stri++)
135 fprintf(svrwfp, "<getProperties version='%g' device='%s'/>\n", INDIV, (*stri).c_str());
136 }
137
138 fflush (svrwfp);
139
140 lillp = newLilXML();
141
142 /* read from server, exit if find all requested properties */
143 while (1)
144 {
145 n = fread(buffer, 1, MAXINDIBUF, svrrfp);
146
147 if (n ==0)
148 {
149 if (ferror(svrrfp))
150 perror ("read");
151 else
152 fprintf (stderr,"INDI server %s/%d disconnected\n", cServer.c_str(), cPort);
153
154 serverDisconnected();
155 return;
156 }
157
158 for (int i=0; i < n; i++)
159 {
160 XMLEle *root = readXMLEle (lillp, buffer[i], msg);
161 if (root)
162 {
163 if ( (err_code = dispatchCommand(root, msg)) < 0)
164 {
165 // Silenty ignore property duplication errors
166 if (err_code != INDI_PROPERTY_DUPLICATED)
167 {
168 IDLog("Dispatch command error: %s\n", msg);
169 prXMLEle (stderr, root, 0);
170 }
171 }
172
173 delXMLEle (root); /* not yet, delete and continue */
174 }
175 else if (msg[0])
176 {
177 fprintf (stderr, "Bad XML from %s/%d: %s\n%s\n", cServer.c_str(), cPort, msg, buffer);
178 return;
179 }
180 }
181 }
182}
183
184int INDI::BaseClient::dispatchCommand(XMLEle *root, char * errmsg)
185{
186 if (!strcmp (tagXMLEle(root), "message"))
187 return messageCmd(root, errmsg);
188 else if (!strcmp (tagXMLEle(root), "delProperty"))
189 return delPropertyCmd(root, errmsg);
190
191 /* Get the device, if not available, create it */
192 INDI::BaseDriver *dp = findDev (root, 1, errmsg);
193 if (dp == NULL)
194 {
195 strcpy(errmsg,"No device available and none was created");
196 return INDI_DEVICE_NOT_FOUND;
197 }
198
199 if ((!strcmp (tagXMLEle(root), "defTextVector")) ||
200 (!strcmp (tagXMLEle(root), "defNumberVector")) ||
201 (!strcmp (tagXMLEle(root), "defSwitchVector")) ||
202 (!strcmp (tagXMLEle(root), "defLightVector")) ||
203 (!strcmp (tagXMLEle(root), "defBLOBVector")))
204 return dp->buildProp(root, errmsg);
205 else if (!strcmp (tagXMLEle(root), "setTextVector") ||
206 !strcmp (tagXMLEle(root), "setNumberVector") ||
207 !strcmp (tagXMLEle(root), "setSwitchVector") ||
208 !strcmp (tagXMLEle(root), "setLightVector") ||
209 !strcmp (tagXMLEle(root), "setBLOBVector"))
210 return dp->setValue(root, errmsg);
211
212 return INDI_DISPATCH_ERROR;
213}
214
215/* delete the property in the given device, including widgets and data structs.
216 * when last property is deleted, delete the device too.
217 * if no property name attribute at all, delete the whole device regardless.
218 * return 0 if ok, else -1 with reason in errmsg[].
219 */
220int INDI::BaseClient::delPropertyCmd (XMLEle *root, char * errmsg)
221{
222 XMLAtt *ap;
223 INDI::BaseDriver *dp;
224
225 /* dig out device and optional property name */
226 dp = findDev (root, 0, errmsg);
227 if (!dp)
228 return INDI_DEVICE_NOT_FOUND;
229
230 checkMsg(root, dp);
231
232 ap = findXMLAtt (root, "name");
233
234 /* Delete property if it exists, otherwise, delete the whole device */
235 if (ap)
236 return dp->removeProperty(valuXMLAtt(ap));
237 // delete the whole device
238 else
239 return removeDevice(dp->deviceName(), errmsg);
240}
241
242int INDI::BaseClient::removeDevice( const char * devName, char * errmsg )
243{
244 std::vector<INDI::BaseDriver *>::iterator devicei = cDevices.begin();
245
246 while (devicei != cDevices.end())
247 {
248 if (devName == NULL || !strcmp(devName, (*devicei)->deviceName()))
249 {
250 cDevices.erase(devicei);
251 delete (*devicei);
252 return 0;
253 }
254
255 devicei++;
256 }
257
258 snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
259 return INDI_DEVICE_NOT_FOUND;
260}
261
262INDI::BaseDriver * INDI::BaseClient::findDev( const char * devName, char * errmsg )
263{
264
265 std::vector<INDI::BaseDriver *>::const_iterator devicei;
266
267 for (devicei = cDevices.begin(); devicei != cDevices.end(); devicei++)
268 {
269 if (!strcmp(devName, (*devicei)->deviceName()))
270 return (*devicei);
271
272 }
273
274 snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
275 return NULL;
276}
277
278/* add new device */
279INDI::BaseDriver * INDI::BaseClient::addDevice (XMLEle *dep, char * errmsg)
280{
281 INDI::BaseDriver *dp;
282 XMLAtt *ap;
283 char * device_name;
284
285 /* allocate new INDI::BaseDriver */
286 ap = findXMLAtt (dep, "device");
287 if (!ap)
288 {
289 strncpy(errmsg, "Unable to find device attribute in XML element. Cannot add device.", MAXRBUF);
290 return NULL;
291 }
292
293 device_name = valuXMLAtt(ap);
294
295 dp = new INDI::BaseDriver();
296 dp->setMediator(this);
297 dp->setDeviceName(device_name);
298
299 cDevices.push_back(dp);
300
301 newDevice();
302
303 /* ok */
304 return dp;
305}
306
307INDI::BaseDriver * INDI::BaseClient::findDev (XMLEle *root, int create, char * errmsg)
308{
309 XMLAtt *ap;
310 INDI::BaseDriver *dp;
311 char *dn;
312
313 /* get device name */
314 ap = findXMLAtt (root, "device");
315 if (!ap)
316 {
317 snprintf(errmsg, MAXRBUF, "No device attribute found in element %s", tagXMLEle(root));
318 return (NULL);
319 }
320
321 dn = valuXMLAtt(ap);
322
323 dp = findDev(dn, errmsg);
324
325 if (dp)
326 return dp;
327
328 /* not found, create if ok */
329 if (create)
330 return (addDevice (root, errmsg));
331
332 snprintf(errmsg, MAXRBUF, "INDI: <%s> no such device %s", tagXMLEle(root), dn);
333 return NULL;
334}
335
336/* a general message command received from the device.
337 * return 0 if ok, else -1 with reason in errmsg[].
338 */
339int INDI::BaseClient::messageCmd (XMLEle *root, char * errmsg)
340{
341 checkMsg (root, findDev (root, 0, errmsg));
342 return (0);
343}
344
345/* add message to queue
346 * N.B. don't put carriage control in msg, we take care of that.
347 */
348void INDI::BaseClient::checkMsg (XMLEle *root, INDI::BaseDriver *dp)
349{
350 XMLAtt *ap;
351 ap = findXMLAtt(root, "message");
352
353 if (ap)
354 doMsg(root, dp);
355}
356
357/* Store msg in queue */
358void INDI::BaseClient::doMsg (XMLEle *msg, INDI::BaseDriver *dp)
359{
360 XMLAtt *message;
361 XMLAtt *time_stamp;
362 char msgBuffer[MAXRBUF];
363
364 if (dp == NULL)
365 return;
366
367 /* prefix our timestamp if not with msg */
368 time_stamp = findXMLAtt (msg, "timestamp");
369
370 if (time_stamp)
371 snprintf(msgBuffer, MAXRBUF, "%s ", valuXMLAtt(time_stamp));
372 else
373 snprintf(msgBuffer, MAXRBUF, "%s ", timestamp());
374
375 /* finally! the msg */
376 message = findXMLAtt(msg, "message");
377
378 if (!message) return;
379
380 // Prepend to the log
381 dp->addMessage(msgBuffer);
382 dp->addMessage(valuXMLAtt(message));
383 dp->addMessage("\n");
384\
385}
386
387void INDI::BaseClient::sendNewText (ITextVectorProperty *tvp)
388{
389 fprintf(svrwfp, "<newTextVector\n");
390 fprintf(svrwfp, " device='%s'\n", tvp->device);
391 fprintf(svrwfp, " name='%s'\n>", tvp->name);
392
393 for (int i=0; i < tvp->ntp; i++)
394 {
395 fprintf(svrwfp, " <oneText\n");
396 fprintf(svrwfp, " name='%s'>\n", tvp->tp[i].name);
397 fprintf(svrwfp, " %s\n", tvp->tp[i].text);
398 fprintf(svrwfp, " </oneText>\n");
399 }
400 fprintf(svrwfp, "</newTextVector>\n");
401
402 fflush(svrwfp);
403}
404
405void INDI::BaseClient::sendNewNumber (INumberVectorProperty *nvp)
406{
407 fprintf(svrwfp, "<newNumberVector\n");
408 fprintf(svrwfp, " device='%s'\n", nvp->device);
409 fprintf(svrwfp, " name='%s'\n>", nvp->name);
410
411 for (int i=0; i < nvp->nnp; i++)
412 {
413 fprintf(svrwfp, " <oneNumber\n");
414 fprintf(svrwfp, " name='%s'>\n", nvp->np[i].name);
415 fprintf(svrwfp, " %g\n", nvp->np[i].value);
416 fprintf(svrwfp, " </oneNumber>\n");
417 }
418 fprintf(svrwfp, "</newNumberVector>\n");
419
420 fflush(svrwfp);
421}
422
423void INDI::BaseClient::sendNewSwitch (ISwitchVectorProperty *svp, ISwitch *sp)
424{
425 fprintf(svrwfp, "<newSwitchVector\n");
426
427 fprintf(svrwfp, " device='%s'\n", svp->device);
428 fprintf(svrwfp, " name='%s'>\n", svp->name);
429 fprintf(svrwfp, " <oneSwitch\n");
430 fprintf(svrwfp, " name='%s'>\n", sp->name);
431 fprintf(svrwfp, " %s\n", (sp->s == ISS_ON) ? "On" : "Off");
432 fprintf(svrwfp, " </oneSwitch>\n");
433
434 fprintf(svrwfp, "</newSwitchVector>\n");
435
436 fflush(svrwfp);
437}
438
439void INDI::BaseClient::startBlob( const char *devName, const char *propName, const char *timestamp)
440{
441 fprintf(svrwfp, "<newBLOBVector\n");
442 fprintf(svrwfp, " device='%s'\n", devName);
443 fprintf(svrwfp, " name='%s'\n", propName);
444 fprintf(svrwfp, " timestamp='%s'>\n", timestamp);
445}
446
447void INDI::BaseClient::sendOneBlob( const char *blobName, unsigned int blobSize, const char *blobFormat, unsigned char * blobBuffer)
448{
449 fprintf(svrwfp, " <oneBLOB\n");
450 fprintf(svrwfp, " name='%s'\n", blobName);
451 fprintf(svrwfp, " size='%d'\n", blobSize);
452 fprintf(svrwfp, " format='%s'>\n", blobFormat);
453
454 for (unsigned i = 0; i < blobSize; i += 72)
455 fprintf(svrwfp, " %.72s\n", blobBuffer+i);
456
457 fprintf(svrwfp, " </oneBLOB>\n");
458}
459
460void INDI::BaseClient::finishBlob()
461{
462 fprintf(svrwfp, "</newBLOBVector>\n");
463 fflush(svrwfp);
464
465}
466
467void INDI::BaseClient::setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop)
468{
469 char blobOpenTag[64];
470
471 if (dev)
472 {
473 if (prop)
474 snprintf(blobOpenTag, 64, "<enableBLOB device='%s' name='%s'>", dev, prop);
475 else
476 snprintf(blobOpenTag, 64, "<enableBLOB device='%s'>", dev);
477 }
478 else
479 snprintf(blobOpenTag, 64, "<enableBLOB>", dev, prop);
480
481
482 switch (blobH)
483 {
484 case B_NEVER:
485 fprintf(svrwfp, "%sNever</enableBLOB>\n", blobOpenTag);
486 break;
487 case B_ALSO:
488 fprintf(svrwfp, "%sAlso</enableBLOB>\n", blobOpenTag);
489 break;
490 case B_ONLY:
491 fprintf(svrwfp, "%sOnly</enableBLOB>\n", blobOpenTag);
492 break;
493 }
494
495 fflush(svrwfp);
496}
497
498
499
Note: See TracBrowser for help on using the repository browser.