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