GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / TTY_IO.cpp
blob53c56baddabca8fd38a8ee88b45b45d2c0979297
1 #include "ace/TTY_IO.h"
2 #include "ace/OS_NS_errno.h"
3 #include "ace/OS_NS_string.h"
4 #include "ace/OS_NS_strings.h"
6 #if defined (ACE_HAS_TERMIOS)
7 # include "ace/os_include/os_termios.h"
8 #elif defined (ACE_HAS_TERMIO)
9 # include <termio.h>
10 #endif
12 namespace
14 const char ACE_TTY_IO_NONE[] = "none";
15 #if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO) || defined (ACE_WIN32)
16 const char ACE_TTY_IO_ODD[] = "odd";
17 const char ACE_TTY_IO_EVEN[] = "even";
18 #endif
19 #if defined (ACE_WIN32)
20 const char ACE_TTY_IO_MARK[] = "mark";
21 const char ACE_TTY_IO_SPACE[] = "space";
22 #endif /* ACE_WIN32 */
25 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
27 ACE_TTY_IO::ACE_TTY_IO (void)
31 ACE_TTY_IO::Serial_Params::Serial_Params (void)
33 baudrate = 9600;
34 xonlim = 0;
35 xofflim = 0;
36 readmincharacters = 0;
37 readtimeoutmsec = 10000;
38 paritymode = ACE_TTY_IO_NONE;
39 ctsenb = false;
40 rtsenb = 0;
41 xinenb = false;
42 xoutenb = false;
43 modem = false;
44 rcvenb = true;
45 dsrenb = false;
46 dtrdisable = false;
47 databits = 8;
48 stopbits = 1;
51 // Interface for reading/writing serial device parameters
53 int ACE_TTY_IO::control (Control_Mode cmd, Serial_Params *arg) const
55 #if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO)
57 #if defined (ACE_HAS_TERMIOS)
58 struct termios devpar;
59 speed_t newbaudrate = 0;
60 if (tcgetattr (get_handle () , &devpar) == -1)
61 #elif defined (TCGETS)
62 struct termios devpar;
63 unsigned int newbaudrate = 0;
64 if (this->ACE_IO_SAP::control (TCGETS, static_cast<void*>(&devpar)) == -1)
65 #elif defined (TCGETA)
66 struct termio devpar;
67 unsigned int newbaudrate = 0;
68 if (this->ACE_IO_SAP::control (TCGETA, static_cast<void*>(&devpar)) == -1)
69 #else
70 errno = ENOSYS;
71 #endif /* ACE_HAS_TERMIOS */
72 return -1;
74 switch (cmd)
76 case SETPARAMS:
77 switch (arg->baudrate)
79 #if defined (B0)
80 case 0: newbaudrate = B0; break;
81 #endif /* B0 */
82 #if defined (B50)
83 case 50: newbaudrate = B50; break;
84 #endif /* B50 */
85 #if defined (B75)
86 case 75: newbaudrate = B75; break;
87 #endif /* B75 */
88 #if defined (B110)
89 case 110: newbaudrate = B110; break;
90 #endif /* B110 */
91 #if defined (B134)
92 case 134: newbaudrate = B134; break;
93 #endif /* B134 */
94 #if defined (B150)
95 case 150: newbaudrate = B150; break;
96 #endif /* B150 */
97 #if defined (B200)
98 case 200: newbaudrate = B200; break;
99 #endif /* B200 */
100 #if defined (B300)
101 case 300: newbaudrate = B300; break;
102 #endif /* B300 */
103 #if defined (B600)
104 case 600: newbaudrate = B600; break;
105 #endif /* B600 */
106 #if defined (B1200)
107 case 1200: newbaudrate = B1200; break;
108 #endif /* B1200 */
109 #if defined (B1800)
110 case 1800: newbaudrate = B1800; break;
111 #endif /* B1800 */
112 #if defined (B2400)
113 case 2400: newbaudrate = B2400; break;
114 #endif /* B2400 */
115 #if defined (B4800)
116 case 4800: newbaudrate = B4800; break;
117 #endif /* B4800 */
118 #if defined (B9600)
119 case 9600: newbaudrate = B9600; break;
120 #endif /* B9600 */
121 #if defined (B19200)
122 case 19200: newbaudrate = B19200; break;
123 #endif /* B19200 */
124 #if defined (B38400)
125 case 38400: newbaudrate = B38400; break;
126 #endif /* B38400 */
127 #if defined (B56000)
128 case 56000: newbaudrate = B56000; break;
129 #endif /* B56000 */
130 #if defined (B57600)
131 case 57600: newbaudrate = B57600; break;
132 #endif /* B57600 */
133 #if defined (B76800)
134 case 76800: newbaudrate = B76800; break;
135 #endif /* B76800 */
136 #if defined (B115200)
137 case 115200: newbaudrate = B115200; break;
138 #endif /* B115200 */
139 #if defined (B128000)
140 case 128000: newbaudrate = B128000; break;
141 #endif /* B128000 */
142 #if defined (B153600)
143 case 153600: newbaudrate = B153600; break;
144 #endif /* B153600 */
145 #if defined (B230400)
146 case 230400: newbaudrate = B230400; break;
147 #endif /* B230400 */
148 #if defined (B307200)
149 case 307200: newbaudrate = B307200; break;
150 #endif /* B307200 */
151 #if defined (B256000)
152 case 256000: newbaudrate = B256000; break;
153 #endif /* B256000 */
154 #if defined (B460800)
155 case 460800: newbaudrate = B460800; break;
156 #endif /* B460800 */
157 #if defined (B500000)
158 case 500000: newbaudrate = B500000; break;
159 #endif /* B500000 */
160 #if defined (B576000)
161 case 576000: newbaudrate = B576000; break;
162 #endif /* B576000 */
163 #if defined (B921600)
164 case 921600: newbaudrate = B921600; break;
165 #endif /* B921600 */
166 #if defined (B1000000)
167 case 1000000: newbaudrate = B1000000; break;
168 #endif /* B1000000 */
169 #if defined (B1152000)
170 case 1152000: newbaudrate = B1152000; break;
171 #endif /* B1152000 */
172 #if defined (B1500000)
173 case 1500000: newbaudrate = B1500000; break;
174 #endif /* B1500000 */
175 #if defined (B2000000)
176 case 2000000: newbaudrate = B2000000; break;
177 #endif /* B2000000 */
178 #if defined (B2500000)
179 case 2500000: newbaudrate = B2500000; break;
180 #endif /* B2500000 */
181 #if defined (B3000000)
182 case 3000000: newbaudrate = B3000000; break;
183 #endif /* B3000000 */
184 #if defined (B3500000)
185 case 3500000: newbaudrate = B3500000; break;
186 #endif /* B3500000 */
187 #if defined (B4000000)
188 case 4000000: newbaudrate = B4000000; break;
189 #endif /* B4000000 */
190 default:
191 return -1;
194 #if defined (ACE_HAS_TERMIOS)
195 // Can you really have different input and output baud rates?!
196 if (cfsetospeed (&devpar, newbaudrate) == -1)
197 return -1;
198 if (cfsetispeed (&devpar, newbaudrate) == -1)
199 return -1;
200 #else
201 devpar.c_cflag &= ~CBAUD;
202 # if defined (CBAUDEX)
203 devpar.c_cflag &= ~CBAUDEX;
204 # endif /* CBAUDEX */
205 devpar.c_cflag |= newbaudrate;
206 #endif /* ACE_HAS_TERMIOS */
208 devpar.c_cflag &= ~CSIZE;
209 switch (arg->databits)
211 case 5:
212 devpar.c_cflag |= CS5;
213 break;
214 case 6:
215 devpar.c_cflag |= CS6;
216 break;
217 case 7:
218 devpar.c_cflag |= CS7;
219 break;
220 case 8:
221 devpar.c_cflag |= CS8;
222 break;
223 default:
224 return -1;
227 switch (arg->stopbits)
229 case 1:
230 devpar.c_cflag &= ~CSTOPB;
231 break;
232 case 2:
233 devpar.c_cflag |= CSTOPB;
234 break;
235 default:
236 return -1;
239 if (arg->paritymode)
241 if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0)
243 devpar.c_cflag |= PARENB;
244 devpar.c_cflag |= PARODD;
245 devpar.c_iflag &= ~IGNPAR;
246 devpar.c_iflag |= INPCK | PARMRK;
248 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0)
250 devpar.c_cflag |= PARENB;
251 devpar.c_cflag &= ~PARODD;
252 devpar.c_iflag &= ~IGNPAR;
253 devpar.c_iflag |= INPCK | PARMRK;
255 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0)
257 devpar.c_cflag &= ~PARENB;
259 else
261 return -1;
264 else
266 devpar.c_cflag &= ~PARENB;
269 #if defined (CNEW_RTSCTS)
270 if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol
271 devpar.c_cflag |= CNEW_RTSCTS;
272 else
273 devpar.c_cflag &= ~CNEW_RTSCTS;
274 #elif defined (CRTSCTS)
275 if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol
276 devpar.c_cflag |= CRTSCTS;
277 else
278 devpar.c_cflag &= ~CRTSCTS;
279 #endif /* NEW_RTSCTS || CRTSCTS */
281 #if defined (CREAD)
282 // Enable/disable receiver
283 if (arg->rcvenb)
284 devpar.c_cflag |= CREAD;
285 else
286 devpar.c_cflag &= ~CREAD;
287 #endif /* CREAD */
289 #if defined (HUPCL)
290 // Cause DTR to drop after port close.
291 devpar.c_cflag |= HUPCL;
292 #endif /* HUPCL */
294 #if defined (CLOCAL)
295 // If device is not a modem set to local device.
296 if (arg->modem)
297 devpar.c_cflag &= ~CLOCAL;
298 else
299 devpar.c_cflag |= CLOCAL;
300 #endif /* CLOCAL */
302 if (arg->databits < 8)
303 devpar.c_iflag |= ISTRIP;
305 #if defined (IGNBRK)
306 // If device is not a modem set to ignore break points
307 if(arg->modem)
308 devpar.c_iflag &= ~IGNBRK;
309 else
310 devpar.c_iflag |= IGNBRK;
311 #endif /* IGNBRK */
313 #if defined (IXOFF)
314 // Enable/disable software flow control on input
315 if (arg->xinenb)
316 devpar.c_iflag |= IXOFF;
317 else
318 devpar.c_iflag &= ~IXOFF;
319 #endif /* IXOFF */
321 #if defined (IXON)
322 // Enable/disable software flow control on output
323 if (arg->xoutenb)
324 devpar.c_iflag |= IXON;
325 else
326 devpar.c_iflag &= ~IXON;
327 #endif /* IXON */
329 #if defined (ICANON)
330 // Enable noncanonical input processing mode
331 devpar.c_lflag &= ~ICANON;
332 #endif /* ICANON */
334 #if defined (ECHO)
335 // Disable echoing of input characters
336 devpar.c_lflag &= ~ECHO;
337 #endif /* ECHO */
339 #if defined (ECHOE)
340 // Disable echoing erase chareacter as BS-SP-BS
341 devpar.c_lflag &= ~ECHOE;
342 #endif /* ECHOE */
344 #if defined (ISIG)
345 // Disable SIGINTR, SIGSUSP, SIGDSUSP and SIGQUIT signals
346 devpar.c_lflag &= ~ISIG;
347 #endif /* ISIG */
349 #if defined (OPOST)
350 // Disable post-processing of output data
351 devpar.c_oflag &= ~OPOST;
352 #endif /* OPOST */
354 if (arg->readtimeoutmsec < 0)
356 // Settings for infinite timeout.
357 devpar.c_cc[VTIME] = 0;
358 // In case of infinite timeout [VMIN] must be at least 1.
359 if (arg->readmincharacters > UCHAR_MAX)
360 devpar.c_cc[VMIN] = UCHAR_MAX;
361 else if (arg->readmincharacters < 1)
362 devpar.c_cc[VMIN] = 1;
363 else
364 devpar.c_cc[VMIN] = static_cast<unsigned char>(arg->readmincharacters);
366 else
368 devpar.c_cc[VTIME] = static_cast<unsigned char>(arg->readtimeoutmsec / 100);
370 if (arg->readmincharacters > UCHAR_MAX)
371 devpar.c_cc[VMIN] = UCHAR_MAX;
372 else if (arg->readmincharacters < 1)
373 devpar.c_cc[VMIN] = 0;
374 else
375 devpar.c_cc[VMIN] = static_cast<unsigned char>(arg->readmincharacters);
378 #if defined (TIOCMGET)
379 int status;
380 this->ACE_IO_SAP::control (TIOCMGET, &status);
382 if (arg->dtrdisable)
383 status &= ~TIOCM_DTR;
384 else
385 status |= TIOCM_DTR;
387 this->ACE_IO_SAP::control (TIOCMSET, &status);
388 #endif /* definded (TIOCMGET) */
390 #if defined (ACE_HAS_TERMIOS)
391 return tcsetattr (get_handle (), TCSANOW, &devpar);
392 #elif defined (TCSETS)
393 return this->ACE_IO_SAP::control (TCSETS, static_cast<void*>(&devpar));
394 #elif defined (TCSETA)
395 return this->ACE_IO_SAP::control (TCSETA, static_cast<void*>(&devpar));
396 #else
397 errno = ENOSYS;
398 return -1;
399 #endif /* ACE_HAS_TERMIOS */
401 case GETPARAMS:
402 return -1; // Not yet implemented.
403 default:
404 return -1; // Wrong cmd.
406 #elif defined (ACE_WIN32)
407 DCB dcb;
408 dcb.DCBlength = sizeof dcb;
409 if (!::GetCommState (this->get_handle (), &dcb))
411 ACE_OS::set_errno_to_last_error ();
412 return -1;
415 COMMTIMEOUTS timeouts;
416 if (!::GetCommTimeouts (this->get_handle(), &timeouts))
418 ACE_OS::set_errno_to_last_error ();
419 return -1;
422 switch (cmd)
424 case SETPARAMS:
425 dcb.BaudRate = arg->baudrate;
427 switch (arg->databits)
429 case 4:
430 case 5:
431 case 6:
432 case 7:
433 case 8:
434 dcb.ByteSize = arg->databits;
435 break;
436 default:
437 return -1;
440 switch (arg->stopbits)
442 case 1:
443 dcb.StopBits = ONESTOPBIT;
444 break;
445 case 2:
446 dcb.StopBits = TWOSTOPBITS;
447 break;
448 default:
449 return -1;
452 if (arg->paritymode)
454 dcb.fParity = TRUE;
455 if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0)
456 dcb.Parity = ODDPARITY;
457 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0)
458 dcb.Parity = EVENPARITY;
459 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0)
460 dcb.Parity = NOPARITY;
461 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_MARK) == 0)
462 dcb.Parity = MARKPARITY;
463 else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_SPACE) == 0)
464 dcb.Parity = SPACEPARITY;
465 else
466 return -1;
468 else
470 dcb.fParity = FALSE;
471 dcb.Parity = NOPARITY;
474 // Enable/disable RTS protocol.
475 switch (arg->rtsenb)
477 case 1:
478 dcb.fRtsControl = RTS_CONTROL_ENABLE;
479 break;
480 case 2:
481 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
482 break;
483 case 3:
484 dcb.fRtsControl = RTS_CONTROL_TOGGLE;
485 break;
486 default:
487 dcb.fRtsControl = RTS_CONTROL_DISABLE;
490 // Enable/disable CTS protocol.
491 if (arg->ctsenb)
492 dcb.fOutxCtsFlow = TRUE;
493 else
494 dcb.fOutxCtsFlow = FALSE;
496 // Enable/disable DSR protocol.
497 if (arg->dsrenb)
498 dcb.fOutxDsrFlow = TRUE;
499 else
500 dcb.fOutxDsrFlow = FALSE;
502 // Disable/enable DTR protocol
503 if (arg->dtrdisable)
504 dcb.fDtrControl = DTR_CONTROL_DISABLE;
505 else
506 dcb.fDtrControl = DTR_CONTROL_ENABLE;
508 // Enable/disable software flow control on input
509 if (arg->xinenb)
510 dcb.fInX = TRUE;
511 else
512 dcb.fInX = FALSE;
514 // Enable/disable software flow control on output
515 if (arg->xoutenb)
516 dcb.fOutX = TRUE;
517 else
518 dcb.fOutX = FALSE;
520 // Always set limits unless set to negative to use default.
521 if (arg->xonlim >= 0)
522 dcb.XonLim = static_cast<WORD>(arg->xonlim);
523 if (arg->xofflim >= 0)
524 dcb.XoffLim = static_cast<WORD>(arg->xofflim);
526 dcb.fAbortOnError = FALSE;
527 dcb.fErrorChar = FALSE;
528 dcb.fNull = FALSE;
529 dcb.fBinary = TRUE;
531 if (!::SetCommState (this->get_handle (), &dcb))
533 ACE_OS::set_errno_to_last_error ();
534 return -1;
537 if (arg->readtimeoutmsec < 0)
539 // Settings for infinite timeout.
540 timeouts.ReadIntervalTimeout = 0;
541 timeouts.ReadTotalTimeoutMultiplier = 0;
542 timeouts.ReadTotalTimeoutConstant = 0;
544 else if (arg->readtimeoutmsec == 0)
546 // Return immediately if no data in the input buffer.
547 timeouts.ReadIntervalTimeout = MAXDWORD;
548 timeouts.ReadTotalTimeoutMultiplier = 0;
549 timeouts.ReadTotalTimeoutConstant = 0;
551 else
553 // Wait for specified timeout for char to arrive before returning.
554 timeouts.ReadIntervalTimeout = MAXDWORD;
555 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
556 timeouts.ReadTotalTimeoutConstant = arg->readtimeoutmsec;
559 if (!::SetCommTimeouts (this->get_handle (), &timeouts))
561 ACE_OS::set_errno_to_last_error ();
562 return -1;
565 return 0;
567 case GETPARAMS:
568 arg->baudrate = dcb.BaudRate;
570 switch (dcb.ByteSize)
572 case 4:
573 case 5:
574 case 6:
575 case 7:
576 case 8:
577 arg->databits = dcb.ByteSize;
578 break;
579 default:
580 return -1;
583 switch (dcb.StopBits)
585 case ONESTOPBIT:
586 arg->stopbits = 1;
587 break;
588 case TWOSTOPBITS:
589 arg->stopbits = 2;
590 break;
591 default:
592 return -1;
595 if (!dcb.fParity)
597 arg->paritymode = ACE_TTY_IO_NONE;
599 else
601 switch (dcb.Parity)
603 case ODDPARITY:
604 arg->paritymode = ACE_TTY_IO_ODD;
605 break;
606 case EVENPARITY:
607 arg->paritymode = ACE_TTY_IO_EVEN;
608 break;
609 case NOPARITY:
610 arg->paritymode = ACE_TTY_IO_NONE;
611 break;
612 case MARKPARITY:
613 arg->paritymode = ACE_TTY_IO_MARK;
614 break;
615 case SPACEPARITY:
616 arg->paritymode = ACE_TTY_IO_SPACE;
617 break;
618 default:
619 return -1;
623 // Enable/disable RTS protocol.
624 switch (dcb.fRtsControl)
626 case RTS_CONTROL_ENABLE:
627 arg->rtsenb = 1;
628 break;
629 case RTS_CONTROL_HANDSHAKE:
630 arg->rtsenb = 2;
631 break;
632 case RTS_CONTROL_TOGGLE:
633 arg->rtsenb = 3;
634 break;
635 case RTS_CONTROL_DISABLE:
636 arg->rtsenb = 0;
637 break;
638 default:
639 return -1;
642 // Enable/disable CTS protocol.
643 if (dcb.fOutxCtsFlow)
644 arg->ctsenb = true;
645 else
646 arg->ctsenb = false;
648 // Enable/disable DSR protocol.
649 if (dcb.fOutxDsrFlow)
650 arg->dsrenb = true;
651 else
652 arg->dsrenb = false;
654 // Disable/enable DTR protocol
655 // Attention: DTR_CONTROL_HANDSHAKE is not supported.
656 switch (dcb.fDtrControl)
658 case DTR_CONTROL_DISABLE:
659 arg->dtrdisable = true;
660 break;
661 case DTR_CONTROL_ENABLE:
662 arg->dtrdisable = false;
663 break;
664 default:
665 return -1;
668 // Enable/disable software flow control on input
669 if (dcb.fInX)
670 arg->xinenb = true;
671 else
672 arg->xinenb = false;
674 // Enable/disable software flow control on output
675 if (dcb.fOutX)
676 arg->xoutenb = true;
677 else
678 arg->xoutenb = false;
680 arg->xonlim = static_cast<int>(dcb.XonLim);
681 arg->xofflim = static_cast<int>(dcb.XoffLim);
683 if (timeouts.ReadIntervalTimeout == 0 &&
684 timeouts.ReadTotalTimeoutMultiplier == 0 &&
685 timeouts.ReadTotalTimeoutConstant == 0)
686 arg->readtimeoutmsec = -1;
687 else
688 arg->readtimeoutmsec = timeouts.ReadTotalTimeoutConstant;
690 return 0;
692 default:
693 return -1; // Wrong cmd.
695 } // arg switch
696 #else
697 ACE_UNUSED_ARG (cmd);
698 ACE_UNUSED_ARG (arg);
699 ACE_NOTSUP_RETURN (-1);
700 #endif /* ACE_HAS_TERMIOS || ACE_HAS_TERMIO */
703 #if defined (ACE_NEEDS_DEV_IO_CONVERSION)
704 ACE_TTY_IO::operator ACE_DEV_IO &()
706 return static_cast<ACE_DEV_IO &>(*this);
708 #endif /* ACE_NEEDS_DEV_IO_CONVERSION */
710 ACE_END_VERSIONED_NAMESPACE_DECL