1
0
mirror of https://github.com/wjwwood/serial.git synced 2026-01-22 11:44:53 +08:00

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

Conflicts:
	include/serial/impl/unix.h
	include/serial/serial.h
	serial.cmake
	src/impl/unix.cc
	src/serial.cc
This commit is contained in:
William Woodall 2012-01-11 23:53:10 -06:00
commit 65fc8fb2a4
5 changed files with 399 additions and 124 deletions

View File

@ -1,6 +1,7 @@
/*! /*!
* \file serial/impl/unix.h * \file serial/impl/unix.h
* \author William Woodall <wjwwood@gmail.com> * \author William Woodall <wjwwood@gmail.com>
* \author John Harrison <ash@greaterthaninfinity.com>
* \version 0.1 * \version 0.1
* *
* \section LICENSE * \section LICENSE
@ -39,31 +40,43 @@
namespace serial { namespace serial {
class Serial::Serial_pimpl { using std::string;
public:
Serial_pimpl (const std::string &port,
int baudrate,
long timeout,
bytesize_t bytesize,
parity_t parity,
stopbits_t stopbits,
flowcontrol_t flowcontrol);
virtual ~Serial_pimpl (); class serial::Serial::SerialImpl {
public:
SerialImpl (const string &port,
int baudrate,
long timeout,
bytesize_t bytesize,
parity_t parity,
stopbits_t stopbits,
flowcontrol_t flowcontrol);
virtual ~SerialImpl ();
void open (); void open ();
void close (); void close ();
bool isOpen (); bool isOpen ();
size_t read (unsigned char* buffer, size_t size = 1); size_t available ();
std::string read (size_t size = 1); string read (size_t size = 1);
size_t read (std::string &buffer, size_t size = 1); size_t write (const string &data);
size_t write (unsigned char* data, size_t length); void flush ();
size_t write (const std::string &data); void flushInput ();
void flushOutput ();
void setPort (const std::string &port); void sendBreak();
std::string getPort () const; void setBreak();
void setRTS();
void setDTR();
void getCTS();
void getDSR();
void getRI();
void getCD();
void setPort (const string &port);
string getPort () const;
void setTimeout (long timeout); void setTimeout (long timeout);
long getTimeout () const; long getTimeout () const;
@ -83,19 +96,26 @@ public:
void setFlowcontrol (flowcontrol_t flowcontrol); void setFlowcontrol (flowcontrol_t flowcontrol);
flowcontrol_t getFlowcontrol () const; flowcontrol_t getFlowcontrol () const;
private: protected:
// Serial handle void reconfigurePort ();
int fd;
// Parameters
std::string port;
int baudrate;
long timeout;
bytesize_t bytesize;
parity_t parity;
stopbits_t stopbits;
flowcontrol_t flowcontrol;
private:
int fd_; // The current file descriptor.
bool isOpen_;
int interCharTimeout_;
int writeTimeout_;
int xonxoff_;
int rtscts_;
string port_; // Path to the file descriptor
int baudrate_; // Baudrate
long timeout_; // Timeout for read operations
bytesize_t bytesize_; // Size of the bytes
parity_t parity_; // Parity
stopbits_t stopbits_; // Stop Bits
flowcontrol_t flowcontrol_; // Flow Control
}; };
} }

View File

@ -37,8 +37,9 @@
#define SERIAL_H #define SERIAL_H
#include <string> #include <string>
#include <memory> // std::shared_ptr
#include <sstream> #include <sstream>
#include <vector>
#include <limits>
namespace serial { namespace serial {
@ -153,6 +154,11 @@ public:
void void
close (); close ();
/* Return the number of characters in the buffer.
*/
size_t
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
@ -166,8 +172,8 @@ public:
* *
* \return A size_t representing the number of bytes actually read. * \return A size_t representing the number of bytes actually read.
*/ */
size_t //size_t
read (unsigned char* buffer, size_t size = 1); //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.
* *
@ -182,6 +188,11 @@ 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(),
std::string eol = "\n");
std::vector<std::string> readlines(std::string eol = "\n");
/*! Read a given amount of bytes from the serial port. /*! Read a given amount of bytes from the serial port.
* *
* Reads into a std::string by reference rather than returning it. * Reads into a std::string by reference rather than returning it.
@ -193,8 +204,8 @@ public:
* *
* \see Serial::read(size_t) * \see Serial::read(size_t)
*/ */
size_t //size_t
read (std::string &buffer, size_t size = 1); //read (std::string &buffer, size_t size = 1);
/*! Write bytes from the data to the serial port by given length. /*! Write bytes from the data to the serial port by given length.
* *
@ -205,8 +216,8 @@ public:
* *
* \return A size_t representing the number of bytes actually written. * \return A size_t representing the number of bytes actually written.
*/ */
size_t //size_t
write (unsigned char* data, size_t length); //write (unsigned char* data, size_t length);
/*! Write a string to the serial port. /*! Write a string to the serial port.
* *
@ -370,9 +381,8 @@ private:
const Serial& operator=(Serial); const Serial& operator=(Serial);
// Pimpl idiom, d_pointer // Pimpl idiom, d_pointer
class Serial_pimpl; class SerialImpl;
Serial_pimpl * pimpl; SerialImpl *pimpl;
}; };
class IOException : public std::exception { class IOException : public std::exception {

View File

@ -41,7 +41,7 @@ ENDIF(NOT DEFINED(LIBRARY_OUTPUT_PATH))
include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_SOURCE_DIR}/include)
# Add default source files # Add default source files
set(SERIAL_SRCS src/serial.cc src/serial_listener.cc) set(SERIAL_SRCS src/serial.cc src/impl/unix.cc) # src/serial_listener.cc)
# Add default header files # Add default header files
set(SERIAL_HEADERS include/serial/serial.h include/serial/serial_listener.h) set(SERIAL_HEADERS include/serial/serial.h include/serial/serial_listener.h)

View File

@ -1,129 +1,320 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <sysexits.h>
#include <termios.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include "serial/impl/unix.h" #include "serial/impl/unix.h"
using namespace serial; #ifndef TIOCINQ
#ifdef FIONREAD
#define TIOCINQ FIONREAD
#else
#define TIOCINQ 0x541B
#endif
#endif
Serial::Serial_pimpl::Serial_pimpl (const std::string &port, int baudrate, using ::serial::Serial;
long timeout, bytesize_t bytesize, using std::string;
parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol) Serial::SerialImpl::SerialImpl (const string &port, int baudrate,
: port(port), baudrate(baudrate), timeout(timeout), bytesize(bytesize), long timeout, bytesize_t bytesize,
parity(parity), stopbits(stopbits), flowcontrol(flowcontrol) parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol)
: fd_(-1), isOpen_(false), interCharTimeout_(-1), port_(port),
baudrate_(baudrate), timeout_(timeout), bytesize_(bytesize),
parity_(parity), stopbits_(stopbits), flowcontrol_(flowcontrol)
{ {
this->fd = -1; if (port_.empty() == false) this->open();
} }
Serial::Serial_pimpl::~Serial_pimpl () { Serial::SerialImpl::~SerialImpl () {
if (this->isOpen()) this->close();
this->close();
} }
void void
Serial::Serial_pimpl::open () { Serial::SerialImpl::open () {
if (port_.empty() == false) throw "error";
if (isOpen_ == false) throw "error";
fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_ == -1) throw "Error";
reconfigurePort();
isOpen_ = true;
} }
void void
Serial::Serial_pimpl::close () { Serial::SerialImpl::reconfigurePort () {
this->fd = -1; if (fd_ == -1) throw "Error"; // Can only operate on a valid file descriptor
struct termios options; // The current 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 (interCharTimeout_ == -1) {
vmin = 1;
vtime = int(interCharTimeout_ * 10);
}
if (tcgetattr(fd_, &originalTTYAttrs) == -1) throw "Error";
options = originalTTYAttrs;
// set up raw mode / no echo / binary
options.c_cflag |= (CLOCAL|CREAD);
options.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|
ISIG|IEXTEN); //|ECHOPRT
options.c_oflag &= ~(OPOST);
options.c_iflag &= ~(INLCR|IGNCR|ICRNL|IGNBRK);
#ifdef IUCLC
options.c_iflag &= ~IUCLC;
#endif
#ifdef PARMRK
options.c_iflag &= ~PARMRK;
#endif
// setup baud rate
// TODO(ash_git): validate baud rate
cfsetspeed(&options, baudrate_);
// setup char len
options.c_cflag &= ~CSIZE;
if (bytesize_ == EIGHTBITS)
options.c_cflag |= CS8;
else if (bytesize_ == SEVENBITS)
options.c_cflag |= CS7;
else if (bytesize_ == SIXBITS)
options.c_cflag |= CS6;
else if (bytesize_ == FIVEBITS)
options.c_cflag |= CS5;
else
throw "ValueError(Invalid char len: %%r)";
// setup stopbits
if (stopbits_ == STOPBITS_ONE)
options.c_cflag &= ~(CSTOPB);
else if (stopbits_ == STOPBITS_ONE_POINT_FIVE)
options.c_cflag |= (CSTOPB); // XXX same as TWO.. there is no POSIX support for 1.5
else if (stopbits_ == STOPBITS_TWO)
options.c_cflag |= (CSTOPB);
else
throw "ValueError(Invalid stop bit specification:)";
// setup parity
options.c_iflag &= ~(INPCK|ISTRIP);
if (parity_ == PARITY_NONE) {
options.c_cflag &= ~(PARENB|PARODD);
}
else if (parity_ == PARITY_EVEN) {
options.c_cflag &= ~(PARODD);
options.c_cflag |= (PARENB);
}
else if (parity_ == PARITY_ODD) {
options.c_cflag |= (PARENB|PARODD);
}
else {
throw "ValueError(Invalid parity:";
}
// setup flow control
// xonxoff
#ifdef IXANY
if (xonxoff_)
options.c_iflag |= (IXON|IXOFF); //|IXANY)
else
options.c_iflag &= ~(IXON|IXOFF|IXANY);
#else
if (xonxoff_)
options.c_iflag |= (IXON|IXOFF);
else
options.c_iflag &= ~(IXON|IXOFF);
#endif
// rtscts
#ifdef CRTSCTS
if (rtscts_)
options.c_cflag |= (CRTSCTS);
else
options.c_cflag &= ~(CRTSCTS);
#elif defined CNEW_RTSCTS
if (rtscts_)
options.c_cflag |= (CNEW_RTSCTS);
else
options.c_cflag &= ~(CNEW_RTSCTS);
#else
#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;
// activate settings
::tcsetattr(fd_, TCSANOW, &options);
} }
void
Serial::SerialImpl::close () {
if (isOpen_ == true) {
if (fd_ != -1) {
::close(fd_);
fd_ = -1;
}
isOpen_ = false;
}
}
bool bool
Serial::Serial_pimpl::isOpen () { Serial::SerialImpl::isOpen () {
return false; return isOpen_;
} }
size_t size_t
Serial::Serial_pimpl::read (unsigned char* buffer, size_t size) { Serial::SerialImpl::available () {
return 0; if (!isOpen_) {
return 0;
}
int count = 0;
int result = ioctl(fd_, TIOCINQ, &count);
if (result == 0) {
return count;
} else {
throw "Error";
}
} }
std::string string
Serial::Serial_pimpl::read (size_t size) { Serial::SerialImpl::read (size_t size) {
return ""; if (!isOpen_) throw "PortNotOpenError()";
string message = "";
char buf[1024];
fd_set readfds;
while (message.length() < size) {
FD_ZERO(&readfds);
FD_SET(fd_, &readfds);
struct timeval timeout;
timeout.tv_sec = timeout_ / 1000;
timeout.tv_usec = timeout_ % 1000;
int r = select(1, &readfds, NULL, NULL, &timeout);
if (r == -1 && errno == EINTR)
continue;
if (r == -1) {
perror("select()");
exit(EXIT_FAILURE);
}
if (FD_ISSET(fd_, &readfds)) {
memset(buf, 0, 1024);
size_t bytes_read = ::read(fd_, buf, 1024);
// 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 "SerialException('device reports readiness to read but returned no data (device disconnected?)')";
}
message.append(buf, bytes_read);
}
else {
break; // Timeout
}
}
return message;
} }
size_t size_t
Serial::Serial_pimpl::read (std::string &buffer, size_t size) { Serial::SerialImpl::write (const string &data) {
return 0; if (isOpen_ == false) throw "portNotOpenError";
}
size_t size_t t = data.length();
Serial::Serial_pimpl::write (unsigned char* data, size_t length) { size_t n = ::write(fd_, data.c_str(), data.length());
return 0; if (n == -1) {
} throw "Write error";
}
size_t return n;
Serial::Serial_pimpl::write (const std::string &data) {
return 0;
} }
void void
Serial::Serial_pimpl::setPort (const std::string &port) { Serial::SerialImpl::setPort (const string &port) {
port_ = port;
} }
std::string string
Serial::Serial_pimpl::getPort () const { Serial::SerialImpl::getPort () const {
return this->port; return port_;
} }
void void
Serial::Serial_pimpl::setTimeout (long timeout) { Serial::SerialImpl::setTimeout (long timeout) {
timeout_ = timeout;
} }
long long
Serial::Serial_pimpl::getTimeout () const { Serial::SerialImpl::getTimeout () const {
return this->timeout; return timeout_;
} }
void void
Serial::Serial_pimpl::setBaudrate (int baudrate) { Serial::SerialImpl::setBaudrate (int baudrate) {
baudrate_ = baudrate;
reconfigurePort();
} }
int int
Serial::Serial_pimpl::getBaudrate () const { Serial::SerialImpl::getBaudrate () const {
return this->baudrate; return baudrate_;
} }
void void
Serial::Serial_pimpl::setBytesize (bytesize_t bytesize) { Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) {
bytesize_ = bytesize;
} }
bytesize_t serial::bytesize_t
Serial::Serial_pimpl::getBytesize () const { Serial::SerialImpl::getBytesize () const {
return this->bytesize; return bytesize_;
} }
void void
Serial::Serial_pimpl::setParity (parity_t parity) { Serial::SerialImpl::setParity (serial::parity_t parity) {
parity_ = parity;
} }
parity_t serial::parity_t
Serial::Serial_pimpl::getParity () const { Serial::SerialImpl::getParity () const {
return this->parity; return parity_;
} }
void void
Serial::Serial_pimpl::setStopbits (stopbits_t stopbits) { Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) {
stopbits_ = stopbits;
} }
stopbits_t serial::stopbits_t
Serial::Serial_pimpl::getStopbits () const { Serial::SerialImpl::getStopbits () const {
return this->stopbits; return stopbits_;
} }
void void
Serial::Serial_pimpl::setFlowcontrol (flowcontrol_t flowcontrol) { Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) {
flowcontrol_ = flowcontrol;
} }
flowcontrol_t serial::flowcontrol_t
Serial::Serial_pimpl::getFlowcontrol () const { Serial::SerialImpl::getFlowcontrol () const {
return this->flowcontrol; return flowcontrol_;
} }

View File

@ -6,15 +6,22 @@
#include "serial/impl/unix.h" #include "serial/impl/unix.h"
#endif #endif
using namespace serial; using serial::Serial;
using serial::bytesize_t;
using serial::parity_t;
using serial::stopbits_t;
using serial::flowcontrol_t;
using std::string;
using std::vector;
using std::numeric_limits;
using std::size_t;
Serial::Serial (const std::string &port, int baudrate, Serial::Serial (const string &port, int baudrate, long timeout,
long timeout, bytesize_t bytesize, bytesize_t bytesize, parity_t parity, stopbits_t stopbits,
parity_t parity, stopbits_t stopbits, flowcontrol_t flowcontrol)
flowcontrol_t flowcontrol)
{ {
pimpl = new Serial_pimpl(port,baudrate,timeout,bytesize,parity,stopbits, pimpl = new Serial_pimpl(port, baudrate, timeout, bytesize, parity,
flowcontrol); stopbits, flowcontrol);
} }
Serial::~Serial () { Serial::~Serial () {
@ -36,36 +43,83 @@ Serial::isOpen () {
} }
size_t size_t
Serial::read (unsigned char* buffer, size_t size) { Serial::available () {
return this->pimpl->read (buffer, size); return this->pimpl->available();
} }
std::string //size_t
//Serial::read (unsigned char* buffer, size_t size) {
// return this->pimpl->read (buffer, size);
//}
string
Serial::read (size_t size) { Serial::read (size_t size) {
return this->pimpl->read (size); return this->pimpl->read (size);
} }
size_t string
Serial::read (std::string &buffer, size_t size) { Serial::readline(size_t size, string eol) {
return this->pimpl->read (buffer, size); size_t leneol = eol.length();
string line;
while (true) {
string c = read(1);
if (c.empty()) {
line += c;
if (line.substr(line.length() - leneol, leneol) == eol) {
break;
}
if (line.length() >= size) {
break;
}
}
else {
// Timeout
break;
}
}
return line;
} }
size_t vector<string>
Serial::write (unsigned char* data, size_t length) { Serial::readlines(string eol) {
return this->pimpl->write (data, length); if (this->pimpl->getTimeout() < 0) {
throw "Error, must be set for readlines";
}
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)
break;
}
else {
// Timeout
break;
}
}
return lines;
} }
//size_t
//Serial::write (unsigned char* data, size_t length) {
// return this->pimpl->write (data, length);
//}
size_t size_t
Serial::write (const std::string &data) { Serial::write (const string &data) {
return this->pimpl->write (data); return this->pimpl->write (data);
} }
void void
Serial::setPort (const std::string &port) { Serial::setPort (const string &port) {
this->pimpl->setPort (port); this->pimpl->setPort (port);
} }
std::string string
Serial::getPort () const { Serial::getPort () const {
return this->pimpl->getPort (); return this->pimpl->getPort ();
} }