1
0
mirror of https://github.com/wjwwood/serial.git synced 2026-01-22 19:54:57 +08:00

Merge branch 'boostless' of https://github.com/wjwwood/serial into boostless

Conflicts:
	include/serial/serial_listener.h
This commit is contained in:
William Woodall 2012-01-15 16:19:51 -06:00
commit 214b763664
10 changed files with 791 additions and 564 deletions

View File

@ -1,10 +1,9 @@
# ash_gti's dumb downed makefile so I can more easily test stuff # # ash_gti's dumb downed makefile so I can more easily test stuff
# CXX=clang++ # CXX=clang++
# CXXFLAGS=-g -I./include # CXXFLAGS=-g -I./include -ferror-limit=5 -O3 -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wall -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment -Wconversion -Wdisabled-optimization -Wfloat-equal -Wformat -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimplicit -Wimport -Winit-self -Winline -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wstack-protector -Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch -Wswitch-default -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings
# #
# test: tests/serial_tests.o src/serial.o src/impl/unix.o # test: tests/serial_tests.o src/serial.o src/impl/unix.o
# $(CXX) -o test tests/serial_tests.o src/serial.o src/impl/unix.o # $(CXX) -o test tests/serial_tests.o src/serial.o src/impl/unix.o
#
ifdef ROS_ROOT ifdef ROS_ROOT
include $(shell rospack find mk)/cmake.mk include $(shell rospack find mk)/cmake.mk
else else

View File

