serial_port.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <swri_serial_util/serial_port.h>
00031 
00032 #include <errno.h> // NOLINT
00033 #include <sys/ioctl.h>
00034 #include <fcntl.h>
00035 #include <unistd.h>
00036 #include <poll.h>
00037 #include <termios.h>
00038 #include <linux/serial.h>
00039 #include <cstring>
00040 
00041 #include <boost/lexical_cast.hpp>
00042 
00043 namespace swri_serial_util
00044 {
00045   SerialConfig::SerialConfig() :
00046       baud(B115200),
00047       data_bits(8),
00048       stop_bits(1),
00049       parity(NO_PARITY),
00050       flow_control(false),
00051       low_latency_mode(false),
00052       writable(false)
00053   {
00054   }
00055 
00056   SerialConfig::SerialConfig(
00057       int32_t baud,
00058       int32_t data_bits,
00059       int32_t stop_bits,
00060       Parity parity,
00061       bool flow_control,
00062       bool low_latency_mode,
00063       bool writable) :
00064           baud(baud),
00065           data_bits(data_bits),
00066           stop_bits(stop_bits),
00067           parity(parity),
00068           flow_control(flow_control),
00069           low_latency_mode(low_latency_mode),
00070           writable(writable)
00071   {
00072   }
00073 
00074   SerialPort::SerialPort() :
00075     fd_(-1),
00076     error_msg_("")
00077   {
00078   }
00079 
00080   SerialPort::~SerialPort()
00081   {
00082     Close();
00083   }
00084 
00085   void SerialPort::Close()
00086   {
00087     if (fd_ < 0)
00088       return;
00089 
00090     close(fd_);
00091     fd_ = -1;
00092   }
00093 
00094   bool SerialPort::Open(const std::string &device, SerialConfig config)
00095   {
00096     Close();
00097 
00098     int32_t baud = ParseBaudRate(config.baud);
00099     if (baud == -1)
00100     {
00101       error_msg_ = "Invalid baud rate: " + boost::lexical_cast<std::string>(config.baud);
00102       return false;
00103     }
00104 
00105     if (config.stop_bits != 1 && config.stop_bits != 2)
00106     {
00107       error_msg_ = "Invalid stop bits: " + boost::lexical_cast<std::string>(config.stop_bits);
00108       return false;
00109     }
00110 
00111     if (config.data_bits != 7 && config.data_bits != 8)
00112     {
00113       error_msg_ = "Invalid data bits: " + boost::lexical_cast<std::string>(config.data_bits);
00114       return false;
00115     }
00116 
00117     if (config.parity != SerialConfig::NO_PARITY &&
00118         config.parity != SerialConfig::EVEN_PARITY &&
00119         config.parity != SerialConfig::ODD_PARITY)
00120     {
00121       error_msg_ = "Invalid parity mode.";
00122       return false;
00123     }
00124 
00125     fd_ = open(device.c_str(), config.writable ? O_RDWR : O_RDONLY);
00126     if (fd_ == -1)
00127     {
00128       error_msg_ = "Error opening serial port <" + device + ">: " + strerror(errno);
00129       return false;
00130     }
00131 
00132     struct termios term;
00133     if (tcgetattr(fd_, &term) < 0)
00134     {
00135       error_msg_ = "Unable to set serial attributes <" + device + ">: " + strerror(errno);
00136       Close();
00137       return false;
00138     }
00139 
00140     cfmakeraw(&term);
00141 
00142     if (config.stop_bits == 2)
00143     {
00144       term.c_cflag |= CSTOPB;
00145     }
00146     else
00147     {
00148       term.c_cflag &= ~CSTOPB;
00149     }
00150 
00151     if (config.parity == SerialConfig::EVEN_PARITY)
00152     {
00153       term.c_cflag |= PARENB;
00154       term.c_cflag &= ~PARODD;
00155     }
00156     else if (config.parity == SerialConfig::ODD_PARITY)
00157     {
00158       term.c_cflag |= PARENB;
00159       term.c_cflag |= PARODD;
00160     }
00161     else
00162     {
00163       term.c_cflag &= ~PARENB;
00164       term.c_cflag &= ~PARODD;
00165     }
00166 
00167     if (config.data_bits == 8)
00168     {
00169       term.c_cflag &= ~CSIZE;
00170       term.c_cflag |= CS8;
00171     }
00172     else
00173     {
00174       term.c_cflag &= ~CSIZE;
00175       term.c_cflag |= CS7;
00176     }
00177 
00178     if (cfsetspeed(&term, config.baud) < 0)
00179     {
00180       error_msg_ = "Invalid baud rate: " + boost::lexical_cast<std::string>(config.baud);
00181       Close();
00182       return false;
00183     }
00184 
00185     if (tcsetattr(fd_, TCSAFLUSH, &term) < 0)
00186     {
00187       error_msg_ = "Unable to set serial port attributes <" + device + ">: " + strerror(errno);
00188       Close();
00189       return false;
00190     }
00191 
00192     if (config.low_latency_mode && !SetLowLatencyMode())
00193     {
00194       Close();
00195       return false;
00196     }
00197 
00198     return true;
00199   }
00200 
00201   bool SerialPort::SetLowLatencyMode()
00202   {
00203     if (fd_ < 0)
00204     {
00205       error_msg_ = "Device not open.";
00206       return false;
00207     }
00208 
00209     struct serial_struct serial_info;
00210 
00211     if (ioctl(fd_, TIOCGSERIAL, &serial_info) < 0)
00212     {
00213       error_msg_ = "Failed to set low latency mode.  Cannot get serial configuration: " + std::string(strerror(errno));
00214       return false;
00215     }
00216 
00217     serial_info.flags |= ASYNC_LOW_LATENCY;
00218 
00219     if (ioctl(fd_, TIOCSSERIAL, &serial_info) < 0)
00220     {
00221       error_msg_ = "Failed to set low latency mode.  Cannot set serial configuration: " + std::string(strerror(errno));
00222       return false;
00223     }
00224 
00225     return true;
00226   }
00227 
00228   int32_t SerialPort::ParseBaudRate(int32_t baud)
00229   {
00230     int32_t value = -1;
00231 
00232     if (baud == B50 || baud == 50)
00233     {
00234       value = B50;
00235     }
00236     else if (baud == B75 || baud == 75)
00237     {
00238       value = B75;
00239     }
00240     else if (baud == B110 || baud == 110)
00241     {
00242       value = B110;
00243     }
00244     else if (baud == B134 || baud == 134)
00245     {
00246       value = B134;
00247     }
00248     else if (baud == B150 || baud == 150)
00249     {
00250       value = B150;
00251     }
00252     else if (baud == B200 || baud == 200)
00253     {
00254       value = B200;
00255     }
00256     else if (baud == B300 || baud == 300)
00257     {
00258       value = B300;
00259     }
00260     else if (baud == B600 || baud == 600)
00261     {
00262       value = B600;
00263     }
00264     else if (baud == B1200 || baud == 1200)
00265     {
00266       value = B1200;
00267     }
00268     else if (baud == B1800 || baud == 1800)
00269     {
00270       value = B1800;
00271     }
00272     else if (baud == B2400 || baud == 2400)
00273     {
00274       value = B2400;
00275     }
00276     else if (baud == B4800 || baud == 4800)
00277     {
00278       value = B4800;
00279     }
00280     else if (baud == B9600 || baud == 9600)
00281     {
00282       value = B9600;
00283     }
00284     else if (baud == B19200 || baud == 19200)
00285     {
00286       value = B19200;
00287     }
00288     else if (baud == B38400 || baud == 38400)
00289     {
00290       value = B38400;
00291     }
00292     else if (baud == B57600 || baud == 57600)
00293     {
00294       value = B57600;
00295     }
00296     else if (baud == B115200 || baud == 115200)
00297     {
00298       value = B115200;
00299     }
00300     else if (baud == B230400 || baud == 230400)
00301     {
00302       value = B230400;
00303     }
00304     else if (baud == B460800 || baud == 460800)
00305     {
00306       value = B460800;
00307     }
00308     else if (baud == B576000 || baud == 576000)
00309     {
00310       value = B576000;
00311     }
00312     else if (baud == B921600 || baud == 921600)
00313     {
00314       value = B921600;
00315     }
00316     else if (baud == B1000000 || baud == 1000000)
00317     {
00318       value = B1000000;
00319     }
00320     else if (baud == B1152000 || baud == 1152000)
00321     {
00322       value = B1152000;
00323     }
00324     else if (baud == B1500000 || baud == 1500000)
00325     {
00326       value = B1500000;
00327     }
00328     else if (baud == B2000000 || baud == 2000000)
00329     {
00330       value = B2000000;
00331     }
00332     else if (baud == B2500000 || baud == 2500000)
00333     {
00334       value = B2500000;
00335     }
00336     else if (baud == B3000000 || baud == 3000000)
00337     {
00338       value = B3000000;
00339     }
00340     else if (baud == B3500000 || baud == 3500000)
00341     {
00342       value = B3500000;
00343     }
00344     else if (baud == B4000000 || baud == 4000000)
00345     {
00346       value = B4000000;
00347     }
00348 
00349     return value;
00350   }
00351 
00352   SerialPort::Result SerialPort::ReadBytes(std::vector<uint8_t>& output, size_t max_bytes, int32_t timeout)
00353   {
00354     if (fd_ < 0)
00355     {
00356       error_msg_ = "Device not open.";
00357       return ERROR;
00358     }
00359 
00360     struct pollfd fds[1];
00361     fds[0].fd = fd_;
00362     fds[0].events = POLLIN;
00363 
00364     int poll_return = poll(fds, 1, timeout);
00365     if (poll_return == 0)
00366     {
00367       error_msg_ = "Timed out while waiting for data.";
00368       return TIMEOUT;
00369     }
00370     else if (poll_return < 0)
00371     {
00372       int error_num = errno;
00373       switch (error_num)
00374       {
00375         case EINTR:
00376           return INTERRUPTED;
00377         default:
00378           error_msg_ = "Error polling serial port: " + std::string(strerror(errno));
00379           return ERROR;
00380       }
00381     }
00382 
00383     size_t to_read = max_bytes;
00384     if (to_read <= 0)
00385     {
00386       int bytes;
00387       ioctl(fd_, FIONREAD, &bytes);
00388       if (bytes < 0)
00389       {
00390         error_msg_ = "Error getting number of available bytes from serial port: " + std::string(strerror(errno));
00391         return ERROR;
00392       }
00393       to_read = static_cast<size_t>(bytes);
00394     }
00395 
00396     size_t output_size = output.size();
00397     output.resize(output_size + to_read);
00398 
00399     int result = read(fd_, output.data() + output_size, to_read);
00400 
00401     if (result > 0)
00402     {
00403       output.resize(output_size + result);
00404     }
00405     else
00406     {
00407       output.resize(output_size);
00408     }
00409 
00410     if (result > 0)
00411     {
00412       return SUCCESS;
00413     }
00414     else if (result == 0)
00415     {
00416       return INTERRUPTED;
00417     }
00418     else
00419     {
00420       int error_num = errno;
00421       switch (error_num)
00422       {
00423         case EINTR:
00424           return INTERRUPTED;
00425           break;
00426         default:
00427           error_msg_ = "Error reading serial port: " + std::string(strerror(errno));
00428           return ERROR;
00429       }
00430     }
00431   }
00432 
00433   int32_t SerialPort::Write(const std::vector<uint8_t>& input)
00434   {
00435     return write(fd_, input.data(), input.size());
00436   }
00437 }


swri_serial_util
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 20:34:57