source: BAORadio/libindi/v1.0.1/indidriver.c@ 674

Last change on this file since 674 was 501, checked in by frichard, 15 years ago

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

File size: 47.0 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 strncpy(bp->name, name, MAXINDINAME);
326 strncpy(bp->label, label, MAXINDILABEL);
327 strncpy(bp->format, label, MAXINDIBLOBFMT);
328 bp->blob = 0;
329 bp->bloblen = 0;
330 bp->size = 0;
331 bp->bvp = 0;
332 bp->aux0 = 0;
333 bp->aux1 = 0;
334 bp->aux2 = 0;
335}
336
337void 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)
338{
339 strncpy(svp->device, dev, MAXINDIDEVICE);
340 strncpy(svp->name, name, MAXINDINAME);
341 strncpy(svp->label, label, MAXINDILABEL);
342 strncpy(svp->group, group, MAXINDIGROUP);
343 strcpy(svp->timestamp, "");
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 strncpy(bvp->device, dev, MAXINDIDEVICE);
402 strncpy(bvp->name, name, MAXINDINAME);
403 strncpy(bvp->label, label, MAXINDILABEL);
404 strncpy(bvp->group, group, MAXINDIGROUP);
405 strcpy(bvp->timestamp, "");
406
407 bvp->p = p;
408 bvp->timeout = timeout;
409 bvp->s = s;
410 bvp->bp = bp;
411 bvp->nbp = nbp;
412
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.