Instrument Neutral Distributed Interface INDI  1.0.0
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  setlocale(LC_NUMERIC,"C");
594  for (i = 0; i < nvp->nnp; i++) {
595  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
596  if (!strcmp (tagXMLEle(ep)+3, "Number") &&
597  !strcmp (nvp->np[i].name, findXMLAttValu(ep, "name"))) {
598  if (f_scansexa (pcdataXMLEle(ep), &nvp->np[i].value) < 0) {
599  setlocale(LC_NUMERIC,"");
600  return (-1); /* bad number format */
601  }
602  break;
603  }
604  }
605  if (!ep) {
606  setlocale(LC_NUMERIC,"");
607  return (-1); /* element not found */
608  }
609  }
610  setlocale(LC_NUMERIC,"");
611 
612  /* ok */
613  return (0);
614 }
615 
616 /* crack the snooped driver setTextVector or defTextVector message into
617  * the given ITextVectorProperty.
618  * return 0 if type, device and name match and all members are present, else
619  * return -1
620  */
621 int
622 IUSnoopText (XMLEle *root, ITextVectorProperty *tvp)
623 {
624  char *dev, *name;
625  XMLEle *ep;
626  int i;
627 
628  /* check and crack type, device, name and state */
629  if (strcmp (tagXMLEle(root)+3, "TextVector") ||
630  crackDN (root, &dev, &name, NULL) < 0)
631  return (-1);
632  if (strcmp (dev, tvp->device) || strcmp (name, tvp->name))
633  return (-1); /* not this property */
634  (void) crackIPState (findXMLAttValu (root,"state"), &tvp->s);
635 
636  /* match each IText with a oneText */
637  for (i = 0; i < tvp->ntp; i++) {
638  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
639  if (!strcmp (tagXMLEle(ep)+3, "Text") &&
640  !strcmp (tvp->tp[i].name, findXMLAttValu(ep, "name"))) {
641  IUSaveText (&tvp->tp[i], pcdataXMLEle(ep));
642  break;
643  }
644  }
645  if (!ep)
646  return (-1); /* element not found */
647  }
648 
649  /* ok */
650  return (0);
651 }
652 
653 /* crack the snooped driver setLightVector or defLightVector message into
654  * the given ILightVectorProperty. it is not necessary that all ILight names
655  * be found.
656  * return 0 if type, device and name match, else return -1.
657  */
658 int
659 IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp)
660 {
661  char *dev, *name;
662  XMLEle *ep;
663  int i;
664 
665  /* check and crack type, device, name and state */
666  if (strcmp (tagXMLEle(root)+3, "LightVector") ||
667  crackDN (root, &dev, &name, NULL) < 0)
668  return (-1);
669  if (strcmp (dev, lvp->device) || strcmp (name, lvp->name))
670  return (-1); /* not this property */
671 
672  (void) crackIPState (findXMLAttValu (root,"state"), &lvp->s);
673 
674  /* match each oneLight with one ILight */
675  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
676  if (!strcmp (tagXMLEle(ep)+3, "Light")) {
677  const char *name = findXMLAttValu (ep, "name");
678  for (i = 0; i < lvp->nlp; i++) {
679  if (!strcmp (lvp->lp[i].name, name)) {
680  if (crackIPState(pcdataXMLEle(ep), &lvp->lp[i].s) < 0) {
681  return (-1); /* unrecognized state */
682  }
683  break;
684  }
685  }
686  }
687  }
688 
689  /* ok */
690  return (0);
691 }
692 
693 /* crack the snooped driver setSwitchVector or defSwitchVector message into the
694  * given ISwitchVectorProperty. it is not necessary that all ISwitch names be
695  * found.
696  * return 0 if type, device and name match, else return -1.
697  */
698 int
700 {
701  char *dev, *name;
702  XMLEle *ep;
703  int i;
704 
705  /* check and crack type, device, name and state */
706  if (strcmp (tagXMLEle(root)+3, "SwitchVector") ||
707  crackDN (root, &dev, &name, NULL) < 0)
708  return (-1);
709  if (strcmp (dev, svp->device) || strcmp (name, svp->name))
710  return (-1); /* not this property */
711  (void) crackIPState (findXMLAttValu (root,"state"), &svp->s);
712 
713  /* match each oneSwitch with one ISwitch */
714  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
715  if (!strcmp (tagXMLEle(ep)+3, "Switch")) {
716  const char *name = findXMLAttValu (ep, "name");
717  for (i = 0; i < svp->nsp; i++) {
718  if (!strcmp (svp->sp[i].name, name)) {
719  if (crackISState(pcdataXMLEle(ep), &svp->sp[i].s) < 0) {
720  return (-1); /* unrecognized state */
721  }
722  break;
723  }
724  }
725  }
726  }
727 
728  /* ok */
729  return (0);
730 }
731 
732 /* crack the snooped driver setBLOBVector message into the given
733  * IBLOBVectorProperty. it is not necessary that all IBLOB names be found.
734  * return 0 if type, device and name match, else return -1.
735  * N.B. we assume any existing blob in bvp has been malloced, which we free
736  * and replace with a newly malloced blob if found.
737  */
738 int
739 IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp)
740 {
741  char *dev, *name;
742  XMLEle *ep;
743  int i;
744 
745  /* check and crack type, device, name and state */
746  if (strcmp (tagXMLEle(root), "setBLOBVector") ||
747  crackDN (root, &dev, &name, NULL) < 0)
748  return (-1);
749  if (strcmp (dev, bvp->device) || strcmp (name, bvp->name))
750  return (-1); /* not this property */
751  (void) crackIPState (findXMLAttValu (root,"state"), &bvp->s);
752 
753  /* match each oneBLOB with one IBLOB */
754  for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
755  if (!strcmp (tagXMLEle(ep)+3, "BLOB")) {
756  const char *name = findXMLAttValu (ep, "name");
757  for (i = 0; i < bvp->nbp; i++) {
758  IBLOB *bp = &bvp->bp[i];
759  if (!strcmp (bp->name, name)) {
760  strcpy (bp->format, findXMLAttValu (ep,"format"));
761  bp->size = atof (findXMLAttValu (ep,"size"));
762  bp->bloblen = pcdatalenXMLEle(ep)+1;
763  if (bp->blob)
764  free (bp->blob);
765  bp->blob = strcpy(malloc(bp->bloblen),pcdataXMLEle(ep));
766  break;
767  }
768  }
769  }
770  }
771 
772  /* ok */
773  return (0);
774 }
775 
776 /* callback when INDI client message arrives on stdin.
777  * collect and dispatch when see outter element closure.
778  * exit if OS trouble or see incompatable INDI version.
779  * arg is not used.
780  */
781 void
782 clientMsgCB (int fd, void *arg)
783 {
784  char buf[1024], msg[1024], *bp;
785  int nr;
786  arg=arg;
787 
788  /* one read */
789  nr = read (fd, buf, sizeof(buf));
790  if (nr < 0) {
791  fprintf (stderr, "%s: %s\n", me, strerror(errno));
792  exit(1);
793  }
794  if (nr == 0) {
795  fprintf (stderr, "%s: EOF\n", me);
796  exit(1);
797  }
798 
799  /* crack and dispatch when complete */
800  for (bp = buf; nr-- > 0; bp++) {
801  XMLEle *root = readXMLEle (clixml, *bp, msg);
802  if (root) {
803  if (dispatch (root, msg) < 0)
804  fprintf (stderr, "%s dispatch error: %s\n", me, msg);
805  delXMLEle (root);
806  } else if (msg[0])
807  fprintf (stderr, "%s XML error: %s\n", me, msg);
808  }
809 
810 }
811 
812 /* crack the given INDI XML element and call driver's IS* entry points as they
813  * are recognized.
814  * return 0 if ok else -1 with reason in msg[].
815  * N.B. exit if getProperties does not proclaim a compatible version.
816  */
817 int
818 dispatch (XMLEle *root, char msg[])
819 {
820 
821 
822  char *rtag = tagXMLEle(root);
823  XMLEle *ep;
824  int n,i=0;
825 
826  if (verbose)
827  prXMLEle (stderr, root, 0);
828 
829  /* check tag in surmised decreasing order of likelyhood */
830 
831  if (!strcmp (rtag, "newNumberVector")) {
832  static double *doubles;
833  static char **names;
834  static int maxn;
835  char *dev, *name;
836 
837  /* pull out device and name */
838  if (crackDN (root, &dev, &name, msg) < 0)
839  return (-1);
840 
841  if (!isPropDefined(name))
842  return -1;
843 
844  /* ensure property is not RO */
845  for (i=0; i < nroCheck; i++)
846  {
847  if (!strcmp(roCheck[i].propName, name))
848  {
849  if (roCheck[i].perm == IP_RO)
850  return -1;
851  else
852  break;
853  }
854  }
855 
856  /* seed for reallocs */
857  if (!doubles) {
858  doubles = (double *) malloc (1);
859  names = (char **) malloc (1);
860  }
861 
862  /* pull out each name/value pair */
863  setlocale(LC_NUMERIC,"C");
864  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
865  if (strcmp (tagXMLEle(ep), "oneNumber") == 0) {
866  XMLAtt *na = findXMLAtt (ep, "name");
867  if (na) {
868  if (n >= maxn) {
869  /* grow for this and another */
870  int newsz = (maxn=n+1)*sizeof(double);
871  doubles = (double *) realloc(doubles,newsz);
872  newsz = maxn*sizeof(char *);
873  names = (char **) realloc (names, newsz);
874  }
875  if (f_scansexa (pcdataXMLEle(ep), &doubles[n]) < 0)
876  IDMessage (dev,"%s: Bad format %s", name,
877  pcdataXMLEle(ep));
878  else
879  names[n++] = valuXMLAtt(na);
880  }
881  }
882  }
883  setlocale(LC_NUMERIC,"");
884 
885  /* invoke driver if something to do, but not an error if not */
886  if (n > 0)
887  ISNewNumber (dev, name, doubles, names, n);
888  else
889  IDMessage(dev,"%s: newNumberVector with no valid members",name);
890  return (0);
891  }
892 
893  if (!strcmp (rtag, "newSwitchVector")) {
894  static ISState *states;
895  static char **names;
896  static int maxn;
897  char *dev, *name;
898  XMLEle *ep;
899 
900  /* pull out device and name */
901  if (crackDN (root, &dev, &name, msg) < 0)
902  return (-1);
903 
904  if (!isPropDefined(name))
905  return -1;
906 
907  /* ensure property is not RO */
908  for (i=0; i < nroCheck; i++)
909  {
910  if (!strcmp(roCheck[i].propName, name))
911  {
912  if (roCheck[i].perm == IP_RO)
913  return -1;
914  else
915  break;
916  }
917  }
918 
919  /* seed for reallocs */
920  if (!states) {
921  states = (ISState *) malloc (1);
922  names = (char **) malloc (1);
923  }
924 
925  /* pull out each name/state pair */
926  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
927  if (strcmp (tagXMLEle(ep), "oneSwitch") == 0) {
928  XMLAtt *na = findXMLAtt (ep, "name");
929  if (na) {
930  if (n >= maxn) {
931  int newsz = (maxn=n+1)*sizeof(ISState);
932  states = (ISState *) realloc(states, newsz);
933  newsz = maxn*sizeof(char *);
934  names = (char **) realloc (names, newsz);
935  }
936  if (strcmp (pcdataXMLEle(ep),"On") == 0) {
937  states[n] = ISS_ON;
938  names[n] = valuXMLAtt(na);
939  n++;
940  } else if (strcmp (pcdataXMLEle(ep),"Off") == 0) {
941  states[n] = ISS_OFF;
942  names[n] = valuXMLAtt(na);
943  n++;
944  } else
945  IDMessage (dev, "%s: must be On or Off: %s", name,
946  pcdataXMLEle(ep));
947  }
948  }
949  }
950 
951  /* invoke driver if something to do, but not an error if not */
952  if (n > 0)
953  ISNewSwitch (dev, name, states, names, n);
954  else
955  IDMessage(dev,"%s: newSwitchVector with no valid members",name);
956  return (0);
957  }
958 
959  if (!strcmp (rtag, "newTextVector")) {
960  static char **texts;
961  static char **names;
962  static int maxn;
963  char *dev, *name;
964 
965  /* pull out device and name */
966  if (crackDN (root, &dev, &name, msg) < 0)
967  return (-1);
968 
969  if (!isPropDefined(name))
970  return -1;
971 
972  /* ensure property is not RO */
973  for (i=0; i < nroCheck; i++)
974  {
975  if (!strcmp(roCheck[i].propName, name))
976  {
977  if (roCheck[i].perm == IP_RO)
978  return -1;
979  else
980  break;
981  }
982  }
983 
984  /* seed for reallocs */
985  if (!texts) {
986  texts = (char **) malloc (1);
987  names = (char **) malloc (1);
988  }
989 
990  /* pull out each name/text pair */
991  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
992  if (strcmp (tagXMLEle(ep), "oneText") == 0) {
993  XMLAtt *na = findXMLAtt (ep, "name");
994  if (na) {
995  if (n >= maxn) {
996  int newsz = (maxn=n+1)*sizeof(char *);
997  texts = (char **) realloc (texts, newsz);
998  names = (char **) realloc (names, newsz);
999  }
1000  texts[n] = pcdataXMLEle(ep);
1001  names[n] = valuXMLAtt(na);
1002  n++;
1003  }
1004  }
1005  }
1006 
1007  /* invoke driver if something to do, but not an error if not */
1008  if (n > 0)
1009  ISNewText (dev, name, texts, names, n);
1010  else
1011  IDMessage (dev, "%s: set with no valid members", name);
1012  return (0);
1013  }
1014 
1015  if (!strcmp (rtag, "newBLOBVector")) {
1016  static char **blobs;
1017  static char **names;
1018  static char **formats;
1019  static int *blobsizes;
1020  static int *sizes;
1021  static int maxn;
1022  char *dev, *name;
1023  int i;
1024 
1025  /* pull out device and name */
1026  if (crackDN (root, &dev, &name, msg) < 0)
1027  return (-1);
1028 
1029  if (!isPropDefined(name))
1030  return -1;
1031 
1032  /* seed for reallocs */
1033  if (!blobs) {
1034  blobs = (char **) malloc (1);
1035  names = (char **) malloc (1);
1036  formats = (char **) malloc (1);
1037  blobsizes = (int *) malloc (1);
1038  sizes = (int *) malloc (1);
1039  }
1040 
1041  /* pull out each name/BLOB pair, decode */
1042  for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
1043  if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) {
1044  XMLAtt *na = findXMLAtt (ep, "name");
1045  XMLAtt *fa = findXMLAtt (ep, "format");
1046  XMLAtt *sa = findXMLAtt (ep, "size");
1047  if (na && fa && sa) {
1048  if (n >= maxn) {
1049  int newsz = (maxn=n+1)*sizeof(char *);
1050  blobs = (char **) realloc (blobs, newsz);
1051  names = (char **) realloc (names, newsz);
1052  formats = (char **) realloc(formats,newsz);
1053  newsz = maxn*sizeof(int);
1054  sizes = (int *) realloc(sizes,newsz);
1055  blobsizes = (int *) realloc(blobsizes,newsz);
1056  }
1057  blobs[n] = malloc (3*pcdatalenXMLEle(ep)/4);
1058  blobsizes[n] = from64tobits(blobs[n], pcdataXMLEle(ep));
1059  names[n] = valuXMLAtt(na);
1060  formats[n] = valuXMLAtt(fa);
1061  sizes[n] = atoi(valuXMLAtt(sa));
1062  n++;
1063  }
1064  }
1065  }
1066 
1067  /* invoke driver if something to do, but not an error if not */
1068  if (n > 0) {
1069  ISNewBLOB (dev, name, sizes, blobsizes, blobs, formats,names,n);
1070  for (i = 0; i < n; i++)
1071  free (blobs[i]);
1072  } else
1073  IDMessage (dev, "%s: newBLOBVector with no valid members",name);
1074  return (0);
1075  }
1076 
1077  if (!strcmp (rtag, "getProperties")) {
1078  XMLAtt *ap;
1079  double v;
1080 
1081  /* check version */
1082  ap = findXMLAtt (root, "version");
1083  if (!ap) {
1084  fprintf (stderr, "%s: getProperties missing version\n", me);
1085  exit(1);
1086  }
1087  v = atof (valuXMLAtt(ap));
1088  if (v > INDIV) {
1089  fprintf (stderr, "%s: client version %g > %g\n", me, v, INDIV);
1090  exit(1);
1091  }
1092 
1093  /* ok */
1094  ap = findXMLAtt (root, "device");
1095  ISGetProperties (ap ? valuXMLAtt(ap) : NULL);
1096  return (0);
1097  }
1098 
1099  /* other commands might be from a snooped device.
1100  * we don't know here which devices are being snooped so we send
1101  * all remaining valid messages
1102  */
1103  if ( !strcmp (rtag, "setNumberVector") ||
1104  !strcmp (rtag, "setTextVector") ||
1105  !strcmp (rtag, "setLightVector") ||
1106  !strcmp (rtag, "setSwitchVector") ||
1107  !strcmp (rtag, "setBLOBVector") ||
1108  !strcmp (rtag, "defNumberVector") ||
1109  !strcmp (rtag, "defTextVector") ||
1110  !strcmp (rtag, "defLightVector") ||
1111  !strcmp (rtag, "defSwitchVector") ||
1112  !strcmp (rtag, "defBLOBVector") ||
1113  !strcmp (rtag, "message") ||
1114  !strcmp (rtag, "delProperty")) {
1115  ISSnoopDevice (root);
1116  return (0);
1117  }
1118 
1119  sprintf (msg, "Unknown command: %s", rtag);
1120  return(1);
1121 }
1122 
1123 int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
1124 {
1125  char configFileName[MAXRBUF];
1126  char *rname, *rdev;
1127  XMLEle *root = NULL, *fproot = NULL;
1128  LilXML *lp = newLilXML();
1129 
1130  FILE *fp = NULL;
1131 
1132  if (filename)
1133  strncpy(configFileName, filename, MAXRBUF);
1134  else
1135  {
1136  if (getenv("INDICONFIG"))
1137  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1138  else
1139  snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
1140 
1141  }
1142 
1143  fp = fopen(configFileName, "r");
1144  if (fp == NULL)
1145  {
1146  snprintf(errmsg, MAXRBUF, "Unable to read user config file. Error loading file %s: %s\n", configFileName, strerror(errno));
1147  return -1;
1148  }
1149 
1150  fproot = readXMLFile(fp, lp, errmsg);
1151 
1152  if (fproot == NULL)
1153  {
1154  snprintf(errmsg, MAXRBUF, "Unable to parse config XML: %s", errmsg);
1155  fclose(fp);
1156  return -1;
1157  }
1158 
1159  if (nXMLEle(fproot) > 0 && silent != 1)
1160  IDMessage(dev, "Loading device configuration...");
1161 
1162  for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0))
1163  {
1164 
1165  /* pull out device and name */
1166  if (crackDN (root, &rdev, &rname, errmsg) < 0)
1167  {
1168  fclose(fp);
1169  return -1;
1170  }
1171 
1172  // It doesn't belong to our device??
1173  if (strcmp(dev, rdev))
1174  continue;
1175 
1176  if ( (property && !strcmp(property, rname)) || property == NULL)
1177  dispatch(root, errmsg);
1178 
1179  }
1180 
1181  if (nXMLEle(fproot) > 0 && silent != 1)
1182  IDMessage(dev, "Device configuration applied.");
1183 
1184  fclose(fp);
1185  delXMLEle(fproot);
1186  delXMLEle(root);
1187  delLilXML(lp);
1188 
1189  return (0);
1190 
1191 }
1192 
1193 
1194 void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
1195 {
1196 
1197  char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF];
1198 
1199  if (source_config)
1200  strncpy(configFileName, source_config, MAXRBUF);
1201  else
1202  {
1203  if (getenv("INDICONFIG"))
1204  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1205  else
1206  snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
1207 
1208  }
1209 
1210  if (dest_config)
1211  strncpy(configDefaultFileName, dest_config, MAXRBUF);
1212  else if (getenv("INDICONFIG"))
1213  snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
1214  else
1215  snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), dev);
1216 
1217  // If the default doesn't exist, create it.
1218  if (access(configDefaultFileName, F_OK))
1219  {
1220  FILE *fpin = fopen(configFileName, "r");
1221  if(fpin != NULL)
1222  {
1223  FILE *fpout = fopen(configDefaultFileName, "w");
1224  if(fpout != NULL)
1225  {
1226  int ch = 0;
1227  while((ch = getc(fpin)) != EOF)
1228  putc(ch, fpout);
1229 
1230  fclose(fpin);
1231  }
1232  fclose(fpout);
1233  }
1234  }
1235 
1236 }
1237 
1238 
1239 
1240 
1241 /* send client a message for a specific device or at large if !dev */
1242 void
1243 IDMessage (const char *dev, const char *fmt, ...)
1244 {
1245 
1246  pthread_mutex_lock(&stdout_mutex);
1247 
1248  xmlv1();
1249  printf ("<message\n");
1250  if (dev)
1251  printf (" device='%s'\n", dev);
1252  printf (" timestamp='%s'\n", timestamp());
1253  if (fmt) {
1254  va_list ap;
1255  va_start (ap, fmt);
1256  printf (" message='");
1257  vprintf (fmt, ap);
1258  printf ("'\n");
1259  va_end (ap);
1260  }
1261  printf ("/>\n");
1262  fflush (stdout);
1263 
1264  pthread_mutex_unlock(&stdout_mutex);
1265 }
1266 
1267 FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[])
1268 {
1269  char configFileName[MAXRBUF];
1270  char configDir[MAXRBUF];
1271  struct stat st;
1272  FILE *fp = NULL;
1273 
1274  snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
1275 
1276  if (filename)
1277  strncpy(configFileName, filename, MAXRBUF);
1278  else
1279  {
1280  if (getenv("INDICONFIG"))
1281  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1282  else
1283  snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1284 
1285  }
1286 
1287  if(stat(configDir,&st) != 0)
1288  {
1289  if (mkdir(configDir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0)
1290  {
1291  snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s\n", configDir, strerror(errno));
1292  return NULL;
1293  }
1294  }
1295 
1296  fp = fopen(configFileName, "w");
1297  if (fp == NULL)
1298  {
1299  snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s\n", configFileName, strerror(errno));
1300  return NULL;
1301  }
1302 
1303  return fp;
1304 }
1305 
1306 void IUSaveConfigTag(FILE *fp, int ctag, const char * dev, int silent)
1307 {
1308  if (!fp)
1309  return;
1310 
1311  /* Opening tag */
1312  if (ctag == 0)
1313  {
1314  fprintf(fp, "<INDIDriver>\n");
1315  if (silent != 1)
1316  IDMessage(dev, "Saving device configuration...");
1317  }
1318  /* Closing tag */
1319  else
1320  {
1321  fprintf(fp, "</INDIDriver>\n");
1322  if (silent != 1)
1323  IDMessage(dev, "Device configuration saved.");
1324  }
1325 }
1326 
1327 void IUSaveConfigNumber (FILE *fp, const INumberVectorProperty *nvp)
1328 {
1329  int i;
1330 
1331  setlocale(LC_NUMERIC,"C");
1332  fprintf (fp, "<newNumberVector device='%s' name='%s'>\n", nvp->device, nvp->name);
1333 
1334  for (i = 0; i < nvp->nnp; i++)
1335  {
1336  INumber *np = &nvp->np[i];
1337  fprintf (fp, " <oneNumber name='%s'>\n", np->name);
1338  fprintf (fp, " %.20g\n", np->value);
1339  fprintf (fp, " </oneNumber>\n");
1340  }
1341 
1342  fprintf (fp, "</newNumberVector>\n");
1343  setlocale(LC_NUMERIC,"");
1344 }
1345 
1346 void IUSaveConfigText (FILE *fp, const ITextVectorProperty *tvp)
1347 {
1348  int i;
1349 
1350  fprintf (fp, "<newTextVector device='%s' name='%s'>\n", tvp->device, tvp->name);
1351 
1352  for (i = 0; i < tvp->ntp; i++)
1353  {
1354  IText *tp = &tvp->tp[i];
1355  fprintf (fp, " <oneText name='%s'>\n", tp->name);
1356  fprintf (fp, " %s\n", tp->text ? tp->text : "");
1357  fprintf (fp, " </oneText>\n");
1358  }
1359 
1360  fprintf (fp, "</newTextVector>\n");
1361 
1362 }
1363 
1364 void IUSaveConfigSwitch (FILE *fp, const ISwitchVectorProperty *svp)
1365 {
1366  int i;
1367 
1368  fprintf (fp, "<newSwitchVector device='%s' name='%s'>\n", svp->device, svp->name);
1369 
1370  for (i = 0; i < svp->nsp; i++)
1371  {
1372  ISwitch *sp = &svp->sp[i];
1373  fprintf (fp, " <oneSwitch name='%s'>\n", sp->name);
1374  fprintf (fp, " %s\n", sstateStr(sp->s));
1375  fprintf (fp, " </oneSwitch>\n");
1376  }
1377 
1378  fprintf (fp, "</newSwitchVector>\n");
1379 
1380 }
1381 
1382 void IUSaveConfigBLOB (FILE *fp, const IBLOBVectorProperty *bvp)
1383 {
1384  int i;
1385 
1386  fprintf (fp, "<newBLOBVector device='%s' name='%s'>\n", bvp->device, bvp->name);
1387 
1388  for (i = 0; i < bvp->nbp; i++)
1389  {
1390  IBLOB *bp = &bvp->bp[i];
1391  unsigned char *encblob;
1392  int j, l;
1393 
1394  fprintf (fp, " <oneBLOB\n");
1395  fprintf (fp, " name='%s'\n", bp->name);
1396  fprintf (fp, " size='%d'\n", bp->size);
1397  fprintf (fp, " format='%s'>\n", bp->format);
1398 
1399  encblob = malloc (4*bp->bloblen/3+4);
1400  l = to64frombits(encblob, bp->blob, bp->bloblen);
1401  for (j = 0; j < l; j += 72)
1402  fprintf (fp, "%.72s\n", encblob+j);
1403  free (encblob);
1404 
1405  fprintf (fp, " </oneBLOB>\n");
1406  }
1407 
1408  fprintf (fp, "</newBLOBVector>\n");
1409 
1410 }
1411 
1412 /* tell client to create a text vector property */
1413 void
1414 IDDefText (const ITextVectorProperty *tvp, const char *fmt, ...)
1415 {
1416  int i;
1417  ROSC *SC;
1418 
1419  pthread_mutex_lock(&stdout_mutex);
1420 
1421  xmlv1();
1422  setlocale(LC_NUMERIC,"C");
1423  printf ("<defTextVector\n");
1424  printf (" device='%s'\n", tvp->device);
1425  printf (" name='%s'\n", tvp->name);
1426  printf (" label='%s'\n", tvp->label);
1427  printf (" group='%s'\n", tvp->group);
1428  printf (" state='%s'\n", pstateStr(tvp->s));
1429  printf (" perm='%s'\n", permStr(tvp->p));
1430  printf (" timeout='%g'\n", tvp->timeout);
1431  printf (" timestamp='%s'\n", timestamp());
1432  if (fmt) {
1433  va_list ap;
1434  va_start (ap, fmt);
1435  printf (" message='");
1436  vprintf (fmt, ap);
1437  printf ("'\n");
1438  va_end (ap);
1439  }
1440  printf (">\n");
1441 
1442  for (i = 0; i < tvp->ntp; i++) {
1443  IText *tp = &tvp->tp[i];
1444  printf (" <defText\n");
1445  printf (" name='%s'\n", tp->name);
1446  printf (" label='%s'>\n", tp->label);
1447  printf (" %s\n", tp->text ? tp->text : "");
1448  printf (" </defText>\n");
1449  }
1450 
1451  printf ("</defTextVector>\n");
1452 
1453  if (!isPropDefined(tvp->name))
1454  {
1455  /* Add this property to insure proper sanity check */
1456  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1457  : (ROSC *) malloc ( sizeof(ROSC));
1458  SC = &roCheck[nroCheck++];
1459 
1460  strcpy(SC->propName, tvp->name);
1461  SC->perm = tvp->p;
1462  }
1463 
1464  setlocale(LC_NUMERIC,"");
1465  fflush (stdout);
1466 
1467  pthread_mutex_unlock(&stdout_mutex);
1468 }
1469 
1470 /* tell client to create a new numeric vector property */
1471 void
1472 IDDefNumber (const INumberVectorProperty *n, const char *fmt, ...)
1473 {
1474  int i;
1475  ROSC *SC;
1476 
1477  pthread_mutex_lock(&stdout_mutex);
1478 
1479  xmlv1();
1480  setlocale(LC_NUMERIC,"C");
1481  printf ("<defNumberVector\n");
1482  printf (" device='%s'\n", n->device);
1483  printf (" name='%s'\n", n->name);
1484  printf (" label='%s'\n", n->label);
1485  printf (" group='%s'\n", n->group);
1486  printf (" state='%s'\n", pstateStr(n->s));
1487  printf (" perm='%s'\n", permStr(n->p));
1488  printf (" timeout='%g'\n", n->timeout);
1489  printf (" timestamp='%s'\n", timestamp());
1490 
1491 
1492  if (fmt) {
1493  va_list ap;
1494  va_start (ap, fmt);
1495  printf (" message='");
1496  vprintf (fmt, ap);
1497  printf ("'\n");
1498  va_end (ap);
1499  }
1500  printf (">\n");
1501 
1502 
1503  for (i = 0; i < n->nnp; i++) {
1504 
1505  INumber *np = &n->np[i];
1506 
1507  printf (" <defNumber\n");
1508  printf (" name='%s'\n", np->name);
1509  printf (" label='%s'\n", np->label);
1510  printf (" format='%s'\n", np->format);
1511  printf (" min='%.20g'\n", np->min);
1512  printf (" max='%.20g'\n", np->max);
1513  printf (" step='%.20g'>\n", np->step);
1514  printf (" %.20g\n", np->value);
1515 
1516  printf (" </defNumber>\n");
1517  }
1518 
1519  printf ("</defNumberVector>\n");
1520 
1521  if (!isPropDefined(n->name))
1522  {
1523  /* Add this property to insure proper sanity check */
1524  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1525  : (ROSC *) malloc ( sizeof(ROSC));
1526  SC = &roCheck[nroCheck++];
1527 
1528  strcpy(SC->propName, n->name);
1529  SC->perm = n->p;
1530 
1531  }
1532 
1533  setlocale(LC_NUMERIC,"");
1534  fflush (stdout);
1535 
1536  pthread_mutex_unlock(&stdout_mutex);
1537 }
1538 
1539 /* tell client to create a new switch vector property */
1540 void
1541 IDDefSwitch (const ISwitchVectorProperty *s, const char *fmt, ...)
1542 
1543 {
1544  int i;
1545  ROSC *SC;
1546 
1547  pthread_mutex_lock(&stdout_mutex);
1548 
1549  xmlv1();
1550  setlocale(LC_NUMERIC,"C");
1551  printf ("<defSwitchVector\n");
1552  printf (" device='%s'\n", s->device);
1553  printf (" name='%s'\n", s->name);
1554  printf (" label='%s'\n", s->label);
1555  printf (" group='%s'\n", s->group);
1556  printf (" state='%s'\n", pstateStr(s->s));
1557  printf (" perm='%s'\n", permStr(s->p));
1558  printf (" rule='%s'\n", ruleStr (s->r));
1559  printf (" timeout='%g'\n", s->timeout);
1560  printf (" timestamp='%s'\n", timestamp());
1561  if (fmt) {
1562  va_list ap;
1563  va_start (ap, fmt);
1564  printf (" message='");
1565  vprintf (fmt, ap);
1566  printf ("'\n");
1567  va_end (ap);
1568  }
1569  printf (">\n");
1570 
1571  for (i = 0; i < s->nsp; i++) {
1572  ISwitch *sp = &s->sp[i];
1573  printf (" <defSwitch\n");
1574  printf (" name='%s'\n", sp->name);
1575  printf (" label='%s'>\n", sp->label);
1576  printf (" %s\n", sstateStr(sp->s));
1577  printf (" </defSwitch>\n");
1578  }
1579 
1580  printf ("</defSwitchVector>\n");
1581 
1582  if (!isPropDefined(s->name))
1583  {
1584  /* Add this property to insure proper sanity check */
1585  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1586  : (ROSC *) malloc ( sizeof(ROSC));
1587  SC = &roCheck[nroCheck++];
1588 
1589  strcpy(SC->propName, s->name);
1590  SC->perm = s->p;
1591  }
1592 
1593  setlocale(LC_NUMERIC,"");
1594  fflush (stdout);
1595 
1596  pthread_mutex_unlock(&stdout_mutex);
1597 }
1598 
1599 /* tell client to create a new lights vector property */
1600 void
1601 IDDefLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1602 {
1603  int i;
1604 
1605  pthread_mutex_lock(&stdout_mutex);
1606 
1607  xmlv1();
1608  printf ("<defLightVector\n");
1609  printf (" device='%s'\n", lvp->device);
1610  printf (" name='%s'\n", lvp->name);
1611  printf (" label='%s'\n", lvp->label);
1612  printf (" group='%s'\n", lvp->group);
1613  printf (" state='%s'\n", pstateStr(lvp->s));
1614  printf (" timestamp='%s'\n", timestamp());
1615  if (fmt) {
1616  va_list ap;
1617  va_start (ap, fmt);
1618  printf (" message='");
1619  vprintf (fmt, ap);
1620  printf ("'\n");
1621  va_end (ap);
1622  }
1623  printf (">\n");
1624 
1625  for (i = 0; i < lvp->nlp; i++) {
1626  ILight *lp = &lvp->lp[i];
1627  printf (" <defLight\n");
1628  printf (" name='%s'\n", lp->name);
1629  printf (" label='%s'>\n", lp->label);
1630  printf (" %s\n", pstateStr(lp->s));
1631  printf (" </defLight>\n");
1632  }
1633 
1634  printf ("</defLightVector>\n");
1635  fflush (stdout);
1636 
1637  pthread_mutex_unlock(&stdout_mutex);
1638 }
1639 
1640 /* tell client to create a new BLOB vector property */
1641 void
1642 IDDefBLOB (const IBLOBVectorProperty *b, const char *fmt, ...)
1643 {
1644  int i;
1645  ROSC *SC;
1646 
1647  pthread_mutex_lock(&stdout_mutex);
1648 
1649  xmlv1();
1650  setlocale(LC_NUMERIC,"C");
1651  printf ("<defBLOBVector\n");
1652  printf (" device='%s'\n", b->device);
1653  printf (" name='%s'\n", b->name);
1654  printf (" label='%s'\n", b->label);
1655  printf (" group='%s'\n", b->group);
1656  printf (" state='%s'\n", pstateStr(b->s));
1657  printf (" perm='%s'\n", permStr(b->p));
1658  printf (" timeout='%g'\n", b->timeout);
1659  printf (" timestamp='%s'\n", timestamp());
1660  if (fmt) {
1661  va_list ap;
1662  va_start (ap, fmt);
1663  printf (" message='");
1664  vprintf (fmt, ap);
1665  printf ("'\n");
1666  va_end (ap);
1667  }
1668  printf (">\n");
1669 
1670  for (i = 0; i < b->nbp; i++) {
1671  IBLOB *bp = &b->bp[i];
1672  printf (" <defBLOB\n");
1673  printf (" name='%s'\n", bp->name);
1674  printf (" label='%s'\n", bp->label);
1675  printf (" />\n");
1676  }
1677 
1678  printf ("</defBLOBVector>\n");
1679 
1680  if (!isPropDefined(b->name))
1681  {
1682  /* Add this property to insure proper sanity check */
1683  roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
1684  : (ROSC *) malloc ( sizeof(ROSC));
1685  SC = &roCheck[nroCheck++];
1686 
1687  strcpy(SC->propName, b->name);
1688  SC->perm = b->p;
1689  }
1690 
1691  setlocale(LC_NUMERIC,"");
1692  fflush (stdout);
1693 
1694  pthread_mutex_unlock(&stdout_mutex);
1695 }
1696 
1697 /* tell client to update an existing text vector property */
1698 void
1699 IDSetText (const ITextVectorProperty *tvp, const char *fmt, ...)
1700 {
1701  int i;
1702 
1703  pthread_mutex_lock(&stdout_mutex);
1704 
1705  xmlv1();
1706  setlocale(LC_NUMERIC,"C");
1707  printf ("<setTextVector\n");
1708  printf (" device='%s'\n", tvp->device);
1709  printf (" name='%s'\n", tvp->name);
1710  printf (" state='%s'\n", pstateStr(tvp->s));
1711  printf (" timeout='%g'\n", tvp->timeout);
1712  printf (" timestamp='%s'\n", timestamp());
1713  if (fmt) {
1714  va_list ap;
1715  va_start (ap, fmt);
1716  printf (" message='");
1717  vprintf (fmt, ap);
1718  printf ("'\n");
1719  va_end (ap);
1720  }
1721  printf (">\n");
1722 
1723  for (i = 0; i < tvp->ntp; i++) {
1724  IText *tp = &tvp->tp[i];
1725  printf (" <oneText name='%s'>\n", tp->name);
1726  printf (" %s\n", tp->text ? tp->text : "");
1727  printf (" </oneText>\n");
1728  }
1729 
1730  printf ("</setTextVector>\n");
1731  setlocale(LC_NUMERIC,"");
1732  fflush (stdout);
1733 
1734  pthread_mutex_unlock(&stdout_mutex);
1735 }
1736 
1737 /* tell client to update an existing numeric vector property */
1738 void
1739 IDSetNumber (const INumberVectorProperty *nvp, const char *fmt, ...)
1740 {
1741  int i;
1742 
1743  pthread_mutex_lock(&stdout_mutex);
1744 
1745  xmlv1();
1746  setlocale(LC_NUMERIC,"C");
1747  printf ("<setNumberVector\n");
1748  printf (" device='%s'\n", nvp->device);
1749  printf (" name='%s'\n", nvp->name);
1750  printf (" state='%s'\n", pstateStr(nvp->s));
1751  printf (" timeout='%g'\n", nvp->timeout);
1752  printf (" timestamp='%s'\n", timestamp());
1753  if (fmt) {
1754  va_list ap;
1755  va_start (ap, fmt);
1756  printf (" message='");
1757  vprintf (fmt, ap);
1758  printf ("'\n");
1759  va_end (ap);
1760  }
1761  printf (">\n");
1762 
1763  for (i = 0; i < nvp->nnp; i++) {
1764  INumber *np = &nvp->np[i];
1765  printf (" <oneNumber name='%s'>\n", np->name);
1766  printf (" %.20g\n", np->value);
1767  printf (" </oneNumber>\n");
1768  }
1769 
1770  printf ("</setNumberVector>\n");
1771  setlocale(LC_NUMERIC,"");
1772  fflush (stdout);
1773 
1774  pthread_mutex_unlock(&stdout_mutex);
1775 }
1776 
1777 /* tell client to update an existing switch vector property */
1778 void
1779 IDSetSwitch (const ISwitchVectorProperty *svp, const char *fmt, ...)
1780 {
1781  int i;
1782 
1783  pthread_mutex_lock(&stdout_mutex);
1784 
1785  xmlv1();
1786  setlocale(LC_NUMERIC,"C");
1787  printf ("<setSwitchVector\n");
1788  printf (" device='%s'\n", svp->device);
1789  printf (" name='%s'\n", svp->name);
1790  printf (" state='%s'\n", pstateStr(svp->s));
1791  printf (" timeout='%g'\n", svp->timeout);
1792  printf (" timestamp='%s'\n", timestamp());
1793  if (fmt) {
1794  va_list ap;
1795  va_start (ap, fmt);
1796  printf (" message='");
1797  vprintf (fmt, ap);
1798  printf ("'\n");
1799  va_end (ap);
1800  }
1801  printf (">\n");
1802 
1803  for (i = 0; i < svp->nsp; i++) {
1804  ISwitch *sp = &svp->sp[i];
1805  printf (" <oneSwitch name='%s'>\n", sp->name);
1806  printf (" %s\n", sstateStr(sp->s));
1807  printf (" </oneSwitch>\n");
1808  }
1809 
1810  printf ("</setSwitchVector>\n");
1811  setlocale(LC_NUMERIC,"");
1812  fflush (stdout);
1813 
1814  pthread_mutex_unlock(&stdout_mutex);
1815 }
1816 
1817 /* tell client to update an existing lights vector property */
1818 void
1819 IDSetLight (const ILightVectorProperty *lvp, const char *fmt, ...)
1820 {
1821  int i;
1822 
1823  pthread_mutex_lock(&stdout_mutex);
1824 
1825  xmlv1();
1826  printf ("<setLightVector\n");
1827  printf (" device='%s'\n", lvp->device);
1828  printf (" name='%s'\n", lvp->name);
1829  printf (" state='%s'\n", pstateStr(lvp->s));
1830  printf (" timestamp='%s'\n", timestamp());
1831  if (fmt) {
1832  va_list ap;
1833  va_start (ap, fmt);
1834  printf (" message='");
1835  vprintf (fmt, ap);
1836  printf ("'\n");
1837  va_end (ap);
1838  }
1839  printf (">\n");
1840 
1841  for (i = 0; i < lvp->nlp; i++) {
1842  ILight *lp = &lvp->lp[i];
1843  printf (" <oneLight name='%s'>\n", lp->name);
1844  printf (" %s\n", pstateStr(lp->s));
1845  printf (" </oneLight>\n");
1846  }
1847 
1848  printf ("</setLightVector>\n");
1849  fflush (stdout);
1850 
1851  pthread_mutex_unlock(&stdout_mutex);
1852 }
1853 
1854 /* tell client to update an existing BLOB vector property */
1855 void
1856 IDSetBLOB (const IBLOBVectorProperty *bvp, const char *fmt, ...)
1857 {
1858  int i;
1859 
1860  pthread_mutex_lock(&stdout_mutex);
1861 
1862  xmlv1();
1863  setlocale(LC_NUMERIC,"C");
1864  printf ("<setBLOBVector\n");
1865  printf (" device='%s'\n", bvp->device);
1866  printf (" name='%s'\n", bvp->name);
1867  printf (" state='%s'\n", pstateStr(bvp->s));
1868  printf (" timeout='%g'\n", bvp->timeout);
1869  printf (" timestamp='%s'\n", timestamp());
1870  if (fmt) {
1871  va_list ap;
1872  va_start (ap, fmt);
1873  printf (" message='");
1874  vprintf (fmt, ap);
1875  printf ("'\n");
1876  va_end (ap);
1877  }
1878  printf (">\n");
1879 
1880  for (i = 0; i < bvp->nbp; i++) {
1881  IBLOB *bp = &bvp->bp[i];
1882  unsigned char *encblob;
1883  int j, l;
1884 
1885  printf (" <oneBLOB\n");
1886  printf (" name='%s'\n", bp->name);
1887  printf (" size='%d'\n", bp->size);
1888  printf (" format='%s'>\n", bp->format);
1889 
1890  encblob = malloc (4*bp->bloblen/3+4);
1891  l = to64frombits(encblob, bp->blob, bp->bloblen);
1892  for (j = 0; j < l; j += 72)
1893  printf ("%.72s\n", encblob+j);
1894  free (encblob);
1895 
1896  printf (" </oneBLOB>\n");
1897  }
1898 
1899  printf ("</setBLOBVector>\n");
1900  setlocale(LC_NUMERIC,"");
1901  fflush (stdout);
1902 
1903  pthread_mutex_unlock(&stdout_mutex);
1904 }
1905 
1906 /* tell client to update min/max elements of an existing number vector property */
1908 {
1909  int i;
1910 
1911  pthread_mutex_lock(&stdout_mutex);
1912  xmlv1();
1913  setlocale(LC_NUMERIC,"C");
1914  printf ("<setNumberVector\n");
1915  printf (" device='%s'\n", nvp->device);
1916  printf (" name='%s'\n", nvp->name);
1917  printf (" state='%s'\n", pstateStr(nvp->s));
1918  printf (" timeout='%g'\n", nvp->timeout);
1919  printf (" timestamp='%s'\n", timestamp());
1920  printf (">\n");
1921 
1922  for (i = 0; i < nvp->nnp; i++) {
1923  INumber *np = &nvp->np[i];
1924  printf (" <oneNumber name='%s'\n", np->name);
1925  printf (" min='%g'\n", np->min);
1926  printf (" max='%g'\n", np->max);
1927  printf (" step='%g'\n", np->step);
1928  printf(">\n");
1929  printf (" %g\n", np->value);
1930  printf (" </oneNumber>\n");
1931  }
1932 
1933  printf ("</setNumberVector>\n");
1934  setlocale(LC_NUMERIC,"");
1935  fflush (stdout);
1936  pthread_mutex_unlock(&stdout_mutex);
1937 }
1938 
1939 /* Return 1 is property is already cached, 0 otherwise */
1940 int isPropDefined(const char *property_name)
1941 {
1942  int i=0;
1943 
1944  for (i=0; i < nroCheck; i++)
1945  if (!strcmp(property_name, roCheck[i].propName))
1946  return 1;
1947 
1948  return 0;
1949 
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:1267
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidriver.c:1346
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:1209
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:1199
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:167
const char * pstateStr(IPState s)
Definition: indicom.c:975
char label[MAXINDILABEL]
Definition: indiapi.h:385
Light vector property descriptor.
Definition: indiapi.h:332
void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
Add opening or closing tag to a configuration file.
Definition: indidriver.c:1306
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:622
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:1699
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Tell client to update an existing switch vector property.
Definition: indidriver.c:1779
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:1472
void IDMessage(const char *dev, const char *fmt,...)
Function Drivers call to send log messages to Clients.
Definition: indidriver.c:1243
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
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:659
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:1642
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:1194
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:1907
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
int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
Loads and processes a configuration file.
Definition: indidriver.c:1123
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Tell client to update an existing number vector property.
Definition: indidriver.c:1739
void IUSaveConfigBLOB(FILE *fp, const IBLOBVectorProperty *bvp)
Add a BLOB vector property value to the configuration file.
Definition: indidriver.c:1382
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:1062
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:1108
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:1327
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:242
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:1160
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:1085
void rmCallback(int cid)
Definition: eventloop.c:187
const char * ruleStr(ISRule r)
Definition: indicom.c:1048
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:1364
int IUSnoopSwitch(XMLEle *root, ISwitchVectorProperty *svp)
Update a snooped switch vector property from the given XML root element.
Definition: indidriver.c:699
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indicom.c:1006
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1121
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:992
int IUSnoopBLOB(XMLEle *root, IBLOBVectorProperty *bvp)
Update a snooped BLOB vector property from the given XML root element.
Definition: indidriver.c:739
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:1856
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:1601
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:1819
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: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: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:1134
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:1175
const char * sstateStr(ISState s)
Definition: indicom.c:1035
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:1541
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:1414
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