Instrument Neutral Distributed Interface INDI  1.5.0
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 
33 #include "config.h"
34 
35 #if defined(HAVE_LIBNOVA)
36 #include <libnova/julian_day.h>
37 #include <libnova/sidereal_time.h>
38 #endif // HAVE_LIBNOVA
39 
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <math.h>
43 #include <stdarg.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 
50 #ifdef __APPLE__
51 #include <sys/param.h>
52 #endif
53 
54 #if defined(BSD) && !defined(__GNU__)
55 #include <IOKit/serial/ioss.h>
56 #include <sys/ioctl.h>
57 #endif
58 
59 #ifdef _WIN32
60 #undef CX
61 #undef CY
62 #endif
63 
64 #ifndef _WIN32
65 #include <unistd.h>
66 #include <termios.h>
67 #include <sys/param.h>
68 #define PARITY_NONE 0
69 #define PARITY_EVEN 1
70 #define PARITY_ODD 2
71 #endif
72 
73 #if defined(_MSC_VER)
74 #define snprintf _snprintf
75 #pragma warning(push)
76 #pragma warning(disable : 4996)
78 #endif
79 
80 #define MAXRBUF 2048
81 
82 int tty_debug = 0;
83 
84 #if defined(HAVE_LIBNOVA)
85 int extractISOTime(const char *timestr, struct ln_date *iso_date)
86 {
87  struct tm utm;
88 
89  if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm))
90  {
91  ln_get_date_from_tm(&utm, iso_date);
92  return (0);
93  }
94 
95  if (strptime(timestr, "%Y-%m-%dT%H:%M:%S", &utm))
96  {
97  ln_get_date_from_tm(&utm, iso_date);
98  return (0);
99  }
100 
101  return (-1);
102 }
103 #endif
104 
105 /* sprint the variable a in sexagesimal format into out[].
106  * w is the number of spaces for the whole part.
107  * fracbase is the number of pieces a whole is to broken into; valid options:
108  * 360000: <w>:mm:ss.ss
109  * 36000: <w>:mm:ss.s
110  * 3600: <w>:mm:ss
111  * 600: <w>:mm.m
112  * 60: <w>:mm
113  * return number of characters written to out, not counting final '\0'.
114  */
115 int fs_sexa(char *out, double a, int w, int fracbase)
116 {
117  char *out0 = out;
118  unsigned long n;
119  int d;
120  int f;
121  int m;
122  int s;
123  int isneg;
124 
125  /* save whether it's negative but do all the rest with a positive */
126  isneg = (a < 0);
127  if (isneg)
128  a = -a;
129 
130  /* convert to an integral number of whole portions */
131  n = (unsigned long)(a * fracbase + 0.5);
132  d = n / fracbase;
133  f = n % fracbase;
134 
135  /* form the whole part; "negative 0" is a special case */
136  if (isneg && d == 0)
137  out += snprintf(out, MAXINDIFORMAT, "%*s-0", w - 2, "");
138  else
139  out += snprintf(out, MAXINDIFORMAT, "%*d", w, isneg ? -d : d);
140 
141  /* do the rest */
142  switch (fracbase)
143  {
144  case 60: /* dd:mm */
145  m = f / (fracbase / 60);
146  out += snprintf(out, MAXINDIFORMAT, ":%02d", m);
147  break;
148  case 600: /* dd:mm.m */
149  out += snprintf(out, MAXINDIFORMAT, ":%02d.%1d", f / 10, f % 10);
150  break;
151  case 3600: /* dd:mm:ss */
152  m = f / (fracbase / 60);
153  s = f % (fracbase / 60);
154  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d", m, s);
155  break;
156  case 36000: /* dd:mm:ss.s*/
157  m = f / (fracbase / 60);
158  s = f % (fracbase / 60);
159  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d.%1d", m, s / 10, s % 10);
160  break;
161  case 360000: /* dd:mm:ss.ss */
162  m = f / (fracbase / 60);
163  s = f % (fracbase / 60);
164  out += snprintf(out, MAXINDIFORMAT, ":%02d:%02d.%02d", m, s / 100, s % 100);
165  break;
166  default:
167  printf("fs_sexa: unknown fracbase: %d\n", fracbase);
168  return -1;
169  }
170 
171  return (out - out0);
172 }
173 
174 /* convert sexagesimal string str AxBxC to double.
175  * x can be anything non-numeric. Any missing A, B or C will be assumed 0.
176  * optional - and + can be anywhere.
177  * return 0 if ok, -1 if can't find a thing.
178  */
179 int f_scansexa(const char *str0, /* input string */
180  double *dp) /* cracked value, if return 0 */
181 {
182  locale_char_t *orig = indi_locale_C_numeric_push();
183 
184  double a = 0, b = 0, c = 0;
185  char str[128];
186  //char *neg;
187  uint8_t isNegative=0;
188  int r= 0;
189 
190  /* copy str0 so we can play with it */
191  strncpy(str, str0, sizeof(str) - 1);
192  str[sizeof(str) - 1] = '\0';
193 
194  /* remove any spaces */
195  char* i = str;
196  char* j = str;
197  while(*j != 0)
198  {
199  *i = *j++;
200  if(*i != ' ')
201  i++;
202  }
203  *i = 0;
204 
205  // This has problem process numbers in scientific notations e.g. 1e-06
206  /*neg = strchr(str, '-');
207  if (neg)
208  *neg = ' ';
209  */
210  if (str[0] == '-')
211  {
212  isNegative = 1;
213  str[0] = ' ';
214  }
215 
216  r = sscanf(str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c);
217 
218  indi_locale_C_numeric_pop(orig);
219 
220  if (r < 1)
221  return (-1);
222  *dp = a + b / 60 + c / 3600;
223  if (isNegative)
224  *dp *= -1;
225  return (0);
226 }
227 
228 void getSexComponents(double value, int *d, int *m, int *s)
229 {
230  *d = (int32_t)fabs(value);
231  *m = (int32_t)((fabs(value) - *d) * 60.0);
232  *s = (int32_t)rint(((fabs(value) - *d) * 60.0 - *m) * 60.0);
233 
234  if (value < 0)
235  *d *= -1;
236 }
237 
238 void getSexComponentsIID(double value, int *d, int *m, double *s)
239 {
240  *d = (int32_t)fabs(value);
241  *m = (int32_t)((fabs(value) - *d) * 60.0);
242  *s = (double)(((fabs(value) - *d) * 60.0 - *m) * 60.0);
243 
244  if (value < 0)
245  *d *= -1;
246 }
247 
248 /* fill buf with properly formatted INumber string. return length */
249 int numberFormat(char *buf, const char *format, double value)
250 {
251  int w, f, s;
252  char m;
253 
254  if (sscanf(format, "%%%d.%d%c", &w, &f, &m) == 3 && m == 'm')
255  {
256  /* INDI sexi format */
257  switch (f)
258  {
259  case 9:
260  s = 360000;
261  break;
262  case 8:
263  s = 36000;
264  break;
265  case 6:
266  s = 3600;
267  break;
268  case 5:
269  s = 600;
270  break;
271  default:
272  s = 60;
273  break;
274  }
275  return (fs_sexa(buf, value, w - f, s));
276  }
277  else
278  {
279  /* normal printf format */
280  return (snprintf(buf, MAXINDIFORMAT, format, value));
281  }
282 }
283 
284 /* log message locally.
285  * this has nothing to do with XML or any Clients.
286  */
287 void IDLog(const char *fmt, ...)
288 {
289  va_list ap;
290  /* JM: Since all INDI's stderr are timestampped now, we don't need to time stamp ID Log */
291  /*fprintf (stderr, "%s ", timestamp());*/
292  va_start(ap, fmt);
293  vfprintf(stderr, fmt, ap);
294  va_end(ap);
295 }
296 
297 /* return current system time in message format */
298 const char *timestamp()
299 {
300  static char ts[32];
301  struct tm *tp;
302  time_t t;
303 
304  time(&t);
305  tp = gmtime(&t);
306  strftime(ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
307  return (ts);
308 }
309 
310 void tty_set_debug(int debug)
311 {
312  tty_debug = debug;
313 }
314 
315 int tty_timeout(int fd, int timeout)
316 {
317 #if defined(_WIN32) || defined(ANDROID)
318  INDI_UNUSED(fd);
319  INDI_UNUSED(timeout);
320  return TTY_ERRNO;
321 #else
322 
323  if (fd == -1)
324  return TTY_ERRNO;
325 
326  struct timeval tv;
327  fd_set readout;
328  int retval;
329 
330  FD_ZERO(&readout);
331  FD_SET(fd, &readout);
332 
333  /* wait for 'timeout' seconds */
334  tv.tv_sec = timeout;
335  tv.tv_usec = 0;
336 
337  /* Wait till we have a change in the fd status */
338  retval = select(fd + 1, &readout, NULL, NULL, &tv);
339 
340  /* Return 0 on successful fd change */
341  if (retval > 0)
342  return TTY_OK;
343  /* Return -1 due to an error */
344  else if (retval == -1)
345  return TTY_SELECT_ERROR;
346  /* Return -2 if time expires before anything interesting happens */
347  else
348  return TTY_TIME_OUT;
349 
350 #endif
351 }
352 
353 int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
354 {
355 #ifdef _WIN32
356  return TTY_ERRNO;
357 #else
358 
359  if (fd == -1)
360  return TTY_ERRNO;
361 
362  int bytes_w = 0;
363  *nbytes_written = 0;
364 
365  if (tty_debug)
366  {
367  int i = 0;
368  for (i = 0; i < nbytes; i++)
369  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char)buf[i], buf[i]);
370  }
371 
372  while (nbytes > 0)
373  {
374  bytes_w = write(fd, buf + (*nbytes_written), nbytes);
375 
376  if (bytes_w < 0)
377  return TTY_WRITE_ERROR;
378 
379  *nbytes_written += bytes_w;
380  //buf += bytes_w;
381  nbytes -= bytes_w;
382  }
383 
384  return TTY_OK;
385 
386 #endif
387 }
388 
389 int tty_write_string(int fd, const char *buf, int *nbytes_written)
390 {
391 #ifdef _WIN32
392  return TTY_ERRNO;
393 #else
394 
395  if (fd == -1)
396  return TTY_ERRNO;
397 
398  unsigned int nbytes;
399  int bytes_w = 0;
400  *nbytes_written = 0;
401 
402  nbytes = strlen(buf);
403 
404  if (tty_debug)
405  {
406  for (int i = 0; i < (int)nbytes; i++)
407  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char)buf[i], buf[i]);
408  }
409 
410  while (nbytes > 0)
411  {
412  bytes_w = write(fd, buf + (*nbytes_written), nbytes);
413 
414  if (bytes_w < 0)
415  return TTY_WRITE_ERROR;
416 
417  *nbytes_written += bytes_w;
418  //buf += bytes_w;
419  nbytes -= bytes_w;
420  }
421 
422  return TTY_OK;
423 
424 #endif
425 }
426 
427 int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
428 {
429 #ifdef _WIN32
430  return TTY_ERRNO;
431 #else
432 
433  if (fd == -1)
434  return TTY_ERRNO;
435 
436  int bytesRead = 0;
437  int err = 0;
438  *nbytes_read = 0;
439 
440  if (nbytes <= 0)
441  return TTY_PARAM_ERROR;
442 
443  if (tty_debug)
444  IDLog("%s: Request to read %d bytes with %d timeout for fd %d\n", __FUNCTION__, nbytes, timeout, fd);
445 
446  while (nbytes > 0)
447  {
448  if ((err = tty_timeout(fd, timeout)))
449  return err;
450 
451  bytesRead = read(fd, buf + (*nbytes_read), ((uint32_t)nbytes));
452 
453  if (bytesRead < 0)
454  return TTY_READ_ERROR;
455 
456  if (tty_debug)
457  {
458  IDLog("%d bytes read and %d bytes remaining...\n", bytesRead, nbytes - bytesRead);
459  int i = 0;
460  for (i = *nbytes_read; i < (*nbytes_read + bytesRead); i++)
461  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char)buf[i], buf[i]);
462  }
463 
464  *nbytes_read += bytesRead;
465  nbytes -= bytesRead;
466  }
467 
468  return TTY_OK;
469 
470 #endif
471 }
472 
473 int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
474 {
475 #ifdef _WIN32
476  return TTY_ERRNO;
477 #else
478 
479  if (fd == -1)
480  return TTY_ERRNO;
481 
482  int bytesRead = 0;
483  int err = TTY_OK;
484  *nbytes_read = 0;
485 
486  uint8_t *read_char = 0;
487 
488  if (tty_debug)
489  IDLog("%s: Request to read until stop char '%c' with %d timeout for fd %d\n", __FUNCTION__, stop_char, timeout,
490  fd);
491 
492  for (;;)
493  {
494  if ((err = tty_timeout(fd, timeout)))
495  return err;
496 
497  read_char = (uint8_t*)(buf + *nbytes_read);
498  bytesRead = read(fd, read_char, 1);
499 
500  if (bytesRead < 0)
501  return TTY_READ_ERROR;
502 
503  if (tty_debug)
504  IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, (*nbytes_read), *read_char, *read_char);
505 
506  (*nbytes_read)++;
507 
508  if (*read_char == stop_char)
509  return TTY_OK;
510  }
511 
512  return TTY_TIME_OUT;
513 
514 #endif
515 }
516 
517 #if defined(BSD) && !defined(__GNU__)
518 // BSD - OSX version
519 int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
520 {
521  int t_fd = -1;
522  int bps;
523  char msg[80];
524  int handshake;
525  struct termios tty_setting;
526 
527  // Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
528  // The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
529  // See open(2) ("man 2 open") for details.
530 
531  t_fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
532  if (t_fd == -1)
533  {
534  IDLog("Error opening serial port (%s) - %s(%d).\n", device, strerror(errno), errno);
535  goto error;
536  }
537 
538  // Note that open() follows POSIX semantics: multiple open() calls to the same file will succeed
539  // unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned
540  // processes.
541  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
542 
543  if (ioctl(t_fd, TIOCEXCL) == -1)
544  {
545  IDLog("Error setting TIOCEXCL on %s - %s(%d).\n", device, strerror(errno), errno);
546  goto error;
547  }
548 
549  // Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block.
550  // See fcntl(2) ("man 2 fcntl") for details.
551 
552  if (fcntl(t_fd, F_SETFL, 0) == -1)
553  {
554  IDLog("Error clearing O_NONBLOCK %s - %s(%d).\n", device, strerror(errno), errno);
555  goto error;
556  }
557 
558  // Get the current options and save them so we can restore the default settings later.
559  if (tcgetattr(t_fd, &tty_setting) == -1)
560  {
561  IDLog("Error getting tty attributes %s - %s(%d).\n", device, strerror(errno), errno);
562  goto error;
563  }
564 
565  // Set raw input (non-canonical) mode, with reads blocking until either a single character
566  // has been received or a one second timeout expires.
567  // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") for details.
568 
569  cfmakeraw(&tty_setting);
570  tty_setting.c_cc[VMIN] = 1;
571  tty_setting.c_cc[VTIME] = 10;
572 
573  // The baud rate, word length, and handshake options can be set as follows:
574  switch (bit_rate)
575  {
576  case 0:
577  bps = B0;
578  break;
579  case 50:
580  bps = B50;
581  break;
582  case 75:
583  bps = B75;
584  break;
585  case 110:
586  bps = B110;
587  break;
588  case 134:
589  bps = B134;
590  break;
591  case 150:
592  bps = B150;
593  break;
594  case 200:
595  bps = B200;
596  break;
597  case 300:
598  bps = B300;
599  break;
600  case 600:
601  bps = B600;
602  break;
603  case 1200:
604  bps = B1200;
605  break;
606  case 1800:
607  bps = B1800;
608  break;
609  case 2400:
610  bps = B2400;
611  break;
612  case 4800:
613  bps = B4800;
614  break;
615  case 9600:
616  bps = B9600;
617  break;
618  case 19200:
619  bps = B19200;
620  break;
621  case 38400:
622  bps = B38400;
623  break;
624  case 57600:
625  bps = B57600;
626  break;
627  case 115200:
628  bps = B115200;
629  break;
630  case 230400:
631  bps = B230400;
632  break;
633  default:
634  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
635  perror(NULL);
636  else
637  perror(msg);
638  return TTY_PARAM_ERROR;
639  }
640 
641  cfsetspeed(&tty_setting, bps); // Set baud rate
642  /* word size */
643  switch (word_size)
644  {
645  case 5:
646  tty_setting.c_cflag |= CS5;
647  break;
648  case 6:
649  tty_setting.c_cflag |= CS6;
650  break;
651  case 7:
652  tty_setting.c_cflag |= CS7;
653  break;
654  case 8:
655  tty_setting.c_cflag |= CS8;
656  break;
657  default:
658  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
659  perror(NULL);
660  else
661  perror(msg);
662 
663  return TTY_PARAM_ERROR;
664  }
665 
666  /* parity */
667  switch (parity)
668  {
669  case PARITY_NONE:
670  break;
671  case PARITY_EVEN:
672  tty_setting.c_cflag |= PARENB;
673  break;
674  case PARITY_ODD:
675  tty_setting.c_cflag |= PARENB | PARODD;
676  break;
677  default:
678  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
679  perror(NULL);
680  else
681  perror(msg);
682 
683  return TTY_PARAM_ERROR;
684  }
685 
686  /* stop_bits */
687  switch (stop_bits)
688  {
689  case 1:
690  break;
691  case 2:
692  tty_setting.c_cflag |= CSTOPB;
693  break;
694  default:
695  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
696  perror(NULL);
697  else
698  perror(msg);
699 
700  return TTY_PARAM_ERROR;
701  }
702 
703 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
704  // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
705  // other than those specified by POSIX. The driver for the underlying serial hardware
706  // ultimately determines which baud rates can be used. This ioctl sets both the input
707  // and output speed.
708 
709  speed_t speed = 14400; // Set 14400 baud
710  if (ioctl(t_fd, IOSSIOSPEED, &speed) == -1)
711  {
712  IDLog("Error calling ioctl(..., IOSSIOSPEED, ...) - %s(%d).\n", strerror(errno), errno);
713  }
714 #endif
715 
716  // Cause the new options to take effect immediately.
717  if (tcsetattr(t_fd, TCSANOW, &tty_setting) == -1)
718  {
719  IDLog("Error setting tty attributes %s - %s(%d).\n", device, strerror(errno), errno);
720  goto error;
721  }
722 
723  // To set the modem handshake lines, use the following ioctls.
724  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
725 
726  if (ioctl(t_fd, TIOCSDTR) == -1) // Assert Data Terminal Ready (DTR)
727  {
728  IDLog("Error asserting DTR %s - %s(%d).\n", device, strerror(errno), errno);
729  }
730 
731  if (ioctl(t_fd, TIOCCDTR) == -1) // Clear Data Terminal Ready (DTR)
732  {
733  IDLog("Error clearing DTR %s - %s(%d).\n", device, strerror(errno), errno);
734  }
735 
736  handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
737  if (ioctl(t_fd, TIOCMSET, &handshake) == -1)
738  // Set the modem lines depending on the bits set in handshake
739  {
740  IDLog("Error setting handshake lines %s - %s(%d).\n", device, strerror(errno), errno);
741  }
742 
743  // To read the state of the modem lines, use the following ioctl.
744  // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
745 
746  if (ioctl(t_fd, TIOCMGET, &handshake) == -1)
747  // Store the state of the modem lines in handshake
748  {
749  IDLog("Error getting handshake lines %s - %s(%d).\n", device, strerror(errno), errno);
750  }
751 
752  IDLog("Handshake lines currently set to %d\n", handshake);
753 
754 #if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
755  unsigned long mics = 1UL;
756 
757  // Set the receive latency in microseconds. Serial drivers use this value to determine how often to
758  // dequeue characters received by the hardware. Most applications don't need to set this value: if an
759  // app reads lines of characters, the app can't do anything until the line termination character has been
760  // received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA
761  // applications.
762 
763  if (ioctl(t_fd, IOSSDATALAT, &mics) == -1)
764  {
765  // set latency to 1 microsecond
766  IDLog("Error setting read latency %s - %s(%d).\n", device, strerror(errno), errno);
767  goto error;
768  }
769 #endif
770 
771  *fd = t_fd;
772  /* return success */
773  return TTY_OK;
774 
775 // Failure path
776 error:
777  if (t_fd != -1)
778  {
779  close(t_fd);
780  *fd = -1;
781  }
782 
783  return TTY_PORT_FAILURE;
784 }
785 #else
786 int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
787 {
788 #ifdef _WIN32
789  return TTY_PORT_FAILURE;
790 
791 #else
792  int t_fd = -1;
793  char msg[80];
794  int bps;
795  struct termios tty_setting;
796 
797  if ((t_fd = open(device, O_RDWR | O_NOCTTY)) == -1)
798  {
799  *fd = -1;
800 
801  return TTY_PORT_FAILURE;
802  }
803 
804  /* Control Modes
805  Set bps rate */
806  switch (bit_rate)
807  {
808  case 0:
809  bps = B0;
810  break;
811  case 50:
812  bps = B50;
813  break;
814  case 75:
815  bps = B75;
816  break;
817  case 110:
818  bps = B110;
819  break;
820  case 134:
821  bps = B134;
822  break;
823  case 150:
824  bps = B150;
825  break;
826  case 200:
827  bps = B200;
828  break;
829  case 300:
830  bps = B300;
831  break;
832  case 600:
833  bps = B600;
834  break;
835  case 1200:
836  bps = B1200;
837  break;
838  case 1800:
839  bps = B1800;
840  break;
841  case 2400:
842  bps = B2400;
843  break;
844  case 4800:
845  bps = B4800;
846  break;
847  case 9600:
848  bps = B9600;
849  break;
850  case 19200:
851  bps = B19200;
852  break;
853  case 38400:
854  bps = B38400;
855  break;
856  case 57600:
857  bps = B57600;
858  break;
859  case 115200:
860  bps = B115200;
861  break;
862  case 230400:
863  bps = B230400;
864  break;
865  default:
866  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
867  perror(NULL);
868  else
869  perror(msg);
870  return TTY_PARAM_ERROR;
871  }
872  if ((cfsetispeed(&tty_setting, bps) < 0) || (cfsetospeed(&tty_setting, bps) < 0))
873  {
874  perror("tty_connect: failed setting bit rate.");
875  return TTY_PORT_FAILURE;
876  }
877 
878  /* Control Modes
879  set no flow control word size, parity and stop bits.
880  Also don't hangup automatically and ignore modem status.
881  Finally enable receiving characters. */
882  tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS);
883  tty_setting.c_cflag |= (CLOCAL | CREAD);
884 
885  /* word size */
886  switch (word_size)
887  {
888  case 5:
889  tty_setting.c_cflag |= CS5;
890  break;
891  case 6:
892  tty_setting.c_cflag |= CS6;
893  break;
894  case 7:
895  tty_setting.c_cflag |= CS7;
896  break;
897  case 8:
898  tty_setting.c_cflag |= CS8;
899  break;
900  default:
901 
902  fprintf(stderr, "Default\n");
903  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
904  perror(NULL);
905  else
906  perror(msg);
907 
908  return TTY_PARAM_ERROR;
909  }
910 
911  /* parity */
912  switch (parity)
913  {
914  case PARITY_NONE:
915  break;
916  case PARITY_EVEN:
917  tty_setting.c_cflag |= PARENB;
918  break;
919  case PARITY_ODD:
920  tty_setting.c_cflag |= PARENB | PARODD;
921  break;
922  default:
923 
924  fprintf(stderr, "Default1\n");
925  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
926  perror(NULL);
927  else
928  perror(msg);
929 
930  return TTY_PARAM_ERROR;
931  }
932 
933  /* stop_bits */
934  switch (stop_bits)
935  {
936  case 1:
937  break;
938  case 2:
939  tty_setting.c_cflag |= CSTOPB;
940  break;
941  default:
942  fprintf(stderr, "Default2\n");
943  if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
944  perror(NULL);
945  else
946  perror(msg);
947 
948  return TTY_PARAM_ERROR;
949  }
950  /* Control Modes complete */
951 
952  /* Ignore bytes with parity errors and make terminal raw and dumb.*/
953  tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY);
954  tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK;
955 
956  /* Raw output.*/
957  tty_setting.c_oflag &= ~(OPOST | ONLCR);
958 
959  /* Local Modes
960  Don't echo characters. Don't generate signals.
961  Don't process any characters.*/
962  tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP);
963  tty_setting.c_lflag |= NOFLSH;
964 
965  /* blocking read until 1 char arrives */
966  tty_setting.c_cc[VMIN] = 1;
967  tty_setting.c_cc[VTIME] = 0;
968 
969  /* now clear input and output buffers and activate the new terminal settings */
970  tcflush(t_fd, TCIOFLUSH);
971  if (tcsetattr(t_fd, TCSANOW, &tty_setting))
972  {
973  perror("tty_connect: failed setting attributes on serial port.");
974  tty_disconnect(t_fd);
975  return TTY_PORT_FAILURE;
976  }
977 
978  *fd = t_fd;
979  /* return success */
980  return TTY_OK;
981 #endif
982 }
983 // Unix - Linux version
984 
985 #endif
986 
988 {
989  if (fd == -1)
990  return TTY_ERRNO;
991 
992 #ifdef _WIN32
993  return TTY_ERRNO;
994 #else
995  int err;
996  tcflush(fd, TCIOFLUSH);
997  err = close(fd);
998 
999  if (err != 0)
1000  return TTY_ERRNO;
1001 
1002  return TTY_OK;
1003 #endif
1004 }
1005 
1006 void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
1007 {
1008  char error_string[512];
1009 
1010  switch (err_code)
1011  {
1012  case TTY_OK:
1013  strncpy(err_msg, "No Error", err_msg_len);
1014  break;
1015 
1016  case TTY_READ_ERROR:
1017  snprintf(error_string, 512, "Read Error: %s", strerror(errno));
1018  strncpy(err_msg, error_string, err_msg_len);
1019  break;
1020 
1021  case TTY_WRITE_ERROR:
1022  snprintf(error_string, 512, "Write Error: %s", strerror(errno));
1023  strncpy(err_msg, error_string, err_msg_len);
1024  break;
1025 
1026  case TTY_SELECT_ERROR:
1027  snprintf(error_string, 512, "Select Error: %s", strerror(errno));
1028  strncpy(err_msg, error_string, err_msg_len);
1029  break;
1030 
1031  case TTY_TIME_OUT:
1032  strncpy(err_msg, "Timeout error", err_msg_len);
1033  break;
1034 
1035  case TTY_PORT_FAILURE:
1036  if (errno == EACCES)
1037  snprintf(error_string, 512,
1038  "Port failure Error: %s. Try adding your user to the dialout group and restart (sudo adduser "
1039  "$USER dialout)",
1040  strerror(errno));
1041  else
1042  snprintf(error_string, 512, "Port failure Error: %s. Check if device is connected to this port.",
1043  strerror(errno));
1044 
1045  strncpy(err_msg, error_string, err_msg_len);
1046  break;
1047 
1048  case TTY_PARAM_ERROR:
1049  strncpy(err_msg, "Parameter error", err_msg_len);
1050  break;
1051 
1052  case TTY_ERRNO:
1053  snprintf(error_string, 512, "%s", strerror(errno));
1054  strncpy(err_msg, error_string, err_msg_len);
1055  break;
1056 
1057  default:
1058  strncpy(err_msg, "Error: unrecognized error code", err_msg_len);
1059  break;
1060  }
1061 }
1062 
1063 /* return static string corresponding to the given property or light state */
1064 const char *pstateStr(IPState s)
1065 {
1066  switch (s)
1067  {
1068  case IPS_IDLE:
1069  return ("Idle");
1070  case IPS_OK:
1071  return ("Ok");
1072  case IPS_BUSY:
1073  return ("Busy");
1074  case IPS_ALERT:
1075  return ("Alert");
1076  default:
1077  fprintf(stderr, "Impossible IPState %d\n", s);
1078  return NULL;
1079  }
1080 }
1081 
1082 /* crack string into IPState.
1083  * return 0 if ok, else -1
1084  */
1085 int crackIPState(const char *str, IPState *ip)
1086 {
1087  if (!strcmp(str, "Idle"))
1088  *ip = IPS_IDLE;
1089  else if (!strncmp(str, "Ok", 2))
1090  *ip = IPS_OK;
1091  else if (!strcmp(str, "Busy"))
1092  *ip = IPS_BUSY;
1093  else if (!strcmp(str, "Alert"))
1094  *ip = IPS_ALERT;
1095  else
1096  return (-1);
1097  return (0);
1098 }
1099 
1100 /* crack string into ISState.
1101  * return 0 if ok, else -1
1102  */
1103 int crackISState(const char *str, ISState *ip)
1104 {
1105  if (!strncmp(str, "On", 2))
1106  *ip = ISS_ON;
1107  else if (!strcmp(str, "Off"))
1108  *ip = ISS_OFF;
1109  else
1110  return (-1);
1111  return (0);
1112 }
1113 
1114 int crackIPerm(const char *str, IPerm *ip)
1115 {
1116  if (!strncmp(str, "rw", 2))
1117  *ip = IP_RW;
1118  else if (!strncmp(str, "ro", 2))
1119  *ip = IP_RO;
1120  else if (!strncmp(str, "wo", 2))
1121  *ip = IP_WO;
1122  else
1123  return (-1);
1124  return (0);
1125 }
1126 
1127 int crackISRule(const char *str, ISRule *ip)
1128 {
1129  if (!strcmp(str, "OneOfMany"))
1130  *ip = ISR_1OFMANY;
1131  else if (!strcmp(str, "AtMostOne"))
1132  *ip = ISR_ATMOST1;
1133  else if (!strcmp(str, "AnyOfMany"))
1134  *ip = ISR_NOFMANY;
1135  else
1136  return (-1);
1137  return (0);
1138 }
1139 
1140 /* return static string corresponding to the given switch state */
1141 const char *sstateStr(ISState s)
1142 {
1143  switch (s)
1144  {
1145  case ISS_ON:
1146  return ("On");
1147  case ISS_OFF:
1148  return ("Off");
1149  default:
1150  fprintf(stderr, "Impossible ISState %d\n", s);
1151  return NULL;
1152  }
1153 }
1154 
1155 /* return static string corresponding to the given Rule */
1156 const char *ruleStr(ISRule r)
1157 {
1158  switch (r)
1159  {
1160  case ISR_1OFMANY:
1161  return ("OneOfMany");
1162  case ISR_ATMOST1:
1163  return ("AtMostOne");
1164  case ISR_NOFMANY:
1165  return ("AnyOfMany");
1166  default:
1167  fprintf(stderr, "Impossible ISRule %d\n", r);
1168  return NULL;
1169  }
1170 }
1171 
1172 /* return static string corresponding to the given IPerm */
1173 const char *permStr(IPerm p)
1174 {
1175  switch (p)
1176  {
1177  case IP_RO:
1178  return ("ro");
1179  case IP_WO:
1180  return ("wo");
1181  case IP_RW:
1182  return ("rw");
1183  default:
1184  fprintf(stderr, "Impossible IPerm %d\n", p);
1185  return NULL;
1186  }
1187 }
1188 
1189 /* print the boilerplate comment introducing xml */
1190 void xmlv1()
1191 {
1192  printf("<?xml version='1.0'?>\n");
1193 }
1194 
1195 /* pull out device and name attributes from root.
1196  * return 0 if ok else -1 with reason in msg[].
1197  */
1198 int crackDN(XMLEle *root, char **dev, char **name, char msg[])
1199 {
1200  XMLAtt *ap;
1201 
1202  ap = findXMLAtt(root, "device");
1203  if (!ap)
1204  {
1205  sprintf(msg, "%s requires 'device' attribute", tagXMLEle(root));
1206  return (-1);
1207  }
1208  *dev = valuXMLAtt(ap);
1209 
1210  ap = findXMLAtt(root, "name");
1211  if (!ap)
1212  {
1213  sprintf(msg, "%s requires 'name' attribute", tagXMLEle(root));
1214  return (-1);
1215  }
1216  *name = valuXMLAtt(ap);
1217 
1218  return (0);
1219 }
1220 
1221 /* find a member of an IText vector, else NULL */
1222 IText *IUFindText(const ITextVectorProperty *tvp, const char *name)
1223 {
1224  int i;
1225 
1226  for (i = 0; i < tvp->ntp; i++)
1227  if (strcmp(tvp->tp[i].name, name) == 0)
1228  return (&tvp->tp[i]);
1229  fprintf(stderr, "No IText '%s' in %s.%s\n", name, tvp->device, tvp->name);
1230  return (NULL);
1231 }
1232 
1233 /* find a member of an INumber vector, else NULL */
1235 {
1236  int i;
1237 
1238  for (i = 0; i < nvp->nnp; i++)
1239  if (strcmp(nvp->np[i].name, name) == 0)
1240  return (&nvp->np[i]);
1241  fprintf(stderr, "No INumber '%s' in %s.%s\n", name, nvp->device, nvp->name);
1242  return (NULL);
1243 }
1244 
1245 /* find a member of an ISwitch vector, else NULL */
1247 {
1248  int i;
1249 
1250  for (i = 0; i < svp->nsp; i++)
1251  if (strcmp(svp->sp[i].name, name) == 0)
1252  return (&svp->sp[i]);
1253  fprintf(stderr, "No ISwitch '%s' in %s.%s\n", name, svp->device, svp->name);
1254  return (NULL);
1255 }
1256 
1257 /* find a member of an ILight vector, else NULL */
1258 ILight *IUFindLight(const ILightVectorProperty *lvp, const char *name)
1259 {
1260  int i;
1261 
1262  for (i = 0; i < lvp->nlp; i++)
1263  if (strcmp(lvp->lp[i].name, name) == 0)
1264  return (&lvp->lp[i]);
1265  fprintf(stderr, "No ILight '%s' in %s.%s\n", name, lvp->device, lvp->name);
1266  return (NULL);
1267 }
1268 
1269 /* find a member of an IBLOB vector, else NULL */
1270 IBLOB *IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
1271 {
1272  int i;
1273 
1274  for (i = 0; i < bvp->nbp; i++)
1275  if (strcmp(bvp->bp[i].name, name) == 0)
1276  return (&bvp->bp[i]);
1277  fprintf(stderr, "No IBLOB '%s' in %s.%s\n", name, bvp->device, bvp->name);
1278  return (NULL);
1279 }
1280 
1281 /* find an ON member of an ISwitch vector, else NULL.
1282  * N.B. user must make sense of result with ISRule in mind.
1283  */
1285 {
1286  int i;
1287 
1288  for (i = 0; i < svp->nsp; i++)
1289  if (svp->sp[i].s == ISS_ON)
1290  return (&svp->sp[i]);
1291  /*fprintf(stderr, "No ISwitch On in %s.%s\n", svp->device, svp->name);*/
1292  return (NULL);
1293 }
1294 
1295 /* Find index of the ON member of an ISwitchVectorProperty */
1297 {
1298  int i;
1299 
1300  for (i = 0; i < svp->nsp; i++)
1301  if (svp->sp[i].s == ISS_ON)
1302  return i;
1303  return -1;
1304 }
1305 
1306 /* Find name the ON member in the given states and names */
1307 const char *IUFindOnSwitchName(ISState *states, char *names[], int n)
1308 {
1309  int i;
1310 
1311  for (i = 0; i < n; i++)
1312  if (states[i] == ISS_ON)
1313  return names[i];
1314  return NULL;
1315 }
1316 
1317 /* Set all switches to off */
1319 {
1320  int i;
1321 
1322  for (i = 0; i < svp->nsp; i++)
1323  svp->sp[i].s = ISS_OFF;
1324 }
1325 
1326 /* save malloced copy of newtext in tp->text, reusing if not first time */
1327 void IUSaveText(IText *tp, const char *newtext)
1328 {
1329  /* seed for realloc */
1330  if (tp->text == NULL)
1331  tp->text = malloc(1);
1332 
1333  /* copy in fresh string */
1334  tp->text = strcpy(realloc(tp->text, strlen(newtext) + 1), newtext);
1335 }
1336 
1337 double rangeHA(double r)
1338 {
1339  double res = r;
1340  while (res < -12.0)
1341  res += 24.0;
1342  while (res >= 12.0)
1343  res -= 24.0;
1344  return res;
1345 }
1346 
1347 double range24(double r)
1348 {
1349  double res = r;
1350  while (res < 0.0)
1351  res += 24.0;
1352  while (res > 24.0)
1353  res -= 24.0;
1354  return res;
1355 }
1356 
1357 double range360(double r)
1358 {
1359  double res = r;
1360  while (res < 0.0)
1361  res += 360.0;
1362  while (res > 360.0)
1363  res -= 360.0;
1364  return res;
1365 }
1366 
1367 double rangeDec(double decdegrees)
1368 {
1369  if ((decdegrees >= 270.0) && (decdegrees <= 360.0))
1370  return (decdegrees - 360.0);
1371  if ((decdegrees >= 180.0) && (decdegrees < 270.0))
1372  return (180.0 - decdegrees);
1373  if ((decdegrees >= 90.0) && (decdegrees < 180.0))
1374  return (180.0 - decdegrees);
1375  return decdegrees;
1376 }
1377 
1378 #if defined(HAVE_LIBNOVA)
1379 double get_local_sideral_time(double longitude)
1380 {
1381  double SD = ln_get_apparent_sidereal_time(ln_get_julian_from_sys()) - (360.0 - longitude) / 15.0;
1382 
1383  return range24(SD);
1384 }
1385 #endif // HAVE_LIBNOVA
1386 
1387 double get_local_hour_angle(double sideral_time, double ra)
1388 {
1389  double HA = sideral_time - ra;
1390  return rangeHA(HA);
1391 }
1392 
1393 #if defined(_MSC_VER)
1394 #undef snprintf
1395 #pragma warning(pop)
1396 #endif
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1327
int tty_debug
Definition: indicom.c:82
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1318
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:179
Light vector property descriptor.
Definition: indiapi.h:387
const char * timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Definition: indicom.c:298
char device[MAXINDIDEVICE]
Definition: indiapi.h:219
Definition: indicom.h:61
char * text
Definition: indiapi.h:203
const char * sstateStr(ISState s)
Definition: indicom.c:1141
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:786
ISState s
Definition: indiapi.h:326
int crackISRule(const char *str, ISRule *ip)
Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string.
Definition: indicom.c:1127
ILight * IUFindLight(const ILightVectorProperty *lvp, const char *name)
Find an ILight member in a vector Light property.
Definition: indicom.c:1258
int extractISOTime(const char *timestr, struct ln_date *iso_date)
Extract ISO 8601 time and store it in a tm struct.
double get_local_sideral_time(double longitude)
get_local_sideral_time Returns local sideral time given longitude and system clock.
IPState
Property state.
Definition: indiapi.h:133
void xmlv1()
Definition: indicom.c:1190
One light descriptor.
Definition: indiapi.h:369
char device[MAXINDIDEVICE]
Definition: indiapi.h:444
IndiDevice * device
Definition: indidevice.cpp:26
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:228
int crackDN(XMLEle *root, char **dev, char **name, char msg[])
Extract dev and name attributes from an XML element.
Definition: indicom.c:1198
One number descriptor.
Definition: indiapi.h:246
void tty_set_debug(int debug)
tty_set_debug Enable or disable debug which prints verbose information.
Definition: indicom.c:310
const char * ruleStr(ISRule r)
Definition: indicom.c:1156
One Blob (Binary Large Object) descriptor.
Definition: indiapi.h:413
double range24(double r)
range24 Limits a number to be between 0-24 range.
Definition: indicom.c:1347
char device[MAXINDIDEVICE]
Definition: indiapi.h:390
const char * pstateStr(IPState s)
Definition: indicom.c:1064
Definition: indiapi.h:156
double rangeHA(double r)
rangeHA Limits the hour angle value to be between -12 —> 12
Definition: indicom.c:1337
Definition: indiapi.h:155
char * valuXMLAtt(XMLAtt *ap)
Return the value of an XML attribute.
Definition: lilxml.c:593
Definition: indiapi.h:157
const char * name
Definition: indiserver.c:112
int crackIPerm(const char *str, IPerm *ip)
Extract property permission state (RW, RO, WO) from the supplied string.
Definition: indicom.c:1114
int tty_disconnect(int fd)
Closes a tty connection and flushes the bus.
Definition: indicom.c:987
Switch vector property descriptor.
Definition: indiapi.h:337
#define PARITY_NONE
Definition: indicom.c:68
int crackIPState(const char *str, IPState *ip)
Extract property state (Idle, OK, Busy, Alert) from the supplied string.
Definition: indicom.c:1085
char name[MAXINDINAME]
Definition: indiapi.h:294
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:389
int numberFormat(char *buf, const char *format, double value)
Fill buffer with properly formatted INumber string.
Definition: indicom.c:249
One switch descriptor.
Definition: indiapi.h:319
IText * IUFindText(const ITextVectorProperty *tvp, const char *name)
Find an IText member in a vector text property.
Definition: indicom.c:1222
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string.
Definition: indicom.c:115
void getSexComponentsIID(double value, int *d, int *m, double *s)
Definition: indicom.c:238
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition: indicom.c:1387
char name[MAXINDINAME]
Definition: indiapi.h:392
BLOB (Binary Large Object) vector property descriptor.
Definition: indiapi.h:441
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:473
char name[MAXINDINAME]
Definition: indiapi.h:249
int crackISState(const char *str, ISState *ip)
Extract switch state (On or Off) from the supplied string.
Definition: indicom.c:1103
IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name)
Find an IBLOB member in a vector BLOB property.
Definition: indicom.c:1270
char locale_char_t
Definition: locale_compat.h:62
#define PARITY_ODD
Definition: indicom.c:70
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1234
char name[MAXINDINAME]
Definition: indiapi.h:416
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1296
Number vector property descriptor.
Definition: indiapi.h:289
One text descriptor.
Definition: indiapi.h:196
int fd
Definition: indiserver.c:113
char name[MAXINDINAME]
Definition: indiapi.h:342
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition: indicom.c:353
XMLAtt * findXMLAtt(XMLEle *ep, const char *name)
Find an XML attribute within an XML element.
Definition: lilxml.c:493
#define MAXINDIFORMAT
Definition: indiapi.h:166
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition: indicom.c:427
char name[MAXINDINAME]
Definition: indiapi.h:221
char name[MAXINDINAME]
Definition: indiapi.h:372
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1006
Interface to the reference INDI C API device implementation on the Device Driver side.
const char * permStr(IPerm p)
Definition: indicom.c:1173
#define INDI_UNUSED(x)
Definition: indidevapi.h:797
void IDLog(const char *fmt,...)
Function Drivers call to log a message locally.
Definition: indicom.c:287
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
Definition: indicom.c:1367
#define PARITY_EVEN
Definition: indicom.c:69
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:1307
IPerm
Permission hint, with respect to client.
Definition: indiapi.h:154
ISState
Switch state.
Definition: indiapi.h:124
char name[MAXINDINAME]
Definition: indiapi.h:199
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition: indicom.c:1357
ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
Find an ISwitch member in a vector switch property.
Definition: indicom.c:1246
int tty_timeout(int fd, int timeout)
Definition: indicom.c:315
ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp)
Returns the first ON switch it finds in the vector switch property.
Definition: indicom.c:1284
Text vector property descriptor.
Definition: indiapi.h:216
char name[MAXINDINAME]
Definition: indiapi.h:446
int errno
char device[MAXINDIDEVICE]
Definition: indiapi.h:340
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition: lilxml.c:569
ISRule
Switch vector rule hint.
Definition: indiapi.h:144
char name[MAXINDINAME]
Definition: indiapi.h:322
double ra
char device[MAXINDIDEVICE]
Definition: indiapi.h:292
Implementations for common driver routines.