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