-/*
- * testtty.c:
+/*
+ * tty.c:
*
* Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
* All rights reserved.
*
*/
-static char rcsid[] = "$Id$";
+static char rcsid[] = "$Id: tty.c,v 1.27 2010/07/27 14:49:35 james Exp $";
-/*
- * $Log$
- * Revision 1.1 2008/02/07 01:02:52 james
+/*
+ * $Log: tty.c,v $
+ * Revision 1.27 2010/07/27 14:49:35 james
+ * add support for byte logging
+ *
+ * Revision 1.26 2008/03/10 11:49:33 james
+ * *** empty log message ***
+ *
+ * Revision 1.25 2008/03/07 13:16:02 james
+ * *** empty log message ***
+ *
+ * Revision 1.24 2008/03/07 12:37:04 james
+ * *** empty log message ***
+ *
+ * Revision 1.23 2008/03/06 16:49:39 james
+ * *** empty log message ***
+ *
+ * Revision 1.22 2008/03/06 16:49:05 james
+ * *** empty log message ***
+ *
+ * Revision 1.21 2008/03/03 06:04:42 james
+ * *** empty log message ***
+ *
+ * Revision 1.20 2008/03/02 10:37:56 james
+ * *** empty log message ***
+ *
+ * Revision 1.19 2008/02/28 16:57:52 james
+ * *** empty log message ***
+ *
+ * Revision 1.18 2008/02/28 16:37:16 james
+ * *** empty log message ***
+ *
+ * Revision 1.17 2008/02/28 15:37:06 james
+ * *** empty log message ***
+ *
+ * Revision 1.16 2008/02/28 12:12:25 james
+ * *** empty log message ***
+ *
+ * Revision 1.15 2008/02/28 00:10:44 james
+ * *** empty log message ***
+ *
+ * Revision 1.14 2008/02/23 13:05:58 staffcvs
+ * *** empty log message ***
+ *
+ * Revision 1.13 2008/02/23 11:48:37 james
+ * *** empty log message ***
+ *
+ * Revision 1.12 2008/02/22 23:39:27 james
+ * *** empty log message ***
+ *
+ * Revision 1.11 2008/02/20 18:31:53 james
+ * *** empty log message ***
+ *
+ * Revision 1.10 2008/02/15 23:52:12 james
* *** empty log message ***
*
- * Revision 1.3 2008/02/06 17:53:28 james
+ * Revision 1.9 2008/02/15 03:32:07 james
* *** empty log message ***
*
- * Revision 1.2 2008/02/04 02:05:06 james
+ * Revision 1.8 2008/02/14 10:36:18 james
* *** empty log message ***
*
- * Revision 1.1 2008/02/04 01:32:39 james
+ * Revision 1.7 2008/02/14 10:34:30 james
+ * *** empty log message ***
+ *
+ * Revision 1.6 2008/02/13 16:59:34 james
+ * *** empty log message ***
+ *
+ * Revision 1.5 2008/02/13 16:57:29 james
+ * *** empty log message ***
+ *
+ * Revision 1.4 2008/02/12 22:36:46 james
+ * *** empty log message ***
+ *
+ * Revision 1.3 2008/02/09 15:47:28 james
* *** empty log message ***
*
*/
+
#include "project.h"
-static void
-set_nonblocking (int fd)
+static int
+speed_t_to_baud (speed_t s)
{
- long arg;
- arg = fcntl (fd, F_GETFL, arg);
- arg |= O_NONBLOCK;
- fcntl (fd, F_SETFL, arg);
+ switch (s) {
+#ifdef B0
+ case B0:
+ return 0;
+#endif
+#ifdef B50
+ case B50:
+ return 50;
+#endif
+#ifdef B75
+ case B75:
+ return 75;
+#endif
+#ifdef B110
+ case B110:
+ return 110;
+#endif
+#ifdef B134
+ case B134:
+ return 134;
+#endif
+#ifdef B150
+ case B150:
+ return 150;
+#endif
+#ifdef B200
+ case B200:
+ return 200;
+#endif
+#ifdef B300
+ case B300:
+ return 300;
+#endif
+#ifdef B600
+ case B600:
+ return 600;
+#endif
+#ifdef B1200
+ case B1200:
+ return 1200;
+#endif
+#ifdef B1800
+ case B1800:
+ return 1800;
+#endif
+#ifdef B2400
+ case B2400:
+ return 2400;
+#endif
+#ifdef B4800
+ case B4800:
+ return 4800;
+#endif
+#ifdef B9600
+ case B9600:
+ return 9600;
+#endif
+#ifdef B19200
+ case B19200:
+ return 19200;
+#endif
+#ifdef B38400
+ case B38400:
+ return 38400;
+#endif
+#ifdef B57600
+ case B57600:
+ return 57600;
+#endif
+#ifdef B115200
+ case B115200:
+ return 115200;
+#endif
+#ifdef B230400
+ case B230400:
+ return 230400;
+#endif
+ }
+
+ return -1;
}
-static void
-set_blocking (int fd)
+static speed_t
+baud_to_speed_t (int baud)
{
- long arg;
- arg = fcntl (fd, F_GETFL, arg);
- arg &= ~O_NONBLOCK;
- fcntl (fd, F_SETFL, arg);
+ switch (baud) {
+#ifdef B0
+ case 0:
+ return B0;
+#endif
+#ifdef B50
+ case 50:
+ return B50;
+#endif
+#ifdef B75
+ case 75:
+ return B75;
+#endif
+#ifdef B110
+ case 110:
+ return B110;
+#endif
+#ifdef B134
+ case 134:
+ return B134;
+#endif
+#ifdef B150
+ case 150:
+ return B150;
+#endif
+#ifdef B200
+ case 200:
+ return B200;
+#endif
+#ifdef B300
+ case 300:
+ return B300;
+#endif
+#ifdef B600
+ case 600:
+ return B600;
+#endif
+#ifdef B1200
+ case 1200:
+ return B1200;
+#endif
+#ifdef B1800
+ case 1800:
+ return B1800;
+#endif
+#ifdef B2400
+ case 2400:
+ return B2400;
+#endif
+#ifdef B4800
+ case 4800:
+ return B4800;
+#endif
+#ifdef B9600
+ case 9600:
+ return B9600;
+#endif
+#ifdef B19200
+ case 19200:
+ return B19200;
+#endif
+#ifdef B38400
+ case 38400:
+ return B38400;
+#endif
+#ifdef B57600
+ case 57600:
+ return B57600;
+#endif
+#ifdef B115200
+ case 115200:
+ return B115200;
+#endif
+#ifdef B230400
+ case 230400:
+ return B230400;
+#endif
+ }
+ return -1;
}
-static void
-default_termios (struct termios *termios)
+void
+tty_pre_select (TTY * t, fd_set * rfds, fd_set * wfds)
{
+ int line;
+ struct timeval now, dif;
- memset (termios, 0, sizeof (termios));
+ if (t->hanging_up) {
- termios->c_iflag = ICRNL | IXON;
- termios->c_oflag = OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
- termios->c_lflag =
- ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE;
+ gettimeofday (&now, NULL);
+ timersub (&now, &t->hangup_clock, &dif);
+ if (dif.tv_sec) {
+ line = TIOCM_DTR;
+ ioctl (t->rfd, TIOCMBIS, &line);
+ t->hanging_up = 0;
+ }
+ }
+
+
+ FD_SET (t->rfd, rfds);
+}
+
+int
+tty_get_status (TTY * t, TTY_Status * s)
+{
+
+ s->lines = 0;
+ ioctl (t->rfd, TIOCMGET, &s->lines);
+
+ if (tcgetattr (t->rfd, &s->termios))
+ return -1;
- termios->c_cc[VINTR] = 003;
- termios->c_cc[VQUIT] = 034;
- termios->c_cc[VERASE] = 0177;
- termios->c_cc[VKILL] = 025;
- termios->c_cc[VEOF] = 004;
- termios->c_cc[VEOL] = 0;
- termios->c_cc[VEOL2] = 0;
- termios->c_cc[VSTART] = 021;
- termios->c_cc[VSTOP] = 023;
- termios->c_cc[VSUSP] = 032;
- termios->c_cc[VLNEXT] = 026;
- termios->c_cc[VWERASE] = 027;
- termios->c_cc[VREPRINT] = 022;
- termios->c_cc[VDISCARD] = 017;
+ s->baud = speed_t_to_baud (cfgetispeed (&s->termios));
+ s->blocked = t->blocked;
- termios->c_cflag = CS8 | CREAD | CLOCAL;
+ return 0;
+}
+
+int
+tty_get_baud (TTY * t)
+{
+ struct termios tios = { 0 };
+
+ if (tcgetattr (t->rfd, &tios))
+ return;
- cfsetispeed (termios, B9600);
- cfsetospeed (termios, B9600);
+ return speed_t_to_baud (cfgetispeed (&tios));
}
-static int
-open_fd_to_bash (void) /*thump */
+void
+tty_set_baud (TTY * t, int rate)
{
- pid_t child;
- int fd;
- struct winsize winsize = { 0 };
- struct termios termios;
+ struct termios tios = { 0 };
- default_termios (&termios);
+ speed_t s = baud_to_speed_t (rate);
- winsize.ws_row = VT102_ROWS;
- winsize.ws_col = VT102_COLS;
+ if (s == (speed_t) - 1)
+ return;
- child = forkpty (&fd, NULL, &termios, &winsize);
+ if (tcgetattr (t->rfd, &tios))
+ return;
- switch (child)
- {
- case -1: /*boo hiss */
- return -1;
- case 0: /*waaah */
- setenv ("TERM", "vt102", 1);
- execl ("/bin/sh", "-", (char *) 0);
- _exit (-1);
- }
+ cfsetispeed (&tios, s);
+ cfsetospeed (&tios, s);
- return fd;
+ tcsetattr (t->rfd, TCSANOW, &tios);
}
+void
+tty_send_break (TTY * t)
+{
+ tcsendbreak (t->wfd, 0);
+}
-TTY *
-tty_new_test (void)
+void
+tty_set_flow (TTY * t, int flow)
{
- TTY *t;
- t = (TTY *) malloc (sizeof (TTY));
- t->fd = open_fd_to_bash ();
+ struct termios tios = { 0 };
+
+ if (tcgetattr (t->rfd, &tios))
+ return;
+
+ if (flow)
+ tios.c_cflag |= CRTSCTS;
+ else
+ tios.c_cflag &= ~CRTSCTS;
- set_nonblocking (t->fd);
+ tcsetattr (t->rfd, TCSANOW, &tios);
- return t;
}
-static int
-wrap_read (int fd, void *buf, int len)
+void
+tty_hangup (TTY * t)
{
- int red;
+ int line;
- red = read (fd, buf, len);
- if (!red)
- return -1;
+ line = TIOCM_DTR;
+ ioctl (t->rfd, TIOCMBIC, &line);
- if ((red < 0) && (errno == EAGAIN))
- red = 0;
+ t->hanging_up = 1;
+ gettimeofday (&t->hangup_clock, NULL);
- return red;
}
-static int
-wrap_write (int fd, void *buf, int len)
+void
+tty_length (TTY * t, int l)
{
- int writ;
+ t->displayed_length = l;
+}
- writ = write (fd, buf, len);
- if (!writ)
- return -1;
+void
+tty_winch (TTY * t, CRT_Pos size)
+{
+ struct winsize sz = { 0 };
- if ((writ < 0) && (errno == -EAGAIN))
- writ = 0;
+ sz.ws_col = size.x;
+ sz.ws_row = size.y;
- return writ;
+ ioctl (t->wfd, TIOCSWINSZ, &sz);
}
-int
-tty_read (TTY * t, void *buf, int len)
+
+
+#if 0
+typedef struct {
+ int in_dle;
+ int in_errmark;
+
+ int bit_edge_frequency[8];
+ int errs;
+}
+#endif
+#define DLE 0377
+#define bit(p,b,z,o) \
+ do { \
+ if ((b && z)) { \
+ p->bitfreq[z]++; \
+ z = 0; \
+ } \
+ \
+ if ((!b && o)) \
+ { \
+ p->bitfreq[z]++; \
+ o = 0; \
+ } \
+ \
+ if (b) \
+ o++; \
+ else \
+ z++; \
+ } \
+ while (0)
+static void
+tty_bit_analyse (Context * c, int err, int ch)
{
- int red, done = 0;
+ int d;
+ int zc = 0, oc = 0;
+ TTY_Parser *p = c->tp;
- do
- {
+ bit (p, 0, zc, oc);
- red = wrap_read (t->fd, buf, len);
- if (red < 0)
- return -1;
- if (!red)
- return done;
+ for (d = 1; d < 0x100; d <<= 1) {
+ bit (p, ch & d, zc, oc);
+ }
+ bit (p, 1, zc, oc);
- buf += red;
- len -= red;
- done += red;
- }
- while (len);
- return done;
+ if (err) {
+ p->biterrs++;
+ gettimeofday (&p->lasterr, NULL);
+ }
+
+ if (p->biterrs) {
+ log_f (c->l,
+ "<tty_bit_analyse: 0%d%d%d%d%d%d%d%d1 [%d,%d,%d,%d,%d,%d,%d,%d,%d,%d]>",
+ ch & 0x01 ? 1 : 0, ch & 0x02 ? 1 : 0, ch & 0x04 ? 1 : 0,
+ ch & 0x08 ? 1 : 0, ch & 0x10 ? 1 : 0, ch & 0x20 ? 1 : 0,
+ ch & 0x40 ? 1 : 0, ch & 0x80 ? 1 : 0, p->bitfreq[0],
+ p->bitfreq[1], p->bitfreq[2], p->bitfreq[3], p->bitfreq[4],
+ p->bitfreq[5], p->bitfreq[6], p->bitfreq[7], p->bitfreq[8],
+ p->bitfreq[9]);
+ }
+
}
+void
+tty_parse_reset (Context * c)
+{
+ TTY_Parser *p = c->tp;
+ memset (p->bitfreq, 0, sizeof (p->bitfreq));
+ p->biterrs = 0;
+ p->guessed_baud = 0;
+}
-int
-tty_write (TTY * t, void *buf, int len)
+void
+tty_analyse (Context * c)
{
- int writ, done = 0;
+ TTY_Parser *p = c->tp;
+ struct timeval now, dif;
+ int i, j, max;
-#if 0
- {
- int i;
- uint8_t *p = buf;
- for (i = 0; i < len; ++i)
- fprintf (stderr, "vw: %03o %c\n", p[i], p[i] > 31 ? p[i] : 32);
+ if (!p->biterrs) {
+ p->guessed_baud = 0;
+ return;
}
-#endif
- do
- {
+ gettimeofday (&now, NULL);
- writ = wrap_write (t->fd, buf, len);
- if (writ < 0)
- return -1;
- if (!writ)
- sleep (1);
+ timersub (&now, &p->lasterr, &dif);
- buf += writ;
- len -= writ;
- done += writ;
+ if (dif.tv_sec > 10) {
+ tty_parse_reset (c);
+ return;
+ }
+
+
+ max = -1;
+ j = 0;
+ for (i = 0; i < TTY_BITFREQ_LEN; ++i) {
+ if (p->bitfreq[i] > max) {
+ max = p->bitfreq[i];
+ j = i;
}
- while (len);
+ }
+
+ if (c->t)
+ i = tty_get_baud (c->t);
+ else
+ i = -1;
+
+ if (j == 1) {
+ /* Closest bit edge is one bit, so the baud rate is too low */
+ p->guessed_baud = -1;
+ } else {
+ if (i > 0 && j > 0)
+ p->guessed_baud = i / j;
+ else
+ p->guessed_baud = 0;
+
+ }
+
+ if (p->guessed_baud == -1) {
+ log_f (c->l, "<tty_analyse: %6d errors, current rate %db is too low>",
+ p->biterrs, i);
+ } else {
+ log_f (c->l, "<tty_analyse: %6d errors, current rate %db, suggest %db>",
+ p->biterrs, i, p->guessed_baud);
+ }
- return done;
}
-void
-tty_free (TTY * t)
+TTY_Parser *
+tty_parser_new (void)
{
- close (t->fd);
- free (t);
+ TTY_Parser *p;
+
+ p = (TTY_Parser *) xmalloc (sizeof (TTY_Parser));
+
+ memset (p, 0, sizeof (TTY_Parser));
+
+ return p;
+}
+
+int
+tty_parse (Context * c, uint8_t * buf, int len)
+{
+ TTY_Parser *p;
+ int err = 0;
+
+ p = c->tp;
+
+ while (len--) {
+
+ if (p->in_dle) {
+ p->in_dle = 0;
+ switch (*buf) {
+ case DLE:
+ tty_bit_analyse (c, 0, *buf);
+ err += utf8_parse (c, *buf);
+ break;
+ case 0:
+ p->in_errmark = 1;
+ break;
+ default:
+ log_f (c->l, "%s:%d DLE parsing error: \\377 \\%03o", __FILE__,
+ __LINE__, *buf);
+ }
+ } else if (p->in_errmark) {
+ p->in_errmark = 0;
+
+ log_f (c->l, "<tty reports error: \\377 \\000 \\%03o>",
+ __FILE__, __LINE__, *buf);
+
+ tty_bit_analyse (c, 1, *buf);
+
+ tty_analyse (c);
+
+ err += utf8_parse (c, *buf);
+
+ err += utf8_parse (c, SYM_CHAR_RESET);
+
+ } else if (*buf == DLE) {
+ p->in_dle = 1;
+
+ } else {
+ tty_bit_analyse (c, 0, *buf);
+
+ tty_analyse (c);
+
+ err += utf8_parse (c, *buf);
+
+ }
+ buf++;
+ }
+ return err;
}