Instrument Neutral Distributed Interface INDI 2.2.5
indidriver.c
Go to the documentation of this file.
1#if 0
2INDI Driver Functions
3
4Copyright (C) 2020 by Pawel Soja <[email protected]>
5Copyright (C) 2003 - 2020 Jasem Mutlaq
6Copyright (C) 2003 - 2006 Elwood C. Downey
7
8This library is free software;
9you can redistribute it and / or
10modify it under the terms of the GNU Lesser General Public
11License as published by the Free Software Foundation;
12either
13version 2.1 of the License, or (at your option) any later version.
14
15This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY;
17without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public
22License along with this library;
23if not, write to the Free Software
24Foundation, 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
49int verbose; /* chatty */
50char *me = ""; /* a.out name */
51
52#define MAXRBUF 2048
53
55enum
56{
63};
64
65extern void waitPingReply(const char *);
66
67// TODO use fast map
68/* insure RO properties are never modified. RO Sanity Check */
69typedef struct {
70 char propName[MAXINDINAME];
71 char devName[MAXINDIDEVICE];
73 const void *ptr;
74 int type;
75} ROSC;
76
77static pthread_mutex_t rosc_mutex = PTHREAD_MUTEX_INITIALIZER;
78
79static ROSC *propCache = NULL;
80static int nPropCache = 0; /* # of elements in roCheck */
81
82static ROSC *rosc_new()
83{
84 assert_mem(propCache = (ROSC *)(realloc(propCache, (nPropCache + 1) * sizeof *propCache)));
85 return &propCache[nPropCache++];
86}
87
88static 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 */
99static 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
108static 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 */
121void 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
132void 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 */
143void 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 */
161void 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 */
180int 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 likelihood */
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 snprintf(msg, MAXRBUF, "Unknown command: %s", rtag);
482 return (1);
483}
484
485int 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
542int 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 snprintf(configFileName, MAXRBUF, "%s", source_config);
548 else
549 {
550 if (getenv("INDICONFIG"))
551 snprintf(configFileName, MAXRBUF, "%s", getenv("INDICONFIG"));
552 else
553 snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev);
554 }
555
556 if (dest_config)
557 snprintf(configDefaultFileName, MAXRBUF, "%s", dest_config);
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
592int 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 {
605 delLilXML(lp);
606 return -1;
607 }
608
609 fproot = readXMLFile(fp, lp, errmsg);
610
611 if (fproot == NULL)
612 {
613 delLilXML(lp);
614 fclose(fp);
615 return -1;
616 }
617
618 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
619 {
620 /* pull out device and name */
621 if (crackDN(root, &rdev, &rname, errmsg) < 0)
622 {
623 fclose(fp);
624 delXMLEle(fproot);
625 return -1;
626 }
627
628 // It doesn't belong to our device??
629 if (strcmp(property->device, rdev))
630 continue;
631
632 if (!strcmp(property->name, rname))
633 {
634 propertyFound = 1;
635 XMLEle *oneSwitch = NULL;
636 int oneSwitchIndex = 0;
637 ISState oneSwitchState;
638 for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0), oneSwitchIndex++)
639 {
640 if (crackISState(pcdataXMLEle(oneSwitch), &oneSwitchState) == 0 && oneSwitchState == ISS_ON)
641 {
642 *index = oneSwitchIndex;
643 break;
644 }
645 }
646 break;
647 }
648 }
649
650 fclose(fp);
651 delXMLEle(fproot);
652 delLilXML(lp);
653
654 return (propertyFound ? 0 : -1);
655}
656
657int IUGetConfigSwitch(const char *dev, const char *property, const char *member, ISState *value)
658{
659 char *rname, *rdev;
660 XMLEle *root = NULL, *fproot = NULL;
661 char errmsg[MAXRBUF];
662 LilXML *lp = newLilXML();
663 int valueFound = 0;
664
665 FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
666
667 if (fp == NULL)
668 {
669 delLilXML(lp);
670 return -1;
671 }
672
673 fproot = readXMLFile(fp, lp, errmsg);
674
675 if (fproot == NULL)
676 {
677 fclose(fp);
678 delLilXML(lp);
679 return -1;
680 }
681
682 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
683 {
684 /* pull out device and name */
685 if (crackDN(root, &rdev, &rname, errmsg) < 0)
686 {
687 fclose(fp);
688 delXMLEle(fproot);
689 return -1;
690 }
691
692 // It doesn't belong to our device??
693 if (strcmp(dev, rdev))
694 continue;
695
696 if ((property && !strcmp(property, rname)) || property == NULL)
697 {
698 XMLEle *oneSwitch = NULL;
699 for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0))
700 {
701 if (!strcmp(member, findXMLAttValu(oneSwitch, "name")))
702 {
703 if (crackISState(pcdataXMLEle(oneSwitch), value) == 0)
704 valueFound = 1;
705 break;
706 }
707 }
708 break;
709 }
710 }
711
712 fclose(fp);
713 delXMLEle(fproot);
714 delLilXML(lp);
715
716 return (valueFound == 1 ? 0 : -1);
717}
718
719int IUGetConfigOnSwitchIndex(const char *dev, const char *property, int *index)
720{
721 char *rname, *rdev;
722 XMLEle *root = NULL, *fproot = NULL;
723 char errmsg[MAXRBUF];
724 LilXML *lp = newLilXML();
725 int valueFound = 0;
726
727 FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
728
729 if (fp == NULL)
730 {
731 delLilXML(lp);
732 return -1;
733 }
734
735 fproot = readXMLFile(fp, lp, errmsg);
736
737 if (fproot == NULL)
738 {
739 delLilXML(lp);
740 fclose(fp);
741 return -1;
742 }
743
744 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
745 {
746 /* pull out device and name */
747 if (crackDN(root, &rdev, &rname, errmsg) < 0)
748 {
749 fclose(fp);
750 delXMLEle(fproot);
751 return -1;
752 }
753
754 // It doesn't belong to our device??
755 if (strcmp(dev, rdev))
756 continue;
757
758 if ((property && !strcmp(property, rname)) || property == NULL)
759 {
760 XMLEle *oneSwitch = NULL;
761 int currentIndex = 0;
762 for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0), currentIndex++)
763 {
764 ISState s = ISS_OFF;
765 if (crackISState(pcdataXMLEle(oneSwitch), &s) == 0 && s == ISS_ON)
766 {
767 *index = currentIndex;
768 valueFound = 1;
769 break;
770 }
771 }
772 break;
773 }
774 }
775
776 fclose(fp);
777 delXMLEle(fproot);
778 delLilXML(lp);
779
780 return (valueFound == 1 ? 0 : -1);
781}
782
783int IUGetConfigOnSwitchName(const char *dev, const char *property, char *name, size_t size)
784{
785 char *rname, *rdev;
786 XMLEle *root = NULL, *fproot = NULL;
787 char errmsg[MAXRBUF];
788 LilXML *lp = newLilXML();
789 int found = -1;
790
791 FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
792
793 if (fp == NULL)
794 {
795 delLilXML(lp);
796 return -1;
797 }
798
799 fproot = readXMLFile(fp, lp, errmsg);
800
801 if (fproot == NULL)
802 {
803 delLilXML(lp);
804 fclose(fp);
805 return -1;
806 }
807
808 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
809 {
810 /* pull out device and name */
811 if (crackDN(root, &rdev, &rname, errmsg) < 0)
812 {
813 fclose(fp);
814 delXMLEle(fproot);
815 return -1;
816 }
817
818 // It doesn't belong to our device??
819 if (strcmp(dev, rdev))
820 continue;
821
822 if ((property && !strcmp(property, rname)) || property == NULL)
823 {
824 XMLEle *oneSwitch = NULL;
825 for (oneSwitch = nextXMLEle(root, 1); oneSwitch != NULL; oneSwitch = nextXMLEle(root, 0))
826 {
827 ISState s = ISS_OFF;
828 if (crackISState(pcdataXMLEle(oneSwitch), &s) == 0 && s == ISS_ON)
829 {
830 found = 0;
831 snprintf(name, size, "%s", findXMLAttValu(oneSwitch, "name"));
832 break;
833 }
834 }
835 break;
836 }
837 }
838
839 fclose(fp);
840 delXMLEle(fproot);
841 delLilXML(lp);
842
843 return found;
844}
845
846int IUGetConfigNumber(const char *dev, const char *property, const char *member, double *value)
847{
848 char *rname, *rdev;
849 XMLEle *root = NULL, *fproot = NULL;
850 char errmsg[MAXRBUF];
851 LilXML *lp = newLilXML();
852 int valueFound = 0;
853
854 FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
855
856 if (fp == NULL)
857 {
858 delLilXML(lp);
859 return -1;
860 }
861
862 fproot = readXMLFile(fp, lp, errmsg);
863
864 if (fproot == NULL)
865 {
866 fclose(fp);
867 delLilXML(lp);
868 return -1;
869 }
870
871 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
872 {
873 /* pull out device and name */
874 if (crackDN(root, &rdev, &rname, errmsg) < 0)
875 {
876 fclose(fp);
877 delXMLEle(fproot);
878 return -1;
879 }
880
881 // It doesn't belong to our device??
882 if (strcmp(dev, rdev))
883 continue;
884
885 if ((property && !strcmp(property, rname)) || property == NULL)
886 {
887 XMLEle *oneNumber = NULL;
888 for (oneNumber = nextXMLEle(root, 1); oneNumber != NULL; oneNumber = nextXMLEle(root, 0))
889 {
890 if (!strcmp(member, findXMLAttValu(oneNumber, "name")))
891 {
892 *value = atof(pcdataXMLEle(oneNumber));
893 valueFound = 1;
894 break;
895 }
896 }
897 break;
898 }
899 }
900
901 fclose(fp);
902 delXMLEle(fproot);
903 delLilXML(lp);
904
905 return (valueFound == 1 ? 0 : -1);
906}
907
908int IUGetConfigText(const char *dev, const char *property, const char *member, char *value, int len)
909{
910 char *rname, *rdev;
911 XMLEle *root = NULL, *fproot = NULL;
912 char errmsg[MAXRBUF];
913 LilXML *lp = newLilXML();
914 int valueFound = 0;
915
916 FILE *fp = IUGetConfigFP(NULL, dev, "r", errmsg);
917
918 if (fp == NULL)
919 {
920 delLilXML(lp);
921 return -1;
922 }
923
924 fproot = readXMLFile(fp, lp, errmsg);
925
926 if (fproot == NULL)
927 {
928 delLilXML(lp);
929 fclose(fp);
930 return -1;
931 }
932
933 for (root = nextXMLEle(fproot, 1); root != NULL; root = nextXMLEle(fproot, 0))
934 {
935 /* pull out device and name */
936 if (crackDN(root, &rdev, &rname, errmsg) < 0)
937 {
938 fclose(fp);
939 delXMLEle(fproot);
940 return -1;
941 }
942
943 // It doesn't belong to our device??
944 if (strcmp(dev, rdev))
945 continue;
946
947 if ((property && !strcmp(property, rname)) || property == NULL)
948 {
949 XMLEle *oneText = NULL;
950 for (oneText = nextXMLEle(root, 1); oneText != NULL; oneText = nextXMLEle(root, 0))
951 {
952 if (!strcmp(member, findXMLAttValu(oneText, "name")))
953 {
954 snprintf(value, len, "%s", pcdataXMLEle(oneText));
955 valueFound = 1;
956 break;
957 }
958 }
959 break;
960 }
961 }
962
963 fclose(fp);
964 delXMLEle(fproot);
965 delLilXML(lp);
966
967 return (valueFound == 1 ? 0 : -1);
968}
969
970/* send client a message for a specific device or at large if !dev */
971void IDMessageVA(const char *dev, const char *fmt, va_list ap)
972{
973 driverio io;
974 driverio_init(&io);
975
976 userio_xmlv1(&io.userio, io.user);
977
978 IDUserIOMessageVA(&io.userio, io.user, dev, fmt, ap);
979
980 driverio_finish(&io);
981}
982
983void IDMessage(const char *dev, const char *fmt, ...)
984{
985 va_list ap;
986 va_start(ap, fmt);
987 IDMessageVA(dev, fmt, ap);
988 va_end(ap);
989}
990
991int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
992{
993 char configFileName[MAXRBUF];
994 char configDir[MAXRBUF];
995
996 snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
997
998 if (filename)
999 snprintf(configFileName, MAXRBUF, "%s", filename);
1000 else
1001 {
1002 if (getenv("INDICONFIG"))
1003 snprintf(configFileName, MAXRBUF, "%s", getenv("INDICONFIG"));
1004 else
1005 snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1006 }
1007
1008 if (remove(configFileName) != 0)
1009 {
1010 snprintf(errmsg, MAXRBUF, "Unable to purge configuration file %s. Error %s", configFileName, strerror(errno));
1011 return -1;
1012 }
1013
1014 return 0;
1015}
1016
1017FILE *IUGetConfigFP(const char *filename, const char *dev, const char *mode, char errmsg[])
1018{
1019 char configFileName[MAXRBUF];
1020 char configDir[MAXRBUF];
1021 struct stat st;
1022 FILE *fp = NULL;
1023
1024 snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME"));
1025
1026 if (filename)
1027 snprintf(configFileName, MAXRBUF, "%s", filename);
1028 else
1029 {
1030 if (getenv("INDICONFIG"))
1031 snprintf(configFileName, MAXRBUF, "%s", getenv("INDICONFIG"));
1032 else
1033 snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev);
1034 }
1035
1036 if (stat(configDir, &st) != 0)
1037 {
1038 if (mkdir(configDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
1039 {
1040 snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s", configDir, strerror(errno));
1041 return NULL;
1042 }
1043 }
1044
1045 /* If file is owned by root and current user is NOT root then abort. Only the owner matters: on macOS,
1046 * new files take the group of their directory, so files in e.g. /tmp belong to group wheel (0). */
1047 if (stat(configFileName, &st) == 0 && st.st_uid == 0 && getuid() != 0)
1048 {
1049 strncpy(errmsg,
1050 "Config file is owned by root! This will lead to serious errors. To fix this, run: sudo chown -R $USER:$USER ~/.indi",
1051 MAXRBUF);
1052 return NULL;
1053 }
1054
1055 fp = fopen(configFileName, mode);
1056 if (fp == NULL)
1057 {
1058 snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s", configFileName,
1059 strerror(errno));
1060 return NULL;
1061 }
1062
1063 return fp;
1064}
1065
1066void IUSaveConfigTag(FILE *fp, int ctag, const char *dev, int silent)
1067{
1068 if (!fp)
1069 return;
1070
1071 IUUserIOConfigTag(userio_file(), fp, ctag);
1072
1073 if (silent != 1)
1074 {
1075 /* Opening tag */
1076 if (ctag == 0)
1077 {
1078 IDMessage(dev, "[INFO] Saving device configuration...");
1079 }
1080 /* Closing tag */
1081 else
1082 {
1083 IDMessage(dev, "[INFO] Device configuration saved.");
1084 }
1085 }
1086}
1087
1088/* tell client to create a text vector property */
1089void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
1090{
1091 driverio io;
1092 driverio_init(&io);
1093
1094 userio_xmlv1(&io.userio, io.user);
1095 IUUserIODefTextVA(&io.userio, io.user, tvp, fmt, ap);
1096
1097 driverio_finish(&io);
1098
1099 /* Add this property to insure proper sanity check */
1100 rosc_add_unique(tvp->name, tvp->device, tvp->p, tvp, INDI_TEXT);
1101
1102}
1103
1104void IDDefText(const ITextVectorProperty *tvp, const char *fmt, ...)
1105{
1106 va_list ap;
1107 va_start(ap, fmt);
1108 IDDefTextVA(tvp, fmt, ap);
1109 va_end(ap);
1110}
1111
1112/* tell client to create a new numeric vector property */
1113void IDDefNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
1114{
1115 driverio io;
1116 driverio_init(&io);
1117
1118 userio_xmlv1(&io.userio, io.user);
1119 IUUserIODefNumberVA(&io.userio, io.user, nvp, fmt, ap);
1120
1121 driverio_finish(&io);
1122
1123 /* Add this property to insure proper sanity check */
1124 rosc_add_unique(nvp->name, nvp->device, nvp->p, nvp, INDI_NUMBER);
1125}
1126
1127void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt, ...)
1128{
1129 va_list ap;
1130 va_start(ap, fmt);
1131 IDDefNumberVA(nvp, fmt, ap);
1132 va_end(ap);
1133}
1134
1135/* tell client to create a new switch vector property */
1136void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
1137{
1138 driverio io;
1139 driverio_init(&io);
1140
1141 userio_xmlv1(&io.userio, io.user);
1142 IUUserIODefSwitchVA(&io.userio, io.user, svp, fmt, ap);
1143
1144 driverio_finish(&io);
1145
1146 /* Add this property to insure proper sanity check */
1147 rosc_add_unique(svp->name, svp->device, svp->p, svp, INDI_SWITCH);
1148}
1149
1150void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt, ...)
1151{
1152 va_list ap;
1153 va_start(ap, fmt);
1154 IDDefSwitchVA(svp, fmt, ap);
1155 va_end(ap);
1156}
1157
1158/* tell client to create a new lights vector property */
1159void IDDefLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
1160{
1161 driverio io;
1162 driverio_init(&io);
1163
1164 userio_xmlv1(&io.userio, io.user);
1165 IUUserIODefLightVA(&io.userio, io.user, lvp, fmt, ap);
1166
1167 driverio_finish(&io);
1168}
1169
1170void IDDefLight(const ILightVectorProperty *lvp, const char *fmt, ...)
1171{
1172 va_list ap;
1173 va_start(ap, fmt);
1174 IDDefLightVA(lvp, fmt, ap);
1175 va_end(ap);
1176}
1177
1178/* tell client to create a new BLOB vector property */
1179void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
1180{
1181 driverio io;
1182 driverio_init(&io);
1183
1184 userio_xmlv1(&io.userio, io.user);
1185 IUUserIODefBLOBVA(&io.userio, io.user, bvp, fmt, ap);
1186
1187 driverio_finish(&io);
1188
1189 /* Add this property to insure proper sanity check */
1190 rosc_add_unique(bvp->name, bvp->device, bvp->p, bvp, INDI_BLOB);
1191
1192}
1193
1194void IDDefBLOB(const IBLOBVectorProperty *bvp, const char *fmt, ...)
1195{
1196 va_list ap;
1197 va_start(ap, fmt);
1198 IDDefBLOBVA(bvp, fmt, ap);
1199 va_end(ap);
1200}
1201
1202/* tell client to update an existing text vector property */
1203void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
1204{
1205 driverio io;
1206 driverio_init(&io);
1207
1208 userio_xmlv1(&io.userio, io.user);
1209 IUUserIOSetTextVA(&io.userio, io.user, tvp, fmt, ap);
1210
1211 driverio_finish(&io);
1212}
1213
1214void IDSetText(const ITextVectorProperty *tvp, const char *fmt, ...)
1215{
1216 va_list ap;
1217 va_start(ap, fmt);
1218 IDSetTextVA(tvp, fmt, ap);
1219 va_end(ap);
1220}
1221
1222/* tell client to update an existing numeric vector property */
1223void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
1224{
1225 driverio io;
1226 driverio_init(&io);
1227
1228 userio_xmlv1(&io.userio, io.user);
1229 IUUserIOSetNumberVA(&io.userio, io.user, nvp, fmt, ap);
1230
1231 driverio_finish(&io);
1232}
1233
1234void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt, ...)
1235{
1236 va_list ap;
1237 va_start(ap, fmt);
1238 IDSetNumberVA(nvp, fmt, ap);
1239 va_end(ap);
1240}
1241
1242/* tell client to update an existing switch vector property */
1243void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
1244{
1245 driverio io;
1246 driverio_init(&io);
1247
1248 userio_xmlv1(&io.userio, io.user);
1249 IUUserIOSetSwitchVA(&io.userio, io.user, svp, fmt, ap);
1250
1251 driverio_finish(&io);
1252}
1253
1254void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt, ...)
1255{
1256 va_list ap;
1257 va_start(ap, fmt);
1258 IDSetSwitchVA(svp, fmt, ap);
1259 va_end(ap);
1260}
1261
1262/* tell client to update an existing lights vector property */
1263void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
1264{
1265 driverio io;
1266 driverio_init(&io);
1267
1268 userio_xmlv1(&io.userio, io.user);
1269 IUUserIOSetLightVA(&io.userio, io.user, lvp, fmt, ap);
1270
1271 driverio_finish(&io);
1272}
1273
1274void IDSetLight(const ILightVectorProperty *lvp, const char *fmt, ...)
1275{
1276 va_list ap;
1277 va_start(ap, fmt);
1278 IDSetLightVA(lvp, fmt, ap);
1279 va_end(ap);
1280}
1281
1282static long lastBlobPingUid = 0;
1283#define BLOB_PING_PATTERN "SetBLOB/%ld"
1284
1285/* tell client to update an existing BLOB vector property */
1286void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
1287{
1288 char buffer[64];
1289
1290 // Wait for ack of previous blob if any
1291 if (lastBlobPingUid) {
1292 snprintf(buffer, 64, BLOB_PING_PATTERN, lastBlobPingUid);
1293 waitPingReply(buffer);
1294 }
1295
1296 driverio io;
1297 driverio_init(&io);
1298
1299 userio_xmlv1(&io.userio, io.user);
1300 IUUserIOSetBLOBVA(&io.userio, io.user, bvp, fmt, ap);
1301
1302 // Send a new <pingReply> so next blob won't be delayed until reception of this one
1303 lastBlobPingUid++;
1304 snprintf(buffer, 64, BLOB_PING_PATTERN, lastBlobPingUid);
1305 IUUserIOPingRequest(&io.userio, io.user, buffer);
1306
1307 driverio_finish(&io);
1308}
1309
1310void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt, ...)
1311{
1312 va_list ap;
1313 va_start(ap, fmt);
1314 IDSetBLOBVA(bvp, fmt, ap);
1315 va_end(ap);
1316}
1317
1318/* tell client to update min/max elements of an existing number vector property */
1320{
1321 driverio io;
1322 driverio_init(&io);
1323
1324 userio_xmlv1(&io.userio, io.user);
1325 IUUserIOUpdateMinMax(&io.userio, io.user, nvp);
1326
1327 driverio_finish(&io);
1328}
1329
1330/* Update property switches in accord with states and names. */
1331int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
1332{
1333 ISwitch *so = NULL; // On switch pointer
1334
1335 assert(svp != NULL && "IUUpdateSwitch SVP is NULL");
1336
1337 /* store On switch pointer */
1338 if (svp->r == ISR_1OFMANY)
1339 {
1340 so = IUFindOnSwitch(svp);
1341 IUResetSwitch(svp);
1342 }
1343
1344 for (int i = 0; i < n; i++)
1345 {
1346 ISwitch *sp = IUFindSwitch(svp, names[i]);
1347
1348 if (!sp)
1349 {
1350 svp->s = IPS_IDLE;
1351 IDSetSwitch(svp, "Error: %s is not a member of %s (%s) property.", names[i], svp->label, svp->name);
1352 return -1;
1353 }
1354
1355 sp->s = states[i];
1356 }
1357
1358 /* Consistency checks for ISR_1OFMANY after update. */
1359 if (svp->r == ISR_1OFMANY)
1360 {
1361 int t_count = 0;
1362 for (int i = 0; i < svp->nsp; i++)
1363 {
1364 if (svp->sp[i].s == ISS_ON)
1365 t_count++;
1366 }
1367 if (t_count != 1)
1368 {
1369 IUResetSwitch(svp);
1370
1371 // restore previous state
1372 if (so)
1373 so->s = ISS_ON;
1374 svp->s = IPS_IDLE;
1375 IDSetSwitch(svp, "Error: invalid state switch for property %s (%s). %s.", svp->label, svp->name,
1376 t_count == 0 ? "No switch is on" : "Too many switches are on");
1377 return -1;
1378 }
1379 }
1380
1381 return 0;
1382}
1383
1384/* Update property numbers in accord with values and names */
1385int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
1386{
1387 assert(nvp != NULL && "IUUpdateNumber NVP is NULL");
1388
1389 for (int i = 0; i < n; i++)
1390 {
1391 INumber *np = IUFindNumber(nvp, names[i]);
1392 if (!np)
1393 {
1394 nvp->s = IPS_IDLE;
1395 IDSetNumber(nvp, "Error: %s is not a member of %s (%s) property.", names[i], nvp->label, nvp->name);
1396 return -1;
1397 }
1398
1399 if (values[i] < np->min || values[i] > np->max)
1400 {
1401 nvp->s = IPS_ALERT;
1402 IDSetNumber(nvp, "Error: Invalid range for %s (%s). Valid range is from %g to %g. Requested value is %g",
1403 np->label, np->name, np->min, np->max, values[i]);
1404 return -1;
1405 }
1406 }
1407
1408 /* First loop checks for error, second loop set all values atomically*/
1409 for (int i = 0; i < n; i++)
1410 {
1411 INumber *np = IUFindNumber(nvp, names[i]);
1412 np->value = values[i];
1413 }
1414
1415 return 0;
1416}
1417
1418/* Update property text in accord with texts and names */
1419int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
1420{
1421 assert(tvp != NULL && "IUUpdateText TVP is NULL");
1422
1423 for (int i = 0; i < n; i++)
1424 {
1425 IText *tp = IUFindText(tvp, names[i]);
1426 if (!tp)
1427 {
1428 tvp->s = IPS_IDLE;
1429 IDSetText(tvp, "Error: %s is not a member of %s (%s) property.", names[i], tvp->label, tvp->name);
1430 return -1;
1431 }
1432 }
1433
1434 /* First loop checks for error, second loop set all values atomically*/
1435 for (int i = 0; i < n; i++)
1436 {
1437 IText *tp = IUFindText(tvp, names[i]);
1438 IUSaveText(tp, texts[i]);
1439 }
1440
1441 return 0;
1442}
1443
1444/* Update property BLOB in accord with BLOBs and names */
1445int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[],
1446 int n)
1447{
1448 assert(bvp != NULL && "IUUpdateBLOB BVP is NULL");
1449
1450 for (int i = 0; i < n; i++)
1451 {
1452 IBLOB *bp = IUFindBLOB(bvp, names[i]);
1453 if (!bp)
1454 {
1455 bvp->s = IPS_IDLE;
1456 IDSetBLOB(bvp, "Error: %s is not a member of %s (%s) property.", names[i], bvp->label, bvp->name);
1457 return -1;
1458 }
1459 }
1460
1461 /* First loop checks for error, second loop set all values atomically*/
1462 for (int i = 0; i < n; i++)
1463 {
1464 IBLOB *bp = IUFindBLOB(bvp, names[i]);
1465 IUSaveBLOB(bp, sizes[i], blobsizes[i], blobs[i], formats[i]);
1466 }
1467
1468 return 0;
1469}
std::string fmt(const char *fmt,...)
Definition Utils.cpp:241
int from64tobits_fast(char *out, const char *in, int inlen)
Definition base64.c:122
int errno
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 ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
#define MAXINDIDEVICE
Definition indiapi.h:191
#define assert_mem(p)
Bails out if memory pointer is 0. Prints file and function.
Definition indiapi.h:503
IPerm
Permission hint, with respect to client.
Definition indiapi.h:181
@ IP_RO
Definition indiapi.h:182
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ ISR_1OFMANY
Definition indiapi.h:171
#define MAXINDINAME
Definition indiapi.h:189
#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:194
Implementations for common driver routines.
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition indidevapi.c:265
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition indidevapi.c:366
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition indidevapi.c:275
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition indidevapi.c:44
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition indidevapi.c:770
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition indidevapi.c:285
int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format)
Function to save blob metadata in the corresponding blob.
Definition indidevapi.c:52
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition indidevapi.c:305
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition indidevapi.c:317
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition indidevapi.c:808
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:267
void IDMessageVA(const char *dev, const char *fmt, va_list ap)
Definition indidriver.c:971
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.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
int verbose
Definition indidriver.c:49
void IDSetNumberVA(const INumberVectorProperty *nvp, const char *fmt, va_list ap)
void IDDefSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
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)
void IDSetLight(const ILightVectorProperty *lvp, const char *fmt,...)
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
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.
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.
void IDDefTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
void IDSetBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
#define BLOB_PING_PATTERN
#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...
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:783
@ 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 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:908
void IDSetTextVA(const ITextVectorProperty *tvp, const char *fmt, va_list ap)
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:846
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)
void IDMessage(const char *dev, const char *fmt,...)
Definition indidriver.c:983
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.
int IUPurgeConfig(const char *filename, const char *dev, char errmsg[])
Definition indidriver.c:991
void IDDefBLOBVA(const IBLOBVectorProperty *bvp, const char *fmt, va_list ap)
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:719
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
void IDDefNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitchVA(const ISwitchVectorProperty *svp, const char *fmt, va_list ap)
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
void IDDefText(const ITextVectorProperty *tvp, const char *fmt,...)
int dispatch(XMLEle *root, char msg[])
Definition indidriver.c:180
void IDDefLight(const ILightVectorProperty *lvp, const char *fmt,...)
void IDDefBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
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:657
char * me
Definition indidriver.c:50
void IDSetLightVA(const ILightVectorProperty *lvp, const char *fmt, va_list ap)
void IDDefSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void driverio_init(driverio *dio)
void driverio_finish(driverio *dio)
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
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition lilxml.cpp:644
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition lilxml.cpp:555
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
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition lilxml.cpp:600
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition lilxml.cpp:624
void prXMLEle(FILE *fp, XMLEle *ep, int level)
Print an XML element.
Definition lilxml.cpp:844
void delXMLEle(XMLEle *ep)
delXMLEle Delete XML element.
Definition lilxml.cpp:167
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition lilxml.cpp:606
void delLilXML(LilXML *lp)
Delete a lilxml parser.
Definition lilxml.cpp:159
XMLEle * readXMLFile(FILE *fp, LilXML *lp, char ynot[])
Handy wrapper to read one xml file.
Definition lilxml.cpp:653
int pcdatalenXMLEle(XMLEle *ep)
Return the number of characters in pcdata in an XML element.
Definition lilxml.cpp:612
char locale_char_t
Namespace to encapsulate INDI client, drivers, and mediator classes.
uint16_t type
Definition pwc-ioctl.h:0
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...
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:469
char label[MAXINDILABEL]
Definition indiapi.h:475
char name[MAXINDINAME]
Definition indiapi.h:473
char device[MAXINDIDEVICE]
Definition indiapi.h:471
Light vector property descriptor.
Definition indiapi.h:415
Number vector property descriptor.
Definition indiapi.h:317
char device[MAXINDIDEVICE]
Definition indiapi.h:319
char name[MAXINDINAME]
Definition indiapi.h:321
char label[MAXINDILABEL]
Definition indiapi.h:323
Switch vector property descriptor.
Definition indiapi.h:365
char device[MAXINDIDEVICE]
Definition indiapi.h:367
char name[MAXINDINAME]
Definition indiapi.h:369
char label[MAXINDILABEL]
Definition indiapi.h:371
ISState s
Definition indiapi.h:353
Text vector property descriptor.
Definition indiapi.h:244
char label[MAXINDILABEL]
Definition indiapi.h:250
char device[MAXINDIDEVICE]
Definition indiapi.h:246
char name[MAXINDINAME]
Definition indiapi.h:248
void * user
struct userio userio
void userio_xmlv1(const userio *io, void *user)
Definition userio.c:104
const struct userio * userio_file()
Definition userio.c:39