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