// serial_dev.cc // robert - programme du robot 2005. {{{ // // Copyright (C) 2005 Nicolas Schodet // // Robot APB Team/Efrei 2005. // Web: http://assos.efrei.fr/robot/ // Email: robot AT efrei DOT fr // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // }}} #include "serial_dev.hh" #include "utils/errno_exception.hh" #include #include #include /// Constructeur. SerialDev::SerialDev (bool blocking/*false*/) : blocking_ (blocking) { } /// Destructeur. SerialDev::~SerialDev (void) { close (); } /// Ouvre et paramètre le port série, accepte plusieurs paramètres séparés par /// des virgules : tty, vitesse, parité (none, odd, even). Par exemple : /// "/dev/ttyS00,115200,even" (par defaut). void SerialDev::open (const std::string &ttyname) { struct termios tios; std::string tty; int speed = 115200; char par = 'e'; // Décode le ttyname. decode (ttyname, tty, speed, par); // Ouvre le port série. fdIn_ = ::open (tty.c_str (), O_RDWR | O_NOCTTY | O_NONBLOCK); if (fdIn_ < 0) throw errno_exception (ttyname, errno); // Rendre le port série asynchrone. //fcntl (fd_, F_SETFL, FASYNC); // Sauver la configuration courante du port série. tcgetattr (fdIn_, &old_); tcgetattr (fdIn_, &tios); // Paramètrer les options du port série. // Vérification de la parité en entrée, remplace toute erreur de // transmission par un caractère nul. Pas de Xon Xoff. Entrée crue. tios.c_iflag &= ~(IGNPAR | PARMRK | ISTRIP | IGNBRK | BRKINT | IGNCR | ICRNL | INLCR | IXON | IXOFF | IXANY | IMAXBEL); tios.c_iflag |= INPCK; // Sortie crue. tios.c_oflag &= ~(OPOST); // Pas de status line, 1 bit de stop, 8 bits de données, règle la parité. tios.c_cflag &= ~(HUPCL | CSTOPB | PARENB | PARODD | CSIZE); tios.c_cflag |= CS8 | CLOCAL | CREAD; if (par != 'n') tios.c_cflag |= PARENB; if (par == 'o') tios.c_cflag |= PARODD; // Cru. tios.c_lflag &= ~(ICANON | ECHO | ISIG | NOFLSH | TOSTOP); // On n'attend jamais si on est en non-block. On attend sinon. tios.c_cc[VTIME] = 0; if (blocking_) tios.c_cc[VMIN] = 1; else tios.c_cc[VMIN] = 0; switch (speed) { case 1200: cfsetspeed (&tios, B1200); break; case 9600: cfsetspeed (&tios, B9600); break; case 19200: cfsetspeed (&tios, B19200); break; case 38400: cfsetspeed (&tios, B38400); break; case 57600: cfsetspeed (&tios, B57600); break; case 115200: cfsetspeed (&tios, B115200); break; case 230400: cfsetspeed (&tios, B230400); break; case 460800: cfsetspeed (&tios, B460800); break; default: throw std::runtime_error ("Vitesse de port série non supportée\n"); } // Vider et configurer le port série. tcflush (fdIn_, TCIFLUSH); tcsetattr (fdIn_, TCSANOW, &tios); fdOut_ = fdIn_; } /// Ferme le port série, appellé automatiquement dans le destructeur de la /// classe SerialBase. void SerialDev::close (void) { if (fdIn_ != -1) { tcsetattr (fdIn_, TCSANOW, &old_); ::close (fdIn_); fdIn_ = -1; fdOut_ = -1; } } /// Décode le ttyname, voir open. void SerialDev::decode (const std::string &ttyname, std::string &tty, int &speed, char &par) const { std::string::size_type a, b, d; int i; a = 0; b = ttyname.find (','); while (a != std::string::npos) { d = b == std::string::npos ? std::string::npos : b - a; std::string s (ttyname, a, d); i = atoi (s.c_str ()); if (i) speed = i; else { if (s == "e" || s == "even") par = 'e'; else if (s == "o" || s == "odd") par = 'o'; else if (s == "n" || s == "none") par = 'n'; else if (tty.empty ()) tty = s; else throw std::runtime_error ("error in ttyname: " + s); } a = b == std::string::npos ? b : b + 1; b = ttyname.find (',', a); } }