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