// $Id$ #include "ace/TTY_IO.h" #include "ace/OS_NS_errno.h" #include "ace/OS_NS_string.h" #include "ace/OS_NS_strings.h" #if defined (ACE_HAS_TERMIOS) # include "ace/os_include/os_termios.h" #elif defined (ACE_HAS_TERMIO) # include #endif ACE_RCSID (ace, TTY_IO, "$Id$") namespace { const char ACE_TTY_IO_NONE[] = "none"; #if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO) || defined (ACE_WIN32) const char ACE_TTY_IO_ODD[] = "odd"; const char ACE_TTY_IO_EVEN[] = "even"; #endif #if defined (ACE_WIN32) const char ACE_TTY_IO_MARK[] = "mark"; const char ACE_TTY_IO_SPACE[] = "space"; #endif /* ACE_WIN32 */ } ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_TTY_IO::Serial_Params::Serial_Params (void) { baudrate = 9600; xonlim = 0; xofflim = 0; readmincharacters = 0; readtimeoutmsec = 10000; paritymode = ACE_TTY_IO_NONE; ctsenb = false; rtsenb = 0; xinenb = false; xoutenb = false; modem = false; rcvenb = true; dsrenb = false; dtrdisable = false; databits = 8; stopbits = 1; } // Interface for reading/writing serial device parameters int ACE_TTY_IO::control (Control_Mode cmd, Serial_Params *arg) const { #if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO) #if defined (ACE_HAS_TERMIOS) struct termios devpar; speed_t newbaudrate = 0; if (tcgetattr (get_handle () , &devpar) == -1) #elif defined (TCGETS) struct termios devpar; unsigned int newbaudrate = 0; if (this->ACE_IO_SAP::control (TCGETS, static_cast(&devpar)) == -1) #elif defined (TCGETA) struct termio devpar; unsigned int newbaudrate = 0; if (this->ACE_IO_SAP::control (TCGETA, static_cast(&devpar)) == -1) #else errno = ENOSYS; #endif /* ACE_HAS_TERMIOS */ return -1; switch (cmd) { case SETPARAMS: switch (arg->baudrate) { #if defined (B0) case 0: newbaudrate = B0; break; #endif /* B0 */ #if defined (B50) case 50: newbaudrate = B50; break; #endif /* B50 */ #if defined (B75) case 75: newbaudrate = B75; break; #endif /* B75 */ #if defined (B110) case 110: newbaudrate = B110; break; #endif /* B110 */ #if defined (B134) case 134: newbaudrate = B134; break; #endif /* B134 */ #if defined (B150) case 150: newbaudrate = B150; break; #endif /* B150 */ #if defined (B200) case 200: newbaudrate = B200; break; #endif /* B200 */ #if defined (B300) case 300: newbaudrate = B300; break; #endif /* B300 */ #if defined (B600) case 600: newbaudrate = B600; break; #endif /* B600 */ #if defined (B1200) case 1200: newbaudrate = B1200; break; #endif /* B1200 */ #if defined (B1800) case 1800: newbaudrate = B1800; break; #endif /* B1800 */ #if defined (B2400) case 2400: newbaudrate = B2400; break; #endif /* B2400 */ #if defined (B4800) case 4800: newbaudrate = B4800; break; #endif /* B4800 */ #if defined (B9600) case 9600: newbaudrate = B9600; break; #endif /* B9600 */ #if defined (B19200) case 19200: newbaudrate = B19200; break; #endif /* B19200 */ #if defined (B38400) case 38400: newbaudrate = B38400; break; #endif /* B38400 */ #if defined (B56000) case 56000: newbaudrate = B56000; break; #endif /* B56000 */ #if defined (B57600) case 57600: newbaudrate = B57600; break; #endif /* B57600 */ #if defined (B76800) case 76800: newbaudrate = B76800; break; #endif /* B76800 */ #if defined (B115200) case 115200: newbaudrate = B115200; break; #endif /* B115200 */ #if defined (B128000) case 128000: newbaudrate = B128000; break; #endif /* B128000 */ #if defined (B153600) case 153600: newbaudrate = B153600; break; #endif /* B153600 */ #if defined (B230400) case 230400: newbaudrate = B230400; break; #endif /* B230400 */ #if defined (B307200) case 307200: newbaudrate = B307200; break; #endif /* B307200 */ #if defined (B256000) case 256000: newbaudrate = B256000; break; #endif /* B256000 */ #if defined (B460800) case 460800: newbaudrate = B460800; break; #endif /* B460800 */ #if defined (B500000) case 500000: newbaudrate = B500000; break; #endif /* B500000 */ #if defined (B576000) case 576000: newbaudrate = B576000; break; #endif /* B576000 */ #if defined (B921600) case 921600: newbaudrate = B921600; break; #endif /* B921600 */ #if defined (B1000000) case 1000000: newbaudrate = B1000000; break; #endif /* B1000000 */ #if defined (B1152000) case 1152000: newbaudrate = B1152000; break; #endif /* B1152000 */ #if defined (B1500000) case 1500000: newbaudrate = B1500000; break; #endif /* B1500000 */ #if defined (B2000000) case 2000000: newbaudrate = B2000000; break; #endif /* B2000000 */ #if defined (B2500000) case 2500000: newbaudrate = B2500000; break; #endif /* B2500000 */ #if defined (B3000000) case 3000000: newbaudrate = B3000000; break; #endif /* B3000000 */ #if defined (B3500000) case 3500000: newbaudrate = B3500000; break; #endif /* B3500000 */ #if defined (B4000000) case 4000000: newbaudrate = B4000000; break; #endif /* B4000000 */ default: return -1; } #if defined (ACE_HAS_TERMIOS) // Can you really have different input and output baud rates?! if (cfsetospeed (&devpar, newbaudrate) == -1) return -1; if (cfsetispeed (&devpar, newbaudrate) == -1) return -1; #else devpar.c_cflag &= ~CBAUD; # if defined (CBAUDEX) devpar.c_cflag &= ~CBAUDEX; # endif /* CBAUDEX */ devpar.c_cflag |= newbaudrate; #endif /* ACE_HAS_TERMIOS */ devpar.c_cflag &= ~CSIZE; switch (arg->databits) { case 5: devpar.c_cflag |= CS5; break; case 6: devpar.c_cflag |= CS6; break; case 7: devpar.c_cflag |= CS7; break; case 8: devpar.c_cflag |= CS8; break; default: return -1; } switch (arg->stopbits) { case 1: devpar.c_cflag &= ~CSTOPB; break; case 2: devpar.c_cflag |= CSTOPB; break; default: return -1; } if (arg->paritymode) { if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0) { devpar.c_cflag |= PARENB; devpar.c_cflag |= PARODD; } else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0) { devpar.c_cflag |= PARENB; devpar.c_cflag &= ~PARODD; } else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0) devpar.c_cflag &= ~PARENB; else return -1; } else { devpar.c_cflag &= ~PARENB; } #if defined (CNEW_RTSCTS) if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol devpar.c_cflag |= CNEW_RTSCTS; else devpar.c_cflag &= ~CNEW_RTSCTS; #elif defined (CRTSCTS) if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol devpar.c_cflag |= CRTSCTS; else devpar.c_cflag &= ~CRTSCTS; #endif /* NEW_RTSCTS || CRTSCTS */ #if defined (CREAD) // Enable/disable receiver if (arg->rcvenb) devpar.c_cflag |= CREAD; else devpar.c_cflag &= ~CREAD; #endif /* CREAD */ #if defined (HUPCL) // Cause DTR to drop after port close. devpar.c_cflag |= HUPCL; #endif /* HUPCL */ #if defined (CLOCAL) // If device is not a modem set to local device. if (arg->modem) devpar.c_cflag &= ~CLOCAL; else devpar.c_cflag |= CLOCAL; #endif /* CLOCAL */ devpar.c_iflag = IGNPAR | INPCK; if (arg->databits < 8) devpar.c_iflag |= ISTRIP; #if defined (IGNBRK) // If device is not a modem set to ignore break points if(arg->modem) devpar.c_iflag &= ~IGNBRK; else devpar.c_iflag |= IGNBRK; #endif /* IGNBRK */ #if defined (IXOFF) // Enable/disable software flow control on input if (arg->xinenb) devpar.c_iflag |= IXOFF; else devpar.c_iflag &= ~IXOFF; #endif /* IXOFF */ #if defined (IXON) // Enable/disable software flow control on output if (arg->xoutenb) devpar.c_iflag |= IXON; else devpar.c_iflag &= ~IXON; #endif /* IXON */ #if defined (ICANON) // Enable noncanonical input processing mode devpar.c_lflag &= ~ICANON; #endif /* ICANON */ #if defined (ECHO) // Disable echoing of input characters devpar.c_lflag &= ~ECHO; #endif /* ECHO */ #if defined (ECHOE) // Disable echoing erase chareacter as BS-SP-BS devpar.c_lflag &= ~ECHOE; #endif /* ECHOE */ #if defined (ISIG) // Disable SIGINTR, SIGSUSP, SIGDSUSP and SIGQUIT signals devpar.c_lflag &= ~ISIG; #endif /* ISIG */ #if defined (OPOST) // Disable post-processing of output data devpar.c_oflag &= ~OPOST; #endif /* OPOST */ if (arg->readtimeoutmsec < 0) { // Settings for infinite timeout. devpar.c_cc[VTIME] = 0; // In case of infinite timeout [VMIN] must be at least 1. if (arg->readmincharacters > UCHAR_MAX) devpar.c_cc[VMIN] = UCHAR_MAX; else if (arg->readmincharacters < 1) devpar.c_cc[VMIN] = 1; else devpar.c_cc[VMIN] = static_cast(arg->readmincharacters); } else { devpar.c_cc[VTIME] = static_cast(arg->readtimeoutmsec / 100); if (arg->readmincharacters > UCHAR_MAX) devpar.c_cc[VMIN] = UCHAR_MAX; else if (arg->readmincharacters < 1) devpar.c_cc[VMIN] = 0; else devpar.c_cc[VMIN] = static_cast(arg->readmincharacters); } #if defined (TIOCMGET) int status; this->ACE_IO_SAP::control (TIOCMGET, &status); if (arg->dtrdisable) status &= ~TIOCM_DTR; else status |= TIOCM_DTR; this->ACE_IO_SAP::control (TIOCMSET, &status); #endif /* definded (TIOCMGET) */ #if defined (ACE_HAS_TERMIOS) return tcsetattr (get_handle (), TCSANOW, &devpar); #elif defined (TCSETS) return this->ACE_IO_SAP::control (TCSETS, static_cast(&devpar)); #elif defined (TCSETA) return this->ACE_IO_SAP::control (TCSETA, static_cast(&devpar)); #else errno = ENOSYS; return -1; #endif /* ACE_HAS_TERMIOS */ case GETPARAMS: return -1; // Not yet implemented. default: return -1; // Wrong cmd. } #elif defined (ACE_WIN32) switch (cmd) { case SETPARAMS: DCB dcb; dcb.DCBlength = sizeof dcb; if (!::GetCommState (this->get_handle (), &dcb)) { ACE_OS::set_errno_to_last_error (); return -1; } dcb.BaudRate = arg->baudrate; switch (arg->databits) { case 4: case 5: case 6: case 7: case 8: dcb.ByteSize = arg->databits; break; default: return -1; } switch (arg->stopbits) { case 1: dcb.StopBits = ONESTOPBIT; break; case 2: dcb.StopBits = TWOSTOPBITS; break; default: return -1; } if (arg->paritymode) { dcb.fParity = TRUE; if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0) dcb.Parity = ODDPARITY; else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0) dcb.Parity = EVENPARITY; else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0) dcb.Parity = NOPARITY; else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_MARK) == 0) dcb.Parity = MARKPARITY; else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_SPACE) == 0) dcb.Parity = SPACEPARITY; else return -1; } else { dcb.fParity = FALSE; dcb.Parity = NOPARITY; } // Enable/disable RTS protocol. switch (arg->rtsenb) { case 1: dcb.fRtsControl = RTS_CONTROL_ENABLE; break; case 2: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; break; case 3: dcb.fRtsControl = RTS_CONTROL_TOGGLE; break; default: dcb.fRtsControl = RTS_CONTROL_DISABLE; } // Enable/disable CTS protocol. if (arg->ctsenb) dcb.fOutxCtsFlow = TRUE; else dcb.fOutxCtsFlow = FALSE; // Enable/disable DSR protocol. if (arg->dsrenb) dcb.fOutxDsrFlow = TRUE; else dcb.fOutxDsrFlow = FALSE; // Disable/enable DTR protocol if (arg->dtrdisable) dcb.fDtrControl = DTR_CONTROL_DISABLE; else dcb.fDtrControl = DTR_CONTROL_ENABLE; // Enable/disable software flow control on input if (arg->xinenb) dcb.fInX = TRUE; else dcb.fInX = FALSE; // Enable/disable software flow control on output if (arg->xoutenb) dcb.fOutX = TRUE; else dcb.fOutX = FALSE; // Always set limits unless set to negative to use default. if (arg->xonlim >= 0) dcb.XonLim = static_cast(arg->xonlim); if (arg->xofflim >= 0) dcb.XoffLim = static_cast(arg->xofflim); dcb.fAbortOnError = FALSE; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fBinary = TRUE; if (!::SetCommState (this->get_handle (), &dcb)) { ACE_OS::set_errno_to_last_error (); return -1; } COMMTIMEOUTS timeouts; if (!::GetCommTimeouts (this->get_handle(), &timeouts)) { ACE_OS::set_errno_to_last_error (); return -1; } if (arg->readtimeoutmsec < 0) { // Settings for infinite timeout. timeouts.ReadIntervalTimeout = 0; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; } else if (arg->readtimeoutmsec == 0) { // Return immediately if no data in the input buffer. timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; } else { // Wait for specified timeout for char to arrive before returning. timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = arg->readtimeoutmsec; } if (!::SetCommTimeouts (this->get_handle (), &timeouts)) { ACE_OS::set_errno_to_last_error (); return -1; } return 0; case GETPARAMS: ACE_NOTSUP_RETURN (-1); // Not yet implemented. default: return -1; // Wrong cmd. } // arg switch #else ACE_UNUSED_ARG (cmd); ACE_UNUSED_ARG (arg); ACE_NOTSUP_RETURN (-1); #endif /* ACE_HAS_TERMIOS || ACE_HAS_TERMIO */ } #if defined (ACE_NEEDS_DEV_IO_CONVERSION) ACE_TTY_IO::operator ACE_DEV_IO &() { return static_cast(*this); } #endif /* ACE_NEEDS_DEV_IO_CONVERSION */ ACE_END_VERSIONED_NAMESPACE_DECL