source: BAORadio/libindi/libindi/libs/indicom.c @ 504

Last change on this file since 504 was 504, checked in by frichard, 13 years ago

-Version 0.8 de libini
-Formule de Marc
-Nouvelles fonctionnalités (goto nom-de l'objet etc...)

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