@ -8,7 +8,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2011 William Woodall * Copyright (c) 2011 William Woodall, John Harrison
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
@ -30,7 +30,9 @@
* *
* \section DESCRIPTION * \section DESCRIPTION
* *
* This provides a unix based pimpl for the Serial class. * This provides a unix based pimpl for the Serial class. This implementation is
* based off termios.h and uses select for multiplexing the IO ports.
*
*/ */
#ifndef SERIAL_IMPL_UNIX_H #ifndef SERIAL_IMPL_UNIX_H
@ -42,6 +44,7 @@ namespace serial {
using std::string; using std::string;
using std::invalid_argument; using std::invalid_argument;
using serial::SerialExecption; using serial::SerialExecption;
using serial::IOException; using serial::IOException;
@ -57,47 +60,98 @@ public:
virtual ~SerialImpl (); virtual ~SerialImpl ();
void open (); void
void close () ; open ();
bool isOpen () const;
size_t available (); void
string read (size_t size = 1); close ();
size_t write (const string &data);
void flush (); bool
void flushInput (); isOpen () const;
void flushOutput ();
void sendBreak(int duration); size_t
void setBreak(bool level); available ();
void setRTS(bool level);
void setDTR(bool level);
bool getCTS();
bool getDSR();
bool getRI();
bool getCD();
void setPort (const string &port); size_t
string getPort () const; read (char* buf, size_t size = 1);
void setTimeout (long timeout); size_t
long getTimeout () const; write (const string &data);
void setBaudrate (unsigned long baudrate); void
unsigned long getBaudrate () const; flush ();
void setBytesize (bytesize_t bytesize); void
bytesize_t getBytesize () const; flushInput ();
void setParity (parity_t parity); void
parity_t getParity () const; flushOutput ();
void setStopbits (stopbits_t stopbits); void
stopbits_t getStopbits () const; sendBreak(int duration);
void setFlowcontrol (flowcontrol_t flowcontrol); void
flowcontrol_t getFlowcontrol () const; setBreak(bool level);
void
setRTS(bool level);
void
setDTR(bool level);
bool
getCTS();
bool
getDSR();
bool
getRI();
bool
getCD();
void
setPort (const string &port);
string
getPort () const;
void
setTimeout (long timeout);
long
getTimeout () const;
void
setBaudrate (unsigned long baudrate);
unsigned long
getBaudrate () const;
void
setBytesize (bytesize_t bytesize);
bytesize_t
getBytesize () const;
void
setParity (parity_t parity);
parity_t
getParity () const;
void
setStopbits (stopbits_t stopbits);
stopbits_t
getStopbits () const;
void
setFlowcontrol (flowcontrol_t flowcontrol);
flowcontrol_t
getFlowcontrol () const;
protected: protected:
void reconfigurePort (); void reconfigurePort ();
@ -106,14 +160,10 @@ private:
string port_; // Path to the file descriptor string port_; // Path to the file descriptor
int fd_; // The current file descriptor int fd_; // The current file descriptor
int interCharTimeout_;
int writeTimeout_;
bool isOpen_; bool isOpen_;
bool xonxoff_; bool xonxoff_;
bool rtscts_; bool rtscts_;
char ___; // lol padding
long timeout_; // Timeout for read operations long timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate unsigned long baudrate_; // Baudrate

View File

@ -153,6 +153,9 @@ public:
* FLOWCONTROL_NONE, possible values are: FLOWCONTROL_NONE, * FLOWCONTROL_NONE, possible values are: FLOWCONTROL_NONE,
* FLOWCONTROL_SOFTWARE, FLOWCONTROL_HARDWARE * FLOWCONTROL_SOFTWARE, FLOWCONTROL_HARDWARE
* *
* \param buffer_size The maximum size of the internal buffer, defaults
* to 256 bytes (2^8).
*
* \throw PortNotOpenedException * \throw PortNotOpenedException
*/ */
Serial (const std::string &port = "", Serial (const std::string &port = "",
@ -161,7 +164,8 @@ public:
bytesize_t bytesize = EIGHTBITS, bytesize_t bytesize = EIGHTBITS,
parity_t parity = PARITY_NONE, parity_t parity = PARITY_NONE,
stopbits_t stopbits = STOPBITS_ONE, stopbits_t stopbits = STOPBITS_ONE,
flowcontrol_t flowcontrol = FLOWCONTROL_NONE); flowcontrol_t flowcontrol = FLOWCONTROL_NONE,
const size_t buffer_size = 256);
/*! Destructor */ /*! Destructor */
virtual ~Serial (); virtual ~Serial ();
@ -197,22 +201,6 @@ public:
size_t size_t
available(); available();
/*! Read a given amount of bytes from the serial port.
*
* If a timeout is set it may return less characters than requested. With
* no timeout it will block until the requested number of bytes have been
* read or until an exception occurs.
*
* \param buffer An unsigned char array large enough to hold incoming data
* up to the requested size.
*
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes actually read.
*/
//size_t
//read (unsigned char* buffer, size_t size = 1);
/*! Read a given amount of bytes from the serial port. /*! Read a given amount of bytes from the serial port.
* *
* If a timeout is set it may return less characters than requested. With * If a timeout is set it may return less characters than requested. With
@ -226,36 +214,30 @@ public:
std::string std::string
read (size_t size = 1); read (size_t size = 1);
std::string readline(size_t size = std::numeric_limits<std::size_t>::max(), /*! Reads in a line or until a given delimiter has been processed
*
* Reads from the serial port until a single line has been read.
*
* \param size A maximum length of a line defaults to size_t::max()
* \param eol A string to match against for the EOL.
*
* \return A std::string containing the line.
*/
std::string
readline(size_t size = std::numeric_limits<std::size_t>::max(),
std::string eol = "\n"); std::string eol = "\n");
std::vector<std::string> readlines(std::string eol = "\n"); /*! Reads in multiple lines until the serail port times out.
/*! Read a given amount of bytes from the serial port.
* *
* Reads into a std::string by reference rather than returning it. * This requires a timeout > 0 before it can be run. It will read until a
* timeout occurs and return a list of strings.
* *
* \param buffer A std::string reference for reading to. * \param eol A string to match against for the EOL.
* \param size A size_t defining how many bytes to be read.
* *
* \return A size_t that represents how many bytes were read. * \return A vector<string> containing the lines.
*
* \see Serial::read(size_t)
*/ */
//size_t std::vector<std::string>
//read (std::string &buffer, size_t size = 1); readlines(std::string eol = "\n");
/*! Write bytes from the data to the serial port by given length.
*
* \param data An unsigned char array containing data to be written to the
* serial port.
*
* \param length A size_t representing the number of bytes to be written.
*
* \return A size_t representing the number of bytes actually written.
*/
//size_t
//write (unsigned char* data, size_t length);
/*! Write a string to the serial port. /*! Write a string to the serial port.
* *
@ -412,17 +394,41 @@ public:
flowcontrol_t flowcontrol_t
getFlowcontrol () const; getFlowcontrol () const;
void flush(); /*! Flush the input and output buffers */
void flushInput(); void
void flushOutput(); flush ();
void sendBreak(int duration);
void setBreak(bool level = true); /*! Flush only the input buffer */
void setRTS(bool level = true); void
void setDTR(bool level = true); flushInput ();
bool getCTS();
bool getDSR(); /*! Flush only the output buffer */
bool getRI(); void
bool getCD(); flushOutput ();
void
sendBreak (int duration);
void
setBreak (bool level = true);
void
setRTS (bool level = true);
void
setDTR (bool level = true);
bool
getCTS ();
bool
getDSR ();
bool
getRI ();
bool
getCD ();
private: private:
// Disable copy constructors // Disable copy constructors
@ -430,9 +436,12 @@ private:
void operator=(const Serial&); void operator=(const Serial&);
const Serial& operator=(Serial); const Serial& operator=(Serial);
const size_t buffer_size_;
char *read_cache_; //!< Cache for doing reads in chunks.
// Pimpl idiom, d_pointer // Pimpl idiom, d_pointer
class SerialImpl; class SerialImpl;
SerialImpl *pimpl; SerialImpl *pimpl_;
}; };
} // namespace serial } // namespace serial

View File

