source: BAORadio/libindi/v1/libs/indicom.c @ 597

Last change on this file since 597 was 490, checked in by campagne, 14 years ago

import libindi (JEC)

File size: 14.5 KB
Line 
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/* needed for sincos() in math.h */
27#ifndef _GNU_SOURCE
28#define _GNU_SOURCE
29#endif
30#ifdef _WIN32
31#define CX _CX
32#define CY _CY
33#endif
34#include <stdlib.h>
35#include <math.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <stdarg.h>
42
43#include <config.h>
44
45#ifdef HAVE_NOVA_H
46#include <libnova.h>
47#endif
48
49
50#include "indicom.h"
51#ifdef _WIN32
52#undef CX
53#undef CY
54#endif
55const char * Direction[] = { "North", "West", "East", "South", "All"};
56const char * SolarSystem[] = { "Mercury", "Venus", "Moon", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"};
57
58/* make it compile on solaris */
59#ifndef M_PI
60#define M_PI 3.14159265358979323846264338327950288419716939937510582097494459
61#endif
62
63#ifndef _WIN32
64#include <termios.h>
65#define PARITY_NONE    0
66#define PARITY_EVEN    1
67#define PARITY_ODD     2
68#endif
69
70void getSexComponents(double value, int *d, int *m, int *s);
71
72
73int extractISOTime(char *timestr, struct ln_date *iso_date)
74{
75  #ifdef HAVE_NOVA_H   
76  struct tm utm;
77
78  if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm))
79  {
80        ln_get_date_from_tm(&utm, iso_date);
81        return (0);
82  }
83
84  if (strptime(timestr, "%Y-%m-%dT%H:%M:%S", &utm))
85  {
86        ln_get_date_from_tm(&utm, iso_date);
87        return (0);
88  }
89  #endif
90 
91  return (-1);
92}
93
94
95/* sprint the variable a in sexagesimal format into out[].
96 * w is the number of spaces for the whole part.
97 * fracbase is the number of pieces a whole is to broken into; valid options:
98 *      360000: <w>:mm:ss.ss
99 *      36000:  <w>:mm:ss.s
100 *      3600:   <w>:mm:ss
101 *      600:    <w>:mm.m
102 *      60:     <w>:mm
103 * return number of characters written to out, not counting finaif (NOVA_FOUND)
104    include_directories(${NOVA_INCLUDE_DIR})
105endif (NOVA_FOUND)l '\0'.
106 */
107int
108fs_sexa (char *out, double a, int w, int fracbase)
109{
110        char *out0 = out;
111        unsigned long n;
112        int d;
113        int f;
114        int m;
115        int s;
116        int isneg;
117
118        /* save whether it's negative but do all the rest with a positive */
119        isneg = (a < 0);
120        if (isneg)
121            a = -a;
122
123        /* convert to an integral number of whole portions */
124        n = (unsigned long)(a * fracbase + 0.5);
125        d = n/fracbase;
126        f = n%fracbase;
127
128        /* form the whole part; "negative 0" is a special case */
129        if (isneg && d == 0)
130            out += sprintf (out, "%*s-0", w-2, "");
131        else
132            out += sprintf (out, "%*d", w, isneg ? -d : d);
133
134        /* do the rest */
135        switch (fracbase) {
136        case 60:        /* dd:mm */
137            m = f/(fracbase/60);
138            out += sprintf (out, ":%02d", m);
139            break;
140        case 600:       /* dd:mm.m */
141            out += sprintf (out, ":%02d.%1d", f/10, f%10);
142            break;
143        case 3600:      /* dd:mm:ss */
144            m = f/(fracbase/60);
145            s = f%(fracbase/60);
146            out += sprintf (out, ":%02d:%02d", m, s);
147            break;
148        case 36000:     /* dd:mm:ss.s*/
149            m = f/(fracbase/60);
150            s = f%(fracbase/60);
151            out += sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10);
152            break;
153        case 360000:    /* dd:mm:ss.ss */
154            m = f/(fracbase/60);
155            s = f%(fracbase/60);
156            out += sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100);
157            break;
158        default:
159            printf ("fs_sexa: unknown fracbase: %d\n", fracbase);
160            exit(1);
161        }
162
163        return (out - out0);
164}
165
166/* convert sexagesimal string str AxBxC to double.
167 *   x can be anything non-numeric. Any missing A, B or C will be assumed 0.
168 *   optional - and + can be anywhere.
169 * return 0 if ok, -1 if can't find a thing.
170 */
171int
172f_scansexa (
173const char *str0,       /* input string */
174double *dp)             /* cracked value, if return 0 */
175{
176        double a = 0, b = 0, c = 0;
177        char str[128];
178        char *neg;
179        int r;
180
181        /* copy str0 so we can play with it */
182        strncpy (str, str0, sizeof(str)-1);
183        str[sizeof(str)-1] = '\0';
184
185        neg = strchr(str, '-');
186        if (neg)
187            *neg = ' ';
188        r = sscanf (str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c);
189        if (r < 1)
190            return (-1);
191        *dp = a + b/60 + c/3600;
192        if (neg)
193            *dp *= -1;
194        return (0);
195}
196
197void getSexComponents(double value, int *d, int *m, int *s)
198{
199
200  *d = (int) fabs(value);
201  *m = (int) ((fabs(value) - *d) * 60.0);
202  *s = (int) rint(((fabs(value) - *d) * 60.0 - *m) *60.0);
203
204  if (value < 0)
205   *d *= -1;
206}
207
208/* fill buf with properly formatted INumber string. return length */
209int
210numberFormat (char *buf, const char *format, double value)
211{
212        int w, f, s;
213        char m;
214
215        if (sscanf (format, "%%%d.%d%c", &w, &f, &m) == 3 && m == 'm') {
216            /* INDI sexi format */
217            switch (f) {
218            case 9:  s = 360000; break;
219            case 8:  s = 36000;  break;
220            case 6:  s = 3600;   break;
221            case 5:  s = 600;    break;
222            default: s = 60;     break;
223            }
224            return (fs_sexa (buf, value, w-f, s));
225        } else {
226            /* normal printf format */
227            return (sprintf (buf, format, value));
228        }
229}
230
231/* log message locally.
232 * this has nothing to do with XML or any Clients.
233 */
234void
235IDLog (const char *fmt, ...)
236{
237        va_list ap;
238        /* JM: Since all INDI's stderr are timestampped now, we don't need to time stamp ID Log */
239        /*fprintf (stderr, "%s ", timestamp());*/
240        va_start (ap, fmt);
241        vfprintf (stderr, fmt, ap);
242        va_end (ap);
243}
244
245/* return current system time in message format */
246const char *
247timestamp()
248{
249        static char ts[32];
250        struct tm *tp;
251        time_t t;
252
253        time (&t);
254        tp = gmtime (&t);
255        strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
256        return (ts);
257}
258
259int tty_timeout(int fd, int timeout)
260{
261  struct timeval tv;
262  fd_set readout;
263  int retval;
264
265  FD_ZERO(&readout);
266  FD_SET(fd, &readout);
267
268  /* wait for 'timeout' seconds */
269  tv.tv_sec = timeout;
270  tv.tv_usec = 0;
271
272  /* Wait till we have a change in the fd status */
273  retval = select (fd+1, &readout, NULL, NULL, &tv);
274
275  /* Return 0 on successful fd change */
276  if (retval > 0)
277   return TTY_OK;
278  /* Return -1 due to an error */
279  else if (retval == -1)
280   return TTY_SELECT_ERROR;
281  /* Return -2 if time expires before anything interesting happens */
282  else 
283    return TTY_TIME_OUT;
284 
285}
286
287int tty_write(int fd, const char * buf, int nbytes, int *nbytes_written)
288{
289  int bytes_w = 0;   
290  *nbytes_written = 0;
291   
292  while (nbytes > 0)
293  {
294   
295    bytes_w = write(fd, buf, nbytes);
296
297    if (bytes_w < 0)
298     return TTY_WRITE_ERROR;
299
300    *nbytes_written += bytes_w;
301    buf += bytes_w;
302    nbytes -= bytes_w;
303  }
304
305  return TTY_OK;
306}
307
308int tty_write_string(int fd, const char * buf, int *nbytes_written)
309{
310  unsigned int nbytes;
311  int bytes_w = 0;
312  *nbytes_written = 0;
313   
314  nbytes = strlen(buf);
315
316  while (nbytes > 0)
317  {
318   
319    bytes_w = write(fd, buf, nbytes);
320
321    if (bytes_w < 0)
322     return TTY_WRITE_ERROR;
323
324   *nbytes_written += bytes_w;
325    buf += bytes_w;
326    nbytes -= bytes_w;
327  }
328
329  return TTY_OK;
330}
331
332int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
333{
334
335 int bytesRead = 0;
336 int err = 0;
337 *nbytes_read =0;
338
339  if (nbytes <=0)
340        return TTY_PARAM_ERROR;
341
342  while (nbytes > 0)
343  {
344     if ( (err = tty_timeout(fd, timeout)) )
345      return err;
346
347     bytesRead = read(fd, buf, ((unsigned) nbytes));
348
349     if (bytesRead < 0 )
350      return TTY_READ_ERROR;
351
352     buf += bytesRead;
353     *nbytes_read += bytesRead;
354     nbytes -= bytesRead;
355  }
356
357  return TTY_OK;
358}
359
360int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
361{
362
363 int bytesRead = 0;
364 int err = TTY_OK;
365 *nbytes_read = 0;
366
367 for (;;)
368 {
369         if ( (err = tty_timeout(fd, timeout)) )
370           return err;
371
372         bytesRead = read(fd, buf, 1);
373
374         if (bytesRead < 0 )
375            return TTY_READ_ERROR;
376
377        if (bytesRead)
378          (*nbytes_read)++;
379
380        if (*buf == stop_char)
381           return TTY_OK;
382
383        buf += bytesRead;
384  }
385
386  return TTY_TIME_OUT;
387}
388
389int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
390{
391#ifdef _WIN32
392  return TTY_PORT_FAILURE;
393
394#else
395 int t_fd=0;
396 char msg[80];
397 int bps;
398 struct termios tty_setting;
399
400 if ( (t_fd = open(device, O_RDWR | O_NOCTTY )) == -1)
401    return TTY_PORT_FAILURE;
402
403    /* Control Modes
404   Set bps rate */
405  switch (bit_rate) {
406    case 0:
407      bps = B0;
408      break;
409    case 50:
410      bps = B50;
411      break;
412    case 75:
413      bps = B75;
414      break;
415    case 110:
416      bps = B110;
417      break;
418    case 134:
419      bps = B134;
420      break;
421    case 150:
422      bps = B150;
423      break;
424    case 200:
425      bps = B200;
426      break;
427    case 300:
428      bps = B300;
429      break;
430    case 600:
431      bps = B600;
432      break;
433    case 1200:
434      bps = B1200;
435      break;
436    case 1800:
437      bps = B1800;
438      break;
439    case 2400:
440      bps = B2400;
441      break;
442    case 4800:
443      bps = B4800;
444      break;
445    case 9600:
446      bps = B9600;
447      break;
448    case 19200:
449      bps = B19200;
450      break;
451    case 38400:
452      bps = B38400;
453      break;
454    case 57600:
455      bps = B57600;
456      break;
457    case 115200:
458      bps = B115200;
459      break;
460    case 230400:
461      bps = B230400;
462      break;
463    default:
464      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
465        perror(NULL);
466      else
467        perror(msg);
468      return TTY_PARAM_ERROR;
469  }
470  if ((cfsetispeed(&tty_setting, bps) < 0) ||
471      (cfsetospeed(&tty_setting, bps) < 0))
472  {
473    perror("tty_connect: failed setting bit rate.");
474    return TTY_PORT_FAILURE;
475  }
476
477   /* Control Modes
478   set no flow control word size, parity and stop bits.
479   Also don't hangup automatically and ignore modem status.
480   Finally enable receiving characters. */
481  tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS);
482  tty_setting.c_cflag |= (CLOCAL | CREAD);
483
484  /* word size */
485  switch (word_size) {
486    case 5:
487      tty_setting.c_cflag |= CS5;
488      break;
489    case 6:
490      tty_setting.c_cflag |= CS6;
491      break;
492    case 7:
493      tty_setting.c_cflag |= CS7;
494      break;
495    case 8:
496      tty_setting.c_cflag |= CS8;
497      break;
498    default:
499
500      fprintf( stderr, "Default\n") ;
501      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
502        perror(NULL);
503      else
504        perror(msg);
505
506      return TTY_PARAM_ERROR;
507  }
508
509  /* parity */
510  switch (parity) {
511    case PARITY_NONE:
512      break;
513    case PARITY_EVEN:
514      tty_setting.c_cflag |= PARENB;
515      break;
516    case PARITY_ODD:
517      tty_setting.c_cflag |= PARENB | PARODD;
518      break;
519    default:
520
521   fprintf( stderr, "Default1\n") ;
522      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
523        perror(NULL);
524      else
525        perror(msg);
526
527      return TTY_PARAM_ERROR;
528  }
529
530  /* stop_bits */
531  switch (stop_bits) {
532    case 1:
533      break;
534    case 2:
535      tty_setting.c_cflag |= CSTOPB;
536      break;
537    default:
538   fprintf( stderr, "Default2\n") ;
539      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
540        perror(NULL);
541      else
542        perror(msg);
543
544      return TTY_PARAM_ERROR;
545  }
546  /* Control Modes complete */
547
548  /* Ignore bytes with parity errors and make terminal raw and dumb.*/
549  tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY);
550  tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK;
551
552  /* Raw output.*/
553  tty_setting.c_oflag &= ~(OPOST | ONLCR);
554
555   /* Local Modes
556   Don't echo characters. Don't generate signals.
557   Don't process any characters.*/
558  tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP);
559  tty_setting.c_lflag |=  NOFLSH;
560
561  /* blocking read until 1 char arrives */
562  tty_setting.c_cc[VMIN]  = 1;
563  tty_setting.c_cc[VTIME] = 0;
564
565  /* now clear input and output buffers and activate the new terminal settings */
566  tcflush(t_fd, TCIOFLUSH);
567  if (tcsetattr(t_fd, TCSANOW, &tty_setting)) 
568  {
569    perror("tty_connect: failed setting attributes on serial port.");
570    tty_disconnect(t_fd);
571    return TTY_PORT_FAILURE;
572  }
573 
574  *fd = t_fd;
575  /* return success */
576  return TTY_OK;
577#endif
578}
579
580int tty_disconnect(int fd)
581{
582#ifdef _WIN32
583        return TTY_ERRNO;
584#else
585        int err;
586        tcflush(fd, TCIOFLUSH);
587        err = close(fd);
588
589        if (err != 0)
590                return TTY_ERRNO;
591
592        return TTY_OK;
593#endif
594}
595
596void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
597{
598      char error_string[512];
599
600  switch (err_code)
601 {
602        case TTY_OK:
603                strncpy(err_msg, "No Error", err_msg_len);
604                break;
605
606        case TTY_READ_ERROR:
607                snprintf(error_string, 512, "Read Error: %s", strerror(errno));
608                strncpy(err_msg, error_string, err_msg_len);
609                break;
610               
611       case TTY_WRITE_ERROR:
612                snprintf(error_string, 512, "Write Error: %s", strerror(errno));
613                strncpy(err_msg, error_string, err_msg_len);
614                break;
615
616        case TTY_SELECT_ERROR:
617                snprintf(error_string, 512, "Select Error: %s", strerror(errno));
618                strncpy(err_msg, error_string, err_msg_len);
619                break;
620
621        case TTY_TIME_OUT:
622                strncpy(err_msg, "Timeout error", err_msg_len);
623                break;
624
625        case TTY_PORT_FAILURE:
626                snprintf(error_string, 512, "Port failure Error: %s", strerror(errno));
627                strncpy(err_msg, error_string, err_msg_len);
628                break;
629
630        case TTY_PARAM_ERROR:
631                strncpy(err_msg, "Parameter error", err_msg_len);
632                break;
633
634        case TTY_ERRNO:
635                snprintf(error_string, 512, "%s", strerror(errno));
636                strncpy(err_msg, error_string, err_msg_len);
637                break;
638
639        default:
640                strncpy(err_msg, "Error: unrecognized error code", err_msg_len);
641                break;
642
643
644   }   
645}
Note: See TracBrowser for help on using the repository browser.