Instrument Neutral Distributed Interface INDI  2.0.2
indidriver.c
Go to the documentation of this file.
1 #if 0
2 INDI Driver Functions
3 
4 Copyright (C) 2020 by Pawel Soja <kernel32.pl@gmail.com>
5 Copyright (C) 2003 - 2020 Jasem Mutlaq
6 Copyright (C) 2003 - 2006 Elwood C. Downey
7 
8 This library is free software;
9 you can redistribute it and / or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation;
12 either
13 version 2.1 of the License, or (at your option) any later version.
14 
15 This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY;
17 without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20 
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library;
23 if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
25 
26 #endif
27 #include "indidriver.h"
28 
29 #include "base64.h"
30 #include "indicom.h"
31 #include "indidevapi.h"
32 #include "locale_compat.h"
33 
34 #include <errno.h>
35 #include <pthread.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <assert.h>
44 
45 #include "userio.h"
46 #include "indiuserio.h"
47 #include "indidriverio.h"
48 
49 int verbose; /* chatty */
50 char *me = ""; /* a.out name */
51 
52 #define MAXRBUF 2048
53 
55 enum
56 {
63 };
64 
65 extern void waitPingReply(const char *);
66 
67 // TODO use fast map
68 /* insure RO properties are never modified. RO Sanity Check */
69 typedef struct {
70  char propName[MAXINDINAME];
71  char devName[MAXINDIDEVICE];
73  const void *ptr;
74  int type;
75 } ROSC;
76 
77 static pthread_mutex_t rosc_mutex = PTHREAD_MUTEX_INITIALIZER;
78 
79 static ROSC *propCache = NULL;
80 static int nPropCache = 0; /* # of elements in roCheck */
81 
82 static ROSC *rosc_new()
83 {
84  assert_mem(propCache = (ROSC *)(realloc(propCache, (nPropCache + 1) * sizeof *propCache)));
85  return &propCache[nPropCache++];
86 }
87 
88 static void rosc_add(const char *propName, const char *devName, IPerm perm, const void *ptr, int type)
89 {
90  ROSC *SC = rosc_new();
91  strcpy(SC->propName, propName);
92  strcpy(SC->devName, devName);
93  SC->perm = perm;
94  SC->ptr = ptr;
95  SC->type = type;
96 }
97 
98 /* Return pointer of property if already cached, NULL otherwise */
99 static ROSC *rosc_find(const char *propName, const char *devName)
100 {
101  for (int i = 0; i < nPropCache; i++)
102  if (!strcmp(propName, propCache[i].propName) && !strcmp(devName, propCache[i].devName))
103  return &propCache[i];
104 
105  return NULL;
106 }
107 
108 static void rosc_add_unique(const char *propName, const char *devName, IPerm perm, const void *ptr, int type)
109 {
110  pthread_mutex_lock(&rosc_mutex);
111 
112  if (rosc_find(propName, devName) == NULL)
113  rosc_add(propName, devName, perm, ptr, type);
114 
115  pthread_mutex_unlock(&rosc_mutex);
116 }
117 
118 /* tell Client to delete the property with given name on given device, or
119  * entire device if !name
120  */
121 void IDDeleteVA(const char *dev, const char *name, const char *fmt, va_list ap)
122 {
123  driverio io;
124  driverio_init(&io);
125 
126  userio_xmlv1(&io.userio, io.user);
127  IUUserIODeleteVA(&io.userio, io.user, dev, name, fmt, ap);
128 
129  driverio_finish(&io);
130 }
131 
132 void IDDelete(const char *dev, const char *name, const char *fmt, ...)
133 {
134  va_list ap;
135  va_start(ap, fmt);
136  IDDeleteVA(dev, name, fmt, ap);
137  va_end(ap);
138 }
139 
140 /* tell indiserver we want to snoop on the given device/property.
141  * name ignored if NULL or empty.
142  */
143 void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
144 {
145  // Ignore empty snooped device
146  if (snooped_device && snooped_device[0])
147  {
148  driverio io;
149  driverio_init(&io);
150 
151  userio_xmlv1(&io.userio, io.user);
152  IUUserIOGetProperties(&io.userio, io.user, snooped_device, snooped_property);
153 
154  driverio_finish(&io);
155  }
156 }
157 
158 /* tell indiserver whether we want BLOBs from the given snooped device.
159  * silently ignored if given device is not already registered for snooping.
160  */
161 void IDSnoopBLOBs(const char *snooped_device, const char *snooped_property, BLOBHandling bh)
162 {
163  if (snooped_device && snooped_device[0])
164  {
165  driverio io;
166  driverio_init(&io);
167 
168  userio_xmlv1(&io.userio, io.user);
169  IUUserIOEnableBLOB(&io.userio, io.user, snooped_device, snooped_property, bh);
170 
171  driverio_finish(&io);
172  }
173 }
174 
175 /* crack the given INDI XML element and call driver's IS* entry points as they
176  * are recognized.
177  * return 0 if ok else -1 with reason in msg[].
178  * N.B. exit if getProperties does not proclaim a compatible version.
179  */
180 int dispatch(XMLEle *root, char msg[])
181 {
182  char *rtag = tagXMLEle(root);
183  XMLEle *ep;
184  int n;
185 
186  if (verbose)
187  prXMLEle(stderr, root, 0);
188 
189  if (!strcmp(rtag, "getProperties"))
190  {
191  XMLAtt *ap, *name, *dev;
192  double v;
193 
194  /* check version */
195  ap = findXMLAtt(root, "version");
196  if (!ap)
197  {
198  fprintf(stderr, "%s: getProperties missing version\n", me);
199  exit(1);
200  }
201  v = atof(valuXMLAtt(ap));
202  if (v > INDIV)
203  {
204  fprintf(stderr, "%s: client version %g > %g\n", me, v, INDIV);
205  exit(1);
206  }
207 
208  // Get device
209  dev = findXMLAtt(root, "device");
210 
211  // Get property name
212  name = findXMLAtt(root, "name");
213 
214  if (name && dev)
215  {
216  pthread_mutex_lock(&rosc_mutex);
217  ROSC *prop = rosc_find(valuXMLAtt(name), valuXMLAtt(dev));
218  // This is unsafe... prop may be modified concurrently here
219  pthread_mutex_unlock(&rosc_mutex);
220 
221  if (prop == NULL)
222  return 0;
223 
224  switch (prop->type)
225  {
226  /* JM 2019-07-18: Why are we using setXXX here? should be defXXX */
227  case INDI_NUMBER:
228  //IDSetNumber((INumberVectorProperty *)(prop->ptr), NULL);
229  IDDefNumber((INumberVectorProperty *)(prop->ptr), NULL);
230  return 0;
231 
232  case INDI_SWITCH:
233  //IDSetSwitch((ISwitchVectorProperty *)(prop->ptr), NULL);
234  IDDefSwitch((ISwitchVectorProperty *)(prop->ptr), NULL);
235  return 0;
236 
237  case INDI_TEXT:
238  //IDSetText((ITextVectorProperty *)(prop->ptr), NULL);
239  IDDefText((ITextVectorProperty *)(prop->ptr), NULL);
240  return 0;
241 
242  case INDI_BLOB:
243  //IDSetBLOB((IBLOBVectorProperty *)(prop->ptr), NULL);
244  IDDefBLOB((IBLOBVectorProperty *)(prop->ptr), NULL);
245  return 0;
246  default:
247  return 0;
248  }
249  }
250 
251  ISGetProperties(dev ? valuXMLAtt(dev) : NULL);
252  return (0);
253  }
254 
255  /* other commands might be from a snooped device.
256  * we don't know here which devices are being snooped so we send
257  * all remaining valid messages
258  */
259  if (!strcmp(rtag, "setNumberVector") || !strcmp(rtag, "setTextVector") || !strcmp(rtag, "setLightVector") ||
260  !strcmp(rtag, "setSwitchVector") || !strcmp(rtag, "setBLOBVector") || !strcmp(rtag, "defNumberVector") ||
261  !strcmp(rtag, "defTextVector") || !strcmp(rtag, "defLightVector") || !strcmp(rtag, "defSwitchVector") ||
262  !strcmp(rtag, "defBLOBVector") || !strcmp(rtag, "message") || !strcmp(rtag, "delProperty"))
263  {
264  ISSnoopDevice(root);
265  return (0);
266  }
267 
268  char *dev, *name;
269  /* pull out device and name */
270  if (crackDN(root, &dev, &name, msg) < 0)
271  return (-1);
272 
273  pthread_mutex_lock(&rosc_mutex);
274  if (rosc_find(name, dev) == NULL)
275  {
276  pthread_mutex_unlock(&rosc_mutex);
277  snprintf(msg, MAXRBUF, "Property %s is not defined in %s.", name, dev);
278  return -1;
279  }
280  pthread_mutex_unlock(&rosc_mutex);
281 
282  /* ensure property is not RO */
283  for (int i = 0; i < nPropCache; i++)
284  {
285  if (!strcmp(propCache[i].propName, name) && !strcmp(propCache[i].devName, dev))
286  {
287  if (propCache[i].perm == IP_RO)
288  {
289  snprintf(msg, MAXRBUF, "Cannot set read-only property %s", name);
290  return -1;
291  }
292  else
293  break;
294  }
295  }
296 
297  /* check tag in surmised decreasing order of likelyhood */
298 
299  if (!strcmp(rtag, "newNumberVector"))
300  {
301  static double *doubles = NULL;
302  static char **names = NULL;
303  static int maxn = 0;
304 
305  // Set locale to C and save previous value
306  locale_char_t *orig = indi_locale_C_numeric_push();
307 
308  /* pull out each name/value pair */
309  for (n = 0, ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
310  {
311  if (strcmp(tagXMLEle(ep), "oneNumber") == 0)
312  {
313  XMLAtt *na = findXMLAtt(ep, "name");
314  if (na)
315  {
316  if (n >= maxn)
317  {
318  /* grow for this and another */
319  maxn = n + 1;
320  assert_mem(doubles = (double *)realloc(doubles, maxn * sizeof *doubles));
321  assert_mem(names = (char **)realloc(names, maxn * sizeof *names));
322  }
323  if (f_scansexa(pcdataXMLEle(ep), &doubles[n]) < 0)
324  IDMessage(dev, "[ERROR] %s: Bad format %s", name, pcdataXMLEle(ep));
325  else
326  names[n++] = valuXMLAtt(na);
327  }
328  }
329  }
330 
331  // Reset locale settings to original value
332  indi_locale_C_numeric_pop(orig);
333 
334  /* invoke driver if something to do, but not an error if not */
335  if (n > 0)
336  ISNewNumber(dev, name, doubles, names, n);
337  else
338  IDMessage(dev, "[ERROR] %s: newNumberVector with no valid members", name);
339  return (0);
340  }
341 
342  if (!strcmp(rtag, "newSwitchVector"))
343  {
344  static ISState *states = NULL;
345  static char **names = NULL;
346  static int maxn = 0;
347  XMLEle *ep;
348 
349  /* pull out each name/state pair */
350  for (n = 0, ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
351  {
352  if (strcmp(tagXMLEle(ep), "oneSwitch") == 0)
353  {
354  XMLAtt *na = findXMLAtt(ep, "name");
355  if (na)
356  {
357  if (n >= maxn)
358  {
359  maxn = n + 1;
360  assert_mem(states = (ISState *)realloc(states, maxn * sizeof *states));
361  assert_mem(names = (char **)realloc(names, maxn * sizeof *names));
362  }
363  if (strncmp(pcdataXMLEle(ep), "On", 2) == 0)
364  {
365  states[n] = ISS_ON;
366  names[n] = valuXMLAtt(na);
367  n++;
368  }
369  else if (strcmp(pcdataXMLEle(ep), "Off") == 0)
370  {
371  states[n] = ISS_OFF;
372  names[n] = valuXMLAtt(na);
373  n++;
374  }
375  else
376  IDMessage(dev, "[ERROR] %s: must be On or Off: %s", name, pcdataXMLEle(ep));
377  }
378  }
379  }
380 
381  /* invoke driver if something to do, but not an error if not */
382  if (n > 0)
383  ISNewSwitch(dev, name, states, names, n);
384  else
385  IDMessage(dev, "[ERROR] %s: newSwitchVector with no valid members", name);
386  return (0);
387  }
388 
389  if (!strcmp(rtag, "newTextVector"))
390  {
391  static char **texts = NULL;
392  static char **names = NULL;
393  static int maxn = 0;
394 
395  /* pull out each name/text pair */
396  for (n = 0, ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
397  {
398  if (strcmp(tagXMLEle(ep), "oneText") == 0)
399  {
400  XMLAtt *na = findXMLAtt(ep, "name");
401  if (na)
402  {
403  if (n >= maxn)
404  {
405  maxn = n + 1;
406  assert_mem(texts = (char **)realloc(texts, maxn * sizeof *texts));
407  assert_mem(names = (char **)realloc(names, maxn * sizeof *names));
408  }
409  texts[n] = pcdataXMLEle(ep);
410  names[n] = valuXMLAtt(na);
411  n++;
412  }
413  }
414  }
415 
416  /* invoke driver if something to do, but not an error if not */
417  if (n > 0)
418  ISNewText(dev, name, texts, names, n);
419  else
420  IDMessage(dev, "[ERROR] %s: set with no valid members", name);
421  return (0);
422  }
423 
424  if (!strcmp(rtag, "newBLOBVector"))
425  {
426  static char **blobs = NULL;
427  static char **names = NULL;
428  static char **formats = NULL;
429  static int *blobsizes = NULL;
430  static int *sizes = NULL;
431  static int maxn = 0;
432 
433  // FIXME: shared blob not supported here
434  /* pull out each name/BLOB pair, decode */
435  for (n = 0, ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
436  {
437  if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
438  {
439  XMLAtt *na = findXMLAtt(ep, "name");
440  XMLAtt *fa = findXMLAtt(ep, "format");
441  XMLAtt *sa = findXMLAtt(ep, "size");
442  XMLAtt *el = findXMLAtt(ep, "enclen");
443  if (na && fa && sa)
444  {
445  if (n >= maxn)
446  {
447  maxn = n + 1;
448  assert_mem(blobs = (char **)realloc(blobs, maxn * sizeof *blobs));
449  assert_mem(names = (char **)realloc(names, maxn * sizeof *names));
450  assert_mem(formats = (char **)realloc(formats, maxn * sizeof *formats));
451  assert_mem(sizes = (int *)realloc(sizes, maxn * sizeof *sizes));
452  assert_mem(blobsizes = (int *)realloc(blobsizes, maxn * sizeof *blobsizes));
453  }
454  // FIXME : here decode using shared buffer
455  int bloblen = pcdatalenXMLEle(ep);
456  // enclen is optional and not required by INDI protocol
457  if (el)
458  bloblen = atoi(valuXMLAtt(el));
459  assert_mem(blobs[n] = (char*)malloc(3 * bloblen / 4));
460  blobsizes[n] = from64tobits_fast(blobs[n], pcdataXMLEle(ep), bloblen);
461  names[n] = valuXMLAtt(na);
462  formats[n] = valuXMLAtt(fa);
463  sizes[n] = atoi(valuXMLAtt(sa));
464  n++;
465  }
466  }
467  }
468 
469  /* invoke driver if something to do, but not an error if not */
470  if (n > 0)
471  {
472  ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
473  for (int i = 0; i < n; i++)
474  free(blobs[i]);
475  }
476  else
477  IDMessage(dev, "[ERROR] %s: newBLOBVector with no valid members", name);
478  return (0);
479  }
480 
481  sprintf(msg, "Unknown command: %s", rtag);
482  return (1);
483 }
484 
485 int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
486 {
487  char *rname, *rdev;
488  XMLEle *root = NULL, *fproot = NULL;
489  LilXML *lp = newLilXML();
490 
491  FILE *fp = IUGetConfigFP(filename, dev, "r", errmsg);
492 
493  if (fp == NULL)
494  return -1;
495 
496  char whynot[MAXRBUF];
497  fproot = readXMLFile(fp, lp, whynot);
498 
499  delLilXML(lp);
500 
501  if (fproot == NULL)
502  {
503  snprintf(errmsg, MAXRBUF, "Unable to parse config XML: %s", whynot);
504  fclose(fp);
505  return -1;
506  }
507 
508  if (nXMLEle(fproot) > 0 && silent != 1)
509  IDMessage(dev, "[INFO] Loading device configuration...");
510 
511  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
512  {
513  /* pull out device and name */
514  if (crackDN(root, &rdev, &rname, errmsg) < 0)
515  {
516  fclose(fp);
517  delXMLEle(fproot);
518  return -1;
519  }
520 
521  // It doesn't belong to our device??
522  if (strcmp(dev, rdev))
523  continue;
524 
525  if ((property && !strcmp(property, rname)) || property == NULL)
526  {
527  dispatch(root, errmsg);
528  if (property)
529  break;
530  }
531  }
532 
533  if (nXMLEle(fproot) > 0 && silent != 1)
534  IDMessage(dev, "[INFO] Device configuration applied.");
535 
536  fclose(fp);
537  delXMLEle(fproot);
538 
539  return (0);
540 }
541 
542 int IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
543 {
544  char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF];
545 
546  if (source_config)
547  strncpy(configFileName, source_config, MAXRBUF);
548  else
549  {
550  if (getenv("INDICONFIG"))
551  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
552  else
553  snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
554  }
555 
556  if (dest_config)
557  strncpy(configDefaultFileName, dest_config, MAXRBUF);
558  else if (getenv("INDICONFIG"))
559  snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
560  else
561  snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), dev);
562 
563  // If the default doesn't exist, create it.
564  if (access(configDefaultFileName, F_OK))
565  {
566  FILE *fpin = fopen(configFileName, "r");
567  if (fpin != NULL)
568  {
569  FILE *fpout = fopen(configDefaultFileName, "w");
570  if (fpout != NULL)
571  {
572  int ch = 0;
573  while ((ch = getc(fpin)) != EOF)
574  putc(ch, fpout);
575 
576  fflush(fpout);
577  fclose(fpout);
578  }
579  fclose(fpin);
580 
581  return 0;
582  }
583  }
584  // If default config file exists already, then no need to modify it
585  else
586  return 0;
587 
588 
589  return -1;
590 }
591 
592 int IUGetConfigOnSwitch(const ISwitchVectorProperty *property, int *index)
593 {
594  char *rname, *rdev;
595  XMLEle *root = NULL, *fproot = NULL;
596  char errmsg[MAXRBUF];
597  LilXML *lp = newLilXML();
598  int propertyFound = 0;
599  *index = -1;
600 
601  FILE *fp = IUGetConfigFP(NULL, property->device, "r", errmsg);
602 
603  if (fp == NULL)
604  return -1;
605 
606  fproot = readXMLFile(fp, lp, errmsg);
607 
608  if (fproot == NULL)
609  {
610  fclose(fp);
611  return -1;
612  }
613 
614  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
615  {
616  /* pull out device and name */
617  if (crackDN(root, &rdev, &rname, errmsg) < 0)
618  {
619  fclose(fp);
620  delXMLEle(fproot);
621  return -1;
622  }
623 
624  // It doesn't belong to our device??
625  if (strcmp(property->device, rdev))
626  continue;
627 
628  if (!strcmp(property->name, rname))
629  {
630  propertyFound = 1;
631  XMLEle *oneSwitch = NULL;
632  int oneSwitchIndex = 0;
633  ISState oneSwitchState;
634  for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0), oneSwitchIndex++)
635  {
636  if (crackISState(pcdataXMLEle(oneSwitch), &oneSwitchState) == 0 && oneSwitchState == ISS_ON)
637  {
638  *index = oneSwitchIndex;
639  break;
640  }
641  }
642  break;
643  }
644  }
645 
646  fclose(fp);
647  delXMLEle(fproot);
648  delLilXML(lp);
649 
650  return (propertyFound ? 0 : -1);
651 }
652 
653 int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
654 {
655  char *rname, *rdev;
656  XMLEle *root = NULL, *fproot = NULL;
657  char errmsg[MAXRBUF];
658  LilXML *lp = newLilXML();
659  int valueFound = 0;
660 
661  FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
662 
663  if (fp == NULL)
664  return -1;
665 
666  fproot = readXMLFile(fp, lp, errmsg);
667 
668  if (fproot == NULL)
669  {
670  fclose(fp);
671  return -1;
672  }
673 
674  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
675  {
676  /* pull out device and name */
677  if (crackDN(root, &rdev, &rname, errmsg) < 0)
678  {
679  fclose(fp);
680  delXMLEle(fproot);
681  return -1;
682  }
683 
684  // It doesn't belong to our device??
685  if (strcmp(dev, rdev))
686  continue;
687 
688  if ((property && !strcmp(property, rname)) || property == NULL)
689  {
690  XMLEle *oneSwitch = NULL;
691  for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0))
692  {
693  if (!strcmp(member, findXMLAttValu(oneSwitch, "name")))
694  {
695  if (crackISState(pcdataXMLEle(oneSwitch), value) == 0)
696  valueFound = 1;
697  break;
698  }
699  }
700  break;
701  }
702  }
703 
704  fclose(fp);
705  delXMLEle(fproot);
706  delLilXML(lp);
707 
708  return (valueFound == 1 ? 0 : -1);
709 }
710 
711 int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
712 {
713  char *rname, *rdev;
714  XMLEle *root = NULL, *fproot = NULL;
715  char errmsg[MAXRBUF];
716  LilXML *lp = newLilXML();
717  int valueFound = 0;
718 
719  FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
720 
721  if (fp == NULL)
722  return -1;
723 
724  fproot = readXMLFile(fp, lp, errmsg);
725 
726  if (fproot == NULL)
727  {
728  fclose(fp);
729  return -1;
730  }
731 
732  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
733  {
734  /* pull out device and name */
735  if (crackDN(root, &rdev, &rname, errmsg) < 0)
736  {
737  fclose(fp);
738  delXMLEle(fproot);
739  return -1;
740  }
741 
742  // It doesn't belong to our device??
743  if (strcmp(dev, rdev))
744  continue;
745 
746  if ((property && !strcmp(property, rname)) || property == NULL)
747  {
748  XMLEle *oneSwitch = NULL;
749  int currentIndex = 0;
750  for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0), currentIndex++)
751  {
752  ISState s = ISS_OFF;
753  if (crackISState(pcdataXMLEle(oneSwitch), &s) == 0 && s == ISS_ON)
754  {
755  *index = currentIndex;
756  valueFound = 1;
757  break;
758  }
759  }
760  break;
761  }
762  }
763 
764  fclose(fp);
765  delXMLEle(fproot);
766  delLilXML(lp);
767 
768  return (valueFound == 1 ? 0 : -1);
769 }
770 
771 int IUGetConfigOnSwitchName(const char *dev, const char *property, char *name, size_t size)
772 {
773  char *rname, *rdev;
774  XMLEle *root = NULL, *fproot = NULL;
775  char errmsg[MAXRBUF];
776  LilXML *lp = newLilXML();
777  int found = -1;
778 
779  FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
780 
781  if (fp == NULL)
782  return -1;
783 
784  fproot = readXMLFile(fp, lp, errmsg);
785 
786  if (fproot == NULL)
787  {
788  fclose(fp);
789  return -1;
790  }
791 
792  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
793  {
794  /* pull out device and name */
795  if (crackDN(root, &rdev, &rname, errmsg) < 0)
796  {
797  fclose(fp);
798  delXMLEle(fproot);
799  return -1;
800  }
801 
802  // It doesn't belong to our device??
803  if (strcmp(dev, rdev))
804  continue;
805 
806  if ((property && !strcmp(property, rname)) || property == NULL)
807  {
808  XMLEle *oneSwitch = NULL;
809  int currentIndex = 0;
810  for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0), currentIndex++)
811  {
812  ISState s = ISS_OFF;
813  if (crackISState(pcdataXMLEle(oneSwitch), &s) == 0 && s == ISS_ON)
814  {
815  found = 0;
816  strncpy(name, findXMLAttValu(oneSwitch, "name"), size);
817  break;
818  }
819  }
820  break;
821  }
822  }
823 
824  fclose(fp);
825  delXMLEle(fproot);
826  delLilXML(lp);
827 
828  return found;
829 }
830 
831 int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
832 {
833  char *rname, *rdev;
834  XMLEle *root = NULL, *fproot = NULL;
835  char errmsg[MAXRBUF];
836  LilXML *lp = newLilXML();
837  int valueFound = 0;
838 
839  FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
840 
841  if (fp == NULL)
842  return -1;
843 
844  fproot = readXMLFile(fp, lp, errmsg);
845 
846  if (fproot == NULL)
847  {
848  fclose(fp);
849  return -1;
850  }
851 
852  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
853  {
854  /* pull out device and name */
855  if (crackDN(root, &rdev, &rname, errmsg) < 0)
856  {
857  fclose(fp);
858  delXMLEle(fproot);
859  return -1;
860  }
861 
862  // It doesn't belong to our device??
863  if (strcmp(dev, rdev))
864  continue;
865 
866  if ((property && !strcmp(property, rname)) || property == NULL)
867  {
868  XMLEle *oneNumber = NULL;
869  for (oneNumber = nextXMLEle(root, 1); oneNumber != NULL; oneNumber = nextXMLEle(root, 0))
870  {
871  if (!strcmp(member, findXMLAttValu(oneNumber, "name")))
872  {
873  *value = atof(pcdataXMLEle(oneNumber));
874  valueFound = 1;
875  break;
876  }
877  }
878  break;
879  }
880  }
881 
882  fclose(fp);
883  delXMLEle(fproot);
884  delLilXML(lp);
885 
886  return (valueFound == 1 ? 0 : -1);
887 }
888 
889 int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
890 {
891  char *rname, *rdev;
892  XMLEle *root = NULL, *fproot = NULL;
893  char errmsg[MAXRBUF];
894  LilXML *lp = newLilXML();
895  int valueFound = 0;
896 
897  FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
898 
899  if (fp == NULL)
900  return -1;
901 
902  fproot = readXMLFile(fp, lp, errmsg);
903 
904  if (fproot == NULL)
905  {
906  fclose(fp);
907  return -1;
908  }
909 
910  for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
911  {
912  /* pull out device and name */
913  if (crackDN(root, &rdev, &rname, errmsg) < 0)
914  {
915  fclose(fp);
916  delXMLEle(fproot);
917  return -1;
918  }
919 
920  // It doesn't belong to our device??
921  if (strcmp(dev, rdev))
922  continue;
923 
924  if ((property && !strcmp(property, rname)) || property == NULL)
925  {
926  XMLEle *oneText = NULL;
927  for (oneText = nextXMLEle(root, 1); oneText != NULL; oneText = nextXMLEle(root, 0))
928  {
929  if (!strcmp(member, findXMLAttValu(oneText, "name")))
930  {
931  strncpy(value, pcdataXMLEle(oneText), len);
932  valueFound = 1;
933  break;
934  }
935  }
936  break;
937  }
938  }
939 
940  fclose(fp);
941  delXMLEle(fproot);
942  delLilXML(lp);
943 
944  return (valueFound == 1 ? 0 : -1);
945 }
946 
947 /* send client a message for a specific device or at large if !dev */
948 void IDMessageVA(const char *dev, const char *fmt, va_list ap)
949 {
950  driverio io;
951  driverio_init(&io);
952 
953  userio_xmlv1(&io.userio, io.user);
954 
955  IDUserIOMessageVA(&io.userio, io.user, dev, fmt, ap);
956 
957  driverio_finish(&io);
958 }
959 
960 void IDMessage(const char *dev, const char *fmt, ...)
961 {
962  va_list ap;
963  va_start(ap, fmt);
964  IDMessageVA(dev, fmt, ap);
965  va_end(ap);
966 }
967 
968 int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
969 {
970  char configFileName[MAXRBUF];
971  char configDir[MAXRBUF];
972 
973  snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
974 
975  if (filename)
976  strncpy(configFileName, filename, MAXRBUF);
977  else
978  {
979  if (getenv("INDICONFIG"))
980  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
981  else
982  snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
983  }
984 
985  if (remove(configFileName) != 0)
986  {
987  snprintf(errmsg, MAXRBUF, "Unable to purge configuration file %s. Error %s", configFileName, strerror(errno));
988  return -1;
989  }
990 
991  return 0;
992 }
993 
994 FILE *IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
995 {
996  char configFileName[MAXRBUF];
997  char configDir[MAXRBUF];
998  struct stat st;
999  FILE *fp = NULL;
1000 
1001  snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
1002 
1003  if (filename)
1004  strncpy(configFileName, filename, MAXRBUF);
1005  else
1006  {
1007  if (getenv("INDICONFIG"))
1008  strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF);
1009  else
1010  snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1011  }
1012 
1013  if (stat(configDir, &st) != 0)
1014  {
1015  if (mkdir(configDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
1016  {
1017  snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s", configDir, strerror(errno));
1018  return NULL;
1019  }
1020  }
1021 
1022  stat(configFileName, &st);
1023  /* If file is owned by root and current user is NOT root then abort */
1024  if ( (st.st_uid == 0 && getuid() != 0) || (st.st_gid == 0 && getgid() != 0) )
1025  {
1026  strncpy(errmsg,
1027  "Config file is owned by root! This will lead to serious errors. To fix this, run: sudo chown -R $USER:$USER ~/.indi",
1028  MAXRBUF);
1029  return NULL;
1030  }
1031 
1032  fp = fopen(configFileName, mode);
1033  if (fp == NULL)
1034  {
1035  snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s", configFileName,
1036  strerror(errno));
1037  return NULL;
1038  }
1039 
1040  return fp;
1041 }
1042 
1043 void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
1044 {
1045  if (!fp)
1046  return;
1047 
1048  IUUserIOConfigTag(userio_file(), fp, ctag);
1049 
1050  if (silent != 1)
1051  {
1052  /* Opening tag */
1053  if (ctag == 0)
1054  {
1055  IDMessage(dev, "[INFO] Saving device configuration...");
1056  }
1057  /* Closing tag */
1058  else
1059  {
1060  IDMessage(dev, "[INFO] Device configuration saved.");
1061  }
1062  }
1063 }
1064 
1065 /* tell client to create a text vector property */
1066 void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
1067 {
1068  driverio io;
1069  driverio_init(&io);
1070 
1071  userio_xmlv1(&io.userio, io.user);
1072  IUUserIODefTextVA(&io.userio, io.user, tvp, fmt, ap);
1073 
1074  driverio_finish(&io);
1075 
1076  /* Add this property to insure proper sanity check */
1077  rosc_add_unique(tvp->name, tvp->device, tvp->p, tvp, INDI_TEXT);
1078 
1079 }
1080 
1081 void IDDefText(const ITextVectorProperty *tvp, const char *fmt, ...)
1082 {
1083  va_list ap;
1084  va_start(ap, fmt);
1085  IDDefTextVA(tvp, fmt, ap);
1086  va_end(ap);
1087 }
1088 
1089 /* tell client to create a new numeric vector property */
1090 void IDDefNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
1091 {
1092  driverio io;
1093  driverio_init(&io);
1094 
1095  userio_xmlv1(&io.userio, io.user);
1096  IUUserIODefNumberVA(&io.userio, io.user, nvp, fmt, ap);
1097 
1098  driverio_finish(&io);
1099 
1100  /* Add this property to insure proper sanity check */
1101  rosc_add_unique(nvp->name, nvp->device, nvp->p, nvp, INDI_NUMBER);
1102 }
1103 
1104 void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt, ...)
1105 {
1106  va_list ap;
1107  va_start(ap, fmt);
1108  IDDefNumberVA(nvp, fmt, ap);
1109  va_end(ap);
1110 }
1111 
1112 /* tell client to create a new switch vector property */
1113 void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
1114 {
1115  driverio io;
1116  driverio_init(&io);
1117 
1118  userio_xmlv1(&io.userio, io.user);
1119  IUUserIODefSwitchVA(&io.userio, io.user, svp, fmt, ap);
1120 
1121  driverio_finish(&io);
1122 
1123  /* Add this property to insure proper sanity check */
1124  rosc_add_unique(svp->name, svp->device, svp->p, svp, INDI_SWITCH);
1125 }
1126 
1127 void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt, ...)
1128 {
1129  va_list ap;
1130  va_start(ap, fmt);
1131  IDDefSwitchVA(svp, fmt, ap);
1132  va_end(ap);
1133 }
1134 
1135 /* tell client to create a new lights vector property */
1136 void IDDefLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
1137 {
1138  driverio io;
1139  driverio_init(&io);
1140 
1141  userio_xmlv1(&io.userio, io.user);
1142  IUUserIODefLightVA(&io.userio, io.user, lvp, fmt, ap);
1143 
1144  driverio_finish(&io);
1145 }
1146 
1147 void IDDefLight(const ILightVectorProperty *lvp, const char *fmt, ...)
1148 {
1149  va_list ap;
1150  va_start(ap, fmt);
1151  IDDefLightVA(lvp, fmt, ap);
1152  va_end(ap);
1153 }
1154 
1155 /* tell client to create a new BLOB vector property */
1156 void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
1157 {
1158  driverio io;
1159  driverio_init(&io);
1160 
1161  userio_xmlv1(&io.userio, io.user);
1162  IUUserIODefBLOBVA(&io.userio, io.user, bvp, fmt, ap);
1163 
1164  driverio_finish(&io);
1165 
1166  /* Add this property to insure proper sanity check */
1167  rosc_add_unique(bvp->name, bvp->device, bvp->p, bvp, INDI_BLOB);
1168 
1169 }
1170 
1171 void IDDefBLOB(const IBLOBVectorProperty *bvp, const char *fmt, ...)
1172 {
1173  va_list ap;
1174  va_start(ap, fmt);
1175  IDDefBLOBVA(bvp, fmt, ap);
1176  va_end(ap);
1177 }
1178 
1179 /* tell client to update an existing text vector property */
1180 void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
1181 {
1182  driverio io;
1183  driverio_init(&io);
1184 
1185  userio_xmlv1(&io.userio, io.user);
1186  IUUserIOSetTextVA(&io.userio, io.user, tvp, fmt, ap);
1187 
1188  driverio_finish(&io);
1189 }
1190 
1191 void IDSetText(const ITextVectorProperty *tvp, const char *fmt, ...)
1192 {
1193  va_list ap;
1194  va_start(ap, fmt);
1195  IDSetTextVA(tvp, fmt, ap);
1196  va_end(ap);
1197 }
1198 
1199 /* tell client to update an existing numeric vector property */
1200 void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
1201 {
1202  driverio io;
1203  driverio_init(&io);
1204 
1205  userio_xmlv1(&io.userio, io.user);
1206  IUUserIOSetNumberVA(&io.userio, io.user, nvp, fmt, ap);
1207 
1208  driverio_finish(&io);
1209 }
1210 
1211 void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt, ...)
1212 {
1213  va_list ap;
1214  va_start(ap, fmt);
1215  IDSetNumberVA(nvp, fmt, ap);
1216  va_end(ap);
1217 }
1218 
1219 /* tell client to update an existing switch vector property */
1220 void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
1221 {
1222  driverio io;
1223  driverio_init(&io);
1224 
1225  userio_xmlv1(&io.userio, io.user);
1226  IUUserIOSetSwitchVA(&io.userio, io.user, svp, fmt, ap);
1227 
1228  driverio_finish(&io);
1229 }
1230 
1231 void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt, ...)
1232 {
1233  va_list ap;
1234  va_start(ap, fmt);
1235  IDSetSwitchVA(svp, fmt, ap);
1236  va_end(ap);
1237 }
1238 
1239 /* tell client to update an existing lights vector property */
1240 void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
1241 {
1242  driverio io;
1243  driverio_init(&io);
1244 
1245  userio_xmlv1(&io.userio, io.user);
1246  IUUserIOSetLightVA(&io.userio, io.user, lvp, fmt, ap);
1247 
1248  driverio_finish(&io);
1249 }
1250 
1251 void IDSetLight(const ILightVectorProperty *lvp, const char *fmt, ...)
1252 {
1253  va_list ap;
1254  va_start(ap, fmt);
1255  IDSetLightVA(lvp, fmt, ap);
1256  va_end(ap);
1257 }
1258 
1259 static long lastBlobPingUid = 0;
1260 #define BLOB_PING_PATTERN "SetBLOB/%ld"
1261 
1262 /* tell client to update an existing BLOB vector property */
1263 void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
1264 {
1265  char buffer[64];
1266 
1267  // Wait for ack of previous blob if any
1268  if (lastBlobPingUid) {
1269  snprintf(buffer, 64, BLOB_PING_PATTERN, lastBlobPingUid);
1271  }
1272 
1273  driverio io;
1274  driverio_init(&io);
1275 
1276  userio_xmlv1(&io.userio, io.user);
1277  IUUserIOSetBLOBVA(&io.userio, io.user, bvp, fmt, ap);
1278 
1279  // Send a new <pingReply> so next blob won't be delayed until reception of this one
1280  lastBlobPingUid++;
1281  snprintf(buffer, 64, BLOB_PING_PATTERN, lastBlobPingUid);
1283 
1284  driverio_finish(&io);
1285 }
1286 
1287 void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt, ...)
1288 {
1289  va_list ap;
1290  va_start(ap, fmt);
1291  IDSetBLOBVA(bvp, fmt, ap);
1292  va_end(ap);
1293 }
1294 
1295 /* tell client to update min/max elements of an existing number vector property */
1297 {
1298  driverio io;
1299  driverio_init(&io);
1300 
1301  userio_xmlv1(&io.userio, io.user);
1302  IUUserIOUpdateMinMax(&io.userio, io.user, nvp);
1303 
1304  driverio_finish(&io);
1305 }
1306 
1307 /* Update property switches in accord with states and names. */
1308 int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
1309 {
1310  ISwitch *so = NULL; // On switch pointer
1311 
1312  assert(svp != NULL && "IUUpdateSwitch SVP is NULL");
1313 
1314  /* store On switch pointer */
1315  if (svp->r == ISR_1OFMANY)
1316  {
1317  so = IUFindOnSwitch(svp);
1318  IUResetSwitch(svp);
1319  }
1320 
1321  for (int i = 0; i < n; i++)
1322  {
1323  ISwitch *sp = IUFindSwitch(svp, names[i]);
1324 
1325  if (!sp)
1326  {
1327  svp->s = IPS_IDLE;
1328  IDSetSwitch(svp, "Error: %s is not a member of %s (%s) property.", names[i], svp->label, svp->name);
1329  return -1;
1330  }
1331 
1332  sp->s = states[i];
1333  }
1334 
1335  /* Consistency checks for ISR_1OFMANY after update. */
1336  if (svp->r == ISR_1OFMANY)
1337  {
1338  int t_count = 0;
1339  for (int i = 0; i < svp->nsp; i++)
1340  {
1341  if (svp->sp[i].s == ISS_ON)
1342  t_count++;
1343  }
1344  if (t_count != 1)
1345  {
1346  IUResetSwitch(svp);
1347 
1348  // restore previous state
1349  if (so)
1350  so->s = ISS_ON;
1351  svp->s = IPS_IDLE;
1352  IDSetSwitch(svp, "Error: invalid state switch for property %s (%s). %s.", svp->label, svp->name,
1353  t_count == 0 ? "No switch is on" : "Too many switches are on");
1354  return -1;
1355  }
1356  }
1357 
1358  return 0;
1359 }
1360 
1361 /* Update property numbers in accord with values and names */
1362 int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
1363 {
1364  assert(nvp != NULL && "IUUpdateNumber NVP is NULL");
1365 
1366  for (int i = 0; i < n; i++)
1367  {
1368  INumber *np = IUFindNumber(nvp, names[i]);
1369  if (!np)
1370  {
1371  nvp->s = IPS_IDLE;
1372  IDSetNumber(nvp, "Error: %s is not a member of %s (%s) property.", names[i], nvp->label, nvp->name);
1373  return -1;
1374  }
1375 
1376  if (values[i] < np->min || values[i] > np->max)
1377  {
1378  nvp->s = IPS_ALERT;
1379  IDSetNumber(nvp, "Error: Invalid range for %s (%s). Valid range is from %g to %g. Requested value is %g",
1380  np->label, np->name, np->min, np->max, values[i]);
1381  return -1;
1382  }
1383  }
1384 
1385  /* First loop checks for error, second loop set all values atomically*/
1386  for (int i = 0; i < n; i++)
1387  {
1388  INumber *np = IUFindNumber(nvp, names[i]);
1389  np->value = values[i];
1390  }
1391 
1392  return 0;
1393 }
1394 
1395 /* Update property text in accord with texts and names */
1396 int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
1397 {
1398  assert(tvp != NULL && "IUUpdateText TVP is NULL");
1399 
1400  for (int i = 0; i < n; i++)
1401  {
1402  IText *tp = IUFindText(tvp, names[i]);
1403  if (!tp)
1404  {
1405  tvp->s = IPS_IDLE;
1406  IDSetText(tvp, "Error: %s is not a member of %s (%s) property.", names[i], tvp->label, tvp->name);
1407  return -1;
1408  }
1409  }
1410 
1411  /* First loop checks for error, second loop set all values atomically*/
1412  for (int i = 0; i < n; i++)
1413  {
1414  IText *tp = IUFindText(tvp, names[i]);
1415  IUSaveText(tp, texts[i]);
1416  }
1417 
1418  return 0;
1419 }
1420 
1421 /* Update property BLOB in accord with BLOBs and names */
1422 int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[],
1423  int n)
1424 {
1425  assert(bvp != NULL && "IUUpdateBLOB BVP is NULL");
1426 
1427  for (int i = 0; i < n; i++)
1428  {
1429  IBLOB *bp = IUFindBLOB(bvp, names[i]);
1430  if (!bp)
1431  {
1432  bvp->s = IPS_IDLE;
1433  IDSetBLOB(bvp, "Error: %s is not a member of %s (%s) property.", names[i], bvp->label, bvp->name);
1434  return -1;
1435  }
1436  }
1437 
1438  /* First loop checks for error, second loop set all values atomically*/
1439  for (int i = 0; i < n; i++)
1440  {
1441  IBLOB *bp = IUFindBLOB(bvp, names[i]);
1442  IUSaveBLOB(bp, sizes[i], blobsizes[i], blobs[i], formats[i]);
1443  }
1444 
1445  return 0;
1446 }
int from64tobits_fast(char *out, const char *in, int inlen)
Definition: base64.c:122
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.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
void ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Update the value of an existing text vector property.
void ISGetProperties(const char *dev)
Get Device Properties.
void ISSnoopDevice(XMLEle *root)
Function defined by Drivers that is called when another Driver it is snooping (by having previously c...
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
int errno
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
#define MAXINDIDEVICE
Definition: indiapi.h:193
#define assert_mem(p)
Bails out if memory pointer is 0. Prints file and function.
Definition: indiapi.h:505
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:183
@ IP_RO
Definition: indiapi.h:184
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ ISR_1OFMANY
Definition: indiapi.h:173
#define MAXINDINAME
Definition: indiapi.h:191
#define INDIV
Definition: indiapi.h:134
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Definition: indicom.c:205
Implementations for common driver routines.
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indidevapi.c:66
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indidevapi.c:148
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition: indidevapi.c:108
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indidevapi.c:36
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indidevapi.c:553
int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format)
Function to save blob metadata in the corresponding blob.
Definition: indidevapi.c:44
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition: indidevapi.c:96
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indidevapi.c:56
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indidevapi.c:591
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indidevapi.c:76
Interface to the reference INDI C API device implementation on the Device Driver side.
BLOBHandling
How drivers handle BLOBs incoming from snooping drivers.
Definition: indidevapi.h:266
void IDMessageVA(const char *dev, const char *fmt, va_list ap)
Definition: indidriver.c:948
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:1422
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
int verbose
Definition: indidriver.c:49
void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
Definition: indidriver.c:1200
void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
Definition: indidriver.c:1113
void IDSnoopBLOBs(const char *snooped_device, const char *snooped_property, BLOBHandling bh)
Function a Driver calls to control whether they will receive BLOBs from snooped devices.
Definition: indidriver.c:161
void IDDefNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
Definition: indidriver.c:1090
void IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
Definition: indidriver.c:1251
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
void IDDelete(const char *dev, const char *name, const char *fmt,...)
Definition: indidriver.c:132
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indidriver.c:1066
void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
Definition: indidriver.c:1263
#define BLOB_PING_PATTERN
Definition: indidriver.c:1260
#define MAXRBUF
Definition: indidriver.c:52
void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
Add opening or closing tag to a configuration file. A configuration file root XML element is <INDIDri...
Definition: indidriver.c:1043
int IUGetConfigOnSwitch(const ISwitchVectorProperty *property, int *index)
IUGetConfigOnSwitch Opens configuration file and reads a single switch vector property to find the in...
Definition: indidriver.c:592
int IUGetConfigOnSwitchName(const char *dev, const char *property, char *name, size_t size)
IUGetConfigOnSwitchLabel Opens configuration file and returns the name of the ON switch property,...
Definition: indidriver.c:771
int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
IUGetConfigText Opens configuration file and reads single text property.
Definition: indidriver.c:889
void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indidriver.c:1180
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:143
void waitPingReply(const char *)
int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
IUGetConfigNumber Opens configuration file and reads single number property.
Definition: indidriver.c:831
int IUReadConfig(const char *filename, const char *dev, const char *property, int silent, char errmsg[])
Loads and processes a configuration file. Once a configuration file is successful loaded,...
Definition: indidriver.c:485
void IDDefLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indidriver.c:1136
void IDMessage(const char *dev, const char *fmt,...)
Definition: indidriver.c:960
void IDDeleteVA(const char *dev, const char *name, const char *fmt, va_list ap)
Definition: indidriver.c:121
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
Definition: indidriver.c:968
void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
Definition: indidriver.c:1156
@ INDI_LIGHT
Definition: indidriver.c:60
@ INDI_TEXT
Definition: indidriver.c:59
@ INDI_UNKNOWN
Definition: indidriver.c:62
@ INDI_NUMBER
Definition: indidriver.c:57
@ INDI_SWITCH
Definition: indidriver.c:58
@ INDI_BLOB
Definition: indidriver.c:61
int IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev)
Copies an existing configuration file into a default configuration file. If no default configuration ...
Definition: indidriver.c:542
int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
IUGetConfigOnSwitchIndex Opens configuration file and reads single switch property to find ON switch ...
Definition: indidriver.c:711
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1296
void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1104
void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
Definition: indidriver.c:1220
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
Definition: indidriver.c:1287
void IDDefText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1081
int dispatch(XMLEle *root, char msg[])
Definition: indidriver.c:180
void IDDefLight(const ILightVectorProperty *lvp, const char *fmt,...)
Definition: indidriver.c:1147
void IDDefBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
Definition: indidriver.c:1171
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
IUGetConfigSwitch Opens configuration file and reads single switch property.
Definition: indidriver.c:653
char * me
Definition: indidriver.c:50
FILE * IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
Open a configuration file for writing and return a configuration file FILE pointer.
Definition: indidriver.c:994
void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indidriver.c:1240
void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1127
void driverio_init(driverio *dio)
Definition: indidriverio.c:359
void driverio_finish(driverio *dio)
Definition: indidriverio.c:371
void IUUserIOSetLightVA(const userio *io, void *user, const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indiuserio.c:704
void IUUserIODefLightVA(const userio *io, void *user, const ILightVectorProperty *lvp, const char *fmt, va_list ap)
Definition: indiuserio.c:546
void IUUserIOUpdateMinMax(const userio *io, void *user, const INumberVectorProperty *nvp)
Definition: indiuserio.c:751
void IUUserIODefBLOBVA(const userio *io, void *user, const IBLOBVectorProperty *b, const char *fmt, va_list ap)
Definition: indiuserio.c:586
void IUUserIODeleteVA(const userio *io, void *user, const char *dev, const char *name, const char *fmt, va_list ap)
Definition: indiuserio.c:286
void IUUserIOSetSwitchVA(const userio *io, void *user, const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
Definition: indiuserio.c:679
void IUUserIODefTextVA(const userio *io, void *user, const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indiuserio.c:402
void IUUserIOSetNumberVA(const userio *io, void *user, const INumberVectorProperty *nvp, const char *fmt, va_list ap)
Definition: indiuserio.c:654
void IUUserIODefSwitchVA(const userio *io, void *user, const ISwitchVectorProperty *s, const char *fmt, va_list ap)
Definition: indiuserio.c:501
void IUUserIOSetBLOBVA(const userio *io, void *user, const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
Definition: indiuserio.c:726
void IUUserIOEnableBLOB(const userio *io, void *user, const char *dev, const char *name, BLOBHandling blobH)
Definition: indiuserio.c:341
void IUUserIOPingRequest(const userio *io, void *user, const char *pingUid)
Definition: indiuserio.c:787
void IDUserIOMessageVA(const userio *io, void *user, const char *dev, const char *fmt, va_list ap)
Definition: indiuserio.c:358
void IUUserIOSetTextVA(const userio *io, void *user, const ITextVectorProperty *tvp, const char *fmt, va_list ap)
Definition: indiuserio.c:629
void IUUserIOConfigTag(const userio *io, void *user, int ctag)
Definition: indiuserio.c:386
void IUUserIOGetProperties(const userio *io, void *user, const char *dev, const char *name)
Definition: indiuserio.c:307
void IUUserIODefNumberVA(const userio *io, void *user, const INumberVectorProperty *n, const char *fmt, va_list ap)
Definition: indiuserio.c:449
int nXMLEle(XMLEle *ep)
Return the number of nested XML elements in a parent XML element.
Definition: lilxml.cpp:630
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.cpp:524
LilXML * newLilXML()
Create a new lilxml parser.
Definition: lilxml.cpp:150
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.cpp:644
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.cpp:606
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.cpp:600
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition: lilxml.cpp:844
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition: lilxml.cpp:653
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.cpp:555
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition: lilxml.cpp:167
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition: lilxml.cpp:159
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition: lilxml.cpp:612
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.cpp:624
char locale_char_t
Definition: locale_compat.h:62
std::vector< uint8_t > buffer
Namespace to encapsulate INDI client, drivers, and mediator classes.
int mkdir(const char *path, mode_t mode)
Definition: indiutility.cpp:41
__le16 type
Definition: pwc-ioctl.h:0
One Blob (Binary Large Object) descriptor.
One number descriptor.
One switch descriptor.
One text descriptor.
const void * ptr
Definition: indidriver.c:73
IPerm perm
Definition: indidriver.c:72
char devName[MAXINDIDEVICE]
Definition: indidriver.c:71
char propName[MAXINDINAME]
Definition: indidriver.c:70
int type
Definition: indidriver.c:74
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:471
char label[MAXINDILABEL]
Definition: indiapi.h:477
char name[MAXINDINAME]
Definition: indiapi.h:475
char device[MAXINDIDEVICE]
Definition: indiapi.h:473
Light vector property descriptor.
Definition: indiapi.h:417
Number vector property descriptor.
Definition: indiapi.h:319
char device[MAXINDIDEVICE]
Definition: indiapi.h:321
char name[MAXINDINAME]
Definition: indiapi.h:323
char label[MAXINDILABEL]
Definition: indiapi.h:325
Switch vector property descriptor.
Definition: indiapi.h:367
char device[MAXINDIDEVICE]
Definition: indiapi.h:369
char name[MAXINDINAME]
Definition: indiapi.h:371
char label[MAXINDILABEL]
Definition: indiapi.h:373
Text vector property descriptor.
Definition: indiapi.h:246
char label[MAXINDILABEL]
Definition: indiapi.h:252
char device[MAXINDIDEVICE]
Definition: indiapi.h:248
char name[MAXINDINAME]
Definition: indiapi.h:250
void * user
Definition: indidriverio.h:30
struct userio userio
Definition: indidriverio.h:29
const struct userio * userio_file()
Definition: userio.c:39
void userio_xmlv1(const userio *io, void *user)
Definition: userio.c:104