@ -15,7 +15,7 @@ IF(EXISTS /usr/bin/clang)
set(CMAKE_CXX_COMPILER /usr/bin/clang++) set(CMAKE_CXX_COMPILER /usr/bin/clang++)
set(CMAKE_OSX_DEPLOYMENT_TARGET "") set(CMAKE_OSX_DEPLOYMENT_TARGET "")
# set(CMAKE_CXX_FLAGS "-ferror-limit=5 -std=c++0x -stdlib=libc++") # set(CMAKE_CXX_FLAGS "-ferror-limit=5 -std=c++0x -stdlib=libc++")
set(CMAKE_CXX_FLAGS "-ferror-limit=5 -m64 -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wall -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment -Wconversion -Wdisabled-optimization -Wfloat-equal -Wformat -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimplicit -Wimport -Winit-self -Winline -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpadded -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wstack-protector -Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch -Wswitch-default -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings") set(CMAKE_CXX_FLAGS "-ferror-limit=5 -O3 -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wall -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment -Wconversion -Wdisabled-optimization -Wfloat-equal -Wformat -Wformat=2 -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimplicit -Wimport -Winit-self -Winline -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wstack-protector -Wstrict-aliasing -Wstrict-aliasing=2 -Wswitch -Wswitch-default -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings")
set(CMAKE_BUILD_TYPE Debug) set(CMAKE_BUILD_TYPE Debug)
ENDIF(EXISTS /usr/bin/clang) ENDIF(EXISTS /usr/bin/clang)

View File

