Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
termios.cpp
Go to the documentation of this file.
1 // Copyright (C) 2008-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU Bayonne.
4 //
5 // GNU Bayonne is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU Bayonne is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
17 
18 #include <config.h>
19 #include <ucommon/ucommon.h>
20 #include <ucommon/export.h>
21 #include <bayonne.h>
22 
23 #if !defined(_MSWINDOWS_) && defined(HAVE_TERMIOS_H)
24 #include <termios.h>
25 #include <sys/select.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <errno.h>
29 
30 #ifdef HAVE_SYS_IOCTL_H
31 #include <sys/ioctl.h>
32 #else
33 #include <ioctl.h>
34 #endif
35 
36 using namespace BAYONNE_NAMESPACE;
37 using namespace UCOMMON_NAMESPACE;
38 
39 class __LOCAL serial : public Serial
40 {
41 private:
42  fd_t fd;
43  struct termios original, current;
44 
45  void restore(void);
46  bool set(const char *format);
47  void dtr(timeout_t timeout);
48  size_t get(void *data, size_t len);
49  size_t put(void *data, size_t len);
50  void bin(size_t size, timeout_t timeout);
51  void text(char nl1, char nl2);
52  void clear(void);
53  bool flush(timeout_t timeout);
54  bool wait(timeout_t timeout);
55  void sync(void);
56 
57  operator bool();
58  bool operator!();
59 
60 public:
61  serial(const char *name);
62  ~serial();
63 };
64 
65 serial::serial(const char *name) : Serial()
66 {
67  fd = ::open(name, O_RDWR | O_NDELAY);
68  if(fd < 0) {
69  error = errno;
70  return;
71  }
72 
73  long ioflags = fcntl(fd, F_GETFL);
74  tcgetattr(fd, &current);
75  tcgetattr(fd, &original);
76 
77  current.c_oflag = current.c_lflag = 0;
78  current.c_cflag = CLOCAL | CREAD | HUPCL;
79  current.c_iflag = IGNBRK;
80 
81  memset(&current.c_cc, 0, sizeof(current.c_cc));
82  current.c_cc[VMIN] = 1;
83 
84  cfsetispeed(&current, cfgetispeed(&original));
85  cfsetospeed(&current, cfgetospeed(&original));
86 
87  current.c_cflag |= original.c_cflag & (CRTSCTS | CSIZE | PARENB | PARODD | CSTOPB);
88  current.c_iflag |= original.c_iflag & (IXON | IXANY | IXOFF);
89 
90  tcsetattr(fd, TCSANOW, &current);
91  fcntl(fd, F_SETFL, ioflags & ~O_NDELAY);
92 
93 #if defined(TIOCM_RTS) && defined(TIOCMODG)
94  int mcs = 0;
95  ioctl(fd, TIOCMODG, &mcs);
96  mcs |= TIOCM_RTS;
97  ioctl(fd, TIOCMODS, &mcs);
98 #endif
99 }
100 
101 serial::~serial()
102 {
103  if(fd < 0)
104  return;
105 
106  restore();
107  ::close(fd);
108  fd = -1;
109 }
110 
111 serial::operator bool()
112 {
113  if(fd > -1)
114  return true;
115 
116  return false;
117 }
118 
119 bool serial::operator!()
120 {
121  if(fd < 0)
122  return true;
123 
124  return false;
125 }
126 
127 void serial::restore(void)
128 {
129  if(fd < 0)
130  return;
131 
132  memcpy(&current, &original, sizeof(current));
133  tcsetattr(fd, TCSANOW, &current);
134 }
135 
136 bool serial::set(const char *format)
137 {
138  assert(format != NULL);
139 
140  if(fd < 0)
141  return false;
142 
143  unsigned long opt;
144  char buf[256];
145  String::set(buf, sizeof(buf), format);
146 
147  char *cp = strtok(buf, ",");
148  while(cp) {
149  switch(*cp) {
150  case 'n':
151  case 'N':
152  current.c_cflag &= ~(PARENB | PARODD);
153  break;
154  case 'e':
155  case 'E':
156  current.c_cflag = (current.c_cflag & ~PARODD) | PARENB;
157  break;
158  case 'o':
159  case 'O':
160  current.c_cflag |= (PARODD | PARENB);
161  break;
162  case 's':
163  case 'S':
164  current.c_cflag &= ~CRTSCTS;
165  current.c_cflag |= (IXON | IXANY | IXOFF);
166  break;
167  case 'h':
168  case 'H':
169  current.c_cflag |= CRTSCTS;
170  current.c_cflag &= ~(IXON | IXANY | IXOFF);
171  break;
172  case 'b':
173  case 'B':
174  current.c_cflag |= CRTSCTS;
175  current.c_cflag |= (IXON | IXANY | IXOFF);
176  break;
177  case '0':
178  case '1':
179  case '2':
180  case '3':
181  case '4':
182  case '5':
183  case '6':
184  case '7':
185  case '8':
186  case '9':
187  opt = atol(cp);
188  switch(opt) {
189  case 1:
190  current.c_cflag &= ~CSTOPB;
191  break;
192  case 2:
193  current.c_cflag |= CSTOPB;
194  break;
195  case 5:
196  current.c_cflag = (current.c_cflag & ~CSIZE) | CS5;
197  break;
198  case 6:
199  current.c_cflag = (current.c_cflag & ~CSIZE) | CS6;
200  break;
201  case 7:
202  current.c_cflag = (current.c_cflag & ~CSIZE) | CS7;
203  break;
204  case 8:
205  current.c_cflag = (current.c_cflag & ~CSIZE) | CS8;
206  break;
207 #ifdef B921600
208  case 921600l:
209  cfsetispeed(&current, B921600);
210  cfsetospeed(&current, B921600);
211  break;
212 #endif
213 #ifdef B576000
214  case 576000l:
215  cfsetispeed(&current, B576000);
216  cfsetospeed(&current, B576000);
217  break;
218 #endif
219 #ifdef B500000
220  case 500000l:
221  cfsetispeed(&current, B500000);
222  cfsetospeed(&current, B500000);
223  break;
224 #endif
225 #ifdef B460800
226  case 460800l:
227  cfsetispeed(&current, B460800);
228  cfsetospeed(&current, B460800);
229  break;
230 #endif
231 #ifdef B230400
232  case 230400l:
233  cfsetispeed(&current, B230400);
234  cfsetospeed(&current, B230400);
235  break;
236 #endif
237 #ifdef B115200
238  case 115200l:
239  cfsetispeed(&current, B115200);
240  cfsetospeed(&current, B115200);
241  break;
242 #endif
243 #ifdef B57600
244  case 57600l:
245  cfsetispeed(&current, B57600);
246  cfsetospeed(&current, B57600);
247  break;
248 #endif
249 #ifdef B38400
250  case 38400l:
251  cfsetispeed(&current, B38400);
252  cfsetospeed(&current, B38400);
253  break;
254 #endif
255  case 19200l:
256  cfsetispeed(&current, B19200);
257  cfsetospeed(&current, B19200);
258  break;
259  case 9600l:
260  cfsetispeed(&current, B9600);
261  cfsetospeed(&current, B9600);
262  break;
263  case 4800l:
264  cfsetispeed(&current, B4800);
265  cfsetospeed(&current, B4800);
266  break;
267  case 2400l:
268  cfsetispeed(&current, B2400);
269  cfsetospeed(&current, B2400);
270  break;
271  case 1200l:
272  cfsetispeed(&current, B1200);
273  cfsetospeed(&current, B1200);
274  break;
275  case 600l:
276  cfsetispeed(&current, B600);
277  cfsetospeed(&current, B600);
278  break;
279  case 300l:
280  cfsetispeed(&current, B300);
281  cfsetospeed(&current, B300);
282  break;
283  case 110l:
284  cfsetispeed(&current, B110);
285  cfsetospeed(&current, B110);
286  break;
287 #ifdef B200
288  case 200l:
289  cfsetispeed(&current, B200);
290  cfsetospeed(&current, B200);
291  break;
292 #endif
293 #ifdef B150
294  case 150l:
295  cfsetispeed(&current, B150);
296  cfsetospeed(&current, B150);
297  break;
298 #endif
299 #ifdef B134
300  case 134l:
301  cfsetispeed(&current, B134);
302  cfsetospeed(&current, B134);
303  break;
304 #endif
305 #ifdef B0
306  case 0:
307  cfsetispeed(&current, B0);
308  cfsetospeed(&current, B0);
309  break;
310 #endif
311  default:
312  error = EINVAL;
313  return false;
314  }
315  break;
316  default:
317  error = EINVAL;
318  return false;
319  }
320  cp = strtok(NULL, ",");
321  }
322  tcsetattr(fd, TCSANOW, &current);
323  return true;
324 }
325 
326 void serial::dtr(timeout_t timeout)
327 {
328  if(fd < 0)
329  return;
330 
331  struct termios tty, old;
332  tcgetattr(fd, &tty);
333  tcgetattr(fd, &old);
334  cfsetospeed(&tty, B0);
335  cfsetispeed(&tty, B0);
336  tcsetattr(fd, TCSANOW, &tty);
337 
338  if(timeout) {
339  Thread::sleep(timeout);
340  tcsetattr(fd, TCSANOW, &old);
341  }
342 }
343 
344 size_t serial::get(void *data, size_t len)
345 {
346  if(fd < 0)
347  return 0;
348 
349  ssize_t rts = ::read(fd, data, len);
350  if(rts < 0) {
351  error = errno;
352  return 0;
353  }
354  return rts;
355 }
356 
357 size_t serial::put(void *data, size_t len)
358 {
359  if(fd < 0)
360  return 0;
361 
362  ssize_t rts = ::write(fd, data, len);
363  if(rts < 0) {
364  error = errno;
365  return 0;
366  }
367  return rts;
368 }
369 
370 void serial::bin(size_t size, timeout_t timeout)
371 {
372  if(fd < 0)
373  return;
374 
375 #ifdef _PC_MAX_INPUT
376  int max = fpathconf(fd, _PC_MAX_INPUT);
377 #else
378  int max = MAX_INPUT;
379 #endif
380  if(size > (size_t)max)
381  size = max;
382 
383  current.c_cc[VEOL] = current.c_cc[VEOL2] = 0;
384  current.c_cc[VMIN] = (unsigned char)size;
385  current.c_cc[VTIME] = (unsigned char)( (timeout + 99l) / 100l);
386  current.c_lflag &= ~ICANON;
387  tcsetattr(fd, TCSANOW, &current);
388 }
389 
390 void serial::text(char nl1, char nl2)
391 {
392  current.c_cc[VMIN] = current.c_cc[VTIME] = 0;
393  current.c_cc[VEOL] = nl1;
394  current.c_cc[VEOL2] = nl2;
395  current.c_lflag |= ICANON;
396  tcsetattr(fd, TCSANOW, &current);
397 }
398 
399 void serial::clear(void)
400 {
401  tcflush(fd, TCIFLUSH);
402 }
403 
404 void serial::sync(void)
405 {
406  tcdrain(fd);
407 }
408 
409 bool serial::wait(timeout_t timeout)
410 {
411  struct timeval tv;
412  fd_set grp;
413  struct timeval *tvp = &tv;
414  int status;
415 
416  if(fd < 0)
417  return false;
418 
419  if(timeout == Timer::inf)
420  tvp = NULL;
421  else {
422  tv.tv_usec = (timeout % 1000) * 1000;
423  tv.tv_sec = timeout / 1000;
424  }
425 
426  FD_ZERO(&grp);
427  FD_SET(fd, &grp);
428  status = select(fd + 1, &grp, NULL, NULL, tvp);
429  if(status < 0)
430  error = errno;
431 
432  if(status < 1)
433  return false;
434 
435  if(FD_ISSET(fd, &grp))
436  return true;
437 
438  return false;
439 }
440 
441 bool serial::flush(timeout_t timeout)
442 {
443  struct timeval tv;
444  fd_set grp;
445  struct timeval *tvp = &tv;
446  int status;
447  bool rtn = false;
448 
449  if(fd < 0)
450  return false;
451 
452  if(timeout == Timer::inf)
453  tvp = NULL;
454  else {
455  tv.tv_usec = (timeout % 1000) * 1000;
456  tv.tv_sec = timeout / 1000;
457  }
458 
459  FD_ZERO(&grp);
460  FD_SET(fd, &grp);
461  status = select(fd + 1, NULL, &grp, NULL, tvp);
462  if(status < 0) {
463  error = errno;
464  return false;
465  }
466 
467  if(status > 0 && FD_ISSET(fd, &grp))
468  rtn = true;
469 
470  if(rtn)
471  tcflush(fd, TCOFLUSH);
472 
473  return rtn;
474 }
475 
476 Serial *Serial::create(const char *name)
477 {
478  assert(name != NULL);
479 
480  char buf[64];
481  fsys::fileinfo_t ino;
482 
483  if(*name == '/') {
484  String::set(buf, sizeof(buf), name);
485  goto check;
486  }
487 
488  if(eq(name, "tty", 3))
489  snprintf(buf, sizeof(buf), "/dev/%s", name);
490  else
491  snprintf(buf, sizeof(buf), "/dev/tty%s", name);
492 
493 check:
494  char *cp = strchr(buf, ':');
495  if(cp)
496  *cp = 0;
497  fsys::fileinfo(buf, &ino);
498  if(!fsys::ischar(&ino))
499  return NULL;
500  serial_t dev = new serial(buf);
501  name = strchr(name, ':');
502  if(dev && name)
503  dev->set(++name);
504  return dev;
505 }
506 
507 stringpager *Serial::list(void)
508 {
509  stringpager *list = new stringpager;
510  char filename[64];
511  fsys_t dir;
512 
513  fsys::open(dir, "/dev", fsys::ACCESS_DIRECTORY);
514  while(is(dir) && fsys::read(dir, filename, sizeof(filename)) > 0) {
515  if(eq(filename, "tty", 3))
516  list->add(filename + 3);
517  }
518  fsys::close(dir);
519 }
520 
521 #endif
522 
523 
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
GNU Bayonne library namespace.