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

Adding in an internal buffer to Serial, this is independent of the SerialImpl and buffers reads to help performance.

Also correcting my styles to match the style guide and adding in some documentation.
This commit is contained in:
John Harrison 2012-01-15 02:06:38 -06:00
parent 87cd030615
commit 8f4b34cc03
10 changed files with 827 additions and 600 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++
# 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
# $(CXX) -o test tests/serial_tests.o src/serial.o src/impl/unix.o
#
ifdef ROS_ROOT
include $(shell rospack find mk)/cmake.mk
else

View File

@ -8,7 +8,7 @@
*
* 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
* copy of this software and associated documentation files (the "Software"),
@ -30,7 +30,9 @@
*
* \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
@ -42,6 +44,7 @@ namespace serial {
using std::string;
using std::invalid_argument;
using serial::SerialExecption;
using serial::IOException;
@ -57,47 +60,98 @@ public:
virtual ~SerialImpl ();
void open ();
void close () ;
bool isOpen () const;
void
open ();
size_t available ();
string read (size_t size = 1);
size_t write (const string &data);
void
close ();
void flush ();
void flushInput ();
void flushOutput ();
bool
isOpen () const;
void sendBreak(int duration);
void setBreak(bool level);
void setRTS(bool level);
void setDTR(bool level);
bool getCTS();
bool getDSR();
bool getRI();
bool getCD();
size_t
available ();
void setPort (const string &port);
string getPort () const;
size_t
read (char* buf, size_t size = 1);
void setTimeout (long timeout);
long getTimeout () const;
size_t
write (const string &data);
void setBaudrate (unsigned long baudrate);
unsigned long getBaudrate () const;
void
flush ();
void setBytesize (bytesize_t bytesize);
bytesize_t getBytesize () const;
void
flushInput ();
void setParity (parity_t parity);
parity_t getParity () const;
void
flushOutput ();
void setStopbits (stopbits_t stopbits);
stopbits_t getStopbits () const;
void
sendBreak(int duration);
void setFlowcontrol (flowcontrol_t flowcontrol);
flowcontrol_t getFlowcontrol () const;
void
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:
void reconfigurePort ();
@ -106,14 +160,10 @@ private:
string port_; // Path to the file descriptor
int fd_; // The current file descriptor
int interCharTimeout_;
int writeTimeout_;
bool isOpen_;
bool xonxoff_;
bool rtscts_;
char ___; // lol padding
long timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate

View File

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

View File

@ -15,7 +15,7 @@ IF(EXISTS /usr/bin/clang)
set(CMAKE_CXX_COMPILER /usr/bin/clang++)
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
# 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)
ENDIF(EXISTS /usr/bin/clang)

View File

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

View File

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

View File

@ -1,3 +1,5 @@
/* Copyright 2012 William Woodall and John Harrison */
#include "serial/serial_listener.h"
/***** 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 <iostream>
@ -14,17 +7,27 @@ using std::string;
using std::cout;
using std::endl;
using serial::Serial;
using serial::SerialExecption;
int main(int argc, char **argv) {
Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000);
s.flush();
int count = 0;
while (1) {
size_t available = s.available();
cout << "avialable: " << available << endl;
string line = s.readline();
cout << count << ": " << line;
count++;
try {
Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000);
s.flush();
long long count = 0;
while (1) {
// size_t available = s.available();
// cout << "avialable: " << available << endl;
string line = s.readline();
cout << count << ": " << line << line.length() << endl;
count++;
}
}
catch (SerialExecption e)
{
cout << "Caught SerialException: " << e.what() << endl;
}
catch (...)
{
cout << "Caught an error." << endl;
}
cout << endl << endl;
}