@ -1,3 +1,5 @@
/* Copyright 2012 William Woodall and John Harrison */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -33,31 +35,36 @@ Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
long timeout, bytesize_t bytesize, long timeout, bytesize_t bytesize,
parity_t parity, stopbits_t stopbits, parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol) flowcontrol_t flowcontrol)
: port_(port), fd_(-1), interCharTimeout_(-1), writeTimeout_(-1), : port_ (port), fd_ (-1), isOpen_ (false), xonxoff_ (true), rtscts_ (false),
isOpen_(false), xonxoff_(false), rtscts_(false), ___(0), timeout_(timeout), timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), bytesize_ (bytesize),
baudrate_(baudrate), parity_(parity), bytesize_(bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
stopbits_(stopbits), flowcontrol_(flowcontrol)
{ {
if (port_.empty() == false) this->open(); if (port_.empty () == false)
open ();
} }
Serial::SerialImpl::~SerialImpl () { Serial::SerialImpl::~SerialImpl ()
this->close(); {
close();
} }
void void
Serial::SerialImpl::open () { Serial::SerialImpl::open ()
if (port_.empty()) { {
throw invalid_argument("bad port specified"); if (port_.empty())
{
throw invalid_argument ("bad port specified");
} }
if (isOpen_ == true) { if (isOpen_ == true)
throw SerialExecption("port already open"); {
throw SerialExecption ("port already open");
} }
fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_ == -1) { if (fd_ == -1)
throw IOException("invalid file descriptor"); {
throw IOException ("invalid file descriptor");
} }
reconfigurePort(); reconfigurePort();
@ -65,31 +72,25 @@ Serial::SerialImpl::open () {
} }
void void
Serial::SerialImpl::reconfigurePort () { Serial::SerialImpl::reconfigurePort ()
if (fd_ == -1) { {
if (fd_ == -1)
{
// Can only operate on a valid file descriptor // Can only operate on a valid file descriptor
throw IOException("invalid file descriptor"); throw IOException ("invalid file descriptor");
} }
struct termios options; // The current options for the file descriptor struct termios options; // The options for the file descriptor
struct termios originalTTYAttrs; // The orignal file descriptor options
uint8_t vmin = 0, vtime = 0; // timeout is done via select if (tcgetattr(fd_, &options) == -1)
if (interCharTimeout_ == -1) { {
vmin = 1; throw IOException ("::tcgetattr");
vtime = uint8_t(interCharTimeout_ * 10);
} }
if (tcgetattr(fd_, &originalTTYAttrs) == -1) {
throw IOException("::tcgetattr");
}
options = originalTTYAttrs;
// set up raw mode / no echo / binary // set up raw mode / no echo / binary
options.c_cflag |= (unsigned long)(CLOCAL|CREAD); options.c_cflag |= (unsigned long) (CLOCAL|CREAD);
options.c_lflag &= (unsigned long) ~(ICANON|ECHO|ECHOE|ECHOK options.c_lflag &= (unsigned long) ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|
|ECHONL|ISIG|IEXTEN); //|ECHOPRT ISIG|IEXTEN); //|ECHOPRT
options.c_oflag &= (unsigned long) ~(OPOST); options.c_oflag &= (unsigned long) ~(OPOST);
options.c_iflag &= (unsigned long) ~(INLCR|IGNCR|ICRNL|IGNBRK); options.c_iflag &= (unsigned long) ~(INLCR|IGNCR|ICRNL|IGNBRK);
@ -115,7 +116,7 @@ Serial::SerialImpl::reconfigurePort () {
else if (bytesize_ == FIVEBITS) else if (bytesize_ == FIVEBITS)
options.c_cflag |= CS5; options.c_cflag |= CS5;
else else
throw invalid_argument("Invalid char len"); throw invalid_argument ("Invalid char len");
// setup stopbits // setup stopbits
if (stopbits_ == STOPBITS_ONE) if (stopbits_ == STOPBITS_ONE)
options.c_cflag &= (unsigned long) ~(CSTOPB); options.c_cflag &= (unsigned long) ~(CSTOPB);
@ -124,21 +125,25 @@ Serial::SerialImpl::reconfigurePort () {
else if (stopbits_ == STOPBITS_TWO) else if (stopbits_ == STOPBITS_TWO)
options.c_cflag |= (CSTOPB); options.c_cflag |= (CSTOPB);
else else
throw invalid_argument("invalid stop bit"); throw invalid_argument ("invalid stop bit");
// setup parity // setup parity
options.c_iflag &= (unsigned long) ~(INPCK|ISTRIP); options.c_iflag &= (unsigned long) ~(INPCK|ISTRIP);
if (parity_ == PARITY_NONE) { if (parity_ == PARITY_NONE)
{
options.c_cflag &= (unsigned long) ~(PARENB|PARODD); options.c_cflag &= (unsigned long) ~(PARENB|PARODD);
} }
else if (parity_ == PARITY_EVEN) { else if (parity_ == PARITY_EVEN)
{
options.c_cflag &= (unsigned long) ~(PARODD); options.c_cflag &= (unsigned long) ~(PARODD);
options.c_cflag |= (PARENB); options.c_cflag |= (PARENB);
} }
else if (parity_ == PARITY_ODD) { else if (parity_ == PARITY_ODD)
{
options.c_cflag |= (PARENB|PARODD); options.c_cflag |= (PARENB|PARODD);
} }
else { else
throw invalid_argument("invalid parity"); {
throw invalid_argument ("invalid parity");
} }
// setup flow control // setup flow control
// xonxoff // xonxoff
@ -168,21 +173,21 @@ Serial::SerialImpl::reconfigurePort () {
#error "OS Support seems wrong." #error "OS Support seems wrong."
#endif #endif
// buffer options.c_cc[VMIN] = 1; // Minimum of 1 character in the buffer
// vmin "minimal number of characters to be read. = for non blocking" options.c_cc[VTIME] = 0; // timeout on waiting for new data
options.c_cc[VMIN] = vmin;
// vtime
options.c_cc[VTIME] = vtime;
// activate settings // activate settings
::tcsetattr(fd_, TCSANOW, &options); ::tcsetattr (fd_, TCSANOW, &options);
} }
void void
Serial::SerialImpl::close () { Serial::SerialImpl::close ()
if (isOpen_ == true) { {
if (fd_ != -1) { if (isOpen_ == true)
::close(fd_); // Ignoring the outcome {
if (fd_ != -1)
{
::close (fd_); // Ignoring the outcome
fd_ = -1; fd_ = -1;
} }
isOpen_ = false; isOpen_ = false;
@ -190,266 +195,318 @@ Serial::SerialImpl::close () {
} }
bool bool
Serial::SerialImpl::isOpen () const { Serial::SerialImpl::isOpen () const
{
return isOpen_; return isOpen_;
} }
size_t size_t
Serial::SerialImpl::available () { Serial::SerialImpl::available ()
if (!isOpen_) { {
if (!isOpen_)
{
return 0; return 0;
} }
int count = 0; int count = 0;
int result = ioctl(fd_, TIOCINQ, &count); int result = ioctl (fd_, TIOCINQ, &count);
if (result == 0) { if (result == 0)
return (size_t)count; {
return static_cast<size_t> (count);
} }
else { else
throw IOException("ioctl"); {
throw IOException ("ioctl");
} }
} }
string size_t
Serial::SerialImpl::read (size_t size) { Serial::SerialImpl::read (char* buf, size_t size)
if (!isOpen_) { {
throw PortNotOpenedException("Serial::read"); if (!isOpen_)
} {
string message = ""; throw PortNotOpenedException ("Serial::read");
char *buf = NULL;
// Using size+1 to leave room for a null character
if (size > 1024) {
buf = (char*)malloc((size + 1) * sizeof(*buf));
}
else {
buf = (char*)alloca((size + 1) * sizeof(*buf));
} }
fd_set readfds; fd_set readfds;
memset(buf, 0, (size + 1) * sizeof(*buf));
ssize_t bytes_read = 0; ssize_t bytes_read = 0;
while (bytes_read < (ssize_t)size) { while (true)
if (timeout_ != -1) { {
FD_ZERO(&readfds); if (timeout_ != -1)
FD_SET(fd_, &readfds); {
FD_ZERO (&readfds);
FD_SET (fd_, &readfds);
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = timeout_ / 1000; timeout.tv_sec = timeout_ / 1000;
timeout.tv_usec = (int) timeout_ % 1000; timeout.tv_usec = static_cast<int> (timeout_ % 1000);
int r = select(fd_ + 1, &readfds, NULL, NULL, &timeout); int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout);
if (r == -1 && errno == EINTR) if (r == -1 && errno == EINTR)
continue; continue;
if (r == -1) { if (r == -1)
{
perror("select()"); perror("select()");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
if (timeout_ == -1 || FD_ISSET(fd_, &readfds)) { if (timeout_ == -1 || FD_ISSET (fd_, &readfds))
ssize_t newest_read = ::read(fd_, {
buf + bytes_read, bytes_read = ::read (fd_, buf, size);
size - static_cast<size_t>(bytes_read));
// read should always return some data as select reported it was // read should always return some data as select reported it was
// ready to read when we get to this point. // ready to read when we get to this point.
if (newest_read < 1) { // printf("bytes_read: %lu\n", bytes_read);
if (bytes_read < 1)
{
// Disconnected devices, at least on Linux, show the // Disconnected devices, at least on Linux, show the
// behavior that they are always ready to read immediately // behavior that they are always ready to read immediately
// but reading returns nothing. // but reading returns nothing.
throw SerialExecption("device reports readiness to read but " throw SerialExecption ("device reports readiness to read but "
"returned no data (device disconnected?)"); "returned no data (device disconnected?)");
} }
bytes_read += newest_read; break;
}
else {
break; // Timeout
} }
} }
if (bytes_read > 0) return static_cast<size_t> (bytes_read);
message.append(buf, (size_t)bytes_read);
if (size > 1024)
free(buf);
return message;
} }
size_t size_t
Serial::SerialImpl::write (const string &data) { Serial::SerialImpl::write (const string &data)
{
if (isOpen_ == false) { if (isOpen_ == false) {
throw PortNotOpenedException("Serial::write"); throw PortNotOpenedException ("Serial::write");
} }
ssize_t n = ::write(fd_, data.c_str(), data.length()); ssize_t n = ::write (fd_, data.c_str (), data.length ());
if (n == -1) { if (n == -1) {
throw IOException("Write"); throw IOException ("Write");
} }
return (size_t)n; return static_cast<size_t> (n);
} }
void void
Serial::SerialImpl::setPort (const string &port) { Serial::SerialImpl::setPort (const string &port)
{
port_ = port; port_ = port;
} }
string string
Serial::SerialImpl::getPort () const { Serial::SerialImpl::getPort () const
{
return port_; return port_;
} }
void void
Serial::SerialImpl::setTimeout (long timeout) { Serial::SerialImpl::setTimeout (long timeout)
{
timeout_ = timeout; timeout_ = timeout;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
long long
Serial::SerialImpl::getTimeout () const { Serial::SerialImpl::getTimeout () const
{
return timeout_; return timeout_;
} }
void void
Serial::SerialImpl::setBaudrate (unsigned long baudrate) { Serial::SerialImpl::setBaudrate (unsigned long baudrate)
{
baudrate_ = baudrate; baudrate_ = baudrate;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
unsigned long unsigned long
Serial::SerialImpl::getBaudrate () const { Serial::SerialImpl::getBaudrate () const
{
return baudrate_; return baudrate_;
} }
void void
Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) { Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
{
bytesize_ = bytesize; bytesize_ = bytesize;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
serial::bytesize_t serial::bytesize_t
Serial::SerialImpl::getBytesize () const { Serial::SerialImpl::getBytesize () const
{
return bytesize_; return bytesize_;
} }
void void
Serial::SerialImpl::setParity (serial::parity_t parity) { Serial::SerialImpl::setParity (serial::parity_t parity)
{
parity_ = parity; parity_ = parity;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
serial::parity_t serial::parity_t
Serial::SerialImpl::getParity () const { Serial::SerialImpl::getParity () const
{
return parity_; return parity_;
} }
void void
Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) { Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
{
stopbits_ = stopbits; stopbits_ = stopbits;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
serial::stopbits_t serial::stopbits_t
Serial::SerialImpl::getStopbits () const { Serial::SerialImpl::getStopbits () const
{
return stopbits_; return stopbits_;
} }
void void
Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) { Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
{
flowcontrol_ = flowcontrol; flowcontrol_ = flowcontrol;
if (isOpen_) reconfigurePort(); if (isOpen_)
reconfigurePort ();
} }
serial::flowcontrol_t serial::flowcontrol_t
Serial::SerialImpl::getFlowcontrol () const { Serial::SerialImpl::getFlowcontrol () const
{
return flowcontrol_; return flowcontrol_;
} }
void Serial::SerialImpl::flush () { void
if (isOpen_ == false) { Serial::SerialImpl::flush ()
throw PortNotOpenedException("Serial::flush"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flush");
} }
tcdrain(fd_); tcdrain (fd_);
} }
void Serial::SerialImpl::flushInput () { void
if (isOpen_ == false) { Serial::SerialImpl::flushInput ()
throw PortNotOpenedException("Serial::flushInput"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flushInput");
} }
tcflush(fd_, TCIFLUSH); tcflush (fd_, TCIFLUSH);
} }
void Serial::SerialImpl::flushOutput () { void
if (isOpen_ == false) { Serial::SerialImpl::flushOutput ()
throw PortNotOpenedException("Serial::flushOutput"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flushOutput");
} }
tcflush(fd_, TCOFLUSH); tcflush (fd_, TCOFLUSH);
} }
void Serial::SerialImpl::sendBreak(int duration) { void
if (isOpen_ == false) { Serial::SerialImpl::sendBreak (int duration)
throw PortNotOpenedException("Serial::sendBreak"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::sendBreak");
} }
tcsendbreak(fd_, int(duration/4)); tcsendbreak (fd_, static_cast<int> (duration/4));
} }
void Serial::SerialImpl::setBreak(bool level) { void
if (isOpen_ == false) { Serial::SerialImpl::setBreak (bool level)
throw PortNotOpenedException("Serial::setBreak"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setBreak");
} }
if (level) { if (level)
ioctl(fd_, TIOCSBRK); {
ioctl (fd_, TIOCSBRK);
} }
else { else {
ioctl(fd_, TIOCCBRK); ioctl (fd_, TIOCCBRK);
} }
} }
void Serial::SerialImpl::setRTS(bool level) { void
if (isOpen_ == false) { Serial::SerialImpl::setRTS (bool level)
throw PortNotOpenedException("Serial::setRTS"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setRTS");
} }
if (level) { if (level)
ioctl(fd_, TIOCMBIS, TIOCM_RTS); {
ioctl (fd_, TIOCMBIS, TIOCM_RTS);
} }
else { else {
ioctl(fd_, TIOCMBIC, TIOCM_RTS); ioctl (fd_, TIOCMBIC, TIOCM_RTS);
} }
} }
void Serial::SerialImpl::setDTR(bool level) { void
if (isOpen_ == false) { Serial::SerialImpl::setDTR (bool level)
throw PortNotOpenedException("Serial::setDTR"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setDTR");
} }
if (level) { if (level)
ioctl(fd_, TIOCMBIS, TIOCM_DTR); {
ioctl (fd_, TIOCMBIS, TIOCM_DTR);
} }
else { else
ioctl(fd_, TIOCMBIC, TIOCM_DTR); {
ioctl (fd_, TIOCMBIC, TIOCM_DTR);
} }
} }
bool Serial::SerialImpl::getCTS() { bool
if (isOpen_ == false) { Serial::SerialImpl::getCTS ()
throw PortNotOpenedException("Serial::getCTS"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getCTS");
} }
int s = ioctl(fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_CTS) != 0; return (s & TIOCM_CTS) != 0;
} }
bool Serial::SerialImpl::getDSR() { bool
if (isOpen_ == false) { Serial::SerialImpl::getDSR()
throw PortNotOpenedException("Serial::getDSR"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getDSR");
} }
int s = ioctl(fd_, TIOCMGET, 0); int s = ioctl(fd_, TIOCMGET, 0);
return (s & TIOCM_DSR) != 0; return (s & TIOCM_DSR) != 0;
} }
bool Serial::SerialImpl::getRI() { bool
if (isOpen_ == false) { Serial::SerialImpl::getRI()
throw PortNotOpenedException("Serial::getRI"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getRI");
} }
int s = ioctl(fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_RI) != 0; return (s & TIOCM_RI) != 0;
} }
bool Serial::SerialImpl::getCD() { bool
if (isOpen_ == false) { Serial::SerialImpl::getCD()
throw PortNotOpenedException("Serial::getCD"); {
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getCD");
} }
int s = ioctl(fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_CD) != 0; return (s & TIOCM_CD) != 0;
} }

View File

@ -1,3 +1,10 @@
/* Copyright 2012 William Woodall and John Harrison */
#include <alloca.h>
#include <cstring>
#include <algorithm>
#include "serial/serial.h" #include "serial/serial.h"
#ifdef _WIN32 #ifdef _WIN32
@ -6,11 +13,14 @@
#include "serial/impl/unix.h" #include "serial/impl/unix.h"
#endif #endif
using std::string;
using std::vector;
using std::numeric_limits;
using std::size_t;
using std::invalid_argument; using std::invalid_argument;
using std::memset;
using std::min;
using std::numeric_limits;
using std::vector;
using std::size_t;
using std::string;
using serial::Serial; using serial::Serial;
using serial::SerialExecption; using serial::SerialExecption;
using serial::IOException; using serial::IOException;
@ -21,204 +31,301 @@ using serial::flowcontrol_t;
Serial::Serial (const string &port, unsigned long baudrate, long timeout, Serial::Serial (const string &port, unsigned long baudrate, long timeout,
bytesize_t bytesize, parity_t parity, stopbits_t stopbits, bytesize_t bytesize, parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol) flowcontrol_t flowcontrol, const size_t buffer_size)
: buffer_size_(buffer_size)
{ {
pimpl = new SerialImpl(port, baudrate, timeout, bytesize, parity, pimpl_ = new SerialImpl (port, baudrate, timeout, bytesize, parity,
stopbits, flowcontrol); stopbits, flowcontrol);
read_cache_ = new char[buffer_size_];
memset (read_cache_, 0, buffer_size_ * sizeof (char));
} }
Serial::~Serial () { Serial::~Serial ()
delete pimpl; {
delete pimpl_;
delete[] read_cache_;
} }
void void
Serial::open () { Serial::open ()
this->pimpl->open (); {
pimpl_->open ();
} }
void void
Serial::close () { Serial::close ()
this->pimpl->close (); {
pimpl_->close ();
memset (read_cache_, 0, buffer_size_ * sizeof (char));
} }
bool bool
Serial::isOpen () const { Serial::isOpen () const
return this->pimpl->isOpen (); {
return pimpl_->isOpen ();
} }
size_t size_t
Serial::available () { Serial::available ()
return this->pimpl->available(); {
return pimpl_->available ();
} }
string string
Serial::read (size_t size) { Serial::read (size_t size)
return this->pimpl->read (size); {
size_t cache_size = strlen (read_cache_);
if (cache_size >= size)
{
// Don't need to do a new read.
string result (read_cache_, size);
memmove (read_cache_, read_cache_ + size, cache_size - size);
*(read_cache_ + cache_size - size) = '\0';
return result;
}
else
{
// Needs to read, loop until we have read enough... or timeout
size_t chars_left = 0;
string result = "";
if (cache_size > 0)
{
result.append (read_cache_, cache_size);
memset (read_cache_, 0, buffer_size_);
chars_left = size - cache_size;
}
else
{
chars_left = size;
}
while (true)
{
size_t chars_read = pimpl_->read (read_cache_, buffer_size_ - 1);
if (chars_read > 0)
{
*(read_cache_ + chars_read) = '\0';
if (chars_left > chars_read)
{
memset (read_cache_, 0, buffer_size_);
result.append (read_cache_);
chars_left -= chars_read;
}
else
{
result.append (read_cache_, static_cast<size_t> (chars_left));
memmove (read_cache_, read_cache_ + chars_left, chars_read - chars_left);
*(read_cache_ + chars_read - chars_left) = '\0';
memset (read_cache_ + chars_read - chars_left, 0,
buffer_size_ - chars_read - chars_left);
// Finished reading all of the data
break;
}
}
else
break; // Timeout occured
}
return result;
}
} }
string string
Serial::readline(size_t size, string eol) { Serial::readline (size_t size, string eol)
size_t leneol = eol.length(); {
size_t leneol = eol.length ();
string line = ""; string line = "";
while (true) { while (true)
string c = pimpl->read(1); {
if (!c.empty()) { string c = read (1);
line.append(c); if (!c.empty ())
if (line.length() > leneol {
&& line.substr(line.length() - leneol, leneol) == eol) line.append (c);
if (line.length () > leneol &&
line.substr (line.length () - leneol, leneol) == eol)
break; break;
if (line.length() >= size) { if (line.length () >= size)
{
break; break;
} }
} }
else { else
// Timeout // Timeout
break; break;
} }
}
return line; return line;
} }
vector<string> vector<string>
Serial::readlines(string eol) { Serial::readlines(string eol)
if (this->pimpl->getTimeout() < 0) { {
if (pimpl_->getTimeout () < 0)
{
throw "Error, must be set for readlines"; throw "Error, must be set for readlines";
} }
size_t leneol = eol.length(); size_t leneol = eol.length ();
vector<string> lines; vector<string> lines;
while (true) { while (true)
string line = readline(numeric_limits<size_t>::max(), eol); {
if (!line.empty()) { string line = readline (numeric_limits<size_t>::max (), eol);
lines.push_back(line); if (!line.empty ())
if (line.substr(line.length() - leneol, leneol) == eol) {
lines.push_back (line);
if (line.substr (line.length () - leneol, leneol) == eol)
break; break;
} }
else { else
// Timeout // Timeout
break; break;
} }
}
return lines; return lines;
} }
size_t size_t
Serial::write (const string &data) { Serial::write (const string &data)
return this->pimpl->write (data); {
return pimpl_->write (data);
} }
void void
Serial::setPort (const string &port) { Serial::setPort (const string &port)
bool was_open = pimpl->isOpen(); {
if (was_open) this->close(); bool was_open = pimpl_->isOpen();
this->pimpl->setPort (port); if (was_open) close();
if (was_open) this->open(); pimpl_->setPort (port);
if (was_open) open();
} }
string string
Serial::getPort () const { Serial::getPort () const
return this->pimpl->getPort (); {
return pimpl_->getPort ();
} }
void void
Serial::setTimeout (long timeout) { Serial::setTimeout (long timeout)
this->pimpl->setTimeout (timeout); {
pimpl_->setTimeout (timeout);
} }
long long
Serial::getTimeout () const { Serial::getTimeout () const {
return this->pimpl->getTimeout (); return pimpl_->getTimeout ();
} }
void void
Serial::setBaudrate (unsigned long baudrate) { Serial::setBaudrate (unsigned long baudrate)
this->pimpl->setBaudrate (baudrate); {
pimpl_->setBaudrate (baudrate);
} }
unsigned long unsigned long
Serial::getBaudrate () const { Serial::getBaudrate () const
return this->pimpl->getBaudrate (); {
return pimpl_->getBaudrate ();
} }
void void
Serial::setBytesize (bytesize_t bytesize) { Serial::setBytesize (bytesize_t bytesize)
this->pimpl->setBytesize (bytesize); {
pimpl_->setBytesize (bytesize);
} }
bytesize_t bytesize_t
Serial::getBytesize () const { Serial::getBytesize () const
return this->pimpl->getBytesize (); {
return pimpl_->getBytesize ();
} }
void void
Serial::setParity (parity_t parity) { Serial::setParity (parity_t parity)
this->pimpl->setParity (parity); {
pimpl_->setParity (parity);
} }
parity_t parity_t
Serial::getParity () const { Serial::getParity () const
return this->pimpl->getParity (); {
return pimpl_->getParity ();
} }
void void
Serial::setStopbits (stopbits_t stopbits) { Serial::setStopbits (stopbits_t stopbits)
this->pimpl->setStopbits (stopbits); {
pimpl_->setStopbits (stopbits);
} }
stopbits_t stopbits_t
Serial::getStopbits () const { Serial::getStopbits () const
return this->pimpl->getStopbits (); {
return pimpl_->getStopbits ();
} }
void void
Serial::setFlowcontrol (flowcontrol_t flowcontrol) { Serial::setFlowcontrol (flowcontrol_t flowcontrol)
this->pimpl->setFlowcontrol (flowcontrol); {
pimpl_->setFlowcontrol (flowcontrol);
} }
flowcontrol_t flowcontrol_t
Serial::getFlowcontrol () const { Serial::getFlowcontrol () const
return this->pimpl->getFlowcontrol (); {
return pimpl_->getFlowcontrol ();
} }
void Serial::flush() { void Serial::flush ()
this->pimpl->flush(); {
pimpl_->flush ();
memset (read_cache_, 0, buffer_size_);
} }
void Serial::flushInput() { void Serial::flushInput ()
this->pimpl->flushInput(); {
pimpl_->flushInput ();
} }
void Serial::flushOutput() { void Serial::flushOutput ()
this->pimpl->flushOutput(); {
pimpl_->flushOutput ();
memset (read_cache_, 0, buffer_size_);
} }
void Serial::sendBreak(int duration) { void Serial::sendBreak (int duration)
this->pimpl->sendBreak(duration); {
pimpl_->sendBreak (duration);
} }
void Serial::setBreak(bool level) { void Serial::setBreak (bool level)
this->pimpl->setBreak(level); {
pimpl_->setBreak (level);
} }
void Serial::setRTS(bool level) { void Serial::setRTS (bool level)
this->pimpl->setRTS(level); {
pimpl_->setRTS (level);
} }
void Serial::setDTR(bool level) { void Serial::setDTR (bool level)
this->pimpl->setDTR(level); {
pimpl_->setDTR (level);
} }
bool Serial::getCTS() { bool Serial::getCTS ()
return this->pimpl->getCTS(); {
return pimpl_->getCTS ();
} }
bool Serial::getDSR() { bool Serial::getDSR ()
return this->pimpl->getDSR(); {
return pimpl_->getDSR ();
} }
bool Serial::getRI() { bool Serial::getRI ()
return this->pimpl->getRI(); {
return pimpl_->getRI ();
} }
bool Serial::getCD() { bool Serial::getCD ()
return this->pimpl->getCD(); {
return pimpl_->getCD ();
} }

View File

@ -1,3 +1,5 @@
/* Copyright 2012 William Woodall and John Harrison */
#include "serial/serial_listener.h" #include "serial/serial_listener.h"
/***** Inline Functions *****/ /***** Inline Functions *****/

View File

@ -1,10 +1,3 @@
#include "gtest/gtest.h"
#include <boost/bind.hpp>
// OMG this is so nasty...
// #define private public
// #define protected public
#include <string> #include <string>
#include <iostream> #include <iostream>
@ -14,17 +7,27 @@ using std::string;
using std::cout; using std::cout;
using std::endl; using std::endl;
using serial::Serial; using serial::Serial;
using serial::SerialExecption;
int main(int argc, char **argv) { int main(int argc, char **argv) {
try {
Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000); Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000);
s.flush(); s.flush();
int count = 0; long long count = 0;
while (1) { while (1) {
size_t available = s.available(); // size_t available = s.available();
cout << "avialable: " << available << endl; // cout << "avialable: " << available << endl;
string line = s.readline(); string line = s.readline();
cout << count << ": " << line; cout << count << ": " << line << line.length() << endl;
count++; count++;
} }
cout << endl << endl; }
catch (SerialExecption e)
{
cout << "Caught SerialException: " << e.what() << endl;
}
catch (...)
{
cout << "Caught an error." << endl;
}
} }