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