/* * tty.c: * * Copyright (c) 2008 James McKenzie , * All rights reserved. * */ static char rcsid[] = "$Id$"; /* * $Log$ * Revision 1.28 2012/06/22 10:22:25 james * *** empty log message *** * * 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.9 2008/02/15 03:32:07 james * *** empty log message *** * * Revision 1.8 2008/02/14 10:36:18 james * *** empty log message *** * * 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 int speed_t_to_baud (speed_t s) { 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 speed_t baud_to_speed_t (int baud) { 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; } void tty_pre_select (TTY * t, fd_set * rfds, fd_set * wfds) { int line; struct timeval now, dif; if (t->hanging_up) { 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; s->baud = speed_t_to_baud (cfgetispeed (&s->termios)); s->blocked = t->blocked; return 0; } int tty_get_baud (TTY * t) { struct termios tios = { 0 }; if (tcgetattr (t->rfd, &tios)) return 0; return speed_t_to_baud (cfgetispeed (&tios)); } void tty_set_baud (TTY * t, int rate) { struct termios tios = { 0 }; speed_t s = baud_to_speed_t (rate); if (s == (speed_t) - 1) return; if (tcgetattr (t->rfd, &tios)) return; cfsetispeed (&tios, s); cfsetospeed (&tios, s); tcsetattr (t->rfd, TCSANOW, &tios); } void tty_send_break (TTY * t) { tcsendbreak (t->wfd, 0); } void tty_set_flow (TTY * t, int flow) { struct termios tios = { 0 }; if (tcgetattr (t->rfd, &tios)) return; if (flow) tios.c_cflag |= CRTSCTS; else tios.c_cflag &= ~CRTSCTS; tcsetattr (t->rfd, TCSANOW, &tios); } void tty_hangup (TTY * t) { int line; line = TIOCM_DTR; ioctl (t->rfd, TIOCMBIC, &line); t->hanging_up = 1; gettimeofday (&t->hangup_clock, NULL); } void tty_length (TTY * t, int l) { t->displayed_length = l; } void tty_winch (TTY * t, CRT_Pos size) { struct winsize sz = { 0 }; sz.ws_col = size.x; sz.ws_row = size.y; ioctl (t->wfd, TIOCSWINSZ, &sz); } #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 d; int zc = 0, oc = 0; TTY_Parser *p = c->tp; bit (p, 0, zc, oc); for (d = 1; d < 0x100; d <<= 1) { bit (p, ch & d, zc, oc); } bit (p, 1, zc, oc); if (err) { p->biterrs++; gettimeofday (&p->lasterr, NULL); } if (p->biterrs) { log_f (c->l, "", 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; } void tty_analyse (Context * c) { TTY_Parser *p = c->tp; struct timeval now, dif; int i, j, max; if (!p->biterrs) { p->guessed_baud = 0; return; } gettimeofday (&now, NULL); timersub (&now, &p->lasterr, &dif); 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; } } 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, "", p->biterrs, i); } else { log_f (c->l, "", p->biterrs, i, p->guessed_baud); } } TTY_Parser * tty_parser_new (void) { 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, "", __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; }