source: BAORadio/libindi/libindi/indidriver.c @ 695

Last change on this file since 695 was 642, checked in by frichard, 12 years ago

-Alignement des antennes
-Version 0.0.9 de libindi

File size: 47.1 KB
Line 
1#if 0
2    INDI
3    Copyright (C) 2003-2006 Elwood C. Downey
4
5                        Updated by Jasem Mutlaq (2003-2010)
6
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    This library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this library; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
21#endif
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <string.h>
28#include <errno.h>
29#include <time.h>
30#include <unistd.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33
34#include "lilxml.h"
35#include "base64.h"
36#include "eventloop.h"
37#include "indidevapi.h"
38#include "indicom.h"
39#include "indidriver.h"
40
41#define MAXRBUF 2048
42
43/* tell Client to delete the property with given name on given device, or
44 * entire device if !name
45 */
46void
47IDDelete (const char *dev, const char *name, const char *fmt, ...)
48{
49        xmlv1();
50        printf ("<delProperty\n  device='%s'\n", dev);
51        if (name)
52            printf (" name='%s'\n", name);
53        printf ("  timestamp='%s'\n", timestamp());
54        if (fmt) {
55            va_list ap;
56            va_start (ap, fmt);
57            printf ("  message='");
58            vprintf (fmt, ap);
59            printf ("'\n");
60            va_end (ap);
61        }
62        printf ("/>\n");
63        fflush (stdout);
64}
65
66/* tell indiserver we want to snoop on the given device/property.
67 * name ignored if NULL or empty.
68 */
69void
70IDSnoopDevice (const char *snooped_device_name, const char *snooped_property_name)
71{
72        xmlv1();
73        if (snooped_property_name && snooped_property_name[0])
74            printf ("<getProperties device='%s' name='%s'/>\n",
75                                    snooped_device_name, snooped_property_name);
76        else
77            printf ("<getProperties device='%s'/>\n", snooped_device_name);
78        fflush (stdout);
79}
80
81/* tell indiserver whether we want BLOBs from the given snooped device.
82 * silently ignored if given device is not already registered for snooping.
83 */
84void 
85IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh)
86{
87        const char *how;
88
89        switch (bh) {
90        case B_NEVER: how = "Never"; break;
91        case B_ALSO:  how = "Also";  break;
92        case B_ONLY:  how = "Only";  break;
93        default: return;
94        }
95
96        xmlv1();
97        printf ("<enableBLOB device='%s'>%s</enableBLOB>\n",
98                                                snooped_device, how);
99        fflush (stdout);
100}
101
102/* "INDI" wrappers to the more generic eventloop facility. */
103
104int
105IEAddCallback (int readfiledes, IE_CBF *fp, void *p)
106{
107        return (addCallback (readfiledes, (CBF*)fp, p));
108}
109
110void
111IERmCallback (int callbackid)
112{
113        rmCallback (callbackid);
114}
115
116int
117IEAddTimer (int millisecs, IE_TCF *fp, void *p)
118{
119        return (addTimer (millisecs, (TCF*)fp, p));
120}
121
122void
123IERmTimer (int timerid)
124{
125        rmTimer (timerid);
126}
127
128int
129IEAddWorkProc (IE_WPF *fp, void *p)
130{
131        return (addWorkProc ((WPF*)fp, p));
132}
133
134void
135IERmWorkProc (int workprocid)
136{
137        rmWorkProc (workprocid);
138}
139
140
141int
142IEDeferLoop (int maxms, int *flagp)
143{
144        return (deferLoop (maxms, flagp));
145}
146
147int
148IEDeferLoop0 (int maxms, int *flagp)
149{
150        return (deferLoop0 (maxms, flagp));
151}
152
153/* Update property switches in accord with states and names. */
154int 
155IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
156{
157 int i=0;
158 ISwitch *sp;
159 char sn[MAXINDINAME];
160
161 /* store On switch name */
162 if (svp->r == ISR_1OFMANY)
163 {
164        sp = IUFindOnSwitch(svp);
165        if (sp) strncpy(sn, sp->name, MAXINDINAME);
166 
167        IUResetSwitch(svp);
168 }
169 
170 for (i = 0; i < n ; i++)
171 {
172   sp = IUFindSwitch(svp, names[i]);
173         
174   if (!sp)
175   {
176              svp->s = IPS_IDLE;
177              IDSetSwitch(svp, "Error: %s is not a member of %s property.", names[i], svp->name);
178              return -1;
179   }
180         
181   sp->s = states[i]; 
182 }
183 
184 /* Consistency checks for ISR_1OFMANY after update. */
185 if (svp->r == ISR_1OFMANY)
186 {
187        int t_count=0;
188        for (i=0; i < svp->nsp; i++)
189        {
190                if (svp->sp[i].s == ISS_ON)
191                        t_count++;
192        }
193        if (t_count != 1)
194        {
195                IUResetSwitch(svp);
196                sp = IUFindSwitch(svp, sn);
197                if (sp) sp->s = ISS_ON;
198                svp->s = IPS_IDLE;
199                IDSetSwitch(svp, "Error: invalid state switch for property %s. %s.", svp->name, t_count == 0 ? "No switch is on" : "Too many switches are on");
200                return -1;
201        }
202 }
203               
204 return 0;
205
206}
207
208/* Update property numbers in accord with values and names */
209int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
210{
211  int i=0;
212 
213  INumber *np;
214 
215  for (i = 0; i < n; i++)
216  {
217    np = IUFindNumber(nvp, names[i]);
218    if (!np)
219    {
220        nvp->s = IPS_IDLE;
221        IDSetNumber(nvp, "Error: %s is not a member of %s property.", names[i], nvp->name);
222        return -1;
223    }
224   
225    if (values[i] < np->min || values[i] > np->max)
226    {
227       nvp->s = IPS_IDLE;
228       IDSetNumber(nvp, "Error: Invalid range. Valid range is from %g to %g", np->min, np->max);
229       return -1;
230    }
231     
232  }
233
234  /* First loop checks for error, second loop set all values atomically*/
235  for (i=0; i < n; i++)
236  {
237    np = IUFindNumber(nvp, names[i]);
238    np->value = values[i]; 
239  }
240
241  return 0;
242
243}
244
245/* Update property text in accord with texts and names */
246int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n)
247{
248  int i=0;
249 
250  IText *tp;
251 
252  for (i = 0; i < n; i++)
253  {
254    tp = IUFindText(tvp, names[i]);
255    if (!tp)
256    {
257        tvp->s = IPS_IDLE;
258        IDSetText(tvp, "Error: %s is not a member of %s property.", names[i], tvp->name);
259        return -1;
260    }
261  }
262
263  /* First loop checks for error, second loop set all values atomically*/
264  for (i=0; i < n; i++)
265  {
266    tp = IUFindText(tvp, names[i]);
267    IUSaveText(tp, texts[i]);
268  }
269
270  return 0;
271
272}
273
274void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s)
275{
276  strncpy(sp->name, name, MAXINDINAME);
277  strncpy(sp->label, label, MAXINDILABEL);
278  sp->s = s;
279  sp->svp = NULL;
280  sp->aux = NULL;
281}
282
283void IUFillLight(ILight *lp, const char *name, const char * label, IPState s)
284{
285  strncpy(lp->name, name, MAXINDINAME);
286  strncpy(lp->label, label, MAXINDILABEL);
287  lp->s = s;
288  lp->lvp = NULL;
289  lp->aux = NULL;
290}
291
292
293void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value)
294{
295
296  strncpy(np->name, name, MAXINDINAME);
297  strncpy(np->label, label, MAXINDILABEL);
298  strncpy(np->format, format, MAXINDIFORMAT);
299 
300  np->min       = min;
301  np->max       = max;
302  np->step      = step;
303  np->value     = value;
304  np->nvp       = NULL;
305  np->aux0      = NULL;
306  np->aux1      = NULL;
307}
308
309void IUFillText(IText *tp, const char *name, const char * label, const char *initialText)
310{
311
312  strncpy(tp->name, name, MAXINDINAME);
313  strncpy(tp->label, label, MAXINDILABEL);
314  tp->text = NULL;
315  tp->tvp  = NULL;
316  tp->aux0 = NULL;
317  tp->aux1 = NULL;
318
319  IUSaveText(tp, initialText);
320
321}
322
323void IUFillBLOB(IBLOB *bp, const char *name, const char * label, const char *format)
324{
325    memset(bp, 0, sizeof(IBLOB));
326    strncpy(bp->name, name, MAXINDINAME);
327    strncpy(bp->label, label, MAXINDILABEL);
328    strncpy(bp->format, label, MAXINDIBLOBFMT);
329    bp->blob     = 0;
330    bp->bloblen  = 0;
331    bp->size     = 0;
332    bp->bvp      = 0;
333    bp->aux0     = 0;
334    bp->aux1     = 0;
335    bp->aux2     = 0;
336}
337
338void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char * dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
339{
340  strncpy(svp->device, dev, MAXINDIDEVICE);
341  strncpy(svp->name, name, MAXINDINAME);
342  strncpy(svp->label, label, MAXINDILABEL);
343  strncpy(svp->group, group, MAXINDIGROUP);
344 
345  svp->p        = p;
346  svp->r        = r;
347  svp->timeout  = timeout;
348  svp->s        = s;
349  svp->sp       = sp;
350  svp->nsp      = nsp;
351}
352
353void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s)
354{
355    strncpy(lvp->device, dev, MAXINDIDEVICE);
356    strncpy(lvp->name, name, MAXINDINAME);
357    strncpy(lvp->label, label, MAXINDILABEL);
358    strncpy(lvp->group, group, MAXINDIGROUP);
359    strcpy(lvp->timestamp, "");
360 
361  lvp->s        = s;
362  lvp->lp       = lp;
363  lvp->nlp      = nlp;
364}
365 
366void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s)
367{
368 
369 strncpy(nvp->device, dev, MAXINDIDEVICE);
370 strncpy(nvp->name, name, MAXINDINAME);
371 strncpy(nvp->label, label, MAXINDILABEL);
372 strncpy(nvp->group, group, MAXINDIGROUP);
373 strcpy(nvp->timestamp, "");
374 
375  nvp->p        = p;
376  nvp->timeout  = timeout;
377  nvp->s        = s;
378  nvp->np       = np;
379  nvp->nnp      = nnp;
380 
381}
382
383void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s)
384{
385    strncpy(tvp->device, dev, MAXINDIDEVICE);
386    strncpy(tvp->name, name, MAXINDINAME);
387    strncpy(tvp->label, label, MAXINDILABEL);
388    strncpy(tvp->group, group, MAXINDIGROUP);
389    strcpy(tvp->timestamp, "");
390 
391  tvp->p        = p;
392  tvp->timeout  = timeout;
393  tvp->s        = s;
394  tvp->tp       = tp;
395  tvp->ntp      = ntp;
396
397}
398
399void IUFillBLOBVector(IBLOBVectorProperty *bvp, IBLOB *bp, int nbp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s)
400{
401    memset(bvp, 0, sizeof(IBLOBVectorProperty));
402    strncpy(bvp->device, dev, MAXINDIDEVICE);
403    strncpy(bvp->name, name, MAXINDINAME);
404    strncpy(bvp->label, label, MAXINDILABEL);
405    strncpy(bvp->group, group, MAXINDIGROUP);
406    strcpy(bvp->timestamp, "");
407
408    bvp->p      = p;
409    bvp->timeout        = timeout;
410    bvp->s      = s;
411    bvp->bp     = bp;
412    bvp->nbp    = nbp;
413}
414
415/*****************************************************************************
416 * convenience functions for use in your implementation of ISSnoopDevice().
417 */
418
419/* crack the snooped driver setNumberVector or defNumberVector message into
420 * the given INumberVectorProperty.
421 * return 0 if type, device and name match and all members are present, else
422 * return -1
423 */
424int
425IUSnoopNumber (XMLEle *root, INumberVectorProperty *nvp)
426{
427        char *dev, *name;
428        XMLEle *ep;
429        int i;
430
431        /* check and crack type, device, name and state */
432        if (strcmp (tagXMLEle(root)+3, "NumberVector") ||
433                                        crackDN (root, &dev, &name, NULL) < 0)
434            return (-1);
435        if (strcmp (dev, nvp->device) || strcmp (name, nvp->name))
436            return (-1);        /* not this property */
437        (void) crackIPState (findXMLAttValu (root,"state"), &nvp->s);
438
439        /* match each INumber with a oneNumber */
440        for (i = 0; i < nvp->nnp; i++) {
441            for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
442                if (!strcmp (tagXMLEle(ep), "oneNumber") &&
443                        !strcmp (nvp->np[i].name, findXMLAttValu(ep, "name"))) {
444                    if (f_scansexa (pcdataXMLEle(ep), &nvp->np[i].value) < 0)
445                        return (-1);    /* bad number format */
446                    break;
447                }
448            }
449            if (!ep)
450                return (-1);    /* element not found */
451        }
452
453        /* ok */
454        return (0);
455}
456
457/* crack the snooped driver setTextVector or defTextVector message into
458 * the given ITextVectorProperty.
459 * return 0 if type, device and name match and all members are present, else
460 * return -1
461 */
462int
463IUSnoopText (XMLEle *root, ITextVectorProperty *tvp)
464{
465        char *dev, *name;
466        XMLEle *ep;
467        int i;
468
469        /* check and crack type, device, name and state */
470        if (strcmp (tagXMLEle(root)+3, "TextVector") ||
471                                        crackDN (root, &dev, &name, NULL) < 0)
472            return (-1);
473        if (strcmp (dev, tvp->device) || strcmp (name, tvp->name))
474            return (-1);        /* not this property */
475        (void) crackIPState (findXMLAttValu (root,"state"), &tvp->s);
476
477        /* match each IText with a oneText */
478        for (i = 0; i < tvp->ntp; i++) {
479            for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
480                if (!strcmp (tagXMLEle(ep), "oneText") &&
481                        !strcmp (tvp->tp[i].name, findXMLAttValu(ep, "name"))) {
482                    IUSaveText (&tvp->tp[i], pcdataXMLEle(ep));
483                    break;
484                }
485            }
486            if (!ep)
487                return (-1);    /* element not found */
488        }
489
490        /* ok */
491        return (0);
492}
493
494/* crack the snooped driver setLightVector or defLightVector message into
495 * the given ILightVectorProperty. it is not necessary that all ILight names
496 * be found.
497 * return 0 if type, device and name match, else return -1.
498 */
499int
500IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp)
501{
502        char *dev, *name;
503        XMLEle *ep;
504        int i;
505
506        /* check and crack type, device, name and state */
507        if (strcmp (tagXMLEle(root)+3, "LightVector") ||
508                                        crackDN (root, &dev, &name, NULL) < 0)
509            return (-1);
510        if (strcmp (dev, lvp->device) || strcmp (name, lvp->name))
511            return (-1);        /* not this property */
512
513        (void) crackIPState (findXMLAttValu (root,"state"), &lvp->s);
514
515        /* match each oneLight with one ILight */
516        for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
517            if (!strcmp (tagXMLEle(ep), "oneLight")) {
518                const char *name = findXMLAttValu (ep, "name");
519                for (i = 0; i < lvp->nlp; i++) {
520                    if (!strcmp (lvp->lp[i].name, name)) {
521                        if (crackIPState(pcdataXMLEle(ep), &lvp->lp[i].s) < 0) {
522                            return (-1);        /* unrecognized state */
523                        }
524                        break;
525                    }
526                }
527            }
528        }
529
530        /* ok */
531        return (0);
532}
533
534/* crack the snooped driver setSwitchVector or defSwitchVector message into the
535 * given ISwitchVectorProperty. it is not necessary that all ISwitch names be
536 * found.
537 * return 0 if type, device and name match, else return -1.
538 */
539int
540IUSnoopSwitch (XMLEle *root, ISwitchVectorProperty *svp)
541{
542        char *dev, *name;
543        XMLEle *ep;
544        int i;
545
546        /* check and crack type, device, name and state */
547        if (strcmp (tagXMLEle(root)+3, "SwitchVector") ||
548                                        crackDN (root, &dev, &name, NULL) < 0)
549            return (-1);
550        if (strcmp (dev, svp->device) || strcmp (name, svp->name))
551            return (-1);        /* not this property */
552        (void) crackIPState (findXMLAttValu (root,"state"), &svp->s);
553
554        /* match each oneSwitch with one ISwitch */
555        for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
556            if (!strcmp (tagXMLEle(ep), "oneSwitch")) {
557                const char *name = findXMLAttValu (ep, "name");
558                for (i = 0; i < svp->nsp; i++) {
559                    if (!strcmp (svp->sp[i].name, name)) {
560                        if (crackISState(pcdataXMLEle(ep), &svp->sp[i].s) < 0) {
561                            return (-1);        /* unrecognized state */
562                        }
563                        break;
564                    }
565                }
566            }
567        }
568
569        /* ok */
570        return (0);
571}
572
573/* crack the snooped driver setBLOBVector message into the given
574 * IBLOBVectorProperty. it is not necessary that all IBLOB names be found.
575 * return 0 if type, device and name match, else return -1.
576 * N.B. we assume any existing blob in bvp has been malloced, which we free
577 *   and replace with a newly malloced blob if found.
578 */
579int
580IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp)
581{
582        char *dev, *name;
583        XMLEle *ep;
584        int i;
585
586        /* check and crack type, device, name and state */
587        if (strcmp (tagXMLEle(root), "setBLOBVector") ||
588                                        crackDN (root, &dev, &name, NULL) < 0)
589            return (-1);
590        if (strcmp (dev, bvp->device) || strcmp (name, bvp->name))
591            return (-1);        /* not this property */
592        (void) crackIPState (findXMLAttValu (root,"state"), &bvp->s);
593
594        /* match each oneBLOB with one IBLOB */
595        for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
596            if (!strcmp (tagXMLEle(ep), "oneBLOB")) {
597                const char *name = findXMLAttValu (ep, "name");
598                for (i = 0; i < bvp->nbp; i++) {
599                    IBLOB *bp = &bvp->bp[i];
600                    if (!strcmp (bp->name, name)) {
601                        strcpy (bp->format, findXMLAttValu (ep,"format"));
602                        bp->size = atof (findXMLAttValu (ep,"size"));
603                        bp->bloblen = pcdatalenXMLEle(ep)+1;
604                        if (bp->blob)
605                            free (bp->blob);
606                        bp->blob = strcpy(malloc(bp->bloblen),pcdataXMLEle(ep));
607                        break;
608                    }
609                }
610            }
611        }
612
613        /* ok */
614        return (0);
615}
616
617/* callback when INDI client message arrives on stdin.
618 * collect and dispatch when see outter element closure.
619 * exit if OS trouble or see incompatable INDI version.
620 * arg is not used.
621 */
622void
623clientMsgCB (int fd, void *arg)
624{
625        char buf[1024], msg[1024], *bp;
626        int nr;
627        arg=arg;
628
629        /* one read */
630        nr = read (fd, buf, sizeof(buf));
631        if (nr < 0) {
632            fprintf (stderr, "%s: %s\n", me, strerror(errno));
633            exit(1);
634        }
635        if (nr == 0) {
636            fprintf (stderr, "%s: EOF\n", me);
637            exit(1);
638        }
639
640        /* crack and dispatch when complete */
641        for (bp = buf; nr-- > 0; bp++) {
642            XMLEle *root = readXMLEle (clixml, *bp, msg);
643            if (root) {
644                if (dispatch (root, msg) < 0)
645                    fprintf (stderr, "%s dispatch error: %s\n", me, msg);
646                delXMLEle (root);
647            } else if (msg[0])
648                fprintf (stderr, "%s XML error: %s\n", me, msg);
649        }
650
651}
652
653/* crack the given INDI XML element and call driver's IS* entry points as they
654 *   are recognized.
655 * return 0 if ok else -1 with reason in msg[].
656 * N.B. exit if getProperties does not proclaim a compatible version.
657 */
658int
659dispatch (XMLEle *root, char msg[])
660{
661        char *rtag = tagXMLEle(root);
662        XMLEle *ep;
663        int n,i=0;
664
665        if (verbose)
666            prXMLEle (stderr, root, 0);
667
668        /* check tag in surmised decreasing order of likelyhood */
669
670        if (!strcmp (rtag, "newNumberVector")) {
671            static double *doubles;
672            static char **names;
673            static int maxn;
674            char *dev, *name;
675
676            /* pull out device and name */
677            if (crackDN (root, &dev, &name, msg) < 0)
678                return (-1);
679
680            /* seed for reallocs */
681            if (!doubles) {
682                doubles = (double *) malloc (1);
683                names = (char **) malloc (1);
684            }
685
686            /* pull out each name/value pair */
687            for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
688                if (strcmp (tagXMLEle(ep), "oneNumber") == 0) {
689                    XMLAtt *na = findXMLAtt (ep, "name");
690                    if (na) {
691                        if (n >= maxn) {
692                            /* grow for this and another */
693                            int newsz = (maxn=n+1)*sizeof(double);
694                            doubles = (double *) realloc(doubles,newsz);
695                            newsz = maxn*sizeof(char *);
696                            names = (char **) realloc (names, newsz);
697                        }
698                        if (f_scansexa (pcdataXMLEle(ep), &doubles[n]) < 0)
699                            IDMessage (dev,"%s: Bad format %s", name,
700                                                            pcdataXMLEle(ep));
701                        else
702                            names[n++] = valuXMLAtt(na);
703                    }
704                }
705            }
706
707            /* insure property is not RO */
708            for (i=0; i < nroCheck; i++)
709            {
710              if (!strcmp(roCheck[i].propName, name))
711              {
712               if (roCheck[i].perm == IP_RO)
713                 return -1;
714              }
715            }
716
717            /* invoke driver if something to do, but not an error if not */
718            if (n > 0)
719                ISNewNumber (dev, name, doubles, names, n);
720            else
721                IDMessage(dev,"%s: newNumberVector with no valid members",name);
722            return (0);
723        }
724
725        if (!strcmp (rtag, "newSwitchVector")) {
726            static ISState *states;
727            static char **names;
728            static int maxn;
729            char *dev, *name;
730            XMLEle *ep;
731
732            /* pull out device and name */
733            if (crackDN (root, &dev, &name, msg) < 0)
734                return (-1);
735
736            /* seed for reallocs */
737            if (!states) {
738                states = (ISState *) malloc (1);
739                names = (char **) malloc (1);
740            }
741
742            /* pull out each name/state pair */
743            for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
744                if (strcmp (tagXMLEle(ep), "oneSwitch") == 0) {
745                    XMLAtt *na = findXMLAtt (ep, "name");
746                    if (na) {
747                        if (n >= maxn) {
748                            int newsz = (maxn=n+1)*sizeof(ISState);
749                            states = (ISState *) realloc(states, newsz);
750                            newsz = maxn*sizeof(char *);
751                            names = (char **) realloc (names, newsz);
752                        }
753                        if (strcmp (pcdataXMLEle(ep),"On") == 0) {
754                            states[n] = ISS_ON;
755                            names[n] = valuXMLAtt(na);
756                            n++;
757                        } else if (strcmp (pcdataXMLEle(ep),"Off") == 0) {
758                            states[n] = ISS_OFF;
759                            names[n] = valuXMLAtt(na);
760                            n++;
761                        } else
762                            IDMessage (dev, "%s: must be On or Off: %s", name,
763                                                            pcdataXMLEle(ep));
764                    }
765                }
766            }
767
768            /* insure property is not RO */
769            for (i=0; i < nroCheck; i++)
770            {
771              if (!strcmp(roCheck[i].propName, name))
772              {
773               if (roCheck[i].perm == IP_RO)
774                 return -1;
775              }
776            }
777
778            /* invoke driver if something to do, but not an error if not */
779            if (n > 0)
780                ISNewSwitch (dev, name, states, names, n);
781            else
782                IDMessage(dev,"%s: newSwitchVector with no valid members",name);
783            return (0);
784        }
785
786        if (!strcmp (rtag, "newTextVector")) {
787            static char **texts;
788            static char **names;
789            static int maxn;
790            char *dev, *name;
791
792            /* pull out device and name */
793            if (crackDN (root, &dev, &name, msg) < 0)
794                return (-1);
795
796            /* seed for reallocs */
797            if (!texts) {
798                texts = (char **) malloc (1);
799                names = (char **) malloc (1);
800            }
801
802            /* pull out each name/text pair */
803            for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
804                if (strcmp (tagXMLEle(ep), "oneText") == 0) {
805                    XMLAtt *na = findXMLAtt (ep, "name");
806                    if (na) {
807                        if (n >= maxn) {
808                            int newsz = (maxn=n+1)*sizeof(char *);
809                            texts = (char **) realloc (texts, newsz);
810                            names = (char **) realloc (names, newsz);
811                        }
812                        texts[n] = pcdataXMLEle(ep);
813                        names[n] = valuXMLAtt(na);
814                        n++;
815                    }
816                }
817            }
818
819            /* insure property is not RO */
820            for (i=0; i < nroCheck; i++)
821            {
822              if (!strcmp(roCheck[i].propName, name))
823              {
824               if (roCheck[i].perm == IP_RO)
825                 return -1;
826              }
827            }
828
829            /* invoke driver if something to do, but not an error if not */
830            if (n > 0)
831                ISNewText (dev, name, texts, names, n);
832            else
833                IDMessage (dev, "%s: set with no valid members", name);
834            return (0);
835        }
836
837        if (!strcmp (rtag, "newBLOBVector")) {
838            static char **blobs;
839            static char **names;
840            static char **formats;
841            static int *blobsizes;
842            static int *sizes;
843            static int maxn;
844            char *dev, *name;
845            int i;
846
847            /* pull out device and name */
848            if (crackDN (root, &dev, &name, msg) < 0)
849                return (-1);
850
851            /* seed for reallocs */
852            if (!blobs) {
853                blobs = (char **) malloc (1);
854                names = (char **) malloc (1);
855                formats = (char **) malloc (1);
856                blobsizes = (int *) malloc (1);
857                sizes = (int *) malloc (1);
858            }
859
860            /* pull out each name/BLOB pair, decode */
861            for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
862                if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) {
863                    XMLAtt *na = findXMLAtt (ep, "name");
864                    XMLAtt *fa = findXMLAtt (ep, "format");
865                    XMLAtt *sa = findXMLAtt (ep, "size");
866                    if (na && fa && sa) {
867                        if (n >= maxn) {
868                            int newsz = (maxn=n+1)*sizeof(char *);
869                            blobs = (char **) realloc (blobs, newsz);
870                            names = (char **) realloc (names, newsz);
871                            formats = (char **) realloc(formats,newsz);
872                            newsz = maxn*sizeof(int);
873                            sizes = (int *) realloc(sizes,newsz);
874                            blobsizes = (int *) realloc(blobsizes,newsz);
875                        }
876                        blobs[n] = malloc (3*pcdatalenXMLEle(ep)/4);
877                        blobsizes[n] = from64tobits(blobs[n], pcdataXMLEle(ep));
878                        names[n] = valuXMLAtt(na);
879                        formats[n] = valuXMLAtt(fa);
880                        sizes[n] = atoi(valuXMLAtt(sa));
881                        n++;
882                    }
883                }
884            }
885
886            /* invoke driver if something to do, but not an error if not */
887            if (n > 0) {
888                ISNewBLOB (dev, name, sizes, blobsizes, blobs, formats,names,n);
889                for (i = 0; i < n; i++)
890                    free (blobs[i]);
891            } else
892                IDMessage (dev, "%s: newBLOBVector with no valid members",name);
893            return (0);
894        }
895
896        if (!strcmp (rtag, "getProperties")) {
897            XMLAtt *ap;
898            double v;
899
900            /* check version */
901            ap = findXMLAtt (root, "version");
902            if (!ap) {
903                fprintf (stderr, "%s: getProperties missing version\n", me);
904                exit(1);
905            }
906            v = atof (valuXMLAtt(ap));
907            if (v > INDIV) {
908                fprintf (stderr, "%s: client version %g > %g\n", me, v, INDIV);
909                exit(1);
910            }
911
912            /* ok */
913            ap = findXMLAtt (root, "device");
914            ISGetProperties (ap ? valuXMLAtt(ap) : NULL);
915            return (0);
916        }
917
918        /* other commands might be from a snooped device.
919         * we don't know here which devices are being snooped so we send
920         * all remaining valid messages
921         */
922        if (        !strcmp (rtag, "setNumberVector") ||
923                    !strcmp (rtag, "setTextVector") ||
924                    !strcmp (rtag, "setLightVector") ||
925                    !strcmp (rtag, "setSwitchVector") ||
926                    !strcmp (rtag, "setBLOBVector") ||
927                    !strcmp (rtag, "defNumberVector") ||
928                    !strcmp (rtag, "defTextVector") ||
929                    !strcmp (rtag, "defLightVector") ||
930                    !strcmp (rtag, "defSwitchVector") ||
931                    !strcmp (rtag, "defBLOBVector") ||
932                    !strcmp (rtag, "message") ||
933                    !strcmp (rtag, "delProperty")) {
934            ISSnoopDevice (root);
935            return (0);
936        }
937
938        sprintf (msg, "Unknown command: %s", rtag);
939        return(1);
940}
941
942int IUReadConfig(const char *filename, const char *dev, char errmsg[])
943{
944    char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF];
945    char *rname, *rdev;
946    XMLEle *root = NULL, *fproot = NULL;
947    LilXML *lp = newLilXML();
948
949    FILE *fp = NULL;
950
951    if (filename)
952         strncpy(configFileName, filename, MAXRBUF);
953     else
954    {
955        if (getenv("INDICONFIG"))
956            strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
957        else
958           snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
959
960    }
961
962    fp = fopen(configFileName, "r");
963    if (fp == NULL)
964    {
965         snprintf(errmsg, MAXRBUF, "Unable to read config file. Error loading file %s: %s\n", filename, strerror(errno));
966         return -1;
967    }
968
969    fproot = readXMLFile(fp, lp, errmsg);
970
971    if (fproot == NULL)
972    {
973        snprintf(errmsg, MAXRBUF, "Unable to parse config XML: %s", errmsg);
974        return -1;
975    }
976
977    for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0))
978    {
979
980        /* pull out device and name */
981        if (crackDN (root, &rdev, &rname, errmsg) < 0)
982            return -1;
983
984        // It doesn't belong to our device??
985        if (strcmp(dev, rdev))
986            continue;
987
988        dispatch(root, errmsg);
989
990    }
991
992    fclose(fp);
993    delXMLEle(fproot);
994    delXMLEle(root);
995    delLilXML(lp);
996
997    return (0);
998
999}
1000
1001
1002void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
1003{
1004
1005    char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF];
1006
1007    if (source_config)
1008         strncpy(configFileName, source_config, MAXRBUF);
1009     else
1010    {
1011        if (getenv("INDICONFIG"))
1012           strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1013        else
1014           snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
1015
1016    }
1017
1018     if (dest_config)
1019         strncpy(configDefaultFileName, dest_config, MAXRBUF);
1020     else if (getenv("INDICONFIG"))
1021         snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
1022     else
1023        snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), dev);
1024
1025  // If the default doesn't exist, create it.
1026  if (access(configDefaultFileName, F_OK))
1027  {
1028    FILE *fpin = fopen(configFileName, "r");
1029      if(fpin != NULL)
1030      {
1031        FILE *fpout = fopen(configDefaultFileName, "w");
1032        if(fpout != NULL)
1033        {
1034          int ch = 0;
1035          while((ch = getc(fpin)) != EOF)
1036            putc(ch, fpout);
1037
1038          fclose(fpin);
1039          fclose(fpout);
1040       }
1041    }
1042  }
1043
1044}
1045
1046
1047
1048
1049/* send client a message for a specific device or at large if !dev */
1050void
1051IDMessage (const char *dev, const char *fmt, ...)
1052{
1053
1054        xmlv1();
1055        printf ("<message\n");
1056        if (dev)
1057            printf (" device='%s'\n", dev);
1058        printf ("  timestamp='%s'\n", timestamp());
1059        if (fmt) {
1060            va_list ap;
1061            va_start (ap, fmt);
1062            printf ("  message='");
1063            vprintf (fmt, ap);
1064            printf ("'\n");
1065            va_end (ap);
1066        }
1067        printf ("/>\n");
1068        fflush (stdout);
1069}
1070
1071FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[])
1072{
1073    char configFileName[MAXRBUF];
1074    char configDir[MAXRBUF];
1075    struct stat st;
1076    FILE *fp = NULL;
1077
1078    snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
1079
1080    if (filename)
1081         strncpy(configFileName, filename, MAXRBUF);
1082     else
1083    {
1084        if (getenv("INDICONFIG"))
1085            strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1086        else
1087           snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1088
1089    }
1090
1091     if(stat(configDir,&st) != 0)
1092     {
1093         if (mkdir(configDir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0)
1094         {
1095             snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s\n", configDir, strerror(errno));
1096             return NULL;
1097         }
1098     }
1099
1100     fp = fopen(configFileName, "w");
1101     if (fp == NULL)
1102     {
1103          snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s\n", configFileName, strerror(errno));
1104          return NULL;
1105     }
1106
1107     return fp;
1108}
1109
1110void IUSaveConfigTag(FILE *fp, int ctag)
1111{
1112    if (!fp)
1113        return;
1114
1115    /* Opening tag */
1116    if (ctag == 0)
1117        fprintf(fp, "<INDIDriver>\n");
1118    /* Closing tag */
1119    else
1120       fprintf(fp, "</INDIDriver>\n");
1121}
1122
1123void IUSaveConfigNumber (FILE *fp, const INumberVectorProperty *nvp)
1124{
1125    int i;
1126
1127    fprintf (fp, "<newNumberVector device='%s' name='%s'>\n", nvp->device, nvp->name);
1128
1129    for (i = 0; i < nvp->nnp; i++)
1130    {
1131        INumber *np = &nvp->np[i];
1132        fprintf (fp, "  <oneNumber name='%s'>\n", np->name);
1133        fprintf (fp, "      %.20g\n", np->value);
1134        fprintf (fp, "  </oneNumber>\n");
1135    }
1136
1137    fprintf (fp, "</newNumberVector>\n");
1138}
1139
1140void IUSaveConfigText (FILE *fp, const ITextVectorProperty *tvp)
1141{
1142    int i;
1143
1144    fprintf (fp, "<newTextVector device='%s' name='%s'>\n", tvp->device, tvp->name);
1145
1146    for (i = 0; i < tvp->ntp; i++)
1147    {
1148        IText *tp = &tvp->tp[i];
1149        fprintf (fp, "  <oneText name='%s'>\n", tp->name);
1150        fprintf (fp, "      %s\n", tp->text ? tp->text : "");
1151        fprintf (fp, "  </oneText>\n");
1152    }
1153
1154    fprintf (fp, "</newTextVector>\n");
1155
1156}
1157
1158void IUSaveConfigSwitch (FILE *fp, const ISwitchVectorProperty *svp)
1159{
1160    int i;
1161
1162    fprintf (fp, "<newSwitchVector device='%s' name='%s'>\n", svp->device, svp->name);
1163
1164    for (i = 0; i < svp->nsp; i++)
1165    {
1166        ISwitch *sp = &svp->sp[i];
1167        fprintf (fp, "  <oneSwitch name='%s'>\n", sp->name);
1168        fprintf (fp, "      %s\n", sstateStr(sp->s));
1169        fprintf (fp, "  </oneSwitch>\n");
1170    }
1171
1172    fprintf (fp, "</newSwitchVector>\n");
1173
1174}
1175
1176void IUSaveConfigBLOB (FILE *fp, const IBLOBVectorProperty *bvp)
1177{
1178    int i;
1179
1180    fprintf (fp, "<newBLOBVector device='%s' name='%s'>\n", bvp->device, bvp->name);
1181
1182    for (i = 0; i < bvp->nbp; i++)
1183    {
1184        IBLOB *bp = &bvp->bp[i];
1185        unsigned char *encblob;
1186        int j, l;
1187
1188        fprintf (fp, "  <oneBLOB\n");
1189        fprintf (fp, "    name='%s'\n", bp->name);
1190        fprintf (fp, "    size='%d'\n", bp->size);
1191        fprintf (fp, "    format='%s'>\n", bp->format);
1192
1193        encblob = malloc (4*bp->bloblen/3+4);
1194        l = to64frombits(encblob, bp->blob, bp->bloblen);
1195        for (j = 0; j < l; j += 72)
1196            fprintf (fp, "%.72s\n", encblob+j);
1197        free (encblob);
1198
1199        fprintf (fp, "  </oneBLOB>\n");
1200    }
1201
1202    fprintf (fp, "</newBLOBVector>\n");
1203
1204}
1205
1206/* tell client to create a text vector property */
1207void
1208IDDefText (const ITextVectorProperty *tvp, const char *fmt, ...)
1209{
1210        int i;
1211        ROSC *SC;
1212
1213        xmlv1();
1214        printf ("<defTextVector\n");
1215        printf ("  device='%s'\n", tvp->device);
1216        printf ("  name='%s'\n", tvp->name);
1217        printf ("  label='%s'\n", tvp->label);
1218        printf ("  group='%s'\n", tvp->group);
1219        printf ("  state='%s'\n", pstateStr(tvp->s));
1220        printf ("  perm='%s'\n", permStr(tvp->p));
1221        printf ("  timeout='%g'\n", tvp->timeout);
1222        printf ("  timestamp='%s'\n", timestamp());
1223        if (fmt) {
1224            va_list ap;
1225            va_start (ap, fmt);
1226            printf ("  message='");
1227            vprintf (fmt, ap);
1228            printf ("'\n");
1229            va_end (ap);
1230        }
1231        printf (">\n");
1232
1233        for (i = 0; i < tvp->ntp; i++) {
1234            IText *tp = &tvp->tp[i];
1235            printf ("  <defText\n");
1236            printf ("    name='%s'\n", tp->name);
1237            printf ("    label='%s'>\n", tp->label);
1238            printf ("      %s\n", tp->text ? tp->text : "");
1239            printf ("  </defText>\n");
1240        }
1241
1242        printf ("</defTextVector>\n");
1243
1244        if (!isPropDefined(tvp->name))
1245        {
1246                /* Add this property to insure proper sanity check */
1247                roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1248                                : (ROSC *) malloc  ( sizeof(ROSC));
1249                SC      = &roCheck[nroCheck++];
1250
1251                strcpy(SC->propName, tvp->name);
1252                SC->perm = tvp->p;
1253        }
1254
1255        fflush (stdout);
1256}
1257
1258/* tell client to create a new numeric vector property */
1259void
1260IDDefNumber (const INumberVectorProperty *n, const char *fmt, ...)
1261{
1262        int i;
1263        ROSC *SC;
1264
1265        xmlv1();
1266        printf ("<defNumberVector\n");
1267        printf ("  device='%s'\n", n->device);
1268        printf ("  name='%s'\n", n->name);
1269        printf ("  label='%s'\n", n->label);
1270        printf ("  group='%s'\n", n->group);
1271        printf ("  state='%s'\n", pstateStr(n->s));
1272        printf ("  perm='%s'\n", permStr(n->p));
1273        printf ("  timeout='%g'\n", n->timeout);
1274        printf ("  timestamp='%s'\n", timestamp());
1275
1276
1277        if (fmt) {
1278            va_list ap;
1279            va_start (ap, fmt);
1280            printf ("  message='");
1281            vprintf (fmt, ap);
1282            printf ("'\n");
1283            va_end (ap);
1284        }
1285        printf (">\n");
1286
1287
1288        for (i = 0; i < n->nnp; i++) {
1289
1290            INumber *np = &n->np[i];
1291
1292            printf ("  <defNumber\n");
1293            printf ("    name='%s'\n", np->name);
1294            printf ("    label='%s'\n", np->label);
1295            printf ("    format='%s'\n", np->format);
1296            printf ("    min='%.20g'\n", np->min);
1297            printf ("    max='%.20g'\n", np->max);
1298            printf ("    step='%.20g'>\n", np->step);
1299            printf ("      %.20g\n", np->value);
1300
1301            printf ("  </defNumber>\n");
1302        }
1303
1304        printf ("</defNumberVector>\n");
1305
1306        if (!isPropDefined(n->name))
1307        {
1308                /* Add this property to insure proper sanity check */
1309                roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1310                                : (ROSC *) malloc  ( sizeof(ROSC));
1311                SC      = &roCheck[nroCheck++];
1312
1313                strcpy(SC->propName, n->name);
1314                SC->perm = n->p;
1315
1316        }
1317
1318        fflush (stdout);
1319}
1320
1321/* tell client to create a new switch vector property */
1322void
1323IDDefSwitch (const ISwitchVectorProperty *s, const char *fmt, ...)
1324
1325{
1326        int i;
1327        ROSC *SC;
1328
1329        xmlv1();
1330        printf ("<defSwitchVector\n");
1331        printf ("  device='%s'\n", s->device);
1332        printf ("  name='%s'\n", s->name);
1333        printf ("  label='%s'\n", s->label);
1334        printf ("  group='%s'\n", s->group);
1335        printf ("  state='%s'\n", pstateStr(s->s));
1336        printf ("  perm='%s'\n", permStr(s->p));
1337        printf ("  rule='%s'\n", ruleStr (s->r));
1338        printf ("  timeout='%g'\n", s->timeout);
1339        printf ("  timestamp='%s'\n", timestamp());
1340        if (fmt) {
1341            va_list ap;
1342            va_start (ap, fmt);
1343            printf ("  message='");
1344            vprintf (fmt, ap);
1345            printf ("'\n");
1346            va_end (ap);
1347        }
1348        printf (">\n");
1349
1350        for (i = 0; i < s->nsp; i++) {
1351            ISwitch *sp = &s->sp[i];
1352            printf ("  <defSwitch\n");
1353            printf ("    name='%s'\n", sp->name);
1354            printf ("    label='%s'>\n", sp->label);
1355            printf ("      %s\n", sstateStr(sp->s));
1356            printf ("  </defSwitch>\n");
1357        }
1358
1359        printf ("</defSwitchVector>\n");
1360
1361        if (!isPropDefined(s->name))
1362        {
1363                /* Add this property to insure proper sanity check */
1364                roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1365                                : (ROSC *) malloc  ( sizeof(ROSC));
1366                SC      = &roCheck[nroCheck++];
1367
1368                strcpy(SC->propName, s->name);
1369                SC->perm = s->p;
1370        }
1371
1372        fflush (stdout);
1373}
1374
1375/* tell client to create a new lights vector property */
1376void
1377IDDefLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1378{
1379        int i;
1380
1381        xmlv1();
1382        printf ("<defLightVector\n");
1383        printf ("  device='%s'\n", lvp->device);
1384        printf ("  name='%s'\n", lvp->name);
1385        printf ("  label='%s'\n", lvp->label);
1386        printf ("  group='%s'\n", lvp->group);
1387        printf ("  state='%s'\n", pstateStr(lvp->s));
1388        printf ("  timestamp='%s'\n", timestamp());
1389        if (fmt) {
1390            va_list ap;
1391            va_start (ap, fmt);
1392            printf ("  message='");
1393            vprintf (fmt, ap);
1394            printf ("'\n");
1395            va_end (ap);
1396        }
1397        printf (">\n");
1398
1399        for (i = 0; i < lvp->nlp; i++) {
1400            ILight *lp = &lvp->lp[i];
1401            printf ("  <defLight\n");
1402            printf ("    name='%s'\n", lp->name);
1403            printf ("    label='%s'>\n", lp->label);
1404            printf ("      %s\n", pstateStr(lp->s));
1405            printf ("  </defLight>\n");
1406        }
1407
1408        printf ("</defLightVector>\n");
1409        fflush (stdout);
1410}
1411
1412/* tell client to create a new BLOB vector property */
1413void
1414IDDefBLOB (const IBLOBVectorProperty *b, const char *fmt, ...)
1415{
1416  int i;
1417  ROSC *SC;
1418
1419        xmlv1();
1420        printf ("<defBLOBVector\n");
1421        printf ("  device='%s'\n", b->device);
1422        printf ("  name='%s'\n", b->name);
1423        printf ("  label='%s'\n", b->label);
1424        printf ("  group='%s'\n", b->group);
1425        printf ("  state='%s'\n", pstateStr(b->s));
1426        printf ("  perm='%s'\n", permStr(b->p));
1427        printf ("  timeout='%g'\n", b->timeout);
1428        printf ("  timestamp='%s'\n", timestamp());
1429        if (fmt) {
1430            va_list ap;
1431            va_start (ap, fmt);
1432            printf ("  message='");
1433            vprintf (fmt, ap);
1434            printf ("'\n");
1435            va_end (ap);
1436        }
1437        printf (">\n");
1438
1439  for (i = 0; i < b->nbp; i++) {
1440    IBLOB *bp = &b->bp[i];
1441    printf ("  <defBLOB\n");
1442    printf ("    name='%s'\n", bp->name);
1443    printf ("    label='%s'\n", bp->label);
1444    printf ("  />\n");
1445  }
1446
1447        printf ("</defBLOBVector>\n");
1448
1449        if (!isPropDefined(b->name))
1450        {
1451                /* Add this property to insure proper sanity check */
1452                roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1453                                : (ROSC *) malloc  ( sizeof(ROSC));
1454                SC      = &roCheck[nroCheck++];
1455
1456                strcpy(SC->propName, b->name);
1457                SC->perm = b->p;
1458        }
1459
1460        fflush (stdout);
1461}
1462
1463/* tell client to update an existing text vector property */
1464void
1465IDSetText (const ITextVectorProperty *tvp, const char *fmt, ...)
1466{
1467        int i;
1468
1469        xmlv1();
1470        printf ("<setTextVector\n");
1471        printf ("  device='%s'\n", tvp->device);
1472        printf ("  name='%s'\n", tvp->name);
1473        printf ("  state='%s'\n", pstateStr(tvp->s));
1474        printf ("  timeout='%g'\n", tvp->timeout);
1475        printf ("  timestamp='%s'\n", timestamp());
1476        if (fmt) {
1477            va_list ap;
1478            va_start (ap, fmt);
1479            printf ("  message='");
1480            vprintf (fmt, ap);
1481            printf ("'\n");
1482            va_end (ap);
1483        }
1484        printf (">\n");
1485
1486        for (i = 0; i < tvp->ntp; i++) {
1487            IText *tp = &tvp->tp[i];
1488            printf ("  <oneText name='%s'>\n", tp->name);
1489            printf ("      %s\n", tp->text ? tp->text : "");
1490            printf ("  </oneText>\n");
1491        }
1492
1493        printf ("</setTextVector>\n");
1494        fflush (stdout);
1495}
1496
1497/* tell client to update an existing numeric vector property */
1498void
1499IDSetNumber (const INumberVectorProperty *nvp, const char *fmt, ...)
1500{
1501        int i;
1502
1503        xmlv1();
1504        printf ("<setNumberVector\n");
1505        printf ("  device='%s'\n", nvp->device);
1506        printf ("  name='%s'\n", nvp->name);
1507        printf ("  state='%s'\n", pstateStr(nvp->s));
1508        printf ("  timeout='%g'\n", nvp->timeout);
1509        printf ("  timestamp='%s'\n", timestamp());
1510        if (fmt) {
1511            va_list ap;
1512            va_start (ap, fmt);
1513            printf ("  message='");
1514            vprintf (fmt, ap);
1515            printf ("'\n");
1516            va_end (ap);
1517        }
1518        printf (">\n");
1519
1520        for (i = 0; i < nvp->nnp; i++) {
1521            INumber *np = &nvp->np[i];
1522            printf ("  <oneNumber name='%s'>\n", np->name);
1523            printf ("      %.20g\n", np->value);
1524            printf ("  </oneNumber>\n");
1525        }
1526
1527        printf ("</setNumberVector>\n");
1528        fflush (stdout);
1529}
1530
1531/* tell client to update an existing switch vector property */
1532void
1533IDSetSwitch (const ISwitchVectorProperty *svp, const char *fmt, ...)
1534{
1535        int i;
1536
1537        xmlv1();
1538        printf ("<setSwitchVector\n");
1539        printf ("  device='%s'\n", svp->device);
1540        printf ("  name='%s'\n", svp->name);
1541        printf ("  state='%s'\n", pstateStr(svp->s));
1542        printf ("  timeout='%g'\n", svp->timeout);
1543        printf ("  timestamp='%s'\n", timestamp());
1544        if (fmt) {
1545            va_list ap;
1546            va_start (ap, fmt);
1547            printf ("  message='");
1548            vprintf (fmt, ap);
1549            printf ("'\n");
1550            va_end (ap);
1551        }
1552        printf (">\n");
1553
1554        for (i = 0; i < svp->nsp; i++) {
1555            ISwitch *sp = &svp->sp[i];
1556            printf ("  <oneSwitch name='%s'>\n", sp->name);
1557            printf ("      %s\n", sstateStr(sp->s));
1558            printf ("  </oneSwitch>\n");
1559        }
1560
1561        printf ("</setSwitchVector>\n");
1562        fflush (stdout);
1563}
1564
1565/* tell client to update an existing lights vector property */
1566void
1567IDSetLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1568{
1569        int i;
1570
1571        xmlv1();
1572        printf ("<setLightVector\n");
1573        printf ("  device='%s'\n", lvp->device);
1574        printf ("  name='%s'\n", lvp->name);
1575        printf ("  state='%s'\n", pstateStr(lvp->s));
1576        printf ("  timestamp='%s'\n", timestamp());
1577        if (fmt) {
1578            va_list ap;
1579            va_start (ap, fmt);
1580            printf ("  message='");
1581            vprintf (fmt, ap);
1582            printf ("'\n");
1583            va_end (ap);
1584        }
1585        printf (">\n");
1586
1587        for (i = 0; i < lvp->nlp; i++) {
1588            ILight *lp = &lvp->lp[i];
1589            printf ("  <oneLight name='%s'>\n", lp->name);
1590            printf ("      %s\n", pstateStr(lp->s));
1591            printf ("  </oneLight>\n");
1592        }
1593
1594        printf ("</setLightVector>\n");
1595        fflush (stdout);
1596}
1597
1598/* tell client to update an existing BLOB vector property */
1599void
1600IDSetBLOB (const IBLOBVectorProperty *bvp, const char *fmt, ...)
1601{
1602        int i;
1603
1604        xmlv1();
1605        printf ("<setBLOBVector\n");
1606        printf ("  device='%s'\n", bvp->device);
1607        printf ("  name='%s'\n", bvp->name);
1608        printf ("  state='%s'\n", pstateStr(bvp->s));
1609        printf ("  timeout='%g'\n", bvp->timeout);
1610        printf ("  timestamp='%s'\n", timestamp());
1611        if (fmt) {
1612            va_list ap;
1613            va_start (ap, fmt);
1614            printf ("  message='");
1615            vprintf (fmt, ap);
1616            printf ("'\n");
1617            va_end (ap);
1618        }
1619        printf (">\n");
1620
1621        for (i = 0; i < bvp->nbp; i++) {
1622            IBLOB *bp = &bvp->bp[i];
1623            unsigned char *encblob;
1624            int j, l;
1625
1626            printf ("  <oneBLOB\n");
1627            printf ("    name='%s'\n", bp->name);
1628            printf ("    size='%d'\n", bp->size);
1629            printf ("    format='%s'>\n", bp->format);
1630
1631            encblob = malloc (4*bp->bloblen/3+4);
1632            l = to64frombits(encblob, bp->blob, bp->bloblen);
1633            for (j = 0; j < l; j += 72)
1634                printf ("%.72s\n", encblob+j);
1635            free (encblob);
1636
1637            printf ("  </oneBLOB>\n");
1638        }
1639
1640  printf ("</setBLOBVector>\n");
1641  fflush (stdout);
1642}
1643
1644/* tell client to update min/max elements of an existing number vector property */
1645void IUUpdateMinMax(const INumberVectorProperty *nvp)
1646{
1647  int i;
1648
1649  xmlv1();
1650  printf ("<setNumberVector\n");
1651  printf ("  device='%s'\n", nvp->device);
1652  printf ("  name='%s'\n", nvp->name);
1653  printf ("  state='%s'\n", pstateStr(nvp->s));
1654  printf ("  timeout='%g'\n", nvp->timeout);
1655  printf ("  timestamp='%s'\n", timestamp());
1656  printf (">\n");
1657
1658  for (i = 0; i < nvp->nnp; i++) {
1659    INumber *np = &nvp->np[i];
1660    printf ("  <oneNumber name='%s'\n", np->name);
1661    printf ("    min='%g'\n", np->min);
1662    printf ("    max='%g'\n", np->max);
1663    printf ("    step='%g'\n", np->step);
1664    printf(">\n");
1665    printf ("      %g\n", np->value);
1666    printf ("  </oneNumber>\n");
1667  }
1668
1669  printf ("</setNumberVector>\n");
1670  fflush (stdout);
1671}
1672
1673/* Return 1 is property is already cached, 0 otherwise */
1674int isPropDefined(const char *property_name)
1675{
1676  int i=0;
1677
1678  for (i=0; i < nroCheck; i++)
1679    if (!strcmp(property_name, roCheck[i].propName))
1680        return 1;
1681
1682  return 0;
1683
1684}
1685
1686
Note: See TracBrowser for help on using the repository browser.