Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #include <swri_serial_util/serial_port.h>
00031 
00032 #include <errno.h> 
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 }