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.h
This commit is contained in:
William Woodall 2012-02-04 21:17:27 -06:00
commit 6cdd3fe795
5 changed files with 344 additions and 281 deletions

View File

@ -1,5 +1,6 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <cstdio>
// OS Specific sleep // OS Specific sleep
#ifdef __WIN32__ #ifdef __WIN32__

View File

@ -75,7 +75,7 @@ public:
available (); available ();
size_t size_t
read (char* buf, size_t size = 1); read (unsigned char* buf, size_t size = 1);
size_t size_t
write (const string &data); write (const string &data);
@ -174,7 +174,7 @@ 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
bool isOpen_; bool is_open_;
bool xonxoff_; bool xonxoff_;
bool rtscts_; bool rtscts_;

View File

@ -88,41 +88,41 @@ typedef enum {
class Serial { class Serial {
public: public:
/*! /*!
* Constructor, creates a SerialPortBoost object and opens the port. * Constructor, creates a SerialPortBoost object and opens the port.
* *
* \param port A std::string containing the address of the serial port, * \param port A std::string containing the address of the serial port,
* which would be something like 'COM1' on Windows and '/dev/ttyS0' * which would be something like 'COM1' on Windows and '/dev/ttyS0'
* on Linux. * on Linux.
* *
* \param baudrate An integer that represents the buadrate * \param baudrate An integer that represents the buadrate
* *
* \param timeout A long that represents the time (in milliseconds) until a * \param timeout A long that represents the time (in milliseconds) until a
* timeout on reads occur. Setting this to zero (0) will cause reading to * timeout on reads occur. Setting this to zero (0) will cause reading to
* be non-blocking, i.e. the available data will be returned immediately, * be non-blocking, i.e. the available data will be returned immediately,
* but it will not block to wait for more. Setting this to a number less * but it will not block to wait for more. Setting this to a number less
* than zero (-1) will result in infinite blocking behaviour, i.e. the * than zero (-1) will result in infinite blocking behaviour, i.e. the
* serial port will block until either size bytes have been read or an * serial port will block until either size bytes have been read or an
* exception has occured. * exception has occured.
* *
* \param bytesize Size of each byte in the serial transmission of data, * \param bytesize Size of each byte in the serial transmission of data,
* default is eightbits, possible values are: fivebits, sixbits, sevenbits, * default is eightbits, possible values are: fivebits, sixbits, sevenbits,
* eightbits * eightbits
* *
* \param parity Method of parity, default is parity_none, possible values * \param parity Method of parity, default is parity_none, possible values
* are: parity_none, parity_odd, parity_even * are: parity_none, parity_odd, parity_even
* *
* \param stopbits Number of stop bits used, default is stopbits_one, * \param stopbits Number of stop bits used, default is stopbits_one,
* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two * possible values are: stopbits_one, stopbits_one_point_five, stopbits_two
* *
* \param flowcontrol Type of flowcontrol used, default is * \param flowcontrol Type of flowcontrol used, default is
* 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 * \param buffer_size The maximum size of the internal buffer, defaults
* to 256 bytes (2^8). * to 256 bytes (2^8).
* *
* \throw PortNotOpenedException * \throw PortNotOpenedException
*/ */
Serial (const std::string &port = "", Serial (const std::string &port = "",
unsigned long baudrate = 9600, unsigned long baudrate = 9600,
long timeout = 0, long timeout = 0,
@ -135,25 +135,25 @@ public:
virtual ~Serial (); virtual ~Serial ();
/*! /*!
* Opens the serial port as long as the portname is set and the port isn't * Opens the serial port as long as the portname is set and the port isn't
* alreay open. * alreay open.
* *
* If the port is provided to the constructor then an explicit call to open * If the port is provided to the constructor then an explicit call to open
* is not needed. * is not needed.
* *
* \see Serial::Serial * \see Serial::Serial
* *
* \throw std::invalid_argument * \throw std::invalid_argument
* \throw serial::SerialExecption * \throw serial::SerialExecption
* \throw serial::IOException * \throw serial::IOException
*/ */
void void
open (); open ();
/*! Gets the open status of the serial port. /*! Gets the open status of the serial port.
* *
* \return Returns true if the port is open, false otherwise. * \return Returns true if the port is open, false otherwise.
*/ */
bool bool
isOpen () const; isOpen () const;
@ -166,51 +166,67 @@ public:
available(); available();
/*! 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
* no timeout it will block until the requested number of bytes have been * no timeout it will block until the requested number of bytes have been
* read or until an exception occurs. * read or until an exception occurs.
* *
* \param size A size_t defining how many bytes to be read. * \param size A size_t defining how many bytes to be read.
* *
* \return A std::string containing the data read. * \return A std::string containing the data read.
*/ */
size_t
read (unsigned char *buffer, size_t size);
size_t
read (std::vector<unsigned char> &buffer, size_t size = 1);
size_t
read (std::string &buffer, size_t size = 1);
std::string std::string
read (size_t size = 1); read (size_t size = 1);
/*! Reads in a line or until a given delimiter has been processed /*! Reads in a line or until a given delimiter has been processed
* *
* Reads from the serial port until a single line has been read. * 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 size A maximum length of a line, defaults to 65536 (2^16)
* \param eol A string to match against for the EOL. * \param eol A string to match against for the EOL.
* *
* \return A std::string containing the line. * \return A std::string containing the line.
*/ */
size_t
readline (std::string &buffer,
size_t size = 65536,
std::string eol = "\n");
std::string std::string
readline(size_t size = std::numeric_limits<std::size_t>::max(), readline (size_t size = 65536,
std::string eol = "\n"); std::string eol = "\n");
/*! Reads in multiple lines until the serail port times out. /*! Reads in multiple lines until the serail port times out.
* *
* This requires a timeout > 0 before it can be run. It will read until a * This requires a timeout > 0 before it can be run. It will read until a
* timeout occurs and return a list of strings. * timeout occurs and return a list of strings.
* *
* \param eol A string to match against for the EOL. * \param size A maximum length of combined lines, defaults to 65536 (2^16)
* *
* \return A vector<string> containing the lines. * \param eol A string to match against for the EOL.
*/ *
* \return A vector<string> containing the lines.
*/
std::vector<std::string> std::vector<std::string>
readlines(std::string eol = "\n"); readlines (size_t size = 65536, std::string eol = "\n");
/*! Write a string to the serial port. /*! Write a string to the serial port.
* *
* \param data A const std::string reference containg the data to be written * \param data A const reference containg the data to be written
* to the serial port. * to the serial port.
* *
* \return A size_t representing the number of bytes actually written to * \return A size_t representing the number of bytes actually written to
* the serial port. * the serial port.
*/ */
size_t
write (const unsigned char *data, size_t size);
size_t
write (const std::vector<unsigned char> &data);
size_t size_t
write (const std::string &data); write (const std::string &data);
@ -410,6 +426,10 @@ private:
class ScopedReadLock; class ScopedReadLock;
class ScopedWriteLock; class ScopedWriteLock;
// Read common function
size_t
read_ (unsigned char *buffer, size_t size);
}; };
class SerialExecption : public std::exception class SerialExecption : public std::exception

View File

@ -10,15 +10,20 @@
#include <sysexits.h> #include <sysexits.h>
#include <termios.h> #include <termios.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h> #include <pthread.h>
#if defined(__linux__) #if defined(__linux__)
# include <linux/serial.h> # include <linux/serial.h>
#endif #endif
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#include "serial/impl/unix.h" #include "serial/impl/unix.h"
#ifndef TIOCINQ #ifndef TIOCINQ
@ -41,7 +46,7 @@ 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), isOpen_ (false), xonxoff_ (true), rtscts_ (false), : port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (true), rtscts_ (false),
timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), timeout_ (timeout), baudrate_ (baudrate), parity_ (parity),
bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
{ {
@ -61,13 +66,13 @@ Serial::SerialImpl::~SerialImpl ()
void void
Serial::SerialImpl::open () Serial::SerialImpl::open ()
{ {
if (port_.empty()) if (port_.empty ())
{ {
throw invalid_argument ("bad port specified"); throw invalid_argument ("Empty port is invalid.");
} }
if (isOpen_ == true) if (is_open_ == true)
{ {
throw SerialExecption ("port already open"); throw SerialExecption ("Serial 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);
@ -82,7 +87,7 @@ Serial::SerialImpl::open ()
return; return;
case ENFILE: case ENFILE:
case EMFILE: case EMFILE:
throw IOException ("to many file handles open"); throw IOException ("Too many file handles open.");
break; break;
default: default:
throw IOException (errno); throw IOException (errno);
@ -90,7 +95,7 @@ Serial::SerialImpl::open ()
} }
reconfigurePort(); reconfigurePort();
isOpen_ = true; is_open_ = true;
} }
void void
@ -99,7 +104,7 @@ 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, is the serial port open?");
} }
struct termios options; // The options for the file descriptor struct termios options; // The options for the file descriptor
@ -266,7 +271,8 @@ Serial::SerialImpl::reconfigurePort ()
if (stopbits_ == STOPBITS_ONE) if (stopbits_ == STOPBITS_ONE)
options.c_cflag &= (unsigned long) ~(CSTOPB); options.c_cflag &= (unsigned long) ~(CSTOPB);
else if (stopbits_ == STOPBITS_ONE_POINT_FIVE) else if (stopbits_ == STOPBITS_ONE_POINT_FIVE)
options.c_cflag |= (CSTOPB); // XXX same as TWO.. there is no POSIX support for 1.5 // ONE POINT FIVE same as TWO.. there is no POSIX support for 1.5
options.c_cflag |= (CSTOPB);
else if (stopbits_ == STOPBITS_TWO) else if (stopbits_ == STOPBITS_TWO)
options.c_cflag |= (CSTOPB); options.c_cflag |= (CSTOPB);
else else
@ -318,8 +324,12 @@ Serial::SerialImpl::reconfigurePort ()
#error "OS Support seems wrong." #error "OS Support seems wrong."
#endif #endif
options.c_cc[VMIN] = 1; // Minimum of 1 character in the buffer // http://www.unixwiz.net/techtips/termios-vmin-vtime.html
options.c_cc[VTIME] = 0; // timeout on waiting for new data // this basically sets the read call up to be a polling read,
// but we are using select to ensure there is data available
// to read before each call, so we should never needlessly poll
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;
// activate settings // activate settings
::tcsetattr (fd_, TCSANOW, &options); ::tcsetattr (fd_, TCSANOW, &options);
@ -328,27 +338,27 @@ Serial::SerialImpl::reconfigurePort ()
void void
Serial::SerialImpl::close () Serial::SerialImpl::close ()
{ {
if (isOpen_ == true) if (is_open_ == true)
{ {
if (fd_ != -1) if (fd_ != -1)
{ {
::close (fd_); // Ignoring the outcome ::close (fd_); // Ignoring the outcome
fd_ = -1; fd_ = -1;
} }
isOpen_ = false; is_open_ = false;
} }
} }
bool bool
Serial::SerialImpl::isOpen () const Serial::SerialImpl::isOpen () const
{ {
return isOpen_; return is_open_;
} }
size_t size_t
Serial::SerialImpl::available () Serial::SerialImpl::available ()
{ {
if (!isOpen_) if (!is_open_)
{ {
return 0; return 0;
} }
@ -364,113 +374,131 @@ Serial::SerialImpl::available ()
} }
} }
inline void get_time_now(struct timespec &time) {
# ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
time.tv_sec = mts.tv_sec;
time.tv_nsec = mts.tv_nsec;
# else
clock_gettime(CLOCK_REALTIME, &time);
# endif
}
size_t size_t
Serial::SerialImpl::read (char* buf, size_t size) Serial::SerialImpl::read (unsigned char* buf, size_t size)
{ {
if (!isOpen_) if (!is_open_)
{ {
throw PortNotOpenedException ("Serial::read"); throw PortNotOpenedException ("Serial::read");
} }
fd_set readfds; fd_set readfds;
ssize_t bytes_read = 0; size_t bytes_read = 0;
int count = 0; struct timeval timeout;
while (true) timeout.tv_sec = timeout_ / 1000;
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000;
while (bytes_read < size)
{ {
count++; FD_ZERO (&readfds);
// printf("Counting: %u\n", count); FD_SET (fd_, &readfds);
if (timeout_ != -1) // On Linux the timeout struct is updated by select to contain the time
{ // left on the timeout to make looping easier, but on other platforms this
FD_ZERO (&readfds); // does not occur.
FD_SET (fd_, &readfds); #if !defined(__linux__)
struct timeval timeout; // Begin timing select
timeout.tv_sec = timeout_ / 1000; struct timespec start, end;
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000; get_time_now(start);
int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout); #endif
// Do the select
int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout);
#if !defined(__linux__)
// Calculate difference and update the structure
get_time_now(end);
// Calculate the time select took
struct timeval diff;
diff.tv_sec = end.tv_sec-start.tv_sec;
diff.tv_usec = (end.tv_nsec-start.tv_nsec)/1000;
// Update the timeout
if (timeout.tv_sec <= diff.tv_sec) {
timeout.tv_sec = 0;
} else {
timeout.tv_sec -= diff.tv_sec;
}
if (timeout.tv_usec <= diff.tv_usec) {
timeout.tv_usec = 0;
} else {
timeout.tv_usec -= diff.tv_usec;
}
#endif
if (r == -1 && errno == EINTR) // Figure out what happened by looking at select's response 'r'
/** Error **/
if (r < 0) {
// Select was interrupted, try again
if (errno == EINTR) {
continue; continue;
if (r == -1)
{
throw IOException (errno);
} }
// Otherwise there was some error
throw IOException (errno);
} }
/** Timeout **/
if (timeout_ == -1 || FD_ISSET (fd_, &readfds)) if (r == 0) {
{
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 (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?)");
}
break; break;
} }
else /** Something ready to read **/
{ if (r > 0) {
break; // Make sure our file descriptor is in the ready to read list
if (FD_ISSET (fd_, &readfds)) {
// This should be non-blocking returning only what is avaialble now
// Then returning so that select can block again.
ssize_t bytes_read_now = ::read (fd_, buf, size-bytes_read);
// read should always return some data as select reported it was
// ready to read when we get to this point.
if (bytes_read_now < 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?)");
}
// Update bytes_read
bytes_read += static_cast<size_t> (bytes_read_now);
// If bytes_read == size then we have read everything we need
if (bytes_read == size) {
break;
}
// If bytes_read < size then we have more to read
if (bytes_read < size) {
continue;
}
// If bytes_read > size then we have over read, which shouldn't happen
if (bytes_read > size) {
throw SerialExecption ("read over read, too many bytes where "
"read, this shouldn't happen, might be "
"a logical error!");
}
}
// This shouldn't happen, if r > 0 our fd has to be in the list!
throw IOException ("select reports ready to read, but our fd isn't"
" in the list, this shouldn't happen!");
} }
} }
return static_cast<size_t> (bytes_read); return bytes_read;
} }
size_t size_t
Serial::SerialImpl::write (const string &data) Serial::SerialImpl::write (const string &data)
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::write"); throw PortNotOpenedException ("Serial::write");
} }
fd_set writefds;
ssize_t bytes_written = 0;
while (true)
{
if (timeout_ != -1)
{
FD_ZERO (&writefds);
FD_SET (fd_, &writefds);
struct timeval timeout;
timeout.tv_sec = timeout_ / 1000;
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000;
int r = select (fd_ + 1, NULL, &writefds, NULL, &timeout);
if (r == -1 && errno == EINTR) return static_cast<size_t> (::write (fd_, data.c_str (), data.length ()));
continue;
if (r == -1)
{
throw IOException (errno);
}
}
if (timeout_ == -1 || FD_ISSET (fd_, &writefds))
{
bytes_written = ::write (fd_, data.c_str (), data.length ());
// read should always return some data as select reported it was
// ready to read when we get to this point.
if (bytes_written < 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?)");
}
break;
}
else
{
break;
}
}
return static_cast<size_t> (bytes_written);
} }
void void
@ -501,7 +529,7 @@ void
Serial::SerialImpl::setBaudrate (unsigned long baudrate) Serial::SerialImpl::setBaudrate (unsigned long baudrate)
{ {
baudrate_ = baudrate; baudrate_ = baudrate;
if (isOpen_) if (is_open_)
reconfigurePort (); reconfigurePort ();
} }
@ -515,7 +543,7 @@ void
Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
{ {
bytesize_ = bytesize; bytesize_ = bytesize;
if (isOpen_) if (is_open_)
reconfigurePort (); reconfigurePort ();
} }
@ -529,7 +557,7 @@ void
Serial::SerialImpl::setParity (serial::parity_t parity) Serial::SerialImpl::setParity (serial::parity_t parity)
{ {
parity_ = parity; parity_ = parity;
if (isOpen_) if (is_open_)
reconfigurePort (); reconfigurePort ();
} }
@ -543,7 +571,7 @@ void
Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
{ {
stopbits_ = stopbits; stopbits_ = stopbits;
if (isOpen_) if (is_open_)
reconfigurePort (); reconfigurePort ();
} }
@ -557,7 +585,7 @@ void
Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
{ {
flowcontrol_ = flowcontrol; flowcontrol_ = flowcontrol;
if (isOpen_) if (is_open_)
reconfigurePort (); reconfigurePort ();
} }
@ -570,7 +598,7 @@ Serial::SerialImpl::getFlowcontrol () const
void void
Serial::SerialImpl::flush () Serial::SerialImpl::flush ()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::flush"); throw PortNotOpenedException ("Serial::flush");
} }
@ -580,7 +608,7 @@ Serial::SerialImpl::flush ()
void void
Serial::SerialImpl::flushInput () Serial::SerialImpl::flushInput ()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::flushInput"); throw PortNotOpenedException ("Serial::flushInput");
} }
@ -590,7 +618,7 @@ Serial::SerialImpl::flushInput ()
void void
Serial::SerialImpl::flushOutput () Serial::SerialImpl::flushOutput ()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::flushOutput"); throw PortNotOpenedException ("Serial::flushOutput");
} }
@ -600,7 +628,7 @@ Serial::SerialImpl::flushOutput ()
void void
Serial::SerialImpl::sendBreak (int duration) Serial::SerialImpl::sendBreak (int duration)
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::sendBreak"); throw PortNotOpenedException ("Serial::sendBreak");
} }
@ -610,7 +638,7 @@ Serial::SerialImpl::sendBreak (int duration)
void void
Serial::SerialImpl::setBreak (bool level) Serial::SerialImpl::setBreak (bool level)
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::setBreak"); throw PortNotOpenedException ("Serial::setBreak");
} }
@ -626,7 +654,7 @@ Serial::SerialImpl::setBreak (bool level)
void void
Serial::SerialImpl::setRTS (bool level) Serial::SerialImpl::setRTS (bool level)
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::setRTS"); throw PortNotOpenedException ("Serial::setRTS");
} }
@ -642,7 +670,7 @@ Serial::SerialImpl::setRTS (bool level)
void void
Serial::SerialImpl::setDTR (bool level) Serial::SerialImpl::setDTR (bool level)
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::setDTR"); throw PortNotOpenedException ("Serial::setDTR");
} }
@ -659,7 +687,7 @@ Serial::SerialImpl::setDTR (bool level)
bool bool
Serial::SerialImpl::getCTS () Serial::SerialImpl::getCTS ()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::getCTS"); throw PortNotOpenedException ("Serial::getCTS");
} }
@ -670,7 +698,7 @@ Serial::SerialImpl::getCTS ()
bool bool
Serial::SerialImpl::getDSR() Serial::SerialImpl::getDSR()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::getDSR"); throw PortNotOpenedException ("Serial::getDSR");
} }
@ -681,7 +709,7 @@ Serial::SerialImpl::getDSR()
bool bool
Serial::SerialImpl::getRI() Serial::SerialImpl::getRI()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::getRI"); throw PortNotOpenedException ("Serial::getRI");
} }
@ -692,7 +720,7 @@ Serial::SerialImpl::getRI()
bool bool
Serial::SerialImpl::getCD() Serial::SerialImpl::getCD()
{ {
if (isOpen_ == false) if (is_open_ == false)
{ {
throw PortNotOpenedException ("Serial::getCD"); throw PortNotOpenedException ("Serial::getCD");
} }

View File

@ -9,7 +9,6 @@
#endif #endif
using std::invalid_argument; using std::invalid_argument;
using std::memset;
using std::min; using std::min;
using std::numeric_limits; using std::numeric_limits;
using std::vector; using std::vector;
@ -86,98 +85,113 @@ Serial::available ()
return pimpl_->available (); return pimpl_->available ();
} }
size_t
Serial::read_ (unsigned char *buffer, size_t size)
{
return this->pimpl_->read (buffer, size);
}
size_t
Serial::read (unsigned char *buffer, size_t size)
{
ScopedReadLock (this->pimpl_);
return this->pimpl_->read (buffer, size);
}
size_t
Serial::read (std::vector<unsigned char> &buffer, size_t size)
{
ScopedReadLock (this->pimpl_);
unsigned char *buffer_ = new unsigned char[size];
size_t bytes_read = this->pimpl_->read (buffer_, size);
buffer.insert (buffer.end (), buffer_, buffer_+bytes_read);
delete[] buffer_;
return bytes_read;
}
size_t
Serial::read (std::string &buffer, size_t size)
{
ScopedReadLock (this->pimpl_);
unsigned char *buffer_ = new unsigned char[size];
size_t bytes_read = this->pimpl_->read (buffer_, size);
buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read);
delete[] buffer_;
return bytes_read;
}
string string
Serial::read (size_t size) Serial::read (size_t size)
{ {
ScopedReadLock(this->pimpl_); std::string buffer;
if (read_cache_.size() >= size) this->read (buffer, size);
{ return buffer;
// Don't need to do a new read. }
string result = read_cache_.substr (0, size);
read_cache_ = read_cache_.substr (size, read_cache_.size ());
return result;
}
else
{
// Needs to read, loop until we have read enough or timeout
string result (read_cache_.substr (0, size));
read_cache_.clear ();
while (true) size_t
{ Serial::readline (string &buffer, size_t size, string eol)
char buf[256]; {
size_t chars_read = pimpl_->read (buf, 256); ScopedReadLock (this->pimpl_);
if (chars_read > 0) size_t eol_len = eol.length();
{ unsigned char buffer_[size];
read_cache_.append(buf, chars_read); size_t read_so_far = 0;
} while (true)
else {
break; // Timeout occured size_t bytes_read = this->read_ (buffer_+read_so_far, 1);
read_so_far += bytes_read;
if (chars_read > size) if (bytes_read == 0) {
{ break; // Timeout occured on reading 1 byte
result.append (read_cache_.substr (0, size)); }
read_cache_ = read_cache_.substr (size, read_cache_.size ()); if (string(buffer_[read_so_far-eol_len], eol_len) == eol) {
break; break; // EOL found
} }
else if (read_so_far == size) {
{ break; // Reached the maximum read length
result.append (read_cache_.substr (0, size));
read_cache_.clear ();
size -= chars_read;
}
} }
return result;
} }
return read_so_far;
} }
string string
Serial::readline (size_t size, string eol) Serial::readline (size_t size, string eol)
{ {
size_t leneol = eol.length (); std::string buffer;
string line = ""; this->readline (buffer, size, eol);
while (true) return buffer;
{
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)
{
break;
}
}
else
// Timeout
break;
}
return line;
} }
vector<string> vector<string>
Serial::readlines(string eol) Serial::readlines (size_t size, string eol)
{ {
if (pimpl_->getTimeout () < 0) ScopedReadLock (this->pimpl_);
{ std::vector<std::string> lines;
throw invalid_argument ("Error, must be set for readlines"); size_t eol_len = eol.length();
} unsigned char buffer_[size];
size_t leneol = eol.length (); size_t read_so_far = 0;
vector<string> lines; size_t start_of_line = 0;
while (true) while (read_so_far < size) {
{ size_t bytes_read = this->read_ (buffer_+read_so_far, 1);
string line = readline (numeric_limits<size_t>::max (), eol); read_so_far += bytes_read;
if (!line.empty ()) if (bytes_read == 0) {
{ if (start_of_line != read_so_far) {
lines.push_back (line); lines.push_back(
if (line.substr (line.length () - leneol, leneol) == eol) std::string(buffer_[start_of_line], read_so_far-start_of_line));
break; }
break; // Timeout occured on reading 1 byte
}
if (string(buffer_[read_so_far-eol_len], eol_len) == eol) {
// EOL found
lines.push_back(
std::string(buffer_[start_of_line], read_so_far-start_of_line));
start_of_line = read_so_far;
}
if (read_so_far == size) {
if (start_of_line != read_so_far) {
lines.push_back(
std::string(buffer_[start_of_line], read_so_far-start_of_line));
}
break; // Reached the maximum read length
} }
else
// Timeout
break;
} }
return lines; return lines;
} }