Instrument Neutral Distributed Interface INDI  1.9.2
indicom.c
Go to the documentation of this file.
1 /*
2  INDI LIB
3  Common routines used by all drivers
4  Copyright (C) 2003 by Jason Harris (jharris@30doradus.org)
5  Elwood C. Downey
6 
7  This is the C version of the astronomical library in KStars
8  modified by Jasem Mutlaq (mutlaqja@ikarustech.com)
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Lesser General Public
12  License as published by the Free Software Foundation; 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; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public
21  License along with this library; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 
24 */
25 
26 #define _GNU_SOURCE 1
27 
28 #include "indicom.h"
29 
30 #include "indidevapi.h"
31 #include "locale_compat.h"
32 #include "base64.h"
33 
34 #include "config.h"
35 
36 #if defined(HAVE_LIBNOVA)
37 #include <libnova/julian_day.h>
38 #include <libnova/sidereal_time.h>
39 #include <libnova/ln_types.h>
40 #include <libnova/transform.h>
41 #endif // HAVE_LIBNOVA
42 
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <math.h>
46 #include <stdarg.h>
47 #include <stdint.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
52 
53 #ifdef __linux__
54 #include <sys/ioctl.h>
55 #endif
56 
57 #ifdef __APPLE__
58 #include <sys/param.h>
59 #include <mach/clock.h>
60 #include <mach/mach.h>
61 #endif
62 
63 #if defined(BSD) && !defined(__GNU__)
64 #include <IOKit/serial/ioss.h>
65 #include <sys/ioctl.h>
66 #endif
67 
68 #ifdef _WIN32
69 #undef CX
70 #undef CY
71 #endif
72 
73 #ifndef _WIN32
74 #include <unistd.h>
75 #include <termios.h>
76 #include <sys/param.h>
77 #define PARITY_NONE 0
78 #define PARITY_EVEN 1
79 #define PARITY_ODD 2
80 #endif
81 
82 #include "userio.h"
83 #include "indiuserio.h"
84 
85 #if defined(_MSC_VER)
86 #define snprintf _snprintf
87 #pragma warning(push)
88 #pragma warning(disable : 4996)
90 #endif
91 
92 #define MAXRBUF 2048
93 
94 static int tty_debug = 0;
95 static int tty_gemini_udp_format = 0;
96 static int tty_generic_udp_format = 0;
97 static int tty_sequence_number = 1;
98 static int tty_clear_trailing_lf = 0;
99 
100 #if defined(HAVE_LIBNOVA)
101 int extractISOTime(const char *timestr, struct ln_date *iso_date)
102 {
103  struct tm utm;
104 
105  if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm))
106  {
107  ln_get_date_from_tm(&utm, iso_date);
108  return (0);
109  }
110 
111  if (strptime(timestr, "%Y-%m-%dT%H:%M:%S", &utm))
112  {
113  ln_get_date_from_tm(&utm, iso_date);
114  return (0);
115  }
116 
117  return (-1);
118 }
119 #endif
120 
121 /* sprint the variable a in sexagesimal format into out[].
122  * w is the number of spaces for the whole part.
123  * fracbase is the number of pieces a whole is to broken into; valid options:
124  * 360000: <w>:mm:ss.ss
125  * 36000: <w>:mm:ss.s
126  * 3600: <w>:mm:ss
127  * 600: <w>:mm.m
128  * 60: <w>:mm
129  * return number of characters written to out, not counting final '\0'.
130  */
131 int fs_sexa(char *out, double a, int w, int fracbase)
132 {
133  char *out0 = out;
134  unsigned long n;
135  int d;
136  int f;
137  int m;
138  int s;
139  int isneg;
140 
141  /* save whether it's negative but do all the rest with a positive */
142  isneg = (a < 0);
143  if (isneg)
144  a = -a;
145 
146  /* convert to an integral number of whole portions */
147  n = (unsigned long)(a * fracbase + 0.5);
148  d = n / fracbase;
149  f = n % fracbase;
150 
151  /* form the whole part; "negative 0" is a special case */
152  if (isneg && d == 0)
153  out += snprintf(out, MAXINDIFORMAT, "%*s-0", w - 2, "");
154  else
155  out += snprintf(out, MAXINDIFORMAT, "%*d", w, isneg ? -d : d);
156 
157  /* do the rest */
158  switch (fracbase)
159  {
160  case 60: /* dd:mm */
161  m = f / (fracbase / 60);
162  out += snprintf(out, MAXINDIFORMAT, ":%02d", m);
163  break;
164  case 600: /* dd:mm.m */
165  out += snprintf(out, MAXINDIFORMAT, ":%02d.%1d", f / 10, f % 10);
166  break;
167  case 3600: /* dd:mm:ss */
168  m = f / (fracbase / 60);
169  s = f % (fracbase / 60);
170  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d", m, s);
171  break;
172  case 36000: /* dd:mm:ss.s*/
173  m = f / (fracbase / 60);
174  s = f % (fracbase / 60);
175  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d.%1d", m, s / 10, s % 10);
176  break;
177  case 360000: /* dd:mm:ss.ss */
178  m = f / (fracbase / 60);
179  s = f % (fracbase / 60);
180  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d.%02d", m, s / 100, s % 100);
181  break;
182  default:
183  printf("fs_sexa: unknown fracbase: %d\n", fracbase);
184  return -1;
185  }
186 
187  return (out - out0);
188 }
189 
190 /* convert sexagesimal string str AxBxC to double.
191  * x can be anything non-numeric. Any missing A, B or C will be assumed 0.
192  * optional - and + can be anywhere.
193  * return 0 if ok, -1 if can't find a thing.
194  */
195 int f_scansexa(const char *str0, /* input string */
196  double *dp) /* cracked value, if return 0 */
197 {
198  locale_char_t *orig = indi_locale_C_numeric_push();
199 
200  double a = 0, b = 0, c = 0;
201  char str[128];
202  //char *neg;
203  uint8_t isNegative=0;
204  int r= 0;
205 
206  /* copy str0 so we can play with it */
207  strncpy(str, str0, sizeof(str) - 1);
208  str[sizeof(str) - 1] = '\0';
209 
210  /* remove any spaces */
211  char* i = str;
212  char* j = str;
213  while(*j != 0)
214  {
215  *i = *j++;
216  if(*i != ' ')
217  i++;
218  }
219  *i = 0;
220 
221  // This has problem process numbers in scientific notations e.g. 1e-06
222  /*neg = strchr(str, '-');
223  if (neg)
224  *neg = ' ';
225  */
226  if (str[0] == '-')
227  {
228  isNegative = 1;
229  str[0] = ' ';
230  }
231 
232  r = sscanf(str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c);
233 
234  indi_locale_C_numeric_pop(orig);
235 
236  if (r < 1)
237  return (-1);
238  *dp = a + b / 60 + c / 3600;
239  if (isNegative)
240  *dp *= -1;
241  return (0);
242 }
243 
244 void getSexComponents(double value, int *d, int *m, int *s)
245 {
246  *d = (int32_t)fabs(value);
247  *m = (int32_t)((fabs(value) - *d) * 60.0);
248  *s = (int32_t)rint(((fabs(value) - *d) * 60.0 - *m) * 60.0);
249 
250  // Special case if seconds are >= 59.5 so it will be rounded by rint above
251  // to 60
252  if (*s == 60)
253  {
254  *s = 0;
255  *m += 1;
256  }
257  if (*m == 60)
258  {
259  *m = 0;
260  *d += 1;
261  }
262 
263  if (value < 0)
264  *d *= -1;
265 }
266 
267 void getSexComponentsIID(double value, int *d, int *m, double *s)
268 {
269  *d = (int32_t)fabs(value);
270  *m = (int32_t)((fabs(value) - *d) * 60.0);
271  *s = (double)(((fabs(value) - *d) * 60.0 - *m) * 60.0);
272 
273  if (value < 0)
274  *d *= -1;
275 }
276 
277 /* fill buf with properly formatted INumber string. return length */
278 int numberFormat(char *buf, const char *format, double value)
279 {
280  int w, f, s;
281  char m;
282 
283  if (sscanf(format, "%%%d.%d%c", &w, &f, &m) == 3 && m == 'm')
284  {
285  /* INDI sexi format */
286  switch (f)
287  {
288  case 9: s = 360000; break;
289  case 8: s = 36000; break;
290  case 6: s = 3600; break;
291  case 5: s = 600; break;
292  default: s = 60; break;
293  }
294  return (fs_sexa(buf, value, w - f, s));
295  }
296  else
297  {
298  /* normal printf format */
299  return (snprintf(buf, MAXINDIFORMAT, format, value));
300  }
301 }
302 
303 /* log message locally.
304  * this has nothing to do with XML or any Clients.
305  */
306 void IDLog(const char *fmt, ...)
307 {
308  va_list ap;
309  /* JM: Since all INDI's stderr are timestampped now, we don't need to time stamp ID Log */
310  /*fprintf (stderr, "%s ", timestamp());*/
311  va_start(ap, fmt);
312  vfprintf(stderr, fmt, ap);
313  va_end(ap);
314 }
315 
316 double time_ns()
317 {
318  struct timespec ts;
319 #ifdef __APPLE__ // OS X does not have clock_gettime, use clock_get_time
320  clock_serv_t cclock;
321  mach_timespec_t mts;
322  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
323  clock_get_time(cclock, &mts);
324  mach_port_deallocate(mach_task_self(), cclock);
325  ts.tv_sec = mts.tv_sec;
326  ts.tv_nsec = mts.tv_nsec;
327 #else
328  timespec_get(&ts, TIME_UTC);
329 #endif
330  return (double)ts.tv_sec+(double)(ts.tv_nsec%1000000000)/1000000000.0;
331 }
332 
333 /* return current system time in message format */
334 const char *timestamp()
335 {
336  static char ts[32];
337  struct tm *tp;
338  time_t t;
339 
340  time(&t);
341  tp = gmtime(&t);
342  strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
343  return (ts);
344 }
345 
346 void tty_set_debug(int debug)
347 {
348  tty_debug = debug;
349 }
350 
351 void tty_set_gemini_udp_format(int enabled)
352 {
353  tty_gemini_udp_format = enabled;
354 }
355 
356 void tty_set_generic_udp_format(int enabled)
357 {
358  tty_generic_udp_format = enabled;
359 }
360 
361 void tty_clr_trailing_read_lf(int enabled)
362 {
363  tty_clear_trailing_lf = enabled;
364 }
365 
366 int tty_timeout(int fd, int timeout)
367 {
368 #if defined(_WIN32) || defined(ANDROID)
369  INDI_UNUSED(fd);
370  INDI_UNUSED(timeout);
371  return TTY_ERRNO;
372 #else
373 
374  if (fd == -1)
375  return TTY_ERRNO;
376 
377  struct timeval tv;
378  fd_set readout;
379  int retval;
380 
381  FD_ZERO(&readout);
382  FD_SET(fd, &readout);
383 
384  /* wait for 'timeout' seconds */
385  tv.tv_sec = timeout;
386  tv.tv_usec = 0;
387 
388  /* Wait till we have a change in the fd status */
389  retval = select(fd + 1, &readout, NULL, NULL, &tv);
390 
391  /* Return 0 on successful fd change */
392  if (retval > 0)
393  return TTY_OK;
394  /* Return -1 due to an error */
395  else if (retval == -1)
396  return TTY_SELECT_ERROR;
397  /* Return -2 if time expires before anything interesting happens */
398  else
399  return TTY_TIME_OUT;
400 
401 #endif
402 }
403 
404 int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
405 {
406 #ifdef _WIN32
407  return TTY_ERRNO;
408 #else
409  int geminiBuffer[66]={0};
410  char *buffer = (char *)buf;
411 
412  if (tty_gemini_udp_format)
413  {
414  buffer = (char*)geminiBuffer;
415  geminiBuffer[0] = ++tty_sequence_number;
416  geminiBuffer[1] = 0;
417  memcpy((char *)&geminiBuffer[2], buf, nbytes);
418  // Add on the 8 bytes for the header and 1 byte for the null terminator
419  nbytes += 9;
420  }
421 
422  if (fd == -1)
423  return TTY_ERRNO;
424 
425  int bytes_w = 0;
426  *nbytes_written = 0;
427 
428  if (tty_debug)
429  {
430  int i = 0;
431  for (i = 0; i < nbytes; i++)
432  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char)buf[i], buf[i]);
433  }
434 
435  while (nbytes > 0)
436  {
437  bytes_w = write(fd, buffer + (*nbytes_written), nbytes);
438 
439  if (bytes_w < 0)
440  return TTY_WRITE_ERROR;
441 
442  *nbytes_written += bytes_w;
443  nbytes -= bytes_w;
444  }
445 
446  if (tty_gemini_udp_format)
447  *nbytes_written -= 9;
448 
449  return TTY_OK;
450 
451 #endif
452 }
453 
454 int tty_write_string(int fd, const char *buf, int *nbytes_written)
455 {
456  unsigned int nbytes;
457  nbytes = strlen(buf);
458 
459  return tty_write(fd, buf, nbytes, nbytes_written);
460 }
461 
462 int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
463 {
464 #ifdef _WIN32
465  return TTY_ERRNO;
466 #else
467 
468  if (fd == -1)
469  return TTY_ERRNO;
470 
471  int numBytesToRead = nbytes;
472  int bytesRead = 0;
473  int err = 0;
474  *nbytes_read = 0;
475 
476  if (nbytes <= 0)
477  return TTY_PARAM_ERROR;
478 
479  if (tty_debug)
480  IDLog("%s: Request to read %d bytes with %d timeout for fd %d\n", __FUNCTION__, nbytes, timeout, fd);
481 
482  char geminiBuffer[257]={0};
483  char* buffer = buf;
484 
485  if (tty_gemini_udp_format)
486  {
487  numBytesToRead = nbytes + 8;
488  buffer = geminiBuffer;
489  }
490 
491  while (numBytesToRead > 0)
492  {
493  if ((err = tty_timeout(fd, timeout)))
494  return err;
495 
496  bytesRead = read(fd, buffer + (*nbytes_read), ((uint32_t)numBytesToRead));
497 
498  if (bytesRead < 0)
499  return TTY_READ_ERROR;
500 
501  if (tty_debug)
502  {
503  IDLog("%d bytes read and %d bytes remaining...\n", bytesRead, numBytesToRead - bytesRead);
504  int i = 0;
505  for (i = *nbytes_read; i < (*nbytes_read + bytesRead); i++)
506  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char)buf[i], buf[i]);
507  }
508 
509  if (*nbytes_read == 0 && tty_clear_trailing_lf && *buffer == 0x0A)
510  {
511  if (tty_debug)
512  IDLog("%s: Cleared LF char left in buf\n", __FUNCTION__);
513 
514  memcpy(buffer, buffer+1,bytesRead);
515  --bytesRead;
516  }
517 
518  *nbytes_read += bytesRead;
519  numBytesToRead -= bytesRead;
520  }
521 
522 
523  if (tty_gemini_udp_format)
524  {
525  int *intSizedBuffer = (int *)geminiBuffer;
526  if (intSizedBuffer[0] != tty_sequence_number)
527  {
528  // Not the right reply just do the read again.
529  return tty_read(fd, buf, nbytes, timeout, nbytes_read);
530  }
531 
532  *nbytes_read -= 8;
533  memcpy(buf, geminiBuffer+8, *nbytes_read);
534  }
535 
536  return TTY_OK;
537 
538 #endif
539 }
540 
541 int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
542 {
543 #ifdef _WIN32
544  return TTY_ERRNO;
545 #else
546 
547  char readBuffer[257]={0};
548 
549  if (fd == -1)
550  return TTY_ERRNO;
551 
552  int bytesRead = 0;
553  int err = TTY_OK;
554  *nbytes_read = 0;
555 
556  uint8_t *read_char = 0;
557 
558  if (tty_debug)
559  IDLog("%s: Request to read until stop char '%#02X' with %d timeout for fd %d\n", __FUNCTION__, stop_char, timeout, fd);
560 
561  if (tty_gemini_udp_format)
562  {
563  bytesRead = read(fd, readBuffer, 255);
564 
565  if (bytesRead < 0)
566  return TTY_READ_ERROR;
567 
568  int *intSizedBuffer = (int *)readBuffer;
569  if (intSizedBuffer[0] != tty_sequence_number)
570  {
571  // Not the right reply just do the read again.
572  return tty_read_section(fd, buf, stop_char, timeout, nbytes_read);
573  }
574 
575  for (int index = 8; index < bytesRead; index++)
576  {
577  (*nbytes_read)++;
578 
579  if (*(readBuffer+index) == stop_char)
580  {
581  strncpy(buf, readBuffer+8, *nbytes_read);
582  return TTY_OK;
583  }
584  }
585  }
586  else if (tty_generic_udp_format)
587  {
588  bytesRead = read(fd, readBuffer, 255);
589  if (bytesRead < 0)
590  return TTY_READ_ERROR;
591  for (int index = 0; index < bytesRead; index++)
592  {
593  (*nbytes_read)++;
594 
595  if (*(readBuffer+index) == stop_char)
596  {
597  strncpy(buf, readBuffer, *nbytes_read);
598  return TTY_OK;
599  }
600  }
601  }
602  else
603  {
604  for (;;)
605  {
606  if ((err = tty_timeout(fd, timeout)))
607  return err;
608 
609  read_char = (uint8_t*)(buf + *nbytes_read);
610  bytesRead = read(fd, read_char, 1);
611 
612  if (bytesRead < 0)
613  return TTY_READ_ERROR;
614 
615  if (tty_debug)
616  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, (*nbytes_read), *read_char, *read_char);
617 
618  if (!(tty_clear_trailing_lf && *read_char == 0X0A && *nbytes_read == 0))
619  (*nbytes_read)++;
620  else {
621  if (tty_debug)
622  IDLog("%s: Cleared LF char left in buf\n", __FUNCTION__);
623  }
624 
625  if (*read_char == stop_char) {
626  return TTY_OK;
627  }
628  }
629  }
630 
631  return TTY_TIME_OUT;
632 
633 #endif
634 }
635 
636 int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
637 {
638 #ifdef _WIN32
639  return TTY_ERRNO;
640 #else
641 
642  if (fd == -1)
643  return TTY_ERRNO;
644 
645  // For Gemini
646  if (tty_gemini_udp_format || tty_generic_udp_format)
647  return tty_read_section(fd, buf, stop_char, timeout, nbytes_read);
648 
649  int bytesRead = 0;
650  int err = TTY_OK;
651  *nbytes_read = 0;
652  uint8_t *read_char = 0;
653  memset(buf, 0, nsize);
654 
655  if (tty_debug)
656  IDLog("%s: Request to read until stop char '%#02X' with %d timeout for fd %d\n", __FUNCTION__, stop_char, timeout, fd);
657 
658  for (;;)
659  {
660  if ((err = tty_timeout(fd, timeout)))
661  return err;
662 
663  read_char = (uint8_t*)(buf + *nbytes_read);
664  bytesRead = read(fd, read_char, 1);
665 
666  if (bytesRead < 0)
667  return TTY_READ_ERROR;
668 
669  if (tty_debug)
670  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, (*nbytes_read), *read_char, *read_char);
671 
672  if (!(tty_clear_trailing_lf && *read_char == 0X0A && *nbytes_read == 0))
673  (*nbytes_read)++;
674  else {
675  if (tty_debug)
676  IDLog("%s: Cleared LF char left in buf\n", __FUNCTION__);
677  }
678 
679  if (*read_char == stop_char)
680  return TTY_OK;
681  else if (*nbytes_read >= nsize)
682  return TTY_OVERFLOW;
683  }
684 
685 #endif
686 }
687 
688 #if defined(BSD) && !defined(__GNU__)
689 // BSD - OSX version
690 int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
691 {
692  int t_fd = -1;
693  int bps;
694  char msg[80];
695  int handshake;
696  struct termios tty_setting;
697 
698  // Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
699  // The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
700  // See open(2) ("man 2 open") for details.
701 
702  t_fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
703  if (t_fd == -1)
704  {
705  IDLog("Error opening serial port (%s) - %s(%d).\n", device, strerror(errno), errno);
706  goto error;
707  }
708 
709  // Note that open() follows POSIX semantics: multiple open() calls to the same file will succeed
710  // unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned
711  // processes.
712  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
713 
714  if (ioctl(t_fd, TIOCEXCL) == -1)
715  {
716  IDLog("Error setting TIOCEXCL on %s - %s(%d).\n", device, strerror(errno), errno);
717  goto error;
718  }
719 
720  // Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block.
721  // See fcntl(2) ("man 2 fcntl") for details.
722 
723  if (fcntl(t_fd, F_SETFL, 0) == -1)
724  {
725  IDLog("Error clearing O_NONBLOCK %s - %s(%d).\n", device, strerror(errno), errno);
726  goto error;
727  }
728 
729  // Get the current options and save them so we can restore the default settings later.
730  if (tcgetattr(t_fd, &tty_setting) == -1)
731  {
732  IDLog("Error getting tty attributes %s - %s(%d).\n", device, strerror(errno), errno);
733  goto error;
734  }
735 
736  // Set raw input (non-canonical) mode, with reads blocking until either a single character
737  // has been received or a one second timeout expires.
738  // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") for details.
739 
740  cfmakeraw(&tty_setting);
741  tty_setting.c_cc[VMIN] = 1;
742  tty_setting.c_cc[VTIME] = 10;
743 
744  // The baud rate, word length, and handshake options can be set as follows:
745  switch (bit_rate)
746  {
747  case 0: bps = B0; break;
748  case 50: bps = B50; break;
749  case 75: bps = B75; break;
750  case 110: bps = B110; break;
751  case 134: bps = B134; break;
752  case 150: bps = B150; break;
753  case 200: bps = B200; break;
754  case 300: bps = B300; break;
755  case 600: bps = B600; break;
756  case 1200: bps = B1200; break;
757  case 1800: bps = B1800; break;
758  case 2400: bps = B2400; break;
759  case 4800: bps = B4800; break;
760  case 9600: bps = B9600; break;
761  case 19200: bps = B19200; break;
762  case 38400: bps = B38400; break;
763  case 57600: bps = B57600; break;
764  case 115200: bps = B115200; break;
765  case 230400: bps = B230400; break;
766 #ifndef __APPLE__
767  case 460800: bps = B460800; break;
768  case 576000: bps = B576000; break;
769  case 921600: bps = B921600; break;
770 #endif
771  default:
772  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
773  perror(NULL);
774  else
775  perror(msg);
776  return TTY_PARAM_ERROR;
777  }
778 
779  cfsetspeed(&tty_setting, bps); // Set baud rate
780  /* word size */
781  switch (word_size)
782  {
783  case 5: tty_setting.c_cflag |= CS5; break;
784  case 6: tty_setting.c_cflag |= CS6; break;
785  case 7: tty_setting.c_cflag |= CS7; break;
786  case 8: tty_setting.c_cflag |= CS8; break;
787  default:
788  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
789  perror(NULL);
790  else
791  perror(msg);
792 
793  return TTY_PARAM_ERROR;
794  }
795 
796  /* parity */
797  switch (parity)
798  {
799  case PARITY_NONE:
800  break;
801  case PARITY_EVEN:
802  tty_setting.c_cflag |= PARENB;
803  break;
804  case PARITY_ODD:
805  tty_setting.c_cflag |= PARENB | PARODD;
806  break;
807  default:
808  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
809  perror(NULL);
810  else
811  perror(msg);
812 
813  return TTY_PARAM_ERROR;
814  }
815 
816  /* stop_bits */
817  switch (stop_bits)
818  {
819  case 1:
820  break;
821  case 2:
822  tty_setting.c_cflag |= CSTOPB;
823  break;
824  default:
825  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
826  perror(NULL);
827  else
828  perror(msg);
829 
830  return TTY_PARAM_ERROR;
831  }
832 
833 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
834  // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
835  // other than those specified by POSIX. The driver for the underlying serial hardware
836  // ultimately determines which baud rates can be used. This ioctl sets both the input
837  // and output speed.
838 
839  speed_t speed = 14400; // Set 14400 baud
840  if (ioctl(t_fd, IOSSIOSPEED, &speed) == -1)
841  {
842  IDLog("Error calling ioctl(..., IOSSIOSPEED, ...) - %s(%d).\n", strerror(errno), errno);
843  }
844 #endif
845 
846  // Cause the new options to take effect immediately.
847  if (tcsetattr(t_fd, TCSANOW, &tty_setting) == -1)
848  {
849  IDLog("Error setting tty attributes %s - %s(%d).\n", device, strerror(errno), errno);
850  goto error;
851  }
852 
853  // To set the modem handshake lines, use the following ioctls.
854  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
855 
856  if (ioctl(t_fd, TIOCSDTR) == -1) // Assert Data Terminal Ready (DTR)
857  {
858  IDLog("Error asserting DTR %s - %s(%d).\n", device, strerror(errno), errno);
859  }
860 
861  if (ioctl(t_fd, TIOCCDTR) == -1) // Clear Data Terminal Ready (DTR)
862  {
863  IDLog("Error clearing DTR %s - %s(%d).\n", device, strerror(errno), errno);
864  }
865 
866  handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
867  if (ioctl(t_fd, TIOCMSET, &handshake) == -1)
868  // Set the modem lines depending on the bits set in handshake
869  {
870  IDLog("Error setting handshake lines %s - %s(%d).\n", device, strerror(errno), errno);
871  }
872 
873  // To read the state of the modem lines, use the following ioctl.
874  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
875 
876  if (ioctl(t_fd, TIOCMGET, &handshake) == -1)
877  // Store the state of the modem lines in handshake
878  {
879  IDLog("Error getting handshake lines %s - %s(%d).\n", device, strerror(errno), errno);
880  }
881 
882  IDLog("Handshake lines currently set to %d\n", handshake);
883 
884 #if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
885  unsigned long mics = 1UL;
886 
887  // Set the receive latency in microseconds. Serial drivers use this value to determine how often to
888  // dequeue characters received by the hardware. Most applications don't need to set this value: if an
889  // app reads lines of characters, the app can't do anything until the line termination character has been
890  // received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA
891  // applications.
892 
893  if (ioctl(t_fd, IOSSDATALAT, &mics) == -1)
894  {
895  // set latency to 1 microsecond
896  IDLog("Error setting read latency %s - %s(%d).\n", device, strerror(errno), errno);
897  goto error;
898  }
899 #endif
900 
901  *fd = t_fd;
902  /* return success */
903  return TTY_OK;
904 
905  // Failure path
906 error:
907  if (t_fd != -1)
908  {
909  close(t_fd);
910  *fd = -1;
911  }
912 
913  return TTY_PORT_FAILURE;
914 }
915 #else
916 int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
917 {
918 #ifdef _WIN32
919  return TTY_PORT_FAILURE;
920 
921 #else
922  int t_fd = -1;
923  int i = 0;
924  char msg[128]={0};
925  int bps;
926  struct termios tty_setting;
927  // Check for bluetooth & virtualcom which can be shared
928  int ignore_exclusive_close = strstr(device, "rfcomm") || strstr(device, "Bluetooth") || strstr(device, "virtualcom");
929 
930 
931  // Open as Read/Write, no fnctl, and close on exclusive
932  for (i = 0 ; i < 3 ; i++)
933  {
934  // Do not use O_CLOEXEC when ignored
935  t_fd = open(device, O_RDWR | O_NOCTTY | (ignore_exclusive_close ? 0 : O_CLOEXEC));
936  if (t_fd > 0)
937  break;
938  else
939  {
940  *fd = -1;
941  if (errno == EBUSY)
942  {
943  usleep(1e6);
944  continue;
945  }
946  else
947  return TTY_PORT_FAILURE;
948  }
949  }
950 
951  if (t_fd == -1)
952  return TTY_PORT_BUSY;
953 
954  // Set port in exclusive mode to prevent other non-root processes from opening it.
955  // JM 2019-08-12: Do not set it when ignored
956  if (ignore_exclusive_close == 0 && ioctl(t_fd, TIOCEXCL) == -1)
957  {
958  perror("tty_connect: Error setting TIOCEXC.");
959  close(t_fd);
960  return TTY_PORT_FAILURE;
961  }
962 
963  // Get the current options and save them so we can restore the default settings later.
964  if (tcgetattr(t_fd, &tty_setting) == -1)
965  {
966  perror("tty_connect: failed getting tty attributes.");
967  close(t_fd);
968  return TTY_PORT_FAILURE;
969  }
970 
971  /* Control Modes
972  Set bps rate */
973  switch (bit_rate)
974  {
975  case 0: bps = B0; break;
976  case 50: bps = B50; break;
977  case 75: bps = B75; break;
978  case 110: bps = B110; break;
979  case 134: bps = B134; break;
980  case 150: bps = B150; break;
981  case 200: bps = B200; break;
982  case 300: bps = B300; break;
983  case 600: bps = B600; break;
984  case 1200: bps = B1200; break;
985  case 1800: bps = B1800; break;
986  case 2400: bps = B2400; break;
987  case 4800: bps = B4800; break;
988  case 9600: bps = B9600; break;
989  case 19200: bps = B19200; break;
990  case 38400: bps = B38400; break;
991  case 57600: bps = B57600; break;
992  case 115200: bps = B115200; break;
993  case 230400: bps = B230400; break;
994  case 460800: bps = B460800; break;
995  case 576000: bps = B576000; break;
996  case 921600: bps = B921600; break;
997  default:
998  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
999  perror(NULL);
1000  else
1001  perror(msg);
1002  close(t_fd);
1003  return TTY_PARAM_ERROR;
1004  }
1005  if ((cfsetispeed(&tty_setting, bps) < 0) || (cfsetospeed(&tty_setting, bps) < 0))
1006  {
1007  perror("tty_connect: failed setting bit rate.");
1008  close(t_fd);
1009  return TTY_PORT_FAILURE;
1010  }
1011 
1012  /* Control Modes
1013  set no flow control word size, parity and stop bits.
1014  Also don't hangup automatically and ignore modem status.
1015  Finally enable receiving characters. */
1016  tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS);
1017  tty_setting.c_cflag |= (CLOCAL | CREAD);
1018 
1019  /* word size */
1020  switch (word_size)
1021  {
1022  case 5: tty_setting.c_cflag |= CS5; break;
1023  case 6: tty_setting.c_cflag |= CS6; break;
1024  case 7: tty_setting.c_cflag |= CS7; break;
1025  case 8: tty_setting.c_cflag |= CS8; break;
1026  default:
1027 
1028  fprintf(stderr, "Default\n");
1029  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
1030  perror(NULL);
1031  else
1032  perror(msg);
1033 
1034  close(t_fd);
1035  return TTY_PARAM_ERROR;
1036  }
1037 
1038  /* parity */
1039  switch (parity)
1040  {
1041  case PARITY_NONE:
1042  break;
1043  case PARITY_EVEN:
1044  tty_setting.c_cflag |= PARENB;
1045  break;
1046  case PARITY_ODD:
1047  tty_setting.c_cflag |= PARENB | PARODD;
1048  break;
1049  default:
1050 
1051  fprintf(stderr, "Default1\n");
1052  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
1053  perror(NULL);
1054  else
1055  perror(msg);
1056 
1057  close(t_fd);
1058  return TTY_PARAM_ERROR;
1059  }
1060 
1061  /* stop_bits */
1062  switch (stop_bits)
1063  {
1064  case 1:
1065  break;
1066  case 2:
1067  tty_setting.c_cflag |= CSTOPB;
1068  break;
1069  default:
1070  fprintf(stderr, "Default2\n");
1071  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
1072  perror(NULL);
1073  else
1074  perror(msg);
1075 
1076  close(t_fd);
1077  return TTY_PARAM_ERROR;
1078  }
1079  /* Control Modes complete */
1080 
1081  /* Ignore bytes with parity errors and make terminal raw and dumb.*/
1082  tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY);
1083  tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK;
1084 
1085  /* Raw output.*/
1086  tty_setting.c_oflag &= ~(OPOST | ONLCR);
1087 
1088  /* Local Modes
1089  Don't echo characters. Don't generate signals.
1090  Don't process any characters.*/
1091  tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP);
1092  tty_setting.c_lflag |= NOFLSH;
1093 
1094  /* blocking read until 1 char arrives */
1095  tty_setting.c_cc[VMIN] = 1;
1096  tty_setting.c_cc[VTIME] = 0;
1097 
1098  /* now clear input and output buffers and activate the new terminal settings */
1099  tcflush(t_fd, TCIOFLUSH);
1100  if (tcsetattr(t_fd, TCSANOW, &tty_setting))
1101  {
1102  perror("tty_connect: failed setting attributes on serial port.");
1103  tty_disconnect(t_fd);
1104  return TTY_PORT_FAILURE;
1105  }
1106 
1107  *fd = t_fd;
1108  /* return success */
1109  return TTY_OK;
1110 #endif
1111 }
1112 // Unix - Linux version
1113 
1114 #endif
1115 
1117 {
1118  if (fd == -1)
1119  return TTY_ERRNO;
1120 
1121 #ifdef _WIN32
1122  return TTY_ERRNO;
1123 #else
1124  int err;
1125  tcflush(fd, TCIOFLUSH);
1126  err = close(fd);
1127 
1128  if (err != 0)
1129  return TTY_ERRNO;
1130 
1131  return TTY_OK;
1132 #endif
1133 }
1134 
1135 void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
1136 {
1137  switch (err_code)
1138  {
1139  case TTY_OK:
1140  snprintf(err_msg, err_msg_len, "No Error");
1141  break;
1142 
1143  case TTY_READ_ERROR:
1144  snprintf(err_msg, err_msg_len, "Read Error: %s", strerror(errno));
1145  break;
1146 
1147  case TTY_WRITE_ERROR:
1148  snprintf(err_msg, err_msg_len, "Write Error: %s", strerror(errno));
1149  break;
1150 
1151  case TTY_SELECT_ERROR:
1152  snprintf(err_msg, err_msg_len, "Select Error: %s", strerror(errno));
1153  break;
1154 
1155  case TTY_TIME_OUT:
1156  snprintf(err_msg, err_msg_len, "Timeout error");
1157  break;
1158 
1159  case TTY_PORT_FAILURE:
1160  if (errno == EACCES)
1161  snprintf(err_msg, err_msg_len,
1162  "Port failure Error: %s. Try adding your user to the dialout group and restart (sudo adduser "
1163  "$USER dialout)",
1164  strerror(errno));
1165  else
1166  snprintf(err_msg, err_msg_len, "Port failure Error: %s. Check if device is connected to this port.",
1167  strerror(errno));
1168 
1169  break;
1170 
1171  case TTY_PARAM_ERROR:
1172  snprintf(err_msg, err_msg_len, "Parameter error");
1173  break;
1174 
1175  case TTY_ERRNO:
1176  snprintf(err_msg, err_msg_len, "%s", strerror(errno));
1177  break;
1178 
1179  case TTY_OVERFLOW:
1180  snprintf(err_msg, err_msg_len, "Read overflow");
1181  break;
1182 
1183  case TTY_PORT_BUSY:
1184  snprintf(err_msg, err_msg_len, "Port is busy");
1185  break;
1186 
1187  default:
1188  snprintf(err_msg, err_msg_len, "Error: unrecognized error code");
1189  break;
1190  }
1191 }
1192 
1193 /* return static string corresponding to the given property or light state */
1194 const char *pstateStr(IPState s)
1195 {
1196  switch (s)
1197  {
1198  case IPS_IDLE: return "Idle";
1199  case IPS_OK: return "Ok";
1200  case IPS_BUSY: return "Busy";
1201  case IPS_ALERT: return "Alert";
1202  default:
1203  fprintf(stderr, "Impossible IPState %d\n", s);
1204  return NULL;
1205  }
1206 }
1207 
1208 /* crack string into IPState.
1209  * return 0 if ok, else -1
1210  */
1211 int crackIPState(const char *str, IPState *ip)
1212 {
1213  if (!strcmp(str, "Idle"))
1214  *ip = IPS_IDLE;
1215  else if (!strncmp(str, "Ok", 2))
1216  *ip = IPS_OK;
1217  else if (!strcmp(str, "Busy"))
1218  *ip = IPS_BUSY;
1219  else if (!strcmp(str, "Alert"))
1220  *ip = IPS_ALERT;
1221  else
1222  return (-1);
1223  return (0);
1224 }
1225 
1226 /* crack string into ISState.
1227  * return 0 if ok, else -1
1228  */
1229 int crackISState(const char *str, ISState *ip)
1230 {
1231  if (!strncmp(str, "On", 2))
1232  *ip = ISS_ON;
1233  else if (!strcmp(str, "Off"))
1234  *ip = ISS_OFF;
1235  else
1236  return (-1);
1237  return (0);
1238 }
1239 
1240 int crackIPerm(const char *str, IPerm *ip)
1241 {
1242  if (!strncmp(str, "rw", 2))
1243  *ip = IP_RW;
1244  else if (!strncmp(str, "ro", 2))
1245  *ip = IP_RO;
1246  else if (!strncmp(str, "wo", 2))
1247  *ip = IP_WO;
1248  else
1249  return (-1);
1250  return (0);
1251 }
1252 
1253 int crackISRule(const char *str, ISRule *ip)
1254 {
1255  if (!strcmp(str, "OneOfMany"))
1256  *ip = ISR_1OFMANY;
1257  else if (!strcmp(str, "AtMostOne"))
1258  *ip = ISR_ATMOST1;
1259  else if (!strcmp(str, "AnyOfMany"))
1260  *ip = ISR_NOFMANY;
1261  else
1262  return (-1);
1263  return (0);
1264 }
1265 
1266 /* return static string corresponding to the given switch state */
1267 const char *sstateStr(ISState s)
1268 {
1269  switch (s)
1270  {
1271  case ISS_ON: return "On";
1272  case ISS_OFF: return "Off";
1273  default:
1274  fprintf(stderr, "Impossible ISState %d\n", s);
1275  return NULL;
1276  }
1277 }
1278 
1279 /* return static string corresponding to the given Rule */
1280 const char *ruleStr(ISRule r)
1281 {
1282  switch (r)
1283  {
1284  case ISR_1OFMANY: return "OneOfMany";
1285  case ISR_ATMOST1: return "AtMostOne";
1286  case ISR_NOFMANY: return "AnyOfMany";
1287  default:
1288  fprintf(stderr, "Impossible ISRule %d\n", r);
1289  return NULL;
1290  }
1291 }
1292 
1293 /* return static string corresponding to the given IPerm */
1294 const char *permStr(IPerm p)
1295 {
1296  switch (p)
1297  {
1298  case IP_RO: return "ro";
1299  case IP_WO: return "wo";
1300  case IP_RW: return "rw";
1301  default:
1302  fprintf(stderr, "Impossible IPerm %d\n", p);
1303  return NULL;
1304  }
1305 }
1306 
1307 /* print the boilerplate comment introducing xml */
1308 void xmlv1()
1309 {
1310  userio_xmlv1(userio_file(), stdout);
1311 }
1312 
1313 
1314 /* pull out device and name attributes from root.
1315  * return 0 if ok else -1 with reason in msg[].
1316  */
1317 int crackDN(XMLEle *root, char **dev, char **name, char msg[])
1318 {
1319  XMLAtt *ap;
1320 
1321  ap = findXMLAtt(root, "device");
1322  if (!ap)
1323  {
1324  sprintf(msg, "%s requires 'device' attribute", tagXMLEle(root));
1325  return (-1);
1326  }
1327  *dev = valuXMLAtt(ap);
1328 
1329  ap = findXMLAtt(root, "name");
1330  if (!ap)
1331  {
1332  sprintf(msg, "%s requires 'name' attribute", tagXMLEle(root));
1333  return (-1);
1334  }
1335  *name = valuXMLAtt(ap);
1336 
1337  return (0);
1338 }
1339 
1340 /* find a member of an IText vector, else NULL */
1341 IText *IUFindText(const ITextVectorProperty *tvp, const char *name)
1342 {
1343  for (int i = 0; i < tvp->ntp; i++)
1344  if (strcmp(tvp->tp[i].name, name) == 0)
1345  return (&tvp->tp[i]);
1346  fprintf(stderr, "No IText '%s' in %s.%s\n", name, tvp->device, tvp->name);
1347  return (NULL);
1348 }
1349 
1350 /* find a member of an INumber vector, else NULL */
1351 INumber *IUFindNumber(const INumberVectorProperty *nvp, const char *name)
1352 {
1353  for (int i = 0; i < nvp->nnp; i++)
1354  if (strcmp(nvp->np[i].name, name) == 0)
1355  return (&nvp->np[i]);
1356  fprintf(stderr, "No INumber '%s' in %s.%s\n", name, nvp->device, nvp->name);
1357  return (NULL);
1358 }
1359 
1360 /* find a member of an ISwitch vector, else NULL */
1361 ISwitch *IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
1362 {
1363  for (int i = 0; i < svp->nsp; i++)
1364  if (strcmp(svp->sp[i].name, name) == 0)
1365  return (&svp->sp[i]);
1366  fprintf(stderr, "No ISwitch '%s' in %s.%s\n", name, svp->device, svp->name);
1367  return (NULL);
1368 }
1369 
1370 /* find a member of an ILight vector, else NULL */
1371 ILight *IUFindLight(const ILightVectorProperty *lvp, const char *name)
1372 {
1373  for (int i = 0; i < lvp->nlp; i++)
1374  if (strcmp(lvp->lp[i].name, name) == 0)
1375  return (&lvp->lp[i]);
1376  fprintf(stderr, "No ILight '%s' in %s.%s\n", name, lvp->device, lvp->name);
1377  return (NULL);
1378 }
1379 
1380 /* find a member of an IBLOB vector, else NULL */
1381 IBLOB *IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
1382 {
1383  for (int i = 0; i < bvp->nbp; i++)
1384  if (strcmp(bvp->bp[i].name, name) == 0)
1385  return (&bvp->bp[i]);
1386  fprintf(stderr, "No IBLOB '%s' in %s.%s\n", name, bvp->device, bvp->name);
1387  return (NULL);
1388 }
1389 
1390 /* find an ON member of an ISwitch vector, else NULL.
1391  * N.B. user must make sense of result with ISRule in mind.
1392  */
1394 {
1395  for (int i = 0; i < svp->nsp; i++)
1396  if (svp->sp[i].s == ISS_ON)
1397  return (&svp->sp[i]);
1398  /*fprintf(stderr, "No ISwitch On in %s.%s\n", svp->device, svp->name);*/
1399  return (NULL);
1400 }
1401 
1402 /* Find index of the ON member of an ISwitchVectorProperty */
1404 {
1405  for (int i = 0; i < svp->nsp; i++)
1406  if (svp->sp[i].s == ISS_ON)
1407  return i;
1408  return -1;
1409 }
1410 
1411 /* Find name the ON member in the given states and names */
1412 const char *IUFindOnSwitchName(ISState *states, char *names[], int n)
1413 {
1414  for (int i = 0; i < n; i++)
1415  if (states[i] == ISS_ON)
1416  return names[i];
1417  return NULL;
1418 }
1419 
1420 /* Set all switches to off */
1422 {
1423  for (int i = 0; i < svp->nsp; i++)
1424  svp->sp[i].s = ISS_OFF;
1425 }
1426 
1427 /* save malloced copy of newtext in tp->text, reusing if not first time */
1428 void IUSaveText(IText *tp, const char *newtext)
1429 {
1430  /* copy in fresh string */
1431  tp->text = strcpy(realloc(tp->text, strlen(newtext) + 1), newtext);
1432 }
1433 
1434 void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
1435 {
1436  IUUserIONewNumber(userio_file(), fp, nvp);
1437 }
1438 
1439 void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
1440 {
1441  IUUserIONewText(userio_file(), fp, tvp);
1442 }
1443 
1444 void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
1445 {
1446  IUUserIONewSwitchFull(userio_file(), fp, svp);
1447 }
1448 
1449 void IUSaveConfigBLOB(FILE *fp, const IBLOBVectorProperty *bvp)
1450 {
1451  IUUserIONewBLOB(userio_file(), fp, bvp);
1452 }
1453 
1454 double rangeHA(double r)
1455 {
1456  double res = r;
1457  while (res < -12.0)
1458  res += 24.0;
1459  while (res >= 12.0)
1460  res -= 24.0;
1461  return res;
1462 }
1463 
1464 double range24(double r)
1465 {
1466  double res = r;
1467  while (res < 0.0)
1468  res += 24.0;
1469  while (res > 24.0)
1470  res -= 24.0;
1471  return res;
1472 }
1473 
1474 double range360(double r)
1475 {
1476  double res = r;
1477  while (res < 0.0)
1478  res += 360.0;
1479  while (res > 360.0)
1480  res -= 360.0;
1481  return res;
1482 }
1483 
1484 double rangeDec(double decdegrees)
1485 {
1486  if ((decdegrees >= 270.0) && (decdegrees <= 360.0))
1487  return (decdegrees - 360.0);
1488  if ((decdegrees >= 180.0) && (decdegrees < 270.0))
1489  return (180.0 - decdegrees);
1490  if ((decdegrees >= 90.0) && (decdegrees < 180.0))
1491  return (180.0 - decdegrees);
1492  return decdegrees;
1493 }
1494 
1495 #if defined(HAVE_LIBNOVA)
1496 double get_local_sidereal_time(double longitude)
1497 {
1498  return range24(ln_get_apparent_sidereal_time(ln_get_julian_from_sys()) + longitude / 15.0);
1499 }
1500 
1501 void get_hrz_from_equ(struct ln_equ_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_hrz_posn *position)
1502 {
1503  ln_get_hrz_from_equ(object, observer, JD, position);
1504  position->az -= 180;
1505  if (position->az < 0)
1506  position->az += 360;
1507 }
1508 
1509 void get_equ_from_hrz(struct ln_hrz_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_equ_posn *position)
1510 {
1511  struct ln_hrz_posn libnova_object;
1512  libnova_object.az = object->az + 180;
1513  if (libnova_object.az > 360)
1514  libnova_object.az -= 360;
1515  libnova_object.alt = object->alt;
1516 
1517  ln_get_equ_from_hrz(&libnova_object, observer, JD, position);
1518 }
1519 
1520 #endif // HAVE_LIBNOVA
1521 
1522 double get_local_hour_angle(double sideral_time, double ra)
1523 {
1524  double HA = sideral_time - ra;
1525  return rangeHA(HA);
1526 }
1527 
1528 void get_alt_az_coordinates(double Ha, double Dec, double Lat, double* Alt, double *Az)
1529 {
1530  double alt, az;
1531  Ha *= M_PI / 180.0;
1532  Dec *= M_PI / 180.0;
1533  Lat *= M_PI / 180.0;
1534  alt = asin(sin(Dec) * sin(Lat) + cos(Dec) * cos(Lat) * cos(Ha));
1535  az = acos((sin(Dec) - sin(alt)*sin(Lat)) / (cos(alt) * cos(Lat)));
1536  alt *= 180.0 / M_PI;
1537  az *= 180.0 / M_PI;
1538  if (sin(Ha) >= 0.0)
1539  az = 360 - az;
1540  *Alt = alt;
1541  *Az = az;
1542 }
1543 
1544 double estimate_geocentric_elevation(double Lat, double El)
1545 {
1546  Lat *= M_PI / 180.0;
1547  Lat = sin(Lat);
1548  El += Lat * (EARTHRADIUSPOLAR - EARTHRADIUSEQUATORIAL);
1549  return El;
1550 }
1551 
1552 double estimate_field_rotation_rate(double Alt, double Az, double Lat)
1553 {
1554  Alt *= M_PI / 180.0;
1555  Az *= M_PI / 180.0;
1556  Lat *= M_PI / 180.0;
1557  double ret = cos(Lat) * cos(Az) / cos(Alt);
1558  ret *= 180.0 / M_PI;
1559  return ret;
1560 }
1561 
1562 double estimate_field_rotation(double HA, double rate)
1563 {
1564  HA *= rate;
1565  while(HA >= 360.0)
1566  HA -= 360.0;
1567  while(HA < 0)
1568  HA += 360.0;
1569  return HA;
1570 }
1571 
1572 double as2rad(double as)
1573 {
1574  return as * M_PI / (60.0*60.0*12.0);
1575 }
1576 
1577 double rad2as(double rad)
1578 {
1579  return rad * (60.0*60.0*12.0) / M_PI;
1580 }
1581 
1582 double estimate_distance(double parsecs, double parallax_radius)
1583 {
1584  return parallax_radius / sin(as2rad(parsecs));
1585 }
1586 
1587 double m2au(double m)
1588 {
1589  return m / ASTRONOMICALUNIT;
1590 }
1591 
1592 double calc_delta_magnitude(double mag_ratio, double *spectrum, double *ref_spectrum, int spectrum_size)
1593 {
1594  double delta_mag = 0;
1595  for(int l = 0; l < spectrum_size; l++) {
1596  delta_mag += spectrum[l] * mag_ratio * ref_spectrum[l] / spectrum[l];
1597  }
1598  delta_mag /= spectrum_size;
1599  return delta_mag;
1600 }
1601 
1602 double calc_star_mass(double delta_mag, double ref_size)
1603 {
1604  return delta_mag * ref_size;
1605 }
1606 
1607 double estimate_orbit_radius(double obs_lambda, double ref_lambda, double period)
1608 {
1609  return M_PI*2*DOPPLER(REDSHIFT(obs_lambda, ref_lambda), LIGHTSPEED)/period;
1610 }
1611 
1612 double estimate_secondary_mass(double star_mass, double star_drift, double orbit_radius)
1613 {
1614  return orbit_radius*pow(star_drift*orbit_radius, 3)*3*star_mass;
1615 }
1616 
1617 double estimate_secondary_size(double star_size, double dropoff_ratio)
1618 {
1619  return pow(dropoff_ratio*pow(star_size, 2), 0.5);
1620 }
1621 
1622 double calc_photon_flux(double rel_magnitude, double filter_bandwidth, double wavelength, double steradian)
1623 {
1624  return pow(10, rel_magnitude*-0.4)*(LUMEN(wavelength)*steradian*filter_bandwidth);
1625 }
1626 
1627 double calc_rel_magnitude(double photon_flux, double filter_bandwidth, double wavelength, double steradian)
1628 {
1629  return pow(10, 1.0/(photon_flux/(LUMEN(wavelength)*steradian*filter_bandwidth)))/-0.4;
1630 }
1631 
1632 double estimate_absolute_magnitude(double delta_dist, double delta_mag)
1633 {
1634  return sqrt(delta_dist) * delta_mag;
1635 }
1636 
1637 void baseline_2d_projection(double alt, double az, double baseline[3], double wavelength, double uvresult[2])
1638 {
1639  az *= M_PI / 180.0;
1640  alt *= M_PI / 180.0;
1641  uvresult[0] = (baseline[0] * sin(az) + baseline[1] * cos(az));
1642  uvresult[1] = (baseline[1] * sin(alt) * sin(az) - baseline[0] * sin(alt) * cos(az) + baseline[2] * cos(alt));
1643  uvresult[0] *= AIRY / wavelength;
1644  uvresult[1] *= AIRY / wavelength;
1645 }
1646 
1647 double baseline_delay(double alt, double az, double baseline[3])
1648 {
1649  az *= M_PI / 180.0;
1650  alt *= M_PI / 180.0;
1651  return cos(az) * baseline[1] * cos(alt) - baseline[0] * sin(az) * cos(alt) + sin(alt) * baseline[2];
1652 }
1653 
1654 #if defined(_MSC_VER)
1655 #undef snprintf
1656 #pragma warning(pop)
1657 #endif
numberFormat
int numberFormat(char *buf, const char *format, double value)
Fill buffer with properly formatted INumber string.
Definition: indicom.c:278
IP_RO
@ IP_RO
Definition: indiapi.h:183
crackDN
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indicom.c:1317
_IBLOBVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:472
TTY_TIME_OUT
@ TTY_TIME_OUT
Definition: indicom.h:98
_IBLOBVectorProperty::nbp
int nbp
Definition: indiapi.h:488
IP_WO
@ IP_WO
Definition: indiapi.h:184
rangeHA
double rangeHA(double r)
rangeHA Limits the hour angle value to be between -12 —> 12
Definition: indicom.c:1454
EARTHRADIUSPOLAR
#define EARTHRADIUSPOLAR
Definition: indicom.h:59
IPState
IPState
Property state.
Definition: indiapi.h:158
tty_nread_section
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:636
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1428
_ISwitchVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:368
IUFindText
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indicom.c:1341
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_ILightVectorProperty
Light vector property descriptor.
Definition: indiapi.h:415
ISwitch
One switch descriptor.
get_local_hour_angle
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition: indicom.c:1522
IUFindOnSwitchName
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
Definition: indicom.c:1412
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
tty_timeout
int tty_timeout(int fd, int timeout)
Definition: indicom.c:366
locale_compat.h
getSexComponents
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:244
ASTRONOMICALUNIT
#define ASTRONOMICALUNIT
Definition: indicom.h:72
tty_disconnect
int tty_disconnect(int fd)
Closes a tty connection and flushes the bus.
Definition: indicom.c:1116
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
f_scansexa
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:195
INumber
One number descriptor.
_INumberVectorProperty::nnp
int nnp
Definition: indiapi.h:336
estimate_field_rotation
double estimate_field_rotation(double HA, double rate)
estimate_field_rotation Returns an estimation of the field rotation rate of the object
Definition: indicom.c:1562
ISR_NOFMANY
@ ISR_NOFMANY
Definition: indiapi.h:174
_IBLOBVectorProperty
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:469
_ILightVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:418
IDLog
void IDLog(const char *fmt,...)
Definition: indicom.c:306
timestamp
const char * timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Definition: indicom.c:334
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
time_ns
double time_ns()
Get a unix timestamp with nanosecond precision.
Definition: indicom.c:316
tty_clr_trailing_read_lf
void tty_clr_trailing_read_lf(int enabled)
Definition: indicom.c:361
crackISRule
int crackISRule(const char *str, ISRule *ip)
Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string.
Definition: indicom.c:1253
indiuserio.h
estimate_absolute_magnitude
double estimate_absolute_magnitude(double delta_dist, double delta_mag)
estimate_absolute_magnitude Returns an estimation of the absolute magnitude of an object given its di...
Definition: indicom.c:1632
_ITextVectorProperty::ntp
int ntp
Definition: indiapi.h:263
TTY_READ_ERROR
@ TTY_READ_ERROR
Definition: indicom.h:95
TTY_OVERFLOW
@ TTY_OVERFLOW
Definition: indicom.h:102
pstateStr
const char * pstateStr(IPState s)
Definition: indicom.c:1194
_IBLOBVectorProperty::bp
IBLOB * bp
Definition: indiapi.h:486
range24
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition: indicom.c:1464
tty_read_section
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition: indicom.c:541
calc_delta_magnitude
double calc_delta_magnitude(double mag_ratio, double *spectrum, double *ref_spectrum, int spectrum_size)
calc_delta_magnitude Returns the difference of magnitudes given two spectra
Definition: indicom.c:1592
estimate_geocentric_elevation
double estimate_geocentric_elevation(double Lat, double El)
estimate_geocentric_elevation Returns an estimation of the actual geocentric elevation
Definition: indicom.c:1544
IUFindBLOB
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition: indicom.c:1381
_ILightVectorProperty::nlp
int nlp
Definition: indiapi.h:430
tty_set_gemini_udp_format
void tty_set_gemini_udp_format(int enabled)
Definition: indicom.c:351
m2au
double m2au(double m)
m2au Convert meters into astronomical units
Definition: indicom.c:1587
_ITextVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:247
IUUserIONewNumber
void IUUserIONewNumber(const userio *io, void *user, const INumberVectorProperty *nvp)
Definition: indiuserio.c:189
permStr
const char * permStr(IPerm p)
Definition: indicom.c:1294
range360
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition: indicom.c:1474
_ILightVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:420
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1135
estimate_secondary_mass
double estimate_secondary_mass(double star_mass, double star_drift, double orbit_radius)
estimate the mass of an object with known mass orbiting around a star.
Definition: indicom.c:1612
_ITextVectorProperty
Text vector property descriptor.
Definition: indiapi.h:244
tty_read
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:462
AIRY
#define AIRY
Definition: indicom.h:67
IUUserIONewBLOB
void IUUserIONewBLOB(const userio *io, void *user, const IBLOBVectorProperty *bvp)
Definition: indiuserio.c:241
device
hid_device * device
Definition: activefocuser_utils.cpp:92
PARITY_NONE
#define PARITY_NONE
Definition: indicom.c:77
TTY_PARAM_ERROR
@ TTY_PARAM_ERROR
Definition: indicom.h:100
PARITY_ODD
#define PARITY_ODD
Definition: indicom.c:79
ILight
One light descriptor.
_ITextVectorProperty::tp
IText * tp
Definition: indiapi.h:261
_INumberVectorProperty
Number vector property descriptor.
Definition: indiapi.h:317
IUSaveConfigText
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indicom.c:1439
ruleStr
const char * ruleStr(ISRule r)
Definition: indicom.c:1280
rad2as
double rad2as(double rad)
rad2as Convert radians into arcseconds
Definition: indicom.c:1577
TTY_PORT_FAILURE
@ TTY_PORT_FAILURE
Definition: indicom.h:99
IUUserIONewText
void IUUserIONewText(const userio *io, void *user, const ITextVectorProperty *tvp)
Definition: indiuserio.c:206
ra
double ra
Definition: ieqprolegacydriver.cpp:43
IText
One text descriptor.
_ISwitchVectorProperty::nsp
int nsp
Definition: indiapi.h:386
indidevapi.h
Interface to the reference INDI C API device implementation on the Device Driver side.
estimate_field_rotation_rate
double estimate_field_rotation_rate(double Alt, double Az, double Lat)
estimate_field_rotation_rate Returns an estimation of the field rotation rate of the object
Definition: indicom.c:1552
calc_rel_magnitude
double calc_rel_magnitude(double photon_flux, double filter_bandwidth, double wavelength, double steradian)
calc_rel_magnitude Returns the relative magnitude of the object with the given photon flux measured a...
Definition: indicom.c:1627
xmlv1
void xmlv1()
Definition: indicom.c:1308
tty_write
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:404
calc_photon_flux
double calc_photon_flux(double rel_magnitude, double filter_bandwidth, double wavelength, double steradian)
calc_photon_flux Returns the photon flux of the object with the given magnitude observed at a determi...
Definition: indicom.c:1622
TTY_ERRNO
@ TTY_ERRNO
Definition: indicom.h:101
crackIPerm
int crackIPerm(const char *str, IPerm *ip)
Extract property permission state (RW, RO, WO) from the supplied string.
Definition: indicom.c:1240
IUFindOnSwitch
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition: indicom.c:1393
xml_att_
Definition: lilxml.c:120
as2rad
double as2rad(double as)
as2rad Convert arcseconds into radians
Definition: indicom.c:1572
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1444
get_hrz_from_equ
void get_hrz_from_equ(struct ln_equ_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_hrz_posn *position)
get_hrz_from_equ Calculate horizontal coordinates from equatorial coordinates.
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
crackISState
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indicom.c:1229
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1421
base64.h
_INumberVectorProperty::np
INumber * np
Definition: indiapi.h:334
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
IUUserIONewSwitchFull
void IUUserIONewSwitchFull(const userio *io, void *user, const ISwitchVectorProperty *svp)
Definition: indiuserio.c:219
tty_connect
int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
Establishes a tty connection to a terminal device.
Definition: indicom.c:916
TTY_WRITE_ERROR
@ TTY_WRITE_ERROR
Definition: indicom.h:96
extractISOTime
int extractISOTime(const char *timestr, struct ln_date *iso_date)
Extract ISO 8601 time and store it in a tm struct.
tagXMLEle
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:569
xml_ele_
Definition: lilxml.c:105
tty_set_debug
void tty_set_debug(int debug)
tty_set_debug Enable or disable debug which prints verbose information.
Definition: indicom.c:346
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
estimate_orbit_radius
double estimate_orbit_radius(double obs_lambda, double ref_lambda, double period)
estimate the orbit radius of an object with known mass orbiting around a star.
Definition: indicom.c:1607
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1403
estimate_secondary_size
double estimate_secondary_size(double star_size, double dropoff_ratio)
estimate the size of an object occulting a star in star_size units.
Definition: indicom.c:1617
REDSHIFT
#define REDSHIFT(wavelength, reference)
Definition: indicom.h:80
LUMEN
#define LUMEN(wavelength)
Definition: indicom.h:79
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
IPerm
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:181
MAXINDIFORMAT
#define MAXINDIFORMAT
Definition: indiapi.h:194
get_local_sidereal_time
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
get_alt_az_coordinates
void get_alt_az_coordinates(double Ha, double Dec, double Lat, double *Alt, double *Az)
get_alt_az_coordinates Returns alt-azimuth coordinates of an object
Definition: indicom.c:1528
fd
int fd
Definition: intelliscope.c:43
baseline_2d_projection
void baseline_2d_projection(double alt, double az, double baseline[3], double wavelength, double uvresult[2])
baseline_2d_projection Returns the coordinates of the projection of a single baseline targeting the o...
Definition: indicom.c:1637
get_equ_from_hrz
void get_equ_from_hrz(struct ln_hrz_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_equ_posn *position)
ln_get_equ_from_hrz Calculate Equatorial EOD Coordinates from horizontal coordinates
locale_char_t
char locale_char_t
Definition: locale_compat.h:62
PARITY_EVEN
#define PARITY_EVEN
Definition: indicom.c:78
DOPPLER
#define DOPPLER(shift, speed)
Definition: indicom.h:81
calc_star_mass
double calc_star_mass(double delta_mag, double ref_size)
Definition: indicom.c:1602
sstateStr
const char * sstateStr(ISState s)
Definition: indicom.c:1267
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1434
IUFindNumber
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1351
tty_setting
struct termios tty_setting
Definition: stvdriver.c:51
estimate_distance
double estimate_distance(double parsecs, double parallax_radius)
estimate_distance Convert parallax arcseconds into meters
Definition: indicom.c:1582
TTY_SELECT_ERROR
@ TTY_SELECT_ERROR
Definition: indicom.h:97
baseline_delay
double baseline_delay(double alt, double az, double baseline[3])
baseline_delay Returns the delay in meters of a single baseline targeting the object by coordinates
Definition: indicom.c:1647
valuXMLAtt
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:593
_INumberVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:320
rangeDec
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
Definition: indicom.c:1484
_ILightVectorProperty::lp
ILight * lp
Definition: indiapi.h:428
_IBLOBVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:474
LIGHTSPEED
#define LIGHTSPEED
Definition: indicom.h:74
crackIPState
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indicom.c:1211
IUFindSwitch
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indicom.c:1361
userio_file
const struct userio * userio_file()
Definition: userio.c:38
fs_sexa
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string.
Definition: indicom.c:131
IP_RW
@ IP_RW
Definition: indiapi.h:185
userio.h
TTY_PORT_BUSY
@ TTY_PORT_BUSY
Definition: indicom.h:103
tty_set_generic_udp_format
void tty_set_generic_udp_format(int enabled)
Definition: indicom.c:356
ISState
ISState
Switch state.
Definition: indiapi.h:148
getSexComponentsIID
void getSexComponentsIID(double value, int *d, int *m, double *s)
Definition: indicom.c:267
_ISwitchVectorProperty::sp
ISwitch * sp
Definition: indiapi.h:384
ISRule
ISRule
Switch vector rule hint.
Definition: indiapi.h:170
userio_xmlv1
void userio_xmlv1(const userio *io, void *user)
Definition: userio.c:103
IUSaveConfigBLOB
void IUSaveConfigBLOB(FILE *fp, const IBLOBVectorProperty *bvp)
Add a BLOB vector property value to the configuration file.
Definition: indicom.c:1449
tty_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:454
TTY_OK
@ TTY_OK
Definition: indicom.h:94
errno
int errno
IUFindLight
ILight * IUFindLight(const ILightVectorProperty *lvp, const char *name)
Find an ILight member in a vector Light property.
Definition: indicom.c:1371
IBLOB
One Blob (Binary Large Object) descriptor.
findXMLAtt
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:493
Aux::buffer
std::vector< uint8_t > buffer
Definition: celestronauxpacket.h:38
_ISwitchVectorProperty
Switch vector property descriptor.
Definition: indiapi.h:365
EARTHRADIUSEQUATORIAL
#define EARTHRADIUSEQUATORIAL
Definition: indicom.h:58
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151