Instrument Neutral Distributed Interface INDI  0.9.9
indidriver.c
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 <locale.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <pthread.h>
35 
36 #include "lilxml.h"
37 #include "base64.h"
38 #include "eventloop.h"
39 #include "indidevapi.h"
40 #include "indicom.h"
41 #include "indidriver.h"
42 
43 pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
44 
45 #define MAXRBUF 2048
46 
47 /* output a string expanding special characters into xml/html escape sequences */
48 /* N.B. You must free the returned buffer after use! */
49 char * escapeXML(const char *s, unsigned int MAX_BUF_SIZE)
50 {
51  char *buf = malloc(sizeof(char)*MAX_BUF_SIZE);
52  char *out = buf;
53  unsigned int i=0;
54 
55  for (i=0; i <= strlen(s); i++)
56  {
57  switch (s[i])
58  {
59  case '&':
60  strncpy(out, "&amp;", 5);
61  out+=5;
62  break;
63  case '\'':
64  strncpy(out, "&apos;", 6);
65  out+=6;
66  break;
67  case '"':
68  strncpy(out, "&quot;", 6);
69  out+=6;
70  break;
71  case '<':
72  strncpy(out, "&lt;", 4);
73  out+=4;
74  break;
75  case '>':
76  strncpy(out, "&gt;", 4);
77  out+=4;
78  break;
79  default:
80  strncpy(out++, s+i, 1);
81  break;
82  }
83 
84  }
85 
86  return buf;
87 }
88 
89 /* tell Client to delete the property with given name on given device, or
90  * entire device if !name
91  */
92 void
93 IDDelete (const char *dev, const char *name, const char *fmt, ...)
94 {
95  pthread_mutex_lock(&stdout_mutex);
96 
97  xmlv1();
98  printf ("<delProperty\n device='%s'\n", dev);
99  if (name)
100  printf (" name='%s'\n", name);
101  printf (" timestamp='%s'\n", timestamp());
102  if (fmt) {
103  va_list ap;
104  va_start (ap, fmt);
105  printf (" message='");
106  vprintf (fmt, ap);
107  printf ("'\n");
108  va_end (ap);
109  }
110  printf ("/>\n");
111  fflush (stdout);
112 
113  pthread_mutex_unlock(&stdout_mutex);
114 }
115 
116 /* tell indiserver we want to snoop on the given device/property.
117  * name ignored if NULL or empty.
118  */
119 void
120 IDSnoopDevice (const char *snooped_device_name, const char *snooped_property_name)
121 {
122  pthread_mutex_lock(&stdout_mutex);
123  xmlv1();
124  if (snooped_property_name && snooped_property_name[0])
125  printf ("<getProperties device='%s' name='%s'/>\n",
126  snooped_device_name, snooped_property_name);
127  else
128  printf ("<getProperties device='%s'/>\n", snooped_device_name);
129  fflush (stdout);
130  pthread_mutex_unlock(&stdout_mutex);
131 }
132 
133 /* tell indiserver whether we want BLOBs from the given snooped device.
134  * silently ignored if given device is not already registered for snooping.
135  */
136 void
137 IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh)
138 {
139  const char *how;
140 
141  switch (bh) {
142  case B_NEVER: how = "Never"; break;
143  case B_ALSO: how = "Also"; break;
144  case B_ONLY: how = "Only"; break;
145  default: return;
146  }
147 
148  pthread_mutex_lock(&stdout_mutex);
149  xmlv1();
150  printf ("<enableBLOB device='%s'>%s</enableBLOB>\n",
151  snooped_device, how);
152  fflush (stdout);
153  pthread_mutex_unlock(&stdout_mutex);
154 }
155 
156 /* "INDI" wrappers to the more generic eventloop facility. */
157 
158 int
159 IEAddCallback (int readfiledes, IE_CBF *fp, void *p)
160 {
161  return (addCallback (readfiledes, (CBF*)fp, p));
162 }
163 
164 void
165 IERmCallback (int callbackid)
166 {
167  rmCallback (callbackid);
168 }
169 
170 int
171 IEAddTimer (int millisecs, IE_TCF *fp, void *p)
172 {
173  return (addTimer (millisecs, (TCF*)fp, p));
174 }
175 
176 void
177 IERmTimer (int timerid)
178 {
179  rmTimer (timerid);
180 }
181 
182 int
183 IEAddWorkProc (IE_WPF *fp, void *p)
184 {
185  return (addWorkProc ((WPF*)fp, p));
186 }
187 
188 void
189 IERmWorkProc (int workprocid)
190 {
191  rmWorkProc (workprocid);
192 }
193 
194 
195 int
196 IEDeferLoop (int maxms, int *flagp)
197 {
198  return (deferLoop (maxms, flagp));
199 }
200 
201 int
202 IEDeferLoop0 (int maxms, int *flagp)
203 {
204  return (deferLoop0 (maxms, flagp));
205 }
206 
207 /* Update property switches in accord with states and names. */
208 int
209 IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
210 {
211  int i=0;
212  ISwitch *sp;
213  char sn[MAXINDINAME];
214 
215  /* store On switch name */
216  if (svp->r == ISR_1OFMANY)
217  {
218  sp = IUFindOnSwitch(svp);
219  if (sp) strncpy(sn, sp->name, MAXINDINAME);
220 
221  IUResetSwitch(svp);
222  }
223 
224  for (i = 0; i < n ; i++)
225  {
226  sp = IUFindSwitch(svp, names[i]);
227 
228  if (!sp)
229  {
230  svp->s = IPS_IDLE;
231  IDSetSwitch(svp, "Error: %s is not a member of %s property.", names[i], svp->name);
232  return -1;
233  }
234 
235  sp->s = states[i];
236  }
237 
238  /* Consistency checks for ISR_1OFMANY after update. */
239  if (svp->r == ISR_1OFMANY)
240  {
241  int t_count=0;
242  for (i=0; i < svp->nsp; i++)
243  {
244  if (svp->sp[i].s == ISS_ON)
245  t_count++;
246  }
247  if (t_count != 1)
248  {
249  IUResetSwitch(svp);
250  sp = IUFindSwitch(svp, sn);
251  if (sp) sp->s = ISS_ON;
252  svp->s = IPS_IDLE;
253  IDSetSwitch(svp, "Error: invalid state switch for property %s. %s.", svp->name, t_count == 0 ? "No switch is on" : "Too many switches are on");
254  return -1;
255  }
256  }
257 
258  return 0;
259 
260 }
261 
262 /* Update property numbers in accord with values and names */
263 int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
264 {
265  int i=0;
266 
267  INumber *np;
268 
269  for (i = 0; i < n; i++)
270  {
271  np = IUFindNumber(nvp, names[i]);
272  if (!np)
273  {
274  nvp->s = IPS_IDLE;
275  IDSetNumber(nvp, "Error: %s is not a member of %s property.", names[i], nvp->name);
276  return -1;
277  }
278 
279  if (values[i] < np->min || values[i] > np->max)
280  {
281  nvp->s = IPS_ALERT;
282  IDSetNumber(nvp, "Error: Invalid range for %s. Valid range is from %g to %g. Requested value is %g", np->name, np->min, np->max, values[i]);
283  return -1;
284  }
285 
286  }
287 
288  /* First loop checks for error, second loop set all values atomically*/
289  for (i=0; i < n; i++)
290  {
291  np = IUFindNumber(nvp, names[i]);
292  np->value = values[i];
293  }
294 
295  return 0;
296 
297 }
298 
299 /* Update property text in accord with texts and names */
300 int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n)
301 {
302  int i=0;
303 
304  IText *tp;
305 
306  for (i = 0; i < n; i++)
307  {
308  tp = IUFindText(tvp, names[i]);
309  if (!tp)
310  {
311  tvp->s = IPS_IDLE;
312  IDSetText(tvp, "Error: %s is not a member of %s property.", names[i], tvp->name);
313  return -1;
314  }
315  }
316 
317  /* First loop checks for error, second loop set all values atomically*/
318  for (i=0; i < n; i++)
319  {
320  tp = IUFindText(tvp, names[i]);
321  IUSaveText(tp, texts[i]);
322  }
323 
324  return 0;
325 
326 }
327 
328 
329 /* Update property BLOB in accord with BLOBs and names */
330 int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
331 {
332  int i=0;
333 
334  IBLOB *bp;
335 
336  for (i = 0; i < n; i++)
337  {
338  bp = IUFindBLOB(bvp, names[i]);
339  if (!bp)
340  {
341  bvp->s = IPS_IDLE;
342  IDSetBLOB(bvp, "Error: %s is not a member of %s property.", names[i], bvp->name);
343  return -1;
344  }
345  }
346 
347  /* First loop checks for error, second loop set all values atomically*/
348  for (i=0; i < n; i++)
349  {
350  bp = IUFindBLOB(bvp, names[i]);
351  IUSaveBLOB(bp, sizes[i], blobsizes[i], blobs[i], formats[i]);
352  }
353 
354  return 0;
355 
356 }
357 
358 int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format)
359 {
360  bp->bloblen = blobsize;
361  bp->size = size;
362  bp->blob = blob;
363  strncpy(bp->format, format, MAXINDIFORMAT);
364  return 0;
365 }
366 
367 void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s)
368 {
369  char *escapedName = escapeXML(name, MAXINDINAME);
370  char *escapedLabel = escapeXML(label, MAXINDILABEL);
371 
372  strncpy(sp->name, escapedName, MAXINDINAME);
373  strncpy(sp->label, escapedLabel, MAXINDILABEL);
374  sp->s = s;
375  sp->svp = NULL;
376  sp->aux = NULL;
377 
378  free(escapedName);
379  free(escapedLabel);
380 }
381 
382 void IUFillLight(ILight *lp, const char *name, const char * label, IPState s)
383 {
384  char *escapedName = escapeXML(name, MAXINDINAME);
385  char *escapedLabel = escapeXML(label, MAXINDILABEL);
386 
387  strncpy(lp->name, escapedName, MAXINDINAME);
388  strncpy(lp->label, escapedLabel, MAXINDILABEL);
389  lp->s = s;
390  lp->lvp = NULL;
391  lp->aux = NULL;
392 
393  free(escapedName);
394  free(escapedLabel);
395 }
396 
397 
398 void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value)
399 {
400  char *escapedName = escapeXML(name, MAXINDINAME);
401  char *escapedLabel = escapeXML(label, MAXINDILABEL);
402 
403  strncpy(np->name, escapedName, MAXINDINAME);
404  strncpy(np->label, escapedLabel, MAXINDILABEL);
405  strncpy(np->format, format, MAXINDIFORMAT);
406 
407  np->min = min;
408  np->max = max;
409  np->step = step;
410  np->value = value;
411  np->nvp = NULL;
412  np->aux0 = NULL;
413  np->aux1 = NULL;
414 
415  free(escapedName);
416  free(escapedLabel);
417 }
418 
419 void IUFillText(IText *tp, const char *name, const char * label, const char *initialText)
420 {
421  char *escapedName = escapeXML(name, MAXINDINAME);
422  char *escapedLabel = escapeXML(label, MAXINDILABEL);
423 
424  strncpy(tp->name, escapedName, MAXINDINAME);
425  strncpy(tp->label, escapedLabel, MAXINDILABEL);
426  tp->text = NULL;
427  tp->tvp = NULL;
428  tp->aux0 = NULL;
429  tp->aux1 = NULL;
430 
431  if (initialText && strlen(initialText) > 0)
432  IUSaveText(tp, initialText);
433 
434  free(escapedName);
435  free(escapedLabel);
436 
437 }
438 
439 void IUFillBLOB(IBLOB *bp, const char *name, const char * label, const char *format)
440 {
441  char *escapedName = escapeXML(name, MAXINDINAME);
442  char *escapedLabel = escapeXML(label, MAXINDILABEL);
443 
444  memset(bp, 0, sizeof(IBLOB));
445  strncpy(bp->name, escapedName, MAXINDINAME);
446  strncpy(bp->label, escapedLabel, MAXINDILABEL);
447  strncpy(bp->format, format, MAXINDIBLOBFMT);
448  bp->blob = 0;
449  bp->bloblen = 0;
450  bp->size = 0;
451  bp->bvp = 0;
452  bp->aux0 = 0;
453  bp->aux1 = 0;
454  bp->aux2 = 0;
455 
456  free(escapedName);
457  free(escapedLabel);
458 }
459 
460 void 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)
461 {
462  char *escapedName = escapeXML(name, MAXINDINAME);
463  char *escapedLabel = escapeXML(label, MAXINDILABEL);
464 
465  strncpy(svp->device, dev, MAXINDIDEVICE);
466  strncpy(svp->name, escapedName, MAXINDINAME);
467  strncpy(svp->label, escapedLabel, MAXINDILABEL);
468  strncpy(svp->group, group, MAXINDIGROUP);
469 
470  svp->p = p;
471  svp->r = r;
472  svp->timeout = timeout;
473  svp->s = s;
474  svp->sp = sp;
475  svp->nsp = nsp;
476 
477  free(escapedName);
478  free(escapedLabel);
479 
480 }
481 
482 void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s)
483 {
484  char *escapedName = escapeXML(name, MAXINDINAME);
485  char *escapedLabel = escapeXML(label, MAXINDILABEL);
486 
487  strncpy(lvp->device, dev, MAXINDIDEVICE);
488  strncpy(lvp->name, escapedName, MAXINDINAME);
489  strncpy(lvp->label, escapedLabel, MAXINDILABEL);
490  strncpy(lvp->group, group, MAXINDIGROUP);
491  strcpy(lvp->timestamp, "");
492 
493  lvp->s = s;
494  lvp->lp = lp;
495  lvp->nlp = nlp;
496 
497  free(escapedName);
498  free(escapedLabel);
499 
500 }
501 
502 void 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)
503 {
504  char *escapedName = escapeXML(name, MAXINDINAME);
505  char *escapedLabel = escapeXML(label, MAXINDILABEL);
506 
507  strncpy(nvp->device, dev, MAXINDIDEVICE);
508  strncpy(nvp->name, escapedName, MAXINDINAME);
509  strncpy(nvp->label, escapedLabel, MAXINDILABEL);
510  strncpy(nvp->group, group, MAXINDIGROUP);
511  strcpy(nvp->timestamp, "");
512 
513  nvp->p = p;
514  nvp->timeout = timeout;
515  nvp->s = s;
516  nvp->np = np;
517  nvp->nnp = nnp;
518 
519  free(escapedName);
520  free(escapedLabel);
521 
522 
523 }
524 
525 void 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)
526 {
527  char *escapedName = escapeXML(name, MAXINDINAME);
528  char *escapedLabel = escapeXML(label, MAXINDILABEL);
529 
530  strncpy(tvp->device, dev, MAXINDIDEVICE);
531  strncpy(tvp->name, escapedName, MAXINDINAME);
532  strncpy(tvp->label, escapedLabel, MAXINDILABEL);
533  strncpy(tvp->group, group, MAXINDIGROUP);
534  strcpy(tvp->timestamp, "");
535 
536  tvp->p = p;
537  tvp->timeout = timeout;
538  tvp->s = s;
539  tvp->tp = tp;
540  tvp->ntp = ntp;
541 
542  free(escapedName);
543  free(escapedLabel);
544 }
545 
546 void 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)
547 {
548  char *escapedName = escapeXML(name, MAXINDINAME);
549  char *escapedLabel = escapeXML(label, MAXINDILABEL);
550 
551  memset(bvp, 0, sizeof(IBLOBVectorProperty));
552  strncpy(bvp->device, dev, MAXINDIDEVICE);
553  strncpy(bvp->name, escapedName, MAXINDINAME);
554  strncpy(bvp->label, escapedLabel, MAXINDILABEL);
555  strncpy(bvp->group, group, MAXINDIGROUP);
556  strcpy(bvp->timestamp, "");
557 
558  bvp->p = p;
559  bvp->timeout = timeout;
560  bvp->s = s;
561  bvp->bp = bp;
562  bvp->nbp = nbp;
563 
564  free(escapedName);
565  free(escapedLabel);
566 }
567 
568 /*****************************************************************************
569  * convenience functions for use in your implementation of ISSnoopDevice().
570  */
571 
572 /* crack the snooped driver setNumberVector or defNumberVector message into
573  * the given INumberVectorProperty.
574  * return 0 if type, device and name match and all members are present, else
575  * return -1
576  */
577 int
579 {
580  char *dev, *name;
581  XMLEle *ep;
582  int i;
583 
584  /* check and crack type, device, name and state */
585  if (strcmp (tagXMLEle(root)+3, "NumberVector") ||
586  crackDN (root, &dev, &name, NULL) < 0)
587  return (-1);
588  if (strcmp (dev, nvp->device) || strcmp (name, nvp->name))
589  return (-1); /* not this property */
590  (void) crackIPState (findXMLAttValu (root,"state"), &nvp->s);
591 
592  /* match each INumber with a oneNumber */
593  for (i = 0; i < nvp->nnp; i++) {
594  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
595  if (!strcmp (tagXMLEle(ep)+3, "Number") &&
596  !strcmp (nvp->np[i].name, findXMLAttValu(ep, "name"))) {
597  if (f_scansexa (pcdataXMLEle(ep), &nvp->np[i].value) < 0)
598  return (-1); /* bad number format */
599  break;
600  }
601  }
602  if (!ep)
603  return (-1); /* element not found */
604  }
605 
606  /* ok */
607  return (0);
608 }
609 
610 /* crack the snooped driver setTextVector or defTextVector message into
611  * the given ITextVectorProperty.
612  * return 0 if type, device and name match and all members are present, else
613  * return -1
614  */
615 int
616 IUSnoopText (XMLEle *root, ITextVectorProperty *tvp)
617 {
618  char *dev, *name;
619  XMLEle *ep;
620  int i;
621 
622  /* check and crack type, device, name and state */
623  if (strcmp (tagXMLEle(root)+3, "TextVector") ||
624  crackDN (root, &dev, &name, NULL) < 0)
625  return (-1);
626  if (strcmp (dev, tvp->device) || strcmp (name, tvp->name))
627  return (-1); /* not this property */
628  (void) crackIPState (findXMLAttValu (root,"state"), &tvp->s);
629 
630  /* match each IText with a oneText */
631  for (i = 0; i < tvp->ntp; i++) {
632  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
633  if (!strcmp (tagXMLEle(ep)+3, "Text") &&
634  !strcmp (tvp->tp[i].name, findXMLAttValu(ep, "name"))) {
635  IUSaveText (&tvp->tp[i], pcdataXMLEle(ep));
636  break;
637  }
638  }
639  if (!ep)
640  return (-1); /* element not found */
641  }
642 
643  /* ok */
644  return (0);
645 }
646 
647 /* crack the snooped driver setLightVector or defLightVector message into
648  * the given ILightVectorProperty. it is not necessary that all ILight names
649  * be found.
650  * return 0 if type, device and name match, else return -1.
651  */
652 int
653 IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp)
654 {
655  char *dev, *name;
656  XMLEle *ep;
657  int i;
658 
659  /* check and crack type, device, name and state */
660  if (strcmp (tagXMLEle(root)+3, "LightVector") ||
661  crackDN (root, &dev, &name, NULL) < 0)
662  return (-1);
663  if (strcmp (dev, lvp->device) || strcmp (name, lvp->name))
664  return (-1); /* not this property */
665 
666  (void) crackIPState (findXMLAttValu (root,"state"), &lvp->s);
667 
668  /* match each oneLight with one ILight */
669  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
670  if (!strcmp (tagXMLEle(ep)+3, "Light")) {
671  const char *name = findXMLAttValu (ep, "name");
672  for (i = 0; i < lvp->nlp; i++) {
673  if (!strcmp (lvp->lp[i].name, name)) {
674  if (crackIPState(pcdataXMLEle(ep), &lvp->lp[i].s) < 0) {
675  return (-1); /* unrecognized state */
676  }
677  break;
678  }
679  }
680  }
681  }
682 
683  /* ok */
684  return (0);
685 }
686 
687 /* crack the snooped driver setSwitchVector or defSwitchVector message into the
688  * given ISwitchVectorProperty. it is not necessary that all ISwitch names be
689  * found.
690  * return 0 if type, device and name match, else return -1.
691  */
692 int
694 {
695  char *dev, *name;
696  XMLEle *ep;
697  int i;
698 
699  /* check and crack type, device, name and state */
700  if (strcmp (tagXMLEle(root)+3, "SwitchVector") ||
701  crackDN (root, &dev, &name, NULL) < 0)
702  return (-1);
703  if (strcmp (dev, svp->device) || strcmp (name, svp->name))
704  return (-1); /* not this property */
705  (void) crackIPState (findXMLAttValu (root,"state"), &svp->s);
706 
707  /* match each oneSwitch with one ISwitch */
708  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
709  if (!strcmp (tagXMLEle(ep)+3, "Switch")) {
710  const char *name = findXMLAttValu (ep, "name");
711  for (i = 0; i < svp->nsp; i++) {
712  if (!strcmp (svp->sp[i].name, name)) {
713  if (crackISState(pcdataXMLEle(ep), &svp->sp[i].s) < 0) {
714  return (-1); /* unrecognized state */
715  }
716  break;
717  }
718  }
719  }
720  }
721 
722  /* ok */
723  return (0);
724 }
725 
726 /* crack the snooped driver setBLOBVector message into the given
727  * IBLOBVectorProperty. it is not necessary that all IBLOB names be found.
728  * return 0 if type, device and name match, else return -1.
729  * N.B. we assume any existing blob in bvp has been malloced, which we free
730  * and replace with a newly malloced blob if found.
731  */
732 int
733 IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp)
734 {
735  char *dev, *name;
736  XMLEle *ep;
737  int i;
738 
739  /* check and crack type, device, name and state */
740  if (strcmp (tagXMLEle(root), "setBLOBVector") ||
741  crackDN (root, &dev, &name, NULL) < 0)
742  return (-1);
743  if (strcmp (dev, bvp->device) || strcmp (name, bvp->name))
744  return (-1); /* not this property */
745  (void) crackIPState (findXMLAttValu (root,"state"), &bvp->s);
746 
747  /* match each oneBLOB with one IBLOB */
748  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
749  if (!strcmp (tagXMLEle(ep)+3, "BLOB")) {
750  const char *name = findXMLAttValu (ep, "name");
751  for (i = 0; i < bvp->nbp; i++) {
752  IBLOB *bp = &bvp->bp[i];
753  if (!strcmp (bp->name, name)) {
754  strcpy (bp->format, findXMLAttValu (ep,"format"));
755  bp->size = atof (findXMLAttValu (ep,"size"));
756  bp->bloblen = pcdatalenXMLEle(ep)+1;
757  if (bp->blob)
758  free (bp->blob);
759  bp->blob = strcpy(malloc(bp->bloblen),pcdataXMLEle(ep));
760  break;
761  }
762  }
763  }
764  }
765 
766  /* ok */
767  return (0);
768 }
769 
770 /* callback when INDI client message arrives on stdin.
771  * collect and dispatch when see outter element closure.
772  * exit if OS trouble or see incompatable INDI version.
773  * arg is not used.
774  */
775 void
776 clientMsgCB (int fd, void *arg)
777 {
778  char buf[1024], msg[1024], *bp;
779  int nr;
780  arg=arg;
781 
782  /* one read */
783  nr = read (fd, buf, sizeof(buf));
784  if (nr < 0) {
785  fprintf (stderr, "%s: %s\n", me, strerror(errno));
786  exit(1);
787  }
788  if (nr == 0) {
789  fprintf (stderr, "%s: EOF\n", me);
790  exit(1);
791  }
792 
793  /* crack and dispatch when complete */
794  for (bp = buf; nr-- > 0; bp++) {
795  XMLEle *root = readXMLEle (clixml, *bp, msg);
796  if (root) {
797  if (dispatch (root, msg) < 0)
798  fprintf (stderr, "%s dispatch error: %s\n", me, msg);
799  delXMLEle (root);
800  } else if (msg[0])
801  fprintf (stderr, "%s XML error: %s\n", me, msg);
802  }
803 
804 }
805 
806 /* crack the given INDI XML element and call driver's IS* entry points as they
807  * are recognized.
808  * return 0 if ok else -1 with reason in msg[].
809  * N.B. exit if getProperties does not proclaim a compatible version.
810  */
811 int
812 dispatch (XMLEle *root, char msg[])
813 {
814 
815 
816  char *rtag = tagXMLEle(root);
817  XMLEle *ep;
818  int n,i=0;
819 
820  if (verbose)
821  prXMLEle (stderr, root, 0);
822 
823  /* check tag in surmised decreasing order of likelyhood */
824 
825  if (!strcmp (rtag, "newNumberVector")) {
826  static double *doubles;
827  static char **names;
828  static int maxn;
829  char *dev, *name;
830 
831  /* pull out device and name */
832  if (crackDN (root, &dev, &name, msg) < 0)
833  return (-1);
834 
835  if (!isPropDefined(name))
836  return -1;
837 
838  /* ensure property is not RO */
839  for (i=0; i < nroCheck; i++)
840  {
841  if (!strcmp(roCheck[i].propName, name))
842  {
843  if (roCheck[i].perm == IP_RO)
844  return -1;
845  else
846  break;
847  }
848  }
849 
850  /* seed for reallocs */
851  if (!doubles) {
852  doubles = (double *) malloc (1);
853  names = (char **) malloc (1);
854  }
855 
856  /* pull out each name/value pair */
857  setlocale(LC_NUMERIC,"C");
858  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
859  if (strcmp (tagXMLEle(ep), "oneNumber") == 0) {
860  XMLAtt *na = findXMLAtt (ep, "name");
861  if (na) {
862  if (n >= maxn) {
863  /* grow for this and another */
864  int newsz = (maxn=n+1)*sizeof(double);
865  doubles = (double *) realloc(doubles,newsz);
866  newsz = maxn*sizeof(char *);
867  names = (char **) realloc (names, newsz);
868  }
869  if (f_scansexa (pcdataXMLEle(ep), &doubles[n]) < 0)
870  IDMessage (dev,"%s: Bad format %s", name,
871  pcdataXMLEle(ep));
872  else
873  names[n++] = valuXMLAtt(na);
874  }
875  }
876  }
877  setlocale(LC_NUMERIC,"");
878 
879  /* invoke driver if something to do, but not an error if not */
880  if (n > 0)
881  ISNewNumber (dev, name, doubles, names, n);
882  else
883  IDMessage(dev,"%s: newNumberVector with no valid members",name);
884  return (0);
885  }
886 
887  if (!strcmp (rtag, "newSwitchVector")) {
888  static ISState *states;
889  static char **names;
890  static int maxn;
891  char *dev, *name;
892  XMLEle *ep;
893 
894  /* pull out device and name */
895  if (crackDN (root, &dev, &name, msg) < 0)
896  return (-1);
897 
898  if (!isPropDefined(name))
899  return -1;
900 
901  /* ensure property is not RO */
902  for (i=0; i < nroCheck; i++)
903  {
904  if (!strcmp(roCheck[i].propName, name))
905  {
906  if (roCheck[i].perm == IP_RO)
907  return -1;
908  else
909  break;
910  }
911  }
912 
913  /* seed for reallocs */
914  if (!states) {
915  states = (ISState *) malloc (1);
916  names = (char **) malloc (1);
917  }
918 
919  /* pull out each name/state pair */
920  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
921  if (strcmp (tagXMLEle(ep), "oneSwitch") == 0) {
922  XMLAtt *na = findXMLAtt (ep, "name");
923  if (na) {
924  if (n >= maxn) {
925  int newsz = (maxn=n+1)*sizeof(ISState);
926  states = (ISState *) realloc(states, newsz);
927  newsz = maxn*sizeof(char *);
928  names = (char **) realloc (names, newsz);
929  }
930  if (strcmp (pcdataXMLEle(ep),"On") == 0) {
931  states[n] = ISS_ON;
932  names[n] = valuXMLAtt(na);
933  n++;
934  } else if (strcmp (pcdataXMLEle(ep),"Off") == 0) {
935  states[n] = ISS_OFF;
936  names[n] = valuXMLAtt(na);
937  n++;
938  } else
939  IDMessage (dev, "%s: must be On or Off: %s", name,
940  pcdataXMLEle(ep));
941  }
942  }
943  }
944 
945  /* invoke driver if something to do, but not an error if not */
946  if (n > 0)
947  ISNewSwitch (dev, name, states, names, n);
948  else
949  IDMessage(dev,"%s: newSwitchVector with no valid members",name);
950  return (0);
951  }
952 
953  if (!strcmp (rtag, "newTextVector")) {
954  static char **texts;
955  static char **names;
956  static int maxn;
957  char *dev, *name;
958 
959  /* pull out device and name */
960  if (crackDN (root, &dev, &name, msg) < 0)
961  return (-1);
962 
963  if (!isPropDefined(name))
964  return -1;
965 
966  /* ensure property is not RO */
967  for (i=0; i < nroCheck; i++)
968  {
969  if (!strcmp(roCheck[i].propName, name))
970  {
971  if (roCheck[i].perm == IP_RO)
972  return -1;
973  else
974  break;
975  }
976  }
977 
978  /* seed for reallocs */
979  if (!texts) {
980  texts = (char **) malloc (1);
981  names = (char **) malloc (1);
982  }
983 
984  /* pull out each name/text pair */
985  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
986  if (strcmp (tagXMLEle(ep), "oneText") == 0) {
987  XMLAtt *na = findXMLAtt (ep, "name");
988  if (na) {
989  if (n >= maxn) {
990  int newsz = (maxn=n+1)*sizeof(char *);
991  texts = (char **) realloc (texts, newsz);
992  names = (char **) realloc (names, newsz);
993  }
994  texts[n] = pcdataXMLEle(ep);
995  names[n] = valuXMLAtt(na);
996  n++;
997  }
998  }
999  }
1000 
1001  /* invoke driver if something to do, but not an error if not */
1002  if (n > 0)
1003  ISNewText (dev, name, texts, names, n);
1004  else
1005  IDMessage (dev, "%s: set with no valid members", name);
1006  return (0);
1007  }
1008 
1009  if (!strcmp (rtag, "newBLOBVector")) {
1010  static char **blobs;
1011  static char **names;
1012  static char **formats;
1013  static int *blobsizes;
1014  static int *sizes;
1015  static int maxn;
1016  char *dev, *name;
1017  int i;
1018 
1019  /* pull out device and name */
1020  if (crackDN (root, &dev, &name, msg) < 0)
1021  return (-1);
1022 
1023  if (!isPropDefined(name))
1024  return -1;
1025 
1026  /* seed for reallocs */
1027  if (!blobs) {
1028  blobs = (char **) malloc (1);
1029  names = (char **) malloc (1);
1030  formats = (char **) malloc (1);
1031  blobsizes = (int *) malloc (1);
1032  sizes = (int *) malloc (1);
1033  }
1034 
1035  /* pull out each name/BLOB pair, decode */
1036  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
1037  if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) {
1038  XMLAtt *na = findXMLAtt (ep, "name");
1039  XMLAtt *fa = findXMLAtt (ep, "format");
1040  XMLAtt *sa = findXMLAtt (ep, "size");
1041  if (na && fa && sa) {
1042  if (n >= maxn) {
1043  int newsz = (maxn=n+1)*sizeof(char *);
1044  blobs = (char **) realloc (blobs, newsz);
1045  names = (char **) realloc (names, newsz);
1046  formats = (char **) realloc(formats,newsz);
1047  newsz = maxn*sizeof(int);
1048  sizes = (int *) realloc(sizes,newsz);
1049  blobsizes = (int *) realloc(blobsizes,newsz);
1050  }
1051  blobs[n] = malloc (3*pcdatalenXMLEle(ep)/4);
1052  blobsizes[n] = from64tobits(blobs[n], pcdataXMLEle(ep));
1053  names[n] = valuXMLAtt(na);
1054  formats[n] = valuXMLAtt(fa);
1055  sizes[n] = atoi(valuXMLAtt(sa));
1056  n++;
1057  }
1058  }
1059  }
1060 
1061  /* invoke driver if something to do, but not an error if not */
1062  if (n > 0) {
1063  ISNewBLOB (dev, name, sizes, blobsizes, blobs, formats,names,n);
1064  for (i = 0; i < n; i++)
1065  free (blobs[i]);
1066  } else
1067  IDMessage (dev, "%s: newBLOBVector with no valid members",name);
1068  return (0);
1069  }
1070 
1071  if (!strcmp (rtag, "getProperties")) {
1072  XMLAtt *ap;
1073  double v;
1074 
1075  /* check version */
1076  ap = findXMLAtt (root, "version");
1077  if (!ap) {
1078  fprintf (stderr, "%s: getProperties missing version\n", me);
1079  exit(1);
1080  }
1081  v = atof (valuXMLAtt(ap));
1082  if (v > INDIV) {
1083  fprintf (stderr, "%s: client version %g > %g\n", me, v, INDIV);
1084  exit(1);
1085  }
1086 
1087  /* ok */
1088  ap = findXMLAtt (root, "device");
1089  ISGetProperties (ap ? valuXMLAtt(ap) : NULL);
1090  return (0);
1091  }
1092 
1093  /* other commands might be from a snooped device.
1094  * we don't know here which devices are being snooped so we send
1095  * all remaining valid messages
1096  */
1097  if ( !strcmp (rtag, "setNumberVector") ||
1098  !strcmp (rtag, "setTextVector") ||
1099  !strcmp (rtag, "setLightVector") ||
1100  !strcmp (rtag, "setSwitchVector") ||
1101  !strcmp (rtag, "setBLOBVector") ||
1102  !strcmp (rtag, "defNumberVector") ||
1103  !strcmp (rtag, "defTextVector") ||
1104  !strcmp (rtag, "defLightVector") ||
1105  !strcmp (rtag, "defSwitchVector") ||
1106  !strcmp (rtag, "defBLOBVector") ||
1107  !strcmp (rtag, "message") ||
1108  !strcmp (rtag, "delProperty")) {
1109  ISSnoopDevice (root);
1110  return (0);
1111  }
1112 
1113  sprintf (msg, "Unknown command: %s", rtag);
1114  return(1);
1115 }
1116 
1117 int IUReadConfig(const char *filename, const char *dev, char errmsg[])
1118 {
1119  char configFileName[MAXRBUF];
1120  char *rname, *rdev;
1121  XMLEle *root = NULL, *fproot = NULL;
1122  LilXML *lp = newLilXML();
1123 
1124  FILE *fp = NULL;
1125 
1126  if (filename)
1127  strncpy(configFileName, filename, MAXRBUF);
1128  else
1129  {
1130  if (getenv("INDICONFIG"))
1131  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1132  else
1133  snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
1134 
1135  }
1136 
1137  fp = fopen(configFileName, "r");
1138  if (fp == NULL)
1139  {
1140  snprintf(errmsg, MAXRBUF, "Unable to read user config file. Error loading file %s: %s\n", configFileName, strerror(errno));
1141  return -1;
1142  }
1143 
1144  fproot = readXMLFile(fp, lp, errmsg);
1145 
1146  if (fproot == NULL)
1147  {
1148  snprintf(errmsg, MAXRBUF, "Unable to parse config XML: %s", errmsg);
1149  fclose(fp);
1150  return -1;
1151  }
1152 
1153  if (nXMLEle(fproot) > 0)
1154  IDMessage(dev, "Loading device configuration...");
1155 
1156  for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0))
1157  {
1158 
1159  /* pull out device and name */
1160  if (crackDN (root, &rdev, &rname, errmsg) < 0)
1161  {
1162  fclose(fp);
1163  return -1;
1164  }
1165 
1166  // It doesn't belong to our device??
1167  if (strcmp(dev, rdev))
1168  continue;
1169 
1170  dispatch(root, errmsg);
1171  }
1172 
1173  if (nXMLEle(fproot) > 0)
1174  IDMessage(dev, "Device configuration applied.");
1175 
1176  fclose(fp);
1177  delXMLEle(fproot);
1178  delXMLEle(root);
1179  delLilXML(lp);
1180 
1181  return (0);
1182 
1183 }
1184 
1185 
1186 void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
1187 {
1188 
1189  char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF];
1190 
1191  if (source_config)
1192  strncpy(configFileName, source_config, MAXRBUF);
1193  else
1194  {
1195  if (getenv("INDICONFIG"))
1196  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1197  else
1198  snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
1199 
1200  }
1201 
1202  if (dest_config)
1203  strncpy(configDefaultFileName, dest_config, MAXRBUF);
1204  else if (getenv("INDICONFIG"))
1205  snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
1206  else
1207  snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), dev);
1208 
1209  // If the default doesn't exist, create it.
1210  if (access(configDefaultFileName, F_OK))
1211  {
1212  FILE *fpin = fopen(configFileName, "r");
1213  if(fpin != NULL)
1214  {
1215  FILE *fpout = fopen(configDefaultFileName, "w");
1216  if(fpout != NULL)
1217  {
1218  int ch = 0;
1219  while((ch = getc(fpin)) != EOF)
1220  putc(ch, fpout);
1221 
1222  fclose(fpin);
1223  }
1224  fclose(fpout);
1225  }
1226  }
1227 
1228 }
1229 
1230 
1231 
1232 
1233 /* send client a message for a specific device or at large if !dev */
1234 void
1235 IDMessage (const char *dev, const char *fmt, ...)
1236 {
1237 
1238  pthread_mutex_lock(&stdout_mutex);
1239 
1240  xmlv1();
1241  printf ("<message\n");
1242  if (dev)
1243  printf (" device='%s'\n", dev);
1244  printf (" timestamp='%s'\n", timestamp());
1245  if (fmt) {
1246  va_list ap;
1247  va_start (ap, fmt);
1248  printf (" message='");
1249  vprintf (fmt, ap);
1250  printf ("'\n");
1251  va_end (ap);
1252  }
1253  printf ("/>\n");
1254  fflush (stdout);
1255 
1256  pthread_mutex_unlock(&stdout_mutex);
1257 }
1258 
1259 FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[])
1260 {
1261  char configFileName[MAXRBUF];
1262  char configDir[MAXRBUF];
1263  struct stat st;
1264  FILE *fp = NULL;
1265 
1266  snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
1267 
1268  if (filename)
1269  strncpy(configFileName, filename, MAXRBUF);
1270  else
1271  {
1272  if (getenv("INDICONFIG"))
1273  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1274  else
1275  snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1276 
1277  }
1278 
1279  if(stat(configDir,&st) != 0)
1280  {
1281  if (mkdir(configDir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0)
1282  {
1283  snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s\n", configDir, strerror(errno));
1284  return NULL;
1285  }
1286  }
1287 
1288  fp = fopen(configFileName, "w");
1289  if (fp == NULL)
1290  {
1291  snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s\n", configFileName, strerror(errno));
1292  return NULL;
1293  }
1294 
1295  return fp;
1296 }
1297 
1298 void IUSaveConfigTag(FILE *fp, int ctag)
1299 {
1300  if (!fp)
1301  return;
1302 
1303  /* Opening tag */
1304  if (ctag == 0)
1305  fprintf(fp, "<INDIDriver>\n");
1306  /* Closing tag */
1307  else
1308  fprintf(fp, "</INDIDriver>\n");
1309 }
1310 
1311 void IUSaveConfigNumber (FILE *fp, const INumberVectorProperty *nvp)
1312 {
1313  int i;
1314 
1315  setlocale(LC_NUMERIC,"C");
1316  fprintf (fp, "<newNumberVector device='%s' name='%s'>\n", nvp->device, nvp->name);
1317 
1318  for (i = 0; i < nvp->nnp; i++)
1319  {
1320  INumber *np = &nvp->np[i];
1321  fprintf (fp, " <oneNumber name='%s'>\n", np->name);
1322  fprintf (fp, " %.20g\n", np->value);
1323  fprintf (fp, " </oneNumber>\n");
1324  }
1325 
1326  fprintf (fp, "</newNumberVector>\n");
1327  setlocale(LC_NUMERIC,"");
1328 }
1329 
1330 void IUSaveConfigText (FILE *fp, const ITextVectorProperty *tvp)
1331 {
1332  int i;
1333 
1334  fprintf (fp, "<newTextVector device='%s' name='%s'>\n", tvp->device, tvp->name);
1335 
1336  for (i = 0; i < tvp->ntp; i++)
1337  {
1338  IText *tp = &tvp->tp[i];
1339  fprintf (fp, " <oneText name='%s'>\n", tp->name);
1340  fprintf (fp, " %s\n", tp->text ? tp->text : "");
1341  fprintf (fp, " </oneText>\n");
1342  }
1343 
1344  fprintf (fp, "</newTextVector>\n");
1345 
1346 }
1347 
1348 void IUSaveConfigSwitch (FILE *fp, const ISwitchVectorProperty *svp)
1349 {
1350  int i;
1351 
1352  fprintf (fp, "<newSwitchVector device='%s' name='%s'>\n", svp->device, svp->name);
1353 
1354  for (i = 0; i < svp->nsp; i++)
1355  {
1356  ISwitch *sp = &svp->sp[i];
1357  fprintf (fp, " <oneSwitch name='%s'>\n", sp->name);
1358  fprintf (fp, " %s\n", sstateStr(sp->s));
1359  fprintf (fp, " </oneSwitch>\n");
1360  }
1361 
1362  fprintf (fp, "</newSwitchVector>\n");
1363 
1364 }
1365 
1366 void IUSaveConfigBLOB (FILE *fp, const IBLOBVectorProperty *bvp)
1367 {
1368  int i;
1369 
1370  fprintf (fp, "<newBLOBVector device='%s' name='%s'>\n", bvp->device, bvp->name);
1371 
1372  for (i = 0; i < bvp->nbp; i++)
1373  {
1374  IBLOB *bp = &bvp->bp[i];
1375  unsigned char *encblob;
1376  int j, l;
1377 
1378  fprintf (fp, " <oneBLOB\n");
1379  fprintf (fp, " name='%s'\n", bp->name);
1380  fprintf (fp, " size='%d'\n", bp->size);
1381  fprintf (fp, " format='%s'>\n", bp->format);
1382 
1383  encblob = malloc (4*bp->bloblen/3+4);
1384  l = to64frombits(encblob, bp->blob, bp->bloblen);
1385  for (j = 0; j < l; j += 72)
1386  fprintf (fp, "%.72s\n", encblob+j);
1387  free (encblob);
1388 
1389  fprintf (fp, " </oneBLOB>\n");
1390  }
1391 
1392  fprintf (fp, "</newBLOBVector>\n");
1393 
1394 }
1395 
1396 /* tell client to create a text vector property */
1397 void
1398 IDDefText (const ITextVectorProperty *tvp, const char *fmt, ...)
1399 {
1400  int i;
1401  ROSC *SC;
1402 
1403  pthread_mutex_lock(&stdout_mutex);
1404 
1405  xmlv1();
1406  setlocale(LC_NUMERIC,"C");
1407  printf ("<defTextVector\n");
1408  printf (" device='%s'\n", tvp->device);
1409  printf (" name='%s'\n", tvp->name);
1410  printf (" label='%s'\n", tvp->label);
1411  printf (" group='%s'\n", tvp->group);
1412  printf (" state='%s'\n", pstateStr(tvp->s));
1413  printf (" perm='%s'\n", permStr(tvp->p));
1414  printf (" timeout='%g'\n", tvp->timeout);
1415  printf (" timestamp='%s'\n", timestamp());
1416  if (fmt) {
1417  va_list ap;
1418  va_start (ap, fmt);
1419  printf (" message='");
1420  vprintf (fmt, ap);
1421  printf ("'\n");
1422  va_end (ap);
1423  }
1424  printf (">\n");
1425 
1426  for (i = 0; i < tvp->ntp; i++) {
1427  IText *tp = &tvp->tp[i];
1428  printf (" <defText\n");
1429  printf (" name='%s'\n", tp->name);
1430  printf (" label='%s'>\n", tp->label);
1431  printf (" %s\n", tp->text ? tp->text : "");
1432  printf (" </defText>\n");
1433  }
1434 
1435  printf ("</defTextVector>\n");
1436 
1437  if (!isPropDefined(tvp->name))
1438  {
1439  /* Add this property to insure proper sanity check */
1440  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1441  : (ROSC *) malloc ( sizeof(ROSC));
1442  SC = &roCheck[nroCheck++];
1443 
1444  strcpy(SC->propName, tvp->name);
1445  SC->perm = tvp->p;
1446  }
1447 
1448  setlocale(LC_NUMERIC,"");
1449  fflush (stdout);
1450 
1451  pthread_mutex_unlock(&stdout_mutex);
1452 }
1453 
1454 /* tell client to create a new numeric vector property */
1455 void
1456 IDDefNumber (const INumberVectorProperty *n, const char *fmt, ...)
1457 {
1458  int i;
1459  ROSC *SC;
1460 
1461  pthread_mutex_lock(&stdout_mutex);
1462 
1463  xmlv1();
1464  setlocale(LC_NUMERIC,"C");
1465  printf ("<defNumberVector\n");
1466  printf (" device='%s'\n", n->device);
1467  printf (" name='%s'\n", n->name);
1468  printf (" label='%s'\n", n->label);
1469  printf (" group='%s'\n", n->group);
1470  printf (" state='%s'\n", pstateStr(n->s));
1471  printf (" perm='%s'\n", permStr(n->p));
1472  printf (" timeout='%g'\n", n->timeout);
1473  printf (" timestamp='%s'\n", timestamp());
1474 
1475 
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 
1487  for (i = 0; i < n->nnp; i++) {
1488 
1489  INumber *np = &n->np[i];
1490 
1491  printf (" <defNumber\n");
1492  printf (" name='%s'\n", np->name);
1493  printf (" label='%s'\n", np->label);
1494  printf (" format='%s'\n", np->format);
1495  printf (" min='%.20g'\n", np->min);
1496  printf (" max='%.20g'\n", np->max);
1497  printf (" step='%.20g'>\n", np->step);
1498  printf (" %.20g\n", np->value);
1499 
1500  printf (" </defNumber>\n");
1501  }
1502 
1503  printf ("</defNumberVector>\n");
1504 
1505  if (!isPropDefined(n->name))
1506  {
1507  /* Add this property to insure proper sanity check */
1508  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1509  : (ROSC *) malloc ( sizeof(ROSC));
1510  SC = &roCheck[nroCheck++];
1511 
1512  strcpy(SC->propName, n->name);
1513  SC->perm = n->p;
1514 
1515  }
1516 
1517  setlocale(LC_NUMERIC,"");
1518  fflush (stdout);
1519 
1520  pthread_mutex_unlock(&stdout_mutex);
1521 }
1522 
1523 /* tell client to create a new switch vector property */
1524 void
1525 IDDefSwitch (const ISwitchVectorProperty *s, const char *fmt, ...)
1526 
1527 {
1528  int i;
1529  ROSC *SC;
1530 
1531  pthread_mutex_lock(&stdout_mutex);
1532 
1533  xmlv1();
1534  setlocale(LC_NUMERIC,"C");
1535  printf ("<defSwitchVector\n");
1536  printf (" device='%s'\n", s->device);
1537  printf (" name='%s'\n", s->name);
1538  printf (" label='%s'\n", s->label);
1539  printf (" group='%s'\n", s->group);
1540  printf (" state='%s'\n", pstateStr(s->s));
1541  printf (" perm='%s'\n", permStr(s->p));
1542  printf (" rule='%s'\n", ruleStr (s->r));
1543  printf (" timeout='%g'\n", s->timeout);
1544  printf (" timestamp='%s'\n", timestamp());
1545  if (fmt) {
1546  va_list ap;
1547  va_start (ap, fmt);
1548  printf (" message='");
1549  vprintf (fmt, ap);
1550  printf ("'\n");
1551  va_end (ap);
1552  }
1553  printf (">\n");
1554 
1555  for (i = 0; i < s->nsp; i++) {
1556  ISwitch *sp = &s->sp[i];
1557  printf (" <defSwitch\n");
1558  printf (" name='%s'\n", sp->name);
1559  printf (" label='%s'>\n", sp->label);
1560  printf (" %s\n", sstateStr(sp->s));
1561  printf (" </defSwitch>\n");
1562  }
1563 
1564  printf ("</defSwitchVector>\n");
1565 
1566  if (!isPropDefined(s->name))
1567  {
1568  /* Add this property to insure proper sanity check */
1569  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1570  : (ROSC *) malloc ( sizeof(ROSC));
1571  SC = &roCheck[nroCheck++];
1572 
1573  strcpy(SC->propName, s->name);
1574  SC->perm = s->p;
1575  }
1576 
1577  setlocale(LC_NUMERIC,"");
1578  fflush (stdout);
1579 
1580  pthread_mutex_unlock(&stdout_mutex);
1581 }
1582 
1583 /* tell client to create a new lights vector property */
1584 void
1585 IDDefLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1586 {
1587  int i;
1588 
1589  pthread_mutex_lock(&stdout_mutex);
1590 
1591  xmlv1();
1592  printf ("<defLightVector\n");
1593  printf (" device='%s'\n", lvp->device);
1594  printf (" name='%s'\n", lvp->name);
1595  printf (" label='%s'\n", lvp->label);
1596  printf (" group='%s'\n", lvp->group);
1597  printf (" state='%s'\n", pstateStr(lvp->s));
1598  printf (" timestamp='%s'\n", timestamp());
1599  if (fmt) {
1600  va_list ap;
1601  va_start (ap, fmt);
1602  printf (" message='");
1603  vprintf (fmt, ap);
1604  printf ("'\n");
1605  va_end (ap);
1606  }
1607  printf (">\n");
1608 
1609  for (i = 0; i < lvp->nlp; i++) {
1610  ILight *lp = &lvp->lp[i];
1611  printf (" <defLight\n");
1612  printf (" name='%s'\n", lp->name);
1613  printf (" label='%s'>\n", lp->label);
1614  printf (" %s\n", pstateStr(lp->s));
1615  printf (" </defLight>\n");
1616  }
1617 
1618  printf ("</defLightVector>\n");
1619  fflush (stdout);
1620 
1621  pthread_mutex_unlock(&stdout_mutex);
1622 }
1623 
1624 /* tell client to create a new BLOB vector property */
1625 void
1626 IDDefBLOB (const IBLOBVectorProperty *b, const char *fmt, ...)
1627 {
1628  int i;
1629  ROSC *SC;
1630 
1631  pthread_mutex_lock(&stdout_mutex);
1632 
1633  xmlv1();
1634  setlocale(LC_NUMERIC,"C");
1635  printf ("<defBLOBVector\n");
1636  printf (" device='%s'\n", b->device);
1637  printf (" name='%s'\n", b->name);
1638  printf (" label='%s'\n", b->label);
1639  printf (" group='%s'\n", b->group);
1640  printf (" state='%s'\n", pstateStr(b->s));
1641  printf (" perm='%s'\n", permStr(b->p));
1642  printf (" timeout='%g'\n", b->timeout);
1643  printf (" timestamp='%s'\n", timestamp());
1644  if (fmt) {
1645  va_list ap;
1646  va_start (ap, fmt);
1647  printf (" message='");
1648  vprintf (fmt, ap);
1649  printf ("'\n");
1650  va_end (ap);
1651  }
1652  printf (">\n");
1653 
1654  for (i = 0; i < b->nbp; i++) {
1655  IBLOB *bp = &b->bp[i];
1656  printf (" <defBLOB\n");
1657  printf (" name='%s'\n", bp->name);
1658  printf (" label='%s'\n", bp->label);
1659  printf (" />\n");
1660  }
1661 
1662  printf ("</defBLOBVector>\n");
1663 
1664  if (!isPropDefined(b->name))
1665  {
1666  /* Add this property to insure proper sanity check */
1667  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1668  : (ROSC *) malloc ( sizeof(ROSC));
1669  SC = &roCheck[nroCheck++];
1670 
1671  strcpy(SC->propName, b->name);
1672  SC->perm = b->p;
1673  }
1674 
1675  setlocale(LC_NUMERIC,"");
1676  fflush (stdout);
1677 
1678  pthread_mutex_unlock(&stdout_mutex);
1679 }
1680 
1681 /* tell client to update an existing text vector property */
1682 void
1683 IDSetText (const ITextVectorProperty *tvp, const char *fmt, ...)
1684 {
1685  int i;
1686 
1687  pthread_mutex_lock(&stdout_mutex);
1688 
1689  xmlv1();
1690  setlocale(LC_NUMERIC,"C");
1691  printf ("<setTextVector\n");
1692  printf (" device='%s'\n", tvp->device);
1693  printf (" name='%s'\n", tvp->name);
1694  printf (" state='%s'\n", pstateStr(tvp->s));
1695  printf (" timeout='%g'\n", tvp->timeout);
1696  printf (" timestamp='%s'\n", timestamp());
1697  if (fmt) {
1698  va_list ap;
1699  va_start (ap, fmt);
1700  printf (" message='");
1701  vprintf (fmt, ap);
1702  printf ("'\n");
1703  va_end (ap);
1704  }
1705  printf (">\n");
1706 
1707  for (i = 0; i < tvp->ntp; i++) {
1708  IText *tp = &tvp->tp[i];
1709  printf (" <oneText name='%s'>\n", tp->name);
1710  printf (" %s\n", tp->text ? tp->text : "");
1711  printf (" </oneText>\n");
1712  }
1713 
1714  printf ("</setTextVector>\n");
1715  setlocale(LC_NUMERIC,"");
1716  fflush (stdout);
1717 
1718  pthread_mutex_unlock(&stdout_mutex);
1719 }
1720 
1721 /* tell client to update an existing numeric vector property */
1722 void
1723 IDSetNumber (const INumberVectorProperty *nvp, const char *fmt, ...)
1724 {
1725  int i;
1726 
1727  pthread_mutex_lock(&stdout_mutex);
1728 
1729  xmlv1();
1730  setlocale(LC_NUMERIC,"C");
1731  printf ("<setNumberVector\n");
1732  printf (" device='%s'\n", nvp->device);
1733  printf (" name='%s'\n", nvp->name);
1734  printf (" state='%s'\n", pstateStr(nvp->s));
1735  printf (" timeout='%g'\n", nvp->timeout);
1736  printf (" timestamp='%s'\n", timestamp());
1737  if (fmt) {
1738  va_list ap;
1739  va_start (ap, fmt);
1740  printf (" message='");
1741  vprintf (fmt, ap);
1742  printf ("'\n");
1743  va_end (ap);
1744  }
1745  printf (">\n");
1746 
1747  for (i = 0; i < nvp->nnp; i++) {
1748  INumber *np = &nvp->np[i];
1749  printf (" <oneNumber name='%s'>\n", np->name);
1750  printf (" %.20g\n", np->value);
1751  printf (" </oneNumber>\n");
1752  }
1753 
1754  printf ("</setNumberVector>\n");
1755  setlocale(LC_NUMERIC,"");
1756  fflush (stdout);
1757 
1758  pthread_mutex_unlock(&stdout_mutex);
1759 }
1760 
1761 /* tell client to update an existing switch vector property */
1762 void
1763 IDSetSwitch (const ISwitchVectorProperty *svp, const char *fmt, ...)
1764 {
1765  int i;
1766 
1767  pthread_mutex_lock(&stdout_mutex);
1768 
1769  xmlv1();
1770  setlocale(LC_NUMERIC,"C");
1771  printf ("<setSwitchVector\n");
1772  printf (" device='%s'\n", svp->device);
1773  printf (" name='%s'\n", svp->name);
1774  printf (" state='%s'\n", pstateStr(svp->s));
1775  printf (" timeout='%g'\n", svp->timeout);
1776  printf (" timestamp='%s'\n", timestamp());
1777  if (fmt) {
1778  va_list ap;
1779  va_start (ap, fmt);
1780  printf (" message='");
1781  vprintf (fmt, ap);
1782  printf ("'\n");
1783  va_end (ap);
1784  }
1785  printf (">\n");
1786 
1787  for (i = 0; i < svp->nsp; i++) {
1788  ISwitch *sp = &svp->sp[i];
1789  printf (" <oneSwitch name='%s'>\n", sp->name);
1790  printf (" %s\n", sstateStr(sp->s));
1791  printf (" </oneSwitch>\n");
1792  }
1793 
1794  printf ("</setSwitchVector>\n");
1795  setlocale(LC_NUMERIC,"");
1796  fflush (stdout);
1797 
1798  pthread_mutex_unlock(&stdout_mutex);
1799 }
1800 
1801 /* tell client to update an existing lights vector property */
1802 void
1803 IDSetLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1804 {
1805  int i;
1806 
1807  pthread_mutex_lock(&stdout_mutex);
1808 
1809  xmlv1();
1810  printf ("<setLightVector\n");
1811  printf (" device='%s'\n", lvp->device);
1812  printf (" name='%s'\n", lvp->name);
1813  printf (" state='%s'\n", pstateStr(lvp->s));
1814  printf (" timestamp='%s'\n", timestamp());
1815  if (fmt) {
1816  va_list ap;
1817  va_start (ap, fmt);
1818  printf (" message='");
1819  vprintf (fmt, ap);
1820  printf ("'\n");
1821  va_end (ap);
1822  }
1823  printf (">\n");
1824 
1825  for (i = 0; i < lvp->nlp; i++) {
1826  ILight *lp = &lvp->lp[i];
1827  printf (" <oneLight name='%s'>\n", lp->name);
1828  printf (" %s\n", pstateStr(lp->s));
1829  printf (" </oneLight>\n");
1830  }
1831 
1832  printf ("</setLightVector>\n");
1833  fflush (stdout);
1834 
1835  pthread_mutex_unlock(&stdout_mutex);
1836 }
1837 
1838 /* tell client to update an existing BLOB vector property */
1839 void
1840 IDSetBLOB (const IBLOBVectorProperty *bvp, const char *fmt, ...)
1841 {
1842  int i;
1843 
1844  pthread_mutex_lock(&stdout_mutex);
1845 
1846  xmlv1();
1847  setlocale(LC_NUMERIC,"C");
1848  printf ("<setBLOBVector\n");
1849  printf (" device='%s'\n", bvp->device);
1850  printf (" name='%s'\n", bvp->name);
1851  printf (" state='%s'\n", pstateStr(bvp->s));
1852  printf (" timeout='%g'\n", bvp->timeout);
1853  printf (" timestamp='%s'\n", timestamp());
1854  if (fmt) {
1855  va_list ap;
1856  va_start (ap, fmt);
1857  printf (" message='");
1858  vprintf (fmt, ap);
1859  printf ("'\n");
1860  va_end (ap);
1861  }
1862  printf (">\n");
1863 
1864  for (i = 0; i < bvp->nbp; i++) {
1865  IBLOB *bp = &bvp->bp[i];
1866  unsigned char *encblob;
1867  int j, l;
1868 
1869  printf (" <oneBLOB\n");
1870  printf (" name='%s'\n", bp->name);
1871  printf (" size='%d'\n", bp->size);
1872  printf (" format='%s'>\n", bp->format);
1873 
1874  encblob = malloc (4*bp->bloblen/3+4);
1875  l = to64frombits(encblob, bp->blob, bp->bloblen);
1876  for (j = 0; j < l; j += 72)
1877  printf ("%.72s\n", encblob+j);
1878  free (encblob);
1879 
1880  printf (" </oneBLOB>\n");
1881  }
1882 
1883  printf ("</setBLOBVector>\n");
1884  setlocale(LC_NUMERIC,"");
1885  fflush (stdout);
1886 
1887  pthread_mutex_unlock(&stdout_mutex);
1888 }
1889 
1890 /* tell client to update min/max elements of an existing number vector property */
1892 {
1893  int i;
1894 
1895  pthread_mutex_lock(&stdout_mutex);
1896  xmlv1();
1897  setlocale(LC_NUMERIC,"C");
1898  printf ("<setNumberVector\n");
1899  printf (" device='%s'\n", nvp->device);
1900  printf (" name='%s'\n", nvp->name);
1901  printf (" state='%s'\n", pstateStr(nvp->s));
1902  printf (" timeout='%g'\n", nvp->timeout);
1903  printf (" timestamp='%s'\n", timestamp());
1904  printf (">\n");
1905 
1906  for (i = 0; i < nvp->nnp; i++) {
1907  INumber *np = &nvp->np[i];
1908  printf (" <oneNumber name='%s'\n", np->name);
1909  printf (" min='%g'\n", np->min);
1910  printf (" max='%g'\n", np->max);
1911  printf (" step='%g'\n", np->step);
1912  printf(">\n");
1913  printf (" %g\n", np->value);
1914  printf (" </oneNumber>\n");
1915  }
1916 
1917  printf ("</setNumberVector>\n");
1918  setlocale(LC_NUMERIC,"");
1919  fflush (stdout);
1920  pthread_mutex_unlock(&stdout_mutex);
1921 }
1922 
1923 /* Return 1 is property is already cached, 0 otherwise */
1924 int isPropDefined(const char *property_name)
1925 {
1926  int i=0;
1927 
1928  for (i=0; i < nroCheck; i++)
1929  if (!strcmp(property_name, roCheck[i].propName))
1930  return 1;
1931 
1932  return 0;
1933 
1934 }
1935 
1936 int IUFindIndex (const char *needle, char **hay, unsigned int n)
1937 {
1938  int i=0;
1939 
1940  for (i=0; i < n; i++)
1941  if (!strcmp(hay[i], needle))
1942  return i;
1943 
1944  return -1;
1945 }
1946 
1947 
FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[])
Open a configuration file for writing and return a configuration file FILE pointer.
Definition: indidriver.c:1259
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidriver.c:1330
void * aux0
Definition: indiapi.h:188
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1181
void * aux0
Definition: indiapi.h:372
struct _ISwitchVectorProperty * svp
Definition: indiapi.h:284
int addCallback(int fd, CBF *fp, void *ud)
Definition: eventloop.c:158
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1171
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.c:449
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition: lilxml.c:401
struct _ITextVectorProperty * tvp
Definition: indiapi.h:186
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:161
const char * pstateStr(IPState s)
Definition: indicom.c:947
char label[MAXINDILABEL]
Definition: indiapi.h:385
void IUSaveConfigTag(FILE *fp, int ctag)
Add opening or closing tag to a configuration file.
Definition: indidriver.c:1298
Light vector property descriptor.
Definition: indiapi.h:332
char label[MAXINDILABEL]
Definition: indiapi.h:323
int IUSnoopText(XMLEle *root, ITextVectorProperty *tvp)
Update a snooped text vector property from the given XML root element.
Definition: indidriver.c:616
char label[MAXINDILABEL]
Definition: indiapi.h:297
void * aux
Definition: indiapi.h:285
char device[MAXINDIDEVICE]
Definition: indiapi.h:198
int from64tobits(char *out, const char *in)
Convert base64 to bytes array.
Definition: base64.c:90
char * text
Definition: indiapi.h:184
Public interface to INDI's eventloop mechanism.
char format[MAXINDIFORMAT]
Definition: indiapi.h:227
void 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)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:502
ISState s
Definition: indiapi.h:283
char format[MAXINDIBLOBFMT]
Definition: indiapi.h:362
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:394
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Tell client to update an existing text vector property.
Definition: indidriver.c:1683
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Tell client to update an existing switch vector property.
Definition: indidriver.c:1763
double step
Definition: indiapi.h:229
IPState
Property state.
Definition: indiapi.h:115
One light descriptor.
Definition: indiapi.h:321
int IEAddWorkProc(IE_WPF *fp, void *p)
Add a new work procedure, fp, to be called with ud when nothing else to do.
Definition: indidriver.c:183
char device[MAXINDIDEVICE]
Definition: indiapi.h:381
void IDDefNumber(const INumberVectorProperty *n, const char *fmt,...)
Tell client to create a number number property.
Definition: indidriver.c:1456
void IDMessage(const char *dev, const char *fmt,...)
Function Drivers call to send log messages to Clients.
Definition: indidriver.c:1235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:209
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:300
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new timer function, fp, to be called with ud as argument after ms.
Definition: indidriver.c:171
One number descriptor.
Definition: indiapi.h:224
int IUReadConfig(const char *filename, const char *dev, char errmsg[])
Loads and processes a configuration file.
Definition: indidriver.c:1117
char timestamp[MAXINDITSTAMP]
Definition: indiapi.h:348
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:263
char group[MAXINDIGROUP]
Definition: indiapi.h:260
int IUSnoopLight(XMLEle *root, ILightVectorProperty *lvp)
Update a snooped light vector property from the given XML root element.
Definition: indidriver.c:653
One Blob (Binary Large Object) descriptor.
Definition: indiapi.h:356
char device[MAXINDIDEVICE]
Definition: indiapi.h:334
int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format)
Function to save blob metadata in the corresponding blob.
Definition: indidriver.c:358
void IDDefBLOB(const IBLOBVectorProperty *b, const char *fmt,...)
Tell client to create a BLOB vector property.
Definition: indidriver.c:1626
Definition: indiapi.h:138
void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
Copies an existing configuration file into a default configuration file.
Definition: indidriver.c:1186
int size
Definition: indiapi.h:368
IPState s
Definition: indiapi.h:324
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
Definition: dome.cpp:79
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:415
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1891
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer.
Definition: indidriver.c:177
char group[MAXINDIGROUP]
Definition: indiapi.h:299
struct _IBLOBVectorProperty * bvp
Definition: indiapi.h:370
void rmTimer(int tid)
Definition: eventloop.c:241
void delXMLEle(XMLEle *ep)
Delete an XML element.
Definition: lilxml.c:153
int addTimer(int ms, TCF *fp, void *ud)
Definition: eventloop.c:208
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Tell client to update an existing number vector property.
Definition: indidriver.c:1723
void IUSaveConfigBLOB(FILE *fp, const IBLOBVectorProperty *bvp)
Add a BLOB vector property value to the configuration file.
Definition: indidriver.c:1366
void( IE_CBF)(int readfiledes, void *userpointer)
Signature of a callback.
Definition: indidevapi.h:326
Switch vector property descriptor.
Definition: indiapi.h:291
char label[MAXINDILABEL]
Definition: indiapi.h:258
Namespace to encapsulate INDI client, drivers, and mediator classes. Developers can subclass the base...
void IDSnoopBLOBs(const char *snooped_device, BLOBHandling bh)
Function a Driver calls to control whether they will receive BLOBs from snooped devices.
Definition: indidriver.c:137
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int num)
Update the value of an existing text vector property.
Definition: dome.cpp:55
char name[MAXINDINAME]
Definition: indiapi.h:256
int bloblen
Definition: indiapi.h:366
void ISNewNumber(const char *dev, const char *name, double *doubles, char *names[], int n)
Update the value of an existing number vector property.
char label[MAXINDILABEL]
Definition: indiapi.h:282
const char * permStr(IPerm p)
Definition: indicom.c:1034
int IUSnoopNumber(XMLEle *root, INumberVectorProperty *nvp)
Update a snooped number vector property from the given XML root element.
Definition: indidriver.c:578
One switch descriptor.
Definition: indiapi.h:280
char timestamp[MAXINDITSTAMP]
Definition: indiapi.h:399
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indicom.c:1080
int nXMLEle(XMLEle *ep)
Return the number of nested XML elements in a parent XML element.
Definition: lilxml.c:422
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL...
Definition: indidriver.c:419
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num)
Update the value of an existing switch vector property.
Definition: dome.cpp:49
struct _ILightVectorProperty * lvp
Definition: indiapi.h:325
void IUFillBLOB(IBLOB *bp, const char *name, const char *label, const char *format)
Assign attributes for a BLOB property. The BLOB's data and auxiliary elements will be set to NULL...
Definition: indidriver.c:439
struct _INumberVectorProperty * nvp
Definition: indiapi.h:231
char name[MAXINDINAME]
Definition: indiapi.h:336
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidriver.c:1311
char label[MAXINDILABEL]
Definition: indiapi.h:360
char label[MAXINDILABEL]
Definition: indiapi.h:202
void rmWorkProc(int wid)
Definition: eventloop.c:293
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL...
Definition: indidriver.c:367
int addWorkProc(WPF *fp, void *ud)
Definition: eventloop.c:264
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:379
const char * timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Definition: indicom.c:236
char label[MAXINDILABEL]
Definition: indiapi.h:338
BLOBHandling
How drivers handle BLOBs incoming from snooping drivers.
Definition: indidevapi.h:294
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.c:134
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition: indicom.c:1132
void IERmCallback(int callbackid)
Remove a callback function.
Definition: indidriver.c:165
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indicom.c:1057
void rmCallback(int cid)
Definition: eventloop.c:187
const char * ruleStr(ISRule r)
Definition: indicom.c:1020
void * blob
Definition: indiapi.h:364
XMLEle * readXMLEle(LilXML *lp, int newc, char ynot[])
Process an XML one char at a time.
Definition: lilxml.c:202
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL...
Definition: indidriver.c:398
void( IE_WPF)(void *userpointer)
Signature of a work procedure function.
Definition: indidevapi.h:334
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidriver.c:1348
int IUSnoopSwitch(XMLEle *root, ISwitchVectorProperty *svp)
Update a snooped switch vector property from the given XML root element.
Definition: indidriver.c:693
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indicom.c:978
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1093
char name[MAXINDINAME]
Definition: indiapi.h:358
void IDSnoopDevice(const char *snooped_device_name, const char *snooped_property_name)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:120
void ISGetProperties(const char *dev)
Get Device Properties.
Definition: dome.cpp:43
Number vector property descriptor.
Definition: indiapi.h:252
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indicom.c:964
int IUSnoopBLOB(XMLEle *root, IBLOBVectorProperty *bvp)
Update a snooped BLOB vector property from the given XML root element.
Definition: indidriver.c:733
One text descriptor.
Definition: indiapi.h:178
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
Tell client to update an existing BLOB vector property.
Definition: indidriver.c:1840
char name[MAXINDINAME]
Definition: indiapi.h:295
char group[MAXINDIGROUP]
Definition: indiapi.h:340
void IDDefLight(const ILightVectorProperty *lvp, const char *fmt,...)
Tell client to create a light vector property.
Definition: indidriver.c:1585
void IERmWorkProc(int workprocid)
Remove a work procedure.
Definition: indidriver.c:189
void IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
Tell client to update an existing light vector property.
Definition: indidriver.c:1803
int IEAddCallback(int readfiledes, IE_CBF *fp, void *p)
Register a new callback, fp, to be called with userpointer as argument when readfiledes is ready...
Definition: indidriver.c:159
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:306
void( IE_TCF)(void *userpointer)
Signature of a timeout caller.
Definition: indidevapi.h:330
double min
Definition: indiapi.h:228
int IUFindIndex(const char *needle, char **hay, unsigned int n)
Returns the index of the string in a string array.
Definition: indidriver.c:1936
void ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update data of an existing blob vector property.
Definition: dome.cpp:67
char label[MAXINDILABEL]
Definition: indiapi.h:182
void( TCF)(void *)
Signature of a timer function.
Definition: eventloop.h:44
void( WPF)(void *)
Signature of a work procedure function.
Definition: eventloop.h:39
char name[MAXINDINAME]
Definition: indiapi.h:200
Interface to the reference INDI C API device implementation on the Device Driver side.
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.c:144
void * aux1
Definition: indiapi.h:190
void 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)
Assign attributes for a BLOB vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:546
void * aux0
Definition: indiapi.h:232
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:136
ISState
Switch state.
Definition: indiapi.h:106
char name[MAXINDINAME]
Definition: indiapi.h:180
char label[MAXINDILABEL]
Definition: indiapi.h:226
void 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)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:460
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:439
A little DOM-style library to handle parsing and processing an XML file.
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indicom.c:1106
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.c:530
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *sp)
Returns the first ON switch it finds in the vector switch property.
Definition: indicom.c:1147
const char * sstateStr(ISState s)
Definition: indicom.c:1007
void 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)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:525
char timestamp[MAXINDITSTAMP]
Definition: indiapi.h:216
void IDDelete(const char *dev, const char *name, const char *fmt,...)
Function Drivers call to inform Clients a Property is no longer available, or the entire device is go...
Definition: indidriver.c:93
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:338
int to64frombits(unsigned char *out, const unsigned char *in, int inlen)
Convert bytes array to base64.
Definition: base64.c:56
char group[MAXINDIGROUP]
Definition: indiapi.h:387
Text vector property descriptor.
Definition: indiapi.h:196
void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char *dev, const char *name, const char *label, const char *group, IPState s)
Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:482
char name[MAXINDINAME]
Definition: indiapi.h:383
char device[MAXINDIDEVICE]
Definition: indiapi.h:293
void * aux
Definition: indiapi.h:326
void( CBF)(int fd, void *)
Signature of a callback function.
Definition: eventloop.h:34
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:387
int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Update all BLOB members in a BLOB vector property.
Definition: indidriver.c:330
ISRule
Switch vector rule hint.
Definition: indiapi.h:126
void IDDefSwitch(const ISwitchVectorProperty *s, const char *fmt,...)
Tell client to create a switch vector property.
Definition: indidriver.c:1525
char timestamp[MAXINDITSTAMP]
Definition: indiapi.h:272
char device[MAXINDIDEVICE]
Definition: indiapi.h:254
char group[MAXINDIGROUP]
Definition: indiapi.h:204
Implementations for common driver routines.
void IDDefText(const ITextVectorProperty *tvp, const char *fmt,...)
Tell client to create a text vector property.
Definition: indidriver.c:1398
void IUFillLight(ILight *lp, const char *name, const char *label, IPState s)
Assign attributes for a light property. The light's auxiliary elements will be set to NULL...
Definition: indidriver.c:382
double value
Definition: indiapi.h:230