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