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