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