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

Last change on this file since 614 was 502, checked in by frichard, 14 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.