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