chiark / gitweb /
f27afea2bff68c1990956a3dc80494d0d151fc81
[sympathy.git] / src / tty.c
1 /*
2  * tty.c:
3  *
4  * Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id$";
10
11 /*
12  * $Log$
13  * Revision 1.18  2008/02/28 16:37:16  james
14  * *** empty log message ***
15  *
16  * Revision 1.17  2008/02/28 15:37:06  james
17  * *** empty log message ***
18  *
19  * Revision 1.16  2008/02/28 12:12:25  james
20  * *** empty log message ***
21  *
22  * Revision 1.15  2008/02/28 00:10:44  james
23  * *** empty log message ***
24  *
25  * Revision 1.14  2008/02/23 13:05:58  staffcvs
26  * *** empty log message ***
27  *
28  * Revision 1.13  2008/02/23 11:48:37  james
29  * *** empty log message ***
30  *
31  * Revision 1.12  2008/02/22 23:39:27  james
32  * *** empty log message ***
33  *
34  * Revision 1.11  2008/02/20 18:31:53  james
35  * *** empty log message ***
36  *
37  * Revision 1.10  2008/02/15 23:52:12  james
38  * *** empty log message ***
39  *
40  * Revision 1.9  2008/02/15 03:32:07  james
41  * *** empty log message ***
42  *
43  * Revision 1.8  2008/02/14 10:36:18  james
44  * *** empty log message ***
45  *
46  * Revision 1.7  2008/02/14 10:34:30  james
47  * *** empty log message ***
48  *
49  * Revision 1.6  2008/02/13 16:59:34  james
50  * *** empty log message ***
51  *
52  * Revision 1.5  2008/02/13 16:57:29  james
53  * *** empty log message ***
54  *
55  * Revision 1.4  2008/02/12 22:36:46  james
56  * *** empty log message ***
57  *
58  * Revision 1.3  2008/02/09 15:47:28  james
59  * *** empty log message ***
60  *
61  */
62
63
64 #include "project.h"
65
66 static int
67 speed_t_to_baud (speed_t s)
68 {
69   switch (s)
70     {
71 #ifdef B0
72     case B0:
73       return 0;
74 #endif
75 #ifdef B50
76     case B50:
77       return 50;
78 #endif
79 #ifdef B75
80     case B75:
81       return 75;
82 #endif
83 #ifdef B110
84     case B110:
85       return 110;
86 #endif
87 #ifdef B134
88     case B134:
89       return 134;
90 #endif
91 #ifdef B150
92     case B150:
93       return 150;
94 #endif
95 #ifdef B200
96     case B200:
97       return 200;
98 #endif
99 #ifdef B300
100     case B300:
101       return 300;
102 #endif
103 #ifdef B600
104     case B600:
105       return 600;
106 #endif
107 #ifdef B1200
108     case B1200:
109       return 1200;
110 #endif
111 #ifdef B1800
112     case B1800:
113       return 1800;
114 #endif
115 #ifdef B2400
116     case B2400:
117       return 2400;
118 #endif
119 #ifdef B4800
120     case B4800:
121       return 4800;
122 #endif
123 #ifdef B9600
124     case B9600:
125       return 9600;
126 #endif
127 #ifdef B19200
128     case B19200:
129       return 19200;
130 #endif
131 #ifdef B38400
132     case B38400:
133       return 38400;
134 #endif
135 #ifdef B57600
136     case B57600:
137       return 57600;
138 #endif
139 #ifdef B115200
140     case B115200:
141       return 115200;
142 #endif
143 #ifdef B230400
144     case B230400:
145       return 230400;
146 #endif
147     }
148
149   return -1;
150 }
151
152 static speed_t
153 baud_to_speed_t (int baud)
154 {
155   switch (baud)
156     {
157 #ifdef B0
158     case 0:
159       return B0;
160 #endif
161 #ifdef B50
162     case 50:
163       return B50;
164 #endif
165 #ifdef B75
166     case 75:
167       return B75;
168 #endif
169 #ifdef B110
170     case 110:
171       return B110;
172 #endif
173 #ifdef B134
174     case 134:
175       return B134;
176 #endif
177 #ifdef B150
178     case 150:
179       return B150;
180 #endif
181 #ifdef B200
182     case 200:
183       return B200;
184 #endif
185 #ifdef B300
186     case 300:
187       return B300;
188 #endif
189 #ifdef B600
190     case 600:
191       return B600;
192 #endif
193 #ifdef B1200
194     case 1200:
195       return B1200;
196 #endif
197 #ifdef B1800
198     case 1800:
199       return B1800;
200 #endif
201 #ifdef B2400
202     case 2400:
203       return B2400;
204 #endif
205 #ifdef B4800
206     case 4800:
207       return B4800;
208 #endif
209 #ifdef B9600
210     case 9600:
211       return B9600;
212 #endif
213 #ifdef B19200
214     case 19200:
215       return B19200;
216 #endif
217 #ifdef B38400
218     case 38400:
219       return B38400;
220 #endif
221 #ifdef B57600
222     case 57600:
223       return B57600;
224 #endif
225 #ifdef B115200
226     case 115200:
227       return B115200;
228 #endif
229 #ifdef B230400
230     case 230400:
231       return B230400;
232 #endif
233     }
234   return -1;
235 }
236
237 void
238 tty_pre_select (TTY * t, fd_set * rfds, fd_set * wfds)
239 {
240   int line;
241   struct timeval now, dif;
242
243   if (t->hanging_up)
244     {
245
246       gettimeofday (&now, NULL);
247       timersub (&now, &t->hangup_clock, &dif);
248       if (dif.tv_sec)
249         {
250           line = TIOCM_DTR;
251           ioctl (t->rfd, TIOCMBIS, &line);
252           t->hanging_up = 0;
253         }
254     }
255
256
257   FD_SET (t->rfd, rfds);
258 }
259
260 int
261 tty_get_status (TTY * t, TTY_Status * s)
262 {
263
264   s->lines = 0;
265   ioctl (t->rfd, TIOCMGET, &s->lines);
266
267   if (tcgetattr (t->rfd, &s->termios))
268     return -1;
269
270   s->baud = speed_t_to_baud (cfgetispeed (&s->termios));
271   s->blocked = t->blocked;
272
273   return 0;
274 }
275
276 int
277 tty_get_baud (TTY * t)
278 {
279   struct termios tios = { 0 };
280
281   if (tcgetattr (t->rfd, &tios))
282     return;
283
284   return speed_t_to_baud (cfgetispeed (&tios));
285 }
286
287
288 void
289 tty_set_baud (TTY * t, int rate)
290 {
291   struct termios tios = { 0 };
292
293   speed_t s = baud_to_speed_t (rate);
294
295   if (s == (speed_t) - 1)
296     return;
297
298   if (tcgetattr (t->rfd, &tios))
299     return;
300
301   cfsetispeed (&tios, s);
302   cfsetospeed (&tios, s);
303
304   tcsetattr (t->rfd, TCSANOW, &tios);
305 }
306
307 void
308 tty_send_break (TTY * t)
309 {
310   tcsendbreak (t->wfd, 0);
311 }
312
313 void
314 tty_set_flow (TTY * t, int flow)
315 {
316   struct termios tios = { 0 };
317
318   if (tcgetattr (t->rfd, &tios))
319     return;
320
321   if (flow)
322     tios.c_cflag |= CRTSCTS;
323   else
324     tios.c_cflag &= ~CRTSCTS;
325
326   tcsetattr (t->rfd, TCSANOW, &tios);
327
328 }
329
330 void
331 tty_hangup (TTY * t)
332 {
333   int line;
334
335   line = TIOCM_DTR;
336   ioctl (t->rfd, TIOCMBIC, &line);
337
338   t->hanging_up = 1;
339   gettimeofday (&t->hangup_clock, NULL);
340
341 }
342
343
344 void tty_winch(TTY * t,CRT_Pos size)
345 {
346   struct winsize sz = { 0 };
347
348   sz.ws_col=size.x;
349   sz.ws_row=size.y;
350
351   ioctl (t->wfd, TIOCSWINSZ, &sz);
352 }
353
354
355
356 #if 0
357 typedef struct
358 {
359   int in_dle;
360   int in_errmark;
361
362   int bit_edge_frequency[8];
363   int errs;
364 }
365 #endif
366
367 #define DLE 0377
368
369 #define bit(p,b,z,o) \
370         do { \
371           if ((b && z)) { \
372             p->bitfreq[z]++; \
373             z = 0; \
374           } \
375           \
376           if ((!b && o)) \
377           { \
378             p->bitfreq[z]++; \
379             o = 0; \
380           } \
381           \
382           if (b) \
383             o++; \
384           else \
385             z++; \
386           } \
387         while (0)
388
389 static void
390 tty_bit_analyse (Context * c, int err, int ch)
391 {
392   int d;
393   int zc = 0, oc = 0;
394   TTY_Parser *p = c->tp;
395
396
397   bit (p, 0, zc, oc);
398
399   for (d = 1; d < 0x100; d <<= 1)
400     {
401       bit (p, ch & d, zc, oc);
402     }
403   bit (p, 1, zc, oc);
404
405
406
407   if (err)
408     {
409       p->biterrs++;
410       gettimeofday (&p->lasterr, NULL);
411     }
412
413   if (p->biterrs)
414     {
415       log_f (c->l,
416              "<tty_bit_analyse: 0%d%d%d%d%d%d%d%d1  [%d,%d,%d,%d,%d,%d,%d,%d,%d,%d]>",
417              ch & 0x01 ? 1 : 0, ch & 0x02 ? 1 : 0, ch & 0x04 ? 1 : 0,
418              ch & 0x08 ? 1 : 0, ch & 0x10 ? 1 : 0, ch & 0x20 ? 1 : 0,
419              ch & 0x40 ? 1 : 0, ch & 0x80 ? 1 : 0, p->bitfreq[0],
420              p->bitfreq[1], p->bitfreq[2], p->bitfreq[3], p->bitfreq[4],
421              p->bitfreq[5], p->bitfreq[6], p->bitfreq[7], p->bitfreq[8],
422              p->bitfreq[9]);
423     }
424
425 }
426
427 void
428 tty_parse_reset (Context * c)
429 {
430   TTY_Parser *p = c->tp;
431   memset (p->bitfreq, 0, sizeof (p->bitfreq));
432   p->biterrs = 0;
433   p->guessed_baud = 0;
434 }
435
436 void
437 tty_analyse (Context * c)
438 {
439   TTY_Parser *p = c->tp;
440   struct timeval now, dif;
441   int i, j, max;
442
443   if (!p->biterrs)
444     {
445       p->guessed_baud = 0;
446       return;
447     }
448
449   gettimeofday (&now, NULL);
450
451   timersub (&now, &p->lasterr, &dif);
452
453   if (dif.tv_sec > 10)
454     {
455       tty_parse_reset (c);
456       return;
457     }
458
459
460   max = -1;
461   j = 0;
462   for (i = 0; i < TTY_BITFREQ_LEN; ++i)
463     {
464       if (p->bitfreq[i] > max)
465         {
466           max = p->bitfreq[i];
467           j = i;
468         }
469     }
470
471   if (c->t)
472     i = tty_get_baud (c->t);
473   else
474     i = -1;
475
476   if (j == 1)
477     {
478       /*Closest bit edge is one bit, so the baud rate is too low */
479       p->guessed_baud = -1;
480
481     }
482   else
483     {
484       if (i > 0)
485         p->guessed_baud = i / j;
486       else
487         p->guessed_baud = 0;
488
489     }
490
491   if (p->guessed_baud == -1)
492     {
493       log_f (c->l, "<tty_analyse: %6d errors, current rate %db is too low>",
494              p->biterrs, i);
495     }
496   else
497     {
498       log_f (c->l, "<tty_analyse: %6d errors, current rate %db, suggest %db>",
499              p->biterrs, i, p->guessed_baud);
500     }
501
502 }
503
504 TTY_Parser *
505 tty_parser_new (void)
506 {
507   TTY_Parser *p;
508
509   p = (TTY_Parser *) malloc (sizeof (TTY_Parser));
510
511   memset (p, 0, sizeof (TTY_Parser));
512
513   return p;
514 }
515
516 void
517 tty_parse (Context * c, uint8_t * buf, int len)
518 {
519   TTY_Parser *p;
520
521   p = c->tp;
522
523   while (len--)
524     {
525
526       if (p->in_dle)
527         {
528           p->in_dle = 0;
529           switch (*buf)
530             {
531             case DLE:
532               tty_bit_analyse (c, 0, *buf);
533               utf8_parse (c, *buf);
534               break;
535             case 0:
536               p->in_errmark = 1;
537               break;
538             default:
539               log_f (c->l, "%s:%d DLE parsing error: \\377 \\%03o", __FILE__,
540                      __LINE__, *buf);
541             }
542         }
543       else if (p->in_errmark)
544         {
545           p->in_errmark = 0;
546
547           log_f (c->l, "<tty reports error: \\377 \\000 \\%03o>",
548                  __FILE__, __LINE__, *buf);
549
550           tty_bit_analyse (c, 1, *buf);
551
552           tty_analyse (c);
553
554           utf8_parse (c, *buf);
555
556           utf8_parse (c, SYM_CHAR_RESET);
557
558         }
559       else if (*buf == DLE)
560         {
561           p->in_dle = 1;
562
563         }
564       else
565         {
566           tty_bit_analyse (c, 0, *buf);
567
568           tty_analyse (c);
569
570           utf8_parse (c, *buf);
571
572         }
573       buf++;
574     }
575 }