source: BAORadio/libindi/v1/indidrivermain.c@ 655

Last change on this file since 655 was 490, checked in by campagne, 15 years ago

import libindi (JEC)

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