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:
parent
87cd030615
commit
8f4b34cc03
5
Makefile
5
Makefile
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
std::string eol = "\n");
|
|
||||||
|
|
||||||
std::vector<std::string> readlines(std::string eol = "\n");
|
|
||||||
|
|
||||||
/*! Read a given amount of bytes from the serial port.
|
|
||||||
*
|
*
|
||||||
* 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 maximum length of a line defaults to size_t::max()
|
||||||
* \param size A size_t defining how many bytes to be read.
|
* \param eol A string to match against for the EOL.
|
||||||
*
|
*
|
||||||
* \return A size_t that represents how many bytes were read.
|
* \return A std::string containing the line.
|
||||||
*
|
|
||||||
* \see Serial::read(size_t)
|
|
||||||
*/
|
*/
|
||||||
//size_t
|
std::string
|
||||||
//read (std::string &buffer, size_t size = 1);
|
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
|
* This requires a timeout > 0 before it can be run. It will read until a
|
||||||
* serial port.
|
* 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
|
std::vector<std::string>
|
||||||
//write (unsigned char* data, size_t length);
|
readlines(std::string eol = "\n");
|
||||||
|
|
||||||
/*! 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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
397
src/impl/unix.cc
397
src/impl/unix.cc
@ -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 < 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;
|
||||||
}
|
}
|
||||||
|
|||||||
293
src/serial.cc
293
src/serial.cc
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 *****/
|
||||||
|
|||||||
@ -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) {
|
||||||
Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000);
|
try {
|
||||||
s.flush();
|
Serial s("/dev/tty.usbserial-A900adHq", 115200, 2000);
|
||||||
int count = 0;
|
s.flush();
|
||||||
while (1) {
|
long long count = 0;
|
||||||
size_t available = s.available();
|
while (1) {
|
||||||
cout << "avialable: " << available << endl;
|
// size_t available = s.available();
|
||||||
string line = s.readline();
|
// cout << "avialable: " << available << endl;
|
||||||
cout << count << ": " << line;
|
string line = s.readline();
|
||||||
count++;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user