Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
-#include "serial.h"
#include <fcntl.h>
-#include <termios.h>
#include <sys/time.h>
+#include "serial.h"
-/* File descriptor used in termios routines to access serial line. */
-static int desc;
-
-/* Saved state about the terminal. */
-static struct termios otermios;
-static int oflags;
-
-const char *
-serial_default_name ()
-{
- return "/dev/ttya";
-}
+static int desc = -1;
void
-serial_raw ()
+serial_raw(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
{
- /* Now happens inside of serial_open */
+ struct termios termios;
+
+ oldstate->flags = fcntl(fd, F_GETFL, 0);
+
+ fcntl(fd, F_SETFL, oldstate->flags|FNDELAY);
+
+ if (tcgetattr(fd, &termios))
+ {
+ fprintf(stderr, "tcgetattr failed: %s\n", safe_strerror(errno));
+ }
+
+ oldstate->termios = termios;
+
+ termios.c_iflag = 0;
+ termios.c_oflag = 0;
+ termios.c_lflag = 0;
+ termios.c_cc[VMIN] = 0;
+ termios.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSANOW, &termios))
+ {
+ fprintf(stderr, "tcsetattr failed: %s\n", safe_strerror(errno));
+ }
}
void
-serial_normal ()
+serial_restore(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
{
- fcntl(desc, oflags, 0);
+ fcntl(fd, F_SETFL, oldstate->flags);
- if (tcsetattr(desc, TCSANOW, &otermios))
- {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ tcsetattr(fd, TCSANOW, &oldstate->termios);
}
+static struct ttystate oldstate;
+
+static fd_set readfds;
+
int
-serial_open (name)
- const char *name;
+serial_open(name)
+ const char *name;
{
struct termios termios;
desc = open (name, O_RDWR);
if (desc < 0)
- perror("Open failed: ");
-
- oflags = fcntl(desc, F_GETFL, 0);
-
- fcntl(desc, F_SETFL, oflags|FNDELAY);
+ error("Open of %s failed: %s", name, safe_strerror(errno));
- if (tcgetattr(desc, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ serial_raw(desc, &oldstate);
- otermios = termios;
+/* Setup constant stuff for select */
- termios.c_iflag = 0;
- termios.c_oflag = 0;
- termios.c_lflag = 0;
- termios.c_cc[VMIN] = 0;
- termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(desc, TCSANOW, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ FD_ZERO(&readfds);
- return 1;
+ return desc;
}
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns -2 if timeout expired, EOF if line dropped
+ dead, or -3 for any other error (see errno in that case). */
+
int
-serial_timedreadchar (timeout, ok)
- int timeout;
- int *ok;
+serial_readchar(timeout)
+ int timeout;
{
- unsigned char buf;
- fd_set readfds;
- int val;
+ static unsigned char buf[BUFSIZ];
+ static unsigned char *bufp;
+ static int bufcnt = 0;
+ int numfds;
struct timeval tv;
- FD_ZERO(&readfds);
- FD_SET(desc, &readfds);
+ if (bufcnt-- > 0)
+ return *bufp++;
tv.tv_sec = timeout;
tv.tv_usec = 0;
- val = select(desc+1, &readfds, 0, 0, &tv);
+ FD_SET(desc, &readfds);
- if (val > 0 && FD_ISSET(desc, &readfds))
- {
- val = read (desc, &buf, 1);
+ if (timeout >= 0)
+ numfds = select(desc+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(desc+1, &readfds, 0, 0, 0);
- if (val == 1)
- {
- *ok = 1;
- return buf;
- }
- }
+ if (numfds <= 0)
+ if (numfds == 0)
+ return -2; /* Timeout */
+ else
+ return -3; /* Got an error from select */
+
+ bufcnt = read(desc, buf, BUFSIZ);
- *ok = 0;
+ if (bufcnt <= 0)
+ if (bufcnt == 0)
+ return EOF; /* 0 chars means end of file */
+ else
+ return -3; /* Got an error from read */
- return 0;
+ bufcnt--;
+ bufp = buf;
+ return *bufp++;
}
/* Translate baud rates from integers to damn B_codes. Unix should
have outgrown this crap years ago, but even POSIX wouldn't buck it. */
-#ifndef B19200
-#define B19200 EXTA
-#endif
-#ifndef B38400
-#define B38400 EXTB
-#endif
-
-static struct {int rate, damn_b;} baudtab[] = {
- {9600, B9600},
-
- {19200, B19200},
- {38400, B38400},
-#if 0
- {300, B300},
- {1200, B1200},
- {2400, B2400},
- {4800, B4800},
-#endif
- {-1, -1},
+static struct
+{
+ int rate;
+ int code;
+} baudtab[] = {
+ {50, B50},
+ {75, B75},
+ {110, B110},
+ {134, B134},
+ {150, B150},
+ {200, B200},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {1800, B1800},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+ {-1, -1},
};
static int
-damn_b (rate)
- int rate;
+rate_to_code(rate)
+ int rate;
{
int i;
+
for (i = 0; baudtab[i].rate != -1; i++)
- {
if (rate == baudtab[i].rate)
- {
- return i;
- }
- }
+ return baudtab[i].code;
+
return -1;
}
-int
-serial_setbaudrate (rate)
+int
+serial_setbaudrate(rate)
int rate;
{
struct termios termios;
- if (tcgetattr(desc, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ if (tcgetattr(desc, &termios))
+ error("tcgetattr failed: %s\n", safe_strerror(errno));
- cfsetospeed(&termios, baudtab[damn_b(rate)].damn_b);
- cfsetispeed(&termios, baudtab[damn_b(rate)].damn_b);
+ cfsetospeed(&termios, rate_to_code(rate));
+ cfsetispeed(&termios, rate_to_code(rate));
- if (tcsetattr(desc, TCSANOW, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ if (tcsetattr(desc, TCSANOW, &termios))
+ error("tcsetattr failed: %s\n", safe_strerror(errno));
return 1;
}
int
-serial_nextbaudrate (rate)
- int rate;
+serial_write(str, len)
+ const char *str;
+ int len;
{
- int lookup;
- lookup = damn_b(rate);
- if (lookup == -1)
- return baudtab[0].rate;
- lookup++;
- if (baudtab[lookup].rate == -1)
- return baudtab[0].rate;
- return baudtab[lookup].rate;
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(desc, str, len);
+
+ if (cc < 0)
+ return 0;
+ len -= cc;
+ str += cc;
+ }
+ return 1;
}
-int
-serial_write (str, len)
- const char *str;
- int len;
+void
+serial_close()
{
- return (write (desc, str, len));
-}
+ if (desc < 0)
+ return;
+ serial_restore(desc, oldstate);
-int
-serial_close ()
-{
- return (close(desc));
+ close(desc);
+ desc = -1;
}