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